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));
+ };
-
- All ({eventCounts.all})
- Sent ({eventCounts.sent})
- Received ({eventCounts.received})
- Delivered ({eventCounts.delivered})
- Acknowledged ({eventCounts.acknowledged})
-
+
{#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)}>
-
-
-
-
-
-
-
- {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
+
+
+
+
+
+
+
+
+ Show Event Types Legend
+
+
+
+
+
+
+
\ 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}
+
+
+
+
+
+
+
+
+
+
+ {#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.