@shipfox/client-triggers 17.0.0 → 22.0.0
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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +41 -0
- package/dist/components/events-filter-bar.d.ts.map +1 -1
- package/dist/components/events-filter-bar.js +98 -94
- package/dist/components/events-filter-bar.js.map +1 -1
- package/dist/components/events-list-states.d.ts.map +1 -1
- package/dist/components/events-list-states.js +31 -35
- package/dist/components/events-list-states.js.map +1 -1
- package/dist/components/events-list.d.ts.map +1 -1
- package/dist/components/events-list.js +5 -3
- package/dist/components/events-list.js.map +1 -1
- package/dist/components/trigger-event-detail.d.ts.map +1 -1
- package/dist/components/trigger-event-detail.js +173 -157
- package/dist/components/trigger-event-detail.js.map +1 -1
- package/dist/pages/events-page.d.ts.map +1 -1
- package/dist/pages/events-page.js +29 -47
- package/dist/pages/events-page.js.map +1 -1
- package/dist/routes/events-settings.d.ts +3 -0
- package/dist/routes/events-settings.js +3 -0
- package/dist/routes/events-settings.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +6 -6
- package/src/components/events-filter-bar.tsx +80 -77
- package/src/components/events-list-states.tsx +32 -30
- package/src/components/events-list.test.tsx +9 -0
- package/src/components/events-list.tsx +6 -3
- package/src/components/trigger-event-detail.test.tsx +3 -0
- package/src/components/trigger-event-detail.tsx +129 -126
- package/src/pages/events-page.test.tsx +7 -0
- package/src/pages/events-page.tsx +1 -15
- package/src/routes/events-settings.tsx +1 -0
- package/tsconfig.build.tsbuildinfo +1 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shipfox/client-triggers",
|
|
3
3
|
"license": "MIT",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "22.0.0",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/ShipfoxHQ/shipfox.git",
|
|
@@ -28,11 +28,11 @@
|
|
|
28
28
|
"@swc/helpers": "^0.5.17",
|
|
29
29
|
"@shipfox/api-triggers-dto": "9.0.2",
|
|
30
30
|
"@shipfox/client-api": "6.0.1",
|
|
31
|
-
"@shipfox/client-projects": "
|
|
32
|
-
"@shipfox/client-shell": "
|
|
33
|
-
"@shipfox/client-ui": "
|
|
34
|
-
"@shipfox/integration-icons": "0.3.
|
|
35
|
-
"@shipfox/react-ui": "1.
|
|
31
|
+
"@shipfox/client-projects": "22.0.0",
|
|
32
|
+
"@shipfox/client-shell": "22.0.0",
|
|
33
|
+
"@shipfox/client-ui": "22.0.0",
|
|
34
|
+
"@shipfox/integration-icons": "0.3.5",
|
|
35
|
+
"@shipfox/react-ui": "2.1.0"
|
|
36
36
|
},
|
|
37
37
|
"peerDependencies": {
|
|
38
38
|
"@tanstack/react-query": "^5.101.0",
|
|
@@ -2,6 +2,7 @@ import {Button} from '@shipfox/react-ui/button';
|
|
|
2
2
|
import {Collapsible, CollapsibleContent, CollapsibleTrigger} from '@shipfox/react-ui/collapsible';
|
|
3
3
|
import {Combobox, type ComboboxOption} from '@shipfox/react-ui/combobox';
|
|
4
4
|
import {type DateRange, DateRangePicker} from '@shipfox/react-ui/date-range-picker';
|
|
5
|
+
import {PanelHeader} from '@shipfox/react-ui/panel';
|
|
5
6
|
import {Text} from '@shipfox/react-ui/typography';
|
|
6
7
|
import {cn} from '@shipfox/react-ui/utils';
|
|
7
8
|
import {type ReactNode, useState} from 'react';
|
|
@@ -95,84 +96,86 @@ export function EventsFilterBar({
|
|
|
95
96
|
}
|
|
96
97
|
|
|
97
98
|
return (
|
|
98
|
-
<
|
|
99
|
-
<
|
|
100
|
-
<
|
|
101
|
-
<
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
<CollapsibleContent>
|
|
118
|
-
<div className="grid grid-cols-1 gap-x-cluster gap-y-inline border-b border-border-neutral-base px-row py-row min-[520px]:grid-cols-2">
|
|
119
|
-
<FilterField label="Date" className="col-span-full">
|
|
120
|
-
<DateRangePicker
|
|
121
|
-
size="small"
|
|
122
|
-
className="w-full"
|
|
123
|
-
{...(dateRange ? {dateRange} : {})}
|
|
124
|
-
onDateRangeSelect={handleDateRange}
|
|
125
|
-
onClear={() => onFiltersChange({from: undefined, to: undefined})}
|
|
126
|
-
placeholder="Any date"
|
|
127
|
-
/>
|
|
128
|
-
</FilterField>
|
|
129
|
-
<FilterField label="Result">
|
|
130
|
-
<Combobox
|
|
131
|
-
multiple
|
|
132
|
-
size="small"
|
|
133
|
-
aria-label="Filter by result"
|
|
134
|
-
options={RESULT_OPTIONS}
|
|
135
|
-
value={resultValue}
|
|
136
|
-
onValueChange={handleResultValue}
|
|
137
|
-
placeholder="All results"
|
|
138
|
-
emptyState="No results"
|
|
139
|
-
className="w-full"
|
|
140
|
-
maxVisibleChips={2}
|
|
141
|
-
/>
|
|
142
|
-
</FilterField>
|
|
143
|
-
<FilterField label="Source">
|
|
144
|
-
<Combobox
|
|
145
|
-
multiple
|
|
146
|
-
size="small"
|
|
147
|
-
options={toOptions(sources)}
|
|
148
|
-
value={filters.source ?? []}
|
|
149
|
-
onValueChange={(value) =>
|
|
150
|
-
onFiltersChange({source: value.length > 0 ? value : undefined})
|
|
151
|
-
}
|
|
152
|
-
placeholder="All sources"
|
|
153
|
-
emptyState="No sources yet"
|
|
154
|
-
className="w-full"
|
|
155
|
-
maxVisibleChips={2}
|
|
156
|
-
/>
|
|
157
|
-
</FilterField>
|
|
158
|
-
<FilterField label="Event">
|
|
159
|
-
<Combobox
|
|
160
|
-
multiple
|
|
161
|
-
size="small"
|
|
162
|
-
options={toOptions(events)}
|
|
163
|
-
value={filters.event ?? []}
|
|
164
|
-
onValueChange={(value) =>
|
|
165
|
-
onFiltersChange({event: value.length > 0 ? value : undefined})
|
|
166
|
-
}
|
|
167
|
-
placeholder="All events"
|
|
168
|
-
emptyState="No events yet"
|
|
169
|
-
className="w-full"
|
|
170
|
-
maxVisibleChips={2}
|
|
171
|
-
/>
|
|
172
|
-
</FilterField>
|
|
99
|
+
<PanelHeader className="min-h-48 flex-col items-stretch gap-0 p-0">
|
|
100
|
+
<Collapsible open={open} onOpenChange={setOpen}>
|
|
101
|
+
<div className="flex items-center justify-between gap-inline px-row py-row">
|
|
102
|
+
<CollapsibleTrigger asChild>
|
|
103
|
+
<Button
|
|
104
|
+
type="button"
|
|
105
|
+
variant="secondary"
|
|
106
|
+
size="sm"
|
|
107
|
+
iconLeft="filter3Line"
|
|
108
|
+
iconRight={open ? 'arrowUpSLine' : 'arrowDownSLine'}
|
|
109
|
+
>
|
|
110
|
+
{activeCount > 0 ? `Filters (${activeCount})` : 'Filters'}
|
|
111
|
+
</Button>
|
|
112
|
+
</CollapsibleTrigger>
|
|
113
|
+
{hasActiveFilters ? (
|
|
114
|
+
<Button type="button" size="2xs" variant="transparentMuted" onClick={onClear}>
|
|
115
|
+
Clear filters
|
|
116
|
+
</Button>
|
|
117
|
+
) : null}
|
|
173
118
|
</div>
|
|
174
|
-
|
|
175
|
-
|
|
119
|
+
<CollapsibleContent>
|
|
120
|
+
<div className="grid grid-cols-1 gap-x-cluster gap-y-inline px-row py-row min-[520px]:grid-cols-2">
|
|
121
|
+
<FilterField label="Date" className="col-span-full">
|
|
122
|
+
<DateRangePicker
|
|
123
|
+
size="small"
|
|
124
|
+
className="w-full"
|
|
125
|
+
{...(dateRange ? {dateRange} : {})}
|
|
126
|
+
onDateRangeSelect={handleDateRange}
|
|
127
|
+
onClear={() => onFiltersChange({from: undefined, to: undefined})}
|
|
128
|
+
placeholder="Any date"
|
|
129
|
+
/>
|
|
130
|
+
</FilterField>
|
|
131
|
+
<FilterField label="Result">
|
|
132
|
+
<Combobox
|
|
133
|
+
multiple
|
|
134
|
+
size="small"
|
|
135
|
+
aria-label="Filter by result"
|
|
136
|
+
options={RESULT_OPTIONS}
|
|
137
|
+
value={resultValue}
|
|
138
|
+
onValueChange={handleResultValue}
|
|
139
|
+
placeholder="All results"
|
|
140
|
+
emptyState="No results"
|
|
141
|
+
className="w-full"
|
|
142
|
+
maxVisibleChips={2}
|
|
143
|
+
/>
|
|
144
|
+
</FilterField>
|
|
145
|
+
<FilterField label="Source">
|
|
146
|
+
<Combobox
|
|
147
|
+
multiple
|
|
148
|
+
size="small"
|
|
149
|
+
options={toOptions(sources)}
|
|
150
|
+
value={filters.source ?? []}
|
|
151
|
+
onValueChange={(value) =>
|
|
152
|
+
onFiltersChange({source: value.length > 0 ? value : undefined})
|
|
153
|
+
}
|
|
154
|
+
placeholder="All sources"
|
|
155
|
+
emptyState="No sources yet"
|
|
156
|
+
className="w-full"
|
|
157
|
+
maxVisibleChips={2}
|
|
158
|
+
/>
|
|
159
|
+
</FilterField>
|
|
160
|
+
<FilterField label="Event">
|
|
161
|
+
<Combobox
|
|
162
|
+
multiple
|
|
163
|
+
size="small"
|
|
164
|
+
options={toOptions(events)}
|
|
165
|
+
value={filters.event ?? []}
|
|
166
|
+
onValueChange={(value) =>
|
|
167
|
+
onFiltersChange({event: value.length > 0 ? value : undefined})
|
|
168
|
+
}
|
|
169
|
+
placeholder="All events"
|
|
170
|
+
emptyState="No events yet"
|
|
171
|
+
className="w-full"
|
|
172
|
+
maxVisibleChips={2}
|
|
173
|
+
/>
|
|
174
|
+
</FilterField>
|
|
175
|
+
</div>
|
|
176
|
+
</CollapsibleContent>
|
|
177
|
+
</Collapsible>
|
|
178
|
+
</PanelHeader>
|
|
176
179
|
);
|
|
177
180
|
}
|
|
178
181
|
|
|
@@ -8,12 +8,16 @@ import {Link} from '@tanstack/react-router';
|
|
|
8
8
|
|
|
9
9
|
export function EventsListSkeleton() {
|
|
10
10
|
return (
|
|
11
|
-
<div
|
|
11
|
+
<div
|
|
12
|
+
className="flex flex-col divide-y divide-border-neutral-base"
|
|
13
|
+
role="status"
|
|
14
|
+
aria-label="Loading events"
|
|
15
|
+
>
|
|
12
16
|
{Array.from({length: 8}).map((_, index) => (
|
|
13
17
|
<div
|
|
14
18
|
// biome-ignore lint/suspicious/noArrayIndexKey: skeleton row, stable position
|
|
15
19
|
key={index}
|
|
16
|
-
className="flex h-
|
|
20
|
+
className="flex min-h-44 items-center gap-cluster px-row py-row"
|
|
17
21
|
>
|
|
18
22
|
<Skeleton className="size-6 shrink-0 rounded-full" />
|
|
19
23
|
<Skeleton className="h-12 w-1/4" />
|
|
@@ -27,39 +31,37 @@ export function EventsListSkeleton() {
|
|
|
27
31
|
|
|
28
32
|
export function EventsListEmpty({workspaceSlug}: {workspaceSlug?: string | undefined}) {
|
|
29
33
|
return (
|
|
30
|
-
<
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
<
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
</div>
|
|
34
|
+
<EmptyState
|
|
35
|
+
icon="pulseLine"
|
|
36
|
+
title="No events yet"
|
|
37
|
+
description="Events appear here once a connected integration delivers one or you fire a trigger."
|
|
38
|
+
action={
|
|
39
|
+
workspaceSlug ? (
|
|
40
|
+
<Button asChild size="sm" variant="secondary">
|
|
41
|
+
<Link to="/w/$workspaceSlug/settings/integrations" params={{workspaceSlug}}>
|
|
42
|
+
Configure integrations
|
|
43
|
+
</Link>
|
|
44
|
+
</Button>
|
|
45
|
+
) : undefined
|
|
46
|
+
}
|
|
47
|
+
variant="panel"
|
|
48
|
+
/>
|
|
46
49
|
);
|
|
47
50
|
}
|
|
48
51
|
|
|
49
52
|
export function EventsListNoMatches({onClear}: {onClear: () => void}) {
|
|
50
53
|
return (
|
|
51
|
-
<
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
</div>
|
|
54
|
+
<EmptyState
|
|
55
|
+
icon="filterOffLine"
|
|
56
|
+
title="No matching events"
|
|
57
|
+
description="No events match your current filters."
|
|
58
|
+
action={
|
|
59
|
+
<Button type="button" size="sm" variant="secondary" onClick={onClear}>
|
|
60
|
+
Clear filters
|
|
61
|
+
</Button>
|
|
62
|
+
}
|
|
63
|
+
variant="panel"
|
|
64
|
+
/>
|
|
63
65
|
);
|
|
64
66
|
}
|
|
65
67
|
|
|
@@ -72,6 +72,15 @@ async function selectResult(label: string) {
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
describe('EventsList', () => {
|
|
75
|
+
test('renders the event list as a panel with a header strip', () => {
|
|
76
|
+
renderList(makeProps());
|
|
77
|
+
|
|
78
|
+
const panel = document.querySelector('[data-slot="panel"]');
|
|
79
|
+
|
|
80
|
+
expect(panel).toBeInTheDocument();
|
|
81
|
+
expect(panel?.querySelector('[data-slot="panel-header"]')).toBeInTheDocument();
|
|
82
|
+
});
|
|
83
|
+
|
|
75
84
|
test('renders a row per event with its match summary', () => {
|
|
76
85
|
renderList(makeProps());
|
|
77
86
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {QueryLoadError} from '@shipfox/client-ui';
|
|
2
2
|
import {Button} from '@shipfox/react-ui/button';
|
|
3
|
+
import {Panel} from '@shipfox/react-ui/panel';
|
|
3
4
|
import {Table, TableBody, TableHead, TableHeader, TableRow} from '@shipfox/react-ui/table';
|
|
4
5
|
import {hasTriggerEventFilters} from '#core/trigger-event.js';
|
|
5
6
|
import {EventsFilterBar} from './events-filter-bar.js';
|
|
@@ -40,7 +41,7 @@ export function EventsList({
|
|
|
40
41
|
}
|
|
41
42
|
|
|
42
43
|
return (
|
|
43
|
-
<
|
|
44
|
+
<Panel className="min-h-0 overflow-hidden p-0">
|
|
44
45
|
<EventsFilterBar
|
|
45
46
|
filters={filters}
|
|
46
47
|
onFiltersChange={onFiltersChange}
|
|
@@ -51,7 +52,9 @@ export function EventsList({
|
|
|
51
52
|
/>
|
|
52
53
|
|
|
53
54
|
{query.isPending ? <EventsListSkeleton /> : null}
|
|
54
|
-
{!query.isPending ?
|
|
55
|
+
{!query.isPending ? (
|
|
56
|
+
<QueryLoadError query={query} subject="events" icon="pulseLine" variant="panel" />
|
|
57
|
+
) : null}
|
|
55
58
|
{!query.isPending && refreshFailed ? <EventsListStaleError query={query} /> : null}
|
|
56
59
|
{showEmptyState && !activeFilters ? <EventsListEmpty workspaceSlug={workspaceSlug} /> : null}
|
|
57
60
|
{showEmptyState && activeFilters ? <EventsListNoMatches onClear={clearFilters} /> : null}
|
|
@@ -92,6 +95,6 @@ export function EventsList({
|
|
|
92
95
|
) : null}
|
|
93
96
|
</>
|
|
94
97
|
) : null}
|
|
95
|
-
</
|
|
98
|
+
</Panel>
|
|
96
99
|
);
|
|
97
100
|
}
|
|
@@ -103,6 +103,9 @@ describe('TriggerEventDetailView', () => {
|
|
|
103
103
|
renderDetailView(makeEvent());
|
|
104
104
|
|
|
105
105
|
expect(await screen.findByText('Triggered 1 workflow')).toBeInTheDocument();
|
|
106
|
+
expect(screen.getByRole('heading', {name: 'Matched workflows'})).toBeInTheDocument();
|
|
107
|
+
expect(screen.getByRole('heading', {name: 'Payload'})).toBeInTheDocument();
|
|
108
|
+
expect(document.querySelectorAll('[data-slot="panel"]')).toHaveLength(2);
|
|
106
109
|
expect(screen.getByText('Deploy production')).toBeInTheDocument();
|
|
107
110
|
expect(screen.getByRole('link', {name: DEPLOY_RUN_LINK_NAME})).toHaveAttribute(
|
|
108
111
|
'href',
|