@conduction/nextcloud-vue 2.102.0 → 2.103.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 (90) hide show
  1. package/dist/esm/components/CnConversationThread/CnConversationThread.vue.js +1 -1
  2. package/dist/esm/components/CnConversationThread/CnConversationThread.vue2.js +73 -0
  3. package/dist/esm/components/CnConversationThread/CnConversationThread.vue2.js.map +1 -1
  4. package/dist/esm/components/CnConversationThread/CnConversationThread.vue3.js +99 -64
  5. package/dist/esm/components/CnConversationThread/CnConversationThread.vue3.js.map +1 -1
  6. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue.js +1 -1
  7. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue2.js +46 -0
  8. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue2.js.map +1 -1
  9. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue3.js +37 -2
  10. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue3.js.map +1 -1
  11. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue.js +1 -1
  12. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +29 -6
  13. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
  14. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
  15. package/dist/esm/components/CnFormDialog/CnFormDialog.vue.js +1 -1
  16. package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js +113 -20
  17. package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js.map +1 -1
  18. package/dist/esm/components/CnFormDialog/CnFormDialog.vue3.js +387 -359
  19. package/dist/esm/components/CnFormDialog/CnFormDialog.vue3.js.map +1 -1
  20. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +14 -0
  21. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  22. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +2 -2
  23. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  24. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue.js +1 -1
  25. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +10 -1
  26. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
  27. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
  28. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +1 -1
  29. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +97 -3
  30. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
  31. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js +46 -2
  32. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
  33. package/dist/esm/components/CnSearchSelect/CnSearchSelect.vue.js +9 -0
  34. package/dist/esm/components/CnSearchSelect/CnSearchSelect.vue.js.map +1 -0
  35. package/dist/esm/components/CnSearchSelect/CnSearchSelect.vue2.js +165 -0
  36. package/dist/esm/components/CnSearchSelect/CnSearchSelect.vue2.js.map +1 -0
  37. package/dist/esm/components/CnSearchSelect/CnSearchSelect.vue3.js +85 -0
  38. package/dist/esm/components/CnSearchSelect/CnSearchSelect.vue3.js.map +1 -0
  39. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue.js +1 -1
  40. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js +54 -6
  41. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js.map +1 -1
  42. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js +3 -1
  43. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js.map +1 -1
  44. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue.js +1 -1
  45. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +8 -1
  46. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
  47. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
  48. package/dist/esm/components/CnWizardDialog/CnWizardDialog.vue.js +1 -1
  49. package/dist/esm/components/CnWizardDialog/CnWizardDialog.vue2.js +19 -0
  50. package/dist/esm/components/CnWizardDialog/CnWizardDialog.vue2.js.map +1 -1
  51. package/dist/esm/components/CnWizardDialog/CnWizardDialog.vue3.js +1 -1
  52. package/dist/esm/components/CnWizardDialog/CnWizardDialog.vue3.js.map +1 -1
  53. package/dist/esm/index.js +1 -0
  54. package/dist/esm/index.js.map +1 -1
  55. package/dist/esm/library-style.js +1 -1
  56. package/dist/esm/mixins/pageViews.js +8 -1
  57. package/dist/esm/mixins/pageViews.js.map +1 -1
  58. package/dist/esm/nextcloud-vue.css +472 -383
  59. package/dist/esm/utils/validateManifestV2.compiled.js +3 -3
  60. package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
  61. package/dist/esm/utils/visibleWhen.js +13 -2
  62. package/dist/esm/utils/visibleWhen.js.map +1 -1
  63. package/dist/nextcloud-vue.cjs.js +10707 -9883
  64. package/dist/nextcloud-vue.cjs.js.map +2 -2
  65. package/dist/nextcloud-vue.css +472 -383
  66. package/package.json +1 -1
  67. package/src/components/CnConversationThread/CnConversationThread.md +17 -0
  68. package/src/components/CnConversationThread/CnConversationThread.vue +113 -8
  69. package/src/components/CnConversationThread/CnConversationWidget.vue +60 -1
  70. package/src/components/CnDashboardPage/CnDashboardPage.md +4 -1
  71. package/src/components/CnDashboardPage/CnDashboardPage.vue +29 -6
  72. package/src/components/CnDetailPage/CnDetailPage.md +1 -1
  73. package/src/components/CnFormDialog/CnFormDialog.md +1 -1
  74. package/src/components/CnFormDialog/CnFormDialog.vue +127 -0
  75. package/src/components/CnIndexPage/CnIndexPage.md +10 -0
  76. package/src/components/CnIndexPage/CnIndexPage.vue +18 -3
  77. package/src/components/CnObjectListWidget/CnObjectListWidget.vue +10 -1
  78. package/src/components/CnRecordListWidget/CnRecordListWidget.vue +134 -2
  79. package/src/components/CnSearchSelect/CnSearchSelect.vue +283 -0
  80. package/src/components/CnSearchSelect/index.js +12 -0
  81. package/src/components/CnSetupWizard/CnSetupWizard.vue +56 -6
  82. package/src/components/CnTabsWidget/CnTabsWidget.vue +8 -1
  83. package/src/components/CnWizardDialog/CnWizardDialog.vue +20 -1
  84. package/src/components/index.js +1 -0
  85. package/src/css/dialog.css +5 -3
  86. package/src/index.js +1 -0
  87. package/src/mixins/pageViews.js +8 -1
  88. package/src/schemas/app-manifest-v2.schema.json +53 -6
  89. package/src/utils/validateManifestV2.compiled.js +3 -3
  90. package/src/utils/visibleWhen.js +13 -2
@@ -5,7 +5,7 @@
5
5
  defaultWidth="wizard"
6
6
  :eyebrow="boardEyebrow"
7
7
  :subtitle="subtitle"
8
- :name="dialogTitle"
8
+ :name="shownTitle"
9
9
  size="large"
10
10
  :open="dialogOpen"
11
11
  :noClose="loading || !cancellable"
@@ -265,6 +265,12 @@ export default {
265
265
  * Empty uses the dialog title.
266
266
  */
267
267
  eyebrowContext: { type: String, default: '' },
268
+ /**
269
+ * Board look: head the dialog with the current step's label, the
270
+ * dialog title moving to the eyebrow's context. The result phase and
271
+ * the Nextcloud look keep `dialogTitle`.
272
+ */
273
+ stepHeading: { type: Boolean, default: false },
268
274
  /**
269
275
  * The eyebrow sentence, with `{context}`, `{step}` and `{total}`
270
276
  * placeholders, so it can be translated.
@@ -356,6 +362,19 @@ export default {
356
362
  .replace('{total}', String(this.steps.length))
357
363
  },
358
364
 
365
+ /**
366
+ * The dialog's heading: the current step's label with `stepHeading`
367
+ * in the board look, otherwise `dialogTitle`.
368
+ *
369
+ * @return {string} The heading.
370
+ */
371
+ shownTitle() {
372
+ if (this.stepHeading && this.isBoardLook && this.result === null && this.currentStep && this.currentStep.label) {
373
+ return this.currentStep.label
374
+ }
375
+ return this.dialogTitle
376
+ },
377
+
359
378
  /** @return {object} The check icon, the default finishing icon. */
360
379
  Check() {
361
380
  return Check
@@ -130,6 +130,7 @@ export { default as CnContactsTab } from '../integrations/builtin/contacts/CnCon
130
130
  export { CnContactPicker } from './CnContactPicker/index.js'
131
131
  export { CnContactCreate } from './CnContactCreate/index.js'
132
132
  export { CnResourceSelect } from './CnResourceSelect/index.js'
133
+ export { CnSearchSelect } from './CnSearchSelect/index.js'
133
134
  export { CnPropertySourceField } from './CnPropertySourceField/index.js'
134
135
  export { CnDurationField } from './CnDurationField/index.js'
135
136
  export { CnFavouriteToggle } from './CnFavouriteToggle/index.js'
@@ -9,14 +9,16 @@
9
9
  * Theme hooks (all optional, defaults below):
10
10
  * --cn-dialog-danger fill of a destructive primary
11
11
  * --cn-dialog-eyebrow-color eyebrow colour
12
- * --cn-dialog-eyebrow-transform uppercase (default) or none
12
+ * --cn-dialog-eyebrow-transform none (default, sentence case) or uppercase
13
+ * --cn-dialog-eyebrow-tracking letter spacing; 0 by default, 0.06em suits capitals
13
14
  */
14
15
 
15
16
  .cn-dialog-board {
16
17
  --cn-dialog-width: 640px;
17
18
  --cn-dialog-danger: var(--color-error);
18
19
  --cn-dialog-eyebrow-color: var(--color-primary-element-text, var(--color-main-text));
19
- --cn-dialog-eyebrow-transform: uppercase;
20
+ --cn-dialog-eyebrow-transform: none;
21
+ --cn-dialog-eyebrow-tracking: 0;
20
22
  }
21
23
 
22
24
  /* Dimmed page behind the dialog: text colour at 45%. */
@@ -73,7 +75,7 @@
73
75
  margin-bottom: 4px;
74
76
  font-size: 13px;
75
77
  font-weight: 700;
76
- letter-spacing: 0.06em;
78
+ letter-spacing: var(--cn-dialog-eyebrow-tracking, 0.06em);
77
79
  text-transform: var(--cn-dialog-eyebrow-transform, uppercase);
78
80
  color: var(--cn-dialog-eyebrow-color, var(--color-main-text));
79
81
  }
package/src/index.js CHANGED
@@ -279,6 +279,7 @@ export {
279
279
  CnSaveViewDialog,
280
280
  CnSchemaFormDialog,
281
281
  CnSearchPage,
282
+ CnSearchSelect,
282
283
  CnSectionsWidget,
283
284
  CnSettingsCard,
284
285
  CnSettingsField,
@@ -270,12 +270,14 @@ export const pageViews = {
270
270
 
271
271
  /**
272
272
  * Whether a user arranges the views for themselves (`userLayout`).
273
+ * Not while Buildiq edits the page (`editingBody`): Buildiq is the
274
+ * layout editor, and it shows and changes the manifest layout.
273
275
  *
274
276
  * @return {boolean}
275
277
  * @spec openspec/changes/page-view-user-layouts/specs/view-switch-containers/spec.md#requirement-a-user-arranges-each-view-for-themselves
276
278
  */
277
279
  viewUserLayoutOn() {
278
- return this.userLayout === true && this.hasViews
280
+ return this.userLayout === true && this.hasViews && this.editingBody !== true
279
281
  },
280
282
 
281
283
  /**
@@ -640,6 +642,11 @@ export const pageViews = {
640
642
  this.viewUserLayouts = { ...this.viewUserLayouts, [view.id]: arranged }
641
643
  this.viewUserLayoutsDirty = { ...this.viewUserLayoutsDirty, [view.id]: true }
642
644
  this.$emit('view-layout-change', { view: view.id, layout: arranged })
645
+ // Outside an in-page edit session (the dashboard's edit mode, the
646
+ // detail page's Arrange) no Done will come to save it.
647
+ if (this.isEditing !== true && this.arrangingView !== true) {
648
+ this.saveViewUserLayouts()
649
+ }
643
650
  return
644
651
  }
645
652
  for (const u of updated) {
@@ -3,7 +3,7 @@
3
3
  "$id": "https://raw.githubusercontent.com/ConductionNL/nextcloud-vue/main/src/schemas/app-manifest-v2.schema.json",
4
4
  "title": "Conduction App Manifest v2",
5
5
  "description": "v2 schema for the JSON-driven page and navigation manifest consumed by @conduction/nextcloud-vue. Introduces a uniform widgets[] array on every page type with a per-slot grid coordinate system, a typed actions[] discriminator, and the required $schema field for version detection. v1 manifests continue to validate against app-manifest.schema.json (unchanged).",
6
- "version": "2.125.0",
6
+ "version": "2.126.0",
7
7
  "type": "object",
8
8
  "required": ["$schema", "version"],
9
9
  "allOf": [
@@ -115,10 +115,11 @@
115
115
  }
116
116
  },
117
117
  "optionsSource": { "type": "string", "description": "choice: where to read the option list from at runtime, instead of declaring it here. Names a key in the app's own GET /api/setup/status document (dots walk into nested objects, e.g. `profiles`). Entries accept `id` for `value` and `name` for `label`, and a numeric `objectCount` becomes the stat a card shows. Use it when the SERVER owns what is on offer, so the manifest cannot drift from it." },
118
- "display": { "type": "string", "enum": ["select", "cards"], "default": "select", "description": "choice: how the options are rendered. `select` is a dropdown; `cards` is a grid of CnChoiceCards, which shows each option's description and stats. Pick cards when the choice needs explaining." },
118
+ "display": { "type": "string", "enum": ["select", "cards", "rows"], "default": "select", "description": "choice: how the options are rendered. `select` is a dropdown; `cards` is a grid of CnChoiceCards, which shows each option's description and stats; `rows` is CnChoiceCards' rows layout, one radio row per option with its description below the label. Pick cards or rows when the choice needs explaining." },
119
119
  "dependsOn": { "type": "string", "description": "choice: the configKey of a previous choice step this one cascades from. Disabled until the parent is set; its option list is taken from optionsByParent[parentValue] (e.g. organisation-type depends on country)." },
120
120
  "optionsByParent": { "type": "object", "description": "choice: map of parent-choice value → options[] for a dependent (dependsOn) choice. Same option item shape as `options`.", "additionalProperties": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": ["value", "label"], "properties": { "value": {}, "label": { "type": "string" } } } } },
121
121
  "suggestFrom": { "type": "string", "description": "choice: the configKey of an earlier choice this step pre-fills a suggestion from. When that value is set and the user has not yet picked here, the option matching suggestMap[parentValue] is auto-selected (still user-overridable)." },
122
+ "default": { "description": "choice: the option value chosen when the step opens (an array of values with `multiple`). Not applied to a step the server already completed." },
122
123
  "suggestMap": { "type": "object", "description": "choice: map of suggestFrom value → suggested option value. Used to auto-suggest a default (e.g. RGS template suggested from organisation type).", "additionalProperties": { "type": "string" } },
123
124
  "multiple": { "type": "boolean", "default": false, "description": "choice: allow multi-select." },
124
125
  "loadAction": { "type": "string", "minLength": 1, "description": "choice with display cards: an actionId each option card loads itself with. Every card except the one whose value is `none` gets its own Load button, which POSTs { dataset: <value> } to /api/setup/action/{loadAction}, spins while it runs and shows the result on that card. A successful load also selects the card. With loadAction the separate run-action step that loaded the picked dataset is no longer needed; manifests that keep it still work." },
@@ -541,6 +542,18 @@
541
542
  }
542
543
  },
543
544
  "$defs": {
545
+ "fieldOverride": {
546
+ "type": "object",
547
+ "additionalProperties": true,
548
+ "description": "One field's overrides over its schema-derived descriptor (label, order, hidden, readOnly, widget, enumLabels and more stay free-form). A `widget` that is not one of the form's own widget names mounts the registered component of that name (the v2 registry, then customComponents). 2.126.0 documents the search look of a single select.",
549
+ "properties": {
550
+ "widget": { "type": "string", "minLength": 1 },
551
+ "look": { "type": "string", "enum": ["search"], "description": "`search` draws a single select as CnSearchSelect: a magnifier instead of the chevron, and rows with initials or an icon, the name, a secondary line and a check on the chosen one (DqOverdragen \"Nieuw team\")." },
552
+ "optionSecondary": { "type": "string", "description": "look 'search': the row's secondary line, a template filled from each option (\"{members} leden · {focus}\")." },
553
+ "optionAvatar": { "type": "boolean", "description": "look 'search': draw each option's initials." },
554
+ "optionIcon": { "type": "string", "minLength": 1, "description": "look 'search': one icon for every row." }
555
+ }
556
+ },
544
557
  "breadcrumbCrumb": {
545
558
  "type": "object",
546
559
  "additionalProperties": false,
@@ -2162,6 +2175,39 @@
2162
2175
  }
2163
2176
  }
2164
2177
  },
2178
+ {
2179
+ "description": "record-list built-in widget (CnRecordListWidget): the action under the list, `props.content.footerAction` (2.126.0). Other content keys stay free-form.",
2180
+ "if": {
2181
+ "properties": { "widgetKey": { "const": "record-list" } },
2182
+ "required": ["widgetKey"]
2183
+ },
2184
+ "then": {
2185
+ "properties": {
2186
+ "props": {
2187
+ "type": "object",
2188
+ "properties": {
2189
+ "content": {
2190
+ "type": "object",
2191
+ "properties": {
2192
+ "footerAction": {
2193
+ "type": "object",
2194
+ "additionalProperties": true,
2195
+ "required": ["label"],
2196
+ "description": "One action under the list, also under the empty text (DqBezwaar \"Beroep registreren\"). Its other keys are an action's (`type`, `route`, `form`, ...). While `disabledWhen` holds it is disabled and says `disabledReason` (\"Kan zodra de beslissing is verzonden\"). Label and reason go through the host's translate.",
2197
+ "properties": {
2198
+ "label": { "type": "string", "minLength": 1 },
2199
+ "icon": { "type": "string", "minLength": 1 },
2200
+ "disabledWhen": { "$ref": "#/$defs/visibleWhen" },
2201
+ "disabledReason": { "type": "string" }
2202
+ }
2203
+ }
2204
+ }
2205
+ }
2206
+ }
2207
+ }
2208
+ }
2209
+ }
2210
+ },
2165
2211
  {
2166
2212
  "description": "audit-trail built-in widget (CnAuditTrailWidget, Wave 1): the object change-log card. All props are optional — register/schema/objectId normally arrive via the detail-page object-context merge; explicit props win.",
2167
2213
  "if": {
@@ -2864,7 +2910,7 @@
2864
2910
  },
2865
2911
  "fieldOverrides": {
2866
2912
  "type": "object",
2867
- "additionalProperties": true,
2913
+ "additionalProperties": { "$ref": "#/$defs/fieldOverride" },
2868
2914
  "description": "open-form: per-field overrides passed to fieldsFromSchema, keyed by field. Recognised keys include label, order, hidden, readOnly and widget."
2869
2915
  },
2870
2916
  "advanced": {
@@ -3201,9 +3247,9 @@
3201
3247
  },
3202
3248
  "op": {
3203
3249
  "type": "string",
3204
- "enum": ["eq", "neq", "gt", "gte", "lt", "lte", "empty", "notEmpty", "in"],
3250
+ "enum": ["eq", "neq", "gt", "gte", "lt", "lte", "empty", "notEmpty", "in", "anyOf"],
3205
3251
  "default": "eq",
3206
- "description": "Comparison operator (default eq). eq/neq compare loosely-normalised primitives; ordering operators coerce both sides to Number. `in` holds when the value is one of the listed `value` array (2.87.0). `empty` / `notEmpty` take no `value` and treat undefined, null, '' and an empty array alike — the one question eq cannot ask, because an unset field arrives in a shape that depends on the store and String(null) is the word 'null' rather than blank."
3252
+ "description": "Comparison operator (default eq). eq/neq compare loosely-normalised primitives; ordering operators coerce both sides to Number. `in` holds when the value is one of the listed `value` array (2.87.0). `anyOf` holds when the value, or any entry of a list value, is one of the listed `value` array: a record whose `dataCategories` holds \"health\" among others matches `anyOf [\"health\", \"ethnicity\"]` (2.126.0). `empty` / `notEmpty` take no `value` and treat undefined, null, '' and an empty array alike — the one question eq cannot ask, because an unset field arrives in a shape that depends on the store and String(null) is the word 'null' rather than blank."
3207
3253
  },
3208
3254
  "value": {
3209
3255
  "description": "The right-hand side of the comparison, resolved through the shared @-token grammar so `@me` names the signed-in reader rather than a literal only the server knows. Omitted for `empty` / `notEmpty`."
@@ -4006,6 +4052,7 @@
4006
4052
  "additionalProperties": true,
4007
4053
  "description": "type='index': the opt-in folder navigation pane (CnFolderSidebar) rendered left of the list. Selecting a folder filters the list by `filterField` (or `field`); \"All\" clears it. Only the per-scope list-layout keys are typed here; the pane's own keys (source, register, schema, idField, nameField, folders, allLabel, title, allowCreate, ...) stay free-form. Maps to CnIndexPage `folderSidebar`.",
4008
4054
  "properties": {
4055
+ "pane": { "type": "boolean", "default": true, "description": "false keeps the folder scope (a deep link such as `?caseType=<uuid>` still applies the scope's look and filter) without drawing the pane (dossiq's simple profile, 2.126.0)." },
4009
4056
  "folders": {
4010
4057
  "type": "array",
4011
4058
  "description": "Explicit folder list for source:'custom', and the place a folder declares its own list layout. Every other folder key stays free-form.",
@@ -4301,7 +4348,7 @@
4301
4348
  },
4302
4349
  "fieldOverrides": {
4303
4350
  "type": "object",
4304
- "additionalProperties": true,
4351
+ "additionalProperties": { "$ref": "#/$defs/fieldOverride" },
4305
4352
  "description": "Per-field overrides merged over the schema-derived field descriptors in the page's built-in Add/Edit form dialog (e.g. `{ \"description\": { \"widget\": \"textarea\" } }`). Which widget a field renders as belongs to the surface, not to the schema. Maps to CnIndexPage / CnDetailPage `fieldOverrides`."
4306
4353
  },
4307
4354
  "createDefaults": {