@conduction/nextcloud-vue 2.132.0 → 2.133.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/components/CnActionButtons/CnActionButtons.vue.js +1 -1
- package/dist/esm/components/CnActionButtons/CnActionButtons.vue2.js +14 -0
- package/dist/esm/components/CnActionButtons/CnActionButtons.vue2.js.map +1 -1
- package/dist/esm/components/CnActionButtons/CnActionButtons.vue3.js +5 -4
- package/dist/esm/components/CnActionButtons/CnActionButtons.vue3.js.map +1 -1
- package/dist/esm/components/CnConditionListEditor/CnConditionListEditor.vue.js +9 -0
- package/dist/esm/components/CnConditionListEditor/CnConditionListEditor.vue.js.map +1 -0
- package/dist/esm/components/CnConditionListEditor/CnConditionListEditor.vue2.js +237 -0
- package/dist/esm/components/CnConditionListEditor/CnConditionListEditor.vue2.js.map +1 -0
- package/dist/esm/components/CnConditionListEditor/CnConditionListEditor.vue3.js +103 -0
- package/dist/esm/components/CnConditionListEditor/CnConditionListEditor.vue3.js.map +1 -0
- package/dist/esm/components/CnConditionListEditor/conditionOperators.js +121 -0
- package/dist/esm/components/CnConditionListEditor/conditionOperators.js.map +1 -0
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +12 -0
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +8 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue.js +1 -1
- package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue2.js +46 -7
- package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue3.js +1 -1
- package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectPartiesWidget/CnObjectPartiesWidget.vue.js +1 -1
- package/dist/esm/components/CnObjectPartiesWidget/CnObjectPartiesWidget.vue2.js +59 -3
- package/dist/esm/components/CnObjectPartiesWidget/CnObjectPartiesWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectPartiesWidget/CnObjectPartiesWidget.vue3.js +197 -127
- package/dist/esm/components/CnObjectPartiesWidget/CnObjectPartiesWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +42 -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/CnTabsWidget/CnTabsWidget.vue.js +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/l10n/en.json.js +17 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +17 -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 +277 -166
- package/dist/esm/store/plugins/liveUpdates.js +13 -4
- package/dist/esm/store/plugins/liveUpdates.js.map +1 -1
- package/dist/esm/store/useObjectStore.js +28 -5
- package/dist/esm/store/useObjectStore.js.map +1 -1
- package/dist/esm/utils/detailActionModel.js +6 -0
- package/dist/esm/utils/detailActionModel.js.map +1 -1
- package/dist/esm/utils/listLenses.js +20 -1
- package/dist/esm/utils/listLenses.js.map +1 -1
- package/dist/esm/utils/objectRows.js +59 -0
- package/dist/esm/utils/objectRows.js.map +1 -0
- package/dist/esm/utils/validateManifestV2.compiled.js +3 -3
- package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +5961 -5127
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +277 -166
- package/l10n/en.json +17 -1
- package/l10n/nl.json +17 -1
- package/package.json +1 -1
- package/src/components/CnActionButtons/CnActionButtons.vue +15 -0
- package/src/components/CnConditionListEditor/CnConditionListEditor.vue +346 -0
- package/src/components/CnConditionListEditor/conditionOperators.js +126 -0
- package/src/components/CnConditionListEditor/index.js +17 -0
- package/src/components/CnDetailPage/CnDetailPage.md +1 -0
- package/src/components/CnDetailPage/CnDetailPage.vue +13 -1
- package/src/components/CnIndexPage/CnIndexPage.vue +8 -1
- package/src/components/CnNcWidgetWidget/CnNcWidgetWidget.vue +47 -8
- package/src/components/CnObjectPartiesWidget/CnObjectPartiesWidget.vue +139 -2
- package/src/components/CnRecordListWidget/CnRecordListWidget.vue +42 -2
- package/src/components/CnTabsWidget/CnTabsWidget.vue +1 -1
- package/src/components/index.js +1 -0
- package/src/css/look-board-index.css +6 -0
- package/src/css/look-board.css +35 -7
- package/src/index.js +2 -0
- package/src/schemas/app-manifest-v2.schema.json +17 -1
- package/src/store/plugins/liveUpdates.js +13 -4
- package/src/store/useObjectStore.js +28 -5
- package/src/utils/detailActionModel.js +6 -0
- package/src/utils/listLenses.js +20 -1
- package/src/utils/objectRows.js +55 -0
- package/src/utils/validateManifestV2.compiled.js +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnObjectPartiesWidget.vue3.js","sources":["../../../../src/components/CnObjectPartiesWidget/CnObjectPartiesWidget.vue?vue&type=template&id=e8220226&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-object-parties\" data-testid=\"cn-object-parties\">\n\t\t<NcLoadingIcon v-if=\"loading\" :size=\"24\" />\n\n\t\t<NcEmptyContent\n\t\t\tv-else-if=\"failed\"\n\t\t\t:name=\"label('failed')\"\n\t\t\t:description=\"label('failedDetail')\"\n\t\t\tdata-testid=\"cn-object-parties-failed\" />\n\n\t\t<NcEmptyContent\n\t\t\tv-else-if=\"groups.length === 0\"\n\t\t\t:name=\"label('empty')\"\n\t\t\t:description=\"label('emptyDetail')\"\n\t\t\tdata-testid=\"cn-object-parties-empty\" />\n\n\t\t<template v-else>\n\t\t\t<div\n\t\t\t\tv-if=\"kinds\"\n\t\t\t\tclass=\"cn-object-parties__accepted\"\n\t\t\t\t:data-source=\"kinds.source\"\n\t\t\t\tdata-testid=\"cn-object-parties-accepted\">\n\t\t\t\t<span class=\"cn-object-parties__accepted-label\">{{ label('accepted') }}</span>\n\t\t\t\t<span\n\t\t\t\t\tv-for=\"(kind, index) in kinds.kinds\"\n\t\t\t\t\t:key=\"kindCode(kind)\"\n\t\t\t\t\tclass=\"cn-status-badge cn-status-badge--default cn-object-parties__accepted-kind\"\n\t\t\t\t\tdata-testid=\"cn-object-parties-accepted-kind\">{{ index + 1 }}. {{ kind.label || kindCode(kind) }}</span>\n\t\t\t\t<span v-if=\"kindsSourceText\" class=\"cn-object-parties__muted\">{{ kindsSourceText }}</span>\n\t\t\t</div>\n\n\t\t\t<div\n\t\t\t\tv-if=\"verdicts.length > 0\"\n\t\t\t\tclass=\"cn-object-parties__verdicts\"\n\t\t\t\tdata-testid=\"cn-object-parties-verdicts\">\n\t\t\t\t<NcNoteCard\n\t\t\t\t\tv-for=\"verdict in verdicts\"\n\t\t\t\t\t:key=\"`${verdict.party}-${verdict.key}`\"\n\t\t\t\t\t:type=\"verdict.severity\"\n\t\t\t\t\t:data-effect=\"verdict.effect\"\n\t\t\t\t\tdata-testid=\"cn-object-parties-verdict\">\n\t\t\t\t\t<strong>{{ verdict.label }}</strong>\n\t\t\t\t\t<span>{{ verdict.sentence }}</span>\n\t\t\t\t</NcNoteCard>\n\t\t\t</div>\n\n\t\t\t<section\n\t\t\t\tv-for=\"group in groups\"\n\t\t\t\t:key=\"group.key\"\n\t\t\t\tclass=\"cn-object-parties__role\"\n\t\t\t\t:data-role=\"group.key\"\n\t\t\t\t:aria-labelledby=\"`${idPrefix}-${group.key}`\"\n\t\t\t\tdata-testid=\"cn-object-parties-role\">\n\t\t\t\t<component :is=\"innerHeadingTag\" :id=\"`${idPrefix}-${group.key}`\" class=\"cn-object-parties__role-label cn-inner-heading\">\n\t\t\t\t\t{{ group.label }}\n\t\t\t\t</component>\n\t\t\t\t<ul class=\"cn-object-parties__list\">\n\t\t\t\t\t<li\n\t\t\t\t\t\tv-for=\"party in group.parties\"\n\t\t\t\t\t\t:key=\"`${group.key}-${party.partyUuid || party.contactUid}`\"\n\t\t\t\t\t\tclass=\"cn-object-parties__party\"\n\t\t\t\t\t\t:data-party=\"party.partyUuid || party.contactUid\"\n\t\t\t\t\t\tdata-testid=\"cn-object-parties-party\">\n\t\t\t\t\t\t<span class=\"cn-object-parties__name\">{{ nameOf(party) }}</span>\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tv-if=\"primary && party.partyUuid === primary\"\n\t\t\t\t\t\t\tclass=\"cn-status-badge cn-status-badge--primary\"\n\t\t\t\t\t\t\tdata-testid=\"cn-object-parties-primary\">{{ label('primary') }}</span>\n\t\t\t\t\t\t<span v-if=\"kindOf(party)\" class=\"cn-object-parties__muted\">{{ kindOf(party) }}</span>\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tv-if=\"notAccepted(party)\"\n\t\t\t\t\t\t\tclass=\"cn-status-badge cn-status-badge--warning\"\n\t\t\t\t\t\t\tdata-testid=\"cn-object-parties-not-accepted\">{{ label('notAccepted') }}</span>\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tv-for=\"(line, index) in extraLinesOf(party)\"\n\t\t\t\t\t\t\t:key=\"`line-${index}`\"\n\t\t\t\t\t\t\tclass=\"cn-object-parties__muted\"\n\t\t\t\t\t\t\tdata-testid=\"cn-object-parties-extra-line\">{{ line }}</span>\n\t\t\t\t\t\t<span v-if=\"party.email\" class=\"cn-object-parties__muted\">{{ party.email }}</span>\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tv-if=\"representedBy(party)\"\n\t\t\t\t\t\t\tclass=\"cn-object-parties__muted\"\n\t\t\t\t\t\t\tdata-testid=\"cn-object-parties-represented\">{{ label('representedBy') }}: {{ representedBy(party) }}</span>\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tv-if=\"correspondenceOf(party)\"\n\t\t\t\t\t\t\tclass=\"cn-object-parties__muted\"\n\t\t\t\t\t\t\t:data-party-documents=\"party.partyUuid || party.contactUid\"\n\t\t\t\t\t\t\tdata-testid=\"cn-object-parties-documents\">{{ correspondenceOf(party) }}</span>\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tv-for=\"indicator in indicatorsFor(party)\"\n\t\t\t\t\t\t\t:key=\"`${party.partyUuid}-${indicator.key}`\"\n\t\t\t\t\t\t\tclass=\"cn-status-badge cn-status-badge--default\"\n\t\t\t\t\t\t\t:class=\"`cn-object-parties__indicator--${indicator.severity}`\"\n\t\t\t\t\t\t\t:data-effect=\"indicator.effect\"\n\t\t\t\t\t\t\t:title=\"indicator.verdict\"\n\t\t\t\t\t\t\tdata-testid=\"cn-object-parties-indicator\">{{ indicator.label }} · {{ indicator.verdict }}</span>\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t</section>\n\t\t</template>\n\t</div>\n</template>\n\n<script>\nimport axios from '@nextcloud/axios'\nimport { translatePlural as n, translate as t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { NcEmptyContent, NcLoadingIcon, NcNoteCard } from '@nextcloud/vue'\nimport { interpolateUrlTokens } from '../../composables/useEndpointSource.js'\nimport innerHeading from '../../mixins/innerHeading.js'\nimport { conditionalLine } from '../../utils/conditionalLine.js'\nimport {\n\tdocumentsOfParty,\n\tindicatorsOf,\n\tindicatorVerdict,\n\tkindCode,\n\trepresentedByMap,\n\trolesInOrder,\n} from '../../utils/objectParties.js'\nimport { readPath } from '../../utils/readPath.js'\n\nlet uid = 0\n\n/**\n * The default words, keyed as `content.labels` overrides them.\n *\n * @return {object} The labels.\n */\nfunction defaultLabels() {\n\treturn {\n\t\tfailed: t('nextcloud-vue', 'The parties could not be read'),\n\t\tfailedDetail: t('nextcloud-vue', 'OpenRegister did not answer. Nothing has been removed.'),\n\t\tempty: t('nextcloud-vue', 'No parties yet'),\n\t\temptyDetail: t('nextcloud-vue', 'Add a party to record who this is for and who acts on it.'),\n\t\taccepted: t('nextcloud-vue', 'Accepted kinds'),\n\t\tprimary: t('nextcloud-vue', 'Primary party'),\n\t\tnotAccepted: t('nextcloud-vue', 'Kind not accepted here'),\n\t\trepresentedBy: t('nextcloud-vue', 'Represented by'),\n\t}\n}\n\n/**\n * CnObjectPartiesWidget — the `parties` widget: a record's parties as\n * OpenRegister's party model answers them, grouped by role with the primary\n * party first. Each party shows its kind, its representative and the\n * indicators on it, each with its verdict. A blocking verdict is also a note\n * above the list, so nobody publishes or sends past it.\n *\n * ```json\n * {\n * \"type\": \"parties\",\n * \"content\": {\n * \"rolesObjects\": { \"register\": \"myapp\", \"schema\": \"role\", \"field\": \"item\" },\n * \"roleLabels\": { \"applicant\": \"Applicant\" },\n * \"kindsSource\": { \"url\": \"/apps/myapp/api/items/@objectId/party-kinds\", \"enforce\": \"crm\" },\n * \"extraLines\": [{ \"endpoint\": \"/apps/myapp/api/items/@objectId/parties/{party}/language\", \"lines\": [\"Language: {language}\"] }],\n * \"correspondence\": { \"endpoint\": \"/apps/myapp/api/items/@objectId/documents\", \"path\": \"documents\" }\n * }\n * }\n * ```\n *\n * A failed read says so and is never shown as \"no parties\".\n *\n * @spec openspec/changes/dq-abstract-record-widgets/specs/record-widgets/spec.md#requirement-a-record-shows-its-parties-by-role\n */\nexport default {\n\tname: 'CnObjectPartiesWidget',\n\n\tcomponents: { NcEmptyContent, NcLoadingIcon, NcNoteCard },\n\n\tmixins: [innerHeading],\n\n\tinject: {\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The configuration: `rolesSource` (the listing URL, default\n\t\t * OpenRegister's `/parties` of this record), `partySource` (one\n\t\t * party, `{uuid}` filled in), `rolesObjects` (`{ register, schema,\n\t\t * field }`, the role rows that say who represents whom), `roleLabels`,\n\t\t * `kindsSource` (`{ url, enforce?, sourceText? }`), `extraLines`\n\t\t * (`[{ endpoint, path?, valueLabels?, lines }]`, one request per\n\t\t * party, `{party}` filled in), `correspondence` (`{ endpoint, path?,\n\t\t * senderField?, recipientsField? }`) and `labels`.\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** The record's id, bound by the detail host. */\n\t\tobjectId: {\n\t\t\ttype: [String, Number],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** The record's register slug. */\n\t\tregister: {\n\t\t\ttype: [String, Object],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** The record's schema slug. */\n\t\tschema: {\n\t\t\ttype: [String, Object],\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\tdata() {\n\t\tuid += 1\n\t\treturn {\n\t\t\tidPrefix: `cn-object-parties-${uid}`,\n\t\t\tloading: true,\n\t\t\tfailed: false,\n\t\t\tlisting: null,\n\t\t\tpartyRecords: {},\n\t\t\trepresented: {},\n\t\t\tkinds: null,\n\t\t\textra: {},\n\t\t\tdocuments: [],\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** @return {Array<object>} The role groups, primary first. */\n\t\tgroups() {\n\t\t\treturn rolesInOrder(this.listing, this.translatedMap(this.content?.roleLabels))\n\t\t},\n\n\t\t/** @return {string|null} The primary party's uuid. */\n\t\tprimary() {\n\t\t\treturn this.listing?.primary || null\n\t\t},\n\n\t\t/** @return {object} The verdict words, translated. */\n\t\tverdictLabels() {\n\t\t\tconst own = this.content?.labels || {}\n\t\t\tconst out = {}\n\t\t\tfor (const key of ['verdictPublication', 'verdictSend', 'verdictWarn']) {\n\t\t\t\tif (typeof own[key] === 'string' && own[key] !== '') {\n\t\t\t\t\tout[key] = this.cnTranslate(own[key])\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn out\n\t\t},\n\n\t\t/** @return {Array<object>} The blocking verdicts, as notes above the list. */\n\t\tverdicts() {\n\t\t\treturn indicatorsOf(Object.values(this.partyRecords))\n\t\t\t\t.map((indicator) => ({\n\t\t\t\t\t...indicatorVerdict(indicator, this.verdictLabels),\n\t\t\t\t\tparty: indicator.party,\n\t\t\t\t\tkey: indicator.key,\n\t\t\t\t\tsentence: this.sentenceFor(indicator),\n\t\t\t\t}))\n\t\t\t\t.filter((verdict) => verdict.severity === 'error')\n\t\t},\n\n\t\t/** @return {string} Where the accepted kinds come from. */\n\t\tkindsSourceText() {\n\t\t\tconst texts = this.content?.kindsSource?.sourceText\n\t\t\tif (!this.kinds || !texts || typeof texts !== 'object') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst text = texts[this.kinds.source] || texts.default || ''\n\t\t\treturn text ? this.cnTranslate(text) : ''\n\t\t},\n\n\t\t/** @return {Record<string, string>} The kind labels the listing declares. */\n\t\tkindLabels() {\n\t\t\tconst labels = {}\n\t\t\tfor (const kind of this.listing?.kinds || []) {\n\t\t\t\tif (kind && kind.key) {\n\t\t\t\t\tlabels[kind.key] = kind.label || kind.key\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn labels\n\t\t},\n\n\t\t/** @return {string} A key that changes when the record does. */\n\t\trecordKey() {\n\t\t\treturn `${this.register}|${this.schema}|${this.objectId}`\n\t\t},\n\t},\n\n\twatch: {\n\t\trecordKey: {\n\t\t\timmediate: true,\n\t\t\thandler() {\n\t\t\t\tthis.load()\n\t\t\t},\n\t\t},\n\t},\n\n\tmethods: {\n\t\tkindCode,\n\n\t\t/**\n\t\t * A label: the content's own (translated), else the default.\n\t\t *\n\t\t * @param {string} key The label key.\n\t\t * @return {string}\n\t\t */\n\t\tlabel(key) {\n\t\t\tconst own = this.content?.labels && typeof this.content.labels[key] === 'string' ? this.content.labels[key] : ''\n\t\t\treturn own !== '' ? this.cnTranslate(own) : defaultLabels()[key]\n\t\t},\n\n\t\t/**\n\t\t * A map of manifest words, translated.\n\t\t *\n\t\t * @param {object} map The map.\n\t\t * @return {Record<string, string>}\n\t\t */\n\t\ttranslatedMap(map) {\n\t\t\tconst out = {}\n\t\t\tfor (const [key, value] of Object.entries(map && typeof map === 'object' ? map : {})) {\n\t\t\t\tout[key] = typeof value === 'string' ? this.cnTranslate(value) : value\n\t\t\t}\n\t\t\treturn out\n\t\t},\n\n\t\t/**\n\t\t * An app path with the record's tokens and `{party}` filled in.\n\t\t *\n\t\t * @param {string} template The path.\n\t\t * @param {string} [party] A party uuid.\n\t\t * @return {string}\n\t\t */\n\t\turlOf(template, party = '') {\n\t\t\tconst withSlugs = String(template)\n\t\t\t\t.replaceAll('@register', String(this.register || ''))\n\t\t\t\t.replaceAll('@schema', String(this.schema || ''))\n\t\t\treturn interpolateUrlTokens(withSlugs, { objectId: this.objectId }).replaceAll('{party}', encodeURIComponent(party)).replaceAll('{uuid}', encodeURIComponent(party))\n\t\t},\n\n\t\t/**\n\t\t * GET an app path; null when it fails.\n\t\t *\n\t\t * @param {string} path The app path.\n\t\t * @param {object} [params] Query parameters.\n\t\t * @return {Promise<unknown>}\n\t\t */\n\t\tasync read(path, params) {\n\t\t\ttry {\n\t\t\t\tconst { data } = await axios.get(generateUrl(path), params ? { params } : undefined)\n\t\t\t\treturn data ?? null\n\t\t\t} catch {\n\t\t\t\treturn null\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Read the listing, then each party, the representation, the kinds,\n\t\t * the extra lines and the correspondence.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync load() {\n\t\t\tif (!this.objectId) {\n\t\t\t\tthis.loading = false\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.failed = false\n\t\t\tthis.partyRecords = {}\n\t\t\tthis.represented = {}\n\t\t\tthis.extra = {}\n\t\t\tthis.documents = []\n\t\t\tconst listing = await this.read(this.urlOf(this.content?.rolesSource || '/apps/openregister/api/objects/@register/@schema/@objectId/parties'))\n\t\t\tif (!listing || typeof listing !== 'object') {\n\t\t\t\tthis.failed = true\n\t\t\t\tthis.listing = null\n\t\t\t\tthis.loading = false\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.listing = listing\n\t\t\tconst uuids = [...new Set((listing.results || []).map((row) => row && row.partyUuid).filter(Boolean))]\n\t\t\tconst partyUrl = this.content?.partySource || '/apps/openregister/api/parties/{uuid}'\n\t\t\tconst records = await Promise.all(uuids.map((uuid) => this.read(this.urlOf(partyUrl, uuid))))\n\t\t\tconst byUuid = {}\n\t\t\tuuids.forEach((uuid, index) => {\n\t\t\t\tif (records[index] && typeof records[index] === 'object') {\n\t\t\t\t\tbyUuid[uuid] = records[index]\n\t\t\t\t}\n\t\t\t})\n\t\t\tthis.partyRecords = byUuid\n\t\t\tawait Promise.all([this.loadRepresentation(), this.loadKinds(), this.loadExtraLines(uuids), this.loadCorrespondence()])\n\t\t\tthis.loading = false\n\t\t},\n\n\t\t/** @return {Promise<void>} Who represents whom, from the role rows. */\n\t\tasync loadRepresentation() {\n\t\t\tconst source = this.content?.rolesObjects\n\t\t\tif (!source || !source.register || !source.schema) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst data = await this.read(`/apps/openregister/api/objects/${encodeURIComponent(source.register)}/${encodeURIComponent(source.schema)}`, { [source.field || 'object']: String(this.objectId), _limit: 200 })\n\t\t\tconst rows = Array.isArray(data?.results) ? data.results : (Array.isArray(data) ? data : [])\n\t\t\tthis.represented = representedByMap(rows)\n\t\t},\n\n\t\t/** @return {Promise<void>} The kinds this record accepts. */\n\t\tasync loadKinds() {\n\t\t\tconst source = this.content?.kindsSource\n\t\t\tthis.kinds = null\n\t\t\tif (!source || !source.url) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst data = await this.read(this.urlOf(source.url))\n\t\t\tthis.kinds = data && Array.isArray(data.kinds) ? data : null\n\t\t},\n\n\t\t/**\n\t\t * One answer per party per extra line.\n\t\t *\n\t\t * @param {Array<string>} uuids The parties.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync loadExtraLines(uuids) {\n\t\t\tconst lines = Array.isArray(this.content?.extraLines) ? this.content.extraLines : []\n\t\t\tconst extra = {}\n\t\t\tawait Promise.all(lines.map(async (spec, index) => {\n\t\t\t\tif (!spec || !spec.endpoint) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tconst answers = await Promise.all(uuids.map((uuid) => this.read(this.urlOf(spec.endpoint, uuid))))\n\t\t\t\tuuids.forEach((uuid, i) => {\n\t\t\t\t\tconst answer = spec.path ? readPath(answers[i], spec.path) : answers[i]\n\t\t\t\t\tif (answer && typeof answer === 'object') {\n\t\t\t\t\t\textra[`${index}|${uuid}`] = answer\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t}))\n\t\t\tthis.extra = extra\n\t\t},\n\n\t\t/** @return {Promise<void>} The documents the correspondence counts read. */\n\t\tasync loadCorrespondence() {\n\t\t\tconst spec = this.content?.correspondence\n\t\t\tif (!spec || !spec.endpoint) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst data = await this.read(this.urlOf(spec.endpoint))\n\t\t\tconst list = spec.path ? readPath(data, spec.path) : data\n\t\t\tthis.documents = Array.isArray(list) ? list : []\n\t\t},\n\n\t\t/**\n\t\t * The extra lines for a party, each the first of its `lines` that applies.\n\t\t *\n\t\t * @param {object} party The listing row.\n\t\t * @return {Array<string>}\n\t\t */\n\t\textraLinesOf(party) {\n\t\t\tconst specs = Array.isArray(this.content?.extraLines) ? this.content.extraLines : []\n\t\t\treturn specs.map((spec, index) => {\n\t\t\t\tconst answer = this.extra[`${index}|${party.partyUuid}`]\n\t\t\t\tif (!answer) {\n\t\t\t\t\treturn ''\n\t\t\t\t}\n\t\t\t\treturn conditionalLine(spec.lines || [], this.labelled(answer, spec.valueLabels), (text) => this.cnTranslate(text))\n\t\t\t}).filter((line) => line !== '')\n\t\t},\n\n\t\t/**\n\t\t * An answer with its coded values replaced by their labels\n\t\t * (`valueLabels: { language: { nl: \"Dutch\" } }`; `nl-NL` reads as `nl`).\n\t\t *\n\t\t * @param {object} answer The answer.\n\t\t * @param {object} valueLabels The labels by field and value.\n\t\t * @return {object}\n\t\t */\n\t\tlabelled(answer, valueLabels) {\n\t\t\tif (!valueLabels || typeof valueLabels !== 'object') {\n\t\t\t\treturn answer\n\t\t\t}\n\t\t\tconst out = { ...answer }\n\t\t\tfor (const [field, map] of Object.entries(valueLabels)) {\n\t\t\t\tconst raw = answer[field]\n\t\t\t\tif (typeof raw !== 'string' || !map) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst hit = map[raw] ?? map[raw.toLowerCase().split('-')[0]]\n\t\t\t\tif (typeof hit === 'string') {\n\t\t\t\t\tout[field] = this.cnTranslate(hit)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn out\n\t\t},\n\n\t\t/**\n\t\t * Whether a party's kind is one this record does not accept. Only when\n\t\t * the kinds come from the source named by `kindsSource.enforce`.\n\t\t *\n\t\t * @param {object} party The listing row.\n\t\t * @return {boolean}\n\t\t */\n\t\tnotAccepted(party) {\n\t\t\tconst enforce = this.content?.kindsSource?.enforce\n\t\t\tif (!party?.partyKind || !this.kinds || (enforce && this.kinds.source !== enforce)) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\treturn !this.kinds.kinds.some((kind) => kindCode(kind) === party.partyKind)\n\t\t},\n\n\t\t/**\n\t\t * A party's kind: the accepted kind's label, else the listing's, else the code.\n\t\t *\n\t\t * @param {object} party The listing row.\n\t\t * @return {string}\n\t\t */\n\t\tkindOf(party) {\n\t\t\tif (!party.partyKind) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst offered = (this.kinds?.kinds || []).find((kind) => kindCode(kind) === party.partyKind)\n\t\t\treturn offered?.label || this.kindLabels[party.partyKind] || party.partyKind\n\t\t},\n\n\t\t/**\n\t\t * Who represents this party, by name.\n\t\t *\n\t\t * @param {object} party The listing row.\n\t\t * @return {string}\n\t\t */\n\t\trepresentedBy(party) {\n\t\t\tconst uuid = this.represented[party.partyUuid || party.contactUid || ''] || ''\n\t\t\tif (uuid === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst row = (this.listing?.results || []).find((candidate) => candidate?.partyUuid === uuid)\n\t\t\treturn row ? this.nameOf(row) : (this.partyRecords[uuid]?.name || uuid)\n\t\t},\n\n\t\t/**\n\t\t * A party's name: the listing's, else the party record's, else its id.\n\t\t *\n\t\t * @param {object} party The listing row.\n\t\t * @return {string}\n\t\t */\n\t\tnameOf(party) {\n\t\t\treturn party.displayName || this.partyRecords[party.partyUuid]?.name || party.contactUid || party.partyUuid || ''\n\t\t},\n\n\t\t/**\n\t\t * How many documents a party sent and received.\n\t\t *\n\t\t * @param {object} party The listing row.\n\t\t * @return {string}\n\t\t */\n\t\tcorrespondenceOf(party) {\n\t\t\tconst spec = this.content?.correspondence || {}\n\t\t\tconst { sent, received } = documentsOfParty(this.documents, party.partyUuid || party.contactUid || '', spec)\n\t\t\tif (sent.length === 0 && received.length === 0) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tif (received.length === 0) {\n\t\t\t\treturn n('nextcloud-vue', '%n document sent', '%n documents sent', sent.length)\n\t\t\t}\n\t\t\tif (sent.length === 0) {\n\t\t\t\treturn n('nextcloud-vue', '%n document received', '%n documents received', received.length)\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', '{sent} sent, {received} received', { sent: sent.length, received: received.length })\n\t\t},\n\n\t\t/**\n\t\t * The indicators on a party, each with its verdict.\n\t\t *\n\t\t * @param {object} party The listing row.\n\t\t * @return {Array<object>}\n\t\t */\n\t\tindicatorsFor(party) {\n\t\t\tconst record = this.partyRecords[party.partyUuid]\n\t\t\tif (!record) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn (record.indicators || []).filter(Boolean).map((indicator) => ({ ...indicatorVerdict(indicator, this.verdictLabels), key: indicator.key }))\n\t\t},\n\n\t\t/**\n\t\t * The sentence of a blocking verdict, naming the party.\n\t\t *\n\t\t * @param {object} indicator The indicator with `partyName`.\n\t\t * @return {string}\n\t\t */\n\t\tsentenceFor(indicator) {\n\t\t\tconst name = indicator.partyName || indicator.party\n\t\t\tconst own = this.content?.labels || {}\n\t\t\tif (indicatorVerdict(indicator).effect === 'refuse-publication') {\n\t\t\t\treturn own.sentencePublication\n\t\t\t\t\t? this.cnTranslate(own.sentencePublication).replaceAll('{party}', name)\n\t\t\t\t\t: t('nextcloud-vue', 'Publishing a file on this record is refused, because of {party}.', { party: name }, undefined, { escape: false })\n\t\t\t}\n\t\t\treturn own.sentenceSend\n\t\t\t\t? this.cnTranslate(own.sentenceSend).replaceAll('{party}', name)\n\t\t\t\t: t('nextcloud-vue', 'A message to {party} is refused.', { party: name }, undefined, { escape: false })\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-object-parties {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: calc(var(--default-grid-baseline, 4px) * 3);\n}\n\n.cn-object-parties__verdicts {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: var(--default-grid-baseline, 4px);\n}\n\n.cn-object-parties__role-label {\n\tmargin: 0 0 var(--default-grid-baseline, 4px) 0;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n}\n\n.cn-object-parties__list {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: var(--default-grid-baseline, 4px);\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-object-parties__party {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: calc(var(--default-grid-baseline, 4px) * 2);\n\tpadding: var(--default-grid-baseline, 4px);\n\tborder-radius: var(--border-radius, 4px);\n}\n\n.cn-object-parties__party:hover {\n\tbackground-color: var(--color-background-hover);\n}\n\n.cn-object-parties__name {\n\tfont-weight: bold;\n}\n\n.cn-object-parties__muted {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-object-parties__accepted {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: calc(var(--default-grid-baseline, 4px) * 2);\n\tpadding: calc(var(--default-grid-baseline, 4px) * 2) calc(var(--default-grid-baseline, 4px) * 3);\n\tborder-radius: var(--border-radius-large, 10px);\n\tbackground-color: var(--color-background-hover);\n}\n\n.cn-object-parties__accepted-label {\n\tfont-weight: 600;\n}\n\n.cn-object-parties__accepted-kind {\n\tborder: 1px solid var(--color-border-dark);\n}\n</style>\n"],"names":["_createBlock","_createElementBlock","_toDisplayString","_openBlock","_Fragment","_renderList","_createElementVNode","_resolveDynamicComponent","_createTextVNode","_normalizeClass"],"mappings":";;;AAWM,EAAA,KAAK,EAAC,mBAAa;AAAA,EAAA,aAAA,EAAA,mBAAA;;;AAqBf,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,mCAAmC,GAAA;;;AAMlB,EAAA,KAAK,EAAA,0BAAA;;;;OAK7B,EAAC,6BAAkB;eACb,EAAC,4BAAiB;;;AAsBzB,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,yBAAyB,GAAA;;AAO3B,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,yBAAyB,GAAA;;;AAGpC,EAAA,KAAK,EAAC,0CAAyC;AAC/C,EAAA,aAAW,EAAC,2BAA2B;;;;AACpC,EAAA,KAAA,EAAA,0BAAA;;;;AAGH,EAAA,KAAK,EAAC,0CAAyB;AAC/B,EAAA,aAAW,EAAC,gCAAgC;;;;AAMzC,EAAA,KAAA,EAAA,0BAAA;;;;AAGH,EAAA,KAAK,EAAC,0BAA0B;AAChC,EAAA,aAAW,EAAC,+BAA+B;;;;;;;;;;;KAhF3B,KAAO,CAAA,OAAA;sBAA3BA,WAAmC,CAAA,wBAAA,EAAA;;AAAL,UAAA,IAAI,EAAC,EAAA;;SAGxB,KAAE,CAAA,MAAA;mCAGqB,CAAA,yBAAA,EAAA;;AAFjC,YAAA,IAAI,EAAE,QAAK,CAAA,KAAA,CAAA,QAAA,CAAA;AACX,YAAA,WAAW,EAAE,QAAK,CAAA,KAAA,CAAA,cAAA,CAAA;AACnB,YAAA,aAAW,EAAC,0BAAsB;;AAGvB,UAAA,CAAA,QAAA,CAAA,MAAI,CAAA,MAAA,KAAA,CAAA;qCAGoB,CAAA,yBAAA,EAAA;;AAFlC,cAAA,IAAE,EAAA,QAAA,CAAA,KAAA,CAAA,OAAA,CAAA;AACF,cAAA,WAAW,EAAA,QAAA,CAAA,KAAA,CAAA,aAAA,CAAA;AACX,cAAA,aAAU,EAAC,yBAAuB;;0BAElCC;eAEI,KAAA,CAAA,KAAA;gCADJA,kBAYK,CAAA,KAAA,EAAA;;AAVJ,oBAAA,KAAI,EAAC,6BAA6B;oBAClC,aAAW,EAAE,KAAK,CAAA,KAAA,CAAC,MAAC;AACpB,oBAAA,aAAU,EAAC,4BAA4B;;sCACsC,CAAA,MAAA,YAAA,EAAAC,eAAA,CAA3B,QAAK,CAAA,KAAA,CAAA,UAAA,CAAA,CAAA,EAAA,CAAA,YAAA;AACxD,qBAAAC,SAAA,CAAA,IAAA,CAAA,EAAAF,kBAAA,CAIyBG,2BAHrB,KAAA,CAAA,KAAA,CAAA,KAAA,EAAA,CAAA,IAAA,EAAA,KAAA,KAAA;2CADJH,kBAIyB,CAAA,MAAA,EAAA;;AADxB,wBAAA,KAAC,EAAA,2EAAA;AACD,wBAAA,aAAW,EAAC,iCAAY;yCAAA,KAAA,GAAA,CAAA,CAAA,GAAA,IAAA,GAAAC,eAAA,CAAA,IAAA,CAAA,KAAA,IAAA,QAAA,CAAA,QAAA,CAAA,IAAA,CAAA,CAAA,EAAA,CAAA,YAAA,CAAA;;qBACb,QAAe,CAAA,eAAA;sCAA3BD,kBAAkC,CAAA,MAAA,EAAlC,UAAkC,EAAAC,eAAA,CAAA,QAAA,CAAA,eAAA,CAAA,EAAA,CAAA,YAAA;;;;AAI5B,cAAA,CAAA,QAAA,CAAA,QAAQ,CAAC,MAAM,GAAA,CAAA;mDAYhB,iBAAA,EAAA;sCATJD,kBAQY,CAAAG,QAAA,EAAA,IAAA,EAAAC,UAAA,CAPM,QAAQ,CAAA,QAAA,EAAA,CAAnB,OAAO,KAAA;2CADdL,WAQY,CAAA,qBAAA,EAAA;AANX,wBAAA,GAAG,KAAK,OAAO,CAAC,KAAK,CAAI,CAAA,EAAA,OAAO,CAAC,GAAA,CAAA,CAAA;wBACjC,IAAI,EAAE,OAAI,CAAA,QAAA;wBACV,aAAE,EAAA,OAAA,CAAA,MAAA;;;yCAEH,MAAK;0BAALM,kBAAK,CAAA,QAAA,EAAA,IAAA,EAAAJ,eAAA,CAAA,OAAA,CAAA,KAAA,CAAA,EAAA,CAAA,YAAA;0BACLI,kBAAqB,CAAA,MAAA,EAAA,IAAA,EAAAJ,eAAA,CAAZ,OAAO,CAAC,QAAI,CAAA,EAAA,CAAA,YAAA;;;;;;;gCAItBD,8CACgB,QAAM,CAAA,MAAA,EAAA,CAAf,KAAK,KAAA;qCADZA;kBAEC,GAAG,EAAE,KAAK,CAAC,GAAG;AACd,kBAAA,KAAI,EAAC,yBAAW;kBAChB,WAAS,EAAC,KAAA,CAAA,GAAA;AACV,kBAAA,iBAAe,EAAK,CAAA,EAAA,KAAA,CAAA,QAAQ,CAAI,CAAA,EAAA,KAAE,CAAA,GAAA,CAAA,CAAA;AAClC,kBAAA,aAAE,EAAA,wBAAA;;4CAGSM,wBAFI,IAAe,CAAA,eAAA,CAAA,EAAA;AAAA,oBAAA,EAAA,EAAA,CAAA,EAAA,KAAA,CAAA,QAAA,CAAA,CAAA,EAAA,KAAA,CAAA,GAAA,CAAA,CAAA;AAAA,oBAAA,KAAA,EAAA,gDAAA;;2CACb;AAAd,sBAAAC,eAAA,CAAAN,eAAA,CAAA,KAAK,CAAC,KAAK,CAAA,EAAA,CAAA,YAAA;;;;;AAGb,qBAAAC,SAAA,CAAA,IAAA,CAAA,EAAAF,kBAAA,SACgB,EAAA,IAAA,EAAAI,UAAA,CAAA,KAAK,CAAC,OAAO,GAAtB,KAAK,KAAA;2CADZJ;wBAEC,GAAG,EAAA,CAAA,EAAA,KAAA,CAAA,GAAA,CAAA,CAAA,EAAA,KAAA,CAAA,SAAA,IAAA,KAAA,CAAA,UAAA,CAAA,CAAA;AACH,wBAAA,KAAI,EAAC,0BAA0B;AAC/B,wBAAA,YAAU,EAAE,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,UAAU;AAC/C,wBAAA,aAAU,EAAC,yBAAyB;;AACrC,wBAAAK,kBAAA,CAAgE,MAAhE,EAAA,UAAgE,EAAvBJ,eAAA,CAAA,QAAA,CAAA,MAAM,CAAC,KAAK,CAAA,CAAA,EAAA,CAAA,YAAA;AAE9C,wBAAA,CAAA,QAAA,CAAA,OAAO,IAAI,KAAK,CAAC,SAAC,KAAA,QAAA,CAAA,OAAA;0CADzBD,kBAGsE,CAAA,MAAA,EAHtE,WAGsE,EAAAC,eAAA,CAA1B,QAAK,CAAA,KAAA,CAAA,SAAA,CAAA,CAAA,EAAA,CAAA,YAAA;;AAC7C,wBAAA,CAAA,QAAA,CAAA,MAAA,CAAA,KAAA,CAAA;AAAJ,6BAAAC,SAAA,EAAA,EAAAF,kBAAA,CAAI,MAAJ,EAAA,WAAI,EAAAC,eAAA,CAAA,QAAA,CAAA,MAAA,CAAA,KAAA,CAAA,CAAA,EAAA,CAAA,YAAA;;AAEG,wBAAA,CAAA,QAAA,CAAA,WAAW,CAAC,KAAG,CAAA;0CADrBD,kBAG2D,CAAA,MAAA,EAH3D,WAG2D,EAAAC,eAAA,CAAX,QAAK,CAAA,KAAA,CAAA,aAAA,CAAA,CAAA,EAAA,CAAA,YAAA;;AACtD,yBAAAC,SAAA,CAAA,IAAA,CAAA,EAAAF,kBAAA,CAI6DG,2BAHzD,QAAA,CAAA,YAAA,CAAA,KAAA,CAAA,EAAA,CAAA,IAAA,EAAA,KAAA,KAAA;+CADJH,kBAI6D,CAAA,MAAA,EAAA;AAF3D,4BAAA,GAAG,UAAU,KAAK,CAAA,CAAA;AACnB,4BAAA,KAAK,EAAC,0BAAyB;AAC/B,4BAAA,aAAW,EAAC,8BAA8B;6CAAG,IAAK,CAAA,EAAA,CAAA,YAAA,CAAA;;AAC/C,wBAAA,CAAA,KAAA,CAAA,KAAA;AAAJ,6BAAAE,SAAA,EAAA,EAAAF,kBAAA,CAAI,MAAJ,EAAA,WAAI,EAAAC,eAAA,CAAA,KAAA,CAAA,KAAA,CAAA,EAAA,CAAA,YAAA;;AAEG,wBAAA,CAAA,QAAA,CAAA,aAAa,CAAC,KAAK,CAAA;4DAEoD,CAAA,MAAA,aAAA,EAA9BA,eAAA,CAAA,QAAA,CAAA,KAAK,qBAAoB,IAAE,GAAAA,eAAA,CAAG,QAAA,CAAA,aAAA,CAAA,KAAA,CAAA,CAAA,EAAA,CAAA,YAAA;;AAEvE,wBAAA,CAAA,QAAA,CAAA,gBAAgB,CAAC,KAAK,CAAA;0CAD7BD,kBAI8D,CAAA,MAAA,EAAA;;AAF7D,8BAAA,KAAK,EAAC,0BAA0B;AAC/B,8BAAA,sBAAoB,EAAE,KAAK,CAAC,SAAS,IAAI,KAAK,CAAA,UAAA;AAC/C,8BAAA,aAAW,EAAC,6BAA6B;AAAI,6BAAA,EAAAC,eAAA,CAAA,QAAA,CAAA,gBAAgB,CAAA,KAAA,CAAA,CAAA,EAAA,CAAA,oBAAA,WAAA,CAAA;;AAC7D,yBAAAC,SAAA,CAAA,IAAA,CAAA,EAAAF,kBAAA,CAODG,QANqB,EAAA,IAAA,EAAAC,UAAA,CAAA,QAAA,CAAA,aAAK,CAAA,KAAA,IAAlB,SAAS,KAAA;+CADhBJ,kBAOD,CAAA,MAAA,EAAA;AALE,4BAAA,GAAG,KAAK,KAAK,CAAC,SAAS,CAAI,CAAA,EAAA,SAAS,CAAC,GAAG,CAAA,CAAA;AACzC,4BAAA,KAAE,EAAAQ,cAAA,CAAA,CAAA,0CAAA,EACD,CAAA,8BAAA,EAAA,SAAA,CAAA,QAAA,CAAA,CAAA,CAAA,CAAA;4BACA,aAAI,EAAA,SAAA,CAAA,MAAA;4BACJ,KAAI,EAAA,SAAA,CAAA,OAAA;AACN,4BAAA,aAAA,EAAA,6BAAA;AAAA,2BAAA,EAAAP,eAAA,CAAA,SAAA,CAAA,KAAA,CAAA,GAAA,KAAA,GAAAA,eAAA,CAAA,SAAA,CAAA,OAAA,CAAA,EAAA,EAAA,2BAAA,WAAA,CAAA,CAAA;;;;;;;;;;;;;"}
|
|
1
|
+
{"version":3,"file":"CnObjectPartiesWidget.vue3.js","sources":["../../../../src/components/CnObjectPartiesWidget/CnObjectPartiesWidget.vue?vue&type=template&id=196e7ade&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-object-parties\" data-testid=\"cn-object-parties\">\n\t\t<NcLoadingIcon v-if=\"loading\" :size=\"24\" />\n\n\t\t<NcEmptyContent\n\t\t\tv-else-if=\"failed\"\n\t\t\t:name=\"label('failed')\"\n\t\t\t:description=\"label('failedDetail')\"\n\t\t\tdata-testid=\"cn-object-parties-failed\" />\n\n\t\t<div\n\t\t\tv-else-if=\"isPrimaryPresentation\"\n\t\t\tclass=\"cn-object-parties__main-card\"\n\t\t\tdata-testid=\"cn-object-parties-main-card\">\n\t\t\t<div\n\t\t\t\tv-if=\"mainParty\"\n\t\t\t\tclass=\"cn-object-parties__main\"\n\t\t\t\t:data-party=\"mainParty.partyUuid\"\n\t\t\t\tdata-testid=\"cn-object-parties-main\">\n\t\t\t\t<span class=\"cn-object-parties__main-initials\" aria-hidden=\"true\" data-testid=\"cn-object-parties-main-initials\">{{ initialsOf(nameOf(mainParty)) }}</span>\n\t\t\t\t<span class=\"cn-object-parties__main-text\">\n\t\t\t\t\t<strong class=\"cn-object-parties__main-name\" data-testid=\"cn-object-parties-main-name\">{{ nameOf(mainParty) }}</strong>\n\t\t\t\t\t<span v-if=\"mainRole\" class=\"cn-object-parties__muted cn-object-parties__main-role\" data-testid=\"cn-object-parties-main-role\">{{ mainRole }}</span>\n\t\t\t\t</span>\n\t\t\t</div>\n\t\t\t<span v-else class=\"cn-object-parties__muted\" data-testid=\"cn-object-parties-main-none\">{{ label('noPrimary') }}</span>\n\t\t\t<a\n\t\t\t\tv-if=\"mainParty && mainParty.email\"\n\t\t\t\tclass=\"cn-object-parties__main-email\"\n\t\t\t\t:href=\"`mailto:${mainParty.email}`\"\n\t\t\t\tdata-testid=\"cn-object-parties-main-email\">\n\t\t\t\t<EmailOutline :size=\"16\" aria-hidden=\"true\" />{{ mainParty.email }}</a>\n\t\t\t<a\n\t\t\t\tv-if=\"footLink\"\n\t\t\t\tclass=\"cn-object-parties__main-link\"\n\t\t\t\t:href=\"footLink.href\"\n\t\t\t\tdata-testid=\"cn-object-parties-main-link\">{{ footLink.label }}</a>\n\t\t</div>\n\n\t\t<NcEmptyContent\n\t\t\tv-else-if=\"groups.length === 0\"\n\t\t\t:name=\"label('empty')\"\n\t\t\t:description=\"label('emptyDetail')\"\n\t\t\tdata-testid=\"cn-object-parties-empty\" />\n\n\t\t<template v-else>\n\t\t\t<div\n\t\t\t\tv-if=\"kinds\"\n\t\t\t\tclass=\"cn-object-parties__accepted\"\n\t\t\t\t:data-source=\"kinds.source\"\n\t\t\t\tdata-testid=\"cn-object-parties-accepted\">\n\t\t\t\t<span class=\"cn-object-parties__accepted-label\">{{ label('accepted') }}</span>\n\t\t\t\t<span\n\t\t\t\t\tv-for=\"(kind, index) in kinds.kinds\"\n\t\t\t\t\t:key=\"kindCode(kind)\"\n\t\t\t\t\tclass=\"cn-status-badge cn-status-badge--default cn-object-parties__accepted-kind\"\n\t\t\t\t\tdata-testid=\"cn-object-parties-accepted-kind\">{{ index + 1 }}. {{ kind.label || kindCode(kind) }}</span>\n\t\t\t\t<span v-if=\"kindsSourceText\" class=\"cn-object-parties__muted\">{{ kindsSourceText }}</span>\n\t\t\t</div>\n\n\t\t\t<div\n\t\t\t\tv-if=\"verdicts.length > 0\"\n\t\t\t\tclass=\"cn-object-parties__verdicts\"\n\t\t\t\tdata-testid=\"cn-object-parties-verdicts\">\n\t\t\t\t<NcNoteCard\n\t\t\t\t\tv-for=\"verdict in verdicts\"\n\t\t\t\t\t:key=\"`${verdict.party}-${verdict.key}`\"\n\t\t\t\t\t:type=\"verdict.severity\"\n\t\t\t\t\t:data-effect=\"verdict.effect\"\n\t\t\t\t\tdata-testid=\"cn-object-parties-verdict\">\n\t\t\t\t\t<strong>{{ verdict.label }}</strong>\n\t\t\t\t\t<span>{{ verdict.sentence }}</span>\n\t\t\t\t</NcNoteCard>\n\t\t\t</div>\n\n\t\t\t<section\n\t\t\t\tv-for=\"group in groups\"\n\t\t\t\t:key=\"group.key\"\n\t\t\t\tclass=\"cn-object-parties__role\"\n\t\t\t\t:data-role=\"group.key\"\n\t\t\t\t:aria-labelledby=\"`${idPrefix}-${group.key}`\"\n\t\t\t\tdata-testid=\"cn-object-parties-role\">\n\t\t\t\t<component :is=\"innerHeadingTag\" :id=\"`${idPrefix}-${group.key}`\" class=\"cn-object-parties__role-label cn-inner-heading\">\n\t\t\t\t\t{{ group.label }}\n\t\t\t\t</component>\n\t\t\t\t<ul class=\"cn-object-parties__list\">\n\t\t\t\t\t<li\n\t\t\t\t\t\tv-for=\"party in group.parties\"\n\t\t\t\t\t\t:key=\"`${group.key}-${party.partyUuid || party.contactUid}`\"\n\t\t\t\t\t\tclass=\"cn-object-parties__party\"\n\t\t\t\t\t\t:data-party=\"party.partyUuid || party.contactUid\"\n\t\t\t\t\t\tdata-testid=\"cn-object-parties-party\">\n\t\t\t\t\t\t<span class=\"cn-object-parties__name\">{{ nameOf(party) }}</span>\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tv-if=\"primary && party.partyUuid === primary\"\n\t\t\t\t\t\t\tclass=\"cn-status-badge cn-status-badge--primary\"\n\t\t\t\t\t\t\tdata-testid=\"cn-object-parties-primary\">{{ label('primary') }}</span>\n\t\t\t\t\t\t<span v-if=\"kindOf(party)\" class=\"cn-object-parties__muted\">{{ kindOf(party) }}</span>\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tv-if=\"notAccepted(party)\"\n\t\t\t\t\t\t\tclass=\"cn-status-badge cn-status-badge--warning\"\n\t\t\t\t\t\t\tdata-testid=\"cn-object-parties-not-accepted\">{{ label('notAccepted') }}</span>\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tv-for=\"(line, index) in extraLinesOf(party)\"\n\t\t\t\t\t\t\t:key=\"`line-${index}`\"\n\t\t\t\t\t\t\tclass=\"cn-object-parties__muted\"\n\t\t\t\t\t\t\tdata-testid=\"cn-object-parties-extra-line\">{{ line }}</span>\n\t\t\t\t\t\t<span v-if=\"party.email\" class=\"cn-object-parties__muted\">{{ party.email }}</span>\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tv-if=\"representedBy(party)\"\n\t\t\t\t\t\t\tclass=\"cn-object-parties__muted\"\n\t\t\t\t\t\t\tdata-testid=\"cn-object-parties-represented\">{{ label('representedBy') }}: {{ representedBy(party) }}</span>\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tv-if=\"correspondenceOf(party)\"\n\t\t\t\t\t\t\tclass=\"cn-object-parties__muted\"\n\t\t\t\t\t\t\t:data-party-documents=\"party.partyUuid || party.contactUid\"\n\t\t\t\t\t\t\tdata-testid=\"cn-object-parties-documents\">{{ correspondenceOf(party) }}</span>\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tv-for=\"indicator in indicatorsFor(party)\"\n\t\t\t\t\t\t\t:key=\"`${party.partyUuid}-${indicator.key}`\"\n\t\t\t\t\t\t\tclass=\"cn-status-badge cn-status-badge--default\"\n\t\t\t\t\t\t\t:class=\"`cn-object-parties__indicator--${indicator.severity}`\"\n\t\t\t\t\t\t\t:data-effect=\"indicator.effect\"\n\t\t\t\t\t\t\t:title=\"indicator.verdict\"\n\t\t\t\t\t\t\tdata-testid=\"cn-object-parties-indicator\">{{ indicator.label }} · {{ indicator.verdict }}</span>\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t</section>\n\t\t</template>\n\t</div>\n</template>\n\n<script>\nimport axios from '@nextcloud/axios'\nimport { translatePlural as n, translate as t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { NcEmptyContent, NcLoadingIcon, NcNoteCard } from '@nextcloud/vue'\nimport EmailOutline from 'vue-material-design-icons/EmailOutline.vue'\nimport { interpolateUrlTokens } from '../../composables/useEndpointSource.js'\nimport innerHeading from '../../mixins/innerHeading.js'\nimport { conditionalLine } from '../../utils/conditionalLine.js'\nimport { initialsOf } from '../../utils/initials.js'\nimport {\n\tdocumentsOfParty,\n\tindicatorsOf,\n\tindicatorVerdict,\n\tkindCode,\n\trepresentedByMap,\n\troleLabel,\n\trolesInOrder,\n} from '../../utils/objectParties.js'\nimport { readPath } from '../../utils/readPath.js'\n\nlet uid = 0\n\n/**\n * The default words, keyed as `content.labels` overrides them.\n *\n * @return {object} The labels.\n */\nfunction defaultLabels() {\n\treturn {\n\t\tfailed: t('nextcloud-vue', 'The parties could not be read'),\n\t\tfailedDetail: t('nextcloud-vue', 'OpenRegister did not answer. Nothing has been removed.'),\n\t\tempty: t('nextcloud-vue', 'No parties yet'),\n\t\temptyDetail: t('nextcloud-vue', 'Add a party to record who this is for and who acts on it.'),\n\t\taccepted: t('nextcloud-vue', 'Accepted kinds'),\n\t\tprimary: t('nextcloud-vue', 'Primary party'),\n\t\tnotAccepted: t('nextcloud-vue', 'Kind not accepted here'),\n\t\trepresentedBy: t('nextcloud-vue', 'Represented by'),\n\t\tnoPrimary: t('nextcloud-vue', 'No main contact yet'),\n\t}\n}\n\n/**\n * CnObjectPartiesWidget — the `parties` widget: a record's parties as\n * OpenRegister's party model answers them, grouped by role with the primary\n * party first. Each party shows its kind, its representative and the\n * indicators on it, each with its verdict. A blocking verdict is also a note\n * above the list, so nobody publishes or sends past it.\n *\n * ```json\n * {\n * \"type\": \"parties\",\n * \"content\": {\n * \"rolesObjects\": { \"register\": \"myapp\", \"schema\": \"role\", \"field\": \"item\" },\n * \"roleLabels\": { \"applicant\": \"Applicant\" },\n * \"kindsSource\": { \"url\": \"/apps/myapp/api/items/@objectId/party-kinds\", \"enforce\": \"crm\" },\n * \"extraLines\": [{ \"endpoint\": \"/apps/myapp/api/items/@objectId/parties/{party}/language\", \"lines\": [\"Language: {language}\"] }],\n * \"correspondence\": { \"endpoint\": \"/apps/myapp/api/items/@objectId/documents\", \"path\": \"documents\" }\n * }\n * }\n * ```\n *\n * `presentation: \"primary\"` draws only the primary party, as a side card\n * does: initials, name and role label, its correspondence e-mail, and\n * `link` (`{ label, href? | tab? }`, `{total}` = the number of parties) at\n * the foot; `tab` opens that tab of the page through the route hash. It\n * reads the listing only.\n *\n * A failed read says so and is never shown as \"no parties\".\n *\n * @spec openspec/changes/dq-abstract-record-widgets/specs/record-widgets/spec.md#requirement-a-record-shows-its-parties-by-role\n */\nexport default {\n\tname: 'CnObjectPartiesWidget',\n\n\tcomponents: { EmailOutline, NcEmptyContent, NcLoadingIcon, NcNoteCard },\n\n\tmixins: [innerHeading],\n\n\tinject: {\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The configuration: `rolesSource` (the listing URL, default\n\t\t * OpenRegister's `/parties` of this record), `partySource` (one\n\t\t * party, `{uuid}` filled in), `rolesObjects` (`{ register, schema,\n\t\t * field }`, the role rows that say who represents whom), `roleLabels`,\n\t\t * `kindsSource` (`{ url, enforce?, sourceText? }`), `extraLines`\n\t\t * (`[{ endpoint, path?, valueLabels?, lines }]`, one request per\n\t\t * party, `{party}` filled in), `correspondence` (`{ endpoint, path?,\n\t\t * senderField?, recipientsField? }`), `labels`, `presentation`\n\t\t * (`\"primary\"`: only the primary party) and `link` (`{ label,\n\t\t * href? | tab? }`, the primary presentation's foot link).\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** The record's id, bound by the detail host. */\n\t\tobjectId: {\n\t\t\ttype: [String, Number],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** The record's register slug. */\n\t\tregister: {\n\t\t\ttype: [String, Object],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** The record's schema slug. */\n\t\tschema: {\n\t\t\ttype: [String, Object],\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\tdata() {\n\t\tuid += 1\n\t\treturn {\n\t\t\tidPrefix: `cn-object-parties-${uid}`,\n\t\t\tloading: true,\n\t\t\tfailed: false,\n\t\t\tlisting: null,\n\t\t\tpartyRecords: {},\n\t\t\trepresented: {},\n\t\t\tkinds: null,\n\t\t\textra: {},\n\t\t\tdocuments: [],\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** @return {Array<object>} The role groups, primary first. */\n\t\tgroups() {\n\t\t\treturn rolesInOrder(this.listing, this.translatedMap(this.content?.roleLabels))\n\t\t},\n\n\t\t/** @return {boolean} Whether only the primary party is drawn. */\n\t\tisPrimaryPresentation() {\n\t\t\treturn this.content?.presentation === 'primary'\n\t\t},\n\n\t\t/** @return {object|null} The primary party's listing row. */\n\t\tmainParty() {\n\t\t\tif (!this.primary) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn (this.listing?.results || []).find((row) => row && row.partyUuid === this.primary) || null\n\t\t},\n\n\t\t/** @return {string} The primary party's role, in the app's words. */\n\t\tmainRole() {\n\t\t\tconst key = this.mainParty?.role\n\t\t\tif (!key) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst own = this.translatedMap(this.content?.roleLabels)\n\t\t\tif (typeof own[key] === 'string' && own[key] !== '') {\n\t\t\t\treturn own[key]\n\t\t\t}\n\t\t\treturn this.cnTranslate(roleLabel(key, this.listing?.roles, {}))\n\t\t},\n\n\t\t/** @return {{label: string, href: string}|null} The primary presentation's foot link; none without parties. */\n\t\tfootLink() {\n\t\t\tconst link = this.content?.link\n\t\t\tconst total = Number(this.listing?.total ?? (this.listing?.results || []).length)\n\t\t\tif (!link || typeof link !== 'object' || !link.label || !(total > 0)) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst href = link.tab ? `#${encodeURIComponent(link.tab)}` : (link.href || '')\n\t\t\tif (href === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn { label: this.cnTranslate(link.label).replaceAll('{total}', String(total)), href }\n\t\t},\n\n\t\t/** @return {string|null} The primary party's uuid. */\n\t\tprimary() {\n\t\t\treturn this.listing?.primary || null\n\t\t},\n\n\t\t/** @return {object} The verdict words, translated. */\n\t\tverdictLabels() {\n\t\t\tconst own = this.content?.labels || {}\n\t\t\tconst out = {}\n\t\t\tfor (const key of ['verdictPublication', 'verdictSend', 'verdictWarn']) {\n\t\t\t\tif (typeof own[key] === 'string' && own[key] !== '') {\n\t\t\t\t\tout[key] = this.cnTranslate(own[key])\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn out\n\t\t},\n\n\t\t/** @return {Array<object>} The blocking verdicts, as notes above the list. */\n\t\tverdicts() {\n\t\t\treturn indicatorsOf(Object.values(this.partyRecords))\n\t\t\t\t.map((indicator) => ({\n\t\t\t\t\t...indicatorVerdict(indicator, this.verdictLabels),\n\t\t\t\t\tparty: indicator.party,\n\t\t\t\t\tkey: indicator.key,\n\t\t\t\t\tsentence: this.sentenceFor(indicator),\n\t\t\t\t}))\n\t\t\t\t.filter((verdict) => verdict.severity === 'error')\n\t\t},\n\n\t\t/** @return {string} Where the accepted kinds come from. */\n\t\tkindsSourceText() {\n\t\t\tconst texts = this.content?.kindsSource?.sourceText\n\t\t\tif (!this.kinds || !texts || typeof texts !== 'object') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst text = texts[this.kinds.source] || texts.default || ''\n\t\t\treturn text ? this.cnTranslate(text) : ''\n\t\t},\n\n\t\t/** @return {Record<string, string>} The kind labels the listing declares. */\n\t\tkindLabels() {\n\t\t\tconst labels = {}\n\t\t\tfor (const kind of this.listing?.kinds || []) {\n\t\t\t\tif (kind && kind.key) {\n\t\t\t\t\tlabels[kind.key] = kind.label || kind.key\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn labels\n\t\t},\n\n\t\t/** @return {string} A key that changes when the record does. */\n\t\trecordKey() {\n\t\t\treturn `${this.register}|${this.schema}|${this.objectId}`\n\t\t},\n\t},\n\n\twatch: {\n\t\trecordKey: {\n\t\t\timmediate: true,\n\t\t\thandler() {\n\t\t\t\tthis.load()\n\t\t\t},\n\t\t},\n\t},\n\n\tmethods: {\n\t\tinitialsOf,\n\t\tkindCode,\n\n\t\t/**\n\t\t * A label: the content's own (translated), else the default.\n\t\t *\n\t\t * @param {string} key The label key.\n\t\t * @return {string}\n\t\t */\n\t\tlabel(key) {\n\t\t\tconst own = this.content?.labels && typeof this.content.labels[key] === 'string' ? this.content.labels[key] : ''\n\t\t\treturn own !== '' ? this.cnTranslate(own) : defaultLabels()[key]\n\t\t},\n\n\t\t/**\n\t\t * A map of manifest words, translated.\n\t\t *\n\t\t * @param {object} map The map.\n\t\t * @return {Record<string, string>}\n\t\t */\n\t\ttranslatedMap(map) {\n\t\t\tconst out = {}\n\t\t\tfor (const [key, value] of Object.entries(map && typeof map === 'object' ? map : {})) {\n\t\t\t\tout[key] = typeof value === 'string' ? this.cnTranslate(value) : value\n\t\t\t}\n\t\t\treturn out\n\t\t},\n\n\t\t/**\n\t\t * An app path with the record's tokens and `{party}` filled in.\n\t\t *\n\t\t * @param {string} template The path.\n\t\t * @param {string} [party] A party uuid.\n\t\t * @return {string}\n\t\t */\n\t\turlOf(template, party = '') {\n\t\t\tconst withSlugs = String(template)\n\t\t\t\t.replaceAll('@register', String(this.register || ''))\n\t\t\t\t.replaceAll('@schema', String(this.schema || ''))\n\t\t\treturn interpolateUrlTokens(withSlugs, { objectId: this.objectId }).replaceAll('{party}', encodeURIComponent(party)).replaceAll('{uuid}', encodeURIComponent(party))\n\t\t},\n\n\t\t/**\n\t\t * GET an app path; null when it fails.\n\t\t *\n\t\t * @param {string} path The app path.\n\t\t * @param {object} [params] Query parameters.\n\t\t * @return {Promise<unknown>}\n\t\t */\n\t\tasync read(path, params) {\n\t\t\ttry {\n\t\t\t\tconst { data } = await axios.get(generateUrl(path), params ? { params } : undefined)\n\t\t\t\treturn data ?? null\n\t\t\t} catch {\n\t\t\t\treturn null\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Read the listing, then each party, the representation, the kinds,\n\t\t * the extra lines and the correspondence.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync load() {\n\t\t\tif (!this.objectId) {\n\t\t\t\tthis.loading = false\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.failed = false\n\t\t\tthis.partyRecords = {}\n\t\t\tthis.represented = {}\n\t\t\tthis.extra = {}\n\t\t\tthis.documents = []\n\t\t\tconst listing = await this.read(this.urlOf(this.content?.rolesSource || '/apps/openregister/api/objects/@register/@schema/@objectId/parties'))\n\t\t\tif (!listing || typeof listing !== 'object') {\n\t\t\t\tthis.failed = true\n\t\t\t\tthis.listing = null\n\t\t\t\tthis.loading = false\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.listing = listing\n\t\t\tif (this.isPrimaryPresentation) {\n\t\t\t\tthis.loading = false\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst uuids = [...new Set((listing.results || []).map((row) => row && row.partyUuid).filter(Boolean))]\n\t\t\tconst partyUrl = this.content?.partySource || '/apps/openregister/api/parties/{uuid}'\n\t\t\tconst records = await Promise.all(uuids.map((uuid) => this.read(this.urlOf(partyUrl, uuid))))\n\t\t\tconst byUuid = {}\n\t\t\tuuids.forEach((uuid, index) => {\n\t\t\t\tif (records[index] && typeof records[index] === 'object') {\n\t\t\t\t\tbyUuid[uuid] = records[index]\n\t\t\t\t}\n\t\t\t})\n\t\t\tthis.partyRecords = byUuid\n\t\t\tawait Promise.all([this.loadRepresentation(), this.loadKinds(), this.loadExtraLines(uuids), this.loadCorrespondence()])\n\t\t\tthis.loading = false\n\t\t},\n\n\t\t/** @return {Promise<void>} Who represents whom, from the role rows. */\n\t\tasync loadRepresentation() {\n\t\t\tconst source = this.content?.rolesObjects\n\t\t\tif (!source || !source.register || !source.schema) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst data = await this.read(`/apps/openregister/api/objects/${encodeURIComponent(source.register)}/${encodeURIComponent(source.schema)}`, { [source.field || 'object']: String(this.objectId), _limit: 200 })\n\t\t\tconst rows = Array.isArray(data?.results) ? data.results : (Array.isArray(data) ? data : [])\n\t\t\tthis.represented = representedByMap(rows)\n\t\t},\n\n\t\t/** @return {Promise<void>} The kinds this record accepts. */\n\t\tasync loadKinds() {\n\t\t\tconst source = this.content?.kindsSource\n\t\t\tthis.kinds = null\n\t\t\tif (!source || !source.url) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst data = await this.read(this.urlOf(source.url))\n\t\t\tthis.kinds = data && Array.isArray(data.kinds) ? data : null\n\t\t},\n\n\t\t/**\n\t\t * One answer per party per extra line.\n\t\t *\n\t\t * @param {Array<string>} uuids The parties.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync loadExtraLines(uuids) {\n\t\t\tconst lines = Array.isArray(this.content?.extraLines) ? this.content.extraLines : []\n\t\t\tconst extra = {}\n\t\t\tawait Promise.all(lines.map(async (spec, index) => {\n\t\t\t\tif (!spec || !spec.endpoint) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tconst answers = await Promise.all(uuids.map((uuid) => this.read(this.urlOf(spec.endpoint, uuid))))\n\t\t\t\tuuids.forEach((uuid, i) => {\n\t\t\t\t\tconst answer = spec.path ? readPath(answers[i], spec.path) : answers[i]\n\t\t\t\t\tif (answer && typeof answer === 'object') {\n\t\t\t\t\t\textra[`${index}|${uuid}`] = answer\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t}))\n\t\t\tthis.extra = extra\n\t\t},\n\n\t\t/** @return {Promise<void>} The documents the correspondence counts read. */\n\t\tasync loadCorrespondence() {\n\t\t\tconst spec = this.content?.correspondence\n\t\t\tif (!spec || !spec.endpoint) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst data = await this.read(this.urlOf(spec.endpoint))\n\t\t\tconst list = spec.path ? readPath(data, spec.path) : data\n\t\t\tthis.documents = Array.isArray(list) ? list : []\n\t\t},\n\n\t\t/**\n\t\t * The extra lines for a party, each the first of its `lines` that applies.\n\t\t *\n\t\t * @param {object} party The listing row.\n\t\t * @return {Array<string>}\n\t\t */\n\t\textraLinesOf(party) {\n\t\t\tconst specs = Array.isArray(this.content?.extraLines) ? this.content.extraLines : []\n\t\t\treturn specs.map((spec, index) => {\n\t\t\t\tconst answer = this.extra[`${index}|${party.partyUuid}`]\n\t\t\t\tif (!answer) {\n\t\t\t\t\treturn ''\n\t\t\t\t}\n\t\t\t\treturn conditionalLine(spec.lines || [], this.labelled(answer, spec.valueLabels), (text) => this.cnTranslate(text))\n\t\t\t}).filter((line) => line !== '')\n\t\t},\n\n\t\t/**\n\t\t * An answer with its coded values replaced by their labels\n\t\t * (`valueLabels: { language: { nl: \"Dutch\" } }`; `nl-NL` reads as `nl`).\n\t\t *\n\t\t * @param {object} answer The answer.\n\t\t * @param {object} valueLabels The labels by field and value.\n\t\t * @return {object}\n\t\t */\n\t\tlabelled(answer, valueLabels) {\n\t\t\tif (!valueLabels || typeof valueLabels !== 'object') {\n\t\t\t\treturn answer\n\t\t\t}\n\t\t\tconst out = { ...answer }\n\t\t\tfor (const [field, map] of Object.entries(valueLabels)) {\n\t\t\t\tconst raw = answer[field]\n\t\t\t\tif (typeof raw !== 'string' || !map) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst hit = map[raw] ?? map[raw.toLowerCase().split('-')[0]]\n\t\t\t\tif (typeof hit === 'string') {\n\t\t\t\t\tout[field] = this.cnTranslate(hit)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn out\n\t\t},\n\n\t\t/**\n\t\t * Whether a party's kind is one this record does not accept. Only when\n\t\t * the kinds come from the source named by `kindsSource.enforce`.\n\t\t *\n\t\t * @param {object} party The listing row.\n\t\t * @return {boolean}\n\t\t */\n\t\tnotAccepted(party) {\n\t\t\tconst enforce = this.content?.kindsSource?.enforce\n\t\t\tif (!party?.partyKind || !this.kinds || (enforce && this.kinds.source !== enforce)) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\treturn !this.kinds.kinds.some((kind) => kindCode(kind) === party.partyKind)\n\t\t},\n\n\t\t/**\n\t\t * A party's kind: the accepted kind's label, else the listing's, else the code.\n\t\t *\n\t\t * @param {object} party The listing row.\n\t\t * @return {string}\n\t\t */\n\t\tkindOf(party) {\n\t\t\tif (!party.partyKind) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst offered = (this.kinds?.kinds || []).find((kind) => kindCode(kind) === party.partyKind)\n\t\t\treturn offered?.label || this.kindLabels[party.partyKind] || party.partyKind\n\t\t},\n\n\t\t/**\n\t\t * Who represents this party, by name.\n\t\t *\n\t\t * @param {object} party The listing row.\n\t\t * @return {string}\n\t\t */\n\t\trepresentedBy(party) {\n\t\t\tconst uuid = this.represented[party.partyUuid || party.contactUid || ''] || ''\n\t\t\tif (uuid === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst row = (this.listing?.results || []).find((candidate) => candidate?.partyUuid === uuid)\n\t\t\treturn row ? this.nameOf(row) : (this.partyRecords[uuid]?.name || uuid)\n\t\t},\n\n\t\t/**\n\t\t * A party's name: the listing's, else the party record's, else its id.\n\t\t *\n\t\t * @param {object} party The listing row.\n\t\t * @return {string}\n\t\t */\n\t\tnameOf(party) {\n\t\t\treturn party.displayName || this.partyRecords[party.partyUuid]?.name || party.contactUid || party.partyUuid || ''\n\t\t},\n\n\t\t/**\n\t\t * How many documents a party sent and received.\n\t\t *\n\t\t * @param {object} party The listing row.\n\t\t * @return {string}\n\t\t */\n\t\tcorrespondenceOf(party) {\n\t\t\tconst spec = this.content?.correspondence || {}\n\t\t\tconst { sent, received } = documentsOfParty(this.documents, party.partyUuid || party.contactUid || '', spec)\n\t\t\tif (sent.length === 0 && received.length === 0) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tif (received.length === 0) {\n\t\t\t\treturn n('nextcloud-vue', '%n document sent', '%n documents sent', sent.length)\n\t\t\t}\n\t\t\tif (sent.length === 0) {\n\t\t\t\treturn n('nextcloud-vue', '%n document received', '%n documents received', received.length)\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', '{sent} sent, {received} received', { sent: sent.length, received: received.length })\n\t\t},\n\n\t\t/**\n\t\t * The indicators on a party, each with its verdict.\n\t\t *\n\t\t * @param {object} party The listing row.\n\t\t * @return {Array<object>}\n\t\t */\n\t\tindicatorsFor(party) {\n\t\t\tconst record = this.partyRecords[party.partyUuid]\n\t\t\tif (!record) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn (record.indicators || []).filter(Boolean).map((indicator) => ({ ...indicatorVerdict(indicator, this.verdictLabels), key: indicator.key }))\n\t\t},\n\n\t\t/**\n\t\t * The sentence of a blocking verdict, naming the party.\n\t\t *\n\t\t * @param {object} indicator The indicator with `partyName`.\n\t\t * @return {string}\n\t\t */\n\t\tsentenceFor(indicator) {\n\t\t\tconst name = indicator.partyName || indicator.party\n\t\t\tconst own = this.content?.labels || {}\n\t\t\tif (indicatorVerdict(indicator).effect === 'refuse-publication') {\n\t\t\t\treturn own.sentencePublication\n\t\t\t\t\t? this.cnTranslate(own.sentencePublication).replaceAll('{party}', name)\n\t\t\t\t\t: t('nextcloud-vue', 'Publishing a file on this record is refused, because of {party}.', { party: name }, undefined, { escape: false })\n\t\t\t}\n\t\t\treturn own.sentenceSend\n\t\t\t\t? this.cnTranslate(own.sentenceSend).replaceAll('{party}', name)\n\t\t\t\t: t('nextcloud-vue', 'A message to {party} is refused.', { party: name }, undefined, { escape: false })\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-object-parties {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: calc(var(--default-grid-baseline, 4px) * 3);\n}\n\n.cn-object-parties__verdicts {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: var(--default-grid-baseline, 4px);\n}\n\n.cn-object-parties__role-label {\n\tmargin: 0 0 var(--default-grid-baseline, 4px) 0;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n}\n\n.cn-object-parties__list {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: var(--default-grid-baseline, 4px);\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-object-parties__party {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: calc(var(--default-grid-baseline, 4px) * 2);\n\tpadding: var(--default-grid-baseline, 4px);\n\tborder-radius: var(--border-radius, 4px);\n}\n\n.cn-object-parties__party:hover {\n\tbackground-color: var(--color-background-hover);\n}\n\n.cn-object-parties__name {\n\tfont-weight: bold;\n}\n\n.cn-object-parties__muted {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-object-parties__main-card {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: calc(var(--default-grid-baseline, 4px) * 3);\n}\n\n.cn-object-parties__main {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: calc(var(--default-grid-baseline, 4px) * 3);\n}\n\n.cn-object-parties__main-initials {\n\tdisplay: flex;\n\tflex: none;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 40px;\n\theight: 40px;\n\tborder-radius: 50%;\n\tbackground-color: var(--color-background-dark);\n\tcolor: var(--color-main-text);\n\tfont-weight: 700;\n}\n\n.cn-object-parties__main-text {\n\tdisplay: flex;\n\tflex-direction: column;\n}\n\n.cn-object-parties__main-name {\n\tfont-size: 15px;\n}\n\n.cn-object-parties__main-role {\n\tfont-size: 13px;\n}\n\n.cn-object-parties__main-email {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: calc(var(--default-grid-baseline, 4px) * 2.5);\n\tcolor: var(--color-main-text);\n\toverflow-wrap: anywhere;\n}\n\n.cn-object-parties__main-link {\n\tcolor: var(--color-primary-element);\n\tfont-weight: 600;\n}\n\n.cn-object-parties__accepted {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: calc(var(--default-grid-baseline, 4px) * 2);\n\tpadding: calc(var(--default-grid-baseline, 4px) * 2) calc(var(--default-grid-baseline, 4px) * 3);\n\tborder-radius: var(--border-radius-large, 10px);\n\tbackground-color: var(--color-background-hover);\n}\n\n.cn-object-parties__accepted-label {\n\tfont-weight: 600;\n}\n\n.cn-object-parties__accepted-kind {\n\tborder: 1px solid var(--color-border-dark);\n}\n</style>\n"],"names":["_createBlock","_openBlock","_createElementBlock","_createElementVNode","_toDisplayString","_createVNode","_createTextVNode","_Fragment","_renderList","_resolveDynamicComponent","_normalizeClass"],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import script from './CnRecordListWidget.vue2.js';
|
|
|
2
2
|
import { render } from './CnRecordListWidget.vue3.js';
|
|
3
3
|
|
|
4
4
|
script.render = render;
|
|
5
|
-
script.__scopeId = "data-v-
|
|
5
|
+
script.__scopeId = "data-v-5aa15b1d";
|
|
6
6
|
const __sfc_main = script;
|
|
7
7
|
|
|
8
8
|
export { __sfc_main as default };
|
|
@@ -19,6 +19,7 @@ import { firstFilled, fillTemplate } from '../../utils/fillTemplate.js';
|
|
|
19
19
|
import { unwrapAppConfig } from '../../utils/formatMetric.js';
|
|
20
20
|
import { initialsOf } from '../../utils/initials.js';
|
|
21
21
|
import { lensUnavailableText, readLensReports } from '../../utils/lensAvailability.js';
|
|
22
|
+
import { isObjectRowsSpec, objectRowsOf } from '../../utils/objectRows.js';
|
|
22
23
|
import { pageFilter, pageSort } from '../../utils/pageControls.js';
|
|
23
24
|
import { readPath } from '../../utils/readPath.js';
|
|
24
25
|
import { dropOptionalUnresolved, resolveFilterTokens, hasUnresolvedTokens, resolveDeepTokens } from '../../utils/resolveFilterTokens.js';
|
|
@@ -85,7 +86,8 @@ function unwrap(value) {
|
|
|
85
86
|
* `object-list` (`register`, `schema`, `filter` with the `@objectId` /
|
|
86
87
|
* `@object.<field>` / `@workspace.<key>` tokens, `sort`, `limit`, `extend`,
|
|
87
88
|
* `rowRoute`, `pageControls`), or `endpointSource` (an app endpoint whose
|
|
88
|
-
* payload, after `responsePath`, is the array of rows, as on the object table)
|
|
89
|
+
* payload, after `responsePath`, is the array of rows, as on the object table), or `objectRows`
|
|
90
|
+
* (`{ path, where?, valuePath? }`: rows the page record holds, such as one answer of a case); `avatar` puts a circle with the initials of a name
|
|
89
91
|
* template before the title; what differs is the drawing: `presentation` is `rows`, `feed`
|
|
90
92
|
* or `inline`, and each line is a template (`"{identifier} · {caseTypeName}"`,
|
|
91
93
|
* `"Termijn {deadline|date}"`). `cards` draws a framed card per row in a
|
|
@@ -125,7 +127,8 @@ var script = {
|
|
|
125
127
|
* with `overVariant: "error"`), or without `maxField` against the
|
|
126
128
|
* largest row. `endpointSource` (`{ url, method?,
|
|
127
129
|
* params?, responsePath? }`) reads the rows from an app endpoint instead
|
|
128
|
-
* of `register` / `schema`. `
|
|
130
|
+
* of `register` / `schema`. `objectRows` (`{ path, where?, valuePath? }`)
|
|
131
|
+
* lists rows the page record holds, with no request. `valueLabels` maps a field's stored values to the labels
|
|
129
132
|
* the templates show. `headerNote` and `headerLink.label` fill `{total}`
|
|
130
133
|
* and `{count:<field>=<value>}`, the loaded rows with that value.
|
|
131
134
|
* A row that is a plain string or number (an endpoint
|
|
@@ -438,6 +441,30 @@ var script = {
|
|
|
438
441
|
return Boolean(source && typeof source === 'object' && source.url)
|
|
439
442
|
},
|
|
440
443
|
|
|
444
|
+
/**
|
|
445
|
+
* Whether the rows come from the page's own record (`objectRows`).
|
|
446
|
+
*
|
|
447
|
+
* @return {boolean}
|
|
448
|
+
* @spec openspec/changes/record-list-object-rows/specs/record-list/spec.md#requirement-a-record-list-can-list-rows-the-page-record-holds
|
|
449
|
+
*/
|
|
450
|
+
objectRowsActive() {
|
|
451
|
+
return isObjectRowsSpec(this.content?.objectRows)
|
|
452
|
+
},
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* The rows `objectRows` names on the page record (see utils/objectRows.js).
|
|
456
|
+
*
|
|
457
|
+
* @return {Array<object>}
|
|
458
|
+
*/
|
|
459
|
+
objectRowsList() {
|
|
460
|
+
return this.objectRowsActive ? objectRowsOf(this.objectData, this.content.objectRows) : []
|
|
461
|
+
},
|
|
462
|
+
|
|
463
|
+
/** @return {string} The page record's rows, to copy into the list when they change. */
|
|
464
|
+
objectRowsKey() {
|
|
465
|
+
return this.objectRowsActive ? JSON.stringify(this.objectRowsList) : ''
|
|
466
|
+
},
|
|
467
|
+
|
|
441
468
|
/** @return {string} The endpoint read's state, to copy into the list when it changes. */
|
|
442
469
|
endpointKey() {
|
|
443
470
|
return this.endpointActive ? JSON.stringify([this.epData, this.epLoading, this.epError]) : ''
|
|
@@ -942,6 +969,10 @@ var script = {
|
|
|
942
969
|
this.fetchRows();
|
|
943
970
|
},
|
|
944
971
|
|
|
972
|
+
objectRowsKey() {
|
|
973
|
+
this.fetchRows();
|
|
974
|
+
},
|
|
975
|
+
|
|
945
976
|
linkIdsKey() {
|
|
946
977
|
this.loadLinkLabels();
|
|
947
978
|
},
|
|
@@ -2087,6 +2118,15 @@ var script = {
|
|
|
2087
2118
|
this.takeEndpointRows();
|
|
2088
2119
|
return
|
|
2089
2120
|
}
|
|
2121
|
+
if (this.objectRowsActive) {
|
|
2122
|
+
this.rows = this.flattenRows(this.objectRowsList.map((row, index) => (row.id === undefined ? { id: `row-${index}`, ...row } : row)));
|
|
2123
|
+
this.total = this.rows.length;
|
|
2124
|
+
this.loading = false;
|
|
2125
|
+
this.error = false;
|
|
2126
|
+
this.lenses = {};
|
|
2127
|
+
this.emitHeader();
|
|
2128
|
+
return
|
|
2129
|
+
}
|
|
2090
2130
|
if (!c.register || !c.schema || this.waiting) {
|
|
2091
2131
|
this.rows = [];
|
|
2092
2132
|
this.total = 0;
|