@picked/svelte 0.0.41 → 0.0.42-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,6 +10,7 @@
10
10
  import ProjectScreen from './screens/project/ProjectScreen.svelte'
11
11
  import HistoryEntriesListScreen from './screens/history/HistoryEntriesListScreen.svelte'
12
12
  import ResponsesListScreen from './screens/responses/ResponsesListScreen.svelte'
13
+ import EventsListScreen from './screens/events/EventsListScreen.svelte'
13
14
 
14
15
  const experience = getExperience()
15
16
 
@@ -26,6 +27,12 @@
26
27
  component: HistoryEntriesListScreen,
27
28
  props: {},
28
29
  },
30
+ {
31
+ id: 'events',
32
+ label: 'Events',
33
+ component: EventsListScreen,
34
+ props: {},
35
+ },
29
36
  {
30
37
  id: 'responses',
31
38
  label: 'Responses',
@@ -20,7 +20,7 @@
20
20
  </tr>
21
21
  </thead>
22
22
  <tbody>
23
- {#each experienceInstances as experienceInstance (experienceInstance.experienceId)}
23
+ {#each experienceInstances as experienceInstance (experienceInstance.id)}
24
24
  <ExperienceInstanceListItem {experienceInstance} />
25
25
  {/each}
26
26
  </tbody>
@@ -0,0 +1,142 @@
1
+ <script lang="ts">
2
+ import type { EventBusPayload, EventHistoryEntry } from '@picked/client'
3
+
4
+ export let event: EventHistoryEntry
5
+ export let isExpanded: boolean
6
+ export let onToggle: () => void
7
+
8
+ function formatTime(date: Date): string {
9
+ return date.toLocaleTimeString('en-US', {
10
+ hour12: false,
11
+ hour: '2-digit',
12
+ minute: '2-digit',
13
+ second: '2-digit',
14
+ fractionalSecondDigits: 3,
15
+ })
16
+ }
17
+
18
+ interface PayloadField {
19
+ label: string
20
+ value: unknown
21
+ }
22
+
23
+ function getPayloadFields(payload: EventBusPayload): PayloadField[] {
24
+ const fields: PayloadField[] = []
25
+
26
+ // Add type
27
+ fields.push({ label: 'Type', value: payload.type })
28
+
29
+ // Add optional value field if present
30
+ if ('value' in payload && payload.value !== undefined) {
31
+ fields.push({ label: 'Value', value: payload.value })
32
+ }
33
+
34
+ // Add experience identifiers if present
35
+ if ('experience' in payload && payload.experience) {
36
+ const exp = payload.experience
37
+ if (exp && typeof exp === 'object') {
38
+ if ('id' in exp && exp.id) {
39
+ fields.push({ label: 'Experience ID', value: exp.id })
40
+ }
41
+ if ('experienceId' in exp && exp.experienceId) {
42
+ fields.push({ label: 'Experience Type', value: exp.experienceId })
43
+ }
44
+ }
45
+ }
46
+
47
+ // Add step information if present
48
+ if ('step' in payload && payload.step) {
49
+ const step = payload.step
50
+ if (step && typeof step === 'object') {
51
+ if ('id' in step && step.id) {
52
+ fields.push({ label: 'Step ID', value: step.id })
53
+ }
54
+ if ('label' in step && step.label) {
55
+ fields.push({ label: 'Step Label', value: step.label })
56
+ }
57
+ }
58
+ }
59
+
60
+ // Add form information if present
61
+ if ('form' in payload && payload.form) {
62
+ fields.push({ label: 'Form', value: JSON.stringify(payload.form) })
63
+ }
64
+
65
+ // Add feature information if present
66
+ if ('feature' in payload && payload.feature) {
67
+ fields.push({ label: 'Feature', value: JSON.stringify(payload.feature) })
68
+ }
69
+
70
+ // Add exception/validation errors if present
71
+ if ('exception' in payload && payload.exception) {
72
+ fields.push({ label: 'Exception', value: JSON.stringify(payload.exception) })
73
+ }
74
+
75
+ // Add version if present
76
+ if ('version' in payload && payload.version) {
77
+ fields.push({ label: 'Version', value: payload.version })
78
+ }
79
+
80
+ // Add session id if present
81
+ if ('id' in payload && payload.id && payload.type === 'session') {
82
+ fields.push({ label: 'Session ID', value: payload.id })
83
+ }
84
+
85
+ return fields
86
+ }
87
+
88
+ function formatValue(value: unknown): string {
89
+ if (value === null) return 'null'
90
+ if (value === undefined) return 'undefined'
91
+ if (typeof value === 'string') return value
92
+ if (typeof value === 'number' || typeof value === 'boolean') return String(value)
93
+ return JSON.stringify(value)
94
+ }
95
+ </script>
96
+
97
+ <tr on:click={onToggle} style="cursor: pointer;">
98
+ <td style="font-family: monospace; font-size: 12px;">
99
+ <span style="margin-right: 0.5rem; display: inline-block; width: 12px;">
100
+ {isExpanded ? '▼' : '▶'}
101
+ </span>
102
+ {formatTime(event.at)}
103
+ </td>
104
+ <td>
105
+ <code
106
+ style="display: inline-block; padding: 0.25rem 0.5rem; background-color: #e8f4ff; border: 1px solid #b3d9ff; border-radius: 3px; font-size: 12px; color: #0066cc;"
107
+ >
108
+ {event.payload.type}
109
+ </code>
110
+ </td>
111
+ <td style="font-size: 13px; color: #333;">
112
+ {'experience' in event.payload && event.payload.experience ? event.payload.experience.experienceId : '-'}
113
+ </td>
114
+ <td style="font-size: 12px; color: #666; font-style: italic;">
115
+ {isExpanded ? 'Click to collapse' : 'Click to expand payload'}
116
+ </td>
117
+ </tr>
118
+ {#if isExpanded}
119
+ <tr>
120
+ <td colspan="4" style="background-color: #f8f9fa; padding: 1rem; border-left: 3px solid #0066cc;">
121
+ <div style="font-weight: 600; margin-bottom: 0.5rem; font-size: 13px; color: #333;">
122
+ Event Payload
123
+ </div>
124
+ <div
125
+ style="background-color: #fff; padding: 0.75rem; border: 1px solid #e0e0e0; border-radius: 4px;"
126
+ >
127
+ {#each getPayloadFields(event.payload) as field}
128
+ <div style="margin-bottom: 0.5rem; font-size: 12px;">
129
+ <span style="font-weight: 600; color: #555; margin-right: 0.5rem;"
130
+ >{field.label}:</span
131
+ >
132
+ <code
133
+ style="font-family: 'Monaco', 'Menlo', 'Courier New', monospace; background-color: #f0f0f0; padding: 0.125rem 0.25rem; border-radius: 2px; color: #333;"
134
+ >
135
+ {formatValue(field.value)}
136
+ </code>
137
+ </div>
138
+ {/each}
139
+ </div>
140
+ </td>
141
+ </tr>
142
+ {/if}
@@ -0,0 +1,19 @@
1
+ <script lang="ts">
2
+ import { getPicked } from '../../../../hooks'
3
+ import EventsTable from './EventsTable.svelte'
4
+
5
+ const { events } = getPicked()
6
+ </script>
7
+
8
+ <div style="display: flex; flex-direction: column; height: 100%;">
9
+ <EventsTable />
10
+ <div
11
+ style="margin-top: auto; padding: 0.5rem; display: flex; justify-content: space-between; align-items: center; border-top: 1px solid lightgray;"
12
+ >
13
+ <div style="display: flex; gap: 0.5rem; align-items: center;">
14
+ <span style="font-size: 13px; color: #666;">
15
+ {$events.length} events
16
+ </span>
17
+ </div>
18
+ </div>
19
+ </div>
@@ -0,0 +1,74 @@
1
+ <script lang="ts">
2
+ import { combine, createStore, createEvent, sample } from 'effector'
3
+ import { getPicked } from '../../../../hooks'
4
+ import EventListItem from './EventListItem.svelte'
5
+ import type { EventHistoryEntry } from '@picked/client'
6
+
7
+ const { events } = getPicked()
8
+
9
+ let expandedRowIds = new Set<number>()
10
+
11
+ function toggleRow(eventId: number) {
12
+ const newSet = new Set(expandedRowIds)
13
+ if (newSet.has(eventId)) {
14
+ newSet.delete(eventId)
15
+ } else {
16
+ newSet.add(eventId)
17
+ }
18
+ expandedRowIds = newSet
19
+ }
20
+
21
+
22
+ const sortDirectionStore = createStore<'asc' | 'desc'>('desc')
23
+ const toggleSortDirection = createEvent<void>()
24
+ const oppositeSortDirection: Record<'asc' | 'desc', 'asc' | 'desc'> = { asc: 'desc', desc: 'asc' }
25
+
26
+ sample({
27
+ clock: toggleSortDirection,
28
+ source: sortDirectionStore,
29
+ fn: (dir) => oppositeSortDirection[dir],
30
+ target: sortDirectionStore,
31
+ })
32
+
33
+ function sortEvents(history: EventHistoryEntry[], sort: 'asc' | 'desc'): EventHistoryEntry[] {
34
+ return [...history].sort((a, b) => {
35
+ const diff = a.at.getTime() - b.at.getTime()
36
+ return sort === 'asc' ? diff : -diff
37
+ })
38
+ }
39
+
40
+ const sortedEvents = combine(events, sortDirectionStore, sortEvents)
41
+ </script>
42
+
43
+ <table>
44
+ <thead>
45
+ <tr>
46
+ <th
47
+ style="width: 140px; cursor: pointer; user-select: none;"
48
+ on:click={() => toggleSortDirection()}
49
+ >
50
+ Time {$sortDirectionStore === 'asc' ? '↑' : '↓'}
51
+ </th>
52
+ <th style="width: 200px;">Event Type</th>
53
+ <th style="width: 180px;">Experience</th>
54
+ <th></th>
55
+ </tr>
56
+ </thead>
57
+ <tbody>
58
+ {#if $sortedEvents.length === 0}
59
+ <tr>
60
+ <td colspan="4" style="text-align: center; padding: 2rem; color: #666;">
61
+ No events yet. Interact with the page to see events.
62
+ </td>
63
+ </tr>
64
+ {:else}
65
+ {#each $sortedEvents as event (event.at)}
66
+ <EventListItem
67
+ {event}
68
+ isExpanded={expandedRowIds.has(event.id)}
69
+ onToggle={() => toggleRow(event.id)}
70
+ />
71
+ {/each}
72
+ {/if}
73
+ </tbody>
74
+ </table>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@picked/svelte",
3
- "version": "0.0.41",
3
+ "version": "0.0.42-next.1",
4
4
  "dependencies": {
5
5
  "d3": "^7.9.0"
6
6
  },
@@ -75,7 +75,7 @@
75
75
  ],
76
76
  "module": "./dist/index.js",
77
77
  "peerDependencies": {
78
- "@picked/client": "0.0.41",
78
+ "@picked/client": "0.0.42-next.1",
79
79
  "effector": "^23.3.0",
80
80
  "svelte": "^5.34.3"
81
81
  },