@conduction/nextcloud-vue 2.104.0 → 2.106.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.map +1 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js +1 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js.map +1 -1
- package/dist/esm/components/CnCardGrid/CnCardGrid.vue.js +1 -1
- package/dist/esm/components/CnCardGrid/CnCardGrid.vue2.js +18 -0
- package/dist/esm/components/CnCardGrid/CnCardGrid.vue2.js.map +1 -1
- package/dist/esm/components/CnCardGrid/CnCardGrid.vue3.js +3 -1
- package/dist/esm/components/CnCardGrid/CnCardGrid.vue3.js.map +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue.js +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js +18 -0
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js.map +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js.map +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue.js +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js +93 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue.js +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +6 -3
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +3 -3
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +112 -5
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue.js +9 -0
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue.js.map +1 -0
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue2.js +24 -0
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue2.js.map +1 -0
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue3.js +49 -0
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue3.js.map +1 -0
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue.js +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js +36 -18
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js +17 -38
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js.map +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue.js +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue.js +1 -1
- package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue2.js +1 -1
- package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue2.js.map +1 -1
- package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue3.js.map +1 -1
- package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue.js +1 -1
- package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue2.js +2 -0
- package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue2.js.map +1 -1
- package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue3.js +32 -29
- package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue3.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue.js +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +53 -2
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +119 -111
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
- package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue.js +1 -1
- package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue2.js +62 -1
- package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue.js +1 -1
- package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue2.js +73 -4
- package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue2.js.map +1 -1
- package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue3.js +74 -27
- package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +208 -46
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +121 -98
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue.js +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue2.js +24 -0
- package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue3.js +20 -4
- package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/useSelfFetchList.js +25 -6
- package/dist/esm/components/CnIndexPage/useSelfFetchList.js.map +1 -1
- package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue2.js +112 -1
- package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue3.js +100 -44
- package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue3.js.map +1 -1
- package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue.js +1 -1
- package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue2.js +67 -4
- package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue3.js +1 -1
- package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnNoticeWidget/CnNoticeWidget.vue.js +9 -0
- package/dist/esm/components/CnNoticeWidget/CnNoticeWidget.vue.js.map +1 -0
- package/dist/esm/components/CnNoticeWidget/CnNoticeWidget.vue2.js +88 -0
- package/dist/esm/components/CnNoticeWidget/CnNoticeWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnNoticeWidget/CnNoticeWidget.vue3.js +39 -0
- package/dist/esm/components/CnNoticeWidget/CnNoticeWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue.js +1 -1
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js +295 -12
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js +267 -144
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue.js +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js +4 -0
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js +3 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +93 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js +322 -246
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue.js +1 -1
- package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue2.js +122 -7
- package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue3.js +189 -93
- package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnSettingsField/CnSettingsField.vue.js +1 -1
- package/dist/esm/components/CnSettingsField/CnSettingsField.vue2.js.map +1 -1
- package/dist/esm/components/CnSettingsField/CnSettingsField.vue3.js +3 -3
- package/dist/esm/components/CnSettingsField/CnSettingsField.vue3.js.map +1 -1
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue.js +1 -1
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js.map +1 -1
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js +16 -4
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js.map +1 -1
- package/dist/esm/components/CnTabs/CnTabs.vue.js +1 -1
- package/dist/esm/components/CnTabs/CnTabs.vue2.js.map +1 -1
- package/dist/esm/components/CnTabs/CnTabs.vue3.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue.js +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +42 -0
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js +38 -19
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue.js +9 -0
- package/dist/esm/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue.js.map +1 -0
- package/dist/esm/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue2.js +258 -0
- package/dist/esm/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue3.js +69 -0
- package/dist/esm/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue.js +1 -1
- package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue2.js +11 -0
- package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue2.js.map +1 -1
- package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue3.js +4 -4
- package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue3.js.map +1 -1
- package/dist/esm/components/CnWidgetGrid/builtInWidgets.js +16 -14
- package/dist/esm/components/CnWidgetGrid/builtInWidgets.js.map +1 -1
- package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js +12 -0
- package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js.map +1 -1
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/l10n/en.json.js +24 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +24 -1
- package/dist/esm/l10n/nl.json.js.map +1 -1
- package/dist/esm/library-style.js +1 -1
- package/dist/esm/nextcloud-vue.css +1369 -748
- package/dist/esm/utils/dueText.js +18 -3
- package/dist/esm/utils/dueText.js.map +1 -1
- package/dist/esm/utils/libraryWidgetKeys.js +2 -0
- package/dist/esm/utils/libraryWidgetKeys.js.map +1 -1
- package/dist/esm/utils/nextcloudApps.js +45 -0
- package/dist/esm/utils/nextcloudApps.js.map +1 -0
- package/dist/esm/utils/scopeListLayout.js +9 -2
- package/dist/esm/utils/scopeListLayout.js.map +1 -1
- package/dist/esm/utils/sortOrder.js +11 -1
- package/dist/esm/utils/sortOrder.js.map +1 -1
- package/dist/esm/utils/validateManifestV2.compiled.js +3 -3
- package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
- package/dist/esm/utils/visibleWhen.js +12 -4
- package/dist/esm/utils/visibleWhen.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +8965 -6497
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +1369 -748
- package/l10n/en.json +24 -1
- package/l10n/nl.json +24 -1
- package/package.json +1 -1
- package/src/components/CnAdminSettingsShell/CnAdminSettingsShell.vue +1 -1
- package/src/components/CnCardGrid/CnCardGrid.md +2 -0
- package/src/components/CnCardGrid/CnCardGrid.vue +20 -0
- package/src/components/CnCellRenderer/CnCellRenderer.vue +19 -1
- package/src/components/CnChartWidget/CnChartWidget.md +2 -0
- package/src/components/CnChartWidget/CnChartWidget.vue +93 -1
- package/src/components/CnDashboardPage/CnDashboardPage.vue +9 -6
- package/src/components/CnDetailPage/CnDetailPage.md +3 -2
- package/src/components/CnDetailPage/CnDetailPage.vue +112 -5
- package/src/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue +60 -0
- package/src/components/CnDetailWidgetHost/CnDetailWidgetHost.vue +36 -29
- package/src/components/CnFactsWidget/CnFactsWidget.vue +4 -0
- package/src/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue +1 -1
- package/src/components/CnFeaturesBoard/CnFeaturesBoard.vue +4 -1
- package/src/components/CnFilesBrowser/CnFilesBrowser.vue +70 -4
- package/src/components/CnFlowRunsWidget/CnFlowRunsWidget.vue +62 -1
- package/src/components/CnFlowsPage/CnFlowBoard.vue +132 -8
- package/src/components/CnIndexPage/CnIndexPage.md +8 -5
- package/src/components/CnIndexPage/CnIndexPage.vue +236 -54
- package/src/components/CnIndexPage/CnIndexPageWidgets.vue +36 -1
- package/src/components/CnIndexPage/useSelfFetchList.js +25 -6
- package/src/components/CnIndexSidebar/CnIndexSidebar.md +2 -0
- package/src/components/CnIndexSidebar/CnIndexSidebar.vue +148 -1
- package/src/components/CnNcWidgetWidget/CnNcWidgetWidget.vue +68 -5
- package/src/components/CnNoticeWidget/CnNoticeWidget.vue +153 -0
- package/src/components/CnNoticeWidget/index.js +12 -0
- package/src/components/CnObjectCard/CnObjectCard.md +1 -0
- package/src/components/CnObjectCard/CnObjectCard.vue +354 -13
- package/src/components/CnObjectSidebar/CnFilesTab.vue +6 -0
- package/src/components/CnRecordListWidget/CnRecordListWidget.vue +190 -4
- package/src/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue +209 -9
- package/src/components/CnSettingsField/CnSettingsField.vue +4 -1
- package/src/components/CnSetupWizard/CnSetupWizard.vue +9 -1
- package/src/components/CnTabs/CnTabs.vue +11 -0
- package/src/components/CnTabsWidget/CnTabsWidget.vue +91 -18
- package/src/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.md +11 -0
- package/src/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue +382 -0
- package/src/components/CnTeamWorkloadWidget/index.js +14 -0
- package/src/components/CnVersionInfoCard/CnVersionInfoCard.vue +15 -4
- package/src/components/CnWidgetGrid/builtInWidgets.js +2 -0
- package/src/components/CnWidgetGrid/registerDashboardWidgets.js +12 -0
- package/src/components/index.js +2 -0
- package/src/css/dialog.css +20 -2
- package/src/css/index-page.css +14 -2
- package/src/css/look-board-detail.css +125 -8
- package/src/css/look-board-index.css +100 -4
- package/src/css/look-board.css +122 -14
- package/src/index.js +2 -1
- package/src/schemas/app-manifest-v2.schema.json +110 -8
- package/src/utils/dueText.js +18 -3
- package/src/utils/libraryWidgetKeys.js +2 -0
- package/src/utils/nextcloudApps.js +50 -0
- package/src/utils/scopeListLayout.js +9 -2
- package/src/utils/sortOrder.js +10 -0
- package/src/utils/validateManifestV2.compiled.js +3 -3
- package/src/utils/visibleWhen.js +12 -4
|
@@ -9,7 +9,7 @@ import { withPersonalLenses } from '../../utils/personalLenses.js'
|
|
|
9
9
|
import { parseSortKeysFromQuery, resolveFilterMap, resolveQueryFilters } from '../../utils/routeFilters.js'
|
|
10
10
|
import { orderToSortKeys } from '../../utils/sortOrder.js'
|
|
11
11
|
|
|
12
|
-
function resolveInitialQuickFilterIndex(quickFilters) {
|
|
12
|
+
export function resolveInitialQuickFilterIndex(quickFilters) {
|
|
13
13
|
const tabs = Array.isArray(quickFilters) ? quickFilters : null
|
|
14
14
|
if (!tabs || tabs.length === 0) {
|
|
15
15
|
return null
|
|
@@ -171,7 +171,8 @@ export function useSelfFetchList(props, instance, inject, extras = {}) {
|
|
|
171
171
|
const objCtx = unwrapCtx(objectCtxRaw)
|
|
172
172
|
const base = (objCtx && typeof objCtx === 'object') ? { ...objCtx } : {}
|
|
173
173
|
base.workspace = unwrapCtx(workspaceCtxRaw) || {}
|
|
174
|
-
|
|
174
|
+
// The page's own `appConfig` prop wins over a config an ancestor provides.
|
|
175
|
+
base.config = { ...(unwrapCtx(appConfigRaw) || {}), ...(props.appConfig || {}) }
|
|
175
176
|
return base
|
|
176
177
|
}
|
|
177
178
|
|
|
@@ -183,7 +184,7 @@ export function useSelfFetchList(props, instance, inject, extras = {}) {
|
|
|
183
184
|
// never again. Stringified (like CnDeltaWidget's `sourceKey`) so the
|
|
184
185
|
// watcher fires on real content changes only, not object identity.
|
|
185
186
|
const workspaceSignature = computed(() => JSON.stringify(unwrapCtx(workspaceCtxRaw) || {}))
|
|
186
|
-
const appConfigSignature = computed(() => JSON.stringify(unwrapCtx(appConfigRaw) || {}))
|
|
187
|
+
const appConfigSignature = computed(() => JSON.stringify({ ...(unwrapCtx(appConfigRaw) || {}), ...(props.appConfig || {}) }))
|
|
187
188
|
|
|
188
189
|
// Pass register/schema in their positional id slots (not as a {register, schema} object as
|
|
189
190
|
// second arg) — that previously made fetch URLs go to `/api/objects/undefined/[object Object]`.
|
|
@@ -227,6 +228,22 @@ export function useSelfFetchList(props, instance, inject, extras = {}) {
|
|
|
227
228
|
? props.sortKeys
|
|
228
229
|
: (props.sortKey ? [{ key: props.sortKey, order: props.sortOrder || 'asc' }] : defaultOrderKeys)
|
|
229
230
|
// The lens that is active on mount may set its own order.
|
|
231
|
+
/**
|
|
232
|
+
* The tabs the strip shows, so the fetch filters by the chip that is
|
|
233
|
+
* lit: the page's `effectiveQuickFilters` (declared, generated from
|
|
234
|
+
* `quickFiltersFrom`, or a named source's), else the prop while the
|
|
235
|
+
* page's computeds do not exist yet (setup).
|
|
236
|
+
*
|
|
237
|
+
* @return {Array<object>|null} The tabs, or null when there are none.
|
|
238
|
+
*/
|
|
239
|
+
function shownQuickFilters() {
|
|
240
|
+
const shown = instance && instance.proxy ? instance.proxy.effectiveQuickFilters : undefined
|
|
241
|
+
if (shown !== undefined) {
|
|
242
|
+
return shown
|
|
243
|
+
}
|
|
244
|
+
return withPersonalLenses(props.quickFilters, props.personalLenses)
|
|
245
|
+
}
|
|
246
|
+
|
|
230
247
|
const initialTabs = withPersonalLenses(props.quickFilters, props.personalLenses)
|
|
231
248
|
const initialTabSort = (!isMultiQuickFilter && Array.isArray(initialTabs))
|
|
232
249
|
? quickFilterSortKeys(initialTabs[activeQuickFilterIndex.value])
|
|
@@ -274,7 +291,7 @@ export function useSelfFetchList(props, instance, inject, extras = {}) {
|
|
|
274
291
|
// The visible calendar month, only while the page is in calendar mode.
|
|
275
292
|
const month = (instance && instance.proxy && instance.proxy.calendarRangeFilter) || {}
|
|
276
293
|
const scope = { ...(widen ? { ...scopeBase, _content_search: 'true' } : scopeBase), ...month }
|
|
277
|
-
const lensed =
|
|
294
|
+
const lensed = shownQuickFilters()
|
|
278
295
|
const tabs = Array.isArray(lensed) ? lensed : null
|
|
279
296
|
if (!tabs) {
|
|
280
297
|
return { ...queryFilters, ...scope, ...base }
|
|
@@ -289,7 +306,9 @@ export function useSelfFetchList(props, instance, inject, extras = {}) {
|
|
|
289
306
|
|
|
290
307
|
// Single mode: the active tab's filter spread last so it wins
|
|
291
308
|
// over a colliding props.filter entry.
|
|
292
|
-
|
|
309
|
+
// Tabs that arrived after setup (`quickFiltersFrom`) have no index
|
|
310
|
+
// yet: the default tab is the one in force, as the strip shows.
|
|
311
|
+
const activeIdx = activeQuickFilterIndex.value ?? resolveInitialQuickFilterIndex(tabs)
|
|
293
312
|
const tabFilter = (activeIdx !== null && activeIdx !== undefined) ? tabs[activeIdx]?.filter : null
|
|
294
313
|
return { ...queryFilters, ...scope, ...base, ...resolveFilterMap(tabFilter, params, ctx) }
|
|
295
314
|
},
|
|
@@ -309,7 +328,7 @@ export function useSelfFetchList(props, instance, inject, extras = {}) {
|
|
|
309
328
|
// for a lens without goes back to the page's own order. A column the
|
|
310
329
|
// person sorts by afterwards still wins until the next switch.
|
|
311
330
|
if (!isMultiQuickFilter && before && now[0] !== before[0]) {
|
|
312
|
-
const tabs =
|
|
331
|
+
const tabs = shownQuickFilters() || []
|
|
313
332
|
const keys = quickFilterSortKeys(tabs[now[0]]) || (quickFilterSortKeys(tabs[before[0]]) ? pageSortKeys : null)
|
|
314
333
|
if (keys && list.sortKeys) {
|
|
315
334
|
list.sortKeys.value = keys
|
|
@@ -197,6 +197,8 @@ With admin-only filter control:
|
|
|
197
197
|
| `visibleColumns` | Array | `null` | Currently visible column keys; `null` means all visible |
|
|
198
198
|
| `personalColumns` | Boolean | `true` | Show the Order and pin list and Reset columns in the Columns tab |
|
|
199
199
|
| `pinnedCount` | Number | `0` | How many of the first visible columns are pinned to the start of the table |
|
|
200
|
+
| `sortOptions` | Array | `[]` | The orders the Sort section in the Search tab offers: `[{ value, label, keys }]`, `keys` a `[{ key, order }]` list read as its ascending form. Empty draws no Sort section. Choosing a field or a direction emits `sort-change` with the new `[{ key, order }]`. |
|
|
201
|
+
| `currentSort` | Array | `[]` | The list's current order, `[{ key, order }]`: the Sort section shows its field, its direction and "Current order: ...". |
|
|
200
202
|
| `facetData` | Object | `{}` | Live facet data from the API: `{ fieldName: { values: [{ value, count }] } }` |
|
|
201
203
|
| `columnGroups` | Array | `[]` | Extra column groups beyond schema properties and built-in Metadata. Each: `{ id, label, columns: [{ key, label }], expanded? }` |
|
|
202
204
|
| `showMetadata` | Boolean | `true` | Whether to include the built-in Metadata column group |
|
|
@@ -37,6 +37,42 @@
|
|
|
37
37
|
@update:modelValue="$emit('search', $event)" />
|
|
38
38
|
</div>
|
|
39
39
|
|
|
40
|
+
<!-- Sort (list, card and map views; the table sorts by its headers):
|
|
41
|
+
the field, the direction and the order the list has now. -->
|
|
42
|
+
<div v-if="sortOptions.length > 0" class="cn-index-sidebar__section cn-index-sidebar__sort" data-testid="cn-index-sidebar-sort">
|
|
43
|
+
<h3>{{ t('nextcloud-vue', 'Sort') }}</h3>
|
|
44
|
+
<NcSelect
|
|
45
|
+
:modelValue="sortSelected"
|
|
46
|
+
:options="sortOptions"
|
|
47
|
+
label="label"
|
|
48
|
+
:clearable="false"
|
|
49
|
+
:inputLabel="t('nextcloud-vue', 'Sort by')"
|
|
50
|
+
@update:modelValue="onSortField" />
|
|
51
|
+
<div class="cn-index-sidebar__sort-direction" role="radiogroup" :aria-label="t('nextcloud-vue', 'Direction')">
|
|
52
|
+
<NcCheckboxRadioSwitch
|
|
53
|
+
type="radio"
|
|
54
|
+
name="cn-index-sidebar-sort-direction"
|
|
55
|
+
value="asc"
|
|
56
|
+
:modelValue="sortDirection"
|
|
57
|
+
:disabled="!sortSelected"
|
|
58
|
+
@update:modelValue="onSortDirection">
|
|
59
|
+
{{ t('nextcloud-vue', 'Ascending') }}
|
|
60
|
+
</NcCheckboxRadioSwitch>
|
|
61
|
+
<NcCheckboxRadioSwitch
|
|
62
|
+
type="radio"
|
|
63
|
+
name="cn-index-sidebar-sort-direction"
|
|
64
|
+
value="desc"
|
|
65
|
+
:modelValue="sortDirection"
|
|
66
|
+
:disabled="!sortSelected"
|
|
67
|
+
@update:modelValue="onSortDirection">
|
|
68
|
+
{{ t('nextcloud-vue', 'Descending') }}
|
|
69
|
+
</NcCheckboxRadioSwitch>
|
|
70
|
+
</div>
|
|
71
|
+
<p class="cn-index-sidebar__sort-current" data-testid="cn-index-sidebar-sort-current">
|
|
72
|
+
{{ currentSortText }}
|
|
73
|
+
</p>
|
|
74
|
+
</div>
|
|
75
|
+
|
|
40
76
|
<div v-if="hasActiveFilters" class="cn-index-sidebar__section">
|
|
41
77
|
<NcButton variant="tertiary" @click="onClearAll">
|
|
42
78
|
<template #icon>
|
|
@@ -273,6 +309,7 @@ import { METADATA_COLUMNS } from '../../constants/metadata.js'
|
|
|
273
309
|
import { facetOptions } from '../../utils/facets.js'
|
|
274
310
|
import { labelLang } from '../../utils/manifestTranslate.js'
|
|
275
311
|
import { columnsFromSchema, filtersFromSchema } from '../../utils/schema.js'
|
|
312
|
+
import { reverseSortKeys, sameSortKeys } from '../../utils/sortOrder.js'
|
|
276
313
|
import { CnDateRangePicker, DEFAULT_DATE_RANGE_PRESETS } from '../CnDateRangePicker/index.js'
|
|
277
314
|
import { CnIcon } from '../CnIcon/index.js'
|
|
278
315
|
|
|
@@ -366,6 +403,22 @@ export default {
|
|
|
366
403
|
default: 0,
|
|
367
404
|
},
|
|
368
405
|
|
|
406
|
+
/**
|
|
407
|
+
* The orders the Sort section offers, `[{ value, label, keys }]`, each
|
|
408
|
+
* `keys` a `[{ key, order }]` list read as its ascending form. Empty
|
|
409
|
+
* draws no Sort section (the table view sorts by its headers).
|
|
410
|
+
*/
|
|
411
|
+
sortOptions: {
|
|
412
|
+
type: Array,
|
|
413
|
+
default: () => [],
|
|
414
|
+
},
|
|
415
|
+
|
|
416
|
+
/** The list's current order, `[{ key, order }]`. */
|
|
417
|
+
currentSort: {
|
|
418
|
+
type: Array,
|
|
419
|
+
default: () => [],
|
|
420
|
+
},
|
|
421
|
+
|
|
369
422
|
/** Current search term */
|
|
370
423
|
searchValue: {
|
|
371
424
|
type: String,
|
|
@@ -508,7 +561,7 @@ export default {
|
|
|
508
561
|
},
|
|
509
562
|
},
|
|
510
563
|
|
|
511
|
-
emits: ['clear-filters', 'columns-change', 'columns-reorder', 'columns-reset', 'pin-change', 'filter-change', 'search', 'tab-change', 'update:open'],
|
|
564
|
+
emits: ['clear-filters', 'columns-change', 'columns-reorder', 'columns-reset', 'pin-change', 'filter-change', 'search', 'sort-change', 'tab-change', 'update:open'],
|
|
512
565
|
|
|
513
566
|
data() {
|
|
514
567
|
return {
|
|
@@ -535,6 +588,56 @@ export default {
|
|
|
535
588
|
},
|
|
536
589
|
|
|
537
590
|
computed: {
|
|
591
|
+
/**
|
|
592
|
+
* The Sort option the current order matches, as declared or reversed.
|
|
593
|
+
*
|
|
594
|
+
* @return {{option: object, direction: string}|null} The match, or null.
|
|
595
|
+
*/
|
|
596
|
+
sortMatch() {
|
|
597
|
+
const current = Array.isArray(this.currentSort) ? this.currentSort : []
|
|
598
|
+
for (const option of this.sortOptions) {
|
|
599
|
+
const keys = Array.isArray(option.keys) ? option.keys : []
|
|
600
|
+
if (sameSortKeys(keys, current)) {
|
|
601
|
+
return { option, direction: 'asc' }
|
|
602
|
+
}
|
|
603
|
+
if (sameSortKeys(reverseSortKeys(keys), current)) {
|
|
604
|
+
return { option, direction: 'desc' }
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
return null
|
|
608
|
+
},
|
|
609
|
+
|
|
610
|
+
/** @return {object|null} The Sort option shown as chosen. */
|
|
611
|
+
sortSelected() {
|
|
612
|
+
return this.sortMatch ? this.sortMatch.option : null
|
|
613
|
+
},
|
|
614
|
+
|
|
615
|
+
/** @return {string} The chosen direction, `asc` or `desc`. */
|
|
616
|
+
sortDirection() {
|
|
617
|
+
return this.sortMatch ? this.sortMatch.direction : 'asc'
|
|
618
|
+
},
|
|
619
|
+
|
|
620
|
+
/**
|
|
621
|
+
* The order the list has now, in words: "Current order: Created,
|
|
622
|
+
* descending", or that it is not sorted.
|
|
623
|
+
*
|
|
624
|
+
* @return {string} The sentence.
|
|
625
|
+
*/
|
|
626
|
+
currentSortText() {
|
|
627
|
+
const current = Array.isArray(this.currentSort) ? this.currentSort : []
|
|
628
|
+
if (current.length === 0) {
|
|
629
|
+
return t('nextcloud-vue', 'Not sorted')
|
|
630
|
+
}
|
|
631
|
+
const labelOf = (key) => {
|
|
632
|
+
const single = this.sortOptions.find((o) => Array.isArray(o.keys) && o.keys.length === 1 && o.keys[0].key === key)
|
|
633
|
+
return single ? single.label : key
|
|
634
|
+
}
|
|
635
|
+
const order = this.sortMatch && this.sortMatch.option.keys.length > 1
|
|
636
|
+
? `${this.sortMatch.option.label}, ${this.sortDirection === 'desc' ? t('nextcloud-vue', 'descending') : t('nextcloud-vue', 'ascending')}`
|
|
637
|
+
: current.map((entry) => `${labelOf(entry.key)}, ${entry.order === 'desc' ? t('nextcloud-vue', 'descending') : t('nextcloud-vue', 'ascending')}`).join('; ')
|
|
638
|
+
return t('nextcloud-vue', 'Current order: {order}', { order })
|
|
639
|
+
},
|
|
640
|
+
|
|
538
641
|
/** Resolved icon — explicit prop overrides schema.icon */
|
|
539
642
|
resolvedIcon() {
|
|
540
643
|
return this.icon || this.schema?.icon || ''
|
|
@@ -692,6 +795,50 @@ export default {
|
|
|
692
795
|
},
|
|
693
796
|
|
|
694
797
|
methods: {
|
|
798
|
+
t,
|
|
799
|
+
|
|
800
|
+
/**
|
|
801
|
+
* A field chosen in the Sort section: its order, in the direction
|
|
802
|
+
* already chosen.
|
|
803
|
+
*
|
|
804
|
+
* @param {object|null} option The chosen option.
|
|
805
|
+
* @return {void}
|
|
806
|
+
*/
|
|
807
|
+
onSortField(option) {
|
|
808
|
+
const chosen = option && this.sortOptions.find((o) => o.value === option.value)
|
|
809
|
+
if (!chosen) {
|
|
810
|
+
return
|
|
811
|
+
}
|
|
812
|
+
this.emitSort(chosen, this.sortDirection)
|
|
813
|
+
},
|
|
814
|
+
|
|
815
|
+
/**
|
|
816
|
+
* A direction chosen in the Sort section, for the chosen field.
|
|
817
|
+
*
|
|
818
|
+
* @param {string} direction `asc` or `desc`.
|
|
819
|
+
* @return {void}
|
|
820
|
+
*/
|
|
821
|
+
onSortDirection(direction) {
|
|
822
|
+
if (!this.sortSelected) {
|
|
823
|
+
return
|
|
824
|
+
}
|
|
825
|
+
this.emitSort(this.sortSelected, direction === 'desc' ? 'desc' : 'asc')
|
|
826
|
+
},
|
|
827
|
+
|
|
828
|
+
/**
|
|
829
|
+
* Emit the order an option stands for in a direction.
|
|
830
|
+
*
|
|
831
|
+
* @param {object} option The Sort option.
|
|
832
|
+
* @param {string} direction `asc` or `desc`.
|
|
833
|
+
* @return {void}
|
|
834
|
+
*/
|
|
835
|
+
emitSort(option, direction) {
|
|
836
|
+
const keys = Array.isArray(option.keys) ? option.keys : []
|
|
837
|
+
/**
|
|
838
|
+
* @event sort-change The Sort section chose an order. Payload: `[{ key, order }]`.
|
|
839
|
+
*/
|
|
840
|
+
this.$emit('sort-change', direction === 'desc' ? reverseSortKeys(keys) : keys.map((k) => ({ key: k.key, order: k.order || 'asc' })))
|
|
841
|
+
},
|
|
695
842
|
|
|
696
843
|
/**
|
|
697
844
|
* A manifest label through the injected lookup, or as written.
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
{{ t('nextcloud-vue', 'This widget can only be shown on the Nextcloud dashboard itself.') }}
|
|
47
47
|
</div>
|
|
48
48
|
|
|
49
|
-
<div v-else-if="
|
|
49
|
+
<div v-else-if="shownItems.length === 0" class="cn-nc-widget-widget__state">
|
|
50
50
|
{{ t('nextcloud-vue', 'No items available') }}
|
|
51
51
|
</div>
|
|
52
52
|
|
|
@@ -137,7 +137,10 @@ export default {
|
|
|
137
137
|
|
|
138
138
|
props: {
|
|
139
139
|
/**
|
|
140
|
-
* Persisted widget content `{widgetId, displayMode, limit?, showAllUrl?, showAllLabel?, showHeader?}`.
|
|
140
|
+
* Persisted widget content `{widgetId, displayMode, limit?, showAllUrl?, showAllLabel?, showHeader?, excludeApps?, excludeTypes?}`.
|
|
141
|
+
* `excludeApps` (`["systemtags"]`) and `excludeTypes` leave out the
|
|
142
|
+
* items of those apps or types (an item's own `app` / `type`, else the
|
|
143
|
+
* app in its link or icon URL); the list then comes from the items API.
|
|
141
144
|
* `showHeader: false` drops the widget's own header (icon and title);
|
|
142
145
|
* it is dropped too when the hosting card draws a title row.
|
|
143
146
|
* `limit` is the most items shown (the list then comes from the items
|
|
@@ -265,7 +268,38 @@ export default {
|
|
|
265
268
|
* @return {object[]} the items.
|
|
266
269
|
*/
|
|
267
270
|
shownItems() {
|
|
268
|
-
|
|
271
|
+
const kept = this.hasExclusions ? this.items.filter((item) => !this.isExcluded(item)) : this.items
|
|
272
|
+
return this.itemLimit > 0 ? kept.slice(0, this.itemLimit) : kept
|
|
273
|
+
},
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* The apps and item types `content.excludeApps` / `content.excludeTypes`
|
|
277
|
+
* leave out, lower-cased.
|
|
278
|
+
*
|
|
279
|
+
* @spec openspec/changes/nc-widget-exclude-apps/specs/nc-widget/spec.md#requirement-a-nextcloud-widget-can-leave-out-items-of-an-app-or-type
|
|
280
|
+
* @return {{apps: string[], types: string[]}}
|
|
281
|
+
*/
|
|
282
|
+
exclusions() {
|
|
283
|
+
const list = (value) => (Array.isArray(value) ? value : (typeof value === 'string' && value !== '' ? [value] : []))
|
|
284
|
+
.filter((entry) => typeof entry === 'string' && entry !== '')
|
|
285
|
+
.map((entry) => entry.toLowerCase())
|
|
286
|
+
return { apps: list(this.content && this.content.excludeApps), types: list(this.content && this.content.excludeTypes) }
|
|
287
|
+
},
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* How many items to ask the API for: the limit (or the default), and
|
|
291
|
+
* more while items are left out, so a filtered list still fills it.
|
|
292
|
+
*
|
|
293
|
+
* @return {number}
|
|
294
|
+
*/
|
|
295
|
+
requestLimit() {
|
|
296
|
+
const base = this.itemLimit > 0 ? this.itemLimit : API_ITEM_LIMIT
|
|
297
|
+
return this.hasExclusions ? Math.max(base * 3, 20) : base
|
|
298
|
+
},
|
|
299
|
+
|
|
300
|
+
/** @return {boolean} Whether any app or type is left out. */
|
|
301
|
+
hasExclusions() {
|
|
302
|
+
return this.exclusions.apps.length > 0 || this.exclusions.types.length > 0
|
|
269
303
|
},
|
|
270
304
|
|
|
271
305
|
/**
|
|
@@ -317,6 +351,34 @@ export default {
|
|
|
317
351
|
},
|
|
318
352
|
|
|
319
353
|
methods: {
|
|
354
|
+
/**
|
|
355
|
+
* Whether an item belongs to an app or type the content leaves out: its
|
|
356
|
+
* own `app` / `type` / `objectType`, else the app in an `/apps/<app>/`
|
|
357
|
+
* part of its link or icons.
|
|
358
|
+
*
|
|
359
|
+
* @spec openspec/changes/nc-widget-exclude-apps/specs/nc-widget/spec.md#requirement-a-nextcloud-widget-can-leave-out-items-of-an-app-or-type
|
|
360
|
+
* @param {object} item A widget item.
|
|
361
|
+
* @return {boolean}
|
|
362
|
+
*/
|
|
363
|
+
isExcluded(item) {
|
|
364
|
+
if (!item || typeof item !== 'object') {
|
|
365
|
+
return false
|
|
366
|
+
}
|
|
367
|
+
const { apps, types } = this.exclusions
|
|
368
|
+
const own = (value) => (typeof value === 'string' ? value.toLowerCase() : '')
|
|
369
|
+
const appsOf = [own(item.app)]
|
|
370
|
+
for (const url of [item.link, item.iconUrl, item.overlayIconUrl]) {
|
|
371
|
+
const match = typeof url === 'string' ? url.match(/\/apps\/([a-z0-9_-]+)\//i) : null
|
|
372
|
+
if (match) {
|
|
373
|
+
appsOf.push(match[1].toLowerCase())
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
if (apps.length > 0 && appsOf.some((app) => app !== '' && apps.includes(app))) {
|
|
377
|
+
return true
|
|
378
|
+
}
|
|
379
|
+
return types.length > 0 && [own(item.type), own(item.objectType)].some((type) => type !== '' && types.includes(type))
|
|
380
|
+
},
|
|
381
|
+
|
|
320
382
|
t,
|
|
321
383
|
|
|
322
384
|
/**
|
|
@@ -339,7 +401,8 @@ export default {
|
|
|
339
401
|
// where the widget has a registered native callback.
|
|
340
402
|
// A `limit` also takes the API list first: the native callback paints
|
|
341
403
|
// as many items as it likes. Its fallback to native stays.
|
|
342
|
-
|
|
404
|
+
// Leaving items out works on the API list only, so it skips native too.
|
|
405
|
+
if (this.displayMode !== 'horizontal' && this.itemLimit === 0 && !this.hasExclusions) {
|
|
343
406
|
const callback = this.resolveNativeCallback()
|
|
344
407
|
if (typeof callback === 'function') {
|
|
345
408
|
this.mountNative(callback)
|
|
@@ -424,7 +487,7 @@ export default {
|
|
|
424
487
|
// both the flat-array (older providers) and `{items}` (v2) shapes.
|
|
425
488
|
const url = generateOcsUrl('/apps/dashboard/api/v2/widget-items')
|
|
426
489
|
const response = await axios.get(url, {
|
|
427
|
-
params: { widgets: [this.widgetId], limit: this.
|
|
490
|
+
params: { widgets: [this.widgetId], limit: this.requestLimit },
|
|
428
491
|
})
|
|
429
492
|
const data = response && response.data && response.data.ocs ? response.data.ocs.data : null
|
|
430
493
|
const widgetData = data ? data[this.widgetId] : null
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
- SPDX-FileCopyrightText: 2026 Conduction B.V.
|
|
3
|
+
- SPDX-License-Identifier: EUPL-1.2
|
|
4
|
+
-->
|
|
5
|
+
<template>
|
|
6
|
+
<section
|
|
7
|
+
v-if="resolvedText || resolvedTitle"
|
|
8
|
+
class="cn-notice-widget"
|
|
9
|
+
:class="`cn-notice-widget--${resolvedVariant}`"
|
|
10
|
+
:aria-label="resolvedTitle || null"
|
|
11
|
+
role="note"
|
|
12
|
+
data-testid="cn-notice-widget">
|
|
13
|
+
<CnIcon
|
|
14
|
+
class="cn-notice-widget__icon"
|
|
15
|
+
:name="resolvedIcon"
|
|
16
|
+
:size="18"
|
|
17
|
+
aria-hidden="true" />
|
|
18
|
+
<p class="cn-notice-widget__text">
|
|
19
|
+
<strong v-if="resolvedTitle" class="cn-notice-widget__title" data-testid="cn-notice-widget-title">{{ resolvedTitle }}</strong>{{ resolvedTitle && resolvedText ? ' ' : '' }}{{ resolvedText }}
|
|
20
|
+
</p>
|
|
21
|
+
</section>
|
|
22
|
+
</template>
|
|
23
|
+
|
|
24
|
+
<script>
|
|
25
|
+
import { CnIcon } from '../CnIcon/index.js'
|
|
26
|
+
|
|
27
|
+
/** The tones a notice takes, and the icon each shows by default. */
|
|
28
|
+
const VARIANT_ICONS = Object.freeze({
|
|
29
|
+
info: 'InformationOutline',
|
|
30
|
+
warning: 'AlertOutline',
|
|
31
|
+
error: 'AlertCircleOutline',
|
|
32
|
+
success: 'CheckCircleOutline',
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* CnNoticeWidget — a toned notice box: an icon, a bold title and a line of
|
|
37
|
+
* text in one rounded box, as the boards draw a warning beside a record
|
|
38
|
+
* (DqSociaalDomein "Bijzondere persoonsgegevens: gezondheid. Elke inzage
|
|
39
|
+
* wordt gelogd met het doel."). Usable in a detail page's side column, its
|
|
40
|
+
* body grid and on a dashboard as widget type `notice`; the surface applies
|
|
41
|
+
* the widget's `visibleWhen`.
|
|
42
|
+
*
|
|
43
|
+
* `content`: `{ variant?, title?, text, icon? }`. `variant` is `info`
|
|
44
|
+
* (default), `warning`, `error` or `success`; `title` and `text` go through
|
|
45
|
+
* the host's translate; `icon` names a CnIcon instead of the variant's own.
|
|
46
|
+
*
|
|
47
|
+
* ```vue
|
|
48
|
+
* <CnNoticeWidget :content="{ variant: 'warning', title: 'Special category data: health.', text: 'Every view is logged with its purpose.' }" />
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export default {
|
|
52
|
+
name: 'CnNoticeWidget',
|
|
53
|
+
|
|
54
|
+
components: { CnIcon },
|
|
55
|
+
|
|
56
|
+
inject: {
|
|
57
|
+
/** The host app's translate function (CnAppRoot `cnTranslate`). */
|
|
58
|
+
cnTranslate: { default: () => (key) => key },
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
props: {
|
|
62
|
+
/**
|
|
63
|
+
* The notice: `{ variant?, title?, text, icon? }`.
|
|
64
|
+
*
|
|
65
|
+
* @type {{variant?: string, title?: string, text?: string, icon?: string}}
|
|
66
|
+
*/
|
|
67
|
+
content: {
|
|
68
|
+
type: Object,
|
|
69
|
+
default: () => ({}),
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
computed: {
|
|
74
|
+
/** @return {string} `info`, `warning`, `error` or `success`. */
|
|
75
|
+
resolvedVariant() {
|
|
76
|
+
const variant = this.content && this.content.variant === 'danger' ? 'error' : this.content && this.content.variant
|
|
77
|
+
return Object.hasOwn(VARIANT_ICONS, variant) ? variant : 'info'
|
|
78
|
+
},
|
|
79
|
+
|
|
80
|
+
/** @return {string} The icon name. */
|
|
81
|
+
resolvedIcon() {
|
|
82
|
+
const icon = this.content && this.content.icon
|
|
83
|
+
return typeof icon === 'string' && icon !== '' ? icon : VARIANT_ICONS[this.resolvedVariant]
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
/** @return {string} The title through the host translate. */
|
|
87
|
+
resolvedTitle() {
|
|
88
|
+
return this.translate(this.content && this.content.title)
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
/** @return {string} The text through the host translate. */
|
|
92
|
+
resolvedText() {
|
|
93
|
+
return this.translate(this.content && this.content.text)
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
methods: {
|
|
98
|
+
/**
|
|
99
|
+
* @param {unknown} text A manifest string.
|
|
100
|
+
* @return {string} Its translation, '' for anything but a non-empty string.
|
|
101
|
+
*/
|
|
102
|
+
translate(text) {
|
|
103
|
+
if (typeof text !== 'string' || text === '') {
|
|
104
|
+
return ''
|
|
105
|
+
}
|
|
106
|
+
return typeof this.cnTranslate === 'function' ? this.cnTranslate(text) : text
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
}
|
|
110
|
+
</script>
|
|
111
|
+
|
|
112
|
+
<style scoped>
|
|
113
|
+
.cn-notice-widget {
|
|
114
|
+
display: flex;
|
|
115
|
+
align-items: flex-start;
|
|
116
|
+
gap: 10px;
|
|
117
|
+
padding: 14px 16px;
|
|
118
|
+
border-radius: var(--cn-board-card-radius, 12px);
|
|
119
|
+
font-size: 14px;
|
|
120
|
+
line-height: 1.5;
|
|
121
|
+
background: color-mix(in srgb, var(--color-info, #0071ad) 10%, var(--color-main-background));
|
|
122
|
+
color: var(--color-main-text);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.cn-notice-widget--warning {
|
|
126
|
+
background: var(--color-warning-light, #fff4de);
|
|
127
|
+
color: var(--color-warning-text, #7a4f00);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.cn-notice-widget--error {
|
|
131
|
+
background: color-mix(in srgb, var(--color-error, #db0606) 10%, var(--color-main-background));
|
|
132
|
+
color: var(--color-error-text, var(--color-main-text));
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.cn-notice-widget--success {
|
|
136
|
+
background: color-mix(in srgb, var(--color-success, #2d7b41) 10%, var(--color-main-background));
|
|
137
|
+
color: var(--color-success-text, var(--color-main-text));
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.cn-notice-widget__icon {
|
|
141
|
+
flex: 0 0 auto;
|
|
142
|
+
margin-top: 2px;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.cn-notice-widget__text {
|
|
146
|
+
margin: 0;
|
|
147
|
+
overflow-wrap: anywhere;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.cn-notice-widget__title {
|
|
151
|
+
font-weight: 700;
|
|
152
|
+
}
|
|
153
|
+
</style>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SPDX-FileCopyrightText: 2026 Conduction B.V.
|
|
3
|
+
* SPDX-License-Identifier: EUPL-1.2
|
|
4
|
+
*
|
|
5
|
+
* CnNoticeWidget — a toned notice box (icon, bold title, text) for a side
|
|
6
|
+
* column, a detail body or a dashboard (widget type `notice`).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import CnNoticeWidget from './CnNoticeWidget.vue'
|
|
10
|
+
|
|
11
|
+
export { CnNoticeWidget }
|
|
12
|
+
export default CnNoticeWidget
|
|
@@ -155,3 +155,4 @@ export default {
|
|
|
155
155
|
| `leading` | Object | `null` | Leading element: `{ initials }` in a circle or `{ icon }` on a tint |
|
|
156
156
|
| `footerAction` | Object | `null` | `{ label, meta?, ariaLabel? }`, one footer action; emits `footer-action` |
|
|
157
157
|
| `cardFields` | Array | `null` | Property keys of the facts list, in order |
|
|
158
|
+
| `layout` | Object | `null` | Board look: the record layout, `{ headPill, number, title, meta, footerPill, footerDate }`; each part names a field and is left out while it is empty. A part whose field names a page column (`cardFieldColumns`) reads through that column's formatter, and a meta part through its widget, as the table cell does. A pill with `due` (`{ soonWithin }`) or `variantWhen` reads its date: overdue as error, soon (or the matching rule) as warning, labelled by `labels[variant]` or `labels.overdue` / `labels.soon` through the host's translate, else Overdue / Soon; any other date draws no pill. |
|