From 054760e75259c5165c8b13f21401e7d588ff178e Mon Sep 17 00:00:00 2001 From: Arseniy Klempner Date: Thu, 27 Mar 2025 19:05:57 -0700 Subject: [PATCH] add legend explaining sds concepts --- .../src/lib/components/History.svelte | 233 +++-------- .../src/lib/components/HistoryItem.svelte | 222 +++++++++++ .../src/lib/components/LegendDemo.svelte | 64 +++ .../src/lib/components/LegendModal.svelte | 371 ++++++++++++++++++ .../src/lib/components/Missing.svelte | 8 +- .../src/lib/components/Register.svelte | 0 .../src/lib/components/Tooltip.svelte | 129 ++++++ .../sds-demo/src/lib/data/history_sample.ts | 2 + .../sds-demo/src/lib/data/sample_history.ts | 51 +++ .../sds-demo/src/lib/utils/tooltipUtils.ts | 91 +++++ .../sds-demo/src/routes/history/+page.svelte | 2 + 11 files changed, 998 insertions(+), 175 deletions(-) create mode 100644 examples/sds-demo/src/lib/components/HistoryItem.svelte create mode 100644 examples/sds-demo/src/lib/components/LegendDemo.svelte create mode 100644 examples/sds-demo/src/lib/components/LegendModal.svelte delete mode 100644 examples/sds-demo/src/lib/components/Register.svelte create mode 100644 examples/sds-demo/src/lib/components/Tooltip.svelte create mode 100644 examples/sds-demo/src/lib/data/history_sample.ts create mode 100644 examples/sds-demo/src/lib/data/sample_history.ts create mode 100644 examples/sds-demo/src/lib/utils/tooltipUtils.ts diff --git a/examples/sds-demo/src/lib/components/History.svelte b/examples/sds-demo/src/lib/components/History.svelte index 3958de5..a519d30 100644 --- a/examples/sds-demo/src/lib/components/History.svelte +++ b/examples/sds-demo/src/lib/components/History.svelte @@ -5,6 +5,8 @@ import { getIdenticon } from '$lib/identicon.svelte'; import { getMessageId } from '$lib/sds/message'; import type { MessageChannelEventObject } from '$lib/sds/stream'; + import HistoryItem from './HistoryItem.svelte'; + import LegendModal from './LegendModal.svelte'; // Map event types to colors using index signature const eventColors: { [key in string]: string } = { @@ -31,6 +33,7 @@ let identicon: any = $state(null); let currentFilter: string = $state('all'); let currentIdFilter: string | null = $state(null); + let showLegend: boolean = $state(false); // Map of filter values to event types const filterMap: { [key: string]: string | null } = { @@ -127,6 +130,11 @@ currentIdFilter = null; } + // Toggle legend display + function toggleLegend() { + showLegend = !showLegend; + } + onMount(async () => { identicon = await getIdenticon(); // Subscribe to the event stream and collect events @@ -137,6 +145,7 @@ } history = [event, ...history]; }); + (window as any).saveHistory = saveHistory; }); onDestroy(() => { @@ -145,16 +154,32 @@ unsubscribe(); } }); + + const saveHistory = () => { + const sampleHistory = history.map((event) => { + if((event.payload as any).bloomFilter) { + (event.payload as any).bloomFilter = new Uint8Array([0, 0, 0, 0]); + } + return { + type: event.type, + payload: event.payload + }; + }); + localStorage.setItem('history', JSON.stringify(sampleHistory)); + };
- +
+ + +
{#if currentIdFilter}
@@ -164,54 +189,16 @@ {/if} {#each filteredHistory as event, index} - {@const color = eventColors[event.type] || '#888'} - {@const name = eventNames[event.type] || event.type} - {@const id = getMessageId(event)} - {@const matchesFilter = currentIdFilter && id === currentIdFilter} -
handleEventClick(id)}> -
-
-
- Identicon -
-
-
- {name} -
-
- {id} -
-
- {#if event.type === MessageChannelEvent.MessageDelivered} -
- {event.payload.sentOrReceived} -
- {/if} - {#if event.type === MessageChannelEvent.MessageSent || event.type === MessageChannelEvent.MessageReceived} -
- {event.payload.lamportTimestamp} -
- {/if} -
- {#if event.type === MessageChannelEvent.MessageSent || event.type === MessageChannelEvent.MessageReceived} - {#each event.payload.causalHistory as dependency} - {@const dependencyMatchesFilter = - currentIdFilter && dependency.messageId === currentIdFilter} -
handleDependencyClick(dependency.messageId, event)} - > - {dependency.messageId} -
- {/each} - {/if} -
-
+ {/each} + +
\ No newline at end of file diff --git a/examples/sds-demo/src/lib/components/LegendDemo.svelte b/examples/sds-demo/src/lib/components/LegendDemo.svelte new file mode 100644 index 0000000..45bd57c --- /dev/null +++ b/examples/sds-demo/src/lib/components/LegendDemo.svelte @@ -0,0 +1,64 @@ + + +
+

Message Events Visualization

+ +
+ +
+ + +
+ + \ No newline at end of file diff --git a/examples/sds-demo/src/lib/components/LegendModal.svelte b/examples/sds-demo/src/lib/components/LegendModal.svelte new file mode 100644 index 0000000..f75c378 --- /dev/null +++ b/examples/sds-demo/src/lib/components/LegendModal.svelte @@ -0,0 +1,371 @@ + + +{#if isOpen} +
+
+ +
+ +
+
+ +
+

Legend

+ +
+
+ {#each legendItems as event} +
+ +
+ {/each} +
+
+
+
+{/if} + + \ No newline at end of file diff --git a/examples/sds-demo/src/lib/components/Missing.svelte b/examples/sds-demo/src/lib/components/Missing.svelte index 7f6cf83..f083aa7 100644 --- a/examples/sds-demo/src/lib/components/Missing.svelte +++ b/examples/sds-demo/src/lib/components/Missing.svelte @@ -160,8 +160,8 @@ font-weight: bold; text-align: left; white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; + /* overflow: hidden; */ + /* text-overflow: ellipsis; */ } .event-id { @@ -169,8 +169,8 @@ font-size: 10px; color: rgba(255, 255, 255, 0.7); max-width: 220px; - overflow: hidden; - text-overflow: ellipsis; + /* overflow: hidden; */ + /* text-overflow: ellipsis; */ white-space: nowrap; } diff --git a/examples/sds-demo/src/lib/components/Register.svelte b/examples/sds-demo/src/lib/components/Register.svelte deleted file mode 100644 index e69de29..0000000 diff --git a/examples/sds-demo/src/lib/components/Tooltip.svelte b/examples/sds-demo/src/lib/components/Tooltip.svelte new file mode 100644 index 0000000..8a551db --- /dev/null +++ b/examples/sds-demo/src/lib/components/Tooltip.svelte @@ -0,0 +1,129 @@ + + +{#if visible} +
+ {@html content} +
+{/if} + + \ No newline at end of file diff --git a/examples/sds-demo/src/lib/data/history_sample.ts b/examples/sds-demo/src/lib/data/history_sample.ts new file mode 100644 index 0000000..195d718 --- /dev/null +++ b/examples/sds-demo/src/lib/data/history_sample.ts @@ -0,0 +1,2 @@ +export const historyJson = + '[{"type":"messageSent","payload":{"messageId":"db7ce7bff8734cc868da5bd8d880b58765ed9e0481f0c2f6b0ec86258322a3fa","channelId":"channel-id","lamportTimestamp":6,"causalHistory":[{"messageId":"bc8701dd8eacca44f01a177a2d7e2ac879dd189b1f8ea2b57b10bbdb82042bc0"},{"messageId":"082ac7ce5441c53e87869cd4be9f8aa558ddb295ae92fc14830742887e53624f","retrievalHint":{"0":214,"1":219,"2":248,"3":34,"4":159,"5":182,"6":204,"7":204,"8":214,"9":158,"10":44,"11":136,"12":61,"13":38,"14":139,"15":74,"16":202,"17":181,"18":89,"19":58,"20":28,"21":58,"22":239,"23":17,"24":222,"25":179,"26":161,"27":31,"28":93,"29":133,"30":33,"31":62}}],"bloomFilter":{"0":0,"1":0,"2":0,"3":0},"content":{"0":131,"1":244,"2":138,"3":91,"4":67,"5":146,"6":230,"7":217,"8":147,"9":127,"10":220,"11":45,"12":186,"13":198,"14":251,"15":233,"16":194,"17":154,"18":173,"19":122,"20":118,"21":63,"22":3,"23":98,"24":54,"25":55,"26":127,"27":223,"28":147,"29":243,"30":248,"31":52}}},{"type":"messageSent","payload":{"messageId":"082ac7ce5441c53e87869cd4be9f8aa558ddb295ae92fc14830742887e53624f","channelId":"channel-id","lamportTimestamp":5,"causalHistory":[{"messageId":"217e647921f9a6fc8ecfc480e207db828e18c5868d229cf5c5bf59be89dc70ff","retrievalHint":{"0":159,"1":58,"2":86,"3":42,"4":89,"5":216,"6":194,"7":116,"8":62,"9":48,"10":100,"11":114,"12":157,"13":109,"14":141,"15":43,"16":118,"17":232,"18":222,"19":233,"20":78,"21":99,"22":178,"23":159,"24":12,"25":128,"26":32,"27":0,"28":107,"29":6,"30":239,"31":248}},{"messageId":"bc8701dd8eacca44f01a177a2d7e2ac879dd189b1f8ea2b57b10bbdb82042bc0"}],"bloomFilter":{"0":0,"1":0,"2":0,"3":0},"content":{"0":216,"1":190,"2":35,"3":52,"4":137,"5":70,"6":190,"7":124,"8":225,"9":102,"10":44,"11":201,"12":253,"13":30,"14":217,"15":215,"16":212,"17":102,"18":248,"19":13,"20":5,"21":176,"22":223,"23":3,"24":237,"25":230,"26":122,"27":71,"28":139,"29":149,"30":84,"31":116}}},{"type":"messageDelivered","payload":{"messageId":"bc8701dd8eacca44f01a177a2d7e2ac879dd189b1f8ea2b57b10bbdb82042bc0","sentOrReceived":"received"}},{"type":"messageAcknowledged","payload":"217e647921f9a6fc8ecfc480e207db828e18c5868d229cf5c5bf59be89dc70ff"},{"type":"messageReceived","payload":{"messageId":"bc8701dd8eacca44f01a177a2d7e2ac879dd189b1f8ea2b57b10bbdb82042bc0","channelId":"channel-id","causalHistory":[{"messageId":"58cf44867e529152f4095aa6a951500a6a45571a062dc0bddb06aef48c97f85b","retrievalHint":{"0":187,"1":27,"2":172,"3":30,"4":21,"5":197,"6":201,"7":205,"8":17,"9":215,"10":52,"11":118,"12":5,"13":77,"14":161,"15":2,"16":86,"17":185,"18":245,"19":179,"20":138,"21":233,"22":236,"23":156,"24":100,"25":62,"26":79,"27":228,"28":233,"29":252,"30":212,"31":159}},{"messageId":"217e647921f9a6fc8ecfc480e207db828e18c5868d229cf5c5bf59be89dc70ff"}],"lamportTimestamp":4,"bloomFilter":{"0":0,"1":0,"2":0,"3":0},"content":{"0":226,"1":83,"2":22,"3":152,"4":152,"5":214,"6":24,"7":242,"8":123,"9":66,"10":241,"11":153,"12":150,"13":129,"14":91,"15":4,"16":252,"17":173,"18":187,"19":245,"20":188,"21":67,"22":246,"23":52,"24":42,"25":134,"26":115,"27":175,"28":98,"29":243,"30":106,"31":7}}},{"type":"messageSent","payload":{"messageId":"217e647921f9a6fc8ecfc480e207db828e18c5868d229cf5c5bf59be89dc70ff","channelId":"channel-id","lamportTimestamp":3,"causalHistory":[{"messageId":"d81b2617e63162843413eea8c62dada058ac7e6c8f8463fd5ef1171939cd9415","retrievalHint":{"0":148,"1":157,"2":166,"3":76,"4":103,"5":163,"6":82,"7":9,"8":108,"9":209,"10":251,"11":214,"12":209,"13":67,"14":38,"15":254,"16":223,"17":48,"18":66,"19":230,"20":42,"21":60,"22":159,"23":238,"24":104,"25":236,"26":176,"27":201,"28":156,"29":229,"30":108,"31":139}},{"messageId":"58cf44867e529152f4095aa6a951500a6a45571a062dc0bddb06aef48c97f85b"}],"bloomFilter":{"0":0,"1":0,"2":0,"3":0},"content":{"0":234,"1":207,"2":59,"3":184,"4":6,"5":114,"6":174,"7":167,"8":117,"9":7,"10":106,"11":72,"12":200,"13":180,"14":42,"15":89,"16":198,"17":192,"18":207,"19":159,"20":132,"21":150,"22":113,"23":137,"24":58,"25":86,"26":59,"27":231,"28":80,"29":155,"30":28,"31":46}}},{"type":"messageDelivered","payload":{"messageId":"58cf44867e529152f4095aa6a951500a6a45571a062dc0bddb06aef48c97f85b","sentOrReceived":"received"}},{"type":"messageAcknowledged","payload":"d81b2617e63162843413eea8c62dada058ac7e6c8f8463fd5ef1171939cd9415"},{"type":"messageReceived","payload":{"messageId":"58cf44867e529152f4095aa6a951500a6a45571a062dc0bddb06aef48c97f85b","channelId":"channel-id","causalHistory":[{"messageId":"d81b2617e63162843413eea8c62dada058ac7e6c8f8463fd5ef1171939cd9415"}],"lamportTimestamp":2,"bloomFilter":{"0":0,"1":0,"2":0,"3":0},"content":{"0":249,"1":28,"2":60,"3":238,"4":206,"5":175,"6":47,"7":195,"8":208,"9":78,"10":219,"11":149,"12":187,"13":140,"14":125,"15":103,"16":42,"17":67,"18":250,"19":140,"20":254,"21":137,"22":17,"23":0,"24":147,"25":162,"26":64,"27":42,"28":47,"29":75,"30":231,"31":72}}},{"type":"messageSent","payload":{"messageId":"d81b2617e63162843413eea8c62dada058ac7e6c8f8463fd5ef1171939cd9415","channelId":"channel-id","lamportTimestamp":1,"causalHistory":[],"bloomFilter":{"0":0,"1":0,"2":0,"3":0},"content":{"0":152,"1":245,"2":147,"3":245,"4":8,"5":125,"6":155,"7":106,"8":193,"9":66,"10":86,"11":63,"12":122,"13":191,"14":114,"15":83,"16":220,"17":101,"18":181,"19":220,"20":197,"21":199,"22":3,"23":173,"24":193,"25":220,"26":156,"27":181,"28":32,"29":254,"30":43,"31":86}}}]'; diff --git a/examples/sds-demo/src/lib/data/sample_history.ts b/examples/sds-demo/src/lib/data/sample_history.ts new file mode 100644 index 0000000..54136d0 --- /dev/null +++ b/examples/sds-demo/src/lib/data/sample_history.ts @@ -0,0 +1,51 @@ +import { MessageChannelEvent } from '@waku/sds'; + +// Sample history with different event types for the legend +export const historyJson = JSON.stringify([ + { + type: MessageChannelEvent.MessageSent, + payload: { + messageId: "db7ce7bff8734cc868da5bd8d880b58765ed9e0481f0c2f6b0ec86258322a3fa", + channelId: "channel-id", + lamportTimestamp: 6, + causalHistory: [], + bloomFilter: { 0: 0, 1: 0, 2: 0, 3: 0 }, + content: { 0: 131, 1: 244 } + } + }, + { + type: MessageChannelEvent.MessageDelivered, + payload: { + messageId: "bc8701dd8eacca44f01a177a2d7e2ac879dd189b1f8ea2b57b10bbdb82042bc0", + sentOrReceived: "received" + } + }, + { + type: MessageChannelEvent.MessageReceived, + payload: { + messageId: "bc8701dd8eacca44f01a177a2d7e2ac879dd189b1f8ea2b57b10bbdb82042bc0", + channelId: "channel-id", + causalHistory: [], + lamportTimestamp: 4, + bloomFilter: { 0: 0, 1: 0, 2: 0, 3: 0 }, + content: { 0: 226, 1: 83 } + } + }, + { + type: MessageChannelEvent.MessageAcknowledged, + payload: "217e647921f9a6fc8ecfc480e207db828e18c5868d229cf5c5bf59be89dc70ff" + }, + { + type: MessageChannelEvent.PartialAcknowledgement, + payload: { + messageId: "d81b2617e63162843413eea8c62dada058ac7e6c8f8463fd5ef1171939cd9415", + acknowledgementBitmask: new Uint8Array([1, 0, 1]) + } + }, + { + type: MessageChannelEvent.MissedMessages, + payload: { + messageIds: ["58cf44867e529152f4095aa6a951500a6a45571a062dc0bddb06aef48c97f85b"] + } + } +]); diff --git a/examples/sds-demo/src/lib/utils/tooltipUtils.ts b/examples/sds-demo/src/lib/utils/tooltipUtils.ts new file mode 100644 index 0000000..c1037fe --- /dev/null +++ b/examples/sds-demo/src/lib/utils/tooltipUtils.ts @@ -0,0 +1,91 @@ +import { mount, unmount } from 'svelte'; +import Tooltip from '$lib/components/Tooltip.svelte'; + +interface TooltipOptions { + position?: 'left' | 'right'; + content: string; + offset?: number; + verticalOffset?: number; + width?: number; + showOnHover?: boolean; + visible?: boolean; + highlightTarget?: boolean; + highlightClass?: string; +} + +/** + * Creates a tooltip positioned relative to a target element + * @param targetElement - The element to attach the tooltip to + * @param options - Configuration options for the tooltip + * @returns An object with methods to control the tooltip + */ +export function createTooltip(targetElement: HTMLElement, options: TooltipOptions) { + const { + position = 'right', + content, + offset = 20, + width = 200, + showOnHover = true, + visible = false, + highlightTarget = false, + highlightClass = 'tooltip-target-highlight', + verticalOffset = 0 + } = options; + + // Store current visibility state + let isVisible = visible; + + // Create a container for the tooltip + const container = document.createElement('div'); + document.body.appendChild(container); + + // Initialize the tooltip component using Svelte's mount API + const tooltipInstance = mount(Tooltip, { + target: container, + props: { + targetElement, + position, + content, + offset, + width, + verticalOffset, + showOnHover, + visible: isVisible, + highlightTarget, + highlightClass + } + }); + + // Return methods to control the tooltip + return { + destroy: () => { + // In Svelte 5, we use the unmount function instead of $destroy + unmount(tooltipInstance); + container.remove(); + }, + updatePosition: () => { + tooltipInstance.$set({ targetElement }); + }, + updateContent: (newContent: string) => { + tooltipInstance.$set({ content: newContent }); + }, + show: () => { + isVisible = true; + tooltipInstance.$set({ visible: true }); + }, + hide: () => { + isVisible = false; + tooltipInstance.$set({ visible: false }); + }, + toggle: () => { + isVisible = !isVisible; + tooltipInstance.$set({ visible: isVisible }); + }, + updateOptions: (newOptions: Partial) => { + if (newOptions.visible !== undefined) { + isVisible = newOptions.visible; + } + tooltipInstance.$set(newOptions); + } + }; +} \ No newline at end of file diff --git a/examples/sds-demo/src/routes/history/+page.svelte b/examples/sds-demo/src/routes/history/+page.svelte index ccdbe94..b45a855 100644 --- a/examples/sds-demo/src/routes/history/+page.svelte +++ b/examples/sds-demo/src/routes/history/+page.svelte @@ -23,12 +23,14 @@
+

Log of all events as they are emitted by the message channel.

+

List of messages that are currently known to be missing from the channel.