@conduction/nextcloud-vue 1.0.0-beta.18 → 1.0.0-beta.19
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/nextcloud-vue.cjs.js +178 -33
- package/dist/nextcloud-vue.cjs.js.map +1 -1
- package/dist/nextcloud-vue.esm.js +178 -33
- package/dist/nextcloud-vue.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/components/CnIndexPage/CnIndexPage.md +1 -0
- package/src/components/CnIndexPage/CnIndexPage.vue +153 -23
- package/src/schemas/app-manifest.schema.json +9 -0
- package/src/utils/validateManifest.js +25 -0
|
@@ -56485,9 +56485,34 @@ function validateActionsArray(cfg, pathSlash, pathBracket, errors) {
|
|
|
56485
56485
|
if (typeof action.label !== 'string' || action.label.length === 0) {
|
|
56486
56486
|
errors.push(`${actionPath}/label: must be a non-empty string`);
|
|
56487
56487
|
}
|
|
56488
|
+
// REQ-MAD-1 / REQ-MAD-2 — `handler` (string, registry name OR
|
|
56489
|
+
// reserved keyword `navigate`/`emit`/`none`) and the matching
|
|
56490
|
+
// `navigate` requirement on `route`. Schema 1.3.0+.
|
|
56491
|
+
if (action.handler !== undefined) {
|
|
56492
|
+
if (typeof action.handler !== 'string') {
|
|
56493
|
+
errors.push(`${actionPath}/handler: must be a string when set`);
|
|
56494
|
+
} else if (!HANDLER_PATTERN.test(action.handler)) {
|
|
56495
|
+
errors.push(
|
|
56496
|
+
`${actionPath}/handler: "${action.handler}" must match `
|
|
56497
|
+
+ '"navigate" | "emit" | "none" | [A-Za-z][A-Za-z0-9_]*',
|
|
56498
|
+
);
|
|
56499
|
+
}
|
|
56500
|
+
if (action.handler === 'navigate'
|
|
56501
|
+
&& (typeof action.route !== 'string' || action.route.length === 0)) {
|
|
56502
|
+
errors.push(`${actionPath}/route: required when handler is "navigate"`);
|
|
56503
|
+
}
|
|
56504
|
+
}
|
|
56488
56505
|
});
|
|
56489
56506
|
}
|
|
56490
56507
|
|
|
56508
|
+
/**
|
|
56509
|
+
* REQ-MAD-1 — Allowed shapes for `actions[].handler`. Either a
|
|
56510
|
+
* reserved keyword (`navigate` | `emit` | `none`) or a JS-identifier
|
|
56511
|
+
* registry name (alphanumeric + underscore, leading letter). Mirrors
|
|
56512
|
+
* the schema's `pattern` on the `handler` property.
|
|
56513
|
+
*/
|
|
56514
|
+
const HANDLER_PATTERN = /^(navigate|emit|none|[A-Za-z][A-Za-z0-9_]*)$/;
|
|
56515
|
+
|
|
56491
56516
|
/**
|
|
56492
56517
|
* Validate `config.widgets[]` for dashboard page type
|
|
56493
56518
|
* (`manifest-config-refs` REQ-MCR). Each entry MUST be an object with
|
|
@@ -57466,14 +57491,20 @@ var script$L = {
|
|
|
57466
57491
|
CnIndexSidebar: __vue_component__$M,
|
|
57467
57492
|
},
|
|
57468
57493
|
|
|
57494
|
+
/**
|
|
57495
|
+
* Inject the customComponents registry from a CnAppRoot ancestor.
|
|
57496
|
+
* Used by:
|
|
57497
|
+
* - REQ-MAD-3 / REQ-MAD-8 (manifest-actions-dispatch): resolves
|
|
57498
|
+
* `actions[].handler` registry names to functions called on
|
|
57499
|
+
* row-action click.
|
|
57500
|
+
* - The cardComponent + form-dialog override paths: when set, the
|
|
57501
|
+
* prop-level `customComponents` wins, but the inject is the
|
|
57502
|
+
* default. See `effectiveCustomComponents`.
|
|
57503
|
+
*
|
|
57504
|
+
* Falls back to an empty object so `CnIndexPage` works standalone
|
|
57505
|
+
* (unit tests, isolated mount) without `CnAppRoot`.
|
|
57506
|
+
*/
|
|
57469
57507
|
inject: {
|
|
57470
|
-
/**
|
|
57471
|
-
* Custom-component registry provided by `CnAppRoot`. Falls back
|
|
57472
|
-
* to an empty object so `CnIndexPage` works when mounted
|
|
57473
|
-
* without `CnAppRoot` (e.g. in unit tests). The explicit
|
|
57474
|
-
* `customComponents` prop wins when set — see
|
|
57475
|
-
* `effectiveCustomComponents`.
|
|
57476
|
-
*/
|
|
57477
57508
|
cnCustomComponents: { default: () => ({}) },
|
|
57478
57509
|
},
|
|
57479
57510
|
|
|
@@ -57816,6 +57847,11 @@ var script$L = {
|
|
|
57816
57847
|
* `cnCustomComponents`. Provided primarily so unit tests can
|
|
57817
57848
|
* pass a registry without mounting `CnAppRoot`.
|
|
57818
57849
|
*
|
|
57850
|
+
* Used by:
|
|
57851
|
+
* - `cardComponent` resolution (REQ-MCI from manifest-card-index)
|
|
57852
|
+
* - `actions[].handler` registry name resolution (REQ-MAD-3 from
|
|
57853
|
+
* manifest-actions-dispatch — handler funcs called on row-action click)
|
|
57854
|
+
*
|
|
57819
57855
|
* @type {object|null}
|
|
57820
57856
|
*/
|
|
57821
57857
|
customComponents: {
|
|
@@ -57920,9 +57956,56 @@ var script$L = {
|
|
|
57920
57956
|
return builtIn
|
|
57921
57957
|
},
|
|
57922
57958
|
|
|
57923
|
-
/**
|
|
57959
|
+
/**
|
|
57960
|
+
* Effective customComponents registry — explicit prop wins over
|
|
57961
|
+
* the injected ancestor registry. Used to:
|
|
57962
|
+
* - Resolve `actions[].handler` registry names (REQ-MAD-3,
|
|
57963
|
+
* manifest-actions-dispatch).
|
|
57964
|
+
* - Resolve the `cardComponent` name for card-grid view (REQ-MCI,
|
|
57965
|
+
* manifest-card-index).
|
|
57966
|
+
*
|
|
57967
|
+
* @return {object}
|
|
57968
|
+
*/
|
|
57969
|
+
effectiveCustomComponents() {
|
|
57970
|
+
return this.customComponents ?? this.cnCustomComponents ?? {}
|
|
57971
|
+
},
|
|
57972
|
+
|
|
57973
|
+
/**
|
|
57974
|
+
* Merged actions: app-provided first, then built-in defaults.
|
|
57975
|
+
*
|
|
57976
|
+
* REQ-MAD-3 / REQ-MAD-4 / REQ-MAD-5 / REQ-MAD-6 / REQ-MAD-7
|
|
57977
|
+
* (manifest-actions-dispatch) — for any action whose `handler`
|
|
57978
|
+
* is a string, resolve it through `resolveHandler()` so
|
|
57979
|
+
* `CnRowActions` sees the same `{ handler: fn }` shape it does
|
|
57980
|
+
* for built-in defaults. Function-typed handlers (the existing
|
|
57981
|
+
* runtime path) pass through untouched.
|
|
57982
|
+
*/
|
|
57924
57983
|
mergedActions() {
|
|
57925
|
-
|
|
57984
|
+
const dispatched = this.actions.map((action) => {
|
|
57985
|
+
if (typeof action.handler === 'function') {
|
|
57986
|
+
// Back-compat: programmatic function handler — keep as-is.
|
|
57987
|
+
return action
|
|
57988
|
+
}
|
|
57989
|
+
if (typeof action.handler !== 'string' || action.handler.length === 0) {
|
|
57990
|
+
// No handler → emit-only path (existing default).
|
|
57991
|
+
return action
|
|
57992
|
+
}
|
|
57993
|
+
const isNone = action.handler === 'none';
|
|
57994
|
+
const resolved = this.resolveHandler(action);
|
|
57995
|
+
if (resolved) {
|
|
57996
|
+
// `none` returns a sentinel no-op handler AND must
|
|
57997
|
+
// suppress the `@action` emit; flag it so onRowAction
|
|
57998
|
+
// can drop the bubbled event.
|
|
57999
|
+
return isNone
|
|
58000
|
+
? { ...action, handler: resolved, _dispatchSuppress: true }
|
|
58001
|
+
: { ...action, handler: resolved }
|
|
58002
|
+
}
|
|
58003
|
+
// Either reserved keyword "emit" / unknown name / non-function
|
|
58004
|
+
// registry entry → page emits @action only; no handler call.
|
|
58005
|
+
const { handler, ...rest } = action;
|
|
58006
|
+
return rest
|
|
58007
|
+
});
|
|
58008
|
+
return [...dispatched, ...this.defaultActions]
|
|
57926
58009
|
},
|
|
57927
58010
|
|
|
57928
58011
|
hasRowActions() {
|
|
@@ -57970,17 +58053,6 @@ var script$L = {
|
|
|
57970
58053
|
return (this.sidebar && this.sidebar.search) || {}
|
|
57971
58054
|
},
|
|
57972
58055
|
|
|
57973
|
-
/**
|
|
57974
|
-
* Effective customComponents registry used to resolve the
|
|
57975
|
-
* `cardComponent` name. Explicit prop wins, inject falls back,
|
|
57976
|
-
* empty object is the last resort.
|
|
57977
|
-
*
|
|
57978
|
-
* @return {object}
|
|
57979
|
-
*/
|
|
57980
|
-
effectiveCustomComponents() {
|
|
57981
|
-
return this.customComponents ?? this.cnCustomComponents ?? {}
|
|
57982
|
-
},
|
|
57983
|
-
|
|
57984
58056
|
/**
|
|
57985
58057
|
* Resolved card component for card-grid view mode. Returns
|
|
57986
58058
|
* `null` when `cardComponent` is empty OR when the name is not
|
|
@@ -58017,6 +58089,89 @@ var script$L = {
|
|
|
58017
58089
|
},
|
|
58018
58090
|
|
|
58019
58091
|
methods: {
|
|
58092
|
+
/**
|
|
58093
|
+
* REQ-MAD-3 / REQ-MAD-4 / REQ-MAD-5 / REQ-MAD-6 / REQ-MAD-7
|
|
58094
|
+
* (manifest-actions-dispatch) — Resolve a manifest-declared
|
|
58095
|
+
* action's `handler` string into a `(row) => void` invocation
|
|
58096
|
+
* function. Returns null when the action should fall back to
|
|
58097
|
+
* the page's `@action`-event-only path.
|
|
58098
|
+
*
|
|
58099
|
+
* - Reserved keyword `"navigate"` → push the configured route
|
|
58100
|
+
* with `params: { id: row[rowKey] }`.
|
|
58101
|
+
* - Reserved keyword `"emit"` → null (page still bubbles
|
|
58102
|
+
* `@action`; explicit no-op).
|
|
58103
|
+
* - Reserved keyword `"none"` → returns a no-op function that
|
|
58104
|
+
* suppresses both the handler and the `@action` emit. The
|
|
58105
|
+
* suppression happens via the special `_dispatchSuppress`
|
|
58106
|
+
* flag on the cloned action; see mergedActions for the
|
|
58107
|
+
* detail.
|
|
58108
|
+
* - Registry name → look up in `effectiveCustomComponents`;
|
|
58109
|
+
* when it's a function, wrap as
|
|
58110
|
+
* `(row) => fn({ actionId: action.id, item: row })`. When
|
|
58111
|
+
* it's a non-function, console.warn and return null.
|
|
58112
|
+
* - Unknown registry name → silent fall-through (null).
|
|
58113
|
+
*
|
|
58114
|
+
* @param {object} action The manifest-shaped action object.
|
|
58115
|
+
* @return {Function|null}
|
|
58116
|
+
*/
|
|
58117
|
+
resolveHandler(action) {
|
|
58118
|
+
const name = action.handler;
|
|
58119
|
+
if (typeof name !== 'string' || name.length === 0) return null
|
|
58120
|
+
if (name === 'navigate') {
|
|
58121
|
+
const route = action.route;
|
|
58122
|
+
if (typeof route !== 'string' || route.length === 0) {
|
|
58123
|
+
// eslint-disable-next-line no-console
|
|
58124
|
+
console.warn(
|
|
58125
|
+
`[CnIndexPage] action "${action.id}" declares handler:"navigate" `
|
|
58126
|
+
+ 'but route is missing; falling back to @action-only.',
|
|
58127
|
+
);
|
|
58128
|
+
return null
|
|
58129
|
+
}
|
|
58130
|
+
return (row) => {
|
|
58131
|
+
this.$router.push({
|
|
58132
|
+
name: route,
|
|
58133
|
+
params: { id: row[this.rowKey] },
|
|
58134
|
+
});
|
|
58135
|
+
}
|
|
58136
|
+
}
|
|
58137
|
+
if (name === 'emit') return null
|
|
58138
|
+
if (name === 'none') {
|
|
58139
|
+
// Returns a sentinel that CnRowActions will treat as a
|
|
58140
|
+
// no-op; we additionally short-circuit @action emit in
|
|
58141
|
+
// `onRowAction` via the action's id.
|
|
58142
|
+
return () => {}
|
|
58143
|
+
}
|
|
58144
|
+
const fn = this.effectiveCustomComponents[name];
|
|
58145
|
+
if (typeof fn === 'function') {
|
|
58146
|
+
return (row) => fn({ actionId: action.id, item: row })
|
|
58147
|
+
}
|
|
58148
|
+
if (fn !== undefined) {
|
|
58149
|
+
// eslint-disable-next-line no-console
|
|
58150
|
+
console.warn(
|
|
58151
|
+
`[CnIndexPage] action.handler "${name}" resolved to a non-function in `
|
|
58152
|
+
+ 'customComponents — components belong to slot overrides; falling '
|
|
58153
|
+
+ 'back to @action-only.',
|
|
58154
|
+
);
|
|
58155
|
+
}
|
|
58156
|
+
return null
|
|
58157
|
+
},
|
|
58158
|
+
|
|
58159
|
+
/**
|
|
58160
|
+
* REQ-MAD-6 (manifest-actions-dispatch) — `handler: "none"`
|
|
58161
|
+
* blocks the `@action` emit entirely. CnRowActions emits
|
|
58162
|
+
* `@action` with `{ action: action.label, row }` and the page
|
|
58163
|
+
* forwards via `@action="$emit('action', $event)"`. This handler
|
|
58164
|
+
* intercepts so the `none`-flagged action is dropped before
|
|
58165
|
+
* re-emit.
|
|
58166
|
+
*
|
|
58167
|
+
* @param {{action: string, row: object}} payload The CnRowActions emit.
|
|
58168
|
+
*/
|
|
58169
|
+
onRowAction(payload) {
|
|
58170
|
+
const matched = this.mergedActions.find((a) => a.label === payload.action);
|
|
58171
|
+
if (matched && matched._dispatchSuppress) return
|
|
58172
|
+
this.$emit('action', payload);
|
|
58173
|
+
},
|
|
58174
|
+
|
|
58020
58175
|
/**
|
|
58021
58176
|
* Handle row click — emits row-click event for the parent to handle navigation.
|
|
58022
58177
|
* @param {object} row The clicked row object
|
|
@@ -58677,11 +58832,7 @@ var __vue_render__$L = function () {
|
|
|
58677
58832
|
actions: _vm.mergedActions,
|
|
58678
58833
|
row: row,
|
|
58679
58834
|
},
|
|
58680
|
-
on: {
|
|
58681
|
-
action: function ($event) {
|
|
58682
|
-
return _vm.$emit("action", $event)
|
|
58683
|
-
},
|
|
58684
|
-
},
|
|
58835
|
+
on: { action: _vm.onRowAction },
|
|
58685
58836
|
}),
|
|
58686
58837
|
]
|
|
58687
58838
|
},
|
|
@@ -58771,11 +58922,7 @@ var __vue_render__$L = function () {
|
|
|
58771
58922
|
actions: _vm.mergedActions,
|
|
58772
58923
|
row: object,
|
|
58773
58924
|
},
|
|
58774
|
-
on: {
|
|
58775
|
-
action: function ($event) {
|
|
58776
|
-
return _vm.$emit("action", $event)
|
|
58777
|
-
},
|
|
58778
|
-
},
|
|
58925
|
+
on: { action: _vm.onRowAction },
|
|
58779
58926
|
}),
|
|
58780
58927
|
]
|
|
58781
58928
|
},
|
|
@@ -58801,9 +58948,7 @@ var __vue_render__$L = function () {
|
|
|
58801
58948
|
"update:open": function ($event) {
|
|
58802
58949
|
_vm.contextMenuOpen = $event;
|
|
58803
58950
|
},
|
|
58804
|
-
action:
|
|
58805
|
-
return _vm.$emit("action", $event)
|
|
58806
|
-
},
|
|
58951
|
+
action: _vm.onRowAction,
|
|
58807
58952
|
close: _vm.closeContextMenu,
|
|
58808
58953
|
},
|
|
58809
58954
|
}),
|