@conduction/nextcloud-vue 2.90.0 → 2.91.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/CnDetailWidgetHost/CnDetailWidgetHost.vue.js +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js +15 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js.map +1 -1
- package/dist/esm/components/CnDialog/CnDialog.vue2.js +1 -1
- package/dist/esm/components/CnDialog/CnDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnDialog/CnDialog.vue3.js.map +1 -1
- package/dist/esm/components/CnDialogHeader/CnDialogHeader.vue2.js +1 -1
- package/dist/esm/components/CnDialogHeader/CnDialogHeader.vue2.js.map +1 -1
- package/dist/esm/components/CnDialogHeader/CnDialogHeader.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue.js +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue2.js +16 -1
- package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue3.js +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnObjectSidebar.vue.js +1 -1
- package/dist/esm/components/CnObjectSidebar/CnObjectSidebar.vue2.js +6 -3
- package/dist/esm/components/CnObjectSidebar/CnObjectSidebar.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnObjectSidebar.vue3.js.map +1 -1
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/library-style.js +1 -1
- package/dist/esm/nextcloud-vue.css +11 -11
- package/dist/nextcloud-vue.cjs.js +153 -122
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +11 -11
- package/package.json +1 -1
- package/src/components/CnDetailWidgetHost/CnDetailWidgetHost.vue +16 -2
- package/src/components/CnDialog/CnDialog.vue +1 -1
- package/src/components/CnDialog/index.js +7 -0
- package/src/components/CnDialogHeader/CnDialogHeader.vue +1 -1
- package/src/components/CnDialogHeader/index.js +7 -0
- package/src/components/CnIndexPage/CnIndexPageWidgets.vue +17 -2
- package/src/components/CnObjectSidebar/CnObjectSidebar.vue +6 -3
- package/src/components/index.js +2 -0
- package/src/index.js +2 -0
|
@@ -25077,7 +25077,7 @@ button.cn-stepper__step[data-v-776581d4] {
|
|
|
25077
25077
|
}
|
|
25078
25078
|
|
|
25079
25079
|
|
|
25080
|
-
.cn-detail-page__catalog-action[data-v-
|
|
25080
|
+
.cn-detail-page__catalog-action[data-v-47b3ec9e] {
|
|
25081
25081
|
align-items: center;
|
|
25082
25082
|
background: var(--color-primary-element-light);
|
|
25083
25083
|
border: 0;
|
|
@@ -25093,19 +25093,19 @@ button.cn-stepper__step[data-v-776581d4] {
|
|
|
25093
25093
|
padding: 0 14px;
|
|
25094
25094
|
white-space: nowrap;
|
|
25095
25095
|
}
|
|
25096
|
-
.cn-detail-page__catalog-note[data-v-
|
|
25096
|
+
.cn-detail-page__catalog-note[data-v-47b3ec9e] {
|
|
25097
25097
|
color: var(--color-text-maxcontrast);
|
|
25098
25098
|
font-size: 14px;
|
|
25099
25099
|
white-space: nowrap;
|
|
25100
25100
|
}
|
|
25101
|
-
.cn-detail-widget-host[data-v-
|
|
25102
|
-
.cn-detail-widget-host[data-v-
|
|
25101
|
+
.cn-detail-widget-host[data-v-47b3ec9e],
|
|
25102
|
+
.cn-detail-widget-host[data-v-47b3ec9e] > * {
|
|
25103
25103
|
height: 100%;
|
|
25104
25104
|
}
|
|
25105
25105
|
|
|
25106
25106
|
/* A bare host is a tab panel's body: it fills the panel and lets the panel
|
|
25107
25107
|
scroll, rather than growing a second scroll region of its own. */
|
|
25108
|
-
.cn-detail-widget-host--bare[data-v-
|
|
25108
|
+
.cn-detail-widget-host--bare[data-v-47b3ec9e] {
|
|
25109
25109
|
min-height: 0;
|
|
25110
25110
|
}
|
|
25111
25111
|
|
|
@@ -36057,14 +36057,14 @@ button.cn-object-calendar__overflow[data-v-e1c69ee2] {
|
|
|
36057
36057
|
}
|
|
36058
36058
|
|
|
36059
36059
|
|
|
36060
|
-
.cn-index-page-widgets--stat-row[data-v-
|
|
36060
|
+
.cn-index-page-widgets--stat-row[data-v-319129cb] {
|
|
36061
36061
|
margin-bottom: var(--cn-board-section-gap, 20px);
|
|
36062
36062
|
}
|
|
36063
|
-
.cn-index-page-widgets__cell[data-v-
|
|
36063
|
+
.cn-index-page-widgets__cell[data-v-319129cb] {
|
|
36064
36064
|
display: flex;
|
|
36065
36065
|
min-width: 0;
|
|
36066
36066
|
}
|
|
36067
|
-
.cn-index-page-widgets__cell[data-v-
|
|
36067
|
+
.cn-index-page-widgets__cell[data-v-319129cb] > * {
|
|
36068
36068
|
flex: 1 1 auto;
|
|
36069
36069
|
min-width: 0;
|
|
36070
36070
|
}
|
|
@@ -36072,7 +36072,7 @@ button.cn-object-calendar__overflow[data-v-e1c69ee2] {
|
|
|
36072
36072
|
/* The side panel column (DqTeamwachtrij: 300px, 16px between cards). Its
|
|
36073
36073
|
place beside the toolbar and the list is set by CnIndexPage
|
|
36074
36074
|
(`cn-index-page--with-side-panel`, index-page.css). */
|
|
36075
|
-
.cn-index-page-widgets--side-panel[data-v-
|
|
36075
|
+
.cn-index-page-widgets--side-panel[data-v-319129cb] {
|
|
36076
36076
|
display: flex;
|
|
36077
36077
|
flex-direction: column;
|
|
36078
36078
|
gap: 16px;
|
|
@@ -40772,10 +40772,10 @@ a.cn-integration-card__title[data-v-093a874d]:hover {
|
|
|
40772
40772
|
* let the strip scroll horizontally once they no longer fit. `flex-basis: 0`
|
|
40773
40773
|
* + equal grow keeps every tab the same width whether the row fits or scrolls.
|
|
40774
40774
|
* Apps with longer labels can widen the floor via --cn-sidebar-tab-min-width. */
|
|
40775
|
-
[data-v-
|
|
40775
|
+
[data-v-09402703] .app-sidebar-tabs__nav {
|
|
40776
40776
|
overflow-x: auto;
|
|
40777
40777
|
}
|
|
40778
|
-
[data-v-
|
|
40778
|
+
[data-v-09402703] .app-sidebar-tabs__nav .app-sidebar-tabs__tab {
|
|
40779
40779
|
flex-grow: 1;
|
|
40780
40780
|
flex-shrink: 0;
|
|
40781
40781
|
flex-basis: 0;
|
|
@@ -26166,7 +26166,7 @@ script$6Y.__scopeId = "data-v-52ba5fea";
|
|
|
26166
26166
|
const __sfc_main$6S = script$6Y;
|
|
26167
26167
|
|
|
26168
26168
|
/**
|
|
26169
|
-
* CnDialogHeader
|
|
26169
|
+
* CnDialogHeader - the board dialog header: eyebrow, 20px title,
|
|
26170
26170
|
* subtitle and a round 36px close button.
|
|
26171
26171
|
*
|
|
26172
26172
|
* The close button emits `close` and is disabled while `noClose` is set, so a
|
|
@@ -26293,7 +26293,7 @@ function resolveDialogWidth(width, defaultWidth) {
|
|
|
26293
26293
|
}
|
|
26294
26294
|
|
|
26295
26295
|
/**
|
|
26296
|
-
* CnDialog
|
|
26296
|
+
* CnDialog - the one place where a `Cn*` dialog turns into the
|
|
26297
26297
|
* board dialog (screens-dialog-parity).
|
|
26298
26298
|
*
|
|
26299
26299
|
* In the Nextcloud look it is `NcDialog` with the caller's `size`, unchanged.
|
|
@@ -152257,6 +152257,108 @@ script$4K.render = render$4K;
|
|
|
152257
152257
|
script$4K.__scopeId = "data-v-f0af265a";
|
|
152258
152258
|
const __sfc_main$4E = script$4K;
|
|
152259
152259
|
|
|
152260
|
+
/**
|
|
152261
|
+
* SPDX-FileCopyrightText: 2026 Conduction B.V.
|
|
152262
|
+
* SPDX-License-Identifier: EUPL-1.2
|
|
152263
|
+
*/
|
|
152264
|
+
|
|
152265
|
+
|
|
152266
|
+
const warned$2 = new Set();
|
|
152267
|
+
|
|
152268
|
+
/**
|
|
152269
|
+
* Add the prop names one component options object declares, following its
|
|
152270
|
+
* `extends` and `mixins`.
|
|
152271
|
+
*
|
|
152272
|
+
* @param {object} options A component options object.
|
|
152273
|
+
* @param {Set<string>} names The set to add camelCase prop names to.
|
|
152274
|
+
* @param {number} depth Recursion guard.
|
|
152275
|
+
*/
|
|
152276
|
+
function collect(options, names, depth) {
|
|
152277
|
+
if (!options || typeof options !== 'object' || depth > 8) {
|
|
152278
|
+
return
|
|
152279
|
+
}
|
|
152280
|
+
const props = options.props;
|
|
152281
|
+
if (Array.isArray(props)) {
|
|
152282
|
+
props.forEach((name) => names.add(vue$1.camelize(String(name))));
|
|
152283
|
+
} else if (props && typeof props === 'object') {
|
|
152284
|
+
Object.keys(props).forEach((name) => names.add(vue$1.camelize(name)));
|
|
152285
|
+
}
|
|
152286
|
+
collect(options.extends, names, depth + 1);
|
|
152287
|
+
if (Array.isArray(options.mixins)) {
|
|
152288
|
+
options.mixins.forEach((mixin) => collect(mixin, names, depth + 1));
|
|
152289
|
+
}
|
|
152290
|
+
}
|
|
152291
|
+
|
|
152292
|
+
/**
|
|
152293
|
+
* The prop names a component declares, or `null` when it takes every
|
|
152294
|
+
* attribute itself and so must keep receiving all of them:
|
|
152295
|
+
* - `inheritAttrs: false`: the component forwards `$attrs` on purpose;
|
|
152296
|
+
* - a functional component without `props`: its attrs are its props;
|
|
152297
|
+
* - an async component that has not resolved yet.
|
|
152298
|
+
*
|
|
152299
|
+
* @spec openspec/changes/dashboard-declared-widget-props/specs/dashboard-page/spec.md#requirement-a-dashboard-widget-receives-only-the-content-keys-it-declares
|
|
152300
|
+
* @param {object|((...args: unknown[]) => unknown)|null} component A component definition.
|
|
152301
|
+
* @return {Set<string>|null} camelCase prop names, or null for "all".
|
|
152302
|
+
*/
|
|
152303
|
+
function declaredPropNames(component) {
|
|
152304
|
+
if (!component) {
|
|
152305
|
+
return null
|
|
152306
|
+
}
|
|
152307
|
+
if (typeof component === 'function') {
|
|
152308
|
+
if (!component.props) {
|
|
152309
|
+
return null
|
|
152310
|
+
}
|
|
152311
|
+
const names = new Set();
|
|
152312
|
+
collect({ props: component.props }, names, 0);
|
|
152313
|
+
return names
|
|
152314
|
+
}
|
|
152315
|
+
if (typeof component !== 'object') {
|
|
152316
|
+
return null
|
|
152317
|
+
}
|
|
152318
|
+
if (component.__asyncLoader) {
|
|
152319
|
+
return component.__asyncResolved ? declaredPropNames(component.__asyncResolved) : null
|
|
152320
|
+
}
|
|
152321
|
+
const chain = [component, component.extends, ...(component.mixins || [])];
|
|
152322
|
+
if (chain.some((options) => options && options.inheritAttrs === false)) {
|
|
152323
|
+
return null
|
|
152324
|
+
}
|
|
152325
|
+
const names = new Set();
|
|
152326
|
+
collect(component, names, 0);
|
|
152327
|
+
return names
|
|
152328
|
+
}
|
|
152329
|
+
|
|
152330
|
+
/**
|
|
152331
|
+
* Keep the entries of `bindings` whose key `component` declares as a prop.
|
|
152332
|
+
* A component for which {@link declaredPropNames} returns null gets every
|
|
152333
|
+
* entry. A dropped key is warned about once outside production when the
|
|
152334
|
+
* component has no `content` prop either, so the key reaches nothing.
|
|
152335
|
+
*
|
|
152336
|
+
* @spec openspec/changes/dashboard-declared-widget-props/specs/dashboard-page/spec.md#requirement-a-dashboard-widget-receives-only-the-content-keys-it-declares
|
|
152337
|
+
* @param {object|((...args: unknown[]) => unknown)|null} component The component that will receive the bindings.
|
|
152338
|
+
* @param {object} bindings The candidate bindings.
|
|
152339
|
+
* @param {string} label Names the component in the warning (for example the widget type).
|
|
152340
|
+
* @return {object} The bindings the component declares.
|
|
152341
|
+
*/
|
|
152342
|
+
function pickDeclaredProps(component, bindings, label) {
|
|
152343
|
+
const declared = declaredPropNames(component);
|
|
152344
|
+
if (!declared || !bindings || typeof bindings !== 'object') {
|
|
152345
|
+
return bindings
|
|
152346
|
+
}
|
|
152347
|
+
const out = {};
|
|
152348
|
+
for (const [key, value] of Object.entries(bindings)) {
|
|
152349
|
+
if (declared.has(vue$1.camelize(key))) {
|
|
152350
|
+
out[key] = value;
|
|
152351
|
+
continue
|
|
152352
|
+
}
|
|
152353
|
+
if (process.env.NODE_ENV !== 'production' && !declared.has('content') && !warned$2.has(`${label}\u0000${key}`)) {
|
|
152354
|
+
warned$2.add(`${label}\u0000${key}`);
|
|
152355
|
+
// eslint-disable-next-line no-console
|
|
152356
|
+
console.warn(`[nextcloud-vue] content key "${key}" is not passed to widget "${label}": it declares neither that prop nor \`content\`.`);
|
|
152357
|
+
}
|
|
152358
|
+
}
|
|
152359
|
+
return out
|
|
152360
|
+
}
|
|
152361
|
+
|
|
152260
152362
|
// SPDX-FileCopyrightText: 2026 Conduction B.V.
|
|
152261
152363
|
// SPDX-License-Identifier: EUPL-1.2
|
|
152262
152364
|
|
|
@@ -158624,7 +158726,7 @@ const DEFAULT_COMPONENT_MAP = Object.freeze({
|
|
|
158624
158726
|
|
|
158625
158727
|
const KNOWN_TYPES = ['boolean', 'number', 'password', 'string', 'enum', 'json', 'file'];
|
|
158626
158728
|
|
|
158627
|
-
const warned$
|
|
158729
|
+
const warned$1 = new Set();
|
|
158628
158730
|
|
|
158629
158731
|
/**
|
|
158630
158732
|
* Coerce an enum field's options into the `{ label, value }` shape
|
|
@@ -158783,8 +158885,8 @@ function cnRenderFormField({ field, value, onInput, t, error, componentMap } = {
|
|
|
158783
158885
|
// per process. It used to be taken unconditionally and silently,
|
|
158784
158886
|
// because the CommonJS lookup that fed `NcTextArea` could never
|
|
158785
158887
|
// resolve from an ESM build.
|
|
158786
|
-
if (!map['string-textarea'] && !warned$
|
|
158787
|
-
warned$
|
|
158888
|
+
if (!map['string-textarea'] && !warned$1.has('__no-nc-textarea')) {
|
|
158889
|
+
warned$1.add('__no-nc-textarea');
|
|
158788
158890
|
// eslint-disable-next-line no-console
|
|
158789
158891
|
console.warn('[cnRenderFormField] NcTextArea is unavailable from @nextcloud/vue; '
|
|
158790
158892
|
+ 'falling back to a bare <textarea> for `widget: "textarea"` fields. '
|
|
@@ -158824,8 +158926,8 @@ function cnRenderFormField({ field, value, onInput, t, error, componentMap } = {
|
|
|
158824
158926
|
}
|
|
158825
158927
|
} else if (!KNOWN_TYPES.includes(field.type)) {
|
|
158826
158928
|
// Unknown type — warn ONCE per type and fall back to NcTextField.
|
|
158827
|
-
if (!warned$
|
|
158828
|
-
warned$
|
|
158929
|
+
if (!warned$1.has(field.type)) {
|
|
158930
|
+
warned$1.add(field.type);
|
|
158829
158931
|
// eslint-disable-next-line no-console
|
|
158830
158932
|
console.warn(`[cnRenderFormField] Unknown field.type "${field.type}" for field "${field.key}". Falling back to NcTextField. Known types: ${KNOWN_TYPES.join(', ')}.`);
|
|
158831
158933
|
}
|
|
@@ -163778,7 +163880,20 @@ var script$4p = {
|
|
|
163778
163880
|
if (title) {
|
|
163779
163881
|
base.title = title;
|
|
163780
163882
|
}
|
|
163781
|
-
return { ...base, ...this.
|
|
163883
|
+
return { ...base, ...this.declaredContent }
|
|
163884
|
+
},
|
|
163885
|
+
|
|
163886
|
+
/**
|
|
163887
|
+
* The content keys the renderer declares as props. An undeclared key
|
|
163888
|
+
* would fall through as an attribute onto the renderer's root and could
|
|
163889
|
+
* override a value the widget computes there; the whole content still
|
|
163890
|
+
* arrives as `content`.
|
|
163891
|
+
*
|
|
163892
|
+
* @return {object} The declared content keys.
|
|
163893
|
+
* @spec openspec/changes/declared-props-detail-index-sidebar/specs/widget-hosts/spec.md#requirement-a-widget-host-passes-only-the-keys-a-widget-declares
|
|
163894
|
+
*/
|
|
163895
|
+
declaredContent() {
|
|
163896
|
+
return pickDeclaredProps(this.renderer, this.content, this.widget?.type || '')
|
|
163782
163897
|
},
|
|
163783
163898
|
|
|
163784
163899
|
/**
|
|
@@ -164268,7 +164383,7 @@ function render$4p(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
164268
164383
|
class: "cn-detail-page__card-fit"
|
|
164269
164384
|
}, vue$1.createSlots({
|
|
164270
164385
|
default: vue$1.withCtx(() => [
|
|
164271
|
-
(vue$1.openBlock(), vue$1.createBlock(vue$1.resolveDynamicComponent($options.renderer), vue$1.mergeProps({ content: $options.content }, $options.
|
|
164386
|
+
(vue$1.openBlock(), vue$1.createBlock(vue$1.resolveDynamicComponent($options.renderer), vue$1.mergeProps({ content: $options.content }, $options.declaredContent), null, 16 /* FULL_PROPS */, ["content"]))
|
|
164272
164387
|
]),
|
|
164273
164388
|
_: 2 /* DYNAMIC */
|
|
164274
164389
|
}, [
|
|
@@ -164295,7 +164410,7 @@ function render$4p(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
164295
164410
|
}
|
|
164296
164411
|
|
|
164297
164412
|
script$4p.render = render$4p;
|
|
164298
|
-
script$4p.__scopeId = "data-v-
|
|
164413
|
+
script$4p.__scopeId = "data-v-47b3ec9e";
|
|
164299
164414
|
const __sfc_main$4j = script$4p;
|
|
164300
164415
|
|
|
164301
164416
|
/**
|
|
@@ -257068,7 +257183,7 @@ const __sfc_main$2l = script$2l;
|
|
|
257068
257183
|
* @spec openspec/changes/environment-banner/tasks.md#task-2
|
|
257069
257184
|
*/
|
|
257070
257185
|
|
|
257071
|
-
let warned
|
|
257186
|
+
let warned = false;
|
|
257072
257187
|
|
|
257073
257188
|
/**
|
|
257074
257189
|
* @param {object} options Options.
|
|
@@ -257094,8 +257209,8 @@ function useEnvironment({ environment, tenant, apiBase = '/apps/openregister/api
|
|
|
257094
257209
|
const value = response && response.data && (response.data.environment ?? (response.data.results && response.data.results.environment));
|
|
257095
257210
|
fetched.value = { ...fetched.value, [uuid]: typeof value === 'string' ? value : '' };
|
|
257096
257211
|
} catch (error) {
|
|
257097
|
-
if (!warned
|
|
257098
|
-
warned
|
|
257212
|
+
if (!warned) {
|
|
257213
|
+
warned = true;
|
|
257099
257214
|
// eslint-disable-next-line no-console
|
|
257100
257215
|
console.warn('[useEnvironment] The organisation could not be read, so no environment is shown.', error);
|
|
257101
257216
|
}
|
|
@@ -265292,7 +265407,7 @@ var script$25 = {
|
|
|
265292
265407
|
* The renderable entries, in the listed order.
|
|
265293
265408
|
*
|
|
265294
265409
|
* @spec openspec/changes/screens-index-stat-row/specs/index-page/spec.md#requirement-an-index-page-can-draw-a-stat-row-above-the-list
|
|
265295
|
-
* @return {Array<{id: string, title: string, content: object, headerLink: (object|null), renderer: object}>}
|
|
265410
|
+
* @return {Array<{id: string, type: string, title: string, content: object, headerLink: (object|null), renderer: object}>}
|
|
265296
265411
|
*/
|
|
265297
265412
|
entries() {
|
|
265298
265413
|
const list = Array.isArray(this.widgets) ? this.widgets : [];
|
|
@@ -265312,6 +265427,7 @@ var script$25 = {
|
|
|
265312
265427
|
const translate = typeof this.cnTranslate === 'function' ? this.cnTranslate : (key) => key;
|
|
265313
265428
|
out.push({
|
|
265314
265429
|
id: def.id,
|
|
265430
|
+
type: def.type,
|
|
265315
265431
|
title: typeof def.title === 'string' && def.title !== '' ? translate(def.title) : '',
|
|
265316
265432
|
content: (def.content && typeof def.content === 'object') ? def.content : {},
|
|
265317
265433
|
headerLink: (def.headerLink && typeof def.headerLink === 'object') ? def.headerLink : null,
|
|
@@ -265323,6 +265439,19 @@ var script$25 = {
|
|
|
265323
265439
|
},
|
|
265324
265440
|
|
|
265325
265441
|
methods: {
|
|
265442
|
+
/**
|
|
265443
|
+
* The content keys an entry's renderer declares as props. An undeclared
|
|
265444
|
+
* key would fall through onto the renderer's root; the whole content
|
|
265445
|
+
* still arrives as `content`.
|
|
265446
|
+
*
|
|
265447
|
+
* @param {{ renderer: object, content: object, type?: string, id: string }} entry A resolved entry.
|
|
265448
|
+
* @return {object} The declared content keys.
|
|
265449
|
+
* @spec openspec/changes/declared-props-detail-index-sidebar/specs/widget-hosts/spec.md#requirement-a-widget-host-passes-only-the-keys-a-widget-declares
|
|
265450
|
+
*/
|
|
265451
|
+
declaredContent(entry) {
|
|
265452
|
+
return pickDeclaredProps(entry.renderer, entry.content, entry.type || entry.id)
|
|
265453
|
+
},
|
|
265454
|
+
|
|
265326
265455
|
/**
|
|
265327
265456
|
* Resolve a widget type: the consumer registry, then the dashboard
|
|
265328
265457
|
* catalog (the type as written, then its alias), then the built-ins.
|
|
@@ -265376,7 +265505,7 @@ function render$25(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
265376
265505
|
(vue$1.openBlock(), vue$1.createBlock(vue$1.resolveDynamicComponent(entry.renderer), vue$1.mergeProps({
|
|
265377
265506
|
widgetId: entry.id,
|
|
265378
265507
|
content: entry.content
|
|
265379
|
-
}, { ref_for: true }, entry
|
|
265508
|
+
}, { ref_for: true }, $options.declaredContent(entry)), null, 16 /* FULL_PROPS */, ["widgetId", "content"]))
|
|
265380
265509
|
]),
|
|
265381
265510
|
_: 2 /* DYNAMIC */
|
|
265382
265511
|
}, 1032 /* PROPS, DYNAMIC_SLOTS */, ["widgetId", "title", "showTitle", "headerLink", "flush"])
|
|
@@ -265389,7 +265518,7 @@ function render$25(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
265389
265518
|
}
|
|
265390
265519
|
|
|
265391
265520
|
script$25.render = render$25;
|
|
265392
|
-
script$25.__scopeId = "data-v-
|
|
265521
|
+
script$25.__scopeId = "data-v-319129cb";
|
|
265393
265522
|
const __sfc_main$25 = script$25;
|
|
265394
265523
|
|
|
265395
265524
|
/**
|
|
@@ -318411,108 +318540,6 @@ script$1j.render = render$1j;
|
|
|
318411
318540
|
script$1j.__scopeId = "data-v-a78d1ec4";
|
|
318412
318541
|
const __sfc_main$1j = script$1j;
|
|
318413
318542
|
|
|
318414
|
-
/**
|
|
318415
|
-
* SPDX-FileCopyrightText: 2026 Conduction B.V.
|
|
318416
|
-
* SPDX-License-Identifier: EUPL-1.2
|
|
318417
|
-
*/
|
|
318418
|
-
|
|
318419
|
-
|
|
318420
|
-
const warned = new Set();
|
|
318421
|
-
|
|
318422
|
-
/**
|
|
318423
|
-
* Add the prop names one component options object declares, following its
|
|
318424
|
-
* `extends` and `mixins`.
|
|
318425
|
-
*
|
|
318426
|
-
* @param {object} options A component options object.
|
|
318427
|
-
* @param {Set<string>} names The set to add camelCase prop names to.
|
|
318428
|
-
* @param {number} depth Recursion guard.
|
|
318429
|
-
*/
|
|
318430
|
-
function collect(options, names, depth) {
|
|
318431
|
-
if (!options || typeof options !== 'object' || depth > 8) {
|
|
318432
|
-
return
|
|
318433
|
-
}
|
|
318434
|
-
const props = options.props;
|
|
318435
|
-
if (Array.isArray(props)) {
|
|
318436
|
-
props.forEach((name) => names.add(vue$1.camelize(String(name))));
|
|
318437
|
-
} else if (props && typeof props === 'object') {
|
|
318438
|
-
Object.keys(props).forEach((name) => names.add(vue$1.camelize(name)));
|
|
318439
|
-
}
|
|
318440
|
-
collect(options.extends, names, depth + 1);
|
|
318441
|
-
if (Array.isArray(options.mixins)) {
|
|
318442
|
-
options.mixins.forEach((mixin) => collect(mixin, names, depth + 1));
|
|
318443
|
-
}
|
|
318444
|
-
}
|
|
318445
|
-
|
|
318446
|
-
/**
|
|
318447
|
-
* The prop names a component declares, or `null` when it takes every
|
|
318448
|
-
* attribute itself and so must keep receiving all of them:
|
|
318449
|
-
* - `inheritAttrs: false`: the component forwards `$attrs` on purpose;
|
|
318450
|
-
* - a functional component without `props`: its attrs are its props;
|
|
318451
|
-
* - an async component that has not resolved yet.
|
|
318452
|
-
*
|
|
318453
|
-
* @spec openspec/changes/dashboard-declared-widget-props/specs/dashboard-page/spec.md#requirement-a-dashboard-widget-receives-only-the-content-keys-it-declares
|
|
318454
|
-
* @param {object|((...args: unknown[]) => unknown)|null} component A component definition.
|
|
318455
|
-
* @return {Set<string>|null} camelCase prop names, or null for "all".
|
|
318456
|
-
*/
|
|
318457
|
-
function declaredPropNames(component) {
|
|
318458
|
-
if (!component) {
|
|
318459
|
-
return null
|
|
318460
|
-
}
|
|
318461
|
-
if (typeof component === 'function') {
|
|
318462
|
-
if (!component.props) {
|
|
318463
|
-
return null
|
|
318464
|
-
}
|
|
318465
|
-
const names = new Set();
|
|
318466
|
-
collect({ props: component.props }, names, 0);
|
|
318467
|
-
return names
|
|
318468
|
-
}
|
|
318469
|
-
if (typeof component !== 'object') {
|
|
318470
|
-
return null
|
|
318471
|
-
}
|
|
318472
|
-
if (component.__asyncLoader) {
|
|
318473
|
-
return component.__asyncResolved ? declaredPropNames(component.__asyncResolved) : null
|
|
318474
|
-
}
|
|
318475
|
-
const chain = [component, component.extends, ...(component.mixins || [])];
|
|
318476
|
-
if (chain.some((options) => options && options.inheritAttrs === false)) {
|
|
318477
|
-
return null
|
|
318478
|
-
}
|
|
318479
|
-
const names = new Set();
|
|
318480
|
-
collect(component, names, 0);
|
|
318481
|
-
return names
|
|
318482
|
-
}
|
|
318483
|
-
|
|
318484
|
-
/**
|
|
318485
|
-
* Keep the entries of `bindings` whose key `component` declares as a prop.
|
|
318486
|
-
* A component for which {@link declaredPropNames} returns null gets every
|
|
318487
|
-
* entry. A dropped key is warned about once outside production when the
|
|
318488
|
-
* component has no `content` prop either, so the key reaches nothing.
|
|
318489
|
-
*
|
|
318490
|
-
* @spec openspec/changes/dashboard-declared-widget-props/specs/dashboard-page/spec.md#requirement-a-dashboard-widget-receives-only-the-content-keys-it-declares
|
|
318491
|
-
* @param {object|((...args: unknown[]) => unknown)|null} component The component that will receive the bindings.
|
|
318492
|
-
* @param {object} bindings The candidate bindings.
|
|
318493
|
-
* @param {string} label Names the component in the warning (for example the widget type).
|
|
318494
|
-
* @return {object} The bindings the component declares.
|
|
318495
|
-
*/
|
|
318496
|
-
function pickDeclaredProps(component, bindings, label) {
|
|
318497
|
-
const declared = declaredPropNames(component);
|
|
318498
|
-
if (!declared || !bindings || typeof bindings !== 'object') {
|
|
318499
|
-
return bindings
|
|
318500
|
-
}
|
|
318501
|
-
const out = {};
|
|
318502
|
-
for (const [key, value] of Object.entries(bindings)) {
|
|
318503
|
-
if (declared.has(vue$1.camelize(key))) {
|
|
318504
|
-
out[key] = value;
|
|
318505
|
-
continue
|
|
318506
|
-
}
|
|
318507
|
-
if (process.env.NODE_ENV !== 'production' && !declared.has('content') && !warned.has(`${label}\u0000${key}`)) {
|
|
318508
|
-
warned.add(`${label}\u0000${key}`);
|
|
318509
|
-
// eslint-disable-next-line no-console
|
|
318510
|
-
console.warn(`[nextcloud-vue] content key "${key}" is not passed to widget "${label}": it declares neither that prop nor \`content\`.`);
|
|
318511
|
-
}
|
|
318512
|
-
}
|
|
318513
|
-
return out
|
|
318514
|
-
}
|
|
318515
|
-
|
|
318516
318543
|
/** Surfaces understood by the pluggable integration registry (AD-19). */
|
|
318517
318544
|
const INTEGRATION_SURFACES = ['user-dashboard', 'app-dashboard', 'detail-page', 'single-entity'];
|
|
318518
318545
|
|
|
@@ -335035,9 +335062,11 @@ var script$N = {
|
|
|
335035
335062
|
* widgets get the shared coordinate context plus the loaded object
|
|
335036
335063
|
* (`objectData`); the prop-driven `data` built-in also gets the schema
|
|
335037
335064
|
* OBJECT bound to its `schema` prop (the other tabs use the `schema`
|
|
335038
|
-
* slug string, so the override is scoped to `type: 'data'`).
|
|
335039
|
-
* own `props
|
|
335065
|
+
* slug string, so the override is scoped to `type: 'data'`). Of a
|
|
335066
|
+
* widget's own `props`, the ones its component declares win on overlap;
|
|
335067
|
+
* an undeclared one would only fall through onto the component's root.
|
|
335040
335068
|
*
|
|
335069
|
+
* @spec openspec/changes/declared-props-detail-index-sidebar/specs/widget-hosts/spec.md#requirement-a-widget-host-passes-only-the-keys-a-widget-declares
|
|
335041
335070
|
* @param {{ type: string, props?: object }} w Widget spec
|
|
335042
335071
|
* @return {object} Props to v-bind onto the resolved widget component
|
|
335043
335072
|
*/
|
|
@@ -335050,7 +335079,7 @@ var script$N = {
|
|
|
335050
335079
|
// a String `schema`.
|
|
335051
335080
|
bindings.schema = this.objectSchema;
|
|
335052
335081
|
}
|
|
335053
|
-
return { ...bindings, ...(w.props || {}) }
|
|
335082
|
+
return { ...bindings, ...pickDeclaredProps(this.resolveWidgetComponent(w.type), w.props || {}, w.type || '') }
|
|
335054
335083
|
},
|
|
335055
335084
|
|
|
335056
335085
|
/**
|
|
@@ -335372,7 +335401,7 @@ function render$N(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
335372
335401
|
}
|
|
335373
335402
|
|
|
335374
335403
|
script$N.render = render$N;
|
|
335375
|
-
script$N.__scopeId = "data-v-
|
|
335404
|
+
script$N.__scopeId = "data-v-09402703";
|
|
335376
335405
|
const __sfc_main$N = script$N;
|
|
335377
335406
|
|
|
335378
335407
|
/**
|
|
@@ -397557,6 +397586,8 @@ exports.CnDetailCard = __sfc_main$6E;
|
|
|
397557
397586
|
exports.CnDetailGrid = __sfc_main$4J;
|
|
397558
397587
|
exports.CnDetailPage = __sfc_main$1m;
|
|
397559
397588
|
exports.CnDetailWidgetHost = __sfc_main$4j;
|
|
397589
|
+
exports.CnDialog = __sfc_main$6Q;
|
|
397590
|
+
exports.CnDialogHeader = __sfc_main$6R;
|
|
397560
397591
|
exports.CnDividerWidget = __sfc_main$4B;
|
|
397561
397592
|
exports.CnDividerWidgetForm = __sfc_main$42;
|
|
397562
397593
|
exports.CnDocumentReviewList = __sfc_main$76;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
[diffend] Oversized file quarantined before diffing.
|
|
2
2
|
name: package/dist/nextcloud-vue.cjs.js.map
|
|
3
|
-
size:
|
|
4
|
-
sha256:
|
|
3
|
+
size: 40783800 bytes
|
|
4
|
+
sha256: 38ecb05b1a9c62bd250ca390394a3597748055d8c7dc1363ad11aa8069730ec1
|
package/dist/nextcloud-vue.css
CHANGED
|
@@ -25077,7 +25077,7 @@ button.cn-stepper__step[data-v-776581d4] {
|
|
|
25077
25077
|
}
|
|
25078
25078
|
|
|
25079
25079
|
|
|
25080
|
-
.cn-detail-page__catalog-action[data-v-
|
|
25080
|
+
.cn-detail-page__catalog-action[data-v-47b3ec9e] {
|
|
25081
25081
|
align-items: center;
|
|
25082
25082
|
background: var(--color-primary-element-light);
|
|
25083
25083
|
border: 0;
|
|
@@ -25093,19 +25093,19 @@ button.cn-stepper__step[data-v-776581d4] {
|
|
|
25093
25093
|
padding: 0 14px;
|
|
25094
25094
|
white-space: nowrap;
|
|
25095
25095
|
}
|
|
25096
|
-
.cn-detail-page__catalog-note[data-v-
|
|
25096
|
+
.cn-detail-page__catalog-note[data-v-47b3ec9e] {
|
|
25097
25097
|
color: var(--color-text-maxcontrast);
|
|
25098
25098
|
font-size: 14px;
|
|
25099
25099
|
white-space: nowrap;
|
|
25100
25100
|
}
|
|
25101
|
-
.cn-detail-widget-host[data-v-
|
|
25102
|
-
.cn-detail-widget-host[data-v-
|
|
25101
|
+
.cn-detail-widget-host[data-v-47b3ec9e],
|
|
25102
|
+
.cn-detail-widget-host[data-v-47b3ec9e] > * {
|
|
25103
25103
|
height: 100%;
|
|
25104
25104
|
}
|
|
25105
25105
|
|
|
25106
25106
|
/* A bare host is a tab panel's body: it fills the panel and lets the panel
|
|
25107
25107
|
scroll, rather than growing a second scroll region of its own. */
|
|
25108
|
-
.cn-detail-widget-host--bare[data-v-
|
|
25108
|
+
.cn-detail-widget-host--bare[data-v-47b3ec9e] {
|
|
25109
25109
|
min-height: 0;
|
|
25110
25110
|
}
|
|
25111
25111
|
|
|
@@ -36057,14 +36057,14 @@ button.cn-object-calendar__overflow[data-v-e1c69ee2] {
|
|
|
36057
36057
|
}
|
|
36058
36058
|
|
|
36059
36059
|
|
|
36060
|
-
.cn-index-page-widgets--stat-row[data-v-
|
|
36060
|
+
.cn-index-page-widgets--stat-row[data-v-319129cb] {
|
|
36061
36061
|
margin-bottom: var(--cn-board-section-gap, 20px);
|
|
36062
36062
|
}
|
|
36063
|
-
.cn-index-page-widgets__cell[data-v-
|
|
36063
|
+
.cn-index-page-widgets__cell[data-v-319129cb] {
|
|
36064
36064
|
display: flex;
|
|
36065
36065
|
min-width: 0;
|
|
36066
36066
|
}
|
|
36067
|
-
.cn-index-page-widgets__cell[data-v-
|
|
36067
|
+
.cn-index-page-widgets__cell[data-v-319129cb] > * {
|
|
36068
36068
|
flex: 1 1 auto;
|
|
36069
36069
|
min-width: 0;
|
|
36070
36070
|
}
|
|
@@ -36072,7 +36072,7 @@ button.cn-object-calendar__overflow[data-v-e1c69ee2] {
|
|
|
36072
36072
|
/* The side panel column (DqTeamwachtrij: 300px, 16px between cards). Its
|
|
36073
36073
|
place beside the toolbar and the list is set by CnIndexPage
|
|
36074
36074
|
(`cn-index-page--with-side-panel`, index-page.css). */
|
|
36075
|
-
.cn-index-page-widgets--side-panel[data-v-
|
|
36075
|
+
.cn-index-page-widgets--side-panel[data-v-319129cb] {
|
|
36076
36076
|
display: flex;
|
|
36077
36077
|
flex-direction: column;
|
|
36078
36078
|
gap: 16px;
|
|
@@ -40772,10 +40772,10 @@ a.cn-integration-card__title[data-v-093a874d]:hover {
|
|
|
40772
40772
|
* let the strip scroll horizontally once they no longer fit. `flex-basis: 0`
|
|
40773
40773
|
* + equal grow keeps every tab the same width whether the row fits or scrolls.
|
|
40774
40774
|
* Apps with longer labels can widen the floor via --cn-sidebar-tab-min-width. */
|
|
40775
|
-
[data-v-
|
|
40775
|
+
[data-v-09402703] .app-sidebar-tabs__nav {
|
|
40776
40776
|
overflow-x: auto;
|
|
40777
40777
|
}
|
|
40778
|
-
[data-v-
|
|
40778
|
+
[data-v-09402703] .app-sidebar-tabs__nav .app-sidebar-tabs__tab {
|
|
40779
40779
|
flex-grow: 1;
|
|
40780
40780
|
flex-shrink: 0;
|
|
40781
40781
|
flex-basis: 0;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@conduction/nextcloud-vue",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.91.0",
|
|
4
4
|
"description": "Shared Vue component library for Conduction Nextcloud apps — complements @nextcloud/vue with higher-level components, OpenRegister integration, and NL Design System support",
|
|
5
5
|
"homepage": "https://github.com/ConductionNL/nextcloud-vue#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -236,7 +236,7 @@
|
|
|
236
236
|
<template v-if="widget.icon" #title-icon>
|
|
237
237
|
<CnIcon :name="widget.icon" :size="20" />
|
|
238
238
|
</template>
|
|
239
|
-
<component :is="renderer" :content="content" v-bind="
|
|
239
|
+
<component :is="renderer" :content="content" v-bind="declaredContent" />
|
|
240
240
|
</CnWidgetWrapper>
|
|
241
241
|
|
|
242
242
|
<!-- Every other content-driven catalog widget, and every bare-mode
|
|
@@ -276,6 +276,7 @@ import { useIntegrationRegistry } from '../../composables/useIntegrationRegistry
|
|
|
276
276
|
import { normalizeLook } from '../../composables/useLook.js'
|
|
277
277
|
import { isAppInstalled } from '../../utils/appInstalled.js'
|
|
278
278
|
import { widgetHeaderLink } from '../../utils/contentHeaderLink.js'
|
|
279
|
+
import { pickDeclaredProps } from '../../utils/declaredProps.js'
|
|
279
280
|
import { unwrapAppConfig } from '../../utils/formatMetric.js'
|
|
280
281
|
import { isActivityWidget } from '../../utils/headerMeta.js'
|
|
281
282
|
import { PANEL_ACTION_SINK } from '../../utils/panelActions.js'
|
|
@@ -997,7 +998,20 @@ export default {
|
|
|
997
998
|
if (title) {
|
|
998
999
|
base.title = title
|
|
999
1000
|
}
|
|
1000
|
-
return { ...base, ...this.
|
|
1001
|
+
return { ...base, ...this.declaredContent }
|
|
1002
|
+
},
|
|
1003
|
+
|
|
1004
|
+
/**
|
|
1005
|
+
* The content keys the renderer declares as props. An undeclared key
|
|
1006
|
+
* would fall through as an attribute onto the renderer's root and could
|
|
1007
|
+
* override a value the widget computes there; the whole content still
|
|
1008
|
+
* arrives as `content`.
|
|
1009
|
+
*
|
|
1010
|
+
* @return {object} The declared content keys.
|
|
1011
|
+
* @spec openspec/changes/declared-props-detail-index-sidebar/specs/widget-hosts/spec.md#requirement-a-widget-host-passes-only-the-keys-a-widget-declares
|
|
1012
|
+
*/
|
|
1013
|
+
declaredContent() {
|
|
1014
|
+
return pickDeclaredProps(this.renderer, this.content, this.widget?.type || '')
|
|
1001
1015
|
},
|
|
1002
1016
|
|
|
1003
1017
|
/**
|
|
@@ -32,7 +32,7 @@ import { useLook } from '../../composables/useLook.js'
|
|
|
32
32
|
import { resolveDialogWidth } from '../../utils/dialogWidths.js'
|
|
33
33
|
|
|
34
34
|
/**
|
|
35
|
-
* CnDialog
|
|
35
|
+
* CnDialog - the one place where a `Cn*` dialog turns into the
|
|
36
36
|
* board dialog (screens-dialog-parity).
|
|
37
37
|
*
|
|
38
38
|
* In the Nextcloud look it is `NcDialog` with the caller's `size`, unchanged.
|
|
@@ -45,7 +45,7 @@ import { NcButton } from '@nextcloud/vue'
|
|
|
45
45
|
import Close from 'vue-material-design-icons/Close.vue'
|
|
46
46
|
|
|
47
47
|
/**
|
|
48
|
-
* CnDialogHeader
|
|
48
|
+
* CnDialogHeader - the board dialog header: eyebrow, 20px title,
|
|
49
49
|
* subtitle and a round 36px close button.
|
|
50
50
|
*
|
|
51
51
|
* The close button emits `close` and is disabled while `noClose` is set, so a
|