@conduction/nextcloud-vue 2.74.0 → 2.76.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 (126) hide show
  1. package/dist/esm/components/CnAppNav/CnAppNav.vue2.js +19 -14
  2. package/dist/esm/components/CnAppNav/CnAppNav.vue2.js.map +1 -1
  3. package/dist/esm/components/CnAppNav/CnAppNav.vue3.js +2 -2
  4. package/dist/esm/components/CnAppNav/CnAppNav.vue3.js.map +1 -1
  5. package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js +77 -26
  6. package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js.map +1 -1
  7. package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js +22 -14
  8. package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js.map +1 -1
  9. package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue2.js +23 -4
  10. package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue2.js.map +1 -1
  11. package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue3.js.map +1 -1
  12. package/dist/esm/components/CnBrandBar/CnBrandBar.vue.js +9 -0
  13. package/dist/esm/components/CnBrandBar/CnBrandBar.vue.js.map +1 -0
  14. package/dist/esm/components/CnBrandBar/CnBrandBar.vue2.js +107 -0
  15. package/dist/esm/components/CnBrandBar/CnBrandBar.vue2.js.map +1 -0
  16. package/dist/esm/components/CnBrandBar/CnBrandBar.vue3.js +79 -0
  17. package/dist/esm/components/CnBrandBar/CnBrandBar.vue3.js.map +1 -0
  18. package/dist/esm/components/CnCardGrid/CnCardGrid.vue2.js +6 -0
  19. package/dist/esm/components/CnCardGrid/CnCardGrid.vue2.js.map +1 -1
  20. package/dist/esm/components/CnCardGrid/CnCardGrid.vue3.js +3 -2
  21. package/dist/esm/components/CnCardGrid/CnCardGrid.vue3.js.map +1 -1
  22. package/dist/esm/components/CnCredentials/CnCredentials.vue2.js +11 -10
  23. package/dist/esm/components/CnCredentials/CnCredentials.vue2.js.map +1 -1
  24. package/dist/esm/components/CnCredentials/CnCredentials.vue3.js.map +1 -1
  25. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +8 -5
  26. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
  27. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
  28. package/dist/esm/components/CnEnvironmentBanner/CnEnvironmentBanner.vue2.js +4 -1
  29. package/dist/esm/components/CnEnvironmentBanner/CnEnvironmentBanner.vue2.js.map +1 -1
  30. package/dist/esm/components/CnEnvironmentBanner/CnEnvironmentBanner.vue3.js.map +1 -1
  31. package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js +7 -0
  32. package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js.map +1 -1
  33. package/dist/esm/components/CnFormDialog/CnFormDialog.vue3.js +14 -7
  34. package/dist/esm/components/CnFormDialog/CnFormDialog.vue3.js.map +1 -1
  35. package/dist/esm/components/CnFormPage/CnFormPage.vue2.js +32 -0
  36. package/dist/esm/components/CnFormPage/CnFormPage.vue2.js.map +1 -1
  37. package/dist/esm/components/CnFormPage/CnFormPage.vue3.js +6 -3
  38. package/dist/esm/components/CnFormPage/CnFormPage.vue3.js.map +1 -1
  39. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +144 -6
  40. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  41. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +14 -13
  42. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  43. package/dist/esm/components/CnIndexPage/selfModeActions.js +90 -14
  44. package/dist/esm/components/CnIndexPage/selfModeActions.js.map +1 -1
  45. package/dist/esm/components/CnIndexPage/useSelfFetchList.js +15 -3
  46. package/dist/esm/components/CnIndexPage/useSelfFetchList.js.map +1 -1
  47. package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js +26 -0
  48. package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js.map +1 -1
  49. package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js +26 -9
  50. package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js.map +1 -1
  51. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +19 -3
  52. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
  53. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
  54. package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue2.js +18 -2
  55. package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue2.js.map +1 -1
  56. package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue3.js +2 -2
  57. package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue3.js.map +1 -1
  58. package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue2.js +153 -38
  59. package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue2.js.map +1 -1
  60. package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue3.js +74 -56
  61. package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue3.js.map +1 -1
  62. package/dist/esm/components/CnStatsBlock/CnStatsBlock.vue2.js +16 -0
  63. package/dist/esm/components/CnStatsBlock/CnStatsBlock.vue2.js.map +1 -1
  64. package/dist/esm/components/CnStatsBlock/CnStatsBlock.vue3.js +2 -2
  65. package/dist/esm/components/CnStatsBlock/CnStatsBlock.vue3.js.map +1 -1
  66. package/dist/esm/composables/useObjectLock.js +41 -10
  67. package/dist/esm/composables/useObjectLock.js.map +1 -1
  68. package/dist/esm/directives/cnSelectAria.js +55 -0
  69. package/dist/esm/directives/cnSelectAria.js.map +1 -0
  70. package/dist/esm/index.js +1 -0
  71. package/dist/esm/index.js.map +1 -1
  72. package/dist/esm/l10n/en.json.js +7 -1
  73. package/dist/esm/l10n/en.json.js.map +1 -1
  74. package/dist/esm/l10n/nl.json.js +8 -2
  75. package/dist/esm/l10n/nl.json.js.map +1 -1
  76. package/dist/esm/nextcloud-vue.css +154 -2
  77. package/dist/esm/store/useObjectStore.js +37 -9
  78. package/dist/esm/store/useObjectStore.js.map +1 -1
  79. package/dist/esm/utils/cnFetch.js +17 -2
  80. package/dist/esm/utils/cnFetch.js.map +1 -1
  81. package/dist/esm/utils/objectSignals.js +44 -0
  82. package/dist/esm/utils/objectSignals.js.map +1 -0
  83. package/dist/esm/utils/resolveBrand.js +38 -0
  84. package/dist/esm/utils/resolveBrand.js.map +1 -0
  85. package/dist/esm/utils/validateManifestV2.compiled.js +2 -2
  86. package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
  87. package/dist/nextcloud-vue.cjs.js +9640 -8649
  88. package/dist/nextcloud-vue.cjs.js.map +2 -2
  89. package/dist/nextcloud-vue.css +154 -2
  90. package/l10n/en.json +7 -1
  91. package/l10n/nl.json +8 -2
  92. package/package.json +1 -1
  93. package/src/components/CnAppNav/CnAppNav.vue +21 -16
  94. package/src/components/CnAppRoot/CnAppRoot.vue +53 -0
  95. package/src/components/CnBannerWidget/CnBannerWidget.vue +23 -4
  96. package/src/components/CnBrandBar/CnBrandBar.vue +230 -0
  97. package/src/components/CnCardGrid/CnCardGrid.md +1 -0
  98. package/src/components/CnCardGrid/CnCardGrid.vue +7 -0
  99. package/src/components/CnCredentials/CnCredentials.vue +17 -16
  100. package/src/components/CnDetailPage/CnDetailPage.vue +8 -5
  101. package/src/components/CnEnvironmentBanner/CnEnvironmentBanner.vue +4 -1
  102. package/src/components/CnFormDialog/CnFormDialog.vue +10 -0
  103. package/src/components/CnFormPage/CnFormPage.vue +33 -0
  104. package/src/components/CnIndexPage/CnIndexPage.md +15 -0
  105. package/src/components/CnIndexPage/CnIndexPage.vue +157 -18
  106. package/src/components/CnIndexPage/selfModeActions.js +89 -13
  107. package/src/components/CnIndexPage/useSelfFetchList.js +15 -3
  108. package/src/components/CnObjectCard/CnObjectCard.md +1 -0
  109. package/src/components/CnObjectCard/CnObjectCard.vue +89 -1
  110. package/src/components/CnObjectListWidget/CnObjectListWidget.vue +19 -3
  111. package/src/components/CnQuickFilterBar/CnQuickFilterBar.vue +20 -4
  112. package/src/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue +181 -38
  113. package/src/components/CnStatsBlock/CnStatsBlock.vue +18 -2
  114. package/src/composables/__tests__/useObjectLock.endpoints.spec.js +83 -0
  115. package/src/composables/useObjectLock.js +41 -10
  116. package/src/css/form-field.css +1 -1
  117. package/src/css/look-board-index.css +35 -1
  118. package/src/directives/cnSelectAria.js +54 -0
  119. package/src/index.js +1 -0
  120. package/src/schemas/app-manifest-v2.schema.json +6 -1
  121. package/src/store/useObjectStore.js +37 -9
  122. package/src/utils/cnFetch.js +16 -1
  123. package/src/utils/index.js +1 -0
  124. package/src/utils/objectSignals.js +41 -0
  125. package/src/utils/resolveBrand.js +37 -0
  126. package/src/utils/validateManifestV2.compiled.js +2 -2
@@ -86,7 +86,10 @@ var script = {
86
86
  return
87
87
  }
88
88
  const all = Object.values(ENVIRONMENT_TITLE_PREFIX);
89
- const bare = document.title.replace(new RegExp(`^(?:${all.map((p) => p.replace(/[[\]]/g, '\\$&')).join('|')}) `), '');
89
+ // Plain string comparison: no pattern is built from the prefixes, so
90
+ // there is nothing to escape.
91
+ const owned = all.find((p) => document.title.startsWith(`${p} `));
92
+ const bare = owned ? document.title.slice(owned.length + 1) : document.title;
90
93
  const wanted = environment ? `${ENVIRONMENT_TITLE_PREFIX[environment]} ${bare}` : bare;
91
94
  if (document.title !== wanted) {
92
95
  document.title = wanted;
@@ -1 +1 @@
1
- {"version":3,"file":"CnEnvironmentBanner.vue2.js","sources":["../../../../src/components/CnEnvironmentBanner/CnEnvironmentBanner.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<div\n\t\tv-if=\"marked\"\n\t\tclass=\"cn-environment-banner\"\n\t\t:class=\"`cn-environment-banner--${marked}`\"\n\t\trole=\"note\"\n\t\t:aria-label=\"label\"\n\t\tdata-testid=\"cn-environment-banner\">\n\t\t<span class=\"cn-environment-banner__label\">{{ label }}</span>\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { ENVIRONMENT_TITLE_PREFIX, MARKED_ENVIRONMENTS, normaliseEnvironment } from '../../utils/environment.js'\n\n/**\n * CnEnvironmentBanner — names a non-production environment on every app screen\n * so acceptance is not mistaken for production.\n *\n * Shows \"Development environment\", \"Test environment\" or \"Acceptance\n * environment\" in words, with a colour per environment, as a `role=\"note\"` with\n * an accessible name. It has no close action and cannot be hidden by a user\n * setting. While it shows, the document title is prefixed `[DEV]`, `[TEST]` or\n * `[ACC]` (and put back when it goes). Production, an unknown value and no\n * value render nothing and leave the title alone.\n *\n * `CnAppRoot` and `CnAdminSettingsShell` place it themselves, from their\n * `environment` prop or the active organisation's `environment` field. An app\n * that does not mount them can place it:\n *\n * ```vue\n * <CnEnvironmentBanner environment=\"acceptance\" />\n * ```\n */\nexport default {\n\tname: 'CnEnvironmentBanner',\n\n\tprops: {\n\t\t/** The environment: `development`, `test` or `acceptance` shows the banner; anything else shows nothing. */\n\t\tenvironment: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\tcomputed: {\n\t\t/** @return {string} The environment to mark, or '' when nothing is shown. */\n\t\tmarked() {\n\t\t\tconst name = normaliseEnvironment(this.environment)\n\t\t\treturn MARKED_ENVIRONMENTS.includes(name) ? name : ''\n\t\t},\n\n\t\t/** @return {string} The name of the environment in words. */\n\t\tlabel() {\n\t\t\treturn {\n\t\t\t\tdevelopment: t('nextcloud-vue', 'Development environment'),\n\t\t\t\ttest: t('nextcloud-vue', 'Test environment'),\n\t\t\t\tacceptance: t('nextcloud-vue', 'Acceptance environment'),\n\t\t\t}[this.marked] || ''\n\t\t},\n\t},\n\n\twatch: {\n\t\tmarked: {\n\t\t\timmediate: true,\n\t\t\thandler(next) {\n\t\t\t\tthis.applyTitlePrefix(next)\n\t\t\t},\n\t\t},\n\t},\n\n\tmounted() {\n\t\t// A router that sets the title after we did must not lose the prefix.\n\t\tconst titleElement = typeof document !== 'undefined' ? document.querySelector('title') : null\n\t\tif (titleElement && typeof MutationObserver !== 'undefined') {\n\t\t\tthis.titleObserver = new MutationObserver(() => this.applyTitlePrefix(this.marked))\n\t\t\tthis.titleObserver.observe(titleElement, { childList: true, characterData: true, subtree: true })\n\t\t}\n\t},\n\n\tbeforeUnmount() {\n\t\tif (this.titleObserver) {\n\t\t\tthis.titleObserver.disconnect()\n\t\t}\n\t\tthis.applyTitlePrefix('')\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Put the environment's prefix at the start of the tab title, or take ours\n\t\t * off when nothing is marked.\n\t\t *\n\t\t * @param {string} environment The marked environment, or ''.\n\t\t * @return {void}\n\t\t */\n\t\tapplyTitlePrefix(environment) {\n\t\t\tif (typeof document === 'undefined') {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst all = Object.values(ENVIRONMENT_TITLE_PREFIX)\n\t\t\tconst bare = document.title.replace(new RegExp(`^(?:${all.map((p) => p.replace(/[[\\]]/g, '\\\\$&')).join('|')}) `), '')\n\t\t\tconst wanted = environment ? `${ENVIRONMENT_TITLE_PREFIX[environment]} ${bare}` : bare\n\t\t\tif (document.title !== wanted) {\n\t\t\t\tdocument.title = wanted\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-environment-banner {\n\t--cn-environment-accent: var(--color-element-info, var(--color-primary-element));\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tbox-sizing: border-box;\n\tmin-height: 24px;\n\tpadding: 2px 12px;\n\tborder-inline-start: 6px solid var(--cn-environment-accent);\n\tborder-block-end: 2px solid var(--cn-environment-accent);\n\tbackground: var(--color-background-dark);\n\tcolor: var(--color-main-text);\n\tfont-weight: bold;\n\tletter-spacing: 0.04em;\n\ttext-transform: uppercase;\n}\n\n.cn-environment-banner--development {\n\t--cn-environment-accent: var(--color-element-info, var(--color-primary-element));\n}\n\n.cn-environment-banner--test {\n\t--cn-environment-accent: var(--color-element-warning, var(--color-warning));\n}\n\n.cn-environment-banner--acceptance {\n\t--cn-environment-accent: var(--color-element-error, var(--color-error));\n}\n</style>\n"],"names":["t"],"mappings":";;;AAoBA;AACC;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAED,aAAe;CACd,IAAI,EAAE,qBAAqB;;AAE3B,CAAA,KAAK,EAAE;AACN;EACA,WAAW,EAAE;GACZ,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,EAAE;GACX;EACD;;AAED,CAAA,QAAQ,EAAE;AACT;AACA,EAAA,MAAM,GAAG;GACR,MAAM,OAAO,oBAAoB,CAAC,IAAI,CAAC,WAAW,EAAA;GAClD,OAAO,mBAAmB,CAAC,QAAQ,CAAC,IAAI,CAAE,GAAE,IAAK,GAAE,EAAC;GACpD;;;AAGD,EAAA,KAAK,GAAG;AACP,GAAA,OAAO;IACN,WAAW,EAAEA,SAAC,CAAC,eAAe,EAAE,yBAAyB,CAAC;AAC1D,IAAA,IAAI,EAAEA,SAAC,CAAC,eAAe,EAAE,kBAAkB,CAAC;IAC5C,UAAU,EAAEA,SAAC,CAAC,eAAe,EAAE,wBAAwB,CAAC;AACzD,IAAC,CAAC,IAAI,CAAC,MAAM,CAAE,IAAG,EAAC;GACnB;EACD;;AAED,CAAA,KAAK,EAAE;AACN,EAAA,MAAM,EAAE;AACP,GAAA,SAAS,EAAE,IAAI;GACf,OAAO,CAAC,IAAI,EAAE;IACb,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAA;IAC1B;GACD;EACD;;AAED,CAAA,OAAO,GAAG;;AAET,EAAA,MAAM,YAAW,GAAI,OAAO,QAAO,KAAM,WAAU,GAAI,QAAQ,CAAC,aAAa,CAAC,OAAO,IAAI,KAAG;EAC5F,IAAI,YAAa,IAAG,OAAO,gBAAe,KAAM,WAAW,EAAE;AAC5D,GAAA,IAAI,CAAC,aAAY,GAAI,IAAI,gBAAgB,CAAC,MAAM,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAA;AAClF,GAAA,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAA;AACjG,GAAA;EACA;;AAED,CAAA,aAAa,GAAG;EACf,IAAI,IAAI,CAAC,aAAa,EAAE;AACvB,GAAA,IAAI,CAAC,aAAa,CAAC,UAAU,GAAC;AAC/B,GAAA;EACA,IAAI,CAAC,gBAAgB,CAAC,EAAE,EAAA;EACxB;;AAED,CAAA,OAAO,EAAE;AACR;;;AAGC;;;;EAID,gBAAgB,CAAC,WAAW,EAAE;AAC7B,GAAA,IAAI,OAAO,QAAS,KAAI,WAAW,EAAE;IACpC,MAAK;AACN,IAAA;GACA,MAAM,GAAE,GAAI,MAAM,CAAC,MAAM,CAAC,wBAAwB,EAAA;GAClD,MAAM,IAAK,GAAE,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,EAAA;AACpH,GAAA,MAAM,SAAS,WAAU,GAAI,CAAC,EAAE,wBAAwB,CAAC,WAAW,CAAC,CAAA,CAAE,EAAE,IAAI,CAAC,CAAA,GAAI,KAAG;GACrF,IAAI,QAAQ,CAAC,KAAM,KAAI,MAAM,EAAE;AAC9B,IAAA,QAAQ,CAAC,KAAM,GAAE,OAAK;AACvB,IAAA;GACA;EACD;AACF;;;;"}
1
+ {"version":3,"file":"CnEnvironmentBanner.vue2.js","sources":["../../../../src/components/CnEnvironmentBanner/CnEnvironmentBanner.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<div\n\t\tv-if=\"marked\"\n\t\tclass=\"cn-environment-banner\"\n\t\t:class=\"`cn-environment-banner--${marked}`\"\n\t\trole=\"note\"\n\t\t:aria-label=\"label\"\n\t\tdata-testid=\"cn-environment-banner\">\n\t\t<span class=\"cn-environment-banner__label\">{{ label }}</span>\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { ENVIRONMENT_TITLE_PREFIX, MARKED_ENVIRONMENTS, normaliseEnvironment } from '../../utils/environment.js'\n\n/**\n * CnEnvironmentBanner — names a non-production environment on every app screen\n * so acceptance is not mistaken for production.\n *\n * Shows \"Development environment\", \"Test environment\" or \"Acceptance\n * environment\" in words, with a colour per environment, as a `role=\"note\"` with\n * an accessible name. It has no close action and cannot be hidden by a user\n * setting. While it shows, the document title is prefixed `[DEV]`, `[TEST]` or\n * `[ACC]` (and put back when it goes). Production, an unknown value and no\n * value render nothing and leave the title alone.\n *\n * `CnAppRoot` and `CnAdminSettingsShell` place it themselves, from their\n * `environment` prop or the active organisation's `environment` field. An app\n * that does not mount them can place it:\n *\n * ```vue\n * <CnEnvironmentBanner environment=\"acceptance\" />\n * ```\n */\nexport default {\n\tname: 'CnEnvironmentBanner',\n\n\tprops: {\n\t\t/** The environment: `development`, `test` or `acceptance` shows the banner; anything else shows nothing. */\n\t\tenvironment: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\tcomputed: {\n\t\t/** @return {string} The environment to mark, or '' when nothing is shown. */\n\t\tmarked() {\n\t\t\tconst name = normaliseEnvironment(this.environment)\n\t\t\treturn MARKED_ENVIRONMENTS.includes(name) ? name : ''\n\t\t},\n\n\t\t/** @return {string} The name of the environment in words. */\n\t\tlabel() {\n\t\t\treturn {\n\t\t\t\tdevelopment: t('nextcloud-vue', 'Development environment'),\n\t\t\t\ttest: t('nextcloud-vue', 'Test environment'),\n\t\t\t\tacceptance: t('nextcloud-vue', 'Acceptance environment'),\n\t\t\t}[this.marked] || ''\n\t\t},\n\t},\n\n\twatch: {\n\t\tmarked: {\n\t\t\timmediate: true,\n\t\t\thandler(next) {\n\t\t\t\tthis.applyTitlePrefix(next)\n\t\t\t},\n\t\t},\n\t},\n\n\tmounted() {\n\t\t// A router that sets the title after we did must not lose the prefix.\n\t\tconst titleElement = typeof document !== 'undefined' ? document.querySelector('title') : null\n\t\tif (titleElement && typeof MutationObserver !== 'undefined') {\n\t\t\tthis.titleObserver = new MutationObserver(() => this.applyTitlePrefix(this.marked))\n\t\t\tthis.titleObserver.observe(titleElement, { childList: true, characterData: true, subtree: true })\n\t\t}\n\t},\n\n\tbeforeUnmount() {\n\t\tif (this.titleObserver) {\n\t\t\tthis.titleObserver.disconnect()\n\t\t}\n\t\tthis.applyTitlePrefix('')\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Put the environment's prefix at the start of the tab title, or take ours\n\t\t * off when nothing is marked.\n\t\t *\n\t\t * @param {string} environment The marked environment, or ''.\n\t\t * @return {void}\n\t\t */\n\t\tapplyTitlePrefix(environment) {\n\t\t\tif (typeof document === 'undefined') {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst all = Object.values(ENVIRONMENT_TITLE_PREFIX)\n\t\t\t// Plain string comparison: no pattern is built from the prefixes, so\n\t\t\t// there is nothing to escape.\n\t\t\tconst owned = all.find((p) => document.title.startsWith(`${p} `))\n\t\t\tconst bare = owned ? document.title.slice(owned.length + 1) : document.title\n\t\t\tconst wanted = environment ? `${ENVIRONMENT_TITLE_PREFIX[environment]} ${bare}` : bare\n\t\t\tif (document.title !== wanted) {\n\t\t\t\tdocument.title = wanted\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-environment-banner {\n\t--cn-environment-accent: var(--color-element-info, var(--color-primary-element));\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tbox-sizing: border-box;\n\tmin-height: 24px;\n\tpadding: 2px 12px;\n\tborder-inline-start: 6px solid var(--cn-environment-accent);\n\tborder-block-end: 2px solid var(--cn-environment-accent);\n\tbackground: var(--color-background-dark);\n\tcolor: var(--color-main-text);\n\tfont-weight: bold;\n\tletter-spacing: 0.04em;\n\ttext-transform: uppercase;\n}\n\n.cn-environment-banner--development {\n\t--cn-environment-accent: var(--color-element-info, var(--color-primary-element));\n}\n\n.cn-environment-banner--test {\n\t--cn-environment-accent: var(--color-element-warning, var(--color-warning));\n}\n\n.cn-environment-banner--acceptance {\n\t--cn-environment-accent: var(--color-element-error, var(--color-error));\n}\n</style>\n"],"names":["t"],"mappings":";;;AAoBA;AACC;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAED,aAAe;CACd,IAAI,EAAE,qBAAqB;;AAE3B,CAAA,KAAK,EAAE;AACN;EACA,WAAW,EAAE;GACZ,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,EAAE;GACX;EACD;;AAED,CAAA,QAAQ,EAAE;AACT;AACA,EAAA,MAAM,GAAG;GACR,MAAM,OAAO,oBAAoB,CAAC,IAAI,CAAC,WAAW,EAAA;GAClD,OAAO,mBAAmB,CAAC,QAAQ,CAAC,IAAI,CAAE,GAAE,IAAK,GAAE,EAAC;GACpD;;;AAGD,EAAA,KAAK,GAAG;AACP,GAAA,OAAO;IACN,WAAW,EAAEA,SAAC,CAAC,eAAe,EAAE,yBAAyB,CAAC;AAC1D,IAAA,IAAI,EAAEA,SAAC,CAAC,eAAe,EAAE,kBAAkB,CAAC;IAC5C,UAAU,EAAEA,SAAC,CAAC,eAAe,EAAE,wBAAwB,CAAC;AACzD,IAAC,CAAC,IAAI,CAAC,MAAM,CAAE,IAAG,EAAC;GACnB;EACD;;AAED,CAAA,KAAK,EAAE;AACN,EAAA,MAAM,EAAE;AACP,GAAA,SAAS,EAAE,IAAI;GACf,OAAO,CAAC,IAAI,EAAE;IACb,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAA;IAC1B;GACD;EACD;;AAED,CAAA,OAAO,GAAG;;AAET,EAAA,MAAM,YAAW,GAAI,OAAO,QAAO,KAAM,WAAU,GAAI,QAAQ,CAAC,aAAa,CAAC,OAAO,IAAI,KAAG;EAC5F,IAAI,YAAa,IAAG,OAAO,gBAAe,KAAM,WAAW,EAAE;AAC5D,GAAA,IAAI,CAAC,aAAY,GAAI,IAAI,gBAAgB,CAAC,MAAM,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAA;AAClF,GAAA,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAA;AACjG,GAAA;EACA;;AAED,CAAA,aAAa,GAAG;EACf,IAAI,IAAI,CAAC,aAAa,EAAE;AACvB,GAAA,IAAI,CAAC,aAAa,CAAC,UAAU,GAAC;AAC/B,GAAA;EACA,IAAI,CAAC,gBAAgB,CAAC,EAAE,EAAA;EACxB;;AAED,CAAA,OAAO,EAAE;AACR;;;AAGC;;;;EAID,gBAAgB,CAAC,WAAW,EAAE;AAC7B,GAAA,IAAI,OAAO,QAAS,KAAI,WAAW,EAAE;IACpC,MAAK;AACN,IAAA;GACA,MAAM,GAAE,GAAI,MAAM,CAAC,MAAM,CAAC,wBAAwB,EAAA;;;GAGlD,MAAM,KAAI,GAAI,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,CAAE,CAAA,CAAC,CAAC,EAAA;AAChE,GAAA,MAAM,IAAG,GAAI,KAAM,GAAE,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,MAAO,GAAE,CAAC,CAAA,GAAI,QAAQ,CAAC,MAAI;AAC3E,GAAA,MAAM,SAAS,WAAU,GAAI,CAAC,EAAE,wBAAwB,CAAC,WAAW,CAAC,CAAA,CAAE,EAAE,IAAI,CAAC,CAAA,GAAI,KAAG;GACrF,IAAI,QAAQ,CAAC,KAAM,KAAI,MAAM,EAAE;AAC9B,IAAA,QAAQ,CAAC,KAAM,GAAE,OAAK;AACvB,IAAA;GACA;EACD;AACF;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"CnEnvironmentBanner.vue3.js","sources":["../../../../src/components/CnEnvironmentBanner/CnEnvironmentBanner.vue?vue&type=template&id=3c3362b9&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<div\n\t\tv-if=\"marked\"\n\t\tclass=\"cn-environment-banner\"\n\t\t:class=\"`cn-environment-banner--${marked}`\"\n\t\trole=\"note\"\n\t\t:aria-label=\"label\"\n\t\tdata-testid=\"cn-environment-banner\">\n\t\t<span class=\"cn-environment-banner__label\">{{ label }}</span>\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { ENVIRONMENT_TITLE_PREFIX, MARKED_ENVIRONMENTS, normaliseEnvironment } from '../../utils/environment.js'\n\n/**\n * CnEnvironmentBanner — names a non-production environment on every app screen\n * so acceptance is not mistaken for production.\n *\n * Shows \"Development environment\", \"Test environment\" or \"Acceptance\n * environment\" in words, with a colour per environment, as a `role=\"note\"` with\n * an accessible name. It has no close action and cannot be hidden by a user\n * setting. While it shows, the document title is prefixed `[DEV]`, `[TEST]` or\n * `[ACC]` (and put back when it goes). Production, an unknown value and no\n * value render nothing and leave the title alone.\n *\n * `CnAppRoot` and `CnAdminSettingsShell` place it themselves, from their\n * `environment` prop or the active organisation's `environment` field. An app\n * that does not mount them can place it:\n *\n * ```vue\n * <CnEnvironmentBanner environment=\"acceptance\" />\n * ```\n */\nexport default {\n\tname: 'CnEnvironmentBanner',\n\n\tprops: {\n\t\t/** The environment: `development`, `test` or `acceptance` shows the banner; anything else shows nothing. */\n\t\tenvironment: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\tcomputed: {\n\t\t/** @return {string} The environment to mark, or '' when nothing is shown. */\n\t\tmarked() {\n\t\t\tconst name = normaliseEnvironment(this.environment)\n\t\t\treturn MARKED_ENVIRONMENTS.includes(name) ? name : ''\n\t\t},\n\n\t\t/** @return {string} The name of the environment in words. */\n\t\tlabel() {\n\t\t\treturn {\n\t\t\t\tdevelopment: t('nextcloud-vue', 'Development environment'),\n\t\t\t\ttest: t('nextcloud-vue', 'Test environment'),\n\t\t\t\tacceptance: t('nextcloud-vue', 'Acceptance environment'),\n\t\t\t}[this.marked] || ''\n\t\t},\n\t},\n\n\twatch: {\n\t\tmarked: {\n\t\t\timmediate: true,\n\t\t\thandler(next) {\n\t\t\t\tthis.applyTitlePrefix(next)\n\t\t\t},\n\t\t},\n\t},\n\n\tmounted() {\n\t\t// A router that sets the title after we did must not lose the prefix.\n\t\tconst titleElement = typeof document !== 'undefined' ? document.querySelector('title') : null\n\t\tif (titleElement && typeof MutationObserver !== 'undefined') {\n\t\t\tthis.titleObserver = new MutationObserver(() => this.applyTitlePrefix(this.marked))\n\t\t\tthis.titleObserver.observe(titleElement, { childList: true, characterData: true, subtree: true })\n\t\t}\n\t},\n\n\tbeforeUnmount() {\n\t\tif (this.titleObserver) {\n\t\t\tthis.titleObserver.disconnect()\n\t\t}\n\t\tthis.applyTitlePrefix('')\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Put the environment's prefix at the start of the tab title, or take ours\n\t\t * off when nothing is marked.\n\t\t *\n\t\t * @param {string} environment The marked environment, or ''.\n\t\t * @return {void}\n\t\t */\n\t\tapplyTitlePrefix(environment) {\n\t\t\tif (typeof document === 'undefined') {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst all = Object.values(ENVIRONMENT_TITLE_PREFIX)\n\t\t\tconst bare = document.title.replace(new RegExp(`^(?:${all.map((p) => p.replace(/[[\\]]/g, '\\\\$&')).join('|')}) `), '')\n\t\t\tconst wanted = environment ? `${ENVIRONMENT_TITLE_PREFIX[environment]} ${bare}` : bare\n\t\t\tif (document.title !== wanted) {\n\t\t\t\tdocument.title = wanted\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-environment-banner {\n\t--cn-environment-accent: var(--color-element-info, var(--color-primary-element));\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tbox-sizing: border-box;\n\tmin-height: 24px;\n\tpadding: 2px 12px;\n\tborder-inline-start: 6px solid var(--cn-environment-accent);\n\tborder-block-end: 2px solid var(--cn-environment-accent);\n\tbackground: var(--color-background-dark);\n\tcolor: var(--color-main-text);\n\tfont-weight: bold;\n\tletter-spacing: 0.04em;\n\ttext-transform: uppercase;\n}\n\n.cn-environment-banner--development {\n\t--cn-environment-accent: var(--color-element-info, var(--color-primary-element));\n}\n\n.cn-environment-banner--test {\n\t--cn-environment-accent: var(--color-element-warning, var(--color-warning));\n}\n\n.cn-environment-banner--acceptance {\n\t--cn-environment-accent: var(--color-element-error, var(--color-error));\n}\n</style>\n"],"names":["_normalizeClass"],"mappings":";;;;;;UAUQ,QAAM,CAAA,MAAA;;;QACZ,KAAK,EAAAA,cAAA,CAAA,CAAC,uBAAuB,EAAA,CAAA,uBAAA,EACK,QAAM,CAAA,MAAA,CAAA,CAAA,CAAA,CAAA;AACxC,QAAA,IAAI,EAAA,MAAA;;;;;;;;;;;"}
1
+ {"version":3,"file":"CnEnvironmentBanner.vue3.js","sources":["../../../../src/components/CnEnvironmentBanner/CnEnvironmentBanner.vue?vue&type=template&id=3c3362b9&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<div\n\t\tv-if=\"marked\"\n\t\tclass=\"cn-environment-banner\"\n\t\t:class=\"`cn-environment-banner--${marked}`\"\n\t\trole=\"note\"\n\t\t:aria-label=\"label\"\n\t\tdata-testid=\"cn-environment-banner\">\n\t\t<span class=\"cn-environment-banner__label\">{{ label }}</span>\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { ENVIRONMENT_TITLE_PREFIX, MARKED_ENVIRONMENTS, normaliseEnvironment } from '../../utils/environment.js'\n\n/**\n * CnEnvironmentBanner — names a non-production environment on every app screen\n * so acceptance is not mistaken for production.\n *\n * Shows \"Development environment\", \"Test environment\" or \"Acceptance\n * environment\" in words, with a colour per environment, as a `role=\"note\"` with\n * an accessible name. It has no close action and cannot be hidden by a user\n * setting. While it shows, the document title is prefixed `[DEV]`, `[TEST]` or\n * `[ACC]` (and put back when it goes). Production, an unknown value and no\n * value render nothing and leave the title alone.\n *\n * `CnAppRoot` and `CnAdminSettingsShell` place it themselves, from their\n * `environment` prop or the active organisation's `environment` field. An app\n * that does not mount them can place it:\n *\n * ```vue\n * <CnEnvironmentBanner environment=\"acceptance\" />\n * ```\n */\nexport default {\n\tname: 'CnEnvironmentBanner',\n\n\tprops: {\n\t\t/** The environment: `development`, `test` or `acceptance` shows the banner; anything else shows nothing. */\n\t\tenvironment: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\tcomputed: {\n\t\t/** @return {string} The environment to mark, or '' when nothing is shown. */\n\t\tmarked() {\n\t\t\tconst name = normaliseEnvironment(this.environment)\n\t\t\treturn MARKED_ENVIRONMENTS.includes(name) ? name : ''\n\t\t},\n\n\t\t/** @return {string} The name of the environment in words. */\n\t\tlabel() {\n\t\t\treturn {\n\t\t\t\tdevelopment: t('nextcloud-vue', 'Development environment'),\n\t\t\t\ttest: t('nextcloud-vue', 'Test environment'),\n\t\t\t\tacceptance: t('nextcloud-vue', 'Acceptance environment'),\n\t\t\t}[this.marked] || ''\n\t\t},\n\t},\n\n\twatch: {\n\t\tmarked: {\n\t\t\timmediate: true,\n\t\t\thandler(next) {\n\t\t\t\tthis.applyTitlePrefix(next)\n\t\t\t},\n\t\t},\n\t},\n\n\tmounted() {\n\t\t// A router that sets the title after we did must not lose the prefix.\n\t\tconst titleElement = typeof document !== 'undefined' ? document.querySelector('title') : null\n\t\tif (titleElement && typeof MutationObserver !== 'undefined') {\n\t\t\tthis.titleObserver = new MutationObserver(() => this.applyTitlePrefix(this.marked))\n\t\t\tthis.titleObserver.observe(titleElement, { childList: true, characterData: true, subtree: true })\n\t\t}\n\t},\n\n\tbeforeUnmount() {\n\t\tif (this.titleObserver) {\n\t\t\tthis.titleObserver.disconnect()\n\t\t}\n\t\tthis.applyTitlePrefix('')\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Put the environment's prefix at the start of the tab title, or take ours\n\t\t * off when nothing is marked.\n\t\t *\n\t\t * @param {string} environment The marked environment, or ''.\n\t\t * @return {void}\n\t\t */\n\t\tapplyTitlePrefix(environment) {\n\t\t\tif (typeof document === 'undefined') {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst all = Object.values(ENVIRONMENT_TITLE_PREFIX)\n\t\t\t// Plain string comparison: no pattern is built from the prefixes, so\n\t\t\t// there is nothing to escape.\n\t\t\tconst owned = all.find((p) => document.title.startsWith(`${p} `))\n\t\t\tconst bare = owned ? document.title.slice(owned.length + 1) : document.title\n\t\t\tconst wanted = environment ? `${ENVIRONMENT_TITLE_PREFIX[environment]} ${bare}` : bare\n\t\t\tif (document.title !== wanted) {\n\t\t\t\tdocument.title = wanted\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-environment-banner {\n\t--cn-environment-accent: var(--color-element-info, var(--color-primary-element));\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tbox-sizing: border-box;\n\tmin-height: 24px;\n\tpadding: 2px 12px;\n\tborder-inline-start: 6px solid var(--cn-environment-accent);\n\tborder-block-end: 2px solid var(--cn-environment-accent);\n\tbackground: var(--color-background-dark);\n\tcolor: var(--color-main-text);\n\tfont-weight: bold;\n\tletter-spacing: 0.04em;\n\ttext-transform: uppercase;\n}\n\n.cn-environment-banner--development {\n\t--cn-environment-accent: var(--color-element-info, var(--color-primary-element));\n}\n\n.cn-environment-banner--test {\n\t--cn-environment-accent: var(--color-element-warning, var(--color-warning));\n}\n\n.cn-environment-banner--acceptance {\n\t--cn-environment-accent: var(--color-element-error, var(--color-error));\n}\n</style>\n"],"names":["_normalizeClass"],"mappings":";;;;;;UAUQ,QAAM,CAAA,MAAA;;;QACZ,KAAK,EAAAA,cAAA,CAAA,CAAC,uBAAuB,EAAA,CAAA,uBAAA,EACK,QAAM,CAAA,MAAA,CAAA,CAAA,CAAA,CAAA;AACxC,QAAA,IAAI,EAAA,MAAA;;;;;;;;;;;"}
@@ -22,6 +22,7 @@ import { splitHeldFiles, uploadHeldFiles, heldFromFailures } from '../../composa
22
22
  import { useIntegrationRegistry } from '../../composables/useIntegrationRegistry.js';
23
23
  import { TENANT_CONTEXT_KEY } from '../../composables/useTenantContext.js';
24
24
  import { useWriteFeedback } from '../../composables/useWriteFeedback.js';
25
+ import { cnSelectAria } from '../../directives/cnSelectAria.js';
25
26
  import { dialogBoardMixin } from '../../mixins/dialogBoard.js';
26
27
  import { useObjectStore } from '../../store/useObjectStore.js';
27
28
  import { resolveCreateOverrideHandler } from '../../utils/actionsDispatcher.js';
@@ -233,6 +234,8 @@ const SEMANTIC_RESOLVE_ENDPOINT = '/apps/openregister/api/schemas/resolve-by-imp
233
234
  var script = {
234
235
  name: 'CnFormDialog',
235
236
 
237
+ directives: { cnSelectAria },
238
+
236
239
  components: {
237
240
  CnFileField: __sfc_main,
238
241
  CnDurationField: __sfc_main$1,
@@ -2842,6 +2845,10 @@ var script = {
2842
2845
  return
2843
2846
  }
2844
2847
  const [head, ...rest] = key.split('.');
2848
+ const unsafe = ['__proto__', 'constructor', 'prototype'];
2849
+ if (unsafe.includes(head) || rest.some((k) => unsafe.includes(k))) {
2850
+ return
2851
+ }
2845
2852
  const clone = JSON.parse(JSON.stringify(this.formData[head] ?? {}));
2846
2853
  let cur = clone;
2847
2854
  rest.slice(0, -1).forEach((k) => {