@conduction/nextcloud-vue 2.136.0 → 2.137.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/CnAdminSettingsShell/CnAdminSettingsShell.vue.js +1 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js +9 -0
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js.map +1 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js +4 -3
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js.map +1 -1
- package/dist/esm/components/CnAppNav/CnAppNav.vue2.js +4 -1
- package/dist/esm/components/CnAppNav/CnAppNav.vue2.js.map +1 -1
- package/dist/esm/components/CnAppNav/CnAppNav.vue3.js +61 -28
- package/dist/esm/components/CnAppNav/CnAppNav.vue3.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +20 -0
- package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue3.js +33 -25
- package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +13 -0
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue.js +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js +2 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +36 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +4 -4
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue.js +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js +11 -0
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js +10 -2
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue.js +1 -1
- package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue2.js.map +1 -1
- package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue3.js +1 -0
- package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue3.js.map +1 -1
- package/dist/esm/components/CnRetentionWidget/CnRetentionWidget.vue.js +1 -1
- package/dist/esm/components/CnRetentionWidget/CnRetentionWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnRetentionWidget/CnRetentionWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnSavedViewMenuSettings/CnSavedViewMenuSettings.vue.js +1 -1
- package/dist/esm/components/CnSavedViewMenuSettings/CnSavedViewMenuSettings.vue2.js +14 -4
- package/dist/esm/components/CnSavedViewMenuSettings/CnSavedViewMenuSettings.vue2.js.map +1 -1
- package/dist/esm/components/CnSavedViewMenuSettings/CnSavedViewMenuSettings.vue3.js.map +1 -1
- package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue.js +1 -1
- package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue2.js +10 -0
- package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue2.js.map +1 -1
- package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue3.js +29 -13
- package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue3.js.map +1 -1
- package/dist/esm/components/CnTimelineWidget/dashboardRegistration.js +3 -1
- package/dist/esm/components/CnTimelineWidget/dashboardRegistration.js.map +1 -1
- package/dist/esm/library-style.js +1 -1
- package/dist/esm/nextcloud-vue.css +258 -160
- package/dist/esm/utils/contentHeaderLink.js +7 -1
- package/dist/esm/utils/contentHeaderLink.js.map +1 -1
- package/dist/esm/utils/savedViewMenu.js +4 -1
- package/dist/esm/utils/savedViewMenu.js.map +1 -1
- package/dist/esm/utils/savedViewSummary.js +11 -4
- package/dist/esm/utils/savedViewSummary.js.map +1 -1
- package/dist/esm/utils/validateManifestV2.compiled.js +2 -2
- package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +422 -225
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +258 -160
- package/package.json +1 -1
- package/src/components/CnAdminSettingsShell/CnAdminSettingsShell.vue +13 -1
- package/src/components/CnAppNav/CnAppNav.vue +28 -3
- package/src/components/CnDataTable/CnDataTable.vue +25 -0
- package/src/components/CnDetailPage/CnDetailPage.vue +14 -1
- package/src/components/CnDetailWidgetHost/CnDetailWidgetHost.vue +1 -0
- package/src/components/CnIndexPage/CnIndexPage.vue +40 -5
- package/src/components/CnObjectDataWidget/CnObjectDataWidget.md +1 -0
- package/src/components/CnObjectDataWidget/CnObjectDataWidget.vue +21 -0
- package/src/components/CnRegisterMapping/CnRegisterMapping.vue +7 -0
- package/src/components/CnRetentionWidget/CnRetentionWidget.vue +13 -0
- package/src/components/CnSavedViewMenuSettings/CnSavedViewMenuSettings.vue +14 -4
- package/src/components/CnTimelineWidget/CnTimelineManage.vue +23 -0
- package/src/components/CnTimelineWidget/dashboardRegistration.js +3 -1
- package/src/css/look-board-detail.css +10 -0
- package/src/css/look-board-index.css +50 -0
- package/src/css/look-board.css +5 -1
- package/src/css/table.css +5 -0
- package/src/schemas/app-manifest-v2.schema.json +4 -2
- package/src/utils/contentHeaderLink.js +7 -1
- package/src/utils/savedViewMenu.js +4 -1
- package/src/utils/savedViewSummary.js +11 -4
- package/src/utils/validateManifestV2.compiled.js +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@conduction/nextcloud-vue",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.137.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": {
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div
|
|
2
|
+
<div
|
|
3
|
+
class="cn-admin-settings-shell"
|
|
4
|
+
:class="[ownLookClass, sectionColumns ? `cn-admin-settings-shell--columns-${sectionColumns}` : '']"
|
|
5
|
+
:style="versionTitleSize ? { '--cn-board-version-title-size': `${versionTitleSize}px` } : null">
|
|
3
6
|
<!-- Names a development, test or acceptance environment; cannot be dismissed. Production shows nothing. -->
|
|
4
7
|
<CnEnvironmentBanner v-if="environmentName" :environment="environmentName" />
|
|
5
8
|
|
|
@@ -768,6 +771,15 @@ export default {
|
|
|
768
771
|
type: Object,
|
|
769
772
|
default: () => ({}),
|
|
770
773
|
},
|
|
774
|
+
|
|
775
|
+
/**
|
|
776
|
+
* The board look's version card title size in px, when the app's board
|
|
777
|
+
* draws it other than 17px (PqBeheer 19, OcInstellingen 18).
|
|
778
|
+
*/
|
|
779
|
+
versionTitleSize: {
|
|
780
|
+
type: Number,
|
|
781
|
+
default: 0,
|
|
782
|
+
},
|
|
771
783
|
},
|
|
772
784
|
|
|
773
785
|
emits: ['update', 'reimported', 'reimport-error', 'tab-change'],
|
|
@@ -184,8 +184,9 @@
|
|
|
184
184
|
:key="item.id"
|
|
185
185
|
:name="resolveLabel(item)"
|
|
186
186
|
:data-testid="`cn-nav-caption-${item.id}`">
|
|
187
|
-
<template v-if="item.href" #actions>
|
|
187
|
+
<template v-if="item.href || item.action === 'user-settings'" #actions>
|
|
188
188
|
<NcActionLink
|
|
189
|
+
v-if="item.href"
|
|
189
190
|
:href="item.href"
|
|
190
191
|
:aria-label="captionEditLabel(item)"
|
|
191
192
|
:data-testid="`cn-nav-caption-edit-${item.id}`">
|
|
@@ -194,6 +195,16 @@
|
|
|
194
195
|
</template>
|
|
195
196
|
{{ captionEditLabel(item) }}
|
|
196
197
|
</NcActionLink>
|
|
198
|
+
<NcActionButton
|
|
199
|
+
v-else
|
|
200
|
+
:aria-label="captionEditLabel(item)"
|
|
201
|
+
:data-testid="`cn-nav-caption-edit-${item.id}`"
|
|
202
|
+
@click="cnOpenUserSettings()">
|
|
203
|
+
<template #icon>
|
|
204
|
+
<Pencil :size="20" />
|
|
205
|
+
</template>
|
|
206
|
+
{{ captionEditLabel(item) }}
|
|
207
|
+
</NcActionButton>
|
|
197
208
|
</template>
|
|
198
209
|
</NcAppNavigationCaption>
|
|
199
210
|
<!-- `type: "hint"`: a muted line, no link, as the empty "My
|
|
@@ -447,8 +458,9 @@
|
|
|
447
458
|
:key="item.id"
|
|
448
459
|
:name="resolveLabel(item)"
|
|
449
460
|
:data-testid="`cn-nav-caption-${item.id}`">
|
|
450
|
-
<template v-if="item.href" #actions>
|
|
461
|
+
<template v-if="item.href || item.action === 'user-settings'" #actions>
|
|
451
462
|
<NcActionLink
|
|
463
|
+
v-if="item.href"
|
|
452
464
|
:href="item.href"
|
|
453
465
|
:aria-label="captionEditLabel(item)"
|
|
454
466
|
:data-testid="`cn-nav-caption-edit-${item.id}`">
|
|
@@ -457,6 +469,16 @@
|
|
|
457
469
|
</template>
|
|
458
470
|
{{ captionEditLabel(item) }}
|
|
459
471
|
</NcActionLink>
|
|
472
|
+
<NcActionButton
|
|
473
|
+
v-else
|
|
474
|
+
:aria-label="captionEditLabel(item)"
|
|
475
|
+
:data-testid="`cn-nav-caption-edit-${item.id}`"
|
|
476
|
+
@click="cnOpenUserSettings()">
|
|
477
|
+
<template #icon>
|
|
478
|
+
<Pencil :size="20" />
|
|
479
|
+
</template>
|
|
480
|
+
{{ captionEditLabel(item) }}
|
|
481
|
+
</NcActionButton>
|
|
460
482
|
</template>
|
|
461
483
|
</NcAppNavigationCaption>
|
|
462
484
|
<NcAppNavigationItem
|
|
@@ -500,7 +522,7 @@
|
|
|
500
522
|
<script>
|
|
501
523
|
import { translate as t } from '@nextcloud/l10n'
|
|
502
524
|
import { generateUrl } from '@nextcloud/router'
|
|
503
|
-
import { NcActionLink, NcAppNavigation, NcAppNavigationCaption, NcAppNavigationItem, NcAppNavigationList, NcAppNavigationNew, NcAppNavigationSettings, NcButton, NcCounterBubble } from '@nextcloud/vue'
|
|
525
|
+
import { NcActionButton, NcActionLink, NcAppNavigation, NcAppNavigationCaption, NcAppNavigationItem, NcAppNavigationList, NcAppNavigationNew, NcAppNavigationSettings, NcButton, NcCounterBubble } from '@nextcloud/vue'
|
|
504
526
|
import { toRaw } from 'vue'
|
|
505
527
|
import BookOpenVariant from 'vue-material-design-icons/BookOpenVariant.vue'
|
|
506
528
|
import Cog from 'vue-material-design-icons/Cog.vue'
|
|
@@ -595,6 +617,7 @@ export default {
|
|
|
595
617
|
name: 'CnAppNav',
|
|
596
618
|
|
|
597
619
|
components: {
|
|
620
|
+
NcActionButton,
|
|
598
621
|
NcActionLink,
|
|
599
622
|
Pencil,
|
|
600
623
|
NcAppNavigation,
|
|
@@ -1974,6 +1997,8 @@ export default {
|
|
|
1974
1997
|
* `icon`, `count`, `children`, and `pinned`. A caption's `href` is
|
|
1975
1998
|
* drawn as a pencil link beside the heading: the place where what
|
|
1976
1999
|
* stands under it is changed (a user's own choice of entries, say).
|
|
2000
|
+
* `action: "user-settings"` draws the same pencil as a button that
|
|
2001
|
+
* opens the user settings dialog.
|
|
1977
2002
|
*
|
|
1978
2003
|
* @param {{ type?: string }} item Menu entry descriptor.
|
|
1979
2004
|
* @return {boolean}
|
|
@@ -346,7 +346,12 @@
|
|
|
346
346
|
falls back to formatValue(). Columns with `aggregate` get a
|
|
347
347
|
count of related objects (see cellValue/loadAggregates). The
|
|
348
348
|
#column-{key} slot still wins. -->
|
|
349
|
+
<span
|
|
350
|
+
v-if="isTextZero(row, col)"
|
|
351
|
+
class="cn-table-cell__zero"
|
|
352
|
+
data-testid="cn-cell-zero">{{ cellValue(row, col) }}</span>
|
|
349
353
|
<CnCellRenderer
|
|
354
|
+
v-else
|
|
350
355
|
:value="cellValue(row, col)"
|
|
351
356
|
:property="columnProperty(col)"
|
|
352
357
|
:formatter="col.formatter || null"
|
|
@@ -2199,6 +2204,26 @@ export default {
|
|
|
2199
2204
|
return this.getCellValue(row, this.columnValueField(col))
|
|
2200
2205
|
},
|
|
2201
2206
|
|
|
2207
|
+
/**
|
|
2208
|
+
* Whether an aggregate cell shows its `zeroLabel` as muted text instead
|
|
2209
|
+
* of through the column's widget (`aggregate.zeroAs: "text"`): a count
|
|
2210
|
+
* of zero, or a max with nothing to read.
|
|
2211
|
+
*
|
|
2212
|
+
* @param {object} row The row data.
|
|
2213
|
+
* @param {object} col The column definition.
|
|
2214
|
+
* @return {boolean}
|
|
2215
|
+
* @spec openspec/changes/aggregate-zero-as-text/specs/index-page/spec.md#requirement-a-count-column-can-show-its-zero-label-as-text
|
|
2216
|
+
*/
|
|
2217
|
+
isTextZero(row, col) {
|
|
2218
|
+
const aggregate = col && col.aggregate
|
|
2219
|
+
if (!aggregate || aggregate.zeroAs !== 'text' || typeof aggregate.zeroLabel !== 'string' || aggregate.zeroLabel === '') {
|
|
2220
|
+
return false
|
|
2221
|
+
}
|
|
2222
|
+
const cached = this.aggregateValues[String(row[this.rowKey])]
|
|
2223
|
+
const v = cached ? cached[col.key] : undefined
|
|
2224
|
+
return v === 0 || v === '0' || v === null
|
|
2225
|
+
},
|
|
2226
|
+
|
|
2202
2227
|
/**
|
|
2203
2228
|
* The row field a column's cell shows: `col.valueField` when set, else
|
|
2204
2229
|
* `col.key`. The key stays what the header sorts and filters on, so a
|
|
@@ -253,7 +253,7 @@
|
|
|
253
253
|
card, next to the checklist that explains it, and not here
|
|
254
254
|
as well: one primary button per page. -->
|
|
255
255
|
<NcButton
|
|
256
|
-
v-if="effectivePrimaryLabel && !showsNextStepCard"
|
|
256
|
+
v-if="effectivePrimaryLabel && !showsNextStepCard && stagePrimaryOnTab"
|
|
257
257
|
:id="primaryActionAnchorId"
|
|
258
258
|
ref="primaryActionButton"
|
|
259
259
|
variant="primary"
|
|
@@ -3832,6 +3832,19 @@ export default {
|
|
|
3832
3832
|
.slice(0, MAX_QUICK_ACTIONS)
|
|
3833
3833
|
},
|
|
3834
3834
|
|
|
3835
|
+
/**
|
|
3836
|
+
* Whether the stage's primary button belongs beside the open body tab:
|
|
3837
|
+
* an inline stage action with `tabs`/`notTabs` follows the tab like a
|
|
3838
|
+
* quick action (DqZaakAssistent: no "Next step" beside AI oversight).
|
|
3839
|
+
* It stays in the Actions menu either way.
|
|
3840
|
+
*
|
|
3841
|
+
* @return {boolean} true when the button may show.
|
|
3842
|
+
* @spec openspec/changes/stage-primary-follows-tab/specs/detail-page/spec.md#requirement-a-stage-action-can-follow-the-open-tab
|
|
3843
|
+
*/
|
|
3844
|
+
stagePrimaryOnTab() {
|
|
3845
|
+
return !this.stagePrimaryEntry || onTab(this.stagePrimary, this.activeBodyTab)
|
|
3846
|
+
},
|
|
3847
|
+
|
|
3835
3848
|
/**
|
|
3836
3849
|
* The stage's primary action in dispatchable form: the menu entry
|
|
3837
3850
|
* CnActionButtons built for it, with its `run()`. Null while the
|
|
@@ -99,6 +99,7 @@
|
|
|
99
99
|
:hideEmpty="content.hideEmpty === true || hideEmpty"
|
|
100
100
|
:columns="content.columns || 3"
|
|
101
101
|
:collapsedFields="content.collapsedFields ?? null"
|
|
102
|
+
:footnote="content.footnote || ''"
|
|
102
103
|
:editable="content.editable !== false" />
|
|
103
104
|
|
|
104
105
|
<!-- `type: 'related'` — resolves this object's relations and links into
|
|
@@ -926,7 +926,7 @@
|
|
|
926
926
|
<template v-if="hasRowActions" #row-actions="{ row }">
|
|
927
927
|
<slot name="row-actions" :row="row">
|
|
928
928
|
<CnRowActions
|
|
929
|
-
:actions="
|
|
929
|
+
:actions="rowMenuActionsFor(row)"
|
|
930
930
|
:row="row"
|
|
931
931
|
:rowLabel="rowTitleFor(row)"
|
|
932
932
|
@action="onRowAction" />
|
|
@@ -1173,7 +1173,7 @@
|
|
|
1173
1173
|
<template v-if="hasRowActions || $slots['row-actions']" #row-actions="{ object }">
|
|
1174
1174
|
<slot name="row-actions" :row="object">
|
|
1175
1175
|
<CnRowActions
|
|
1176
|
-
:actions="
|
|
1176
|
+
:actions="rowMenuActionsFor(object)"
|
|
1177
1177
|
:row="object"
|
|
1178
1178
|
:rowLabel="rowTitleFor(object)"
|
|
1179
1179
|
@action="onRowAction" />
|
|
@@ -1225,7 +1225,7 @@
|
|
|
1225
1225
|
<template v-if="hasRowActions" #card-actions="{ object }">
|
|
1226
1226
|
<slot name="row-actions" :row="object">
|
|
1227
1227
|
<CnRowActions
|
|
1228
|
-
:actions="
|
|
1228
|
+
:actions="rowMenuActionsFor(object)"
|
|
1229
1229
|
:row="object"
|
|
1230
1230
|
:rowLabel="rowTitleFor(object)"
|
|
1231
1231
|
:triggerLabel="isBoardLook ? t('nextcloud-vue', 'More actions for {name}', { name: rowTitleFor(object) }) : ''"
|
|
@@ -1237,7 +1237,7 @@
|
|
|
1237
1237
|
<!-- Right-click context menu (positioned at cursor via CSS). Same per-row list as the row actions menu, so the two never drift. -->
|
|
1238
1238
|
<CnContextMenu
|
|
1239
1239
|
v-model:open="contextMenuOpen"
|
|
1240
|
-
:actions="
|
|
1240
|
+
:actions="rowMenuActionsFor(contextMenuShownRow)"
|
|
1241
1241
|
:targetItem="contextMenuShownRow"
|
|
1242
1242
|
@action="onRowAction"
|
|
1243
1243
|
@close="closeContextMenu" />
|
|
@@ -8017,7 +8017,26 @@ export default {
|
|
|
8017
8017
|
},
|
|
8018
8018
|
|
|
8019
8019
|
hasRowActions() {
|
|
8020
|
-
|
|
8020
|
+
const refs = this.columnActionRefs
|
|
8021
|
+
return this.$slots['row-actions'] || this.mergedActions.some((action) => action && !refs.has(String(action.id || action.label)) && !refs.has(String(action.label)))
|
|
8022
|
+
},
|
|
8023
|
+
|
|
8024
|
+
/**
|
|
8025
|
+
* The row actions an `actions` column already shows as buttons, by the
|
|
8026
|
+
* ids (or labels) its `widgetProps.actions` names. The row menu leaves
|
|
8027
|
+
* them out, so a row does not offer the same action twice (DqPostvak).
|
|
8028
|
+
*
|
|
8029
|
+
* @return {Set<string>}
|
|
8030
|
+
* @spec openspec/changes/column-actions-leave-the-row-menu/specs/column-actions-leave-the-row-menu/spec.md
|
|
8031
|
+
*/
|
|
8032
|
+
columnActionRefs() {
|
|
8033
|
+
const refs = new Set()
|
|
8034
|
+
for (const col of Array.isArray(this.columns) ? this.columns : []) {
|
|
8035
|
+
if (col && typeof col === 'object' && col.widget === 'actions' && Array.isArray(col.widgetProps?.actions)) {
|
|
8036
|
+
col.widgetProps.actions.forEach((ref) => refs.add(String(ref)))
|
|
8037
|
+
}
|
|
8038
|
+
}
|
|
8039
|
+
return refs
|
|
8021
8040
|
},
|
|
8022
8041
|
|
|
8023
8042
|
/**
|
|
@@ -11864,6 +11883,22 @@ export default {
|
|
|
11864
11883
|
)
|
|
11865
11884
|
},
|
|
11866
11885
|
|
|
11886
|
+
/**
|
|
11887
|
+
* The row menu's actions: the row's actions less those an `actions`
|
|
11888
|
+
* column already shows as buttons.
|
|
11889
|
+
*
|
|
11890
|
+
* @param {object} row The row.
|
|
11891
|
+
* @return {Array<object>}
|
|
11892
|
+
* @spec openspec/changes/column-actions-leave-the-row-menu/specs/column-actions-leave-the-row-menu/spec.md
|
|
11893
|
+
*/
|
|
11894
|
+
rowMenuActionsFor(row) {
|
|
11895
|
+
const refs = this.columnActionRefs
|
|
11896
|
+
if (refs.size === 0) {
|
|
11897
|
+
return this.rowActionsFor(row)
|
|
11898
|
+
}
|
|
11899
|
+
return this.rowActionsFor(row).filter((action) => !refs.has(String(action.id || action.label)) && !refs.has(String(action.label)))
|
|
11900
|
+
},
|
|
11901
|
+
|
|
11867
11902
|
/**
|
|
11868
11903
|
* The row's own name, for the row menu button's accessible name
|
|
11869
11904
|
* ("Actions for <title>"): the `nameFormatter`, else the
|
|
@@ -141,3 +141,4 @@ export default {
|
|
|
141
141
|
| `borderless` | Boolean | `false` | Drop the card border and background, for a host that draws its own (a tab panel). |
|
|
142
142
|
| `flush` | Boolean | `false` | Drop the content padding, for a host that supplies its own inset. |
|
|
143
143
|
| `chromeless` | Boolean | `false` | Draw no card at all: what a tab panel wants, in one prop instead of three. Implies `show-title="false"`, `borderless` and `flush`, and drops the header divider too. The Save button keeps its header. Forwarded to `CnWidgetWrapper`. |
|
|
144
|
+
| `footnote` | String | `''` | A muted line under the fields, through the host translate (DqZaakContact "Ontvangstbevestiging"). |
|
|
@@ -396,6 +396,10 @@
|
|
|
396
396
|
</NcButton>
|
|
397
397
|
</div>
|
|
398
398
|
|
|
399
|
+
<p v-if="footnote" class="cn-object-data-widget__footnote" data-testid="cn-object-data-widget-footnote">
|
|
400
|
+
{{ cnTranslate(footnote) }}
|
|
401
|
+
</p>
|
|
402
|
+
|
|
399
403
|
<!-- Read-only @self metadata, surfaced on demand from the
|
|
400
404
|
Metadata action item rather than as a permanent page widget. -->
|
|
401
405
|
<CnObjectMetadataModal
|
|
@@ -837,6 +841,17 @@ export default {
|
|
|
837
841
|
default: () => t('nextcloud-vue', 'No data available'),
|
|
838
842
|
},
|
|
839
843
|
|
|
844
|
+
/**
|
|
845
|
+
* A muted line under the fields, through the host translate
|
|
846
|
+
* (DqZaakContact "Ontvangstbevestiging").
|
|
847
|
+
*
|
|
848
|
+
* @spec openspec/changes/data-widget-footnote/specs/data-widget-footnote/spec.md#requirement-a-data-card-can-end-with-a-footnote
|
|
849
|
+
*/
|
|
850
|
+
footnote: {
|
|
851
|
+
type: String,
|
|
852
|
+
default: '',
|
|
853
|
+
},
|
|
854
|
+
|
|
840
855
|
/** Label for the Metadata item in the overflow Actions menu. */
|
|
841
856
|
metadataLabel: {
|
|
842
857
|
type: String,
|
|
@@ -2535,6 +2550,12 @@ export default {
|
|
|
2535
2550
|
outline: none;
|
|
2536
2551
|
}
|
|
2537
2552
|
|
|
2553
|
+
.cn-object-data-widget__footnote {
|
|
2554
|
+
margin: calc(var(--default-grid-baseline, 4px) * 3) 0 0;
|
|
2555
|
+
color: var(--color-text-maxcontrast);
|
|
2556
|
+
font-size: 13px;
|
|
2557
|
+
}
|
|
2558
|
+
|
|
2538
2559
|
.cn-object-data-widget__empty {
|
|
2539
2560
|
color: var(--color-text-maxcontrast);
|
|
2540
2561
|
font-style: italic;
|
|
@@ -72,6 +72,7 @@
|
|
|
72
72
|
:options="schemaSelectOptions(groupIdx)"
|
|
73
73
|
:placeholder="labels.selectSchema"
|
|
74
74
|
:inputLabel="type.label"
|
|
75
|
+
:clearable="false"
|
|
75
76
|
label="label"
|
|
76
77
|
trackBy="value"
|
|
77
78
|
@update:modelValue="handleSchemaChange(groupIdx, type, $event)" />
|
|
@@ -1371,6 +1372,12 @@ export default {
|
|
|
1371
1372
|
max-width: 50%;
|
|
1372
1373
|
}
|
|
1373
1374
|
|
|
1375
|
+
/* DqBeheerinstellingen: the register select fills its half of the card. */
|
|
1376
|
+
.cn-register-mapping__selects-register :deep(.v-select) {
|
|
1377
|
+
width: 100%;
|
|
1378
|
+
max-width: none;
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1374
1381
|
.cn-register-mapping__select-grid {
|
|
1375
1382
|
display: grid;
|
|
1376
1383
|
grid-template-columns: repeat(var(--cn-register-mapping-columns, 3), minmax(0, 1fr));
|
|
@@ -603,13 +603,26 @@ export default {
|
|
|
603
603
|
margin: 0;
|
|
604
604
|
}
|
|
605
605
|
|
|
606
|
+
/* The server draws every dt as a 130px right-aligned inline block and pads
|
|
607
|
+
dt and dd 12px; a fact is a label over its value. */
|
|
608
|
+
.cn-retention__fact dt,
|
|
609
|
+
.cn-retention__fact dd {
|
|
610
|
+
display: block;
|
|
611
|
+
width: auto;
|
|
612
|
+
white-space: normal;
|
|
613
|
+
text-align: start;
|
|
614
|
+
}
|
|
615
|
+
|
|
606
616
|
.cn-retention__fact dt {
|
|
617
|
+
margin: 0;
|
|
618
|
+
padding: 0;
|
|
607
619
|
color: var(--color-text-maxcontrast);
|
|
608
620
|
font-size: 13px;
|
|
609
621
|
}
|
|
610
622
|
|
|
611
623
|
.cn-retention__fact dd {
|
|
612
624
|
margin: 0;
|
|
625
|
+
padding: 0;
|
|
613
626
|
font-weight: 600;
|
|
614
627
|
}
|
|
615
628
|
|
|
@@ -93,13 +93,23 @@ function loadSchema(register, schema) {
|
|
|
93
93
|
/**
|
|
94
94
|
* The names of referenced records, each asked once.
|
|
95
95
|
*
|
|
96
|
-
* @param {{register: string, schema: string, labelField: string, ids: Array<string>}} ref The reference filter.
|
|
96
|
+
* @param {{register: string, schema: string, labelField: string, matchField?: string, ids: Array<string>}} ref The reference filter; with `matchField` the ids are that field's values.
|
|
97
97
|
* @return {Promise<{[id: string]: string}>}
|
|
98
98
|
*/
|
|
99
99
|
async function loadLabels(ref) {
|
|
100
|
-
const prefix = `${ref.register}|${ref.schema}|${ref.labelField}|`
|
|
100
|
+
const prefix = `${ref.register}|${ref.schema}|${ref.labelField}|${ref.matchField || ''}|`
|
|
101
101
|
const missing = ref.ids.filter((id) => !labelCache.has(prefix + id))
|
|
102
|
-
|
|
102
|
+
// A value that identifies a record by another field: one read per value.
|
|
103
|
+
if (missing.length > 0 && ref.matchField) {
|
|
104
|
+
for (const value of missing) {
|
|
105
|
+
labelCache.set(prefix + value, getJson(`/apps/openregister/api/objects/${encodeURIComponent(ref.register)}/${encodeURIComponent(ref.schema)}`, { [ref.matchField]: value, _limit: 1 })
|
|
106
|
+
.then((data) => {
|
|
107
|
+
const row = Array.isArray(data && data.results) ? data.results[0] : null
|
|
108
|
+
return row ? pickRefLabel(row, ref.labelField) : null
|
|
109
|
+
})
|
|
110
|
+
.catch(() => null))
|
|
111
|
+
}
|
|
112
|
+
} else if (missing.length > 0) {
|
|
103
113
|
const request = getJson(`/apps/openregister/api/objects/${encodeURIComponent(ref.register)}/${encodeURIComponent(ref.schema)}`, { _ids: missing.join(','), _limit: missing.length })
|
|
104
114
|
.then((data) => {
|
|
105
115
|
const byId = {}
|
|
@@ -372,7 +382,7 @@ export default {
|
|
|
372
382
|
const fields = fieldsFromSchema(schema, { includeReadOnly: true })
|
|
373
383
|
const refs = this.candidates
|
|
374
384
|
.filter((c) => c.page === page.id)
|
|
375
|
-
.flatMap((c) => viewFilterReferences(c.state, fields))
|
|
385
|
+
.flatMap((c) => viewFilterReferences(c.state, fields, page.filterLabels))
|
|
376
386
|
for (const ref of refs) {
|
|
377
387
|
const labels = await loadLabels({ ...ref, register: ref.register || page.register })
|
|
378
388
|
if (Object.keys(labels).length === 0) {
|
|
@@ -169,6 +169,19 @@
|
|
|
169
169
|
</div>
|
|
170
170
|
</template>
|
|
171
171
|
|
|
172
|
+
<div v-if="composerOnly && canManage && composerEnabled"
|
|
173
|
+
class="cn-timeline-manage__header"
|
|
174
|
+
data-testid="cn-timeline-composer-heading">
|
|
175
|
+
<div class="cn-timeline-manage__heading">
|
|
176
|
+
<h3 class="cn-timeline-manage__title">
|
|
177
|
+
{{ composerTitleText }}
|
|
178
|
+
</h3>
|
|
179
|
+
<p class="cn-timeline-manage__subtitle">
|
|
180
|
+
{{ composerSubtitleText }}
|
|
181
|
+
</p>
|
|
182
|
+
</div>
|
|
183
|
+
</div>
|
|
184
|
+
|
|
172
185
|
<NcNoteCard v-if="composerOnly && error" type="error" data-testid="cn-timeline-error">
|
|
173
186
|
{{ error }}
|
|
174
187
|
</NcNoteCard>
|
|
@@ -332,6 +345,16 @@ export default {
|
|
|
332
345
|
return this.content.subtitle ? this.translate(this.content.subtitle) : t('nextcloud-vue', 'What happened, who did it and when, newest first')
|
|
333
346
|
},
|
|
334
347
|
|
|
348
|
+
/** @return {string} The title of the note form's own card (`composer: "only"`): `content.title`, else Add note. */
|
|
349
|
+
composerTitleText() {
|
|
350
|
+
return this.content.title ? this.translate(this.content.title) : t('nextcloud-vue', 'Add note')
|
|
351
|
+
},
|
|
352
|
+
|
|
353
|
+
/** @return {string} The line under that title: `content.subtitle`, else where the note goes. */
|
|
354
|
+
composerSubtitleText() {
|
|
355
|
+
return this.content.subtitle ? this.translate(this.content.subtitle) : t('nextcloud-vue', 'Goes on the timeline above, internal unless you make it visible')
|
|
356
|
+
},
|
|
357
|
+
|
|
335
358
|
publicLabel() {
|
|
336
359
|
return this.content.publicLabel ? this.translate(this.content.publicLabel) : t('nextcloud-vue', 'Visible to the requester')
|
|
337
360
|
},
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
* dashboardWidgetRegistry. Like `audit-trail` it is a DETAIL-PAGE surface:
|
|
7
7
|
* the object comes from the page's object context. It has no config form
|
|
8
8
|
* yet, so it is placed from the manifest and never offered in the
|
|
9
|
-
* Add-widget picker.
|
|
9
|
+
* Add-widget picker. It draws its own title row and asks for the card, so a
|
|
10
|
+
* tab stack or the side column stands it in an untitled card.
|
|
10
11
|
*
|
|
11
12
|
* @spec openspec/changes/timeline-widget/specs/timeline-widget/spec.md#requirement-a-timeline-widget-shows-an-objects-dated-events-in-order
|
|
12
13
|
*/
|
|
@@ -29,4 +30,5 @@ registerDashboardWidget('timeline', {
|
|
|
29
30
|
icon: 'TimelineClockOutline',
|
|
30
31
|
surfaces: ['detail-page'],
|
|
31
32
|
ownsTitle: true,
|
|
33
|
+
chrome: 'card',
|
|
32
34
|
})
|
|
@@ -1213,6 +1213,16 @@
|
|
|
1213
1213
|
font-weight: 500;
|
|
1214
1214
|
}
|
|
1215
1215
|
|
|
1216
|
+
/* "Bewaren voor een procedure" and "Overdracht naar het e-Depot" are 15px/600
|
|
1217
|
+
section titles over their rows, not the inner heading's 1.4em. */
|
|
1218
|
+
.cn-look-board .cn-retention .cn-retention__section > .cn-inner-heading,
|
|
1219
|
+
.cn-look-board .cn-retention .cn-retention__outcome > .cn-inner-heading {
|
|
1220
|
+
margin: 4px 0 0;
|
|
1221
|
+
font-size: 15px;
|
|
1222
|
+
font-weight: 600;
|
|
1223
|
+
line-height: 1.2;
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1216
1226
|
/* ---- The task table's row button (CnTasksWidget table, DqZaakTaken) ------ */
|
|
1217
1227
|
/* "Afronden" is a 34px secondary with 13px text 14px in. NcButton pads a
|
|
1218
1228
|
text-only label 12px plus 4px inside; the doubled class outranks its
|
|
@@ -1368,6 +1368,7 @@
|
|
|
1368
1368
|
margin-inline-start: auto;
|
|
1369
1369
|
color: var(--color-text-maxcontrast);
|
|
1370
1370
|
font-size: 13px;
|
|
1371
|
+
white-space: nowrap;
|
|
1371
1372
|
}
|
|
1372
1373
|
|
|
1373
1374
|
.cn-look-board .cn-object-card--board .cn-object-card__record .cn-object-card__title {
|
|
@@ -1380,12 +1381,19 @@
|
|
|
1380
1381
|
}
|
|
1381
1382
|
|
|
1382
1383
|
.cn-look-board .cn-object-card--board .cn-object-card__record-meta {
|
|
1384
|
+
--nldesign-component-paragraph-font-size: 14px;
|
|
1385
|
+
--nldesign-component-paragraph-color: var(--color-text-maxcontrast);
|
|
1383
1386
|
margin: 0;
|
|
1384
1387
|
color: var(--color-text-maxcontrast);
|
|
1385
1388
|
font-size: 14px;
|
|
1386
1389
|
}
|
|
1387
1390
|
|
|
1391
|
+
/* The meta line, note and description are paragraphs: each hands the theme,
|
|
1392
|
+
which sets paragraphs with `!important`, its own size and ink. */
|
|
1388
1393
|
.cn-look-board .cn-object-card--board .cn-object-card__record-note {
|
|
1394
|
+
--nldesign-component-paragraph-font-size: 13px;
|
|
1395
|
+
--nldesign-component-paragraph-font-weight: 600;
|
|
1396
|
+
--nldesign-component-paragraph-color: var(--cn-board-text-soft);
|
|
1389
1397
|
margin: 0;
|
|
1390
1398
|
color: var(--cn-board-text-soft);
|
|
1391
1399
|
font-size: 13px;
|
|
@@ -1393,10 +1401,12 @@
|
|
|
1393
1401
|
}
|
|
1394
1402
|
|
|
1395
1403
|
.cn-look-board .cn-object-card--board .cn-object-card__record-note--purple {
|
|
1404
|
+
--nldesign-component-paragraph-color: var(--cn-status-purple-text);
|
|
1396
1405
|
color: var(--cn-status-purple-text);
|
|
1397
1406
|
}
|
|
1398
1407
|
|
|
1399
1408
|
.cn-look-board .cn-object-card--board .cn-object-card__record-note--teal {
|
|
1409
|
+
--nldesign-component-paragraph-color: var(--cn-status-teal-text);
|
|
1400
1410
|
color: var(--cn-status-teal-text);
|
|
1401
1411
|
}
|
|
1402
1412
|
|
|
@@ -1433,6 +1443,9 @@
|
|
|
1433
1443
|
}
|
|
1434
1444
|
|
|
1435
1445
|
.cn-look-board .cn-object-card--board .cn-object-card__record-description {
|
|
1446
|
+
--nldesign-component-paragraph-font-size: 14px;
|
|
1447
|
+
--nldesign-component-paragraph-line-height: 1.4;
|
|
1448
|
+
--nldesign-component-paragraph-color: var(--color-text-maxcontrast);
|
|
1436
1449
|
margin: 0;
|
|
1437
1450
|
color: var(--color-text-maxcontrast);
|
|
1438
1451
|
font-size: 14px;
|
|
@@ -1869,6 +1882,22 @@
|
|
|
1869
1882
|
font-weight: 700;
|
|
1870
1883
|
}
|
|
1871
1884
|
|
|
1885
|
+
/* A pill in a trailing cell stays inside the cell's width and ends in an
|
|
1886
|
+
ellipsis, instead of running over the next cell (DqTeamwachtrij). */
|
|
1887
|
+
.cn-look-board .cn-object-row__trail .cn-cell-renderer:not(.cn-look-nextcloud *) {
|
|
1888
|
+
display: block;
|
|
1889
|
+
max-width: 100%;
|
|
1890
|
+
}
|
|
1891
|
+
|
|
1892
|
+
.cn-look-board .cn-object-row__trail .cn-status-badge:not(.cn-look-nextcloud *) {
|
|
1893
|
+
display: inline-block;
|
|
1894
|
+
box-sizing: border-box;
|
|
1895
|
+
max-width: 100%;
|
|
1896
|
+
overflow: hidden;
|
|
1897
|
+
text-overflow: ellipsis;
|
|
1898
|
+
vertical-align: middle;
|
|
1899
|
+
}
|
|
1900
|
+
|
|
1872
1901
|
/* ---- The map view's missing-address card (DqZakenKaart) ---------------- */
|
|
1873
1902
|
/* The board draws "3 zaken zonder adres" as a 15px title at its normal line
|
|
1874
1903
|
height with "Toon ze in de tabel" under it as a link flush with the title,
|
|
@@ -2030,3 +2059,24 @@
|
|
|
2030
2059
|
.cn-look-board .cn-saved-views-panel:not(.cn-look-nextcloud *) .cn-saved-views-panel__row:is(.cn-saved-views-panel__row--selected, :has(.action-item--open)) .cn-saved-views-panel__name-text {
|
|
2031
2060
|
color: var(--color-primary-element-light-text);
|
|
2032
2061
|
}
|
|
2062
|
+
|
|
2063
|
+
/* ---- The side-panel grid's row spacing --------------------------------- */
|
|
2064
|
+
/* The side-panel page is a grid of seven rows; a row-gap opens between every
|
|
2065
|
+
pair, empty or not, so a page without below-header, stat row or chip row
|
|
2066
|
+
drew 60px of nothing under its header (DqZoekresultaten). The grid has no
|
|
2067
|
+
row gap here; each part that is present carries the section gap under it.
|
|
2068
|
+
@spec openspec/changes/side-panel-grid-no-empty-row-gaps/specs/side-panel-grid-no-empty-row-gaps/spec.md */
|
|
2069
|
+
.cn-look-board .cn-index-page--with-side-panel:not(.cn-look-nextcloud *) {
|
|
2070
|
+
row-gap: 0;
|
|
2071
|
+
}
|
|
2072
|
+
|
|
2073
|
+
.cn-look-board .cn-index-page--with-side-panel:not(.cn-look-nextcloud *) > :first-child,
|
|
2074
|
+
.cn-look-board .cn-index-page--with-side-panel:not(.cn-look-nextcloud *) > .cn-index-page__below-header,
|
|
2075
|
+
.cn-look-board .cn-index-page--with-side-panel:not(.cn-look-nextcloud *) > .cn-index-page__stat-row,
|
|
2076
|
+
.cn-look-board .cn-index-page--with-side-panel:not(.cn-look-nextcloud *) > .cn-actions-bar {
|
|
2077
|
+
margin-bottom: var(--cn-board-section-gap);
|
|
2078
|
+
}
|
|
2079
|
+
|
|
2080
|
+
.cn-look-board .cn-index-page--with-side-panel:not(.cn-look-nextcloud *) > .cn-index-page__quick-filter-row {
|
|
2081
|
+
margin-bottom: calc(var(--cn-board-section-gap) + 12px);
|
|
2082
|
+
}
|
package/src/css/look-board.css
CHANGED
|
@@ -2886,8 +2886,12 @@ body:has(.cn-look-board):not(:has(.cn-look-nextcloud)) .v-popper__popper.action-
|
|
|
2886
2886
|
font-size: 14px;
|
|
2887
2887
|
}
|
|
2888
2888
|
|
|
2889
|
+
/* The version card's title follows its board: 17px on DqInstellingenAlgemeen
|
|
2890
|
+
and LrBeheerinstellingen; an app whose board draws another size passes the
|
|
2891
|
+
shell's `versionTitleSize`.
|
|
2892
|
+
@spec openspec/changes/board-version-title-size/specs/board-settings-card-controls/spec.md */
|
|
2889
2893
|
.cn-look-board .settings-section:not(.cn-look-nextcloud *):has(.cn-version-info--compact) > .settings-section__name {
|
|
2890
|
-
font-size:
|
|
2894
|
+
font-size: var(--cn-board-version-title-size, 17px);
|
|
2891
2895
|
}
|
|
2892
2896
|
|
|
2893
2897
|
/* ---- A card titled as a side card (`titleTone: "side"`) ------------------ */
|
package/src/css/table.css
CHANGED
|
@@ -203,6 +203,11 @@
|
|
|
203
203
|
/* The overline of a cell (`columns[].overline` / `overlineText`): muted and
|
|
204
204
|
smaller, on its own line above the value. Same theme hooks as the
|
|
205
205
|
secondary line. */
|
|
206
|
+
/* A count column's zero label as text (`aggregate.zeroAs: "text"`): "Geen" in the muted ink. */
|
|
207
|
+
.cn-data-table .cn-table-cell__zero {
|
|
208
|
+
color: var(--color-text-maxcontrast);
|
|
209
|
+
}
|
|
210
|
+
|
|
206
211
|
.cn-data-table .cn-table-cell__overline {
|
|
207
212
|
display: block;
|
|
208
213
|
color: var(--cn-table-secondary-color, var(--color-text-maxcontrast));
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"$id": "https://raw.githubusercontent.com/ConductionNL/nextcloud-vue/main/src/schemas/app-manifest-v2.schema.json",
|
|
4
4
|
"title": "Conduction App Manifest v2",
|
|
5
5
|
"description": "v2 schema for the JSON-driven page and navigation manifest consumed by @conduction/nextcloud-vue. Introduces a uniform widgets[] array on every page type with a per-slot grid coordinate system, a typed actions[] discriminator, and the required $schema field for version detection. v1 manifests continue to validate against app-manifest.schema.json (unchanged).",
|
|
6
|
-
"version": "2.
|
|
6
|
+
"version": "2.155.0",
|
|
7
7
|
"type": "object",
|
|
8
8
|
"required": ["$schema", "version"],
|
|
9
9
|
"allOf": [
|
|
@@ -3609,7 +3609,9 @@
|
|
|
3609
3609
|
"else": {
|
|
3610
3610
|
"$ref": "#/$defs/actionFields",
|
|
3611
3611
|
"properties": {
|
|
3612
|
-
"children": { "items": { "$ref": "#/$defs/headerAction" } }
|
|
3612
|
+
"children": { "items": { "$ref": "#/$defs/headerAction" } },
|
|
3613
|
+
"tabs": { "type": "array", "items": { "type": "string", "minLength": 1 }, "description": "As a `primaryActionByStage` entry: the body tabs beside which its header button shows (2.155.0)." },
|
|
3614
|
+
"notTabs": { "type": "array", "items": { "type": "string", "minLength": 1 }, "description": "As a `primaryActionByStage` entry: the body tabs beside which its header button stands aside; it stays in the Actions menu (2.155.0)." }
|
|
3613
3615
|
},
|
|
3614
3616
|
"unevaluatedProperties": false
|
|
3615
3617
|
}
|
|
@@ -52,6 +52,8 @@ export function contentHeaderLink(content) {
|
|
|
52
52
|
/**
|
|
53
53
|
* The header link a widget DEFINITION declares: `headerLink` on the
|
|
54
54
|
* definition itself, else what its content asks for (see contentHeaderLink).
|
|
55
|
+
* A view-all the widget draws under its own content
|
|
56
|
+
* (`viewAllPlacement: "footer"`) is not a header link.
|
|
55
57
|
*
|
|
56
58
|
* @param {object|null|undefined} widget A widget definition.
|
|
57
59
|
* @return {{label: string, route?: string, params?: object, query?: object, href?: string}|null}
|
|
@@ -64,7 +66,11 @@ export function widgetHeaderLink(widget) {
|
|
|
64
66
|
if (declared && typeof declared === 'object' && typeof declared.label === 'string' && declared.label !== '') {
|
|
65
67
|
return declared
|
|
66
68
|
}
|
|
67
|
-
|
|
69
|
+
const content = widget.content
|
|
70
|
+
if (content && content.viewAllPlacement === 'footer' && !content.headerLink) {
|
|
71
|
+
return null
|
|
72
|
+
}
|
|
73
|
+
return contentHeaderLink(content)
|
|
68
74
|
}
|
|
69
75
|
|
|
70
76
|
/**
|