@conduction/nextcloud-vue 2.119.0 → 2.121.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/CnAiFeaturesWidget/CnAiFeaturesWidget.vue.js +9 -0
- package/dist/esm/components/CnAiFeaturesWidget/CnAiFeaturesWidget.vue.js.map +1 -0
- package/dist/esm/components/CnAiFeaturesWidget/CnAiFeaturesWidget.vue2.js +226 -0
- package/dist/esm/components/CnAiFeaturesWidget/CnAiFeaturesWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnAiFeaturesWidget/CnAiFeaturesWidget.vue3.js +211 -0
- package/dist/esm/components/CnAiFeaturesWidget/CnAiFeaturesWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnAiFeaturesWidget/CnAiSuggestionDecision.vue.js +9 -0
- package/dist/esm/components/CnAiFeaturesWidget/CnAiSuggestionDecision.vue.js.map +1 -0
- package/dist/esm/components/CnAiFeaturesWidget/CnAiSuggestionDecision.vue2.js +64 -0
- package/dist/esm/components/CnAiFeaturesWidget/CnAiSuggestionDecision.vue2.js.map +1 -0
- package/dist/esm/components/CnAiFeaturesWidget/CnAiSuggestionDecision.vue3.js +89 -0
- package/dist/esm/components/CnAiFeaturesWidget/CnAiSuggestionDecision.vue3.js.map +1 -0
- package/dist/esm/components/CnIcon/semanticIcons.js +2 -2
- package/dist/esm/components/CnIcon/semanticIcons.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +53 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +546 -523
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/useNamedSource.js +9 -0
- package/dist/esm/components/CnIndexPage/useNamedSource.js.map +1 -1
- package/dist/esm/components/CnObjectPermissionsTab/CnObjectPermissionsTab.vue.js +9 -0
- package/dist/esm/components/CnObjectPermissionsTab/CnObjectPermissionsTab.vue.js.map +1 -0
- package/dist/esm/components/CnObjectPermissionsTab/CnObjectPermissionsTab.vue2.js +257 -0
- package/dist/esm/components/CnObjectPermissionsTab/CnObjectPermissionsTab.vue2.js.map +1 -0
- package/dist/esm/components/CnObjectPermissionsTab/CnObjectPermissionsTab.vue3.js +266 -0
- package/dist/esm/components/CnObjectPermissionsTab/CnObjectPermissionsTab.vue3.js.map +1 -0
- package/dist/esm/components/CnObjectSidebar/CnObjectSidebar.vue.js +1 -1
- package/dist/esm/components/CnObjectSidebar/CnObjectSidebar.vue2.js +14 -7
- package/dist/esm/components/CnObjectSidebar/CnObjectSidebar.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnObjectSidebar.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectTranslationsWidget/CnObjectTranslationsWidget.vue.js +9 -0
- package/dist/esm/components/CnObjectTranslationsWidget/CnObjectTranslationsWidget.vue.js.map +1 -0
- package/dist/esm/components/CnObjectTranslationsWidget/CnObjectTranslationsWidget.vue2.js +278 -0
- package/dist/esm/components/CnObjectTranslationsWidget/CnObjectTranslationsWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnObjectTranslationsWidget/CnObjectTranslationsWidget.vue3.js +128 -0
- package/dist/esm/components/CnObjectTranslationsWidget/CnObjectTranslationsWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnReadinessChecklist/CnReadinessChecklist.vue.js +9 -0
- package/dist/esm/components/CnReadinessChecklist/CnReadinessChecklist.vue.js.map +1 -0
- package/dist/esm/components/CnReadinessChecklist/CnReadinessChecklist.vue2.js +214 -0
- package/dist/esm/components/CnReadinessChecklist/CnReadinessChecklist.vue2.js.map +1 -0
- package/dist/esm/components/CnReadinessChecklist/CnReadinessChecklist.vue3.js +125 -0
- package/dist/esm/components/CnReadinessChecklist/CnReadinessChecklist.vue3.js.map +1 -0
- package/dist/esm/components/CnSchemaRulesWidget/CnSchemaRulesWidget.vue.js +9 -0
- package/dist/esm/components/CnSchemaRulesWidget/CnSchemaRulesWidget.vue.js.map +1 -0
- package/dist/esm/components/CnSchemaRulesWidget/CnSchemaRulesWidget.vue2.js +163 -0
- package/dist/esm/components/CnSchemaRulesWidget/CnSchemaRulesWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnSchemaRulesWidget/CnSchemaRulesWidget.vue3.js +131 -0
- package/dist/esm/components/CnSchemaRulesWidget/CnSchemaRulesWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnSchemaRulesWidget/schemaRules.js +127 -0
- package/dist/esm/components/CnSchemaRulesWidget/schemaRules.js.map +1 -0
- package/dist/esm/components/CnSearchIndexStatus/CnSearchIndexStatus.vue.js +9 -0
- package/dist/esm/components/CnSearchIndexStatus/CnSearchIndexStatus.vue.js.map +1 -0
- package/dist/esm/components/CnSearchIndexStatus/CnSearchIndexStatus.vue2.js +82 -0
- package/dist/esm/components/CnSearchIndexStatus/CnSearchIndexStatus.vue2.js.map +1 -0
- package/dist/esm/components/CnSearchIndexStatus/CnSearchIndexStatus.vue3.js +61 -0
- package/dist/esm/components/CnSearchIndexStatus/CnSearchIndexStatus.vue3.js.map +1 -0
- package/dist/esm/components/CnSearchIndexStatus/searchIndexStatus.js +60 -0
- package/dist/esm/components/CnSearchIndexStatus/searchIndexStatus.js.map +1 -0
- package/dist/esm/components/CnShippedConfigurationSection/CnShippedConfigurationSection.vue.js +10 -0
- package/dist/esm/components/CnShippedConfigurationSection/CnShippedConfigurationSection.vue.js.map +1 -0
- package/dist/esm/components/CnShippedConfigurationSection/CnShippedConfigurationSection.vue2.js +226 -0
- package/dist/esm/components/CnShippedConfigurationSection/CnShippedConfigurationSection.vue2.js.map +1 -0
- package/dist/esm/components/CnShippedConfigurationSection/CnShippedConfigurationSection.vue3.js +126 -0
- package/dist/esm/components/CnShippedConfigurationSection/CnShippedConfigurationSection.vue3.js.map +1 -0
- package/dist/esm/components/CnStateMachineEditor/CnStateMachineEditor.vue.js +10 -0
- package/dist/esm/components/CnStateMachineEditor/CnStateMachineEditor.vue.js.map +1 -0
- package/dist/esm/components/CnStateMachineEditor/CnStateMachineEditor.vue2.js +944 -0
- package/dist/esm/components/CnStateMachineEditor/CnStateMachineEditor.vue2.js.map +1 -0
- package/dist/esm/components/CnStateMachineEditor/CnStateMachineEditor.vue3.js +276 -0
- package/dist/esm/components/CnStateMachineEditor/CnStateMachineEditor.vue3.js.map +1 -0
- package/dist/esm/components/CnStateMachineEditor/CnStateMachineFields.vue.js +9 -0
- package/dist/esm/components/CnStateMachineEditor/CnStateMachineFields.vue.js.map +1 -0
- package/dist/esm/components/CnStateMachineEditor/CnStateMachineFields.vue2.js +354 -0
- package/dist/esm/components/CnStateMachineEditor/CnStateMachineFields.vue2.js.map +1 -0
- package/dist/esm/components/CnStateMachineEditor/CnStateMachineFields.vue3.js +392 -0
- package/dist/esm/components/CnStateMachineEditor/CnStateMachineFields.vue3.js.map +1 -0
- package/dist/esm/components/CnStateMachineEditor/CnStateMachineNode.vue.js +9 -0
- package/dist/esm/components/CnStateMachineEditor/CnStateMachineNode.vue.js.map +1 -0
- package/dist/esm/components/CnStateMachineEditor/CnStateMachineNode.vue2.js +180 -0
- package/dist/esm/components/CnStateMachineEditor/CnStateMachineNode.vue2.js.map +1 -0
- package/dist/esm/components/CnStateMachineEditor/CnStateMachineNode.vue3.js +208 -0
- package/dist/esm/components/CnStateMachineEditor/CnStateMachineNode.vue3.js.map +1 -0
- package/dist/esm/components/CnStateMachineEditor/CnStateMachinePanel.vue.js +9 -0
- package/dist/esm/components/CnStateMachineEditor/CnStateMachinePanel.vue.js.map +1 -0
- package/dist/esm/components/CnStateMachineEditor/CnStateMachinePanel.vue2.js +244 -0
- package/dist/esm/components/CnStateMachineEditor/CnStateMachinePanel.vue2.js.map +1 -0
- package/dist/esm/components/CnStateMachineEditor/CnStateMachinePanel.vue3.js +76 -0
- package/dist/esm/components/CnStateMachineEditor/CnStateMachinePanel.vue3.js.map +1 -0
- package/dist/esm/components/CnStateMachineEditor/stateMachineFields.js +290 -0
- package/dist/esm/components/CnStateMachineEditor/stateMachineFields.js.map +1 -0
- package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue.js +9 -0
- package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue.js.map +1 -0
- package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue2.js +448 -0
- package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue2.js.map +1 -0
- package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue3.js +303 -0
- package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue3.js.map +1 -0
- package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue.js +1 -1
- package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue2.js +19 -2
- package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue3.js +73 -62
- package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnWidgetGrid/builtInWidgets.js +6 -0
- package/dist/esm/components/CnWidgetGrid/builtInWidgets.js.map +1 -1
- package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js +42 -32
- package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js.map +1 -1
- package/dist/esm/composables/indexSources.js +116 -16
- package/dist/esm/composables/indexSources.js.map +1 -1
- package/dist/esm/index.js +9 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/l10n/en.json.js +207 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +207 -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 +951 -16
- package/dist/esm/utils/aiFeatures.js +245 -0
- package/dist/esm/utils/aiFeatures.js.map +1 -0
- package/dist/esm/utils/aiSuggestionTracker.js +182 -0
- package/dist/esm/utils/aiSuggestionTracker.js.map +1 -0
- package/dist/esm/utils/libraryWidgetKeys.js +2 -0
- package/dist/esm/utils/libraryWidgetKeys.js.map +1 -1
- package/dist/esm/utils/objectPermissions.js +552 -0
- package/dist/esm/utils/objectPermissions.js.map +1 -0
- package/dist/esm/utils/objectTranslations.js +180 -0
- package/dist/esm/utils/objectTranslations.js.map +1 -0
- package/dist/esm/utils/stateMachineValidation.js +254 -0
- package/dist/esm/utils/stateMachineValidation.js.map +1 -0
- package/dist/esm/utils/widgetDispatch.js +3 -1
- package/dist/esm/utils/widgetDispatch.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +23038 -14567
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +951 -16
- package/l10n/en.json +207 -1
- package/l10n/nl.json +207 -1
- package/package.json +1 -1
- package/src/components/CnAiFeaturesWidget/CnAiFeaturesWidget.vue +416 -0
- package/src/components/CnAiFeaturesWidget/CnAiSuggestionDecision.vue +136 -0
- package/src/components/CnAiFeaturesWidget/__tests__/CnAiFeaturesWidget.spec.js +213 -0
- package/src/components/CnAiFeaturesWidget/index.js +14 -0
- package/src/components/CnIndexPage/CnIndexPage.vue +74 -3
- package/src/components/CnIndexPage/useNamedSource.js +9 -0
- package/src/components/CnObjectPermissionsTab/CnObjectPermissionsTab.vue +499 -0
- package/src/components/CnObjectPermissionsTab/__tests__/CnObjectPermissionsTab.spec.js +186 -0
- package/src/components/CnObjectPermissionsTab/index.js +13 -0
- package/src/components/CnObjectSidebar/CnObjectSidebar.vue +8 -1
- package/src/components/CnObjectTranslationsWidget/CnObjectTranslationsWidget.vue +424 -0
- package/src/components/CnObjectTranslationsWidget/__tests__/CnObjectTranslationsWidget.spec.js +189 -0
- package/src/components/CnObjectTranslationsWidget/index.js +13 -0
- package/src/components/CnReadinessChecklist/CnReadinessChecklist.vue +335 -0
- package/src/components/CnReadinessChecklist/index.js +9 -0
- package/src/components/CnSchemaRulesWidget/CnSchemaRulesWidget.vue +300 -0
- package/src/components/CnSchemaRulesWidget/index.js +10 -0
- package/src/components/CnSchemaRulesWidget/schemaRules.js +123 -0
- package/src/components/CnSearchIndexStatus/CnSearchIndexStatus.vue +160 -0
- package/src/components/CnSearchIndexStatus/index.js +10 -0
- package/src/components/CnSearchIndexStatus/searchIndexStatus.js +56 -0
- package/src/components/CnShippedConfigurationSection/CnShippedConfigurationSection.vue +328 -0
- package/src/components/CnShippedConfigurationSection/index.js +9 -0
- package/src/components/CnStateMachineEditor/CnStateMachineEditor.vue +1332 -0
- package/src/components/CnStateMachineEditor/CnStateMachineFields.vue +791 -0
- package/src/components/CnStateMachineEditor/CnStateMachineNode.vue +442 -0
- package/src/components/CnStateMachineEditor/CnStateMachinePanel.vue +326 -0
- package/src/components/CnStateMachineEditor/index.js +8 -0
- package/src/components/CnStateMachineEditor/stateMachineFields.js +287 -0
- package/src/components/CnTimelineWidget/CnTimelineManage.vue +827 -0
- package/src/components/CnTimelineWidget/CnTimelineWidget.vue +29 -3
- package/src/components/CnWidgetGrid/builtInWidgets.js +6 -0
- package/src/components/CnWidgetGrid/registerDashboardWidgets.js +10 -0
- package/src/components/index.js +8 -0
- package/src/composables/indexSources.js +116 -16
- package/src/css/index-page.css +7 -0
- package/src/index.js +9 -0
- package/src/utils/aiFeatures.js +241 -0
- package/src/utils/aiSuggestionTracker.js +178 -0
- package/src/utils/libraryWidgetKeys.js +2 -0
- package/src/utils/objectPermissions.js +548 -0
- package/src/utils/objectTranslations.js +176 -0
- package/src/utils/stateMachineValidation.js +250 -0
- package/src/utils/widgetDispatch.js +3 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stateMachineFields.js","sources":["../../../../src/components/CnStateMachineEditor/stateMachineFields.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V. <info@conduction.nl>\n * SPDX-License-Identifier: EUPL-1.2\n *\n * The record model behind CnStateMachineEditor's property panels: turning a\n * stored record into an editable copy described by field descriptors, and the\n * copy back into the record the host stores.\n *\n * A field descriptor is `{ key, type, label, ... }` with `type` one of\n * `text`, `textarea`, `number`, `checkbox`, `select`, `checkboxes`, `list`,\n * `typed-list`, `group` or `row`. A `group` with a `key` edits a nested object;\n * without one, like a `row`, it only arranges its `fields`.\n *\n * @module components/CnStateMachineEditor/stateMachineFields\n */\n\nconst LIST_TYPES = new Set(['list', 'typed-list', 'checkboxes'])\n\nlet generatedIds = 0\n\n/**\n * Parse a value a host may have stored as a JSON string.\n *\n * @param {unknown} raw The stored value.\n * @return {unknown} The parsed value, or the value itself when it is not JSON text.\n */\nexport function parseStored(raw) {\n\tif (typeof raw !== 'string') {\n\t\treturn raw\n\t}\n\tconst text = raw.trim()\n\tif (text.charAt(0) !== '[' && text.charAt(0) !== '{') {\n\t\treturn raw\n\t}\n\ttry {\n\t\treturn JSON.parse(text)\n\t} catch {\n\t\treturn raw\n\t}\n}\n\n/**\n * Deep copy of plain data.\n *\n * @param {unknown} value The value.\n * @return {unknown} The copy.\n */\nexport function cloneData(value) {\n\tif (value === undefined) {\n\t\treturn undefined\n\t}\n\treturn JSON.parse(JSON.stringify(value))\n}\n\n/**\n * Whether a value counts as not filled in.\n *\n * @param {unknown} value The value.\n * @return {boolean} True for null, undefined, '', NaN and blank strings.\n */\nexport function isBlank(value) {\n\tif (value === null || value === undefined) {\n\t\treturn true\n\t}\n\tif (typeof value === 'number') {\n\t\treturn Number.isNaN(value)\n\t}\n\treturn typeof value === 'string' && value.trim() === ''\n}\n\n/**\n * Whether a value is a plain object.\n *\n * @param {unknown} value The value.\n * @return {boolean} True for `{}`-like values.\n */\nfunction isPlainObject(value) {\n\treturn value !== null && typeof value === 'object' && !Array.isArray(value)\n}\n\n/**\n * A fresh id for a new list item.\n *\n * @param {string} prefix The id prefix.\n * @return {string} The id.\n */\nexport function newItemId(prefix = 'item-') {\n\tgeneratedIds += 1\n\treturn `${prefix}${Date.now().toString(36)}-${generatedIds}`\n}\n\n/**\n * The path that identifies an optional group in the enabled map.\n *\n * @param {string} base The parent path.\n * @param {string} key The group key.\n * @return {string} The path.\n */\nfunction pathOf(base, key) {\n\treturn base ? `${base}.${key}` : key\n}\n\n/**\n * Normalise `target` in place so every described field holds an editable value,\n * and record which optional groups are switched on.\n *\n * Text fields that are absent stay absent: a panel opened and closed must not\n * add empty keys to a record.\n *\n * @param {object} target The copy being edited.\n * @param {Array<object>} fields The descriptors.\n * @param {object} enabled Optional-group state by path, filled in here.\n * @param {string} [base] The path of `target`.\n * @return {object} `target`.\n */\nexport function normaliseFields(target, fields, enabled, base = '') {\n\tfor (const field of fields || []) {\n\t\tif ((field.type === 'group' && !field.key) || field.type === 'row') {\n\t\t\tnormaliseFields(target, field.fields, enabled, base)\n\t\t\tcontinue\n\t\t}\n\t\tif (!field.key) {\n\t\t\tcontinue\n\t\t}\n\t\tconst stored = parseStored(target[field.key])\n\t\tif (field.type === 'group') {\n\t\t\tconst present = isPlainObject(stored)\n\t\t\tif (field.optional) {\n\t\t\t\tenabled[pathOf(base, field.key)] = present\n\t\t\t}\n\t\t\tconst value = { ...cloneData(field.defaults || {}), ...(present ? stored : {}) }\n\t\t\tnormaliseFields(value, field.fields, enabled, pathOf(base, field.key))\n\t\t\ttarget[field.key] = value\n\t\t} else if (LIST_TYPES.has(field.type)) {\n\t\t\ttarget[field.key] = Array.isArray(stored) ? stored : []\n\t\t} else if (field.type === 'checkbox') {\n\t\t\tif (stored !== undefined || field.default !== undefined) {\n\t\t\t\ttarget[field.key] = stored === undefined ? !!field.default : !!stored\n\t\t\t}\n\t\t} else if (stored === undefined && field.default !== undefined) {\n\t\t\ttarget[field.key] = cloneData(field.default)\n\t\t} else if (stored !== undefined) {\n\t\t\ttarget[field.key] = stored\n\t\t}\n\t}\n\treturn target\n}\n\n/**\n * Turn a stored record into the copy a panel edits.\n *\n * @param {object} record The stored record.\n * @param {Array<object>} fields The descriptors.\n * @return {{ model: object, enabled: object }} The copy, and which optional groups are on.\n */\nexport function readRecord(record, fields) {\n\tconst enabled = {}\n\tconst model = normaliseFields(cloneData(record || {}), fields, enabled)\n\treturn { model, enabled }\n}\n\n/**\n * Every leaf key a group describes, through rows and key-less groups.\n *\n * @param {Array<object>} fields The descriptors.\n * @return {Array<object>} The leaf descriptors.\n */\nfunction leafFields(fields) {\n\tconst leaves = []\n\tfor (const field of fields || []) {\n\t\tif ((field.type === 'group' && !field.key) || field.type === 'row') {\n\t\t\tleaves.push(...leafFields(field.fields))\n\t\t} else if (field.key) {\n\t\t\tleaves.push(field)\n\t\t}\n\t}\n\treturn leaves\n}\n\n/**\n * Drop what is not filled in from one pruned object.\n *\n * Lists of strings lose their blank entries; then any key holding a blank\n * value or an empty list goes. `false` and `0` are values and stay.\n *\n * @param {object} value The object.\n * @param {Array<object>} fields Its descriptors.\n * @return {object} The pruned object.\n */\nfunction prune(value, fields) {\n\tconst byKey = Object.fromEntries(leafFields(fields).map((field) => [field.key, field]))\n\tfor (const key of Object.keys(value)) {\n\t\tlet entry = value[key]\n\t\tconst field = byKey[key]\n\t\tif (Array.isArray(entry) && field && field.type === 'list' && field.itemType !== 'object') {\n\t\t\tentry = entry.filter((item) => !isBlank(item))\n\t\t\tvalue[key] = entry\n\t\t}\n\t\tif (isBlank(entry) || (Array.isArray(entry) && entry.length === 0)) {\n\t\t\tdelete value[key]\n\t\t}\n\t}\n\treturn value\n}\n\n/**\n * Turn an edited copy back into the record to store.\n *\n * Per group: an optional group that is off is left out; a `requireAll` group is\n * left out unless every leaf is filled in; a `prune` group drops its empty\n * entries and, with `omitWhenEmpty`, is left out once nothing remains.\n *\n * @param {object} model The edited copy.\n * @param {Array<object>} fields The descriptors.\n * @param {object} enabled Optional-group state by path.\n * @param {string} [base] The path of `model`.\n * @return {object} The record.\n */\nexport function buildRecord(model, fields, enabled, base = '') {\n\tconst out = cloneData(model || {})\n\tconst visit = (target, list, path) => {\n\t\tfor (const field of list || []) {\n\t\t\tif ((field.type === 'group' && !field.key) || field.type === 'row') {\n\t\t\t\tvisit(target, field.fields, path)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif (field.type !== 'group' || !field.key) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tconst groupPath = pathOf(path, field.key)\n\t\t\tif (field.optional && !enabled[groupPath]) {\n\t\t\t\tdelete target[field.key]\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tconst inner = isPlainObject(target[field.key]) ? target[field.key] : {}\n\t\t\tvisit(inner, field.fields, groupPath)\n\t\t\tif (field.requireAll && leafFields(field.fields).some((leaf) => isBlank(inner[leaf.key]))) {\n\t\t\t\tdelete target[field.key]\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif (field.prune) {\n\t\t\t\tprune(inner, field.fields)\n\t\t\t}\n\t\t\tif (field.omitWhenEmpty && Object.keys(inner).length === 0) {\n\t\t\t\tdelete target[field.key]\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\ttarget[field.key] = inner\n\t\t}\n\t}\n\tvisit(out, fields, base)\n\treturn out\n}\n\n/**\n * A new item for a list field.\n *\n * @param {object} field The list descriptor.\n * @return {unknown} The item: '' for a list of strings, else a copy of `newItem` with a fresh id when `idKey` is set.\n */\nexport function newListItem(field) {\n\tif (field.type === 'list' && field.itemType !== 'object') {\n\t\treturn ''\n\t}\n\tconst item = cloneData(field.newItem || {})\n\tif (field.idKey) {\n\t\titem[field.idKey] = newItemId(field.idPrefix)\n\t}\n\treturn item\n}\n\n/**\n * Move one entry of a list.\n *\n * @param {Array} list The list, changed in place.\n * @param {number} from The entry's index.\n * @param {number} to Its new index.\n * @return {boolean} Whether anything moved.\n */\nexport function moveItem(list, from, to) {\n\tif (from === to || from < 0 || to < 0 || from >= list.length || to >= list.length) {\n\t\treturn false\n\t}\n\tconst [item] = list.splice(from, 1)\n\tlist.splice(to, 0, item)\n\treturn true\n}\n"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,YAAY,EAAE,YAAY,CAAC,EAAC;AAChE;AACA,IAAI,YAAY,GAAG,EAAC;AACpB;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,WAAW,CAAC,GAAG,EAAE;AACjC,CAAC,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE;AAC9B,EAAE,OAAO,GAAG;AACZ,EAAE;AACF,CAAC,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,GAAE;AACxB,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE;AACvD,EAAE,OAAO,GAAG;AACZ,EAAE;AACF,CAAC,IAAI;AACL,EAAE,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;AACzB,EAAE,CAAC,MAAM;AACT,EAAE,OAAO,GAAG;AACZ,EAAE;AACF,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,SAAS,CAAC,KAAK,EAAE;AACjC,CAAC,IAAI,KAAK,KAAK,SAAS,EAAE;AAC1B,EAAE,OAAO,SAAS;AAClB,EAAE;AACF,CAAC,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;AACzC,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,OAAO,CAAC,KAAK,EAAE;AAC/B,CAAC,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,EAAE;AAC5C,EAAE,OAAO,IAAI;AACb,EAAE;AACF,CAAC,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;AAChC,EAAE,OAAO,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC;AAC5B,EAAE;AACF,CAAC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE;AACxD,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,aAAa,CAAC,KAAK,EAAE;AAC9B,CAAC,OAAO,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;AAC5E,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,SAAS,CAAC,MAAM,GAAG,OAAO,EAAE;AAC5C,CAAC,YAAY,IAAI,EAAC;AAClB,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC;AAC7D,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE;AAC3B,CAAC,OAAO,IAAI,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,GAAG;AACrC,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,GAAG,EAAE,EAAE;AACpE,CAAC,KAAK,MAAM,KAAK,IAAI,MAAM,IAAI,EAAE,EAAE;AACnC,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,KAAK,KAAK,CAAC,IAAI,KAAK,KAAK,EAAE;AACtE,GAAG,eAAe,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAC;AACvD,GAAG,QAAQ;AACX,GAAG;AACH,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE;AAClB,GAAG,QAAQ;AACX,GAAG;AACH,EAAE,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,EAAC;AAC/C,EAAE,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE;AAC9B,GAAG,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,EAAC;AACxC,GAAG,IAAI,KAAK,CAAC,QAAQ,EAAE;AACvB,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,QAAO;AAC9C,IAAI;AACJ,GAAG,MAAM,KAAK,GAAG,EAAE,GAAG,SAAS,CAAC,KAAK,CAAC,QAAQ,IAAI,EAAE,CAAC,EAAE,IAAI,OAAO,GAAG,MAAM,GAAG,EAAE,CAAC,GAAE;AACnF,GAAG,eAAe,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,EAAC;AACzE,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,MAAK;AAC5B,GAAG,MAAM,IAAI,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE;AACzC,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,GAAG,GAAE;AAC1D,GAAG,MAAM,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE;AACxC,GAAG,IAAI,MAAM,KAAK,SAAS,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS,EAAE;AAC5D,IAAI,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,MAAM,KAAK,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC,OAAM;AACzE,IAAI;AACJ,GAAG,MAAM,IAAI,MAAM,KAAK,SAAS,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS,EAAE;AAClE,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC,KAAK,CAAC,OAAO,EAAC;AAC/C,GAAG,MAAM,IAAI,MAAM,KAAK,SAAS,EAAE;AACnC,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,OAAM;AAC7B,GAAG;AACH,EAAE;AACF,CAAC,OAAO,MAAM;AACd,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE;AAC3C,CAAC,MAAM,OAAO,GAAG,GAAE;AACnB,CAAC,MAAM,KAAK,GAAG,eAAe,CAAC,SAAS,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,OAAO,EAAC;AACxE,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE;AAC1B,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,UAAU,CAAC,MAAM,EAAE;AAC5B,CAAC,MAAM,MAAM,GAAG,GAAE;AAClB,CAAC,KAAK,MAAM,KAAK,IAAI,MAAM,IAAI,EAAE,EAAE;AACnC,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,KAAK,KAAK,CAAC,IAAI,KAAK,KAAK,EAAE;AACtE,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,EAAC;AAC3C,GAAG,MAAM,IAAI,KAAK,CAAC,GAAG,EAAE;AACxB,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,EAAC;AACrB,GAAG;AACH,EAAE;AACF,CAAC,OAAO,MAAM;AACd,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE;AAC9B,CAAC,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,EAAC;AACxF,CAAC,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;AACvC,EAAE,IAAI,KAAK,GAAG,KAAK,CAAC,GAAG,EAAC;AACxB,EAAE,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,EAAC;AAC1B,EAAE,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,KAAK,CAAC,QAAQ,KAAK,QAAQ,EAAE;AAC7F,GAAG,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAC;AACjD,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,MAAK;AACrB,GAAG;AACH,EAAE,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,EAAE;AACtE,GAAG,OAAO,KAAK,CAAC,GAAG,EAAC;AACpB,GAAG;AACH,EAAE;AACF,CAAC,OAAO,KAAK;AACb,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,GAAG,EAAE,EAAE;AAC/D,CAAC,MAAM,GAAG,GAAG,SAAS,CAAC,KAAK,IAAI,EAAE,EAAC;AACnC,CAAC,MAAM,KAAK,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,KAAK;AACvC,EAAE,KAAK,MAAM,KAAK,IAAI,IAAI,IAAI,EAAE,EAAE;AAClC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,KAAK,KAAK,CAAC,IAAI,KAAK,KAAK,EAAE;AACvE,IAAI,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,IAAI,EAAC;AACrC,IAAI,QAAQ;AACZ,IAAI;AACJ,GAAG,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE;AAC7C,IAAI,QAAQ;AACZ,IAAI;AACJ,GAAG,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,EAAC;AAC5C,GAAG,IAAI,KAAK,CAAC,QAAQ,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE;AAC9C,IAAI,OAAO,MAAM,CAAC,KAAK,CAAC,GAAG,EAAC;AAC5B,IAAI,QAAQ;AACZ,IAAI;AACJ,GAAG,MAAM,KAAK,GAAG,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,GAAE;AAC1E,GAAG,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,SAAS,EAAC;AACxC,GAAG,IAAI,KAAK,CAAC,UAAU,IAAI,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;AAC9F,IAAI,OAAO,MAAM,CAAC,KAAK,CAAC,GAAG,EAAC;AAC5B,IAAI,QAAQ;AACZ,IAAI;AACJ,GAAG,IAAI,KAAK,CAAC,KAAK,EAAE;AACpB,IAAI,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,EAAC;AAC9B,IAAI;AACJ,GAAG,IAAI,KAAK,CAAC,aAAa,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE;AAC/D,IAAI,OAAO,MAAM,CAAC,KAAK,CAAC,GAAG,EAAC;AAC5B,IAAI,QAAQ;AACZ,IAAI;AACJ,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,MAAK;AAC5B,GAAG;AACH,GAAE;AACF,CAAC,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAC;AACzB,CAAC,OAAO,GAAG;AACX,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,WAAW,CAAC,KAAK,EAAE;AACnC,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,KAAK,CAAC,QAAQ,KAAK,QAAQ,EAAE;AAC3D,EAAE,OAAO,EAAE;AACX,EAAE;AACF,CAAC,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,OAAO,IAAI,EAAE,EAAC;AAC5C,CAAC,IAAI,KAAK,CAAC,KAAK,EAAE;AAClB,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,SAAS,CAAC,KAAK,CAAC,QAAQ,EAAC;AAC/C,EAAE;AACF,CAAC,OAAO,IAAI;AACZ,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE;AACzC,CAAC,IAAI,IAAI,KAAK,EAAE,IAAI,IAAI,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,IAAI,IAAI,IAAI,CAAC,MAAM,IAAI,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE;AACpF,EAAE,OAAO,KAAK;AACd,EAAE;AACF,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,EAAC;AACpC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,EAAE,IAAI,EAAC;AACzB,CAAC,OAAO,IAAI;AACZ;;;;"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import script from './CnTimelineManage.vue2.js';
|
|
2
|
+
import { render } from './CnTimelineManage.vue3.js';
|
|
3
|
+
|
|
4
|
+
script.render = render;
|
|
5
|
+
script.__scopeId = "data-v-397b3dd4";
|
|
6
|
+
const __sfc_main = script;
|
|
7
|
+
|
|
8
|
+
export { __sfc_main as default };
|
|
9
|
+
//# sourceMappingURL=CnTimelineManage.vue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CnTimelineManage.vue.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;"}
|
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
import axios__default from '@nextcloud/axios';
|
|
2
|
+
import { translate, translatePlural } from '@nextcloud/l10n';
|
|
3
|
+
import { NcButton, NcCheckboxRadioSwitch, NcEmptyContent, NcLoadingIcon, NcNoteCard, NcSelect } from '@nextcloud/vue';
|
|
4
|
+
import Download from 'vue-material-design-icons/Download.vue';
|
|
5
|
+
import Plus from 'vue-material-design-icons/Plus.vue';
|
|
6
|
+
import { prefixUrl } from '../../utils/headers.js';
|
|
7
|
+
|
|
8
|
+
let instanceCount = 0;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Read a dotted path off a value.
|
|
12
|
+
*
|
|
13
|
+
* @param {object} value The value.
|
|
14
|
+
* @param {string} path The path.
|
|
15
|
+
* @return {unknown} What is there, or undefined.
|
|
16
|
+
*/
|
|
17
|
+
function readPath(value, path) {
|
|
18
|
+
return String(path).split('.').reduce((at, key) => (at === null || at === undefined ? undefined : at[key]), value)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
var script = {
|
|
22
|
+
name: 'CnTimelineManage',
|
|
23
|
+
|
|
24
|
+
components: { Download, NcButton, NcCheckboxRadioSwitch, NcEmptyContent, NcLoadingIcon, NcNoteCard, NcSelect, Plus },
|
|
25
|
+
|
|
26
|
+
inject: {
|
|
27
|
+
/** The app's component registry; entry actions resolve their modal here. */
|
|
28
|
+
cnRegistry: { default: () => ({}) },
|
|
29
|
+
/** Consumer translation function; manifest labels are authored in English. */
|
|
30
|
+
cnTranslate: { default: () => (key) => key },
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
props: {
|
|
34
|
+
/** Register slug. */
|
|
35
|
+
register: { type: String, default: '' },
|
|
36
|
+
/** Schema slug. */
|
|
37
|
+
schema: { type: String, default: '' },
|
|
38
|
+
/** The object's id. */
|
|
39
|
+
objectId: { type: String, default: '' },
|
|
40
|
+
/** OpenRegister API base. */
|
|
41
|
+
apiBase: { type: String, default: '/apps/openregister/api' },
|
|
42
|
+
/**
|
|
43
|
+
* The widget content: `{ title?, subtitle?, publicLabel?, exportName?,
|
|
44
|
+
* composer?, textBlocks?, entryActions? }`.
|
|
45
|
+
*/
|
|
46
|
+
content: { type: Object, default: () => ({}) },
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
data() {
|
|
50
|
+
instanceCount += 1;
|
|
51
|
+
return {
|
|
52
|
+
uid: instanceCount,
|
|
53
|
+
allEntries: [],
|
|
54
|
+
entries: [],
|
|
55
|
+
kinds: [],
|
|
56
|
+
loading: false,
|
|
57
|
+
error: '',
|
|
58
|
+
canManage: false,
|
|
59
|
+
kindFilter: null,
|
|
60
|
+
visibilityFilter: null,
|
|
61
|
+
textBlocks: [],
|
|
62
|
+
chosenBlock: null,
|
|
63
|
+
draft: '',
|
|
64
|
+
draftIsPublic: false,
|
|
65
|
+
saving: false,
|
|
66
|
+
activeModal: null,
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
computed: {
|
|
71
|
+
titleText() {
|
|
72
|
+
return this.content.title ? this.translate(this.content.title) : translate('nextcloud-vue', 'History')
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
subtitleText() {
|
|
76
|
+
return this.content.subtitle ? this.translate(this.content.subtitle) : translate('nextcloud-vue', 'What happened, who did it and when, newest first')
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
publicLabel() {
|
|
80
|
+
return this.content.publicLabel ? this.translate(this.content.publicLabel) : translate('nextcloud-vue', 'Visible to the applicant')
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
composerEnabled() {
|
|
84
|
+
return this.content.composer !== false
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
draftId() {
|
|
88
|
+
return `cn-timeline-draft-${this.uid}`
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* The kind options, the plain note first. A note is an entry with NO
|
|
93
|
+
* kind, so "Note" filters on its absence.
|
|
94
|
+
*
|
|
95
|
+
* @return {Array<object>} The options.
|
|
96
|
+
*/
|
|
97
|
+
kindOptions() {
|
|
98
|
+
return [{ id: '', label: translate('nextcloud-vue', 'Note') }].concat(this.kinds.map((kind) => ({ id: kind.slug, label: kind.title || kind.slug })))
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* All, then every kind the object has entries of, each with its count.
|
|
103
|
+
*
|
|
104
|
+
* @return {Array<object>} The chips.
|
|
105
|
+
*/
|
|
106
|
+
kindChips() {
|
|
107
|
+
const chosen = this.kindFilter ? (this.kindFilter.id || '') : null;
|
|
108
|
+
const counts = new Map();
|
|
109
|
+
for (const entry of this.allEntries) {
|
|
110
|
+
const kind = entry.kind || '';
|
|
111
|
+
counts.set(kind, (counts.get(kind) || 0) + 1);
|
|
112
|
+
}
|
|
113
|
+
const chips = [{ key: 'all', id: null, label: translate('nextcloud-vue', 'All'), count: this.allEntries.length, active: chosen === null }];
|
|
114
|
+
for (const option of this.kindOptions) {
|
|
115
|
+
const count = counts.get(option.id) || 0;
|
|
116
|
+
if (count > 0) {
|
|
117
|
+
chips.push({ key: option.id || 'note', id: option.id, label: option.label, count, active: chosen === option.id });
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return chips
|
|
121
|
+
},
|
|
122
|
+
|
|
123
|
+
blockOptions() {
|
|
124
|
+
return this.textBlocks.map((block) => ({ id: block.slug, label: block.title || block.slug }))
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
visibilityOptions() {
|
|
128
|
+
return [
|
|
129
|
+
{ id: 'internal', label: translate('nextcloud-vue', 'Internal only') },
|
|
130
|
+
{ id: 'public', label: this.publicLabel },
|
|
131
|
+
]
|
|
132
|
+
},
|
|
133
|
+
|
|
134
|
+
base() {
|
|
135
|
+
return this.apiBase.replace(/\/$/, '')
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
timelineUrl() {
|
|
139
|
+
if (!this.objectId || !this.register || !this.schema) {
|
|
140
|
+
return ''
|
|
141
|
+
}
|
|
142
|
+
return prefixUrl(`${this.base}/objects/${this.register}/${this.schema}/${this.objectId}/timeline`)
|
|
143
|
+
},
|
|
144
|
+
|
|
145
|
+
entryActions() {
|
|
146
|
+
return Array.isArray(this.content.entryActions) ? this.content.entryActions.filter((action) => action && action.id) : []
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
|
|
150
|
+
watch: {
|
|
151
|
+
objectId: 'load',
|
|
152
|
+
},
|
|
153
|
+
|
|
154
|
+
mounted() {
|
|
155
|
+
this.loadKinds();
|
|
156
|
+
if (this.content.textBlocks !== false) {
|
|
157
|
+
this.loadTextBlocks();
|
|
158
|
+
}
|
|
159
|
+
this.load();
|
|
160
|
+
},
|
|
161
|
+
|
|
162
|
+
methods: {
|
|
163
|
+
t: translate,
|
|
164
|
+
n: translatePlural,
|
|
165
|
+
|
|
166
|
+
translate(text) {
|
|
167
|
+
return text ? this.cnTranslate(text) : ''
|
|
168
|
+
},
|
|
169
|
+
|
|
170
|
+
/** Read the declared kinds, so the filter names them as administered. */
|
|
171
|
+
async loadKinds() {
|
|
172
|
+
try {
|
|
173
|
+
const response = await axios__default.get(prefixUrl(`${this.base}/timeline/kinds`));
|
|
174
|
+
this.kinds = response.data?.results || [];
|
|
175
|
+
} catch {
|
|
176
|
+
this.kinds = [];
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
|
|
180
|
+
/** Read the seeded standard notes. */
|
|
181
|
+
async loadTextBlocks() {
|
|
182
|
+
try {
|
|
183
|
+
const response = await axios__default.get(prefixUrl(`${this.base}/timeline/text-blocks`));
|
|
184
|
+
this.textBlocks = response.data?.results || [];
|
|
185
|
+
} catch {
|
|
186
|
+
this.textBlocks = [];
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Note which standard note was picked. The BLOCK is sent, not its body:
|
|
192
|
+
* OpenRegister fills the object's own values into it on the way in.
|
|
193
|
+
*
|
|
194
|
+
* @param {object|null} block The picked option.
|
|
195
|
+
*/
|
|
196
|
+
pickBlock(block) {
|
|
197
|
+
this.chosenBlock = block || null;
|
|
198
|
+
if (block) {
|
|
199
|
+
const declared = this.textBlocks.find((entry) => entry.slug === block.id);
|
|
200
|
+
this.draft = declared?.title || block.label;
|
|
201
|
+
}
|
|
202
|
+
},
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Write the drafted note onto this object.
|
|
206
|
+
*
|
|
207
|
+
* @return {Promise<void>}
|
|
208
|
+
*/
|
|
209
|
+
async submit() {
|
|
210
|
+
if (!this.draft.trim() || !this.timelineUrl) {
|
|
211
|
+
return
|
|
212
|
+
}
|
|
213
|
+
this.saving = true;
|
|
214
|
+
this.error = '';
|
|
215
|
+
try {
|
|
216
|
+
const payload = { visibility: this.draftIsPublic ? 'public' : 'internal' };
|
|
217
|
+
if (this.chosenBlock?.id) {
|
|
218
|
+
payload.textBlock = this.chosenBlock.id;
|
|
219
|
+
} else {
|
|
220
|
+
payload.message = this.draft;
|
|
221
|
+
}
|
|
222
|
+
await axios__default.post(this.timelineUrl, payload);
|
|
223
|
+
this.draft = '';
|
|
224
|
+
this.chosenBlock = null;
|
|
225
|
+
this.draftIsPublic = false;
|
|
226
|
+
await this.load();
|
|
227
|
+
} catch {
|
|
228
|
+
this.error = translate('nextcloud-vue', 'That note could not be saved.');
|
|
229
|
+
} finally {
|
|
230
|
+
this.saving = false;
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Read the timeline with the visibility filter, if one is set.
|
|
236
|
+
*
|
|
237
|
+
* @return {Promise<void>}
|
|
238
|
+
*/
|
|
239
|
+
async load() {
|
|
240
|
+
if (!this.timelineUrl) {
|
|
241
|
+
return
|
|
242
|
+
}
|
|
243
|
+
this.loading = true;
|
|
244
|
+
this.error = '';
|
|
245
|
+
try {
|
|
246
|
+
const params = {};
|
|
247
|
+
if (this.visibilityFilter?.id) {
|
|
248
|
+
params.visibility = this.visibilityFilter.id;
|
|
249
|
+
}
|
|
250
|
+
const response = await axios__default.get(this.timelineUrl, { params });
|
|
251
|
+
this.canManage = response.data?.canManage === true;
|
|
252
|
+
this.allEntries = response.data?.results || [];
|
|
253
|
+
this.entries = this.applyKindFilter(this.allEntries);
|
|
254
|
+
} catch {
|
|
255
|
+
this.allEntries = [];
|
|
256
|
+
this.entries = [];
|
|
257
|
+
this.error = translate('nextcloud-vue', 'The timeline could not be read. Try again, or ask an administrator to check OpenRegister.');
|
|
258
|
+
} finally {
|
|
259
|
+
this.loading = false;
|
|
260
|
+
}
|
|
261
|
+
},
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Show one kind, or every kind for `null`, without reading again.
|
|
265
|
+
*
|
|
266
|
+
* @param {string|null} id The kind slug, '' for a note, null for all.
|
|
267
|
+
*/
|
|
268
|
+
chooseKind(id) {
|
|
269
|
+
this.kindFilter = id === null ? null : { id };
|
|
270
|
+
this.entries = this.applyKindFilter(this.allEntries);
|
|
271
|
+
},
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* The kind filter is applied in the reading: the list endpoint does not
|
|
275
|
+
* read a kind parameter, so sending one would be dropped in silence.
|
|
276
|
+
*
|
|
277
|
+
* @param {Array<object>} results The entries as read.
|
|
278
|
+
* @return {Array<object>} The entries to show.
|
|
279
|
+
*/
|
|
280
|
+
applyKindFilter(results) {
|
|
281
|
+
if (!this.kindFilter) {
|
|
282
|
+
return results
|
|
283
|
+
}
|
|
284
|
+
const wanted = this.kindFilter.id || '';
|
|
285
|
+
return results.filter((entry) => (entry.kind || '') === wanted)
|
|
286
|
+
},
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* The shown entries as CSV: when, kind, who, visibility and what.
|
|
290
|
+
*
|
|
291
|
+
* @return {string} The CSV text.
|
|
292
|
+
*/
|
|
293
|
+
entriesCsv() {
|
|
294
|
+
const cell = (value) => `"${String(value ?? '').replace(/"/g, '""')}"`;
|
|
295
|
+
const rows = [[translate('nextcloud-vue', 'When'), translate('nextcloud-vue', 'Kind'), translate('nextcloud-vue', 'Who'), translate('nextcloud-vue', 'Visibility'), translate('nextcloud-vue', 'Message')]];
|
|
296
|
+
for (const entry of this.entries) {
|
|
297
|
+
rows.push([entry.created, this.kindLabel(entry), entry.author, entry.visibility, entry.message]);
|
|
298
|
+
}
|
|
299
|
+
return rows.map((row) => row.map(cell).join(',')).join('\r\n')
|
|
300
|
+
},
|
|
301
|
+
|
|
302
|
+
/** Download the shown entries as a CSV file. */
|
|
303
|
+
exportEntries() {
|
|
304
|
+
const blob = new Blob([this.entriesCsv()], { type: 'text/csv;charset=utf-8' });
|
|
305
|
+
const url = URL.createObjectURL(blob);
|
|
306
|
+
const link = document.createElement('a');
|
|
307
|
+
link.href = url;
|
|
308
|
+
link.download = `${this.content.exportName || 'history'}-${this.objectId || 'record'}.csv`;
|
|
309
|
+
document.body.appendChild(link);
|
|
310
|
+
link.click();
|
|
311
|
+
link.remove();
|
|
312
|
+
URL.revokeObjectURL(url);
|
|
313
|
+
},
|
|
314
|
+
|
|
315
|
+
/** Bring the composer into view and focus its text. */
|
|
316
|
+
focusComposer() {
|
|
317
|
+
const form = this.$refs.composer;
|
|
318
|
+
if (!form) {
|
|
319
|
+
return
|
|
320
|
+
}
|
|
321
|
+
form.scrollIntoView?.({ behavior: 'smooth', block: 'center' });
|
|
322
|
+
form.querySelector('textarea')?.focus();
|
|
323
|
+
},
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* The label of one entry's kind, falling back to "Note".
|
|
327
|
+
*
|
|
328
|
+
* @param {object} entry The entry.
|
|
329
|
+
* @return {string} The label.
|
|
330
|
+
*/
|
|
331
|
+
kindLabel(entry) {
|
|
332
|
+
if (!entry.kind) {
|
|
333
|
+
return translate('nextcloud-vue', 'Note')
|
|
334
|
+
}
|
|
335
|
+
const declared = this.kinds.find((kind) => kind.slug === entry.kind);
|
|
336
|
+
return declared?.title || entry.kind
|
|
337
|
+
},
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* One moment in the reader's locale.
|
|
341
|
+
*
|
|
342
|
+
* @param {string} value An ISO 8601 stamp.
|
|
343
|
+
* @return {string} The moment, or the raw value.
|
|
344
|
+
*/
|
|
345
|
+
moment(value) {
|
|
346
|
+
if (!value) {
|
|
347
|
+
return ''
|
|
348
|
+
}
|
|
349
|
+
const parsed = new Date(value);
|
|
350
|
+
return isNaN(parsed.getTime()) ? value : parsed.toLocaleString()
|
|
351
|
+
},
|
|
352
|
+
|
|
353
|
+
async togglePin(entry) {
|
|
354
|
+
await this.patch(entry, { pinned: !entry.pinned });
|
|
355
|
+
},
|
|
356
|
+
|
|
357
|
+
async closeFollowUp(entry) {
|
|
358
|
+
await this.patch(entry, { followUp: 'done' });
|
|
359
|
+
},
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Write one change onto one entry and read the timeline back (pinning
|
|
363
|
+
* changes the order, so patching in place would look like nothing).
|
|
364
|
+
*
|
|
365
|
+
* @param {object} entry The entry.
|
|
366
|
+
* @param {object} changes The fields to write.
|
|
367
|
+
* @return {Promise<void>}
|
|
368
|
+
*/
|
|
369
|
+
async patch(entry, changes) {
|
|
370
|
+
try {
|
|
371
|
+
await axios__default.patch(`${this.timelineUrl}/${entry.id}`, changes);
|
|
372
|
+
await this.load();
|
|
373
|
+
} catch {
|
|
374
|
+
this.error = translate('nextcloud-vue', 'That change could not be saved.');
|
|
375
|
+
}
|
|
376
|
+
},
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* The configured entry actions that apply to one entry (`kinds` limits
|
|
380
|
+
* an action to entries of those kinds).
|
|
381
|
+
*
|
|
382
|
+
* @param {object} entry The entry.
|
|
383
|
+
* @return {Array<object>} The actions.
|
|
384
|
+
*/
|
|
385
|
+
actionsFor(entry) {
|
|
386
|
+
return this.entryActions.filter((action) => !Array.isArray(action.kinds) || action.kinds.includes(entry.kind || ''))
|
|
387
|
+
},
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Resolve `@objectId` and `@row.<path>` tokens in an action's props.
|
|
391
|
+
*
|
|
392
|
+
* @param {object} props The props as declared.
|
|
393
|
+
* @param {object} entry The entry.
|
|
394
|
+
* @return {object} The resolved props.
|
|
395
|
+
*/
|
|
396
|
+
resolveProps(props, entry) {
|
|
397
|
+
const out = {};
|
|
398
|
+
for (const [key, value] of Object.entries(props || {})) {
|
|
399
|
+
if (value === '@objectId') {
|
|
400
|
+
out[key] = this.objectId;
|
|
401
|
+
} else if (typeof value === 'string' && value.startsWith('@row.')) {
|
|
402
|
+
const found = readPath(entry, value.slice('@row.'.length));
|
|
403
|
+
out[key] = found === undefined || found === null ? '' : found;
|
|
404
|
+
} else {
|
|
405
|
+
out[key] = value;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
return out
|
|
409
|
+
},
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Open an entry action's modal from the app's registry. On its
|
|
413
|
+
* `doneEvent` (default `done`) the entry's open follow-up is closed when
|
|
414
|
+
* the action says so; otherwise the timeline is read again.
|
|
415
|
+
*
|
|
416
|
+
* @param {object} action The action.
|
|
417
|
+
* @param {object} entry The entry.
|
|
418
|
+
*/
|
|
419
|
+
openAction(action, entry) {
|
|
420
|
+
const registered = (this.cnRegistry || {})[action.modal];
|
|
421
|
+
const component = registered && (registered.component || registered);
|
|
422
|
+
if (!component) {
|
|
423
|
+
// eslint-disable-next-line no-console
|
|
424
|
+
console.warn(`[CnTimelineWidget] entry action "${action.id}" names modal "${action.modal}", which the registry does not hold.`);
|
|
425
|
+
return
|
|
426
|
+
}
|
|
427
|
+
const close = () => {
|
|
428
|
+
this.activeModal = null;
|
|
429
|
+
};
|
|
430
|
+
const done = async () => {
|
|
431
|
+
this.activeModal = null;
|
|
432
|
+
if (action.closesFollowUp === true && entry.followUp === 'open') {
|
|
433
|
+
await this.closeFollowUp(entry);
|
|
434
|
+
return
|
|
435
|
+
}
|
|
436
|
+
await this.load();
|
|
437
|
+
};
|
|
438
|
+
this.activeModal = {
|
|
439
|
+
component,
|
|
440
|
+
props: this.resolveProps(action.props, entry),
|
|
441
|
+
listeners: { [action.doneEvent || 'done']: done, close },
|
|
442
|
+
};
|
|
443
|
+
},
|
|
444
|
+
},
|
|
445
|
+
};
|
|
446
|
+
|
|
447
|
+
export { script as default };
|
|
448
|
+
//# sourceMappingURL=CnTimelineManage.vue2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CnTimelineManage.vue2.js","sources":["../../../../src/components/CnTimelineWidget/CnTimelineManage.vue"],"sourcesContent":["<!--\n SPDX-FileCopyrightText: 2026 Conduction B.V.\n SPDX-License-Identifier: EUPL-1.2\n\n CnTimelineManage — the `manage` mode of CnTimelineWidget: one chronological\n read of OpenRegister's timeline on an object (notes, calls, messages), newest\n first with pinned entries on top, plus what a reader who may manage it can do\n there: filter by kind and visibility, pin, close a follow-up, write a note\n (optionally from a standard text block, optionally visible outside), export\n the shown entries as CSV, and run configured entry actions such as a reply\n dialog.\n\n The list read is filtered by OpenRegister whether or not a filter is asked\n for; the response says whether the reader may manage (`canManage`), and the\n controls are drawn from that rather than guessed. A failed read is not an\n empty history.\n-->\n<template>\n\t<div class=\"cn-timeline-manage\" data-testid=\"cn-timeline-manage\">\n\t\t<div class=\"cn-timeline-manage__header\">\n\t\t\t<div class=\"cn-timeline-manage__heading\">\n\t\t\t\t<h3 class=\"cn-timeline-manage__title\">\n\t\t\t\t\t{{ titleText }}\n\t\t\t\t</h3>\n\t\t\t\t<p class=\"cn-timeline-manage__subtitle\">\n\t\t\t\t\t{{ subtitleText }}\n\t\t\t\t</p>\n\t\t\t</div>\n\t\t\t<div class=\"cn-timeline-manage__header-actions\">\n\t\t\t\t<NcButton v-if=\"canManage && composerEnabled\"\n\t\t\t\t\tdata-testid=\"cn-timeline-add-note\"\n\t\t\t\t\t@click=\"focusComposer\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<Plus :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ t('nextcloud-vue', 'Add a note') }}\n\t\t\t\t</NcButton>\n\t\t\t\t<NcButton data-testid=\"cn-timeline-export\" @click=\"exportEntries\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<Download :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ t('nextcloud-vue', 'Export') }}\n\t\t\t\t</NcButton>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<div class=\"cn-timeline-manage__chips\"\n\t\t\trole=\"group\"\n\t\t\t:aria-label=\"t('nextcloud-vue', 'Kind')\"\n\t\t\tdata-testid=\"cn-timeline-kind-filter\">\n\t\t\t<button v-for=\"chip in kindChips\"\n\t\t\t\t:key=\"chip.key\"\n\t\t\t\ttype=\"button\"\n\t\t\t\tclass=\"cn-timeline-manage__chip\"\n\t\t\t\t:class=\"{ 'cn-timeline-manage__chip--active': chip.active }\"\n\t\t\t\t:aria-pressed=\"chip.active ? 'true' : 'false'\"\n\t\t\t\t:data-testid=\"'cn-timeline-chip-' + chip.key\"\n\t\t\t\t@click=\"chooseKind(chip.id)\">\n\t\t\t\t{{ chip.label }}\n\t\t\t\t<span class=\"cn-timeline-manage__chip-count\">{{ chip.count }}</span>\n\t\t\t</button>\n\t\t</div>\n\n\t\t<div class=\"cn-timeline-manage__controls\">\n\t\t\t<NcSelect v-if=\"canManage\"\n\t\t\t\tv-model=\"visibilityFilter\"\n\t\t\t\tclass=\"cn-timeline-manage__filter\"\n\t\t\t\t:options=\"visibilityOptions\"\n\t\t\t\t:clearable=\"true\"\n\t\t\t\tlabel=\"label\"\n\t\t\t\t:inputLabel=\"t('nextcloud-vue', 'Visibility')\"\n\t\t\t\t:placeholder=\"t('nextcloud-vue', 'Internal and public')\"\n\t\t\t\tdata-testid=\"cn-timeline-visibility-filter\"\n\t\t\t\t@update:modelValue=\"load\" />\n\t\t</div>\n\n\t\t<NcLoadingIcon v-if=\"loading\" :size=\"32\" />\n\n\t\t<NcNoteCard v-else-if=\"error\" type=\"error\" data-testid=\"cn-timeline-error\">\n\t\t\t{{ error }}\n\t\t</NcNoteCard>\n\n\t\t<NcEmptyContent v-else-if=\"entries.length === 0\"\n\t\t\t:name=\"t('nextcloud-vue', 'Nothing recorded yet')\"\n\t\t\t:description=\"t('nextcloud-vue', 'Notes, calls and messages appear here in the order they happened.')\"\n\t\t\tdata-testid=\"cn-timeline-empty\" />\n\n\t\t<ul v-else class=\"cn-timeline-manage__list\" data-testid=\"cn-timeline-list\">\n\t\t\t<li v-for=\"entry in entries\"\n\t\t\t\t:key=\"entry.id\"\n\t\t\t\tclass=\"cn-timeline-manage__entry\"\n\t\t\t\t:class=\"{ 'cn-timeline-manage__entry--pinned': entry.pinned }\"\n\t\t\t\t:data-kind=\"entry.kind || 'note'\"\n\t\t\t\tdata-testid=\"cn-timeline-entry\">\n\t\t\t\t<div class=\"cn-timeline-manage__head\">\n\t\t\t\t\t<span class=\"cn-timeline-manage__kind\">{{ kindLabel(entry) }}</span>\n\t\t\t\t\t<span class=\"cn-timeline-manage__author\">{{ entry.author }}</span>\n\t\t\t\t\t<span class=\"cn-timeline-manage__moment\">{{ moment(entry.created) }}</span>\n\t\t\t\t\t<span v-if=\"entry.visibility === 'public'\"\n\t\t\t\t\t\tclass=\"cn-timeline-manage__badge\"\n\t\t\t\t\t\tdata-testid=\"cn-timeline-public\">\n\t\t\t\t\t\t{{ publicLabel }}\n\t\t\t\t\t</span>\n\t\t\t\t\t<span v-if=\"entry.followUp === 'open'\"\n\t\t\t\t\t\tclass=\"cn-timeline-manage__badge cn-timeline-manage__badge--open\"\n\t\t\t\t\t\tdata-testid=\"cn-timeline-followup-open\">\n\t\t\t\t\t\t{{ t('nextcloud-vue', 'Needs an answer') }}\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\n\t\t\t\t<p class=\"cn-timeline-manage__message\">\n\t\t\t\t\t{{ entry.message }}\n\t\t\t\t</p>\n\n\t\t\t\t<p v-if=\"entry.siblings && entry.siblings.length\"\n\t\t\t\t\tclass=\"cn-timeline-manage__siblings\"\n\t\t\t\t\tdata-testid=\"cn-timeline-siblings\">\n\t\t\t\t\t{{ n('nextcloud-vue', 'Also written on %n other record', 'Also written on %n other records', entry.siblings.length) }}\n\t\t\t\t</p>\n\n\t\t\t\t<div v-if=\"canManage\" class=\"cn-timeline-manage__actions\">\n\t\t\t\t\t<NcButton variant=\"tertiary\"\n\t\t\t\t\t\t:data-testid=\"'cn-timeline-pin-' + entry.id\"\n\t\t\t\t\t\t@click=\"togglePin(entry)\">\n\t\t\t\t\t\t{{ entry.pinned ? t('nextcloud-vue', 'Unpin') : t('nextcloud-vue', 'Pin') }}\n\t\t\t\t\t</NcButton>\n\t\t\t\t\t<NcButton v-for=\"action in actionsFor(entry)\"\n\t\t\t\t\t\t:key=\"action.id\"\n\t\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t\t:data-testid=\"'cn-timeline-action-' + action.id + '-' + entry.id\"\n\t\t\t\t\t\t@click=\"openAction(action, entry)\">\n\t\t\t\t\t\t{{ translate(action.label) }}\n\t\t\t\t\t</NcButton>\n\t\t\t\t\t<NcButton v-if=\"entry.followUp === 'open'\"\n\t\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t\t:data-testid=\"'cn-timeline-followup-' + entry.id\"\n\t\t\t\t\t\t@click=\"closeFollowUp(entry)\">\n\t\t\t\t\t\t{{ t('nextcloud-vue', 'Mark as answered') }}\n\t\t\t\t\t</NcButton>\n\t\t\t\t</div>\n\t\t\t</li>\n\t\t</ul>\n\n\t\t<p v-if=\"!loading && !error && allEntries.length > 0\"\n\t\t\tclass=\"cn-timeline-manage__count\"\n\t\t\tdata-testid=\"cn-timeline-count\">\n\t\t\t{{ t('nextcloud-vue', '{shown} of {total} events', { shown: entries.length, total: allEntries.length }) }}\n\t\t</p>\n\n\t\t<form v-if=\"canManage && composerEnabled\"\n\t\t\tref=\"composer\"\n\t\t\tclass=\"cn-timeline-manage__composer\"\n\t\t\tdata-testid=\"cn-timeline-composer\"\n\t\t\t@submit.prevent=\"submit\">\n\t\t\t<h3 class=\"cn-timeline-manage__composer-title\">\n\t\t\t\t{{ t('nextcloud-vue', 'Add a note') }}\n\t\t\t</h3>\n\t\t\t<p class=\"cn-timeline-manage__composer-hint\">\n\t\t\t\t{{ t('nextcloud-vue', 'Goes on the timeline above, internal unless you make it visible') }}\n\t\t\t</p>\n\t\t\t<NcSelect v-if=\"textBlocks.length\"\n\t\t\t\tv-model=\"chosenBlock\"\n\t\t\t\tclass=\"cn-timeline-manage__filter\"\n\t\t\t\t:options=\"blockOptions\"\n\t\t\t\t:clearable=\"true\"\n\t\t\t\tlabel=\"label\"\n\t\t\t\t:inputLabel=\"t('nextcloud-vue', 'Standard note')\"\n\t\t\t\t:placeholder=\"t('nextcloud-vue', 'Write your own')\"\n\t\t\t\tdata-testid=\"cn-timeline-block\"\n\t\t\t\t@update:modelValue=\"pickBlock\" />\n\n\t\t\t<label class=\"cn-timeline-manage__draft-label\" :for=\"draftId\">\n\t\t\t\t{{ t('nextcloud-vue', 'Write a note on this record') }}\n\t\t\t</label>\n\t\t\t<textarea :id=\"draftId\"\n\t\t\t\tv-model=\"draft\"\n\t\t\t\tclass=\"cn-timeline-manage__draft\"\n\t\t\t\t:placeholder=\"t('nextcloud-vue', 'Write a note on this record')\"\n\t\t\t\tdata-testid=\"cn-timeline-draft\" />\n\n\t\t\t<NcCheckboxRadioSwitch v-model=\"draftIsPublic\" data-testid=\"cn-timeline-draft-public\">\n\t\t\t\t{{ publicLabel }}\n\t\t\t</NcCheckboxRadioSwitch>\n\n\t\t\t<NcButton variant=\"primary\"\n\t\t\t\ttype=\"submit\"\n\t\t\t\t:disabled=\"saving || !draft.trim()\"\n\t\t\t\tdata-testid=\"cn-timeline-save\">\n\t\t\t\t{{ t('nextcloud-vue', 'Add to the timeline') }}\n\t\t\t</NcButton>\n\t\t</form>\n\n\t\t<component :is=\"activeModal.component\"\n\t\t\tv-if=\"activeModal\"\n\t\t\tv-bind=\"activeModal.props\"\n\t\t\tv-on=\"activeModal.listeners\" />\n\t</div>\n</template>\n\n<script>\nimport axios from '@nextcloud/axios'\nimport { translatePlural as n, translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcCheckboxRadioSwitch, NcEmptyContent, NcLoadingIcon, NcNoteCard, NcSelect } from '@nextcloud/vue'\nimport Download from 'vue-material-design-icons/Download.vue'\nimport Plus from 'vue-material-design-icons/Plus.vue'\nimport { prefixUrl } from '../../utils/headers.js'\n\nlet instanceCount = 0\n\n/**\n * Read a dotted path off a value.\n *\n * @param {object} value The value.\n * @param {string} path The path.\n * @return {unknown} What is there, or undefined.\n */\nfunction readPath(value, path) {\n\treturn String(path).split('.').reduce((at, key) => (at === null || at === undefined ? undefined : at[key]), value)\n}\n\nexport default {\n\tname: 'CnTimelineManage',\n\n\tcomponents: { Download, NcButton, NcCheckboxRadioSwitch, NcEmptyContent, NcLoadingIcon, NcNoteCard, NcSelect, Plus },\n\n\tinject: {\n\t\t/** The app's component registry; entry actions resolve their modal here. */\n\t\tcnRegistry: { default: () => ({}) },\n\t\t/** Consumer translation function; manifest labels are authored in English. */\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/** Register slug. */\n\t\tregister: { type: String, default: '' },\n\t\t/** Schema slug. */\n\t\tschema: { type: String, default: '' },\n\t\t/** The object's id. */\n\t\tobjectId: { type: String, default: '' },\n\t\t/** OpenRegister API base. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/**\n\t\t * The widget content: `{ title?, subtitle?, publicLabel?, exportName?,\n\t\t * composer?, textBlocks?, entryActions? }`.\n\t\t */\n\t\tcontent: { type: Object, default: () => ({}) },\n\t},\n\n\tdata() {\n\t\tinstanceCount += 1\n\t\treturn {\n\t\t\tuid: instanceCount,\n\t\t\tallEntries: [],\n\t\t\tentries: [],\n\t\t\tkinds: [],\n\t\t\tloading: false,\n\t\t\terror: '',\n\t\t\tcanManage: false,\n\t\t\tkindFilter: null,\n\t\t\tvisibilityFilter: null,\n\t\t\ttextBlocks: [],\n\t\t\tchosenBlock: null,\n\t\t\tdraft: '',\n\t\t\tdraftIsPublic: false,\n\t\t\tsaving: false,\n\t\t\tactiveModal: null,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\ttitleText() {\n\t\t\treturn this.content.title ? this.translate(this.content.title) : t('nextcloud-vue', 'History')\n\t\t},\n\n\t\tsubtitleText() {\n\t\t\treturn this.content.subtitle ? this.translate(this.content.subtitle) : t('nextcloud-vue', 'What happened, who did it and when, newest first')\n\t\t},\n\n\t\tpublicLabel() {\n\t\t\treturn this.content.publicLabel ? this.translate(this.content.publicLabel) : t('nextcloud-vue', 'Visible to the applicant')\n\t\t},\n\n\t\tcomposerEnabled() {\n\t\t\treturn this.content.composer !== false\n\t\t},\n\n\t\tdraftId() {\n\t\t\treturn `cn-timeline-draft-${this.uid}`\n\t\t},\n\n\t\t/**\n\t\t * The kind options, the plain note first. A note is an entry with NO\n\t\t * kind, so \"Note\" filters on its absence.\n\t\t *\n\t\t * @return {Array<object>} The options.\n\t\t */\n\t\tkindOptions() {\n\t\t\treturn [{ id: '', label: t('nextcloud-vue', 'Note') }].concat(this.kinds.map((kind) => ({ id: kind.slug, label: kind.title || kind.slug })))\n\t\t},\n\n\t\t/**\n\t\t * All, then every kind the object has entries of, each with its count.\n\t\t *\n\t\t * @return {Array<object>} The chips.\n\t\t */\n\t\tkindChips() {\n\t\t\tconst chosen = this.kindFilter ? (this.kindFilter.id || '') : null\n\t\t\tconst counts = new Map()\n\t\t\tfor (const entry of this.allEntries) {\n\t\t\t\tconst kind = entry.kind || ''\n\t\t\t\tcounts.set(kind, (counts.get(kind) || 0) + 1)\n\t\t\t}\n\t\t\tconst chips = [{ key: 'all', id: null, label: t('nextcloud-vue', 'All'), count: this.allEntries.length, active: chosen === null }]\n\t\t\tfor (const option of this.kindOptions) {\n\t\t\t\tconst count = counts.get(option.id) || 0\n\t\t\t\tif (count > 0) {\n\t\t\t\t\tchips.push({ key: option.id || 'note', id: option.id, label: option.label, count, active: chosen === option.id })\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn chips\n\t\t},\n\n\t\tblockOptions() {\n\t\t\treturn this.textBlocks.map((block) => ({ id: block.slug, label: block.title || block.slug }))\n\t\t},\n\n\t\tvisibilityOptions() {\n\t\t\treturn [\n\t\t\t\t{ id: 'internal', label: t('nextcloud-vue', 'Internal only') },\n\t\t\t\t{ id: 'public', label: this.publicLabel },\n\t\t\t]\n\t\t},\n\n\t\tbase() {\n\t\t\treturn this.apiBase.replace(/\\/$/, '')\n\t\t},\n\n\t\ttimelineUrl() {\n\t\t\tif (!this.objectId || !this.register || !this.schema) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn prefixUrl(`${this.base}/objects/${this.register}/${this.schema}/${this.objectId}/timeline`)\n\t\t},\n\n\t\tentryActions() {\n\t\t\treturn Array.isArray(this.content.entryActions) ? this.content.entryActions.filter((action) => action && action.id) : []\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: 'load',\n\t},\n\n\tmounted() {\n\t\tthis.loadKinds()\n\t\tif (this.content.textBlocks !== false) {\n\t\t\tthis.loadTextBlocks()\n\t\t}\n\t\tthis.load()\n\t},\n\n\tmethods: {\n\t\tt,\n\t\tn,\n\n\t\ttranslate(text) {\n\t\t\treturn text ? this.cnTranslate(text) : ''\n\t\t},\n\n\t\t/** Read the declared kinds, so the filter names them as administered. */\n\t\tasync loadKinds() {\n\t\t\ttry {\n\t\t\t\tconst response = await axios.get(prefixUrl(`${this.base}/timeline/kinds`))\n\t\t\t\tthis.kinds = response.data?.results || []\n\t\t\t} catch {\n\t\t\t\tthis.kinds = []\n\t\t\t}\n\t\t},\n\n\t\t/** Read the seeded standard notes. */\n\t\tasync loadTextBlocks() {\n\t\t\ttry {\n\t\t\t\tconst response = await axios.get(prefixUrl(`${this.base}/timeline/text-blocks`))\n\t\t\t\tthis.textBlocks = response.data?.results || []\n\t\t\t} catch {\n\t\t\t\tthis.textBlocks = []\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Note which standard note was picked. The BLOCK is sent, not its body:\n\t\t * OpenRegister fills the object's own values into it on the way in.\n\t\t *\n\t\t * @param {object|null} block The picked option.\n\t\t */\n\t\tpickBlock(block) {\n\t\t\tthis.chosenBlock = block || null\n\t\t\tif (block) {\n\t\t\t\tconst declared = this.textBlocks.find((entry) => entry.slug === block.id)\n\t\t\t\tthis.draft = declared?.title || block.label\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Write the drafted note onto this object.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync submit() {\n\t\t\tif (!this.draft.trim() || !this.timelineUrl) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.saving = true\n\t\t\tthis.error = ''\n\t\t\ttry {\n\t\t\t\tconst payload = { visibility: this.draftIsPublic ? 'public' : 'internal' }\n\t\t\t\tif (this.chosenBlock?.id) {\n\t\t\t\t\tpayload.textBlock = this.chosenBlock.id\n\t\t\t\t} else {\n\t\t\t\t\tpayload.message = this.draft\n\t\t\t\t}\n\t\t\t\tawait axios.post(this.timelineUrl, payload)\n\t\t\t\tthis.draft = ''\n\t\t\t\tthis.chosenBlock = null\n\t\t\t\tthis.draftIsPublic = false\n\t\t\t\tawait this.load()\n\t\t\t} catch {\n\t\t\t\tthis.error = t('nextcloud-vue', 'That note could not be saved.')\n\t\t\t} finally {\n\t\t\t\tthis.saving = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Read the timeline with the visibility filter, if one is set.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync load() {\n\t\t\tif (!this.timelineUrl) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.error = ''\n\t\t\ttry {\n\t\t\t\tconst params = {}\n\t\t\t\tif (this.visibilityFilter?.id) {\n\t\t\t\t\tparams.visibility = this.visibilityFilter.id\n\t\t\t\t}\n\t\t\t\tconst response = await axios.get(this.timelineUrl, { params })\n\t\t\t\tthis.canManage = response.data?.canManage === true\n\t\t\t\tthis.allEntries = response.data?.results || []\n\t\t\t\tthis.entries = this.applyKindFilter(this.allEntries)\n\t\t\t} catch {\n\t\t\t\tthis.allEntries = []\n\t\t\t\tthis.entries = []\n\t\t\t\tthis.error = t('nextcloud-vue', 'The timeline could not be read. Try again, or ask an administrator to check OpenRegister.')\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 * Show one kind, or every kind for `null`, without reading again.\n\t\t *\n\t\t * @param {string|null} id The kind slug, '' for a note, null for all.\n\t\t */\n\t\tchooseKind(id) {\n\t\t\tthis.kindFilter = id === null ? null : { id }\n\t\t\tthis.entries = this.applyKindFilter(this.allEntries)\n\t\t},\n\n\t\t/**\n\t\t * The kind filter is applied in the reading: the list endpoint does not\n\t\t * read a kind parameter, so sending one would be dropped in silence.\n\t\t *\n\t\t * @param {Array<object>} results The entries as read.\n\t\t * @return {Array<object>} The entries to show.\n\t\t */\n\t\tapplyKindFilter(results) {\n\t\t\tif (!this.kindFilter) {\n\t\t\t\treturn results\n\t\t\t}\n\t\t\tconst wanted = this.kindFilter.id || ''\n\t\t\treturn results.filter((entry) => (entry.kind || '') === wanted)\n\t\t},\n\n\t\t/**\n\t\t * The shown entries as CSV: when, kind, who, visibility and what.\n\t\t *\n\t\t * @return {string} The CSV text.\n\t\t */\n\t\tentriesCsv() {\n\t\t\tconst cell = (value) => `\"${String(value ?? '').replace(/\"/g, '\"\"')}\"`\n\t\t\tconst rows = [[t('nextcloud-vue', 'When'), t('nextcloud-vue', 'Kind'), t('nextcloud-vue', 'Who'), t('nextcloud-vue', 'Visibility'), t('nextcloud-vue', 'Message')]]\n\t\t\tfor (const entry of this.entries) {\n\t\t\t\trows.push([entry.created, this.kindLabel(entry), entry.author, entry.visibility, entry.message])\n\t\t\t}\n\t\t\treturn rows.map((row) => row.map(cell).join(',')).join('\\r\\n')\n\t\t},\n\n\t\t/** Download the shown entries as a CSV file. */\n\t\texportEntries() {\n\t\t\tconst blob = new Blob([this.entriesCsv()], { type: 'text/csv;charset=utf-8' })\n\t\t\tconst url = URL.createObjectURL(blob)\n\t\t\tconst link = document.createElement('a')\n\t\t\tlink.href = url\n\t\t\tlink.download = `${this.content.exportName || 'history'}-${this.objectId || 'record'}.csv`\n\t\t\tdocument.body.appendChild(link)\n\t\t\tlink.click()\n\t\t\tlink.remove()\n\t\t\tURL.revokeObjectURL(url)\n\t\t},\n\n\t\t/** Bring the composer into view and focus its text. */\n\t\tfocusComposer() {\n\t\t\tconst form = this.$refs.composer\n\t\t\tif (!form) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tform.scrollIntoView?.({ behavior: 'smooth', block: 'center' })\n\t\t\tform.querySelector('textarea')?.focus()\n\t\t},\n\n\t\t/**\n\t\t * The label of one entry's kind, falling back to \"Note\".\n\t\t *\n\t\t * @param {object} entry The entry.\n\t\t * @return {string} The label.\n\t\t */\n\t\tkindLabel(entry) {\n\t\t\tif (!entry.kind) {\n\t\t\t\treturn t('nextcloud-vue', 'Note')\n\t\t\t}\n\t\t\tconst declared = this.kinds.find((kind) => kind.slug === entry.kind)\n\t\t\treturn declared?.title || entry.kind\n\t\t},\n\n\t\t/**\n\t\t * One moment in the reader's locale.\n\t\t *\n\t\t * @param {string} value An ISO 8601 stamp.\n\t\t * @return {string} The moment, or the raw value.\n\t\t */\n\t\tmoment(value) {\n\t\t\tif (!value) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst parsed = new Date(value)\n\t\t\treturn isNaN(parsed.getTime()) ? value : parsed.toLocaleString()\n\t\t},\n\n\t\tasync togglePin(entry) {\n\t\t\tawait this.patch(entry, { pinned: !entry.pinned })\n\t\t},\n\n\t\tasync closeFollowUp(entry) {\n\t\t\tawait this.patch(entry, { followUp: 'done' })\n\t\t},\n\n\t\t/**\n\t\t * Write one change onto one entry and read the timeline back (pinning\n\t\t * changes the order, so patching in place would look like nothing).\n\t\t *\n\t\t * @param {object} entry The entry.\n\t\t * @param {object} changes The fields to write.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync patch(entry, changes) {\n\t\t\ttry {\n\t\t\t\tawait axios.patch(`${this.timelineUrl}/${entry.id}`, changes)\n\t\t\t\tawait this.load()\n\t\t\t} catch {\n\t\t\t\tthis.error = t('nextcloud-vue', 'That change could not be saved.')\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The configured entry actions that apply to one entry (`kinds` limits\n\t\t * an action to entries of those kinds).\n\t\t *\n\t\t * @param {object} entry The entry.\n\t\t * @return {Array<object>} The actions.\n\t\t */\n\t\tactionsFor(entry) {\n\t\t\treturn this.entryActions.filter((action) => !Array.isArray(action.kinds) || action.kinds.includes(entry.kind || ''))\n\t\t},\n\n\t\t/**\n\t\t * Resolve `@objectId` and `@row.<path>` tokens in an action's props.\n\t\t *\n\t\t * @param {object} props The props as declared.\n\t\t * @param {object} entry The entry.\n\t\t * @return {object} The resolved props.\n\t\t */\n\t\tresolveProps(props, entry) {\n\t\t\tconst out = {}\n\t\t\tfor (const [key, value] of Object.entries(props || {})) {\n\t\t\t\tif (value === '@objectId') {\n\t\t\t\t\tout[key] = this.objectId\n\t\t\t\t} else if (typeof value === 'string' && value.startsWith('@row.')) {\n\t\t\t\t\tconst found = readPath(entry, value.slice('@row.'.length))\n\t\t\t\t\tout[key] = found === undefined || found === null ? '' : found\n\t\t\t\t} else {\n\t\t\t\t\tout[key] = value\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn out\n\t\t},\n\n\t\t/**\n\t\t * Open an entry action's modal from the app's registry. On its\n\t\t * `doneEvent` (default `done`) the entry's open follow-up is closed when\n\t\t * the action says so; otherwise the timeline is read again.\n\t\t *\n\t\t * @param {object} action The action.\n\t\t * @param {object} entry The entry.\n\t\t */\n\t\topenAction(action, entry) {\n\t\t\tconst registered = (this.cnRegistry || {})[action.modal]\n\t\t\tconst component = registered && (registered.component || registered)\n\t\t\tif (!component) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn(`[CnTimelineWidget] entry action \"${action.id}\" names modal \"${action.modal}\", which the registry does not hold.`)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst close = () => {\n\t\t\t\tthis.activeModal = null\n\t\t\t}\n\t\t\tconst done = async () => {\n\t\t\t\tthis.activeModal = null\n\t\t\t\tif (action.closesFollowUp === true && entry.followUp === 'open') {\n\t\t\t\t\tawait this.closeFollowUp(entry)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tawait this.load()\n\t\t\t}\n\t\t\tthis.activeModal = {\n\t\t\t\tcomponent,\n\t\t\t\tprops: this.resolveProps(action.props, entry),\n\t\t\t\tlisteners: { [action.doneEvent || 'done']: done, close },\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-timeline-manage__header {\n\tdisplay: flex;\n\talign-items: flex-start;\n\tjustify-content: space-between;\n\tgap: 12px;\n\tmargin-block-end: 16px;\n}\n\n.cn-timeline-manage__heading {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n}\n\n.cn-timeline-manage__header-actions {\n\tdisplay: flex;\n\tgap: 8px;\n}\n\n.cn-timeline-manage__title {\n\tmargin: 0;\n\tfont-size: 17px;\n\tfont-weight: 700;\n\tline-height: 1.2;\n}\n\n.cn-timeline-manage__subtitle {\n\tmargin: 0;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 14px;\n}\n\n.cn-timeline-manage__chips {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 8px;\n\tmargin-block-end: 12px;\n}\n\n.cn-timeline-manage__chip {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 8px;\n\tbox-sizing: border-box;\n\theight: 36px;\n\tpadding: 0 12px;\n\tborder: 1px solid var(--color-border-dark);\n\tborder-radius: 18px;\n\tbackground: var(--color-main-background);\n\tcolor: var(--color-main-text);\n\tfont-size: 14px;\n\tfont-weight: 600;\n\tcursor: pointer;\n}\n\n/* The chosen kind is a filled chip with no outline. */\n.cn-timeline-manage__chip--active {\n\tborder: 0;\n\tbackground: var(--color-main-text);\n\tcolor: var(--color-main-background);\n}\n\n.cn-timeline-manage__chip-count {\n\tpadding: 1px 7px;\n\tborder-radius: 10px;\n\tbackground: var(--color-border);\n\tcolor: var(--color-main-text);\n\tfont-size: 12px;\n}\n\n/* On the filled chip the count is a lighter ink bubble with light text. */\n.cn-timeline-manage__chip--active .cn-timeline-manage__chip-count {\n\tbackground: color-mix(in srgb, var(--color-main-background) 18%, var(--color-main-text));\n\tcolor: var(--color-main-background);\n}\n\n.cn-timeline-manage__count {\n\tmargin: 12px 0 0;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-timeline-manage__composer {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 8px;\n\tmargin-block-start: 24px;\n\tpadding-block-start: 16px;\n\tborder-block-start: 1px solid var(--color-border);\n}\n\n.cn-timeline-manage__composer-title {\n\tmargin: 0;\n\tfont-size: 16px;\n\tfont-weight: bold;\n}\n\n.cn-timeline-manage__composer-hint {\n\tmargin: 0;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-timeline-manage__draft-label {\n\tfont-weight: bold;\n}\n\n.cn-timeline-manage__draft {\n\twidth: 100%;\n\tmin-height: 70px;\n}\n\n.cn-timeline-manage__controls {\n\tdisplay: flex;\n\tgap: 12px;\n\tflex-wrap: wrap;\n\tmargin-block-end: 12px;\n}\n\n.cn-timeline-manage__filter {\n\tmin-width: 200px;\n}\n\n.cn-timeline-manage__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n.cn-timeline-manage__entry {\n\tborder-block-end: 1px solid var(--color-border);\n\tpadding-block: 12px;\n}\n\n.cn-timeline-manage__entry--pinned {\n\tborder-inline-start: 3px solid var(--color-primary-element);\n\tpadding-inline-start: 8px;\n}\n\n.cn-timeline-manage__head {\n\tdisplay: flex;\n\tgap: 8px;\n\tflex-wrap: wrap;\n\talign-items: baseline;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n}\n\n.cn-timeline-manage__kind {\n\tfont-weight: bold;\n\tcolor: var(--color-main-text);\n}\n\n.cn-timeline-manage__badge {\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius);\n\tpadding: 0 6px;\n}\n\n.cn-timeline-manage__badge--open {\n\tborder-color: var(--color-warning);\n\tcolor: var(--color-warning-text);\n}\n\n.cn-timeline-manage__message {\n\tmargin-block: 4px 0;\n\twhite-space: pre-wrap;\n}\n\n.cn-timeline-manage__siblings {\n\tmargin-block: 4px 0;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n}\n\n.cn-timeline-manage__actions {\n\tdisplay: flex;\n\tgap: 8px;\n\tmargin-block-start: 4px;\n}\n</style>\n"],"names":["t","n","axios"],"mappings":"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"}
|