@shipfox/react-ui 0.22.0 → 0.24.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 (56) hide show
  1. package/dist/components/dashboard/context/dashboard-context.d.ts +12 -8
  2. package/dist/components/dashboard/context/dashboard-context.js +42 -7
  3. package/dist/components/dashboard/context/index.d.ts +2 -2
  4. package/dist/components/dashboard/context/index.js +1 -1
  5. package/dist/components/dashboard/context/types.d.ts +9 -7
  6. package/dist/components/dashboard/index.d.ts +2 -4
  7. package/dist/components/dashboard/index.js +1 -2
  8. package/dist/components/dashboard/pages/analytics-page.js +2 -9
  9. package/dist/components/dashboard/pages/jobs-page.js +2 -4
  10. package/dist/components/dashboard/toolbar/filter-button.d.ts +6 -10
  11. package/dist/components/dashboard/toolbar/filter-button.js +109 -76
  12. package/dist/components/dashboard/toolbar/page-toolbar.d.ts +7 -19
  13. package/dist/components/dashboard/toolbar/page-toolbar.js +11 -99
  14. package/dist/components/dashboard/toolbar/toolbar-actions.js +3 -3
  15. package/dist/components/index.d.ts +1 -0
  16. package/dist/components/index.js +1 -0
  17. package/dist/components/interval-selector/hooks/index.d.ts +4 -0
  18. package/dist/components/interval-selector/hooks/index.js +5 -0
  19. package/dist/components/interval-selector/hooks/use-interval-selector-input.d.ts +30 -0
  20. package/dist/components/interval-selector/hooks/use-interval-selector-input.js +125 -0
  21. package/dist/components/interval-selector/hooks/use-interval-selector-navigation.d.ts +21 -0
  22. package/dist/components/interval-selector/hooks/use-interval-selector-navigation.js +58 -0
  23. package/dist/components/interval-selector/hooks/use-interval-selector.d.ts +25 -0
  24. package/dist/components/interval-selector/hooks/use-interval-selector.js +75 -0
  25. package/dist/components/interval-selector/index.d.ts +3 -0
  26. package/dist/components/interval-selector/index.js +4 -0
  27. package/dist/components/interval-selector/interval-selector-calendar.d.ts +7 -0
  28. package/dist/components/interval-selector/interval-selector-calendar.js +47 -0
  29. package/dist/components/interval-selector/interval-selector-input.d.ts +8 -0
  30. package/dist/components/interval-selector/interval-selector-input.js +34 -0
  31. package/dist/components/interval-selector/interval-selector-suggestions.d.ts +11 -0
  32. package/dist/components/interval-selector/interval-selector-suggestions.js +107 -0
  33. package/dist/components/interval-selector/interval-selector.d.ts +12 -0
  34. package/dist/components/interval-selector/interval-selector.js +56 -0
  35. package/dist/components/interval-selector/interval-selector.stories.js +232 -0
  36. package/dist/components/interval-selector/types.d.ts +19 -0
  37. package/dist/components/interval-selector/types.js +3 -0
  38. package/dist/components/interval-selector/utils/constants.d.ts +24 -0
  39. package/dist/components/interval-selector/utils/constants.js +129 -0
  40. package/dist/components/interval-selector/utils/format.d.ts +16 -0
  41. package/dist/components/interval-selector/utils/format.js +23 -0
  42. package/dist/components/interval-selector/utils/index.d.ts +3 -0
  43. package/dist/components/interval-selector/utils/index.js +4 -0
  44. package/dist/components/modal/modal.d.ts +10 -3
  45. package/dist/components/modal/modal.js +30 -2
  46. package/dist/components/popover/popover.d.ts +3 -1
  47. package/dist/components/popover/popover.js +2 -1
  48. package/dist/styles.css +1 -1
  49. package/dist/utils/date.js +130 -22
  50. package/dist/utils/format/date.d.ts +1 -0
  51. package/dist/utils/format/date.js +11 -4
  52. package/package.json +3 -2
  53. package/dist/components/dashboard/filters/expression-filter-bar.d.ts +0 -42
  54. package/dist/components/dashboard/filters/expression-filter-bar.js +0 -80
  55. package/dist/components/dashboard/filters/index.d.ts +0 -6
  56. package/dist/components/dashboard/filters/index.js +0 -5
@@ -2,10 +2,14 @@
2
2
  * Dashboard Context Provider
3
3
  *
4
4
  * Provides centralized state management for dashboard components including
5
- * search, filters, column visibility, time period, and sidebar navigation.
5
+ * search, filters, column visibility, time interval, and sidebar navigation.
6
6
  */
7
+ import type { IntervalSelection } from '../../../components/interval-selector';
7
8
  import { type ReactNode } from 'react';
8
- import type { DashboardState, FilterOption, ResourceType, TimePeriod, ViewColumn } from './types';
9
+ import type { DashboardState, FilterOption, ResourceType, ResourceTypeOption, ViewColumn } from './types';
10
+ export declare const RESOURCE_TYPES: Array<ResourceType>;
11
+ export declare const RESOURCE_TYPE_LABELS: Record<ResourceType, string>;
12
+ export declare const RESOURCE_TYPE_OPTIONS: ResourceTypeOption[];
9
13
  export interface DashboardProviderProps {
10
14
  children: ReactNode;
11
15
  /**
@@ -19,10 +23,10 @@ export interface DashboardProviderProps {
19
23
  */
20
24
  initialFilters?: FilterOption[];
21
25
  /**
22
- * Initial time period
23
- * @default '2days'
26
+ * Initial time interval selection
27
+ * @default { type: 'relative', duration: {days: 7} }
24
28
  */
25
- initialTimePeriod?: TimePeriod;
29
+ initialSelection?: IntervalSelection;
26
30
  /**
27
31
  * Initial active sidebar item
28
32
  * @default 'reliability'
@@ -30,7 +34,7 @@ export interface DashboardProviderProps {
30
34
  initialActiveSidebarItem?: string;
31
35
  /**
32
36
  * Initial resource type
33
- * @default 'ci-pipeline'
37
+ * @default 'ci.pipeline'
34
38
  */
35
39
  initialResourceType?: ResourceType;
36
40
  /**
@@ -46,12 +50,12 @@ export interface DashboardProviderProps {
46
50
  *
47
51
  * @example
48
52
  * ```tsx
49
- * <DashboardProvider initialTimePeriod="7days">
53
+ * <DashboardProvider initialInterval={intervalToNowFromDuration({days: 7})}>
50
54
  * <AnalyticsContent />
51
55
  * </DashboardProvider>
52
56
  * ```
53
57
  */
54
- export declare function DashboardProvider({ children, initialColumns, initialFilters, initialTimePeriod, initialActiveSidebarItem, initialResourceType, columnMapping, }: DashboardProviderProps): import("react/jsx-runtime").JSX.Element;
58
+ export declare function DashboardProvider({ children, initialColumns, initialFilters, initialSelection, initialActiveSidebarItem, initialResourceType, columnMapping, }: DashboardProviderProps): import("react/jsx-runtime").JSX.Element;
55
59
  /**
56
60
  * Hook to access dashboard context
57
61
  *
@@ -2,7 +2,7 @@
2
2
  * Dashboard Context Provider
3
3
  *
4
4
  * Provides centralized state management for dashboard components including
5
- * search, filters, column visibility, time period, and sidebar navigation.
5
+ * search, filters, column visibility, time interval, and sidebar navigation.
6
6
  */ import { jsx as _jsx } from "react/jsx-runtime";
7
7
  import { createContext, useCallback, useContext, useMemo, useState } from 'react';
8
8
  import { updateViewColumnsFromVisibility, viewColumnsToVisibilityState } from './utils.js';
@@ -85,6 +85,37 @@ const DashboardContext = /*#__PURE__*/ createContext(undefined);
85
85
  checked: false
86
86
  }
87
87
  ];
88
+ export const RESOURCE_TYPES = [
89
+ 'ci.pipeline',
90
+ 'ci.job',
91
+ 'ci.step',
92
+ 'test.run',
93
+ 'test.suite',
94
+ 'test.case'
95
+ ];
96
+ export const RESOURCE_TYPE_LABELS = {
97
+ 'ci.pipeline': 'CI Pipeline',
98
+ 'ci.job': 'CI Job',
99
+ 'ci.step': 'CI Step',
100
+ 'test.run': 'Test Run',
101
+ 'test.suite': 'Test Suite',
102
+ 'test.case': 'Test Case'
103
+ };
104
+ export const RESOURCE_TYPE_OPTIONS = [
105
+ ...RESOURCE_TYPES.map((type)=>({
106
+ id: type,
107
+ label: RESOURCE_TYPE_LABELS[type],
108
+ disabled: type.startsWith('test.')
109
+ }))
110
+ ];
111
+ /**
112
+ * Default selection (relative: last 7 days)
113
+ */ const DEFAULT_SELECTION = {
114
+ type: 'relative',
115
+ duration: {
116
+ days: 7
117
+ }
118
+ };
88
119
  /**
89
120
  * Dashboard Provider Component
90
121
  *
@@ -92,19 +123,22 @@ const DashboardContext = /*#__PURE__*/ createContext(undefined);
92
123
  *
93
124
  * @example
94
125
  * ```tsx
95
- * <DashboardProvider initialTimePeriod="7days">
126
+ * <DashboardProvider initialInterval={intervalToNowFromDuration({days: 7})}>
96
127
  * <AnalyticsContent />
97
128
  * </DashboardProvider>
98
129
  * ```
99
- */ export function DashboardProvider({ children, initialColumns = DEFAULT_COLUMNS, initialFilters = DEFAULT_FILTERS, initialTimePeriod = '2days', initialActiveSidebarItem = 'reliability', initialResourceType = 'ci-pipeline', columnMapping }) {
130
+ */ export function DashboardProvider({ children, initialColumns = DEFAULT_COLUMNS, initialFilters = DEFAULT_FILTERS, initialSelection = DEFAULT_SELECTION, initialActiveSidebarItem = 'reliability', initialResourceType = 'ci.pipeline', columnMapping }) {
100
131
  // State management
101
132
  const [searchQuery, setSearchQuery] = useState('');
102
- const [timePeriod, setTimePeriod] = useState(initialTimePeriod);
133
+ const [selection, setSelection] = useState(initialSelection);
103
134
  const [lastUpdated, setLastUpdated] = useState('13s ago');
104
135
  const [columns, setColumns] = useState(initialColumns);
105
136
  const [filters, setFilters] = useState(initialFilters);
106
137
  const [activeSidebarItem, setActiveSidebarItem] = useState(initialActiveSidebarItem);
107
138
  const [resourceType, setResourceType] = useState(initialResourceType);
139
+ const handleSelectionChange = useCallback((newSelection)=>{
140
+ setSelection(newSelection);
141
+ }, []);
108
142
  // Compute column visibility state
109
143
  const columnVisibility = useMemo(()=>viewColumnsToVisibilityState(columns, columnMapping), [
110
144
  columns,
@@ -121,8 +155,8 @@ const DashboardContext = /*#__PURE__*/ createContext(undefined);
121
155
  const value = useMemo(()=>({
122
156
  searchQuery,
123
157
  setSearchQuery,
124
- timePeriod,
125
- setTimePeriod,
158
+ selection,
159
+ setSelection: handleSelectionChange,
126
160
  lastUpdated,
127
161
  setLastUpdated,
128
162
  columns,
@@ -137,7 +171,8 @@ const DashboardContext = /*#__PURE__*/ createContext(undefined);
137
171
  setResourceType
138
172
  }), [
139
173
  searchQuery,
140
- timePeriod,
174
+ selection,
175
+ handleSelectionChange,
141
176
  lastUpdated,
142
177
  columns,
143
178
  columnVisibility,
@@ -2,7 +2,7 @@
2
2
  * Dashboard Context exports
3
3
  */
4
4
  export type { DashboardProviderProps } from './dashboard-context';
5
- export { DashboardProvider, useDashboardContext } from './dashboard-context';
6
- export type { DashboardState, FilterOption, ResourceType, TimePeriod, ViewColumn } from './types';
5
+ export { DashboardProvider, RESOURCE_TYPE_LABELS, RESOURCE_TYPE_OPTIONS, RESOURCE_TYPES, useDashboardContext, } from './dashboard-context';
6
+ export type { DashboardState, FilterOption, ResourceType, ResourceTypeOption, ViewColumn, } from './types';
7
7
  export { DEFAULT_COLUMN_ID_TO_ACCESSOR_KEY, updateViewColumnsFromVisibility, viewColumnsToVisibilityState, } from './utils';
8
8
  //# sourceMappingURL=index.d.ts.map
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Dashboard Context exports
3
- */ export { DashboardProvider, useDashboardContext } from './dashboard-context.js';
3
+ */ export { DashboardProvider, RESOURCE_TYPE_LABELS, RESOURCE_TYPE_OPTIONS, RESOURCE_TYPES, useDashboardContext } from './dashboard-context.js';
4
4
  export { DEFAULT_COLUMN_ID_TO_ACCESSOR_KEY, updateViewColumnsFromVisibility, viewColumnsToVisibilityState } from './utils.js';
5
5
 
6
6
  //# sourceMappingURL=index.js.map
@@ -2,6 +2,7 @@
2
2
  * Shared types for dashboard components
3
3
  */
4
4
  import type { VisibilityState } from '@tanstack/react-table';
5
+ import type { IntervalSelection } from '../../../components/interval-selector';
5
6
  /**
6
7
  * View column configuration for table visibility control
7
8
  */
@@ -18,22 +19,23 @@ export interface FilterOption {
18
19
  label: string;
19
20
  checked: boolean;
20
21
  }
21
- /**
22
- * Time period option
23
- */
24
- export type TimePeriod = '1hour' | '1day' | '2days' | '7days' | '30days';
22
+ export type ResourceType = 'ci.pipeline' | 'ci.job' | 'ci.step' | 'test.run' | 'test.suite' | 'test.case';
25
23
  /**
26
24
  * Resource type option
27
25
  */
28
- export type ResourceType = 'ci-pipeline' | 'ci-jobs' | 'ci-steps' | 'runners' | 'suite' | 'cases';
26
+ export interface ResourceTypeOption {
27
+ id: ResourceType;
28
+ label: string;
29
+ disabled?: boolean;
30
+ }
29
31
  /**
30
32
  * Dashboard context state
31
33
  */
32
34
  export interface DashboardState {
33
35
  searchQuery: string;
34
36
  setSearchQuery: (query: string) => void;
35
- timePeriod: TimePeriod;
36
- setTimePeriod: (period: TimePeriod) => void;
37
+ selection: IntervalSelection;
38
+ setSelection: (selection: IntervalSelection) => void;
37
39
  lastUpdated: string;
38
40
  setLastUpdated: (timestamp: string) => void;
39
41
  columns: ViewColumn[];
@@ -7,12 +7,10 @@ export type { MobileSidebarProps } from './components/mobile-sidebar';
7
7
  export { MobileSidebar } from './components/mobile-sidebar';
8
8
  export type { SidebarNavItem, SidebarProps } from './components/sidebar';
9
9
  export { defaultSidebarItems, Sidebar } from './components/sidebar';
10
- export type { DashboardProviderProps, DashboardState, FilterOption, ResourceType, TimePeriod, ViewColumn, } from './context';
11
- export { DashboardProvider, DEFAULT_COLUMN_ID_TO_ACCESSOR_KEY, updateViewColumnsFromVisibility, useDashboardContext, viewColumnsToVisibilityState, } from './context';
10
+ export type { DashboardProviderProps, DashboardState, FilterOption, ResourceType, ViewColumn, } from './context';
11
+ export { DashboardProvider, DEFAULT_COLUMN_ID_TO_ACCESSOR_KEY, RESOURCE_TYPE_OPTIONS, updateViewColumnsFromVisibility, useDashboardContext, viewColumnsToVisibilityState, } from './context';
12
12
  export type { DashboardProps } from './dashboard';
13
13
  export { Dashboard } from './dashboard';
14
- export type { ExpressionFilterBarProps, ResourceTypeOption } from './filters';
15
- export { ExpressionFilterBar } from './filters';
16
14
  export { AnalyticsPage, JobsPage } from './pages';
17
15
  export type { TableWrapperProps } from './table';
18
16
  export { TableWrapper } from './table';
@@ -3,9 +3,8 @@ export { DashboardAlert } from './components/dashboard-alert.js';
3
3
  export { KpiCard, KpiCardsGroup } from './components/kpi-card.js';
4
4
  export { MobileSidebar } from './components/mobile-sidebar.js';
5
5
  export { defaultSidebarItems, Sidebar } from './components/sidebar.js';
6
- export { DashboardProvider, DEFAULT_COLUMN_ID_TO_ACCESSOR_KEY, updateViewColumnsFromVisibility, useDashboardContext, viewColumnsToVisibilityState } from './context/index.js';
6
+ export { DashboardProvider, DEFAULT_COLUMN_ID_TO_ACCESSOR_KEY, RESOURCE_TYPE_OPTIONS, updateViewColumnsFromVisibility, useDashboardContext, viewColumnsToVisibilityState } from './context/index.js';
7
7
  export { Dashboard } from './dashboard.js';
8
- export { ExpressionFilterBar } from './filters/index.js';
9
8
  export { AnalyticsPage, JobsPage } from './pages/index.js';
10
9
  export { TableWrapper } from './table/index.js';
11
10
  export { FilterButton, PageToolbar, ToolbarActions, ToolbarSearch, ViewDropdown } from './toolbar/index.js';
@@ -15,7 +15,6 @@ import { KpiCardsGroup } from '../components/kpi-card.js';
15
15
  import { MobileSidebar } from '../components/mobile-sidebar.js';
16
16
  import { defaultSidebarItems, Sidebar } from '../components/sidebar.js';
17
17
  import { useDashboardContext } from '../context/index.js';
18
- import { ExpressionFilterBar } from '../filters/index.js';
19
18
  import { TableWrapper } from '../table/index.js';
20
19
  import { PageToolbar, ToolbarActions } from '../toolbar/index.js';
21
20
  const performanceData = [
@@ -147,7 +146,7 @@ const kpiCards = [
147
146
  }
148
147
  ];
149
148
  export function AnalyticsPage() {
150
- const { searchQuery, setSearchQuery, timePeriod, setTimePeriod, lastUpdated, columnVisibility, updateColumnVisibility, activeSidebarItem, setActiveSidebarItem, resourceType, setResourceType } = useDashboardContext();
149
+ const { searchQuery, setSearchQuery, columnVisibility, updateColumnVisibility, activeSidebarItem, setActiveSidebarItem } = useDashboardContext();
151
150
  const isDesktop = useMediaQuery('(min-width: 1024px)');
152
151
  const [performanceTimeRange, setPerformanceTimeRange] = useState('2h');
153
152
  const pageTitle = useMemo(()=>{
@@ -164,9 +163,7 @@ export function AnalyticsPage() {
164
163
  children: [
165
164
  /*#__PURE__*/ _jsx(PageToolbar, {
166
165
  title: pageTitle,
167
- timePeriod: timePeriod,
168
- onTimePeriodChange: setTimePeriod,
169
- lastUpdated: lastUpdated,
166
+ onRefresh: ()=>undefined,
170
167
  children: !isDesktop && /*#__PURE__*/ _jsx(MobileSidebar, {
171
168
  items: defaultSidebarItems,
172
169
  activeItemId: activeSidebarItem,
@@ -196,10 +193,6 @@ export function AnalyticsPage() {
196
193
  onClick: ()=>undefined
197
194
  }
198
195
  }),
199
- /*#__PURE__*/ _jsx(ExpressionFilterBar, {
200
- value: resourceType,
201
- onValueChange: setResourceType
202
- }),
203
196
  /*#__PURE__*/ _jsx(ToolbarActions, {}),
204
197
  /*#__PURE__*/ _jsx(KpiCardsGroup, {
205
198
  cards: kpiCards
@@ -9,7 +9,7 @@ import { useDashboardContext } from '../context/index.js';
9
9
  import { TableWrapper } from '../table/index.js';
10
10
  import { PageToolbar } from '../toolbar/index.js';
11
11
  export function JobsPage() {
12
- const { searchQuery, setSearchQuery, timePeriod, setTimePeriod, lastUpdated, columnVisibility, updateColumnVisibility } = useDashboardContext();
12
+ const { searchQuery, setSearchQuery, columnVisibility, updateColumnVisibility } = useDashboardContext();
13
13
  const filteredData = useMemo(()=>jobsData.filter((job)=>job.name.toLowerCase().includes(searchQuery.toLowerCase())), [
14
14
  searchQuery
15
15
  ]);
@@ -18,9 +18,7 @@ export function JobsPage() {
18
18
  children: [
19
19
  /*#__PURE__*/ _jsx(PageToolbar, {
20
20
  title: "Jobs",
21
- timePeriod: timePeriod,
22
- onTimePeriodChange: setTimePeriod,
23
- lastUpdated: lastUpdated
21
+ onRefresh: ()=>undefined
24
22
  }),
25
23
  /*#__PURE__*/ _jsx("div", {
26
24
  className: "flex-1 px-12 pb-12 pt-4 md:px-24 md:pb-24 overflow-auto",
@@ -1,12 +1,8 @@
1
- export interface FilterOption {
2
- id: string;
3
- label: string;
4
- checked: boolean;
1
+ import type { HTMLAttributes } from 'react';
2
+ import type { ResourceType } from '../context/types';
3
+ export interface FilterButtonProps extends HTMLAttributes<HTMLButtonElement> {
4
+ value: ResourceType;
5
+ onValueChange: (value: ResourceType) => void;
5
6
  }
6
- export interface FilterButtonProps {
7
- filters?: FilterOption[];
8
- onFiltersChange?: (filters: FilterOption[]) => void;
9
- className?: string;
10
- }
11
- export declare function FilterButton({ filters: controlledFilters, onFiltersChange, className, }: FilterButtonProps): import("react/jsx-runtime").JSX.Element;
7
+ export declare function FilterButton({ value, onValueChange, className, ...props }: FilterButtonProps): import("react/jsx-runtime").JSX.Element;
12
8
  //# sourceMappingURL=filter-button.d.ts.map
@@ -1,73 +1,66 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { Button } from '../../../components/button/index.js';
3
- import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger } from '../../../components/dropdown-menu/index.js';
4
- import { Icon } from '../../../components/icon/index.js';
3
+ import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuTrigger } from '../../../components/dropdown-menu/index.js';
5
4
  import { Kbd } from '../../../components/kbd/index.js';
6
5
  import { useEffect, useState } from 'react';
7
6
  import { cn } from '../../../utils/cn.js';
8
- const defaultFilters = [
9
- {
10
- id: 'success',
11
- label: 'Success',
12
- checked: false
13
- },
14
- {
15
- id: 'failed',
16
- label: 'Failed',
17
- checked: false
18
- },
19
- {
20
- id: 'neutral',
21
- label: 'Neutral',
22
- checked: false
23
- },
24
- {
25
- id: 'flaked',
26
- label: 'Flaked',
27
- checked: false
28
- },
29
- {
30
- id: 'running',
31
- label: 'Running',
32
- checked: false
33
- }
34
- ];
35
- export function FilterButton({ filters: controlledFilters, onFiltersChange, className }) {
36
- const [internalFilters, setInternalFilters] = useState(defaultFilters);
7
+ import { RESOURCE_TYPE_LABELS, RESOURCE_TYPE_OPTIONS } from '../context/index.js';
8
+ export function FilterButton({ value, onValueChange, className, ...props }) {
37
9
  const [open, setOpen] = useState(false);
38
- const filters = controlledFilters ?? internalFilters;
39
- const handleFilterChange = (filterId, checked)=>{
40
- const updatedFilters = filters.map((f)=>f.id === filterId ? {
41
- ...f,
42
- checked
43
- } : f);
44
- if (onFiltersChange) {
45
- onFiltersChange(updatedFilters);
46
- } else {
47
- setInternalFilters(updatedFilters);
10
+ const filterOptions = RESOURCE_TYPE_OPTIONS.filter((opt)=>!opt.disabled);
11
+ const normalizedValue = filterOptions.some((opt)=>opt.id === value) ? value : filterOptions[0]?.id ?? value;
12
+ const selectedLabel = RESOURCE_TYPE_LABELS[normalizedValue] ?? normalizedValue;
13
+ const selectedIndex = filterOptions.findIndex((opt)=>opt.id === normalizedValue);
14
+ const handleFilterChange = (filterId)=>{
15
+ onValueChange(filterId);
16
+ setOpen(false);
17
+ };
18
+ const indicator = (index)=>{
19
+ if (index === 0) {
20
+ return /*#__PURE__*/ _jsx("span", {
21
+ className: "size-[8.3px] rotate-45 border border-tag-purple-icon"
22
+ });
23
+ }
24
+ return /*#__PURE__*/ _jsx("span", {
25
+ className: "size-10 rounded-full border border-tag-neutral-icon"
26
+ });
27
+ };
28
+ const calculatePaddingLeft = (index)=>{
29
+ switch(index){
30
+ case 0:
31
+ return 10;
32
+ case 1:
33
+ return 28;
34
+ case 2:
35
+ return 48;
36
+ default:
37
+ return 0;
38
+ }
39
+ };
40
+ const calculateLeftPosition = (index)=>{
41
+ switch(index){
42
+ case 0:
43
+ return 0;
44
+ case 1:
45
+ return 16;
46
+ case 2:
47
+ return 34;
48
+ default:
49
+ return 0;
48
50
  }
49
51
  };
50
- const activeCount = filters.filter((f)=>f.checked).length;
51
- // Keyboard shortcut handler for "F" key
52
52
  useEffect(()=>{
53
53
  const handleKeyDown = (event)=>{
54
- // Check if key is 'f' or 'F'
55
- if (event.key !== 'f' && event.key !== 'F') {
56
- return;
57
- }
58
- // Ignore if event is from input, textarea, or contentEditable
59
- const target = event.target;
60
- if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) {
61
- return;
54
+ if (event.key === 'ArrowDown' && (event.metaKey || event.ctrlKey) && event.target instanceof HTMLElement && ![
55
+ 'INPUT',
56
+ 'TEXTAREA'
57
+ ].includes(event.target.tagName) && !event.target.isContentEditable) {
58
+ event.preventDefault();
59
+ setOpen(true);
62
60
  }
63
- // Open the dropdown
64
- event.preventDefault();
65
- setOpen(true);
66
61
  };
67
62
  window.addEventListener('keydown', handleKeyDown);
68
- return ()=>{
69
- window.removeEventListener('keydown', handleKeyDown);
70
- };
63
+ return ()=>window.removeEventListener('keydown', handleKeyDown);
71
64
  }, []);
72
65
  return /*#__PURE__*/ _jsxs(DropdownMenu, {
73
66
  open: open,
@@ -78,25 +71,35 @@ export function FilterButton({ filters: controlledFilters, onFiltersChange, clas
78
71
  children: /*#__PURE__*/ _jsxs(Button, {
79
72
  variant: "secondary",
80
73
  size: "sm",
81
- className: cn(className),
74
+ className: cn('px-10', className),
75
+ ...props,
82
76
  children: [
83
- /*#__PURE__*/ _jsx(Icon, {
84
- name: "filterLine",
85
- className: "size-16 text-foreground-neutral-subtle block md:hidden"
86
- }),
87
77
  /*#__PURE__*/ _jsxs("span", {
88
78
  className: "hidden md:inline-flex items-center gap-6",
89
79
  children: [
90
- "Filter ",
80
+ /*#__PURE__*/ _jsxs("span", {
81
+ className: "inline-flex items-center gap-8",
82
+ children: [
83
+ selectedIndex >= 0 && indicator(selectedIndex),
84
+ /*#__PURE__*/ _jsx("span", {
85
+ children: selectedLabel
86
+ })
87
+ ]
88
+ }),
91
89
  /*#__PURE__*/ _jsx(Kbd, {
92
90
  className: "h-16 min-w-16 px-4 text-[10px]",
93
- children: "F"
91
+ children: "⌘↓"
94
92
  })
95
93
  ]
96
94
  }),
97
- activeCount > 0 && /*#__PURE__*/ _jsx("span", {
98
- className: "size-16 rounded-full bg-foreground-highlight-interactive text-[10px] font-medium text-foreground-neutral-on-color flex items-center justify-center",
99
- children: activeCount
95
+ /*#__PURE__*/ _jsxs("span", {
96
+ className: "flex md:hidden items-center gap-8",
97
+ children: [
98
+ selectedIndex >= 0 && indicator(selectedIndex),
99
+ /*#__PURE__*/ _jsx("span", {
100
+ children: selectedLabel
101
+ })
102
+ ]
100
103
  })
101
104
  ]
102
105
  })
@@ -106,15 +109,45 @@ export function FilterButton({ filters: controlledFilters, onFiltersChange, clas
106
109
  className: "w-200",
107
110
  children: [
108
111
  /*#__PURE__*/ _jsx(DropdownMenuLabel, {
109
- children: "Status"
112
+ className: "text-foreground-neutral-muted text-xs",
113
+ children: "CI Structure"
110
114
  }),
111
- /*#__PURE__*/ _jsx(DropdownMenuSeparator, {}),
112
- filters.map((filter)=>/*#__PURE__*/ _jsx(DropdownMenuCheckboxItem, {
113
- checked: filter.checked,
114
- onCheckedChange: (checked)=>handleFilterChange(filter.id, checked),
115
- closeOnSelect: false,
116
- children: filter.label
117
- }, filter.id))
115
+ /*#__PURE__*/ _jsx(DropdownMenuGroup, {
116
+ children: filterOptions.map((option, index)=>{
117
+ return /*#__PURE__*/ _jsxs(DropdownMenuItem, {
118
+ onClick: ()=>handleFilterChange(option.id),
119
+ style: {
120
+ paddingLeft: calculatePaddingLeft(index)
121
+ },
122
+ className: cn('relative hover:text-foreground-neutral-base', selectedIndex === index && 'text-foreground-neutral-base'),
123
+ children: [
124
+ index !== 0 && /*#__PURE__*/ _jsxs(_Fragment, {
125
+ children: [
126
+ /*#__PURE__*/ _jsx("span", {
127
+ className: "absolute top-0 bottom-0 w-px bg-border-neutral-strong h-16",
128
+ style: {
129
+ left: calculateLeftPosition(index)
130
+ }
131
+ }),
132
+ /*#__PURE__*/ _jsx("span", {
133
+ className: "absolute top-16 bottom-0 w-6 bg-border-neutral-strong h-px",
134
+ style: {
135
+ left: calculateLeftPosition(index)
136
+ }
137
+ })
138
+ ]
139
+ }),
140
+ /*#__PURE__*/ _jsxs("span", {
141
+ className: "inline-flex items-center gap-8 ml-2",
142
+ children: [
143
+ indicator(index),
144
+ option.label
145
+ ]
146
+ })
147
+ ]
148
+ }, option.id);
149
+ })
150
+ })
118
151
  ]
119
152
  })
120
153
  ]
@@ -5,26 +5,11 @@
5
5
  * time period selector, and playback controls.
6
6
  */
7
7
  import type { ComponentProps, ReactNode } from 'react';
8
- import type { TimePeriod } from '../context';
9
8
  export interface PageToolbarProps extends Omit<ComponentProps<'div'>, 'title' | 'children'> {
10
9
  /**
11
10
  * The title to display in the toolbar header
12
11
  */
13
12
  title: ReactNode;
14
- /**
15
- * Last updated timestamp text
16
- * @default '13s ago'
17
- */
18
- lastUpdated?: string;
19
- /**
20
- * Current time period value
21
- * @default '2days'
22
- */
23
- timePeriod?: TimePeriod;
24
- /**
25
- * Callback when time period changes
26
- */
27
- onTimePeriodChange?: (value: TimePeriod) => void;
28
13
  /**
29
14
  * Callback when refresh button is clicked
30
15
  */
@@ -54,22 +39,25 @@ export interface PageToolbarProps extends Omit<ComponentProps<'div'>, 'title' |
54
39
  * Children to render (e.g., mobile menu button)
55
40
  */
56
41
  children?: ReactNode;
42
+ /**
43
+ * Custom container for the interval selector popover
44
+ */
45
+ intervalSelectorContainer?: HTMLElement | null;
57
46
  }
58
47
  /**
59
48
  * Generic Page Toolbar
60
49
  *
61
50
  * A flexible toolbar component that can be used across different dashboard pages.
62
- * Supports title customization, time period selection, refresh indicator, and playback controls.
51
+ * Supports title customization, time interval selection, refresh indicator, and playback controls.
52
+ * Uses DashboardContext for interval state management.
63
53
  *
64
54
  * @example
65
55
  * ```tsx
66
56
  * <PageToolbar
67
57
  * title="Analytics"
68
- * timePeriod="2days"
69
- * onTimePeriodChange={setTimePeriod}
70
58
  * onRefresh={handleRefresh}
71
59
  * />
72
60
  * ```
73
61
  */
74
- export declare function PageToolbar({ title, lastUpdated, timePeriod, onTimePeriodChange, onRefresh, showPlaybackControls, onRewind, onPlay, onSpeed, actions, children, className, ...props }: PageToolbarProps): import("react/jsx-runtime").JSX.Element;
62
+ export declare function PageToolbar({ title, onRefresh, showPlaybackControls, onRewind, onPlay, onSpeed, actions, children, intervalSelectorContainer, className, ...props }: PageToolbarProps): import("react/jsx-runtime").JSX.Element;
75
63
  //# sourceMappingURL=page-toolbar.d.ts.map