@conduction/nextcloud-vue 2.73.0 → 2.73.1
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/CnAppRoot/CnAppRoot.vue2.js +29 -0
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js.map +1 -1
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +18 -0
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +9 -6
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js +16 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js +5 -4
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +16 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +6 -6
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnNotificationPreferences/CnNotificationPreferences.vue2.js +53 -5
- package/dist/esm/components/CnNotificationPreferences/CnNotificationPreferences.vue2.js.map +1 -1
- package/dist/esm/components/CnNotificationPreferences/CnNotificationPreferences.vue3.js +1 -1
- package/dist/esm/components/CnNotificationPreferences/CnNotificationPreferences.vue3.js.map +1 -1
- package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue2.js +133 -0
- package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue2.js.map +1 -1
- package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue3.js +22 -14
- package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue3.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +15 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js +3 -2
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnWidgetGrid/CnWidgetGrid.vue2.js +15 -1
- package/dist/esm/components/CnWidgetGrid/CnWidgetGrid.vue2.js.map +1 -1
- package/dist/esm/components/CnWidgetGrid/CnWidgetGrid.vue3.js +2 -2
- package/dist/esm/components/CnWidgetGrid/CnWidgetGrid.vue3.js.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/utils/notificationRuleLabel.js +132 -0
- package/dist/esm/utils/notificationRuleLabel.js.map +1 -0
- package/dist/nextcloud-vue.cjs.js +473 -43
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/package.json +1 -1
- package/src/components/CnAppRoot/CnAppRoot.md +1 -0
- package/src/components/CnAppRoot/CnAppRoot.vue +29 -0
- package/src/components/CnDetailPage/CnDetailPage.vue +24 -3
- package/src/components/CnDetailWidgetHost/CnDetailWidgetHost.vue +22 -4
- package/src/components/CnIndexPage/CnIndexPage.vue +17 -2
- package/src/components/CnNotificationPreferences/CnNotificationPreferences.vue +54 -6
- package/src/components/CnPageRenderer/CnPageRenderer.vue +147 -6
- package/src/components/CnTabsWidget/CnTabsWidget.vue +17 -2
- package/src/components/CnWidgetGrid/CnWidgetGrid.vue +19 -3
- package/src/index.js +2 -0
- package/src/utils/notificationRuleLabel.js +129 -0
- package/webpack/index.d.ts +16 -0
- package/webpack/index.js +70 -0
|
@@ -136551,7 +136551,7 @@ var script$3W = {
|
|
|
136551
136551
|
},
|
|
136552
136552
|
},
|
|
136553
136553
|
|
|
136554
|
-
emits: ['geo-saved', 'open-integration'],
|
|
136554
|
+
emits: ['geo-saved', 'open-integration', 'select-object'],
|
|
136555
136555
|
|
|
136556
136556
|
setup() {
|
|
136557
136557
|
// Every integration component this host renders goes through the
|
|
@@ -137056,6 +137056,21 @@ var script$3W = {
|
|
|
137056
137056
|
this.$emit('open-integration', integrationId);
|
|
137057
137057
|
},
|
|
137058
137058
|
|
|
137059
|
+
/**
|
|
137060
|
+
* Pass a related-object click up; the page decides where it opens. Heard
|
|
137061
|
+
* from the Related widget itself and from a registry widget that nests a
|
|
137062
|
+
* host of its own (a Tabs widget with a Related tab).
|
|
137063
|
+
*
|
|
137064
|
+
* @param {object} raw The clicked object as the related widget holds it.
|
|
137065
|
+
*/
|
|
137066
|
+
onSelectObject(raw) {
|
|
137067
|
+
/**
|
|
137068
|
+
* @event select-object A related object was clicked in the related widget. Payload is the raw object; its `@self` names the register and schema.
|
|
137069
|
+
* @type {object}
|
|
137070
|
+
*/
|
|
137071
|
+
this.$emit('select-object', raw);
|
|
137072
|
+
},
|
|
137073
|
+
|
|
137059
137074
|
/**
|
|
137060
137075
|
* Delegate to the rendered list widget's own create affordance, so the
|
|
137061
137076
|
* card's Add action and the widget's footer button open the same form.
|
|
@@ -137158,8 +137173,9 @@ function render$3W(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
137158
137173
|
includeGroups: $options.content.groups || [],
|
|
137159
137174
|
hideSingleTabTitle: $options.content.hideSingleTabTitle !== false,
|
|
137160
137175
|
showTotalCount: $options.content.showTotalCount !== false,
|
|
137161
|
-
onOpenIntegration: $options.onOpenIntegration
|
|
137162
|
-
|
|
137176
|
+
onOpenIntegration: $options.onOpenIntegration,
|
|
137177
|
+
onSelectObject: $options.onSelectObject
|
|
137178
|
+
}, null, 8 /* PROPS */, ["title", "bare", "objectType", "objectId", "objectData", "register", "schema", "store", "includeGroups", "hideSingleTabTitle", "showTotalCount", "onOpenIntegration", "onSelectObject"]))
|
|
137163
137179
|
: ($options.isGeo)
|
|
137164
137180
|
? (vue$1.openBlock(), vue$1.createBlock(_component_CnObjectGeoWidget, {
|
|
137165
137181
|
key: 3,
|
|
@@ -137198,7 +137214,7 @@ function render$3W(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
137198
137214
|
class: "cn-detail-page__catalog-card"
|
|
137199
137215
|
}, vue$1.createSlots({
|
|
137200
137216
|
default: vue$1.withCtx(() => [
|
|
137201
|
-
(vue$1.openBlock(), vue$1.createBlock(vue$1.resolveDynamicComponent($options.renderer), vue$1.mergeProps({ ref: "renderer" }, $options.rendererProps), null, 16 /* FULL_PROPS
|
|
137217
|
+
(vue$1.openBlock(), vue$1.createBlock(vue$1.resolveDynamicComponent($options.renderer), vue$1.mergeProps({ ref: "renderer" }, $options.rendererProps, { onSelectObject: $options.onSelectObject }), null, 16 /* FULL_PROPS */, ["onSelectObject"]))
|
|
137202
137218
|
]),
|
|
137203
137219
|
_: 2 /* DYNAMIC */
|
|
137204
137220
|
}, [
|
|
@@ -137266,7 +137282,7 @@ function render$3W(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
137266
137282
|
? (vue$1.openBlock(), vue$1.createBlock(vue$1.resolveDynamicComponent($options.renderer), vue$1.mergeProps({
|
|
137267
137283
|
key: 8,
|
|
137268
137284
|
ref: "renderer"
|
|
137269
|
-
}, $options.rendererProps), null, 16 /* FULL_PROPS
|
|
137285
|
+
}, $options.rendererProps, { onSelectObject: $options.onSelectObject }), null, 16 /* FULL_PROPS */, ["onSelectObject"]))
|
|
137270
137286
|
: vue$1.createCommentVNode("v-if", true)
|
|
137271
137287
|
], 2 /* CLASS */))
|
|
137272
137288
|
}
|
|
@@ -138248,7 +138264,7 @@ var script$3T = {
|
|
|
138248
138264
|
},
|
|
138249
138265
|
},
|
|
138250
138266
|
|
|
138251
|
-
emits: ['geo-saved', 'open-integration'],
|
|
138267
|
+
emits: ['geo-saved', 'open-integration', 'select-object'],
|
|
138252
138268
|
|
|
138253
138269
|
data() {
|
|
138254
138270
|
return {
|
|
@@ -138421,6 +138437,20 @@ var script$3T = {
|
|
|
138421
138437
|
this.$emit('open-integration', integrationId);
|
|
138422
138438
|
},
|
|
138423
138439
|
|
|
138440
|
+
/**
|
|
138441
|
+
* Re-emit a related child's object click; the page opens the object.
|
|
138442
|
+
*
|
|
138443
|
+
* @param {object} raw The clicked object.
|
|
138444
|
+
* @return {void}
|
|
138445
|
+
*/
|
|
138446
|
+
onSelectObject(raw) {
|
|
138447
|
+
/**
|
|
138448
|
+
* @event select-object Re-emitted from a related child whose object row was clicked. Payload is the raw object.
|
|
138449
|
+
* @type {object}
|
|
138450
|
+
*/
|
|
138451
|
+
this.$emit('select-object', raw);
|
|
138452
|
+
},
|
|
138453
|
+
|
|
138424
138454
|
/**
|
|
138425
138455
|
* Follow the strip's own selection, so keyboard navigation moves the
|
|
138426
138456
|
* hoisted Actions menu too.
|
|
@@ -138547,8 +138577,9 @@ function render$3T(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
138547
138577
|
integrationContext: $props.integrationContext,
|
|
138548
138578
|
cnRegistry: $props.cnRegistry,
|
|
138549
138579
|
onGeoSaved: $options.onGeoSaved,
|
|
138550
|
-
onOpenIntegration: $options.onOpenIntegration
|
|
138551
|
-
|
|
138580
|
+
onOpenIntegration: $options.onOpenIntegration,
|
|
138581
|
+
onSelectObject: $options.onSelectObject
|
|
138582
|
+
}, null, 8 /* PROPS */, ["widget", "objectId", "object", "objectType", "schemaObject", "register", "schema", "store", "surface", "integrationContext", "cnRegistry", "onGeoSaved", "onOpenIntegration", "onSelectObject"]))
|
|
138552
138583
|
: (vue$1.openBlock(), vue$1.createBlock(_component_NcEmptyContent, {
|
|
138553
138584
|
key: 1,
|
|
138554
138585
|
name: $options.missingLabel(entry)
|
|
@@ -248344,7 +248375,7 @@ function namedFilterToQuery(values) {
|
|
|
248344
248375
|
* @event {object} row-aux-click — Table row or card middle-clicked. Payload: (row, event) — the row object and the native auxclick event
|
|
248345
248376
|
* @event {{ key: string, order: string }} sort — Column sort changed
|
|
248346
248377
|
* @event {number} page-changed — Pagination page changed
|
|
248347
|
-
* @event {number} page-size-changed — Pagination page size changed
|
|
248378
|
+
* @event {number} page-size-changed — Pagination page size changed. In self-fetch mode the list refetches page 1 at the new size first.
|
|
248348
248379
|
* @event {string[]} select — Selection changed. Payload: array of selected IDs
|
|
248349
248380
|
* @event {object} action — Row action triggered. Payload: { action, row }
|
|
248350
248381
|
* @event {{ action: string, id: string, selectedIds: Array, count: number }} bulk-action — A declarative bulk action was triggered from the selection strip. The SELECTION travels with it: an action that has to go and find out what was selected is one re-render away from acting on a different set than the user saw highlighted.
|
|
@@ -252769,6 +252800,21 @@ var script$1A = {
|
|
|
252769
252800
|
this.$emit('page-changed', page);
|
|
252770
252801
|
},
|
|
252771
252802
|
|
|
252803
|
+
/**
|
|
252804
|
+
* Page-size pick from CnPagination. In self-fetch mode the list refetches
|
|
252805
|
+
* page 1 at the new size — the event alone left the select changing and
|
|
252806
|
+
* the table not, since a manifest page has no host listening.
|
|
252807
|
+
*
|
|
252808
|
+
* @param {number} size Requested page size.
|
|
252809
|
+
* @return {void}
|
|
252810
|
+
*/
|
|
252811
|
+
onPageSizeEvent(size) {
|
|
252812
|
+
if (this.isSelfFetchMode && typeof this.list.onPageSizeChange === 'function') {
|
|
252813
|
+
this.list.onPageSizeChange(size);
|
|
252814
|
+
}
|
|
252815
|
+
this.$emit('page-size-changed', size);
|
|
252816
|
+
},
|
|
252817
|
+
|
|
252772
252818
|
/**
|
|
252773
252819
|
* @param {{key: string, values: Array}} payload Facet-filter change from the sidebar.
|
|
252774
252820
|
* @return {void}
|
|
@@ -254376,7 +254422,7 @@ function render$1A(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
254376
254422
|
return (vue$1.openBlock(), vue$1.createElementBlock("div", {
|
|
254377
254423
|
class: "cn-index-page",
|
|
254378
254424
|
"data-testid": "cn-index-page",
|
|
254379
|
-
onKeydown: _cache[
|
|
254425
|
+
onKeydown: _cache[25] || (_cache[25] = (...args) => ($options.onListKeydown && $options.onListKeydown(...args)))
|
|
254380
254426
|
}, [
|
|
254381
254427
|
vue$1.renderSlot(_ctx.$slots, "header", {
|
|
254382
254428
|
title: $props.title,
|
|
@@ -254866,7 +254912,7 @@ function render$1A(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
254866
254912
|
'cn-index-page__main--table': $data.currentViewMode === 'table',
|
|
254867
254913
|
'cn-index-page__main--split': $options.splitLayout === 'split',
|
|
254868
254914
|
}]),
|
|
254869
|
-
onScroll: _cache[
|
|
254915
|
+
onScroll: _cache[22] || (_cache[22] = (...args) => ($options.onListScroll && $options.onListScroll(...args)))
|
|
254870
254916
|
}, [
|
|
254871
254917
|
vue$1.renderSlot(_ctx.$slots, "before-collection"),
|
|
254872
254918
|
($options.showInitialLoader)
|
|
@@ -255235,8 +255281,8 @@ function render$1A(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
255235
255281
|
currentPageSize: $options.effectivePagination.limit || 20,
|
|
255236
255282
|
class: "cn-index-page__pagination",
|
|
255237
255283
|
onPageChanged: $options.onPageEvent,
|
|
255238
|
-
onPageSizeChanged:
|
|
255239
|
-
}, null, 8 /* PROPS */, ["currentPage", "totalPages", "totalItems", "currentPageSize", "onPageChanged"]))
|
|
255284
|
+
onPageSizeChanged: $options.onPageSizeEvent
|
|
255285
|
+
}, null, 8 /* PROPS */, ["currentPage", "totalPages", "totalItems", "currentPageSize", "onPageChanged", "onPageSizeChanged"]))
|
|
255240
255286
|
: vue$1.createCommentVNode("v-if", true)
|
|
255241
255287
|
], 34 /* CLASS, NEED_HYDRATION */), [
|
|
255242
255288
|
[vue$1.vShow, $options.splitLayout !== 'detail']
|
|
@@ -255256,7 +255302,7 @@ function render$1A(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
255256
255302
|
href: $options.splitCloseHref,
|
|
255257
255303
|
title: $options.splitCloseTitle,
|
|
255258
255304
|
"data-testid": "cn-index-page-split-close",
|
|
255259
|
-
onClick: _cache[
|
|
255305
|
+
onClick: _cache[23] || (_cache[23] = vue$1.withModifiers((...args) => ($options.closeSplitPane && $options.closeSplitPane(...args)), ["prevent"]))
|
|
255260
255306
|
}, [
|
|
255261
255307
|
vue$1.createVNode(_component_Close, { size: 16 }),
|
|
255262
255308
|
vue$1.createElementVNode("span", null, vue$1.toDisplayString($options.splitCloseTitle), 1 /* TEXT */)
|
|
@@ -255286,7 +255332,7 @@ function render$1A(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
255286
255332
|
facetData: $options.effectiveFacetData,
|
|
255287
255333
|
showMetadata: $options.resolvedSidebar.showMetadata !== false
|
|
255288
255334
|
}, $options.sidebarSearchProps, {
|
|
255289
|
-
"onUpdate:open": _cache[
|
|
255335
|
+
"onUpdate:open": _cache[24] || (_cache[24] = $event => ($data.sidebarOpen = $event)),
|
|
255290
255336
|
onSearch: $options.onSearchEvent,
|
|
255291
255337
|
onColumnsChange: $options.onColumnsEvent,
|
|
255292
255338
|
onFilterChange: $options.onFilterEvent,
|
|
@@ -268586,6 +268632,7 @@ var script$1c = {
|
|
|
268586
268632
|
'layout-change',
|
|
268587
268633
|
'open-integration',
|
|
268588
268634
|
'refresh',
|
|
268635
|
+
'related-object-click',
|
|
268589
268636
|
'related-row-click',
|
|
268590
268637
|
'relation-linked',
|
|
268591
268638
|
'request-feature',
|
|
@@ -270567,6 +270614,23 @@ var script$1c = {
|
|
|
270567
270614
|
this.$emit('open-integration', integrationId);
|
|
270568
270615
|
},
|
|
270569
270616
|
|
|
270617
|
+
/**
|
|
270618
|
+
* Re-emit a click on an object in the Related widget. The page does not
|
|
270619
|
+
* know the routes; the host (CnPageRenderer on a manifest page) opens
|
|
270620
|
+
* the object's own detail page.
|
|
270621
|
+
*
|
|
270622
|
+
* @param {object} raw The clicked object; `@self` names its register and schema.
|
|
270623
|
+
*/
|
|
270624
|
+
onRelatedObjectSelect(raw) {
|
|
270625
|
+
/**
|
|
270626
|
+
* @event related-object-click An object in the Related widget was
|
|
270627
|
+
* clicked. Payload is the raw object; `@self` carries its register,
|
|
270628
|
+
* schema and id.
|
|
270629
|
+
* @type {object}
|
|
270630
|
+
*/
|
|
270631
|
+
this.$emit('related-object-click', raw);
|
|
270632
|
+
},
|
|
270633
|
+
|
|
270570
270634
|
/**
|
|
270571
270635
|
* Re-fetch the object after the geo widget persists `@self.geo` (so the
|
|
270572
270636
|
* rest of the page — metadata, other widgets — reflects the new value),
|
|
@@ -272377,8 +272441,9 @@ function render$1c(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
272377
272441
|
cnRegistry: $options.cnRegistry,
|
|
272378
272442
|
availableWidgets: _ctx.widgets,
|
|
272379
272443
|
onGeoSaved: $options.onGeoSaved,
|
|
272380
|
-
onOpenIntegration: $options.onAutoBodyOpenIntegration
|
|
272381
|
-
|
|
272444
|
+
onOpenIntegration: $options.onAutoBodyOpenIntegration,
|
|
272445
|
+
onSelectObject: $options.onRelatedObjectSelect
|
|
272446
|
+
}, null, 8 /* PROPS */, ["widget", "objectId", "object", "objectType", "schemaObject", "register", "schema", "store", "surface", "integrationContext", "hideEmpty", "cnRegistry", "availableWidgets", "onGeoSaved", "onOpenIntegration", "onSelectObject"])
|
|
272382
272447
|
])
|
|
272383
272448
|
]))
|
|
272384
272449
|
: vue$1.createCommentVNode("v-if", true)
|
|
@@ -272602,8 +272667,9 @@ function render$1c(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
272602
272667
|
cnRegistry: $options.cnRegistry,
|
|
272603
272668
|
availableWidgets: $options.bodyGridWidgets,
|
|
272604
272669
|
onGeoSaved: $options.onGeoSaved,
|
|
272605
|
-
onOpenIntegration: $options.onAutoBodyOpenIntegration
|
|
272606
|
-
|
|
272670
|
+
onOpenIntegration: $options.onAutoBodyOpenIntegration,
|
|
272671
|
+
onSelectObject: $options.onRelatedObjectSelect
|
|
272672
|
+
}, null, 8 /* PROPS */, ["widget", "showCardTitle", "showActions", "objectId", "object", "objectType", "schemaObject", "register", "schema", "store", "surface", "integrationContext", "hideEmpty", "cnRegistry", "availableWidgets", "onGeoSaved", "onOpenIntegration", "onSelectObject"])
|
|
272607
272673
|
])
|
|
272608
272674
|
], 10 /* CLASS, PROPS */, _hoisted_19$8)
|
|
272609
272675
|
]),
|
|
@@ -272784,8 +272850,9 @@ function render$1c(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
272784
272850
|
cnRegistry: $options.cnRegistry,
|
|
272785
272851
|
availableWidgets: _ctx.widgets,
|
|
272786
272852
|
onGeoSaved: $options.onGeoSaved,
|
|
272787
|
-
onOpenIntegration: $options.onAutoBodyOpenIntegration
|
|
272788
|
-
|
|
272853
|
+
onOpenIntegration: $options.onAutoBodyOpenIntegration,
|
|
272854
|
+
onSelectObject: $options.onRelatedObjectSelect
|
|
272855
|
+
}, null, 8 /* PROPS */, ["widget", "showActions", "objectId", "object", "objectType", "schemaObject", "register", "schema", "store", "surface", "integrationContext", "hideEmpty", "cnRegistry", "availableWidgets", "onGeoSaved", "onOpenIntegration", "onSelectObject"])
|
|
272789
272856
|
])
|
|
272790
272857
|
], 8 /* PROPS */, _hoisted_34$1))
|
|
272791
272858
|
}), 128 /* KEYED_FRAGMENT */))
|
|
@@ -295314,7 +295381,7 @@ var script$s = {
|
|
|
295314
295381
|
},
|
|
295315
295382
|
},
|
|
295316
295383
|
|
|
295317
|
-
emits: ['layout-change'],
|
|
295384
|
+
emits: ['layout-change', 'select-object'],
|
|
295318
295385
|
|
|
295319
295386
|
data() {
|
|
295320
295387
|
return {
|
|
@@ -295524,6 +295591,20 @@ var script$s = {
|
|
|
295524
295591
|
},
|
|
295525
295592
|
|
|
295526
295593
|
methods: {
|
|
295594
|
+
/**
|
|
295595
|
+
* Pass a related widget's object click up; the page opens the object.
|
|
295596
|
+
*
|
|
295597
|
+
* @param {object} raw The clicked object.
|
|
295598
|
+
* @return {void}
|
|
295599
|
+
*/
|
|
295600
|
+
onSelectObject(raw) {
|
|
295601
|
+
/**
|
|
295602
|
+
* @event select-object An object row in a related widget of this grid was clicked. Payload is the raw object.
|
|
295603
|
+
* @type {object}
|
|
295604
|
+
*/
|
|
295605
|
+
this.$emit('select-object', raw);
|
|
295606
|
+
},
|
|
295607
|
+
|
|
295527
295608
|
// Expose the shared grid helpers to the template.
|
|
295528
295609
|
cnGridCellStyle,
|
|
295529
295610
|
hasGridRow,
|
|
@@ -295618,7 +295699,7 @@ function render$s(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
295618
295699
|
"gs-h": widget.gridHeight
|
|
295619
295700
|
}, [
|
|
295620
295701
|
vue$1.createElementVNode("div", _hoisted_4$v, [
|
|
295621
|
-
(vue$1.openBlock(), vue$1.createBlock(vue$1.resolveDynamicComponent(widget.component), vue$1.mergeProps({ ref_for: true }, widget.props), null, 16 /* FULL_PROPS
|
|
295702
|
+
(vue$1.openBlock(), vue$1.createBlock(vue$1.resolveDynamicComponent(widget.component), vue$1.mergeProps({ ref_for: true }, widget.props, { onSelectObject: $options.onSelectObject }), null, 16 /* FULL_PROPS */, ["onSelectObject"]))
|
|
295622
295703
|
])
|
|
295623
295704
|
], 8 /* PROPS */, _hoisted_3$w))
|
|
295624
295705
|
}), 128 /* KEYED_FRAGMENT */))
|
|
@@ -295636,7 +295717,7 @@ function render$s(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
295636
295717
|
class: vue$1.normalizeClass(["cn-grid__item", { 'cn-grid__item--row': $options.hasGridRow(widget) }]),
|
|
295637
295718
|
style: vue$1.normalizeStyle($options.cnGridCellStyle(widget, $options.gridColumns))
|
|
295638
295719
|
}, [
|
|
295639
|
-
(vue$1.openBlock(), vue$1.createBlock(vue$1.resolveDynamicComponent(widget.component), vue$1.mergeProps({ ref_for: true }, widget.props), null, 16 /* FULL_PROPS
|
|
295720
|
+
(vue$1.openBlock(), vue$1.createBlock(vue$1.resolveDynamicComponent(widget.component), vue$1.mergeProps({ ref_for: true }, widget.props, { onSelectObject: $options.onSelectObject }), null, 16 /* FULL_PROPS */, ["onSelectObject"]))
|
|
295640
295721
|
], 6 /* CLASS, STYLE */))
|
|
295641
295722
|
}), 128 /* KEYED_FRAGMENT */))
|
|
295642
295723
|
], 14 /* CLASS, STYLE, PROPS */, _hoisted_5$j))
|
|
@@ -296139,6 +296220,53 @@ const defaultPageTypes = {
|
|
|
296139
296220
|
'flow-detail': vue$1.defineAsyncComponent(() => Promise.resolve().then(function () { return CnFlowEditorPage; }).then((m) => m.default)),
|
|
296140
296221
|
};
|
|
296141
296222
|
|
|
296223
|
+
/**
|
|
296224
|
+
* OpenRegister registers and schemas already described by id, so a click on
|
|
296225
|
+
* a related object costs at most one request per register or schema for as
|
|
296226
|
+
* long as this module stays loaded (the SPA's lifetime, across page
|
|
296227
|
+
* changes). Keyed by `${kind}:${id}`; a failed lookup is dropped again so the
|
|
296228
|
+
* next click retries it.
|
|
296229
|
+
*
|
|
296230
|
+
* @type {Map<string, Promise<{ id: string, slug: string }>>}
|
|
296231
|
+
*/
|
|
296232
|
+
const entityDescriptorCache = new Map();
|
|
296233
|
+
|
|
296234
|
+
/**
|
|
296235
|
+
* Describe an OpenRegister register or schema (`{ id, slug }`) by its id or
|
|
296236
|
+
* slug, or null when it cannot be fetched. An object's `@self` names its
|
|
296237
|
+
* register and schema by id while a manifest may name them by slug; this is
|
|
296238
|
+
* the bridge. Lazy-imports axios and the router helper like the widgets do.
|
|
296239
|
+
*
|
|
296240
|
+
* @param {'registers'|'schemas'} kind The collection to ask.
|
|
296241
|
+
* @param {string|number} idOrSlug The id (or slug) to describe.
|
|
296242
|
+
* @return {Promise<{ id: string, slug: string }|null>} The descriptor.
|
|
296243
|
+
*/
|
|
296244
|
+
function describeOpenRegisterEntity(kind, idOrSlug) {
|
|
296245
|
+
const key = `${kind}:${idOrSlug}`;
|
|
296246
|
+
if (!entityDescriptorCache.has(key)) {
|
|
296247
|
+
entityDescriptorCache.set(key, (async () => {
|
|
296248
|
+
try {
|
|
296249
|
+
const [{ default: axios }, { generateUrl }] = await Promise.all([
|
|
296250
|
+
import('@nextcloud/axios'),
|
|
296251
|
+
import('@nextcloud/router'),
|
|
296252
|
+
]);
|
|
296253
|
+
const url = generateUrl('/apps/openregister/api/{kind}/{id}', { kind, id: String(idOrSlug) });
|
|
296254
|
+
const res = await axios.get(url);
|
|
296255
|
+
const data = res && res.data;
|
|
296256
|
+
if (!data || typeof data !== 'object') {
|
|
296257
|
+
throw new Error(`no descriptor for ${key}`)
|
|
296258
|
+
}
|
|
296259
|
+
return { id: String(data.id ?? idOrSlug), slug: String(data.slug ?? '') }
|
|
296260
|
+
} catch (error) {
|
|
296261
|
+
// One failed request must not pin every later click to nowhere.
|
|
296262
|
+
entityDescriptorCache.delete(key);
|
|
296263
|
+
throw error
|
|
296264
|
+
}
|
|
296265
|
+
})());
|
|
296266
|
+
}
|
|
296267
|
+
return entityDescriptorCache.get(key).catch(() => null)
|
|
296268
|
+
}
|
|
296269
|
+
|
|
296142
296270
|
/** Recognised fixed slot names for v2 manifests. */
|
|
296143
296271
|
const KNOWN_SLOTS = new Set(['body', 'sidebar', 'header-actions', 'footer', 'modal']);
|
|
296144
296272
|
|
|
@@ -297666,6 +297794,92 @@ var script$r = {
|
|
|
297666
297794
|
})
|
|
297667
297795
|
},
|
|
297668
297796
|
|
|
297797
|
+
/**
|
|
297798
|
+
* Open the detail page of an object clicked in a Related widget —
|
|
297799
|
+
* reaching here as `CnDetailPage`'s `related-object-click`, or as
|
|
297800
|
+
* `CnWidgetGrid`'s `select-object` on a v2 widget-grid page. Nothing
|
|
297801
|
+
* listened to either, so the rows looked like links and went nowhere.
|
|
297802
|
+
*
|
|
297803
|
+
* @param {object} raw The clicked object as the Related widget holds it.
|
|
297804
|
+
* @return {Promise<void>}
|
|
297805
|
+
*/
|
|
297806
|
+
async onRelatedObjectOpen(raw) {
|
|
297807
|
+
const target = await this.relatedObjectTarget(raw);
|
|
297808
|
+
if (target) {
|
|
297809
|
+
this.$router.push(target).catch(() => {});
|
|
297810
|
+
}
|
|
297811
|
+
},
|
|
297812
|
+
|
|
297813
|
+
/**
|
|
297814
|
+
* Where a related object opens: the first `type: 'detail'` page bound
|
|
297815
|
+
* to the object's register and schema, with the id in whichever param
|
|
297816
|
+
* that page's route declares. The object's `@self` names register and
|
|
297817
|
+
* schema by id and a manifest may name them by slug, so a miss on the
|
|
297818
|
+
* literal pair describes both (one request each, cached) and matches
|
|
297819
|
+
* again. Null, silently, when there is no router or the object carries
|
|
297820
|
+
* no register, schema or id (nothing to open); null with a warning,
|
|
297821
|
+
* like a dead row click, when no detail page matches or the router
|
|
297822
|
+
* lacks the route.
|
|
297823
|
+
*
|
|
297824
|
+
* @param {object} raw The clicked object.
|
|
297825
|
+
* @return {Promise<object|null>} The router location, or null.
|
|
297826
|
+
*/
|
|
297827
|
+
async relatedObjectTarget(raw) {
|
|
297828
|
+
const router = this.$router;
|
|
297829
|
+
if (!router || !raw || typeof raw !== 'object') {
|
|
297830
|
+
return null
|
|
297831
|
+
}
|
|
297832
|
+
const self = raw['@self'] || {};
|
|
297833
|
+
const id = raw.id ?? self.id ?? self.uuid ?? raw.uuid;
|
|
297834
|
+
const register = self.register ?? raw.register;
|
|
297835
|
+
const schema = self.schema ?? raw.schema;
|
|
297836
|
+
const missing = (v) => v === undefined || v === null || v === '';
|
|
297837
|
+
if (missing(id) || missing(register) || missing(schema)) {
|
|
297838
|
+
return null
|
|
297839
|
+
}
|
|
297840
|
+
let page = this.detailPageFor([String(register)], [String(schema)]);
|
|
297841
|
+
if (!page) {
|
|
297842
|
+
const [reg, sch] = await Promise.all([
|
|
297843
|
+
describeOpenRegisterEntity('registers', register),
|
|
297844
|
+
describeOpenRegisterEntity('schemas', schema),
|
|
297845
|
+
]);
|
|
297846
|
+
page = this.detailPageFor(
|
|
297847
|
+
[String(register), reg?.id, reg?.slug].filter(Boolean),
|
|
297848
|
+
[String(schema), sch?.id, sch?.slug].filter(Boolean),
|
|
297849
|
+
);
|
|
297850
|
+
}
|
|
297851
|
+
if (!page) {
|
|
297852
|
+
// eslint-disable-next-line no-console
|
|
297853
|
+
console.warn(`[CnPageRenderer] No detail page is bound to register "${register}" and schema "${schema}", so related object "${id}" opens nowhere.`);
|
|
297854
|
+
return null
|
|
297855
|
+
}
|
|
297856
|
+
if (this.routeNameIsKnown(page.id) === false) {
|
|
297857
|
+
// eslint-disable-next-line no-console
|
|
297858
|
+
console.warn(`[CnPageRenderer] Detail page "${page.id}" is not a route the router has, so related object "${id}" opens nowhere.`);
|
|
297859
|
+
return null
|
|
297860
|
+
}
|
|
297861
|
+
const path = page.route ?? routePathFor(router, page.id);
|
|
297862
|
+
return { name: page.id, params: buildRouteParams(path, id, this.$route?.params) }
|
|
297863
|
+
},
|
|
297864
|
+
|
|
297865
|
+
/**
|
|
297866
|
+
* The first `type: 'detail'` page whose register and schema are both
|
|
297867
|
+
* among the given names (ids or slugs, compared as strings).
|
|
297868
|
+
*
|
|
297869
|
+
* @param {Array<string>} registerNames Names the register goes by.
|
|
297870
|
+
* @param {Array<string>} schemaNames Names the schema goes by.
|
|
297871
|
+
* @return {object|null} The page, or null.
|
|
297872
|
+
*/
|
|
297873
|
+
detailPageFor(registerNames, schemaNames) {
|
|
297874
|
+
for (const page of this.detailPageByRegisterSchema.values()) {
|
|
297875
|
+
const cfg = page.config || {};
|
|
297876
|
+
if (registerNames.includes(String(cfg.register)) && schemaNames.includes(String(cfg.schema))) {
|
|
297877
|
+
return page
|
|
297878
|
+
}
|
|
297879
|
+
}
|
|
297880
|
+
return null
|
|
297881
|
+
},
|
|
297882
|
+
|
|
297669
297883
|
/**
|
|
297670
297884
|
* Whether the router has a route by this name.
|
|
297671
297885
|
*
|
|
@@ -298075,14 +298289,16 @@ function render$r(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
298075
298289
|
key: 0,
|
|
298076
298290
|
widgets: $options.widgetsBySlot.get('body'),
|
|
298077
298291
|
editable: $options.bodyEditable,
|
|
298078
|
-
slotName: "body"
|
|
298079
|
-
|
|
298292
|
+
slotName: "body",
|
|
298293
|
+
onSelectObject: $options.onRelatedObjectOpen
|
|
298294
|
+
}, null, 8 /* PROPS */, ["widgets", "editable", "onSelectObject"]))
|
|
298080
298295
|
: ($options.resolvedComponent)
|
|
298081
298296
|
? (vue$1.openBlock(), vue$1.createBlock(vue$1.resolveDynamicComponent($options.resolvedComponent), vue$1.mergeProps({ key: $options.pageRenderKey }, { ..._ctx.$attrs, ...$options.resolvedProps }, {
|
|
298082
298297
|
onView: $options.onRowOpen,
|
|
298083
298298
|
onRowClick: $options.onRowOpen,
|
|
298084
298299
|
onRowAuxClick: $options.onRowOpen,
|
|
298085
298300
|
onEditOpen: $options.onRowOpen,
|
|
298301
|
+
onRelatedObjectClick: $options.onRelatedObjectOpen,
|
|
298086
298302
|
onConfigure: _cache[0] || (_cache[0] = $event => ($data.showConfigModal = true))
|
|
298087
298303
|
}), vue$1.createSlots({ _: 2 /* DYNAMIC */ }, [
|
|
298088
298304
|
vue$1.renderList($options.resolvedSlotEntries, (entry) => {
|
|
@@ -298118,42 +298334,47 @@ function render$r(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
298118
298334
|
key: "0"
|
|
298119
298335
|
}
|
|
298120
298336
|
: undefined
|
|
298121
|
-
]), 1040 /* FULL_PROPS, DYNAMIC_SLOTS */, ["onView", "onRowClick", "onRowAuxClick", "onEditOpen"]))
|
|
298337
|
+
]), 1040 /* FULL_PROPS, DYNAMIC_SLOTS */, ["onView", "onRowClick", "onRowAuxClick", "onEditOpen", "onRelatedObjectClick"]))
|
|
298122
298338
|
: vue$1.createCommentVNode("v-if", true),
|
|
298123
298339
|
($options.widgetsBySlot.has('header-actions'))
|
|
298124
298340
|
? (vue$1.openBlock(), vue$1.createBlock(_component_CnWidgetGrid, {
|
|
298125
298341
|
key: 2,
|
|
298126
298342
|
widgets: $options.widgetsBySlot.get('header-actions'),
|
|
298127
|
-
slotName: "header-actions"
|
|
298128
|
-
|
|
298343
|
+
slotName: "header-actions",
|
|
298344
|
+
onSelectObject: $options.onRelatedObjectOpen
|
|
298345
|
+
}, null, 8 /* PROPS */, ["widgets", "onSelectObject"]))
|
|
298129
298346
|
: vue$1.createCommentVNode("v-if", true),
|
|
298130
298347
|
($options.widgetsBySlot.has('footer'))
|
|
298131
298348
|
? (vue$1.openBlock(), vue$1.createBlock(_component_CnWidgetGrid, {
|
|
298132
298349
|
key: 3,
|
|
298133
298350
|
widgets: $options.widgetsBySlot.get('footer'),
|
|
298134
|
-
slotName: "footer"
|
|
298135
|
-
|
|
298351
|
+
slotName: "footer",
|
|
298352
|
+
onSelectObject: $options.onRelatedObjectOpen
|
|
298353
|
+
}, null, 8 /* PROPS */, ["widgets", "onSelectObject"]))
|
|
298136
298354
|
: vue$1.createCommentVNode("v-if", true),
|
|
298137
298355
|
($options.widgetsBySlot.has('modal'))
|
|
298138
298356
|
? (vue$1.openBlock(), vue$1.createBlock(_component_CnWidgetGrid, {
|
|
298139
298357
|
key: 4,
|
|
298140
298358
|
widgets: $options.widgetsBySlot.get('modal'),
|
|
298141
|
-
slotName: "modal"
|
|
298142
|
-
|
|
298359
|
+
slotName: "modal",
|
|
298360
|
+
onSelectObject: $options.onRelatedObjectOpen
|
|
298361
|
+
}, null, 8 /* PROPS */, ["widgets", "onSelectObject"]))
|
|
298143
298362
|
: vue$1.createCommentVNode("v-if", true),
|
|
298144
298363
|
($options.widgetsBySlot.has('sidebar') && $options.pageSidebarVisibleValue)
|
|
298145
298364
|
? (vue$1.openBlock(), vue$1.createBlock(_component_CnWidgetGrid, {
|
|
298146
298365
|
key: 5,
|
|
298147
298366
|
widgets: $options.widgetsBySlot.get('sidebar'),
|
|
298148
|
-
slotName: "sidebar"
|
|
298149
|
-
|
|
298367
|
+
slotName: "sidebar",
|
|
298368
|
+
onSelectObject: $options.onRelatedObjectOpen
|
|
298369
|
+
}, null, 8 /* PROPS */, ["widgets", "onSelectObject"]))
|
|
298150
298370
|
: vue$1.createCommentVNode("v-if", true),
|
|
298151
298371
|
(vue$1.openBlock(true), vue$1.createElementBlock(vue$1.Fragment, null, vue$1.renderList($options.dynamicSlotKeys, (dynamicSlot) => {
|
|
298152
298372
|
return (vue$1.openBlock(), vue$1.createBlock(_component_CnWidgetGrid, {
|
|
298153
298373
|
key: dynamicSlot,
|
|
298154
298374
|
widgets: $options.widgetsBySlot.get(dynamicSlot),
|
|
298155
|
-
slotName: dynamicSlot
|
|
298156
|
-
|
|
298375
|
+
slotName: dynamicSlot,
|
|
298376
|
+
onSelectObject: $options.onRelatedObjectOpen
|
|
298377
|
+
}, null, 8 /* PROPS */, ["widgets", "slotName", "onSelectObject"]))
|
|
298157
298378
|
}), 128 /* KEYED_FRAGMENT */))
|
|
298158
298379
|
], 64 /* STABLE_FRAGMENT */))
|
|
298159
298380
|
: ($options.resolvedComponent)
|
|
@@ -298162,6 +298383,7 @@ function render$r(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
298162
298383
|
onRowClick: $options.onRowOpen,
|
|
298163
298384
|
onRowAuxClick: $options.onRowOpen,
|
|
298164
298385
|
onEditOpen: $options.onRowOpen,
|
|
298386
|
+
onRelatedObjectClick: $options.onRelatedObjectOpen,
|
|
298165
298387
|
onConfigure: _cache[1] || (_cache[1] = $event => ($data.showConfigModal = true))
|
|
298166
298388
|
}), vue$1.createSlots({ _: 2 /* DYNAMIC */ }, [
|
|
298167
298389
|
vue$1.renderList($options.resolvedSlotEntries, (entry) => {
|
|
@@ -298197,7 +298419,7 @@ function render$r(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
298197
298419
|
key: "0"
|
|
298198
298420
|
}
|
|
298199
298421
|
: undefined
|
|
298200
|
-
]), 1040 /* FULL_PROPS, DYNAMIC_SLOTS */, ["onView", "onRowClick", "onRowAuxClick", "onEditOpen"]))
|
|
298422
|
+
]), 1040 /* FULL_PROPS, DYNAMIC_SLOTS */, ["onView", "onRowClick", "onRowAuxClick", "onEditOpen", "onRelatedObjectClick"]))
|
|
298201
298423
|
: vue$1.createCommentVNode("v-if", true),
|
|
298202
298424
|
(!$options.hasRenderableBody)
|
|
298203
298425
|
? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_2$A, [
|
|
@@ -304521,6 +304743,136 @@ script$j.render = render$j;
|
|
|
304521
304743
|
script$j.__file = "src/components/CnAiCompanion/CnAiCompanion.vue";
|
|
304522
304744
|
const __sfc_main$j = script$j;
|
|
304523
304745
|
|
|
304746
|
+
/**
|
|
304747
|
+
* SPDX-FileCopyrightText: 2026 Conduction B.V. <info@conduction.nl>
|
|
304748
|
+
* SPDX-License-Identifier: EUPL-1.2
|
|
304749
|
+
*
|
|
304750
|
+
* The label a person reads for one notification rule in their settings.
|
|
304751
|
+
*
|
|
304752
|
+
* A rule is declared in a schema's `x-openregister-notifications` map under a
|
|
304753
|
+
* KEY (`caseAssigned`, `clientUpdated`, `onCreate`). The key is an identifier
|
|
304754
|
+
* for a developer. The settings pane used to print it as is, so a person saw
|
|
304755
|
+
* "substitutionRegisteredForSubstitute" next to a switch and had to guess.
|
|
304756
|
+
*
|
|
304757
|
+
* The label is taken from the first source that has one, most specific first:
|
|
304758
|
+
*
|
|
304759
|
+
* 1. the rule's own words, when OpenRegister passes them on the preference
|
|
304760
|
+
* entry (`label`, then `title`), as a plain string or a per-locale map
|
|
304761
|
+
* like the dialect's `subject` (`{ "nl": "…", "en": "…" }`);
|
|
304762
|
+
* 2. the app's own label for the rule, from the `labels` map the app hands
|
|
304763
|
+
* to CnAppRoot (`notificationLabels`), keyed `<schema>.<key>` or `<key>`;
|
|
304764
|
+
* 3. the library's wording for the generic object-event keys;
|
|
304765
|
+
* 4. the key made readable: `caseAssigned` becomes "Case assigned".
|
|
304766
|
+
*
|
|
304767
|
+
* The rule's `subject` is used only when it carries no `{{placeholder}}`: it
|
|
304768
|
+
* is the notification TITLE template, and "Case "{{title}}" assigned to you"
|
|
304769
|
+
* reads worse as a setting than the readable key does.
|
|
304770
|
+
*
|
|
304771
|
+
* Pure: no store, no fetch, no Vue.
|
|
304772
|
+
*
|
|
304773
|
+
* @spec openspec/changes/notification-rule-labels-and-runtime-version/specs/notification-preferences/spec.md
|
|
304774
|
+
*/
|
|
304775
|
+
|
|
304776
|
+
/**
|
|
304777
|
+
* Pick the string for the current language out of a string or per-locale map.
|
|
304778
|
+
*
|
|
304779
|
+
* @param {string|object|null|undefined} value A string, or `{ nl, en, … }`.
|
|
304780
|
+
* @param {string} [language] The current language, e.g. `nl` or `de_DE`.
|
|
304781
|
+
* @return {string} The resolved text, or '' when there is none.
|
|
304782
|
+
*/
|
|
304783
|
+
function resolveLocalised(value, language = 'en') {
|
|
304784
|
+
if (typeof value === 'string') {
|
|
304785
|
+
return value.trim()
|
|
304786
|
+
}
|
|
304787
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
304788
|
+
return ''
|
|
304789
|
+
}
|
|
304790
|
+
const lang = String(language || 'en');
|
|
304791
|
+
const base = lang.split(/[-_]/)[0];
|
|
304792
|
+
for (const candidate of [lang, base, 'en']) {
|
|
304793
|
+
if (typeof value[candidate] === 'string' && value[candidate].trim() !== '') {
|
|
304794
|
+
return value[candidate].trim()
|
|
304795
|
+
}
|
|
304796
|
+
}
|
|
304797
|
+
const first = Object.values(value).find((text) => typeof text === 'string' && text.trim() !== '');
|
|
304798
|
+
return first ? first.trim() : ''
|
|
304799
|
+
}
|
|
304800
|
+
|
|
304801
|
+
/**
|
|
304802
|
+
* Make a rule key readable: split camelCase, snake_case and kebab-case into
|
|
304803
|
+
* words, keep acronyms, and capitalise only the first word.
|
|
304804
|
+
*
|
|
304805
|
+
* `caseAssigned` → "Case assigned", `object_created` → "Object created",
|
|
304806
|
+
* `newBRPRecord` → "New BRP record".
|
|
304807
|
+
*
|
|
304808
|
+
* @param {string} key The rule key.
|
|
304809
|
+
* @return {string} A readable sentence-case label, or the key when it has no words.
|
|
304810
|
+
*/
|
|
304811
|
+
function humaniseRuleKey(key) {
|
|
304812
|
+
const words = String(key || '')
|
|
304813
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1 $2')
|
|
304814
|
+
.replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')
|
|
304815
|
+
.split(/[\s_\-.]+/)
|
|
304816
|
+
.filter(Boolean);
|
|
304817
|
+
if (words.length === 0) {
|
|
304818
|
+
return String(key || '')
|
|
304819
|
+
}
|
|
304820
|
+
return words
|
|
304821
|
+
.map((word, index) => {
|
|
304822
|
+
const isAcronym = word.length > 1 && word === word.toUpperCase() && /[A-Z]/.test(word);
|
|
304823
|
+
if (isAcronym) {
|
|
304824
|
+
return word
|
|
304825
|
+
}
|
|
304826
|
+
const lower = word.toLowerCase();
|
|
304827
|
+
return index === 0 ? lower.charAt(0).toUpperCase() + lower.slice(1) : lower
|
|
304828
|
+
})
|
|
304829
|
+
.join(' ')
|
|
304830
|
+
}
|
|
304831
|
+
|
|
304832
|
+
/**
|
|
304833
|
+
* The label for one preference entry.
|
|
304834
|
+
*
|
|
304835
|
+
* @param {object} entry A preference entry: `{ schema, notification, label?, title?, subject? }`.
|
|
304836
|
+
* @param {object} [options] Where else a label may come from.
|
|
304837
|
+
* @param {object} [options.labels] App-supplied labels keyed `<schema>.<key>` or `<key>`;
|
|
304838
|
+
* values are strings or per-locale maps.
|
|
304839
|
+
* @param {object} [options.known] Library wording for generic keys, keyed by rule key.
|
|
304840
|
+
* @param {string} [options.language] The current language.
|
|
304841
|
+
* @return {string} The label to show.
|
|
304842
|
+
*/
|
|
304843
|
+
function notificationRuleLabel(entry, { labels = {}, known = {}, language = 'en' } = {}) {
|
|
304844
|
+
const key = String(entry?.notification ?? '');
|
|
304845
|
+
const schema = String(entry?.schema ?? '');
|
|
304846
|
+
|
|
304847
|
+
for (const field of ['label', 'title']) {
|
|
304848
|
+
const own = resolveLocalised(entry?.[field], language);
|
|
304849
|
+
if (own) {
|
|
304850
|
+
return own
|
|
304851
|
+
}
|
|
304852
|
+
}
|
|
304853
|
+
|
|
304854
|
+
const map = labels && typeof labels === 'object' ? labels : {};
|
|
304855
|
+
for (const lookup of [schema ? `${schema}.${key}` : '', key]) {
|
|
304856
|
+
if (lookup && Object.hasOwn(map, lookup)) {
|
|
304857
|
+
const fromApp = resolveLocalised(map[lookup], language);
|
|
304858
|
+
if (fromApp) {
|
|
304859
|
+
return fromApp
|
|
304860
|
+
}
|
|
304861
|
+
}
|
|
304862
|
+
}
|
|
304863
|
+
|
|
304864
|
+
if (known && typeof known[key] === 'string' && known[key]) {
|
|
304865
|
+
return known[key]
|
|
304866
|
+
}
|
|
304867
|
+
|
|
304868
|
+
const subject = resolveLocalised(entry?.subject, language);
|
|
304869
|
+
if (subject && !subject.includes('{{')) {
|
|
304870
|
+
return subject
|
|
304871
|
+
}
|
|
304872
|
+
|
|
304873
|
+
return humaniseRuleKey(key)
|
|
304874
|
+
}
|
|
304875
|
+
|
|
304524
304876
|
const PREFS_PATH = '/apps/openregister/api/notification-preferences';
|
|
304525
304877
|
|
|
304526
304878
|
var script$i = {
|
|
@@ -304544,6 +304896,28 @@ var script$i = {
|
|
|
304544
304896
|
* than an always-empty pane.
|
|
304545
304897
|
*/
|
|
304546
304898
|
cnAppId: { default: () => '' },
|
|
304899
|
+
/**
|
|
304900
|
+
* App-supplied labels for its notification rules, provided by the
|
|
304901
|
+
* CnAppRoot ancestor from its `notificationLabels` prop. Keyed
|
|
304902
|
+
* `<schema>.<key>` or `<key>`.
|
|
304903
|
+
*/
|
|
304904
|
+
cnNotificationLabels: { default: () => ({}) },
|
|
304905
|
+
},
|
|
304906
|
+
|
|
304907
|
+
props: {
|
|
304908
|
+
/**
|
|
304909
|
+
* Labels for the notification rules, keyed `<schema>.<key>` or
|
|
304910
|
+
* `<key>`; values are strings or per-locale maps (`{ nl, en }`).
|
|
304911
|
+
* Optional: inside CnAppRoot the app's `notificationLabels` arrive by
|
|
304912
|
+
* inject, and a rule without a label still reads as words, never as
|
|
304913
|
+
* its raw key. A prop given here wins over the injected map.
|
|
304914
|
+
*
|
|
304915
|
+
* @spec openspec/changes/notification-rule-labels-and-runtime-version/specs/notification-preferences/spec.md
|
|
304916
|
+
*/
|
|
304917
|
+
labels: {
|
|
304918
|
+
type: Object,
|
|
304919
|
+
default: null,
|
|
304920
|
+
},
|
|
304547
304921
|
},
|
|
304548
304922
|
|
|
304549
304923
|
data() {
|
|
@@ -304669,18 +305043,43 @@ var script$i = {
|
|
|
304669
305043
|
},
|
|
304670
305044
|
|
|
304671
305045
|
/**
|
|
304672
|
-
* Human-readable label for a notification
|
|
305046
|
+
* Human-readable label for a notification rule. Never the raw key: the
|
|
305047
|
+
* rule's own label, then the app's, then the library's wording for the
|
|
305048
|
+
* generic keys, then the key split into words.
|
|
304673
305049
|
*
|
|
304674
|
-
* @param {
|
|
305050
|
+
* @param {object} entry The preference row.
|
|
304675
305051
|
* @return {string} A display label.
|
|
305052
|
+
*
|
|
305053
|
+
* @spec openspec/changes/notification-rule-labels-and-runtime-version/specs/notification-preferences/spec.md
|
|
304676
305054
|
*/
|
|
304677
|
-
notificationLabel(
|
|
305055
|
+
notificationLabel(entry) {
|
|
304678
305056
|
const known = {
|
|
304679
305057
|
object_created: l10n.translate('nextcloud-vue', 'When an item is created'),
|
|
304680
305058
|
object_updated: l10n.translate('nextcloud-vue', 'When an item is updated'),
|
|
304681
305059
|
object_transitioned: l10n.translate('nextcloud-vue', 'When an item is assigned or changes status'),
|
|
304682
305060
|
};
|
|
304683
|
-
|
|
305061
|
+
const language = this.currentLanguage();
|
|
305062
|
+
const injected = typeof this.cnNotificationLabels === 'function'
|
|
305063
|
+
? this.cnNotificationLabels()
|
|
305064
|
+
: this.cnNotificationLabels;
|
|
305065
|
+
return notificationRuleLabel(entry, {
|
|
305066
|
+
labels: { ...(injected || {}), ...(this.labels || {}) },
|
|
305067
|
+
known,
|
|
305068
|
+
language,
|
|
305069
|
+
})
|
|
305070
|
+
},
|
|
305071
|
+
|
|
305072
|
+
/**
|
|
305073
|
+
* The person's language, `en` when it cannot be read.
|
|
305074
|
+
*
|
|
305075
|
+
* @return {string} The language code.
|
|
305076
|
+
*/
|
|
305077
|
+
currentLanguage() {
|
|
305078
|
+
try {
|
|
305079
|
+
return (typeof l10n.getLanguage === 'function' && l10n.getLanguage()) || 'en'
|
|
305080
|
+
} catch {
|
|
305081
|
+
return 'en'
|
|
305082
|
+
}
|
|
304684
305083
|
},
|
|
304685
305084
|
|
|
304686
305085
|
/**
|
|
@@ -304770,7 +305169,7 @@ function render$i(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
304770
305169
|
"onUpdate:modelValue": $event => ($options.onToggle(entry, $event))
|
|
304771
305170
|
}, {
|
|
304772
305171
|
default: vue$1.withCtx(() => [
|
|
304773
|
-
vue$1.createTextVNode(vue$1.toDisplayString($options.notificationLabel(entry
|
|
305172
|
+
vue$1.createTextVNode(vue$1.toDisplayString($options.notificationLabel(entry)), 1 /* TEXT */)
|
|
304774
305173
|
]),
|
|
304775
305174
|
_: 2 /* DYNAMIC */
|
|
304776
305175
|
}, 1032 /* PROPS, DYNAMIC_SLOTS */, ["modelValue", "disabled", "onUpdate:modelValue"]),
|
|
@@ -306588,6 +306987,18 @@ var script$f = {
|
|
|
306588
306987
|
* wiring.
|
|
306589
306988
|
*/
|
|
306590
306989
|
cnAppId: this.appId,
|
|
306990
|
+
/**
|
|
306991
|
+
* The app's labels for its notification rules, read by the
|
|
306992
|
+
* notification-preferences pane in the user-settings modal. A
|
|
306993
|
+
* getter so a late prop update is still seen by a pane that
|
|
306994
|
+
* mounts after it.
|
|
306995
|
+
*
|
|
306996
|
+
* @spec openspec/changes/notification-rule-labels-and-runtime-version/specs/notification-preferences/spec.md
|
|
306997
|
+
*/
|
|
306998
|
+
get cnNotificationLabels() {
|
|
306999
|
+
return self.notificationLabels || {}
|
|
307000
|
+
},
|
|
307001
|
+
|
|
306591
307002
|
/**
|
|
306592
307003
|
* Target repo slug for the in-product feature-request deep
|
|
306593
307004
|
* link (e.g. `ConductionNL/pipelinq`). Read from the
|
|
@@ -307003,6 +307414,23 @@ var script$f = {
|
|
|
307003
307414
|
default: (key) => key,
|
|
307004
307415
|
},
|
|
307005
307416
|
|
|
307417
|
+
/**
|
|
307418
|
+
* Labels for the app's notification rules, shown in the
|
|
307419
|
+
* user-settings notification pane instead of the rule keys. Keyed
|
|
307420
|
+
* `<schema>.<key>` (or just `<key>`); values are already translated
|
|
307421
|
+
* strings, e.g. `{ 'case.caseAssigned': t('dossiq', 'A case is
|
|
307422
|
+
* assigned to me') }`, or per-locale maps `{ nl, en }`. A rule's own
|
|
307423
|
+
* `label` from OpenRegister wins; a rule with no label anywhere reads
|
|
307424
|
+
* as its key split into words, never as the raw key.
|
|
307425
|
+
*
|
|
307426
|
+
* @type {{[key: string]: (string|object)}}
|
|
307427
|
+
* @spec openspec/changes/notification-rule-labels-and-runtime-version/specs/notification-preferences/spec.md
|
|
307428
|
+
*/
|
|
307429
|
+
notificationLabels: {
|
|
307430
|
+
type: Object,
|
|
307431
|
+
default: () => ({}),
|
|
307432
|
+
},
|
|
307433
|
+
|
|
307006
307434
|
/**
|
|
307007
307435
|
* List of permission strings the current user holds. Forwarded
|
|
307008
307436
|
* to CnAppNav's permission filter.
|
|
@@ -349573,6 +350001,7 @@ exports.getRegisterApiUrl = getRegisterApiUrl;
|
|
|
349573
350001
|
exports.getSchemaApiUrl = getSchemaApiUrl;
|
|
349574
350002
|
exports.getSharedRegistry = getSharedRegistry;
|
|
349575
350003
|
exports.getWidgetTypeEntry = getWidgetTypeEntry;
|
|
350004
|
+
exports.humaniseRuleKey = humaniseRuleKey;
|
|
349576
350005
|
exports.installIntegrationRegistry = installIntegrationRegistry;
|
|
349577
350006
|
exports.installModalStack = installModalStack;
|
|
349578
350007
|
exports.integrations = integrations;
|
|
@@ -349604,6 +350033,7 @@ exports.mergePages = mergePages;
|
|
|
349604
350033
|
exports.mergeUserLayout = mergeUserLayout;
|
|
349605
350034
|
exports.networkError = networkError;
|
|
349606
350035
|
exports.notesIntegration = notesIntegration;
|
|
350036
|
+
exports.notificationRuleLabel = notificationRuleLabel;
|
|
349607
350037
|
exports.offlineCollection = index;
|
|
349608
350038
|
exports.openRowTarget = openRowTarget;
|
|
349609
350039
|
exports.openprojectIntegration = openprojectIntegration;
|