@conduction/nextcloud-vue 2.102.0 → 2.104.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/CnActionsBar/CnActionsBar.vue2.js +23 -0
- package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js.map +1 -1
- package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js +94 -72
- package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js.map +1 -1
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js +18 -1
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js.map +1 -1
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js +3 -3
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js.map +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue.js +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue2.js +73 -0
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue2.js.map +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue3.js +99 -64
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue3.js.map +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue.js +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue2.js +46 -0
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue3.js +37 -2
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue.js +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +29 -6
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +39 -2
- package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue3.js +14 -0
- package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +40 -2
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue.js +1 -1
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js +113 -20
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue3.js +387 -359
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +173 -3
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +107 -87
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/useSelfFetchList.js +7 -2
- package/dist/esm/components/CnIndexPage/useSelfFetchList.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue.js +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +10 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectRow/CnObjectRow.vue.js +1 -1
- package/dist/esm/components/CnObjectRow/CnObjectRow.vue2.js +57 -5
- package/dist/esm/components/CnObjectRow/CnObjectRow.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectRow/CnObjectRow.vue3.js +37 -4
- package/dist/esm/components/CnObjectRow/CnObjectRow.vue3.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +97 -3
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js +46 -2
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnSearchSelect/CnSearchSelect.vue.js +9 -0
- package/dist/esm/components/CnSearchSelect/CnSearchSelect.vue.js.map +1 -0
- package/dist/esm/components/CnSearchSelect/CnSearchSelect.vue2.js +165 -0
- package/dist/esm/components/CnSearchSelect/CnSearchSelect.vue2.js.map +1 -0
- package/dist/esm/components/CnSearchSelect/CnSearchSelect.vue3.js +85 -0
- package/dist/esm/components/CnSearchSelect/CnSearchSelect.vue3.js.map +1 -0
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue.js +1 -1
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js +54 -6
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js.map +1 -1
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js +3 -1
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue.js +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +8 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnUserSettingsDialog/CnUserSettingsDialog.vue.js +1 -1
- package/dist/esm/components/CnUserSettingsDialog/CnUserSettingsDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnUserSettingsDialog/CnUserSettingsDialog.vue3.js.map +1 -1
- package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue.js +1 -1
- package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue2.js +18 -2
- package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue2.js.map +1 -1
- package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue3.js.map +1 -1
- package/dist/esm/components/CnWizardDialog/CnWizardDialog.vue.js +1 -1
- package/dist/esm/components/CnWizardDialog/CnWizardDialog.vue2.js +19 -0
- package/dist/esm/components/CnWizardDialog/CnWizardDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnWizardDialog/CnWizardDialog.vue3.js +1 -1
- package/dist/esm/components/CnWizardDialog/CnWizardDialog.vue3.js.map +1 -1
- package/dist/esm/composables/indexSources.js +7 -7
- package/dist/esm/composables/indexSources.js.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/l10n/en.json.js +4 -0
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +4 -0
- package/dist/esm/l10n/nl.json.js.map +1 -1
- package/dist/esm/library-style.js +1 -1
- package/dist/esm/mixins/pageViews.js +8 -1
- package/dist/esm/mixins/pageViews.js.map +1 -1
- package/dist/esm/nextcloud-vue.css +586 -416
- package/dist/esm/utils/nextcloudDirectory.js +18 -1
- package/dist/esm/utils/nextcloudDirectory.js.map +1 -1
- package/dist/esm/utils/sortOrder.js +61 -0
- package/dist/esm/utils/sortOrder.js.map +1 -0
- package/dist/esm/utils/validateManifestV2.compiled.js +3 -3
- package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
- package/dist/esm/utils/visibleWhen.js +13 -2
- package/dist/esm/utils/visibleWhen.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +12270 -10936
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +586 -416
- package/l10n/en.json +4 -0
- package/l10n/nl.json +4 -0
- package/package.json +1 -1
- package/src/components/CnActionsBar/CnActionsBar.md +1 -0
- package/src/components/CnActionsBar/CnActionsBar.vue +39 -2
- package/src/components/CnAppRoot/CnAppRoot.md +1 -1
- package/src/components/CnAppRoot/CnAppRoot.vue +21 -4
- package/src/components/CnConversationThread/CnConversationThread.md +17 -0
- package/src/components/CnConversationThread/CnConversationThread.vue +113 -8
- package/src/components/CnConversationThread/CnConversationWidget.vue +60 -1
- package/src/components/CnDashboardPage/CnDashboardPage.md +4 -1
- package/src/components/CnDashboardPage/CnDashboardPage.vue +29 -6
- package/src/components/CnDataTable/CnDataTable.md +1 -0
- package/src/components/CnDataTable/CnDataTable.vue +49 -0
- package/src/components/CnDetailPage/CnDetailPage.md +2 -1
- package/src/components/CnDetailPage/CnDetailPage.vue +40 -2
- package/src/components/CnFormDialog/CnFormDialog.md +1 -1
- package/src/components/CnFormDialog/CnFormDialog.vue +127 -0
- package/src/components/CnIndexPage/CnIndexPage.md +14 -2
- package/src/components/CnIndexPage/CnIndexPage.vue +192 -11
- package/src/components/CnIndexPage/useSelfFetchList.js +6 -1
- package/src/components/CnObjectListWidget/CnObjectListWidget.vue +10 -1
- package/src/components/CnObjectRow/CnObjectRow.vue +95 -1
- package/src/components/CnRecordListWidget/CnRecordListWidget.vue +134 -2
- package/src/components/CnSearchSelect/CnSearchSelect.vue +283 -0
- package/src/components/CnSearchSelect/index.js +12 -0
- package/src/components/CnSetupWizard/CnSetupWizard.vue +56 -6
- package/src/components/CnTabsWidget/CnTabsWidget.vue +8 -1
- package/src/components/CnUserSettingsDialog/CnUserSettingsDialog.vue +7 -2
- package/src/components/CnWidgetObjectTable/CnWidgetObjectTable.vue +18 -2
- package/src/components/CnWizardDialog/CnWizardDialog.vue +20 -1
- package/src/components/index.js +1 -0
- package/src/composables/indexSources.js +7 -7
- package/src/css/dialog.css +5 -3
- package/src/css/index-page.css +19 -0
- package/src/css/look-board-index.css +48 -0
- package/src/index.js +1 -0
- package/src/mixins/pageViews.js +8 -1
- package/src/schemas/app-manifest-v2.schema.json +75 -6
- package/src/utils/nextcloudDirectory.js +17 -0
- package/src/utils/sortOrder.js +58 -0
- package/src/utils/validateManifestV2.compiled.js +3 -3
- package/src/utils/visibleWhen.js +13 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnObjectRow.vue2.js","sources":["../../../../src/components/CnObjectRow/CnObjectRow.vue"],"sourcesContent":["<template>\n\t<div\n\t\tclass=\"cn-object-row\"\n\t\t:class=\"{ 'cn-object-row--selected': selected }\"\n\t\t@mousedown=\"onRowMouseDown\"\n\t\t@click=\"onRowClick($event)\"\n\t\t@auxclick=\"onRowAuxClick($event)\">\n\t\t<!-- Selection checkbox -->\n\t\t<div v-if=\"selectable\"\n\t\t\tclass=\"cn-object-row__checkbox\"\n\t\t\t@click.stop\n\t\t\t@auxclick.stop>\n\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t:modelValue=\"selected\"\n\t\t\t\t@update:modelValue=\"$emit('select', object)\" />\n\t\t</div>\n\n\t\t<!-- Leading icon / image — omitted entirely when nothing is configured\n\t\t (no image, no icon name, no slot). -->\n\t\t<span v-if=\"hasLeadingIcon\" class=\"cn-object-row__icon\">\n\t\t\t<!-- @slot icon Replace the leading icon/image. -->\n\t\t\t<!-- @binding {object} object The row's object. -->\n\t\t\t<slot name=\"icon\" :object=\"object\">\n\t\t\t\t<img\n\t\t\t\t\tv-if=\"imageUrl\"\n\t\t\t\t\t:src=\"imageUrl\"\n\t\t\t\t\talt=\"\"\n\t\t\t\t\twidth=\"24\"\n\t\t\t\t\theight=\"24\"\n\t\t\t\t\tclass=\"cn-object-row__image\">\n\t\t\t\t<CnIcon v-else-if=\"iconName\" :name=\"iconName\" :size=\"24\" />\n\t\t\t</slot>\n\t\t</span>\n\n\t\t<!-- Main: title + subtitle -->\n\t\t<span class=\"cn-object-row__main\">\n\t\t\t<span class=\"cn-object-row__title\">{{ title }}</span>\n\t\t\t<span v-if=\"subtitle\" class=\"cn-object-row__subtitle\">{{ subtitle }}</span>\n\t\t</span>\n\n\t\t<!-- Badges (default: config-driven status badge) -->\n\t\t<span v-if=\"$slots.badges || badgeLabel\" class=\"cn-object-row__badges\">\n\t\t\t<!-- @slot badges Replace the badge area (overrides the config-driven badge). -->\n\t\t\t<!-- @binding {object} object The row's object. -->\n\t\t\t<slot name=\"badges\" :object=\"object\">\n\t\t\t\t<CnStatusBadge\n\t\t\t\t\tv-if=\"badgeLabel\"\n\t\t\t\t\t:label=\"badgeLabel\"\n\t\t\t\t\t:variant=\"badgeVariant\"\n\t\t\t\t\t:colorMap=\"badgeColorMap\"\n\t\t\t\t\tsize=\"small\" />\n\t\t\t</slot>\n\t\t</span>\n\n\t\t<!-- Trailing actions -->\n\t\t<span v-if=\"$slots.actions\"\n\t\t\tclass=\"cn-object-row__actions\"\n\t\t\t@click.stop\n\t\t\t@auxclick.stop>\n\t\t\t<!-- @slot actions Trailing actions (copy button, menu, …). -->\n\t\t\t<!-- @binding {object} object The row's object. -->\n\t\t\t<slot name=\"actions\" :object=\"object\" />\n\t\t</span>\n\t</div>\n</template>\n\n<script>\nimport { NcCheckboxRadioSwitch } from '@nextcloud/vue'\nimport { useClickDragGuard } from '../../composables/useClickDragGuard.js'\nimport { resolveImageUrl } from '../../utils/resolveImageUrl.js'\nimport { isRowMiddleClick, preventMiddleClickAutoscroll } from '../../utils/rowAuxClick.js'\nimport { CnIcon } from '../CnIcon/index.js'\nimport { CnStatusBadge } from '../CnStatusBadge/index.js'\n\n/**\n * CnObjectRow — Compact single-line list row for object display.\n *\n * The list-mode counterpart to `CnObjectCard`: a leading icon (or image), a\n * name with an optional subtitle, an optional status badge, and a trailing\n * actions area. Which object fields map to each slot is resolved from the\n * `config` prop first, then from `schema.configuration` (so a schema that\n * already declares `objectNameField` / `objectDescriptionField` / `objectImageField`\n * works with zero extra config).\n *\n * ```vue\n * <CnObjectRow\n * :object=\"secret\"\n * :schema=\"secretSchema\"\n * :config=\"{ subtitleField: 'url', iconName: 'Key' }\">\n * <template #actions=\"{ object }\">\n * <NcButton @click=\"copy(object)\">Copy</NcButton>\n * </template>\n * </CnObjectRow>\n * ```\n */\nexport default {\n\tname: 'CnObjectRow',\n\n\tcomponents: {\n\t\tNcCheckboxRadioSwitch,\n\t\tCnIcon,\n\t\tCnStatusBadge,\n\t},\n\n\tprops: {\n\t\t/** The object data */\n\t\tobject: {\n\t\t\ttype: Object,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Schema definition; `schema.configuration` supplies field defaults */\n\t\tschema: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Explicit field mapping. Every key is optional and overrides the\n\t\t * schema-configuration default.\n\t\t *\n\t\t * @type {{ titleField?: string, subtitleField?: string, imageField?: string, iconField?: string, iconName?: string, badgeField?: string, badgeVariantField?: string, badgeVariant?: string, badgeColorMap?: object }}\n\t\t */\n\t\tconfig: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** Whether this row is selected */\n\t\tselected: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Whether to show the selection checkbox */\n\t\tselectable: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\t},\n\n\t// Vue 2 had a separate listener channel, so a consumer's `@click` only ever\n\t// saw `$emit('click')`. In Vue 3 an UNDECLARED event name stays a\n\t// fallthrough attribute: `onClick` lands on the root `<div>` as a native\n\t// handler, so the consumer's handler fires once from the DOM click and\n\t// again from `$emit('click', object)` — twice per click, with different\n\t// payloads. Declaring the names here removes them from `$attrs`, which is\n\t// also what stops VTU v2 recording the native DOM event into `emitted()`.\n\temits: ['select', 'click', 'aux-click'],\n\n\tsetup() {\n\t\t// Tell a deliberate row click apart from a text-selection drag.\n\t\treturn useClickDragGuard()\n\t},\n\n\tcomputed: {\n\t\t/** Schema-level configuration block (empty when no schema). */\n\t\tschemaConfig() {\n\t\t\treturn this.schema?.configuration || {}\n\t\t},\n\n\t\ttitle() {\n\t\t\tconst field = this.config.titleField || this.schemaConfig.objectNameField\n\t\t\tif (field && this.object[field] !== null && this.object[field] !== undefined) {\n\t\t\t\treturn String(this.object[field])\n\t\t\t}\n\t\t\treturn this.object.title || this.object.name || this.object.id || '—'\n\t\t},\n\n\t\tsubtitle() {\n\t\t\tconst field = this.config.subtitleField || this.schemaConfig.objectDescriptionField\n\t\t\tif (field && this.object[field] !== null && this.object[field] !== undefined && this.object[field] !== '') {\n\t\t\t\treturn String(this.object[field])\n\t\t\t}\n\t\t\treturn null\n\t\t},\n\n\t\timageUrl() {\n\t\t\tconst field = this.config.imageField || this.schemaConfig.objectImageField\n\t\t\tif (field && this.object[field]) {\n\t\t\t\treturn resolveImageUrl(String(this.object[field]))\n\t\t\t}\n\t\t\treturn null\n\t\t},\n\n\t\ticonName() {\n\t\t\tconst field = this.config.iconField\n\t\t\tif (field && this.object[field]) {\n\t\t\t\treturn String(this.object[field])\n\t\t\t}\n\t\t\treturn this.config.iconName || ''\n\t\t},\n\n\t\t/** Whether to render the leading icon column at all. */\n\t\thasLeadingIcon() {\n\t\t\treturn Boolean(this.imageUrl || this.iconName || this.$slots.icon)\n\t\t},\n\n\t\tbadgeLabel() {\n\t\t\tconst field = this.config.badgeField\n\t\t\tif (field && this.object[field] !== null && this.object[field] !== undefined && this.object[field] !== '') {\n\t\t\t\treturn String(this.object[field])\n\t\t\t}\n\t\t\treturn null\n\t\t},\n\n\t\tbadgeVariant() {\n\t\t\tconst field = this.config.badgeVariantField\n\t\t\tif (field && this.object[field]) {\n\t\t\t\treturn String(this.object[field])\n\t\t\t}\n\t\t\treturn this.config.badgeVariant || 'default'\n\t\t},\n\n\t\tbadgeColorMap() {\n\t\t\treturn this.config.badgeColorMap || null\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Row-body click: emits `select` when `selectable` (ignoring drags),\n\t\t * otherwise emits `click` for navigation.\n\t\t *\n\t\t * @param {MouseEvent} [event] The originating click event.\n\t\t */\n\t\tonRowClick(event) {\n\t\t\tif (this.selectable) {\n\t\t\t\tif (this.wasDrag(event)) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\t/**\n\t\t\t\t * @event select Emitted when a selectable row toggles selection (body or checkbox click).\n\t\t\t\t * @type {object} The row's object.\n\t\t\t\t */\n\t\t\t\tthis.$emit('select', this.object)\n\t\t\t\treturn\n\t\t\t}\n\t\t\t/**\n\t\t\t * @event click Emitted when a non-selectable row is clicked (navigation). Payload: `(object, event)` — the row's object and the native click event, for opening it in a new tab on a ctrl/cmd/shift click. A middle click emits `aux-click` instead.\n\t\t\t * @type {object} The row's object.\n\t\t\t */\n\t\t\tthis.$emit('click', this.object, event)\n\t\t},\n\n\t\t/**\n\t\t * Row mousedown: record the press for the drag guard, and on a\n\t\t * non-selectable row keep a middle press from starting autoscroll.\n\t\t *\n\t\t * @param {MouseEvent} event The mousedown event.\n\t\t */\n\t\tonRowMouseDown(event) {\n\t\t\tthis.onPointerDown(event)\n\t\t\tif (!this.selectable) {\n\t\t\t\tpreventMiddleClickAutoscroll(event)\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Row-body middle click on a non-selectable row: emits `aux-click`, not\n\t\t * `click`, so an existing `click` listener that navigates never moves\n\t\t * the current tab away.\n\t\t *\n\t\t * @param {MouseEvent} event The auxclick event.\n\t\t */\n\t\tonRowAuxClick(event) {\n\t\t\tif (this.selectable || !isRowMiddleClick(event)) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\t/**\n\t\t\t * @event aux-click Emitted when a non-selectable row is middle-clicked, for opening it in a new tab (see `openRowTarget`). Payload: `(object, event)` — the row's object and the native auxclick event.\n\t\t\t * @type {object} The row's object.\n\t\t\t */\n\t\t\tthis.$emit('aux-click', this.object, event)\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-object-row {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 12px;\n\tpadding: 8px 12px;\n\tborder-bottom: 1px solid var(--color-border);\n\tcursor: pointer;\n}\n\n.cn-object-row:hover {\n\tbackground-color: var(--color-background-hover);\n}\n\n.cn-object-row--selected {\n\t/* Inset accent — never border-left (would shift cell content). */\n\tbox-shadow: inset 3px 0 0 0 var(--color-primary-element);\n\tbackground-color: var(--color-primary-element-light);\n}\n\n.cn-object-row__checkbox {\n\tflex-shrink: 0;\n}\n\n.cn-object-row__icon {\n\tflex-shrink: 0;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 24px;\n\theight: 24px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-object-row__image {\n\twidth: 24px;\n\theight: 24px;\n\tobject-fit: contain;\n\tborder-radius: var(--border-radius);\n}\n\n.cn-object-row__main {\n\tdisplay: flex;\n\tflex-direction: column;\n\tmin-width: 0;\n\tflex: 1;\n}\n\n.cn-object-row__title {\n\tfont-weight: 600;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-object-row__subtitle {\n\tfont-size: 13px;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-object-row__badges {\n\tflex-shrink: 0;\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 6px;\n}\n\n.cn-object-row__actions {\n\tflex-shrink: 0;\n\tdisplay: flex;\n\talign-items: center;\n}\n</style>\n"],"names":["CnIcon","CnStatusBadge"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnObjectRow.vue2.js","sources":["../../../../src/components/CnObjectRow/CnObjectRow.vue"],"sourcesContent":["<template>\n\t<div\n\t\tclass=\"cn-object-row\"\n\t\t:class=\"{ 'cn-object-row--selected': selected }\"\n\t\t@mousedown=\"onRowMouseDown\"\n\t\t@click=\"onRowClick($event)\"\n\t\t@auxclick=\"onRowAuxClick($event)\">\n\t\t<!-- Selection checkbox -->\n\t\t<div v-if=\"selectable\"\n\t\t\tclass=\"cn-object-row__checkbox\"\n\t\t\t@click.stop\n\t\t\t@auxclick.stop>\n\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t:modelValue=\"selected\"\n\t\t\t\t@update:modelValue=\"$emit('select', object)\" />\n\t\t</div>\n\n\t\t<!-- `config.leading`: one cell before the title, as a table cell renders\n\t\t it (`{ key, widget?, widgetProps?, formatter? }`), e.g. the age\n\t\t \"6 dagen\" in the team queue. -->\n\t\t<span\n\t\t\tv-if=\"leadingCell\"\n\t\t\tclass=\"cn-object-row__lead\"\n\t\t\t:style=\"leadingCell.width ? { width: leadingCell.width } : null\"\n\t\t\tdata-testid=\"cn-object-row-lead\">\n\t\t\t<CnCellRenderer\n\t\t\t\t:value=\"cellValue(leadingCell)\"\n\t\t\t\t:formatter=\"leadingCell.formatter || null\"\n\t\t\t\t:widget=\"leadingCell.widget || null\"\n\t\t\t\t:widgetProps=\"leadingCell.widgetProps || undefined\"\n\t\t\t\t:row=\"object\" />\n\t\t</span>\n\n\t\t<!-- Leading icon / image — omitted entirely when nothing is configured\n\t\t (no image, no icon name, no slot). -->\n\t\t<span v-if=\"hasLeadingIcon\" class=\"cn-object-row__icon\">\n\t\t\t<!-- @slot icon Replace the leading icon/image. -->\n\t\t\t<!-- @binding {object} object The row's object. -->\n\t\t\t<slot name=\"icon\" :object=\"object\">\n\t\t\t\t<img\n\t\t\t\t\tv-if=\"imageUrl\"\n\t\t\t\t\t:src=\"imageUrl\"\n\t\t\t\t\talt=\"\"\n\t\t\t\t\twidth=\"24\"\n\t\t\t\t\theight=\"24\"\n\t\t\t\t\tclass=\"cn-object-row__image\">\n\t\t\t\t<CnIcon v-else-if=\"iconName\" :name=\"iconName\" :size=\"24\" />\n\t\t\t</slot>\n\t\t</span>\n\n\t\t<!-- Main: title + subtitle -->\n\t\t<span class=\"cn-object-row__main\">\n\t\t\t<span class=\"cn-object-row__title\">{{ title }}</span>\n\t\t\t<span v-if=\"subtitle\" class=\"cn-object-row__subtitle\">{{ subtitle }}</span>\n\t\t</span>\n\n\t\t<!-- Badges (default: config-driven status badge) -->\n\t\t<span v-if=\"$slots.badges || badgeLabel\" class=\"cn-object-row__badges\">\n\t\t\t<!-- @slot badges Replace the badge area (overrides the config-driven badge). -->\n\t\t\t<!-- @binding {object} object The row's object. -->\n\t\t\t<slot name=\"badges\" :object=\"object\">\n\t\t\t\t<CnStatusBadge\n\t\t\t\t\tv-if=\"badgeLabel\"\n\t\t\t\t\t:label=\"badgeLabel\"\n\t\t\t\t\t:variant=\"badgeVariant\"\n\t\t\t\t\t:colorMap=\"badgeColorMap\"\n\t\t\t\t\tsize=\"small\" />\n\t\t\t</slot>\n\t\t</span>\n\n\t\t<!-- `config.trailing`: cells after the badges, each in its own column\n\t\t (the case type badge, the due text). -->\n\t\t<span\n\t\t\tv-for=\"(cell, index) in trailingCells\"\n\t\t\t:key=\"cell.key + '-' + index\"\n\t\t\tclass=\"cn-object-row__trail\"\n\t\t\t:style=\"cell.width ? { width: cell.width } : null\"\n\t\t\tdata-testid=\"cn-object-row-trail\">\n\t\t\t<CnCellRenderer\n\t\t\t\t:value=\"cellValue(cell)\"\n\t\t\t\t:formatter=\"cell.formatter || null\"\n\t\t\t\t:widget=\"cell.widget || null\"\n\t\t\t\t:widgetProps=\"cell.widgetProps || undefined\"\n\t\t\t\t:row=\"object\" />\n\t\t</span>\n\n\t\t<!-- Trailing actions -->\n\t\t<span v-if=\"$slots.actions\"\n\t\t\tclass=\"cn-object-row__actions\"\n\t\t\t@click.stop\n\t\t\t@auxclick.stop>\n\t\t\t<!-- @slot actions Trailing actions (copy button, menu, …). -->\n\t\t\t<!-- @binding {object} object The row's object. -->\n\t\t\t<slot name=\"actions\" :object=\"object\" />\n\t\t</span>\n\t</div>\n</template>\n\n<script>\nimport { NcCheckboxRadioSwitch } from '@nextcloud/vue'\nimport { useClickDragGuard } from '../../composables/useClickDragGuard.js'\nimport { joinTemplateParts } from '../../utils/fillTemplate.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { resolveImageUrl } from '../../utils/resolveImageUrl.js'\nimport { isRowMiddleClick, preventMiddleClickAutoscroll } from '../../utils/rowAuxClick.js'\nimport { CnCellRenderer } from '../CnCellRenderer/index.js'\nimport { CnIcon } from '../CnIcon/index.js'\nimport { CnStatusBadge } from '../CnStatusBadge/index.js'\n\n/**\n * CnObjectRow — Compact single-line list row for object display.\n *\n * The list-mode counterpart to `CnObjectCard`: a leading icon (or image), a\n * name with an optional subtitle, an optional status badge, and a trailing\n * actions area. Which object fields map to each slot is resolved from the\n * `config` prop first, then from `schema.configuration` (so a schema that\n * already declares `objectNameField` / `objectDescriptionField` / `objectImageField`\n * works with zero extra config).\n *\n * ```vue\n * <CnObjectRow\n * :object=\"secret\"\n * :schema=\"secretSchema\"\n * :config=\"{ subtitleField: 'url', iconName: 'Key' }\">\n * <template #actions=\"{ object }\">\n * <NcButton @click=\"copy(object)\">Copy</NcButton>\n * </template>\n * </CnObjectRow>\n * ```\n */\nexport default {\n\tname: 'CnObjectRow',\n\n\tcomponents: {\n\t\tNcCheckboxRadioSwitch,\n\t\tCnCellRenderer,\n\t\tCnIcon,\n\t\tCnStatusBadge,\n\t},\n\n\tprops: {\n\t\t/** The object data */\n\t\tobject: {\n\t\t\ttype: Object,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Schema definition; `schema.configuration` supplies field defaults */\n\t\tschema: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Explicit field mapping. Every key is optional and overrides the\n\t\t * schema-configuration default.\n\t\t *\n\t\t * `subtitleTemplate` fills `{field}` tokens from the row (empty parts and\n\t\t * their separators drop). `leading` (one cell) and `trailing` (a cell or\n\t\t * a list) draw cells as a table column does, `{ key, widget?,\n\t\t * widgetProps?, formatter? }`: `{ key: \"createdAt\", widget: \"age\" }`\n\t\t * reads \"6 dagen\", `{ key: \"deadline\", widget: \"date\", widgetProps: {\n\t\t * due: {} } }` the due text. A cell's `width` (CSS) lines the column\n\t\t * up across rows.\n\t\t *\n\t\t * @type {{ titleField?: string, subtitleField?: string, subtitleTemplate?: string, imageField?: string, iconField?: string, iconName?: string, badgeField?: string, badgeVariantField?: string, badgeVariant?: string, badgeColorMap?: object, leading?: object, trailing?: (object|Array<object>) }}\n\t\t */\n\t\tconfig: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** Whether this row is selected */\n\t\tselected: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Whether to show the selection checkbox */\n\t\tselectable: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\t},\n\n\t// Vue 2 had a separate listener channel, so a consumer's `@click` only ever\n\t// saw `$emit('click')`. In Vue 3 an UNDECLARED event name stays a\n\t// fallthrough attribute: `onClick` lands on the root `<div>` as a native\n\t// handler, so the consumer's handler fires once from the DOM click and\n\t// again from `$emit('click', object)` — twice per click, with different\n\t// payloads. Declaring the names here removes them from `$attrs`, which is\n\t// also what stops VTU v2 recording the native DOM event into `emitted()`.\n\temits: ['select', 'click', 'aux-click'],\n\n\tsetup() {\n\t\t// Tell a deliberate row click apart from a text-selection drag.\n\t\treturn useClickDragGuard()\n\t},\n\n\tcomputed: {\n\t\t/** Schema-level configuration block (empty when no schema). */\n\t\tschemaConfig() {\n\t\t\treturn this.schema?.configuration || {}\n\t\t},\n\n\t\ttitle() {\n\t\t\tconst field = this.config.titleField || this.schemaConfig.objectNameField\n\t\t\tif (field && this.object[field] !== null && this.object[field] !== undefined) {\n\t\t\t\treturn String(this.object[field])\n\t\t\t}\n\t\t\treturn this.object.title || this.object.name || this.object.id || '—'\n\t\t},\n\n\t\tsubtitle() {\n\t\t\tif (typeof this.config.subtitleTemplate === 'string' && this.config.subtitleTemplate !== '') {\n\t\t\t\tconst text = joinTemplateParts(this.config.subtitleTemplate, (key) => {\n\t\t\t\t\tconst value = readPath(this.object, key)\n\t\t\t\t\treturn value === null || value === undefined ? '' : String(value)\n\t\t\t\t})\n\t\t\t\treturn text.trim() || null\n\t\t\t}\n\t\t\tconst field = this.config.subtitleField || this.schemaConfig.objectDescriptionField\n\t\t\tif (field && this.object[field] !== null && this.object[field] !== undefined && this.object[field] !== '') {\n\t\t\t\treturn String(this.object[field])\n\t\t\t}\n\t\t\treturn null\n\t\t},\n\n\t\timageUrl() {\n\t\t\tconst field = this.config.imageField || this.schemaConfig.objectImageField\n\t\t\tif (field && this.object[field]) {\n\t\t\t\treturn resolveImageUrl(String(this.object[field]))\n\t\t\t}\n\t\t\treturn null\n\t\t},\n\n\t\ticonName() {\n\t\t\tconst field = this.config.iconField\n\t\t\tif (field && this.object[field]) {\n\t\t\t\treturn String(this.object[field])\n\t\t\t}\n\t\t\treturn this.config.iconName || ''\n\t\t},\n\n\t\t/** Whether to render the leading icon column at all. */\n\t\thasLeadingIcon() {\n\t\t\treturn Boolean(this.imageUrl || this.iconName || this.$slots.icon)\n\t\t},\n\n\t\tbadgeLabel() {\n\t\t\tconst field = this.config.badgeField\n\t\t\tif (field && this.object[field] !== null && this.object[field] !== undefined && this.object[field] !== '') {\n\t\t\t\treturn String(this.object[field])\n\t\t\t}\n\t\t\treturn null\n\t\t},\n\n\t\tbadgeVariant() {\n\t\t\tconst field = this.config.badgeVariantField\n\t\t\tif (field && this.object[field]) {\n\t\t\t\treturn String(this.object[field])\n\t\t\t}\n\t\t\treturn this.config.badgeVariant || 'default'\n\t\t},\n\n\t\tbadgeColorMap() {\n\t\t\treturn this.config.badgeColorMap || null\n\t\t},\n\n\t\t/**\n\t\t * The `config.leading` cell, or null.\n\t\t *\n\t\t * @spec openspec/changes/index-row-list-cells/specs/object-row/spec.md#requirement-a-list-row-can-carry-leading-and-trailing-cells\n\t\t * @return {object|null}\n\t\t */\n\t\tleadingCell() {\n\t\t\tconst cell = this.config.leading\n\t\t\treturn cell && typeof cell === 'object' && typeof cell.key === 'string' && cell.key !== '' ? cell : null\n\t\t},\n\n\t\t/**\n\t\t * The `config.trailing` cells (one object or a list), those with a key.\n\t\t *\n\t\t * @spec openspec/changes/index-row-list-cells/specs/object-row/spec.md#requirement-a-list-row-can-carry-leading-and-trailing-cells\n\t\t * @return {Array<object>}\n\t\t */\n\t\ttrailingCells() {\n\t\t\tconst cells = this.config.trailing\n\t\t\tconst list = Array.isArray(cells) ? cells : (cells && typeof cells === 'object' ? [cells] : [])\n\t\t\treturn list.filter((cell) => cell && typeof cell === 'object' && typeof cell.key === 'string' && cell.key !== '')\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * A cell's value: the dot-path `key` read off the row.\n\t\t *\n\t\t * @param {{key: string}} cell The cell.\n\t\t * @return {unknown} The value.\n\t\t */\n\t\tcellValue(cell) {\n\t\t\treturn readPath(this.object, cell.key)\n\t\t},\n\n\t\t/**\n\t\t * Row-body click: emits `select` when `selectable` (ignoring drags),\n\t\t * otherwise emits `click` for navigation.\n\t\t *\n\t\t * @param {MouseEvent} [event] The originating click event.\n\t\t */\n\t\tonRowClick(event) {\n\t\t\tif (this.selectable) {\n\t\t\t\tif (this.wasDrag(event)) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\t/**\n\t\t\t\t * @event select Emitted when a selectable row toggles selection (body or checkbox click).\n\t\t\t\t * @type {object} The row's object.\n\t\t\t\t */\n\t\t\t\tthis.$emit('select', this.object)\n\t\t\t\treturn\n\t\t\t}\n\t\t\t/**\n\t\t\t * @event click Emitted when a non-selectable row is clicked (navigation). Payload: `(object, event)` — the row's object and the native click event, for opening it in a new tab on a ctrl/cmd/shift click. A middle click emits `aux-click` instead.\n\t\t\t * @type {object} The row's object.\n\t\t\t */\n\t\t\tthis.$emit('click', this.object, event)\n\t\t},\n\n\t\t/**\n\t\t * Row mousedown: record the press for the drag guard, and on a\n\t\t * non-selectable row keep a middle press from starting autoscroll.\n\t\t *\n\t\t * @param {MouseEvent} event The mousedown event.\n\t\t */\n\t\tonRowMouseDown(event) {\n\t\t\tthis.onPointerDown(event)\n\t\t\tif (!this.selectable) {\n\t\t\t\tpreventMiddleClickAutoscroll(event)\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Row-body middle click on a non-selectable row: emits `aux-click`, not\n\t\t * `click`, so an existing `click` listener that navigates never moves\n\t\t * the current tab away.\n\t\t *\n\t\t * @param {MouseEvent} event The auxclick event.\n\t\t */\n\t\tonRowAuxClick(event) {\n\t\t\tif (this.selectable || !isRowMiddleClick(event)) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\t/**\n\t\t\t * @event aux-click Emitted when a non-selectable row is middle-clicked, for opening it in a new tab (see `openRowTarget`). Payload: `(object, event)` — the row's object and the native auxclick event.\n\t\t\t * @type {object} The row's object.\n\t\t\t */\n\t\t\tthis.$emit('aux-click', this.object, event)\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-object-row {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 12px;\n\tpadding: 8px 12px;\n\tborder-bottom: 1px solid var(--color-border);\n\tcursor: pointer;\n}\n\n.cn-object-row:hover {\n\tbackground-color: var(--color-background-hover);\n}\n\n.cn-object-row--selected {\n\t/* Inset accent — never border-left (would shift cell content). */\n\tbox-shadow: inset 3px 0 0 0 var(--color-primary-element);\n\tbackground-color: var(--color-primary-element-light);\n}\n\n.cn-object-row__lead,\n.cn-object-row__trail {\n\tflex: 0 0 auto;\n\tmin-width: 0;\n}\n\n.cn-object-row__lead {\n\tfont-weight: 600;\n}\n\n.cn-object-row__checkbox {\n\tflex-shrink: 0;\n}\n\n.cn-object-row__icon {\n\tflex-shrink: 0;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 24px;\n\theight: 24px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-object-row__image {\n\twidth: 24px;\n\theight: 24px;\n\tobject-fit: contain;\n\tborder-radius: var(--border-radius);\n}\n\n.cn-object-row__main {\n\tdisplay: flex;\n\tflex-direction: column;\n\tmin-width: 0;\n\tflex: 1;\n}\n\n.cn-object-row__title {\n\tfont-weight: 600;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-object-row__subtitle {\n\tfont-size: 13px;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-object-row__badges {\n\tflex-shrink: 0;\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 6px;\n}\n\n.cn-object-row__actions {\n\tflex-shrink: 0;\n\tdisplay: flex;\n\talign-items: center;\n}\n</style>\n"],"names":["CnCellRenderer","CnIcon","CnStatusBadge"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { resolveComponent, openBlock, createElementBlock, normalizeClass, withModifiers, createVNode, createCommentVNode, renderSlot, createBlock, createElementVNode, toDisplayString } from 'vue';
|
|
1
|
+
import { resolveComponent, openBlock, createElementBlock, normalizeClass, withModifiers, createVNode, createCommentVNode, normalizeStyle, renderSlot, createBlock, createElementVNode, toDisplayString, Fragment, renderList } from 'vue';
|
|
2
2
|
|
|
3
3
|
const _hoisted_1 = {
|
|
4
|
-
key:
|
|
4
|
+
key: 2,
|
|
5
5
|
class: "cn-object-row__icon"
|
|
6
6
|
};
|
|
7
7
|
const _hoisted_2 = ["src"];
|
|
@@ -12,12 +12,13 @@ const _hoisted_5 = {
|
|
|
12
12
|
class: "cn-object-row__subtitle"
|
|
13
13
|
};
|
|
14
14
|
const _hoisted_6 = {
|
|
15
|
-
key:
|
|
15
|
+
key: 3,
|
|
16
16
|
class: "cn-object-row__badges"
|
|
17
17
|
};
|
|
18
18
|
|
|
19
19
|
function render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
20
20
|
const _component_NcCheckboxRadioSwitch = resolveComponent("NcCheckboxRadioSwitch");
|
|
21
|
+
const _component_CnCellRenderer = resolveComponent("CnCellRenderer");
|
|
21
22
|
const _component_CnIcon = resolveComponent("CnIcon");
|
|
22
23
|
const _component_CnStatusBadge = resolveComponent("CnStatusBadge");
|
|
23
24
|
|
|
@@ -40,6 +41,22 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
40
41
|
}, null, 8 /* PROPS */, ["modelValue"])
|
|
41
42
|
], 32 /* NEED_HYDRATION */))
|
|
42
43
|
: createCommentVNode("v-if", true),
|
|
44
|
+
($options.leadingCell)
|
|
45
|
+
? (openBlock(), createElementBlock("span", {
|
|
46
|
+
key: 1,
|
|
47
|
+
class: "cn-object-row__lead",
|
|
48
|
+
style: normalizeStyle($options.leadingCell.width ? { width: $options.leadingCell.width } : null),
|
|
49
|
+
"data-testid": "cn-object-row-lead"
|
|
50
|
+
}, [
|
|
51
|
+
createVNode(_component_CnCellRenderer, {
|
|
52
|
+
value: $options.cellValue($options.leadingCell),
|
|
53
|
+
formatter: $options.leadingCell.formatter || null,
|
|
54
|
+
widget: $options.leadingCell.widget || null,
|
|
55
|
+
widgetProps: $options.leadingCell.widgetProps || undefined,
|
|
56
|
+
row: $props.object
|
|
57
|
+
}, null, 8 /* PROPS */, ["value", "formatter", "widget", "widgetProps", "row"])
|
|
58
|
+
], 4 /* STYLE */))
|
|
59
|
+
: createCommentVNode("v-if", true),
|
|
43
60
|
($options.hasLeadingIcon)
|
|
44
61
|
? (openBlock(), createElementBlock("span", _hoisted_1, [
|
|
45
62
|
renderSlot(_ctx.$slots, "icon", { object: $props.object }, () => [
|
|
@@ -83,9 +100,25 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
83
100
|
])
|
|
84
101
|
]))
|
|
85
102
|
: createCommentVNode("v-if", true),
|
|
103
|
+
(openBlock(true), createElementBlock(Fragment, null, renderList($options.trailingCells, (cell, index) => {
|
|
104
|
+
return (openBlock(), createElementBlock("span", {
|
|
105
|
+
key: cell.key + '-' + index,
|
|
106
|
+
class: "cn-object-row__trail",
|
|
107
|
+
style: normalizeStyle(cell.width ? { width: cell.width } : null),
|
|
108
|
+
"data-testid": "cn-object-row-trail"
|
|
109
|
+
}, [
|
|
110
|
+
createVNode(_component_CnCellRenderer, {
|
|
111
|
+
value: $options.cellValue(cell),
|
|
112
|
+
formatter: cell.formatter || null,
|
|
113
|
+
widget: cell.widget || null,
|
|
114
|
+
widgetProps: cell.widgetProps || undefined,
|
|
115
|
+
row: $props.object
|
|
116
|
+
}, null, 8 /* PROPS */, ["value", "formatter", "widget", "widgetProps", "row"])
|
|
117
|
+
], 4 /* STYLE */))
|
|
118
|
+
}), 128 /* KEYED_FRAGMENT */)),
|
|
86
119
|
(_ctx.$slots.actions)
|
|
87
120
|
? (openBlock(), createElementBlock("span", {
|
|
88
|
-
key:
|
|
121
|
+
key: 4,
|
|
89
122
|
class: "cn-object-row__actions",
|
|
90
123
|
onClick: _cache[3] || (_cache[3] = withModifiers(() => {}, ["stop"])),
|
|
91
124
|
onAuxclick: _cache[4] || (_cache[4] = withModifiers(() => {}, ["stop"]))
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnObjectRow.vue3.js","sources":["../../../../src/components/CnObjectRow/CnObjectRow.vue?vue&type=template&id=a4a78a68&lang.js"],"sourcesContent":["<template>\n\t<div\n\t\tclass=\"cn-object-row\"\n\t\t:class=\"{ 'cn-object-row--selected': selected }\"\n\t\t@mousedown=\"onRowMouseDown\"\n\t\t@click=\"onRowClick($event)\"\n\t\t@auxclick=\"onRowAuxClick($event)\">\n\t\t<!-- Selection checkbox -->\n\t\t<div v-if=\"selectable\"\n\t\t\tclass=\"cn-object-row__checkbox\"\n\t\t\t@click.stop\n\t\t\t@auxclick.stop>\n\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t:modelValue=\"selected\"\n\t\t\t\t@update:modelValue=\"$emit('select', object)\" />\n\t\t</div>\n\n\t\t<!-- Leading icon / image — omitted entirely when nothing is configured\n\t\t (no image, no icon name, no slot). -->\n\t\t<span v-if=\"hasLeadingIcon\" class=\"cn-object-row__icon\">\n\t\t\t<!-- @slot icon Replace the leading icon/image. -->\n\t\t\t<!-- @binding {object} object The row's object. -->\n\t\t\t<slot name=\"icon\" :object=\"object\">\n\t\t\t\t<img\n\t\t\t\t\tv-if=\"imageUrl\"\n\t\t\t\t\t:src=\"imageUrl\"\n\t\t\t\t\talt=\"\"\n\t\t\t\t\twidth=\"24\"\n\t\t\t\t\theight=\"24\"\n\t\t\t\t\tclass=\"cn-object-row__image\">\n\t\t\t\t<CnIcon v-else-if=\"iconName\" :name=\"iconName\" :size=\"24\" />\n\t\t\t</slot>\n\t\t</span>\n\n\t\t<!-- Main: title + subtitle -->\n\t\t<span class=\"cn-object-row__main\">\n\t\t\t<span class=\"cn-object-row__title\">{{ title }}</span>\n\t\t\t<span v-if=\"subtitle\" class=\"cn-object-row__subtitle\">{{ subtitle }}</span>\n\t\t</span>\n\n\t\t<!-- Badges (default: config-driven status badge) -->\n\t\t<span v-if=\"$slots.badges || badgeLabel\" class=\"cn-object-row__badges\">\n\t\t\t<!-- @slot badges Replace the badge area (overrides the config-driven badge). -->\n\t\t\t<!-- @binding {object} object The row's object. -->\n\t\t\t<slot name=\"badges\" :object=\"object\">\n\t\t\t\t<CnStatusBadge\n\t\t\t\t\tv-if=\"badgeLabel\"\n\t\t\t\t\t:label=\"badgeLabel\"\n\t\t\t\t\t:variant=\"badgeVariant\"\n\t\t\t\t\t:colorMap=\"badgeColorMap\"\n\t\t\t\t\tsize=\"small\" />\n\t\t\t</slot>\n\t\t</span>\n\n\t\t<!-- Trailing actions -->\n\t\t<span v-if=\"$slots.actions\"\n\t\t\tclass=\"cn-object-row__actions\"\n\t\t\t@click.stop\n\t\t\t@auxclick.stop>\n\t\t\t<!-- @slot actions Trailing actions (copy button, menu, …). -->\n\t\t\t<!-- @binding {object} object The row's object. -->\n\t\t\t<slot name=\"actions\" :object=\"object\" />\n\t\t</span>\n\t</div>\n</template>\n\n<script>\nimport { NcCheckboxRadioSwitch } from '@nextcloud/vue'\nimport { useClickDragGuard } from '../../composables/useClickDragGuard.js'\nimport { resolveImageUrl } from '../../utils/resolveImageUrl.js'\nimport { isRowMiddleClick, preventMiddleClickAutoscroll } from '../../utils/rowAuxClick.js'\nimport { CnIcon } from '../CnIcon/index.js'\nimport { CnStatusBadge } from '../CnStatusBadge/index.js'\n\n/**\n * CnObjectRow — Compact single-line list row for object display.\n *\n * The list-mode counterpart to `CnObjectCard`: a leading icon (or image), a\n * name with an optional subtitle, an optional status badge, and a trailing\n * actions area. Which object fields map to each slot is resolved from the\n * `config` prop first, then from `schema.configuration` (so a schema that\n * already declares `objectNameField` / `objectDescriptionField` / `objectImageField`\n * works with zero extra config).\n *\n * ```vue\n * <CnObjectRow\n * :object=\"secret\"\n * :schema=\"secretSchema\"\n * :config=\"{ subtitleField: 'url', iconName: 'Key' }\">\n * <template #actions=\"{ object }\">\n * <NcButton @click=\"copy(object)\">Copy</NcButton>\n * </template>\n * </CnObjectRow>\n * ```\n */\nexport default {\n\tname: 'CnObjectRow',\n\n\tcomponents: {\n\t\tNcCheckboxRadioSwitch,\n\t\tCnIcon,\n\t\tCnStatusBadge,\n\t},\n\n\tprops: {\n\t\t/** The object data */\n\t\tobject: {\n\t\t\ttype: Object,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Schema definition; `schema.configuration` supplies field defaults */\n\t\tschema: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Explicit field mapping. Every key is optional and overrides the\n\t\t * schema-configuration default.\n\t\t *\n\t\t * @type {{ titleField?: string, subtitleField?: string, imageField?: string, iconField?: string, iconName?: string, badgeField?: string, badgeVariantField?: string, badgeVariant?: string, badgeColorMap?: object }}\n\t\t */\n\t\tconfig: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** Whether this row is selected */\n\t\tselected: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Whether to show the selection checkbox */\n\t\tselectable: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\t},\n\n\t// Vue 2 had a separate listener channel, so a consumer's `@click` only ever\n\t// saw `$emit('click')`. In Vue 3 an UNDECLARED event name stays a\n\t// fallthrough attribute: `onClick` lands on the root `<div>` as a native\n\t// handler, so the consumer's handler fires once from the DOM click and\n\t// again from `$emit('click', object)` — twice per click, with different\n\t// payloads. Declaring the names here removes them from `$attrs`, which is\n\t// also what stops VTU v2 recording the native DOM event into `emitted()`.\n\temits: ['select', 'click', 'aux-click'],\n\n\tsetup() {\n\t\t// Tell a deliberate row click apart from a text-selection drag.\n\t\treturn useClickDragGuard()\n\t},\n\n\tcomputed: {\n\t\t/** Schema-level configuration block (empty when no schema). */\n\t\tschemaConfig() {\n\t\t\treturn this.schema?.configuration || {}\n\t\t},\n\n\t\ttitle() {\n\t\t\tconst field = this.config.titleField || this.schemaConfig.objectNameField\n\t\t\tif (field && this.object[field] !== null && this.object[field] !== undefined) {\n\t\t\t\treturn String(this.object[field])\n\t\t\t}\n\t\t\treturn this.object.title || this.object.name || this.object.id || '—'\n\t\t},\n\n\t\tsubtitle() {\n\t\t\tconst field = this.config.subtitleField || this.schemaConfig.objectDescriptionField\n\t\t\tif (field && this.object[field] !== null && this.object[field] !== undefined && this.object[field] !== '') {\n\t\t\t\treturn String(this.object[field])\n\t\t\t}\n\t\t\treturn null\n\t\t},\n\n\t\timageUrl() {\n\t\t\tconst field = this.config.imageField || this.schemaConfig.objectImageField\n\t\t\tif (field && this.object[field]) {\n\t\t\t\treturn resolveImageUrl(String(this.object[field]))\n\t\t\t}\n\t\t\treturn null\n\t\t},\n\n\t\ticonName() {\n\t\t\tconst field = this.config.iconField\n\t\t\tif (field && this.object[field]) {\n\t\t\t\treturn String(this.object[field])\n\t\t\t}\n\t\t\treturn this.config.iconName || ''\n\t\t},\n\n\t\t/** Whether to render the leading icon column at all. */\n\t\thasLeadingIcon() {\n\t\t\treturn Boolean(this.imageUrl || this.iconName || this.$slots.icon)\n\t\t},\n\n\t\tbadgeLabel() {\n\t\t\tconst field = this.config.badgeField\n\t\t\tif (field && this.object[field] !== null && this.object[field] !== undefined && this.object[field] !== '') {\n\t\t\t\treturn String(this.object[field])\n\t\t\t}\n\t\t\treturn null\n\t\t},\n\n\t\tbadgeVariant() {\n\t\t\tconst field = this.config.badgeVariantField\n\t\t\tif (field && this.object[field]) {\n\t\t\t\treturn String(this.object[field])\n\t\t\t}\n\t\t\treturn this.config.badgeVariant || 'default'\n\t\t},\n\n\t\tbadgeColorMap() {\n\t\t\treturn this.config.badgeColorMap || null\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Row-body click: emits `select` when `selectable` (ignoring drags),\n\t\t * otherwise emits `click` for navigation.\n\t\t *\n\t\t * @param {MouseEvent} [event] The originating click event.\n\t\t */\n\t\tonRowClick(event) {\n\t\t\tif (this.selectable) {\n\t\t\t\tif (this.wasDrag(event)) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\t/**\n\t\t\t\t * @event select Emitted when a selectable row toggles selection (body or checkbox click).\n\t\t\t\t * @type {object} The row's object.\n\t\t\t\t */\n\t\t\t\tthis.$emit('select', this.object)\n\t\t\t\treturn\n\t\t\t}\n\t\t\t/**\n\t\t\t * @event click Emitted when a non-selectable row is clicked (navigation). Payload: `(object, event)` — the row's object and the native click event, for opening it in a new tab on a ctrl/cmd/shift click. A middle click emits `aux-click` instead.\n\t\t\t * @type {object} The row's object.\n\t\t\t */\n\t\t\tthis.$emit('click', this.object, event)\n\t\t},\n\n\t\t/**\n\t\t * Row mousedown: record the press for the drag guard, and on a\n\t\t * non-selectable row keep a middle press from starting autoscroll.\n\t\t *\n\t\t * @param {MouseEvent} event The mousedown event.\n\t\t */\n\t\tonRowMouseDown(event) {\n\t\t\tthis.onPointerDown(event)\n\t\t\tif (!this.selectable) {\n\t\t\t\tpreventMiddleClickAutoscroll(event)\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Row-body middle click on a non-selectable row: emits `aux-click`, not\n\t\t * `click`, so an existing `click` listener that navigates never moves\n\t\t * the current tab away.\n\t\t *\n\t\t * @param {MouseEvent} event The auxclick event.\n\t\t */\n\t\tonRowAuxClick(event) {\n\t\t\tif (this.selectable || !isRowMiddleClick(event)) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\t/**\n\t\t\t * @event aux-click Emitted when a non-selectable row is middle-clicked, for opening it in a new tab (see `openRowTarget`). Payload: `(object, event)` — the row's object and the native auxclick event.\n\t\t\t * @type {object} The row's object.\n\t\t\t */\n\t\t\tthis.$emit('aux-click', this.object, event)\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-object-row {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 12px;\n\tpadding: 8px 12px;\n\tborder-bottom: 1px solid var(--color-border);\n\tcursor: pointer;\n}\n\n.cn-object-row:hover {\n\tbackground-color: var(--color-background-hover);\n}\n\n.cn-object-row--selected {\n\t/* Inset accent — never border-left (would shift cell content). */\n\tbox-shadow: inset 3px 0 0 0 var(--color-primary-element);\n\tbackground-color: var(--color-primary-element-light);\n}\n\n.cn-object-row__checkbox {\n\tflex-shrink: 0;\n}\n\n.cn-object-row__icon {\n\tflex-shrink: 0;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 24px;\n\theight: 24px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-object-row__image {\n\twidth: 24px;\n\theight: 24px;\n\tobject-fit: contain;\n\tborder-radius: var(--border-radius);\n}\n\n.cn-object-row__main {\n\tdisplay: flex;\n\tflex-direction: column;\n\tmin-width: 0;\n\tflex: 1;\n}\n\n.cn-object-row__title {\n\tfont-weight: 600;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-object-row__subtitle {\n\tfont-size: 13px;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-object-row__badges {\n\tflex-shrink: 0;\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 6px;\n}\n\n.cn-object-row__actions {\n\tflex-shrink: 0;\n\tdisplay: flex;\n\talign-items: center;\n}\n</style>\n"],"names":["_createElementBlock","_normalizeClass","_createVNode","_openBlock","_renderSlot","_createBlock","_createElementVNode","_toDisplayString"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnObjectRow.vue3.js","sources":["../../../../src/components/CnObjectRow/CnObjectRow.vue?vue&type=template&id=6e2b35c2&lang.js"],"sourcesContent":["<template>\n\t<div\n\t\tclass=\"cn-object-row\"\n\t\t:class=\"{ 'cn-object-row--selected': selected }\"\n\t\t@mousedown=\"onRowMouseDown\"\n\t\t@click=\"onRowClick($event)\"\n\t\t@auxclick=\"onRowAuxClick($event)\">\n\t\t<!-- Selection checkbox -->\n\t\t<div v-if=\"selectable\"\n\t\t\tclass=\"cn-object-row__checkbox\"\n\t\t\t@click.stop\n\t\t\t@auxclick.stop>\n\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t:modelValue=\"selected\"\n\t\t\t\t@update:modelValue=\"$emit('select', object)\" />\n\t\t</div>\n\n\t\t<!-- `config.leading`: one cell before the title, as a table cell renders\n\t\t it (`{ key, widget?, widgetProps?, formatter? }`), e.g. the age\n\t\t \"6 dagen\" in the team queue. -->\n\t\t<span\n\t\t\tv-if=\"leadingCell\"\n\t\t\tclass=\"cn-object-row__lead\"\n\t\t\t:style=\"leadingCell.width ? { width: leadingCell.width } : null\"\n\t\t\tdata-testid=\"cn-object-row-lead\">\n\t\t\t<CnCellRenderer\n\t\t\t\t:value=\"cellValue(leadingCell)\"\n\t\t\t\t:formatter=\"leadingCell.formatter || null\"\n\t\t\t\t:widget=\"leadingCell.widget || null\"\n\t\t\t\t:widgetProps=\"leadingCell.widgetProps || undefined\"\n\t\t\t\t:row=\"object\" />\n\t\t</span>\n\n\t\t<!-- Leading icon / image — omitted entirely when nothing is configured\n\t\t (no image, no icon name, no slot). -->\n\t\t<span v-if=\"hasLeadingIcon\" class=\"cn-object-row__icon\">\n\t\t\t<!-- @slot icon Replace the leading icon/image. -->\n\t\t\t<!-- @binding {object} object The row's object. -->\n\t\t\t<slot name=\"icon\" :object=\"object\">\n\t\t\t\t<img\n\t\t\t\t\tv-if=\"imageUrl\"\n\t\t\t\t\t:src=\"imageUrl\"\n\t\t\t\t\talt=\"\"\n\t\t\t\t\twidth=\"24\"\n\t\t\t\t\theight=\"24\"\n\t\t\t\t\tclass=\"cn-object-row__image\">\n\t\t\t\t<CnIcon v-else-if=\"iconName\" :name=\"iconName\" :size=\"24\" />\n\t\t\t</slot>\n\t\t</span>\n\n\t\t<!-- Main: title + subtitle -->\n\t\t<span class=\"cn-object-row__main\">\n\t\t\t<span class=\"cn-object-row__title\">{{ title }}</span>\n\t\t\t<span v-if=\"subtitle\" class=\"cn-object-row__subtitle\">{{ subtitle }}</span>\n\t\t</span>\n\n\t\t<!-- Badges (default: config-driven status badge) -->\n\t\t<span v-if=\"$slots.badges || badgeLabel\" class=\"cn-object-row__badges\">\n\t\t\t<!-- @slot badges Replace the badge area (overrides the config-driven badge). -->\n\t\t\t<!-- @binding {object} object The row's object. -->\n\t\t\t<slot name=\"badges\" :object=\"object\">\n\t\t\t\t<CnStatusBadge\n\t\t\t\t\tv-if=\"badgeLabel\"\n\t\t\t\t\t:label=\"badgeLabel\"\n\t\t\t\t\t:variant=\"badgeVariant\"\n\t\t\t\t\t:colorMap=\"badgeColorMap\"\n\t\t\t\t\tsize=\"small\" />\n\t\t\t</slot>\n\t\t</span>\n\n\t\t<!-- `config.trailing`: cells after the badges, each in its own column\n\t\t (the case type badge, the due text). -->\n\t\t<span\n\t\t\tv-for=\"(cell, index) in trailingCells\"\n\t\t\t:key=\"cell.key + '-' + index\"\n\t\t\tclass=\"cn-object-row__trail\"\n\t\t\t:style=\"cell.width ? { width: cell.width } : null\"\n\t\t\tdata-testid=\"cn-object-row-trail\">\n\t\t\t<CnCellRenderer\n\t\t\t\t:value=\"cellValue(cell)\"\n\t\t\t\t:formatter=\"cell.formatter || null\"\n\t\t\t\t:widget=\"cell.widget || null\"\n\t\t\t\t:widgetProps=\"cell.widgetProps || undefined\"\n\t\t\t\t:row=\"object\" />\n\t\t</span>\n\n\t\t<!-- Trailing actions -->\n\t\t<span v-if=\"$slots.actions\"\n\t\t\tclass=\"cn-object-row__actions\"\n\t\t\t@click.stop\n\t\t\t@auxclick.stop>\n\t\t\t<!-- @slot actions Trailing actions (copy button, menu, …). -->\n\t\t\t<!-- @binding {object} object The row's object. -->\n\t\t\t<slot name=\"actions\" :object=\"object\" />\n\t\t</span>\n\t</div>\n</template>\n\n<script>\nimport { NcCheckboxRadioSwitch } from '@nextcloud/vue'\nimport { useClickDragGuard } from '../../composables/useClickDragGuard.js'\nimport { joinTemplateParts } from '../../utils/fillTemplate.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { resolveImageUrl } from '../../utils/resolveImageUrl.js'\nimport { isRowMiddleClick, preventMiddleClickAutoscroll } from '../../utils/rowAuxClick.js'\nimport { CnCellRenderer } from '../CnCellRenderer/index.js'\nimport { CnIcon } from '../CnIcon/index.js'\nimport { CnStatusBadge } from '../CnStatusBadge/index.js'\n\n/**\n * CnObjectRow — Compact single-line list row for object display.\n *\n * The list-mode counterpart to `CnObjectCard`: a leading icon (or image), a\n * name with an optional subtitle, an optional status badge, and a trailing\n * actions area. Which object fields map to each slot is resolved from the\n * `config` prop first, then from `schema.configuration` (so a schema that\n * already declares `objectNameField` / `objectDescriptionField` / `objectImageField`\n * works with zero extra config).\n *\n * ```vue\n * <CnObjectRow\n * :object=\"secret\"\n * :schema=\"secretSchema\"\n * :config=\"{ subtitleField: 'url', iconName: 'Key' }\">\n * <template #actions=\"{ object }\">\n * <NcButton @click=\"copy(object)\">Copy</NcButton>\n * </template>\n * </CnObjectRow>\n * ```\n */\nexport default {\n\tname: 'CnObjectRow',\n\n\tcomponents: {\n\t\tNcCheckboxRadioSwitch,\n\t\tCnCellRenderer,\n\t\tCnIcon,\n\t\tCnStatusBadge,\n\t},\n\n\tprops: {\n\t\t/** The object data */\n\t\tobject: {\n\t\t\ttype: Object,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Schema definition; `schema.configuration` supplies field defaults */\n\t\tschema: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Explicit field mapping. Every key is optional and overrides the\n\t\t * schema-configuration default.\n\t\t *\n\t\t * `subtitleTemplate` fills `{field}` tokens from the row (empty parts and\n\t\t * their separators drop). `leading` (one cell) and `trailing` (a cell or\n\t\t * a list) draw cells as a table column does, `{ key, widget?,\n\t\t * widgetProps?, formatter? }`: `{ key: \"createdAt\", widget: \"age\" }`\n\t\t * reads \"6 dagen\", `{ key: \"deadline\", widget: \"date\", widgetProps: {\n\t\t * due: {} } }` the due text. A cell's `width` (CSS) lines the column\n\t\t * up across rows.\n\t\t *\n\t\t * @type {{ titleField?: string, subtitleField?: string, subtitleTemplate?: string, imageField?: string, iconField?: string, iconName?: string, badgeField?: string, badgeVariantField?: string, badgeVariant?: string, badgeColorMap?: object, leading?: object, trailing?: (object|Array<object>) }}\n\t\t */\n\t\tconfig: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** Whether this row is selected */\n\t\tselected: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Whether to show the selection checkbox */\n\t\tselectable: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\t},\n\n\t// Vue 2 had a separate listener channel, so a consumer's `@click` only ever\n\t// saw `$emit('click')`. In Vue 3 an UNDECLARED event name stays a\n\t// fallthrough attribute: `onClick` lands on the root `<div>` as a native\n\t// handler, so the consumer's handler fires once from the DOM click and\n\t// again from `$emit('click', object)` — twice per click, with different\n\t// payloads. Declaring the names here removes them from `$attrs`, which is\n\t// also what stops VTU v2 recording the native DOM event into `emitted()`.\n\temits: ['select', 'click', 'aux-click'],\n\n\tsetup() {\n\t\t// Tell a deliberate row click apart from a text-selection drag.\n\t\treturn useClickDragGuard()\n\t},\n\n\tcomputed: {\n\t\t/** Schema-level configuration block (empty when no schema). */\n\t\tschemaConfig() {\n\t\t\treturn this.schema?.configuration || {}\n\t\t},\n\n\t\ttitle() {\n\t\t\tconst field = this.config.titleField || this.schemaConfig.objectNameField\n\t\t\tif (field && this.object[field] !== null && this.object[field] !== undefined) {\n\t\t\t\treturn String(this.object[field])\n\t\t\t}\n\t\t\treturn this.object.title || this.object.name || this.object.id || '—'\n\t\t},\n\n\t\tsubtitle() {\n\t\t\tif (typeof this.config.subtitleTemplate === 'string' && this.config.subtitleTemplate !== '') {\n\t\t\t\tconst text = joinTemplateParts(this.config.subtitleTemplate, (key) => {\n\t\t\t\t\tconst value = readPath(this.object, key)\n\t\t\t\t\treturn value === null || value === undefined ? '' : String(value)\n\t\t\t\t})\n\t\t\t\treturn text.trim() || null\n\t\t\t}\n\t\t\tconst field = this.config.subtitleField || this.schemaConfig.objectDescriptionField\n\t\t\tif (field && this.object[field] !== null && this.object[field] !== undefined && this.object[field] !== '') {\n\t\t\t\treturn String(this.object[field])\n\t\t\t}\n\t\t\treturn null\n\t\t},\n\n\t\timageUrl() {\n\t\t\tconst field = this.config.imageField || this.schemaConfig.objectImageField\n\t\t\tif (field && this.object[field]) {\n\t\t\t\treturn resolveImageUrl(String(this.object[field]))\n\t\t\t}\n\t\t\treturn null\n\t\t},\n\n\t\ticonName() {\n\t\t\tconst field = this.config.iconField\n\t\t\tif (field && this.object[field]) {\n\t\t\t\treturn String(this.object[field])\n\t\t\t}\n\t\t\treturn this.config.iconName || ''\n\t\t},\n\n\t\t/** Whether to render the leading icon column at all. */\n\t\thasLeadingIcon() {\n\t\t\treturn Boolean(this.imageUrl || this.iconName || this.$slots.icon)\n\t\t},\n\n\t\tbadgeLabel() {\n\t\t\tconst field = this.config.badgeField\n\t\t\tif (field && this.object[field] !== null && this.object[field] !== undefined && this.object[field] !== '') {\n\t\t\t\treturn String(this.object[field])\n\t\t\t}\n\t\t\treturn null\n\t\t},\n\n\t\tbadgeVariant() {\n\t\t\tconst field = this.config.badgeVariantField\n\t\t\tif (field && this.object[field]) {\n\t\t\t\treturn String(this.object[field])\n\t\t\t}\n\t\t\treturn this.config.badgeVariant || 'default'\n\t\t},\n\n\t\tbadgeColorMap() {\n\t\t\treturn this.config.badgeColorMap || null\n\t\t},\n\n\t\t/**\n\t\t * The `config.leading` cell, or null.\n\t\t *\n\t\t * @spec openspec/changes/index-row-list-cells/specs/object-row/spec.md#requirement-a-list-row-can-carry-leading-and-trailing-cells\n\t\t * @return {object|null}\n\t\t */\n\t\tleadingCell() {\n\t\t\tconst cell = this.config.leading\n\t\t\treturn cell && typeof cell === 'object' && typeof cell.key === 'string' && cell.key !== '' ? cell : null\n\t\t},\n\n\t\t/**\n\t\t * The `config.trailing` cells (one object or a list), those with a key.\n\t\t *\n\t\t * @spec openspec/changes/index-row-list-cells/specs/object-row/spec.md#requirement-a-list-row-can-carry-leading-and-trailing-cells\n\t\t * @return {Array<object>}\n\t\t */\n\t\ttrailingCells() {\n\t\t\tconst cells = this.config.trailing\n\t\t\tconst list = Array.isArray(cells) ? cells : (cells && typeof cells === 'object' ? [cells] : [])\n\t\t\treturn list.filter((cell) => cell && typeof cell === 'object' && typeof cell.key === 'string' && cell.key !== '')\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * A cell's value: the dot-path `key` read off the row.\n\t\t *\n\t\t * @param {{key: string}} cell The cell.\n\t\t * @return {unknown} The value.\n\t\t */\n\t\tcellValue(cell) {\n\t\t\treturn readPath(this.object, cell.key)\n\t\t},\n\n\t\t/**\n\t\t * Row-body click: emits `select` when `selectable` (ignoring drags),\n\t\t * otherwise emits `click` for navigation.\n\t\t *\n\t\t * @param {MouseEvent} [event] The originating click event.\n\t\t */\n\t\tonRowClick(event) {\n\t\t\tif (this.selectable) {\n\t\t\t\tif (this.wasDrag(event)) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\t/**\n\t\t\t\t * @event select Emitted when a selectable row toggles selection (body or checkbox click).\n\t\t\t\t * @type {object} The row's object.\n\t\t\t\t */\n\t\t\t\tthis.$emit('select', this.object)\n\t\t\t\treturn\n\t\t\t}\n\t\t\t/**\n\t\t\t * @event click Emitted when a non-selectable row is clicked (navigation). Payload: `(object, event)` — the row's object and the native click event, for opening it in a new tab on a ctrl/cmd/shift click. A middle click emits `aux-click` instead.\n\t\t\t * @type {object} The row's object.\n\t\t\t */\n\t\t\tthis.$emit('click', this.object, event)\n\t\t},\n\n\t\t/**\n\t\t * Row mousedown: record the press for the drag guard, and on a\n\t\t * non-selectable row keep a middle press from starting autoscroll.\n\t\t *\n\t\t * @param {MouseEvent} event The mousedown event.\n\t\t */\n\t\tonRowMouseDown(event) {\n\t\t\tthis.onPointerDown(event)\n\t\t\tif (!this.selectable) {\n\t\t\t\tpreventMiddleClickAutoscroll(event)\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Row-body middle click on a non-selectable row: emits `aux-click`, not\n\t\t * `click`, so an existing `click` listener that navigates never moves\n\t\t * the current tab away.\n\t\t *\n\t\t * @param {MouseEvent} event The auxclick event.\n\t\t */\n\t\tonRowAuxClick(event) {\n\t\t\tif (this.selectable || !isRowMiddleClick(event)) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\t/**\n\t\t\t * @event aux-click Emitted when a non-selectable row is middle-clicked, for opening it in a new tab (see `openRowTarget`). Payload: `(object, event)` — the row's object and the native auxclick event.\n\t\t\t * @type {object} The row's object.\n\t\t\t */\n\t\t\tthis.$emit('aux-click', this.object, event)\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-object-row {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 12px;\n\tpadding: 8px 12px;\n\tborder-bottom: 1px solid var(--color-border);\n\tcursor: pointer;\n}\n\n.cn-object-row:hover {\n\tbackground-color: var(--color-background-hover);\n}\n\n.cn-object-row--selected {\n\t/* Inset accent — never border-left (would shift cell content). */\n\tbox-shadow: inset 3px 0 0 0 var(--color-primary-element);\n\tbackground-color: var(--color-primary-element-light);\n}\n\n.cn-object-row__lead,\n.cn-object-row__trail {\n\tflex: 0 0 auto;\n\tmin-width: 0;\n}\n\n.cn-object-row__lead {\n\tfont-weight: 600;\n}\n\n.cn-object-row__checkbox {\n\tflex-shrink: 0;\n}\n\n.cn-object-row__icon {\n\tflex-shrink: 0;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 24px;\n\theight: 24px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-object-row__image {\n\twidth: 24px;\n\theight: 24px;\n\tobject-fit: contain;\n\tborder-radius: var(--border-radius);\n}\n\n.cn-object-row__main {\n\tdisplay: flex;\n\tflex-direction: column;\n\tmin-width: 0;\n\tflex: 1;\n}\n\n.cn-object-row__title {\n\tfont-weight: 600;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-object-row__subtitle {\n\tfont-size: 13px;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-object-row__badges {\n\tflex-shrink: 0;\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 6px;\n}\n\n.cn-object-row__actions {\n\tflex-shrink: 0;\n\tdisplay: flex;\n\talign-items: center;\n}\n</style>\n"],"names":["_createElementBlock","_normalizeClass","_createVNode","_openBlock","_renderSlot","_createBlock","_createElementVNode","_toDisplayString","_Fragment","_renderList"],"mappings":";;;;AAmC8B,EAAA,KAAK,EAAC,qBAAqB;;;AAgBjD,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,qBAAqB,GAAA;AAC1B,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,sBAAsB,GAAA;;;AACZ,EAAA,KAAK,EAAC,yBAAyB;;;;AAIb,EAAA,KAAK,EAAC,uBAAuB;;;;;;;;;uBAxDvEA,kBA8FK,CAAA,KAAA,EAAA;IA7FJ,KAAK,EAAAC,cAAA,CAAA,CAAC,eAAc,EAAA,EAAA,yBAAA,EACiB;AACpC,IAAA,WAAS,0CAAE,QAAc,CAAA,cAAA,IAAA,QAAA,CAAA,cAAA,CAAA,GAAA,IAAA,CAAA,CAAA,CAAA;IACzB,OAAK,EAAA,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAA,MAAA,KAAE,QAAU,CAAA,UAAA,CAAC,MAAM,CAAA,CAAA,CAAA;IACxB,UAAQ,EAAA,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAA,MAAA,KAAE,QAAa,CAAA,aAAA,CAAC,MAAM,CAAA,CAAA,CAAA;;KAEpB,MAAU,CAAA,UAAA;sBAArBD,kBAOK,CAAA,KAAA,EAAA;;AANJ,UAAA,KAAK,EAAC,yBAAwB;AAC7B,UAAA,OAAK,0CAAN,MAAU,EAAA,EAAA,CAAA,MAAA,CAAA,CAAA,CAAA;AACT,UAAA,UAAQ,0CAAT,MAAc,EAAA,EAAA,CAAA,MAAA,CAAA,CAAA,CAAA;;UACdE,WAE+C,CAAA,gCAAA,EAAA;AAD7C,YAAA,UAAU,EAAE,MAAQ,CAAA,QAAA;YACpB,qBAAiB,EAAA,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAA,MAAA,KAAE,IAAK,CAAA,KAAA,CAAA,QAAA,EAAW,MAAM,CAAA,MAAA,CAAA,CAAA,CAAA;;;;KAOrC,QAAW,CAAA,WAAA;sBADlBF,kBAWM,CAAA,MAAA,EAAA;;AATL,UAAA,KAAK,EAAC,qBAAoB;AACzB,UAAA,KAAK,iBAAE,QAAW,CAAA,WAAA,CAAC,KAAM,GAAW,EAAA,KAAA,EAAA,QAAA,CAAA,WAAW,CAAC,KAAM,EAAA,GAAA,IAAA,CAAA;AACvD,UAAA,aAAW,EAAC,oBAAoB;;UAChCE,WAKgB,CAAA,yBAAA,EAAA;YAJd,KAAK,EAAE,QAAS,CAAA,SAAA,CAAC,QAAW,CAAA,WAAA,CAAA;YAC5B,SAAS,EAAE,QAAW,CAAA,WAAA,CAAC,SAAU,IAAA,IAAA;YACjC,MAAM,EAAE,QAAW,CAAA,WAAA,CAAC,MAAK,IAAA,IAAA;AACzB,YAAA,WAAW,EAAE,QAAA,CAAA,WAAW,CAAC,eAAe,SAAS;AACjD,YAAA,GAAG,EAAE,MAAM,CAAA,MAAA;;;;KAKF,QAAc,CAAA,cAAA;AAA1B,SAAAC,SAAA,EAAA,EAAAH,kBAAA,CAaM,QAbN,UAaM,EAAA;AAVL,UAAAI,UAAA,CASM,IATa,CAAA,MAAA,EAAA,MAAA,EAAA,EAAA,MAAM,EAAE,MAAA,CAAA,MAAM,IAAjC,MASM;aAPE,QAAQ,CAAA,QAAA;8BADfJ,kBAM6B,CAAA,KAAA,EAAA;;AAJ3B,kBAAA,GAAG,EAAE,QAAQ,CAAA,QAAA;AACd,kBAAA,GAAG,EAAC,EAAC;AACL,kBAAA,KAAK,EAAC,IAAG;AACT,kBAAA,MAAM,EAAC,IAAG;AACV,kBAAA,KAAK,EAAC,sBAAsB;;iBACV,QAAQ,CAAA,QAAA;gCAA3BK,WAA0D,CAAA,iBAAA,EAAA;;AAA5B,oBAAA,IAAI,EAAE,QAAQ,CAAA,QAAA;AAAG,oBAAA,IAAI,EAAE,EAAE;;;;;;AAKzD,IAAAC,kBAAA,CAGM,QAHN,UAGM,EAAA;MAFLA,kBAAoD,CAAA,MAAA,EAApD,UAAoD,EAAAC,eAAA,CAAd;OAC1B,QAAQ,CAAA,QAAA;wBAApBP,kBAA0E,CAAA,MAAA,EAA1E,UAA0E,EAAAO,eAAA,CAAjB,QAAO,CAAA,QAAA,CAAA,EAAA,CAAA,YAAA;;;KAIrD,IAAM,CAAA,MAAA,CAAC,MAAK,IAAK,QAAU,CAAA,UAAA;AAAvC,SAAAJ,SAAA,EAAA,EAAAH,kBAAA,CAWM,QAXN,UAWM,EAAA;AARL,UAAAI,UAAA,CAOM,IAPe,CAAA,MAAA,EAAA,QAAA,EAAA,EAAA,MAAM,EAAE,MAAA,CAAA,MAAM,IAAnC,MAOM;aALE,QAAU,CAAA,UAAA;8BADjBC,WAKe,CAAA,wBAAA,EAAA;;AAHb,kBAAA,KAAK,EAAE,QAAU,CAAA,UAAA;AACjB,kBAAA,OAAO,EAAE,QAAY,CAAA,YAAA;AACrB,kBAAA,QAAQ,EAAE,QAAa,CAAA,aAAA;AACxB,kBAAA,IAAI,EAAC,OAAM;;;;;;AAMd,KAAAF,SAAA,CAAA,IAAA,CAAA,EAAAH,kBAAA,CAYMQ,QAXmB,EAAA,IAAA,EAAAC,UAAA,CAAA,QAAA,CAAA,aAAa,EAA7B,CAAA,IAAI,EAAE,KAAK,KAAA;2BADpBT,kBAYM,CAAA,MAAA,EAAA;AAVJ,QAAA,GAAG,EAAE,IAAI,CAAC,GAAI,SAAQ,KAAK;AAC5B,QAAA,KAAK,EAAC,sBAAqB;AAC1B,QAAA,KAAK,iBAAE,IAAI,CAAC,KAAI,GAAa,EAAA,KAAA,EAAA,IAAI,CAAC,KAAM,EAAA,GAAA,IAAA,CAAA;AACzC,QAAA,aAAW,EAAC,qBAAqB;;QACjCE,WAKgB,CAAA,yBAAA,EAAA;UAJd,KAAK,EAAE,QAAS,CAAA,SAAA,CAAC,IAAI,CAAA;UACrB,SAAS,EAAE,IAAI,CAAC,SAAQ,IAAA,IAAA;UACxB,MAAM,EAAE,IAAI,CAAC,MAAK,IAAA,IAAA;AAClB,UAAA,WAAW,EAAE,IAAI,CAAC,WAAY,IAAG,SAAS;AAC1C,UAAA,GAAG,EAAE,MAAM,CAAA,MAAA;;;;AAIF,IAAA,CAAA,IAAA,CAAA,MAAM,CAAC,OAAO;sBAA1BF,kBAOM,CAAA,MAAA,EAAA;;AANL,UAAA,KAAK,EAAC,wBAAuB;AAC5B,UAAA,OAAK,0CAAN,MAAU,EAAA,EAAA,CAAA,MAAA,CAAA,CAAA,CAAA;AACT,UAAA,UAAQ,0CAAT,MAAc,EAAA,EAAA,CAAA,MAAA,CAAA,CAAA,CAAA;;UAGdI,UAAuC,CAAA,IAAA,CAAA,MAAA,EAAA,SAAA,EAAA,EAAjB,MAAM,EAAE,MAAM,CAAA,MAAA,EAAA,CAAA;;;;;;;;"}
|
|
@@ -2,7 +2,7 @@ import script from './CnRecordListWidget.vue2.js';
|
|
|
2
2
|
import { render } from './CnRecordListWidget.vue3.js';
|
|
3
3
|
|
|
4
4
|
script.render = render;
|
|
5
|
-
script.__scopeId = "data-v-
|
|
5
|
+
script.__scopeId = "data-v-7d1cc1e6";
|
|
6
6
|
const __sfc_main = script;
|
|
7
7
|
|
|
8
8
|
export { __sfc_main as default };
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { subscribe, unsubscribe } from '@nextcloud/event-bus';
|
|
2
2
|
import { translate } from '@nextcloud/l10n';
|
|
3
|
-
import { NcLoadingIcon } from '@nextcloud/vue';
|
|
3
|
+
import { NcButton, NcLoadingIcon } from '@nextcloud/vue';
|
|
4
4
|
import { inject, ref } from 'vue';
|
|
5
5
|
import ChevronRight from 'vue-material-design-icons/ChevronRight.vue';
|
|
6
6
|
import __sfc_main from '../CnIcon/CnIcon.vue.js';
|
|
7
7
|
import __sfc_main$1 from '../CnStatusBadge/CnStatusBadge.vue.js';
|
|
8
8
|
import { useEndpointSource } from '../../composables/useEndpointSource.js';
|
|
9
|
-
import { interpolateActionTarget, actionLink
|
|
9
|
+
import { dispatchAction, interpolateActionTarget, actionLink } from '../../utils/actionsDispatcher.js';
|
|
10
10
|
import { isBadgeVariant } from '../../utils/badgeVariants.js';
|
|
11
11
|
import { ageInDays } from '../../utils/boardDate.js';
|
|
12
12
|
import { resolveDue } from '../../utils/dueText.js';
|
|
@@ -17,8 +17,12 @@ import { lensUnavailableText, readLensReports } from '../../utils/lensAvailabili
|
|
|
17
17
|
import { pageFilter, pageSort } from '../../utils/pageControls.js';
|
|
18
18
|
import { readPath } from '../../utils/readPath.js';
|
|
19
19
|
import { dropOptionalUnresolved, resolveFilterTokens, hasUnresolvedTokens } from '../../utils/resolveFilterTokens.js';
|
|
20
|
+
import { evaluateVisibleWhen } from '../../utils/visibleWhen.js';
|
|
20
21
|
|
|
21
22
|
const PAGE_REFRESH_CHANNEL = 'cn:page:refresh';
|
|
23
|
+
|
|
24
|
+
/** Gives each list's footer reason its own element id. */
|
|
25
|
+
let footerSeq = 0;
|
|
22
26
|
const PRESENTATIONS = ['rows', 'feed', 'inline', 'cards', 'notice'];
|
|
23
27
|
|
|
24
28
|
/** The tones a `notice` list takes. */
|
|
@@ -72,7 +76,7 @@ function unwrap(value) {
|
|
|
72
76
|
var script = {
|
|
73
77
|
name: 'CnRecordListWidget',
|
|
74
78
|
|
|
75
|
-
components: { ChevronRight, CnIcon: __sfc_main, CnStatusBadge: __sfc_main$1, NcLoadingIcon },
|
|
79
|
+
components: { ChevronRight, CnIcon: __sfc_main, CnStatusBadge: __sfc_main$1, NcButton, NcLoadingIcon },
|
|
76
80
|
|
|
77
81
|
inject: {
|
|
78
82
|
/** Detail-page object context (`{ objectId, object, register, schema }`). */
|
|
@@ -107,6 +111,10 @@ var script = {
|
|
|
107
111
|
* `presentation: "notice"` draws the rows as sentences in one box toned by
|
|
108
112
|
* `variant` (`info`, `warning` or `error`), after an optional `lead`
|
|
109
113
|
* (`{total}` filled in).
|
|
114
|
+
* `footerAction` (`{ label, icon?, type, ..., disabledWhen?,
|
|
115
|
+
* disabledReason? }`) ends the card with one action, also under the
|
|
116
|
+
* empty text; while the visibleWhen condition `disabledWhen` holds the
|
|
117
|
+
* button is disabled and `disabledReason` shows under it.
|
|
110
118
|
*
|
|
111
119
|
* @type {object}
|
|
112
120
|
*/
|
|
@@ -160,10 +168,48 @@ var script = {
|
|
|
160
168
|
error: false,
|
|
161
169
|
/** Personal-lens reports (`@self.lenses`) of the latest response. */
|
|
162
170
|
lenses: {},
|
|
171
|
+
/** Whether `footerAction.disabledWhen` holds. */
|
|
172
|
+
footerDisabled: false,
|
|
173
|
+
footerReasonId: `cn-record-list-footer-reason-${++footerSeq}`,
|
|
163
174
|
}
|
|
164
175
|
},
|
|
165
176
|
|
|
166
177
|
computed: {
|
|
178
|
+
/**
|
|
179
|
+
* The action under the list (`footerAction`: `{ label, icon?, type,
|
|
180
|
+
* ..., disabledWhen?, disabledReason? }`), labels through the host
|
|
181
|
+
* translate, or null without a label.
|
|
182
|
+
*
|
|
183
|
+
* @spec openspec/changes/record-list-footer-action/specs/record-list/spec.md#requirement-a-record-list-can-end-with-an-action-that-says-why-it-is-disabled
|
|
184
|
+
* @return {{label: string, icon: string, reason: string, action: object}|null}
|
|
185
|
+
*/
|
|
186
|
+
footerAction() {
|
|
187
|
+
const action = this.content?.footerAction;
|
|
188
|
+
if (!action || typeof action !== 'object' || typeof action.label !== 'string' || action.label === '') {
|
|
189
|
+
return null
|
|
190
|
+
}
|
|
191
|
+
return {
|
|
192
|
+
label: this.translate(action.label),
|
|
193
|
+
icon: typeof action.icon === 'string' ? action.icon : '',
|
|
194
|
+
reason: typeof action.disabledReason === 'string' && action.disabledReason !== '' ? this.translate(action.disabledReason) : '',
|
|
195
|
+
action,
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* What `footerAction.disabledWhen` depends on, so it is evaluated again
|
|
201
|
+
* when the condition, the record or the workspace changes.
|
|
202
|
+
*
|
|
203
|
+
* @return {string}
|
|
204
|
+
*/
|
|
205
|
+
footerDisabledKey() {
|
|
206
|
+
const cond = this.content?.footerAction?.disabledWhen;
|
|
207
|
+
if (!cond) {
|
|
208
|
+
return ''
|
|
209
|
+
}
|
|
210
|
+
return JSON.stringify({ cond, object: this.tokenCtx.object, workspace: this.tokenCtx.workspace, total: this.total })
|
|
211
|
+
},
|
|
212
|
+
|
|
167
213
|
/** @return {string} `rows`, `feed`, `inline` or `cards`. */
|
|
168
214
|
/**
|
|
169
215
|
* The tone of a `notice` list (`content.variant`): info, warning or error.
|
|
@@ -388,6 +434,13 @@ var script = {
|
|
|
388
434
|
this.fetchRows();
|
|
389
435
|
},
|
|
390
436
|
|
|
437
|
+
footerDisabledKey: {
|
|
438
|
+
immediate: true,
|
|
439
|
+
handler() {
|
|
440
|
+
this.evaluateFooterDisabled();
|
|
441
|
+
},
|
|
442
|
+
},
|
|
443
|
+
|
|
391
444
|
endpointKey() {
|
|
392
445
|
this.fetchRows();
|
|
393
446
|
},
|
|
@@ -414,6 +467,47 @@ var script = {
|
|
|
414
467
|
return typeof this.cnTranslate === 'function' ? this.cnTranslate(text) : text
|
|
415
468
|
},
|
|
416
469
|
|
|
470
|
+
/**
|
|
471
|
+
* Settle whether the footer action is disabled: `disabledWhen` is a
|
|
472
|
+
* visibleWhen condition read against the page's record (`field`), the
|
|
473
|
+
* workspace, an endpoint or a source; `total` is the list's total.
|
|
474
|
+
*
|
|
475
|
+
* @spec openspec/changes/record-list-footer-action/specs/record-list/spec.md#requirement-a-record-list-can-end-with-an-action-that-says-why-it-is-disabled
|
|
476
|
+
* @return {Promise<void>}
|
|
477
|
+
*/
|
|
478
|
+
async evaluateFooterDisabled() {
|
|
479
|
+
const cond = this.content?.footerAction?.disabledWhen;
|
|
480
|
+
if (!cond) {
|
|
481
|
+
this.footerDisabled = false;
|
|
482
|
+
return
|
|
483
|
+
}
|
|
484
|
+
const ctx = { ...this.tokenCtx, object: { ...(this.tokenCtx.object || {}), total: this.total } };
|
|
485
|
+
const key = this.footerDisabledKey;
|
|
486
|
+
const disabled = await evaluateVisibleWhen(cond, ctx);
|
|
487
|
+
if (key === this.footerDisabledKey) {
|
|
488
|
+
this.footerDisabled = disabled;
|
|
489
|
+
}
|
|
490
|
+
},
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* Run the footer action through the page's dispatcher, with the page's
|
|
494
|
+
* record as the token context.
|
|
495
|
+
*
|
|
496
|
+
* @spec openspec/changes/record-list-footer-action/specs/record-list/spec.md#requirement-a-record-list-can-end-with-an-action-that-says-why-it-is-disabled
|
|
497
|
+
* @return {unknown} What the dispatcher returns.
|
|
498
|
+
*/
|
|
499
|
+
runFooterAction() {
|
|
500
|
+
const declared = this.footerAction?.action;
|
|
501
|
+
if (!declared || this.footerDisabled) {
|
|
502
|
+
return undefined
|
|
503
|
+
}
|
|
504
|
+
const { disabledWhen, disabledReason, ...action } = declared;
|
|
505
|
+
if (typeof this.cnDispatchAction === 'function') {
|
|
506
|
+
return this.cnDispatchAction(action)
|
|
507
|
+
}
|
|
508
|
+
return dispatchAction(action, { router: this.$router || null, tokenCtx: this.tokenCtx, source: { register: this.content?.register, schema: this.content?.schema } })
|
|
509
|
+
},
|
|
510
|
+
|
|
417
511
|
/**
|
|
418
512
|
* A row's `bar`: its value, the maximum it is measured against (the
|
|
419
513
|
* row's `maxField`, else the largest row), the filled share and
|