@metaobjectsdev/runtime-web 1.0.0-rc.3 → 1.0.0-rc.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/grid-from-metadata.d.ts.map +1 -1
- package/dist/grid-from-metadata.js +47 -12
- package/dist/grid-from-metadata.js.map +1 -1
- package/dist/join-base-url.d.ts +1 -1
- package/dist/join-base-url.js +1 -1
- package/package.json +2 -2
- package/src/grid-from-metadata.ts +52 -11
- package/src/join-base-url.ts +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grid-from-metadata.d.ts","sourceRoot":"","sources":["../src/grid-from-metadata.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,UAAU,EAAuB,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"grid-from-metadata.d.ts","sourceRoot":"","sources":["../src/grid-from-metadata.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,UAAU,EAAuB,MAAM,0BAA0B,CAAC;AAgBhF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAM/C,6EAA6E;AAC7E,MAAM,WAAW,UAAU;IACzB,wDAAwD;IACxD,KAAK,EAAE,MAAM,CAAC;IACd,gFAAgF;IAChF,MAAM,EAAE,MAAM,CAAC;IACf,6EAA6E;IAC7E,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,UAAU,CAAC;IACnB,OAAO,EAAE,UAAU,EAAE,CAAC;CACvB;AAwDD;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,QAAQ,CAmCvE"}
|
|
@@ -3,26 +3,56 @@
|
|
|
3
3
|
// constant import from it made every browser bundle fail ("Browser polyfill for module
|
|
4
4
|
// node:url doesn't have a matching export named fileURLToPath"). The type import above is
|
|
5
5
|
// fine on the root: `import type` is erased at build time and drags in no runtime dep.
|
|
6
|
-
import { LAYOUT_SUBTYPE_DATA_GRID, LAYOUT_DATA_GRID_ATTR_COLUMNS, LAYOUT_DATA_GRID_ATTR_PAGE_SIZE, LAYOUT_DATA_GRID_ATTR_DEFAULT_SORT_FIELD, LAYOUT_DATA_GRID_ATTR_DEFAULT_SORT_ORDER, LAYOUT_DATA_GRID_ATTR_FILTERABLE, } from "@metaobjectsdev/metadata/constants";
|
|
6
|
+
import { LAYOUT_SUBTYPE_DATA_GRID, LAYOUT_DATA_GRID_ATTR_COLUMNS, LAYOUT_DATA_GRID_ATTR_PAGE_SIZE, LAYOUT_DATA_GRID_ATTR_DEFAULT_SORT_FIELD, LAYOUT_DATA_GRID_ATTR_DEFAULT_SORT_ORDER, LAYOUT_DATA_GRID_ATTR_FILTERABLE, FIELD_ATTR_SORTABLE_DEFAULT_ORDER, DOC_ATTR_TITLE, } from "@metaobjectsdev/metadata/constants";
|
|
7
7
|
const DEFAULT_PAGE_SIZE = 25;
|
|
8
8
|
const DEFAULT_GRID_NAME = "default";
|
|
9
|
-
// The view's display-label attr. Mirrors the literal used by the columns-file
|
|
10
|
-
// codegen; there is no exported constant for it in @metaobjectsdev/metadata.
|
|
11
|
-
const VIEW_ATTR_LABEL = "label";
|
|
12
9
|
/** camelCase / PascalCase → "Title Case" (matches the codegen `humanize`). */
|
|
13
10
|
function humanize(s) {
|
|
14
11
|
return s.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/^./, (c) => c.toUpperCase());
|
|
15
12
|
}
|
|
16
13
|
function firstView(field) {
|
|
17
|
-
|
|
14
|
+
// views(), not ownViews(): ADR-0039 — a field that `extends` an abstract parent
|
|
15
|
+
// inherits the parent's view, and an own-only read drops it, so the column would
|
|
16
|
+
// silently lose both its header and its renderer hint.
|
|
17
|
+
return field.views()[0];
|
|
18
18
|
}
|
|
19
19
|
function header(field) {
|
|
20
|
-
|
|
20
|
+
// DOC_ATTR_TITLE, not the literal "label". `@label` is registered by NO provider in
|
|
21
|
+
// any port — `@title` is the documentation commonAttr chartered as the display label
|
|
22
|
+
// — so this read was `undefined` for every field that ever set one, and every grid
|
|
23
|
+
// header silently fell back to humanize(field.name). Same shape as `attr("isArray")`:
|
|
24
|
+
// an unregistered name answers `undefined`, which is indistinguishable from "unset".
|
|
25
|
+
//
|
|
26
|
+
// attr(), not ownAttr(), for the same ADR-0039 reason as firstView above.
|
|
27
|
+
const label = firstView(field)?.attr(DOC_ATTR_TITLE);
|
|
21
28
|
return typeof label === "string" ? label : humanize(field.name);
|
|
22
29
|
}
|
|
23
30
|
function viewKind(field) {
|
|
24
31
|
return firstView(field)?.subType ?? field.subType;
|
|
25
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* A grid's initial sort DIRECTION: the layout's `@defaultSortOrder` when it declares one,
|
|
35
|
+
* otherwise the named field's `@sortableDefaultOrder`, otherwise ascending.
|
|
36
|
+
*
|
|
37
|
+
* This is the runtime twin of `resolveGridDefaultSort()` in `codegen-ts`'s
|
|
38
|
+
* `filter-shared.ts`, and it must stay identical to it. It is duplicated rather than
|
|
39
|
+
* imported because that module lives in a SERVER package: `runtime-web` is the pure
|
|
40
|
+
* browser core and may depend only on `@metaobjectsdev/metadata` (see #287 — a single
|
|
41
|
+
* value import from the wrong entry point made every browser bundle fail).
|
|
42
|
+
*
|
|
43
|
+
* Reading only `@defaultSortOrder` — which this did — makes the runtime-built grid sort
|
|
44
|
+
* the opposite way from the generated grid AND from the endpoint it queries, for the one
|
|
45
|
+
* case the attribute exists to cover: a layout that names a field and lets the field say
|
|
46
|
+
* which way it runs.
|
|
47
|
+
*
|
|
48
|
+
* ADR-0039: `attr()` resolves, so a `@sortableDefaultOrder` inherited via `extends` counts.
|
|
49
|
+
*/
|
|
50
|
+
function gridDefaultSortOrder(declaredOrder, field) {
|
|
51
|
+
if (declaredOrder === "asc" || declaredOrder === "desc")
|
|
52
|
+
return declaredOrder;
|
|
53
|
+
const fromField = field?.attr(FIELD_ATTR_SORTABLE_DEFAULT_ORDER);
|
|
54
|
+
return fromField === "desc" ? "desc" : "asc";
|
|
55
|
+
}
|
|
26
56
|
/**
|
|
27
57
|
* Build a grid (config + columns) from a MetaObject at runtime.
|
|
28
58
|
*
|
|
@@ -35,7 +65,12 @@ export function buildGrid(meta, gridName) {
|
|
|
35
65
|
const layouts = meta.layouts().filter((l) => l.subType === LAYOUT_SUBTYPE_DATA_GRID);
|
|
36
66
|
const layout = gridName ? layouts.find((l) => l.name === gridName) : layouts[0];
|
|
37
67
|
const fieldsByName = new Map(meta.fields().map((f) => [f.name, f]));
|
|
38
|
-
|
|
68
|
+
// attr(), not ownAttr(), on every layout read below — same ADR-0039 reason as
|
|
69
|
+
// firstView/header above, which this file already applies to its FIELD reads: a
|
|
70
|
+
// `layout.dataGrid` that inherits its attrs via `extends` keeps them on the parent,
|
|
71
|
+
// and an own-only read silently drops every one of them (no columns, default page
|
|
72
|
+
// size, no initial sort) on a grid that plainly declares them.
|
|
73
|
+
const columnsAttr = layout?.attr(LAYOUT_DATA_GRID_ATTR_COLUMNS);
|
|
39
74
|
const names = Array.isArray(columnsAttr)
|
|
40
75
|
? columnsAttr.filter((x) => typeof x === "string")
|
|
41
76
|
: meta.fields().map((f) => f.name);
|
|
@@ -43,15 +78,15 @@ export function buildGrid(meta, gridName) {
|
|
|
43
78
|
.map((n) => fieldsByName.get(n))
|
|
44
79
|
.filter((f) => f !== undefined)
|
|
45
80
|
.map((f) => ({ field: f.name, header: header(f), viewKind: viewKind(f) }));
|
|
46
|
-
const pageSizeAttr = layout?.
|
|
47
|
-
const sortField = layout?.
|
|
48
|
-
const sortOrder = layout?.
|
|
81
|
+
const pageSizeAttr = layout?.attr(LAYOUT_DATA_GRID_ATTR_PAGE_SIZE);
|
|
82
|
+
const sortField = layout?.attr(LAYOUT_DATA_GRID_ATTR_DEFAULT_SORT_FIELD);
|
|
83
|
+
const sortOrder = layout?.attr(LAYOUT_DATA_GRID_ATTR_DEFAULT_SORT_ORDER);
|
|
49
84
|
const config = {
|
|
50
85
|
name: layout?.name ?? gridName ?? DEFAULT_GRID_NAME,
|
|
51
86
|
pageSize: typeof pageSizeAttr === "number" ? pageSizeAttr : DEFAULT_PAGE_SIZE,
|
|
52
|
-
filterable: layout?.
|
|
87
|
+
filterable: layout?.attr(LAYOUT_DATA_GRID_ATTR_FILTERABLE) === true,
|
|
53
88
|
...(typeof sortField === "string"
|
|
54
|
-
? { defaultSort: { field: sortField, order: sortOrder
|
|
89
|
+
? { defaultSort: { field: sortField, order: gridDefaultSortOrder(sortOrder, fieldsByName.get(sortField)) } }
|
|
55
90
|
: {}),
|
|
56
91
|
};
|
|
57
92
|
return { config, columns };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grid-from-metadata.js","sourceRoot":"","sources":["../src/grid-from-metadata.ts"],"names":[],"mappings":"AAYA,yFAAyF;AACzF,yFAAyF;AACzF,uFAAuF;AACvF,0FAA0F;AAC1F,uFAAuF;AACvF,OAAO,EACL,wBAAwB,EACxB,6BAA6B,EAC7B,+BAA+B,EAC/B,wCAAwC,EACxC,wCAAwC,EACxC,gCAAgC,
|
|
1
|
+
{"version":3,"file":"grid-from-metadata.js","sourceRoot":"","sources":["../src/grid-from-metadata.ts"],"names":[],"mappings":"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"}
|
package/dist/join-base-url.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Join a client base URL to a generated entity-relative path.
|
|
3
3
|
*
|
|
4
4
|
* ONE implementation, shared by both client tiers on purpose. `@metaobjectsdev/tanstack`
|
|
5
|
-
* wraps `
|
|
5
|
+
* wraps `useEntityPathFetcher()` with it and `@metaobjectsdev/angular` wraps the
|
|
6
6
|
* `EntityFetcherToken`; implemented separately they would eventually disagree about a
|
|
7
7
|
* trailing slash, and the disagreement would surface as a 404 in one framework only.
|
|
8
8
|
*
|
package/dist/join-base-url.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Join a client base URL to a generated entity-relative path.
|
|
3
3
|
*
|
|
4
4
|
* ONE implementation, shared by both client tiers on purpose. `@metaobjectsdev/tanstack`
|
|
5
|
-
* wraps `
|
|
5
|
+
* wraps `useEntityPathFetcher()` with it and `@metaobjectsdev/angular` wraps the
|
|
6
6
|
* `EntityFetcherToken`; implemented separately they would eventually disagree about a
|
|
7
7
|
* trailing slash, and the disagreement would surface as a 404 in one framework only.
|
|
8
8
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metaobjectsdev/runtime-web",
|
|
3
|
-
"version": "1.0.0-rc.
|
|
3
|
+
"version": "1.0.0-rc.5",
|
|
4
4
|
"description": "Pure framework-agnostic browser core for metaobjects: currency, filter URL serialization, fetcher contract types.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"access": "public"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@metaobjectsdev/metadata": "1.0.0-rc.
|
|
48
|
+
"@metaobjectsdev/metadata": "1.0.0-rc.5",
|
|
49
49
|
"qs": "^6.13.0"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
@@ -22,14 +22,14 @@ import {
|
|
|
22
22
|
LAYOUT_DATA_GRID_ATTR_DEFAULT_SORT_FIELD,
|
|
23
23
|
LAYOUT_DATA_GRID_ATTR_DEFAULT_SORT_ORDER,
|
|
24
24
|
LAYOUT_DATA_GRID_ATTR_FILTERABLE,
|
|
25
|
+
FIELD_ATTR_SORTABLE_DEFAULT_ORDER,
|
|
26
|
+
DOC_ATTR_TITLE,
|
|
25
27
|
} from "@metaobjectsdev/metadata/constants";
|
|
26
28
|
import type { GridConfig } from "./fetcher.js";
|
|
27
29
|
|
|
28
30
|
const DEFAULT_PAGE_SIZE = 25;
|
|
29
31
|
const DEFAULT_GRID_NAME = "default";
|
|
30
|
-
|
|
31
|
-
// codegen; there is no exported constant for it in @metaobjectsdev/metadata.
|
|
32
|
-
const VIEW_ATTR_LABEL = "label";
|
|
32
|
+
|
|
33
33
|
|
|
34
34
|
/** A neutral, framework-agnostic column descriptor derived from metadata. */
|
|
35
35
|
export interface MetaColumn {
|
|
@@ -52,11 +52,21 @@ function humanize(s: string): string {
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
function firstView(field: MetaField): MetaView | undefined {
|
|
55
|
-
|
|
55
|
+
// views(), not ownViews(): ADR-0039 — a field that `extends` an abstract parent
|
|
56
|
+
// inherits the parent's view, and an own-only read drops it, so the column would
|
|
57
|
+
// silently lose both its header and its renderer hint.
|
|
58
|
+
return field.views()[0];
|
|
56
59
|
}
|
|
57
60
|
|
|
58
61
|
function header(field: MetaField): string {
|
|
59
|
-
|
|
62
|
+
// DOC_ATTR_TITLE, not the literal "label". `@label` is registered by NO provider in
|
|
63
|
+
// any port — `@title` is the documentation commonAttr chartered as the display label
|
|
64
|
+
// — so this read was `undefined` for every field that ever set one, and every grid
|
|
65
|
+
// header silently fell back to humanize(field.name). Same shape as `attr("isArray")`:
|
|
66
|
+
// an unregistered name answers `undefined`, which is indistinguishable from "unset".
|
|
67
|
+
//
|
|
68
|
+
// attr(), not ownAttr(), for the same ADR-0039 reason as firstView above.
|
|
69
|
+
const label = firstView(field)?.attr(DOC_ATTR_TITLE);
|
|
60
70
|
return typeof label === "string" ? label : humanize(field.name);
|
|
61
71
|
}
|
|
62
72
|
|
|
@@ -64,6 +74,32 @@ function viewKind(field: MetaField): string {
|
|
|
64
74
|
return firstView(field)?.subType ?? field.subType;
|
|
65
75
|
}
|
|
66
76
|
|
|
77
|
+
/**
|
|
78
|
+
* A grid's initial sort DIRECTION: the layout's `@defaultSortOrder` when it declares one,
|
|
79
|
+
* otherwise the named field's `@sortableDefaultOrder`, otherwise ascending.
|
|
80
|
+
*
|
|
81
|
+
* This is the runtime twin of `resolveGridDefaultSort()` in `codegen-ts`'s
|
|
82
|
+
* `filter-shared.ts`, and it must stay identical to it. It is duplicated rather than
|
|
83
|
+
* imported because that module lives in a SERVER package: `runtime-web` is the pure
|
|
84
|
+
* browser core and may depend only on `@metaobjectsdev/metadata` (see #287 — a single
|
|
85
|
+
* value import from the wrong entry point made every browser bundle fail).
|
|
86
|
+
*
|
|
87
|
+
* Reading only `@defaultSortOrder` — which this did — makes the runtime-built grid sort
|
|
88
|
+
* the opposite way from the generated grid AND from the endpoint it queries, for the one
|
|
89
|
+
* case the attribute exists to cover: a layout that names a field and lets the field say
|
|
90
|
+
* which way it runs.
|
|
91
|
+
*
|
|
92
|
+
* ADR-0039: `attr()` resolves, so a `@sortableDefaultOrder` inherited via `extends` counts.
|
|
93
|
+
*/
|
|
94
|
+
function gridDefaultSortOrder(
|
|
95
|
+
declaredOrder: unknown,
|
|
96
|
+
field: MetaField | undefined,
|
|
97
|
+
): "asc" | "desc" {
|
|
98
|
+
if (declaredOrder === "asc" || declaredOrder === "desc") return declaredOrder;
|
|
99
|
+
const fromField = field?.attr(FIELD_ATTR_SORTABLE_DEFAULT_ORDER);
|
|
100
|
+
return fromField === "desc" ? "desc" : "asc";
|
|
101
|
+
}
|
|
102
|
+
|
|
67
103
|
/**
|
|
68
104
|
* Build a grid (config + columns) from a MetaObject at runtime.
|
|
69
105
|
*
|
|
@@ -78,7 +114,12 @@ export function buildGrid(meta: MetaObject, gridName?: string): MetaGrid {
|
|
|
78
114
|
|
|
79
115
|
const fieldsByName = new Map(meta.fields().map((f) => [f.name, f] as const));
|
|
80
116
|
|
|
81
|
-
|
|
117
|
+
// attr(), not ownAttr(), on every layout read below — same ADR-0039 reason as
|
|
118
|
+
// firstView/header above, which this file already applies to its FIELD reads: a
|
|
119
|
+
// `layout.dataGrid` that inherits its attrs via `extends` keeps them on the parent,
|
|
120
|
+
// and an own-only read silently drops every one of them (no columns, default page
|
|
121
|
+
// size, no initial sort) on a grid that plainly declares them.
|
|
122
|
+
const columnsAttr = layout?.attr(LAYOUT_DATA_GRID_ATTR_COLUMNS);
|
|
82
123
|
const names: string[] = Array.isArray(columnsAttr)
|
|
83
124
|
? columnsAttr.filter((x): x is string => typeof x === "string")
|
|
84
125
|
: meta.fields().map((f) => f.name);
|
|
@@ -88,16 +129,16 @@ export function buildGrid(meta: MetaObject, gridName?: string): MetaGrid {
|
|
|
88
129
|
.filter((f): f is MetaField => f !== undefined)
|
|
89
130
|
.map((f) => ({ field: f.name, header: header(f), viewKind: viewKind(f) }));
|
|
90
131
|
|
|
91
|
-
const pageSizeAttr = layout?.
|
|
92
|
-
const sortField = layout?.
|
|
93
|
-
const sortOrder = layout?.
|
|
132
|
+
const pageSizeAttr = layout?.attr(LAYOUT_DATA_GRID_ATTR_PAGE_SIZE);
|
|
133
|
+
const sortField = layout?.attr(LAYOUT_DATA_GRID_ATTR_DEFAULT_SORT_FIELD);
|
|
134
|
+
const sortOrder = layout?.attr(LAYOUT_DATA_GRID_ATTR_DEFAULT_SORT_ORDER);
|
|
94
135
|
|
|
95
136
|
const config: GridConfig = {
|
|
96
137
|
name: layout?.name ?? gridName ?? DEFAULT_GRID_NAME,
|
|
97
138
|
pageSize: typeof pageSizeAttr === "number" ? pageSizeAttr : DEFAULT_PAGE_SIZE,
|
|
98
|
-
filterable: layout?.
|
|
139
|
+
filterable: layout?.attr(LAYOUT_DATA_GRID_ATTR_FILTERABLE) === true,
|
|
99
140
|
...(typeof sortField === "string"
|
|
100
|
-
? { defaultSort: { field: sortField, order: sortOrder
|
|
141
|
+
? { defaultSort: { field: sortField, order: gridDefaultSortOrder(sortOrder, fieldsByName.get(sortField)) } }
|
|
101
142
|
: {}),
|
|
102
143
|
};
|
|
103
144
|
|
package/src/join-base-url.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Join a client base URL to a generated entity-relative path.
|
|
3
3
|
*
|
|
4
4
|
* ONE implementation, shared by both client tiers on purpose. `@metaobjectsdev/tanstack`
|
|
5
|
-
* wraps `
|
|
5
|
+
* wraps `useEntityPathFetcher()` with it and `@metaobjectsdev/angular` wraps the
|
|
6
6
|
* `EntityFetcherToken`; implemented separately they would eventually disagree about a
|
|
7
7
|
* trailing slash, and the disagreement would surface as a 404 in one framework only.
|
|
8
8
|
*
|