@cosmicdrift/kumiko-headless 0.235.1 → 0.235.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cosmicdrift/kumiko-headless",
3
- "version": "0.235.1",
3
+ "version": "0.235.3",
4
4
  "description": "Headless UI logic for Kumiko — Dispatcher contract, Form-Controller, View-Model, Nav-Resolver. Plattform- und React-frei; jeder Renderer (renderer, renderer-web, renderer-native, …) komponiert darauf.",
5
5
  "license": "BUSL-1.1",
6
6
  "author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
@@ -36,7 +36,7 @@
36
36
  }
37
37
  },
38
38
  "dependencies": {
39
- "@cosmicdrift/kumiko-framework": "0.235.1",
39
+ "@cosmicdrift/kumiko-framework": "0.235.3",
40
40
  "temporal-polyfill": "^0.3.2",
41
41
  "zod": "^4.4.3"
42
42
  },
@@ -3,7 +3,10 @@ import type {
3
3
  EntityDefinition,
4
4
  EntityListScreenDefinition,
5
5
  } from "@cosmicdrift/kumiko-framework/ui-types";
6
- import { LIST_ROW_META_COLUMNS } from "@cosmicdrift/kumiko-framework/ui-types";
6
+ import {
7
+ LIST_ROW_META_COLUMNS,
8
+ LIST_ROW_META_REFERENCES,
9
+ } from "@cosmicdrift/kumiko-framework/ui-types";
7
10
  import { computeListViewModel } from "../list";
8
11
 
9
12
  // Minimal EntityDefinition-shape. ui-core's view-model only reads
@@ -283,15 +286,59 @@ describe("computeListViewModel", () => {
283
286
  featureName: "tasks",
284
287
  });
285
288
 
289
+ const ref = LIST_ROW_META_REFERENCES[field];
286
290
  expect(vm.columns[1]).toEqual({
287
291
  field,
288
292
  label: `tasks:entity:task:field:${field}`,
289
- type: expectedType,
290
- sortable: true,
293
+ ...(ref !== undefined
294
+ ? {
295
+ type: "reference",
296
+ sortable: false,
297
+ refFeature: ref.refFeature,
298
+ refEntity: ref.refEntity,
299
+ refLabelField: ref.refLabelField,
300
+ }
301
+ : { type: expectedType, sortable: true }),
291
302
  });
292
303
  }
293
304
  });
294
305
 
306
+ // tenantId carries a GUID in the DB but should render the referenced
307
+ // tenant's display name, like a declared reference field does — not the
308
+ // raw GUID. insertedById stays unchanged: this also pins that the map
309
+ // switches exactly one column, not every row-meta ID column.
310
+ test("tenantId row-meta column resolves as a reference column, insertedById unchanged", () => {
311
+ const vm = computeListViewModel({
312
+ screen: listScreen(["tenantId", "insertedById", "id"]),
313
+ entity: taskEntity,
314
+ rows: [],
315
+ translate,
316
+ featureName: "tasks",
317
+ });
318
+
319
+ expect(vm.columns[0]).toEqual({
320
+ field: "tenantId",
321
+ label: "tasks:entity:task:field:tenantId",
322
+ type: "reference",
323
+ sortable: false,
324
+ refFeature: "tenant",
325
+ refEntity: "tenant",
326
+ refLabelField: "name",
327
+ });
328
+ expect(vm.columns[1]).toEqual({
329
+ field: "insertedById",
330
+ label: "tasks:entity:task:field:insertedById",
331
+ type: "text",
332
+ sortable: true,
333
+ });
334
+ expect(vm.columns[2]).toEqual({
335
+ field: "id",
336
+ label: "tasks:entity:task:field:id",
337
+ type: "text",
338
+ sortable: true,
339
+ });
340
+ });
341
+
295
342
  test("row-meta column: explicit label + renderer are passed through unchanged", () => {
296
343
  const fmt = { format: "currency" as const, symbol: "€" };
297
344
  const vm = computeListViewModel({
@@ -5,6 +5,7 @@ import type {
5
5
  } from "@cosmicdrift/kumiko-framework/ui-types";
6
6
  import {
7
7
  LIST_ROW_META_COLUMNS,
8
+ LIST_ROW_META_REFERENCES,
8
9
  normalizeListColumn,
9
10
  parseRefTarget,
10
11
  } from "@cosmicdrift/kumiko-framework/ui-types";
@@ -50,17 +51,26 @@ export function computeListViewModel(input: ComputeListViewModelInput): ListView
50
51
  // a real base-table column that's never a declared entity field, e.g.
51
52
  // a SystemAdmin cross-tenant list exposing tenantId. Unlike the
52
53
  // derivedFields branch above, these are actual DB columns, so
53
- // server-side ORDER BY works — sortable stays true.
54
+ // server-side ORDER BY works — sortable stays true, except for the
55
+ // ID columns in LIST_ROW_META_REFERENCES (see their reference branch).
54
56
  const rowMetaType = LIST_ROW_META_COLUMNS[normalized.field];
55
57
  if (rowMetaType !== undefined) {
58
+ const rowMetaRef = LIST_ROW_META_REFERENCES[normalized.field];
56
59
  columns.push({
57
60
  field: normalized.field,
58
61
  label: translate(
59
62
  normalized.label ?? fieldLabelKey(featureName, screen.entity, normalized.field),
60
63
  ),
61
- type: rowMetaType,
62
- sortable: true,
64
+ type: rowMetaRef !== undefined ? "reference" : rowMetaType,
65
+ // The DB column holds the GUID, not the resolved label — server-side
66
+ // ORDER BY would sort by GUID while the cell shows the name.
67
+ sortable: rowMetaRef === undefined,
63
68
  ...(normalized.renderer !== undefined && { renderer: normalized.renderer }),
69
+ ...(rowMetaRef !== undefined && {
70
+ refEntity: rowMetaRef.refEntity,
71
+ refFeature: rowMetaRef.refFeature,
72
+ refLabelField: rowMetaRef.refLabelField,
73
+ }),
64
74
  });
65
75
  continue;
66
76
  }