@conduction/nextcloud-vue 2.100.0 → 2.102.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js +22 -0
- package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js.map +1 -1
- package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js +8 -6
- package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js.map +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue.js +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js +29 -4
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue3.js +9 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue.js +1 -1
- package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue2.js +22 -1
- package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue2.js.map +1 -1
- package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue3.js +26 -16
- package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue3.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue.js +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +70 -6
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +105 -74
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
- package/dist/esm/components/CnExportsWidget/CnExportsWidget.vue.js +9 -0
- package/dist/esm/components/CnExportsWidget/CnExportsWidget.vue.js.map +1 -0
- package/dist/esm/components/CnExportsWidget/CnExportsWidget.vue2.js +139 -0
- package/dist/esm/components/CnExportsWidget/CnExportsWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnExportsWidget/CnExportsWidget.vue3.js +76 -0
- package/dist/esm/components/CnExportsWidget/CnExportsWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue.js +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +160 -2
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +206 -94
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/filesReview.js +61 -0
- package/dist/esm/components/CnFilesBrowser/filesReview.js.map +1 -0
- package/dist/esm/components/CnGroupedCardsWidget/CnGroupedCardsWidget.vue.js +9 -0
- package/dist/esm/components/CnGroupedCardsWidget/CnGroupedCardsWidget.vue.js.map +1 -0
- package/dist/esm/components/CnGroupedCardsWidget/CnGroupedCardsWidget.vue2.js +279 -0
- package/dist/esm/components/CnGroupedCardsWidget/CnGroupedCardsWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnGroupedCardsWidget/CnGroupedCardsWidget.vue3.js +122 -0
- package/dist/esm/components/CnGroupedCardsWidget/CnGroupedCardsWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnGroupedCardsWidget/index.js +29 -0
- package/dist/esm/components/CnGroupedCardsWidget/index.js.map +1 -0
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +320 -74
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +323 -213
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/useNamedSource.js +30 -3
- package/dist/esm/components/CnIndexPage/useNamedSource.js.map +1 -1
- package/dist/esm/components/CnMapWidget/CnMapWidget.vue.js +1 -1
- package/dist/esm/components/CnMapWidget/CnMapWidget.vue2.js +15 -0
- package/dist/esm/components/CnMapWidget/CnMapWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnMapWidget/CnMapWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnMenuWidget/CnMenuWidget.vue.js +1 -1
- package/dist/esm/components/CnMenuWidget/CnMenuWidget.vue2.js +25 -1
- package/dist/esm/components/CnMenuWidget/CnMenuWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnMenuWidget/CnMenuWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue.js +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +14 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js +14 -6
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue.js +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js +10 -0
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js +6 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js.map +1 -1
- package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue.js +1 -1
- package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue2.js +91 -4
- package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue2.js.map +1 -1
- package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue3.js +63 -38
- package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue3.js.map +1 -1
- package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue.js +1 -1
- package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue2.js +106 -4
- package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue2.js.map +1 -1
- package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue3.js +70 -25
- package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue3.js.map +1 -1
- package/dist/esm/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue.js +9 -0
- package/dist/esm/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue.js.map +1 -0
- package/dist/esm/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue2.js +175 -0
- package/dist/esm/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue3.js +77 -0
- package/dist/esm/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue.js +1 -1
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js +35 -2
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js.map +1 -1
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js.map +1 -1
- package/dist/esm/components/CnWidgetGrid/builtInWidgets.js +4 -0
- package/dist/esm/components/CnWidgetGrid/builtInWidgets.js.map +1 -1
- package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js +1 -0
- package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js.map +1 -1
- package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue.js +1 -1
- package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue2.js +2 -23
- package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue2.js.map +1 -1
- package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue3.js.map +1 -1
- package/dist/esm/composables/indexSources.js +176 -20
- package/dist/esm/composables/indexSources.js.map +1 -1
- package/dist/esm/composables/useEndpointSource.js +28 -6
- package/dist/esm/composables/useEndpointSource.js.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/l10n/en.json.js +41 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +39 -1
- package/dist/esm/l10n/nl.json.js.map +1 -1
- package/dist/esm/library-style.js +1 -1
- package/dist/esm/nextcloud-vue.css +939 -376
- package/dist/esm/utils/builtInFormatters.js +24 -4
- package/dist/esm/utils/builtInFormatters.js.map +1 -1
- package/dist/esm/utils/languageMapText.js +50 -0
- package/dist/esm/utils/languageMapText.js.map +1 -0
- package/dist/esm/utils/libraryWidgetKeys.js +3 -0
- package/dist/esm/utils/libraryWidgetKeys.js.map +1 -1
- package/dist/esm/utils/mapList.js +71 -0
- package/dist/esm/utils/mapList.js.map +1 -0
- package/dist/esm/utils/rowClassRules.js +43 -0
- package/dist/esm/utils/rowClassRules.js.map +1 -0
- package/dist/esm/utils/validateManifestV2.compiled.js +3 -3
- package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
- package/dist/esm/utils/visibleWhen.js +19 -2
- package/dist/esm/utils/visibleWhen.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +9681 -7136
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +939 -376
- package/l10n/en.json +41 -1
- package/l10n/nl.json +39 -1
- package/package.json +1 -1
- package/src/components/CnActionsBar/CnActionsBar.md +1 -0
- package/src/components/CnActionsBar/CnActionsBar.vue +31 -4
- package/src/components/CnChartWidget/CnChartWidget.md +3 -2
- package/src/components/CnChartWidget/CnChartWidget.vue +42 -4
- package/src/components/CnChoiceCards/CnChoiceCards.md +39 -0
- package/src/components/CnChoiceCards/CnChoiceCards.vue +93 -16
- package/src/components/CnDashboardPage/CnDashboardPage.vue +110 -21
- package/src/components/CnExportsWidget/CnExportsWidget.vue +233 -0
- package/src/components/CnExportsWidget/index.js +7 -0
- package/src/components/CnFilesBrowser/CnFilesBrowser.vue +324 -0
- package/src/components/CnFilesBrowser/filesReview.js +57 -0
- package/src/components/CnGroupedCardsWidget/CnGroupedCardsWidget.vue +433 -0
- package/src/components/CnGroupedCardsWidget/index.js +28 -0
- package/src/components/CnIndexPage/CnIndexPage.md +5 -1
- package/src/components/CnIndexPage/CnIndexPage.vue +313 -9
- package/src/components/CnIndexPage/useNamedSource.js +30 -3
- package/src/components/CnMapWidget/CnMapWidget.vue +37 -0
- package/src/components/CnMenuWidget/CnMenuWidget.vue +25 -1
- package/src/components/CnObjectListWidget/CnObjectListWidget.vue +29 -1
- package/src/components/CnObjectSidebar/CnFilesTab.vue +15 -0
- package/src/components/CnOrderedListField/CnOrderedListField.vue +151 -5
- package/src/components/CnQuickFilterBar/CnQuickFilterBar.md +1 -0
- package/src/components/CnQuickFilterBar/CnQuickFilterBar.vue +159 -5
- package/src/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue +272 -0
- package/src/components/CnSavedViewAlertWidget/index.js +7 -0
- package/src/components/CnSetupWizard/CnSetupWizard.vue +35 -2
- package/src/components/CnWidgetGrid/builtInWidgets.js +4 -0
- package/src/components/CnWidgetGrid/registerDashboardWidgets.js +1 -0
- package/src/components/CnWidgetObjectTable/CnWidgetObjectTable.vue +2 -23
- package/src/components/index.js +3 -0
- package/src/composables/indexSources.js +175 -19
- package/src/composables/useEndpointSource.js +28 -6
- package/src/css/index-page.css +117 -0
- package/src/css/look-board-index.css +10 -0
- package/src/css/look-board.css +44 -0
- package/src/index.js +1 -0
- package/src/schemas/app-manifest-v2.schema.json +85 -3
- package/src/utils/builtInFormatters.js +24 -4
- package/src/utils/languageMapText.js +46 -0
- package/src/utils/libraryWidgetKeys.js +3 -0
- package/src/utils/mapList.js +67 -0
- package/src/utils/rowClassRules.js +39 -0
- package/src/utils/validateManifestV2.compiled.js +3 -3
- package/src/utils/visibleWhen.js +19 -2
|
@@ -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.
|
|
6
|
+
"version": "2.125.0",
|
|
7
7
|
"type": "object",
|
|
8
8
|
"required": ["$schema", "version"],
|
|
9
9
|
"allOf": [
|
|
@@ -98,6 +98,7 @@
|
|
|
98
98
|
"title": { "type": "string" },
|
|
99
99
|
"body": { "type": "string", "description": "info: explanatory copy." },
|
|
100
100
|
"note": { "type": "string", "minLength": 1, "description": "choice: a footnote under the options, translated like body." },
|
|
101
|
+
"visibleWhen": { "description": "Offer the step only when the setup status says so: a dotted path into the setup status document whose value must be truthy, or { path, equals } for an exact value. Hidden while the status loads.", "oneOf": [ { "type": "string", "minLength": 1 }, { "type": "object", "required": ["path"], "additionalProperties": false, "properties": { "path": { "type": "string", "minLength": 1 }, "equals": {} } } ] },
|
|
101
102
|
"footnote": { "type": "string", "minLength": 1, "description": "choice: the same footnote under another name; note wins when both are set." },
|
|
102
103
|
"required": { "type": "boolean", "default": false, "description": "When true the step gates the app until done." },
|
|
103
104
|
"schema": { "description": "config-fields: a JSON Schema ref (string) or inline object rendered via fieldsFromSchema." },
|
|
@@ -2220,7 +2221,8 @@
|
|
|
2220
2221
|
},
|
|
2221
2222
|
"emptyLabel": { "type": "string", "description": "Empty-state message rendered instead of the chart when the resolved series contain no data points." },
|
|
2222
2223
|
"barMax": { "type": "number", "exclusiveMinimum": 0, "description": "chartKind 'bar-list': the value a full track stands for (100 for percentages). Omitted = the largest value." },
|
|
2223
|
-
"footnote": { "type": "string", "description": "
|
|
2224
|
+
"footnote": { "type": "string", "description": "A line under the chart, through the host's translate: under the rows of a bar-list or matrix, and under the plot of a line, area or bar chart." },
|
|
2225
|
+
"emptyCellLabel": { "type": "string", "description": "chartKind 'matrix': the text of a cell without a value (\"geen\"), through the host's translate. Empty leaves the cell blank. Passed through to CnChartWidget." },
|
|
2224
2226
|
"highlight": {
|
|
2225
2227
|
"type": "object",
|
|
2226
2228
|
"additionalProperties": false,
|
|
@@ -3737,7 +3739,58 @@
|
|
|
3737
3739
|
"enum": ["flows", "flowRuns", "tasks", "endpoint", "search", "users", "organisations"],
|
|
3738
3740
|
"description": "Name a registered NON-OBJECT entity collection for a type='index' page, instead of register+schema. Deliberately NOT called `source`: that key is already taken on page config and is polymorphic (a URL string in some manifests, an object with `params` in others), so reusing it would give one key two meanings and break six deployed shillinq pages. A flow definition is deliberately not an OpenRegister object, so an index had nothing to bind to and such lists became bespoke type='custom' pages. With a source the index loads the list itself. Takes precedence over register/schema; non-empty `objects` still wins over both. Registered sources live in src/composables/indexSources.js. `tasks` lists the viewer's task inbox from OpenRegister's flow-tasks read (cn-tasks-entity-source). `organisations` lists the OpenRegister organisations the viewer belongs to. On a type='detail' page a source that reads one record (today `organisations`) loads the record whose id is the route's objectId, instead of register+schema, and feeds the header, pills, widgets and @objectId / @object.* tokens like a fetched object (organisations-entity-source)."
|
|
3739
3741
|
},
|
|
3740
|
-
"
|
|
3742
|
+
"bulkBandAlways": { "type": "boolean", "default": false, "description": "type='index', board look: draw the bulk band (its actions and hint) before a selection too, its buttons disabled until rows are selected (DqZaken, DqWerkbord). Maps to CnIndexPage `bulkBandAlways`." },
|
|
3743
|
+
"quickFilterPlacement": { "type": "string", "enum": ["", "toolbar"], "default": "", "description": "type='index': where the quick-filter chips sit. `toolbar` keeps them on one row with the Filter button and the view switch beside a side panel, the chips that do not fit behind the overflow chip (DqTeamwachtrij). Maps to CnIndexPage `quickFilterPlacement`." },
|
|
3744
|
+
"rowClass": {
|
|
3745
|
+
"type": "array",
|
|
3746
|
+
"description": "type='index': per-row CSS class rules, compiled into the table's rowClass function as on the object-table widget. Each rule { when: { field, op?, value }, class } adds `class` to a row whose `field` (a dot-path) compares to `value` with `op` (default eq; the visibleWhen operators and tokens such as `@today`, with two dates compared as moments), e.g. an overdue task `{ when: { field: \"dueAt\", op: \"lt\", value: \"@today\" }, class: \"cn-row--overdue\" }`. Maps to CnIndexPage `rowClass`.",
|
|
3747
|
+
"items": {
|
|
3748
|
+
"type": "object",
|
|
3749
|
+
"additionalProperties": false,
|
|
3750
|
+
"required": [
|
|
3751
|
+
"when",
|
|
3752
|
+
"class"
|
|
3753
|
+
],
|
|
3754
|
+
"properties": {
|
|
3755
|
+
"when": {
|
|
3756
|
+
"type": "object",
|
|
3757
|
+
"additionalProperties": false,
|
|
3758
|
+
"required": [
|
|
3759
|
+
"field",
|
|
3760
|
+
"value"
|
|
3761
|
+
],
|
|
3762
|
+
"description": "The predicate evaluated against the row (shared visibleWhen grammar, LOCAL form).",
|
|
3763
|
+
"properties": {
|
|
3764
|
+
"field": {
|
|
3765
|
+
"type": "string",
|
|
3766
|
+
"description": "Dot-path into the row."
|
|
3767
|
+
},
|
|
3768
|
+
"op": {
|
|
3769
|
+
"type": "string",
|
|
3770
|
+
"enum": [
|
|
3771
|
+
"eq",
|
|
3772
|
+
"neq",
|
|
3773
|
+
"gt",
|
|
3774
|
+
"gte",
|
|
3775
|
+
"lt",
|
|
3776
|
+
"lte"
|
|
3777
|
+
],
|
|
3778
|
+
"default": "eq",
|
|
3779
|
+
"description": "Comparison operator (default eq)."
|
|
3780
|
+
},
|
|
3781
|
+
"value": {
|
|
3782
|
+
"description": "Literal right-hand side of the comparison."
|
|
3783
|
+
}
|
|
3784
|
+
}
|
|
3785
|
+
},
|
|
3786
|
+
"class": {
|
|
3787
|
+
"type": "string",
|
|
3788
|
+
"description": "CSS class added to the row when `when` holds."
|
|
3789
|
+
}
|
|
3790
|
+
}
|
|
3791
|
+
}
|
|
3792
|
+
},
|
|
3793
|
+
"sourceConfig": { "type": "object", "additionalProperties": true, "description": "type='index' with `entitySource`: what the named source loads with. `endpoint`: `url` (an app path, required) and `rowsPath` (default `results`); its other keys go along as query parameters. `search`: `kinds` (`{ id, label, register, schema, titleField?, subtitleField?, statusField?, href?, limit? }` or `{ id, label, files: true }`), `term` and `termQuery` (default `q`). `users`: `defaultGroup`, `functionField`, `rolesField`. `flows` / `tasks`: `app`, `scope`. Maps to CnIndexPage `sourceConfig`.", "properties": { "url": { "type": "string", "minLength": 1 }, "rowsPath": { "type": "string", "minLength": 1 }, "kinds": { "type": "array", "items": { "type": "object", "required": ["id"], "additionalProperties": true, "properties": { "id": { "type": "string", "minLength": 1 }, "label": { "type": "string" }, "register": { "type": "string" }, "schema": { "type": "string" }, "files": { "type": "boolean" } } } }, "term": { "type": "string" }, "termQuery": { "type": "string", "minLength": 1 }, "defaultGroup": { "type": "string", "minLength": 1 }, "limit": { "type": "integer", "minimum": 1, "description": "A paging source: rows per page (20 by default); the pager moves through the pages." } } },
|
|
3741
3794
|
"app": {
|
|
3742
3795
|
"type": "string",
|
|
3743
3796
|
"description": "Scopes a named `entitySource` to one app (e.g. entitySource='flows' with app='dossiq' lists that app's flows)."
|
|
@@ -4372,6 +4425,35 @@
|
|
|
4372
4425
|
"default": true,
|
|
4373
4426
|
"description": "type='dashboard' and type='detail': `false` drops the overflow Actions menu from every widget that does not set `showActions` itself, for a dashboard whose widget headers carry a header link and nothing else (zuiddrecht-pixel-gaps-2), or a record page whose data cards carry none (zuiddrecht-pixel-gaps-3; a card with an Add action keeps it). When the key is not set a detail page keeps the menu, except under the board look, where side cards carry none (screens-detail-page-parity). Maps to CnDashboardPage / CnDetailPage `showWidgetActions`."
|
|
4374
4427
|
},
|
|
4428
|
+
"pageFilters": {
|
|
4429
|
+
"type": "array",
|
|
4430
|
+
"description": "type='dashboard': page-level filter controls in the header. Each selection is written into the page's workspace context, so a widget reads it through a `@page.<key>` / `@workspace.<key>` token (an endpoint widget also in its `responsePath`). Maps to the CnDashboardPage `pageFilters` prop.",
|
|
4431
|
+
"items": {
|
|
4432
|
+
"type": "object",
|
|
4433
|
+
"required": ["key", "options"],
|
|
4434
|
+
"additionalProperties": false,
|
|
4435
|
+
"properties": {
|
|
4436
|
+
"key": { "type": "string", "minLength": 1, "description": "Workspace-context key written on change (the `@page.<key>` / `@workspace.<key>` token name)." },
|
|
4437
|
+
"label": { "type": "string", "description": "Control label (i18n key or plain text)." },
|
|
4438
|
+
"type": { "type": "string", "enum": ["select"], "default": "select", "description": "Control type, carried over from v1." },
|
|
4439
|
+
"control": { "type": "string", "enum": ["select", "segmented"], "default": "select", "description": "How the filter is drawn: a select, or a compact segmented group." },
|
|
4440
|
+
"placement": { "type": "string", "enum": ["row", "description"], "default": "row", "description": "Where the filter sits: in the header's filter row, or (a segmented group) on the description line after the period group (DqProcesanalyse)." },
|
|
4441
|
+
"default": { "type": ["string", "number"], "description": "Initial value seeded into the context on mount; the first option's value when omitted." },
|
|
4442
|
+
"options": {
|
|
4443
|
+
"type": "array",
|
|
4444
|
+
"items": {
|
|
4445
|
+
"type": "object",
|
|
4446
|
+
"required": ["value", "label"],
|
|
4447
|
+
"additionalProperties": false,
|
|
4448
|
+
"properties": {
|
|
4449
|
+
"value": { "type": ["string", "number"], "description": "Value written into the context when picked." },
|
|
4450
|
+
"label": { "type": "string", "description": "Display text (i18n key or plain text)." }
|
|
4451
|
+
}
|
|
4452
|
+
}
|
|
4453
|
+
}
|
|
4454
|
+
}
|
|
4455
|
+
}
|
|
4456
|
+
},
|
|
4375
4457
|
"kpiRow": {
|
|
4376
4458
|
"type": "array",
|
|
4377
4459
|
"items": { "type": "string" },
|
|
@@ -379,25 +379,45 @@ const CONNECTION_STATUS_LABELS = {
|
|
|
379
379
|
error: 'Error',
|
|
380
380
|
}
|
|
381
381
|
|
|
382
|
+
/**
|
|
383
|
+
* The short labels `formatterOptions.short` draws (board DqInstellingen
|
|
384
|
+
* "Aan / Uit / Fout"): a connection that works in some form is on, one that
|
|
385
|
+
* does not run is off, and a failing one is an error.
|
|
386
|
+
*/
|
|
387
|
+
const CONNECTION_STATUS_SHORT_LABELS = {
|
|
388
|
+
configured: 'On',
|
|
389
|
+
limited: 'On',
|
|
390
|
+
simulated: 'On',
|
|
391
|
+
unconfigured: 'Off',
|
|
392
|
+
disabled: 'Off',
|
|
393
|
+
unavailable: 'Off',
|
|
394
|
+
error: 'Error',
|
|
395
|
+
}
|
|
396
|
+
|
|
382
397
|
/**
|
|
383
398
|
* Connection status formatter (`connectionStatus` registry key) for the
|
|
384
399
|
* fleet connection registry. Renders one of the seven stored status values
|
|
385
400
|
* as its translated label through the library's own slug (`nextcloud-vue`).
|
|
401
|
+
* With `formatterOptions.short` it renders the board's three short labels
|
|
402
|
+
* instead: On (configured, limited, simulated), Off (not configured,
|
|
403
|
+
* switched off, not available) and Error.
|
|
386
404
|
*
|
|
387
405
|
* An unknown value passes through unchanged, so a status added later still
|
|
388
406
|
* shows as its raw value instead of an empty cell. Null and undefined render
|
|
389
407
|
* as `''`. Never throws.
|
|
390
408
|
*
|
|
391
409
|
* @param {unknown} value The stored status value.
|
|
410
|
+
* @param {object} [row] The row (unused).
|
|
411
|
+
* @param {object} [property] The column's property (unused).
|
|
412
|
+
* @param {{short?: boolean}} [options] The column's `formatterOptions`.
|
|
392
413
|
* @return {string} The translated label, or the value itself when it is not one of the seven.
|
|
393
414
|
*/
|
|
394
|
-
export function formatConnectionStatus(value) {
|
|
415
|
+
export function formatConnectionStatus(value, row, property, options) {
|
|
395
416
|
if (value === null || value === undefined) {
|
|
396
417
|
return ''
|
|
397
418
|
}
|
|
398
|
-
const
|
|
399
|
-
|
|
400
|
-
: null
|
|
419
|
+
const labels = options && options.short === true ? CONNECTION_STATUS_SHORT_LABELS : CONNECTION_STATUS_LABELS
|
|
420
|
+
const label = Object.hasOwn(labels, value) ? labels[value] : null
|
|
401
421
|
return label ? t('nextcloud-vue', label) : String(value)
|
|
402
422
|
}
|
|
403
423
|
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SPDX-FileCopyrightText: 2026 Conduction B.V.
|
|
3
|
+
* SPDX-License-Identifier: EUPL-1.2
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { getLanguage } from '@nextcloud/l10n'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The user's Nextcloud language as a bare code (`nl_NL` reads `nl`), or ''.
|
|
10
|
+
*
|
|
11
|
+
* @return {string} The code.
|
|
12
|
+
*/
|
|
13
|
+
function userLanguage() {
|
|
14
|
+
try {
|
|
15
|
+
return String(getLanguage() || '').split(/[-_]/)[0].toLowerCase()
|
|
16
|
+
} catch {
|
|
17
|
+
return ''
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The text of a value that may be a language map (`{ nl: 'Ontvangst', en:
|
|
23
|
+
* 'Intake' }`), in the user's Nextcloud language, then Dutch, then English,
|
|
24
|
+
* then the first text it holds. A plain value comes back as text; anything
|
|
25
|
+
* else as ''.
|
|
26
|
+
*
|
|
27
|
+
* @param {(string|number|object|null|undefined)} value The value.
|
|
28
|
+
* @return {string} The text.
|
|
29
|
+
* @spec openspec/changes/grouped-cards-widget/specs/grouped-cards-widget/spec.md#requirement-a-widget-draws-groups-of-cards-from-an-endpoint
|
|
30
|
+
*/
|
|
31
|
+
export function languageMapText(value) {
|
|
32
|
+
if (typeof value === 'string' || typeof value === 'number') {
|
|
33
|
+
return String(value)
|
|
34
|
+
}
|
|
35
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
36
|
+
return ''
|
|
37
|
+
}
|
|
38
|
+
const language = userLanguage()
|
|
39
|
+
for (const key of [language, 'nl', 'en']) {
|
|
40
|
+
if (key && typeof value[key] === 'string' && value[key] !== '') {
|
|
41
|
+
return value[key]
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const first = Object.values(value).find((text) => typeof text === 'string' && text !== '')
|
|
45
|
+
return first || ''
|
|
46
|
+
}
|
|
@@ -71,6 +71,8 @@ export const BUILT_IN_WIDGET_KEYS = Object.freeze([
|
|
|
71
71
|
'header',
|
|
72
72
|
'text',
|
|
73
73
|
'divider',
|
|
74
|
+
'saved-view-alert',
|
|
75
|
+
'exports',
|
|
74
76
|
])
|
|
75
77
|
|
|
76
78
|
/**
|
|
@@ -109,6 +111,7 @@ export const DASHBOARD_CATALOG_WIDGET_KEYS = Object.freeze([
|
|
|
109
111
|
'files',
|
|
110
112
|
'flow-runs',
|
|
111
113
|
'gauge',
|
|
114
|
+
'grouped-cards',
|
|
112
115
|
'header',
|
|
113
116
|
'image',
|
|
114
117
|
'interaction-form',
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SPDX-FileCopyrightText: 2026 Conduction B.V.
|
|
3
|
+
* SPDX-License-Identifier: EUPL-1.2
|
|
4
|
+
*/
|
|
5
|
+
import { isBadgeVariant } from './badgeVariants.js'
|
|
6
|
+
import { fillTemplate } from './fillTemplate.js'
|
|
7
|
+
import { readPath } from './readPath.js'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* The numbered list beside an index map (DqZakenKaart): one entry per row
|
|
11
|
+
* that has a place on the map, numbered in list order so the number on the
|
|
12
|
+
* pin and the number in the list are the same, and the rows without one.
|
|
13
|
+
*
|
|
14
|
+
* `spec` is `mapConfig.list`: `{ title, sub?, pills?: [{ path?, text?, map?,
|
|
15
|
+
* colorMap? }], due? }`. `title`, `sub` and `due` are field templates
|
|
16
|
+
* (`"{title}"`, `"{address} · {identifier}"`, `"{deadline|date}"`), already
|
|
17
|
+
* translated by the caller; a pill reads `path` (or shows `text`), maps it
|
|
18
|
+
* through `map`, and takes its tone from `colorMap` by the raw value.
|
|
19
|
+
*
|
|
20
|
+
* @param {Array<object>} rows The rows, in display order.
|
|
21
|
+
* @param {object} spec The list declaration.
|
|
22
|
+
* @param {object} options How to read a row.
|
|
23
|
+
* @param {string} options.rowKey The row's key field.
|
|
24
|
+
* @param {Function} options.located Whether a row has a place on the map.
|
|
25
|
+
* @param {Function} [options.translate] The host's translate, for pill labels.
|
|
26
|
+
* @return {{items: Array<{key: string, n: number, row: object, title: string, sub: string, due: string, pills: Array<{label: string, variant: string}>}>, missing: Array<object>}}
|
|
27
|
+
*/
|
|
28
|
+
export function mapListItems(rows, spec, { rowKey, located, translate = (text) => text }) {
|
|
29
|
+
const items = []
|
|
30
|
+
const missing = []
|
|
31
|
+
const list = spec && typeof spec === 'object' ? spec : {}
|
|
32
|
+
for (const row of Array.isArray(rows) ? rows : []) {
|
|
33
|
+
if (!located(row)) {
|
|
34
|
+
missing.push(row)
|
|
35
|
+
continue
|
|
36
|
+
}
|
|
37
|
+
const pills = (Array.isArray(list.pills) ? list.pills : [])
|
|
38
|
+
.map((pill) => {
|
|
39
|
+
if (!pill || typeof pill !== 'object') {
|
|
40
|
+
return null
|
|
41
|
+
}
|
|
42
|
+
const raw = typeof pill.path === 'string' && pill.path !== '' ? readPath(row, pill.path) : undefined
|
|
43
|
+
const mapped = pill.map && (typeof raw === 'string' || typeof raw === 'number') && Object.hasOwn(pill.map, raw) ? pill.map[raw] : undefined
|
|
44
|
+
const text = mapped ?? pill.text ?? raw
|
|
45
|
+
if (typeof text !== 'string' && typeof text !== 'number') {
|
|
46
|
+
return null
|
|
47
|
+
}
|
|
48
|
+
const label = translate(String(text))
|
|
49
|
+
if (label === '') {
|
|
50
|
+
return null
|
|
51
|
+
}
|
|
52
|
+
const tone = pill.colorMap && (typeof raw === 'string' || typeof raw === 'number') ? pill.colorMap[raw] : pill.variant
|
|
53
|
+
return { label, variant: isBadgeVariant(tone) ? tone : 'default' }
|
|
54
|
+
})
|
|
55
|
+
.filter(Boolean)
|
|
56
|
+
items.push({
|
|
57
|
+
key: String(row[rowKey]),
|
|
58
|
+
n: items.length + 1,
|
|
59
|
+
row,
|
|
60
|
+
title: fillTemplate(list.title || '', row),
|
|
61
|
+
sub: fillTemplate(list.sub || '', row),
|
|
62
|
+
due: fillTemplate(list.due || '', row),
|
|
63
|
+
pills,
|
|
64
|
+
})
|
|
65
|
+
}
|
|
66
|
+
return { items, missing }
|
|
67
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SPDX-FileCopyrightText: 2026 Conduction B.V.
|
|
3
|
+
* SPDX-License-Identifier: EUPL-1.2
|
|
4
|
+
*/
|
|
5
|
+
import { compareVisibleWhen, readVisibleWhenPath } from './visibleWhen.js'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Compile a row-class declaration into the `(row) => string` CnDataTable
|
|
9
|
+
* takes. A function passes straight through. An array of rules
|
|
10
|
+
* `[{ when: { field, op?, value }, class }]` adds each rule's `class` to a row
|
|
11
|
+
* whose `field` (a dot-path) compares to `value` with `op` (`eq` by default;
|
|
12
|
+
* the shared `visibleWhen` operators, `@today` and the other tokens included),
|
|
13
|
+
* every matching class space-joined: an overdue row can be marked from the
|
|
14
|
+
* manifest (`{ when: { field: "dueAt", op: "lt", value: "@today" }, class:
|
|
15
|
+
* "cn-row--overdue" }`). Anything else, or an empty list, is null.
|
|
16
|
+
*
|
|
17
|
+
* @param {Function|Array<{when: {field: string, op?: string, value: unknown}, class: string}>|null} rowClass The declaration.
|
|
18
|
+
* @return {?(row: object) => string} The row-class function, or null.
|
|
19
|
+
*/
|
|
20
|
+
export function compileRowClass(rowClass) {
|
|
21
|
+
if (typeof rowClass === 'function') {
|
|
22
|
+
return rowClass
|
|
23
|
+
}
|
|
24
|
+
if (!Array.isArray(rowClass) || rowClass.length === 0) {
|
|
25
|
+
return null
|
|
26
|
+
}
|
|
27
|
+
const rules = rowClass.filter((rule) => rule && typeof rule.class === 'string' && rule.class !== '')
|
|
28
|
+
return (row) => {
|
|
29
|
+
const classes = []
|
|
30
|
+
for (const rule of rules) {
|
|
31
|
+
const when = rule.when || {}
|
|
32
|
+
const actual = readVisibleWhenPath(row, when.field)
|
|
33
|
+
if (compareVisibleWhen(actual, when.op || 'eq', when.value)) {
|
|
34
|
+
classes.push(rule.class)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return classes.join(' ')
|
|
38
|
+
}
|
|
39
|
+
}
|