@evenicanpm/portal-table-ui 2.2.3 → 2.3.1
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/package.json +5 -5
- package/src/features/table/components/dashboard/table/details/details.tsx +1 -1
- package/src/features/table/components/dashboard/table/details/rows/table.tsx +1 -1
- package/src/features/table/components/dashboard/table/details/templates/invoice-details.tsx +31 -5
- package/src/features/table/components/dashboard/table/table-header.tsx +1 -1
- package/src/features/table/components/dashboard/table/table-input.tsx +11 -9
- package/src/features/table/components/dashboard/table/table.tsx +6 -3
- package/src/features/table/components/dashboard/table-dashboard.tsx +19 -17
- package/src/features/table/logic/resolvers.ts +4 -5
- package/src/features/table/logic/transformers.ts +2 -2
- package/src/features/table/types/handlers.ts +1 -1
- package/src/features/table/types/index.ts +2 -0
- package/src/features/table/types/queries.ts +1 -1
- package/src/features/table/types/schemas.ts +1 -1
- package/src/features/table/types/table-param.ts +51 -0
- package/src/features/table/types/view-config.ts +122 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@evenicanpm/portal-table-ui",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"license": "ISC",
|
|
6
6
|
"author": "",
|
|
@@ -36,16 +36,16 @@
|
|
|
36
36
|
"@emotion/styled": "^11.11.0",
|
|
37
37
|
"@mui/icons-material": "^7.3.6",
|
|
38
38
|
"@mui/material": "^6.1.7",
|
|
39
|
+
"@tanstack/react-query": "^5.90.11",
|
|
39
40
|
"@types/react": "^18.3.24",
|
|
40
41
|
"typescript": "^5.6.3"
|
|
41
42
|
},
|
|
42
43
|
"dependencies": {
|
|
43
44
|
"@arrows/multimethod": "^2.1.0",
|
|
44
|
-
"@evenicanpm/portal-types-schemas": "^2.0.0",
|
|
45
45
|
"@evenicanpm/ui": "^2.0.0",
|
|
46
46
|
"@mui/lab": "^7.0.1-beta.19",
|
|
47
|
-
"
|
|
48
|
-
"
|
|
47
|
+
"date-fns": "^4.1.0",
|
|
48
|
+
"zod": "^4.4.3"
|
|
49
49
|
},
|
|
50
|
-
"gitHead": "
|
|
50
|
+
"gitHead": "7a5a6a8c3c3dd9efe96fbbb884b21e7681d32550"
|
|
51
51
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { method, multi } from "@arrows/multimethod";
|
|
3
|
-
import type { Column } from "@evenicanpm/portal-types-schemas";
|
|
4
3
|
import { FlexBox, H6, Subtitle } from "@evenicanpm/ui";
|
|
5
4
|
import ArrowBackIcon from "@mui/icons-material/ArrowBack";
|
|
6
5
|
import { Box, Button } from "@mui/material";
|
|
7
6
|
import Grid from "@mui/material/Grid2";
|
|
8
7
|
import { resolvers, transformers } from "../../../../logic";
|
|
9
8
|
import type * as Types from "../../../../types";
|
|
9
|
+
import type { Column } from "../../../../types";
|
|
10
10
|
import type { StatusColorMap, StatusTextMap } from "../../../../types/schemas";
|
|
11
11
|
import { StatusPill } from "../status-pill";
|
|
12
12
|
import { DetailsRowLabel } from "./label";
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import type { Column } from "@evenicanpm/portal-types-schemas";
|
|
4
3
|
import {
|
|
5
4
|
Table,
|
|
6
5
|
TableBody,
|
|
@@ -10,6 +9,7 @@ import {
|
|
|
10
9
|
TableRow,
|
|
11
10
|
} from "@mui/material";
|
|
12
11
|
import { resolvers } from "../../../../../logic";
|
|
12
|
+
import type { Column } from "../../../../../types";
|
|
13
13
|
import type { DataMaskMap } from "../../../../../types/handlers";
|
|
14
14
|
|
|
15
15
|
interface Props {
|
|
@@ -55,7 +55,6 @@ interface InvoiceLine {
|
|
|
55
55
|
Price?: number;
|
|
56
56
|
NetAmount?: number;
|
|
57
57
|
UnitOfMeasure?: string;
|
|
58
|
-
LineDiscount?: number;
|
|
59
58
|
DiscountAmount: number;
|
|
60
59
|
HasDiscount: boolean;
|
|
61
60
|
}
|
|
@@ -67,6 +66,7 @@ interface InvoiceData {
|
|
|
67
66
|
InvoiceSubtotal?: number;
|
|
68
67
|
TotalTaxAmount?: number;
|
|
69
68
|
Amount?: number;
|
|
69
|
+
AmountBalance?: number;
|
|
70
70
|
CompanyName?: string;
|
|
71
71
|
CompanyEmail?: string;
|
|
72
72
|
CompanyAddress?: string;
|
|
@@ -78,6 +78,7 @@ interface InvoiceData {
|
|
|
78
78
|
Notes?: string;
|
|
79
79
|
Id: string;
|
|
80
80
|
OrderedByCustomerName?: string;
|
|
81
|
+
ChargeTotal?: number;
|
|
81
82
|
}
|
|
82
83
|
|
|
83
84
|
interface TableColumn {
|
|
@@ -88,7 +89,7 @@ interface TableColumn {
|
|
|
88
89
|
|
|
89
90
|
const detailSkeletonKeys = ["from", "bill-to", "invoice-date", "due-date"];
|
|
90
91
|
const tableSkeletonRowKeys = ["line-1", "line-2", "line-3", "line-4"];
|
|
91
|
-
const totalSkeletonKeys = ["subtotal", "tax", "total"];
|
|
92
|
+
const totalSkeletonKeys = ["subtotal", "charge-total", "tax", "total"];
|
|
92
93
|
|
|
93
94
|
const isDataEmpty = (data: InvoiceData | null | undefined): boolean => {
|
|
94
95
|
if (!data) return true;
|
|
@@ -138,15 +139,15 @@ export const InvoiceDetailsTemplate = ({
|
|
|
138
139
|
const subtotal = invoice?.InvoiceSubtotal ?? 0;
|
|
139
140
|
const tax = invoice?.TotalTaxAmount ?? 0;
|
|
140
141
|
const total = invoice?.Amount ?? 0;
|
|
141
|
-
|
|
142
|
+
const chargeTotal = invoice?.ChargeTotal ?? 0;
|
|
142
143
|
// Fixed column definitions with specific widths
|
|
143
144
|
const columns: TableColumn[] = [
|
|
144
145
|
{ label: "#", width: 60, aligned: "left" },
|
|
145
146
|
{ label: "Product", width: 200, aligned: "left" },
|
|
146
|
-
{ label: "Qty", width:
|
|
147
|
+
{ label: "Qty", width: 40, aligned: "right" },
|
|
147
148
|
{ label: "Unit", width: 60, aligned: "right" },
|
|
148
149
|
{ label: "Unit Price", width: 120, aligned: "right" },
|
|
149
|
-
{ label: "
|
|
150
|
+
{ label: "Line Savings", width: 120, aligned: "right" },
|
|
150
151
|
{ label: "Line Total", width: 120, aligned: "right" },
|
|
151
152
|
{ label: "", width: 40, aligned: "center" },
|
|
152
153
|
];
|
|
@@ -562,6 +563,12 @@ export const InvoiceDetailsTemplate = ({
|
|
|
562
563
|
{formatCurrency(subtotal)}
|
|
563
564
|
</Typography>
|
|
564
565
|
</Box>
|
|
566
|
+
<Box display="flex" justifyContent="space-between" mb={1}>
|
|
567
|
+
<Typography variant="body2">Total Charges</Typography>
|
|
568
|
+
<Typography variant="body2" fontWeight={500}>
|
|
569
|
+
{formatCurrency(chargeTotal)}
|
|
570
|
+
</Typography>
|
|
571
|
+
</Box>
|
|
565
572
|
<Box display="flex" justifyContent="space-between" mb={1}>
|
|
566
573
|
<Typography variant="body2">Tax</Typography>
|
|
567
574
|
<Typography variant="body2" fontWeight={500}>
|
|
@@ -577,6 +584,25 @@ export const InvoiceDetailsTemplate = ({
|
|
|
577
584
|
{formatCurrency(total)}
|
|
578
585
|
</Typography>
|
|
579
586
|
</Box>
|
|
587
|
+
|
|
588
|
+
{/* Paid and Remaining lines */}
|
|
589
|
+
{invoice?.Status !== 1 && (
|
|
590
|
+
<Box display="flex" justifyContent="space-between" mt={1}>
|
|
591
|
+
<Typography variant="body2">Paid</Typography>
|
|
592
|
+
<Typography variant="body2">
|
|
593
|
+
{formatCurrency(total - (invoice?.AmountBalance ?? 0))}
|
|
594
|
+
</Typography>
|
|
595
|
+
</Box>
|
|
596
|
+
)}
|
|
597
|
+
|
|
598
|
+
{invoice?.Status !== 1 && (invoice?.AmountBalance ?? 0) > 0 && (
|
|
599
|
+
<Box display="flex" justifyContent="space-between" mt={0.5}>
|
|
600
|
+
<Typography variant="body2">Remaining</Typography>
|
|
601
|
+
<Typography variant="body2">
|
|
602
|
+
{formatCurrency(invoice?.AmountBalance ?? 0)}
|
|
603
|
+
</Typography>
|
|
604
|
+
</Box>
|
|
605
|
+
)}
|
|
580
606
|
</Box>
|
|
581
607
|
</Box>
|
|
582
608
|
</>
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type { Column } from "@evenicanpm/portal-types-schemas";
|
|
2
1
|
import { Skeleton } from "@mui/material";
|
|
3
2
|
import Checkbox from "@mui/material/Checkbox";
|
|
4
3
|
import { styled } from "@mui/material/styles";
|
|
5
4
|
import TableCell from "@mui/material/TableCell";
|
|
6
5
|
import TableHead from "@mui/material/TableHead";
|
|
7
6
|
import TableRow from "@mui/material/TableRow";
|
|
7
|
+
import type { Column } from "../../../types";
|
|
8
8
|
|
|
9
9
|
// STYLED COMPONENTS
|
|
10
10
|
const StyledTableCell = styled(TableCell)(({ theme }) => ({
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { Column } from "@evenicanpm/portal-types-schemas";
|
|
2
1
|
import { SearchInput } from "@evenicanpm/ui";
|
|
3
2
|
import { MenuItem, Select } from "@mui/material";
|
|
4
3
|
import React from "react";
|
|
4
|
+
import type { Column } from "../../../types";
|
|
5
5
|
|
|
6
6
|
interface SearchProps {
|
|
7
7
|
searchTerm: string;
|
|
@@ -84,14 +84,16 @@ const SearchField = React.memo(
|
|
|
84
84
|
: "Select a column to search"
|
|
85
85
|
}
|
|
86
86
|
endAdornment={
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
87
|
+
searchCols.length > 1 ? (
|
|
88
|
+
<ColumnSelect
|
|
89
|
+
selected={selectedColumn?.Data || ""}
|
|
90
|
+
searchCols={searchCols}
|
|
91
|
+
handleChange={(value) => {
|
|
92
|
+
const col = searchCols.find((c) => c.Data === value);
|
|
93
|
+
if (col) setColumn(col);
|
|
94
|
+
}}
|
|
95
|
+
/>
|
|
96
|
+
) : undefined
|
|
95
97
|
}
|
|
96
98
|
/>
|
|
97
99
|
);
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { Column } from "@evenicanpm/portal-types-schemas";
|
|
2
1
|
import { FlexBox, ResponsiveTablePagination } from "@evenicanpm/ui";
|
|
3
2
|
import Table from "@mui/material/Table";
|
|
4
3
|
import TableBody from "@mui/material/TableBody";
|
|
@@ -10,6 +9,7 @@ import type React from "react";
|
|
|
10
9
|
import { useState } from "react";
|
|
11
10
|
import { resolvers, transformers } from "../../../logic";
|
|
12
11
|
import type * as Types from "../../../types";
|
|
12
|
+
import type { Column } from "../../../types";
|
|
13
13
|
import { BulkActionButton } from "./bulk-action-button";
|
|
14
14
|
import { dataMaskMap as dataMaskMapLocal } from "./data-mask-map";
|
|
15
15
|
import { Details } from "./details";
|
|
@@ -241,13 +241,16 @@ export default function DocumentTable({
|
|
|
241
241
|
bulkRegistry,
|
|
242
242
|
);
|
|
243
243
|
|
|
244
|
-
const hasActions =
|
|
244
|
+
/* const hasActions =
|
|
245
245
|
configPending ||
|
|
246
246
|
(resolvedActions.length > 0 &&
|
|
247
247
|
rows?.data?.some((row) =>
|
|
248
248
|
resolvedActions.some((a) => !a.isEnabled || a.isEnabled(row)),
|
|
249
249
|
)) ||
|
|
250
|
-
false;
|
|
250
|
+
false; */
|
|
251
|
+
// we want the column to appear by default, actions will render separately
|
|
252
|
+
// when ready which is currently the desired behaviour per item 7435
|
|
253
|
+
const hasActions = config?.Actions.length > 0;
|
|
251
254
|
const hasBulkActions = resolvedBulkActions.length > 0;
|
|
252
255
|
|
|
253
256
|
// --- Render --- //
|
|
@@ -49,23 +49,25 @@ export const TableDashboard = ({
|
|
|
49
49
|
return (
|
|
50
50
|
<Box sx={{ width: "100%", minHeight: "70vh" }}>
|
|
51
51
|
<TabContext value={value}>
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
{
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
52
|
+
{resources?.length > 1 && (
|
|
53
|
+
<Box
|
|
54
|
+
sx={{
|
|
55
|
+
borderBottom: 1,
|
|
56
|
+
borderColor: "divider",
|
|
57
|
+
"@media print": { display: "none" },
|
|
58
|
+
}}
|
|
59
|
+
>
|
|
60
|
+
<TabList onChange={handleChange}>
|
|
61
|
+
{resources?.map((resource, i) => (
|
|
62
|
+
<Tab
|
|
63
|
+
key={resource?.name + String(i)}
|
|
64
|
+
label={resource?.label}
|
|
65
|
+
value={resource?.name}
|
|
66
|
+
/>
|
|
67
|
+
))}
|
|
68
|
+
</TabList>
|
|
69
|
+
</Box>
|
|
70
|
+
)}
|
|
69
71
|
{resources?.map((resource, i) => (
|
|
70
72
|
<Box key={resource.name + String(i)}>
|
|
71
73
|
<TabPanel
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { method, multi } from "@arrows/multimethod";
|
|
2
|
-
import type { Column } from "@evenicanpm/portal-types-schemas";
|
|
3
2
|
import type * as Types from "../types";
|
|
4
3
|
import type { TableConfig } from "../types/queries";
|
|
5
4
|
import type { UIAction, UIBulkAction } from "../types/schemas";
|
|
@@ -37,7 +36,7 @@ export const resolveFilterUI = multi(
|
|
|
37
36
|
* @internal
|
|
38
37
|
*/
|
|
39
38
|
export const resolveDataMask = multi(
|
|
40
|
-
(col: Column, handlers: Types.Handlers.DataMaskMap) => {
|
|
39
|
+
(col: Types.Column, handlers: Types.Handlers.DataMaskMap) => {
|
|
41
40
|
if (!col?.DataMask) return "SKIP";
|
|
42
41
|
if (handlers?.[col?.DataType]) return "BY_TYPE";
|
|
43
42
|
if (handlers?.[col?.Data]) return "BY_NAME";
|
|
@@ -45,12 +44,12 @@ export const resolveDataMask = multi(
|
|
|
45
44
|
},
|
|
46
45
|
method(
|
|
47
46
|
"BY_TYPE",
|
|
48
|
-
(col: Column, handlers: Types.Handlers.DataMaskMap) =>
|
|
47
|
+
(col: Types.Column, handlers: Types.Handlers.DataMaskMap) =>
|
|
49
48
|
handlers?.[col?.DataType],
|
|
50
49
|
),
|
|
51
50
|
method(
|
|
52
51
|
"BY_NAME",
|
|
53
|
-
(col: Column, handlers: Types.Handlers.DataMaskMap) =>
|
|
52
|
+
(col: Types.Column, handlers: Types.Handlers.DataMaskMap) =>
|
|
54
53
|
handlers?.[col?.Data],
|
|
55
54
|
),
|
|
56
55
|
method("SKIP", () => (value: string | number) => value),
|
|
@@ -61,7 +60,7 @@ export const resolveDataMask = multi(
|
|
|
61
60
|
* @internal
|
|
62
61
|
*/
|
|
63
62
|
export const resolveCellUI = (
|
|
64
|
-
col: Column,
|
|
63
|
+
col: Types.Column,
|
|
65
64
|
handlers: Types.Handlers.CellRenderMap,
|
|
66
65
|
) => {
|
|
67
66
|
if (Object.hasOwn(handlers, col.Data)) return handlers?.[col?.Data];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Column } from "
|
|
1
|
+
import type { Column } from "../types";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* These are pure static functions that include business rules
|
|
@@ -32,7 +32,7 @@ export const getVisibleColumns = (columns: Column[] | undefined) =>
|
|
|
32
32
|
columns
|
|
33
33
|
?.filter(
|
|
34
34
|
(column): column is Column & { ColumnOrder: number } =>
|
|
35
|
-
typeof column.ColumnOrder === "number",
|
|
35
|
+
typeof column.ColumnOrder === "number" && column.IsVisible !== false,
|
|
36
36
|
)
|
|
37
37
|
.sort((a, b) => a.ColumnOrder - b.ColumnOrder);
|
|
38
38
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type { TableViewParams } from "@evenicanpm/portal-types-schemas";
|
|
2
1
|
import type { SvgIconComponent } from "@mui/icons-material";
|
|
3
2
|
import type { UseMutationOptions } from "@tanstack/react-query";
|
|
4
3
|
import type { Table } from "..";
|
|
5
4
|
import type { DetailsTemplateKey } from "../components/dashboard/table/details/templates/template-registry";
|
|
5
|
+
import type { TableViewParams } from "../types";
|
|
6
6
|
import type {
|
|
7
7
|
CellRenderMap,
|
|
8
8
|
DataMaskMap,
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
export const TableViewParamsSchema = z.object({
|
|
4
|
+
pageSize: z.number().default(5),
|
|
5
|
+
page: z.number().default(0),
|
|
6
|
+
filters: z.record(z.string(), z.unknown()).optional(),
|
|
7
|
+
searchTerm: z.string().optional().default(""),
|
|
8
|
+
searchColumn: z.string().default("all"),
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
// Extract the TypeScript interface from the schema
|
|
12
|
+
export type TableViewParams = z.infer<typeof TableViewParamsSchema>;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* convert the table state into url params.
|
|
16
|
+
* @param params Filters and params stored from table state
|
|
17
|
+
* @returns Url params.
|
|
18
|
+
*/
|
|
19
|
+
export const tableStateToQuery = (params: TableViewParams): URLSearchParams => {
|
|
20
|
+
const { page, pageSize, searchTerm, searchColumn, filters } = params;
|
|
21
|
+
const searchParams = new URLSearchParams();
|
|
22
|
+
searchParams.set("page", String(page));
|
|
23
|
+
searchParams.set("pageSize", String(pageSize));
|
|
24
|
+
|
|
25
|
+
if (searchTerm && searchColumn) {
|
|
26
|
+
searchParams.set("searchTerm", searchTerm);
|
|
27
|
+
searchParams.set("searchColumn", searchColumn);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (filters) searchParams.set("filters", JSON.stringify(filters));
|
|
31
|
+
return searchParams;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Pre-processes url params into portal format to be
|
|
36
|
+
* inserted into one of the DMS URL builders
|
|
37
|
+
*
|
|
38
|
+
* @param searchParams url params from next endpoint
|
|
39
|
+
* @returns table view params formatted filters/pagination
|
|
40
|
+
*/
|
|
41
|
+
export const queryToTableState = (
|
|
42
|
+
searchParams: URLSearchParams,
|
|
43
|
+
): TableViewParams => {
|
|
44
|
+
const page = Number(searchParams.get("page") ?? 0);
|
|
45
|
+
const pageSize = Number(searchParams.get("pageSize") ?? 5);
|
|
46
|
+
const searchTerm = searchParams.get("searchTerm") ?? "";
|
|
47
|
+
const searchColumn = searchParams.get("searchColumn") ?? "";
|
|
48
|
+
const filtersValue = searchParams.get("filters");
|
|
49
|
+
const filters = filtersValue && JSON.parse(filtersValue);
|
|
50
|
+
return { page, pageSize, searchColumn, searchTerm, filters };
|
|
51
|
+
};
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* ColumnDataType
|
|
4
|
+
*/
|
|
5
|
+
export const ColumnDataTypeSchema = z.enum([
|
|
6
|
+
"String",
|
|
7
|
+
"int",
|
|
8
|
+
"numeric",
|
|
9
|
+
"date",
|
|
10
|
+
"datetime",
|
|
11
|
+
"url",
|
|
12
|
+
]);
|
|
13
|
+
export type ColumnDataType = z.infer<typeof ColumnDataTypeSchema>;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* DataMaskFormat
|
|
17
|
+
*/
|
|
18
|
+
export const DataMaskFormatSchema = z.enum([
|
|
19
|
+
"MM/DD/YYYY",
|
|
20
|
+
"MM-DD-YYYY",
|
|
21
|
+
"DD/MM/YYYY",
|
|
22
|
+
"DD-MM-YYYY",
|
|
23
|
+
"YYYY/MM/DD",
|
|
24
|
+
"YYYY-MM-DD HH:MI:SS",
|
|
25
|
+
"$0.00",
|
|
26
|
+
"0,00€",
|
|
27
|
+
]);
|
|
28
|
+
export type DataMaskFormat = z.infer<typeof DataMaskFormatSchema>;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* FilterOperation
|
|
32
|
+
*/
|
|
33
|
+
export const FilterOperationSchema = z.enum([
|
|
34
|
+
"eq",
|
|
35
|
+
"gt",
|
|
36
|
+
"lt",
|
|
37
|
+
"gte",
|
|
38
|
+
"lte",
|
|
39
|
+
"in",
|
|
40
|
+
]);
|
|
41
|
+
export type FilterOperation = z.infer<typeof FilterOperationSchema>;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* FilterOption
|
|
45
|
+
*/
|
|
46
|
+
export const FilterOptionSchema = z.object({
|
|
47
|
+
value: z.union([z.string(), z.number()]),
|
|
48
|
+
label: z.string(),
|
|
49
|
+
});
|
|
50
|
+
export type FilterOption = z.infer<typeof FilterOptionSchema>;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* FilterConfig
|
|
54
|
+
*/
|
|
55
|
+
export const FilterConfigSchema = z.object({
|
|
56
|
+
FilterOptions: z.array(FilterOptionSchema),
|
|
57
|
+
FilterType: z.string(),
|
|
58
|
+
FilterOperation: FilterOperationSchema,
|
|
59
|
+
});
|
|
60
|
+
export type FilterConfig = z.infer<typeof FilterConfigSchema>;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Filter (from table metadata response)
|
|
64
|
+
*/
|
|
65
|
+
export const FilterSchema = z.object({
|
|
66
|
+
Operation: FilterOperationSchema,
|
|
67
|
+
Data: z.string(),
|
|
68
|
+
Value: z.union([z.string(), z.array(z.string()), z.number()]),
|
|
69
|
+
});
|
|
70
|
+
export type Filter = z.infer<typeof FilterSchema>;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Column (recursive)
|
|
74
|
+
*/
|
|
75
|
+
export const ColumnSchema = z.object({
|
|
76
|
+
Label: z.string(),
|
|
77
|
+
Data: z.string(),
|
|
78
|
+
DataType: z.string(),
|
|
79
|
+
DataMask: z.string().optional(),
|
|
80
|
+
ColumnOrder: z.number().nullable().optional(),
|
|
81
|
+
IsSearchable: z.boolean().optional(),
|
|
82
|
+
IsFilterable: z.boolean().optional(),
|
|
83
|
+
Filters: z.array(FilterConfigSchema).optional(),
|
|
84
|
+
IsVisible: z.boolean().optional(),
|
|
85
|
+
IsSortable: z.boolean().optional(),
|
|
86
|
+
DisplayOrder: z.number().optional(),
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
export type Action = {
|
|
90
|
+
Name: string;
|
|
91
|
+
Type: string;
|
|
92
|
+
IdField?: string;
|
|
93
|
+
IsEnabled: boolean;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
export type BulkAction = {
|
|
97
|
+
Name: string;
|
|
98
|
+
Type: string;
|
|
99
|
+
IdField?: string;
|
|
100
|
+
IsEnabled: boolean;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
export interface Column {
|
|
104
|
+
Label: string;
|
|
105
|
+
Data: string;
|
|
106
|
+
DataType: string;
|
|
107
|
+
ColumnOrder: number | undefined | null;
|
|
108
|
+
DataMask?: string;
|
|
109
|
+
IsSearchable?: boolean;
|
|
110
|
+
IsFilterable?: boolean;
|
|
111
|
+
Filters?: FilterConfig[];
|
|
112
|
+
IsVisible?: boolean;
|
|
113
|
+
IsSortable?: boolean;
|
|
114
|
+
DisplayOrder?: number;
|
|
115
|
+
Children?: Column[];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export type ViewConfig = {
|
|
119
|
+
Columns: Column[];
|
|
120
|
+
Actions?: Action[];
|
|
121
|
+
BulkActions?: BulkAction[];
|
|
122
|
+
};
|