@object-ui/plugin-dashboard 17.6.0 → 18.0.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/CHANGELOG.md +5044 -0
- package/README.md +465 -85
- package/dist/DashboardConfigPanel.d.ts +1 -1
- package/dist/DashboardFilterBar.d.ts.map +1 -1
- package/dist/DashboardGridLayout.d.ts +10 -8
- package/dist/DashboardGridLayout.d.ts.map +1 -1
- package/dist/DashboardRenderer.d.ts +60 -2
- package/dist/DashboardRenderer.d.ts.map +1 -1
- package/dist/DashboardWithConfig.d.ts +1 -1
- package/dist/DashboardWithConfig.d.ts.map +1 -1
- package/dist/DatasetWidget.d.ts +41 -14
- package/dist/DatasetWidget.d.ts.map +1 -1
- package/dist/DrillDownDrawer.d.ts +14 -5
- package/dist/DrillDownDrawer.d.ts.map +1 -1
- package/dist/MetricCard.d.ts +7 -1
- package/dist/MetricCard.d.ts.map +1 -1
- package/dist/MetricWidget.d.ts +48 -6
- package/dist/MetricWidget.d.ts.map +1 -1
- package/dist/ObjectDataTable.d.ts +407 -18
- package/dist/ObjectDataTable.d.ts.map +1 -1
- package/dist/ObjectMetricWidget.d.ts +35 -8
- package/dist/ObjectMetricWidget.d.ts.map +1 -1
- package/dist/ObjectPivotTable.d.ts +47 -7
- package/dist/ObjectPivotTable.d.ts.map +1 -1
- package/dist/PivotTable.d.ts +20 -3
- package/dist/PivotTable.d.ts.map +1 -1
- package/dist/RecordDetailDrawer.d.ts +21 -2
- package/dist/RecordDetailDrawer.d.ts.map +1 -1
- package/dist/WidgetConfigPanel.d.ts +2 -2
- package/dist/WidgetConfigPanel.d.ts.map +1 -1
- package/dist/WidgetEmptyState.d.ts +27 -0
- package/dist/WidgetEmptyState.d.ts.map +1 -0
- package/dist/chartRenderHandoff.d.ts +9 -0
- package/dist/chartRenderHandoff.d.ts.map +1 -0
- package/dist/domPassthroughPins.d.ts.map +1 -1
- package/dist/index.d.ts +22 -21
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1977 -1715
- package/dist/index.umd.cjs +3 -2
- package/dist/legacyRetiredWidget.d.ts +28 -3
- package/dist/legacyRetiredWidget.d.ts.map +1 -1
- package/dist/measureRefusal.d.ts +50 -0
- package/dist/measureRefusal.d.ts.map +1 -0
- package/dist/metricTile.d.ts +87 -0
- package/dist/metricTile.d.ts.map +1 -0
- package/dist/recordFields.d.ts +119 -8
- package/dist/recordFields.d.ts.map +1 -1
- package/dist/retired-node-types.d.ts +29 -0
- package/dist/retired-node-types.d.ts.map +1 -0
- package/dist/schemaHostProps.d.ts +55 -11
- package/dist/schemaHostProps.d.ts.map +1 -1
- package/dist/useDashboardAutoRefresh.d.ts +47 -0
- package/dist/useDashboardAutoRefresh.d.ts.map +1 -0
- package/dist/utils.d.ts +60 -13
- package/dist/utils.d.ts.map +1 -1
- package/dist/widgetDispatch.d.ts +174 -18
- package/dist/widgetDispatch.d.ts.map +1 -1
- package/package.json +15 -16
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DashboardWidgetSlotEntry } from './widgetDispatch.js';
|
|
2
2
|
/**
|
|
3
3
|
* The placeholder schema rendered in place of a retired inline-analytics widget.
|
|
4
4
|
*
|
|
@@ -10,7 +10,7 @@ import { DashboardWidgetSchema } from '@object-ui/types';
|
|
|
10
10
|
*/
|
|
11
11
|
export declare const LEGACY_RETIRED_WIDGET_SCHEMA: {
|
|
12
12
|
readonly type: "text";
|
|
13
|
-
readonly
|
|
13
|
+
readonly content: "This widget uses a retired data format. Edit it to bind a dataset.";
|
|
14
14
|
readonly variant: "caption";
|
|
15
15
|
readonly align: "center";
|
|
16
16
|
readonly className: "flex h-full w-full items-center justify-center rounded border border-dashed border-destructive/40 bg-destructive/5 p-4 text-center text-destructive";
|
|
@@ -37,5 +37,30 @@ export declare const LEGACY_RETIRED_WIDGET_SCHEMA: {
|
|
|
37
37
|
* surface no observable behavior, and it keeps the predicate true on its own
|
|
38
38
|
* terms for any surface that has no such fork.
|
|
39
39
|
*/
|
|
40
|
-
export declare function isLegacyRetiredWidget(widget:
|
|
40
|
+
export declare function isLegacyRetiredWidget(widget: DashboardWidgetSlotEntry | null | undefined): boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Is `node`, read from a widget's legacy `component` envelope
|
|
43
|
+
* (`{ id, component, layout }`, objectui's own format, which the spec's widget
|
|
44
|
+
* has no member for), a node the surfaces no longer draw? True for every node
|
|
45
|
+
* but a `metric-card` (objectui#12254).
|
|
46
|
+
*
|
|
47
|
+
* The envelope takes a `metric-card` and nothing else: the 2026-08-14 slot
|
|
48
|
+
* ruling (objectstack#8593) allowed that one node, and since objectui#12163
|
|
49
|
+
* (ruling C) both zod faces and `DashboardWidgetSchema['component']` refuse any
|
|
50
|
+
* other node by name. objectui#12254 retires the draw to match, after a census
|
|
51
|
+
* of stored use found no producer. So the accept set is the authoring one, read
|
|
52
|
+
* from the same closed list, `DASHBOARD_COMPONENT_WIDGET_TYPES`: a node whose
|
|
53
|
+
* `type` is a member draws as before, and anything else in the envelope (a
|
|
54
|
+
* node of another type, a node with no `type`, a string or a number) draws
|
|
55
|
+
* {@link LEGACY_RETIRED_WIDGET_SCHEMA}, the rebind prompt the metric and pivot
|
|
56
|
+
* arms return, and sends no query. The `object-metric` node objectui#11466
|
|
57
|
+
* retired here first is one case of the rule.
|
|
58
|
+
*
|
|
59
|
+
* An empty envelope (`component` absent, or a falsy value) holds no node, so
|
|
60
|
+
* this answers false and the widget draws by its family, as before.
|
|
61
|
+
*
|
|
62
|
+
* ⛔ Read only at the envelope: the same node types authored on a page, or a
|
|
63
|
+
* `metric-card` placed directly in `widgets[]`, are not judged here.
|
|
64
|
+
*/
|
|
65
|
+
export declare function isRetiredEnvelopeNode(node: unknown): boolean;
|
|
41
66
|
//# sourceMappingURL=legacyRetiredWidget.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"legacyRetiredWidget.d.ts","sourceRoot":"","sources":["../src/legacyRetiredWidget.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"legacyRetiredWidget.d.ts","sourceRoot":"","sources":["../src/legacyRetiredWidget.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAuDH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAC;AAEjE;;;;;;;;GAQG;AACH,eAAO,MAAM,4BAA4B;;;;;;CAM/B,CAAC;AAoBX;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,wBAAwB,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAMlG;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAI5D"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObjectUI
|
|
3
|
+
* Copyright (c) 2024-present ObjectStack Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* objectui#8894 — what the widget door says about a widget's MEASURES.
|
|
10
|
+
*
|
|
11
|
+
* Returns the message of the `custom` issue objectui's authoring door raises at
|
|
12
|
+
* `values` for this type, these measures and these dimensions, or `undefined`
|
|
13
|
+
* when the door accepts them. The door is `DashboardWidgetSchema` from
|
|
14
|
+
* `@object-ui/types/zod`, which re-attaches the spec's own object-level checks,
|
|
15
|
+
* so its verdict and its message are the spec's (pinned by
|
|
16
|
+
* `packages/types/src/__tests__/dashboard-widget-metric-measure-door-8894.test.ts`).
|
|
17
|
+
*
|
|
18
|
+
* The door is ASKED, never restated: no widget-type list lives here. Whichever
|
|
19
|
+
* types the spec refuses a second measure on — the metric family since
|
|
20
|
+
* `@objectstack/spec` 17.5.0 (`checkDashboardWidgetMetricMeasureArity`), and
|
|
21
|
+
* any further shape once a spec release refuses it and the mirror re-attaches
|
|
22
|
+
* that check (objectstack#20958 is the pending one) — the authoring pickers that
|
|
23
|
+
* read this follow without an edit here.
|
|
24
|
+
*
|
|
25
|
+
* Only the keys a measure rule reads go into the probe — `id` (the message
|
|
26
|
+
* names it), `type`, `values` and `dimensions` — each kept to a shape the door
|
|
27
|
+
* accepts. zod skips object-level checks once a field-level issue aborts the
|
|
28
|
+
* parse, and a draft in an editor is half-written by nature: measured on the
|
|
29
|
+
* mirror, a numeric `id`, a non-string dimension or a malformed `title`
|
|
30
|
+
* anywhere in the document each hide the measure verdict completely, which
|
|
31
|
+
* would read as "accepted". The probe keeps those faults out of the question it
|
|
32
|
+
* asks.
|
|
33
|
+
*
|
|
34
|
+
* Module-private to this package (not re-exported from its index).
|
|
35
|
+
*/
|
|
36
|
+
export declare function measureRefusal(widget: {
|
|
37
|
+
id?: unknown;
|
|
38
|
+
type?: unknown;
|
|
39
|
+
values?: unknown;
|
|
40
|
+
dimensions?: unknown;
|
|
41
|
+
}): string | undefined;
|
|
42
|
+
/**
|
|
43
|
+
* A stand-in for "one more measure", used to ask the door whether a picker may
|
|
44
|
+
* offer another one before the author has chosen which. The door's measure
|
|
45
|
+
* rules judge how many measures a widget declares, not their names (whether a
|
|
46
|
+
* measure exists in the bound dataset is out of the widget schema's reach), so
|
|
47
|
+
* any name the widget does not already carry asks the same question.
|
|
48
|
+
*/
|
|
49
|
+
export declare const NEXT_MEASURE_PROBE = "__next_measure__";
|
|
50
|
+
//# sourceMappingURL=measureRefusal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"measureRefusal.d.ts","sourceRoot":"","sources":["../src/measureRefusal.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE;IACrC,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,GAAG,MAAM,GAAG,SAAS,CAgBrB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The metric tile's layout rule — ONE home, read by every metric tile in this
|
|
3
|
+
* package: the plain cards (`MetricCard`, `MetricWidget`, and through it
|
|
4
|
+
* `ObjectMetricWidget` and every `object-metric` page block) and the
|
|
5
|
+
* dataset-bound tile (`DatasetWidget`) (objectui#12623).
|
|
6
|
+
*
|
|
7
|
+
* - The title owns the first line: 13 px / 500, up to two lines, an ellipsis
|
|
8
|
+
* on the second. Nothing shares its line but the plain card's icon chip.
|
|
9
|
+
* - The value never wraps, and it scales before it would clip
|
|
10
|
+
* (objectui#12942). A short value is one step smaller (20 px) in a tile
|
|
11
|
+
* narrower than 160 px, 24 px from 160 px up. A longer one — a seven-digit
|
|
12
|
+
* money figure with cents — takes a size ladder from 14 px to 24 px whose
|
|
13
|
+
* steps start where that size fits (`metricTileValueClass`).
|
|
14
|
+
* - The measure label (dataset-bound tile only) is an 11 px muted line under
|
|
15
|
+
* the value, dropped below 160 px. The title's tooltip carries it, so it is
|
|
16
|
+
* still there at every width.
|
|
17
|
+
*
|
|
18
|
+
* Width rules key off the TILE's own box (`@container` on the tile, `@[160px]:`
|
|
19
|
+
* variants), never the viewport: a dashboard grid, a page block and the
|
|
20
|
+
* Studio's folded canvas each size the same tile differently.
|
|
21
|
+
*
|
|
22
|
+
* Class strings stay static literals so Tailwind's content scanner sees them
|
|
23
|
+
* (`apps/console/src/index.css` sources this package's `src/**`).
|
|
24
|
+
*/
|
|
25
|
+
/** Put on the tile's root: the box the width rules below are measured against. */
|
|
26
|
+
export declare const METRIC_TILE_CONTAINER_CLASS = "@container";
|
|
27
|
+
/** The title: owns the first line, at most two lines, an ellipsis on the second. */
|
|
28
|
+
export declare const METRIC_TILE_TITLE_CLASS = "min-w-0 line-clamp-2 break-words text-[13px] font-medium leading-snug text-foreground";
|
|
29
|
+
/**
|
|
30
|
+
* The value: never wraps; 20 px below a 160 px tile, 24 px from 160 px up. The
|
|
31
|
+
* short value's face on a plain tile, and the dataset-bound tile's value at
|
|
32
|
+
* every length: that tile has no Card inset, so its value has the container's
|
|
33
|
+
* whole width and the ladder below, measured against a Card, does not apply.
|
|
34
|
+
*/
|
|
35
|
+
export declare const METRIC_TILE_VALUE_CLASS = "max-w-full overflow-hidden text-ellipsis whitespace-nowrap tabular-nums text-xl @[160px]:text-2xl";
|
|
36
|
+
/**
|
|
37
|
+
* The value's size ladder, chosen by how wide the value is (objectui#12942).
|
|
38
|
+
*
|
|
39
|
+
* A plain tile (`MetricCard`, `MetricWidget`: a `Card`, 1 px border, the value
|
|
40
|
+
* in `CardContent`'s 24 px side padding) gives its value the container's width
|
|
41
|
+
* less {@link METRIC_TILE_VALUE_INSET} px — the container query reads the
|
|
42
|
+
* Card's content box, inside the border. A value `em` wide fits at a size of
|
|
43
|
+
* `px` from a container `INSET + em * px` wide, so each `@[N px]:` step below
|
|
44
|
+
* starts at `ceil(INSET + maxEm * px)` for its rung's widest value. The
|
|
45
|
+
* `metricTileValueScale-12942` test re-derives every step from that formula.
|
|
46
|
+
*
|
|
47
|
+
* The first rung is the short value's face, {@link METRIC_TILE_VALUE_CLASS}'s
|
|
48
|
+
* sizes unchanged. Every later rung starts at 14 px; past the last one, 14 px
|
|
49
|
+
* at every width. A value still wider than its tile at 14 px keeps the
|
|
50
|
+
* ellipsis, and the value node carries the full figure as its tooltip.
|
|
51
|
+
*
|
|
52
|
+
* Literals only: Tailwind's content scanner must see every class.
|
|
53
|
+
*/
|
|
54
|
+
export declare const METRIC_TILE_VALUE_INSET = 48;
|
|
55
|
+
export declare const METRIC_TILE_VALUE_LADDER: ReadonlyArray<{
|
|
56
|
+
readonly maxEm: number;
|
|
57
|
+
readonly sizes: string;
|
|
58
|
+
}>;
|
|
59
|
+
/** Past the ladder's last rung: 14 px at every width. */
|
|
60
|
+
export declare const METRIC_TILE_VALUE_FINAL_SIZES = "text-sm";
|
|
61
|
+
/**
|
|
62
|
+
* How wide `text` draws, in em, at the tile's bold tabular figures — an upper
|
|
63
|
+
* bound read off Inter, the console's face: a digit is 0.65 em, a digit
|
|
64
|
+
* separator (`,` `.` `'` or a space) 0.27 em, a sign or currency symbol 0.7 em,
|
|
65
|
+
* and any other character a full em (letters, CJK).
|
|
66
|
+
*/
|
|
67
|
+
export declare function metricTileValueEm(text: string): number;
|
|
68
|
+
/**
|
|
69
|
+
* The value node's class for `value`: the rung of {@link METRIC_TILE_VALUE_LADDER}
|
|
70
|
+
* its width falls in, or the 14 px final face past the last rung.
|
|
71
|
+
*/
|
|
72
|
+
export declare function metricTileValueClass(value: string | number): string;
|
|
73
|
+
/** The measure label: an 11 px muted line under the value, dropped below 160 px. */
|
|
74
|
+
export declare const METRIC_TILE_MEASURE_LABEL_CLASS = "hidden max-w-full truncate text-[11px] text-muted-foreground @[160px]:block";
|
|
75
|
+
/**
|
|
76
|
+
* The title's tooltip: the description when one is authored, else the title,
|
|
77
|
+
* then the measure label on its own line — the one place the label survives in
|
|
78
|
+
* a tile too narrow to draw it.
|
|
79
|
+
*/
|
|
80
|
+
export declare function metricTileTooltip(title: string | undefined, description?: string, measureLabel?: string): string | undefined;
|
|
81
|
+
/**
|
|
82
|
+
* The value node's tooltip: the full figure, for a value past the short rung —
|
|
83
|
+
* the one place it survives in a tile too narrow even for 14 px. A short value
|
|
84
|
+
* draws none, as before.
|
|
85
|
+
*/
|
|
86
|
+
export declare function metricTileValueTitle(value: string | number): string | undefined;
|
|
87
|
+
//# sourceMappingURL=metricTile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metricTile.d.ts","sourceRoot":"","sources":["../src/metricTile.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,kFAAkF;AAClF,eAAO,MAAM,2BAA2B,eAAe,CAAC;AAExD,oFAAoF;AACpF,eAAO,MAAM,uBAAuB,0FAA0F,CAAC;AAE/H;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,sGAAsG,CAAC;AAE3I;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,uBAAuB,KAAK,CAAC;AAE1C,eAAO,MAAM,wBAAwB,EAAE,aAAa,CAAC;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAOtG,CAAC;AAEF,yDAAyD;AACzD,eAAO,MAAM,6BAA6B,YAAY,CAAC;AAIvD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAStD;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAInE;AAED,oFAAoF;AACpF,eAAO,MAAM,+BAA+B,gFAAgF,CAAC;AAE7H;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAG5H;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAG/E"}
|
package/dist/recordFields.d.ts
CHANGED
|
@@ -8,6 +8,74 @@ export declare const SYSTEM_FIELDS: Set<string>;
|
|
|
8
8
|
export declare function isSystemField(name: string, def?: any): boolean;
|
|
9
9
|
/** Numeric-flavoured field types (right-aligned in tables). */
|
|
10
10
|
export declare const NUMERIC_FIELD_TYPES: Set<string>;
|
|
11
|
+
/**
|
|
12
|
+
* The override vocabulary this package's two field surfaces share.
|
|
13
|
+
*
|
|
14
|
+
* ⚠️ This type is a DERIVATION SOURCE, not only a shape: `ObjectDataTable`'s
|
|
15
|
+
* two column bands are both `Exclude<keyof FieldMeta, …>` — `EnrichedColumn`'s
|
|
16
|
+
* write-side tombstones (objectui#6373) and `AuthoredColumnOverrides`' read-side
|
|
17
|
+
* refusal band (objectui#6425). So a member REMOVED here silently leaves both
|
|
18
|
+
* bands, and any refusal that rode on its membership stops enforcing with
|
|
19
|
+
* nothing going red. A member being retired must therefore be re-refused
|
|
20
|
+
* explicitly at that seam before it leaves this type — see
|
|
21
|
+
* `ObjectDataTableRetiredDecimalsTombstone` in `ObjectDataTable.tsx`, which is
|
|
22
|
+
* what `decimals` left behind.
|
|
23
|
+
*
|
|
24
|
+
* ⛔ `decimals` was RETIRED from this type by objectui#6625 — written from the
|
|
25
|
+
* schema def on every call and read by nothing (zero `.decimals` member reads
|
|
26
|
+
* across `@object-ui/fields`, `@object-ui/i18n`, `@object-ui/components`,
|
|
27
|
+
* `@object-ui/core` and this package, measured against a `.scale` positive
|
|
28
|
+
* control that hits `NumberField.tsx` / `GridField.tsx` / `index.tsx`). If a
|
|
29
|
+
* reader is ever wanted here it reads `scale` — the field def's decimal-places
|
|
30
|
+
* key, which is what the retired write resolved to anyway and what
|
|
31
|
+
* `NumberCellRenderer` already reads (`precision` is the total digit count, a
|
|
32
|
+
* different question — objectui#2131). ⛔ Do not resurrect `decimals`.
|
|
33
|
+
*
|
|
34
|
+
* ⛔ `referenceTo` was RETIRED from this type by objectui#6597 (enforce-or-remove,
|
|
35
|
+
* withdraw branch — maintainer's standing startup-stage rule, 2026-08-27: no
|
|
36
|
+
* measured demand retires immediately). It was documented by this package's
|
|
37
|
+
* README as an author-facing column override, but the promise was never kept:
|
|
38
|
+
* `LookupCellRenderer` (`@object-ui/fields`) resolves its lookup target from
|
|
39
|
+
* `field.reference_to` / `field.reference` — never `field.referenceTo` — and
|
|
40
|
+
* `computeLookupExpand` (`ObjectDataTable.tsx`) builds `$expand` from the OBJECT
|
|
41
|
+
* SCHEMA's field types, never from an authored override. Measured with the
|
|
42
|
+
* `referenceTo`-vs-`options` positive control in
|
|
43
|
+
* `ObjectDataTable.overrideSource-6425.test.tsx`: `options` (a live override)
|
|
44
|
+
* separates two equal-valued columns, `referenceTo` does not — an authored
|
|
45
|
+
* override renders byte-identical to its absence. No authoring story survived
|
|
46
|
+
* the search either: the sibling `ObjectGrid` producer's own relational-meta
|
|
47
|
+
* pass-through (`applyRelationalMeta`, `plugin-grid/src/ObjectGrid.tsx`) copies
|
|
48
|
+
* `reference_to` / `reference` from the SCHEMA field def only, never from an
|
|
49
|
+
* authored column override, and no example/doc/fixture in this repo shows a
|
|
50
|
+
* table column pinning a lookup's target to something other than what its
|
|
51
|
+
* schema field already says. If a reader for the resolved reference target is
|
|
52
|
+
* ever wanted here, it reads `reference_to` / `reference` off the schema field
|
|
53
|
+
* def directly — the spelling `LookupCellRenderer` and `computeLookupExpand`
|
|
54
|
+
* actually use. ⛔ Do not resurrect `referenceTo`.
|
|
55
|
+
*
|
|
56
|
+
* ⭐ That reader ARRIVED (objectui#6694): `reference` / `displayField` below
|
|
57
|
+
* (with `reference_to` beside them until objectui#11070 round 4 retired it,
|
|
58
|
+
* and `display_field` until objectui#11070's text-family round did), copied
|
|
59
|
+
* from the SCHEMA field def by {@link buildFieldMeta} and justified per key on
|
|
60
|
+
* `CELL_RELATIONAL_META_KEYS`.
|
|
61
|
+
* They are the "future reader" both retirement notes predicted, in the spelling
|
|
62
|
+
* they named, and they change neither verdict — the source is the schema field
|
|
63
|
+
* def, never an authored column override, which is the exact distinction
|
|
64
|
+
* objectui#6597 measured and withdrew on.
|
|
65
|
+
*
|
|
66
|
+
* ⚠️ Being `FieldMeta` members they GROW both derived bands in
|
|
67
|
+
* `ObjectDataTable.tsx` — `EnrichedColumn`'s emit tombstones and
|
|
68
|
+
* `UnheldFieldMetaOverrideKey`'s read-side refusal. `reference_to` left the
|
|
69
|
+
* type in objectui#11070 round 4 and `display_field` in its text-family round,
|
|
70
|
+
* so — by the rule at the top of this docblock — each one's refusal is
|
|
71
|
+
* re-stated by hand there (`ObjectDataTableRetiredReferenceToSnakeTombstone`,
|
|
72
|
+
* `ObjectDataTableRetiredDisplayFieldSnakeTombstone`). That is the intended
|
|
73
|
+
* verdict rather than a side effect: an AUTHORED column may not source a
|
|
74
|
+
* lookup's reference target (objectui#6597 measured no authoring story for
|
|
75
|
+
* one), while the schema-derived write is reached by neither band. They landed
|
|
76
|
+
* in both without anyone editing a list — the property this derivation exists
|
|
77
|
+
* for.
|
|
78
|
+
*/
|
|
11
79
|
export interface FieldMeta {
|
|
12
80
|
name: string;
|
|
13
81
|
label: string;
|
|
@@ -17,10 +85,34 @@ export interface FieldMeta {
|
|
|
17
85
|
label: string;
|
|
18
86
|
color?: string;
|
|
19
87
|
}>;
|
|
20
|
-
referenceTo?: unknown;
|
|
21
88
|
format?: string;
|
|
22
89
|
currency?: string;
|
|
23
|
-
|
|
90
|
+
/**
|
|
91
|
+
* The field def's declared upper bound, which on a `percent` field is its
|
|
92
|
+
* STORAGE statement: the spec's `percentScaleOf` reads a fraction unless
|
|
93
|
+
* `max` is above 1 (objectui#11475). Copied from the SCHEMA field def by
|
|
94
|
+
* {@link buildFieldMeta} so the percent cell and the `%` branch of
|
|
95
|
+
* {@link renderFieldValue} read the field's storage rather than guess it
|
|
96
|
+
* from the value. Never an authored column override: as a `FieldMeta`
|
|
97
|
+
* member it lands in `ObjectDataTable`'s read-side refusal band, which is
|
|
98
|
+
* the intended verdict — a column may not restate how its field stores.
|
|
99
|
+
*/
|
|
100
|
+
max?: number;
|
|
101
|
+
/**
|
|
102
|
+
* Lookup target object — the spelling `@objectstack/spec`'s `FieldSchema`
|
|
103
|
+
* declares and the only one `LookupCellRenderer` reads. Its snake_case twin
|
|
104
|
+
* `reference_to` was RETIRED from this type by objectui#11070 round 4.
|
|
105
|
+
*/
|
|
106
|
+
reference?: string;
|
|
107
|
+
/**
|
|
108
|
+
* Author-declared display field on the lookup, in the SPEC spelling
|
|
109
|
+
* (`FieldSchema.displayField`) — it beats every resolver in the cell. The
|
|
110
|
+
* first leg of `LookupCellRenderer`'s `displayField || reference_field`
|
|
111
|
+
* chain, and the only leg a spec-compliant producer can emit
|
|
112
|
+
* (objectui#6875). Its snake_case twin `display_field` was RETIRED from this
|
|
113
|
+
* type by objectui#11070's text-family round: no reader read it.
|
|
114
|
+
*/
|
|
115
|
+
displayField?: string;
|
|
24
116
|
}
|
|
25
117
|
/**
|
|
26
118
|
* Normalize an object schema's `fields` into a `{ name → def }` map. Accepts
|
|
@@ -37,20 +129,39 @@ export interface BuildFieldMetaParams {
|
|
|
37
129
|
objectName?: string;
|
|
38
130
|
/** Translator for per-option labels (from `useSafeFieldLabel`). */
|
|
39
131
|
fieldOptionLabel?: (objectName: string, field: string, value: string, fallback: string) => string;
|
|
40
|
-
/**
|
|
132
|
+
/**
|
|
133
|
+
* Per-column overrides (table columns may pin type/format/options).
|
|
134
|
+
*
|
|
135
|
+
* A subset of {@link FieldMeta}, which is what makes that type the pool
|
|
136
|
+
* `ObjectDataTable`'s refusal band derives from. `decimals` left with the
|
|
137
|
+
* member (objectui#6625): its last feeder went when objectui#6425's ruling
|
|
138
|
+
* removed the authored read from `ObjectDataTable.enrich()`, and
|
|
139
|
+
* `RecordDetailDrawer` — the only other caller — passes no overrides at all.
|
|
140
|
+
* `referenceTo` left the same way (objectui#6597): `ObjectDataTable.enrich()`
|
|
141
|
+
* no longer reads it off the authored column, and `RecordDetailDrawer` never
|
|
142
|
+
* did.
|
|
143
|
+
*/
|
|
41
144
|
overrides?: {
|
|
42
145
|
type?: string;
|
|
43
146
|
format?: string;
|
|
44
147
|
options?: any;
|
|
45
|
-
referenceTo?: unknown;
|
|
46
148
|
currency?: string;
|
|
47
|
-
decimals?: number;
|
|
48
149
|
};
|
|
49
150
|
}
|
|
50
151
|
/**
|
|
51
|
-
* Build the `FieldMeta` for a single field, resolving
|
|
52
|
-
*
|
|
53
|
-
*
|
|
152
|
+
* Build the `FieldMeta` for a single field, resolving currency from the
|
|
153
|
+
* schema field def and translating select options. Column-level overrides
|
|
154
|
+
* win over schema-derived values.
|
|
155
|
+
*
|
|
156
|
+
* The field def's currency goes through `resolveFieldCurrency`
|
|
157
|
+
* (`@object-ui/i18n`) rather than a chain of this helper's own (objectui#10463).
|
|
158
|
+
* The resolver is what reads `currencyConfig`, the spec's one fixed-currency
|
|
159
|
+
* declaration, and only under `currencyMode: 'fixed'`. The chain it replaced
|
|
160
|
+
* read the flat `currency` / `defaultCurrency` spellings only, so a fixed
|
|
161
|
+
* field painted in the tenant currency in both the table cell and the record
|
|
162
|
+
* drawer. The call passes NO tenant default: `renderFieldValue` backstops with
|
|
163
|
+
* the tenant only after the symbol it infers from a `format`, and a tenant code
|
|
164
|
+
* resolved here would jump ahead of that symbol.
|
|
54
165
|
*/
|
|
55
166
|
export declare function buildFieldMeta(params: BuildFieldMetaParams): FieldMeta;
|
|
56
167
|
/** Whether a `FieldMeta` should be right-aligned (numeric / currency / percent). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recordFields.d.ts","sourceRoot":"","sources":["../src/recordFields.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"recordFields.d.ts","sourceRoot":"","sources":["../src/recordFields.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAyB1B;;;GAGG;AACH,eAAO,MAAM,aAAa,aAIxB,CAAC;AAEH,kFAAkF;AAClF,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,GAAG,OAAO,CAG9D;AAKD,+DAA+D;AAC/D,eAAO,MAAM,mBAAmB,aAE9B,CAAC;AAyIH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmEG;AACH,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,GAAG,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;;;;;OASG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAUxE;AAED,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,0DAA0D;IAC1D,GAAG,CAAC,EAAE,GAAG,CAAC;IACV,2DAA2D;IAC3D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mEAAmE;IACnE,gBAAgB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;IAClG;;;;;;;;;;;OAWG;IACH,SAAS,CAAC,EAAE;QACV,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,GAAG,CAAC;QACd,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,oBAAoB,GAAG,SAAS,CA8CtE;AAED,oFAAoF;AACpF,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,QAAQ,CAAC,GAAG,OAAO,CAKzF;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,GAAG,EACV,SAAS,EAAE,SAAS,EACpB,cAAc,CAAC,EAAE,MAAM,EAKvB,aAAa,CAAC,EAAE,MAAM,GACrB,KAAK,CAAC,SAAS,CA4EjB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAMhD"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* The bare name of every retired spelling, mapped to the refusal text the
|
|
4
|
+
* tombstone renders and logs. Keyed by the BARE name because that is what
|
|
5
|
+
* `ComponentRegistry.register` takes; the namespace is spelled at the call.
|
|
6
|
+
*
|
|
7
|
+
* The message names BOTH halves deliberately — the spelling that was written
|
|
8
|
+
* and the spelling that replaces it. A refusal that only says "unknown" is the
|
|
9
|
+
* one this table exists to stop being.
|
|
10
|
+
*/
|
|
11
|
+
export declare const RETIRED_DASHBOARD_NODE_TYPES: Readonly<Record<string, string>>;
|
|
12
|
+
/**
|
|
13
|
+
* Log a retired node-type spelling once. Exported for the pin test, which has
|
|
14
|
+
* to be able to observe a SECOND occurrence being suppressed without inventing
|
|
15
|
+
* its own copy of the set.
|
|
16
|
+
*/
|
|
17
|
+
export declare function reportRetiredDashboardNodeType(spelling: string): void;
|
|
18
|
+
/** Test seam: forget what has been reported, so a pin can measure the first one. */
|
|
19
|
+
export declare function resetRetiredDashboardNodeTypeReports(): void;
|
|
20
|
+
/**
|
|
21
|
+
* The widget a RETIRED dashboard node-type spelling renders.
|
|
22
|
+
*
|
|
23
|
+
* The rendered text and the logged text are the SAME string, read from
|
|
24
|
+
* {@link RETIRED_DASHBOARD_NODE_TYPES}. A pin that asserts only "nothing
|
|
25
|
+
* rendered" cannot tell this refusal apart from the key having been deleted
|
|
26
|
+
* outright, which is why the text is part of the contract and not decoration.
|
|
27
|
+
*/
|
|
28
|
+
export declare const RetiredDashboardNodeTombstone: React.FC<Record<string, unknown>>;
|
|
29
|
+
//# sourceMappingURL=retired-node-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retired-node-types.d.ts","sourceRoot":"","sources":["../src/retired-node-types.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B;;;;;;;;GAQG;AACH,eAAO,MAAM,4BAA4B,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAOxE,CAAC;AAKH;;;;GAIG;AACH,wBAAgB,8BAA8B,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAOrE;AAED,oFAAoF;AACpF,wBAAgB,oCAAoC,IAAI,IAAI,CAE3D;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,6BAA6B,EAAE,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAwB3E,CAAC"}
|
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* ObjectUI
|
|
3
|
-
* Copyright (c) 2024-present ObjectStack Inc.
|
|
4
|
-
*
|
|
5
|
-
* This source code is licensed under the MIT license found in the
|
|
6
|
-
* LICENSE file in the root directory of this source tree.
|
|
7
|
-
*/
|
|
1
|
+
import { DomProps } from '@object-ui/core';
|
|
8
2
|
/**
|
|
9
3
|
* The props `SchemaRenderer` hands a widget that are NOT DOM attributes
|
|
10
4
|
* (objectui#4357).
|
|
@@ -43,10 +37,21 @@
|
|
|
43
37
|
*
|
|
44
38
|
* The line this type draws is **"is the key an HTML attribute name"**. None of
|
|
45
39
|
* the seven is (the two dashed `aria-*` forms the renderer emits itself are, and
|
|
46
|
-
* they keep flowing).
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
* the
|
|
40
|
+
* they keep flowing). Removing the spread instead would have been the wrong fix —
|
|
41
|
+
* it is the component's only accessibility passthrough.
|
|
42
|
+
*
|
|
43
|
+
* ⚠️ That line was a DENY-LIST, and on the renderer's door it is no longer the
|
|
44
|
+
* judge. It stripped every one of the seven and the leak gate
|
|
45
|
+
* (`packages/app-shell/src/__tests__/widget-dom-leak-sweep.test.tsx`) still
|
|
46
|
+
* found the OPEN TAIL on both components — an authored key neither declares
|
|
47
|
+
* (`zzcanary`, `reference_to`, a `props: { colorVariant }` on `metric-card`, a
|
|
48
|
+
* `label` on `metric-card`) and `name` all landed as attributes, because a
|
|
49
|
+
* deny-list can only name what already exists. Per objectui#4425's phase-2
|
|
50
|
+
* ruling, what a component reached through `SchemaRenderer` may put on its
|
|
51
|
+
* element is decided by `toDomProps`' WHITELIST — see {@link hostDomProps}
|
|
52
|
+
* below. The seven are still destructured by name: they are this type's keys,
|
|
53
|
+
* and on the direct React door (below) the destructure is still what keeps them
|
|
54
|
+
* off the element.
|
|
50
55
|
*
|
|
51
56
|
* The renderer strips its own schema metadata (`type` / `children` / `visible` /
|
|
52
57
|
* the schema's `dataSource` binding / …) before spreading, so those never
|
|
@@ -77,4 +82,43 @@ export interface SchemaHostProps {
|
|
|
77
82
|
*/
|
|
78
83
|
dataSource?: unknown;
|
|
79
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* What a KPI card may spread onto its host element, decided by the DOOR the
|
|
87
|
+
* render came through (objectui#4425, phase-2 ruling: "a registered SDUI
|
|
88
|
+
* widget's host element receives only what passes the `toDomProps` whitelist").
|
|
89
|
+
*
|
|
90
|
+
* Both metric components have two doors, and they hand the component two
|
|
91
|
+
* different populations:
|
|
92
|
+
*
|
|
93
|
+
* - **The renderer's door.** `SchemaRenderer` — the registry render path, and
|
|
94
|
+
* so also an app that registers the exported component under a key of its
|
|
95
|
+
* own — hands the component the authored node's own keys, the contents of
|
|
96
|
+
* its `props` container, the runtime props it injects and its host's
|
|
97
|
+
* trailing props. That set is unbounded, so only the whitelist may decide
|
|
98
|
+
* what reaches the element: `toDomProps` keeps the SDUI contract's declared
|
|
99
|
+
* pass-through set (`SDUI_DOM_PASS_THROUGH_KEYS`) and the `aria-*` /
|
|
100
|
+
* `data-*` families, and drops everything else — `name`, `disabled`, the
|
|
101
|
+
* injected adapter, every authored key neither component declares. One
|
|
102
|
+
* executor, `@object-ui/core`'s, the
|
|
103
|
+
* one `DashboardRenderer`'s grid container and `plugin-chatbot`'s
|
|
104
|
+
* registrations already use — not a third list.
|
|
105
|
+
* - **The direct React door.** A host rendering the exported component passes
|
|
106
|
+
* typed props, and both props interfaces DECLARE `React.HTMLAttributes` as
|
|
107
|
+
* their DOM pass-through (objectui#4426). That declaration is the
|
|
108
|
+
* objectui#4435 pattern the ruling keeps available, so this door stays as it
|
|
109
|
+
* was: narrowing it at runtime while the exported interface still extends
|
|
110
|
+
* `HTMLAttributes` would type-check a `title` or an `onMouseEnter` and drop
|
|
111
|
+
* it — declared but not delivered. Narrowing the interface itself is a
|
|
112
|
+
* public prop-surface change, which this card's fence excludes.
|
|
113
|
+
*
|
|
114
|
+
* The discriminator is `schema`: the one key `SchemaRenderer` injects on EVERY
|
|
115
|
+
* render (the table above), declared on this type as the renderer's private
|
|
116
|
+
* door and never on either exported props interface. A direct consumer that
|
|
117
|
+
* passes it anyway has chosen the renderer's door and gets the whitelist, so a
|
|
118
|
+
* mistaken reading DROPS an attribute and never leaks one. If the renderer ever
|
|
119
|
+
* stopped injecting it, every canary the leak gate plants would reach the DOM
|
|
120
|
+
* again and the gate would go red — that sweep is what holds this function to
|
|
121
|
+
* its claim, alongside `__tests__/MetricWidget.domProps.test.tsx`.
|
|
122
|
+
*/
|
|
123
|
+
export declare function hostDomProps<P extends object>(schema: unknown, rest: P): P | DomProps<P>;
|
|
80
124
|
//# sourceMappingURL=schemaHostProps.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schemaHostProps.d.ts","sourceRoot":"","sources":["../src/schemaHostProps.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH
|
|
1
|
+
{"version":3,"file":"schemaHostProps.d.ts","sourceRoot":"","sources":["../src/schemaHostProps.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAc,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE5D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8DG;AACH,MAAM,WAAW,eAAe;IAC9B,kFAAkF;IAClF,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,sDAAsD;IACtD,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,2EAA2E;IAC3E,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,wEAAwE;IACxE,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,6EAA6E;IAC7E,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,sEAAsE;IACtE,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAExF"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { DashboardComponentSchema } from '@object-ui/types';
|
|
2
|
+
/**
|
|
3
|
+
* The dashboard auto-refresh timer: ONE implementation, two mount points
|
|
4
|
+
* (objectui#8820).
|
|
5
|
+
*
|
|
6
|
+
* `DashboardGridLayout` and `DashboardRenderer` each used to carry their own
|
|
7
|
+
* copy of the same three things: a `refreshing` flag, a `handleRefresh`
|
|
8
|
+
* callback shared by the manual "Refresh All" button and the timer, and an
|
|
9
|
+
* effect that read the authored period and drove `setInterval`. The copies were
|
|
10
|
+
* identical in logic, and two copies of one rule is two places to change and
|
|
11
|
+
* one place to forget: the `refreshInterval` to `refreshIntervalSeconds` rename
|
|
12
|
+
* (objectui#7783) had to be made twice, and a copy that drifted would still
|
|
13
|
+
* pass its own component's tests.
|
|
14
|
+
*
|
|
15
|
+
* This hook is that logic, moved here. Both surfaces call it, so the authored
|
|
16
|
+
* period is read in exactly one place.
|
|
17
|
+
*
|
|
18
|
+
* - The period is `refreshIntervalSeconds`, in seconds, and nothing else. The
|
|
19
|
+
* retired `refreshInterval` spelling is refused by the spec's
|
|
20
|
+
* `DashboardSchema`, so no fallback reads it (AGENTS.md #0.1).
|
|
21
|
+
* - The timer runs only when the host wired `onRefresh` AND the period is
|
|
22
|
+
* greater than zero: an absent period, `0` and a negative value all mean
|
|
23
|
+
* "off".
|
|
24
|
+
* - The interval is armed on VALUES only: the period and whether a handler is
|
|
25
|
+
* wired. The handler itself is read through a ref when a run happens, so a
|
|
26
|
+
* new handler identity, from the host or from React discarding a memo, never
|
|
27
|
+
* re-arms the interval or moves its phase, and the run still calls the
|
|
28
|
+
* CURRENT handler (AGENTS.md #10, objectui#11004).
|
|
29
|
+
* - The indicator clears itself 600ms after each run, manual or timed.
|
|
30
|
+
*
|
|
31
|
+
* `__tests__/dashboardAutoRefreshTimer.test.tsx` mounts both surfaces and
|
|
32
|
+
* counts `onRefresh` calls under fake timers. It pins the first three points,
|
|
33
|
+
* the third under a forced memo discard; nothing pins the 600ms indicator.
|
|
34
|
+
*/
|
|
35
|
+
/** What a dashboard surface needs to drive its refresh affordance. */
|
|
36
|
+
export interface DashboardAutoRefresh {
|
|
37
|
+
/** True while a refresh is in flight; drives the spinner and disables the button. */
|
|
38
|
+
refreshing: boolean;
|
|
39
|
+
/** Run a refresh now. Wired to both the manual button and the timer. */
|
|
40
|
+
handleRefresh: () => void;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Owns the refresh indicator, the manual refresh handler, and the auto-refresh
|
|
44
|
+
* interval for one dashboard surface.
|
|
45
|
+
*/
|
|
46
|
+
export declare function useDashboardAutoRefresh(schema: DashboardComponentSchema, onRefresh?: () => void): DashboardAutoRefresh;
|
|
47
|
+
//# sourceMappingURL=useDashboardAutoRefresh.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useDashboardAutoRefresh.d.ts","sourceRoot":"","sources":["../src/useDashboardAutoRefresh.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAC;AAEjE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,sEAAsE;AACtE,MAAM,WAAW,oBAAoB;IACnC,qFAAqF;IACrF,UAAU,EAAE,OAAO,CAAC;IACpB,wEAAwE;IACxE,aAAa,EAAE,MAAM,IAAI,CAAC;CAC3B;AAoBD;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,wBAAwB,EAChC,SAAS,CAAC,EAAE,MAAM,IAAI,GACrB,oBAAoB,CAsCtB"}
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* ObjectUI
|
|
3
|
-
* Copyright (c) 2024-present ObjectStack Inc.
|
|
4
|
-
*
|
|
5
|
-
* This source code is licensed under the MIT license found in the
|
|
6
|
-
* LICENSE file in the root directory of this source tree.
|
|
7
|
-
*/
|
|
1
|
+
import { useObjectLabel, useObjectTranslation } from '@object-ui/i18n';
|
|
8
2
|
/** Returns true when the widget data config uses provider: 'object' (async data source). */
|
|
9
3
|
export declare function isObjectProvider(widgetData: unknown): widgetData is {
|
|
10
4
|
provider: 'object';
|
|
@@ -21,6 +15,41 @@ export declare function isObjectProvider(widgetData: unknown): widgetData is {
|
|
|
21
15
|
* path derives headers with it when no columns were declared at all.
|
|
22
16
|
*/
|
|
23
17
|
export declare function humanizeFieldKey(key: string): string;
|
|
18
|
+
/**
|
|
19
|
+
* Resolve a chart series label — the SINGLE authority both dashboard relays
|
|
20
|
+
* (`DashboardRenderer`, `DashboardGridLayout`) call, so the three-arm decision
|
|
21
|
+
* below lives once instead of as two copies that could drift.
|
|
22
|
+
*
|
|
23
|
+
* Originated as a `DashboardRenderer`-local `useCallback` (objectui#9055,
|
|
24
|
+
* which fixed arms 2 and 3 there). `DashboardGridLayout` composed
|
|
25
|
+
* `series: [{ dataKey }]` with no `label` key on either of its branches — the
|
|
26
|
+
* legend and tooltip rendered the raw field key while the sibling relay's
|
|
27
|
+
* chart for the same widget rendered the humanized one (objectui#9172). That
|
|
28
|
+
* card is what moved this here rather than growing a second copy of the
|
|
29
|
+
* three-arm logic: a helper duplicated across the two relays is exactly the
|
|
30
|
+
* "one value, two spellings" class `56f4e34c0` ruled out.
|
|
31
|
+
*
|
|
32
|
+
* ⭐ THREE ARMS, and only the last two derive a display string from a FIELD
|
|
33
|
+
* KEY:
|
|
34
|
+
*
|
|
35
|
+
* arm 1 synthetic y-field ('value' / 'count' / '') + an aggregate function
|
|
36
|
+
* -> an i18n'd aggregate name (Count / Sum / Average …), so a
|
|
37
|
+
* fieldless count aggregate doesn't leak the placeholder 'value' /
|
|
38
|
+
* 'count' string into the legend / tooltip.
|
|
39
|
+
* arm 2 a real object + a real field -> `fieldLabel`'s bundle lookup, with
|
|
40
|
+
* the HUMANIZED key (not the raw one) as its fallback.
|
|
41
|
+
* arm 3 no object name at all (a static-data chart) -> the humanized key
|
|
42
|
+
* outright.
|
|
43
|
+
*
|
|
44
|
+
* `t` and `fieldLabel` are injected rather than the hooks themselves, so this
|
|
45
|
+
* stays a plain function callable from either relay's own
|
|
46
|
+
* `useObjectTranslation()` / `useObjectLabel()` instances — no shared hook
|
|
47
|
+
* identity to manage, and each relay keeps memoizing its own `useCallback`
|
|
48
|
+
* wrapper over this (objectui#10's caution against depending on a memo's
|
|
49
|
+
* IDENTITY is about correctness, not about composing plain functions like
|
|
50
|
+
* this one).
|
|
51
|
+
*/
|
|
52
|
+
export declare function composeSeriesLabel(t: ReturnType<typeof useObjectTranslation>['t'], fieldLabel: ReturnType<typeof useObjectLabel>['fieldLabel'], objectName: string | undefined, yField: string, aggFn: string | undefined): string;
|
|
24
53
|
/**
|
|
25
54
|
* Columns for a STATIC (inline `options.data`) table widget whose author
|
|
26
55
|
* declared none — objectui#4618.
|
|
@@ -48,6 +77,19 @@ export declare function deriveStaticTableColumns(rows: unknown): Array<{
|
|
|
48
77
|
}>;
|
|
49
78
|
export { resolveDateMacros, resolveFilterPlaceholders } from '@object-ui/core';
|
|
50
79
|
export { shiftFilterByCompareTo, compareToTrendLabelKey, type CompareToConfig, } from '@object-ui/core';
|
|
80
|
+
/**
|
|
81
|
+
* A period-over-period delta as `computeMetricDelta` returns it.
|
|
82
|
+
*
|
|
83
|
+
* `value` is the absolute percentage change, or `null` when the change has no
|
|
84
|
+
* percentage: a zero baseline with a non-zero current value (objectui#12677).
|
|
85
|
+
* Going from 0 to 10 is not a 100% increase — a percent change from zero is
|
|
86
|
+
* undefined — so the delta keeps its direction and states no number. Every
|
|
87
|
+
* reader draws it through {@link formatMetricDeltaPercent}.
|
|
88
|
+
*/
|
|
89
|
+
export interface MetricDelta {
|
|
90
|
+
value: number | null;
|
|
91
|
+
direction: 'up' | 'down' | 'neutral';
|
|
92
|
+
}
|
|
51
93
|
/**
|
|
52
94
|
* Compute a percentage delta between the current and previous metric values.
|
|
53
95
|
*
|
|
@@ -56,13 +98,18 @@ export { shiftFilterByCompareTo, compareToTrendLabelKey, type CompareToConfig, }
|
|
|
56
98
|
* - previousValue is null / undefined (no comparison data)
|
|
57
99
|
*
|
|
58
100
|
* Edge cases:
|
|
59
|
-
* - both 0 → neutral
|
|
60
|
-
* - previous is 0 and current ≠ 0 →
|
|
101
|
+
* - both 0 → neutral, `value: 0`
|
|
102
|
+
* - previous is 0 and current ≠ 0 → current's direction, `value: null` (no
|
|
103
|
+
* percentage is defined from a zero baseline; objectui#12677)
|
|
61
104
|
* - previous is negative → uses |previous| as denominator so that "less
|
|
62
105
|
* negative" reads as a positive (up) delta.
|
|
63
106
|
*/
|
|
64
|
-
export declare function computeMetricDelta(current: number | null | undefined, previous: number | null | undefined):
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
107
|
+
export declare function computeMetricDelta(current: number | null | undefined, previous: number | null | undefined): MetricDelta | null;
|
|
108
|
+
/**
|
|
109
|
+
* The text a delta badge draws for {@link MetricDelta.value}: `20%` for a
|
|
110
|
+
* defined percentage, and an em dash — never a number — when there is none
|
|
111
|
+
* (a zero baseline, objectui#12677). A symbol, not a word, so no locale pack
|
|
112
|
+
* carries it. The direction arrow beside it still says which way it moved.
|
|
113
|
+
*/
|
|
114
|
+
export declare function formatMetricDeltaPercent(value: number | null): string;
|
|
68
115
|
//# sourceMappingURL=utils.d.ts.map
|