@conduction/nextcloud-vue 2.84.0 → 2.85.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/CnAdminSettingsShell/CnAdminSettingsShell.vue.js +1 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js +131 -3
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js.map +1 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js +54 -18
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js.map +1 -1
- package/dist/esm/components/CnBoardView/CnBoardView.vue.js +1 -1
- package/dist/esm/components/CnBoardView/CnBoardView.vue2.js +232 -4
- package/dist/esm/components/CnBoardView/CnBoardView.vue2.js.map +1 -1
- package/dist/esm/components/CnBoardView/CnBoardView.vue3.js +95 -51
- package/dist/esm/components/CnBoardView/CnBoardView.vue3.js.map +1 -1
- package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue.js +1 -1
- package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue2.js +114 -0
- package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue3.js +2 -2
- package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue3.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue.js +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +45 -0
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +22 -12
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +23 -4
- 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/CnDetailWidgetHost/CnDetailWidgetHost.vue.js +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js +3 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js.map +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue.js +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js +18 -5
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +548 -77
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +191 -82
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/useSelfFetchList.js +11 -2
- package/dist/esm/components/CnIndexPage/useSelfFetchList.js.map +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue.js +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js +95 -0
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js +24 -2
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +70 -2
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue.js +1 -1
- package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue2.js +67 -5
- package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue2.js.map +1 -1
- package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue3.js +181 -124
- package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue3.js.map +1 -1
- package/dist/esm/components/CnSettingsPage/CnSettingsPage.vue.js +1 -1
- package/dist/esm/components/CnSettingsPage/CnSettingsPage.vue2.js +5 -1
- package/dist/esm/components/CnSettingsPage/CnSettingsPage.vue2.js.map +1 -1
- package/dist/esm/components/CnSettingsPage/CnSettingsPage.vue3.js.map +1 -1
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue.js +1 -1
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js +134 -10
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js +6 -2
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue.js +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +6 -3
- 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/CnToggleTableWidget/CnToggleTableWidget.vue.js +1 -1
- package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue2.js +140 -7
- package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue.js +1 -1
- package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue2.js +37 -9
- package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue2.js.map +1 -1
- package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue3.js +6 -5
- package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue3.js.map +1 -1
- package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue.js +1 -1
- package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue2.js +2 -1
- package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnWidgetCardGrid/CnWidgetCardGrid.vue2.js +53 -1
- package/dist/esm/components/CnWidgetCardGrid/CnWidgetCardGrid.vue2.js.map +1 -1
- package/dist/esm/components/CnWidgetCardGrid/CnWidgetCardGrid.vue3.js +3 -2
- package/dist/esm/components/CnWidgetCardGrid/CnWidgetCardGrid.vue3.js.map +1 -1
- package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue.js +1 -1
- package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue2.js +135 -0
- 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/CnWidgetWrapper/CnWidgetWrapper.vue.js +1 -1
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue2.js +19 -0
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue2.js.map +1 -1
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue3.js +37 -19
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue3.js.map +1 -1
- package/dist/esm/composables/useListView.js +21 -0
- package/dist/esm/composables/useListView.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 +23 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +41 -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 +742 -397
- package/dist/esm/store/useObjectStore.js +16 -2
- package/dist/esm/store/useObjectStore.js.map +1 -1
- package/dist/esm/utils/boardColumns.js +8 -1
- package/dist/esm/utils/boardColumns.js.map +1 -1
- package/dist/esm/utils/boardReferenceColumns.js +278 -0
- package/dist/esm/utils/boardReferenceColumns.js.map +1 -0
- package/dist/esm/utils/buildManifest.js +4 -1
- package/dist/esm/utils/buildManifest.js.map +1 -1
- package/dist/esm/utils/gridStack.js +40 -1
- package/dist/esm/utils/gridStack.js.map +1 -1
- package/dist/esm/utils/humaniseKey.js +41 -0
- package/dist/esm/utils/humaniseKey.js.map +1 -0
- package/dist/esm/utils/notificationRuleLabel.js +6 -23
- package/dist/esm/utils/notificationRuleLabel.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/esm/utils/widgetDispatch.js +8 -2
- package/dist/esm/utils/widgetDispatch.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +15075 -12590
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +742 -397
- package/l10n/en.json +23 -1
- package/l10n/nl.json +41 -1
- package/package.json +1 -1
- package/src/components/CnAdminSettingsShell/CnAdminSettingsShell.vue +160 -8
- package/src/components/CnBoardView/CnBoardView.vue +262 -6
- package/src/components/CnDashboardGrid/CnDashboardGrid.vue +116 -2
- package/src/components/CnDashboardPage/CnDashboardPage.vue +57 -2
- package/src/components/CnDetailPage/CnDetailPage.md +1 -1
- package/src/components/CnDetailPage/CnDetailPage.vue +23 -4
- package/src/components/CnDetailWidgetHost/CnDetailWidgetHost.vue +3 -1
- package/src/components/CnFactsWidget/CnFactsWidget.vue +18 -5
- package/src/components/CnIndexPage/CnIndexPage.vue +586 -25
- package/src/components/CnIndexPage/useSelfFetchList.js +10 -1
- package/src/components/CnObjectDataWidget/CnObjectDataWidget.vue +123 -3
- package/src/components/CnRecordListWidget/CnRecordListWidget.vue +70 -2
- package/src/components/CnRegisterMapping/CnRegisterMapping.md +5 -0
- package/src/components/CnRegisterMapping/CnRegisterMapping.vue +231 -96
- package/src/components/CnSettingsPage/CnSettingsPage.vue +5 -1
- package/src/components/CnStatWidget/CnStatWidget.vue +136 -11
- package/src/components/CnTabsWidget/CnTabsWidget.vue +6 -3
- package/src/components/CnToggleTableWidget/CnToggleTableWidget.vue +140 -7
- package/src/components/CnVersionInfoCard/CnVersionInfoCard.md +2 -1
- package/src/components/CnVersionInfoCard/CnVersionInfoCard.vue +42 -13
- package/src/components/CnWeekStripWidget/CnWeekStripWidget.vue +2 -1
- package/src/components/CnWidgetCardGrid/CnWidgetCardGrid.vue +55 -2
- package/src/components/CnWidgetObjectTable/CnWidgetObjectTable.vue +135 -0
- package/src/components/CnWidgetWrapper/CnWidgetWrapper.md +10 -0
- package/src/components/CnWidgetWrapper/CnWidgetWrapper.vue +44 -1
- package/src/composables/useListView.js +21 -0
- package/src/css/board.css +65 -4
- package/src/css/dialog.css +4 -2
- package/src/css/index-page.css +49 -0
- package/src/css/kpi-card.css +13 -0
- package/src/css/look-board.css +96 -7
- package/src/index.js +2 -0
- package/src/schemas/app-manifest-v2.schema.json +115 -5
- package/src/store/useObjectStore.js +16 -2
- package/src/utils/boardColumns.js +8 -1
- package/src/utils/boardReferenceColumns.js +274 -0
- package/src/utils/buildManifest.js +4 -1
- package/src/utils/gridStack.js +39 -0
- package/src/utils/humaniseKey.js +38 -0
- package/src/utils/notificationRuleLabel.js +5 -23
- package/src/utils/validateManifestV2.compiled.js +3 -3
- package/src/utils/widgetDispatch.js +8 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnToggleTableWidget.vue2.js","sources":["../../../../src/components/CnToggleTableWidget/CnToggleTableWidget.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<div class=\"cn-toggle-table\" data-testid=\"cn-toggle-table\">\n\t\t<p v-if=\"rows.length === 0\" class=\"cn-toggle-table__empty\" data-testid=\"cn-toggle-table-empty\">\n\t\t\t{{ emptyLabel }}\n\t\t</p>\n\t\t<table v-else class=\"cn-toggle-table__table\">\n\t\t\t<thead v-if=\"showHeader\">\n\t\t\t\t<tr>\n\t\t\t\t\t<th scope=\"col\" class=\"cn-toggle-table__head\">\n\t\t\t\t\t\t{{ titleHeader }}\n\t\t\t\t\t</th>\n\t\t\t\t\t<th\n\t\t\t\t\t\tv-for=\"column in columns\"\n\t\t\t\t\t\t:key=\"column.path\"\n\t\t\t\t\t\tscope=\"col\"\n\t\t\t\t\t\tclass=\"cn-toggle-table__head\">\n\t\t\t\t\t\t{{ column.header }}\n\t\t\t\t\t</th>\n\t\t\t\t\t<th scope=\"col\" class=\"cn-toggle-table__head cn-toggle-table__head--toggle\">\n\t\t\t\t\t\t{{ toggleHeader }}\n\t\t\t\t\t</th>\n\t\t\t\t</tr>\n\t\t\t</thead>\n\t\t\t<tbody>\n\t\t\t\t<tr\n\t\t\t\t\tv-for=\"row in rows\"\n\t\t\t\t\t:key=\"row.key\"\n\t\t\t\t\tclass=\"cn-toggle-table__row\"\n\t\t\t\t\t:data-testid=\"`cn-toggle-table-row-${row.key}`\">\n\t\t\t\t\t<td class=\"cn-toggle-table__cell cn-toggle-table__cell--main\">\n\t\t\t\t\t\t<span class=\"cn-toggle-table__title\">{{ row.title }}</span>\n\t\t\t\t\t\t<span v-if=\"row.hint\" class=\"cn-toggle-table__hint\">{{ row.hint }}</span>\n\t\t\t\t\t</td>\n\t\t\t\t\t<td\n\t\t\t\t\t\tv-for=\"column in columns\"\n\t\t\t\t\t\t:key=\"column.path\"\n\t\t\t\t\t\tclass=\"cn-toggle-table__cell\">\n\t\t\t\t\t\t{{ cell(row, column) }}\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"cn-toggle-table__cell cn-toggle-table__cell--toggle\">\n\t\t\t\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t\t\t\t:key=\"`${row.key}-${undone[row.key] || 0}`\"\n\t\t\t\t\t\t\t:modelValue=\"isOn(row)\"\n\t\t\t\t\t\t\ttype=\"switch\"\n\t\t\t\t\t\t\t:disabled=\"readOnly || busy === row.key\"\n\t\t\t\t\t\t\t:aria-label=\"row.title\"\n\t\t\t\t\t\t\t@update:modelValue=\"toggle(row, $event)\" />\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t</tbody>\n\t\t</table>\n\t\t<NcNoteCard v-if=\"notice\" type=\"error\" data-testid=\"cn-toggle-table-notice\">\n\t\t\t{{ notice }}\n\t\t</NcNoteCard>\n\t</div>\n</template>\n\n<script>\nimport { NcCheckboxRadioSwitch, NcNoteCard } from '@nextcloud/vue'\nimport { prefixUrl } from '../../utils/headers.js'\nimport { objectUrlOf, writeFields } from '../../utils/objectWrite.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { serverErrorMessage } from '../../utils/serverErrorMessage.js'\n\n/**\n * CnToggleTableWidget — the `toggle-table` widget: rows from a configured list\n * (`rows`) or read from a source (`source`), each with a switch bound to the\n * CURRENT object, and optional extra columns read off the row. A switch is\n * stored in one of two ways:\n *\n * - `bind.mode: 'flag'` — each row names its own boolean field of the object\n * (`row.field`); the switch is that field.\n * - `bind.mode: 'list'` — ONE array field of the object (`bind.field`) holds\n * the keys of the rows that are in it; the switch is on when the row's key is\n * in the list, or NOT in it with `bind.invert` (a list of hidden items shown\n * as \"visible\" switches).\n *\n * A toggle saves at once with ONE PATCH of that field; a refused PATCH puts the\n * switch back and shows the server's words.\n *\n * @spec openspec/changes/abstract-toggle-table/specs/toggle-table/spec.md\n */\nexport default {\n\tname: 'CnToggleTableWidget',\n\n\tcomponents: { NcCheckboxRadioSwitch, NcNoteCard },\n\n\tinject: {\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The widget configuration.\n\t\t *\n\t\t * - `bind` — `{ mode: 'flag' }` (default) or `{ mode: 'list', field, invert? }`.\n\t\t * - `rows` — static rows `[{ key, label, hint?, field?, ...extra }]`.\n\t\t * - `source` — `{ url, path?, key, label, hint? }`: rows read from an endpoint (tokens `@objectId`, `@object.<field>`), in addition to `rows`.\n\t\t * - `columns` — extra columns `[{ header, path, map? }]` read off each row.\n\t\t * - `titleHeader`, `toggleHeader`, `emptyText`, `readOnly`.\n\t\t * - `save` — `{ url, method?, payload? }`, write through an app endpoint (tokens `{value}`, `{field}`, `{changes}`, `{object.<path>}`).\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** The current detail-page object. */\n\t\tobjectData: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** The current object id. */\n\t\tobjectId: {\n\t\t\ttype: [String, Number],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** OpenRegister register slug of the surface. */\n\t\tregister: {\n\t\t\ttype: [String, Object],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** OpenRegister schema slug of the surface. */\n\t\tschema: {\n\t\t\ttype: [String, Object],\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\temits: ['saved'],\n\n\tdata() {\n\t\treturn {\n\t\t\t/** Rows read from `source`. */\n\t\t\tsourced: [],\n\t\t\t/** What the object holds, by field: the flags and the list, as last saved. */\n\t\t\tsaved: {},\n\t\t\tbusy: '',\n\t\t\tnotice: '',\n\t\t\t/** Per row, how often a refused toggle forced the switch to be drawn again from the stored value. */\n\t\t\tundone: {},\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tbind() {\n\t\t\tconst bind = this.content.bind || {}\n\t\t\treturn bind.mode === 'list' ? { mode: 'list', field: bind.field, invert: bind.invert === true } : { mode: 'flag' }\n\t\t},\n\n\t\t/** The drawn rows: configured first, then sourced, each with a key, title and hint. */\n\t\trows() {\n\t\t\tconst configured = (Array.isArray(this.content.rows) ? this.content.rows : [])\n\t\t\t\t.filter((row) => row && row.key !== undefined)\n\t\t\t\t.map((row) => ({ ...row, key: String(row.key), title: this.tr(row.label || String(row.key)), hint: this.tr(row.hint || '') }))\n\t\t\treturn [...configured, ...this.sourced]\n\t\t},\n\n\t\tcolumns() {\n\t\t\treturn (Array.isArray(this.content.columns) ? this.content.columns : [])\n\t\t\t\t.filter((column) => column && column.path)\n\t\t\t\t.map((column) => ({ ...column, header: this.tr(column.header || '') }))\n\t\t},\n\n\t\tshowHeader() {\n\t\t\treturn this.columns.length > 0 || Boolean(this.content.titleHeader || this.content.toggleHeader)\n\t\t},\n\n\t\ttitleHeader() {\n\t\t\treturn this.tr(this.content.titleHeader || '')\n\t\t},\n\n\t\ttoggleHeader() {\n\t\t\treturn this.tr(this.content.toggleHeader || '')\n\t\t},\n\n\t\temptyLabel() {\n\t\t\treturn this.tr(this.content.emptyText || 'Nothing listed yet')\n\t\t},\n\n\t\treadOnly() {\n\t\t\treturn this.content.readOnly === true\n\t\t},\n\n\t\tobjectUrl() {\n\t\t\treturn objectUrlOf(this.register, this.schema, this.objectId || (this.objectData && this.objectData.id))\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectData() {\n\t\t\tthis.saved = {}\n\t\t\tthis.loadSource()\n\t\t},\n\t},\n\n\tcreated() {\n\t\tthis.loadSource()\n\t},\n\n\tmethods: {\n\t\ttr(text) {\n\t\t\tif (typeof text !== 'string' || text === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn typeof this.cnTranslate === 'function' ? this.cnTranslate(text) : text\n\t\t},\n\n\t\t/**\n\t\t * The stored value of a field: what this widget last saved, else the object's.\n\t\t *\n\t\t * @param {string} field The field.\n\t\t * @return {unknown}\n\t\t */\n\t\tstored(field) {\n\t\t\treturn Object.hasOwn(this.saved, field) ? this.saved[field] : readPath(this.objectData || {}, field)\n\t\t},\n\n\t\t/**\n\t\t * Whether a row's switch is on.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @return {boolean}\n\t\t */\n\t\tisOn(row) {\n\t\t\tif (this.bind.mode === 'list') {\n\t\t\t\tconst list = this.stored(this.bind.field)\n\t\t\t\tconst inList = Array.isArray(list) && list.map(String).includes(row.key)\n\t\t\t\treturn this.bind.invert ? !inList : inList\n\t\t\t}\n\t\t\treturn row.field ? this.stored(row.field) === true : false\n\t\t},\n\n\t\t/**\n\t\t * The text of an extra column for a row.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @param {object} column The column.\n\t\t * @return {string}\n\t\t */\n\t\tcell(row, column) {\n\t\t\tconst raw = readPath(row, column.path)\n\t\t\tif (raw === undefined || raw === null || raw === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tif (column.map && Object.hasOwn(column.map, String(raw))) {\n\t\t\t\treturn this.tr(column.map[String(raw)])\n\t\t\t}\n\t\t\treturn typeof raw === 'object' ? '' : String(raw)\n\t\t},\n\n\t\t/** Read the rows of `source`, resolving tokens in its url. */\n\t\tasync loadSource() {\n\t\t\tconst source = this.content.source\n\t\t\tif (!source || !source.url || !source.key) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst object = this.objectData || {}\n\t\t\tconst url = String(source.url)\n\t\t\t\t.replace(/@objectId/g, () => encodeURIComponent(String(this.objectId || object.id || '')))\n\t\t\t\t.replace(/@object\\.([\\w.@]+)/g, (m, path) => encodeURIComponent(String(readPath(object, path) ?? '')))\n\t\t\ttry {\n\t\t\t\tconst { default: axios } = await import('@nextcloud/axios')\n\t\t\t\tconst { data } = await axios.get(prefixUrl(url))\n\t\t\t\tconst list = source.path ? readPath(data, source.path) : data\n\t\t\t\tthis.sourced = (Array.isArray(list) ? list : [])\n\t\t\t\t\t.filter((item) => item && readPath(item, source.key) !== undefined)\n\t\t\t\t\t.map((item) => ({\n\t\t\t\t\t\t...item,\n\t\t\t\t\t\tkey: String(readPath(item, source.key)),\n\t\t\t\t\t\ttitle: String(readPath(item, source.label || source.key) ?? readPath(item, source.key)),\n\t\t\t\t\t\thint: source.hint ? String(readPath(item, source.hint) ?? '') : '',\n\t\t\t\t\t}))\n\t\t\t} catch (e) {\n\t\t\t\tthis.notice = serverErrorMessage(e)\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Flip one switch and save that one field.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @param {boolean} on The new switch state.\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/abstract-toggle-table/specs/toggle-table/spec.md#requirement-a-toggle-saves-one-field\n\t\t */\n\t\tasync toggle(row, on) {\n\t\t\tconst field = this.bind.mode === 'list' ? this.bind.field : row.field\n\t\t\tif ((!this.objectUrl && !(this.content.save && this.content.save.url)) || !field) {\n\t\t\t\tthis.notice = this.tr('This switch cannot be saved here.')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tlet next\n\t\t\tif (this.bind.mode === 'list') {\n\t\t\t\tconst list = (Array.isArray(this.stored(field)) ? this.stored(field) : []).map(String)\n\t\t\t\tconst wantInList = this.bind.invert ? !on : on\n\t\t\t\tnext = wantInList ? (list.includes(row.key) ? list : [...list, row.key]) : list.filter((key) => key !== row.key)\n\t\t\t} else {\n\t\t\t\tnext = on\n\t\t\t}\n\t\t\tthis.notice = ''\n\t\t\tthis.busy = row.key\n\t\t\ttry {\n\t\t\t\tconst data = await writeFields(this.objectUrl, { [field]: next }, { save: this.content.save, object: this.objectData })\n\t\t\t\tconst answered = readPath(data, field)\n\t\t\t\tconst written = answered !== undefined ? answered : next\n\t\t\t\tthis.saved = { ...this.saved, [field]: written }\n\t\t\t\t/**\n\t\t\t\t * @event saved A switch was written.\n\t\t\t\t * @type {{field: string, value: unknown}}\n\t\t\t\t */\n\t\t\t\tthis.$emit('saved', { field, value: written })\n\t\t\t} catch (e) {\n\t\t\t\tthis.notice = serverErrorMessage(e)\n\t\t\t\tthis.undone = { ...this.undone, [row.key]: (this.undone[row.key] || 0) + 1 }\n\t\t\t} finally {\n\t\t\t\tthis.busy = ''\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-toggle-table {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 8px;\n\tmin-width: 0;\n}\n\n.cn-toggle-table__table {\n\twidth: 100%;\n\tborder-collapse: collapse;\n}\n\n.cn-toggle-table__head {\n\tpadding: 8px 12px;\n\ttext-align: start;\n\tfont-size: 13px;\n\tfont-weight: 600;\n\tcolor: var(--color-text-maxcontrast);\n\tbackground: var(--color-background-hover);\n}\n\n.cn-toggle-table__head--toggle,\n.cn-toggle-table__cell--toggle {\n\twidth: 1%;\n\twhite-space: nowrap;\n\ttext-align: end;\n}\n\n.cn-toggle-table__row {\n\tborder-top: 1px solid var(--cn-board-hairline, var(--color-border));\n}\n\n.cn-toggle-table__cell {\n\tpadding: 10px 12px;\n\tvertical-align: middle;\n\toverflow-wrap: anywhere;\n}\n\n.cn-toggle-table__title {\n\tdisplay: block;\n\tfont-weight: 600;\n}\n\n.cn-toggle-table__hint {\n\tdisplay: block;\n\tfont-size: 12px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-toggle-table__empty {\n\tmargin: 0;\n\tcolor: var(--color-text-maxcontrast);\n}\n</style>\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnToggleTableWidget.vue2.js","sources":["../../../../src/components/CnToggleTableWidget/CnToggleTableWidget.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<div class=\"cn-toggle-table\" data-testid=\"cn-toggle-table\">\n\t\t<p v-if=\"rows.length === 0\" class=\"cn-toggle-table__empty\" data-testid=\"cn-toggle-table-empty\">\n\t\t\t{{ emptyLabel }}\n\t\t</p>\n\t\t<table v-else class=\"cn-toggle-table__table\">\n\t\t\t<thead v-if=\"showHeader\">\n\t\t\t\t<tr>\n\t\t\t\t\t<th scope=\"col\" class=\"cn-toggle-table__head\">\n\t\t\t\t\t\t{{ titleHeader }}\n\t\t\t\t\t</th>\n\t\t\t\t\t<th\n\t\t\t\t\t\tv-for=\"column in columns\"\n\t\t\t\t\t\t:key=\"column.path\"\n\t\t\t\t\t\tscope=\"col\"\n\t\t\t\t\t\tclass=\"cn-toggle-table__head\">\n\t\t\t\t\t\t{{ column.header }}\n\t\t\t\t\t</th>\n\t\t\t\t\t<th scope=\"col\" class=\"cn-toggle-table__head cn-toggle-table__head--toggle\">\n\t\t\t\t\t\t{{ toggleHeader }}\n\t\t\t\t\t</th>\n\t\t\t\t</tr>\n\t\t\t</thead>\n\t\t\t<tbody>\n\t\t\t\t<tr\n\t\t\t\t\tv-for=\"row in rows\"\n\t\t\t\t\t:key=\"row.key\"\n\t\t\t\t\tclass=\"cn-toggle-table__row\"\n\t\t\t\t\t:data-testid=\"`cn-toggle-table-row-${row.key}`\">\n\t\t\t\t\t<td class=\"cn-toggle-table__cell cn-toggle-table__cell--main\">\n\t\t\t\t\t\t<span class=\"cn-toggle-table__title\">{{ row.title }}</span>\n\t\t\t\t\t\t<span v-if=\"row.hint\" class=\"cn-toggle-table__hint\">{{ row.hint }}</span>\n\t\t\t\t\t</td>\n\t\t\t\t\t<td\n\t\t\t\t\t\tv-for=\"column in columns\"\n\t\t\t\t\t\t:key=\"column.path\"\n\t\t\t\t\t\tclass=\"cn-toggle-table__cell\">\n\t\t\t\t\t\t{{ cell(row, column) }}\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"cn-toggle-table__cell cn-toggle-table__cell--toggle\">\n\t\t\t\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t\t\t\t:key=\"`${row.key}-${undone[row.key] || 0}`\"\n\t\t\t\t\t\t\t:modelValue=\"isOn(row)\"\n\t\t\t\t\t\t\ttype=\"switch\"\n\t\t\t\t\t\t\t:disabled=\"readOnly || busy === row.key\"\n\t\t\t\t\t\t\t:aria-label=\"row.title\"\n\t\t\t\t\t\t\t@update:modelValue=\"toggle(row, $event)\" />\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t</tbody>\n\t\t</table>\n\t\t<NcNoteCard v-if=\"notice\" type=\"error\" data-testid=\"cn-toggle-table-notice\">\n\t\t\t{{ notice }}\n\t\t</NcNoteCard>\n\t</div>\n</template>\n\n<script>\nimport { NcCheckboxRadioSwitch, NcNoteCard } from '@nextcloud/vue'\nimport { prefixUrl } from '../../utils/headers.js'\nimport { objectUrlOf, writeFields } from '../../utils/objectWrite.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { serverErrorMessage } from '../../utils/serverErrorMessage.js'\n\n/**\n * CnToggleTableWidget — the `toggle-table` widget: rows from a configured list\n * (`rows`) or read from a source (`source`), each with a switch bound to the\n * CURRENT object, and optional extra columns read off the row. A switch is\n * stored in one of two ways:\n *\n * - `bind.mode: 'flag'` — each row names its own boolean field of the object\n * (`row.field`); the switch is that field.\n * - `bind.mode: 'list'` — ONE array field of the object (`bind.field`) holds\n * the keys of the rows that are in it; the switch is on when the row's key is\n * in the list, or NOT in it with `bind.invert` (a list of hidden items shown\n * as \"visible\" switches).\n * - `bind.mode: 'each'` — every row IS an object (read by `source`, its key the\n * object id); the switch is that object's own boolean field (`bind.field`)\n * and a toggle PATCHes that object (`bind.register` / `bind.schema`, else the\n * surface's). No current object is needed, so it serves a settings page.\n * - `bind.mode: 'map'` — a config map holds a boolean per row key: read from\n * `bind.url` (at `bind.path`) and written through `save`, or one object field\n * of the current object (`bind.field`) written by its dot-path.\n *\n * A toggle saves at once with ONE PATCH of that field; a refused PATCH puts the\n * switch back and shows the server's words.\n *\n * @spec openspec/changes/abstract-toggle-table/specs/toggle-table/spec.md\n */\nexport default {\n\tname: 'CnToggleTableWidget',\n\n\tcomponents: { NcCheckboxRadioSwitch, NcNoteCard },\n\n\tinject: {\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The widget configuration.\n\t\t *\n\t\t * - `bind` — `{ mode: 'flag' }` (default), `{ mode: 'list', field, invert? }`, `{ mode: 'each', field, register?, schema?, invert? }` or `{ mode: 'map', url?, path?, field?, invert? }`.\n\t\t * - `rows` — static rows `[{ key, label, hint?, field?, ...extra }]`.\n\t\t * - `source` — `{ url, path?, key, label, hint? }`: rows read from an endpoint (tokens `@objectId`, `@object.<field>`), in addition to `rows`.\n\t\t * - `columns` — extra columns `[{ header, path, map? }]` read off each row.\n\t\t * - `titleHeader`, `toggleHeader`, `emptyText`, `readOnly`.\n\t\t * - `save` — `{ url, method?, payload? }`, write through an app endpoint (tokens `{value}`, `{field}`, `{changes}`, `{object.<path>}`).\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** The current detail-page object. */\n\t\tobjectData: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** The current object id. */\n\t\tobjectId: {\n\t\t\ttype: [String, Number],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** OpenRegister register slug of the surface. */\n\t\tregister: {\n\t\t\ttype: [String, Object],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** OpenRegister schema slug of the surface. */\n\t\tschema: {\n\t\t\ttype: [String, Object],\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\temits: ['saved'],\n\n\tdata() {\n\t\treturn {\n\t\t\t/** Rows read from `source`. */\n\t\t\tsourced: [],\n\t\t\t/** What the object holds, by field: the flags and the list, as last saved. */\n\t\t\tsaved: {},\n\t\t\tbusy: '',\n\t\t\tnotice: '',\n\t\t\t/** Per row, how often a refused toggle forced the switch to be drawn again from the stored value. */\n\t\t\tundone: {},\n\t\t\t/** `each` and `map`: the value written per row key. */\n\t\t\trowSaved: {},\n\t\t\t/** `map` with `bind.url`: the map as read. */\n\t\t\tmap: null,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * How a switch is stored.\n\t\t *\n\t\t * @return {object} The normalised `bind`.\n\t\t * @spec openspec/changes/toggle-table-objects-and-map/specs/toggle-table/spec.md#requirement-a-toggle-table-can-switch-objects-or-a-config-map\n\t\t */\n\t\tbind() {\n\t\t\tconst bind = this.content.bind || {}\n\t\t\tconst invert = bind.invert === true\n\t\t\tif (bind.mode === 'list') {\n\t\t\t\treturn { mode: 'list', field: bind.field, invert }\n\t\t\t}\n\t\t\tif (bind.mode === 'each') {\n\t\t\t\treturn { mode: 'each', field: bind.field || '', invert, register: bind.register || this.register, schema: bind.schema || this.schema }\n\t\t\t}\n\t\t\tif (bind.mode === 'map') {\n\t\t\t\treturn { mode: 'map', field: bind.field || '', url: bind.url || '', path: bind.path || '', invert }\n\t\t\t}\n\t\t\treturn { mode: 'flag' }\n\t\t},\n\n\t\t/** The drawn rows: configured first, then sourced, each with a key, title and hint. */\n\t\trows() {\n\t\t\tconst configured = (Array.isArray(this.content.rows) ? this.content.rows : [])\n\t\t\t\t.filter((row) => row && row.key !== undefined)\n\t\t\t\t.map((row) => ({ ...row, key: String(row.key), title: this.tr(row.label || String(row.key)), hint: this.tr(row.hint || '') }))\n\t\t\treturn [...configured, ...this.sourced]\n\t\t},\n\n\t\tcolumns() {\n\t\t\treturn (Array.isArray(this.content.columns) ? this.content.columns : [])\n\t\t\t\t.filter((column) => column && column.path)\n\t\t\t\t.map((column) => ({ ...column, header: this.tr(column.header || '') }))\n\t\t},\n\n\t\tshowHeader() {\n\t\t\treturn this.columns.length > 0 || Boolean(this.content.titleHeader || this.content.toggleHeader)\n\t\t},\n\n\t\ttitleHeader() {\n\t\t\treturn this.tr(this.content.titleHeader || '')\n\t\t},\n\n\t\ttoggleHeader() {\n\t\t\treturn this.tr(this.content.toggleHeader || '')\n\t\t},\n\n\t\temptyLabel() {\n\t\t\treturn this.tr(this.content.emptyText || 'Nothing listed yet')\n\t\t},\n\n\t\treadOnly() {\n\t\t\treturn this.content.readOnly === true\n\t\t},\n\n\t\tobjectUrl() {\n\t\t\treturn objectUrlOf(this.register, this.schema, this.objectId || (this.objectData && this.objectData.id))\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectData() {\n\t\t\tthis.saved = {}\n\t\t\tthis.rowSaved = {}\n\t\t\tthis.loadSource()\n\t\t\tthis.loadMap()\n\t\t},\n\t},\n\n\tcreated() {\n\t\tthis.loadSource()\n\t\tthis.loadMap()\n\t},\n\n\tmethods: {\n\t\ttr(text) {\n\t\t\tif (typeof text !== 'string' || text === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn typeof this.cnTranslate === 'function' ? this.cnTranslate(text) : text\n\t\t},\n\n\t\t/**\n\t\t * The stored value of a field: what this widget last saved, else the object's.\n\t\t *\n\t\t * @param {string} field The field.\n\t\t * @return {unknown}\n\t\t */\n\t\tstored(field) {\n\t\t\treturn Object.hasOwn(this.saved, field) ? this.saved[field] : readPath(this.objectData || {}, field)\n\t\t},\n\n\t\t/**\n\t\t * Whether a row's switch is on.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @return {boolean}\n\t\t */\n\t\tisOn(row) {\n\t\t\tif (this.bind.mode === 'each' || this.bind.mode === 'map') {\n\t\t\t\tconst on = this.rowValue(row) === true\n\t\t\t\treturn this.bind.invert ? !on : on\n\t\t\t}\n\t\t\tif (this.bind.mode === 'list') {\n\t\t\t\tconst list = this.stored(this.bind.field)\n\t\t\t\tconst inList = Array.isArray(list) && list.map(String).includes(row.key)\n\t\t\t\treturn this.bind.invert ? !inList : inList\n\t\t\t}\n\t\t\treturn row.field ? this.stored(row.field) === true : false\n\t\t},\n\n\t\t/**\n\t\t * `each` and `map`: the stored value of a row's switch, as last written,\n\t\t * else read off the row's object or the map.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @return {unknown}\n\t\t * @spec openspec/changes/toggle-table-objects-and-map/specs/toggle-table/spec.md#requirement-a-toggle-table-can-switch-objects-or-a-config-map\n\t\t */\n\t\trowValue(row) {\n\t\t\tif (Object.hasOwn(this.rowSaved, row.key)) {\n\t\t\t\treturn this.rowSaved[row.key]\n\t\t\t}\n\t\t\tif (this.bind.mode === 'each') {\n\t\t\t\treturn this.bind.field ? readPath(row.item || row, this.bind.field) : undefined\n\t\t\t}\n\t\t\tconst map = this.bind.url ? this.map : (this.bind.field ? this.stored(this.bind.field) : null)\n\t\t\treturn map && typeof map === 'object' ? map[row.key] : undefined\n\t\t},\n\n\t\t/**\n\t\t * Resolve `@objectId` and `@object.<path>` in a url.\n\t\t *\n\t\t * @param {string} url The url.\n\t\t * @return {string}\n\t\t */\n\t\tfillUrl(url) {\n\t\t\tconst object = this.objectData || {}\n\t\t\treturn String(url)\n\t\t\t\t.replace(/@objectId/g, () => encodeURIComponent(String(this.objectId || object.id || '')))\n\t\t\t\t.replace(/@object\\.([\\w.@]+)/g, (m, path) => encodeURIComponent(String(readPath(object, path) ?? '')))\n\t\t},\n\n\t\t/**\n\t\t * `map` with `bind.url`: read the map.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/toggle-table-objects-and-map/specs/toggle-table/spec.md#requirement-a-toggle-table-can-switch-objects-or-a-config-map\n\t\t */\n\t\tasync loadMap() {\n\t\t\tif (this.bind.mode !== 'map' || !this.bind.url) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst { default: axios } = await import('@nextcloud/axios')\n\t\t\t\tconst { data } = await axios.get(prefixUrl(this.fillUrl(this.bind.url)))\n\t\t\t\tconst map = this.bind.path ? readPath(data, this.bind.path) : data\n\t\t\t\tthis.map = map && typeof map === 'object' ? map : {}\n\t\t\t} catch (e) {\n\t\t\t\tthis.notice = serverErrorMessage(e)\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * `each` and `map`: write one row's switch.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @param {boolean} value The value to store.\n\t\t * @return {Promise<unknown>} The value the server holds now.\n\t\t * @spec openspec/changes/toggle-table-objects-and-map/specs/toggle-table/spec.md#requirement-a-toggle-table-can-switch-objects-or-a-config-map\n\t\t */\n\t\tasync writeRow(row, value) {\n\t\t\tconst save = this.content.save\n\t\t\tconst hasSave = Boolean(save && save.url)\n\t\t\tif (this.bind.mode === 'each') {\n\t\t\t\tconst url = objectUrlOf(this.bind.register, this.bind.schema, row.key)\n\t\t\t\tif ((!url && !hasSave) || !this.bind.field) {\n\t\t\t\t\tthrow new Error(this.tr('This switch cannot be saved here.'))\n\t\t\t\t}\n\t\t\t\tconst data = await writeFields(url, { [this.bind.field]: value }, { save, object: row.item || row })\n\t\t\t\tconst answered = hasSave ? undefined : readPath(data, this.bind.field)\n\t\t\t\treturn answered !== undefined ? answered : value\n\t\t\t}\n\t\t\tif (this.bind.url) {\n\t\t\t\tif (!hasSave) {\n\t\t\t\t\tthrow new Error(this.tr('This switch cannot be saved here.'))\n\t\t\t\t}\n\t\t\t\tawait writeFields('', { [row.key]: value }, { save, object: this.objectData })\n\t\t\t\treturn value\n\t\t\t}\n\t\t\tif ((!this.objectUrl && !hasSave) || !this.bind.field) {\n\t\t\t\tthrow new Error(this.tr('This switch cannot be saved here.'))\n\t\t\t}\n\t\t\tawait writeFields(this.objectUrl, { [`${this.bind.field}.${row.key}`]: value }, { save, object: this.objectData })\n\t\t\treturn value\n\t\t},\n\n\t\t/**\n\t\t * The text of an extra column for a row.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @param {object} column The column.\n\t\t * @return {string}\n\t\t */\n\t\tcell(row, column) {\n\t\t\tconst raw = readPath(row, column.path)\n\t\t\tif (raw === undefined || raw === null || raw === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tif (column.map && Object.hasOwn(column.map, String(raw))) {\n\t\t\t\treturn this.tr(column.map[String(raw)])\n\t\t\t}\n\t\t\treturn typeof raw === 'object' ? '' : String(raw)\n\t\t},\n\n\t\t/** Read the rows of `source`, resolving tokens in its url. */\n\t\tasync loadSource() {\n\t\t\tconst source = this.content.source\n\t\t\tif (!source || !source.url || !source.key) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst url = this.fillUrl(source.url)\n\t\t\ttry {\n\t\t\t\tconst { default: axios } = await import('@nextcloud/axios')\n\t\t\t\tconst { data } = await axios.get(prefixUrl(url))\n\t\t\t\tconst list = source.path ? readPath(data, source.path) : data\n\t\t\t\tthis.sourced = (Array.isArray(list) ? list : [])\n\t\t\t\t\t.filter((item) => item && readPath(item, source.key) !== undefined)\n\t\t\t\t\t.map((item) => ({\n\t\t\t\t\t\t...item,\n\t\t\t\t\t\titem,\n\t\t\t\t\t\tkey: String(readPath(item, source.key)),\n\t\t\t\t\t\ttitle: String(readPath(item, source.label || source.key) ?? readPath(item, source.key)),\n\t\t\t\t\t\thint: source.hint ? String(readPath(item, source.hint) ?? '') : '',\n\t\t\t\t\t}))\n\t\t\t} catch (e) {\n\t\t\t\tthis.notice = serverErrorMessage(e)\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Flip one switch and save that one field.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @param {boolean} on The new switch state.\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/abstract-toggle-table/specs/toggle-table/spec.md#requirement-a-toggle-saves-one-field\n\t\t */\n\t\tasync toggle(row, on) {\n\t\t\tif (this.bind.mode === 'each' || this.bind.mode === 'map') {\n\t\t\t\tthis.notice = ''\n\t\t\t\tthis.busy = row.key\n\t\t\t\ttry {\n\t\t\t\t\tconst written = await this.writeRow(row, this.bind.invert ? !on : on)\n\t\t\t\t\tthis.rowSaved = { ...this.rowSaved, [row.key]: written }\n\t\t\t\t\tthis.$emit('saved', { field: this.bind.mode === 'each' ? this.bind.field : row.key, key: row.key, value: written })\n\t\t\t\t} catch (e) {\n\t\t\t\t\tthis.notice = serverErrorMessage(e)\n\t\t\t\t\tthis.undone = { ...this.undone, [row.key]: (this.undone[row.key] || 0) + 1 }\n\t\t\t\t} finally {\n\t\t\t\t\tthis.busy = ''\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst field = this.bind.mode === 'list' ? this.bind.field : row.field\n\t\t\tif ((!this.objectUrl && !(this.content.save && this.content.save.url)) || !field) {\n\t\t\t\tthis.notice = this.tr('This switch cannot be saved here.')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tlet next\n\t\t\tif (this.bind.mode === 'list') {\n\t\t\t\tconst list = (Array.isArray(this.stored(field)) ? this.stored(field) : []).map(String)\n\t\t\t\tconst wantInList = this.bind.invert ? !on : on\n\t\t\t\tnext = wantInList ? (list.includes(row.key) ? list : [...list, row.key]) : list.filter((key) => key !== row.key)\n\t\t\t} else {\n\t\t\t\tnext = on\n\t\t\t}\n\t\t\tthis.notice = ''\n\t\t\tthis.busy = row.key\n\t\t\ttry {\n\t\t\t\tconst data = await writeFields(this.objectUrl, { [field]: next }, { save: this.content.save, object: this.objectData })\n\t\t\t\tconst answered = readPath(data, field)\n\t\t\t\tconst written = answered !== undefined ? answered : next\n\t\t\t\tthis.saved = { ...this.saved, [field]: written }\n\t\t\t\t/**\n\t\t\t\t * @event saved A switch was written.\n\t\t\t\t * @type {{field: string, key?: string, value: unknown}} `key` is the row, in the `each` and `map` modes.\n\t\t\t\t */\n\t\t\t\tthis.$emit('saved', { field, value: written })\n\t\t\t} catch (e) {\n\t\t\t\tthis.notice = serverErrorMessage(e)\n\t\t\t\tthis.undone = { ...this.undone, [row.key]: (this.undone[row.key] || 0) + 1 }\n\t\t\t} finally {\n\t\t\t\tthis.busy = ''\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-toggle-table {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 8px;\n\tmin-width: 0;\n}\n\n.cn-toggle-table__table {\n\twidth: 100%;\n\tborder-collapse: collapse;\n}\n\n.cn-toggle-table__head {\n\tpadding: 8px 12px;\n\ttext-align: start;\n\tfont-size: 13px;\n\tfont-weight: 600;\n\tcolor: var(--color-text-maxcontrast);\n\tbackground: var(--color-background-hover);\n}\n\n.cn-toggle-table__head--toggle,\n.cn-toggle-table__cell--toggle {\n\twidth: 1%;\n\twhite-space: nowrap;\n\ttext-align: end;\n}\n\n.cn-toggle-table__row {\n\tborder-top: 1px solid var(--cn-board-hairline, var(--color-border));\n}\n\n.cn-toggle-table__cell {\n\tpadding: 10px 12px;\n\tvertical-align: middle;\n\toverflow-wrap: anywhere;\n}\n\n.cn-toggle-table__title {\n\tdisplay: block;\n\tfont-weight: 600;\n}\n\n.cn-toggle-table__hint {\n\tdisplay: block;\n\tfont-size: 12px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-toggle-table__empty {\n\tmargin: 0;\n\tcolor: var(--color-text-maxcontrast);\n}\n</style>\n"],"names":[],"mappings":";;;;;;AAqEA;AACC;;;AAGA;AACA;;AAEA;AACA;;;AAGA;AACA;AACA;AACA;;;AAGA;;AAEA;AACA;AACA;AACA;AACA;;AAED,aAAe;CACd,IAAI,EAAE,qBAAqB;;AAE3B,CAAA,UAAU,EAAE,EAAE,qBAAqB,EAAE,YAAY;;AAEjD,CAAA,MAAM,EAAE;AACP,EAAA,WAAW,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,GAAG,KAAK,KAAK;EAC5C;;AAED,CAAA,KAAK,EAAE;AACN;;AAEC;AACA;;;;;;AAMA;;;AAGD,EAAA,OAAO,EAAE;GACR,IAAI,EAAE,MAAM;AACZ,GAAA,OAAO,EAAE,OAAO,EAAE,CAAC;GACnB;;AAED;EACA,UAAU,EAAE;GACX,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,IAAI;GACb;;;AAGD,EAAA,QAAQ,EAAE;AACT,GAAA,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC;GACtB,OAAO,EAAE,EAAE;GACX;;AAED;AACA,EAAA,QAAQ,EAAE;AACT,GAAA,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC;GACtB,OAAO,EAAE,EAAE;GACX;;AAED;AACA,EAAA,MAAM,EAAE;AACP,GAAA,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC;GACtB,OAAO,EAAE,EAAE;GACX;EACD;;AAED,CAAA,KAAK,EAAE,CAAC,OAAO,CAAC;;AAEhB,CAAA,IAAI,GAAG;AACN,EAAA,OAAO;;GAEN,OAAO,EAAE,EAAE;AACX;AACA,GAAA,KAAK,EAAE,EAAE;AACT,GAAA,IAAI,EAAE,EAAE;AACR,GAAA,MAAM,EAAE,EAAE;AACV;AACA,GAAA,MAAM,EAAE,EAAE;AACV;GACA,QAAQ,EAAE,EAAE;AACZ;AACA,GAAA,GAAG,EAAE,IAAI;AACV,GAAA;EACA;;AAED,CAAA,QAAQ,EAAE;AACT;AACC;AACA;AACA;AACA;;AAED,EAAA,IAAI,GAAG;AACN,GAAA,MAAM,IAAG,GAAI,IAAI,CAAC,OAAO,CAAC,IAAG,IAAK,GAAC;GACnC,MAAM,MAAO,GAAE,IAAI,CAAC,MAAO,KAAI,KAAG;GAClC,IAAI,IAAI,CAAC,SAAS,MAAM,EAAE;AACzB,IAAA,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,MAAO,EAAA;AAClD,IAAA;GACA,IAAI,IAAI,CAAC,SAAS,MAAM,EAAE;IACzB,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,KAAI,IAAK,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAS,IAAG,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,UAAU,IAAI,CAAC,MAAO,EAAA;AACtI,IAAA;AACA,GAAA,IAAI,IAAI,CAAC,IAAK,KAAI,KAAK,EAAE;AACxB,IAAA,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,KAAI,IAAK,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,GAAI,IAAG,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAK,IAAG,EAAE,EAAE,MAAO,EAAA;AACnG,IAAA;AACA,GAAA,OAAO,EAAE,IAAI,EAAE,MAAO,EAAA;GACtB;;AAED;AACA,EAAA,IAAI,GAAG;AACN,GAAA,MAAM,aAAa,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAE,GAAE,IAAI,CAAC,OAAO,CAAC,IAAK,GAAE,EAAE;AAC5E,KAAC,MAAM,CAAC,CAAC,GAAG,KAAK,GAAI,IAAG,GAAG,CAAC,QAAQ,SAAS,CAAA;KAC5C,GAAG,CAAC,CAAC,GAAG,MAAM,EAAE,GAAG,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAM,IAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAG,IAAK,EAAE,CAAE,EAAC,CAAC,EAAA;AAC9H,GAAA,OAAO,CAAC,GAAG,UAAU,EAAE,GAAG,IAAI,CAAC,OAAO,CAAA;GACtC;;AAED,EAAA,OAAO,GAAG;AACT,GAAA,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAE,GAAE,IAAI,CAAC,OAAO,CAAC,OAAQ,GAAE,EAAE;AACtE,KAAC,MAAM,CAAC,CAAC,MAAM,KAAK,MAAO,IAAG,MAAM,CAAC,IAAI,CAAA;AACzC,KAAC,GAAG,CAAC,CAAC,MAAM,MAAM,EAAE,GAAG,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,MAAK,IAAK,EAAE,CAAE,EAAC,CAAC,CAAA;GACvE;;EAED,UAAU,GAAG;AACZ,GAAA,OAAO,IAAI,CAAC,OAAO,CAAC,MAAO,GAAE,KAAK,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,eAAe,IAAI,CAAC,OAAO,CAAC,YAAY,CAAA;GAC/F;;EAED,WAAW,GAAG;AACb,GAAA,OAAO,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,CAAA;GAC7C;;AAED,EAAA,YAAY,GAAG;AACd,GAAA,OAAO,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAA;GAC9C;;EAED,UAAU,GAAG;GACZ,OAAO,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,oBAAoB,CAAA;GAC7D;;EAED,QAAQ,GAAG;AACV,GAAA,OAAO,IAAI,CAAC,OAAO,CAAC,QAAO,KAAM,IAAG;GACpC;;EAED,SAAS,GAAG;GACX,OAAO,WAAW,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,QAAO,KAAM,IAAI,CAAC,UAAS,IAAK,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,CAAA;GACvG;EACD;;AAED,CAAA,KAAK,EAAE;EACN,UAAU,GAAG;GACZ,IAAI,CAAC,KAAM,GAAE,GAAC;AACd,GAAA,IAAI,CAAC,QAAO,GAAI,GAAC;AACjB,GAAA,IAAI,CAAC,UAAU,GAAC;GAChB,IAAI,CAAC,OAAO,GAAC;GACb;EACD;;AAED,CAAA,OAAO,GAAG;AACT,EAAA,IAAI,CAAC,UAAU,GAAC;EAChB,IAAI,CAAC,OAAO,GAAC;EACb;;AAED,CAAA,OAAO,EAAE;AACR,EAAA,EAAE,CAAC,IAAI,EAAE;AACR,GAAA,IAAI,OAAO,IAAG,KAAM,QAAO,IAAK,SAAS,EAAE,EAAE;AAC5C,IAAA,OAAO,EAAC;AACT,IAAA;AACA,GAAA,OAAO,OAAO,IAAI,CAAC,WAAY,KAAI,UAAW,GAAE,IAAI,CAAC,WAAW,CAAC,IAAI,CAAA,GAAI,IAAG;GAC5E;;AAED;AACC;AACA;;AAEA;;EAED,MAAM,CAAC,KAAK,EAAE;AACb,GAAA,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,CAAE,GAAE,QAAQ,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,KAAK,CAAA;GACnG;;AAED;;AAEC;;AAEA;;AAED,EAAA,IAAI,CAAC,GAAG,EAAE;GACT,IAAI,IAAI,CAAC,IAAI,CAAC,IAAK,KAAI,UAAU,IAAI,CAAC,IAAI,CAAC,IAAK,KAAI,KAAK,EAAE;AAC1D,IAAA,MAAM,EAAC,GAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAA,KAAM,KAAG;IACrC,OAAO,IAAI,CAAC,IAAI,CAAC,MAAO,GAAE,CAAC,EAAG,GAAE,EAAC;AAClC,IAAA;GACA,IAAI,IAAI,CAAC,IAAI,CAAC,IAAK,KAAI,MAAM,EAAE;AAC9B,IAAA,MAAM,IAAK,GAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAA;AACxC,IAAA,MAAM,MAAK,GAAI,KAAK,CAAC,OAAO,CAAC,IAAI,KAAK,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAA;AACvE,IAAA,OAAO,IAAI,CAAC,IAAI,CAAC,MAAK,GAAI,CAAC,SAAS,MAAK;AAC1C,IAAA;GACA,OAAO,GAAG,CAAC,KAAI,GAAI,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAA,KAAM,OAAO,KAAI;GACzD;;AAED;;AAEC;AACA;;AAEA;AACA;;EAED,QAAQ,CAAC,GAAG,EAAE;AACb,GAAA,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,GAAG,CAAC,EAAE;IAC1C,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAA;AAC7B,IAAA;GACA,IAAI,IAAI,CAAC,IAAI,CAAC,IAAK,KAAI,MAAM,EAAE;AAC9B,IAAA,OAAO,IAAI,CAAC,IAAI,CAAC,KAAI,GAAI,QAAQ,CAAC,GAAG,CAAC,IAAG,IAAK,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAE,GAAE,SAAQ;AAC/E,IAAA;AACA,GAAA,MAAM,GAAI,GAAE,IAAI,CAAC,IAAI,CAAC,GAAE,GAAI,IAAI,CAAC,GAAI,IAAG,IAAI,CAAC,IAAI,CAAC,KAAI,GAAI,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAA,GAAI,IAAI,EAAA;GAC7F,OAAO,GAAI,IAAG,OAAO,QAAQ,QAAO,GAAI,GAAG,CAAC,GAAG,CAAC,GAAG,CAAE,GAAE,SAAQ;GAC/D;;AAED;AACC;AACA;;AAEA;;EAED,OAAO,CAAC,GAAG,EAAE;AACZ,GAAA,MAAM,MAAK,GAAI,IAAI,CAAC,UAAS,IAAK,GAAC;AACnC,GAAA,OAAO,MAAM,CAAC,GAAG,CAAA;AAChB,KAAC,OAAO,CAAC,YAAY,EAAE,MAAM,kBAAkB,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,MAAM,CAAC,EAAG,IAAG,EAAE,CAAC,CAAC,CAAA;KACxF,OAAO,CAAC,qBAAqB,EAAE,CAAC,CAAC,EAAE,IAAI,KAAK,kBAAkB,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAE,IAAG,EAAE,CAAC,CAAC,CAAA;GACtG;;AAED;AACC;AACA;;AAEA;;AAED,EAAA,MAAM,OAAO,GAAG;AACf,GAAA,IAAI,IAAI,CAAC,IAAI,CAAC,IAAK,KAAI,KAAM,IAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE;IAC/C,MAAK;AACN,IAAA;AACA,GAAA,IAAI;IACH,MAAM,EAAE,OAAO,EAAE,OAAQ,GAAE,MAAM,OAAO,kBAAkB,EAAA;AAC1D,IAAA,MAAM,EAAE,IAAK,EAAA,GAAI,MAAM,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAA;IACvE,MAAM,GAAI,GAAE,IAAI,CAAC,IAAI,CAAC,IAAK,GAAE,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAE,GAAE,KAAG;AACjE,IAAA,IAAI,CAAC,GAAI,GAAE,OAAO,OAAO,QAAQ,QAAS,GAAE,GAAE,GAAI,GAAC;AACpD,IAAA,CAAE,OAAO,CAAC,EAAE;AACX,IAAA,IAAI,CAAC,MAAK,GAAI,kBAAkB,CAAC,CAAC,EAAA;AACnC,IAAA;GACA;;AAED;AACC;AACA;;AAEA;;AAEA;;EAED,MAAM,QAAQ,CAAC,GAAG,EAAE,KAAK,EAAE;GAC1B,MAAM,IAAG,GAAI,IAAI,CAAC,OAAO,CAAC,KAAG;AAC7B,GAAA,MAAM,OAAM,GAAI,OAAO,CAAC,IAAK,IAAG,IAAI,CAAC,GAAG,EAAA;GACxC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAK,KAAI,MAAM,EAAE;AAC9B,IAAA,MAAM,GAAI,GAAE,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,EAAA;AACrE,IAAA,IAAI,CAAC,CAAC,GAAI,IAAG,CAAC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE;KAC3C,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,mCAAmC,CAAC,CAAA;AAC7D,KAAA;AACA,IAAA,MAAM,IAAG,GAAI,MAAM,WAAW,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,GAAG,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,IAAK,IAAG,KAAK,EAAA;IACnG,MAAM,QAAS,GAAE,OAAQ,GAAE,SAAU,GAAE,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,EAAA;AACrE,IAAA,OAAO,QAAO,KAAM,SAAU,GAAE,QAAO,GAAI,KAAI;AAChD,IAAA;AACA,GAAA,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE;IAClB,IAAI,CAAC,OAAO,EAAE;KACb,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,mCAAmC,CAAC,CAAA;AAC7D,KAAA;AACA,IAAA,MAAM,WAAW,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,GAAG,KAAM,EAAC,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,YAAY,EAAA;IAC7E,OAAO,KAAI;AACZ,IAAA;GACA,IAAI,CAAC,CAAC,IAAI,CAAC,SAAU,IAAG,CAAC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE;IACtD,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,mCAAmC,CAAC,CAAA;AAC7D,IAAA;GACA,MAAM,WAAW,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,KAAM,EAAC,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,UAAS,EAAG,EAAA;GACjH,OAAO,KAAI;GACX;;AAED;AACC;AACA;;AAEA;AACA;;AAED,EAAA,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE;AACjB,GAAA,MAAM,GAAI,GAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,EAAA;AACrC,GAAA,IAAI,GAAE,KAAM,aAAa,QAAQ,IAAK,IAAG,GAAI,KAAI,EAAE,EAAE;AACpD,IAAA,OAAO,EAAC;AACT,IAAA;GACA,IAAI,MAAM,CAAC,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE;AACzD,IAAA,OAAO,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;AACvC,IAAA;AACA,GAAA,OAAO,OAAO,QAAQ,QAAS,GAAE,EAAG,GAAE,MAAM,CAAC,GAAG,CAAA;GAChD;;;AAGD,EAAA,MAAM,UAAU,GAAG;AAClB,GAAA,MAAM,MAAK,GAAI,IAAI,CAAC,OAAO,CAAC,OAAK;AACjC,GAAA,IAAI,CAAC,MAAK,IAAK,CAAC,MAAM,CAAC,GAAE,IAAK,CAAC,MAAM,CAAC,GAAG,EAAE;IAC1C,MAAK;AACN,IAAA;AACA,GAAA,MAAM,GAAI,GAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,EAAA;AACnC,GAAA,IAAI;IACH,MAAM,EAAE,OAAO,EAAE,OAAQ,GAAE,MAAM,OAAO,kBAAkB,EAAA;AAC1D,IAAA,MAAM,EAAE,IAAK,EAAA,GAAI,MAAM,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,EAAA;IAC/C,MAAM,IAAK,GAAE,MAAM,CAAC,IAAK,GAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAE,GAAE,KAAG;AAC5D,IAAA,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAA,GAAI,IAAK,GAAE,EAAE;MAC7C,MAAM,CAAC,CAAC,IAAI,KAAK,IAAK,IAAG,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,CAAE,KAAI,SAAS,CAAA;AAClE,MAAC,GAAG,CAAC,CAAC,IAAI,MAAM;AACf,MAAA,GAAG,IAAI;MACP,IAAI;AACJ,MAAA,GAAG,EAAE,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;AACvC,MAAA,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,KAAM,IAAG,MAAM,CAAC,GAAG,CAAA,IAAK,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;MACvF,IAAI,EAAE,MAAM,CAAC,IAAK,GAAE,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAE,IAAG,EAAE,CAAA,GAAI,EAAE;AACnE,MAAC,CAAC,EAAA;AACJ,IAAA,CAAE,OAAO,CAAC,EAAE;AACX,IAAA,IAAI,CAAC,MAAK,GAAI,kBAAkB,CAAC,CAAC,EAAA;AACnC,IAAA;GACA;;AAED;AACC;AACA;;AAEA;;;;AAID,EAAA,MAAM,MAAM,CAAC,GAAG,EAAE,EAAE,EAAE;GACrB,IAAI,IAAI,CAAC,IAAI,CAAC,IAAK,KAAI,UAAU,IAAI,CAAC,IAAI,CAAC,IAAK,KAAI,KAAK,EAAE;IAC1D,IAAI,CAAC,MAAO,GAAE,GAAC;AACf,IAAA,IAAI,CAAC,IAAK,GAAE,GAAG,CAAC,IAAE;AAClB,IAAA,IAAI;KACH,MAAM,OAAM,GAAI,MAAM,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,MAAK,GAAI,CAAC,EAAC,GAAI,EAAE,EAAA;KACpE,IAAI,CAAC,QAAS,GAAE,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,GAAG,GAAG,OAAQ,GAAA;KACvD,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,IAAG,KAAM,MAAO,GAAE,IAAI,CAAC,IAAI,CAAC,KAAI,GAAI,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,OAAM,EAAG,EAAA;AACnH,KAAA,CAAE,OAAO,CAAC,EAAE;AACX,KAAA,IAAI,CAAC,MAAK,GAAI,kBAAkB,CAAC,CAAC,EAAA;AAClC,KAAA,IAAI,CAAC,MAAK,GAAI,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAA,IAAK,CAAC,IAAI,CAAE,GAAA;AAC5E,KAAA,SAAU;KACT,IAAI,CAAC,IAAK,GAAE,GAAC;AACd,KAAA;IACA,MAAK;AACN,IAAA;GACA,MAAM,KAAI,GAAI,IAAI,CAAC,IAAI,CAAC,IAAG,KAAM,MAAK,GAAI,IAAI,CAAC,IAAI,CAAC,KAAI,GAAI,GAAG,CAAC,MAAI;AACpE,GAAA,IAAI,CAAC,CAAC,IAAI,CAAC,SAAU,IAAG,EAAE,IAAI,CAAC,OAAO,CAAC,IAAK,IAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE;IACjF,IAAI,CAAC,MAAO,GAAE,IAAI,CAAC,EAAE,CAAC,mCAAmC,EAAA;IACzD,MAAK;AACN,IAAA;AACA,GAAA,IAAI,KAAG;GACP,IAAI,IAAI,CAAC,IAAI,CAAC,IAAK,KAAI,MAAM,EAAE;AAC9B,IAAA,MAAM,IAAG,GAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA,GAAI,IAAI,CAAC,MAAM,CAAC,KAAK,CAAE,GAAE,EAAE,EAAE,GAAG,CAAC,MAAM,EAAA;AACrF,IAAA,MAAM,UAAW,GAAE,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,EAAC,GAAI,GAAC;IAC7C,IAAK,GAAE,cAAc,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,IAAI,IAAG,GAAI,CAAC,GAAG,IAAI,EAAE,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,KAAK,GAAI,KAAI,GAAG,CAAC,GAAG,EAAA;IAC9G,MAAK;AACN,IAAA,IAAK,GAAE,GAAC;AACT,IAAA;GACA,IAAI,CAAC,MAAO,GAAE,GAAC;AACf,GAAA,IAAI,CAAC,IAAK,GAAE,GAAG,CAAC,IAAE;AAClB,GAAA,IAAI;IACH,MAAM,IAAK,GAAE,MAAM,WAAW,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC,KAAK,GAAG,IAAG,EAAG,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,UAAS,EAAG,EAAA;AACtH,IAAA,MAAM,QAAO,GAAI,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAA;IACrC,MAAM,UAAU,aAAa,YAAY,WAAW,KAAG;AACvD,IAAA,IAAI,CAAC,KAAM,GAAE,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,GAAG,OAAQ,GAAA;AAC/C;;AAEC;;AAED,IAAA,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAA;AAC9C,IAAA,CAAE,OAAO,CAAC,EAAE;AACX,IAAA,IAAI,CAAC,MAAK,GAAI,kBAAkB,CAAC,CAAC,EAAA;AAClC,IAAA,IAAI,CAAC,MAAK,GAAI,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAA,IAAK,CAAC,IAAI,CAAE,GAAA;AAC5E,IAAA,SAAU;IACT,IAAI,CAAC,IAAK,GAAE,GAAC;AACd,IAAA;GACA;EACD;AACF;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnToggleTableWidget.vue3.js","sources":["../../../../src/components/CnToggleTableWidget/CnToggleTableWidget.vue?vue&type=template&id=1bb40018&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<div class=\"cn-toggle-table\" data-testid=\"cn-toggle-table\">\n\t\t<p v-if=\"rows.length === 0\" class=\"cn-toggle-table__empty\" data-testid=\"cn-toggle-table-empty\">\n\t\t\t{{ emptyLabel }}\n\t\t</p>\n\t\t<table v-else class=\"cn-toggle-table__table\">\n\t\t\t<thead v-if=\"showHeader\">\n\t\t\t\t<tr>\n\t\t\t\t\t<th scope=\"col\" class=\"cn-toggle-table__head\">\n\t\t\t\t\t\t{{ titleHeader }}\n\t\t\t\t\t</th>\n\t\t\t\t\t<th\n\t\t\t\t\t\tv-for=\"column in columns\"\n\t\t\t\t\t\t:key=\"column.path\"\n\t\t\t\t\t\tscope=\"col\"\n\t\t\t\t\t\tclass=\"cn-toggle-table__head\">\n\t\t\t\t\t\t{{ column.header }}\n\t\t\t\t\t</th>\n\t\t\t\t\t<th scope=\"col\" class=\"cn-toggle-table__head cn-toggle-table__head--toggle\">\n\t\t\t\t\t\t{{ toggleHeader }}\n\t\t\t\t\t</th>\n\t\t\t\t</tr>\n\t\t\t</thead>\n\t\t\t<tbody>\n\t\t\t\t<tr\n\t\t\t\t\tv-for=\"row in rows\"\n\t\t\t\t\t:key=\"row.key\"\n\t\t\t\t\tclass=\"cn-toggle-table__row\"\n\t\t\t\t\t:data-testid=\"`cn-toggle-table-row-${row.key}`\">\n\t\t\t\t\t<td class=\"cn-toggle-table__cell cn-toggle-table__cell--main\">\n\t\t\t\t\t\t<span class=\"cn-toggle-table__title\">{{ row.title }}</span>\n\t\t\t\t\t\t<span v-if=\"row.hint\" class=\"cn-toggle-table__hint\">{{ row.hint }}</span>\n\t\t\t\t\t</td>\n\t\t\t\t\t<td\n\t\t\t\t\t\tv-for=\"column in columns\"\n\t\t\t\t\t\t:key=\"column.path\"\n\t\t\t\t\t\tclass=\"cn-toggle-table__cell\">\n\t\t\t\t\t\t{{ cell(row, column) }}\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"cn-toggle-table__cell cn-toggle-table__cell--toggle\">\n\t\t\t\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t\t\t\t:key=\"`${row.key}-${undone[row.key] || 0}`\"\n\t\t\t\t\t\t\t:modelValue=\"isOn(row)\"\n\t\t\t\t\t\t\ttype=\"switch\"\n\t\t\t\t\t\t\t:disabled=\"readOnly || busy === row.key\"\n\t\t\t\t\t\t\t:aria-label=\"row.title\"\n\t\t\t\t\t\t\t@update:modelValue=\"toggle(row, $event)\" />\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t</tbody>\n\t\t</table>\n\t\t<NcNoteCard v-if=\"notice\" type=\"error\" data-testid=\"cn-toggle-table-notice\">\n\t\t\t{{ notice }}\n\t\t</NcNoteCard>\n\t</div>\n</template>\n\n<script>\nimport { NcCheckboxRadioSwitch, NcNoteCard } from '@nextcloud/vue'\nimport { prefixUrl } from '../../utils/headers.js'\nimport { objectUrlOf, writeFields } from '../../utils/objectWrite.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { serverErrorMessage } from '../../utils/serverErrorMessage.js'\n\n/**\n * CnToggleTableWidget — the `toggle-table` widget: rows from a configured list\n * (`rows`) or read from a source (`source`), each with a switch bound to the\n * CURRENT object, and optional extra columns read off the row. A switch is\n * stored in one of two ways:\n *\n * - `bind.mode: 'flag'` — each row names its own boolean field of the object\n * (`row.field`); the switch is that field.\n * - `bind.mode: 'list'` — ONE array field of the object (`bind.field`) holds\n * the keys of the rows that are in it; the switch is on when the row's key is\n * in the list, or NOT in it with `bind.invert` (a list of hidden items shown\n * as \"visible\" switches).\n *\n * A toggle saves at once with ONE PATCH of that field; a refused PATCH puts the\n * switch back and shows the server's words.\n *\n * @spec openspec/changes/abstract-toggle-table/specs/toggle-table/spec.md\n */\nexport default {\n\tname: 'CnToggleTableWidget',\n\n\tcomponents: { NcCheckboxRadioSwitch, NcNoteCard },\n\n\tinject: {\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The widget configuration.\n\t\t *\n\t\t * - `bind` — `{ mode: 'flag' }` (default) or `{ mode: 'list', field, invert? }`.\n\t\t * - `rows` — static rows `[{ key, label, hint?, field?, ...extra }]`.\n\t\t * - `source` — `{ url, path?, key, label, hint? }`: rows read from an endpoint (tokens `@objectId`, `@object.<field>`), in addition to `rows`.\n\t\t * - `columns` — extra columns `[{ header, path, map? }]` read off each row.\n\t\t * - `titleHeader`, `toggleHeader`, `emptyText`, `readOnly`.\n\t\t * - `save` — `{ url, method?, payload? }`, write through an app endpoint (tokens `{value}`, `{field}`, `{changes}`, `{object.<path>}`).\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** The current detail-page object. */\n\t\tobjectData: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** The current object id. */\n\t\tobjectId: {\n\t\t\ttype: [String, Number],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** OpenRegister register slug of the surface. */\n\t\tregister: {\n\t\t\ttype: [String, Object],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** OpenRegister schema slug of the surface. */\n\t\tschema: {\n\t\t\ttype: [String, Object],\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\temits: ['saved'],\n\n\tdata() {\n\t\treturn {\n\t\t\t/** Rows read from `source`. */\n\t\t\tsourced: [],\n\t\t\t/** What the object holds, by field: the flags and the list, as last saved. */\n\t\t\tsaved: {},\n\t\t\tbusy: '',\n\t\t\tnotice: '',\n\t\t\t/** Per row, how often a refused toggle forced the switch to be drawn again from the stored value. */\n\t\t\tundone: {},\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tbind() {\n\t\t\tconst bind = this.content.bind || {}\n\t\t\treturn bind.mode === 'list' ? { mode: 'list', field: bind.field, invert: bind.invert === true } : { mode: 'flag' }\n\t\t},\n\n\t\t/** The drawn rows: configured first, then sourced, each with a key, title and hint. */\n\t\trows() {\n\t\t\tconst configured = (Array.isArray(this.content.rows) ? this.content.rows : [])\n\t\t\t\t.filter((row) => row && row.key !== undefined)\n\t\t\t\t.map((row) => ({ ...row, key: String(row.key), title: this.tr(row.label || String(row.key)), hint: this.tr(row.hint || '') }))\n\t\t\treturn [...configured, ...this.sourced]\n\t\t},\n\n\t\tcolumns() {\n\t\t\treturn (Array.isArray(this.content.columns) ? this.content.columns : [])\n\t\t\t\t.filter((column) => column && column.path)\n\t\t\t\t.map((column) => ({ ...column, header: this.tr(column.header || '') }))\n\t\t},\n\n\t\tshowHeader() {\n\t\t\treturn this.columns.length > 0 || Boolean(this.content.titleHeader || this.content.toggleHeader)\n\t\t},\n\n\t\ttitleHeader() {\n\t\t\treturn this.tr(this.content.titleHeader || '')\n\t\t},\n\n\t\ttoggleHeader() {\n\t\t\treturn this.tr(this.content.toggleHeader || '')\n\t\t},\n\n\t\temptyLabel() {\n\t\t\treturn this.tr(this.content.emptyText || 'Nothing listed yet')\n\t\t},\n\n\t\treadOnly() {\n\t\t\treturn this.content.readOnly === true\n\t\t},\n\n\t\tobjectUrl() {\n\t\t\treturn objectUrlOf(this.register, this.schema, this.objectId || (this.objectData && this.objectData.id))\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectData() {\n\t\t\tthis.saved = {}\n\t\t\tthis.loadSource()\n\t\t},\n\t},\n\n\tcreated() {\n\t\tthis.loadSource()\n\t},\n\n\tmethods: {\n\t\ttr(text) {\n\t\t\tif (typeof text !== 'string' || text === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn typeof this.cnTranslate === 'function' ? this.cnTranslate(text) : text\n\t\t},\n\n\t\t/**\n\t\t * The stored value of a field: what this widget last saved, else the object's.\n\t\t *\n\t\t * @param {string} field The field.\n\t\t * @return {unknown}\n\t\t */\n\t\tstored(field) {\n\t\t\treturn Object.hasOwn(this.saved, field) ? this.saved[field] : readPath(this.objectData || {}, field)\n\t\t},\n\n\t\t/**\n\t\t * Whether a row's switch is on.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @return {boolean}\n\t\t */\n\t\tisOn(row) {\n\t\t\tif (this.bind.mode === 'list') {\n\t\t\t\tconst list = this.stored(this.bind.field)\n\t\t\t\tconst inList = Array.isArray(list) && list.map(String).includes(row.key)\n\t\t\t\treturn this.bind.invert ? !inList : inList\n\t\t\t}\n\t\t\treturn row.field ? this.stored(row.field) === true : false\n\t\t},\n\n\t\t/**\n\t\t * The text of an extra column for a row.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @param {object} column The column.\n\t\t * @return {string}\n\t\t */\n\t\tcell(row, column) {\n\t\t\tconst raw = readPath(row, column.path)\n\t\t\tif (raw === undefined || raw === null || raw === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tif (column.map && Object.hasOwn(column.map, String(raw))) {\n\t\t\t\treturn this.tr(column.map[String(raw)])\n\t\t\t}\n\t\t\treturn typeof raw === 'object' ? '' : String(raw)\n\t\t},\n\n\t\t/** Read the rows of `source`, resolving tokens in its url. */\n\t\tasync loadSource() {\n\t\t\tconst source = this.content.source\n\t\t\tif (!source || !source.url || !source.key) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst object = this.objectData || {}\n\t\t\tconst url = String(source.url)\n\t\t\t\t.replace(/@objectId/g, () => encodeURIComponent(String(this.objectId || object.id || '')))\n\t\t\t\t.replace(/@object\\.([\\w.@]+)/g, (m, path) => encodeURIComponent(String(readPath(object, path) ?? '')))\n\t\t\ttry {\n\t\t\t\tconst { default: axios } = await import('@nextcloud/axios')\n\t\t\t\tconst { data } = await axios.get(prefixUrl(url))\n\t\t\t\tconst list = source.path ? readPath(data, source.path) : data\n\t\t\t\tthis.sourced = (Array.isArray(list) ? list : [])\n\t\t\t\t\t.filter((item) => item && readPath(item, source.key) !== undefined)\n\t\t\t\t\t.map((item) => ({\n\t\t\t\t\t\t...item,\n\t\t\t\t\t\tkey: String(readPath(item, source.key)),\n\t\t\t\t\t\ttitle: String(readPath(item, source.label || source.key) ?? readPath(item, source.key)),\n\t\t\t\t\t\thint: source.hint ? String(readPath(item, source.hint) ?? '') : '',\n\t\t\t\t\t}))\n\t\t\t} catch (e) {\n\t\t\t\tthis.notice = serverErrorMessage(e)\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Flip one switch and save that one field.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @param {boolean} on The new switch state.\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/abstract-toggle-table/specs/toggle-table/spec.md#requirement-a-toggle-saves-one-field\n\t\t */\n\t\tasync toggle(row, on) {\n\t\t\tconst field = this.bind.mode === 'list' ? this.bind.field : row.field\n\t\t\tif ((!this.objectUrl && !(this.content.save && this.content.save.url)) || !field) {\n\t\t\t\tthis.notice = this.tr('This switch cannot be saved here.')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tlet next\n\t\t\tif (this.bind.mode === 'list') {\n\t\t\t\tconst list = (Array.isArray(this.stored(field)) ? this.stored(field) : []).map(String)\n\t\t\t\tconst wantInList = this.bind.invert ? !on : on\n\t\t\t\tnext = wantInList ? (list.includes(row.key) ? list : [...list, row.key]) : list.filter((key) => key !== row.key)\n\t\t\t} else {\n\t\t\t\tnext = on\n\t\t\t}\n\t\t\tthis.notice = ''\n\t\t\tthis.busy = row.key\n\t\t\ttry {\n\t\t\t\tconst data = await writeFields(this.objectUrl, { [field]: next }, { save: this.content.save, object: this.objectData })\n\t\t\t\tconst answered = readPath(data, field)\n\t\t\t\tconst written = answered !== undefined ? answered : next\n\t\t\t\tthis.saved = { ...this.saved, [field]: written }\n\t\t\t\t/**\n\t\t\t\t * @event saved A switch was written.\n\t\t\t\t * @type {{field: string, value: unknown}}\n\t\t\t\t */\n\t\t\t\tthis.$emit('saved', { field, value: written })\n\t\t\t} catch (e) {\n\t\t\t\tthis.notice = serverErrorMessage(e)\n\t\t\t\tthis.undone = { ...this.undone, [row.key]: (this.undone[row.key] || 0) + 1 }\n\t\t\t} finally {\n\t\t\t\tthis.busy = ''\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-toggle-table {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 8px;\n\tmin-width: 0;\n}\n\n.cn-toggle-table__table {\n\twidth: 100%;\n\tborder-collapse: collapse;\n}\n\n.cn-toggle-table__head {\n\tpadding: 8px 12px;\n\ttext-align: start;\n\tfont-size: 13px;\n\tfont-weight: 600;\n\tcolor: var(--color-text-maxcontrast);\n\tbackground: var(--color-background-hover);\n}\n\n.cn-toggle-table__head--toggle,\n.cn-toggle-table__cell--toggle {\n\twidth: 1%;\n\twhite-space: nowrap;\n\ttext-align: end;\n}\n\n.cn-toggle-table__row {\n\tborder-top: 1px solid var(--cn-board-hairline, var(--color-border));\n}\n\n.cn-toggle-table__cell {\n\tpadding: 10px 12px;\n\tvertical-align: middle;\n\toverflow-wrap: anywhere;\n}\n\n.cn-toggle-table__title {\n\tdisplay: block;\n\tfont-weight: 600;\n}\n\n.cn-toggle-table__hint {\n\tdisplay: block;\n\tfont-size: 12px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-toggle-table__empty {\n\tmargin: 0;\n\tcolor: var(--color-text-maxcontrast);\n}\n</style>\n"],"names":["_createElementBlock","_toDisplayString","_createElementVNode","_Fragment","_renderList","_openBlock"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnToggleTableWidget.vue3.js","sources":["../../../../src/components/CnToggleTableWidget/CnToggleTableWidget.vue?vue&type=template&id=24769640&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<div class=\"cn-toggle-table\" data-testid=\"cn-toggle-table\">\n\t\t<p v-if=\"rows.length === 0\" class=\"cn-toggle-table__empty\" data-testid=\"cn-toggle-table-empty\">\n\t\t\t{{ emptyLabel }}\n\t\t</p>\n\t\t<table v-else class=\"cn-toggle-table__table\">\n\t\t\t<thead v-if=\"showHeader\">\n\t\t\t\t<tr>\n\t\t\t\t\t<th scope=\"col\" class=\"cn-toggle-table__head\">\n\t\t\t\t\t\t{{ titleHeader }}\n\t\t\t\t\t</th>\n\t\t\t\t\t<th\n\t\t\t\t\t\tv-for=\"column in columns\"\n\t\t\t\t\t\t:key=\"column.path\"\n\t\t\t\t\t\tscope=\"col\"\n\t\t\t\t\t\tclass=\"cn-toggle-table__head\">\n\t\t\t\t\t\t{{ column.header }}\n\t\t\t\t\t</th>\n\t\t\t\t\t<th scope=\"col\" class=\"cn-toggle-table__head cn-toggle-table__head--toggle\">\n\t\t\t\t\t\t{{ toggleHeader }}\n\t\t\t\t\t</th>\n\t\t\t\t</tr>\n\t\t\t</thead>\n\t\t\t<tbody>\n\t\t\t\t<tr\n\t\t\t\t\tv-for=\"row in rows\"\n\t\t\t\t\t:key=\"row.key\"\n\t\t\t\t\tclass=\"cn-toggle-table__row\"\n\t\t\t\t\t:data-testid=\"`cn-toggle-table-row-${row.key}`\">\n\t\t\t\t\t<td class=\"cn-toggle-table__cell cn-toggle-table__cell--main\">\n\t\t\t\t\t\t<span class=\"cn-toggle-table__title\">{{ row.title }}</span>\n\t\t\t\t\t\t<span v-if=\"row.hint\" class=\"cn-toggle-table__hint\">{{ row.hint }}</span>\n\t\t\t\t\t</td>\n\t\t\t\t\t<td\n\t\t\t\t\t\tv-for=\"column in columns\"\n\t\t\t\t\t\t:key=\"column.path\"\n\t\t\t\t\t\tclass=\"cn-toggle-table__cell\">\n\t\t\t\t\t\t{{ cell(row, column) }}\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"cn-toggle-table__cell cn-toggle-table__cell--toggle\">\n\t\t\t\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t\t\t\t:key=\"`${row.key}-${undone[row.key] || 0}`\"\n\t\t\t\t\t\t\t:modelValue=\"isOn(row)\"\n\t\t\t\t\t\t\ttype=\"switch\"\n\t\t\t\t\t\t\t:disabled=\"readOnly || busy === row.key\"\n\t\t\t\t\t\t\t:aria-label=\"row.title\"\n\t\t\t\t\t\t\t@update:modelValue=\"toggle(row, $event)\" />\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t</tbody>\n\t\t</table>\n\t\t<NcNoteCard v-if=\"notice\" type=\"error\" data-testid=\"cn-toggle-table-notice\">\n\t\t\t{{ notice }}\n\t\t</NcNoteCard>\n\t</div>\n</template>\n\n<script>\nimport { NcCheckboxRadioSwitch, NcNoteCard } from '@nextcloud/vue'\nimport { prefixUrl } from '../../utils/headers.js'\nimport { objectUrlOf, writeFields } from '../../utils/objectWrite.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { serverErrorMessage } from '../../utils/serverErrorMessage.js'\n\n/**\n * CnToggleTableWidget — the `toggle-table` widget: rows from a configured list\n * (`rows`) or read from a source (`source`), each with a switch bound to the\n * CURRENT object, and optional extra columns read off the row. A switch is\n * stored in one of two ways:\n *\n * - `bind.mode: 'flag'` — each row names its own boolean field of the object\n * (`row.field`); the switch is that field.\n * - `bind.mode: 'list'` — ONE array field of the object (`bind.field`) holds\n * the keys of the rows that are in it; the switch is on when the row's key is\n * in the list, or NOT in it with `bind.invert` (a list of hidden items shown\n * as \"visible\" switches).\n * - `bind.mode: 'each'` — every row IS an object (read by `source`, its key the\n * object id); the switch is that object's own boolean field (`bind.field`)\n * and a toggle PATCHes that object (`bind.register` / `bind.schema`, else the\n * surface's). No current object is needed, so it serves a settings page.\n * - `bind.mode: 'map'` — a config map holds a boolean per row key: read from\n * `bind.url` (at `bind.path`) and written through `save`, or one object field\n * of the current object (`bind.field`) written by its dot-path.\n *\n * A toggle saves at once with ONE PATCH of that field; a refused PATCH puts the\n * switch back and shows the server's words.\n *\n * @spec openspec/changes/abstract-toggle-table/specs/toggle-table/spec.md\n */\nexport default {\n\tname: 'CnToggleTableWidget',\n\n\tcomponents: { NcCheckboxRadioSwitch, NcNoteCard },\n\n\tinject: {\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The widget configuration.\n\t\t *\n\t\t * - `bind` — `{ mode: 'flag' }` (default), `{ mode: 'list', field, invert? }`, `{ mode: 'each', field, register?, schema?, invert? }` or `{ mode: 'map', url?, path?, field?, invert? }`.\n\t\t * - `rows` — static rows `[{ key, label, hint?, field?, ...extra }]`.\n\t\t * - `source` — `{ url, path?, key, label, hint? }`: rows read from an endpoint (tokens `@objectId`, `@object.<field>`), in addition to `rows`.\n\t\t * - `columns` — extra columns `[{ header, path, map? }]` read off each row.\n\t\t * - `titleHeader`, `toggleHeader`, `emptyText`, `readOnly`.\n\t\t * - `save` — `{ url, method?, payload? }`, write through an app endpoint (tokens `{value}`, `{field}`, `{changes}`, `{object.<path>}`).\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** The current detail-page object. */\n\t\tobjectData: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** The current object id. */\n\t\tobjectId: {\n\t\t\ttype: [String, Number],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** OpenRegister register slug of the surface. */\n\t\tregister: {\n\t\t\ttype: [String, Object],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** OpenRegister schema slug of the surface. */\n\t\tschema: {\n\t\t\ttype: [String, Object],\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\temits: ['saved'],\n\n\tdata() {\n\t\treturn {\n\t\t\t/** Rows read from `source`. */\n\t\t\tsourced: [],\n\t\t\t/** What the object holds, by field: the flags and the list, as last saved. */\n\t\t\tsaved: {},\n\t\t\tbusy: '',\n\t\t\tnotice: '',\n\t\t\t/** Per row, how often a refused toggle forced the switch to be drawn again from the stored value. */\n\t\t\tundone: {},\n\t\t\t/** `each` and `map`: the value written per row key. */\n\t\t\trowSaved: {},\n\t\t\t/** `map` with `bind.url`: the map as read. */\n\t\t\tmap: null,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * How a switch is stored.\n\t\t *\n\t\t * @return {object} The normalised `bind`.\n\t\t * @spec openspec/changes/toggle-table-objects-and-map/specs/toggle-table/spec.md#requirement-a-toggle-table-can-switch-objects-or-a-config-map\n\t\t */\n\t\tbind() {\n\t\t\tconst bind = this.content.bind || {}\n\t\t\tconst invert = bind.invert === true\n\t\t\tif (bind.mode === 'list') {\n\t\t\t\treturn { mode: 'list', field: bind.field, invert }\n\t\t\t}\n\t\t\tif (bind.mode === 'each') {\n\t\t\t\treturn { mode: 'each', field: bind.field || '', invert, register: bind.register || this.register, schema: bind.schema || this.schema }\n\t\t\t}\n\t\t\tif (bind.mode === 'map') {\n\t\t\t\treturn { mode: 'map', field: bind.field || '', url: bind.url || '', path: bind.path || '', invert }\n\t\t\t}\n\t\t\treturn { mode: 'flag' }\n\t\t},\n\n\t\t/** The drawn rows: configured first, then sourced, each with a key, title and hint. */\n\t\trows() {\n\t\t\tconst configured = (Array.isArray(this.content.rows) ? this.content.rows : [])\n\t\t\t\t.filter((row) => row && row.key !== undefined)\n\t\t\t\t.map((row) => ({ ...row, key: String(row.key), title: this.tr(row.label || String(row.key)), hint: this.tr(row.hint || '') }))\n\t\t\treturn [...configured, ...this.sourced]\n\t\t},\n\n\t\tcolumns() {\n\t\t\treturn (Array.isArray(this.content.columns) ? this.content.columns : [])\n\t\t\t\t.filter((column) => column && column.path)\n\t\t\t\t.map((column) => ({ ...column, header: this.tr(column.header || '') }))\n\t\t},\n\n\t\tshowHeader() {\n\t\t\treturn this.columns.length > 0 || Boolean(this.content.titleHeader || this.content.toggleHeader)\n\t\t},\n\n\t\ttitleHeader() {\n\t\t\treturn this.tr(this.content.titleHeader || '')\n\t\t},\n\n\t\ttoggleHeader() {\n\t\t\treturn this.tr(this.content.toggleHeader || '')\n\t\t},\n\n\t\temptyLabel() {\n\t\t\treturn this.tr(this.content.emptyText || 'Nothing listed yet')\n\t\t},\n\n\t\treadOnly() {\n\t\t\treturn this.content.readOnly === true\n\t\t},\n\n\t\tobjectUrl() {\n\t\t\treturn objectUrlOf(this.register, this.schema, this.objectId || (this.objectData && this.objectData.id))\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectData() {\n\t\t\tthis.saved = {}\n\t\t\tthis.rowSaved = {}\n\t\t\tthis.loadSource()\n\t\t\tthis.loadMap()\n\t\t},\n\t},\n\n\tcreated() {\n\t\tthis.loadSource()\n\t\tthis.loadMap()\n\t},\n\n\tmethods: {\n\t\ttr(text) {\n\t\t\tif (typeof text !== 'string' || text === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn typeof this.cnTranslate === 'function' ? this.cnTranslate(text) : text\n\t\t},\n\n\t\t/**\n\t\t * The stored value of a field: what this widget last saved, else the object's.\n\t\t *\n\t\t * @param {string} field The field.\n\t\t * @return {unknown}\n\t\t */\n\t\tstored(field) {\n\t\t\treturn Object.hasOwn(this.saved, field) ? this.saved[field] : readPath(this.objectData || {}, field)\n\t\t},\n\n\t\t/**\n\t\t * Whether a row's switch is on.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @return {boolean}\n\t\t */\n\t\tisOn(row) {\n\t\t\tif (this.bind.mode === 'each' || this.bind.mode === 'map') {\n\t\t\t\tconst on = this.rowValue(row) === true\n\t\t\t\treturn this.bind.invert ? !on : on\n\t\t\t}\n\t\t\tif (this.bind.mode === 'list') {\n\t\t\t\tconst list = this.stored(this.bind.field)\n\t\t\t\tconst inList = Array.isArray(list) && list.map(String).includes(row.key)\n\t\t\t\treturn this.bind.invert ? !inList : inList\n\t\t\t}\n\t\t\treturn row.field ? this.stored(row.field) === true : false\n\t\t},\n\n\t\t/**\n\t\t * `each` and `map`: the stored value of a row's switch, as last written,\n\t\t * else read off the row's object or the map.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @return {unknown}\n\t\t * @spec openspec/changes/toggle-table-objects-and-map/specs/toggle-table/spec.md#requirement-a-toggle-table-can-switch-objects-or-a-config-map\n\t\t */\n\t\trowValue(row) {\n\t\t\tif (Object.hasOwn(this.rowSaved, row.key)) {\n\t\t\t\treturn this.rowSaved[row.key]\n\t\t\t}\n\t\t\tif (this.bind.mode === 'each') {\n\t\t\t\treturn this.bind.field ? readPath(row.item || row, this.bind.field) : undefined\n\t\t\t}\n\t\t\tconst map = this.bind.url ? this.map : (this.bind.field ? this.stored(this.bind.field) : null)\n\t\t\treturn map && typeof map === 'object' ? map[row.key] : undefined\n\t\t},\n\n\t\t/**\n\t\t * Resolve `@objectId` and `@object.<path>` in a url.\n\t\t *\n\t\t * @param {string} url The url.\n\t\t * @return {string}\n\t\t */\n\t\tfillUrl(url) {\n\t\t\tconst object = this.objectData || {}\n\t\t\treturn String(url)\n\t\t\t\t.replace(/@objectId/g, () => encodeURIComponent(String(this.objectId || object.id || '')))\n\t\t\t\t.replace(/@object\\.([\\w.@]+)/g, (m, path) => encodeURIComponent(String(readPath(object, path) ?? '')))\n\t\t},\n\n\t\t/**\n\t\t * `map` with `bind.url`: read the map.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/toggle-table-objects-and-map/specs/toggle-table/spec.md#requirement-a-toggle-table-can-switch-objects-or-a-config-map\n\t\t */\n\t\tasync loadMap() {\n\t\t\tif (this.bind.mode !== 'map' || !this.bind.url) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst { default: axios } = await import('@nextcloud/axios')\n\t\t\t\tconst { data } = await axios.get(prefixUrl(this.fillUrl(this.bind.url)))\n\t\t\t\tconst map = this.bind.path ? readPath(data, this.bind.path) : data\n\t\t\t\tthis.map = map && typeof map === 'object' ? map : {}\n\t\t\t} catch (e) {\n\t\t\t\tthis.notice = serverErrorMessage(e)\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * `each` and `map`: write one row's switch.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @param {boolean} value The value to store.\n\t\t * @return {Promise<unknown>} The value the server holds now.\n\t\t * @spec openspec/changes/toggle-table-objects-and-map/specs/toggle-table/spec.md#requirement-a-toggle-table-can-switch-objects-or-a-config-map\n\t\t */\n\t\tasync writeRow(row, value) {\n\t\t\tconst save = this.content.save\n\t\t\tconst hasSave = Boolean(save && save.url)\n\t\t\tif (this.bind.mode === 'each') {\n\t\t\t\tconst url = objectUrlOf(this.bind.register, this.bind.schema, row.key)\n\t\t\t\tif ((!url && !hasSave) || !this.bind.field) {\n\t\t\t\t\tthrow new Error(this.tr('This switch cannot be saved here.'))\n\t\t\t\t}\n\t\t\t\tconst data = await writeFields(url, { [this.bind.field]: value }, { save, object: row.item || row })\n\t\t\t\tconst answered = hasSave ? undefined : readPath(data, this.bind.field)\n\t\t\t\treturn answered !== undefined ? answered : value\n\t\t\t}\n\t\t\tif (this.bind.url) {\n\t\t\t\tif (!hasSave) {\n\t\t\t\t\tthrow new Error(this.tr('This switch cannot be saved here.'))\n\t\t\t\t}\n\t\t\t\tawait writeFields('', { [row.key]: value }, { save, object: this.objectData })\n\t\t\t\treturn value\n\t\t\t}\n\t\t\tif ((!this.objectUrl && !hasSave) || !this.bind.field) {\n\t\t\t\tthrow new Error(this.tr('This switch cannot be saved here.'))\n\t\t\t}\n\t\t\tawait writeFields(this.objectUrl, { [`${this.bind.field}.${row.key}`]: value }, { save, object: this.objectData })\n\t\t\treturn value\n\t\t},\n\n\t\t/**\n\t\t * The text of an extra column for a row.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @param {object} column The column.\n\t\t * @return {string}\n\t\t */\n\t\tcell(row, column) {\n\t\t\tconst raw = readPath(row, column.path)\n\t\t\tif (raw === undefined || raw === null || raw === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tif (column.map && Object.hasOwn(column.map, String(raw))) {\n\t\t\t\treturn this.tr(column.map[String(raw)])\n\t\t\t}\n\t\t\treturn typeof raw === 'object' ? '' : String(raw)\n\t\t},\n\n\t\t/** Read the rows of `source`, resolving tokens in its url. */\n\t\tasync loadSource() {\n\t\t\tconst source = this.content.source\n\t\t\tif (!source || !source.url || !source.key) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst url = this.fillUrl(source.url)\n\t\t\ttry {\n\t\t\t\tconst { default: axios } = await import('@nextcloud/axios')\n\t\t\t\tconst { data } = await axios.get(prefixUrl(url))\n\t\t\t\tconst list = source.path ? readPath(data, source.path) : data\n\t\t\t\tthis.sourced = (Array.isArray(list) ? list : [])\n\t\t\t\t\t.filter((item) => item && readPath(item, source.key) !== undefined)\n\t\t\t\t\t.map((item) => ({\n\t\t\t\t\t\t...item,\n\t\t\t\t\t\titem,\n\t\t\t\t\t\tkey: String(readPath(item, source.key)),\n\t\t\t\t\t\ttitle: String(readPath(item, source.label || source.key) ?? readPath(item, source.key)),\n\t\t\t\t\t\thint: source.hint ? String(readPath(item, source.hint) ?? '') : '',\n\t\t\t\t\t}))\n\t\t\t} catch (e) {\n\t\t\t\tthis.notice = serverErrorMessage(e)\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Flip one switch and save that one field.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @param {boolean} on The new switch state.\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/abstract-toggle-table/specs/toggle-table/spec.md#requirement-a-toggle-saves-one-field\n\t\t */\n\t\tasync toggle(row, on) {\n\t\t\tif (this.bind.mode === 'each' || this.bind.mode === 'map') {\n\t\t\t\tthis.notice = ''\n\t\t\t\tthis.busy = row.key\n\t\t\t\ttry {\n\t\t\t\t\tconst written = await this.writeRow(row, this.bind.invert ? !on : on)\n\t\t\t\t\tthis.rowSaved = { ...this.rowSaved, [row.key]: written }\n\t\t\t\t\tthis.$emit('saved', { field: this.bind.mode === 'each' ? this.bind.field : row.key, key: row.key, value: written })\n\t\t\t\t} catch (e) {\n\t\t\t\t\tthis.notice = serverErrorMessage(e)\n\t\t\t\t\tthis.undone = { ...this.undone, [row.key]: (this.undone[row.key] || 0) + 1 }\n\t\t\t\t} finally {\n\t\t\t\t\tthis.busy = ''\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst field = this.bind.mode === 'list' ? this.bind.field : row.field\n\t\t\tif ((!this.objectUrl && !(this.content.save && this.content.save.url)) || !field) {\n\t\t\t\tthis.notice = this.tr('This switch cannot be saved here.')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tlet next\n\t\t\tif (this.bind.mode === 'list') {\n\t\t\t\tconst list = (Array.isArray(this.stored(field)) ? this.stored(field) : []).map(String)\n\t\t\t\tconst wantInList = this.bind.invert ? !on : on\n\t\t\t\tnext = wantInList ? (list.includes(row.key) ? list : [...list, row.key]) : list.filter((key) => key !== row.key)\n\t\t\t} else {\n\t\t\t\tnext = on\n\t\t\t}\n\t\t\tthis.notice = ''\n\t\t\tthis.busy = row.key\n\t\t\ttry {\n\t\t\t\tconst data = await writeFields(this.objectUrl, { [field]: next }, { save: this.content.save, object: this.objectData })\n\t\t\t\tconst answered = readPath(data, field)\n\t\t\t\tconst written = answered !== undefined ? answered : next\n\t\t\t\tthis.saved = { ...this.saved, [field]: written }\n\t\t\t\t/**\n\t\t\t\t * @event saved A switch was written.\n\t\t\t\t * @type {{field: string, key?: string, value: unknown}} `key` is the row, in the `each` and `map` modes.\n\t\t\t\t */\n\t\t\t\tthis.$emit('saved', { field, value: written })\n\t\t\t} catch (e) {\n\t\t\t\tthis.notice = serverErrorMessage(e)\n\t\t\t\tthis.undone = { ...this.undone, [row.key]: (this.undone[row.key] || 0) + 1 }\n\t\t\t} finally {\n\t\t\t\tthis.busy = ''\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-toggle-table {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 8px;\n\tmin-width: 0;\n}\n\n.cn-toggle-table__table {\n\twidth: 100%;\n\tborder-collapse: collapse;\n}\n\n.cn-toggle-table__head {\n\tpadding: 8px 12px;\n\ttext-align: start;\n\tfont-size: 13px;\n\tfont-weight: 600;\n\tcolor: var(--color-text-maxcontrast);\n\tbackground: var(--color-background-hover);\n}\n\n.cn-toggle-table__head--toggle,\n.cn-toggle-table__cell--toggle {\n\twidth: 1%;\n\twhite-space: nowrap;\n\ttext-align: end;\n}\n\n.cn-toggle-table__row {\n\tborder-top: 1px solid var(--cn-board-hairline, var(--color-border));\n}\n\n.cn-toggle-table__cell {\n\tpadding: 10px 12px;\n\tvertical-align: middle;\n\toverflow-wrap: anywhere;\n}\n\n.cn-toggle-table__title {\n\tdisplay: block;\n\tfont-weight: 600;\n}\n\n.cn-toggle-table__hint {\n\tdisplay: block;\n\tfont-size: 12px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-toggle-table__empty {\n\tmargin: 0;\n\tcolor: var(--color-text-maxcontrast);\n}\n</style>\n"],"names":["_createElementBlock","_toDisplayString","_createElementVNode","_Fragment","_renderList","_openBlock"],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import script from './CnVersionInfoCard.vue2.js';
|
|
|
2
2
|
import { render } from './CnVersionInfoCard.vue3.js';
|
|
3
3
|
|
|
4
4
|
script.render = render;
|
|
5
|
-
script.__scopeId = "data-v-
|
|
5
|
+
script.__scopeId = "data-v-17db98e4";
|
|
6
6
|
const __sfc_main = script;
|
|
7
7
|
|
|
8
8
|
export { __sfc_main as default };
|
|
@@ -67,6 +67,18 @@ var script = {
|
|
|
67
67
|
default: '',
|
|
68
68
|
},
|
|
69
69
|
|
|
70
|
+
/**
|
|
71
|
+
* Under the board look the card spans the whole settings grid, as the
|
|
72
|
+
* boards draw the version card. Set to `false` to keep it one card in
|
|
73
|
+
* the grid. Without the board look it has no effect.
|
|
74
|
+
*
|
|
75
|
+
* @spec openspec/changes/board-version-card-full-width/specs/settings-board-look/spec.md#requirement-the-board-version-card-spans-the-settings-grid
|
|
76
|
+
*/
|
|
77
|
+
wide: {
|
|
78
|
+
type: Boolean,
|
|
79
|
+
default: true,
|
|
80
|
+
},
|
|
81
|
+
|
|
70
82
|
/** Section title */
|
|
71
83
|
title: {
|
|
72
84
|
type: String,
|
|
@@ -142,14 +154,13 @@ var script = {
|
|
|
142
154
|
default: false,
|
|
143
155
|
},
|
|
144
156
|
|
|
145
|
-
/**
|
|
157
|
+
/**
|
|
158
|
+
* Custom labels for the standard fields, `{ appName?, version?, configuredVersion? }`.
|
|
159
|
+
* A label left out keeps the translated default.
|
|
160
|
+
*/
|
|
146
161
|
labels: {
|
|
147
162
|
type: Object,
|
|
148
|
-
default: () => ({
|
|
149
|
-
appName: 'Application Name',
|
|
150
|
-
version: 'Version',
|
|
151
|
-
configuredVersion: 'Configured Version',
|
|
152
|
-
}),
|
|
163
|
+
default: () => ({}),
|
|
153
164
|
},
|
|
154
165
|
},
|
|
155
166
|
|
|
@@ -161,6 +172,21 @@ var script = {
|
|
|
161
172
|
},
|
|
162
173
|
|
|
163
174
|
computed: {
|
|
175
|
+
/**
|
|
176
|
+
* The field labels: the app's, else the library's in the reader's language.
|
|
177
|
+
*
|
|
178
|
+
* @return {{appName: string, version: string, configuredVersion: string}}
|
|
179
|
+
* @spec openspec/changes/version-card-dutch-and-header/specs/settings-board-look/spec.md#requirement-the-admin-chrome-reads-in-the-readers-language
|
|
180
|
+
*/
|
|
181
|
+
fieldLabels() {
|
|
182
|
+
return {
|
|
183
|
+
appName: translate('nextcloud-vue', 'Application name'),
|
|
184
|
+
version: translate('nextcloud-vue', 'Version'),
|
|
185
|
+
configuredVersion: translate('nextcloud-vue', 'Configured version'),
|
|
186
|
+
...(this.labels || {}),
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
|
|
164
190
|
/** @return {string} Button type based on update status */
|
|
165
191
|
updateButtonType() {
|
|
166
192
|
if (this.isUpToDate) {
|
|
@@ -177,16 +203,18 @@ var script = {
|
|
|
177
203
|
/** @return {string} Update button label text */
|
|
178
204
|
updateButtonText() {
|
|
179
205
|
if (this.updating) {
|
|
180
|
-
return 'Updating
|
|
206
|
+
return translate('nextcloud-vue', 'Updating…')
|
|
181
207
|
}
|
|
182
208
|
if (this.isUpToDate) {
|
|
183
|
-
return 'Up to date'
|
|
209
|
+
return translate('nextcloud-vue', 'Up to date')
|
|
184
210
|
}
|
|
185
|
-
return 'Update'
|
|
211
|
+
return translate('nextcloud-vue', 'Update')
|
|
186
212
|
},
|
|
187
213
|
},
|
|
188
214
|
|
|
189
215
|
methods: {
|
|
216
|
+
t: translate,
|
|
217
|
+
|
|
190
218
|
handleUpdateClick() {
|
|
191
219
|
if (!this.updateButtonDisabled) {
|
|
192
220
|
this.$emit('update');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnVersionInfoCard.vue2.js","sources":["../../../../src/components/CnVersionInfoCard/CnVersionInfoCard.vue"],"sourcesContent":["<template>\n\t<CnSettingsSection\n\t\t:name=\"title\"\n\t\t:description=\"description\"\n\t\t:docUrl=\"docUrl\"\n\t\t:loading=\"loading\"\n\t\tloadingMessage=\"Loading version information...\">\n\t\t<!-- Actions slot (top right). Under the board look the same buttons sit\n\t\t in the footer row of the card instead. -->\n\t\t<template v-if=\"!isBoard\" #actions>\n\t\t\t<!-- Update Button -->\n\t\t\t<NcButton\n\t\t\t\tv-if=\"showUpdateButton\"\n\t\t\t\t:type=\"updateButtonType\"\n\t\t\t\t:disabled=\"updateButtonDisabled\"\n\t\t\t\t@click=\"handleUpdateClick\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<NcLoadingIcon v-if=\"updating\" :size=\"20\" />\n\t\t\t\t\t<Check v-else-if=\"isUpToDate\" :size=\"20\" />\n\t\t\t\t\t<Update v-else :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ updateButtonText }}\n\t\t\t</NcButton>\n\n\t\t\t<!-- Additional Actions (slot) -->\n\t\t\t<slot name=\"actions\" />\n\t\t</template>\n\n\t\t<!-- Main content (only shown when not loading) -->\n\t\t<div v-if=\"!loading\" class=\"cn-version-info\" :class=\"{ 'cn-version-info--board': isBoard }\">\n\t\t\t<!-- Version card with gray background -->\n\t\t\t<div class=\"cn-version-info__card\">\n\t\t\t\t<h4>{{ cardTitle }}</h4>\n\t\t\t\t<div class=\"cn-version-info__details\">\n\t\t\t\t\t<!-- Application Name -->\n\t\t\t\t\t<div class=\"cn-version-info__item\">\n\t\t\t\t\t\t<span class=\"cn-version-info__label\">{{ labels.appName }}:</span>\n\t\t\t\t\t\t<span class=\"cn-version-info__value\">{{ appName }}</span>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<!-- Version -->\n\t\t\t\t\t<div class=\"cn-version-info__item\">\n\t\t\t\t\t\t<span class=\"cn-version-info__label\">{{ labels.version }}:</span>\n\t\t\t\t\t\t<span class=\"cn-version-info__value\">{{ appVersion }}</span>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<!-- Configured Version (if provided) -->\n\t\t\t\t\t<div v-if=\"configuredVersion\" class=\"cn-version-info__item\">\n\t\t\t\t\t\t<span class=\"cn-version-info__label\">{{ labels.configuredVersion }}:</span>\n\t\t\t\t\t\t<span class=\"cn-version-info__value\">{{ configuredVersion }}</span>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<!-- Additional items -->\n\t\t\t\t\t<div v-for=\"item in additionalItems\" :key=\"item.label\" class=\"cn-version-info__item\">\n\t\t\t\t\t\t<span class=\"cn-version-info__label\">{{ item.label }}:</span>\n\t\t\t\t\t\t<span class=\"cn-version-info__value\" :class=\"item.statusClass\">{{ item.value }}</span>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<!-- Optional additional items slot -->\n\t\t\t\t\t<slot name=\"additional-items\" />\n\t\t\t\t</div>\n\n\t\t\t\t<!-- The state, then the actions (re-import), after a hairline. -->\n\t\t\t\t<div v-if=\"isBoard\" class=\"cn-version-info__footer-row\" data-testid=\"cn-version-info-footer-row\">\n\t\t\t\t\t<NcButton\n\t\t\t\t\t\tv-if=\"showUpdateButton\"\n\t\t\t\t\t\t:type=\"updateButtonType\"\n\t\t\t\t\t\t:disabled=\"updateButtonDisabled\"\n\t\t\t\t\t\t@click=\"handleUpdateClick\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<NcLoadingIcon v-if=\"updating\" :size=\"20\" />\n\t\t\t\t\t\t\t<Check v-else-if=\"isUpToDate\" :size=\"20\" />\n\t\t\t\t\t\t\t<Update v-else :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ updateButtonText }}\n\t\t\t\t\t</NcButton>\n\t\t\t\t\t<slot name=\"actions\" />\n\t\t\t\t</div>\n\n\t\t\t\t<!-- Optional footer slot -->\n\t\t\t\t<slot name=\"footer\" />\n\t\t\t</div>\n\n\t\t\t<!-- Optional extra cards slot -->\n\t\t\t<slot name=\"extra-cards\" />\n\t\t</div>\n\t</CnSettingsSection>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcLoadingIcon } from '@nextcloud/vue'\nimport Check from 'vue-material-design-icons/Check.vue'\nimport Update from 'vue-material-design-icons/Update.vue'\nimport { useLook } from '../../composables/useLook.js'\nimport { CnSettingsSection } from '../CnSettingsSection/index.js'\n\n/**\n * CnVersionInfoCard - App version information card for admin settings pages.\n *\n * Displays application name, version, and optional configured version with an\n * update button. Wraps CnSettingsSection for consistent admin settings layout.\n *\n * Every Conduction Nextcloud app should show this as the first section on its\n * admin settings page.\n *\n * Basic usage\n * ```vue\n * <CnVersionInfoCard app-name=\"Open Register\" app-version=\"0.2.3\" />\n * ```\n *\n * With update button\n * ```vue\n * <CnVersionInfoCard\n * app-name=\"Open Register\"\n * app-version=\"0.2.3\"\n * configured-version=\"0.2.2\"\n * :is-up-to-date=\"false\"\n * :show-update-button=\"true\"\n * :updating=\"isUpdating\"\n * @update=\"runUpdate\" />\n * ```\n *\n * With additional items and actions\n * ```vue\n * <CnVersionInfoCard\n * app-name=\"Pipelinq\"\n * app-version=\"0.1.7\"\n * :additional-items=\"[{ label: 'Database', value: 'Connected', statusClass: 'cn-version-info__status--ok' }]\">\n * <template #actions>\n * <NcButton @click=\"clearCache\">Clear App Store Cache</NcButton>\n * </template>\n * </CnVersionInfoCard>\n * ```\n */\nexport default {\n\tname: 'CnVersionInfoCard',\n\n\tcomponents: {\n\t\tCnSettingsSection,\n\t\tNcLoadingIcon,\n\t\tNcButton,\n\t\tCheck,\n\t\tUpdate,\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The look the card is drawn in: `board` or `nextcloud`. Empty follows\n\t\t * the `cnLook` that CnAppRoot provides. Under `board` the facts are a\n\t\t * two-column list and the actions sit in a footer row.\n\t\t *\n\t\t * @spec openspec/changes/screens-chrome-parity/specs/settings-board-look/spec.md#requirement-the-version-card-takes-the-board-facts-and-footer\n\t\t */\n\t\tlook: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Section title */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Version information'),\n\t\t},\n\n\t\t/** Section description */\n\t\tdescription: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Information about the current application installation'),\n\t\t},\n\n\t\t/** Documentation URL (shows info icon next to title) */\n\t\tdocUrl: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Card heading text */\n\t\tcardTitle: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Application information'),\n\t\t},\n\n\t\t/** Application name to display */\n\t\tappName: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Application version string */\n\t\tappVersion: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Configured version (optional, for apps that track configuration versions separately) */\n\t\tconfiguredVersion: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Whether the app configuration is up to date */\n\t\tisUpToDate: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/** Whether to show the update button */\n\t\tshowUpdateButton: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Whether an update is currently in progress */\n\t\tupdating: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Additional key-value items to display.\n\t\t * Format: [{ label: 'Label', value: 'Value', statusClass: 'cn-version-info__status--ok' }]\n\t\t */\n\t\tadditionalItems: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** Whether version info is loading */\n\t\tloading: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Custom labels for the standard fields */\n\t\tlabels: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({\n\t\t\t\tappName: 'Application Name',\n\t\t\t\tversion: 'Version',\n\t\t\t\tconfiguredVersion: 'Configured Version',\n\t\t\t}),\n\t\t},\n\t},\n\n\temits: ['update'],\n\n\tsetup(props) {\n\t\tconst { isBoard } = useLook(props)\n\t\treturn { isBoard }\n\t},\n\n\tcomputed: {\n\t\t/** @return {string} Button type based on update status */\n\t\tupdateButtonType() {\n\t\t\tif (this.isUpToDate) {\n\t\t\t\treturn 'success'\n\t\t\t}\n\t\t\treturn 'error'\n\t\t},\n\n\t\t/** @return {boolean} Whether the update button should be disabled */\n\t\tupdateButtonDisabled() {\n\t\t\treturn this.isUpToDate || this.updating\n\t\t},\n\n\t\t/** @return {string} Update button label text */\n\t\tupdateButtonText() {\n\t\t\tif (this.updating) {\n\t\t\t\treturn 'Updating...'\n\t\t\t}\n\t\t\tif (this.isUpToDate) {\n\t\t\t\treturn 'Up to date'\n\t\t\t}\n\t\t\treturn 'Update'\n\t\t},\n\t},\n\n\tmethods: {\n\t\thandleUpdateClick() {\n\t\t\tif (!this.updateButtonDisabled) {\n\t\t\t\tthis.$emit('update')\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-version-info__card {\n\tbackground: var(--color-background-hover);\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-large);\n\tpadding: 20px;\n\tmargin-bottom: 20px;\n}\n\n.cn-version-info__card h4 {\n\tmargin: 0 0 16px 0;\n\tfont-size: 16px;\n\tfont-weight: 600;\n\tcolor: var(--color-main-text);\n}\n\n.cn-version-info__details {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 12px;\n}\n\n.cn-version-info__item {\n\tdisplay: flex;\n\tjustify-content: space-between;\n\talign-items: center;\n\tpadding: 8px 0;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-version-info__item:last-child {\n\tborder-bottom: none;\n}\n\n.cn-version-info__label {\n\tfont-weight: 500;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 14px;\n}\n\n.cn-version-info__value {\n\tfont-family: 'Courier New', Courier, monospace;\n\tfont-weight: 600;\n\tcolor: var(--color-main-text);\n\tfont-size: 14px;\n}\n\n/* Status classes for values */\n.cn-version-info__status--ok {\n\tcolor: var(--color-success);\n\tfont-weight: 600;\n}\n\n.cn-version-info__status--warning {\n\tcolor: var(--color-warning);\n\tfont-weight: 600;\n}\n\n.cn-version-info__status--error {\n\tcolor: var(--color-error);\n\tfont-weight: 600;\n}\n\n@media (max-width: 768px) {\n\t.cn-version-info__item {\n\t\tflex-direction: column;\n\t\talign-items: flex-start;\n\t\tgap: 4px;\n\t}\n\n\t.cn-version-info__label {\n\t\tfont-weight: 600;\n\t}\n\n\t.cn-version-info__value {\n\t\tword-break: break-all;\n\t}\n}\n</style>\n"],"names":["CnSettingsSection","t"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnVersionInfoCard.vue2.js","sources":["../../../../src/components/CnVersionInfoCard/CnVersionInfoCard.vue"],"sourcesContent":["<template>\n\t<CnSettingsSection\n\t\t:name=\"title\"\n\t\t:description=\"description\"\n\t\t:docUrl=\"docUrl\"\n\t\t:loading=\"loading\"\n\t\t:wide=\"isBoard && wide\"\n\t\t:loadingMessage=\"t('nextcloud-vue', 'Loading version information…')\">\n\t\t<!-- Actions slot (top right). Under the board look the same buttons sit\n\t\t in the footer row of the card instead. -->\n\t\t<template v-if=\"!isBoard\" #actions>\n\t\t\t<!-- Update Button -->\n\t\t\t<NcButton\n\t\t\t\tv-if=\"showUpdateButton\"\n\t\t\t\t:type=\"updateButtonType\"\n\t\t\t\t:disabled=\"updateButtonDisabled\"\n\t\t\t\t@click=\"handleUpdateClick\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<NcLoadingIcon v-if=\"updating\" :size=\"20\" />\n\t\t\t\t\t<Check v-else-if=\"isUpToDate\" :size=\"20\" />\n\t\t\t\t\t<Update v-else :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ updateButtonText }}\n\t\t\t</NcButton>\n\n\t\t\t<!-- Additional Actions (slot) -->\n\t\t\t<slot name=\"actions\" />\n\t\t</template>\n\n\t\t<!-- Main content (only shown when not loading) -->\n\t\t<div v-if=\"!loading\" class=\"cn-version-info\" :class=\"{ 'cn-version-info--board': isBoard }\">\n\t\t\t<!-- Version card with gray background -->\n\t\t\t<div class=\"cn-version-info__card\">\n\t\t\t\t<h4>{{ cardTitle }}</h4>\n\t\t\t\t<div class=\"cn-version-info__details\">\n\t\t\t\t\t<!-- Application Name -->\n\t\t\t\t\t<div class=\"cn-version-info__item\">\n\t\t\t\t\t\t<span class=\"cn-version-info__label\">{{ fieldLabels.appName }}:</span>\n\t\t\t\t\t\t<span class=\"cn-version-info__value\">{{ appName }}</span>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<!-- Version -->\n\t\t\t\t\t<div class=\"cn-version-info__item\">\n\t\t\t\t\t\t<span class=\"cn-version-info__label\">{{ fieldLabels.version }}:</span>\n\t\t\t\t\t\t<span class=\"cn-version-info__value\">{{ appVersion }}</span>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<!-- Configured Version (if provided) -->\n\t\t\t\t\t<div v-if=\"configuredVersion\" class=\"cn-version-info__item\">\n\t\t\t\t\t\t<span class=\"cn-version-info__label\">{{ fieldLabels.configuredVersion }}:</span>\n\t\t\t\t\t\t<span class=\"cn-version-info__value\">{{ configuredVersion }}</span>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<!-- Additional items -->\n\t\t\t\t\t<div v-for=\"item in additionalItems\" :key=\"item.label\" class=\"cn-version-info__item\">\n\t\t\t\t\t\t<span class=\"cn-version-info__label\">{{ item.label }}:</span>\n\t\t\t\t\t\t<span class=\"cn-version-info__value\" :class=\"item.statusClass\">{{ item.value }}</span>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<!-- Optional additional items slot -->\n\t\t\t\t\t<slot name=\"additional-items\" />\n\t\t\t\t</div>\n\n\t\t\t\t<!-- The state, then the actions (re-import), after a hairline. -->\n\t\t\t\t<div v-if=\"isBoard\" class=\"cn-version-info__footer-row\" data-testid=\"cn-version-info-footer-row\">\n\t\t\t\t\t<NcButton\n\t\t\t\t\t\tv-if=\"showUpdateButton\"\n\t\t\t\t\t\t:type=\"updateButtonType\"\n\t\t\t\t\t\t:disabled=\"updateButtonDisabled\"\n\t\t\t\t\t\t@click=\"handleUpdateClick\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<NcLoadingIcon v-if=\"updating\" :size=\"20\" />\n\t\t\t\t\t\t\t<Check v-else-if=\"isUpToDate\" :size=\"20\" />\n\t\t\t\t\t\t\t<Update v-else :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ updateButtonText }}\n\t\t\t\t\t</NcButton>\n\t\t\t\t\t<slot name=\"actions\" />\n\t\t\t\t</div>\n\n\t\t\t\t<!-- Optional footer slot -->\n\t\t\t\t<slot name=\"footer\" />\n\t\t\t</div>\n\n\t\t\t<!-- Optional extra cards slot -->\n\t\t\t<slot name=\"extra-cards\" />\n\t\t</div>\n\t</CnSettingsSection>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcLoadingIcon } from '@nextcloud/vue'\nimport Check from 'vue-material-design-icons/Check.vue'\nimport Update from 'vue-material-design-icons/Update.vue'\nimport { useLook } from '../../composables/useLook.js'\nimport { CnSettingsSection } from '../CnSettingsSection/index.js'\n\n/**\n * CnVersionInfoCard - App version information card for admin settings pages.\n *\n * Displays application name, version, and optional configured version with an\n * update button. Wraps CnSettingsSection for consistent admin settings layout.\n *\n * Every Conduction Nextcloud app should show this as the first section on its\n * admin settings page.\n *\n * Basic usage\n * ```vue\n * <CnVersionInfoCard app-name=\"Open Register\" app-version=\"0.2.3\" />\n * ```\n *\n * With update button\n * ```vue\n * <CnVersionInfoCard\n * app-name=\"Open Register\"\n * app-version=\"0.2.3\"\n * configured-version=\"0.2.2\"\n * :is-up-to-date=\"false\"\n * :show-update-button=\"true\"\n * :updating=\"isUpdating\"\n * @update=\"runUpdate\" />\n * ```\n *\n * With additional items and actions\n * ```vue\n * <CnVersionInfoCard\n * app-name=\"Pipelinq\"\n * app-version=\"0.1.7\"\n * :additional-items=\"[{ label: 'Database', value: 'Connected', statusClass: 'cn-version-info__status--ok' }]\">\n * <template #actions>\n * <NcButton @click=\"clearCache\">Clear App Store Cache</NcButton>\n * </template>\n * </CnVersionInfoCard>\n * ```\n */\nexport default {\n\tname: 'CnVersionInfoCard',\n\n\tcomponents: {\n\t\tCnSettingsSection,\n\t\tNcLoadingIcon,\n\t\tNcButton,\n\t\tCheck,\n\t\tUpdate,\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The look the card is drawn in: `board` or `nextcloud`. Empty follows\n\t\t * the `cnLook` that CnAppRoot provides. Under `board` the facts are a\n\t\t * two-column list and the actions sit in a footer row.\n\t\t *\n\t\t * @spec openspec/changes/screens-chrome-parity/specs/settings-board-look/spec.md#requirement-the-version-card-takes-the-board-facts-and-footer\n\t\t */\n\t\tlook: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Under the board look the card spans the whole settings grid, as the\n\t\t * boards draw the version card. Set to `false` to keep it one card in\n\t\t * the grid. Without the board look it has no effect.\n\t\t *\n\t\t * @spec openspec/changes/board-version-card-full-width/specs/settings-board-look/spec.md#requirement-the-board-version-card-spans-the-settings-grid\n\t\t */\n\t\twide: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/** Section title */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Version information'),\n\t\t},\n\n\t\t/** Section description */\n\t\tdescription: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Information about the current application installation'),\n\t\t},\n\n\t\t/** Documentation URL (shows info icon next to title) */\n\t\tdocUrl: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Card heading text */\n\t\tcardTitle: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Application information'),\n\t\t},\n\n\t\t/** Application name to display */\n\t\tappName: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Application version string */\n\t\tappVersion: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Configured version (optional, for apps that track configuration versions separately) */\n\t\tconfiguredVersion: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Whether the app configuration is up to date */\n\t\tisUpToDate: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/** Whether to show the update button */\n\t\tshowUpdateButton: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Whether an update is currently in progress */\n\t\tupdating: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Additional key-value items to display.\n\t\t * Format: [{ label: 'Label', value: 'Value', statusClass: 'cn-version-info__status--ok' }]\n\t\t */\n\t\tadditionalItems: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** Whether version info is loading */\n\t\tloading: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Custom labels for the standard fields, `{ appName?, version?, configuredVersion? }`.\n\t\t * A label left out keeps the translated default.\n\t\t */\n\t\tlabels: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\t},\n\n\temits: ['update'],\n\n\tsetup(props) {\n\t\tconst { isBoard } = useLook(props)\n\t\treturn { isBoard }\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The field labels: the app's, else the library's in the reader's language.\n\t\t *\n\t\t * @return {{appName: string, version: string, configuredVersion: string}}\n\t\t * @spec openspec/changes/version-card-dutch-and-header/specs/settings-board-look/spec.md#requirement-the-admin-chrome-reads-in-the-readers-language\n\t\t */\n\t\tfieldLabels() {\n\t\t\treturn {\n\t\t\t\tappName: t('nextcloud-vue', 'Application name'),\n\t\t\t\tversion: t('nextcloud-vue', 'Version'),\n\t\t\t\tconfiguredVersion: t('nextcloud-vue', 'Configured version'),\n\t\t\t\t...(this.labels || {}),\n\t\t\t}\n\t\t},\n\n\t\t/** @return {string} Button type based on update status */\n\t\tupdateButtonType() {\n\t\t\tif (this.isUpToDate) {\n\t\t\t\treturn 'success'\n\t\t\t}\n\t\t\treturn 'error'\n\t\t},\n\n\t\t/** @return {boolean} Whether the update button should be disabled */\n\t\tupdateButtonDisabled() {\n\t\t\treturn this.isUpToDate || this.updating\n\t\t},\n\n\t\t/** @return {string} Update button label text */\n\t\tupdateButtonText() {\n\t\t\tif (this.updating) {\n\t\t\t\treturn t('nextcloud-vue', 'Updating…')\n\t\t\t}\n\t\t\tif (this.isUpToDate) {\n\t\t\t\treturn t('nextcloud-vue', 'Up to date')\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', 'Update')\n\t\t},\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\thandleUpdateClick() {\n\t\t\tif (!this.updateButtonDisabled) {\n\t\t\t\tthis.$emit('update')\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-version-info__card {\n\tbackground: var(--color-background-hover);\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-large);\n\tpadding: 20px;\n\tmargin-bottom: 20px;\n}\n\n.cn-version-info__card h4 {\n\tmargin: 0 0 16px 0;\n\tfont-size: 16px;\n\tfont-weight: 600;\n\tcolor: var(--color-main-text);\n}\n\n.cn-version-info__details {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 12px;\n}\n\n.cn-version-info__item {\n\tdisplay: flex;\n\tjustify-content: space-between;\n\talign-items: center;\n\tpadding: 8px 0;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-version-info__item:last-child {\n\tborder-bottom: none;\n}\n\n.cn-version-info__label {\n\tfont-weight: 500;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 14px;\n}\n\n.cn-version-info__value {\n\tfont-family: 'Courier New', Courier, monospace;\n\tfont-weight: 600;\n\tcolor: var(--color-main-text);\n\tfont-size: 14px;\n}\n\n/* Status classes for values */\n.cn-version-info__status--ok {\n\tcolor: var(--color-success);\n\tfont-weight: 600;\n}\n\n.cn-version-info__status--warning {\n\tcolor: var(--color-warning);\n\tfont-weight: 600;\n}\n\n.cn-version-info__status--error {\n\tcolor: var(--color-error);\n\tfont-weight: 600;\n}\n\n@media (max-width: 768px) {\n\t.cn-version-info__item {\n\t\tflex-direction: column;\n\t\talign-items: flex-start;\n\t\tgap: 4px;\n\t}\n\n\t.cn-version-info__label {\n\t\tfont-weight: 600;\n\t}\n\n\t.cn-version-info__value {\n\t\tword-break: break-all;\n\t}\n}\n</style>\n"],"names":["CnSettingsSection","t"],"mappings":"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"}
|
|
@@ -33,7 +33,8 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
33
33
|
description: $props.description,
|
|
34
34
|
docUrl: $props.docUrl,
|
|
35
35
|
loading: $props.loading,
|
|
36
|
-
|
|
36
|
+
wide: $setup.isBoard && $props.wide,
|
|
37
|
+
loadingMessage: $options.t('nextcloud-vue', 'Loading version information…')
|
|
37
38
|
}, createSlots({
|
|
38
39
|
default: withCtx(() => [
|
|
39
40
|
(!$props.loading)
|
|
@@ -45,16 +46,16 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
45
46
|
createElementVNode("h4", null, toDisplayString($props.cardTitle), 1 /* TEXT */),
|
|
46
47
|
createElementVNode("div", _hoisted_2, [
|
|
47
48
|
createElementVNode("div", _hoisted_3, [
|
|
48
|
-
createElementVNode("span", _hoisted_4, toDisplayString($
|
|
49
|
+
createElementVNode("span", _hoisted_4, toDisplayString($options.fieldLabels.appName) + ":", 1 /* TEXT */),
|
|
49
50
|
createElementVNode("span", _hoisted_5, toDisplayString($props.appName), 1 /* TEXT */)
|
|
50
51
|
]),
|
|
51
52
|
createElementVNode("div", _hoisted_6, [
|
|
52
|
-
createElementVNode("span", _hoisted_7, toDisplayString($
|
|
53
|
+
createElementVNode("span", _hoisted_7, toDisplayString($options.fieldLabels.version) + ":", 1 /* TEXT */),
|
|
53
54
|
createElementVNode("span", _hoisted_8, toDisplayString($props.appVersion), 1 /* TEXT */)
|
|
54
55
|
]),
|
|
55
56
|
($props.configuredVersion)
|
|
56
57
|
? (openBlock(), createElementBlock("div", _hoisted_9, [
|
|
57
|
-
createElementVNode("span", _hoisted_10, toDisplayString($
|
|
58
|
+
createElementVNode("span", _hoisted_10, toDisplayString($options.fieldLabels.configuredVersion) + ":", 1 /* TEXT */),
|
|
58
59
|
createElementVNode("span", _hoisted_11, toDisplayString($props.configuredVersion), 1 /* TEXT */)
|
|
59
60
|
]))
|
|
60
61
|
: createCommentVNode("v-if", true),
|
|
@@ -151,7 +152,7 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
151
152
|
key: "0"
|
|
152
153
|
}
|
|
153
154
|
: undefined
|
|
154
|
-
]), 1032 /* PROPS, DYNAMIC_SLOTS */, ["name", "description", "docUrl", "loading"]))
|
|
155
|
+
]), 1032 /* PROPS, DYNAMIC_SLOTS */, ["name", "description", "docUrl", "loading", "wide", "loadingMessage"]))
|
|
155
156
|
}
|
|
156
157
|
|
|
157
158
|
export { render };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnVersionInfoCard.vue3.js","sources":["../../../../src/components/CnVersionInfoCard/CnVersionInfoCard.vue?vue&type=template&id=7a828af4&lang.js"],"sourcesContent":["<template>\n\t<CnSettingsSection\n\t\t:name=\"title\"\n\t\t:description=\"description\"\n\t\t:docUrl=\"docUrl\"\n\t\t:loading=\"loading\"\n\t\tloadingMessage=\"Loading version information...\">\n\t\t<!-- Actions slot (top right). Under the board look the same buttons sit\n\t\t in the footer row of the card instead. -->\n\t\t<template v-if=\"!isBoard\" #actions>\n\t\t\t<!-- Update Button -->\n\t\t\t<NcButton\n\t\t\t\tv-if=\"showUpdateButton\"\n\t\t\t\t:type=\"updateButtonType\"\n\t\t\t\t:disabled=\"updateButtonDisabled\"\n\t\t\t\t@click=\"handleUpdateClick\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<NcLoadingIcon v-if=\"updating\" :size=\"20\" />\n\t\t\t\t\t<Check v-else-if=\"isUpToDate\" :size=\"20\" />\n\t\t\t\t\t<Update v-else :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ updateButtonText }}\n\t\t\t</NcButton>\n\n\t\t\t<!-- Additional Actions (slot) -->\n\t\t\t<slot name=\"actions\" />\n\t\t</template>\n\n\t\t<!-- Main content (only shown when not loading) -->\n\t\t<div v-if=\"!loading\" class=\"cn-version-info\" :class=\"{ 'cn-version-info--board': isBoard }\">\n\t\t\t<!-- Version card with gray background -->\n\t\t\t<div class=\"cn-version-info__card\">\n\t\t\t\t<h4>{{ cardTitle }}</h4>\n\t\t\t\t<div class=\"cn-version-info__details\">\n\t\t\t\t\t<!-- Application Name -->\n\t\t\t\t\t<div class=\"cn-version-info__item\">\n\t\t\t\t\t\t<span class=\"cn-version-info__label\">{{ labels.appName }}:</span>\n\t\t\t\t\t\t<span class=\"cn-version-info__value\">{{ appName }}</span>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<!-- Version -->\n\t\t\t\t\t<div class=\"cn-version-info__item\">\n\t\t\t\t\t\t<span class=\"cn-version-info__label\">{{ labels.version }}:</span>\n\t\t\t\t\t\t<span class=\"cn-version-info__value\">{{ appVersion }}</span>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<!-- Configured Version (if provided) -->\n\t\t\t\t\t<div v-if=\"configuredVersion\" class=\"cn-version-info__item\">\n\t\t\t\t\t\t<span class=\"cn-version-info__label\">{{ labels.configuredVersion }}:</span>\n\t\t\t\t\t\t<span class=\"cn-version-info__value\">{{ configuredVersion }}</span>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<!-- Additional items -->\n\t\t\t\t\t<div v-for=\"item in additionalItems\" :key=\"item.label\" class=\"cn-version-info__item\">\n\t\t\t\t\t\t<span class=\"cn-version-info__label\">{{ item.label }}:</span>\n\t\t\t\t\t\t<span class=\"cn-version-info__value\" :class=\"item.statusClass\">{{ item.value }}</span>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<!-- Optional additional items slot -->\n\t\t\t\t\t<slot name=\"additional-items\" />\n\t\t\t\t</div>\n\n\t\t\t\t<!-- The state, then the actions (re-import), after a hairline. -->\n\t\t\t\t<div v-if=\"isBoard\" class=\"cn-version-info__footer-row\" data-testid=\"cn-version-info-footer-row\">\n\t\t\t\t\t<NcButton\n\t\t\t\t\t\tv-if=\"showUpdateButton\"\n\t\t\t\t\t\t:type=\"updateButtonType\"\n\t\t\t\t\t\t:disabled=\"updateButtonDisabled\"\n\t\t\t\t\t\t@click=\"handleUpdateClick\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<NcLoadingIcon v-if=\"updating\" :size=\"20\" />\n\t\t\t\t\t\t\t<Check v-else-if=\"isUpToDate\" :size=\"20\" />\n\t\t\t\t\t\t\t<Update v-else :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ updateButtonText }}\n\t\t\t\t\t</NcButton>\n\t\t\t\t\t<slot name=\"actions\" />\n\t\t\t\t</div>\n\n\t\t\t\t<!-- Optional footer slot -->\n\t\t\t\t<slot name=\"footer\" />\n\t\t\t</div>\n\n\t\t\t<!-- Optional extra cards slot -->\n\t\t\t<slot name=\"extra-cards\" />\n\t\t</div>\n\t</CnSettingsSection>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcLoadingIcon } from '@nextcloud/vue'\nimport Check from 'vue-material-design-icons/Check.vue'\nimport Update from 'vue-material-design-icons/Update.vue'\nimport { useLook } from '../../composables/useLook.js'\nimport { CnSettingsSection } from '../CnSettingsSection/index.js'\n\n/**\n * CnVersionInfoCard - App version information card for admin settings pages.\n *\n * Displays application name, version, and optional configured version with an\n * update button. Wraps CnSettingsSection for consistent admin settings layout.\n *\n * Every Conduction Nextcloud app should show this as the first section on its\n * admin settings page.\n *\n * Basic usage\n * ```vue\n * <CnVersionInfoCard app-name=\"Open Register\" app-version=\"0.2.3\" />\n * ```\n *\n * With update button\n * ```vue\n * <CnVersionInfoCard\n * app-name=\"Open Register\"\n * app-version=\"0.2.3\"\n * configured-version=\"0.2.2\"\n * :is-up-to-date=\"false\"\n * :show-update-button=\"true\"\n * :updating=\"isUpdating\"\n * @update=\"runUpdate\" />\n * ```\n *\n * With additional items and actions\n * ```vue\n * <CnVersionInfoCard\n * app-name=\"Pipelinq\"\n * app-version=\"0.1.7\"\n * :additional-items=\"[{ label: 'Database', value: 'Connected', statusClass: 'cn-version-info__status--ok' }]\">\n * <template #actions>\n * <NcButton @click=\"clearCache\">Clear App Store Cache</NcButton>\n * </template>\n * </CnVersionInfoCard>\n * ```\n */\nexport default {\n\tname: 'CnVersionInfoCard',\n\n\tcomponents: {\n\t\tCnSettingsSection,\n\t\tNcLoadingIcon,\n\t\tNcButton,\n\t\tCheck,\n\t\tUpdate,\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The look the card is drawn in: `board` or `nextcloud`. Empty follows\n\t\t * the `cnLook` that CnAppRoot provides. Under `board` the facts are a\n\t\t * two-column list and the actions sit in a footer row.\n\t\t *\n\t\t * @spec openspec/changes/screens-chrome-parity/specs/settings-board-look/spec.md#requirement-the-version-card-takes-the-board-facts-and-footer\n\t\t */\n\t\tlook: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Section title */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Version information'),\n\t\t},\n\n\t\t/** Section description */\n\t\tdescription: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Information about the current application installation'),\n\t\t},\n\n\t\t/** Documentation URL (shows info icon next to title) */\n\t\tdocUrl: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Card heading text */\n\t\tcardTitle: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Application information'),\n\t\t},\n\n\t\t/** Application name to display */\n\t\tappName: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Application version string */\n\t\tappVersion: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Configured version (optional, for apps that track configuration versions separately) */\n\t\tconfiguredVersion: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Whether the app configuration is up to date */\n\t\tisUpToDate: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/** Whether to show the update button */\n\t\tshowUpdateButton: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Whether an update is currently in progress */\n\t\tupdating: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Additional key-value items to display.\n\t\t * Format: [{ label: 'Label', value: 'Value', statusClass: 'cn-version-info__status--ok' }]\n\t\t */\n\t\tadditionalItems: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** Whether version info is loading */\n\t\tloading: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Custom labels for the standard fields */\n\t\tlabels: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({\n\t\t\t\tappName: 'Application Name',\n\t\t\t\tversion: 'Version',\n\t\t\t\tconfiguredVersion: 'Configured Version',\n\t\t\t}),\n\t\t},\n\t},\n\n\temits: ['update'],\n\n\tsetup(props) {\n\t\tconst { isBoard } = useLook(props)\n\t\treturn { isBoard }\n\t},\n\n\tcomputed: {\n\t\t/** @return {string} Button type based on update status */\n\t\tupdateButtonType() {\n\t\t\tif (this.isUpToDate) {\n\t\t\t\treturn 'success'\n\t\t\t}\n\t\t\treturn 'error'\n\t\t},\n\n\t\t/** @return {boolean} Whether the update button should be disabled */\n\t\tupdateButtonDisabled() {\n\t\t\treturn this.isUpToDate || this.updating\n\t\t},\n\n\t\t/** @return {string} Update button label text */\n\t\tupdateButtonText() {\n\t\t\tif (this.updating) {\n\t\t\t\treturn 'Updating...'\n\t\t\t}\n\t\t\tif (this.isUpToDate) {\n\t\t\t\treturn 'Up to date'\n\t\t\t}\n\t\t\treturn 'Update'\n\t\t},\n\t},\n\n\tmethods: {\n\t\thandleUpdateClick() {\n\t\t\tif (!this.updateButtonDisabled) {\n\t\t\t\tthis.$emit('update')\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-version-info__card {\n\tbackground: var(--color-background-hover);\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-large);\n\tpadding: 20px;\n\tmargin-bottom: 20px;\n}\n\n.cn-version-info__card h4 {\n\tmargin: 0 0 16px 0;\n\tfont-size: 16px;\n\tfont-weight: 600;\n\tcolor: var(--color-main-text);\n}\n\n.cn-version-info__details {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 12px;\n}\n\n.cn-version-info__item {\n\tdisplay: flex;\n\tjustify-content: space-between;\n\talign-items: center;\n\tpadding: 8px 0;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-version-info__item:last-child {\n\tborder-bottom: none;\n}\n\n.cn-version-info__label {\n\tfont-weight: 500;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 14px;\n}\n\n.cn-version-info__value {\n\tfont-family: 'Courier New', Courier, monospace;\n\tfont-weight: 600;\n\tcolor: var(--color-main-text);\n\tfont-size: 14px;\n}\n\n/* Status classes for values */\n.cn-version-info__status--ok {\n\tcolor: var(--color-success);\n\tfont-weight: 600;\n}\n\n.cn-version-info__status--warning {\n\tcolor: var(--color-warning);\n\tfont-weight: 600;\n}\n\n.cn-version-info__status--error {\n\tcolor: var(--color-error);\n\tfont-weight: 600;\n}\n\n@media (max-width: 768px) {\n\t.cn-version-info__item {\n\t\tflex-direction: column;\n\t\talign-items: flex-start;\n\t\tgap: 4px;\n\t}\n\n\t.cn-version-info__label {\n\t\tfont-weight: 600;\n\t}\n\n\t.cn-version-info__value {\n\t\tword-break: break-all;\n\t}\n}\n</style>\n"],"names":["_createBlock","_createElementBlock","_normalizeClass","_createElementVNode","_toDisplayString","_openBlock","_Fragment","_renderList","_renderSlot","_createTextVNode"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnVersionInfoCard.vue3.js","sources":["../../../../src/components/CnVersionInfoCard/CnVersionInfoCard.vue?vue&type=template&id=17db98e4&lang.js"],"sourcesContent":["<template>\n\t<CnSettingsSection\n\t\t:name=\"title\"\n\t\t:description=\"description\"\n\t\t:docUrl=\"docUrl\"\n\t\t:loading=\"loading\"\n\t\t:wide=\"isBoard && wide\"\n\t\t:loadingMessage=\"t('nextcloud-vue', 'Loading version information…')\">\n\t\t<!-- Actions slot (top right). Under the board look the same buttons sit\n\t\t in the footer row of the card instead. -->\n\t\t<template v-if=\"!isBoard\" #actions>\n\t\t\t<!-- Update Button -->\n\t\t\t<NcButton\n\t\t\t\tv-if=\"showUpdateButton\"\n\t\t\t\t:type=\"updateButtonType\"\n\t\t\t\t:disabled=\"updateButtonDisabled\"\n\t\t\t\t@click=\"handleUpdateClick\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<NcLoadingIcon v-if=\"updating\" :size=\"20\" />\n\t\t\t\t\t<Check v-else-if=\"isUpToDate\" :size=\"20\" />\n\t\t\t\t\t<Update v-else :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ updateButtonText }}\n\t\t\t</NcButton>\n\n\t\t\t<!-- Additional Actions (slot) -->\n\t\t\t<slot name=\"actions\" />\n\t\t</template>\n\n\t\t<!-- Main content (only shown when not loading) -->\n\t\t<div v-if=\"!loading\" class=\"cn-version-info\" :class=\"{ 'cn-version-info--board': isBoard }\">\n\t\t\t<!-- Version card with gray background -->\n\t\t\t<div class=\"cn-version-info__card\">\n\t\t\t\t<h4>{{ cardTitle }}</h4>\n\t\t\t\t<div class=\"cn-version-info__details\">\n\t\t\t\t\t<!-- Application Name -->\n\t\t\t\t\t<div class=\"cn-version-info__item\">\n\t\t\t\t\t\t<span class=\"cn-version-info__label\">{{ fieldLabels.appName }}:</span>\n\t\t\t\t\t\t<span class=\"cn-version-info__value\">{{ appName }}</span>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<!-- Version -->\n\t\t\t\t\t<div class=\"cn-version-info__item\">\n\t\t\t\t\t\t<span class=\"cn-version-info__label\">{{ fieldLabels.version }}:</span>\n\t\t\t\t\t\t<span class=\"cn-version-info__value\">{{ appVersion }}</span>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<!-- Configured Version (if provided) -->\n\t\t\t\t\t<div v-if=\"configuredVersion\" class=\"cn-version-info__item\">\n\t\t\t\t\t\t<span class=\"cn-version-info__label\">{{ fieldLabels.configuredVersion }}:</span>\n\t\t\t\t\t\t<span class=\"cn-version-info__value\">{{ configuredVersion }}</span>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<!-- Additional items -->\n\t\t\t\t\t<div v-for=\"item in additionalItems\" :key=\"item.label\" class=\"cn-version-info__item\">\n\t\t\t\t\t\t<span class=\"cn-version-info__label\">{{ item.label }}:</span>\n\t\t\t\t\t\t<span class=\"cn-version-info__value\" :class=\"item.statusClass\">{{ item.value }}</span>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<!-- Optional additional items slot -->\n\t\t\t\t\t<slot name=\"additional-items\" />\n\t\t\t\t</div>\n\n\t\t\t\t<!-- The state, then the actions (re-import), after a hairline. -->\n\t\t\t\t<div v-if=\"isBoard\" class=\"cn-version-info__footer-row\" data-testid=\"cn-version-info-footer-row\">\n\t\t\t\t\t<NcButton\n\t\t\t\t\t\tv-if=\"showUpdateButton\"\n\t\t\t\t\t\t:type=\"updateButtonType\"\n\t\t\t\t\t\t:disabled=\"updateButtonDisabled\"\n\t\t\t\t\t\t@click=\"handleUpdateClick\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<NcLoadingIcon v-if=\"updating\" :size=\"20\" />\n\t\t\t\t\t\t\t<Check v-else-if=\"isUpToDate\" :size=\"20\" />\n\t\t\t\t\t\t\t<Update v-else :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ updateButtonText }}\n\t\t\t\t\t</NcButton>\n\t\t\t\t\t<slot name=\"actions\" />\n\t\t\t\t</div>\n\n\t\t\t\t<!-- Optional footer slot -->\n\t\t\t\t<slot name=\"footer\" />\n\t\t\t</div>\n\n\t\t\t<!-- Optional extra cards slot -->\n\t\t\t<slot name=\"extra-cards\" />\n\t\t</div>\n\t</CnSettingsSection>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcLoadingIcon } from '@nextcloud/vue'\nimport Check from 'vue-material-design-icons/Check.vue'\nimport Update from 'vue-material-design-icons/Update.vue'\nimport { useLook } from '../../composables/useLook.js'\nimport { CnSettingsSection } from '../CnSettingsSection/index.js'\n\n/**\n * CnVersionInfoCard - App version information card for admin settings pages.\n *\n * Displays application name, version, and optional configured version with an\n * update button. Wraps CnSettingsSection for consistent admin settings layout.\n *\n * Every Conduction Nextcloud app should show this as the first section on its\n * admin settings page.\n *\n * Basic usage\n * ```vue\n * <CnVersionInfoCard app-name=\"Open Register\" app-version=\"0.2.3\" />\n * ```\n *\n * With update button\n * ```vue\n * <CnVersionInfoCard\n * app-name=\"Open Register\"\n * app-version=\"0.2.3\"\n * configured-version=\"0.2.2\"\n * :is-up-to-date=\"false\"\n * :show-update-button=\"true\"\n * :updating=\"isUpdating\"\n * @update=\"runUpdate\" />\n * ```\n *\n * With additional items and actions\n * ```vue\n * <CnVersionInfoCard\n * app-name=\"Pipelinq\"\n * app-version=\"0.1.7\"\n * :additional-items=\"[{ label: 'Database', value: 'Connected', statusClass: 'cn-version-info__status--ok' }]\">\n * <template #actions>\n * <NcButton @click=\"clearCache\">Clear App Store Cache</NcButton>\n * </template>\n * </CnVersionInfoCard>\n * ```\n */\nexport default {\n\tname: 'CnVersionInfoCard',\n\n\tcomponents: {\n\t\tCnSettingsSection,\n\t\tNcLoadingIcon,\n\t\tNcButton,\n\t\tCheck,\n\t\tUpdate,\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The look the card is drawn in: `board` or `nextcloud`. Empty follows\n\t\t * the `cnLook` that CnAppRoot provides. Under `board` the facts are a\n\t\t * two-column list and the actions sit in a footer row.\n\t\t *\n\t\t * @spec openspec/changes/screens-chrome-parity/specs/settings-board-look/spec.md#requirement-the-version-card-takes-the-board-facts-and-footer\n\t\t */\n\t\tlook: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Under the board look the card spans the whole settings grid, as the\n\t\t * boards draw the version card. Set to `false` to keep it one card in\n\t\t * the grid. Without the board look it has no effect.\n\t\t *\n\t\t * @spec openspec/changes/board-version-card-full-width/specs/settings-board-look/spec.md#requirement-the-board-version-card-spans-the-settings-grid\n\t\t */\n\t\twide: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/** Section title */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Version information'),\n\t\t},\n\n\t\t/** Section description */\n\t\tdescription: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Information about the current application installation'),\n\t\t},\n\n\t\t/** Documentation URL (shows info icon next to title) */\n\t\tdocUrl: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Card heading text */\n\t\tcardTitle: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Application information'),\n\t\t},\n\n\t\t/** Application name to display */\n\t\tappName: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Application version string */\n\t\tappVersion: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Configured version (optional, for apps that track configuration versions separately) */\n\t\tconfiguredVersion: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Whether the app configuration is up to date */\n\t\tisUpToDate: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/** Whether to show the update button */\n\t\tshowUpdateButton: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Whether an update is currently in progress */\n\t\tupdating: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Additional key-value items to display.\n\t\t * Format: [{ label: 'Label', value: 'Value', statusClass: 'cn-version-info__status--ok' }]\n\t\t */\n\t\tadditionalItems: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** Whether version info is loading */\n\t\tloading: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Custom labels for the standard fields, `{ appName?, version?, configuredVersion? }`.\n\t\t * A label left out keeps the translated default.\n\t\t */\n\t\tlabels: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\t},\n\n\temits: ['update'],\n\n\tsetup(props) {\n\t\tconst { isBoard } = useLook(props)\n\t\treturn { isBoard }\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The field labels: the app's, else the library's in the reader's language.\n\t\t *\n\t\t * @return {{appName: string, version: string, configuredVersion: string}}\n\t\t * @spec openspec/changes/version-card-dutch-and-header/specs/settings-board-look/spec.md#requirement-the-admin-chrome-reads-in-the-readers-language\n\t\t */\n\t\tfieldLabels() {\n\t\t\treturn {\n\t\t\t\tappName: t('nextcloud-vue', 'Application name'),\n\t\t\t\tversion: t('nextcloud-vue', 'Version'),\n\t\t\t\tconfiguredVersion: t('nextcloud-vue', 'Configured version'),\n\t\t\t\t...(this.labels || {}),\n\t\t\t}\n\t\t},\n\n\t\t/** @return {string} Button type based on update status */\n\t\tupdateButtonType() {\n\t\t\tif (this.isUpToDate) {\n\t\t\t\treturn 'success'\n\t\t\t}\n\t\t\treturn 'error'\n\t\t},\n\n\t\t/** @return {boolean} Whether the update button should be disabled */\n\t\tupdateButtonDisabled() {\n\t\t\treturn this.isUpToDate || this.updating\n\t\t},\n\n\t\t/** @return {string} Update button label text */\n\t\tupdateButtonText() {\n\t\t\tif (this.updating) {\n\t\t\t\treturn t('nextcloud-vue', 'Updating…')\n\t\t\t}\n\t\t\tif (this.isUpToDate) {\n\t\t\t\treturn t('nextcloud-vue', 'Up to date')\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', 'Update')\n\t\t},\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\thandleUpdateClick() {\n\t\t\tif (!this.updateButtonDisabled) {\n\t\t\t\tthis.$emit('update')\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-version-info__card {\n\tbackground: var(--color-background-hover);\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-large);\n\tpadding: 20px;\n\tmargin-bottom: 20px;\n}\n\n.cn-version-info__card h4 {\n\tmargin: 0 0 16px 0;\n\tfont-size: 16px;\n\tfont-weight: 600;\n\tcolor: var(--color-main-text);\n}\n\n.cn-version-info__details {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 12px;\n}\n\n.cn-version-info__item {\n\tdisplay: flex;\n\tjustify-content: space-between;\n\talign-items: center;\n\tpadding: 8px 0;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-version-info__item:last-child {\n\tborder-bottom: none;\n}\n\n.cn-version-info__label {\n\tfont-weight: 500;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 14px;\n}\n\n.cn-version-info__value {\n\tfont-family: 'Courier New', Courier, monospace;\n\tfont-weight: 600;\n\tcolor: var(--color-main-text);\n\tfont-size: 14px;\n}\n\n/* Status classes for values */\n.cn-version-info__status--ok {\n\tcolor: var(--color-success);\n\tfont-weight: 600;\n}\n\n.cn-version-info__status--warning {\n\tcolor: var(--color-warning);\n\tfont-weight: 600;\n}\n\n.cn-version-info__status--error {\n\tcolor: var(--color-error);\n\tfont-weight: 600;\n}\n\n@media (max-width: 768px) {\n\t.cn-version-info__item {\n\t\tflex-direction: column;\n\t\talign-items: flex-start;\n\t\tgap: 4px;\n\t}\n\n\t.cn-version-info__label {\n\t\tfont-weight: 600;\n\t}\n\n\t.cn-version-info__value {\n\t\tword-break: break-all;\n\t}\n}\n</style>\n"],"names":["_createBlock","_createElementBlock","_normalizeClass","_createElementVNode","_toDisplayString","_openBlock","_Fragment","_renderList","_renderSlot","_createTextVNode"],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import script from './CnWeekStripWidget.vue2.js';
|
|
|
2
2
|
import { render } from './CnWeekStripWidget.vue3.js';
|
|
3
3
|
|
|
4
4
|
script.render = render;
|
|
5
|
-
script.__scopeId = "data-v-
|
|
5
|
+
script.__scopeId = "data-v-27a717bd";
|
|
6
6
|
const __sfc_main = script;
|
|
7
7
|
|
|
8
8
|
export { __sfc_main as default };
|
|
@@ -16,7 +16,8 @@ const DEFAULT_LIMIT = 100;
|
|
|
16
16
|
*
|
|
17
17
|
* It renders the five working days by default (`days: 7` adds the weekend),
|
|
18
18
|
* highlights today, marks items that are late, and says so when a day has
|
|
19
|
-
* nothing. On a narrow screen the strip scrolls sideways
|
|
19
|
+
* nothing. On a narrow screen the strip scrolls sideways; under the board
|
|
20
|
+
* look (`.cn-look-board`) the days wrap into rows instead.
|
|
20
21
|
*
|
|
21
22
|
* Items come from an OpenRegister source (one request for the whole week) or
|
|
22
23
|
* from static `items`. Resolved by its registry type key `week-strip`.
|