@picked/svelte 0.0.41-next.1 → 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.
- package/dist/plugins/devtools/DevToolsExperience.svelte +7 -0
- package/dist/plugins/devtools/components/ExperienceInstancesTable.svelte +1 -1
- package/dist/plugins/devtools/screens/events/EventListItem.svelte +142 -0
- package/dist/plugins/devtools/screens/events/EventsListScreen.svelte +19 -0
- package/dist/plugins/devtools/screens/events/EventsTable.svelte +74 -0
- package/package.json +2 -2
|
@@ -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.
|
|
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.
|
|
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.
|
|
78
|
+
"@picked/client": "0.0.42-next.1",
|
|
79
79
|
"effector": "^23.3.0",
|
|
80
80
|
"svelte": "^5.34.3"
|
|
81
81
|
},
|