@conduction/nextcloud-vue 2.115.0 → 2.116.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.
Files changed (117) hide show
  1. package/dist/esm/components/CnActionButtons/CnActionButtons.vue.js +1 -1
  2. package/dist/esm/components/CnActionButtons/CnActionButtons.vue2.js +92 -0
  3. package/dist/esm/components/CnActionButtons/CnActionButtons.vue2.js.map +1 -1
  4. package/dist/esm/components/CnActionButtons/CnActionButtons.vue3.js +2 -2
  5. package/dist/esm/components/CnActionButtons/CnActionButtons.vue3.js.map +1 -1
  6. package/dist/esm/components/CnChecklistWidget/CnChecklistWidget.vue.js +9 -0
  7. package/dist/esm/components/CnChecklistWidget/CnChecklistWidget.vue.js.map +1 -0
  8. package/dist/esm/components/CnChecklistWidget/CnChecklistWidget.vue2.js +145 -0
  9. package/dist/esm/components/CnChecklistWidget/CnChecklistWidget.vue2.js.map +1 -0
  10. package/dist/esm/components/CnChecklistWidget/CnChecklistWidget.vue3.js +58 -0
  11. package/dist/esm/components/CnChecklistWidget/CnChecklistWidget.vue3.js.map +1 -0
  12. package/dist/esm/components/CnChecklistWidget/index.js +28 -0
  13. package/dist/esm/components/CnChecklistWidget/index.js.map +1 -0
  14. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue.js +1 -1
  15. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +25 -0
  16. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
  17. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +1 -1
  18. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
  19. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +376 -51
  20. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
  21. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +364 -285
  22. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
  23. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue.js +1 -1
  24. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js +11 -0
  25. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js.map +1 -1
  26. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js +6 -4
  27. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js.map +1 -1
  28. package/dist/esm/components/CnGroupedCardsWidget/CnGroupedCardsWidget.vue.js +1 -1
  29. package/dist/esm/components/CnGroupedCardsWidget/CnGroupedCardsWidget.vue2.js +48 -1
  30. package/dist/esm/components/CnGroupedCardsWidget/CnGroupedCardsWidget.vue2.js.map +1 -1
  31. package/dist/esm/components/CnGroupedCardsWidget/CnGroupedCardsWidget.vue3.js +11 -2
  32. package/dist/esm/components/CnGroupedCardsWidget/CnGroupedCardsWidget.vue3.js.map +1 -1
  33. package/dist/esm/components/CnMacrosWidget/CnMacrosWidget.vue.js +1 -1
  34. package/dist/esm/components/CnMacrosWidget/CnMacrosWidget.vue2.js +11 -3
  35. package/dist/esm/components/CnMacrosWidget/CnMacrosWidget.vue2.js.map +1 -1
  36. package/dist/esm/components/CnMacrosWidget/CnMacrosWidget.vue3.js +8 -3
  37. package/dist/esm/components/CnMacrosWidget/CnMacrosWidget.vue3.js.map +1 -1
  38. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue.js +1 -1
  39. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +55 -2
  40. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
  41. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
  42. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +1 -1
  43. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +94 -4
  44. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
  45. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js +248 -239
  46. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
  47. package/dist/esm/components/CnRecordListWidget/CnRecordNoteRows.vue.js +9 -0
  48. package/dist/esm/components/CnRecordListWidget/CnRecordNoteRows.vue.js.map +1 -0
  49. package/dist/esm/components/CnRecordListWidget/CnRecordNoteRows.vue2.js +282 -0
  50. package/dist/esm/components/CnRecordListWidget/CnRecordNoteRows.vue2.js.map +1 -0
  51. package/dist/esm/components/CnRecordListWidget/CnRecordNoteRows.vue3.js +202 -0
  52. package/dist/esm/components/CnRecordListWidget/CnRecordNoteRows.vue3.js.map +1 -0
  53. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue.js +1 -1
  54. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +10 -5
  55. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
  56. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
  57. package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js +1 -0
  58. package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js.map +1 -1
  59. package/dist/esm/composables/indexSources.js +64 -0
  60. package/dist/esm/composables/indexSources.js.map +1 -1
  61. package/dist/esm/composables/useTaskInboxStore.js +85 -0
  62. package/dist/esm/composables/useTaskInboxStore.js.map +1 -1
  63. package/dist/esm/dialogs/CnAccessPurposeDialog.vue.js +9 -0
  64. package/dist/esm/dialogs/CnAccessPurposeDialog.vue.js.map +1 -0
  65. package/dist/esm/dialogs/CnAccessPurposeDialog.vue2.js +107 -0
  66. package/dist/esm/dialogs/CnAccessPurposeDialog.vue2.js.map +1 -0
  67. package/dist/esm/dialogs/CnAccessPurposeDialog.vue3.js +110 -0
  68. package/dist/esm/dialogs/CnAccessPurposeDialog.vue3.js.map +1 -0
  69. package/dist/esm/index.js +1 -0
  70. package/dist/esm/index.js.map +1 -1
  71. package/dist/esm/l10n/en.json.js +19 -1
  72. package/dist/esm/l10n/en.json.js.map +1 -1
  73. package/dist/esm/l10n/nl.json.js +23 -1
  74. package/dist/esm/l10n/nl.json.js.map +1 -1
  75. package/dist/esm/library-style.js +1 -1
  76. package/dist/esm/nextcloud-vue.css +1054 -911
  77. package/dist/esm/utils/actionsDispatcher.js +10 -5
  78. package/dist/esm/utils/actionsDispatcher.js.map +1 -1
  79. package/dist/esm/utils/detailActionModel.js +6 -2
  80. package/dist/esm/utils/detailActionModel.js.map +1 -1
  81. package/dist/esm/utils/libraryWidgetKeys.js +1 -0
  82. package/dist/esm/utils/libraryWidgetKeys.js.map +1 -1
  83. package/dist/esm/utils/validateManifestV2.compiled.js +3 -3
  84. package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
  85. package/dist/esm/utils/widgetDispatch.js +1 -1
  86. package/dist/esm/utils/widgetDispatch.js.map +1 -1
  87. package/dist/nextcloud-vue.cjs.js +17078 -15224
  88. package/dist/nextcloud-vue.cjs.js.map +2 -2
  89. package/dist/nextcloud-vue.css +1054 -911
  90. package/l10n/en.json +19 -1
  91. package/l10n/nl.json +23 -1
  92. package/package.json +1 -1
  93. package/src/components/CnActionButtons/CnActionButtons.vue +93 -1
  94. package/src/components/CnChecklistWidget/CnChecklistWidget.vue +206 -0
  95. package/src/components/CnChecklistWidget/index.js +27 -0
  96. package/src/components/CnDashboardPage/CnDashboardPage.vue +26 -1
  97. package/src/components/CnDetailPage/CnDetailPage.md +2 -0
  98. package/src/components/CnDetailPage/CnDetailPage.vue +377 -10
  99. package/src/components/CnDetailWidgetHost/CnDetailWidgetHost.vue +15 -2
  100. package/src/components/CnGroupedCardsWidget/CnGroupedCardsWidget.vue +59 -1
  101. package/src/components/CnMacrosWidget/CnMacrosWidget.vue +16 -6
  102. package/src/components/CnObjectListWidget/CnObjectListWidget.vue +55 -2
  103. package/src/components/CnRecordListWidget/CnRecordListWidget.vue +101 -3
  104. package/src/components/CnRecordListWidget/CnRecordNoteRows.vue +508 -0
  105. package/src/components/CnTabsWidget/CnTabsWidget.vue +10 -5
  106. package/src/components/CnWidgetGrid/registerDashboardWidgets.js +1 -0
  107. package/src/components/index.js +1 -0
  108. package/src/composables/indexSources.js +64 -0
  109. package/src/composables/useTaskInboxStore.js +85 -0
  110. package/src/dialogs/CnAccessPurposeDialog.vue +183 -0
  111. package/src/index.js +1 -0
  112. package/src/schemas/app-manifest-v2.schema.json +49 -3
  113. package/src/utils/actionsDispatcher.js +10 -5
  114. package/src/utils/detailActionModel.js +6 -2
  115. package/src/utils/libraryWidgetKeys.js +1 -0
  116. package/src/utils/validateManifestV2.compiled.js +3 -3
  117. package/src/utils/widgetDispatch.js +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"useTaskInboxStore.js","sources":["../../../src/composables/useTaskInboxStore.js"],"sourcesContent":["/**\n * SPDX-License-Identifier: EUPL-1.2\n * SPDX-FileCopyrightText: 2026 Conduction B.V. <info@conduction.nl>\n */\n\nimport axios from '@nextcloud/axios'\nimport { generateUrl } from '@nextcloud/router'\nimport { defineStore } from 'pinia'\n\n/**\n * The OpenRegister inbox read behind the `tasks` entity source.\n *\n * One endpoint for the whole fleet (ADR-098): every Conduction app runs its\n * human tasks on OpenRegister's one task store, so \"what is waiting for me\"\n * has a single answer per viewer and this store can be app-agnostic.\n *\n * @type {string}\n */\nexport const FLOW_TASKS_URL = '/apps/openregister/api/flow-tasks'\n\n/**\n * The query parameters the inbox read accepts, and the ONLY ones this store\n * forwards. The list is an allowlist on purpose: the endpoint decides whose\n * inbox it answers from the session, and no config key may widen that. A\n * `uid` or `assignee` smuggled into the loader config is dropped here, so\n * \"the source resolves the CURRENT user's inbox\" is enforced structurally\n * rather than by convention.\n *\n * @type {string[]}\n */\n// `isTerminal` is in the list because the SERVER has always accepted it\n// (`TaskController`: \"'true'|'false' to restrict on terminality\") and only\n// this allowlist withheld it. Without it an app cannot express \"closed\" or\n// \"my open work\" as a scope tab: dossiq's task lenses are\n// All / Mine / Unclaimed / Closed / Overdue, and two of those are exactly\n// this filter. Boolean-ish, like `overdue`, so it is stringified on the way\n// out.\n// `kind` is in the list for the same reason `isTerminal` is: the server\n// accepts it (`TaskController`: \"Restrict to one kind of work\") and only this\n// allowlist would withhold it. A kind is what sort of work a task is, as the\n// creating app named it, so it is the one filter that lets a Tasks page say\n// \"the reminders\" without the engine learning what a reminder is. It widens\n// nothing: it narrows within the inbox the session already decides.\nconst ALLOWED_PARAMS = ['scope', 'state', 'isTerminal', 'priority', 'kind', 'overdue', 'dueAfter', 'dueBefore', 'objectUuid', 'sort', 'limit', 'offset']\n\n/**\n * The flat body `POST /api/flow-tasks` takes for a task on a record.\n *\n * Only the task entity's own keys are ever sent, and never `requester` or\n * `state`: OpenRegister pins the requester to the caller and refuses a\n * terminal state. A user task carries `assignee`; a group task carries\n * `performerType: \"group\"` with `candidateGroups` (a pool until someone claims\n * it), because the server defaults `performerType` to `user`.\n *\n * @param {object} data The task to create.\n * @param {string} data.title Required title.\n * @param {string} [data.description] Optional description.\n * @param {string} [data.dueAt] Optional due date, ISO 8601.\n * @param {{objectUuid: string, registerId: string, schemaId: string}} data.anchor The record the task hangs on.\n * @param {{kind: ('user'|'group'), id: string}|null} [data.assignee] A user, or a group as a pool.\n * @return {object} The request body.\n * @spec openspec/changes/tasks-tab-flow-task-source/tasks.md#task-1\n */\nexport function buildFlowTaskBody(data) {\n\tconst body = { title: String(data.title || '').trim() }\n\tif (data.description) {\n\t\tbody.description = data.description\n\t}\n\tif (data.dueAt) {\n\t\tbody.dueAt = data.dueAt\n\t}\n\tconst anchor = data.anchor || {}\n\tbody.objectUuid = anchor.objectUuid\n\tbody.registerId = anchor.registerId\n\tbody.schemaId = anchor.schemaId\n\tif (data.assignee && data.assignee.id) {\n\t\tif (data.assignee.kind === 'group') {\n\t\t\tbody.performerType = 'group'\n\t\t\tbody.candidateGroups = [data.assignee.id]\n\t\t} else {\n\t\t\tbody.assignee = data.assignee.id\n\t\t}\n\t}\n\treturn body\n}\n\n/**\n * Read the server's message off a failed axios call.\n *\n * @param {object} error The axios error.\n * @return {string} The message, or ''.\n */\nfunction serverMessage(error) {\n\tconst data = error && error.response && error.response.data\n\tif (typeof data === 'string') {\n\t\treturn data\n\t}\n\treturn (data && (data.error || data.message)) || (error && error.message) || ''\n}\n\n/**\n * Internal Pinia store for the `tasks` index source (cn-tasks-entity-source).\n *\n * Deliberately NOT a public export: the public surface is the manifest line\n * (`entitySource: \"tasks\"`), and the adapter in `indexSources.js` is its only\n * consumer. Keeping the store internal leaves the HTTP contract in one file\n * should the endpoint move.\n *\n * @spec openspec/changes/cn-tasks-entity-source/specs/cn-tasks-entity-source/spec.md\n */\nexport const useTaskInboxStore = defineStore('cnTaskInbox', {\n\tstate: () => ({\n\t\t/** @type {Array<object>} The inbox rows as the endpoint returned them. */\n\t\ttasks: [],\n\t\t/** @type {number} The datastore total, independent of the page size. */\n\t\ttotal: 0,\n\t\t/** @type {boolean} Whether a load is in flight. */\n\t\tloading: false,\n\t\t/** @type {string|null} The last load failure, for the console trail. */\n\t\terror: null,\n\t\t/** @type {Object<string, object>} Single tasks read for a detail page, keyed on their uuid. */\n\t\trecords: {},\n\t\t/** @type {Object<string, number|null>} The HTTP status of a failed single read, keyed on the uuid. */\n\t\trecordErrors: {},\n\t}),\n\n\tactions: {\n\t\t/**\n\t\t * Read one task into `records`, for a `type: \"detail\"` page on the\n\t\t * `tasks` source. A refusal (403) or a missing task (404) leaves no\n\t\t * record and keeps the status in `recordErrors`, so the page can tell\n\t\t * \"not found\" from \"still loading\". The engine decides what the caller\n\t\t * may read; nothing here widens that.\n\t\t *\n\t\t * @param {string} uuid The task uuid.\n\t\t * @return {Promise<object|null>} The task, or null when it could not be read.\n\t\t * @spec openspec/changes/tasks-record-source/specs/tasks-record-source/spec.md#requirement-the-tasks-source-reads-one-task\n\t\t */\n\t\tasync fetchRecord(uuid) {\n\t\t\tconst key = String(uuid || '').trim()\n\t\t\tif (key === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst response = await axios.get(generateUrl(`${FLOW_TASKS_URL}/${encodeURIComponent(key)}`))\n\t\t\t\tconst data = response.data\n\t\t\t\tconst task = data && typeof data === 'object' && data.results && !Array.isArray(data.results) ? data.results : data\n\t\t\t\tconst { [key]: dropped, ...errors } = this.recordErrors\n\t\t\t\tthis.recordErrors = errors\n\t\t\t\tif (!task || typeof task !== 'object' || Array.isArray(task)) {\n\t\t\t\t\treturn null\n\t\t\t\t}\n\t\t\t\tthis.records = { ...this.records, [key]: task }\n\t\t\t\treturn task\n\t\t\t} catch (error) {\n\t\t\t\tconst { [key]: dropped, ...records } = this.records\n\t\t\t\tthis.records = records\n\t\t\t\tthis.recordErrors = { ...this.recordErrors, [key]: error?.response?.status ?? null }\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error(`[useTaskInboxStore] Loading task \"${key}\" failed`, error)\n\t\t\t\treturn null\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Read one inbox page WITHOUT touching the store's state, so a surface\n\t\t * that lists a different slice (the Tasks tab of one record) cannot\n\t\t * overwrite what an inbox page on the same screen shows.\n\t\t *\n\t\t * @param {object} [config] Loader config, as for `load`.\n\t\t * @return {Promise<{results: Array<object>, total: number}>} The rows and the total.\n\t\t * @spec openspec/changes/tasks-tab-flow-task-source/tasks.md#task-1\n\t\t */\n\t\tasync fetchFor(config = {}) {\n\t\t\tconst params = { scope: 'assigned', sort: '-dueAt' }\n\t\t\tfor (const key of ALLOWED_PARAMS) {\n\t\t\t\tconst value = config ? config[key] : undefined\n\t\t\t\tif (value === undefined || value === null || value === '') {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tparams[key] = (key === 'overdue' || key === 'isTerminal') ? String(value) : value\n\t\t\t}\n\t\t\tconst response = await axios.get(generateUrl(FLOW_TASKS_URL), { params })\n\t\t\tconst results = response.data?.results || []\n\t\t\treturn { results, total: Number(response.data?.total ?? results.length) || 0 }\n\t\t},\n\n\t\t/**\n\t\t * Create a flow task. A refusal is returned, not thrown, with the\n\t\t * server's message and the HTTP status (404: the creator may not read\n\t\t * the record).\n\t\t *\n\t\t * @param {object} data See `buildFlowTaskBody`.\n\t\t * @return {Promise<{ok: boolean, status: (number|null), task: (object|null), message: string}>} The outcome.\n\t\t * @spec openspec/changes/tasks-tab-flow-task-source/tasks.md#task-1\n\t\t */\n\t\tasync createTask(data) {\n\t\t\ttry {\n\t\t\t\tconst response = await axios.post(generateUrl(FLOW_TASKS_URL), buildFlowTaskBody(data))\n\t\t\t\treturn { ok: true, status: response.status || 201, task: response.data?.task || response.data || null, message: '' }\n\t\t\t} catch (error) {\n\t\t\t\treturn { ok: false, status: error?.response?.status ?? null, task: null, message: serverMessage(error) }\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Run one lifecycle verb on a task (`claim`, `unclaim`, `reassign`,\n\t\t * `complete`, `cancel`). A refusal is returned, not thrown, with the\n\t\t * server's message, so the row can show it and stay as it was.\n\t\t *\n\t\t * @param {string} uuid The task uuid.\n\t\t * @param {string} verb The verb.\n\t\t * @param {object} [body] Optional body (for `reassign`: `{ assignee }`).\n\t\t * @return {Promise<{ok: boolean, status: (number|null), task: (object|null), message: string}>} The outcome.\n\t\t * @spec openspec/changes/tasks-tab-flow-task-source/tasks.md#task-1\n\t\t */\n\t\tasync runVerb(uuid, verb, body = {}) {\n\t\t\ttry {\n\t\t\t\tconst response = await axios.post(generateUrl(`${FLOW_TASKS_URL}/${encodeURIComponent(uuid)}/${encodeURIComponent(verb)}`), body || {})\n\t\t\t\treturn { ok: true, status: response.status || 200, task: response.data?.task || response.data || null, message: '' }\n\t\t\t} catch (error) {\n\t\t\t\treturn { ok: false, status: error?.response?.status ?? null, task: null, message: serverMessage(error) }\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Load one inbox page.\n\t\t *\n\t\t * Defaults are the inbox's resting shape: the viewer's ASSIGNED tasks,\n\t\t * most urgent due date first (`-dueAt`). Every key is optional and\n\t\t * only allowlisted keys are forwarded; filtering, sorting and paging\n\t\t * are the server's, never applied over a returned page.\n\t\t *\n\t\t * @param {object} [config] Loader config from the page (`sourceConfig`\n\t\t * merged with the active quick-filter tab): `scope`, `state`,\n\t\t * `priority`, `kind`, `overdue`, `objectUuid`, `sort`, `limit`,\n\t\t * `offset`.\n\t\t *\n\t\t * @return {Promise<void>} Resolves when the rows are in the store.\n\t\t *\n\t\t * @spec openspec/changes/cn-tasks-entity-source/specs/cn-tasks-entity-source/spec.md\n\t\t */\n\t\tasync load(config = {}) {\n\t\t\tconst params = { scope: 'assigned', sort: '-dueAt' }\n\t\t\tfor (const key of ALLOWED_PARAMS) {\n\t\t\t\tconst value = config ? config[key] : undefined\n\t\t\t\tif (value === undefined || value === null || value === '') {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\t// The endpoint reads `overdue` as a boolean-ish string; a quick\n\t\t\t\t// filter authors it as `true` for legibility.\n\t\t\t\tparams[key] = (key === 'overdue' || key === 'isTerminal') ? String(value) : value\n\t\t\t}\n\n\t\t\tthis.loading = true\n\t\t\tthis.error = null\n\t\t\ttry {\n\t\t\t\tconst response = await axios.get(generateUrl(FLOW_TASKS_URL), { params })\n\t\t\t\tthis.tasks = response.data?.results || []\n\t\t\t\tthis.total = Number(response.data?.total ?? this.tasks.length) || 0\n\t\t\t} catch (error) {\n\t\t\t\t// Surfaced, not swallowed: an empty inbox with no trace of why is\n\t\t\t\t// indistinguishable from a healthy quiet one.\n\t\t\t\tthis.error = error?.message || String(error)\n\t\t\t\tthis.tasks = []\n\t\t\t\tthis.total = 0\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[useTaskInboxStore] Loading the task inbox failed', error)\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\t},\n})\n"],"names":["axios"],"mappings":"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"}
1
+ {"version":3,"file":"useTaskInboxStore.js","sources":["../../../src/composables/useTaskInboxStore.js"],"sourcesContent":["/**\n * SPDX-License-Identifier: EUPL-1.2\n * SPDX-FileCopyrightText: 2026 Conduction B.V. <info@conduction.nl>\n */\n\nimport axios from '@nextcloud/axios'\nimport { generateUrl } from '@nextcloud/router'\nimport { defineStore } from 'pinia'\n\n/**\n * The OpenRegister inbox read behind the `tasks` entity source.\n *\n * One endpoint for the whole fleet (ADR-098): every Conduction app runs its\n * human tasks on OpenRegister's one task store, so \"what is waiting for me\"\n * has a single answer per viewer and this store can be app-agnostic.\n *\n * @type {string}\n */\nexport const FLOW_TASKS_URL = '/apps/openregister/api/flow-tasks'\n\n/**\n * The query parameters the inbox read accepts, and the ONLY ones this store\n * forwards. The list is an allowlist on purpose: the endpoint decides whose\n * inbox it answers from the session, and no config key may widen that. A\n * `uid` or `assignee` smuggled into the loader config is dropped here, so\n * \"the source resolves the CURRENT user's inbox\" is enforced structurally\n * rather than by convention.\n *\n * @type {string[]}\n */\n// `isTerminal` is in the list because the SERVER has always accepted it\n// (`TaskController`: \"'true'|'false' to restrict on terminality\") and only\n// this allowlist withheld it. Without it an app cannot express \"closed\" or\n// \"my open work\" as a scope tab: dossiq's task lenses are\n// All / Mine / Unclaimed / Closed / Overdue, and two of those are exactly\n// this filter. Boolean-ish, like `overdue`, so it is stringified on the way\n// out.\n// `kind` is in the list for the same reason `isTerminal` is: the server\n// accepts it (`TaskController`: \"Restrict to one kind of work\") and only this\n// allowlist would withhold it. A kind is what sort of work a task is, as the\n// creating app named it, so it is the one filter that lets a Tasks page say\n// \"the reminders\" without the engine learning what a reminder is. It widens\n// nothing: it narrows within the inbox the session already decides.\nconst ALLOWED_PARAMS = ['scope', 'state', 'isTerminal', 'priority', 'kind', 'overdue', 'dueAfter', 'dueBefore', 'objectUuid', 'sort', 'limit', 'offset']\n\n/**\n * The flat body `POST /api/flow-tasks` takes for a task on a record.\n *\n * Only the task entity's own keys are ever sent, and never `requester` or\n * `state`: OpenRegister pins the requester to the caller and refuses a\n * terminal state. A user task carries `assignee`; a group task carries\n * `performerType: \"group\"` with `candidateGroups` (a pool until someone claims\n * it), because the server defaults `performerType` to `user`.\n *\n * @param {object} data The task to create.\n * @param {string} data.title Required title.\n * @param {string} [data.description] Optional description.\n * @param {string} [data.dueAt] Optional due date, ISO 8601.\n * @param {{objectUuid: string, registerId: string, schemaId: string}} data.anchor The record the task hangs on.\n * @param {{kind: ('user'|'group'), id: string}|null} [data.assignee] A user, or a group as a pool.\n * @return {object} The request body.\n * @spec openspec/changes/tasks-tab-flow-task-source/tasks.md#task-1\n */\nexport function buildFlowTaskBody(data) {\n\tconst body = { title: String(data.title || '').trim() }\n\tif (data.description) {\n\t\tbody.description = data.description\n\t}\n\tif (data.dueAt) {\n\t\tbody.dueAt = data.dueAt\n\t}\n\tconst anchor = data.anchor || {}\n\tbody.objectUuid = anchor.objectUuid\n\tbody.registerId = anchor.registerId\n\tbody.schemaId = anchor.schemaId\n\tif (data.assignee && data.assignee.id) {\n\t\tif (data.assignee.kind === 'group') {\n\t\t\tbody.performerType = 'group'\n\t\t\tbody.candidateGroups = [data.assignee.id]\n\t\t} else {\n\t\t\tbody.assignee = data.assignee.id\n\t\t}\n\t}\n\treturn body\n}\n\n/**\n * Read the server's message off a failed axios call.\n *\n * @param {object} error The axios error.\n * @return {string} The message, or ''.\n */\nfunction serverMessage(error) {\n\tconst data = error && error.response && error.response.data\n\tif (typeof data === 'string') {\n\t\treturn data\n\t}\n\treturn (data && (data.error || data.message)) || (error && error.message) || ''\n}\n\n/**\n * Internal Pinia store for the `tasks` index source (cn-tasks-entity-source).\n *\n * Deliberately NOT a public export: the public surface is the manifest line\n * (`entitySource: \"tasks\"`), and the adapter in `indexSources.js` is its only\n * consumer. Keeping the store internal leaves the HTTP contract in one file\n * should the endpoint move.\n *\n * @spec openspec/changes/cn-tasks-entity-source/specs/cn-tasks-entity-source/spec.md\n */\nexport const useTaskInboxStore = defineStore('cnTaskInbox', {\n\tstate: () => ({\n\t\t/** @type {Array<object>} The inbox rows as the endpoint returned them. */\n\t\ttasks: [],\n\t\t/** @type {number} The datastore total, independent of the page size. */\n\t\ttotal: 0,\n\t\t/** @type {boolean} Whether a load is in flight. */\n\t\tloading: false,\n\t\t/** @type {string|null} The last load failure, for the console trail. */\n\t\terror: null,\n\t\t/** @type {Object<string, object>} Single tasks read for a detail page, keyed on their uuid. */\n\t\trecords: {},\n\t\t/** @type {Object<string, number|null>} The HTTP status of a failed single read, keyed on the uuid. */\n\t\trecordErrors: {},\n\t}),\n\n\tactions: {\n\t\t/**\n\t\t * Read one task into `records`, for a `type: \"detail\"` page on the\n\t\t * `tasks` source. A refusal (403) or a missing task (404) leaves no\n\t\t * record and keeps the status in `recordErrors`, so the page can tell\n\t\t * \"not found\" from \"still loading\". The engine decides what the caller\n\t\t * may read; nothing here widens that.\n\t\t *\n\t\t * @param {string} uuid The task uuid.\n\t\t * @return {Promise<object|null>} The task, or null when it could not be read.\n\t\t * @spec openspec/changes/tasks-record-source/specs/tasks-record-source/spec.md#requirement-the-tasks-source-reads-one-task\n\t\t */\n\t\tasync fetchRecord(uuid) {\n\t\t\tconst key = String(uuid || '').trim()\n\t\t\tif (key === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst response = await axios.get(generateUrl(`${FLOW_TASKS_URL}/${encodeURIComponent(key)}`))\n\t\t\t\tconst data = response.data\n\t\t\t\tconst task = data && typeof data === 'object' && data.results && !Array.isArray(data.results) ? data.results : data\n\t\t\t\tconst { [key]: dropped, ...errors } = this.recordErrors\n\t\t\t\tthis.recordErrors = errors\n\t\t\t\tif (!task || typeof task !== 'object' || Array.isArray(task)) {\n\t\t\t\t\treturn null\n\t\t\t\t}\n\t\t\t\tthis.records = { ...this.records, [key]: task }\n\t\t\t\treturn task\n\t\t\t} catch (error) {\n\t\t\t\tconst { [key]: dropped, ...records } = this.records\n\t\t\t\tthis.records = records\n\t\t\t\tthis.recordErrors = { ...this.recordErrors, [key]: error?.response?.status ?? null }\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error(`[useTaskInboxStore] Loading task \"${key}\" failed`, error)\n\t\t\t\treturn null\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Read one inbox page WITHOUT touching the store's state, so a surface\n\t\t * that lists a different slice (the Tasks tab of one record) cannot\n\t\t * overwrite what an inbox page on the same screen shows.\n\t\t *\n\t\t * @param {object} [config] Loader config, as for `load`.\n\t\t * @return {Promise<{results: Array<object>, total: number}>} The rows and the total.\n\t\t * @spec openspec/changes/tasks-tab-flow-task-source/tasks.md#task-1\n\t\t */\n\t\tasync fetchFor(config = {}) {\n\t\t\tconst params = { scope: 'assigned', sort: '-dueAt' }\n\t\t\tfor (const key of ALLOWED_PARAMS) {\n\t\t\t\tconst value = config ? config[key] : undefined\n\t\t\t\tif (value === undefined || value === null || value === '') {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tparams[key] = (key === 'overdue' || key === 'isTerminal') ? String(value) : value\n\t\t\t}\n\t\t\tconst response = await axios.get(generateUrl(FLOW_TASKS_URL), { params })\n\t\t\tconst results = response.data?.results || []\n\t\t\treturn { results, total: Number(response.data?.total ?? results.length) || 0 }\n\t\t},\n\n\t\t/**\n\t\t * Create a flow task. A refusal is returned, not thrown, with the\n\t\t * server's message and the HTTP status (404: the creator may not read\n\t\t * the record).\n\t\t *\n\t\t * @param {object} data See `buildFlowTaskBody`.\n\t\t * @return {Promise<{ok: boolean, status: (number|null), task: (object|null), message: string}>} The outcome.\n\t\t * @spec openspec/changes/tasks-tab-flow-task-source/tasks.md#task-1\n\t\t */\n\t\tasync createTask(data) {\n\t\t\ttry {\n\t\t\t\tconst response = await axios.post(generateUrl(FLOW_TASKS_URL), buildFlowTaskBody(data))\n\t\t\t\treturn { ok: true, status: response.status || 201, task: response.data?.task || response.data || null, message: '' }\n\t\t\t} catch (error) {\n\t\t\t\treturn { ok: false, status: error?.response?.status ?? null, task: null, message: serverMessage(error) }\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Run one lifecycle verb on a task (`claim`, `unclaim`, `reassign`,\n\t\t * `complete`, `cancel`). A refusal is returned, not thrown, with the\n\t\t * server's message, so the row can show it and stay as it was.\n\t\t *\n\t\t * @param {string} uuid The task uuid.\n\t\t * @param {string} verb The verb.\n\t\t * @param {object} [body] Optional body (for `reassign`: `{ assignee }`).\n\t\t * @return {Promise<{ok: boolean, status: (number|null), task: (object|null), message: string}>} The outcome.\n\t\t * @spec openspec/changes/tasks-tab-flow-task-source/tasks.md#task-1\n\t\t */\n\t\tasync runVerb(uuid, verb, body = {}) {\n\t\t\ttry {\n\t\t\t\tconst response = await axios.post(generateUrl(`${FLOW_TASKS_URL}/${encodeURIComponent(uuid)}/${encodeURIComponent(verb)}`), body || {})\n\t\t\t\treturn { ok: true, status: response.status || 200, task: response.data?.task || response.data || null, message: '' }\n\t\t\t} catch (error) {\n\t\t\t\treturn { ok: false, status: error?.response?.status ?? null, task: null, message: serverMessage(error) }\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Run one lifecycle verb on a task read for a detail page, and keep\n\t\t * that record in step with the engine's answer.\n\t\t *\n\t\t * `url` replaces the engine's own verb route for an app that puts a\n\t\t * step of its own in front of the engine (dossiq completes a task\n\t\t * through its own endpoint, which checks the case type's form first).\n\t\t * `{id}` in it is the task uuid. A refusal is returned with the\n\t\t * server's message as-is and leaves the record as it was.\n\t\t *\n\t\t * @param {string} uuid The task uuid.\n\t\t * @param {string} verb The verb.\n\t\t * @param {{url?: string}} [options] An app route to post the verb to instead.\n\t\t * @return {Promise<{ok: boolean, status: (number|null), record: (object|null), message: string}>} The outcome.\n\t\t * @spec openspec/changes/record-source-verbs/specs/record-source-verbs/spec.md#requirement-a-record-source-offers-header-verbs\n\t\t */\n\t\tasync runRecordVerb(uuid, verb, options = {}) {\n\t\t\tconst key = String(uuid || '').trim()\n\t\t\tconst name = String(verb || '').trim()\n\t\t\tif (key === '' || name === '') {\n\t\t\t\treturn { ok: false, status: null, record: null, message: '' }\n\t\t\t}\n\t\t\tconst route = typeof options.url === 'string' && options.url !== ''\n\t\t\t\t? options.url.replace('{id}', encodeURIComponent(key))\n\t\t\t\t: `${FLOW_TASKS_URL}/${encodeURIComponent(key)}/${encodeURIComponent(name)}`\n\t\t\ttry {\n\t\t\t\tconst response = await axios.post(generateUrl(route), {})\n\t\t\t\treturn { ok: true, status: response.status || 200, record: await this.keepRecord(key, response.data), message: '' }\n\t\t\t} catch (error) {\n\t\t\t\treturn { ok: false, status: error?.response?.status ?? null, record: null, message: serverMessage(error) }\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Tick or untick one checklist item on a task read for a detail page\n\t\t * (`PATCH /flow-tasks/{uuid}/checklist/{itemId}?checked=`). The engine\n\t\t * answers with the whole task, which replaces the record, so a refused\n\t\t * tick leaves the item as it was on screen.\n\t\t *\n\t\t * @param {string} uuid The task uuid.\n\t\t * @param {string} itemId The checklist item id.\n\t\t * @param {boolean} checked The new state.\n\t\t * @return {Promise<{ok: boolean, status: (number|null), record: (object|null), message: string}>} The outcome.\n\t\t * @spec openspec/changes/record-checklist-widget/specs/record-checklist-widget/spec.md#requirement-a-checklist-widget-ticks-items-through-the-record-source\n\t\t */\n\t\tasync checkRecordItem(uuid, itemId, checked) {\n\t\t\tconst key = String(uuid || '').trim()\n\t\t\tconst item = String(itemId || '').trim()\n\t\t\tif (key === '' || item === '') {\n\t\t\t\treturn { ok: false, status: null, record: null, message: '' }\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst response = await axios.patch(\n\t\t\t\t\tgenerateUrl(`${FLOW_TASKS_URL}/${encodeURIComponent(key)}/checklist/${encodeURIComponent(item)}`),\n\t\t\t\t\tnull,\n\t\t\t\t\t{ params: { checked: checked === true ? 'true' : 'false' } },\n\t\t\t\t)\n\t\t\t\treturn { ok: true, status: response.status || 200, record: await this.keepRecord(key, response.data), message: '' }\n\t\t\t} catch (error) {\n\t\t\t\treturn { ok: false, status: error?.response?.status ?? null, record: null, message: serverMessage(error) }\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Store the task a write answered with as the detail record. An answer\n\t\t * that carries no task (an app route that returns only a status) is\n\t\t * followed by a fresh read, so the page never shows the state from\n\t\t * before the write.\n\t\t *\n\t\t * @param {string} key The task uuid.\n\t\t * @param {unknown} data The response body.\n\t\t * @return {Promise<object|null>} The task now held.\n\t\t */\n\t\tasync keepRecord(key, data) {\n\t\t\tconst body = data && typeof data === 'object' ? data : null\n\t\t\tconst task = body && (body.results || body.task) && typeof (body.results || body.task) === 'object' && !Array.isArray(body.results || body.task)\n\t\t\t\t? (body.results || body.task)\n\t\t\t\t: body\n\t\t\tif (task && typeof task === 'object' && !Array.isArray(task) && String(task.uuid || '') === key) {\n\t\t\t\tthis.records = { ...this.records, [key]: task }\n\t\t\t\treturn task\n\t\t\t}\n\t\t\treturn this.fetchRecord(key)\n\t\t},\n\n\t\t/**\n\t\t * Load one inbox page.\n\t\t *\n\t\t * Defaults are the inbox's resting shape: the viewer's ASSIGNED tasks,\n\t\t * most urgent due date first (`-dueAt`). Every key is optional and\n\t\t * only allowlisted keys are forwarded; filtering, sorting and paging\n\t\t * are the server's, never applied over a returned page.\n\t\t *\n\t\t * @param {object} [config] Loader config from the page (`sourceConfig`\n\t\t * merged with the active quick-filter tab): `scope`, `state`,\n\t\t * `priority`, `kind`, `overdue`, `objectUuid`, `sort`, `limit`,\n\t\t * `offset`.\n\t\t *\n\t\t * @return {Promise<void>} Resolves when the rows are in the store.\n\t\t *\n\t\t * @spec openspec/changes/cn-tasks-entity-source/specs/cn-tasks-entity-source/spec.md\n\t\t */\n\t\tasync load(config = {}) {\n\t\t\tconst params = { scope: 'assigned', sort: '-dueAt' }\n\t\t\tfor (const key of ALLOWED_PARAMS) {\n\t\t\t\tconst value = config ? config[key] : undefined\n\t\t\t\tif (value === undefined || value === null || value === '') {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\t// The endpoint reads `overdue` as a boolean-ish string; a quick\n\t\t\t\t// filter authors it as `true` for legibility.\n\t\t\t\tparams[key] = (key === 'overdue' || key === 'isTerminal') ? String(value) : value\n\t\t\t}\n\n\t\t\tthis.loading = true\n\t\t\tthis.error = null\n\t\t\ttry {\n\t\t\t\tconst response = await axios.get(generateUrl(FLOW_TASKS_URL), { params })\n\t\t\t\tthis.tasks = response.data?.results || []\n\t\t\t\tthis.total = Number(response.data?.total ?? this.tasks.length) || 0\n\t\t\t} catch (error) {\n\t\t\t\t// Surfaced, not swallowed: an empty inbox with no trace of why is\n\t\t\t\t// indistinguishable from a healthy quiet one.\n\t\t\t\tthis.error = error?.message || String(error)\n\t\t\t\tthis.tasks = []\n\t\t\t\tthis.total = 0\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[useTaskInboxStore] Loading the task inbox failed', error)\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\t},\n})\n"],"names":["axios"],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import script from './CnAccessPurposeDialog.vue2.js';
2
+ import { render } from './CnAccessPurposeDialog.vue3.js';
3
+
4
+ script.render = render;
5
+ script.__scopeId = "data-v-7fa35363";
6
+ const __sfc_main = script;
7
+
8
+ export { __sfc_main as default };
9
+ //# sourceMappingURL=CnAccessPurposeDialog.vue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CnAccessPurposeDialog.vue.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;"}
@@ -0,0 +1,107 @@
1
+ import { translate } from '@nextcloud/l10n';
2
+ import { NcButton, NcCheckboxRadioSwitch, NcLoadingIcon, NcNoteCard, NcTextArea } from '@nextcloud/vue';
3
+ import __sfc_main from '../components/CnDialog/CnDialog.vue.js';
4
+
5
+ /** The value of the "Other" choice, which asks for a written purpose. */
6
+ const OTHER = 'other';
7
+
8
+ /**
9
+ * CnAccessPurposeDialog — asks why the reader opens a record before the page
10
+ * shows it (detail page `accessPurpose`). A short list of purposes plus
11
+ * "Other", which needs a written purpose. Emits the choice; the page records
12
+ * it and decides whether to open.
13
+ *
14
+ * @spec openspec/changes/detail-access-purpose/specs/detail-access-purpose/spec.md#requirement-a-detail-page-can-ask-for-a-purpose-before-it-opens
15
+ */
16
+ var script = {
17
+ name: 'CnAccessPurposeDialog',
18
+
19
+ components: { CnDialog: __sfc_main, NcButton, NcCheckboxRadioSwitch, NcLoadingIcon, NcNoteCard, NcTextArea },
20
+
21
+ props: {
22
+ /** The dialog's title; a default question when empty. */
23
+ title: {
24
+ type: String,
25
+ default: '',
26
+ },
27
+
28
+ /** The sentence under the title; a default when empty. */
29
+ description: {
30
+ type: String,
31
+ default: '',
32
+ },
33
+
34
+ /**
35
+ * The purposes offered, already translated. "Other" is added at the end.
36
+ *
37
+ * @type {Array<{value: string, label: string}>}
38
+ */
39
+ options: {
40
+ type: Array,
41
+ default: () => [],
42
+ },
43
+
44
+ /** Whether the purpose is being recorded. */
45
+ loading: {
46
+ type: Boolean,
47
+ default: false,
48
+ },
49
+
50
+ /** Why the last attempt was refused, shown in the dialog. */
51
+ error: {
52
+ type: String,
53
+ default: '',
54
+ },
55
+ },
56
+
57
+ emits: [
58
+ /**
59
+ * The reader chose a purpose.
60
+ *
61
+ * @type {{purpose: string, note: string}}
62
+ */
63
+ 'submit',
64
+ /** The reader closed the dialog without a purpose. */
65
+ 'cancel',
66
+ ],
67
+
68
+ data() {
69
+ return { purpose: '', note: '', OTHER }
70
+ },
71
+
72
+ computed: {
73
+ /** @return {Array<{value: string, label: string}>} The offered purposes and "Other". */
74
+ choices() {
75
+ const own = (Array.isArray(this.options) ? this.options : [])
76
+ .filter((option) => option && typeof option.value === 'string' && option.value !== '' && option.value !== OTHER);
77
+ return [...own, { value: OTHER, label: translate('nextcloud-vue', 'Other') }]
78
+ },
79
+
80
+ /** @return {boolean} Whether a purpose is chosen and, for "Other", written. */
81
+ complete() {
82
+ if (this.purpose === '') {
83
+ return false
84
+ }
85
+ return this.purpose !== OTHER || this.note.trim() !== ''
86
+ },
87
+ },
88
+
89
+ methods: {
90
+ t: translate,
91
+
92
+ /**
93
+ * Emit the chosen purpose; the written note only goes with "Other".
94
+ *
95
+ * @return {void}
96
+ */
97
+ submit() {
98
+ if (!this.complete) {
99
+ return
100
+ }
101
+ this.$emit('submit', { purpose: this.purpose, note: this.purpose === OTHER ? this.note.trim() : '' });
102
+ },
103
+ },
104
+ };
105
+
106
+ export { script as default };
107
+ //# sourceMappingURL=CnAccessPurposeDialog.vue2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CnAccessPurposeDialog.vue2.js","sources":["../../../src/dialogs/CnAccessPurposeDialog.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<CnDialog\n\t\t:name=\"title || t('nextcloud-vue', 'Why are you opening this?')\"\n\t\tdefaultWidth=\"confirm\"\n\t\tsize=\"small\"\n\t\t:noClose=\"loading\"\n\t\tdata-testid=\"cn-access-purpose-dialog\"\n\t\t@closing=\"$emit('cancel')\">\n\t\t<p class=\"cn-access-purpose__sentence\">\n\t\t\t{{ description || t('nextcloud-vue', 'This record holds special categories of personal data. Your purpose is recorded with your name and the time.') }}\n\t\t</p>\n\t\t<fieldset class=\"cn-access-purpose__choices\">\n\t\t\t<legend class=\"cn-access-purpose__legend\">\n\t\t\t\t{{ t('nextcloud-vue', 'Purpose') }}\n\t\t\t</legend>\n\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\tv-for=\"option in choices\"\n\t\t\t\t:key=\"option.value\"\n\t\t\t\tv-model=\"purpose\"\n\t\t\t\ttype=\"radio\"\n\t\t\t\tname=\"cn-access-purpose\"\n\t\t\t\t:value=\"option.value\"\n\t\t\t\t:disabled=\"loading\"\n\t\t\t\t:data-testid=\"`cn-access-purpose-option-${option.value}`\">\n\t\t\t\t{{ option.label }}\n\t\t\t</NcCheckboxRadioSwitch>\n\t\t</fieldset>\n\t\t<NcTextArea\n\t\t\tv-if=\"purpose === OTHER\"\n\t\t\tv-model=\"note\"\n\t\t\t:label=\"t('nextcloud-vue', 'Describe your purpose')\"\n\t\t\t:maxlength=\"500\"\n\t\t\t:disabled=\"loading\"\n\t\t\tdata-testid=\"cn-access-purpose-note\" />\n\t\t<NcNoteCard v-if=\"error\" type=\"error\" data-testid=\"cn-access-purpose-error\">\n\t\t\t{{ error }}\n\t\t</NcNoteCard>\n\n\t\t<template #actions>\n\t\t\t<NcButton :disabled=\"loading\" data-testid=\"cn-access-purpose-cancel\" @click=\"$emit('cancel')\">\n\t\t\t\t{{ t('nextcloud-vue', 'Cancel') }}\n\t\t\t</NcButton>\n\t\t\t<NcButton\n\t\t\t\tvariant=\"primary\"\n\t\t\t\t:disabled=\"!complete || loading\"\n\t\t\t\tdata-testid=\"cn-access-purpose-submit\"\n\t\t\t\t@click=\"submit\">\n\t\t\t\t<template v-if=\"loading\" #icon>\n\t\t\t\t\t<NcLoadingIcon :size=\"20\" :name=\"t('nextcloud-vue', 'Loading …')\" />\n\t\t\t\t</template>\n\t\t\t\t{{ t('nextcloud-vue', 'Open') }}\n\t\t\t</NcButton>\n\t\t</template>\n\t</CnDialog>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcCheckboxRadioSwitch, NcLoadingIcon, NcNoteCard, NcTextArea } from '@nextcloud/vue'\nimport CnDialog from '../components/CnDialog/CnDialog.vue'\n\n/** The value of the \"Other\" choice, which asks for a written purpose. */\nconst OTHER = 'other'\n\n/**\n * CnAccessPurposeDialog — asks why the reader opens a record before the page\n * shows it (detail page `accessPurpose`). A short list of purposes plus\n * \"Other\", which needs a written purpose. Emits the choice; the page records\n * it and decides whether to open.\n *\n * @spec openspec/changes/detail-access-purpose/specs/detail-access-purpose/spec.md#requirement-a-detail-page-can-ask-for-a-purpose-before-it-opens\n */\nexport default {\n\tname: 'CnAccessPurposeDialog',\n\n\tcomponents: { CnDialog, NcButton, NcCheckboxRadioSwitch, NcLoadingIcon, NcNoteCard, NcTextArea },\n\n\tprops: {\n\t\t/** The dialog's title; a default question when empty. */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** The sentence under the title; a default when empty. */\n\t\tdescription: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * The purposes offered, already translated. \"Other\" is added at the end.\n\t\t *\n\t\t * @type {Array<{value: string, label: string}>}\n\t\t */\n\t\toptions: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** Whether the purpose is being recorded. */\n\t\tloading: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Why the last attempt was refused, shown in the dialog. */\n\t\terror: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\temits: [\n\t\t/**\n\t\t * The reader chose a purpose.\n\t\t *\n\t\t * @type {{purpose: string, note: string}}\n\t\t */\n\t\t'submit',\n\t\t/** The reader closed the dialog without a purpose. */\n\t\t'cancel',\n\t],\n\n\tdata() {\n\t\treturn { purpose: '', note: '', OTHER }\n\t},\n\n\tcomputed: {\n\t\t/** @return {Array<{value: string, label: string}>} The offered purposes and \"Other\". */\n\t\tchoices() {\n\t\t\tconst own = (Array.isArray(this.options) ? this.options : [])\n\t\t\t\t.filter((option) => option && typeof option.value === 'string' && option.value !== '' && option.value !== OTHER)\n\t\t\treturn [...own, { value: OTHER, label: t('nextcloud-vue', 'Other') }]\n\t\t},\n\n\t\t/** @return {boolean} Whether a purpose is chosen and, for \"Other\", written. */\n\t\tcomplete() {\n\t\t\tif (this.purpose === '') {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\treturn this.purpose !== OTHER || this.note.trim() !== ''\n\t\t},\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\t/**\n\t\t * Emit the chosen purpose; the written note only goes with \"Other\".\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tsubmit() {\n\t\t\tif (!this.complete) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.$emit('submit', { purpose: this.purpose, note: this.purpose === OTHER ? this.note.trim() : '' })\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-access-purpose__sentence {\n\tmargin: 0 0 12px;\n}\n\n.cn-access-purpose__choices {\n\tmargin: 0 0 12px;\n\tpadding: 0;\n\tborder: 0;\n}\n\n.cn-access-purpose__legend {\n\tmargin-bottom: 4px;\n\tfont-weight: 600;\n}\n</style>\n"],"names":["CnDialog","t"],"mappings":";;;;AAiEA;AACA,MAAM,KAAI,GAAI,QAAM;;AAEpB;AACC;;AAEA;;AAEA;AACA;;AAED,aAAe;CACd,IAAI,EAAE,uBAAuB;;AAE7B,CAAA,UAAU,EAAE,YAAEA,UAAQ,EAAE,QAAQ,EAAE,qBAAqB,EAAE,aAAa,EAAE,UAAU,EAAE,YAAY;;AAEhG,CAAA,KAAK,EAAE;;AAEN,EAAA,KAAK,EAAE;GACN,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,EAAE;GACX;;;EAGD,WAAW,EAAE;GACZ,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,EAAE;GACX;;AAED;;AAEC;AACA;;AAED,EAAA,OAAO,EAAE;GACR,IAAI,EAAE,KAAK;AACX,GAAA,OAAO,EAAE,MAAM,EAAE;GACjB;;AAED;AACA,EAAA,OAAO,EAAE;GACR,IAAI,EAAE,OAAO;GACb,OAAO,EAAE,KAAK;GACd;;;AAGD,EAAA,KAAK,EAAE;GACN,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,EAAE;GACX;EACD;;AAED,CAAA,KAAK,EAAE;AACN;;AAEC;AACA;;AAED,EAAA,QAAQ;AACR;AACA,EAAA,QAAQ;EACR;;AAED,CAAA,IAAI,GAAG;AACN,EAAA,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,KAAM,EAAA;EACtC;;AAED,CAAA,QAAQ,EAAE;AACT;AACA,EAAA,OAAO,GAAG;GACT,MAAM,GAAE,GAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAE,GAAE,IAAI,CAAC,OAAM,GAAI,EAAE;KAC1D,MAAM,CAAC,CAAC,MAAM,KAAK,UAAU,OAAO,MAAM,CAAC,KAAI,KAAM,YAAY,MAAM,CAAC,KAAI,KAAM,EAAG,IAAG,MAAM,CAAC,UAAU,KAAK,EAAA;GAChH,OAAO,CAAC,GAAG,GAAG,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAEC,SAAC,CAAC,eAAe,EAAE,OAAO,CAAA,EAAG,CAAA;GACpE;;AAED;EACA,QAAQ,GAAG;AACV,GAAA,IAAI,IAAI,CAAC,OAAQ,KAAI,EAAE,EAAE;IACxB,OAAO,KAAI;AACZ,IAAA;GACA,OAAO,IAAI,CAAC,YAAY,KAAM,IAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAG,KAAI,EAAC;GACvD;EACD;;AAED,CAAA,OAAO,EAAE;KACRA,SAAC;;AAED;;AAEC;;;AAGD,EAAA,MAAM,GAAG;AACR,GAAA,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;IACnB,MAAK;AACN,IAAA;AACA,GAAA,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,OAAQ,KAAI,KAAM,GAAE,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,EAAA;GACpG;EACD;AACF;;;;"}
@@ -0,0 +1,110 @@
1
+ import { resolveComponent, openBlock, createBlock, withCtx, createVNode, createTextVNode, toDisplayString, createSlots, createElementVNode, createElementBlock, Fragment, renderList, createCommentVNode } from 'vue';
2
+
3
+ const _hoisted_1 = { class: "cn-access-purpose__sentence" };
4
+ const _hoisted_2 = { class: "cn-access-purpose__choices" };
5
+ const _hoisted_3 = { class: "cn-access-purpose__legend" };
6
+
7
+ function render(_ctx, _cache, $props, $setup, $data, $options) {
8
+ const _component_NcCheckboxRadioSwitch = resolveComponent("NcCheckboxRadioSwitch");
9
+ const _component_NcTextArea = resolveComponent("NcTextArea");
10
+ const _component_NcNoteCard = resolveComponent("NcNoteCard");
11
+ const _component_NcButton = resolveComponent("NcButton");
12
+ const _component_NcLoadingIcon = resolveComponent("NcLoadingIcon");
13
+ const _component_CnDialog = resolveComponent("CnDialog");
14
+
15
+ return (openBlock(), createBlock(_component_CnDialog, {
16
+ name: $props.title || $options.t('nextcloud-vue', 'Why are you opening this?'),
17
+ defaultWidth: "confirm",
18
+ size: "small",
19
+ noClose: $props.loading,
20
+ "data-testid": "cn-access-purpose-dialog",
21
+ onClosing: _cache[3] || (_cache[3] = $event => (_ctx.$emit('cancel')))
22
+ }, {
23
+ actions: withCtx(() => [
24
+ createVNode(_component_NcButton, {
25
+ disabled: $props.loading,
26
+ "data-testid": "cn-access-purpose-cancel",
27
+ onClick: _cache[2] || (_cache[2] = $event => (_ctx.$emit('cancel')))
28
+ }, {
29
+ default: withCtx(() => [
30
+ createTextVNode(toDisplayString($options.t('nextcloud-vue', 'Cancel')), 1 /* TEXT */)
31
+ ]),
32
+ _: 1 /* STABLE */
33
+ }, 8 /* PROPS */, ["disabled"]),
34
+ createVNode(_component_NcButton, {
35
+ variant: "primary",
36
+ disabled: !$options.complete || $props.loading,
37
+ "data-testid": "cn-access-purpose-submit",
38
+ onClick: $options.submit
39
+ }, createSlots({
40
+ default: withCtx(() => [
41
+ createTextVNode(" " + toDisplayString($options.t('nextcloud-vue', 'Open')), 1 /* TEXT */)
42
+ ]),
43
+ _: 2 /* DYNAMIC */
44
+ }, [
45
+ ($props.loading)
46
+ ? {
47
+ name: "icon",
48
+ fn: withCtx(() => [
49
+ createVNode(_component_NcLoadingIcon, {
50
+ size: 20,
51
+ name: $options.t('nextcloud-vue', 'Loading …')
52
+ }, null, 8 /* PROPS */, ["name"])
53
+ ]),
54
+ key: "0"
55
+ }
56
+ : undefined
57
+ ]), 1032 /* PROPS, DYNAMIC_SLOTS */, ["disabled", "onClick"])
58
+ ]),
59
+ default: withCtx(() => [
60
+ createElementVNode("p", _hoisted_1, toDisplayString($props.description || $options.t('nextcloud-vue', 'This record holds special categories of personal data. Your purpose is recorded with your name and the time.')), 1 /* TEXT */),
61
+ createElementVNode("fieldset", _hoisted_2, [
62
+ createElementVNode("legend", _hoisted_3, toDisplayString($options.t('nextcloud-vue', 'Purpose')), 1 /* TEXT */),
63
+ (openBlock(true), createElementBlock(Fragment, null, renderList($options.choices, (option) => {
64
+ return (openBlock(), createBlock(_component_NcCheckboxRadioSwitch, {
65
+ key: option.value,
66
+ modelValue: $data.purpose,
67
+ "onUpdate:modelValue": _cache[0] || (_cache[0] = $event => (($data.purpose) = $event)),
68
+ type: "radio",
69
+ name: "cn-access-purpose",
70
+ value: option.value,
71
+ disabled: $props.loading,
72
+ "data-testid": `cn-access-purpose-option-${option.value}`
73
+ }, {
74
+ default: withCtx(() => [
75
+ createTextVNode(toDisplayString(option.label), 1 /* TEXT */)
76
+ ]),
77
+ _: 2 /* DYNAMIC */
78
+ }, 1032 /* PROPS, DYNAMIC_SLOTS */, ["modelValue", "value", "disabled", "data-testid"]))
79
+ }), 128 /* KEYED_FRAGMENT */))
80
+ ]),
81
+ ($data.purpose === $data.OTHER)
82
+ ? (openBlock(), createBlock(_component_NcTextArea, {
83
+ key: 0,
84
+ modelValue: $data.note,
85
+ "onUpdate:modelValue": _cache[1] || (_cache[1] = $event => (($data.note) = $event)),
86
+ label: $options.t('nextcloud-vue', 'Describe your purpose'),
87
+ maxlength: 500,
88
+ disabled: $props.loading,
89
+ "data-testid": "cn-access-purpose-note"
90
+ }, null, 8 /* PROPS */, ["modelValue", "label", "disabled"]))
91
+ : createCommentVNode("v-if", true),
92
+ ($props.error)
93
+ ? (openBlock(), createBlock(_component_NcNoteCard, {
94
+ key: 1,
95
+ type: "error",
96
+ "data-testid": "cn-access-purpose-error"
97
+ }, {
98
+ default: withCtx(() => [
99
+ createTextVNode(toDisplayString($props.error), 1 /* TEXT */)
100
+ ]),
101
+ _: 1 /* STABLE */
102
+ }))
103
+ : createCommentVNode("v-if", true)
104
+ ]),
105
+ _: 1 /* STABLE */
106
+ }, 8 /* PROPS */, ["name", "noClose"]))
107
+ }
108
+
109
+ export { render };
110
+ //# sourceMappingURL=CnAccessPurposeDialog.vue3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CnAccessPurposeDialog.vue3.js","sources":["../../../src/dialogs/CnAccessPurposeDialog.vue?vue&type=template&id=7fa35363&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<CnDialog\n\t\t:name=\"title || t('nextcloud-vue', 'Why are you opening this?')\"\n\t\tdefaultWidth=\"confirm\"\n\t\tsize=\"small\"\n\t\t:noClose=\"loading\"\n\t\tdata-testid=\"cn-access-purpose-dialog\"\n\t\t@closing=\"$emit('cancel')\">\n\t\t<p class=\"cn-access-purpose__sentence\">\n\t\t\t{{ description || t('nextcloud-vue', 'This record holds special categories of personal data. Your purpose is recorded with your name and the time.') }}\n\t\t</p>\n\t\t<fieldset class=\"cn-access-purpose__choices\">\n\t\t\t<legend class=\"cn-access-purpose__legend\">\n\t\t\t\t{{ t('nextcloud-vue', 'Purpose') }}\n\t\t\t</legend>\n\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\tv-for=\"option in choices\"\n\t\t\t\t:key=\"option.value\"\n\t\t\t\tv-model=\"purpose\"\n\t\t\t\ttype=\"radio\"\n\t\t\t\tname=\"cn-access-purpose\"\n\t\t\t\t:value=\"option.value\"\n\t\t\t\t:disabled=\"loading\"\n\t\t\t\t:data-testid=\"`cn-access-purpose-option-${option.value}`\">\n\t\t\t\t{{ option.label }}\n\t\t\t</NcCheckboxRadioSwitch>\n\t\t</fieldset>\n\t\t<NcTextArea\n\t\t\tv-if=\"purpose === OTHER\"\n\t\t\tv-model=\"note\"\n\t\t\t:label=\"t('nextcloud-vue', 'Describe your purpose')\"\n\t\t\t:maxlength=\"500\"\n\t\t\t:disabled=\"loading\"\n\t\t\tdata-testid=\"cn-access-purpose-note\" />\n\t\t<NcNoteCard v-if=\"error\" type=\"error\" data-testid=\"cn-access-purpose-error\">\n\t\t\t{{ error }}\n\t\t</NcNoteCard>\n\n\t\t<template #actions>\n\t\t\t<NcButton :disabled=\"loading\" data-testid=\"cn-access-purpose-cancel\" @click=\"$emit('cancel')\">\n\t\t\t\t{{ t('nextcloud-vue', 'Cancel') }}\n\t\t\t</NcButton>\n\t\t\t<NcButton\n\t\t\t\tvariant=\"primary\"\n\t\t\t\t:disabled=\"!complete || loading\"\n\t\t\t\tdata-testid=\"cn-access-purpose-submit\"\n\t\t\t\t@click=\"submit\">\n\t\t\t\t<template v-if=\"loading\" #icon>\n\t\t\t\t\t<NcLoadingIcon :size=\"20\" :name=\"t('nextcloud-vue', 'Loading …')\" />\n\t\t\t\t</template>\n\t\t\t\t{{ t('nextcloud-vue', 'Open') }}\n\t\t\t</NcButton>\n\t\t</template>\n\t</CnDialog>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcCheckboxRadioSwitch, NcLoadingIcon, NcNoteCard, NcTextArea } from '@nextcloud/vue'\nimport CnDialog from '../components/CnDialog/CnDialog.vue'\n\n/** The value of the \"Other\" choice, which asks for a written purpose. */\nconst OTHER = 'other'\n\n/**\n * CnAccessPurposeDialog — asks why the reader opens a record before the page\n * shows it (detail page `accessPurpose`). A short list of purposes plus\n * \"Other\", which needs a written purpose. Emits the choice; the page records\n * it and decides whether to open.\n *\n * @spec openspec/changes/detail-access-purpose/specs/detail-access-purpose/spec.md#requirement-a-detail-page-can-ask-for-a-purpose-before-it-opens\n */\nexport default {\n\tname: 'CnAccessPurposeDialog',\n\n\tcomponents: { CnDialog, NcButton, NcCheckboxRadioSwitch, NcLoadingIcon, NcNoteCard, NcTextArea },\n\n\tprops: {\n\t\t/** The dialog's title; a default question when empty. */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** The sentence under the title; a default when empty. */\n\t\tdescription: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * The purposes offered, already translated. \"Other\" is added at the end.\n\t\t *\n\t\t * @type {Array<{value: string, label: string}>}\n\t\t */\n\t\toptions: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** Whether the purpose is being recorded. */\n\t\tloading: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Why the last attempt was refused, shown in the dialog. */\n\t\terror: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\temits: [\n\t\t/**\n\t\t * The reader chose a purpose.\n\t\t *\n\t\t * @type {{purpose: string, note: string}}\n\t\t */\n\t\t'submit',\n\t\t/** The reader closed the dialog without a purpose. */\n\t\t'cancel',\n\t],\n\n\tdata() {\n\t\treturn { purpose: '', note: '', OTHER }\n\t},\n\n\tcomputed: {\n\t\t/** @return {Array<{value: string, label: string}>} The offered purposes and \"Other\". */\n\t\tchoices() {\n\t\t\tconst own = (Array.isArray(this.options) ? this.options : [])\n\t\t\t\t.filter((option) => option && typeof option.value === 'string' && option.value !== '' && option.value !== OTHER)\n\t\t\treturn [...own, { value: OTHER, label: t('nextcloud-vue', 'Other') }]\n\t\t},\n\n\t\t/** @return {boolean} Whether a purpose is chosen and, for \"Other\", written. */\n\t\tcomplete() {\n\t\t\tif (this.purpose === '') {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\treturn this.purpose !== OTHER || this.note.trim() !== ''\n\t\t},\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\t/**\n\t\t * Emit the chosen purpose; the written note only goes with \"Other\".\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tsubmit() {\n\t\t\tif (!this.complete) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.$emit('submit', { purpose: this.purpose, note: this.purpose === OTHER ? this.note.trim() : '' })\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-access-purpose__sentence {\n\tmargin: 0 0 12px;\n}\n\n.cn-access-purpose__choices {\n\tmargin: 0 0 12px;\n\tpadding: 0;\n\tborder: 0;\n}\n\n.cn-access-purpose__legend {\n\tmargin-bottom: 4px;\n\tfont-weight: 600;\n}\n</style>\n"],"names":["_createBlock","_createVNode","_createTextVNode","_createElementVNode","_toDisplayString","_Fragment","_renderList"],"mappings":"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"}
package/dist/esm/index.js CHANGED
@@ -84,6 +84,7 @@ export { default as CnChartWidget } from './components/CnChartWidget/CnChartWidg
84
84
  export { default as CnChartWidgetForm } from './components/CnChartWidgetForm/CnChartWidgetForm.vue.js';
85
85
  export { default as CnChatPage } from './components/CnChatPage/CnChatPage.vue.js';
86
86
  export { default as CnChecklistRunWidget } from './components/CnChecklistRunWidget/CnChecklistRunWidget.vue.js';
87
+ export { default as CnChecklistWidget } from './components/CnChecklistWidget/CnChecklistWidget.vue.js';
87
88
  export { default as CnChildRecordsField } from './components/CnChildRecordsField/CnChildRecordsField.vue.js';
88
89
  export { default as CnChipsFieldWidget } from './components/CnChipsFieldWidget/CnChipsFieldWidget.vue.js';
89
90
  export { default as CnChoiceCards } from './components/CnChoiceCards/CnChoiceCards.vue.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -1931,7 +1931,25 @@ var translations = {
1931
1931
  no: "no",
1932
1932
  "Recompute nomination": "Recompute nomination",
1933
1933
  Recompute: "Recompute",
1934
- "Task deadline": "Deadline"
1934
+ "Task deadline": "Deadline",
1935
+ "The note could not be recorded. It is kept here; try again.": "The note could not be recorded. It is kept here; try again.",
1936
+ "This field is not available here.": "This field is not available here.",
1937
+ "filled in, not recorded yet": "filled in, not recorded yet",
1938
+ "Why are you opening this?": "Why are you opening this?",
1939
+ "This record holds special categories of personal data. Your purpose is recorded with your name and the time.": "This record holds special categories of personal data. Your purpose is recorded with your name and the time.",
1940
+ Purpose: "Purpose",
1941
+ "Describe your purpose": "Describe your purpose",
1942
+ "State a purpose to open this": "State a purpose to open this",
1943
+ "This record holds special categories of personal data. It opens once your purpose is recorded.": "This record holds special categories of personal data. It opens once your purpose is recorded.",
1944
+ "State a purpose": "State a purpose",
1945
+ "This page cannot record a purpose, so the record stays closed.": "This page cannot record a purpose, so the record stays closed.",
1946
+ "Your purpose could not be recorded, so the record stays closed.": "Your purpose could not be recorded, so the record stays closed.",
1947
+ "Hand back": "Hand back",
1948
+ "Pick up": "Pick up",
1949
+ "Task completed": "Task completed",
1950
+ "This could not be done. Try again.": "This could not be done. Try again.",
1951
+ "{done} of {total} done": "{done} of {total} done",
1952
+ "Nothing to check off": "Nothing to check off"
1935
1953
  };
1936
1954
  var plurals = {
1937
1955
  "{count} member": [
@@ -1 +1 @@
1
- {"version":3,"file":"en.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"en.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -2148,7 +2148,25 @@ var translations = {
2148
2148
  "Last run: {name}, {date}": "Laatst uitgevoerd: {name}, {date}",
2149
2149
  "This record has no macros": "Er zijn geen macro's voor dit item",
2150
2150
  "Running …": "Bezig …",
2151
- Execute: "Uitvoeren"
2151
+ Execute: "Uitvoeren",
2152
+ "The note could not be recorded. It is kept here; try again.": "De notitie kon niet worden vastgelegd. Ze blijft hier staan; probeer het opnieuw.",
2153
+ "This field is not available here.": "Dit veld is hier niet beschikbaar.",
2154
+ "filled in, not recorded yet": "ingevuld, nog niet vastgelegd",
2155
+ "Why are you opening this?": "Waarom open je dit?",
2156
+ "This record holds special categories of personal data. Your purpose is recorded with your name and the time.": "Hierin staan bijzondere persoonsgegevens. Je doel wordt vastgelegd met je naam en het tijdstip.",
2157
+ Purpose: "Doel",
2158
+ "Describe your purpose": "Beschrijf je doel",
2159
+ "State a purpose to open this": "Geef een doel op om dit te openen",
2160
+ "This record holds special categories of personal data. It opens once your purpose is recorded.": "Hierin staan bijzondere persoonsgegevens. Het opent zodra je doel is vastgelegd.",
2161
+ "State a purpose": "Doel opgeven",
2162
+ "This page cannot record a purpose, so the record stays closed.": "Deze pagina kan geen doel vastleggen, dus het blijft gesloten.",
2163
+ "Your purpose could not be recorded, so the record stays closed.": "Je doel kon niet worden vastgelegd, dus het blijft gesloten.",
2164
+ "Hand back": "Teruggeven",
2165
+ "Pick up": "Oppakken",
2166
+ "Task completed": "Taak afgerond",
2167
+ "This could not be done. Try again.": "Dit lukte niet. Probeer het opnieuw.",
2168
+ "{done} of {total} done": "{done} van {total} klaar",
2169
+ "Nothing to check off": "Niets af te vinken"
2152
2170
  };
2153
2171
  var plurals = {
2154
2172
  "{count} member": [
@@ -2278,6 +2296,10 @@ var plurals = {
2278
2296
  "%n passage found. Review each one.": [
2279
2297
  "%n passage gevonden. Beoordeel elke passage.",
2280
2298
  "%n passages gevonden. Beoordeel elke passage."
2299
+ ],
2300
+ "{count} change: {list}": [
2301
+ "{count} wijziging: {list}",
2302
+ "{count} wijzigingen: {list}"
2281
2303
  ]
2282
2304
  };
2283
2305
  var nl = {
@@ -1 +1 @@
1
- {"version":3,"file":"nl.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"nl.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}