@izumisy-tailor/tailor-data-viewer 0.2.32 → 0.2.33
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/README.md +59 -51
- package/package.json +1 -1
- package/src/component/data-table/column-selector.test.tsx +3 -4
- package/src/component/data-table/column-selector.tsx +3 -4
- package/src/component/data-table/csv-button.test.tsx +6 -2
- package/src/component/data-table/csv-button.tsx +4 -10
- package/src/component/data-table/data-table.test.tsx +10 -16
- package/src/component/data-table/data-table.tsx +27 -55
- package/src/component/data-table/pagination.test.tsx +2 -2
- package/src/component/data-table/search-filter-form.test.tsx +9 -12
- package/src/component/data-table/search-filter-form.tsx +8 -14
- package/src/component/data-table/use-data-table.test.ts +13 -16
- package/src/component/data-table/use-data-table.ts +1 -1
- package/src/component/field-helpers.test.ts +219 -136
- package/src/component/field-helpers.ts +93 -144
- package/src/component/index.ts +1 -6
- package/src/component/types.ts +47 -103
|
@@ -1,181 +1,102 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
1
2
|
import type { TableMetadata } from "../generator/metadata-generator";
|
|
2
3
|
import type {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
DisplayColumnOptions,
|
|
6
|
-
FieldColumn,
|
|
7
|
-
FieldColumnOptions,
|
|
4
|
+
Column,
|
|
5
|
+
ColumnOptions,
|
|
8
6
|
TableFieldName,
|
|
9
7
|
FilterConfig,
|
|
10
8
|
MetadataFieldOptions,
|
|
11
|
-
MetadataFieldsOptions,
|
|
12
9
|
SortConfig,
|
|
13
10
|
} from "./types";
|
|
14
11
|
import { fieldTypeToFilterConfig, fieldTypeToSortConfig } from "./types";
|
|
15
12
|
|
|
16
13
|
// =============================================================================
|
|
17
|
-
//
|
|
14
|
+
// column() helper
|
|
18
15
|
// =============================================================================
|
|
19
16
|
|
|
20
17
|
/**
|
|
21
|
-
* Define a
|
|
18
|
+
* Define a column with explicit render and optional sort/filter/accessor.
|
|
22
19
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
* @param dataKey - Property name on the row object.
|
|
26
|
-
* @param options - Column options (label, width, sort, filter, renderer).
|
|
20
|
+
* @param options - Column options (label, render, sort, filter, accessor, width).
|
|
27
21
|
*
|
|
28
22
|
* @example
|
|
29
23
|
* ```tsx
|
|
30
|
-
*
|
|
24
|
+
* column({
|
|
31
25
|
* label: "Name",
|
|
32
|
-
*
|
|
33
|
-
*
|
|
26
|
+
* render: (row) => row.name,
|
|
27
|
+
* sort: { field: "name", type: "string" },
|
|
28
|
+
* filter: { field: "name", type: "string" },
|
|
34
29
|
* })
|
|
35
30
|
* ```
|
|
36
31
|
*/
|
|
37
|
-
export function
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
): FieldColumn<TRow> {
|
|
32
|
+
export function column<TRow extends Record<string, unknown>>(
|
|
33
|
+
options: ColumnOptions<TRow>,
|
|
34
|
+
): Column<TRow> {
|
|
41
35
|
return {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
width: options
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
36
|
+
label: options.label,
|
|
37
|
+
render: options.render,
|
|
38
|
+
id: options.id,
|
|
39
|
+
width: options.width,
|
|
40
|
+
accessor: options.accessor,
|
|
41
|
+
sort: options.sort,
|
|
42
|
+
filter: options.filter,
|
|
49
43
|
};
|
|
50
44
|
}
|
|
51
45
|
|
|
52
46
|
// =============================================================================
|
|
53
|
-
//
|
|
47
|
+
// inferColumns() — metadata-driven column defaults
|
|
54
48
|
// =============================================================================
|
|
55
49
|
|
|
56
50
|
/**
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
* Sort and filter are always disabled for display columns.
|
|
60
|
-
*
|
|
61
|
-
* @param id - Unique column identifier.
|
|
62
|
-
* @param options - Column options (label, width, render function).
|
|
63
|
-
*
|
|
64
|
-
* @example
|
|
65
|
-
* ```tsx
|
|
66
|
-
* display("actions", {
|
|
67
|
-
* width: 50,
|
|
68
|
-
* render: (row) => <ActionMenu row={row} />,
|
|
69
|
-
* })
|
|
70
|
-
* ```
|
|
51
|
+
* Default value formatter for cell display.
|
|
71
52
|
*/
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
)
|
|
76
|
-
return
|
|
77
|
-
|
|
78
|
-
id,
|
|
79
|
-
label: options.label,
|
|
80
|
-
width: options.width,
|
|
81
|
-
render: options.render,
|
|
82
|
-
};
|
|
53
|
+
function formatValue(value: unknown): ReactNode {
|
|
54
|
+
if (value == null) return "";
|
|
55
|
+
if (typeof value === "boolean") return value ? "✓" : "✗";
|
|
56
|
+
if (value instanceof Date) return value.toLocaleDateString();
|
|
57
|
+
if (typeof value === "object") return JSON.stringify(value);
|
|
58
|
+
return String(value);
|
|
83
59
|
}
|
|
84
60
|
|
|
85
|
-
// =============================================================================
|
|
86
|
-
// createColumnHelper() factory
|
|
87
|
-
// =============================================================================
|
|
88
|
-
|
|
89
61
|
/**
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
* This avoids repeating the row type parameter on every helper call.
|
|
93
|
-
* Use `inferColumns(tableMetadata)` to create metadata-inferred columns
|
|
94
|
-
* without specifying TRow again.
|
|
62
|
+
* Return a function that produces `ColumnOptions` from metadata field names.
|
|
95
63
|
*
|
|
96
64
|
* @example
|
|
97
65
|
* ```tsx
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
* // Manual columns
|
|
103
|
-
* const manualColumns = [
|
|
104
|
-
* field("title", { label: "Title", sort: { type: "string" } }),
|
|
105
|
-
* display("actions", { render: (row) => <ActionMenu row={row} /> }),
|
|
66
|
+
* const infer = inferColumns<OrderRow>(tableMetadata.order);
|
|
67
|
+
* const columns = [
|
|
68
|
+
* column(infer("title")),
|
|
69
|
+
* column({ ...infer("status"), render: (row) => <StatusBadge value={row.status} /> }),
|
|
106
70
|
* ];
|
|
107
|
-
*
|
|
108
|
-
* // Metadata-inferred columns (no need to pass TRow again)
|
|
109
|
-
* const { column } = inferColumns(tableMetadata.order);
|
|
110
|
-
* const inferredColumns = [column("title"), column("amount")];
|
|
111
71
|
* ```
|
|
112
72
|
*/
|
|
113
|
-
export function
|
|
114
|
-
field: (
|
|
115
|
-
dataKey: keyof TRow & string,
|
|
116
|
-
options?: FieldColumnOptions<TRow>,
|
|
117
|
-
) => FieldColumn<TRow>;
|
|
118
|
-
display: (
|
|
119
|
-
id: string,
|
|
120
|
-
options: DisplayColumnOptions<TRow>,
|
|
121
|
-
) => DisplayColumn<TRow>;
|
|
122
|
-
inferColumns: <const TTable extends TableMetadata>(
|
|
123
|
-
tableMetadata: TTable,
|
|
124
|
-
) => {
|
|
125
|
-
column: (
|
|
126
|
-
dataKey: TableFieldName<TTable>,
|
|
127
|
-
options?: MetadataFieldOptions<TRow>,
|
|
128
|
-
) => FieldColumn<TRow>;
|
|
129
|
-
columns: (
|
|
130
|
-
dataKeys: TableFieldName<TTable>[],
|
|
131
|
-
options?: MetadataFieldsOptions,
|
|
132
|
-
) => FieldColumn<TRow>[];
|
|
133
|
-
};
|
|
134
|
-
} {
|
|
135
|
-
return {
|
|
136
|
-
field: (dataKey, options) => field<TRow>(dataKey, options),
|
|
137
|
-
display: (id, options) => display<TRow>(id, options),
|
|
138
|
-
inferColumns: (tableMetadata) => inferColumnHelper<TRow>(tableMetadata),
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// =============================================================================
|
|
143
|
-
// Internal: metadata-based column inference (used by createColumnHelper)
|
|
144
|
-
// =============================================================================
|
|
145
|
-
|
|
146
|
-
function inferColumnHelper<
|
|
73
|
+
export function inferColumns<
|
|
147
74
|
TRow extends Record<string, unknown>,
|
|
148
75
|
const TTable extends TableMetadata = TableMetadata,
|
|
149
76
|
>(
|
|
150
77
|
tableMetadata: TTable,
|
|
151
|
-
):
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
) => FieldColumn<TRow>;
|
|
156
|
-
|
|
157
|
-
columns: (
|
|
158
|
-
dataKeys: TableFieldName<TTable>[],
|
|
159
|
-
options?: MetadataFieldsOptions,
|
|
160
|
-
) => FieldColumn<TRow>[];
|
|
161
|
-
} {
|
|
78
|
+
): (
|
|
79
|
+
dataKey: TableFieldName<TTable>,
|
|
80
|
+
options?: MetadataFieldOptions,
|
|
81
|
+
) => ColumnOptions<TRow> {
|
|
162
82
|
const fields = tableMetadata.fields;
|
|
163
83
|
|
|
164
|
-
|
|
84
|
+
return (
|
|
165
85
|
dataKey: TableFieldName<TTable>,
|
|
166
|
-
columnOptions?: MetadataFieldOptions
|
|
167
|
-
):
|
|
168
|
-
const
|
|
86
|
+
columnOptions?: MetadataFieldOptions,
|
|
87
|
+
): ColumnOptions<TRow> => {
|
|
88
|
+
const fieldName = dataKey as string;
|
|
89
|
+
const fieldMeta = fields.find((f) => f.name === fieldName);
|
|
169
90
|
if (!fieldMeta) {
|
|
170
91
|
throw new Error(
|
|
171
|
-
`Field "${
|
|
92
|
+
`Field "${fieldName}" not found in table "${tableMetadata.name}" metadata`,
|
|
172
93
|
);
|
|
173
94
|
}
|
|
174
95
|
|
|
175
96
|
// Auto-detect sort config
|
|
176
97
|
let sort: SortConfig | undefined;
|
|
177
98
|
if (columnOptions?.sort !== false) {
|
|
178
|
-
sort = fieldTypeToSortConfig(fieldMeta.type);
|
|
99
|
+
sort = fieldTypeToSortConfig(fieldName, fieldMeta.type);
|
|
179
100
|
}
|
|
180
101
|
if (columnOptions?.sort === false) {
|
|
181
102
|
sort = undefined;
|
|
@@ -184,37 +105,65 @@ function inferColumnHelper<
|
|
|
184
105
|
// Auto-detect filter config
|
|
185
106
|
let filter: FilterConfig | undefined;
|
|
186
107
|
if (columnOptions?.filter !== false) {
|
|
187
|
-
filter = fieldTypeToFilterConfig(
|
|
108
|
+
filter = fieldTypeToFilterConfig(
|
|
109
|
+
fieldName,
|
|
110
|
+
fieldMeta.type,
|
|
111
|
+
fieldMeta.enumValues,
|
|
112
|
+
);
|
|
188
113
|
}
|
|
189
114
|
if (columnOptions?.filter === false) {
|
|
190
115
|
filter = undefined;
|
|
191
116
|
}
|
|
192
117
|
|
|
118
|
+
const label =
|
|
119
|
+
columnOptions?.label ?? fieldMeta.description ?? fieldMeta.name;
|
|
120
|
+
|
|
193
121
|
return {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
122
|
+
label,
|
|
123
|
+
render: ((row: Record<string, unknown>) =>
|
|
124
|
+
formatValue(row[fieldName])) as (row: TRow) => ReactNode,
|
|
125
|
+
accessor: ((row: Record<string, unknown>) => row[fieldName]) as (
|
|
126
|
+
row: TRow,
|
|
127
|
+
) => unknown,
|
|
197
128
|
width: columnOptions?.width,
|
|
198
129
|
sort,
|
|
199
130
|
filter,
|
|
200
|
-
renderer: columnOptions?.renderer as CellRenderer<TRow> | undefined,
|
|
201
131
|
};
|
|
202
132
|
};
|
|
133
|
+
}
|
|
203
134
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
): FieldColumn<TRow>[] => {
|
|
208
|
-
return dataKeys.map((dataKey) => {
|
|
209
|
-
const overrides = options?.overrides?.[dataKey as string];
|
|
210
|
-
return column(dataKey, {
|
|
211
|
-
label: overrides?.label,
|
|
212
|
-
width: overrides?.width,
|
|
213
|
-
sort: overrides?.sort ?? options?.sort,
|
|
214
|
-
filter: overrides?.filter ?? options?.filter,
|
|
215
|
-
});
|
|
216
|
-
});
|
|
217
|
-
};
|
|
135
|
+
// =============================================================================
|
|
136
|
+
// createColumnHelper() — factory with TRow bound once
|
|
137
|
+
// =============================================================================
|
|
218
138
|
|
|
219
|
-
|
|
139
|
+
/**
|
|
140
|
+
* Factory that captures the row type once and returns `column` and `inferColumns`
|
|
141
|
+
* with `TRow` already bound, avoiding repeated type annotations.
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* ```tsx
|
|
145
|
+
* const { column, inferColumns } = createColumnHelper<Order>();
|
|
146
|
+
*
|
|
147
|
+
* const infer = inferColumns(tableMetadata.order);
|
|
148
|
+
* const columns = [
|
|
149
|
+
* column(infer("title")),
|
|
150
|
+
* column({ label: "Actions", render: (row) => <button>Edit {row.name}</button> }),
|
|
151
|
+
* ];
|
|
152
|
+
* ```
|
|
153
|
+
*/
|
|
154
|
+
export function createColumnHelper<TRow extends Record<string, unknown>>(): {
|
|
155
|
+
column: (options: ColumnOptions<TRow>) => Column<TRow>;
|
|
156
|
+
inferColumns: <const TTable extends TableMetadata = TableMetadata>(
|
|
157
|
+
tableMetadata: TTable,
|
|
158
|
+
) => (
|
|
159
|
+
dataKey: TableFieldName<TTable>,
|
|
160
|
+
options?: MetadataFieldOptions,
|
|
161
|
+
) => ColumnOptions<TRow>;
|
|
162
|
+
} {
|
|
163
|
+
return {
|
|
164
|
+
column: (options: ColumnOptions<TRow>) => column<TRow>(options),
|
|
165
|
+
inferColumns: <const TTable extends TableMetadata = TableMetadata>(
|
|
166
|
+
tableMetadata: TTable,
|
|
167
|
+
) => inferColumns<TRow, TTable>(tableMetadata),
|
|
168
|
+
};
|
|
220
169
|
}
|
package/src/component/index.ts
CHANGED
|
@@ -10,12 +10,7 @@ export type {
|
|
|
10
10
|
QueryVariables,
|
|
11
11
|
CollectionResult,
|
|
12
12
|
NodeType,
|
|
13
|
-
|
|
14
|
-
CellRenderer,
|
|
15
|
-
FieldColumnOptions,
|
|
16
|
-
DisplayColumnOptions,
|
|
17
|
-
FieldColumn,
|
|
18
|
-
DisplayColumn,
|
|
13
|
+
ColumnOptions,
|
|
19
14
|
Column,
|
|
20
15
|
ColumnDefinition,
|
|
21
16
|
UseCollectionOptions,
|
package/src/component/types.ts
CHANGED
|
@@ -12,12 +12,13 @@ import type {
|
|
|
12
12
|
/**
|
|
13
13
|
* Sort configuration for a column.
|
|
14
14
|
* The `type` determines how values are compared when sorting.
|
|
15
|
+
* The `field` identifies the backend field name used for ordering.
|
|
15
16
|
*/
|
|
16
17
|
export type SortConfig =
|
|
17
|
-
| { type: "string" }
|
|
18
|
-
| { type: "number" }
|
|
19
|
-
| { type: "date" }
|
|
20
|
-
| { type: "boolean" };
|
|
18
|
+
| { field: string; type: "string" }
|
|
19
|
+
| { field: string; type: "number" }
|
|
20
|
+
| { field: string; type: "date" }
|
|
21
|
+
| { field: string; type: "boolean" };
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
24
|
* Select option for enum/dropdown filters.
|
|
@@ -30,14 +31,15 @@ export interface SelectOption {
|
|
|
30
31
|
/**
|
|
31
32
|
* Filter configuration for a column.
|
|
32
33
|
* The `type` determines which operators are available.
|
|
34
|
+
* The `field` identifies the backend field name used for filtering.
|
|
33
35
|
*/
|
|
34
36
|
export type FilterConfig =
|
|
35
|
-
| { type: "string" }
|
|
36
|
-
| { type: "number" }
|
|
37
|
-
| { type: "date" }
|
|
38
|
-
| { type: "enum"; options: SelectOption[] }
|
|
39
|
-
| { type: "boolean" }
|
|
40
|
-
| { type: "uuid" };
|
|
37
|
+
| { field: string; type: "string" }
|
|
38
|
+
| { field: string; type: "number" }
|
|
39
|
+
| { field: string; type: "date" }
|
|
40
|
+
| { field: string; type: "enum"; options: SelectOption[] }
|
|
41
|
+
| { field: string; type: "boolean" }
|
|
42
|
+
| { field: string; type: "uuid" };
|
|
41
43
|
|
|
42
44
|
// =============================================================================
|
|
43
45
|
// Filter Operators (Single Source of Truth)
|
|
@@ -265,114 +267,57 @@ export interface CollectionResult<T> {
|
|
|
265
267
|
* type OrdersData = ResultOf<typeof GET_ORDERS>;
|
|
266
268
|
* type Order = NodeType<OrdersData["orders"]>;
|
|
267
269
|
*
|
|
268
|
-
* const {
|
|
270
|
+
* const { column } = createColumnHelper<Order>();
|
|
269
271
|
* ```
|
|
270
272
|
*/
|
|
271
273
|
export type NodeType<
|
|
272
274
|
T extends { edges: { node: unknown }[] } | null | undefined,
|
|
273
275
|
> = NonNullable<T>["edges"][number]["node"];
|
|
274
276
|
|
|
275
|
-
// =============================================================================
|
|
276
|
-
// Cell Renderer
|
|
277
|
-
// =============================================================================
|
|
278
|
-
|
|
279
|
-
/**
|
|
280
|
-
* Props passed to a custom cell renderer.
|
|
281
|
-
*/
|
|
282
|
-
export interface CellRendererProps<
|
|
283
|
-
TRow extends Record<string, unknown>,
|
|
284
|
-
TKey extends keyof TRow = never,
|
|
285
|
-
> {
|
|
286
|
-
/** The value of the cell */
|
|
287
|
-
value: [TKey] extends [never] ? unknown : TRow[TKey];
|
|
288
|
-
/** The entire row data */
|
|
289
|
-
row: TRow;
|
|
290
|
-
/** The row index (0-based) */
|
|
291
|
-
rowIndex: number;
|
|
292
|
-
/** The column definition */
|
|
293
|
-
column: ColumnDefinition<TRow>;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
/**
|
|
297
|
-
* Custom cell renderer component.
|
|
298
|
-
*/
|
|
299
|
-
export type CellRenderer<TRow extends Record<string, unknown>> = (
|
|
300
|
-
props: CellRendererProps<TRow>,
|
|
301
|
-
) => ReactNode;
|
|
302
|
-
|
|
303
277
|
// =============================================================================
|
|
304
278
|
// Column Definitions
|
|
305
279
|
// =============================================================================
|
|
306
280
|
|
|
307
281
|
/**
|
|
308
|
-
* Options for a
|
|
282
|
+
* Options for defining a column (used with `column()` helper).
|
|
309
283
|
*/
|
|
310
|
-
export interface
|
|
311
|
-
/** Column header label */
|
|
284
|
+
export interface ColumnOptions<TRow extends Record<string, unknown>> {
|
|
285
|
+
/** Column header label (displayed in table header, column selector, filter form) */
|
|
312
286
|
label?: string;
|
|
287
|
+
/** Render function for cell content (required) */
|
|
288
|
+
render: (row: TRow) => ReactNode;
|
|
289
|
+
/** Optional column identifier for visibility management (defaults to label) */
|
|
290
|
+
id?: string;
|
|
313
291
|
/** Column width in pixels */
|
|
314
292
|
width?: number;
|
|
293
|
+
/** Data accessor for CSV export and non-rendering data extraction */
|
|
294
|
+
accessor?: (row: TRow) => unknown;
|
|
315
295
|
/** Sort configuration. When specified, sorting is enabled for this column. */
|
|
316
296
|
sort?: SortConfig;
|
|
317
297
|
/** Filter configuration. When specified, filtering is enabled for this column. */
|
|
318
298
|
filter?: FilterConfig;
|
|
319
|
-
/** Custom cell renderer */
|
|
320
|
-
renderer?: CellRenderer<TRow>;
|
|
321
299
|
}
|
|
322
300
|
|
|
323
301
|
/**
|
|
324
|
-
*
|
|
302
|
+
* A column definition (produced by `column()` helper).
|
|
325
303
|
*/
|
|
326
|
-
export interface
|
|
304
|
+
export interface Column<TRow extends Record<string, unknown>> {
|
|
327
305
|
/** Column header label */
|
|
328
306
|
label?: string;
|
|
329
|
-
/**
|
|
330
|
-
width?: number;
|
|
331
|
-
/** Render function for the cell content */
|
|
307
|
+
/** Render function for cell content */
|
|
332
308
|
render: (row: TRow) => ReactNode;
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
/**
|
|
336
|
-
* A data field column definition (produced by `field()` helper).
|
|
337
|
-
*/
|
|
338
|
-
export interface FieldColumn<TRow extends Record<string, unknown>> {
|
|
339
|
-
kind: "field";
|
|
340
|
-
/** Data key corresponding to a property on the row object */
|
|
341
|
-
dataKey: string;
|
|
342
|
-
/** Column header label */
|
|
343
|
-
label?: string;
|
|
309
|
+
/** Optional column identifier for visibility management */
|
|
310
|
+
id?: string;
|
|
344
311
|
/** Column width in pixels */
|
|
345
312
|
width?: number;
|
|
313
|
+
/** Data accessor for CSV export and non-rendering data extraction */
|
|
314
|
+
accessor?: (row: TRow) => unknown;
|
|
346
315
|
/** Sort configuration */
|
|
347
316
|
sort?: SortConfig;
|
|
348
317
|
/** Filter configuration */
|
|
349
318
|
filter?: FilterConfig;
|
|
350
|
-
/** Custom cell renderer */
|
|
351
|
-
renderer?: CellRenderer<TRow>;
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
/**
|
|
355
|
-
* A display-only column definition (produced by `display()` helper).
|
|
356
|
-
*/
|
|
357
|
-
export interface DisplayColumn<TRow extends Record<string, unknown>> {
|
|
358
|
-
kind: "display";
|
|
359
|
-
/** Column identifier */
|
|
360
|
-
id: string;
|
|
361
|
-
/** Column header label */
|
|
362
|
-
label?: string;
|
|
363
|
-
/** Column width in pixels */
|
|
364
|
-
width?: number;
|
|
365
|
-
/** Render function for the cell content */
|
|
366
|
-
render: (row: TRow) => ReactNode;
|
|
367
319
|
}
|
|
368
320
|
|
|
369
|
-
/**
|
|
370
|
-
* Union of all column types.
|
|
371
|
-
*/
|
|
372
|
-
export type Column<TRow extends Record<string, unknown>> =
|
|
373
|
-
| FieldColumn<TRow>
|
|
374
|
-
| DisplayColumn<TRow>;
|
|
375
|
-
|
|
376
321
|
/**
|
|
377
322
|
* Column definition used by `useDataTable` (same as `Column`).
|
|
378
323
|
*/
|
|
@@ -960,19 +905,13 @@ export type MatchingTableName<
|
|
|
960
905
|
}[string & keyof TMetadata];
|
|
961
906
|
|
|
962
907
|
/**
|
|
963
|
-
* Options for metadata-based single field
|
|
964
|
-
*
|
|
965
|
-
* @typeParam TRow - The row type for type-safe renderer access.
|
|
908
|
+
* Options for metadata-based single field inference.
|
|
966
909
|
*/
|
|
967
|
-
export interface MetadataFieldOptions
|
|
968
|
-
TRow extends Record<string, unknown> = Record<string, unknown>,
|
|
969
|
-
> {
|
|
910
|
+
export interface MetadataFieldOptions {
|
|
970
911
|
/** Label override (defaults to metadata description or field name) */
|
|
971
912
|
label?: string;
|
|
972
913
|
/** Column width */
|
|
973
914
|
width?: number;
|
|
974
|
-
/** Custom cell renderer with typed row data */
|
|
975
|
-
renderer?: CellRenderer<TRow>;
|
|
976
915
|
/** Enable/disable sort (default: auto-detected from type) */
|
|
977
916
|
sort?: boolean;
|
|
978
917
|
/** Enable/disable filter (default: auto-detected from type) */
|
|
@@ -1143,20 +1082,23 @@ export interface PaginationProps {
|
|
|
1143
1082
|
* Map metadata field type to SortConfig.
|
|
1144
1083
|
* Returns undefined for types that don't support sorting.
|
|
1145
1084
|
*/
|
|
1146
|
-
export function fieldTypeToSortConfig(
|
|
1085
|
+
export function fieldTypeToSortConfig(
|
|
1086
|
+
field: string,
|
|
1087
|
+
type: FieldType,
|
|
1088
|
+
): SortConfig | undefined {
|
|
1147
1089
|
switch (type) {
|
|
1148
1090
|
case "string":
|
|
1149
|
-
return { type: "string" };
|
|
1091
|
+
return { field, type: "string" };
|
|
1150
1092
|
case "number":
|
|
1151
|
-
return { type: "number" };
|
|
1093
|
+
return { field, type: "number" };
|
|
1152
1094
|
case "boolean":
|
|
1153
|
-
return { type: "boolean" };
|
|
1095
|
+
return { field, type: "boolean" };
|
|
1154
1096
|
case "datetime":
|
|
1155
1097
|
case "date":
|
|
1156
1098
|
case "time":
|
|
1157
|
-
return { type: "date" };
|
|
1099
|
+
return { field, type: "date" };
|
|
1158
1100
|
case "enum":
|
|
1159
|
-
return { type: "string" };
|
|
1101
|
+
return { field, type: "string" };
|
|
1160
1102
|
default:
|
|
1161
1103
|
return undefined;
|
|
1162
1104
|
}
|
|
@@ -1167,24 +1109,26 @@ export function fieldTypeToSortConfig(type: FieldType): SortConfig | undefined {
|
|
|
1167
1109
|
* Returns undefined for types that don't support filtering.
|
|
1168
1110
|
*/
|
|
1169
1111
|
export function fieldTypeToFilterConfig(
|
|
1112
|
+
field: string,
|
|
1170
1113
|
type: FieldType,
|
|
1171
1114
|
enumValues?: readonly string[],
|
|
1172
1115
|
): FilterConfig | undefined {
|
|
1173
1116
|
switch (type) {
|
|
1174
1117
|
case "string":
|
|
1175
|
-
return { type: "string" };
|
|
1118
|
+
return { field, type: "string" };
|
|
1176
1119
|
case "number":
|
|
1177
|
-
return { type: "number" };
|
|
1120
|
+
return { field, type: "number" };
|
|
1178
1121
|
case "boolean":
|
|
1179
|
-
return { type: "boolean" };
|
|
1122
|
+
return { field, type: "boolean" };
|
|
1180
1123
|
case "uuid":
|
|
1181
|
-
return { type: "uuid" };
|
|
1124
|
+
return { field, type: "uuid" };
|
|
1182
1125
|
case "datetime":
|
|
1183
1126
|
case "date":
|
|
1184
1127
|
case "time":
|
|
1185
|
-
return { type: "date" };
|
|
1128
|
+
return { field, type: "date" };
|
|
1186
1129
|
case "enum":
|
|
1187
1130
|
return {
|
|
1131
|
+
field,
|
|
1188
1132
|
type: "enum",
|
|
1189
1133
|
options: (enumValues ?? []).map((v) => ({ value: v, label: v })),
|
|
1190
1134
|
};
|