@conduction/nextcloud-vue 2.110.0 → 2.112.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.
Files changed (142) hide show
  1. package/dist/esm/components/CnActionDialog/CnActionDialog.vue.js +1 -1
  2. package/dist/esm/components/CnActionDialog/CnActionDialog.vue2.js +3 -2
  3. package/dist/esm/components/CnActionDialog/CnActionDialog.vue2.js.map +1 -1
  4. package/dist/esm/components/CnActionDialog/CnActionDialog.vue3.js +4 -2
  5. package/dist/esm/components/CnActionDialog/CnActionDialog.vue3.js.map +1 -1
  6. package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js +2 -1
  7. package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js.map +1 -1
  8. package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js.map +1 -1
  9. package/dist/esm/components/CnAssignDialog/CnAssignDialog.vue.js +1 -1
  10. package/dist/esm/components/CnAssignDialog/CnAssignDialog.vue2.js +3 -2
  11. package/dist/esm/components/CnAssignDialog/CnAssignDialog.vue2.js.map +1 -1
  12. package/dist/esm/components/CnAssignDialog/CnAssignDialog.vue3.js +2 -1
  13. package/dist/esm/components/CnAssignDialog/CnAssignDialog.vue3.js.map +1 -1
  14. package/dist/esm/components/CnBoardView/CnBoardView.vue.js +1 -1
  15. package/dist/esm/components/CnBoardView/CnBoardView.vue2.js +54 -5
  16. package/dist/esm/components/CnBoardView/CnBoardView.vue2.js.map +1 -1
  17. package/dist/esm/components/CnBoardView/CnBoardView.vue3.js +16 -2
  18. package/dist/esm/components/CnBoardView/CnBoardView.vue3.js.map +1 -1
  19. package/dist/esm/components/CnCardGrid/CnCardGrid.vue.js +1 -1
  20. package/dist/esm/components/CnCardGrid/CnCardGrid.vue2.js +10 -0
  21. package/dist/esm/components/CnCardGrid/CnCardGrid.vue2.js.map +1 -1
  22. package/dist/esm/components/CnCardGrid/CnCardGrid.vue3.js +2 -1
  23. package/dist/esm/components/CnCardGrid/CnCardGrid.vue3.js.map +1 -1
  24. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue.js +1 -1
  25. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js +22 -2
  26. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js.map +1 -1
  27. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js +17 -3
  28. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js.map +1 -1
  29. package/dist/esm/components/CnChartWidget/CnChartWidget.vue.js +1 -1
  30. package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js.map +1 -1
  31. package/dist/esm/components/CnChartWidget/CnChartWidget.vue3.js.map +1 -1
  32. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +52 -8
  33. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
  34. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +98 -63
  35. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
  36. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue.js +1 -1
  37. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js +48 -11
  38. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js.map +1 -1
  39. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js +160 -97
  40. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js.map +1 -1
  41. package/dist/esm/components/CnFormDialog/CnFormDialog.vue.js +1 -1
  42. package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js.map +1 -1
  43. package/dist/esm/components/CnFormDialog/CnFormDialog.vue3.js +2 -2
  44. package/dist/esm/components/CnFormDialog/CnFormDialog.vue3.js.map +1 -1
  45. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +203 -14
  46. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  47. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +19 -4
  48. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  49. package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue2.js.map +1 -1
  50. package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue3.js +1 -1
  51. package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue3.js.map +1 -1
  52. package/dist/esm/components/CnNcDashboardList/CnNcDashboardList.vue.js +1 -1
  53. package/dist/esm/components/CnNcDashboardList/CnNcDashboardList.vue2.js +21 -1
  54. package/dist/esm/components/CnNcDashboardList/CnNcDashboardList.vue2.js.map +1 -1
  55. package/dist/esm/components/CnNcDashboardList/CnNcDashboardList.vue3.js.map +1 -1
  56. package/dist/esm/components/CnObjectCard/CnObjectCard.vue.js +1 -1
  57. package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js +36 -2
  58. package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js.map +1 -1
  59. package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js +44 -5
  60. package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js.map +1 -1
  61. package/dist/esm/components/CnPartyPicker/CnPartyPicker.vue.js +1 -0
  62. package/dist/esm/components/CnPartyPicker/CnPartyPicker.vue.js.map +1 -1
  63. package/dist/esm/components/CnPartyPicker/CnPartyPicker.vue2.js +22 -2
  64. package/dist/esm/components/CnPartyPicker/CnPartyPicker.vue2.js.map +1 -1
  65. package/dist/esm/components/CnPartyPicker/CnPartyPicker.vue3.js +36 -16
  66. package/dist/esm/components/CnPartyPicker/CnPartyPicker.vue3.js.map +1 -1
  67. package/dist/esm/components/CnSearchSelect/CnSearchSelect.vue.js +1 -1
  68. package/dist/esm/components/CnSearchSelect/CnSearchSelect.vue2.js.map +1 -1
  69. package/dist/esm/components/CnSearchSelect/CnSearchSelect.vue3.js.map +1 -1
  70. package/dist/esm/composables/useRefLabels.js +26 -6
  71. package/dist/esm/composables/useRefLabels.js.map +1 -1
  72. package/dist/esm/integrations/registry.js +4 -0
  73. package/dist/esm/integrations/registry.js.map +1 -1
  74. package/dist/esm/l10n/en.json.js +3 -1
  75. package/dist/esm/l10n/en.json.js.map +1 -1
  76. package/dist/esm/l10n/nl.json.js +3 -1
  77. package/dist/esm/l10n/nl.json.js.map +1 -1
  78. package/dist/esm/library-style.js +1 -1
  79. package/dist/esm/nextcloud-vue.css +630 -303
  80. package/dist/esm/store/plugins/liveUpdates.js +3 -1
  81. package/dist/esm/store/plugins/liveUpdates.js.map +1 -1
  82. package/dist/esm/store/plugins/logs.js +2 -1
  83. package/dist/esm/store/plugins/logs.js.map +1 -1
  84. package/dist/esm/utils/detailActionModel.js +28 -1
  85. package/dist/esm/utils/detailActionModel.js.map +1 -1
  86. package/dist/esm/utils/fillTemplate.js +13 -5
  87. package/dist/esm/utils/fillTemplate.js.map +1 -1
  88. package/dist/esm/utils/headerFieldChips.js +21 -2
  89. package/dist/esm/utils/headerFieldChips.js.map +1 -1
  90. package/dist/esm/utils/mapList.js +26 -11
  91. package/dist/esm/utils/mapList.js.map +1 -1
  92. package/dist/esm/utils/savedViewHelpers.js +40 -3
  93. package/dist/esm/utils/savedViewHelpers.js.map +1 -1
  94. package/dist/esm/utils/savedViewMenu.js +12 -5
  95. package/dist/esm/utils/savedViewMenu.js.map +1 -1
  96. package/dist/esm/utils/validateManifestV2.compiled.js +3 -3
  97. package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
  98. package/dist/nextcloud-vue.cjs.js +2760 -1995
  99. package/dist/nextcloud-vue.cjs.js.map +2 -2
  100. package/dist/nextcloud-vue.css +630 -303
  101. package/l10n/en.json +3 -1
  102. package/l10n/nl.json +3 -1
  103. package/package.json +1 -1
  104. package/src/components/CnActionDialog/CnActionDialog.vue +32 -9
  105. package/src/components/CnAppRoot/CnAppRoot.vue +2 -1
  106. package/src/components/CnAssignDialog/CnAssignDialog.vue +4 -2
  107. package/src/components/CnBoardView/CnBoardView.vue +58 -5
  108. package/src/components/CnCardGrid/CnCardGrid.md +1 -0
  109. package/src/components/CnCardGrid/CnCardGrid.vue +11 -0
  110. package/src/components/CnCellRenderer/CnCellRenderer.vue +27 -3
  111. package/src/components/CnChartWidget/CnChartWidget.vue +6 -0
  112. package/src/components/CnDetailPage/CnDetailPage.vue +77 -20
  113. package/src/components/CnDetailWidgetHost/CnDetailWidgetHost.vue +100 -5
  114. package/src/components/CnFormDialog/CnFormDialog.vue +1 -1
  115. package/src/components/CnIndexPage/CnIndexPage.md +1 -1
  116. package/src/components/CnIndexPage/CnIndexPage.vue +211 -16
  117. package/src/components/CnIndexSidebar/CnIndexSidebar.md +1 -1
  118. package/src/components/CnIndexSidebar/CnIndexSidebar.vue +2 -2
  119. package/src/components/CnNcDashboardList/CnNcDashboardList.vue +21 -1
  120. package/src/components/CnObjectCard/CnObjectCard.md +1 -0
  121. package/src/components/CnObjectCard/CnObjectCard.vue +51 -5
  122. package/src/components/CnPartyPicker/CnPartyPicker.vue +62 -16
  123. package/src/components/CnSearchSelect/CnSearchSelect.vue +8 -0
  124. package/src/composables/useRefLabels.js +25 -5
  125. package/src/css/board.css +5 -2
  126. package/src/css/dialog.css +53 -3
  127. package/src/css/index-page.css +26 -1
  128. package/src/css/look-board-detail.css +55 -22
  129. package/src/css/look-board-index.css +82 -12
  130. package/src/css/look-board-reports.css +1 -1
  131. package/src/css/look-board.css +84 -11
  132. package/src/integrations/registry.js +4 -0
  133. package/src/schemas/app-manifest-v2.schema.json +11 -5
  134. package/src/store/plugins/liveUpdates.js +3 -1
  135. package/src/store/plugins/logs.js +2 -1
  136. package/src/utils/detailActionModel.js +27 -0
  137. package/src/utils/fillTemplate.js +13 -5
  138. package/src/utils/headerFieldChips.js +21 -2
  139. package/src/utils/mapList.js +26 -11
  140. package/src/utils/savedViewHelpers.js +39 -2
  141. package/src/utils/savedViewMenu.js +12 -5
  142. package/src/utils/validateManifestV2.compiled.js +3 -3
@@ -55,7 +55,7 @@ import { isRowActionVisible, rowActionPayload } from '../../utils/rowActionItem.
55
55
  import { isNewTabClick, preventMiddleClickAutoscroll, isRowMiddleClick, isNewTabHandled, markNewTabHandled } from '../../utils/rowAuxClick.js';
56
56
  import { compileRowClass } from '../../utils/rowClassRules.js';
57
57
  import { DEFAULT_ROW_INDICATOR_CAP } from '../../utils/rowIndicators.js';
58
- import { defaultFilterViews, viewMatchesScope, normalizeSharedWith, extractViewState, buildRouteQueryFromViewState, extractViewStateFromRouteQuery, buildViewCreatePayload, savedViewScope, schemaSlug } from '../../utils/savedViewHelpers.js';
58
+ import { defaultFilterViews, pageOffersSavedViews, viewMatchesScope, normalizeSharedWith, extractViewState, buildRouteQueryFromViewState, extractViewStateFromRouteQuery, buildViewCreatePayload, savedViewScope, schemaSlug } from '../../utils/savedViewHelpers.js';
59
59
  import { savedViewOverrides, savedViewBadge } from '../../utils/savedViewOverrides.js';
60
60
  import { fieldsFromSchema, columnsFromSchema } from '../../utils/schema.js';
61
61
  import { resolveScopeLayout, resolveScopePresentation } from '../../utils/scopeListLayout.js';
@@ -180,11 +180,22 @@ function declaredFilterFields(props) {
180
180
  * @return {object} The `{ fieldKey: values }` map, empty when the link carries none.
181
181
  */
182
182
  function namedFiltersFromRoute(instance, props) {
183
+ const route = instance && instance.proxy && instance.proxy.$route;
184
+ return namedFiltersFromQuery((route && route.query) || {}, props)
185
+ }
186
+
187
+ /**
188
+ * The named-source filters a query carries, as `namedFiltersFromRoute` reads them.
189
+ *
190
+ * @param {object} query The route query.
191
+ * @param {object} props The CnIndexPage props.
192
+ *
193
+ * @return {object} The `{ fieldKey: values }` map.
194
+ */
195
+ function namedFiltersFromQuery(query, props) {
183
196
  if (!props.entitySource) {
184
197
  return {}
185
198
  }
186
- const route = instance && instance.proxy && instance.proxy.$route;
187
- const query = (route && route.query) || {};
188
199
  const properties = declaredFilterFields(props);
189
200
  const out = {};
190
201
 
@@ -432,6 +443,8 @@ var script = {
432
443
 
433
444
  inject: {
434
445
  cnCustomComponents: { default: () => ({}) },
446
+ /** The app's named formatters, provided by CnAppRoot, for the map list's pills and template tokens. */
447
+ cnFormatters: { default: () => ({}) },
435
448
  /** The permissions the user holds, provided by CnAppRoot; for gated page tabs. */
436
449
  cnPermissions: { default: () => [] },
437
450
  /** The app config an ancestor provides, for `@config.<key>` in quick-filter labels. */
@@ -1627,9 +1640,11 @@ var script = {
1627
1640
  },
1628
1641
 
1629
1642
  /**
1630
- * Opt-in flag for the saved-views control (saved-views-ui) rendered
1631
- * in the toolbar. Defaults to `false` — an app must explicitly
1632
- * enable it per page. When `true`, a Views dropdown lists the
1643
+ * Saved views (saved-views-ui). Unset, the sidebar's Views tab is on
1644
+ * for every page with a sidebar and a source a view can be scoped to
1645
+ * (register and schema, `entitySource` or `savedViewsScope`); `false`
1646
+ * turns it off. `true` also forces the sidebar and adds the toolbar
1647
+ * control, where a Views dropdown lists the
1633
1648
  * current user's OpenRegister saved-search views
1634
1649
  * (`GET /apps/openregister/api/views`); applying one writes its
1635
1650
  * stored filters/search/sort into the route query (reusing the
@@ -1641,7 +1656,7 @@ var script = {
1641
1656
  */
1642
1657
  allowSavedViews: {
1643
1658
  type: Boolean,
1644
- default: false,
1659
+ default: null,
1645
1660
  },
1646
1661
 
1647
1662
  /**
@@ -2788,6 +2803,8 @@ var script = {
2788
2803
  boardPrevPageSize: this.viewMode === 'board' ? ((this.pagination && this.pagination.limit) || 20) : null,
2789
2804
  /** Resolved labels of reference columns: `{ [columnKey]: { [id]: label|null } }`. */
2790
2805
  refLabels: {},
2806
+ /** Colour and icon names of the records badge columns point at: `{ [columnKey]: { [id]: { color, icon } } }`. */
2807
+ refLooks: {},
2791
2808
  /** Count per tab-strip index, for the entries that asked for one; null = none. */
2792
2809
  tabCounts: null,
2793
2810
  // The counts of the `filterStrip` pills, by pill key ('all', 'v0', ...).
@@ -4203,7 +4220,7 @@ var script = {
4203
4220
  * @spec openspec/changes/saved-views-manage-and-defaults/tasks.md#task-6
4204
4221
  */
4205
4222
  savedViewsForSidebar() {
4206
- if (!this.allowSavedViews) {
4223
+ if (!this.savedViewsOffered) {
4207
4224
  return null
4208
4225
  }
4209
4226
  return {
@@ -4702,6 +4719,12 @@ var script = {
4702
4719
  */
4703
4720
  renderedColumns() {
4704
4721
  let cols = this.tableColumns;
4722
+ if (this.refLookSpecs.length > 0) {
4723
+ const lookKeys = new Set(this.refLookSpecs.map((spec) => spec.key));
4724
+ cols = cols.map((col) => (col && typeof col === 'object' && lookKeys.has(col.key)
4725
+ ? { ...col, widgetProps: { ...(col.widgetProps || {}), looks: this.refLooks[col.key] || {} } }
4726
+ : col));
4727
+ }
4705
4728
  if (this.refLabelSpecs.length > 0) {
4706
4729
  const byKey = new Map(this.refLabelSpecs.map((s) => [s.key, s]));
4707
4730
  cols = cols.map((col) => {
@@ -4772,6 +4795,108 @@ var script = {
4772
4795
  *
4773
4796
  * @return {Object<string, string[]>} Distinct ids per column key.
4774
4797
  */
4798
+ /**
4799
+ * The pills that take their tone and icon from the record they point at
4800
+ * (`resolve: { colorField?, iconField?, register?, schema? }`): badge
4801
+ * columns and the list view's leading and trailing cells
4802
+ * (`widgetProps.resolve`), the board card's pill (`board.card.resolve`)
4803
+ * and the record card's pills (`cardLayout` headPill, footerPill, chips).
4804
+ * Register and schema default to the field's reference in the schema.
4805
+ *
4806
+ * @return {Array<{key: string, register: string, schema: string, colorField: string, iconField: string}>} The specs.
4807
+ * @spec openspec/changes/pill-color-field/specs/pill-color-field/spec.md#requirement-a-badge-cell-takes-its-tone-and-icon-from-the-referenced-record
4808
+ */
4809
+ refLookSpecs() {
4810
+ const list = this.listConfig || {};
4811
+ const listCells = [list.leading, ...(Array.isArray(list.trailing) ? list.trailing : [list.trailing])];
4812
+ const badgeSources = [...this.tableColumns, ...listCells]
4813
+ .filter((c) => c && typeof c === 'object' && c.widget === 'badge' && c.widgetProps)
4814
+ .map((c) => ({ key: c.key, resolve: c.widgetProps.resolve }));
4815
+ // The board card's pill (`board.card.pill` with `board.card.resolve`)
4816
+ // and the record card's pills (`cardLayout` headPill, footerPill,
4817
+ // chips, each with its own `resolve`).
4818
+ const card = this.board && this.board.card && typeof this.board.card === 'object' ? this.board.card : {};
4819
+ const layout = this.cardLayout && typeof this.cardLayout === 'object' ? this.cardLayout : {};
4820
+ const layoutPills = [layout.headPill, layout.footerPill, ...(Array.isArray(layout.chips) ? layout.chips : [])]
4821
+ .filter((def) => def && typeof def === 'object')
4822
+ .map((def) => ({ key: def.field, resolve: def.resolve }));
4823
+ // The map list's pills (`mapConfig.list.pills`, each with its own `resolve`).
4824
+ const mapListPills = (this.mapListEnabled && Array.isArray(this.mapConfig.list.pills) ? this.mapConfig.list.pills : [])
4825
+ .filter((def) => def && typeof def === 'object')
4826
+ .map((def) => ({ key: def.path, resolve: def.resolve }));
4827
+ const seen = new Set();
4828
+ const cols = [...badgeSources, { key: card.pill, resolve: card.resolve }, ...layoutPills, ...mapListPills].filter((c) => {
4829
+ const wanted = typeof c.key === 'string' && c.key !== '' && c.resolve && typeof c.resolve === 'object'
4830
+ && (c.resolve.colorField || c.resolve.iconField) && !seen.has(c.key);
4831
+ if (wanted) {
4832
+ seen.add(c.key);
4833
+ }
4834
+ return wanted
4835
+ });
4836
+ if (cols.length === 0) {
4837
+ return []
4838
+ }
4839
+ const fields = this.effectiveSchema ? fieldsFromSchema(this.effectiveSchema, { includeReadOnly: true }) : [];
4840
+ const specs = [];
4841
+ for (const col of cols) {
4842
+ const resolve = col.resolve;
4843
+ const field = fields.find((f) => f.key === col.key);
4844
+ const ref = (field && field.reference) || {};
4845
+ const register = resolve.register || ref.register || (typeof this.register === 'string' ? this.register : '');
4846
+ const schema = resolve.schema || (ref.schema !== undefined && ref.schema !== null ? String(ref.schema) : '');
4847
+ if (!register || !schema) {
4848
+ continue
4849
+ }
4850
+ specs.push({ key: col.key, register, schema, colorField: resolve.colorField || '', iconField: resolve.iconField || '' });
4851
+ }
4852
+ return specs
4853
+ },
4854
+
4855
+ /**
4856
+ * `listConfig` with the referenced records' looks on its badge cells,
4857
+ * as `renderedColumns` does for the table.
4858
+ *
4859
+ * @return {object} The list view's config.
4860
+ * @spec openspec/changes/pill-color-field/specs/pill-color-field/spec.md#requirement-a-badge-cell-takes-its-tone-and-icon-from-the-referenced-record
4861
+ */
4862
+ renderedListConfig() {
4863
+ const list = this.listConfig;
4864
+ if (!list || this.refLookSpecs.length === 0) {
4865
+ return list
4866
+ }
4867
+ const lookKeys = new Set(this.refLookSpecs.map((spec) => spec.key));
4868
+ const withLooks = (cell) => (cell && typeof cell === 'object' && lookKeys.has(cell.key)
4869
+ ? { ...cell, widgetProps: { ...(cell.widgetProps || {}), looks: this.refLooks[cell.key] || {} } }
4870
+ : cell);
4871
+ return {
4872
+ ...list,
4873
+ ...(list.leading ? { leading: withLooks(list.leading) } : {}),
4874
+ ...(list.trailing ? { trailing: Array.isArray(list.trailing) ? list.trailing.map(withLooks) : withLooks(list.trailing) } : {}),
4875
+ }
4876
+ },
4877
+
4878
+ /**
4879
+ * The ids each `refLookSpecs` column shows on screen.
4880
+ *
4881
+ * @return {{[key: string]: Array<string>}} Sorted ids by column key.
4882
+ */
4883
+ refLookIds() {
4884
+ const out = {};
4885
+ for (const spec of this.refLookSpecs) {
4886
+ const ids = new Set();
4887
+ for (const row of this.displayObjects) {
4888
+ const v = row ? row[spec.key] : undefined
4889
+ ;(Array.isArray(v) ? v : [v]).forEach((id) => {
4890
+ if (id !== null && id !== undefined && id !== '' && typeof id !== 'object') {
4891
+ ids.add(String(id));
4892
+ }
4893
+ });
4894
+ }
4895
+ out[spec.key] = [...ids].sort();
4896
+ }
4897
+ return out
4898
+ },
4899
+
4775
4900
  refLabelIds() {
4776
4901
  const out = {};
4777
4902
  const facets = this.storeFacets || this.resolvedSidebar.facets || {};
@@ -5039,13 +5164,15 @@ var script = {
5039
5164
  const translated = {
5040
5165
  ...list,
5041
5166
  title: this.cnTranslate(list.title),
5042
- sub: list.sub ? this.cnTranslate(list.sub) : '',
5167
+ sub: Array.isArray(list.sub) ? list.sub.map((s) => this.cnTranslate(s)) : (list.sub ? this.cnTranslate(list.sub) : ''),
5043
5168
  due: list.due ? this.cnTranslate(list.due) : '',
5044
5169
  };
5045
5170
  return mapListItems(this.displayObjects, translated, {
5046
5171
  rowKey: this.rowKey,
5047
5172
  located: (row) => Boolean(this.resolveRowGeometry(row)),
5048
5173
  translate: (text) => this.cnTranslate(text),
5174
+ formatters: this.cnFormatters,
5175
+ looks: this.refLooks,
5049
5176
  })
5050
5177
  },
5051
5178
 
@@ -5344,7 +5471,16 @@ var script = {
5344
5471
  * @return {{ scope: string, register: string, schema: object|string|null }} The page's source.
5345
5472
  */
5346
5473
  savedViewsPage() {
5347
- return { scope: this.savedViewsScope, register: this.register, schema: this.schema }
5474
+ return { scope: this.savedViewsScope, register: this.register, schema: this.schema, source: this.entitySource }
5475
+ },
5476
+
5477
+ /**
5478
+ * Whether this page offers saved views in its sidebar.
5479
+ *
5480
+ * @return {boolean}
5481
+ */
5482
+ savedViewsOffered() {
5483
+ return pageOffersSavedViews(this)
5348
5484
  },
5349
5485
 
5350
5486
  /**
@@ -6660,6 +6796,15 @@ var script = {
6660
6796
  },
6661
6797
  },
6662
6798
 
6799
+ // Read the colour and icon of the records badge columns point at.
6800
+ refLookIds: {
6801
+ immediate: true,
6802
+ deep: true,
6803
+ handler() {
6804
+ this.loadRefLooks();
6805
+ },
6806
+ },
6807
+
6663
6808
  // The Active line names a referenced value, not its id.
6664
6809
  activeFilterRefIds: {
6665
6810
  deep: true,
@@ -6917,7 +7062,7 @@ var script = {
6917
7062
  created() {
6918
7063
  this.applyViewModeFromRoute();
6919
7064
  this.pushAiContext();
6920
- if (this.allowSavedViews) {
7065
+ if (this.savedViewsOffered) {
6921
7066
  this.fetchSavedViews();
6922
7067
  }
6923
7068
  this.selfActions = createSelfModeActions({
@@ -7111,6 +7256,45 @@ var script = {
7111
7256
  }));
7112
7257
  },
7113
7258
 
7259
+ /**
7260
+ * Read the colour and icon names `refLookSpecs` columns need, for the
7261
+ * rows on screen, with the same resolver as the labels. A failure
7262
+ * leaves the badge as declared.
7263
+ *
7264
+ * @return {Promise<void>}
7265
+ * @spec openspec/changes/pill-color-field/specs/pill-color-field/spec.md#requirement-a-badge-cell-takes-its-tone-and-icon-from-the-referenced-record
7266
+ */
7267
+ async loadRefLooks() {
7268
+ if (this.refLookSpecs.length === 0) {
7269
+ return
7270
+ }
7271
+ if (!this._refLabelResolver) {
7272
+ this._refLabelResolver = createRefLabelResolver(() => {
7273
+ try {
7274
+ return (this.list && this.list.objectStore) || useObjectStore()
7275
+ } catch {
7276
+ return null
7277
+ }
7278
+ });
7279
+ }
7280
+ const read = (spec, ids, name) => (name
7281
+ ? this._refLabelResolver.resolve(spec.register, spec.schema, ids, name, { strict: true }).catch(() => ({}))
7282
+ : Promise.resolve({}));
7283
+ await Promise.all(this.refLookSpecs.map(async (spec) => {
7284
+ const known = this.refLooks[spec.key] || {};
7285
+ const ids = (this.refLookIds[spec.key] || []).filter((id) => !Object.hasOwn(known, id));
7286
+ if (ids.length === 0) {
7287
+ return
7288
+ }
7289
+ const [colors, icons] = await Promise.all([read(spec, ids, spec.colorField), read(spec, ids, spec.iconField)]);
7290
+ const found = {};
7291
+ ids.forEach((id) => {
7292
+ found[id] = { color: (colors && colors[id]) || null, icon: (icons && icons[id]) || null };
7293
+ });
7294
+ this.refLooks = { ...this.refLooks, [spec.key]: { ...(this.refLooks[spec.key] || {}), ...found } };
7295
+ }));
7296
+ },
7297
+
7114
7298
  /**
7115
7299
  * Whether a saved view shows its record count (`viewCounts`).
7116
7300
  *
@@ -10025,8 +10209,8 @@ var script = {
10025
10209
 
10026
10210
  /**
10027
10211
  * Fetch the current user's saved views (own + public) from
10028
- * OpenRegister's views API. Called from created() when
10029
- * `allowSavedViews` is enabled.
10212
+ * OpenRegister's views API. Called from created() when the page
10213
+ * offers saved views.
10030
10214
  */
10031
10215
  async fetchSavedViews() {
10032
10216
  this.savedViewsLoading = true;
@@ -10096,6 +10280,9 @@ var script = {
10096
10280
  query.savedView = this.appliedSavedViewId;
10097
10281
  }
10098
10282
  const nav = this.$router.replace({ query });
10283
+ if (this.isNamedSource) {
10284
+ this.namedActiveFilters = namedFiltersFromQuery(query, this);
10285
+ }
10099
10286
  // Swallow the duplicate-navigation rejection (Vue Router 3)
10100
10287
  // when the applied view matches the current query.
10101
10288
  if (nav && typeof nav.catch === 'function') {
@@ -10269,7 +10456,7 @@ var script = {
10269
10456
  return
10270
10457
  }
10271
10458
  const badge = this.savedViewMenuBadge(view);
10272
- menu.toggle({ id: String(view.id || view.slug), page: this.savedViewPage, name: view.name, ...(badge ? { badge } : {}) });
10459
+ menu.toggle({ id: String(view.id || view.slug), page: this.savedViewPage, name: view.name, ...(typeof view.icon === 'string' && view.icon !== '' ? { icon: view.icon } : {}), ...(badge ? { badge } : {}) });
10273
10460
  },
10274
10461
 
10275
10462
  /**
@@ -10804,7 +10991,9 @@ var script = {
10804
10991
  if (resultData && resultData.success && this._refLabelResolver) {
10805
10992
  this._refLabelResolver.invalidate();
10806
10993
  this.refLabels = {};
10994
+ this.refLooks = {};
10807
10995
  this.loadRefLabels();
10996
+ this.loadRefLooks();
10808
10997
  }
10809
10998
  },
10810
10999