| <!-- |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, |
| software distributed under the License is distributed on an |
| "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| KIND, either express or implied. See the License for the |
| specific language governing permissions and limitations |
| under the License. |
| --> |
| |
| <script lang="ts"> |
| import Button from '../Button.svelte'; |
| import Select from '../Select.svelte'; |
| import { decoderRegistry } from './decoders/utils/decoderRegistry'; |
| import { decodeBase64 } from '$lib/utils/base64Utils'; |
| |
| interface Props { |
| payload?: string | undefined; |
| codec?: string | undefined | null; |
| } |
| |
| let { payload = undefined, codec = undefined }: Props = $props(); |
| |
| type ErrorState = { title: string; message: string }; |
| type DecodedState = |
| | { status: 'idle'; forceChangeDecoder: boolean } |
| | { status: 'error'; error: ErrorState } |
| | { status: 'success'; content: string }; |
| |
| let decodeState = $state<DecodedState>({ status: 'idle', forceChangeDecoder: false }); |
| let showRaw = $state(false); |
| let selectedDecoder = $state(codec || 'string'); |
| |
| function getError(type: 'no_payload' | 'unsupported_codec' | 'invalid_format'): ErrorState { |
| switch (type) { |
| case 'no_payload': |
| return { |
| title: 'No payload', |
| message: 'This message has no payload to decode' |
| }; |
| case 'unsupported_codec': |
| return { |
| title: 'Unsupported codec', |
| message: `The specified codec ${codec} is not supported. Select another decoder from the dropdown below.` |
| }; |
| case 'invalid_format': |
| return { |
| title: 'Invalid format', |
| message: `The payload is not valid ${selectedDecoder.toUpperCase()}` |
| }; |
| } |
| } |
| |
| function decode() { |
| if (!payload) { |
| decodeState = { status: 'error', error: getError('no_payload') }; |
| return; |
| } |
| |
| const decodedPayload = decodeBase64(payload); |
| if (!decodedPayload) { |
| decodeState = { status: 'error', error: getError('invalid_format') }; |
| return; |
| } |
| |
| const decoder = decoderRegistry.get(selectedDecoder); |
| if (!decoder) { |
| decodeState = { status: 'error', error: getError('unsupported_codec') }; |
| return; |
| } |
| |
| const content = decoder.decode(decodedPayload); |
| if (!content) { |
| decodeState = { status: 'error', error: getError('invalid_format') }; |
| return; |
| } |
| |
| decodeState = { status: 'success', content }; |
| } |
| </script> |
| |
| {#if decodeState.status === 'idle'} |
| {#if !codec || !decoderRegistry.get(codec) || decodeState.forceChangeDecoder} |
| <div class="mb-4"> |
| <Select |
| label="Select decoder" |
| name="decoder" |
| options={decoderRegistry.getNames()} |
| bind:value={selectedDecoder} |
| /> |
| </div> |
| {/if} |
| <Button variant="contained" onclick={decode}>Decode</Button> |
| {:else} |
| {#if decodeState.status === 'error'} |
| <div class="bg-red-100 dark:bg-red-900 p-4 rounded-md w-full"> |
| <p class="font-bold">{decodeState.error.title}</p> |
| <p>{decodeState.error.message}</p> |
| </div> |
| {/if} |
| |
| {#if decodeState.status === 'success'} |
| <div class="flex items-center gap-3"> |
| <p class="font-bold">Codec: {selectedDecoder}</p> |
| <Button |
| variant="text" |
| onclick={() => (decodeState = { status: 'idle', forceChangeDecoder: true })} |
| >Change decoder</Button |
| > |
| </div> |
| <div class="w-full mt-2"> |
| <pre class="bg-gray-100 dark:bg-gray-800 p-1 rounded-md overflow-auto"><code |
| >{decodeState.content}</code |
| ></pre> |
| </div> |
| {/if} |
| |
| <div class="mt-4 mb-2"> |
| <Button variant="text" onclick={() => (showRaw = !showRaw)}> |
| {showRaw ? 'Hide' : 'Show'} raw payload (base64) |
| </Button> |
| </div> |
| |
| {#if showRaw && payload} |
| <div class="w-full"> |
| <pre |
| class="bg-gray-100 dark:bg-gray-800 p-4 rounded-md overflow-auto whitespace-pre-wrap break-all"><code |
| >{payload}</code |
| ></pre> |
| </div> |
| {/if} |
| {/if} |