@conduction/nextcloud-vue 2.109.0 → 2.110.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/CnActionDialog/CnActionDialog.vue.js +1 -1
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue2.js +115 -12
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue3.js +36 -9
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue3.js.map +1 -1
- package/dist/esm/components/CnWorkQueue/CnWorkQueue.vue.js +1 -1
- package/dist/esm/components/CnWorkQueue/CnWorkQueue.vue2.js +8 -1
- package/dist/esm/components/CnWorkQueue/CnWorkQueue.vue2.js.map +1 -1
- package/dist/esm/components/CnWorkQueue/CnWorkQueue.vue3.js.map +1 -1
- package/dist/esm/library-style.js +1 -1
- package/dist/esm/nextcloud-vue.css +33 -33
- package/dist/esm/utils/actionsDispatcher.js +5 -2
- package/dist/esm/utils/actionsDispatcher.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +281 -142
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +33 -33
- package/package.json +1 -1
- package/src/components/CnActionDialog/CnActionDialog.vue +134 -13
- package/src/components/CnWorkQueue/CnWorkQueue.vue +8 -1
- package/src/utils/actionsDispatcher.js +4 -1
|
@@ -2,7 +2,7 @@ import script from './CnWorkQueue.vue2.js';
|
|
|
2
2
|
import { render } from './CnWorkQueue.vue3.js';
|
|
3
3
|
|
|
4
4
|
script.render = render;
|
|
5
|
-
script.__scopeId = "data-v-
|
|
5
|
+
script.__scopeId = "data-v-d5bc0a42";
|
|
6
6
|
const __sfc_main = script;
|
|
7
7
|
|
|
8
8
|
export { __sfc_main as default };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import axios__default from '@nextcloud/axios';
|
|
2
|
+
import { subscribe, unsubscribe } from '@nextcloud/event-bus';
|
|
2
3
|
import { translate } from '@nextcloud/l10n';
|
|
3
4
|
import { generateUrl } from '@nextcloud/router';
|
|
4
5
|
import { NcButton, NcEmptyContent, NcLoadingIcon, NcNoteCard } from '@nextcloud/vue';
|
|
@@ -15,7 +16,8 @@ import { openRowTarget } from '../../utils/linkNavigation.js';
|
|
|
15
16
|
* not be read is named at the top rather than folded into "nothing is
|
|
16
17
|
* waiting". A group can be hidden until tomorrow, through the server, so the
|
|
17
18
|
* choice follows the reader to another device. dossiq's personal queue is
|
|
18
|
-
* the first; pipelinq's queue has the same shape.
|
|
19
|
+
* the first; pipelinq's queue has the same shape. It reads again on
|
|
20
|
+
* `cn:page:refresh`, so work planned or closed in a dialog shows at once.
|
|
19
21
|
*
|
|
20
22
|
* `content`:
|
|
21
23
|
* - `source`: an endpointSource answering `{ groups, hiddenGroups?, unavailable? }`.
|
|
@@ -82,9 +84,14 @@ var script = {
|
|
|
82
84
|
},
|
|
83
85
|
|
|
84
86
|
mounted() {
|
|
87
|
+
subscribe('cn:page:refresh', this.load);
|
|
85
88
|
this.load();
|
|
86
89
|
},
|
|
87
90
|
|
|
91
|
+
beforeUnmount() {
|
|
92
|
+
unsubscribe('cn:page:refresh', this.load);
|
|
93
|
+
},
|
|
94
|
+
|
|
88
95
|
methods: {
|
|
89
96
|
t: translate,
|
|
90
97
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnWorkQueue.vue2.js","sources":["../../../../src/components/CnWorkQueue/CnWorkQueue.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<div class=\"cn-work-queue\" data-testid=\"cn-work-queue\">\n\t\t<div v-if=\"title || $slots.actions\" class=\"cn-work-queue__head\">\n\t\t\t<h2 v-if=\"title\" class=\"cn-work-queue__title\">\n\t\t\t\t{{ title }}\n\t\t\t</h2>\n\t\t\t<div class=\"cn-work-queue__actions\">\n\t\t\t\t<!-- @slot Buttons beside the title (\"Plan an item\"). -->\n\t\t\t\t<slot name=\"actions\" />\n\t\t\t</div>\n\t\t</div>\n\n\t\t<NcNoteCard v-for=\"source in unavailable\"\n\t\t\t:key=\"source.source\"\n\t\t\ttype=\"warning\"\n\t\t\t:data-testid=\"`cn-work-queue-unavailable-${source.source}`\">\n\t\t\t{{ t('nextcloud-vue', '{source} could not be read, so this list is incomplete.', { source: source.label || source.source }) }}\n\t\t</NcNoteCard>\n\n\t\t<NcLoadingIcon v-if=\"loading\" :size=\"32\" />\n\t\t<NcEmptyContent v-else-if=\"error\"\n\t\t\t:name=\"t('nextcloud-vue', 'This queue could not be read')\"\n\t\t\t:description=\"error\"\n\t\t\tdata-testid=\"cn-work-queue-error\">\n\t\t\t<template #action>\n\t\t\t\t<NcButton @click=\"load\">\n\t\t\t\t\t{{ t('nextcloud-vue', 'Try again') }}\n\t\t\t\t</NcButton>\n\t\t\t</template>\n\t\t</NcEmptyContent>\n\t\t<template v-else>\n\t\t\t<p v-if=\"shownGroups.length === 0\" class=\"cn-work-queue__muted\" data-testid=\"cn-work-queue-empty\">\n\t\t\t\t{{ text(content.emptyText) || t('nextcloud-vue', 'Nothing is waiting on you.') }}\n\t\t\t</p>\n\t\t\t<section v-for=\"group in shownGroups\"\n\t\t\t\t:key=\"group.key\"\n\t\t\t\tclass=\"cn-work-queue__group\"\n\t\t\t\t:data-testid=\"`cn-work-queue-group-${group.key}`\">\n\t\t\t\t<div class=\"cn-work-queue__group-head\">\n\t\t\t\t\t<h3 class=\"cn-work-queue__group-title\">\n\t\t\t\t\t\t{{ group.label }}\n\t\t\t\t\t\t<span class=\"cn-work-queue__count\">{{ group.items.length }}</span>\n\t\t\t\t\t</h3>\n\t\t\t\t\t<NcButton v-if=\"content.hide\"\n\t\t\t\t\t\tvariant=\"secondary\"\n\t\t\t\t\t\t:aria-label=\"t('nextcloud-vue', 'Hide this group until tomorrow')\"\n\t\t\t\t\t\t:data-testid=\"`cn-work-queue-hide-${group.key}`\"\n\t\t\t\t\t\t@click=\"setHidden(group.key, true)\">\n\t\t\t\t\t\t{{ t('nextcloud-vue', 'Hide until tomorrow') }}\n\t\t\t\t\t</NcButton>\n\t\t\t\t</div>\n\t\t\t\t<p v-if=\"group.closesWhen\" class=\"cn-work-queue__muted\">\n\t\t\t\t\t{{ group.closesWhen }}\n\t\t\t\t</p>\n\t\t\t\t<ul class=\"cn-work-queue__items\">\n\t\t\t\t\t<li v-for=\"item in group.items\"\n\t\t\t\t\t\t:key=\"item.id\"\n\t\t\t\t\t\tclass=\"cn-work-queue__item\"\n\t\t\t\t\t\t:class=\"{ 'cn-work-queue__item--late': item.deadlineTier === 'overdue' }\"\n\t\t\t\t\t\t:data-testid=\"`cn-work-queue-item-${item.id}`\">\n\t\t\t\t\t\t<span class=\"cn-work-queue__avatar\" aria-hidden=\"true\">{{ initials(item.title) }}</span>\n\t\t\t\t\t\t<span class=\"cn-work-queue__body\">\n\t\t\t\t\t\t\t<a :href=\"hrefOf(item) || '#'\" class=\"cn-work-queue__link\" @click=\"onOpen(item, $event)\">{{ item.title }}</a>\n\t\t\t\t\t\t\t<span v-if=\"item.covered || waitingText(item)\" class=\"cn-work-queue__sub\">\n\t\t\t\t\t\t\t\t<span v-if=\"item.covered\">{{ t('nextcloud-vue', 'Covering for {person}', { person: String(item.coveredFor || '') }) }}</span>\n\t\t\t\t\t\t\t\t<span v-if=\"waitingText(item)\" :data-testid=\"`cn-work-queue-waiting-${item.id}`\">{{ waitingText(item) }}</span>\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<span v-if=\"item.dueAt\" class=\"cn-work-queue__muted\">{{ item.dueAt }}</span>\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t</section>\n\t\t</template>\n\n\t\t<section v-if=\"content.hide && hidden.length\" class=\"cn-work-queue__group\" data-testid=\"cn-work-queue-hidden\">\n\t\t\t<h3 class=\"cn-work-queue__group-title\">\n\t\t\t\t{{ t('nextcloud-vue', 'Hidden until tomorrow') }}\n\t\t\t</h3>\n\t\t\t<NcButton v-for=\"key in hidden\"\n\t\t\t\t:key=\"key\"\n\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t:data-testid=\"`cn-work-queue-show-${key}`\"\n\t\t\t\t@click=\"setHidden(key, false)\">\n\t\t\t\t{{ t('nextcloud-vue', 'Show {group} again', { group: labelOf(key) }) }}\n\t\t\t</NcButton>\n\t\t</section>\n\t</div>\n</template>\n\n<script>\nimport axios from '@nextcloud/axios'\nimport { translate as t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { NcButton, NcEmptyContent, NcLoadingIcon, NcNoteCard } from '@nextcloud/vue'\nimport { fetchEndpointSource } from '../../composables/useEndpointSource.js'\nimport { fillTemplate } from '../../utils/fillTemplate.js'\nimport { openRowTarget } from '../../utils/linkNavigation.js'\n\n/**\n * CnWorkQueue — one list of everything waiting on the reader: tasks,\n * consultations, mentions, calendar items, work they cover for a colleague,\n * from as many sources as the server declares. The component names no\n * source: the server answers the groups (`key`, `label`, `closesWhen`,\n * `items`), so a new kind of work needs no change here. A source that could\n * not be read is named at the top rather than folded into \"nothing is\n * waiting\". A group can be hidden until tomorrow, through the server, so the\n * choice follows the reader to another device. dossiq's personal queue is\n * the first; pipelinq's queue has the same shape.\n *\n * `content`:\n * - `source`: an endpointSource answering `{ groups, hiddenGroups?, unavailable? }`.\n * An item is `{ id, title, dueAt?, deadlineTier?, covered?, coveredFor?,\n * waiting?: { on, days, chases }, route?, href? }`.\n * - `hide`, `show`: url templates with `{group}` that hide a group until\n * tomorrow and show it again, each answering `{ hiddenGroups }`; without\n * `hide` no group can be hidden.\n * - `itemHref`: a template filled from an item, when items carry no `route`/`href`.\n * - `waitingParties`: words for `waiting.on` (`{ applicant: \"the applicant\" }`).\n * - `emptyText`: through the host translate.\n */\nexport default {\n\tname: 'CnWorkQueue',\n\n\tcomponents: { NcButton, NcEmptyContent, NcLoadingIcon, NcNoteCard },\n\n\tinject: {\n\t\t/** The host app's translate (CnAppRoot `cnTranslate`). */\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The queue's configuration (see the component docs).\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 heading above the queue; none when empty. */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\temits: ['open'],\n\n\tdata() {\n\t\treturn {\n\t\t\tloading: true,\n\t\t\terror: '',\n\t\t\tgroups: [],\n\t\t\thidden: [],\n\t\t\tunavailable: [],\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The groups not hidden today.\n\t\t *\n\t\t * @spec openspec/changes/work-queue/specs/work-queue/spec.md#requirement-one-queue-over-every-source\n\t\t * @return {Array<object>}\n\t\t */\n\t\tshownGroups() {\n\t\t\tconst hidden = new Set(this.hidden.map(String))\n\t\t\treturn this.groups.filter((group) => !hidden.has(String(group.key)))\n\t\t},\n\t},\n\n\tmounted() {\n\t\tthis.load()\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\t/**\n\t\t * A config text through the host translate.\n\t\t *\n\t\t * @param {unknown} value The text.\n\t\t * @return {string}\n\t\t */\n\t\ttext(value) {\n\t\t\treturn typeof value === 'string' && value !== '' ? this.cnTranslate(value) : ''\n\t\t},\n\n\t\t/**\n\t\t * Read the queue; a failed read is an error with a retry.\n\t\t *\n\t\t * @spec openspec/changes/work-queue/specs/work-queue/spec.md#requirement-one-queue-over-every-source\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync load() {\n\t\t\tthis.loading = true\n\t\t\tthis.error = ''\n\t\t\ttry {\n\t\t\t\tconst data = (await fetchEndpointSource(this.content.source, {}, { fresh: true })) || {}\n\t\t\t\tthis.groups = (Array.isArray(data.groups) ? data.groups : [])\n\t\t\t\t\t.filter((g) => g && g.key !== undefined)\n\t\t\t\t\t.map((g) => ({ ...g, items: Array.isArray(g.items) ? g.items : [] }))\n\t\t\t\tthis.hidden = Array.isArray(data.hiddenGroups) ? data.hiddenGroups.map(String) : []\n\t\t\t\tthis.unavailable = Array.isArray(data.unavailable) ? data.unavailable.filter((s) => s && s.source) : []\n\t\t\t} catch (failure) {\n\t\t\t\tconst body = failure && failure.response && failure.response.data\n\t\t\t\tthis.error = String((body && (body.message || body.error)) || (failure && failure.message) || failure)\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Hide a group until tomorrow, or show it again, through the server.\n\t\t *\n\t\t * @spec openspec/changes/work-queue/specs/work-queue/spec.md#requirement-one-queue-over-every-source\n\t\t * @param {string} key The group key.\n\t\t * @param {boolean} hide Hide (true) or show (false).\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync setHidden(key, hide) {\n\t\t\tconst template = hide ? this.content.hide : this.content.show\n\t\t\tif (!template) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst { data } = await axios.post(generateUrl(fillTemplate(template, { group: encodeURIComponent(key) })), {})\n\t\t\t\tthis.hidden = Array.isArray(data && data.hiddenGroups) ? data.hiddenGroups.map(String) : this.hidden\n\t\t\t} catch {\n\t\t\t\t// The group stays as it was; the server decides.\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * A group's label by key, for a hidden group.\n\t\t *\n\t\t * @param {string} key The key.\n\t\t * @return {string}\n\t\t */\n\t\tlabelOf(key) {\n\t\t\tconst group = this.groups.find((g) => String(g.key) === String(key))\n\t\t\treturn group && group.label ? group.label : String(key)\n\t\t},\n\n\t\t/**\n\t\t * An item's page as an href.\n\t\t *\n\t\t * @param {object} item The item.\n\t\t * @return {string}\n\t\t */\n\t\threfOf(item) {\n\t\t\tif (item.route && this.$router) {\n\t\t\t\ttry {\n\t\t\t\t\treturn this.$router.resolve(item.route).href\n\t\t\t\t} catch {\n\t\t\t\t\treturn ''\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (item.href) {\n\t\t\t\treturn String(item.href)\n\t\t\t}\n\t\t\treturn this.content.itemHref ? generateUrl(fillTemplate(this.content.itemHref, item)) : ''\n\t\t},\n\n\t\t/**\n\t\t * Open an item: its route through the router, else its href like a link, else tell the host.\n\t\t *\n\t\t * @param {object} item The item.\n\t\t * @param {MouseEvent} event The click.\n\t\t */\n\t\tonOpen(item, event) {\n\t\t\tif (item.route && this.$router && event && !(event.ctrlKey || event.metaKey || event.shiftKey || event.button === 1)) {\n\t\t\t\tevent.preventDefault()\n\t\t\t\tthis.$router.push(item.route).catch(() => {})\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst href = this.hrefOf(item)\n\t\t\tif (href) {\n\t\t\t\tif (event) {\n\t\t\t\t\tevent.preventDefault()\n\t\t\t\t}\n\t\t\t\topenRowTarget(event, href)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (event) {\n\t\t\t\tevent.preventDefault()\n\t\t\t}\n\t\t\t/** @event open An item without a route or href was opened. Payload: the item. */\n\t\t\tthis.$emit('open', item)\n\t\t},\n\n\t\t/**\n\t\t * Who the item waits on, for how long and how often chased.\n\t\t *\n\t\t * @param {object} item The item.\n\t\t * @return {string}\n\t\t */\n\t\twaitingText(item) {\n\t\t\tconst waiting = item && item.waiting\n\t\t\tif (!waiting || typeof waiting !== 'object' || !waiting.on) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst parties = {\n\t\t\t\tapplicant: t('nextcloud-vue', 'the applicant'),\n\t\t\t\tthirdParty: t('nextcloud-vue', 'a third party'),\n\t\t\t\tus: t('nextcloud-vue', 'us'),\n\t\t\t}\n\t\t\tconst own = this.content.waitingParties && this.content.waitingParties[waiting.on]\n\t\t\tconst party = own ? this.cnTranslate(own) : (parties[waiting.on] || String(waiting.on))\n\t\t\tconst days = Number.isFinite(waiting.days) ? waiting.days : 0\n\t\t\tconst chases = Number.isFinite(waiting.chases) ? waiting.chases : 0\n\t\t\tif (chases === 0) {\n\t\t\t\treturn t('nextcloud-vue', 'Waiting on {party} for {days} days', { party, days })\n\t\t\t}\n\t\t\tif (chases === 1) {\n\t\t\t\treturn t('nextcloud-vue', 'Waiting on {party} for {days} days, chased once', { party, days })\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', 'Waiting on {party} for {days} days, chased {chases} times', { party, days, chases })\n\t\t},\n\n\t\t/**\n\t\t * Up to two initials of a title.\n\t\t *\n\t\t * @param {string} title The title.\n\t\t * @return {string}\n\t\t */\n\t\tinitials(title) {\n\t\t\treturn String(title ?? '').trim().split(/\\s+/).filter(Boolean).slice(0, 2).map((w) => w[0]).join('').toUpperCase()\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-work-queue {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 24px;\n}\n\n.cn-work-queue__head,\n.cn-work-queue__group-head {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tjustify-content: space-between;\n\tgap: 12px;\n}\n\n.cn-work-queue__title {\n\tmargin: 0;\n\tfont-size: 28px;\n\tfont-weight: 700;\n}\n\n.cn-work-queue__actions {\n\tdisplay: flex;\n\tgap: 8px;\n}\n\n.cn-work-queue__group {\n\tpadding: 20px 24px;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-large);\n\tbackground: var(--color-main-background);\n}\n\n.cn-work-queue__group-title {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tmargin: 0;\n\tfont-size: 18px;\n\tfont-weight: 700;\n}\n\n.cn-work-queue__count {\n\tpadding: 0 8px;\n\tborder-radius: 10px;\n\tbackground: var(--color-background-dark);\n\tfont-size: 12px;\n\tfont-weight: 600;\n}\n\n.cn-work-queue__muted {\n\tmargin: 4px 0 8px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-work-queue__items {\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-work-queue__item {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 16px;\n\tpadding: 12px 0;\n\tborder-block-end: 1px solid var(--color-border);\n}\n\n.cn-work-queue__item:last-child {\n\tborder-block-end: none;\n}\n\n.cn-work-queue__avatar {\n\tdisplay: inline-flex;\n\tflex: none;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 32px;\n\theight: 32px;\n\tborder-radius: 50%;\n\tbackground: var(--color-background-dark);\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 12px;\n\tfont-weight: 700;\n}\n\n.cn-work-queue__body {\n\tdisplay: flex;\n\tflex: 1 1 auto;\n\tflex-direction: column;\n\tmin-width: 0;\n}\n\n.cn-work-queue__link {\n\tcolor: var(--color-main-text);\n\tfont-weight: 700;\n\ttext-decoration: none;\n}\n\n.cn-work-queue__link:hover {\n\ttext-decoration: underline;\n}\n\n.cn-work-queue__item--late .cn-work-queue__link {\n\tcolor: var(--color-error);\n}\n\n.cn-work-queue__sub {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 12px;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n}\n</style>\n"],"names":["t","axios"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnWorkQueue.vue2.js","sources":["../../../../src/components/CnWorkQueue/CnWorkQueue.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<div class=\"cn-work-queue\" data-testid=\"cn-work-queue\">\n\t\t<div v-if=\"title || $slots.actions\" class=\"cn-work-queue__head\">\n\t\t\t<h2 v-if=\"title\" class=\"cn-work-queue__title\">\n\t\t\t\t{{ title }}\n\t\t\t</h2>\n\t\t\t<div class=\"cn-work-queue__actions\">\n\t\t\t\t<!-- @slot Buttons beside the title (\"Plan an item\"). -->\n\t\t\t\t<slot name=\"actions\" />\n\t\t\t</div>\n\t\t</div>\n\n\t\t<NcNoteCard v-for=\"source in unavailable\"\n\t\t\t:key=\"source.source\"\n\t\t\ttype=\"warning\"\n\t\t\t:data-testid=\"`cn-work-queue-unavailable-${source.source}`\">\n\t\t\t{{ t('nextcloud-vue', '{source} could not be read, so this list is incomplete.', { source: source.label || source.source }) }}\n\t\t</NcNoteCard>\n\n\t\t<NcLoadingIcon v-if=\"loading\" :size=\"32\" />\n\t\t<NcEmptyContent v-else-if=\"error\"\n\t\t\t:name=\"t('nextcloud-vue', 'This queue could not be read')\"\n\t\t\t:description=\"error\"\n\t\t\tdata-testid=\"cn-work-queue-error\">\n\t\t\t<template #action>\n\t\t\t\t<NcButton @click=\"load\">\n\t\t\t\t\t{{ t('nextcloud-vue', 'Try again') }}\n\t\t\t\t</NcButton>\n\t\t\t</template>\n\t\t</NcEmptyContent>\n\t\t<template v-else>\n\t\t\t<p v-if=\"shownGroups.length === 0\" class=\"cn-work-queue__muted\" data-testid=\"cn-work-queue-empty\">\n\t\t\t\t{{ text(content.emptyText) || t('nextcloud-vue', 'Nothing is waiting on you.') }}\n\t\t\t</p>\n\t\t\t<section v-for=\"group in shownGroups\"\n\t\t\t\t:key=\"group.key\"\n\t\t\t\tclass=\"cn-work-queue__group\"\n\t\t\t\t:data-testid=\"`cn-work-queue-group-${group.key}`\">\n\t\t\t\t<div class=\"cn-work-queue__group-head\">\n\t\t\t\t\t<h3 class=\"cn-work-queue__group-title\">\n\t\t\t\t\t\t{{ group.label }}\n\t\t\t\t\t\t<span class=\"cn-work-queue__count\">{{ group.items.length }}</span>\n\t\t\t\t\t</h3>\n\t\t\t\t\t<NcButton v-if=\"content.hide\"\n\t\t\t\t\t\tvariant=\"secondary\"\n\t\t\t\t\t\t:aria-label=\"t('nextcloud-vue', 'Hide this group until tomorrow')\"\n\t\t\t\t\t\t:data-testid=\"`cn-work-queue-hide-${group.key}`\"\n\t\t\t\t\t\t@click=\"setHidden(group.key, true)\">\n\t\t\t\t\t\t{{ t('nextcloud-vue', 'Hide until tomorrow') }}\n\t\t\t\t\t</NcButton>\n\t\t\t\t</div>\n\t\t\t\t<p v-if=\"group.closesWhen\" class=\"cn-work-queue__muted\">\n\t\t\t\t\t{{ group.closesWhen }}\n\t\t\t\t</p>\n\t\t\t\t<ul class=\"cn-work-queue__items\">\n\t\t\t\t\t<li v-for=\"item in group.items\"\n\t\t\t\t\t\t:key=\"item.id\"\n\t\t\t\t\t\tclass=\"cn-work-queue__item\"\n\t\t\t\t\t\t:class=\"{ 'cn-work-queue__item--late': item.deadlineTier === 'overdue' }\"\n\t\t\t\t\t\t:data-testid=\"`cn-work-queue-item-${item.id}`\">\n\t\t\t\t\t\t<span class=\"cn-work-queue__avatar\" aria-hidden=\"true\">{{ initials(item.title) }}</span>\n\t\t\t\t\t\t<span class=\"cn-work-queue__body\">\n\t\t\t\t\t\t\t<a :href=\"hrefOf(item) || '#'\" class=\"cn-work-queue__link\" @click=\"onOpen(item, $event)\">{{ item.title }}</a>\n\t\t\t\t\t\t\t<span v-if=\"item.covered || waitingText(item)\" class=\"cn-work-queue__sub\">\n\t\t\t\t\t\t\t\t<span v-if=\"item.covered\">{{ t('nextcloud-vue', 'Covering for {person}', { person: String(item.coveredFor || '') }) }}</span>\n\t\t\t\t\t\t\t\t<span v-if=\"waitingText(item)\" :data-testid=\"`cn-work-queue-waiting-${item.id}`\">{{ waitingText(item) }}</span>\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<span v-if=\"item.dueAt\" class=\"cn-work-queue__muted\">{{ item.dueAt }}</span>\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t</section>\n\t\t</template>\n\n\t\t<section v-if=\"content.hide && hidden.length\" class=\"cn-work-queue__group\" data-testid=\"cn-work-queue-hidden\">\n\t\t\t<h3 class=\"cn-work-queue__group-title\">\n\t\t\t\t{{ t('nextcloud-vue', 'Hidden until tomorrow') }}\n\t\t\t</h3>\n\t\t\t<NcButton v-for=\"key in hidden\"\n\t\t\t\t:key=\"key\"\n\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t:data-testid=\"`cn-work-queue-show-${key}`\"\n\t\t\t\t@click=\"setHidden(key, false)\">\n\t\t\t\t{{ t('nextcloud-vue', 'Show {group} again', { group: labelOf(key) }) }}\n\t\t\t</NcButton>\n\t\t</section>\n\t</div>\n</template>\n\n<script>\nimport axios from '@nextcloud/axios'\nimport { subscribe, unsubscribe } from '@nextcloud/event-bus'\nimport { translate as t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { NcButton, NcEmptyContent, NcLoadingIcon, NcNoteCard } from '@nextcloud/vue'\nimport { fetchEndpointSource } from '../../composables/useEndpointSource.js'\nimport { fillTemplate } from '../../utils/fillTemplate.js'\nimport { openRowTarget } from '../../utils/linkNavigation.js'\n\n/**\n * CnWorkQueue — one list of everything waiting on the reader: tasks,\n * consultations, mentions, calendar items, work they cover for a colleague,\n * from as many sources as the server declares. The component names no\n * source: the server answers the groups (`key`, `label`, `closesWhen`,\n * `items`), so a new kind of work needs no change here. A source that could\n * not be read is named at the top rather than folded into \"nothing is\n * waiting\". A group can be hidden until tomorrow, through the server, so the\n * choice follows the reader to another device. dossiq's personal queue is\n * the first; pipelinq's queue has the same shape. It reads again on\n * `cn:page:refresh`, so work planned or closed in a dialog shows at once.\n *\n * `content`:\n * - `source`: an endpointSource answering `{ groups, hiddenGroups?, unavailable? }`.\n * An item is `{ id, title, dueAt?, deadlineTier?, covered?, coveredFor?,\n * waiting?: { on, days, chases }, route?, href? }`.\n * - `hide`, `show`: url templates with `{group}` that hide a group until\n * tomorrow and show it again, each answering `{ hiddenGroups }`; without\n * `hide` no group can be hidden.\n * - `itemHref`: a template filled from an item, when items carry no `route`/`href`.\n * - `waitingParties`: words for `waiting.on` (`{ applicant: \"the applicant\" }`).\n * - `emptyText`: through the host translate.\n */\nexport default {\n\tname: 'CnWorkQueue',\n\n\tcomponents: { NcButton, NcEmptyContent, NcLoadingIcon, NcNoteCard },\n\n\tinject: {\n\t\t/** The host app's translate (CnAppRoot `cnTranslate`). */\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The queue's configuration (see the component docs).\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 heading above the queue; none when empty. */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\temits: ['open'],\n\n\tdata() {\n\t\treturn {\n\t\t\tloading: true,\n\t\t\terror: '',\n\t\t\tgroups: [],\n\t\t\thidden: [],\n\t\t\tunavailable: [],\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The groups not hidden today.\n\t\t *\n\t\t * @spec openspec/changes/work-queue/specs/work-queue/spec.md#requirement-one-queue-over-every-source\n\t\t * @return {Array<object>}\n\t\t */\n\t\tshownGroups() {\n\t\t\tconst hidden = new Set(this.hidden.map(String))\n\t\t\treturn this.groups.filter((group) => !hidden.has(String(group.key)))\n\t\t},\n\t},\n\n\tmounted() {\n\t\tsubscribe('cn:page:refresh', this.load)\n\t\tthis.load()\n\t},\n\n\tbeforeUnmount() {\n\t\tunsubscribe('cn:page:refresh', this.load)\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\t/**\n\t\t * A config text through the host translate.\n\t\t *\n\t\t * @param {unknown} value The text.\n\t\t * @return {string}\n\t\t */\n\t\ttext(value) {\n\t\t\treturn typeof value === 'string' && value !== '' ? this.cnTranslate(value) : ''\n\t\t},\n\n\t\t/**\n\t\t * Read the queue; a failed read is an error with a retry.\n\t\t *\n\t\t * @spec openspec/changes/work-queue/specs/work-queue/spec.md#requirement-one-queue-over-every-source\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync load() {\n\t\t\tthis.loading = true\n\t\t\tthis.error = ''\n\t\t\ttry {\n\t\t\t\tconst data = (await fetchEndpointSource(this.content.source, {}, { fresh: true })) || {}\n\t\t\t\tthis.groups = (Array.isArray(data.groups) ? data.groups : [])\n\t\t\t\t\t.filter((g) => g && g.key !== undefined)\n\t\t\t\t\t.map((g) => ({ ...g, items: Array.isArray(g.items) ? g.items : [] }))\n\t\t\t\tthis.hidden = Array.isArray(data.hiddenGroups) ? data.hiddenGroups.map(String) : []\n\t\t\t\tthis.unavailable = Array.isArray(data.unavailable) ? data.unavailable.filter((s) => s && s.source) : []\n\t\t\t} catch (failure) {\n\t\t\t\tconst body = failure && failure.response && failure.response.data\n\t\t\t\tthis.error = String((body && (body.message || body.error)) || (failure && failure.message) || failure)\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Hide a group until tomorrow, or show it again, through the server.\n\t\t *\n\t\t * @spec openspec/changes/work-queue/specs/work-queue/spec.md#requirement-one-queue-over-every-source\n\t\t * @param {string} key The group key.\n\t\t * @param {boolean} hide Hide (true) or show (false).\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync setHidden(key, hide) {\n\t\t\tconst template = hide ? this.content.hide : this.content.show\n\t\t\tif (!template) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst { data } = await axios.post(generateUrl(fillTemplate(template, { group: encodeURIComponent(key) })), {})\n\t\t\t\tthis.hidden = Array.isArray(data && data.hiddenGroups) ? data.hiddenGroups.map(String) : this.hidden\n\t\t\t} catch {\n\t\t\t\t// The group stays as it was; the server decides.\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * A group's label by key, for a hidden group.\n\t\t *\n\t\t * @param {string} key The key.\n\t\t * @return {string}\n\t\t */\n\t\tlabelOf(key) {\n\t\t\tconst group = this.groups.find((g) => String(g.key) === String(key))\n\t\t\treturn group && group.label ? group.label : String(key)\n\t\t},\n\n\t\t/**\n\t\t * An item's page as an href.\n\t\t *\n\t\t * @param {object} item The item.\n\t\t * @return {string}\n\t\t */\n\t\threfOf(item) {\n\t\t\tif (item.route && this.$router) {\n\t\t\t\ttry {\n\t\t\t\t\treturn this.$router.resolve(item.route).href\n\t\t\t\t} catch {\n\t\t\t\t\treturn ''\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (item.href) {\n\t\t\t\treturn String(item.href)\n\t\t\t}\n\t\t\treturn this.content.itemHref ? generateUrl(fillTemplate(this.content.itemHref, item)) : ''\n\t\t},\n\n\t\t/**\n\t\t * Open an item: its route through the router, else its href like a link, else tell the host.\n\t\t *\n\t\t * @param {object} item The item.\n\t\t * @param {MouseEvent} event The click.\n\t\t */\n\t\tonOpen(item, event) {\n\t\t\tif (item.route && this.$router && event && !(event.ctrlKey || event.metaKey || event.shiftKey || event.button === 1)) {\n\t\t\t\tevent.preventDefault()\n\t\t\t\tthis.$router.push(item.route).catch(() => {})\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst href = this.hrefOf(item)\n\t\t\tif (href) {\n\t\t\t\tif (event) {\n\t\t\t\t\tevent.preventDefault()\n\t\t\t\t}\n\t\t\t\topenRowTarget(event, href)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (event) {\n\t\t\t\tevent.preventDefault()\n\t\t\t}\n\t\t\t/** @event open An item without a route or href was opened. Payload: the item. */\n\t\t\tthis.$emit('open', item)\n\t\t},\n\n\t\t/**\n\t\t * Who the item waits on, for how long and how often chased.\n\t\t *\n\t\t * @param {object} item The item.\n\t\t * @return {string}\n\t\t */\n\t\twaitingText(item) {\n\t\t\tconst waiting = item && item.waiting\n\t\t\tif (!waiting || typeof waiting !== 'object' || !waiting.on) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst parties = {\n\t\t\t\tapplicant: t('nextcloud-vue', 'the applicant'),\n\t\t\t\tthirdParty: t('nextcloud-vue', 'a third party'),\n\t\t\t\tus: t('nextcloud-vue', 'us'),\n\t\t\t}\n\t\t\tconst own = this.content.waitingParties && this.content.waitingParties[waiting.on]\n\t\t\tconst party = own ? this.cnTranslate(own) : (parties[waiting.on] || String(waiting.on))\n\t\t\tconst days = Number.isFinite(waiting.days) ? waiting.days : 0\n\t\t\tconst chases = Number.isFinite(waiting.chases) ? waiting.chases : 0\n\t\t\tif (chases === 0) {\n\t\t\t\treturn t('nextcloud-vue', 'Waiting on {party} for {days} days', { party, days })\n\t\t\t}\n\t\t\tif (chases === 1) {\n\t\t\t\treturn t('nextcloud-vue', 'Waiting on {party} for {days} days, chased once', { party, days })\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', 'Waiting on {party} for {days} days, chased {chases} times', { party, days, chases })\n\t\t},\n\n\t\t/**\n\t\t * Up to two initials of a title.\n\t\t *\n\t\t * @param {string} title The title.\n\t\t * @return {string}\n\t\t */\n\t\tinitials(title) {\n\t\t\treturn String(title ?? '').trim().split(/\\s+/).filter(Boolean).slice(0, 2).map((w) => w[0]).join('').toUpperCase()\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-work-queue {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 24px;\n}\n\n.cn-work-queue__head,\n.cn-work-queue__group-head {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tjustify-content: space-between;\n\tgap: 12px;\n}\n\n.cn-work-queue__title {\n\tmargin: 0;\n\tfont-size: 28px;\n\tfont-weight: 700;\n}\n\n.cn-work-queue__actions {\n\tdisplay: flex;\n\tgap: 8px;\n}\n\n.cn-work-queue__group {\n\tpadding: 20px 24px;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-large);\n\tbackground: var(--color-main-background);\n}\n\n.cn-work-queue__group-title {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tmargin: 0;\n\tfont-size: 18px;\n\tfont-weight: 700;\n}\n\n.cn-work-queue__count {\n\tpadding: 0 8px;\n\tborder-radius: 10px;\n\tbackground: var(--color-background-dark);\n\tfont-size: 12px;\n\tfont-weight: 600;\n}\n\n.cn-work-queue__muted {\n\tmargin: 4px 0 8px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-work-queue__items {\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-work-queue__item {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 16px;\n\tpadding: 12px 0;\n\tborder-block-end: 1px solid var(--color-border);\n}\n\n.cn-work-queue__item:last-child {\n\tborder-block-end: none;\n}\n\n.cn-work-queue__avatar {\n\tdisplay: inline-flex;\n\tflex: none;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 32px;\n\theight: 32px;\n\tborder-radius: 50%;\n\tbackground: var(--color-background-dark);\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 12px;\n\tfont-weight: 700;\n}\n\n.cn-work-queue__body {\n\tdisplay: flex;\n\tflex: 1 1 auto;\n\tflex-direction: column;\n\tmin-width: 0;\n}\n\n.cn-work-queue__link {\n\tcolor: var(--color-main-text);\n\tfont-weight: 700;\n\ttext-decoration: none;\n}\n\n.cn-work-queue__link:hover {\n\ttext-decoration: underline;\n}\n\n.cn-work-queue__item--late .cn-work-queue__link {\n\tcolor: var(--color-error);\n}\n\n.cn-work-queue__sub {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 12px;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n}\n</style>\n"],"names":["t","axios"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnWorkQueue.vue3.js","sources":["../../../../src/components/CnWorkQueue/CnWorkQueue.vue?vue&type=template&id=793630f4&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<div class=\"cn-work-queue\" data-testid=\"cn-work-queue\">\n\t\t<div v-if=\"title || $slots.actions\" class=\"cn-work-queue__head\">\n\t\t\t<h2 v-if=\"title\" class=\"cn-work-queue__title\">\n\t\t\t\t{{ title }}\n\t\t\t</h2>\n\t\t\t<div class=\"cn-work-queue__actions\">\n\t\t\t\t<!-- @slot Buttons beside the title (\"Plan an item\"). -->\n\t\t\t\t<slot name=\"actions\" />\n\t\t\t</div>\n\t\t</div>\n\n\t\t<NcNoteCard v-for=\"source in unavailable\"\n\t\t\t:key=\"source.source\"\n\t\t\ttype=\"warning\"\n\t\t\t:data-testid=\"`cn-work-queue-unavailable-${source.source}`\">\n\t\t\t{{ t('nextcloud-vue', '{source} could not be read, so this list is incomplete.', { source: source.label || source.source }) }}\n\t\t</NcNoteCard>\n\n\t\t<NcLoadingIcon v-if=\"loading\" :size=\"32\" />\n\t\t<NcEmptyContent v-else-if=\"error\"\n\t\t\t:name=\"t('nextcloud-vue', 'This queue could not be read')\"\n\t\t\t:description=\"error\"\n\t\t\tdata-testid=\"cn-work-queue-error\">\n\t\t\t<template #action>\n\t\t\t\t<NcButton @click=\"load\">\n\t\t\t\t\t{{ t('nextcloud-vue', 'Try again') }}\n\t\t\t\t</NcButton>\n\t\t\t</template>\n\t\t</NcEmptyContent>\n\t\t<template v-else>\n\t\t\t<p v-if=\"shownGroups.length === 0\" class=\"cn-work-queue__muted\" data-testid=\"cn-work-queue-empty\">\n\t\t\t\t{{ text(content.emptyText) || t('nextcloud-vue', 'Nothing is waiting on you.') }}\n\t\t\t</p>\n\t\t\t<section v-for=\"group in shownGroups\"\n\t\t\t\t:key=\"group.key\"\n\t\t\t\tclass=\"cn-work-queue__group\"\n\t\t\t\t:data-testid=\"`cn-work-queue-group-${group.key}`\">\n\t\t\t\t<div class=\"cn-work-queue__group-head\">\n\t\t\t\t\t<h3 class=\"cn-work-queue__group-title\">\n\t\t\t\t\t\t{{ group.label }}\n\t\t\t\t\t\t<span class=\"cn-work-queue__count\">{{ group.items.length }}</span>\n\t\t\t\t\t</h3>\n\t\t\t\t\t<NcButton v-if=\"content.hide\"\n\t\t\t\t\t\tvariant=\"secondary\"\n\t\t\t\t\t\t:aria-label=\"t('nextcloud-vue', 'Hide this group until tomorrow')\"\n\t\t\t\t\t\t:data-testid=\"`cn-work-queue-hide-${group.key}`\"\n\t\t\t\t\t\t@click=\"setHidden(group.key, true)\">\n\t\t\t\t\t\t{{ t('nextcloud-vue', 'Hide until tomorrow') }}\n\t\t\t\t\t</NcButton>\n\t\t\t\t</div>\n\t\t\t\t<p v-if=\"group.closesWhen\" class=\"cn-work-queue__muted\">\n\t\t\t\t\t{{ group.closesWhen }}\n\t\t\t\t</p>\n\t\t\t\t<ul class=\"cn-work-queue__items\">\n\t\t\t\t\t<li v-for=\"item in group.items\"\n\t\t\t\t\t\t:key=\"item.id\"\n\t\t\t\t\t\tclass=\"cn-work-queue__item\"\n\t\t\t\t\t\t:class=\"{ 'cn-work-queue__item--late': item.deadlineTier === 'overdue' }\"\n\t\t\t\t\t\t:data-testid=\"`cn-work-queue-item-${item.id}`\">\n\t\t\t\t\t\t<span class=\"cn-work-queue__avatar\" aria-hidden=\"true\">{{ initials(item.title) }}</span>\n\t\t\t\t\t\t<span class=\"cn-work-queue__body\">\n\t\t\t\t\t\t\t<a :href=\"hrefOf(item) || '#'\" class=\"cn-work-queue__link\" @click=\"onOpen(item, $event)\">{{ item.title }}</a>\n\t\t\t\t\t\t\t<span v-if=\"item.covered || waitingText(item)\" class=\"cn-work-queue__sub\">\n\t\t\t\t\t\t\t\t<span v-if=\"item.covered\">{{ t('nextcloud-vue', 'Covering for {person}', { person: String(item.coveredFor || '') }) }}</span>\n\t\t\t\t\t\t\t\t<span v-if=\"waitingText(item)\" :data-testid=\"`cn-work-queue-waiting-${item.id}`\">{{ waitingText(item) }}</span>\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<span v-if=\"item.dueAt\" class=\"cn-work-queue__muted\">{{ item.dueAt }}</span>\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t</section>\n\t\t</template>\n\n\t\t<section v-if=\"content.hide && hidden.length\" class=\"cn-work-queue__group\" data-testid=\"cn-work-queue-hidden\">\n\t\t\t<h3 class=\"cn-work-queue__group-title\">\n\t\t\t\t{{ t('nextcloud-vue', 'Hidden until tomorrow') }}\n\t\t\t</h3>\n\t\t\t<NcButton v-for=\"key in hidden\"\n\t\t\t\t:key=\"key\"\n\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t:data-testid=\"`cn-work-queue-show-${key}`\"\n\t\t\t\t@click=\"setHidden(key, false)\">\n\t\t\t\t{{ t('nextcloud-vue', 'Show {group} again', { group: labelOf(key) }) }}\n\t\t\t</NcButton>\n\t\t</section>\n\t</div>\n</template>\n\n<script>\nimport axios from '@nextcloud/axios'\nimport { translate as t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { NcButton, NcEmptyContent, NcLoadingIcon, NcNoteCard } from '@nextcloud/vue'\nimport { fetchEndpointSource } from '../../composables/useEndpointSource.js'\nimport { fillTemplate } from '../../utils/fillTemplate.js'\nimport { openRowTarget } from '../../utils/linkNavigation.js'\n\n/**\n * CnWorkQueue — one list of everything waiting on the reader: tasks,\n * consultations, mentions, calendar items, work they cover for a colleague,\n * from as many sources as the server declares. The component names no\n * source: the server answers the groups (`key`, `label`, `closesWhen`,\n * `items`), so a new kind of work needs no change here. A source that could\n * not be read is named at the top rather than folded into \"nothing is\n * waiting\". A group can be hidden until tomorrow, through the server, so the\n * choice follows the reader to another device. dossiq's personal queue is\n * the first; pipelinq's queue has the same shape.\n *\n * `content`:\n * - `source`: an endpointSource answering `{ groups, hiddenGroups?, unavailable? }`.\n * An item is `{ id, title, dueAt?, deadlineTier?, covered?, coveredFor?,\n * waiting?: { on, days, chases }, route?, href? }`.\n * - `hide`, `show`: url templates with `{group}` that hide a group until\n * tomorrow and show it again, each answering `{ hiddenGroups }`; without\n * `hide` no group can be hidden.\n * - `itemHref`: a template filled from an item, when items carry no `route`/`href`.\n * - `waitingParties`: words for `waiting.on` (`{ applicant: \"the applicant\" }`).\n * - `emptyText`: through the host translate.\n */\nexport default {\n\tname: 'CnWorkQueue',\n\n\tcomponents: { NcButton, NcEmptyContent, NcLoadingIcon, NcNoteCard },\n\n\tinject: {\n\t\t/** The host app's translate (CnAppRoot `cnTranslate`). */\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The queue's configuration (see the component docs).\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 heading above the queue; none when empty. */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\temits: ['open'],\n\n\tdata() {\n\t\treturn {\n\t\t\tloading: true,\n\t\t\terror: '',\n\t\t\tgroups: [],\n\t\t\thidden: [],\n\t\t\tunavailable: [],\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The groups not hidden today.\n\t\t *\n\t\t * @spec openspec/changes/work-queue/specs/work-queue/spec.md#requirement-one-queue-over-every-source\n\t\t * @return {Array<object>}\n\t\t */\n\t\tshownGroups() {\n\t\t\tconst hidden = new Set(this.hidden.map(String))\n\t\t\treturn this.groups.filter((group) => !hidden.has(String(group.key)))\n\t\t},\n\t},\n\n\tmounted() {\n\t\tthis.load()\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\t/**\n\t\t * A config text through the host translate.\n\t\t *\n\t\t * @param {unknown} value The text.\n\t\t * @return {string}\n\t\t */\n\t\ttext(value) {\n\t\t\treturn typeof value === 'string' && value !== '' ? this.cnTranslate(value) : ''\n\t\t},\n\n\t\t/**\n\t\t * Read the queue; a failed read is an error with a retry.\n\t\t *\n\t\t * @spec openspec/changes/work-queue/specs/work-queue/spec.md#requirement-one-queue-over-every-source\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync load() {\n\t\t\tthis.loading = true\n\t\t\tthis.error = ''\n\t\t\ttry {\n\t\t\t\tconst data = (await fetchEndpointSource(this.content.source, {}, { fresh: true })) || {}\n\t\t\t\tthis.groups = (Array.isArray(data.groups) ? data.groups : [])\n\t\t\t\t\t.filter((g) => g && g.key !== undefined)\n\t\t\t\t\t.map((g) => ({ ...g, items: Array.isArray(g.items) ? g.items : [] }))\n\t\t\t\tthis.hidden = Array.isArray(data.hiddenGroups) ? data.hiddenGroups.map(String) : []\n\t\t\t\tthis.unavailable = Array.isArray(data.unavailable) ? data.unavailable.filter((s) => s && s.source) : []\n\t\t\t} catch (failure) {\n\t\t\t\tconst body = failure && failure.response && failure.response.data\n\t\t\t\tthis.error = String((body && (body.message || body.error)) || (failure && failure.message) || failure)\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Hide a group until tomorrow, or show it again, through the server.\n\t\t *\n\t\t * @spec openspec/changes/work-queue/specs/work-queue/spec.md#requirement-one-queue-over-every-source\n\t\t * @param {string} key The group key.\n\t\t * @param {boolean} hide Hide (true) or show (false).\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync setHidden(key, hide) {\n\t\t\tconst template = hide ? this.content.hide : this.content.show\n\t\t\tif (!template) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst { data } = await axios.post(generateUrl(fillTemplate(template, { group: encodeURIComponent(key) })), {})\n\t\t\t\tthis.hidden = Array.isArray(data && data.hiddenGroups) ? data.hiddenGroups.map(String) : this.hidden\n\t\t\t} catch {\n\t\t\t\t// The group stays as it was; the server decides.\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * A group's label by key, for a hidden group.\n\t\t *\n\t\t * @param {string} key The key.\n\t\t * @return {string}\n\t\t */\n\t\tlabelOf(key) {\n\t\t\tconst group = this.groups.find((g) => String(g.key) === String(key))\n\t\t\treturn group && group.label ? group.label : String(key)\n\t\t},\n\n\t\t/**\n\t\t * An item's page as an href.\n\t\t *\n\t\t * @param {object} item The item.\n\t\t * @return {string}\n\t\t */\n\t\threfOf(item) {\n\t\t\tif (item.route && this.$router) {\n\t\t\t\ttry {\n\t\t\t\t\treturn this.$router.resolve(item.route).href\n\t\t\t\t} catch {\n\t\t\t\t\treturn ''\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (item.href) {\n\t\t\t\treturn String(item.href)\n\t\t\t}\n\t\t\treturn this.content.itemHref ? generateUrl(fillTemplate(this.content.itemHref, item)) : ''\n\t\t},\n\n\t\t/**\n\t\t * Open an item: its route through the router, else its href like a link, else tell the host.\n\t\t *\n\t\t * @param {object} item The item.\n\t\t * @param {MouseEvent} event The click.\n\t\t */\n\t\tonOpen(item, event) {\n\t\t\tif (item.route && this.$router && event && !(event.ctrlKey || event.metaKey || event.shiftKey || event.button === 1)) {\n\t\t\t\tevent.preventDefault()\n\t\t\t\tthis.$router.push(item.route).catch(() => {})\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst href = this.hrefOf(item)\n\t\t\tif (href) {\n\t\t\t\tif (event) {\n\t\t\t\t\tevent.preventDefault()\n\t\t\t\t}\n\t\t\t\topenRowTarget(event, href)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (event) {\n\t\t\t\tevent.preventDefault()\n\t\t\t}\n\t\t\t/** @event open An item without a route or href was opened. Payload: the item. */\n\t\t\tthis.$emit('open', item)\n\t\t},\n\n\t\t/**\n\t\t * Who the item waits on, for how long and how often chased.\n\t\t *\n\t\t * @param {object} item The item.\n\t\t * @return {string}\n\t\t */\n\t\twaitingText(item) {\n\t\t\tconst waiting = item && item.waiting\n\t\t\tif (!waiting || typeof waiting !== 'object' || !waiting.on) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst parties = {\n\t\t\t\tapplicant: t('nextcloud-vue', 'the applicant'),\n\t\t\t\tthirdParty: t('nextcloud-vue', 'a third party'),\n\t\t\t\tus: t('nextcloud-vue', 'us'),\n\t\t\t}\n\t\t\tconst own = this.content.waitingParties && this.content.waitingParties[waiting.on]\n\t\t\tconst party = own ? this.cnTranslate(own) : (parties[waiting.on] || String(waiting.on))\n\t\t\tconst days = Number.isFinite(waiting.days) ? waiting.days : 0\n\t\t\tconst chases = Number.isFinite(waiting.chases) ? waiting.chases : 0\n\t\t\tif (chases === 0) {\n\t\t\t\treturn t('nextcloud-vue', 'Waiting on {party} for {days} days', { party, days })\n\t\t\t}\n\t\t\tif (chases === 1) {\n\t\t\t\treturn t('nextcloud-vue', 'Waiting on {party} for {days} days, chased once', { party, days })\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', 'Waiting on {party} for {days} days, chased {chases} times', { party, days, chases })\n\t\t},\n\n\t\t/**\n\t\t * Up to two initials of a title.\n\t\t *\n\t\t * @param {string} title The title.\n\t\t * @return {string}\n\t\t */\n\t\tinitials(title) {\n\t\t\treturn String(title ?? '').trim().split(/\\s+/).filter(Boolean).slice(0, 2).map((w) => w[0]).join('').toUpperCase()\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-work-queue {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 24px;\n}\n\n.cn-work-queue__head,\n.cn-work-queue__group-head {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tjustify-content: space-between;\n\tgap: 12px;\n}\n\n.cn-work-queue__title {\n\tmargin: 0;\n\tfont-size: 28px;\n\tfont-weight: 700;\n}\n\n.cn-work-queue__actions {\n\tdisplay: flex;\n\tgap: 8px;\n}\n\n.cn-work-queue__group {\n\tpadding: 20px 24px;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-large);\n\tbackground: var(--color-main-background);\n}\n\n.cn-work-queue__group-title {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tmargin: 0;\n\tfont-size: 18px;\n\tfont-weight: 700;\n}\n\n.cn-work-queue__count {\n\tpadding: 0 8px;\n\tborder-radius: 10px;\n\tbackground: var(--color-background-dark);\n\tfont-size: 12px;\n\tfont-weight: 600;\n}\n\n.cn-work-queue__muted {\n\tmargin: 4px 0 8px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-work-queue__items {\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-work-queue__item {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 16px;\n\tpadding: 12px 0;\n\tborder-block-end: 1px solid var(--color-border);\n}\n\n.cn-work-queue__item:last-child {\n\tborder-block-end: none;\n}\n\n.cn-work-queue__avatar {\n\tdisplay: inline-flex;\n\tflex: none;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 32px;\n\theight: 32px;\n\tborder-radius: 50%;\n\tbackground: var(--color-background-dark);\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 12px;\n\tfont-weight: 700;\n}\n\n.cn-work-queue__body {\n\tdisplay: flex;\n\tflex: 1 1 auto;\n\tflex-direction: column;\n\tmin-width: 0;\n}\n\n.cn-work-queue__link {\n\tcolor: var(--color-main-text);\n\tfont-weight: 700;\n\ttext-decoration: none;\n}\n\n.cn-work-queue__link:hover {\n\ttext-decoration: underline;\n}\n\n.cn-work-queue__item--late .cn-work-queue__link {\n\tcolor: var(--color-error);\n}\n\n.cn-work-queue__sub {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 12px;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n}\n</style>\n"],"names":["_openBlock","_createElementBlock","_toDisplayString","_createElementVNode","_renderSlot","_Fragment","_renderList","_createTextVNode","_createBlock","_createVNode","_normalizeClass"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnWorkQueue.vue3.js","sources":["../../../../src/components/CnWorkQueue/CnWorkQueue.vue?vue&type=template&id=d5bc0a42&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<div class=\"cn-work-queue\" data-testid=\"cn-work-queue\">\n\t\t<div v-if=\"title || $slots.actions\" class=\"cn-work-queue__head\">\n\t\t\t<h2 v-if=\"title\" class=\"cn-work-queue__title\">\n\t\t\t\t{{ title }}\n\t\t\t</h2>\n\t\t\t<div class=\"cn-work-queue__actions\">\n\t\t\t\t<!-- @slot Buttons beside the title (\"Plan an item\"). -->\n\t\t\t\t<slot name=\"actions\" />\n\t\t\t</div>\n\t\t</div>\n\n\t\t<NcNoteCard v-for=\"source in unavailable\"\n\t\t\t:key=\"source.source\"\n\t\t\ttype=\"warning\"\n\t\t\t:data-testid=\"`cn-work-queue-unavailable-${source.source}`\">\n\t\t\t{{ t('nextcloud-vue', '{source} could not be read, so this list is incomplete.', { source: source.label || source.source }) }}\n\t\t</NcNoteCard>\n\n\t\t<NcLoadingIcon v-if=\"loading\" :size=\"32\" />\n\t\t<NcEmptyContent v-else-if=\"error\"\n\t\t\t:name=\"t('nextcloud-vue', 'This queue could not be read')\"\n\t\t\t:description=\"error\"\n\t\t\tdata-testid=\"cn-work-queue-error\">\n\t\t\t<template #action>\n\t\t\t\t<NcButton @click=\"load\">\n\t\t\t\t\t{{ t('nextcloud-vue', 'Try again') }}\n\t\t\t\t</NcButton>\n\t\t\t</template>\n\t\t</NcEmptyContent>\n\t\t<template v-else>\n\t\t\t<p v-if=\"shownGroups.length === 0\" class=\"cn-work-queue__muted\" data-testid=\"cn-work-queue-empty\">\n\t\t\t\t{{ text(content.emptyText) || t('nextcloud-vue', 'Nothing is waiting on you.') }}\n\t\t\t</p>\n\t\t\t<section v-for=\"group in shownGroups\"\n\t\t\t\t:key=\"group.key\"\n\t\t\t\tclass=\"cn-work-queue__group\"\n\t\t\t\t:data-testid=\"`cn-work-queue-group-${group.key}`\">\n\t\t\t\t<div class=\"cn-work-queue__group-head\">\n\t\t\t\t\t<h3 class=\"cn-work-queue__group-title\">\n\t\t\t\t\t\t{{ group.label }}\n\t\t\t\t\t\t<span class=\"cn-work-queue__count\">{{ group.items.length }}</span>\n\t\t\t\t\t</h3>\n\t\t\t\t\t<NcButton v-if=\"content.hide\"\n\t\t\t\t\t\tvariant=\"secondary\"\n\t\t\t\t\t\t:aria-label=\"t('nextcloud-vue', 'Hide this group until tomorrow')\"\n\t\t\t\t\t\t:data-testid=\"`cn-work-queue-hide-${group.key}`\"\n\t\t\t\t\t\t@click=\"setHidden(group.key, true)\">\n\t\t\t\t\t\t{{ t('nextcloud-vue', 'Hide until tomorrow') }}\n\t\t\t\t\t</NcButton>\n\t\t\t\t</div>\n\t\t\t\t<p v-if=\"group.closesWhen\" class=\"cn-work-queue__muted\">\n\t\t\t\t\t{{ group.closesWhen }}\n\t\t\t\t</p>\n\t\t\t\t<ul class=\"cn-work-queue__items\">\n\t\t\t\t\t<li v-for=\"item in group.items\"\n\t\t\t\t\t\t:key=\"item.id\"\n\t\t\t\t\t\tclass=\"cn-work-queue__item\"\n\t\t\t\t\t\t:class=\"{ 'cn-work-queue__item--late': item.deadlineTier === 'overdue' }\"\n\t\t\t\t\t\t:data-testid=\"`cn-work-queue-item-${item.id}`\">\n\t\t\t\t\t\t<span class=\"cn-work-queue__avatar\" aria-hidden=\"true\">{{ initials(item.title) }}</span>\n\t\t\t\t\t\t<span class=\"cn-work-queue__body\">\n\t\t\t\t\t\t\t<a :href=\"hrefOf(item) || '#'\" class=\"cn-work-queue__link\" @click=\"onOpen(item, $event)\">{{ item.title }}</a>\n\t\t\t\t\t\t\t<span v-if=\"item.covered || waitingText(item)\" class=\"cn-work-queue__sub\">\n\t\t\t\t\t\t\t\t<span v-if=\"item.covered\">{{ t('nextcloud-vue', 'Covering for {person}', { person: String(item.coveredFor || '') }) }}</span>\n\t\t\t\t\t\t\t\t<span v-if=\"waitingText(item)\" :data-testid=\"`cn-work-queue-waiting-${item.id}`\">{{ waitingText(item) }}</span>\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<span v-if=\"item.dueAt\" class=\"cn-work-queue__muted\">{{ item.dueAt }}</span>\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t</section>\n\t\t</template>\n\n\t\t<section v-if=\"content.hide && hidden.length\" class=\"cn-work-queue__group\" data-testid=\"cn-work-queue-hidden\">\n\t\t\t<h3 class=\"cn-work-queue__group-title\">\n\t\t\t\t{{ t('nextcloud-vue', 'Hidden until tomorrow') }}\n\t\t\t</h3>\n\t\t\t<NcButton v-for=\"key in hidden\"\n\t\t\t\t:key=\"key\"\n\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t:data-testid=\"`cn-work-queue-show-${key}`\"\n\t\t\t\t@click=\"setHidden(key, false)\">\n\t\t\t\t{{ t('nextcloud-vue', 'Show {group} again', { group: labelOf(key) }) }}\n\t\t\t</NcButton>\n\t\t</section>\n\t</div>\n</template>\n\n<script>\nimport axios from '@nextcloud/axios'\nimport { subscribe, unsubscribe } from '@nextcloud/event-bus'\nimport { translate as t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { NcButton, NcEmptyContent, NcLoadingIcon, NcNoteCard } from '@nextcloud/vue'\nimport { fetchEndpointSource } from '../../composables/useEndpointSource.js'\nimport { fillTemplate } from '../../utils/fillTemplate.js'\nimport { openRowTarget } from '../../utils/linkNavigation.js'\n\n/**\n * CnWorkQueue — one list of everything waiting on the reader: tasks,\n * consultations, mentions, calendar items, work they cover for a colleague,\n * from as many sources as the server declares. The component names no\n * source: the server answers the groups (`key`, `label`, `closesWhen`,\n * `items`), so a new kind of work needs no change here. A source that could\n * not be read is named at the top rather than folded into \"nothing is\n * waiting\". A group can be hidden until tomorrow, through the server, so the\n * choice follows the reader to another device. dossiq's personal queue is\n * the first; pipelinq's queue has the same shape. It reads again on\n * `cn:page:refresh`, so work planned or closed in a dialog shows at once.\n *\n * `content`:\n * - `source`: an endpointSource answering `{ groups, hiddenGroups?, unavailable? }`.\n * An item is `{ id, title, dueAt?, deadlineTier?, covered?, coveredFor?,\n * waiting?: { on, days, chases }, route?, href? }`.\n * - `hide`, `show`: url templates with `{group}` that hide a group until\n * tomorrow and show it again, each answering `{ hiddenGroups }`; without\n * `hide` no group can be hidden.\n * - `itemHref`: a template filled from an item, when items carry no `route`/`href`.\n * - `waitingParties`: words for `waiting.on` (`{ applicant: \"the applicant\" }`).\n * - `emptyText`: through the host translate.\n */\nexport default {\n\tname: 'CnWorkQueue',\n\n\tcomponents: { NcButton, NcEmptyContent, NcLoadingIcon, NcNoteCard },\n\n\tinject: {\n\t\t/** The host app's translate (CnAppRoot `cnTranslate`). */\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The queue's configuration (see the component docs).\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 heading above the queue; none when empty. */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\temits: ['open'],\n\n\tdata() {\n\t\treturn {\n\t\t\tloading: true,\n\t\t\terror: '',\n\t\t\tgroups: [],\n\t\t\thidden: [],\n\t\t\tunavailable: [],\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The groups not hidden today.\n\t\t *\n\t\t * @spec openspec/changes/work-queue/specs/work-queue/spec.md#requirement-one-queue-over-every-source\n\t\t * @return {Array<object>}\n\t\t */\n\t\tshownGroups() {\n\t\t\tconst hidden = new Set(this.hidden.map(String))\n\t\t\treturn this.groups.filter((group) => !hidden.has(String(group.key)))\n\t\t},\n\t},\n\n\tmounted() {\n\t\tsubscribe('cn:page:refresh', this.load)\n\t\tthis.load()\n\t},\n\n\tbeforeUnmount() {\n\t\tunsubscribe('cn:page:refresh', this.load)\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\t/**\n\t\t * A config text through the host translate.\n\t\t *\n\t\t * @param {unknown} value The text.\n\t\t * @return {string}\n\t\t */\n\t\ttext(value) {\n\t\t\treturn typeof value === 'string' && value !== '' ? this.cnTranslate(value) : ''\n\t\t},\n\n\t\t/**\n\t\t * Read the queue; a failed read is an error with a retry.\n\t\t *\n\t\t * @spec openspec/changes/work-queue/specs/work-queue/spec.md#requirement-one-queue-over-every-source\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync load() {\n\t\t\tthis.loading = true\n\t\t\tthis.error = ''\n\t\t\ttry {\n\t\t\t\tconst data = (await fetchEndpointSource(this.content.source, {}, { fresh: true })) || {}\n\t\t\t\tthis.groups = (Array.isArray(data.groups) ? data.groups : [])\n\t\t\t\t\t.filter((g) => g && g.key !== undefined)\n\t\t\t\t\t.map((g) => ({ ...g, items: Array.isArray(g.items) ? g.items : [] }))\n\t\t\t\tthis.hidden = Array.isArray(data.hiddenGroups) ? data.hiddenGroups.map(String) : []\n\t\t\t\tthis.unavailable = Array.isArray(data.unavailable) ? data.unavailable.filter((s) => s && s.source) : []\n\t\t\t} catch (failure) {\n\t\t\t\tconst body = failure && failure.response && failure.response.data\n\t\t\t\tthis.error = String((body && (body.message || body.error)) || (failure && failure.message) || failure)\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Hide a group until tomorrow, or show it again, through the server.\n\t\t *\n\t\t * @spec openspec/changes/work-queue/specs/work-queue/spec.md#requirement-one-queue-over-every-source\n\t\t * @param {string} key The group key.\n\t\t * @param {boolean} hide Hide (true) or show (false).\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync setHidden(key, hide) {\n\t\t\tconst template = hide ? this.content.hide : this.content.show\n\t\t\tif (!template) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst { data } = await axios.post(generateUrl(fillTemplate(template, { group: encodeURIComponent(key) })), {})\n\t\t\t\tthis.hidden = Array.isArray(data && data.hiddenGroups) ? data.hiddenGroups.map(String) : this.hidden\n\t\t\t} catch {\n\t\t\t\t// The group stays as it was; the server decides.\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * A group's label by key, for a hidden group.\n\t\t *\n\t\t * @param {string} key The key.\n\t\t * @return {string}\n\t\t */\n\t\tlabelOf(key) {\n\t\t\tconst group = this.groups.find((g) => String(g.key) === String(key))\n\t\t\treturn group && group.label ? group.label : String(key)\n\t\t},\n\n\t\t/**\n\t\t * An item's page as an href.\n\t\t *\n\t\t * @param {object} item The item.\n\t\t * @return {string}\n\t\t */\n\t\threfOf(item) {\n\t\t\tif (item.route && this.$router) {\n\t\t\t\ttry {\n\t\t\t\t\treturn this.$router.resolve(item.route).href\n\t\t\t\t} catch {\n\t\t\t\t\treturn ''\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (item.href) {\n\t\t\t\treturn String(item.href)\n\t\t\t}\n\t\t\treturn this.content.itemHref ? generateUrl(fillTemplate(this.content.itemHref, item)) : ''\n\t\t},\n\n\t\t/**\n\t\t * Open an item: its route through the router, else its href like a link, else tell the host.\n\t\t *\n\t\t * @param {object} item The item.\n\t\t * @param {MouseEvent} event The click.\n\t\t */\n\t\tonOpen(item, event) {\n\t\t\tif (item.route && this.$router && event && !(event.ctrlKey || event.metaKey || event.shiftKey || event.button === 1)) {\n\t\t\t\tevent.preventDefault()\n\t\t\t\tthis.$router.push(item.route).catch(() => {})\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst href = this.hrefOf(item)\n\t\t\tif (href) {\n\t\t\t\tif (event) {\n\t\t\t\t\tevent.preventDefault()\n\t\t\t\t}\n\t\t\t\topenRowTarget(event, href)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (event) {\n\t\t\t\tevent.preventDefault()\n\t\t\t}\n\t\t\t/** @event open An item without a route or href was opened. Payload: the item. */\n\t\t\tthis.$emit('open', item)\n\t\t},\n\n\t\t/**\n\t\t * Who the item waits on, for how long and how often chased.\n\t\t *\n\t\t * @param {object} item The item.\n\t\t * @return {string}\n\t\t */\n\t\twaitingText(item) {\n\t\t\tconst waiting = item && item.waiting\n\t\t\tif (!waiting || typeof waiting !== 'object' || !waiting.on) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst parties = {\n\t\t\t\tapplicant: t('nextcloud-vue', 'the applicant'),\n\t\t\t\tthirdParty: t('nextcloud-vue', 'a third party'),\n\t\t\t\tus: t('nextcloud-vue', 'us'),\n\t\t\t}\n\t\t\tconst own = this.content.waitingParties && this.content.waitingParties[waiting.on]\n\t\t\tconst party = own ? this.cnTranslate(own) : (parties[waiting.on] || String(waiting.on))\n\t\t\tconst days = Number.isFinite(waiting.days) ? waiting.days : 0\n\t\t\tconst chases = Number.isFinite(waiting.chases) ? waiting.chases : 0\n\t\t\tif (chases === 0) {\n\t\t\t\treturn t('nextcloud-vue', 'Waiting on {party} for {days} days', { party, days })\n\t\t\t}\n\t\t\tif (chases === 1) {\n\t\t\t\treturn t('nextcloud-vue', 'Waiting on {party} for {days} days, chased once', { party, days })\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', 'Waiting on {party} for {days} days, chased {chases} times', { party, days, chases })\n\t\t},\n\n\t\t/**\n\t\t * Up to two initials of a title.\n\t\t *\n\t\t * @param {string} title The title.\n\t\t * @return {string}\n\t\t */\n\t\tinitials(title) {\n\t\t\treturn String(title ?? '').trim().split(/\\s+/).filter(Boolean).slice(0, 2).map((w) => w[0]).join('').toUpperCase()\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-work-queue {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 24px;\n}\n\n.cn-work-queue__head,\n.cn-work-queue__group-head {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tjustify-content: space-between;\n\tgap: 12px;\n}\n\n.cn-work-queue__title {\n\tmargin: 0;\n\tfont-size: 28px;\n\tfont-weight: 700;\n}\n\n.cn-work-queue__actions {\n\tdisplay: flex;\n\tgap: 8px;\n}\n\n.cn-work-queue__group {\n\tpadding: 20px 24px;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-large);\n\tbackground: var(--color-main-background);\n}\n\n.cn-work-queue__group-title {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tmargin: 0;\n\tfont-size: 18px;\n\tfont-weight: 700;\n}\n\n.cn-work-queue__count {\n\tpadding: 0 8px;\n\tborder-radius: 10px;\n\tbackground: var(--color-background-dark);\n\tfont-size: 12px;\n\tfont-weight: 600;\n}\n\n.cn-work-queue__muted {\n\tmargin: 4px 0 8px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-work-queue__items {\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-work-queue__item {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 16px;\n\tpadding: 12px 0;\n\tborder-block-end: 1px solid var(--color-border);\n}\n\n.cn-work-queue__item:last-child {\n\tborder-block-end: none;\n}\n\n.cn-work-queue__avatar {\n\tdisplay: inline-flex;\n\tflex: none;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 32px;\n\theight: 32px;\n\tborder-radius: 50%;\n\tbackground: var(--color-background-dark);\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 12px;\n\tfont-weight: 700;\n}\n\n.cn-work-queue__body {\n\tdisplay: flex;\n\tflex: 1 1 auto;\n\tflex-direction: column;\n\tmin-width: 0;\n}\n\n.cn-work-queue__link {\n\tcolor: var(--color-main-text);\n\tfont-weight: 700;\n\ttext-decoration: none;\n}\n\n.cn-work-queue__link:hover {\n\ttext-decoration: underline;\n}\n\n.cn-work-queue__item--late .cn-work-queue__link {\n\tcolor: var(--color-error);\n}\n\n.cn-work-queue__sub {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 12px;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n}\n</style>\n"],"names":["_openBlock","_createElementBlock","_toDisplayString","_createElementVNode","_renderSlot","_Fragment","_renderList","_createTextVNode","_createBlock","_createVNode","_normalizeClass"],"mappings":"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"}
|