@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.
Files changed (32) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +41 -0
  3. package/dist/components/events-filter-bar.d.ts.map +1 -1
  4. package/dist/components/events-filter-bar.js +98 -94
  5. package/dist/components/events-filter-bar.js.map +1 -1
  6. package/dist/components/events-list-states.d.ts.map +1 -1
  7. package/dist/components/events-list-states.js +31 -35
  8. package/dist/components/events-list-states.js.map +1 -1
  9. package/dist/components/events-list.d.ts.map +1 -1
  10. package/dist/components/events-list.js +5 -3
  11. package/dist/components/events-list.js.map +1 -1
  12. package/dist/components/trigger-event-detail.d.ts.map +1 -1
  13. package/dist/components/trigger-event-detail.js +173 -157
  14. package/dist/components/trigger-event-detail.js.map +1 -1
  15. package/dist/pages/events-page.d.ts.map +1 -1
  16. package/dist/pages/events-page.js +29 -47
  17. package/dist/pages/events-page.js.map +1 -1
  18. package/dist/routes/events-settings.d.ts +3 -0
  19. package/dist/routes/events-settings.js +3 -0
  20. package/dist/routes/events-settings.js.map +1 -1
  21. package/dist/tsconfig.test.tsbuildinfo +1 -1
  22. package/package.json +6 -6
  23. package/src/components/events-filter-bar.tsx +80 -77
  24. package/src/components/events-list-states.tsx +32 -30
  25. package/src/components/events-list.test.tsx +9 -0
  26. package/src/components/events-list.tsx +6 -3
  27. package/src/components/trigger-event-detail.test.tsx +3 -0
  28. package/src/components/trigger-event-detail.tsx +129 -126
  29. package/src/pages/events-page.test.tsx +7 -0
  30. package/src/pages/events-page.tsx +1 -15
  31. package/src/routes/events-settings.tsx +1 -0
  32. package/tsconfig.build.tsbuildinfo +1 -1
@@ -14,6 +14,7 @@ import {
14
14
  } from '@shipfox/react-ui/code-block';
15
15
  import {EmptyState} from '@shipfox/react-ui/empty-state';
16
16
  import {Icon} from '@shipfox/react-ui/icon';
17
+ import {Panel, PanelBody, PanelHeader, PanelTitle} from '@shipfox/react-ui/panel';
17
18
  import {RelativeTime} from '@shipfox/react-ui/relative-time';
18
19
  import {Skeleton} from '@shipfox/react-ui/skeleton';
19
20
  import {Tooltip, TooltipContent, TooltipTrigger} from '@shipfox/react-ui/tooltip';
@@ -29,8 +30,6 @@ import {useTriggerEventQuery} from '#hooks/api/trigger-events.js';
29
30
  import {triggerEventResult} from './trigger-event-result.js';
30
31
  import {TriggerSourceIcon} from './trigger-source-icon.js';
31
32
 
32
- const PANEL_CLASS =
33
- 'min-h-0 rounded-8 border border-border-neutral-base bg-background-neutral-base';
34
33
  const DETAIL_RAIL_CLASS =
35
34
  '@min-[820px]:sticky @min-[820px]:top-16 @min-[820px]:max-h-[calc(var(--app-content-h,100dvh_-_96px)_-_32px)] @min-[820px]:min-h-[min(320px,calc(var(--app-content-h,100dvh_-_96px)_-_32px))]';
36
35
 
@@ -87,9 +86,9 @@ export function TriggerEventDetailView({
87
86
  return (
88
87
  <aside
89
88
  aria-label="Event details"
90
- className={cn(PANEL_CLASS, DETAIL_RAIL_CLASS, 'flex min-h-0 flex-col overflow-hidden')}
89
+ className={cn(DETAIL_RAIL_CLASS, 'flex min-h-0 flex-col gap-group')}
91
90
  >
92
- <div className="flex shrink-0 flex-col gap-cluster border-b border-border-neutral-base p-panel-compact">
91
+ <div className="flex shrink-0 flex-col gap-cluster p-panel-compact">
93
92
  <Button
94
93
  type="button"
95
94
  variant="transparentMuted"
@@ -138,7 +137,7 @@ export function TriggerEventDetailView({
138
137
 
139
138
  <div
140
139
  key={event.id}
141
- className="flex min-h-0 flex-1 flex-col gap-section overflow-y-auto p-panel-compact scrollbar"
140
+ className="flex min-h-0 flex-1 flex-col gap-group overflow-y-auto scrollbar"
142
141
  >
143
142
  <EventRuns workspaceId={workspaceId} workspaceSlug={workspaceSlug} event={event} />
144
143
  <EventPayload payload={formattedPayload} />
@@ -157,14 +156,10 @@ function triggerEventFullLabel(event: Pick<TriggerEventDetailModel, 'event' | 's
157
156
 
158
157
  function TriggerEventDetailPlaceholder() {
159
158
  return (
160
- <aside
161
- aria-label="Event details"
162
- className={cn(
163
- PANEL_CLASS,
164
- 'hidden min-h-[240px] items-center justify-center p-panel @min-[820px]:flex',
165
- )}
166
- >
167
- <EmptyState icon="pulseLine" variant="compact" title="No event selected" />
159
+ <aside aria-label="Event details" className="hidden min-h-[240px] @min-[820px]:flex">
160
+ <Panel className="flex min-h-0 flex-1 items-center justify-center p-panel">
161
+ <EmptyState icon="pulseLine" variant="compact" title="No event selected" />
162
+ </Panel>
168
163
  </aside>
169
164
  );
170
165
  }
@@ -173,28 +168,26 @@ function TriggerEventDetailLoading({onBack}: {onBack: () => void}) {
173
168
  return (
174
169
  <aside
175
170
  aria-label="Event details"
176
- className={cn(
177
- PANEL_CLASS,
178
- DETAIL_RAIL_CLASS,
179
- 'flex min-h-[320px] flex-col gap-group p-panel-compact',
180
- )}
171
+ className={cn(DETAIL_RAIL_CLASS, 'flex min-h-[320px] flex-col')}
181
172
  >
182
- <Button
183
- type="button"
184
- variant="transparentMuted"
185
- size="sm"
186
- iconLeft="arrowLeftLine"
187
- className="self-start @min-[820px]:hidden"
188
- onClick={onBack}
189
- >
190
- Back to events
191
- </Button>
192
- <div className="flex flex-col gap-inline">
193
- <Skeleton className="h-16 w-160" />
194
- <Skeleton className="h-12 w-120" />
195
- </div>
196
- <Skeleton className="h-96" />
197
- <Skeleton className="h-160" />
173
+ <Panel className="flex min-h-[320px] flex-col gap-group p-panel-compact">
174
+ <Button
175
+ type="button"
176
+ variant="transparentMuted"
177
+ size="sm"
178
+ iconLeft="arrowLeftLine"
179
+ className="self-start @min-[820px]:hidden"
180
+ onClick={onBack}
181
+ >
182
+ Back to events
183
+ </Button>
184
+ <div className="flex flex-col gap-inline">
185
+ <Skeleton className="h-16 w-160" />
186
+ <Skeleton className="h-12 w-120" />
187
+ </div>
188
+ <Skeleton className="h-96" />
189
+ <Skeleton className="h-160" />
190
+ </Panel>
198
191
  </aside>
199
192
  );
200
193
  }
@@ -203,30 +196,28 @@ function TriggerEventDetailError({onBack, onRetry}: {onBack: () => void; onRetry
203
196
  return (
204
197
  <aside
205
198
  aria-label="Event details"
206
- className={cn(
207
- PANEL_CLASS,
208
- DETAIL_RAIL_CLASS,
209
- 'flex min-h-[320px] flex-col gap-group p-panel-compact',
210
- )}
199
+ className={cn(DETAIL_RAIL_CLASS, 'flex min-h-[320px] flex-col')}
211
200
  >
212
- <Button
213
- type="button"
214
- variant="transparentMuted"
215
- size="sm"
216
- iconLeft="arrowLeftLine"
217
- className="self-start @min-[820px]:hidden"
218
- onClick={onBack}
219
- >
220
- Back to events
221
- </Button>
222
- <Callout role="alert" type="error">
223
- <div className="flex items-center justify-between gap-cluster">
224
- <Text size="sm">Event detail could not be loaded.</Text>
225
- <Button type="button" variant="secondary" size="xs" onClick={onRetry}>
226
- Retry
227
- </Button>
228
- </div>
229
- </Callout>
201
+ <Panel className="flex min-h-[320px] flex-col gap-group p-panel-compact">
202
+ <Button
203
+ type="button"
204
+ variant="transparentMuted"
205
+ size="sm"
206
+ iconLeft="arrowLeftLine"
207
+ className="self-start @min-[820px]:hidden"
208
+ onClick={onBack}
209
+ >
210
+ Back to events
211
+ </Button>
212
+ <Callout role="alert" type="error">
213
+ <div className="flex items-center justify-between gap-cluster">
214
+ <Text size="sm">Event detail could not be loaded.</Text>
215
+ <Button type="button" variant="secondary" size="xs" onClick={onRetry}>
216
+ Retry
217
+ </Button>
218
+ </div>
219
+ </Callout>
220
+ </Panel>
230
221
  </aside>
231
222
  );
232
223
  }
@@ -243,9 +234,13 @@ function EventRuns({
243
234
  if (event.decisions.length === 0) {
244
235
  if (event.outcome === 'discarded') {
245
236
  return (
246
- <Text size="sm" className="text-foreground-neutral-muted">
247
- No workflows are subscribed to this event.
248
- </Text>
237
+ <Panel>
238
+ <PanelBody className="p-panel-compact">
239
+ <Text size="sm" className="text-foreground-neutral-muted">
240
+ No workflows are subscribed to this event.
241
+ </Text>
242
+ </PanelBody>
243
+ </Panel>
249
244
  );
250
245
  }
251
246
  return null;
@@ -301,23 +296,25 @@ function EventRunsList({
301
296
  event: TriggerEventDetailModel;
302
297
  }) {
303
298
  return (
304
- <section aria-labelledby="trigger-event-runs-heading" className="flex flex-col gap-inline">
305
- <Text id="trigger-event-runs-heading" size="sm" bold>
306
- Matched workflows
307
- </Text>
308
- <ul className="-mx-inline flex flex-col gap-tight">
309
- {event.decisions.map((decision) => (
310
- <DecisionRow
311
- key={decision.id}
312
- workspaceSlug={workspaceSlug}
313
- projectId={decision.projectId ?? undefined}
314
- projectSlug={decision.projectId ? projectSlugs.get(decision.projectId) : undefined}
315
- projectDetailLookupEnabled={projectDetailLookupEnabled}
316
- decision={decision}
317
- />
318
- ))}
319
- </ul>
320
- </section>
299
+ <Panel>
300
+ <PanelHeader>
301
+ <PanelTitle>Matched workflows</PanelTitle>
302
+ </PanelHeader>
303
+ <PanelBody>
304
+ <ul>
305
+ {event.decisions.map((decision) => (
306
+ <DecisionRow
307
+ key={decision.id}
308
+ workspaceSlug={workspaceSlug}
309
+ projectId={decision.projectId ?? undefined}
310
+ projectSlug={decision.projectId ? projectSlugs.get(decision.projectId) : undefined}
311
+ projectDetailLookupEnabled={projectDetailLookupEnabled}
312
+ decision={decision}
313
+ />
314
+ ))}
315
+ </ul>
316
+ </PanelBody>
317
+ </Panel>
321
318
  );
322
319
  }
323
320
 
@@ -343,25 +340,27 @@ function DecisionRow({
343
340
 
344
341
  if (decision.decision !== 'triggered' || !decision.runId || !decision.runName) {
345
342
  return (
346
- <li className="flex min-w-0 items-start gap-inline rounded-6 p-tight">
347
- <Icon
348
- name="cornerDownRightLine"
349
- className="size-14 shrink-0 text-foreground-neutral-disabled"
350
- aria-hidden="true"
351
- />
352
- <div className="flex min-w-0 flex-col gap-tight">
353
- <Text size="sm" className="min-w-0 truncate text-foreground-neutral-base">
354
- {decision.subscriptionName}
355
- </Text>
356
- {decision.reason ? (
357
- <Text size="xs" className="text-foreground-highlight-error">
358
- {decision.reason}
359
- </Text>
360
- ) : (
361
- <Text size="xs" className="text-foreground-neutral-disabled">
362
- No run created
343
+ <li className="border-b border-border-neutral-base px-row py-row last:border-b-0">
344
+ <div className="flex min-w-0 items-start gap-inline">
345
+ <Icon
346
+ name="cornerDownRightLine"
347
+ className="size-14 shrink-0 text-foreground-neutral-disabled"
348
+ aria-hidden="true"
349
+ />
350
+ <div className="flex min-w-0 flex-col gap-tight">
351
+ <Text size="sm" className="min-w-0 truncate text-foreground-neutral-base">
352
+ {decision.subscriptionName}
363
353
  </Text>
364
- )}
354
+ {decision.reason ? (
355
+ <Text size="xs" className="text-foreground-highlight-error">
356
+ {decision.reason}
357
+ </Text>
358
+ ) : (
359
+ <Text size="xs" className="text-foreground-neutral-disabled">
360
+ No run created
361
+ </Text>
362
+ )}
363
+ </div>
365
364
  </div>
366
365
  </li>
367
366
  );
@@ -385,10 +384,10 @@ function DecisionRow({
385
384
  </>
386
385
  );
387
386
  const rowClassName =
388
- 'flex min-w-0 items-start gap-inline rounded-6 p-tight hover:bg-background-components-hover focus-visible:outline-none focus-visible:shadow-button-neutral-focus';
387
+ 'flex min-w-0 items-start gap-inline px-row py-row hover:bg-background-neutral-hover focus-visible:outline-none focus-visible:shadow-button-neutral-focus';
389
388
 
390
389
  return (
391
- <li>
390
+ <li className="border-b border-border-neutral-base last:border-b-0">
392
391
  {workspaceSlug && resolvedProjectSlug ? (
393
392
  <Link
394
393
  to="/w/$workspaceSlug/p/$projectSlug/runs/$workflowRunId"
@@ -412,34 +411,38 @@ function EventPayload({payload}: {payload: string}) {
412
411
  const data = [{language: 'json', filename: 'payload.json', code: payload}];
413
412
 
414
413
  return (
415
- <section aria-labelledby="trigger-event-payload-heading" className="flex flex-col gap-inline">
416
- <Text id="trigger-event-payload-heading" size="sm" bold>
417
- Payload
418
- </Text>
419
- <CodeBlock
420
- data={data}
421
- className="flex h-auto flex-col overflow-visible rounded-8 bg-background-contrast-base shadow-none"
422
- >
423
- <CodeBlockHeader className="sticky top-0 z-10 shrink-0 border-b border-border-contrast-base bg-background-contrast-base p-tight">
424
- <CodeBlockFiles>
425
- {(item) => <CodeBlockFilename value={item.filename}>{item.filename}</CodeBlockFilename>}
426
- </CodeBlockFiles>
427
- <CodeBlockCopyButton />
428
- </CodeBlockHeader>
429
- <CodeBlockBody className="min-h-0 scrollbar">
430
- {(item) => (
431
- <CodeBlockItem
432
- value={item.filename}
433
- lineNumbers={false}
434
- className="px-0 pb-0 [&>div]:rounded-none [&>div]:border-0 [&>div]:bg-background-contrast-base [&>div]:dark:bg-background-contrast-base [&_code]:!text-foreground-neutral-on-color"
435
- >
436
- <CodeBlockContent language="json" syntaxHighlighting={false}>
437
- {item.code}
438
- </CodeBlockContent>
439
- </CodeBlockItem>
440
- )}
441
- </CodeBlockBody>
442
- </CodeBlock>
443
- </section>
414
+ <Panel>
415
+ <PanelHeader>
416
+ <PanelTitle>Payload</PanelTitle>
417
+ </PanelHeader>
418
+ <PanelBody className="p-0">
419
+ <CodeBlock
420
+ data={data}
421
+ className="flex h-auto flex-col overflow-visible rounded-none bg-background-contrast-base shadow-none"
422
+ >
423
+ <CodeBlockHeader className="sticky top-0 z-10 shrink-0 border-b border-border-contrast-base bg-background-contrast-base p-tight">
424
+ <CodeBlockFiles>
425
+ {(item) => (
426
+ <CodeBlockFilename value={item.filename}>{item.filename}</CodeBlockFilename>
427
+ )}
428
+ </CodeBlockFiles>
429
+ <CodeBlockCopyButton />
430
+ </CodeBlockHeader>
431
+ <CodeBlockBody className="min-h-0 scrollbar">
432
+ {(item) => (
433
+ <CodeBlockItem
434
+ value={item.filename}
435
+ lineNumbers={false}
436
+ className="px-0 pb-0 [&>div]:rounded-none [&>div]:border-0 [&>div]:bg-background-contrast-base [&_code]:!text-foreground-neutral-on-color"
437
+ >
438
+ <CodeBlockContent language="json" syntaxHighlighting={false}>
439
+ {item.code}
440
+ </CodeBlockContent>
441
+ </CodeBlockItem>
442
+ )}
443
+ </CodeBlockBody>
444
+ </CodeBlock>
445
+ </PanelBody>
446
+ </Panel>
444
447
  );
445
448
  }
@@ -13,6 +13,7 @@ import {EventsPage} from './events-page.js';
13
13
 
14
14
  const WORKSPACE_ID = '11111111-1111-4111-8111-111111111111';
15
15
  const EVENT_ID = '22222222-2222-4222-8222-222222222222';
16
+ const EVENTS_HEADING = /^Events$/u;
16
17
 
17
18
  const useTriggerEventsInfiniteQueryMock = vi.mocked(useTriggerEventsInfiniteQuery);
18
19
  const useTriggerEventFacetsQueryMock = vi.mocked(useTriggerEventFacetsQuery);
@@ -89,6 +90,12 @@ describe('EventsPage', () => {
89
90
  );
90
91
  fireEvent.click(await screen.findByRole('button', {name: 'Open details for github · push'}));
91
92
  expect(screen.getByRole('button', {name: 'Back to events'})).toBeInTheDocument();
93
+ expect(screen.queryByRole('heading', {name: EVENTS_HEADING})).not.toBeInTheDocument();
94
+ expect(
95
+ screen.queryByText(
96
+ 'A workspace-wide audit log of trigger events received from integrations, schedules, and manual trigger calls.',
97
+ ),
98
+ ).not.toBeInTheDocument();
92
99
 
93
100
  useTriggerEventsInfiniteQueryMock.mockReturnValue(makeListQuery([]));
94
101
  rerender(<EventsPage workspaceId={WORKSPACE_ID} filters={{}} onFiltersChange={vi.fn()} />);
@@ -1,5 +1,4 @@
1
1
  import {RelativeTimeProvider} from '@shipfox/react-ui/relative-time';
2
- import {Header, Text} from '@shipfox/react-ui/typography';
3
2
  import {cn} from '@shipfox/react-ui/utils';
4
3
  import {useEffect, useMemo, useState} from 'react';
5
4
  import {EventsList} from '#components/events-list.js';
@@ -43,20 +42,7 @@ export function EventsPage({
43
42
 
44
43
  return (
45
44
  <RelativeTimeProvider>
46
- <section
47
- className="@container flex min-w-0 flex-col gap-group"
48
- aria-labelledby="trigger-events-heading"
49
- >
50
- <div className="flex flex-col gap-tight">
51
- <Header id="trigger-events-heading" variant="h3">
52
- Events
53
- </Header>
54
- <Text size="sm" className="text-foreground-neutral-muted">
55
- A workspace-wide audit log of trigger events received from integrations, schedules, and
56
- manual trigger calls.
57
- </Text>
58
- </div>
59
-
45
+ <section className="@container flex min-w-0 flex-col gap-group" aria-label="Events">
60
46
  <div className="grid min-h-0 items-start gap-group @min-[820px]:grid-cols-[minmax(0,1fr)_minmax(360px,420px)]">
61
47
  <div className={cn('min-w-0', selectedEventId && '@max-[820px]:hidden')}>
62
48
  <EventsList
@@ -15,6 +15,7 @@ function validateSearch(search: Record<string, unknown>): TriggerEventsSearch {
15
15
  }
16
16
 
17
17
  export default defineRoute({
18
+ staticData: {frame: 'data'},
18
19
  validateSearch,
19
20
  component: () => {
20
21
  const workspace = useActiveWorkspace();