@shipfox/react-ui 0.17.0 → 0.18.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/dist/components/count-up/count-up.d.ts +14 -0
- package/dist/components/count-up/count-up.js +98 -0
- package/dist/components/count-up/count-up.stories.js +568 -0
- package/dist/components/count-up/index.d.ts +2 -0
- package/dist/components/count-up/index.js +3 -0
- package/dist/components/dashboard/components/kpi-card.d.ts +8 -9
- package/dist/components/dashboard/components/kpi-card.js +26 -44
- package/dist/components/dashboard/index.d.ts +1 -6
- package/dist/components/dashboard/index.js +0 -11
- package/dist/components/dashboard/pages/analytics-page.d.ts +0 -18
- package/dist/components/dashboard/pages/analytics-page.js +83 -37
- package/dist/components/dashboard/pages/jobs-page.d.ts +0 -18
- package/dist/components/dashboard/pages/jobs-page.js +27 -24
- package/dist/components/dashboard/table/table-wrapper.d.ts +21 -24
- package/dist/components/dashboard/table/table-wrapper.js +38 -51
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.js +1 -0
- package/dist/components/item/item.stories.js +3 -3
- package/dist/components/table/data-table.d.ts +8 -1
- package/dist/components/table/data-table.js +5 -4
- package/dist/components/table/table-column-header.d.ts +14 -1
- package/dist/components/table/table-column-header.js +12 -5
- package/dist/components/table/table-pagination.d.ts +14 -1
- package/dist/components/table/table-pagination.js +6 -2
- package/dist/components/table/table.js +3 -3
- package/dist/styles.css +1 -1
- package/package.json +3 -3
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
1
|
+
import type { ComponentProps, ReactNode } from 'react';
|
|
2
|
+
export type KpiVariant = 'neutral' | 'success' | 'warning' | 'error' | 'info' | 'purple';
|
|
3
|
+
export interface KpiCardProps extends Omit<ComponentProps<'div'>, 'title'> {
|
|
3
4
|
label: string;
|
|
4
|
-
value: string | number;
|
|
5
|
+
value: string | number | ReactNode;
|
|
5
6
|
variant?: KpiVariant;
|
|
6
|
-
|
|
7
|
+
isLoading?: boolean;
|
|
7
8
|
}
|
|
8
|
-
export declare function KpiCard({ label, value, variant, className }: KpiCardProps): import("react/jsx-runtime").JSX.Element;
|
|
9
|
-
export interface KpiCardsGroupProps {
|
|
9
|
+
export declare function KpiCard({ label, value, variant, isLoading, className, ...props }: KpiCardProps): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export interface KpiCardsGroupProps extends ComponentProps<'div'> {
|
|
10
11
|
cards: KpiCardProps[];
|
|
11
|
-
className?: string;
|
|
12
12
|
}
|
|
13
|
-
export declare function KpiCardsGroup({ cards, className }: KpiCardsGroupProps): import("react/jsx-runtime").JSX.Element;
|
|
14
|
-
export declare const defaultKpiCards: KpiCardProps[];
|
|
13
|
+
export declare function KpiCardsGroup({ cards, className, ...props }: KpiCardsGroupProps): import("react/jsx-runtime").JSX.Element;
|
|
15
14
|
//# sourceMappingURL=kpi-card.d.ts.map
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Card } from '../../../components/card/index.js';
|
|
3
|
+
import { Skeleton } from '../../../components/skeleton/index.js';
|
|
2
4
|
import { Text } from '../../../components/typography/index.js';
|
|
3
5
|
import { cn } from '../../../utils/cn.js';
|
|
4
6
|
const variantDotStyles = {
|
|
@@ -6,23 +8,28 @@ const variantDotStyles = {
|
|
|
6
8
|
success: 'bg-green-500',
|
|
7
9
|
warning: 'bg-orange-500',
|
|
8
10
|
error: 'bg-red-500',
|
|
9
|
-
info: 'bg-blue-500'
|
|
11
|
+
info: 'bg-blue-500',
|
|
12
|
+
purple: 'bg-purple-500'
|
|
10
13
|
};
|
|
11
|
-
export function KpiCard({ label, value, variant = 'neutral', className }) {
|
|
12
|
-
return /*#__PURE__*/ _jsxs(
|
|
13
|
-
className: cn('flex flex-col gap-4 p-12
|
|
14
|
+
export function KpiCard({ label, value, variant = 'neutral', isLoading, className, ...props }) {
|
|
15
|
+
return /*#__PURE__*/ _jsxs(Card, {
|
|
16
|
+
className: cn('flex flex-col gap-4 p-12 min-w-120 flex-1', className),
|
|
17
|
+
...props,
|
|
14
18
|
children: [
|
|
15
|
-
/*#__PURE__*/ _jsx(
|
|
16
|
-
|
|
19
|
+
/*#__PURE__*/ _jsx(Text, {
|
|
20
|
+
size: "xs",
|
|
21
|
+
className: "text-foreground-neutral-subtle",
|
|
17
22
|
children: label
|
|
18
23
|
}),
|
|
19
24
|
/*#__PURE__*/ _jsxs("div", {
|
|
20
25
|
className: "flex items-center gap-6",
|
|
21
26
|
children: [
|
|
22
27
|
/*#__PURE__*/ _jsx("span", {
|
|
23
|
-
className: cn('size-8 rounded-2
|
|
28
|
+
className: cn('shrink-0 size-8 rounded-2', variantDotStyles[variant])
|
|
24
29
|
}),
|
|
25
|
-
/*#__PURE__*/ _jsx(
|
|
30
|
+
isLoading ? /*#__PURE__*/ _jsx(Skeleton, {
|
|
31
|
+
className: "w-48 h-20 rounded-4"
|
|
32
|
+
}) : /*#__PURE__*/ _jsx(Text, {
|
|
26
33
|
size: "sm",
|
|
27
34
|
className: "font-medium text-foreground-neutral-base",
|
|
28
35
|
children: value
|
|
@@ -32,46 +39,21 @@ export function KpiCard({ label, value, variant = 'neutral', className }) {
|
|
|
32
39
|
]
|
|
33
40
|
});
|
|
34
41
|
}
|
|
35
|
-
export function KpiCardsGroup({ cards, className }) {
|
|
42
|
+
export function KpiCardsGroup({ cards, className, ...props }) {
|
|
36
43
|
return /*#__PURE__*/ _jsx("div", {
|
|
37
|
-
className: cn(
|
|
38
|
-
|
|
39
|
-
'overflow-x-auto scrollbar-none pb-4 md:pb-0', // Scroll snap for smooth swiping
|
|
40
|
-
'snap-x snap-mandatory', // Hide scrollbar but allow scrolling
|
|
41
|
-
'[&::-webkit-scrollbar]:hidden', // Smooth scrolling
|
|
42
|
-
'scroll-smooth', className),
|
|
44
|
+
className: cn('flex gap-12 md:gap-16 overflow-x-auto pb-4 md:pb-0 snap-x snap-mandatory [&::-webkit-scrollbar]:hidden [-ms-overflow-style:none] [scrollbar-width:none] scroll-smooth', className),
|
|
45
|
+
...props,
|
|
43
46
|
children: /*#__PURE__*/ _jsx("div", {
|
|
44
|
-
className: "flex gap-16 pl-
|
|
45
|
-
children: cards.map((card, index)
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
'md:flex-1')
|
|
50
|
-
}, `${card.label}-${index}`)
|
|
47
|
+
className: "flex gap-16 pl-0 w-full",
|
|
48
|
+
children: cards.map((card, index)=>{
|
|
49
|
+
const { key: _key, ...cardProps } = card;
|
|
50
|
+
return /*#__PURE__*/ _jsx(KpiCard, {
|
|
51
|
+
...cardProps,
|
|
52
|
+
className: cn('shrink-0 w-[calc((100vw-56px)/2)] snap-start md:flex-1 md:w-0', card.className)
|
|
53
|
+
}, `${card.label}-${index}`);
|
|
54
|
+
})
|
|
51
55
|
})
|
|
52
56
|
});
|
|
53
57
|
}
|
|
54
|
-
export const defaultKpiCards = [
|
|
55
|
-
{
|
|
56
|
-
label: 'Total',
|
|
57
|
-
value: '1211',
|
|
58
|
-
variant: 'neutral'
|
|
59
|
-
},
|
|
60
|
-
{
|
|
61
|
-
label: 'Success',
|
|
62
|
-
value: '1200',
|
|
63
|
-
variant: 'success'
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
label: 'Neutral',
|
|
67
|
-
value: '11',
|
|
68
|
-
variant: 'neutral'
|
|
69
|
-
},
|
|
70
|
-
{
|
|
71
|
-
label: 'Failure rate',
|
|
72
|
-
value: '0%',
|
|
73
|
-
variant: 'success'
|
|
74
|
-
}
|
|
75
|
-
];
|
|
76
58
|
|
|
77
59
|
//# sourceMappingURL=kpi-card.js.map
|
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Dashboard Component Exports
|
|
3
|
-
*
|
|
4
|
-
* Comprehensive export file for all dashboard-related components and utilities.
|
|
5
|
-
*/
|
|
6
1
|
export type { BarChartProps, ChartColor, LineChartProps } from './components/charts';
|
|
7
2
|
export { BarChart, LineChart } from './components/charts';
|
|
8
3
|
export { DashboardAlert } from './components/dashboard-alert';
|
|
9
|
-
export type { KpiCardProps } from './components/kpi-card';
|
|
4
|
+
export type { KpiCardProps, KpiCardsGroupProps, KpiVariant } from './components/kpi-card';
|
|
10
5
|
export { KpiCard, KpiCardsGroup } from './components/kpi-card';
|
|
11
6
|
export type { MobileSidebarProps } from './components/mobile-sidebar';
|
|
12
7
|
export { MobileSidebar } from './components/mobile-sidebar';
|
|
@@ -1,24 +1,13 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Dashboard Component Exports
|
|
3
|
-
*
|
|
4
|
-
* Comprehensive export file for all dashboard-related components and utilities.
|
|
5
|
-
*/ // Chart Components
|
|
6
1
|
export { BarChart, LineChart } from './components/charts/index.js';
|
|
7
|
-
// Shared Components
|
|
8
2
|
export { DashboardAlert } from './components/dashboard-alert.js';
|
|
9
3
|
export { KpiCard, KpiCardsGroup } from './components/kpi-card.js';
|
|
10
4
|
export { MobileSidebar } from './components/mobile-sidebar.js';
|
|
11
5
|
export { defaultSidebarItems, Sidebar } from './components/sidebar.js';
|
|
12
|
-
// Context API
|
|
13
6
|
export { DashboardProvider, DEFAULT_COLUMN_ID_TO_ACCESSOR_KEY, updateViewColumnsFromVisibility, useDashboardContext, viewColumnsToVisibilityState } from './context/index.js';
|
|
14
|
-
// Main Dashboard Component
|
|
15
7
|
export { Dashboard } from './dashboard.js';
|
|
16
|
-
// Filter Components
|
|
17
8
|
export { ExpressionFilterBar } from './filters/index.js';
|
|
18
|
-
// Page Components
|
|
19
9
|
export { AnalyticsPage, JobsPage } from './pages/index.js';
|
|
20
10
|
export { TableWrapper } from './table/index.js';
|
|
21
|
-
// Generic Reusable Components
|
|
22
11
|
export { FilterButton, PageToolbar, ToolbarActions, ToolbarSearch, ViewDropdown } from './toolbar/index.js';
|
|
23
12
|
|
|
24
13
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,20 +1,2 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Analytics Page Component
|
|
3
|
-
*
|
|
4
|
-
* Refactored analytics page using DashboardContext and generic components.
|
|
5
|
-
*/
|
|
6
|
-
/**
|
|
7
|
-
* Analytics Page
|
|
8
|
-
*
|
|
9
|
-
* Main analytics page with KPI cards, charts, and jobs table.
|
|
10
|
-
* Uses DashboardContext for state management and generic reusable components.
|
|
11
|
-
*
|
|
12
|
-
* @example
|
|
13
|
-
* ```tsx
|
|
14
|
-
* <DashboardProvider>
|
|
15
|
-
* <AnalyticsPage />
|
|
16
|
-
* </DashboardProvider>
|
|
17
|
-
* ```
|
|
18
|
-
*/
|
|
19
1
|
export declare function AnalyticsPage(): import("react/jsx-runtime").JSX.Element;
|
|
20
2
|
//# sourceMappingURL=analytics-page.d.ts.map
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { Button } from '../../../components/button/index.js';
|
|
3
|
+
import { CountUp } from '../../../components/count-up/count-up.js';
|
|
4
|
+
import { Icon } from '../../../components/icon/index.js';
|
|
5
|
+
import { SearchInline } from '../../../components/search/search-inline.js';
|
|
6
|
+
import { jobColumns } from '../../../components/table/table.stories.columns.js';
|
|
7
7
|
import { jobsData } from '../../../components/table/table.stories.data.js';
|
|
8
8
|
import { useMediaQuery } from '../../../hooks/useMediaQuery.js';
|
|
9
9
|
import { useMemo } from 'react';
|
|
@@ -17,7 +17,6 @@ import { useDashboardContext } from '../context/index.js';
|
|
|
17
17
|
import { ExpressionFilterBar } from '../filters/index.js';
|
|
18
18
|
import { TableWrapper } from '../table/index.js';
|
|
19
19
|
import { PageToolbar, ToolbarActions } from '../toolbar/index.js';
|
|
20
|
-
// Sample data for the performance chart
|
|
21
20
|
const performanceData = [
|
|
22
21
|
{
|
|
23
22
|
label: '1',
|
|
@@ -62,7 +61,6 @@ const performanceData = [
|
|
|
62
61
|
dataD: 160
|
|
63
62
|
}
|
|
64
63
|
];
|
|
65
|
-
// Generate sample data for duration distribution
|
|
66
64
|
function generateDurationData() {
|
|
67
65
|
const count = 40;
|
|
68
66
|
const data = [];
|
|
@@ -77,54 +75,85 @@ function generateDurationData() {
|
|
|
77
75
|
return data;
|
|
78
76
|
}
|
|
79
77
|
const durationData = generateDurationData();
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
78
|
+
const KPI_VALUE_REGEX = /^([^\d]*)([\d.,]+)([^\d]*)$/;
|
|
79
|
+
function parseKpiValue(value) {
|
|
80
|
+
if (typeof value === 'number') {
|
|
81
|
+
return {
|
|
82
|
+
prefix: '',
|
|
83
|
+
numericValue: value,
|
|
84
|
+
suffix: '',
|
|
85
|
+
isNumeric: true
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
const match = value.match(KPI_VALUE_REGEX);
|
|
89
|
+
if (match) {
|
|
90
|
+
const [, prefix, numericStr, suffix] = match;
|
|
91
|
+
const numericValue = parseFloat(numericStr.replace(/,/g, ''));
|
|
92
|
+
if (!Number.isNaN(numericValue)) {
|
|
93
|
+
return {
|
|
94
|
+
prefix,
|
|
95
|
+
numericValue,
|
|
96
|
+
suffix,
|
|
97
|
+
isNumeric: true
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
prefix: '',
|
|
103
|
+
numericValue: 0,
|
|
104
|
+
suffix: '',
|
|
105
|
+
isNumeric: false
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function renderKpiValue(value) {
|
|
109
|
+
const parsed = parseKpiValue(value);
|
|
110
|
+
if (parsed.isNumeric) {
|
|
111
|
+
return /*#__PURE__*/ _jsxs(_Fragment, {
|
|
112
|
+
children: [
|
|
113
|
+
parsed.prefix,
|
|
114
|
+
/*#__PURE__*/ _jsx(CountUp, {
|
|
115
|
+
to: parsed.numericValue,
|
|
116
|
+
from: 0,
|
|
117
|
+
duration: 0.5,
|
|
118
|
+
className: "inline"
|
|
119
|
+
}),
|
|
120
|
+
parsed.suffix
|
|
121
|
+
]
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
return value;
|
|
125
|
+
}
|
|
126
|
+
const kpiCards = [
|
|
83
127
|
{
|
|
84
128
|
label: 'Total',
|
|
85
|
-
value: '1211',
|
|
86
|
-
variant: '
|
|
129
|
+
value: renderKpiValue('1211'),
|
|
130
|
+
variant: 'info'
|
|
87
131
|
},
|
|
88
132
|
{
|
|
89
133
|
label: 'Success',
|
|
90
|
-
value: '1200',
|
|
134
|
+
value: renderKpiValue('1200'),
|
|
91
135
|
variant: 'success'
|
|
92
136
|
},
|
|
93
137
|
{
|
|
94
138
|
label: 'Neutral',
|
|
95
|
-
value: '11',
|
|
139
|
+
value: renderKpiValue('11'),
|
|
96
140
|
variant: 'neutral'
|
|
97
141
|
},
|
|
98
142
|
{
|
|
99
143
|
label: 'Failure rate',
|
|
100
|
-
value: '0%',
|
|
144
|
+
value: renderKpiValue('0%'),
|
|
101
145
|
variant: 'success'
|
|
102
146
|
}
|
|
103
147
|
];
|
|
104
|
-
|
|
105
|
-
* Analytics Page
|
|
106
|
-
*
|
|
107
|
-
* Main analytics page with KPI cards, charts, and jobs table.
|
|
108
|
-
* Uses DashboardContext for state management and generic reusable components.
|
|
109
|
-
*
|
|
110
|
-
* @example
|
|
111
|
-
* ```tsx
|
|
112
|
-
* <DashboardProvider>
|
|
113
|
-
* <AnalyticsPage />
|
|
114
|
-
* </DashboardProvider>
|
|
115
|
-
* ```
|
|
116
|
-
*/ export function AnalyticsPage() {
|
|
148
|
+
export function AnalyticsPage() {
|
|
117
149
|
const { searchQuery, setSearchQuery, timePeriod, setTimePeriod, lastUpdated, columnVisibility, updateColumnVisibility, activeSidebarItem, setActiveSidebarItem, resourceType, setResourceType } = useDashboardContext();
|
|
118
|
-
// Responsive breakpoints
|
|
119
150
|
const isDesktop = useMediaQuery('(min-width: 1024px)');
|
|
120
|
-
// Get the active sidebar item label for the title
|
|
121
151
|
const pageTitle = useMemo(()=>{
|
|
122
152
|
const activeItem = defaultSidebarItems.find((item)=>item.id === activeSidebarItem);
|
|
123
|
-
return activeItem?.label || 'Reliability';
|
|
153
|
+
return activeItem?.label || 'Reliability';
|
|
124
154
|
}, [
|
|
125
155
|
activeSidebarItem
|
|
126
156
|
]);
|
|
127
|
-
// Filter data based on search query
|
|
128
157
|
const filteredData = useMemo(()=>jobsData.filter((job)=>job.name.toLowerCase().includes(searchQuery.toLowerCase())), [
|
|
129
158
|
searchQuery
|
|
130
159
|
]);
|
|
@@ -143,7 +172,7 @@ const durationData = generateDurationData();
|
|
|
143
172
|
})
|
|
144
173
|
}),
|
|
145
174
|
/*#__PURE__*/ _jsxs("div", {
|
|
146
|
-
className: "flex flex-1 overflow-hidden
|
|
175
|
+
className: "flex flex-1 overflow-hidden",
|
|
147
176
|
children: [
|
|
148
177
|
isDesktop && /*#__PURE__*/ _jsx(Sidebar, {
|
|
149
178
|
items: defaultSidebarItems,
|
|
@@ -241,9 +270,26 @@ const durationData = generateDurationData();
|
|
|
241
270
|
title: "Analytics breakdown",
|
|
242
271
|
columns: jobColumns,
|
|
243
272
|
data: filteredData,
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
273
|
+
headerActions: /*#__PURE__*/ _jsxs(_Fragment, {
|
|
274
|
+
children: [
|
|
275
|
+
/*#__PURE__*/ _jsx(SearchInline, {
|
|
276
|
+
placeholder: "Search...",
|
|
277
|
+
value: searchQuery,
|
|
278
|
+
onChange: (e)=>setSearchQuery(e.target.value),
|
|
279
|
+
onClear: ()=>setSearchQuery(''),
|
|
280
|
+
className: "flex-1 md:w-240"
|
|
281
|
+
}),
|
|
282
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
283
|
+
variant: "secondary",
|
|
284
|
+
"aria-label": "Insert column left",
|
|
285
|
+
className: "shrink-0",
|
|
286
|
+
children: /*#__PURE__*/ _jsx(Icon, {
|
|
287
|
+
name: "insertColumnLeft",
|
|
288
|
+
className: "size-16 text-foreground-neutral-subtle"
|
|
289
|
+
})
|
|
290
|
+
})
|
|
291
|
+
]
|
|
292
|
+
}),
|
|
247
293
|
columnVisibility: columnVisibility,
|
|
248
294
|
onColumnVisibilityChange: updateColumnVisibility
|
|
249
295
|
})
|
|
@@ -1,20 +1,2 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Jobs Page Component
|
|
3
|
-
*
|
|
4
|
-
* Refactored jobs page using DashboardContext and generic components.
|
|
5
|
-
*/
|
|
6
|
-
/**
|
|
7
|
-
* Jobs Page
|
|
8
|
-
*
|
|
9
|
-
* Simple jobs page with table showing job breakdown.
|
|
10
|
-
* Uses DashboardContext for state management and generic reusable components.
|
|
11
|
-
*
|
|
12
|
-
* @example
|
|
13
|
-
* ```tsx
|
|
14
|
-
* <DashboardProvider>
|
|
15
|
-
* <JobsPage />
|
|
16
|
-
* </DashboardProvider>
|
|
17
|
-
* ```
|
|
18
|
-
*/
|
|
19
1
|
export declare function JobsPage(): import("react/jsx-runtime").JSX.Element;
|
|
20
2
|
//# sourceMappingURL=jobs-page.d.ts.map
|
|
@@ -1,29 +1,15 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
*/ import { jobColumns } from '../../../components/table/table.stories.columns.js';
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { Button } from '../../../components/button/index.js';
|
|
3
|
+
import { Icon } from '../../../components/icon/index.js';
|
|
4
|
+
import { SearchInline } from '../../../components/search/search-inline.js';
|
|
5
|
+
import { jobColumns } from '../../../components/table/table.stories.columns.js';
|
|
7
6
|
import { jobsData } from '../../../components/table/table.stories.data.js';
|
|
8
7
|
import { useMemo } from 'react';
|
|
9
8
|
import { useDashboardContext } from '../context/index.js';
|
|
10
9
|
import { TableWrapper } from '../table/index.js';
|
|
11
10
|
import { PageToolbar } from '../toolbar/index.js';
|
|
12
|
-
|
|
13
|
-
* Jobs Page
|
|
14
|
-
*
|
|
15
|
-
* Simple jobs page with table showing job breakdown.
|
|
16
|
-
* Uses DashboardContext for state management and generic reusable components.
|
|
17
|
-
*
|
|
18
|
-
* @example
|
|
19
|
-
* ```tsx
|
|
20
|
-
* <DashboardProvider>
|
|
21
|
-
* <JobsPage />
|
|
22
|
-
* </DashboardProvider>
|
|
23
|
-
* ```
|
|
24
|
-
*/ export function JobsPage() {
|
|
11
|
+
export function JobsPage() {
|
|
25
12
|
const { searchQuery, setSearchQuery, timePeriod, setTimePeriod, lastUpdated, columnVisibility, updateColumnVisibility } = useDashboardContext();
|
|
26
|
-
// Filter data based on search query
|
|
27
13
|
const filteredData = useMemo(()=>jobsData.filter((job)=>job.name.toLowerCase().includes(searchQuery.toLowerCase())), [
|
|
28
14
|
searchQuery
|
|
29
15
|
]);
|
|
@@ -37,14 +23,31 @@ import { PageToolbar } from '../toolbar/index.js';
|
|
|
37
23
|
lastUpdated: lastUpdated
|
|
38
24
|
}),
|
|
39
25
|
/*#__PURE__*/ _jsx("div", {
|
|
40
|
-
className: "flex-1 px-12 pb-12 pt-4 md:px-24 md:pb-24
|
|
26
|
+
className: "flex-1 px-12 pb-12 pt-4 md:px-24 md:pb-24 overflow-auto",
|
|
41
27
|
children: /*#__PURE__*/ _jsx(TableWrapper, {
|
|
42
28
|
title: "Jobs breakdown",
|
|
43
29
|
columns: jobColumns,
|
|
44
30
|
data: filteredData,
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
31
|
+
headerActions: /*#__PURE__*/ _jsxs(_Fragment, {
|
|
32
|
+
children: [
|
|
33
|
+
/*#__PURE__*/ _jsx(SearchInline, {
|
|
34
|
+
placeholder: "Search...",
|
|
35
|
+
value: searchQuery,
|
|
36
|
+
onChange: (e)=>setSearchQuery(e.target.value),
|
|
37
|
+
onClear: ()=>setSearchQuery(''),
|
|
38
|
+
className: "flex-1 md:w-240"
|
|
39
|
+
}),
|
|
40
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
41
|
+
variant: "secondary",
|
|
42
|
+
"aria-label": "Insert column left",
|
|
43
|
+
className: "shrink-0",
|
|
44
|
+
children: /*#__PURE__*/ _jsx(Icon, {
|
|
45
|
+
name: "insertColumnLeft",
|
|
46
|
+
className: "size-16 text-foreground-neutral-subtle"
|
|
47
|
+
})
|
|
48
|
+
})
|
|
49
|
+
]
|
|
50
|
+
}),
|
|
48
51
|
columnVisibility: columnVisibility,
|
|
49
52
|
onColumnVisibilityChange: updateColumnVisibility
|
|
50
53
|
})
|
|
@@ -18,23 +18,6 @@ export interface TableWrapperProps<TData, TValue> extends Omit<ComponentProps<'d
|
|
|
18
18
|
* Data to display in the table
|
|
19
19
|
*/
|
|
20
20
|
data: TData[];
|
|
21
|
-
/**
|
|
22
|
-
* Search query value
|
|
23
|
-
*/
|
|
24
|
-
searchQuery?: string;
|
|
25
|
-
/**
|
|
26
|
-
* Search input change handler
|
|
27
|
-
*/
|
|
28
|
-
onSearchChange?: (value: string) => void;
|
|
29
|
-
/**
|
|
30
|
-
* Search clear handler
|
|
31
|
-
*/
|
|
32
|
-
onSearchClear?: () => void;
|
|
33
|
-
/**
|
|
34
|
-
* Search placeholder text
|
|
35
|
-
* @default 'Search...'
|
|
36
|
-
*/
|
|
37
|
-
searchPlaceholder?: string;
|
|
38
21
|
/**
|
|
39
22
|
* Column visibility state
|
|
40
23
|
*/
|
|
@@ -72,14 +55,20 @@ export interface TableWrapperProps<TData, TValue> extends Omit<ComponentProps<'d
|
|
|
72
55
|
*/
|
|
73
56
|
emptyState?: ReactNode;
|
|
74
57
|
/**
|
|
75
|
-
*
|
|
58
|
+
* Header actions to display in the card header
|
|
76
59
|
*/
|
|
77
60
|
headerActions?: ReactNode;
|
|
78
61
|
/**
|
|
79
|
-
*
|
|
80
|
-
|
|
62
|
+
* Loading state - displays skeleton when true
|
|
63
|
+
*/
|
|
64
|
+
isLoading?: boolean;
|
|
65
|
+
/**
|
|
66
|
+
* Optional scoped container element for dropdown portals.
|
|
67
|
+
*
|
|
68
|
+
* When provided, dropdowns (like pagination select) will be rendered inside this container
|
|
69
|
+
* instead of the document body. This is useful for scoped CSS styling.
|
|
81
70
|
*/
|
|
82
|
-
|
|
71
|
+
scopedContainer?: HTMLElement | null;
|
|
83
72
|
}
|
|
84
73
|
/**
|
|
85
74
|
* Generic Table Wrapper
|
|
@@ -93,12 +82,20 @@ export interface TableWrapperProps<TData, TValue> extends Omit<ComponentProps<'d
|
|
|
93
82
|
* title="Jobs breakdown"
|
|
94
83
|
* columns={jobColumns}
|
|
95
84
|
* data={jobsData}
|
|
96
|
-
*
|
|
97
|
-
*
|
|
85
|
+
* headerActions={
|
|
86
|
+
* <>
|
|
87
|
+
* <SearchInline
|
|
88
|
+
* placeholder="Search..."
|
|
89
|
+
* value={searchQuery}
|
|
90
|
+
* onChange={(e) => setSearchQuery(e.target.value)}
|
|
91
|
+
* />
|
|
92
|
+
* <Button variant="secondary">Action</Button>
|
|
93
|
+
* </>
|
|
94
|
+
* }
|
|
98
95
|
* columnVisibility={columnVisibility}
|
|
99
96
|
* onColumnVisibilityChange={updateColumnVisibility}
|
|
100
97
|
* />
|
|
101
98
|
* ```
|
|
102
99
|
*/
|
|
103
|
-
export declare function TableWrapper<TData, TValue>({ title, columns, data,
|
|
100
|
+
export declare function TableWrapper<TData, TValue>({ title, columns, data, columnVisibility, onColumnVisibilityChange, pagination, pageSize, pageSizeOptions, showSelectedCount, onRowClick, emptyState, headerActions, isLoading, scopedContainer, className, ...props }: TableWrapperProps<TData, TValue>): import("react/jsx-runtime").JSX.Element;
|
|
104
101
|
//# sourceMappingURL=table-wrapper.d.ts.map
|
|
@@ -2,12 +2,9 @@
|
|
|
2
2
|
* Generic Table Wrapper Component
|
|
3
3
|
*
|
|
4
4
|
* A reusable wrapper for dashboard tables with header, search, and actions.
|
|
5
|
-
*/ import { jsx as _jsx, jsxs as _jsxs
|
|
6
|
-
import {
|
|
7
|
-
import { Icon } from '../../../components/icon/index.js';
|
|
8
|
-
import { SearchInline } from '../../../components/search/search-inline.js';
|
|
5
|
+
*/ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
6
|
+
import { Card, CardAction, CardContent, CardHeader, CardTitle } from '../../../components/card/index.js';
|
|
9
7
|
import { DataTable } from '../../../components/table/data-table.js';
|
|
10
|
-
import { Header as TypographyHeader } from '../../../components/typography/index.js';
|
|
11
8
|
import { cn } from '../../../utils/cn.js';
|
|
12
9
|
/**
|
|
13
10
|
* Generic Table Wrapper
|
|
@@ -21,70 +18,60 @@ import { cn } from '../../../utils/cn.js';
|
|
|
21
18
|
* title="Jobs breakdown"
|
|
22
19
|
* columns={jobColumns}
|
|
23
20
|
* data={jobsData}
|
|
24
|
-
*
|
|
25
|
-
*
|
|
21
|
+
* headerActions={
|
|
22
|
+
* <>
|
|
23
|
+
* <SearchInline
|
|
24
|
+
* placeholder="Search..."
|
|
25
|
+
* value={searchQuery}
|
|
26
|
+
* onChange={(e) => setSearchQuery(e.target.value)}
|
|
27
|
+
* />
|
|
28
|
+
* <Button variant="secondary">Action</Button>
|
|
29
|
+
* </>
|
|
30
|
+
* }
|
|
26
31
|
* columnVisibility={columnVisibility}
|
|
27
32
|
* onColumnVisibilityChange={updateColumnVisibility}
|
|
28
33
|
* />
|
|
29
34
|
* ```
|
|
30
|
-
*/ export function TableWrapper({ title, columns, data,
|
|
35
|
+
*/ export function TableWrapper({ title, columns, data, columnVisibility, onColumnVisibilityChange, pagination = true, pageSize = 10, pageSizeOptions = [
|
|
31
36
|
10,
|
|
32
37
|
20,
|
|
33
38
|
50,
|
|
34
39
|
100
|
|
35
|
-
], showSelectedCount = false, onRowClick, emptyState, headerActions,
|
|
36
|
-
return /*#__PURE__*/ _jsxs(
|
|
37
|
-
className: cn('rounded-t-8 overflow-hidden', className),
|
|
40
|
+
], showSelectedCount = false, onRowClick, emptyState, headerActions, isLoading, scopedContainer, className, ...props }) {
|
|
41
|
+
return /*#__PURE__*/ _jsxs(Card, {
|
|
42
|
+
className: cn('rounded-t-8 overflow-hidden p-0 gap-0 border-none', className),
|
|
38
43
|
...props,
|
|
39
44
|
children: [
|
|
40
|
-
/*#__PURE__*/ _jsxs(
|
|
41
|
-
className: "flex flex-col md:flex-row md:items-center md:justify-between gap-12 md:gap-0 p-12 border-t border-x border-border-neutral-base
|
|
45
|
+
/*#__PURE__*/ _jsxs(CardHeader, {
|
|
46
|
+
className: "flex flex-col md:flex-row md:items-center md:justify-between gap-12 md:gap-0 p-12 rounded-t-8 border-t border-x border-border-neutral-base",
|
|
42
47
|
children: [
|
|
43
|
-
typeof title === 'string' ? /*#__PURE__*/ _jsx(
|
|
48
|
+
typeof title === 'string' ? /*#__PURE__*/ _jsx(CardTitle, {
|
|
44
49
|
variant: "h3",
|
|
45
|
-
className: "text-foreground-neutral-base",
|
|
46
50
|
children: title
|
|
47
51
|
}) : title,
|
|
48
|
-
|
|
52
|
+
headerActions && /*#__PURE__*/ _jsx(CardAction, {
|
|
49
53
|
className: "flex items-center gap-8 md:gap-16 w-full md:w-auto",
|
|
50
|
-
children:
|
|
51
|
-
showDefaultActions && /*#__PURE__*/ _jsxs(_Fragment, {
|
|
52
|
-
children: [
|
|
53
|
-
/*#__PURE__*/ _jsx(SearchInline, {
|
|
54
|
-
placeholder: searchPlaceholder,
|
|
55
|
-
value: searchQuery,
|
|
56
|
-
onChange: (e)=>onSearchChange?.(e.target.value),
|
|
57
|
-
onClear: ()=>onSearchClear?.(),
|
|
58
|
-
className: "flex-1 md:w-240"
|
|
59
|
-
}),
|
|
60
|
-
/*#__PURE__*/ _jsx(Button, {
|
|
61
|
-
variant: "secondary",
|
|
62
|
-
"aria-label": "Insert column left",
|
|
63
|
-
className: "shrink-0",
|
|
64
|
-
children: /*#__PURE__*/ _jsx(Icon, {
|
|
65
|
-
name: "insertColumnLeft",
|
|
66
|
-
className: "size-16 text-foreground-neutral-subtle"
|
|
67
|
-
})
|
|
68
|
-
})
|
|
69
|
-
]
|
|
70
|
-
}),
|
|
71
|
-
headerActions
|
|
72
|
-
]
|
|
54
|
+
children: headerActions
|
|
73
55
|
})
|
|
74
56
|
]
|
|
75
57
|
}),
|
|
76
|
-
/*#__PURE__*/ _jsx(
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
58
|
+
/*#__PURE__*/ _jsx(CardContent, {
|
|
59
|
+
className: "p-0",
|
|
60
|
+
children: /*#__PURE__*/ _jsx(DataTable, {
|
|
61
|
+
columns: columns,
|
|
62
|
+
data: data,
|
|
63
|
+
isLoading: isLoading,
|
|
64
|
+
pagination: pagination,
|
|
65
|
+
pageSize: pageSize,
|
|
66
|
+
pageSizeOptions: pageSizeOptions,
|
|
67
|
+
showSelectedCount: showSelectedCount,
|
|
68
|
+
onRowClick: onRowClick,
|
|
69
|
+
emptyState: emptyState,
|
|
70
|
+
columnVisibility: columnVisibility,
|
|
71
|
+
onColumnVisibilityChange: onColumnVisibilityChange,
|
|
72
|
+
scopedContainer: scopedContainer,
|
|
73
|
+
className: "rounded-t-none"
|
|
74
|
+
})
|
|
88
75
|
})
|
|
89
76
|
]
|
|
90
77
|
});
|