@asteby/metacore-runtime-react 17.0.2 → 17.0.3
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/CHANGELOG.md +13 -0
- package/dist/dynamic-columns.d.ts +15 -0
- package/dist/dynamic-columns.d.ts.map +1 -1
- package/dist/dynamic-columns.js +32 -12
- package/dist/dynamic-table.d.ts.map +1 -1
- package/dist/dynamic-table.js +2 -2
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/__tests__/format-date-cell.test.ts +52 -0
- package/src/dynamic-columns.tsx +48 -19
- package/src/dynamic-table.tsx +3 -2
- package/src/types.ts +5 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# @asteby/metacore-runtime-react
|
|
2
2
|
|
|
3
|
+
## 17.0.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- b5c8f5f: Pro datetime columns: `datetime`/`timestamp`/`timestamptz` columns now use the
|
|
8
|
+
date cell renderer instead of falling through to the raw-ISO fallback. Datetime
|
|
9
|
+
variants show day + time with a full-precision tooltip on hover (the 7Leguas
|
|
10
|
+
pattern); plain `date` columns stay day-only. Null and the Go zero-time render
|
|
11
|
+
an em-dash. Date-typed columns (including the timestamp variants) now infer the
|
|
12
|
+
`date_range` filter. Adds a pure `formatDateCell` helper (+ tests).
|
|
13
|
+
- Updated dependencies [b5c8f5f]
|
|
14
|
+
- @asteby/metacore-ui@2.4.2
|
|
15
|
+
|
|
3
16
|
## 17.0.2
|
|
4
17
|
|
|
5
18
|
### Patch Changes
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type Locale } from 'date-fns';
|
|
1
2
|
import type { ColumnDefinition } from './types';
|
|
2
3
|
import type { GetDynamicColumns } from './dynamic-columns-shim';
|
|
3
4
|
/** Host-supplied helpers consumed by avatar/image cell renderers. */
|
|
@@ -37,6 +38,20 @@ export declare const isActionAllowedForRowState: (action: any, row: any) => bool
|
|
|
37
38
|
* cell can read `row[relationKeyFor(col)]`.
|
|
38
39
|
*/
|
|
39
40
|
export declare const relationKeyFor: (col: Pick<ColumnDefinition, "key">) => string;
|
|
41
|
+
/** Cell renderers (`cellStyle`/`type`) that resolve to the date renderer. */
|
|
42
|
+
export declare const DATE_CELL_TYPES: readonly ["date", "datetime", "timestamp", "timestamptz"];
|
|
43
|
+
/**
|
|
44
|
+
* Pure formatter behind the date/datetime cell. Returns the display string and
|
|
45
|
+
* an optional full-precision `title` (tooltip), or `null` when the value is
|
|
46
|
+
* empty/invalid/the Go zero-time so the cell renders an em-dash.
|
|
47
|
+
* - `date`: day only (`PPP`), no tooltip.
|
|
48
|
+
* - `datetime`/`timestamp(tz)`: day + time (`Pp`) with a full-precision
|
|
49
|
+
* tooltip (`PPpp`) — the 7Leguas pattern.
|
|
50
|
+
*/
|
|
51
|
+
export declare function formatDateCell(value: unknown, renderAs: string | undefined, locale: Locale): {
|
|
52
|
+
display: string;
|
|
53
|
+
title?: string;
|
|
54
|
+
} | null;
|
|
40
55
|
/**
|
|
41
56
|
* Reads the resolved relation/option label a backend serves for an FK or
|
|
42
57
|
* option column, falling back to the raw value. Pure so the cell renderers and
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dynamic-columns.d.ts","sourceRoot":"","sources":["../src/dynamic-columns.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"dynamic-columns.d.ts","sourceRoot":"","sources":["../src/dynamic-columns.tsx"],"names":[],"mappings":"AAgBA,OAAO,EAAU,KAAK,MAAM,EAAE,MAAM,UAAU,CAAA;AAgC9C,OAAO,KAAK,EAAiB,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAE9D,OAAO,KAAK,EAER,iBAAiB,EACpB,MAAM,wBAAwB,CAAA;AAE/B,qEAAqE;AACrE,MAAM,WAAW,qBAAqB;IAClC;;;;OAIG;IACH,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA;IACtC;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;CACtB;AAgGD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,0BAA0B,GAAI,QAAQ,GAAG,EAAE,KAAK,GAAG,KAAG,OAMlE,CAAA;AA0HD;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,GAAI,KAAK,IAAI,CAAC,gBAAgB,EAAE,KAAK,CAAC,KAAG,MAGnE,CAAA;AAED,6EAA6E;AAC7E,eAAO,MAAM,eAAe,2DAA4D,CAAA;AAExF;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC1B,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,MAAM,EAAE,MAAM,GACf;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAY5C;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,GAAI,KAAK,gBAAgB,EAAE,KAAK,GAAG,KAAG,MAWtE,CAAA;AAiED;;;;GAIG;AACH,wBAAgB,4BAA4B,CACxC,OAAO,GAAE,qBAA0B,GACpC,iBAAiB,CAsmBnB;AAED;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,EAAE,iBACL,CAAA"}
|
package/dist/dynamic-columns.js
CHANGED
|
@@ -201,6 +201,31 @@ export const relationKeyFor = (col) => {
|
|
|
201
201
|
const k = col.key;
|
|
202
202
|
return k.endsWith('_id') ? k.slice(0, -3) : k;
|
|
203
203
|
};
|
|
204
|
+
/** Cell renderers (`cellStyle`/`type`) that resolve to the date renderer. */
|
|
205
|
+
export const DATE_CELL_TYPES = ['date', 'datetime', 'timestamp', 'timestamptz'];
|
|
206
|
+
/**
|
|
207
|
+
* Pure formatter behind the date/datetime cell. Returns the display string and
|
|
208
|
+
* an optional full-precision `title` (tooltip), or `null` when the value is
|
|
209
|
+
* empty/invalid/the Go zero-time so the cell renders an em-dash.
|
|
210
|
+
* - `date`: day only (`PPP`), no tooltip.
|
|
211
|
+
* - `datetime`/`timestamp(tz)`: day + time (`Pp`) with a full-precision
|
|
212
|
+
* tooltip (`PPpp`) — the 7Leguas pattern.
|
|
213
|
+
*/
|
|
214
|
+
export function formatDateCell(value, renderAs, locale) {
|
|
215
|
+
if (value === null || value === undefined || value === '')
|
|
216
|
+
return null;
|
|
217
|
+
const date = new Date(value);
|
|
218
|
+
if (isNaN(date.getTime()) || date.getFullYear() <= 1)
|
|
219
|
+
return null;
|
|
220
|
+
const withTime = renderAs !== 'date';
|
|
221
|
+
if (withTime) {
|
|
222
|
+
return {
|
|
223
|
+
display: format(date, 'Pp', { locale }),
|
|
224
|
+
title: format(date, 'PPpp', { locale }),
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
return { display: format(date, 'PPP', { locale }) };
|
|
228
|
+
}
|
|
204
229
|
/**
|
|
205
230
|
* Reads the resolved relation/option label a backend serves for an FK or
|
|
206
231
|
* option column, falling back to the raw value. Pure so the cell renderers and
|
|
@@ -370,19 +395,14 @@ export function makeDefaultGetDynamicColumns(helpers = {}) {
|
|
|
370
395
|
return _jsx(Badge, { variant: "outline", children: humanizeToken(value) });
|
|
371
396
|
}
|
|
372
397
|
switch (renderAs) {
|
|
373
|
-
case 'date':
|
|
374
|
-
|
|
398
|
+
case 'date':
|
|
399
|
+
case 'datetime':
|
|
400
|
+
case 'timestamp':
|
|
401
|
+
case 'timestamptz': {
|
|
402
|
+
const formatted = formatDateCell(value, renderAs, dateLocale);
|
|
403
|
+
if (!formatted)
|
|
375
404
|
return _jsx("span", { className: "text-muted-foreground", children: "-" });
|
|
376
|
-
|
|
377
|
-
const date = new Date(value);
|
|
378
|
-
if (isNaN(date.getTime()) || date.getFullYear() <= 1) {
|
|
379
|
-
return _jsx("span", { className: "text-muted-foreground", children: "-" });
|
|
380
|
-
}
|
|
381
|
-
return (_jsxs("div", { className: "flex items-center gap-1.5 text-muted-foreground", children: [_jsx(icons.Calendar, { className: "h-3.5 w-3.5 opacity-70" }), _jsx("span", { className: "text-sm font-medium", children: format(date, 'PPP', { locale: dateLocale }) })] }));
|
|
382
|
-
}
|
|
383
|
-
catch {
|
|
384
|
-
return _jsx("span", { children: String(value) });
|
|
385
|
-
}
|
|
405
|
+
return (_jsxs("div", { className: "flex items-center gap-1.5 text-muted-foreground", title: formatted.title, children: [_jsx(icons.Calendar, { className: "h-3.5 w-3.5 opacity-70" }), _jsx("span", { className: "text-sm font-medium", children: formatted.display })] }));
|
|
386
406
|
}
|
|
387
407
|
case 'search':
|
|
388
408
|
case 'avatar':
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dynamic-table.d.ts","sourceRoot":"","sources":["../src/dynamic-table.tsx"],"names":[],"mappings":"AAiBA,OAAO,EAKH,KAAK,SAAS,EAajB,MAAM,uBAAuB,CAAA;AA+B9B,OAAO,KAAK,EAAsB,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAUnF,UAAU,iBAAiB;IACvB,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;IACxB,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,IAAI,CAAA;IAC7C,cAAc,CAAC,EAAE,GAAG,CAAA;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACpC,YAAY,CAAC,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,CAAA;IAC/B;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,iBAAiB,CAAA;CACxC;AAED,wBAAgB,YAAY,CAAC,EACzB,KAAK,EACL,QAAQ,EACR,aAAoB,EACpB,aAAkB,EAClB,QAAQ,EACR,cAAc,EACd,cAAc,EACd,YAAiB,EACjB,iBAA4C,GAC/C,EAAE,iBAAiB,+
|
|
1
|
+
{"version":3,"file":"dynamic-table.d.ts","sourceRoot":"","sources":["../src/dynamic-table.tsx"],"names":[],"mappings":"AAiBA,OAAO,EAKH,KAAK,SAAS,EAajB,MAAM,uBAAuB,CAAA;AA+B9B,OAAO,KAAK,EAAsB,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAUnF,UAAU,iBAAiB;IACvB,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;IACxB,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,IAAI,CAAA;IAC7C,cAAc,CAAC,EAAE,GAAG,CAAA;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACpC,YAAY,CAAC,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,CAAA;IAC/B;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,iBAAiB,CAAA;CACxC;AAED,wBAAgB,YAAY,CAAC,EACzB,KAAK,EACL,QAAQ,EACR,aAAoB,EACpB,aAAkB,EAClB,QAAQ,EACR,cAAc,EACd,cAAc,EACd,YAAiB,EACjB,iBAA4C,GAC/C,EAAE,iBAAiB,+BAgyBnB"}
|
package/dist/dynamic-table.js
CHANGED
|
@@ -24,7 +24,7 @@ import { toast } from 'sonner';
|
|
|
24
24
|
import { Progress } from './dialogs/_primitives';
|
|
25
25
|
import { useMetadataCache } from './metadata-cache';
|
|
26
26
|
import { useApi, useCurrentBranch } from './api-context';
|
|
27
|
-
import { defaultGetDynamicColumns } from './dynamic-columns';
|
|
27
|
+
import { defaultGetDynamicColumns, DATE_CELL_TYPES } from './dynamic-columns';
|
|
28
28
|
import { OptionsContext } from './options-context';
|
|
29
29
|
import { ActionModalDispatcher } from './action-modal-dispatcher';
|
|
30
30
|
import { getSearchableColumnKeys } from './column-visibility';
|
|
@@ -520,7 +520,7 @@ export function DynamicTable({ model, endpoint, enableUrlSync = true, hiddenColu
|
|
|
520
520
|
filterType = 'boolean';
|
|
521
521
|
else if (c.type === 'number')
|
|
522
522
|
filterType = 'number_range';
|
|
523
|
-
else if (c.type
|
|
523
|
+
else if (DATE_CELL_TYPES.includes(c.type))
|
|
524
524
|
filterType = 'date_range';
|
|
525
525
|
else
|
|
526
526
|
filterType = 'text';
|
package/dist/types.d.ts
CHANGED
|
@@ -81,7 +81,7 @@ export type ColumnVisibility = 'all' | 'table' | 'modal' | 'list' | (string & {}
|
|
|
81
81
|
export interface ColumnDefinition {
|
|
82
82
|
key: string;
|
|
83
83
|
label: string;
|
|
84
|
-
type: 'text' | 'number' | 'date' | 'select' | 'search' | 'relation-badge-list' | 'avatar' | 'boolean' | 'phone' | 'media-gallery' | 'image' | 'url' | 'link' | 'email' | 'currency' | 'percent' | 'progress' | 'badge' | 'status' | 'tags' | 'color' | 'code' | 'truncate-text' | 'creator' | 'user' | 'relation';
|
|
84
|
+
type: 'text' | 'number' | 'date' | 'datetime' | 'timestamp' | 'timestamptz' | 'select' | 'search' | 'relation-badge-list' | 'avatar' | 'boolean' | 'phone' | 'media-gallery' | 'image' | 'url' | 'link' | 'email' | 'currency' | 'percent' | 'progress' | 'badge' | 'status' | 'tags' | 'color' | 'code' | 'truncate-text' | 'creator' | 'user' | 'relation';
|
|
85
85
|
sortable: boolean;
|
|
86
86
|
filterable: boolean;
|
|
87
87
|
/**
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,aAAa;IAC1B,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,gBAAgB,EAAE,CAAA;IAC3B,OAAO,EAAE,gBAAgB,EAAE,CAAA;IAC3B,OAAO,CAAC,EAAE,gBAAgB,EAAE,CAAA;IAC5B,cAAc,EAAE,MAAM,EAAE,CAAA;IACxB,cAAc,EAAE,MAAM,CAAA;IACtB,iBAAiB,EAAE,MAAM,CAAA;IACzB,iBAAiB,EAAE,OAAO,CAAA;IAC1B,UAAU,EAAE,OAAO,CAAA;IACnB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,YAAY,EAAE,CAAA;CAC7B;AAED;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IACzB,4EAA4E;IAC5E,IAAI,EAAE,MAAM,CAAA;IACZ,kEAAkE;IAClE,IAAI,EAAE,aAAa,GAAG,cAAc,CAAA;IACpC;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAA;IACf,sDAAsD;IACtD,WAAW,EAAE,MAAM,CAAA;IACnB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC9B,mCAAmC;IACnC,KAAK,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC7B,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb;;;;;OAKG;IACH,IAAI,EAAE,QAAQ,GAAG,gBAAgB,GAAG,SAAS,GAAG,YAAY,GAAG,cAAc,GAAG,MAAM,CAAA;IACtF,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IACrF,cAAc,CAAC,EAAE,MAAM,CAAA;CAC1B;AAED;;;;;;;;;GASG;AACH,MAAM,MAAM,gBAAgB,GAAG,KAAK,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAA;AAEjF,MAAM,WAAW,gBAAgB;IAC7B,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EACE,MAAM,GACN,QAAQ,GACR,MAAM,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@asteby/metacore-runtime-react",
|
|
3
|
-
"version": "17.0.
|
|
3
|
+
"version": "17.0.3",
|
|
4
4
|
"description": "React runtime for metacore hosts — renders addon contributions dynamically",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"date-fns": ">=3",
|
|
35
35
|
"react-day-picker": ">=8",
|
|
36
36
|
"@asteby/metacore-sdk": "^3.2.0",
|
|
37
|
-
"@asteby/metacore-ui": "^2.4.
|
|
37
|
+
"@asteby/metacore-ui": "^2.4.2"
|
|
38
38
|
},
|
|
39
39
|
"peerDependenciesMeta": {
|
|
40
40
|
"@tanstack/react-router": {
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
"vitest": "^4.0.0",
|
|
63
63
|
"zustand": "^5.0.0",
|
|
64
64
|
"@asteby/metacore-sdk": "3.2.0",
|
|
65
|
-
"@asteby/metacore-ui": "2.4.
|
|
65
|
+
"@asteby/metacore-ui": "2.4.2"
|
|
66
66
|
},
|
|
67
67
|
"scripts": {
|
|
68
68
|
"build": "tsc -p tsconfig.json",
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// Pure-logic coverage for the date/datetime cell formatter behind
|
|
2
|
+
// `defaultGetDynamicColumns`. Locks the contract the JSX cell relies on:
|
|
3
|
+
// `date` → day only (no tooltip), `datetime`/`timestamp(tz)` → day + time with
|
|
4
|
+
// a full-precision tooltip, and null/invalid/Go-zero-time → `null` (em-dash).
|
|
5
|
+
import { describe, it, expect } from 'vitest'
|
|
6
|
+
import { enUS } from 'date-fns/locale'
|
|
7
|
+
import { formatDateCell } from '../dynamic-columns'
|
|
8
|
+
|
|
9
|
+
describe('formatDateCell', () => {
|
|
10
|
+
const iso = '2026-06-06T17:47:33.201Z'
|
|
11
|
+
|
|
12
|
+
it('renders day only with no tooltip for `date`', () => {
|
|
13
|
+
const out = formatDateCell(iso, 'date', enUS)
|
|
14
|
+
expect(out).not.toBeNull()
|
|
15
|
+
expect(out!.title).toBeUndefined()
|
|
16
|
+
// `PPP` is the long day form — no time component.
|
|
17
|
+
expect(out!.display).not.toMatch(/\d{1,2}:\d{2}/)
|
|
18
|
+
expect(out!.display).toMatch(/2026/)
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
it('renders day + time and a full-precision tooltip for `datetime`', () => {
|
|
22
|
+
const out = formatDateCell(iso, 'datetime', enUS)
|
|
23
|
+
expect(out).not.toBeNull()
|
|
24
|
+
expect(out!.display).toMatch(/\d{1,2}:\d{2}/)
|
|
25
|
+
expect(out!.title).toBeDefined()
|
|
26
|
+
expect(out!.title).toMatch(/\d{1,2}:\d{2}/)
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
it('treats timestamp/timestamptz like datetime (day + time + tooltip)', () => {
|
|
30
|
+
for (const t of ['timestamp', 'timestamptz']) {
|
|
31
|
+
const out = formatDateCell(iso, t, enUS)
|
|
32
|
+
expect(out).not.toBeNull()
|
|
33
|
+
expect(out!.display).toMatch(/\d{1,2}:\d{2}/)
|
|
34
|
+
expect(out!.title).toBeDefined()
|
|
35
|
+
}
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('returns null for null/undefined/empty (empty cell)', () => {
|
|
39
|
+
expect(formatDateCell(null, 'datetime', enUS)).toBeNull()
|
|
40
|
+
expect(formatDateCell(undefined, 'datetime', enUS)).toBeNull()
|
|
41
|
+
expect(formatDateCell('', 'datetime', enUS)).toBeNull()
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it('returns null for the Go zero-time (0001-01-01T00:00:00Z)', () => {
|
|
45
|
+
expect(formatDateCell('0001-01-01T00:00:00Z', 'datetime', enUS)).toBeNull()
|
|
46
|
+
expect(formatDateCell('0001-01-01T00:00:00Z', 'date', enUS)).toBeNull()
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it('returns null for an unparseable value', () => {
|
|
50
|
+
expect(formatDateCell('not-a-date', 'datetime', enUS)).toBeNull()
|
|
51
|
+
})
|
|
52
|
+
})
|
package/src/dynamic-columns.tsx
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
import * as React from 'react'
|
|
16
16
|
import { ColumnDef } from '@tanstack/react-table'
|
|
17
|
-
import { format } from 'date-fns'
|
|
17
|
+
import { format, type Locale } from 'date-fns'
|
|
18
18
|
import { es, enUS } from 'date-fns/locale'
|
|
19
19
|
import * as icons from 'lucide-react'
|
|
20
20
|
import { MoreHorizontal } from 'lucide-react'
|
|
@@ -316,6 +316,35 @@ export const relationKeyFor = (col: Pick<ColumnDefinition, 'key'>): string => {
|
|
|
316
316
|
return k.endsWith('_id') ? k.slice(0, -3) : k
|
|
317
317
|
}
|
|
318
318
|
|
|
319
|
+
/** Cell renderers (`cellStyle`/`type`) that resolve to the date renderer. */
|
|
320
|
+
export const DATE_CELL_TYPES = ['date', 'datetime', 'timestamp', 'timestamptz'] as const
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Pure formatter behind the date/datetime cell. Returns the display string and
|
|
324
|
+
* an optional full-precision `title` (tooltip), or `null` when the value is
|
|
325
|
+
* empty/invalid/the Go zero-time so the cell renders an em-dash.
|
|
326
|
+
* - `date`: day only (`PPP`), no tooltip.
|
|
327
|
+
* - `datetime`/`timestamp(tz)`: day + time (`Pp`) with a full-precision
|
|
328
|
+
* tooltip (`PPpp`) — the 7Leguas pattern.
|
|
329
|
+
*/
|
|
330
|
+
export function formatDateCell(
|
|
331
|
+
value: unknown,
|
|
332
|
+
renderAs: string | undefined,
|
|
333
|
+
locale: Locale,
|
|
334
|
+
): { display: string; title?: string } | null {
|
|
335
|
+
if (value === null || value === undefined || value === '') return null
|
|
336
|
+
const date = new Date(value as any)
|
|
337
|
+
if (isNaN(date.getTime()) || date.getFullYear() <= 1) return null
|
|
338
|
+
const withTime = renderAs !== 'date'
|
|
339
|
+
if (withTime) {
|
|
340
|
+
return {
|
|
341
|
+
display: format(date, 'Pp', { locale }),
|
|
342
|
+
title: format(date, 'PPpp', { locale }),
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
return { display: format(date, 'PPP', { locale }) }
|
|
346
|
+
}
|
|
347
|
+
|
|
319
348
|
/**
|
|
320
349
|
* Reads the resolved relation/option label a backend serves for an FK or
|
|
321
350
|
* option column, falling back to the raw value. Pure so the cell renderers and
|
|
@@ -564,24 +593,24 @@ export function makeDefaultGetDynamicColumns(
|
|
|
564
593
|
}
|
|
565
594
|
|
|
566
595
|
switch (renderAs) {
|
|
567
|
-
case 'date':
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
596
|
+
case 'date':
|
|
597
|
+
case 'datetime':
|
|
598
|
+
case 'timestamp':
|
|
599
|
+
case 'timestamptz': {
|
|
600
|
+
const formatted = formatDateCell(value, renderAs, dateLocale)
|
|
601
|
+
if (!formatted)
|
|
602
|
+
return <span className="text-muted-foreground">-</span>
|
|
603
|
+
return (
|
|
604
|
+
<div
|
|
605
|
+
className="flex items-center gap-1.5 text-muted-foreground"
|
|
606
|
+
title={formatted.title}
|
|
607
|
+
>
|
|
608
|
+
<icons.Calendar className="h-3.5 w-3.5 opacity-70" />
|
|
609
|
+
<span className="text-sm font-medium">
|
|
610
|
+
{formatted.display}
|
|
611
|
+
</span>
|
|
612
|
+
</div>
|
|
613
|
+
)
|
|
585
614
|
}
|
|
586
615
|
|
|
587
616
|
case 'search':
|
package/src/dynamic-table.tsx
CHANGED
|
@@ -65,7 +65,7 @@ import { Progress } from './dialogs/_primitives'
|
|
|
65
65
|
import { useMetadataCache } from './metadata-cache'
|
|
66
66
|
import { useApi, useCurrentBranch } from './api-context'
|
|
67
67
|
import type { ColumnFilterConfig, GetDynamicColumns } from './dynamic-columns-shim'
|
|
68
|
-
import { defaultGetDynamicColumns } from './dynamic-columns'
|
|
68
|
+
import { defaultGetDynamicColumns, DATE_CELL_TYPES } from './dynamic-columns'
|
|
69
69
|
import { OptionsContext } from './options-context'
|
|
70
70
|
import { ActionModalDispatcher } from './action-modal-dispatcher'
|
|
71
71
|
import type { TableMetadata, ApiResponse, ActionMetadata } from './types'
|
|
@@ -555,7 +555,8 @@ export function DynamicTable({
|
|
|
555
555
|
else if (hasStaticOptions || hasEndpoint) filterType = 'select'
|
|
556
556
|
else if (c.type === 'boolean') filterType = 'boolean'
|
|
557
557
|
else if (c.type === 'number') filterType = 'number_range'
|
|
558
|
-
else if (c.type
|
|
558
|
+
else if ((DATE_CELL_TYPES as readonly string[]).includes(c.type))
|
|
559
|
+
filterType = 'date_range'
|
|
559
560
|
else filterType = 'text'
|
|
560
561
|
|
|
561
562
|
const options = hasStaticOptions
|
package/src/types.ts
CHANGED
|
@@ -87,6 +87,11 @@ export interface ColumnDefinition {
|
|
|
87
87
|
| 'text'
|
|
88
88
|
| 'number'
|
|
89
89
|
| 'date'
|
|
90
|
+
// Timestamp variants. They share the `date` cell renderer but append
|
|
91
|
+
// the time + a full-precision tooltip (see formatDateCell).
|
|
92
|
+
| 'datetime'
|
|
93
|
+
| 'timestamp'
|
|
94
|
+
| 'timestamptz'
|
|
90
95
|
| 'select'
|
|
91
96
|
| 'search'
|
|
92
97
|
| 'relation-badge-list'
|