@shipfox/client-triggers 0.2.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/.storybook/main.ts +1 -0
- package/.storybook/preview.css +8 -0
- package/.storybook/preview.tsx +89 -0
- package/.turbo/turbo-build.log +2 -0
- package/.turbo/turbo-type$colon$emit.log +1 -0
- package/.turbo/turbo-type.log +1 -0
- package/CHANGELOG.md +120 -0
- package/LICENSE +21 -0
- package/dist/components/events-filter-bar.d.ts +13 -0
- package/dist/components/events-filter-bar.d.ts.map +1 -0
- package/dist/components/events-filter-bar.js +198 -0
- package/dist/components/events-filter-bar.js.map +1 -0
- package/dist/components/events-list-states.d.ts +16 -0
- package/dist/components/events-list-states.d.ts.map +1 -0
- package/dist/components/events-list-states.js +105 -0
- package/dist/components/events-list-states.js.map +1 -0
- package/dist/components/events-list.d.ts +3 -0
- package/dist/components/events-list.d.ts.map +1 -0
- package/dist/components/events-list.js +97 -0
- package/dist/components/events-list.js.map +1 -0
- package/dist/components/events-list.stories.d.ts +53 -0
- package/dist/components/events-list.stories.d.ts.map +1 -0
- package/dist/components/events-list.stories.js +180 -0
- package/dist/components/events-list.stories.js.map +1 -0
- package/dist/components/trigger-event-detail.d.ts +13 -0
- package/dist/components/trigger-event-detail.d.ts.map +1 -0
- package/dist/components/trigger-event-detail.js +376 -0
- package/dist/components/trigger-event-detail.js.map +1 -0
- package/dist/components/trigger-event-detail.stories.d.ts +65 -0
- package/dist/components/trigger-event-detail.stories.d.ts.map +1 -0
- package/dist/components/trigger-event-detail.stories.js +181 -0
- package/dist/components/trigger-event-detail.stories.js.map +1 -0
- package/dist/components/trigger-event-result.d.ts +15 -0
- package/dist/components/trigger-event-result.d.ts.map +1 -0
- package/dist/components/trigger-event-result.js +48 -0
- package/dist/components/trigger-event-result.js.map +1 -0
- package/dist/components/trigger-event-row.d.ts +9 -0
- package/dist/components/trigger-event-row.d.ts.map +1 -0
- package/dist/components/trigger-event-row.js +91 -0
- package/dist/components/trigger-event-row.js.map +1 -0
- package/dist/components/trigger-source-icon.d.ts +20 -0
- package/dist/components/trigger-source-icon.d.ts.map +1 -0
- package/dist/components/trigger-source-icon.js +28 -0
- package/dist/components/trigger-source-icon.js.map +1 -0
- package/dist/components/types.d.ts +20 -0
- package/dist/components/types.d.ts.map +1 -0
- package/dist/components/types.js +3 -0
- package/dist/components/types.js.map +1 -0
- package/dist/hooks/api/trigger-events.d.ts +164 -0
- package/dist/hooks/api/trigger-events.d.ts.map +1 -0
- package/dist/hooks/api/trigger-events.js +122 -0
- package/dist/hooks/api/trigger-events.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/pages/events-page.d.ts +12 -0
- package/dist/pages/events-page.d.ts.map +1 -0
- package/dist/pages/events-page.js +82 -0
- package/dist/pages/events-page.js.map +1 -0
- package/dist/search.d.ts +23 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/search.js +28 -0
- package/dist/search.js.map +1 -0
- package/dist/tsconfig.test.tsbuildinfo +1 -0
- package/package.json +92 -0
- package/src/components/events-filter-bar.tsx +191 -0
- package/src/components/events-list-states.tsx +89 -0
- package/src/components/events-list.stories.tsx +141 -0
- package/src/components/events-list.test.tsx +173 -0
- package/src/components/events-list.tsx +107 -0
- package/src/components/trigger-event-detail.stories.tsx +169 -0
- package/src/components/trigger-event-detail.test.tsx +201 -0
- package/src/components/trigger-event-detail.tsx +317 -0
- package/src/components/trigger-event-result.test.ts +40 -0
- package/src/components/trigger-event-result.ts +40 -0
- package/src/components/trigger-event-row.tsx +86 -0
- package/src/components/trigger-source-icon.react.test.tsx +34 -0
- package/src/components/trigger-source-icon.test.ts +23 -0
- package/src/components/trigger-source-icon.tsx +36 -0
- package/src/components/types.ts +22 -0
- package/src/hooks/api/trigger-events.test.ts +252 -0
- package/src/hooks/api/trigger-events.ts +143 -0
- package/src/index.ts +4 -0
- package/src/pages/events-page.test.tsx +100 -0
- package/src/pages/events-page.tsx +79 -0
- package/src/search.test.ts +66 -0
- package/src/search.ts +38 -0
- package/test/setup.ts +35 -0
- package/tsconfig.build.json +9 -0
- package/tsconfig.build.tsbuildinfo +1 -0
- package/tsconfig.json +3 -0
- package/tsconfig.test.json +8 -0
- package/vercel.json +8 -0
- package/vitest.config.ts +68 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {default} from '../../.storybook/main.ts';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
@import "@shipfox/react-ui/index.css";
|
|
2
|
+
|
|
3
|
+
/* The `@import` pulls in the full design-system theme (tokens, preflight, base layer) from
|
|
4
|
+
react-ui. Tailwind v4 only emits utilities for classes it finds in scanned source, and
|
|
5
|
+
these stories render react-ui components whose classes live in react-ui's own source, so
|
|
6
|
+
scan both trees to keep them styled. */
|
|
7
|
+
@source "../src";
|
|
8
|
+
@source "../../../shared/react/ui/src";
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import './preview.css';
|
|
2
|
+
import {RelativeTimeProvider} from '@shipfox/react-ui/relative-time';
|
|
3
|
+
import {ThemeProvider} from '@shipfox/react-ui/theme';
|
|
4
|
+
import type {Decorator, Preview} from '@storybook/react';
|
|
5
|
+
import {
|
|
6
|
+
createMemoryHistory,
|
|
7
|
+
createRootRoute,
|
|
8
|
+
createRoute,
|
|
9
|
+
createRouter,
|
|
10
|
+
RouterProvider,
|
|
11
|
+
} from '@tanstack/react-router';
|
|
12
|
+
|
|
13
|
+
if (typeof document !== 'undefined' && document.fonts) {
|
|
14
|
+
void Promise.all([
|
|
15
|
+
document.fonts.load("16px 'Inter'"),
|
|
16
|
+
document.fonts.load("italic 16px 'Inter'"),
|
|
17
|
+
document.fonts.load("16px 'Commit Mono'"),
|
|
18
|
+
document.fonts.load("bold 16px 'Commit Mono'"),
|
|
19
|
+
]);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const withTheme: Decorator = (Story, context) => {
|
|
23
|
+
const theme = context.globals.theme;
|
|
24
|
+
return (
|
|
25
|
+
<ThemeProvider key={theme} defaultTheme={theme} storageKey={`shipfox-theme-${theme}`}>
|
|
26
|
+
<Story />
|
|
27
|
+
</ThemeProvider>
|
|
28
|
+
);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const withRelativeTime: Decorator = (Story) => (
|
|
32
|
+
<RelativeTimeProvider>
|
|
33
|
+
<Story />
|
|
34
|
+
</RelativeTimeProvider>
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
// The empty state renders `<Link to="/workspaces/$wid/settings/integrations">`, which needs a
|
|
38
|
+
// router in context to resolve its href. A memory router seeded at a matching path lets the
|
|
39
|
+
// story render the link without the real app shell.
|
|
40
|
+
const withRouter: Decorator = (Story) => {
|
|
41
|
+
const rootRoute = createRootRoute();
|
|
42
|
+
const integrationsRoute = createRoute({
|
|
43
|
+
getParentRoute: () => rootRoute,
|
|
44
|
+
path: '/workspaces/$wid/settings/integrations',
|
|
45
|
+
component: () => <Story />,
|
|
46
|
+
});
|
|
47
|
+
const router = createRouter({
|
|
48
|
+
routeTree: rootRoute.addChildren([integrationsRoute]),
|
|
49
|
+
history: createMemoryHistory({
|
|
50
|
+
initialEntries: ['/workspaces/ws-demo/settings/integrations'],
|
|
51
|
+
}),
|
|
52
|
+
});
|
|
53
|
+
return <RouterProvider router={router} />;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const preview: Preview = {
|
|
57
|
+
decorators: [withTheme, withRelativeTime, withRouter],
|
|
58
|
+
parameters: {
|
|
59
|
+
argos: {
|
|
60
|
+
// Dual-theme coverage lives in @shipfox/react-ui (the theming source of truth);
|
|
61
|
+
// feature packages capture only the primary dark theme to limit Argos spend.
|
|
62
|
+
modes: {
|
|
63
|
+
dark: {theme: 'dark'},
|
|
64
|
+
},
|
|
65
|
+
fitToContent: false,
|
|
66
|
+
},
|
|
67
|
+
options: {
|
|
68
|
+
storySort: {method: 'alphabetical'},
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
globalTypes: {
|
|
72
|
+
theme: {
|
|
73
|
+
name: 'Theme',
|
|
74
|
+
description: 'Global theme for components',
|
|
75
|
+
defaultValue: 'dark',
|
|
76
|
+
toolbar: {
|
|
77
|
+
icon: 'sun',
|
|
78
|
+
items: [
|
|
79
|
+
{value: 'light', icon: 'sun', title: 'Light'},
|
|
80
|
+
{value: 'dark', icon: 'moon', title: 'Dark'},
|
|
81
|
+
{value: 'system', icon: 'info', title: 'System'},
|
|
82
|
+
],
|
|
83
|
+
showName: true,
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
export default preview;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
$ shipfox-tsc-emit
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
$ shipfox-tsc-check
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# @shipfox/client-triggers
|
|
2
|
+
|
|
3
|
+
## 0.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 3d064b8: Publishes the client runtime closure with shell, feature, route, Vite, and testing contracts.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Updated dependencies [3d064b8]
|
|
12
|
+
- Updated dependencies [6bc2e45]
|
|
13
|
+
- @shipfox/client-api@0.2.0
|
|
14
|
+
- @shipfox/client-integrations@0.2.0
|
|
15
|
+
- @shipfox/client-ui@0.2.0
|
|
16
|
+
|
|
17
|
+
## 0.1.2
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- Updated dependencies [c18d624]
|
|
22
|
+
- @shipfox/react-ui@0.3.1
|
|
23
|
+
- @shipfox/client-integrations@0.1.2
|
|
24
|
+
- @shipfox/client-ui@0.1.2
|
|
25
|
+
|
|
26
|
+
## 0.1.1
|
|
27
|
+
|
|
28
|
+
### Patch Changes
|
|
29
|
+
|
|
30
|
+
- Updated dependencies [1b0d344]
|
|
31
|
+
- @shipfox/api-triggers-dto@2.0.0
|
|
32
|
+
- @shipfox/client-ui@0.1.1
|
|
33
|
+
- @shipfox/client-integrations@0.1.1
|
|
34
|
+
- @shipfox/client-api@0.0.1
|
|
35
|
+
- @shipfox/react-ui@0.3.0
|
|
36
|
+
|
|
37
|
+
## 0.1.0
|
|
38
|
+
|
|
39
|
+
### Minor Changes
|
|
40
|
+
|
|
41
|
+
- e4c6abf: Add reusable, source-keyed icon building blocks so any surface can render an integration or trigger icon without re-implementing the catalog lookup and fallback.
|
|
42
|
+
|
|
43
|
+
`@shipfox/client-integrations` exposes `getIntegrationIcon(source)` and `<IntegrationIcon source />`, resolving an integration source (a connection `provider`, a run `trigger_source`, or a trigger event `source`) against the central `PROVIDER_CATALOG` with a neutral `componentLine` fallback. The catalog stays the single place each integration declares its icon; the integration gallery now renders `<IntegrationIcon>` instead of an inline lookup (no behavior change).
|
|
44
|
+
|
|
45
|
+
New `@shipfox/client-triggers` package adds `getTriggerSourceIcon(source)` and `<TriggerSourceIcon source />`, built on the integration resolver. It recognizes the system trigger sources `manual` (a person fired the run) and `cron` (a schedule), and delegates every other source to the integration catalog. This is the building block for showing an icon on run rows and trigger events; adopting it on those surfaces lands separately.
|
|
46
|
+
|
|
47
|
+
- 2c352bb: Add the trigger events data layer to `@shipfox/client-triggers`: transport
|
|
48
|
+
functions, colocated query keys, and React Query hooks for the workspace Events
|
|
49
|
+
view. `useTriggerEventsInfiniteQuery(workspaceId, filters)` paginates the event
|
|
50
|
+
history newest-first with cursor-based infinite scroll, and `useTriggerEventQuery(id)`
|
|
51
|
+
loads a single event with its routing decisions. Filters (`source`, `event`,
|
|
52
|
+
`outcome`, `from`, `to`) are normalized into a stable cache key so an out-of-order
|
|
53
|
+
or duplicated `outcome` selection reuses the same cache entry. Consumes the
|
|
54
|
+
`@shipfox/api-triggers-dto` contracts; no UI yet.
|
|
55
|
+
- e5d2f13: Add the workspace **Events** page in Settings: a filterable, cursor-paginated table of
|
|
56
|
+
trigger events (status dot, source/event, routing summary, delivery id, received time)
|
|
57
|
+
mounted at `/workspaces/$wid/settings/events` and wired into the settings sub-nav. Filters
|
|
58
|
+
(date range, source, event, outcome) live in the URL via `validateSearch`, so a filtered
|
|
59
|
+
view is shareable. Source and event filters are populated by a new
|
|
60
|
+
`GET /trigger-events/facets` endpoint that returns each workspace's distinct source/event
|
|
61
|
+
values with counts (top 50, backed by `(workspace_id, source)` / `(workspace_id, event)`
|
|
62
|
+
indexes); the list still renders if facets fail to load.
|
|
63
|
+
- a460020: Add trigger event detail decisions with stored subscription names, run links, and payload inspection.
|
|
64
|
+
|
|
65
|
+
### Patch Changes
|
|
66
|
+
|
|
67
|
+
- Updated dependencies [43d7996]
|
|
68
|
+
- Updated dependencies [14e0bea]
|
|
69
|
+
- Updated dependencies [9018f0b]
|
|
70
|
+
- Updated dependencies [7fdfd72]
|
|
71
|
+
- Updated dependencies [2a3193f]
|
|
72
|
+
- Updated dependencies [f104ff2]
|
|
73
|
+
- Updated dependencies [7341569]
|
|
74
|
+
- Updated dependencies [d245be8]
|
|
75
|
+
- Updated dependencies [0f06c02]
|
|
76
|
+
- Updated dependencies [e4c6abf]
|
|
77
|
+
- Updated dependencies [e4c6abf]
|
|
78
|
+
- Updated dependencies [e5d2f13]
|
|
79
|
+
- Updated dependencies [a982f20]
|
|
80
|
+
- Updated dependencies [5d0676a]
|
|
81
|
+
- Updated dependencies [a460020]
|
|
82
|
+
- Updated dependencies [a35c2dc]
|
|
83
|
+
- Updated dependencies [58f7aef]
|
|
84
|
+
- Updated dependencies [5264a22]
|
|
85
|
+
- Updated dependencies [9674879]
|
|
86
|
+
- Updated dependencies [225c9a5]
|
|
87
|
+
- Updated dependencies [42443b4]
|
|
88
|
+
- Updated dependencies [24f131b]
|
|
89
|
+
- Updated dependencies [bb2a7bc]
|
|
90
|
+
- Updated dependencies [63bcac8]
|
|
91
|
+
- Updated dependencies [5eb06d0]
|
|
92
|
+
- Updated dependencies [4e13e5f]
|
|
93
|
+
- Updated dependencies [e92150d]
|
|
94
|
+
- Updated dependencies [8037501]
|
|
95
|
+
- Updated dependencies [0fb6018]
|
|
96
|
+
- Updated dependencies [c27a1ed]
|
|
97
|
+
- Updated dependencies [b8e49ff]
|
|
98
|
+
- Updated dependencies [8037501]
|
|
99
|
+
- Updated dependencies [6c0da64]
|
|
100
|
+
- Updated dependencies [07f8ff8]
|
|
101
|
+
- Updated dependencies [e457582]
|
|
102
|
+
- Updated dependencies [8b5c905]
|
|
103
|
+
- Updated dependencies [e192d86]
|
|
104
|
+
- Updated dependencies [5ec8367]
|
|
105
|
+
- Updated dependencies [f849131]
|
|
106
|
+
- Updated dependencies [a7da648]
|
|
107
|
+
- Updated dependencies [94bdcc5]
|
|
108
|
+
- Updated dependencies [a34c8ea]
|
|
109
|
+
- Updated dependencies [27770eb]
|
|
110
|
+
- Updated dependencies [8ac4bf4]
|
|
111
|
+
- Updated dependencies [3a0be6b]
|
|
112
|
+
- Updated dependencies [d42baf4]
|
|
113
|
+
- Updated dependencies [8037501]
|
|
114
|
+
- Updated dependencies [54bb8a3]
|
|
115
|
+
- Updated dependencies [f711e18]
|
|
116
|
+
- @shipfox/client-integrations@0.1.0
|
|
117
|
+
- @shipfox/react-ui@0.3.0
|
|
118
|
+
- @shipfox/api-triggers-dto@0.1.0
|
|
119
|
+
- @shipfox/client-api@0.0.1
|
|
120
|
+
- @shipfox/client-ui@0.1.0
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Shipfox
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { TriggerEventFacetItemDto } from '@shipfox/api-triggers-dto';
|
|
2
|
+
import type { TriggerEventFilters } from '#hooks/api/trigger-events.js';
|
|
3
|
+
interface EventsFilterBarProps {
|
|
4
|
+
filters: TriggerEventFilters;
|
|
5
|
+
onFiltersChange: (patch: Partial<TriggerEventFilters>) => void;
|
|
6
|
+
sources: TriggerEventFacetItemDto[] | undefined;
|
|
7
|
+
events: TriggerEventFacetItemDto[] | undefined;
|
|
8
|
+
hasActiveFilters: boolean;
|
|
9
|
+
onClear: () => void;
|
|
10
|
+
}
|
|
11
|
+
export declare function EventsFilterBar({ filters, onFiltersChange, sources, events, hasActiveFilters, onClear, }: EventsFilterBarProps): import("react").JSX.Element;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=events-filter-bar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events-filter-bar.d.ts","sourceRoot":"","sources":["../../src/components/events-filter-bar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,wBAAwB,EAAyB,MAAM,2BAA2B,CAAC;AAQhG,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,8BAA8B,CAAC;AAwBtE,UAAU,oBAAoB;IAC5B,OAAO,EAAE,mBAAmB,CAAC;IAC7B,eAAe,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,mBAAmB,CAAC,KAAK,IAAI,CAAC;IAC/D,OAAO,EAAE,wBAAwB,EAAE,GAAG,SAAS,CAAC;IAChD,MAAM,EAAE,wBAAwB,EAAE,GAAG,SAAS,CAAC;IAC/C,gBAAgB,EAAE,OAAO,CAAC;IAC1B,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,wBAAgB,eAAe,CAAC,EAC9B,OAAO,EACP,eAAe,EACf,OAAO,EACP,MAAM,EACN,gBAAgB,EAChB,OAAO,GACR,EAAE,oBAAoB,+BA2HtB"}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Button } from '@shipfox/react-ui/button';
|
|
3
|
+
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@shipfox/react-ui/collapsible';
|
|
4
|
+
import { Combobox } from '@shipfox/react-ui/combobox';
|
|
5
|
+
import { DateRangePicker } from '@shipfox/react-ui/date-range-picker';
|
|
6
|
+
import { Text } from '@shipfox/react-ui/typography';
|
|
7
|
+
import { cn } from '@shipfox/react-ui/utils';
|
|
8
|
+
import { useState } from 'react';
|
|
9
|
+
// Filters expose the same plain-language results shown in the table. `failed`
|
|
10
|
+
// includes `errored` so the Failed filter does not hide rows rendered as failed.
|
|
11
|
+
const RESULT_FILTERS = [
|
|
12
|
+
{
|
|
13
|
+
value: 'routed',
|
|
14
|
+
selects: [
|
|
15
|
+
'routed'
|
|
16
|
+
],
|
|
17
|
+
label: 'Triggered'
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
value: 'discarded',
|
|
21
|
+
selects: [
|
|
22
|
+
'discarded'
|
|
23
|
+
],
|
|
24
|
+
label: 'No match'
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
value: 'failed',
|
|
28
|
+
selects: [
|
|
29
|
+
'failed',
|
|
30
|
+
'errored'
|
|
31
|
+
],
|
|
32
|
+
label: 'Failed'
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
value: 'received',
|
|
36
|
+
selects: [
|
|
37
|
+
'received'
|
|
38
|
+
],
|
|
39
|
+
label: 'Evaluating'
|
|
40
|
+
}
|
|
41
|
+
];
|
|
42
|
+
const RESULT_OPTIONS = RESULT_FILTERS.map(({ value, label })=>({
|
|
43
|
+
value,
|
|
44
|
+
label
|
|
45
|
+
}));
|
|
46
|
+
function toOptions(facets) {
|
|
47
|
+
return (facets ?? []).map((facet)=>({
|
|
48
|
+
value: facet.value,
|
|
49
|
+
label: `${facet.value} (${facet.count})`
|
|
50
|
+
}));
|
|
51
|
+
}
|
|
52
|
+
export function EventsFilterBar({ filters, onFiltersChange, sources, events, hasActiveFilters, onClear }) {
|
|
53
|
+
const [open, setOpen] = useState(false);
|
|
54
|
+
const dateRange = filters.from || filters.to ? {
|
|
55
|
+
start: filters.from ? new Date(filters.from) : undefined,
|
|
56
|
+
end: filters.to ? new Date(filters.to) : undefined
|
|
57
|
+
} : undefined;
|
|
58
|
+
const selectedOutcomes = new Set(filters.outcome ?? []);
|
|
59
|
+
const resultValue = RESULT_FILTERS.filter(({ selects })=>selects.some((outcome)=>selectedOutcomes.has(outcome))).map(({ value })=>value);
|
|
60
|
+
// Count active dimensions, not selected options, so the badge stays stable as chips grow.
|
|
61
|
+
const activeCount = (dateRange ? 1 : 0) + (filters.source?.length ? 1 : 0) + (filters.event?.length ? 1 : 0) + (resultValue.length > 0 ? 1 : 0);
|
|
62
|
+
function handleResultValue(values) {
|
|
63
|
+
const next = RESULT_FILTERS.filter(({ value })=>values.includes(value)).flatMap(({ selects })=>selects);
|
|
64
|
+
onFiltersChange({
|
|
65
|
+
outcome: next.length > 0 ? next : undefined
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
function handleDateRange(range) {
|
|
69
|
+
const from = range?.start ? new Date(range.start).toISOString() : undefined;
|
|
70
|
+
let to;
|
|
71
|
+
if (range?.end) {
|
|
72
|
+
// The backend filters received_at <= to; extend to end-of-day so the picked end
|
|
73
|
+
// date is inclusive rather than cutting off at its midnight.
|
|
74
|
+
const end = new Date(range.end);
|
|
75
|
+
end.setHours(23, 59, 59, 999);
|
|
76
|
+
to = end.toISOString();
|
|
77
|
+
}
|
|
78
|
+
onFiltersChange({
|
|
79
|
+
from,
|
|
80
|
+
to
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
return /*#__PURE__*/ _jsxs(Collapsible, {
|
|
84
|
+
open: open,
|
|
85
|
+
onOpenChange: setOpen,
|
|
86
|
+
children: [
|
|
87
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
88
|
+
className: "flex items-center justify-between gap-8 border-b border-border-neutral-base px-12 py-8",
|
|
89
|
+
children: [
|
|
90
|
+
/*#__PURE__*/ _jsx(CollapsibleTrigger, {
|
|
91
|
+
asChild: true,
|
|
92
|
+
children: /*#__PURE__*/ _jsx(Button, {
|
|
93
|
+
type: "button",
|
|
94
|
+
variant: "secondary",
|
|
95
|
+
size: "sm",
|
|
96
|
+
iconLeft: "filter3Line",
|
|
97
|
+
iconRight: open ? 'arrowUpSLine' : 'arrowDownSLine',
|
|
98
|
+
children: activeCount > 0 ? `Filters (${activeCount})` : 'Filters'
|
|
99
|
+
})
|
|
100
|
+
}),
|
|
101
|
+
hasActiveFilters ? /*#__PURE__*/ _jsx(Button, {
|
|
102
|
+
type: "button",
|
|
103
|
+
size: "2xs",
|
|
104
|
+
variant: "transparentMuted",
|
|
105
|
+
onClick: onClear,
|
|
106
|
+
children: "Clear filters"
|
|
107
|
+
}) : null
|
|
108
|
+
]
|
|
109
|
+
}),
|
|
110
|
+
/*#__PURE__*/ _jsx(CollapsibleContent, {
|
|
111
|
+
children: /*#__PURE__*/ _jsxs("div", {
|
|
112
|
+
className: "grid grid-cols-1 gap-x-12 gap-y-10 border-b border-border-neutral-base px-12 py-12 min-[520px]:grid-cols-2",
|
|
113
|
+
children: [
|
|
114
|
+
/*#__PURE__*/ _jsx(FilterField, {
|
|
115
|
+
label: "Date",
|
|
116
|
+
className: "col-span-full",
|
|
117
|
+
children: /*#__PURE__*/ _jsx(DateRangePicker, {
|
|
118
|
+
size: "small",
|
|
119
|
+
className: "w-full",
|
|
120
|
+
...dateRange ? {
|
|
121
|
+
dateRange
|
|
122
|
+
} : {},
|
|
123
|
+
onDateRangeSelect: handleDateRange,
|
|
124
|
+
onClear: ()=>onFiltersChange({
|
|
125
|
+
from: undefined,
|
|
126
|
+
to: undefined
|
|
127
|
+
}),
|
|
128
|
+
placeholder: "Any date"
|
|
129
|
+
})
|
|
130
|
+
}),
|
|
131
|
+
/*#__PURE__*/ _jsx(FilterField, {
|
|
132
|
+
label: "Result",
|
|
133
|
+
children: /*#__PURE__*/ _jsx(Combobox, {
|
|
134
|
+
multiple: true,
|
|
135
|
+
size: "small",
|
|
136
|
+
"aria-label": "Filter by result",
|
|
137
|
+
options: RESULT_OPTIONS,
|
|
138
|
+
value: resultValue,
|
|
139
|
+
onValueChange: handleResultValue,
|
|
140
|
+
placeholder: "All results",
|
|
141
|
+
emptyState: "No results",
|
|
142
|
+
className: "w-full",
|
|
143
|
+
maxVisibleChips: 2
|
|
144
|
+
})
|
|
145
|
+
}),
|
|
146
|
+
/*#__PURE__*/ _jsx(FilterField, {
|
|
147
|
+
label: "Source",
|
|
148
|
+
children: /*#__PURE__*/ _jsx(Combobox, {
|
|
149
|
+
multiple: true,
|
|
150
|
+
size: "small",
|
|
151
|
+
options: toOptions(sources),
|
|
152
|
+
value: filters.source ?? [],
|
|
153
|
+
onValueChange: (value)=>onFiltersChange({
|
|
154
|
+
source: value.length > 0 ? value : undefined
|
|
155
|
+
}),
|
|
156
|
+
placeholder: "All sources",
|
|
157
|
+
emptyState: "No sources yet",
|
|
158
|
+
className: "w-full",
|
|
159
|
+
maxVisibleChips: 2
|
|
160
|
+
})
|
|
161
|
+
}),
|
|
162
|
+
/*#__PURE__*/ _jsx(FilterField, {
|
|
163
|
+
label: "Event",
|
|
164
|
+
children: /*#__PURE__*/ _jsx(Combobox, {
|
|
165
|
+
multiple: true,
|
|
166
|
+
size: "small",
|
|
167
|
+
options: toOptions(events),
|
|
168
|
+
value: filters.event ?? [],
|
|
169
|
+
onValueChange: (value)=>onFiltersChange({
|
|
170
|
+
event: value.length > 0 ? value : undefined
|
|
171
|
+
}),
|
|
172
|
+
placeholder: "All events",
|
|
173
|
+
emptyState: "No events yet",
|
|
174
|
+
className: "w-full",
|
|
175
|
+
maxVisibleChips: 2
|
|
176
|
+
})
|
|
177
|
+
})
|
|
178
|
+
]
|
|
179
|
+
})
|
|
180
|
+
})
|
|
181
|
+
]
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
function FilterField({ label, className, children }) {
|
|
185
|
+
return /*#__PURE__*/ _jsxs("div", {
|
|
186
|
+
className: cn('flex min-w-0 flex-col gap-4', className),
|
|
187
|
+
children: [
|
|
188
|
+
/*#__PURE__*/ _jsx(Text, {
|
|
189
|
+
size: "xs",
|
|
190
|
+
className: "font-medium text-foreground-neutral-muted",
|
|
191
|
+
children: label
|
|
192
|
+
}),
|
|
193
|
+
children
|
|
194
|
+
]
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
//# sourceMappingURL=events-filter-bar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/events-filter-bar.tsx"],"sourcesContent":["import type {TriggerEventFacetItemDto, TriggerEventOutcomeDto} from '@shipfox/api-triggers-dto';\nimport {Button} from '@shipfox/react-ui/button';\nimport {Collapsible, CollapsibleContent, CollapsibleTrigger} from '@shipfox/react-ui/collapsible';\nimport {Combobox, type ComboboxOption} from '@shipfox/react-ui/combobox';\nimport {type DateRange, DateRangePicker} from '@shipfox/react-ui/date-range-picker';\nimport {Text} from '@shipfox/react-ui/typography';\nimport {cn} from '@shipfox/react-ui/utils';\nimport {type ReactNode, useState} from 'react';\nimport type {TriggerEventFilters} from '#hooks/api/trigger-events.js';\n\n// Filters expose the same plain-language results shown in the table. `failed`\n// includes `errored` so the Failed filter does not hide rows rendered as failed.\nconst RESULT_FILTERS: {\n value: TriggerEventOutcomeDto;\n selects: TriggerEventOutcomeDto[];\n label: string;\n}[] = [\n {value: 'routed', selects: ['routed'], label: 'Triggered'},\n {value: 'discarded', selects: ['discarded'], label: 'No match'},\n {value: 'failed', selects: ['failed', 'errored'], label: 'Failed'},\n {value: 'received', selects: ['received'], label: 'Evaluating'},\n];\n\nconst RESULT_OPTIONS: ComboboxOption[] = RESULT_FILTERS.map(({value, label}) => ({value, label}));\n\nfunction toOptions(facets: TriggerEventFacetItemDto[] | undefined): ComboboxOption[] {\n return (facets ?? []).map((facet) => ({\n value: facet.value,\n label: `${facet.value} (${facet.count})`,\n }));\n}\n\ninterface EventsFilterBarProps {\n filters: TriggerEventFilters;\n onFiltersChange: (patch: Partial<TriggerEventFilters>) => void;\n sources: TriggerEventFacetItemDto[] | undefined;\n events: TriggerEventFacetItemDto[] | undefined;\n hasActiveFilters: boolean;\n onClear: () => void;\n}\n\nexport function EventsFilterBar({\n filters,\n onFiltersChange,\n sources,\n events,\n hasActiveFilters,\n onClear,\n}: EventsFilterBarProps) {\n const [open, setOpen] = useState(false);\n\n const dateRange: DateRange | undefined =\n filters.from || filters.to\n ? {\n start: filters.from ? new Date(filters.from) : undefined,\n end: filters.to ? new Date(filters.to) : undefined,\n }\n : undefined;\n\n const selectedOutcomes = new Set(filters.outcome ?? []);\n const resultValue = RESULT_FILTERS.filter(({selects}) =>\n selects.some((outcome) => selectedOutcomes.has(outcome)),\n ).map(({value}) => value);\n\n // Count active dimensions, not selected options, so the badge stays stable as chips grow.\n const activeCount =\n (dateRange ? 1 : 0) +\n (filters.source?.length ? 1 : 0) +\n (filters.event?.length ? 1 : 0) +\n (resultValue.length > 0 ? 1 : 0);\n\n function handleResultValue(values: string[]) {\n const next = RESULT_FILTERS.filter(({value}) => values.includes(value)).flatMap(\n ({selects}) => selects,\n );\n onFiltersChange({outcome: next.length > 0 ? next : undefined});\n }\n\n function handleDateRange(range: DateRange | undefined) {\n const from = range?.start ? new Date(range.start).toISOString() : undefined;\n let to: string | undefined;\n if (range?.end) {\n // The backend filters received_at <= to; extend to end-of-day so the picked end\n // date is inclusive rather than cutting off at its midnight.\n const end = new Date(range.end);\n end.setHours(23, 59, 59, 999);\n to = end.toISOString();\n }\n onFiltersChange({from, to});\n }\n\n return (\n <Collapsible open={open} onOpenChange={setOpen}>\n <div className=\"flex items-center justify-between gap-8 border-b border-border-neutral-base px-12 py-8\">\n <CollapsibleTrigger asChild>\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"sm\"\n iconLeft=\"filter3Line\"\n iconRight={open ? 'arrowUpSLine' : 'arrowDownSLine'}\n >\n {activeCount > 0 ? `Filters (${activeCount})` : 'Filters'}\n </Button>\n </CollapsibleTrigger>\n {hasActiveFilters ? (\n <Button type=\"button\" size=\"2xs\" variant=\"transparentMuted\" onClick={onClear}>\n Clear filters\n </Button>\n ) : null}\n </div>\n <CollapsibleContent>\n <div className=\"grid grid-cols-1 gap-x-12 gap-y-10 border-b border-border-neutral-base px-12 py-12 min-[520px]:grid-cols-2\">\n <FilterField label=\"Date\" className=\"col-span-full\">\n <DateRangePicker\n size=\"small\"\n className=\"w-full\"\n {...(dateRange ? {dateRange} : {})}\n onDateRangeSelect={handleDateRange}\n onClear={() => onFiltersChange({from: undefined, to: undefined})}\n placeholder=\"Any date\"\n />\n </FilterField>\n <FilterField label=\"Result\">\n <Combobox\n multiple\n size=\"small\"\n aria-label=\"Filter by result\"\n options={RESULT_OPTIONS}\n value={resultValue}\n onValueChange={handleResultValue}\n placeholder=\"All results\"\n emptyState=\"No results\"\n className=\"w-full\"\n maxVisibleChips={2}\n />\n </FilterField>\n <FilterField label=\"Source\">\n <Combobox\n multiple\n size=\"small\"\n options={toOptions(sources)}\n value={filters.source ?? []}\n onValueChange={(value) =>\n onFiltersChange({source: value.length > 0 ? value : undefined})\n }\n placeholder=\"All sources\"\n emptyState=\"No sources yet\"\n className=\"w-full\"\n maxVisibleChips={2}\n />\n </FilterField>\n <FilterField label=\"Event\">\n <Combobox\n multiple\n size=\"small\"\n options={toOptions(events)}\n value={filters.event ?? []}\n onValueChange={(value) =>\n onFiltersChange({event: value.length > 0 ? value : undefined})\n }\n placeholder=\"All events\"\n emptyState=\"No events yet\"\n className=\"w-full\"\n maxVisibleChips={2}\n />\n </FilterField>\n </div>\n </CollapsibleContent>\n </Collapsible>\n );\n}\n\nfunction FilterField({\n label,\n className,\n children,\n}: {\n label: string;\n className?: string;\n children: ReactNode;\n}) {\n return (\n <div className={cn('flex min-w-0 flex-col gap-4', className)}>\n <Text size=\"xs\" className=\"font-medium text-foreground-neutral-muted\">\n {label}\n </Text>\n {children}\n </div>\n );\n}\n"],"names":["Button","Collapsible","CollapsibleContent","CollapsibleTrigger","Combobox","DateRangePicker","Text","cn","useState","RESULT_FILTERS","value","selects","label","RESULT_OPTIONS","map","toOptions","facets","facet","count","EventsFilterBar","filters","onFiltersChange","sources","events","hasActiveFilters","onClear","open","setOpen","dateRange","from","to","start","Date","undefined","end","selectedOutcomes","Set","outcome","resultValue","filter","some","has","activeCount","source","length","event","handleResultValue","values","next","includes","flatMap","handleDateRange","range","toISOString","setHours","onOpenChange","div","className","asChild","type","variant","size","iconLeft","iconRight","onClick","FilterField","onDateRangeSelect","placeholder","multiple","aria-label","options","onValueChange","emptyState","maxVisibleChips","children"],"mappings":";AACA,SAAQA,MAAM,QAAO,2BAA2B;AAChD,SAAQC,WAAW,EAAEC,kBAAkB,EAAEC,kBAAkB,QAAO,gCAAgC;AAClG,SAAQC,QAAQ,QAA4B,6BAA6B;AACzE,SAAwBC,eAAe,QAAO,sCAAsC;AACpF,SAAQC,IAAI,QAAO,+BAA+B;AAClD,SAAQC,EAAE,QAAO,0BAA0B;AAC3C,SAAwBC,QAAQ,QAAO,QAAQ;AAG/C,8EAA8E;AAC9E,iFAAiF;AACjF,MAAMC,iBAIA;IACJ;QAACC,OAAO;QAAUC,SAAS;YAAC;SAAS;QAAEC,OAAO;IAAW;IACzD;QAACF,OAAO;QAAaC,SAAS;YAAC;SAAY;QAAEC,OAAO;IAAU;IAC9D;QAACF,OAAO;QAAUC,SAAS;YAAC;YAAU;SAAU;QAAEC,OAAO;IAAQ;IACjE;QAACF,OAAO;QAAYC,SAAS;YAAC;SAAW;QAAEC,OAAO;IAAY;CAC/D;AAED,MAAMC,iBAAmCJ,eAAeK,GAAG,CAAC,CAAC,EAACJ,KAAK,EAAEE,KAAK,EAAC,GAAM,CAAA;QAACF;QAAOE;IAAK,CAAA;AAE9F,SAASG,UAAUC,MAA8C;IAC/D,OAAO,AAACA,CAAAA,UAAU,EAAE,AAAD,EAAGF,GAAG,CAAC,CAACG,QAAW,CAAA;YACpCP,OAAOO,MAAMP,KAAK;YAClBE,OAAO,GAAGK,MAAMP,KAAK,CAAC,EAAE,EAAEO,MAAMC,KAAK,CAAC,CAAC,CAAC;QAC1C,CAAA;AACF;AAWA,OAAO,SAASC,gBAAgB,EAC9BC,OAAO,EACPC,eAAe,EACfC,OAAO,EACPC,MAAM,EACNC,gBAAgB,EAChBC,OAAO,EACc;IACrB,MAAM,CAACC,MAAMC,QAAQ,GAAGnB,SAAS;IAEjC,MAAMoB,YACJR,QAAQS,IAAI,IAAIT,QAAQU,EAAE,GACtB;QACEC,OAAOX,QAAQS,IAAI,GAAG,IAAIG,KAAKZ,QAAQS,IAAI,IAAII;QAC/CC,KAAKd,QAAQU,EAAE,GAAG,IAAIE,KAAKZ,QAAQU,EAAE,IAAIG;IAC3C,IACAA;IAEN,MAAME,mBAAmB,IAAIC,IAAIhB,QAAQiB,OAAO,IAAI,EAAE;IACtD,MAAMC,cAAc7B,eAAe8B,MAAM,CAAC,CAAC,EAAC5B,OAAO,EAAC,GAClDA,QAAQ6B,IAAI,CAAC,CAACH,UAAYF,iBAAiBM,GAAG,CAACJ,WAC/CvB,GAAG,CAAC,CAAC,EAACJ,KAAK,EAAC,GAAKA;IAEnB,0FAA0F;IAC1F,MAAMgC,cACJ,AAACd,CAAAA,YAAY,IAAI,CAAA,IAChBR,CAAAA,QAAQuB,MAAM,EAAEC,SAAS,IAAI,CAAA,IAC7BxB,CAAAA,QAAQyB,KAAK,EAAED,SAAS,IAAI,CAAA,IAC5BN,CAAAA,YAAYM,MAAM,GAAG,IAAI,IAAI,CAAA;IAEhC,SAASE,kBAAkBC,MAAgB;QACzC,MAAMC,OAAOvC,eAAe8B,MAAM,CAAC,CAAC,EAAC7B,KAAK,EAAC,GAAKqC,OAAOE,QAAQ,CAACvC,QAAQwC,OAAO,CAC7E,CAAC,EAACvC,OAAO,EAAC,GAAKA;QAEjBU,gBAAgB;YAACgB,SAASW,KAAKJ,MAAM,GAAG,IAAII,OAAOf;QAAS;IAC9D;IAEA,SAASkB,gBAAgBC,KAA4B;QACnD,MAAMvB,OAAOuB,OAAOrB,QAAQ,IAAIC,KAAKoB,MAAMrB,KAAK,EAAEsB,WAAW,KAAKpB;QAClE,IAAIH;QACJ,IAAIsB,OAAOlB,KAAK;YACd,gFAAgF;YAChF,6DAA6D;YAC7D,MAAMA,MAAM,IAAIF,KAAKoB,MAAMlB,GAAG;YAC9BA,IAAIoB,QAAQ,CAAC,IAAI,IAAI,IAAI;YACzBxB,KAAKI,IAAImB,WAAW;QACtB;QACAhC,gBAAgB;YAACQ;YAAMC;QAAE;IAC3B;IAEA,qBACE,MAAC7B;QAAYyB,MAAMA;QAAM6B,cAAc5B;;0BACrC,MAAC6B;gBAAIC,WAAU;;kCACb,KAACtD;wBAAmBuD,OAAO;kCACzB,cAAA,KAAC1D;4BACC2D,MAAK;4BACLC,SAAQ;4BACRC,MAAK;4BACLC,UAAS;4BACTC,WAAWrC,OAAO,iBAAiB;sCAElCgB,cAAc,IAAI,CAAC,SAAS,EAAEA,YAAY,CAAC,CAAC,GAAG;;;oBAGnDlB,iCACC,KAACxB;wBAAO2D,MAAK;wBAASE,MAAK;wBAAMD,SAAQ;wBAAmBI,SAASvC;kCAAS;yBAG5E;;;0BAEN,KAACvB;0BACC,cAAA,MAACsD;oBAAIC,WAAU;;sCACb,KAACQ;4BAAYrD,OAAM;4BAAO6C,WAAU;sCAClC,cAAA,KAACpD;gCACCwD,MAAK;gCACLJ,WAAU;gCACT,GAAI7B,YAAY;oCAACA;gCAAS,IAAI,CAAC,CAAC;gCACjCsC,mBAAmBf;gCACnB1B,SAAS,IAAMJ,gBAAgB;wCAACQ,MAAMI;wCAAWH,IAAIG;oCAAS;gCAC9DkC,aAAY;;;sCAGhB,KAACF;4BAAYrD,OAAM;sCACjB,cAAA,KAACR;gCACCgE,QAAQ;gCACRP,MAAK;gCACLQ,cAAW;gCACXC,SAASzD;gCACTH,OAAO4B;gCACPiC,eAAezB;gCACfqB,aAAY;gCACZK,YAAW;gCACXf,WAAU;gCACVgB,iBAAiB;;;sCAGrB,KAACR;4BAAYrD,OAAM;sCACjB,cAAA,KAACR;gCACCgE,QAAQ;gCACRP,MAAK;gCACLS,SAASvD,UAAUO;gCACnBZ,OAAOU,QAAQuB,MAAM,IAAI,EAAE;gCAC3B4B,eAAe,CAAC7D,QACdW,gBAAgB;wCAACsB,QAAQjC,MAAMkC,MAAM,GAAG,IAAIlC,QAAQuB;oCAAS;gCAE/DkC,aAAY;gCACZK,YAAW;gCACXf,WAAU;gCACVgB,iBAAiB;;;sCAGrB,KAACR;4BAAYrD,OAAM;sCACjB,cAAA,KAACR;gCACCgE,QAAQ;gCACRP,MAAK;gCACLS,SAASvD,UAAUQ;gCACnBb,OAAOU,QAAQyB,KAAK,IAAI,EAAE;gCAC1B0B,eAAe,CAAC7D,QACdW,gBAAgB;wCAACwB,OAAOnC,MAAMkC,MAAM,GAAG,IAAIlC,QAAQuB;oCAAS;gCAE9DkC,aAAY;gCACZK,YAAW;gCACXf,WAAU;gCACVgB,iBAAiB;;;;;;;;AAO/B;AAEA,SAASR,YAAY,EACnBrD,KAAK,EACL6C,SAAS,EACTiB,QAAQ,EAKT;IACC,qBACE,MAAClB;QAAIC,WAAWlD,GAAG,+BAA+BkD;;0BAChD,KAACnD;gBAAKuD,MAAK;gBAAKJ,WAAU;0BACvB7C;;YAEF8D;;;AAGP"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { QueryLoadErrorQuery } from '@shipfox/client-ui';
|
|
2
|
+
export declare function EventsListSkeleton(): import("react").JSX.Element;
|
|
3
|
+
export declare function EventsListEmpty({ workspaceId }: {
|
|
4
|
+
workspaceId: string;
|
|
5
|
+
}): import("react").JSX.Element;
|
|
6
|
+
export declare function EventsListNoMatches({ onClear }: {
|
|
7
|
+
onClear: () => void;
|
|
8
|
+
}): import("react").JSX.Element;
|
|
9
|
+
/**
|
|
10
|
+
* Slim banner shown when a background refetch fails after a prior success, so the loaded
|
|
11
|
+
* rows stay on screen with the retry inline rather than being wiped by a full placeholder.
|
|
12
|
+
*/
|
|
13
|
+
export declare function EventsListStaleError({ query }: {
|
|
14
|
+
query: QueryLoadErrorQuery;
|
|
15
|
+
}): import("react").JSX.Element;
|
|
16
|
+
//# sourceMappingURL=events-list-states.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events-list-states.d.ts","sourceRoot":"","sources":["../../src/components/events-list-states.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,oBAAoB,CAAC;AAQ5D,wBAAgB,kBAAkB,gCAiBjC;AAED,wBAAgB,eAAe,CAAC,EAAC,WAAW,EAAC,EAAE;IAAC,WAAW,EAAE,MAAM,CAAA;CAAC,+BAiBnE;AAED,wBAAgB,mBAAmB,CAAC,EAAC,OAAO,EAAC,EAAE;IAAC,OAAO,EAAE,MAAM,IAAI,CAAA;CAAC,+BAenE;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,EAAC,KAAK,EAAC,EAAE;IAAC,KAAK,EAAE,mBAAmB,CAAA;CAAC,+BAqBzE"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Button } from '@shipfox/react-ui/button';
|
|
3
|
+
import { Callout } from '@shipfox/react-ui/callout';
|
|
4
|
+
import { EmptyState } from '@shipfox/react-ui/empty-state';
|
|
5
|
+
import { Skeleton } from '@shipfox/react-ui/skeleton';
|
|
6
|
+
import { Text } from '@shipfox/react-ui/typography';
|
|
7
|
+
import { Link } from '@tanstack/react-router';
|
|
8
|
+
export function EventsListSkeleton() {
|
|
9
|
+
return /*#__PURE__*/ _jsx("div", {
|
|
10
|
+
className: "flex flex-col gap-8 p-8",
|
|
11
|
+
role: "status",
|
|
12
|
+
"aria-label": "Loading events",
|
|
13
|
+
children: Array.from({
|
|
14
|
+
length: 8
|
|
15
|
+
}).map((_, index)=>/*#__PURE__*/ _jsxs("div", {
|
|
16
|
+
className: "flex h-20 items-center gap-12",
|
|
17
|
+
children: [
|
|
18
|
+
/*#__PURE__*/ _jsx(Skeleton, {
|
|
19
|
+
className: "size-6 shrink-0 rounded-full"
|
|
20
|
+
}),
|
|
21
|
+
/*#__PURE__*/ _jsx(Skeleton, {
|
|
22
|
+
className: "h-12 w-1/4"
|
|
23
|
+
}),
|
|
24
|
+
/*#__PURE__*/ _jsx(Skeleton, {
|
|
25
|
+
className: "h-12 w-20"
|
|
26
|
+
}),
|
|
27
|
+
/*#__PURE__*/ _jsx(Skeleton, {
|
|
28
|
+
className: "ml-auto h-12 w-40"
|
|
29
|
+
})
|
|
30
|
+
]
|
|
31
|
+
}, index))
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
export function EventsListEmpty({ workspaceId }) {
|
|
35
|
+
return /*#__PURE__*/ _jsx("div", {
|
|
36
|
+
className: "p-16",
|
|
37
|
+
children: /*#__PURE__*/ _jsx(EmptyState, {
|
|
38
|
+
icon: "pulseLine",
|
|
39
|
+
title: "No events yet",
|
|
40
|
+
description: "Events appear here once a connected integration delivers one or you fire a trigger.",
|
|
41
|
+
action: /*#__PURE__*/ _jsx(Button, {
|
|
42
|
+
asChild: true,
|
|
43
|
+
size: "sm",
|
|
44
|
+
variant: "secondary",
|
|
45
|
+
children: /*#__PURE__*/ _jsx(Link, {
|
|
46
|
+
to: "/workspaces/$wid/settings/integrations",
|
|
47
|
+
params: {
|
|
48
|
+
wid: workspaceId
|
|
49
|
+
},
|
|
50
|
+
children: "Configure integrations"
|
|
51
|
+
})
|
|
52
|
+
})
|
|
53
|
+
})
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
export function EventsListNoMatches({ onClear }) {
|
|
57
|
+
return /*#__PURE__*/ _jsx("div", {
|
|
58
|
+
className: "p-16",
|
|
59
|
+
children: /*#__PURE__*/ _jsx(EmptyState, {
|
|
60
|
+
icon: "filterOffLine",
|
|
61
|
+
title: "No matching events",
|
|
62
|
+
description: "No events match your current filters.",
|
|
63
|
+
action: /*#__PURE__*/ _jsx(Button, {
|
|
64
|
+
type: "button",
|
|
65
|
+
size: "sm",
|
|
66
|
+
variant: "secondary",
|
|
67
|
+
onClick: onClear,
|
|
68
|
+
children: "Clear filters"
|
|
69
|
+
})
|
|
70
|
+
})
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Slim banner shown when a background refetch fails after a prior success, so the loaded
|
|
75
|
+
* rows stay on screen with the retry inline rather than being wiped by a full placeholder.
|
|
76
|
+
*/ export function EventsListStaleError({ query }) {
|
|
77
|
+
return /*#__PURE__*/ _jsx("div", {
|
|
78
|
+
className: "p-8",
|
|
79
|
+
children: /*#__PURE__*/ _jsx(Callout, {
|
|
80
|
+
role: "alert",
|
|
81
|
+
type: "error",
|
|
82
|
+
children: /*#__PURE__*/ _jsxs("div", {
|
|
83
|
+
className: "flex items-center justify-between gap-8",
|
|
84
|
+
children: [
|
|
85
|
+
/*#__PURE__*/ _jsx(Text, {
|
|
86
|
+
size: "xs",
|
|
87
|
+
children: "Could not refresh events."
|
|
88
|
+
}),
|
|
89
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
90
|
+
type: "button",
|
|
91
|
+
size: "2xs",
|
|
92
|
+
variant: "secondary",
|
|
93
|
+
isLoading: query.isFetching,
|
|
94
|
+
onClick: ()=>{
|
|
95
|
+
void query.refetch();
|
|
96
|
+
},
|
|
97
|
+
children: "Retry"
|
|
98
|
+
})
|
|
99
|
+
]
|
|
100
|
+
})
|
|
101
|
+
})
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
//# sourceMappingURL=events-list-states.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/events-list-states.tsx"],"sourcesContent":["import type {QueryLoadErrorQuery} from '@shipfox/client-ui';\nimport {Button} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {EmptyState} from '@shipfox/react-ui/empty-state';\nimport {Skeleton} from '@shipfox/react-ui/skeleton';\nimport {Text} from '@shipfox/react-ui/typography';\nimport {Link} from '@tanstack/react-router';\n\nexport function EventsListSkeleton() {\n return (\n <div className=\"flex flex-col gap-8 p-8\" role=\"status\" aria-label=\"Loading events\">\n {Array.from({length: 8}).map((_, index) => (\n <div\n // biome-ignore lint/suspicious/noArrayIndexKey: skeleton row, stable position\n key={index}\n className=\"flex h-20 items-center gap-12\"\n >\n <Skeleton className=\"size-6 shrink-0 rounded-full\" />\n <Skeleton className=\"h-12 w-1/4\" />\n <Skeleton className=\"h-12 w-20\" />\n <Skeleton className=\"ml-auto h-12 w-40\" />\n </div>\n ))}\n </div>\n );\n}\n\nexport function EventsListEmpty({workspaceId}: {workspaceId: string}) {\n return (\n <div className=\"p-16\">\n <EmptyState\n icon=\"pulseLine\"\n title=\"No events yet\"\n description=\"Events appear here once a connected integration delivers one or you fire a trigger.\"\n action={\n <Button asChild size=\"sm\" variant=\"secondary\">\n <Link to=\"/workspaces/$wid/settings/integrations\" params={{wid: workspaceId}}>\n Configure integrations\n </Link>\n </Button>\n }\n />\n </div>\n );\n}\n\nexport function EventsListNoMatches({onClear}: {onClear: () => void}) {\n return (\n <div className=\"p-16\">\n <EmptyState\n icon=\"filterOffLine\"\n title=\"No matching events\"\n description=\"No events match your current filters.\"\n action={\n <Button type=\"button\" size=\"sm\" variant=\"secondary\" onClick={onClear}>\n Clear filters\n </Button>\n }\n />\n </div>\n );\n}\n\n/**\n * Slim banner shown when a background refetch fails after a prior success, so the loaded\n * rows stay on screen with the retry inline rather than being wiped by a full placeholder.\n */\nexport function EventsListStaleError({query}: {query: QueryLoadErrorQuery}) {\n return (\n <div className=\"p-8\">\n <Callout role=\"alert\" type=\"error\">\n <div className=\"flex items-center justify-between gap-8\">\n <Text size=\"xs\">Could not refresh events.</Text>\n <Button\n type=\"button\"\n size=\"2xs\"\n variant=\"secondary\"\n isLoading={query.isFetching}\n onClick={() => {\n void query.refetch();\n }}\n >\n Retry\n </Button>\n </div>\n </Callout>\n </div>\n );\n}\n"],"names":["Button","Callout","EmptyState","Skeleton","Text","Link","EventsListSkeleton","div","className","role","aria-label","Array","from","length","map","_","index","EventsListEmpty","workspaceId","icon","title","description","action","asChild","size","variant","to","params","wid","EventsListNoMatches","onClear","type","onClick","EventsListStaleError","query","isLoading","isFetching","refetch"],"mappings":";AACA,SAAQA,MAAM,QAAO,2BAA2B;AAChD,SAAQC,OAAO,QAAO,4BAA4B;AAClD,SAAQC,UAAU,QAAO,gCAAgC;AACzD,SAAQC,QAAQ,QAAO,6BAA6B;AACpD,SAAQC,IAAI,QAAO,+BAA+B;AAClD,SAAQC,IAAI,QAAO,yBAAyB;AAE5C,OAAO,SAASC;IACd,qBACE,KAACC;QAAIC,WAAU;QAA0BC,MAAK;QAASC,cAAW;kBAC/DC,MAAMC,IAAI,CAAC;YAACC,QAAQ;QAAC,GAAGC,GAAG,CAAC,CAACC,GAAGC,sBAC/B,MAACT;gBAGCC,WAAU;;kCAEV,KAACL;wBAASK,WAAU;;kCACpB,KAACL;wBAASK,WAAU;;kCACpB,KAACL;wBAASK,WAAU;;kCACpB,KAACL;wBAASK,WAAU;;;eANfQ;;AAWf;AAEA,OAAO,SAASC,gBAAgB,EAACC,WAAW,EAAwB;IAClE,qBACE,KAACX;QAAIC,WAAU;kBACb,cAAA,KAACN;YACCiB,MAAK;YACLC,OAAM;YACNC,aAAY;YACZC,sBACE,KAACtB;gBAAOuB,OAAO;gBAACC,MAAK;gBAAKC,SAAQ;0BAChC,cAAA,KAACpB;oBAAKqB,IAAG;oBAAyCC,QAAQ;wBAACC,KAAKV;oBAAW;8BAAG;;;;;AAQ1F;AAEA,OAAO,SAASW,oBAAoB,EAACC,OAAO,EAAwB;IAClE,qBACE,KAACvB;QAAIC,WAAU;kBACb,cAAA,KAACN;YACCiB,MAAK;YACLC,OAAM;YACNC,aAAY;YACZC,sBACE,KAACtB;gBAAO+B,MAAK;gBAASP,MAAK;gBAAKC,SAAQ;gBAAYO,SAASF;0BAAS;;;;AAOhF;AAEA;;;CAGC,GACD,OAAO,SAASG,qBAAqB,EAACC,KAAK,EAA+B;IACxE,qBACE,KAAC3B;QAAIC,WAAU;kBACb,cAAA,KAACP;YAAQQ,MAAK;YAAQsB,MAAK;sBACzB,cAAA,MAACxB;gBAAIC,WAAU;;kCACb,KAACJ;wBAAKoB,MAAK;kCAAK;;kCAChB,KAACxB;wBACC+B,MAAK;wBACLP,MAAK;wBACLC,SAAQ;wBACRU,WAAWD,MAAME,UAAU;wBAC3BJ,SAAS;4BACP,KAAKE,MAAMG,OAAO;wBACpB;kCACD;;;;;;AAOX"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { EventsListProps } from './types.js';
|
|
2
|
+
export declare function EventsList({ events, query, facets, filters, onFiltersChange, workspaceId, hasNextPage, isFetchingNextPage, onLoadMore, selectedEventId, onSelectEvent, }: EventsListProps): import("react").JSX.Element;
|
|
3
|
+
//# sourceMappingURL=events-list.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events-list.d.ts","sourceRoot":"","sources":["../../src/components/events-list.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,YAAY,CAAC;AAYhD,wBAAgB,UAAU,CAAC,EACzB,MAAM,EACN,KAAK,EACL,MAAM,EACN,OAAO,EACP,eAAe,EACf,WAAW,EACX,WAAW,EACX,kBAAkB,EAClB,UAAU,EACV,eAAe,EACf,aAAa,GACd,EAAE,eAAe,+BAsEjB"}
|