@conduction/nextcloud-vue 2.111.0 → 2.113.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/dist/esm/components/CnActionButtons/CnActionButtons.vue.js +1 -1
- package/dist/esm/components/CnActionButtons/CnActionButtons.vue2.js +4 -6
- package/dist/esm/components/CnActionButtons/CnActionButtons.vue2.js.map +1 -1
- package/dist/esm/components/CnActionButtons/CnActionButtons.vue3.js.map +1 -1
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue.js +1 -1
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue2.js +3 -2
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue3.js +4 -2
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue3.js.map +1 -1
- package/dist/esm/components/CnAssignDialog/CnAssignDialog.vue.js +1 -1
- package/dist/esm/components/CnAssignDialog/CnAssignDialog.vue2.js +3 -2
- package/dist/esm/components/CnAssignDialog/CnAssignDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnAssignDialog/CnAssignDialog.vue3.js +2 -1
- package/dist/esm/components/CnAssignDialog/CnAssignDialog.vue3.js.map +1 -1
- package/dist/esm/components/CnBoardView/CnBoardView.vue.js +1 -1
- package/dist/esm/components/CnBoardView/CnBoardView.vue2.js +54 -5
- package/dist/esm/components/CnBoardView/CnBoardView.vue2.js.map +1 -1
- package/dist/esm/components/CnBoardView/CnBoardView.vue3.js +16 -2
- package/dist/esm/components/CnBoardView/CnBoardView.vue3.js.map +1 -1
- package/dist/esm/components/CnCardGrid/CnCardGrid.vue.js +1 -1
- package/dist/esm/components/CnCardGrid/CnCardGrid.vue2.js +10 -0
- package/dist/esm/components/CnCardGrid/CnCardGrid.vue2.js.map +1 -1
- package/dist/esm/components/CnCardGrid/CnCardGrid.vue3.js +2 -1
- package/dist/esm/components/CnCardGrid/CnCardGrid.vue3.js.map +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue.js +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js +22 -2
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js.map +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js +17 -3
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js.map +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue.js +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue.js +1 -1
- package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue2.js.map +1 -1
- package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue3.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue.js +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +18 -3
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +2 -2
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +52 -13
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +31 -3
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue.js +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js +48 -11
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js +160 -97
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js.map +1 -1
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue.js +1 -1
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue3.js +2 -2
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +222 -15
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +24 -7
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnNcDashboardList/CnNcDashboardList.vue.js +1 -1
- package/dist/esm/components/CnNcDashboardList/CnNcDashboardList.vue2.js +21 -1
- package/dist/esm/components/CnNcDashboardList/CnNcDashboardList.vue2.js.map +1 -1
- package/dist/esm/components/CnNcDashboardList/CnNcDashboardList.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue.js +1 -1
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js +36 -2
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js +44 -5
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js.map +1 -1
- package/dist/esm/components/CnPartyPicker/CnPartyPicker.vue.js +1 -0
- package/dist/esm/components/CnPartyPicker/CnPartyPicker.vue.js.map +1 -1
- package/dist/esm/components/CnPartyPicker/CnPartyPicker.vue2.js +22 -2
- package/dist/esm/components/CnPartyPicker/CnPartyPicker.vue2.js.map +1 -1
- package/dist/esm/components/CnPartyPicker/CnPartyPicker.vue3.js +36 -16
- package/dist/esm/components/CnPartyPicker/CnPartyPicker.vue3.js.map +1 -1
- package/dist/esm/components/CnReportsPage/CnReportsPage.vue.js +1 -1
- package/dist/esm/components/CnReportsPage/CnReportsPage.vue2.js +29 -12
- package/dist/esm/components/CnReportsPage/CnReportsPage.vue2.js.map +1 -1
- package/dist/esm/components/CnReportsPage/CnReportsPage.vue3.js +3 -1
- package/dist/esm/components/CnReportsPage/CnReportsPage.vue3.js.map +1 -1
- package/dist/esm/components/CnSearchSelect/CnSearchSelect.vue.js +1 -1
- package/dist/esm/components/CnSearchSelect/CnSearchSelect.vue2.js.map +1 -1
- package/dist/esm/components/CnSearchSelect/CnSearchSelect.vue3.js.map +1 -1
- package/dist/esm/composables/useRefLabels.js +26 -6
- package/dist/esm/composables/useRefLabels.js.map +1 -1
- package/dist/esm/integrations/registry.js +4 -0
- package/dist/esm/integrations/registry.js.map +1 -1
- package/dist/esm/l10n/en.json.js +3 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +3 -1
- package/dist/esm/l10n/nl.json.js.map +1 -1
- package/dist/esm/library-style.js +1 -1
- package/dist/esm/nextcloud-vue.css +680 -449
- package/dist/esm/store/plugins/liveUpdates.js +3 -1
- package/dist/esm/store/plugins/liveUpdates.js.map +1 -1
- package/dist/esm/store/plugins/logs.js +2 -1
- package/dist/esm/store/plugins/logs.js.map +1 -1
- package/dist/esm/utils/actionLink.js +104 -1
- package/dist/esm/utils/actionLink.js.map +1 -1
- package/dist/esm/utils/detailActionModel.js +28 -1
- package/dist/esm/utils/detailActionModel.js.map +1 -1
- package/dist/esm/utils/fillTemplate.js +13 -5
- package/dist/esm/utils/fillTemplate.js.map +1 -1
- package/dist/esm/utils/headerFieldChips.js +21 -2
- package/dist/esm/utils/headerFieldChips.js.map +1 -1
- package/dist/esm/utils/mapList.js +26 -11
- package/dist/esm/utils/mapList.js.map +1 -1
- package/dist/esm/utils/savedViewMenu.js +12 -5
- package/dist/esm/utils/savedViewMenu.js.map +1 -1
- package/dist/esm/utils/validateManifestV2.compiled.js +3 -3
- package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +2800 -1933
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +680 -449
- package/l10n/en.json +3 -1
- package/l10n/nl.json +3 -1
- package/package.json +1 -1
- package/src/components/CnActionButtons/CnActionButtons.vue +4 -6
- package/src/components/CnActionDialog/CnActionDialog.vue +32 -9
- package/src/components/CnAssignDialog/CnAssignDialog.vue +4 -2
- package/src/components/CnBoardView/CnBoardView.vue +58 -5
- package/src/components/CnCardGrid/CnCardGrid.md +1 -0
- package/src/components/CnCardGrid/CnCardGrid.vue +11 -0
- package/src/components/CnCellRenderer/CnCellRenderer.vue +27 -3
- package/src/components/CnChartWidget/CnChartWidget.vue +6 -0
- package/src/components/CnChoiceCards/CnChoiceCards.vue +0 -3
- package/src/components/CnDashboardPage/CnDashboardPage.vue +20 -5
- package/src/components/CnDetailPage/CnDetailPage.vue +62 -14
- package/src/components/CnDetailWidgetHost/CnDetailWidgetHost.vue +100 -5
- package/src/components/CnFormDialog/CnFormDialog.vue +1 -1
- package/src/components/CnIndexPage/CnIndexPage.vue +233 -18
- package/src/components/CnNcDashboardList/CnNcDashboardList.vue +21 -1
- package/src/components/CnObjectCard/CnObjectCard.md +1 -0
- package/src/components/CnObjectCard/CnObjectCard.vue +51 -5
- package/src/components/CnPartyPicker/CnPartyPicker.vue +62 -16
- package/src/components/CnReportsPage/CnReportsPage.vue +31 -12
- package/src/components/CnSearchSelect/CnSearchSelect.vue +8 -0
- package/src/composables/useRefLabels.js +25 -5
- package/src/css/badge.css +15 -13
- package/src/css/board.css +0 -1
- package/src/css/dialog.css +53 -3
- package/src/css/index-page.css +26 -1
- package/src/css/look-board-detail.css +36 -15
- package/src/css/look-board-index.css +67 -15
- package/src/css/look-board.css +32 -18
- package/src/integrations/registry.js +4 -0
- package/src/schemas/app-manifest-v2.schema.json +61 -13
- package/src/store/plugins/liveUpdates.js +3 -1
- package/src/store/plugins/logs.js +2 -1
- package/src/utils/actionLink.js +103 -0
- package/src/utils/detailActionModel.js +27 -0
- package/src/utils/fillTemplate.js +13 -5
- package/src/utils/headerFieldChips.js +21 -2
- package/src/utils/mapList.js +26 -11
- package/src/utils/savedViewMenu.js +12 -5
- package/src/utils/validateManifestV2.compiled.js +3 -3
|
@@ -27,8 +27,8 @@ import { createRefLabelResolver } from '../../composables/useRefLabels.js';
|
|
|
27
27
|
import { useSavedViewsApi } from '../../composables/useSavedViewsApi.js';
|
|
28
28
|
import { METADATA_COLUMNS } from '../../constants/metadata.js';
|
|
29
29
|
import { useObjectStore } from '../../store/useObjectStore.js';
|
|
30
|
-
import { routeHref, followItemActionLink, resolveItemActionLink } from '../../utils/actionLink.js';
|
|
31
|
-
import { resolveRegisteredHandler, buildOnSuccessRoute } from '../../utils/actionsDispatcher.js';
|
|
30
|
+
import { routeHref, headerActionAsLink, followItemActionLink, resolveItemActionLink } from '../../utils/actionLink.js';
|
|
31
|
+
import { resolveRegisteredHandler, isExternalActionTarget, buildOnSuccessRoute } from '../../utils/actionsDispatcher.js';
|
|
32
32
|
import { columnFieldsOf, refIdOf, buildValueStages, buildReferenceStages, columnKeyOfRow, resolveDropValue, fullTargetOf, referenceTargetOf, fetchReferenceObjects } from '../../utils/boardReferenceColumns.js';
|
|
33
33
|
import { isColumnSortable } from '../../utils/columnFilters.js';
|
|
34
34
|
import { reportBindingProblems } from '../../utils/diagnostics.js';
|
|
@@ -443,6 +443,8 @@ var script = {
|
|
|
443
443
|
|
|
444
444
|
inject: {
|
|
445
445
|
cnCustomComponents: { default: () => ({}) },
|
|
446
|
+
/** The app's named formatters, provided by CnAppRoot, for the map list's pills and template tokens. */
|
|
447
|
+
cnFormatters: { default: () => ({}) },
|
|
446
448
|
/** The permissions the user holds, provided by CnAppRoot; for gated page tabs. */
|
|
447
449
|
cnPermissions: { default: () => [] },
|
|
448
450
|
/** The app config an ancestor provides, for `@config.<key>` in quick-filter labels. */
|
|
@@ -2587,11 +2589,16 @@ var script = {
|
|
|
2587
2589
|
* (unless the handler is the `'none'` keyword) emits
|
|
2588
2590
|
* `@header-action({ action: id, id })`.
|
|
2589
2591
|
*
|
|
2592
|
+
* An entry with `href` instead renders as a real link and is never
|
|
2593
|
+
* dispatched or emitted: an absolute `http(s)`, `mailto:`, `tel:` or
|
|
2594
|
+
* `//host/...` URL is used as written, an instance path (leading `/`) goes through
|
|
2595
|
+
* `generateUrl()`. `target: '_blank'` opens it in a new tab.
|
|
2596
|
+
*
|
|
2590
2597
|
* Reserved ids (those used by built-ins on the bar — `refresh`,
|
|
2591
2598
|
* `import`, `export`, `copy`, `delete`) are dropped from the
|
|
2592
2599
|
* merged list with a `console.warn`.
|
|
2593
2600
|
*
|
|
2594
|
-
* @type {Array<{ id: string, label: string, icon?: string, handler?: string|(() => void), route?: string, disabled?: boolean }>}
|
|
2601
|
+
* @type {Array<{ id: string, label: string, icon?: string, handler?: string|(() => void), route?: string, href?: string, target?: ('_blank'|'_self'), disabled?: boolean }>}
|
|
2595
2602
|
*/
|
|
2596
2603
|
headerActions: {
|
|
2597
2604
|
type: Array,
|
|
@@ -2801,6 +2808,8 @@ var script = {
|
|
|
2801
2808
|
boardPrevPageSize: this.viewMode === 'board' ? ((this.pagination && this.pagination.limit) || 20) : null,
|
|
2802
2809
|
/** Resolved labels of reference columns: `{ [columnKey]: { [id]: label|null } }`. */
|
|
2803
2810
|
refLabels: {},
|
|
2811
|
+
/** Colour and icon names of the records badge columns point at: `{ [columnKey]: { [id]: { color, icon } } }`. */
|
|
2812
|
+
refLooks: {},
|
|
2804
2813
|
/** Count per tab-strip index, for the entries that asked for one; null = none. */
|
|
2805
2814
|
tabCounts: null,
|
|
2806
2815
|
// The counts of the `filterStrip` pills, by pill key ('all', 'v0', ...).
|
|
@@ -3042,7 +3051,7 @@ var script = {
|
|
|
3042
3051
|
/**
|
|
3043
3052
|
* The header actions that open a dialog: `type: "open-form"` (the
|
|
3044
3053
|
* schema-driven create form, as the navigation's primary action opens
|
|
3045
|
-
* it) or `type: "open-modal"`, without a `handler` of their own.
|
|
3054
|
+
* it) or `type: "open-modal"`, without a `handler` or `href` of their own.
|
|
3046
3055
|
* Reserved ids are left out, as in `mergedHeaderActions`.
|
|
3047
3056
|
*
|
|
3048
3057
|
* @spec openspec/changes/index-header-open-form/specs/index-header/spec.md#requirement-an-index-header-action-can-open-the-create-form
|
|
@@ -3054,9 +3063,18 @@ var script = {
|
|
|
3054
3063
|
&& typeof entry.id === 'string'
|
|
3055
3064
|
&& !reserved.has(entry.id)
|
|
3056
3065
|
&& (entry.handler === undefined || entry.handler === null || entry.handler === '')
|
|
3066
|
+
&& !entry.href
|
|
3057
3067
|
&& (entry.type === 'open-form' || entry.type === 'open-modal'))
|
|
3058
3068
|
},
|
|
3059
3069
|
|
|
3070
|
+
/**
|
|
3071
|
+
* The header actions without reserved ids, each through
|
|
3072
|
+
* `resolveHeaderHandler` (a manifest `href` entry becomes a link with
|
|
3073
|
+
* `_dispatchSuppress`, so the page neither runs nor emits it).
|
|
3074
|
+
*
|
|
3075
|
+
* @spec openspec/changes/header-action-href/specs/header-action-href/spec.md#requirement-a-header-action-with-href-is-a-link-that-runs-and-emits-nothing
|
|
3076
|
+
* @return {Array<object>}
|
|
3077
|
+
*/
|
|
3060
3078
|
mergedHeaderActions() {
|
|
3061
3079
|
const reserved = new Set(['refresh', 'import', 'export', 'copy', 'delete']);
|
|
3062
3080
|
const merged = [];
|
|
@@ -4715,6 +4733,12 @@ var script = {
|
|
|
4715
4733
|
*/
|
|
4716
4734
|
renderedColumns() {
|
|
4717
4735
|
let cols = this.tableColumns;
|
|
4736
|
+
if (this.refLookSpecs.length > 0) {
|
|
4737
|
+
const lookKeys = new Set(this.refLookSpecs.map((spec) => spec.key));
|
|
4738
|
+
cols = cols.map((col) => (col && typeof col === 'object' && lookKeys.has(col.key)
|
|
4739
|
+
? { ...col, widgetProps: { ...(col.widgetProps || {}), looks: this.refLooks[col.key] || {} } }
|
|
4740
|
+
: col));
|
|
4741
|
+
}
|
|
4718
4742
|
if (this.refLabelSpecs.length > 0) {
|
|
4719
4743
|
const byKey = new Map(this.refLabelSpecs.map((s) => [s.key, s]));
|
|
4720
4744
|
cols = cols.map((col) => {
|
|
@@ -4785,6 +4809,108 @@ var script = {
|
|
|
4785
4809
|
*
|
|
4786
4810
|
* @return {Object<string, string[]>} Distinct ids per column key.
|
|
4787
4811
|
*/
|
|
4812
|
+
/**
|
|
4813
|
+
* The pills that take their tone and icon from the record they point at
|
|
4814
|
+
* (`resolve: { colorField?, iconField?, register?, schema? }`): badge
|
|
4815
|
+
* columns and the list view's leading and trailing cells
|
|
4816
|
+
* (`widgetProps.resolve`), the board card's pill (`board.card.resolve`)
|
|
4817
|
+
* and the record card's pills (`cardLayout` headPill, footerPill, chips).
|
|
4818
|
+
* Register and schema default to the field's reference in the schema.
|
|
4819
|
+
*
|
|
4820
|
+
* @return {Array<{key: string, register: string, schema: string, colorField: string, iconField: string}>} The specs.
|
|
4821
|
+
* @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
|
|
4822
|
+
*/
|
|
4823
|
+
refLookSpecs() {
|
|
4824
|
+
const list = this.listConfig || {};
|
|
4825
|
+
const listCells = [list.leading, ...(Array.isArray(list.trailing) ? list.trailing : [list.trailing])];
|
|
4826
|
+
const badgeSources = [...this.tableColumns, ...listCells]
|
|
4827
|
+
.filter((c) => c && typeof c === 'object' && c.widget === 'badge' && c.widgetProps)
|
|
4828
|
+
.map((c) => ({ key: c.key, resolve: c.widgetProps.resolve }));
|
|
4829
|
+
// The board card's pill (`board.card.pill` with `board.card.resolve`)
|
|
4830
|
+
// and the record card's pills (`cardLayout` headPill, footerPill,
|
|
4831
|
+
// chips, each with its own `resolve`).
|
|
4832
|
+
const card = this.board && this.board.card && typeof this.board.card === 'object' ? this.board.card : {};
|
|
4833
|
+
const layout = this.cardLayout && typeof this.cardLayout === 'object' ? this.cardLayout : {};
|
|
4834
|
+
const layoutPills = [layout.headPill, layout.footerPill, ...(Array.isArray(layout.chips) ? layout.chips : [])]
|
|
4835
|
+
.filter((def) => def && typeof def === 'object')
|
|
4836
|
+
.map((def) => ({ key: def.field, resolve: def.resolve }));
|
|
4837
|
+
// The map list's pills (`mapConfig.list.pills`, each with its own `resolve`).
|
|
4838
|
+
const mapListPills = (this.mapListEnabled && Array.isArray(this.mapConfig.list.pills) ? this.mapConfig.list.pills : [])
|
|
4839
|
+
.filter((def) => def && typeof def === 'object')
|
|
4840
|
+
.map((def) => ({ key: def.path, resolve: def.resolve }));
|
|
4841
|
+
const seen = new Set();
|
|
4842
|
+
const cols = [...badgeSources, { key: card.pill, resolve: card.resolve }, ...layoutPills, ...mapListPills].filter((c) => {
|
|
4843
|
+
const wanted = typeof c.key === 'string' && c.key !== '' && c.resolve && typeof c.resolve === 'object'
|
|
4844
|
+
&& (c.resolve.colorField || c.resolve.iconField) && !seen.has(c.key);
|
|
4845
|
+
if (wanted) {
|
|
4846
|
+
seen.add(c.key);
|
|
4847
|
+
}
|
|
4848
|
+
return wanted
|
|
4849
|
+
});
|
|
4850
|
+
if (cols.length === 0) {
|
|
4851
|
+
return []
|
|
4852
|
+
}
|
|
4853
|
+
const fields = this.effectiveSchema ? fieldsFromSchema(this.effectiveSchema, { includeReadOnly: true }) : [];
|
|
4854
|
+
const specs = [];
|
|
4855
|
+
for (const col of cols) {
|
|
4856
|
+
const resolve = col.resolve;
|
|
4857
|
+
const field = fields.find((f) => f.key === col.key);
|
|
4858
|
+
const ref = (field && field.reference) || {};
|
|
4859
|
+
const register = resolve.register || ref.register || (typeof this.register === 'string' ? this.register : '');
|
|
4860
|
+
const schema = resolve.schema || (ref.schema !== undefined && ref.schema !== null ? String(ref.schema) : '');
|
|
4861
|
+
if (!register || !schema) {
|
|
4862
|
+
continue
|
|
4863
|
+
}
|
|
4864
|
+
specs.push({ key: col.key, register, schema, colorField: resolve.colorField || '', iconField: resolve.iconField || '' });
|
|
4865
|
+
}
|
|
4866
|
+
return specs
|
|
4867
|
+
},
|
|
4868
|
+
|
|
4869
|
+
/**
|
|
4870
|
+
* `listConfig` with the referenced records' looks on its badge cells,
|
|
4871
|
+
* as `renderedColumns` does for the table.
|
|
4872
|
+
*
|
|
4873
|
+
* @return {object} The list view's config.
|
|
4874
|
+
* @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
|
|
4875
|
+
*/
|
|
4876
|
+
renderedListConfig() {
|
|
4877
|
+
const list = this.listConfig;
|
|
4878
|
+
if (!list || this.refLookSpecs.length === 0) {
|
|
4879
|
+
return list
|
|
4880
|
+
}
|
|
4881
|
+
const lookKeys = new Set(this.refLookSpecs.map((spec) => spec.key));
|
|
4882
|
+
const withLooks = (cell) => (cell && typeof cell === 'object' && lookKeys.has(cell.key)
|
|
4883
|
+
? { ...cell, widgetProps: { ...(cell.widgetProps || {}), looks: this.refLooks[cell.key] || {} } }
|
|
4884
|
+
: cell);
|
|
4885
|
+
return {
|
|
4886
|
+
...list,
|
|
4887
|
+
...(list.leading ? { leading: withLooks(list.leading) } : {}),
|
|
4888
|
+
...(list.trailing ? { trailing: Array.isArray(list.trailing) ? list.trailing.map(withLooks) : withLooks(list.trailing) } : {}),
|
|
4889
|
+
}
|
|
4890
|
+
},
|
|
4891
|
+
|
|
4892
|
+
/**
|
|
4893
|
+
* The ids each `refLookSpecs` column shows on screen.
|
|
4894
|
+
*
|
|
4895
|
+
* @return {{[key: string]: Array<string>}} Sorted ids by column key.
|
|
4896
|
+
*/
|
|
4897
|
+
refLookIds() {
|
|
4898
|
+
const out = {};
|
|
4899
|
+
for (const spec of this.refLookSpecs) {
|
|
4900
|
+
const ids = new Set();
|
|
4901
|
+
for (const row of this.displayObjects) {
|
|
4902
|
+
const v = row ? row[spec.key] : undefined
|
|
4903
|
+
;(Array.isArray(v) ? v : [v]).forEach((id) => {
|
|
4904
|
+
if (id !== null && id !== undefined && id !== '' && typeof id !== 'object') {
|
|
4905
|
+
ids.add(String(id));
|
|
4906
|
+
}
|
|
4907
|
+
});
|
|
4908
|
+
}
|
|
4909
|
+
out[spec.key] = [...ids].sort();
|
|
4910
|
+
}
|
|
4911
|
+
return out
|
|
4912
|
+
},
|
|
4913
|
+
|
|
4788
4914
|
refLabelIds() {
|
|
4789
4915
|
const out = {};
|
|
4790
4916
|
const facets = this.storeFacets || this.resolvedSidebar.facets || {};
|
|
@@ -5052,13 +5178,15 @@ var script = {
|
|
|
5052
5178
|
const translated = {
|
|
5053
5179
|
...list,
|
|
5054
5180
|
title: this.cnTranslate(list.title),
|
|
5055
|
-
sub: list.sub ? this.cnTranslate(list.sub) : '',
|
|
5181
|
+
sub: Array.isArray(list.sub) ? list.sub.map((s) => this.cnTranslate(s)) : (list.sub ? this.cnTranslate(list.sub) : ''),
|
|
5056
5182
|
due: list.due ? this.cnTranslate(list.due) : '',
|
|
5057
5183
|
};
|
|
5058
5184
|
return mapListItems(this.displayObjects, translated, {
|
|
5059
5185
|
rowKey: this.rowKey,
|
|
5060
5186
|
located: (row) => Boolean(this.resolveRowGeometry(row)),
|
|
5061
5187
|
translate: (text) => this.cnTranslate(text),
|
|
5188
|
+
formatters: this.cnFormatters,
|
|
5189
|
+
looks: this.refLooks,
|
|
5062
5190
|
})
|
|
5063
5191
|
},
|
|
5064
5192
|
|
|
@@ -5985,11 +6113,13 @@ var script = {
|
|
|
5985
6113
|
*
|
|
5986
6114
|
* @spec openspec/changes/zuiddrecht-pixel-gaps-3/specs/zuiddrecht-pixel-gaps-3/spec.md#requirement-an-index-page-can-take-the-board-header
|
|
5987
6115
|
* @spec openspec/changes/screens-index-header-buttons-parity/specs/index-list-board-look/spec.md#requirement-the-add-header-button-carries-a-plus
|
|
5988
|
-
* @
|
|
6116
|
+
* @spec openspec/changes/header-action-href/specs/header-action-href/spec.md#requirement-a-header-action-with-href-is-a-link-that-runs-and-emits-nothing
|
|
6117
|
+
* @return {Array<{key: string, label: string, action: string, variant: string, icon: string, format: string, link: ({href: string, target: (string|undefined)}|null)}>}
|
|
5989
6118
|
*/
|
|
5990
6119
|
resolvedHeaderButtons() {
|
|
5991
6120
|
const headerButtons = this.presented('headerButtons');
|
|
5992
6121
|
const declared = Array.isArray(headerButtons) ? headerButtons : [];
|
|
6122
|
+
const builtInActions = new Set(['add', 'export', 'import', 'refresh', 'save-view', 'actions-menu']);
|
|
5993
6123
|
return declared
|
|
5994
6124
|
.filter((button) => button && typeof button === 'object' && typeof button.action === 'string' && button.action !== '')
|
|
5995
6125
|
.map((button, index) => {
|
|
@@ -6016,6 +6146,13 @@ var script = {
|
|
|
6016
6146
|
if (label === '' && button.action === 'save-view') {
|
|
6017
6147
|
label = translate('nextcloud-vue', 'Save view');
|
|
6018
6148
|
}
|
|
6149
|
+
const run = typeof button.run === 'string' ? button.run : '';
|
|
6150
|
+
// A button that runs a manifest `href` header action is that link;
|
|
6151
|
+
// a `type: "navigate"` or function-handler entry keeps dispatching.
|
|
6152
|
+
const actionId = button.action === 'export' ? run : (builtInActions.has(button.action) ? '' : button.action);
|
|
6153
|
+
const linked = actionId
|
|
6154
|
+
? this.mergedHeaderActions.find((entry) => entry && entry.id === actionId && entry.href && entry._dispatchSuppress && (!entry.type || entry.type === 'handler'))
|
|
6155
|
+
: null;
|
|
6019
6156
|
return {
|
|
6020
6157
|
key: String(button.id || button.action || index),
|
|
6021
6158
|
label,
|
|
@@ -6023,7 +6160,8 @@ var script = {
|
|
|
6023
6160
|
variant: button.variant === 'primary' ? 'primary' : 'secondary',
|
|
6024
6161
|
icon,
|
|
6025
6162
|
format: button.format === 'excel' ? 'excel' : 'csv',
|
|
6026
|
-
run
|
|
6163
|
+
run,
|
|
6164
|
+
link: linked ? { href: linked.href, target: linked.linkTarget || undefined } : null,
|
|
6027
6165
|
items: Array.isArray(button.items)
|
|
6028
6166
|
? button.items.filter((item) => (typeof item === 'string' && item !== '')
|
|
6029
6167
|
|| (item && typeof item === 'object' && typeof item.heading === 'string' && item.heading !== ''))
|
|
@@ -6682,6 +6820,15 @@ var script = {
|
|
|
6682
6820
|
},
|
|
6683
6821
|
},
|
|
6684
6822
|
|
|
6823
|
+
// Read the colour and icon of the records badge columns point at.
|
|
6824
|
+
refLookIds: {
|
|
6825
|
+
immediate: true,
|
|
6826
|
+
deep: true,
|
|
6827
|
+
handler() {
|
|
6828
|
+
this.loadRefLooks();
|
|
6829
|
+
},
|
|
6830
|
+
},
|
|
6831
|
+
|
|
6685
6832
|
// The Active line names a referenced value, not its id.
|
|
6686
6833
|
activeFilterRefIds: {
|
|
6687
6834
|
deep: true,
|
|
@@ -7133,6 +7280,45 @@ var script = {
|
|
|
7133
7280
|
}));
|
|
7134
7281
|
},
|
|
7135
7282
|
|
|
7283
|
+
/**
|
|
7284
|
+
* Read the colour and icon names `refLookSpecs` columns need, for the
|
|
7285
|
+
* rows on screen, with the same resolver as the labels. A failure
|
|
7286
|
+
* leaves the badge as declared.
|
|
7287
|
+
*
|
|
7288
|
+
* @return {Promise<void>}
|
|
7289
|
+
* @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
|
|
7290
|
+
*/
|
|
7291
|
+
async loadRefLooks() {
|
|
7292
|
+
if (this.refLookSpecs.length === 0) {
|
|
7293
|
+
return
|
|
7294
|
+
}
|
|
7295
|
+
if (!this._refLabelResolver) {
|
|
7296
|
+
this._refLabelResolver = createRefLabelResolver(() => {
|
|
7297
|
+
try {
|
|
7298
|
+
return (this.list && this.list.objectStore) || useObjectStore()
|
|
7299
|
+
} catch {
|
|
7300
|
+
return null
|
|
7301
|
+
}
|
|
7302
|
+
});
|
|
7303
|
+
}
|
|
7304
|
+
const read = (spec, ids, name) => (name
|
|
7305
|
+
? this._refLabelResolver.resolve(spec.register, spec.schema, ids, name, { strict: true }).catch(() => ({}))
|
|
7306
|
+
: Promise.resolve({}));
|
|
7307
|
+
await Promise.all(this.refLookSpecs.map(async (spec) => {
|
|
7308
|
+
const known = this.refLooks[spec.key] || {};
|
|
7309
|
+
const ids = (this.refLookIds[spec.key] || []).filter((id) => !Object.hasOwn(known, id));
|
|
7310
|
+
if (ids.length === 0) {
|
|
7311
|
+
return
|
|
7312
|
+
}
|
|
7313
|
+
const [colors, icons] = await Promise.all([read(spec, ids, spec.colorField), read(spec, ids, spec.iconField)]);
|
|
7314
|
+
const found = {};
|
|
7315
|
+
ids.forEach((id) => {
|
|
7316
|
+
found[id] = { color: (colors && colors[id]) || null, icon: (icons && icons[id]) || null };
|
|
7317
|
+
});
|
|
7318
|
+
this.refLooks = { ...this.refLooks, [spec.key]: { ...(this.refLooks[spec.key] || {}), ...found } };
|
|
7319
|
+
}));
|
|
7320
|
+
},
|
|
7321
|
+
|
|
7136
7322
|
/**
|
|
7137
7323
|
* Whether a saved view shows its record count (`viewCounts`).
|
|
7138
7324
|
*
|
|
@@ -7633,8 +7819,11 @@ var script = {
|
|
|
7633
7819
|
* manifest-actions-dispatch — `navigate`, `emit`, `none`, or a
|
|
7634
7820
|
* registry name (resolved through `resolveRegisteredHandler`).
|
|
7635
7821
|
*
|
|
7822
|
+
* @spec openspec/changes/header-action-href/specs/header-action-href/spec.md#requirement-a-header-action-with-href-is-a-link-that-runs-and-emits-nothing
|
|
7636
7823
|
* @param {object} entry Raw headerActions entry.
|
|
7637
|
-
* @return {object} Possibly-mutated copy:
|
|
7824
|
+
* @return {object} Possibly-mutated copy: an `href` becomes a
|
|
7825
|
+
* resolved link with `linkTarget`, no handler (a function one
|
|
7826
|
+
* included) and `_dispatchSuppress: true`; function-typed
|
|
7638
7827
|
* handlers untouched; `'emit'` and unknown registry names
|
|
7639
7828
|
* strip the `handler` (emit-only fall-through); `'navigate'`
|
|
7640
7829
|
* becomes a `$router.push` thunk (with the entry's literal
|
|
@@ -7646,14 +7835,23 @@ var script = {
|
|
|
7646
7835
|
if (!entry) {
|
|
7647
7836
|
return entry
|
|
7648
7837
|
}
|
|
7838
|
+
// An `href` makes the entry a link, which only navigates: it
|
|
7839
|
+
// carries no handler, and the page emits nothing for it.
|
|
7840
|
+
if (typeof entry.href === 'string' && entry.href !== '') {
|
|
7841
|
+
const link = headerActionAsLink(entry);
|
|
7842
|
+
return link.href ? { ...link, linkTarget: link.target, _dispatchSuppress: true } : link
|
|
7843
|
+
}
|
|
7649
7844
|
const handler = entry.handler;
|
|
7650
7845
|
if (typeof handler === 'function') {
|
|
7651
7846
|
return { ...entry }
|
|
7652
7847
|
}
|
|
7653
7848
|
// `type: "navigate"` with a `target` URL is a link: the bar and the
|
|
7654
|
-
// header's Actions menu render it as a real anchor
|
|
7849
|
+
// header's Actions menu render it as a real anchor, an external URL
|
|
7850
|
+
// in a new tab.
|
|
7655
7851
|
if (typeof handler !== 'string' && entry.type === 'navigate' && typeof entry.target === 'string' && entry.target !== '' && !entry.href) {
|
|
7656
|
-
return
|
|
7852
|
+
return isExternalActionTarget(entry.target)
|
|
7853
|
+
? { ...entry, href: entry.target, linkTarget: '_blank' }
|
|
7854
|
+
: { ...entry, href: entry.target }
|
|
7657
7855
|
}
|
|
7658
7856
|
if (typeof handler !== 'string') {
|
|
7659
7857
|
// No handler declared — emit-only fall-through.
|
|
@@ -7824,8 +8022,9 @@ var script = {
|
|
|
7824
8022
|
*
|
|
7825
8023
|
* @spec openspec/changes/screens-index-header-actions-menu/specs/index-header/spec.md#requirement-the-header-actions-menu-lists-what-its-items-name
|
|
7826
8024
|
* @spec openspec/changes/screens-index-header-menu-headings/specs/index-header/spec.md#requirement-the-header-actions-menu-can-draw-group-headings-and-separators
|
|
8025
|
+
* @spec openspec/changes/header-action-href/specs/header-action-href/spec.md#requirement-a-header-action-with-href-is-a-link-that-runs-and-emits-nothing
|
|
7827
8026
|
* @param {{items?: Array<(string|{heading: string})>|null, format?: string}} button The resolved header button.
|
|
7828
|
-
* @return {Array<{key: string, label: string, kind?: ('heading'|'separator'), icon?: string, href?: string, disabled?: boolean, title?: string, iconComponent?: object, run?:
|
|
8027
|
+
* @return {Array<{key: string, label: string, kind?: ('heading'|'separator'), icon?: string, href?: string, linkTarget?: string, disabled?: boolean, title?: string, iconComponent?: object, run?: () => void}>}
|
|
7829
8028
|
*/
|
|
7830
8029
|
headerMenuEntries(button) {
|
|
7831
8030
|
const fromAction = (entry) => ({
|
|
@@ -7833,6 +8032,7 @@ var script = {
|
|
|
7833
8032
|
label: entry.label ? this.cnTranslate(entry.label) : '',
|
|
7834
8033
|
icon: entry.icon && typeof entry.icon === 'string' && !entry.icon.startsWith('icon-') ? entry.icon : '',
|
|
7835
8034
|
href: typeof entry.href === 'string' && entry.href !== '' ? entry.href : '',
|
|
8035
|
+
linkTarget: entry.linkTarget || '',
|
|
7836
8036
|
// A `handler: "navigate"` entry whose route resolves carries `to`
|
|
7837
8037
|
// (resolveHeaderHandler drops its handler): the menu draws it as
|
|
7838
8038
|
// an in-app link, as the actions bar does, so it navigates.
|
|
@@ -7866,7 +8066,7 @@ var script = {
|
|
|
7866
8066
|
}),
|
|
7867
8067
|
|
|
7868
8068
|
documentation: () => (this.documentationUrl
|
|
7869
|
-
? { key: 'documentation', label: this.documentationLabel || translate('nextcloud-vue', 'Documentation'), icon: 'BookOpenVariantOutline', href: this.documentationUrl }
|
|
8069
|
+
? { key: 'documentation', label: this.documentationLabel || translate('nextcloud-vue', 'Documentation'), icon: 'BookOpenVariantOutline', href: this.documentationUrl, linkTarget: '_blank' }
|
|
7870
8070
|
: null),
|
|
7871
8071
|
};
|
|
7872
8072
|
const entries = [];
|
|
@@ -7962,13 +8162,18 @@ var script = {
|
|
|
7962
8162
|
|
|
7963
8163
|
/**
|
|
7964
8164
|
* A header button was clicked: run its built-in action, or dispatch
|
|
7965
|
-
* it as the `headerActions` entry with that id.
|
|
8165
|
+
* it as the `headerActions` entry with that id. A button that is a
|
|
8166
|
+
* link is left to the browser.
|
|
7966
8167
|
*
|
|
7967
8168
|
* @spec openspec/changes/zuiddrecht-pixel-gaps-3/specs/zuiddrecht-pixel-gaps-3/spec.md#requirement-an-index-page-can-take-the-board-header
|
|
7968
|
-
* @
|
|
8169
|
+
* @spec openspec/changes/header-action-href/specs/header-action-href/spec.md#requirement-a-header-action-with-href-is-a-link-that-runs-and-emits-nothing
|
|
8170
|
+
* @param {{action: string, format: string, link?: object}} button The resolved button.
|
|
7969
8171
|
* @return {void}
|
|
7970
8172
|
*/
|
|
7971
8173
|
onHeaderButton(button) {
|
|
8174
|
+
if (button.link) {
|
|
8175
|
+
return
|
|
8176
|
+
}
|
|
7972
8177
|
if (button.action === 'add') {
|
|
7973
8178
|
this.onAddClick();
|
|
7974
8179
|
} else if (button.action === 'export') {
|
|
@@ -10294,7 +10499,7 @@ var script = {
|
|
|
10294
10499
|
return
|
|
10295
10500
|
}
|
|
10296
10501
|
const badge = this.savedViewMenuBadge(view);
|
|
10297
|
-
menu.toggle({ id: String(view.id || view.slug), page: this.savedViewPage, name: view.name, ...(badge ? { badge } : {}) });
|
|
10502
|
+
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 } : {}) });
|
|
10298
10503
|
},
|
|
10299
10504
|
|
|
10300
10505
|
/**
|
|
@@ -10829,7 +11034,9 @@ var script = {
|
|
|
10829
11034
|
if (resultData && resultData.success && this._refLabelResolver) {
|
|
10830
11035
|
this._refLabelResolver.invalidate();
|
|
10831
11036
|
this.refLabels = {};
|
|
11037
|
+
this.refLooks = {};
|
|
10832
11038
|
this.loadRefLabels();
|
|
11039
|
+
this.loadRefLooks();
|
|
10833
11040
|
}
|
|
10834
11041
|
},
|
|
10835
11042
|
|