@conduction/nextcloud-vue 2.62.0 → 2.64.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/CnAdminActionCard/CnAdminActionCard.vue.js +10 -0
- package/dist/esm/components/CnAdminActionCard/CnAdminActionCard.vue.js.map +1 -0
- package/dist/esm/components/CnAdminActionCard/CnAdminActionCard.vue2.js +189 -0
- package/dist/esm/components/CnAdminActionCard/CnAdminActionCard.vue2.js.map +1 -0
- package/dist/esm/components/CnAdminActionCard/CnAdminActionCard.vue3.js +72 -0
- package/dist/esm/components/CnAdminActionCard/CnAdminActionCard.vue3.js.map +1 -0
- package/dist/esm/components/CnAppNav/CnAppNav.vue2.js +425 -39
- package/dist/esm/components/CnAppNav/CnAppNav.vue2.js.map +1 -1
- package/dist/esm/components/CnAppNav/CnAppNav.vue3.js +119 -42
- package/dist/esm/components/CnAppNav/CnAppNav.vue3.js.map +1 -1
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js +186 -9
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js.map +1 -1
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js +65 -42
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js.map +1 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js +61 -16
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js.map +1 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue3.js.map +1 -1
- package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue2.js +20 -0
- package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue3.js +3 -2
- package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js +33 -2
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js.map +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js.map +1 -1
- package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue2.js.map +1 -1
- package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue3.js +53 -37
- package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue3.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +29 -0
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +152 -135
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnColumnFilterPopover.vue.js +10 -0
- package/dist/esm/components/CnDataTable/CnColumnFilterPopover.vue.js.map +1 -0
- package/dist/esm/components/CnDataTable/CnColumnFilterPopover.vue2.js +293 -0
- package/dist/esm/components/CnDataTable/CnColumnFilterPopover.vue2.js.map +1 -0
- package/dist/esm/components/CnDataTable/CnColumnFilterPopover.vue3.js +189 -0
- package/dist/esm/components/CnDataTable/CnColumnFilterPopover.vue3.js.map +1 -0
- package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +253 -9
- package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue3.js +126 -50
- package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +66 -14
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +23 -14
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +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/CnFieldHelper/CnFieldHelper.vue2.js +3 -1
- package/dist/esm/components/CnFieldHelper/CnFieldHelper.vue2.js.map +1 -1
- package/dist/esm/components/CnFieldHelper/CnFieldHelper.vue3.js +1 -1
- package/dist/esm/components/CnFieldHelper/CnFieldHelper.vue3.js.map +1 -1
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js +234 -9
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue3.js +96 -57
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue3.js.map +1 -1
- package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue2.js +81 -4
- package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue3.js +22 -5
- package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +81 -2
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +7 -3
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/selfModeActions.js +3 -3
- package/dist/esm/components/CnIndexPage/selfModeActions.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +41 -2
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js +8 -3
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnResourceSelect/CnResourceSelect.vue2.js +121 -12
- package/dist/esm/components/CnResourceSelect/CnResourceSelect.vue2.js.map +1 -1
- package/dist/esm/components/CnResourceSelect/CnResourceSelect.vue3.js +3 -1
- package/dist/esm/components/CnResourceSelect/CnResourceSelect.vue3.js.map +1 -1
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js +326 -1
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js.map +1 -1
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js +112 -26
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js.map +1 -1
- package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue2.js +63 -2
- package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue3.js +96 -37
- package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnStagesWidget/stagesModel.js +5 -2
- package/dist/esm/components/CnStagesWidget/stagesModel.js.map +1 -1
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js +52 -2
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js +6 -6
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +14 -2
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js +2 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue.js +10 -0
- package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue.js.map +1 -0
- package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue2.js +337 -0
- package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue3.js +102 -0
- package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnTimelineWidget/dashboardRegistration.js +34 -0
- package/dist/esm/components/CnTimelineWidget/dashboardRegistration.js.map +1 -0
- package/dist/esm/components/CnWalkthrough/CnWalkthrough.vue2.js +131 -8
- package/dist/esm/components/CnWalkthrough/CnWalkthrough.vue2.js.map +1 -1
- package/dist/esm/components/CnWalkthrough/CnWalkthrough.vue3.js +40 -38
- package/dist/esm/components/CnWalkthrough/CnWalkthrough.vue3.js.map +1 -1
- package/dist/esm/components/CnWidgetGrid/builtInWidgets.js +8 -6
- package/dist/esm/components/CnWidgetGrid/builtInWidgets.js.map +1 -1
- package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js +1 -0
- package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js.map +1 -1
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue2.js +73 -1
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue2.js.map +1 -1
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue3.js +14 -2
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue3.js.map +1 -1
- package/dist/esm/components/CnWizardDialog/CnWizardDialog.vue2.js +19 -0
- package/dist/esm/components/CnWizardDialog/CnWizardDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnWizardDialog/CnWizardDialog.vue3.js +1 -1
- package/dist/esm/components/CnWizardDialog/CnWizardDialog.vue3.js.map +1 -1
- package/dist/esm/composables/useDependencyCheck.js +65 -0
- package/dist/esm/composables/useDependencyCheck.js.map +1 -0
- package/dist/esm/composables/useWalkthrough.js +218 -6
- package/dist/esm/composables/useWalkthrough.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 +45 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +45 -1
- package/dist/esm/l10n/nl.json.js.map +1 -1
- package/dist/esm/nextcloud-vue.css +780 -81
- package/dist/esm/store/useObjectStore.js +8 -0
- package/dist/esm/store/useObjectStore.js.map +1 -1
- package/dist/esm/utils/columnFilters.js +311 -0
- package/dist/esm/utils/columnFilters.js.map +1 -0
- package/dist/esm/utils/groupAutocomplete.js +123 -0
- package/dist/esm/utils/groupAutocomplete.js.map +1 -0
- package/dist/esm/utils/libraryWidgetKeys.js +2 -0
- package/dist/esm/utils/libraryWidgetKeys.js.map +1 -1
- package/dist/esm/utils/pickerOptions.js +198 -0
- package/dist/esm/utils/pickerOptions.js.map +1 -0
- package/dist/esm/utils/schema.js +83 -7
- package/dist/esm/utils/schema.js.map +1 -1
- package/dist/esm/utils/schemaRefSlug.js +19 -3
- package/dist/esm/utils/schemaRefSlug.js.map +1 -1
- package/dist/esm/utils/timelineEvents.js +174 -0
- package/dist/esm/utils/timelineEvents.js.map +1 -0
- package/dist/esm/utils/validateManifestV2.compiled.js +2 -2
- package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
- package/dist/esm/utils/walkthroughSignals.js +88 -0
- package/dist/esm/utils/walkthroughSignals.js.map +1 -0
- package/dist/nextcloud-vue.cjs.js +13088 -7937
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +780 -81
- package/l10n/en.json +45 -0
- package/l10n/nl.json +45 -0
- package/package.json +1 -1
- package/src/components/CnAdminActionCard/CnAdminActionCard.vue +234 -0
- package/src/components/CnAdminActionCard/index.js +4 -0
- package/src/components/CnAppNav/CnAppNav.vue +568 -43
- package/src/components/CnAppRoot/CnAppRoot.md +4 -0
- package/src/components/CnAppRoot/CnAppRoot.vue +223 -16
- package/src/components/CnAuditTrailCard/CnAuditTrailCard.vue +61 -16
- package/src/components/CnAuditTrailWidget/CnAuditTrailWidget.vue +22 -1
- package/src/components/CnCellRenderer/CnCellRenderer.vue +33 -2
- package/src/components/CnChoiceCards/CnChoiceCards.vue +56 -31
- package/src/components/CnDashboardPage/CnDashboardPage.vue +45 -4
- package/src/components/CnDataTable/CnColumnFilterPopover.vue +524 -0
- package/src/components/CnDataTable/CnDataTable.md +3 -0
- package/src/components/CnDataTable/CnDataTable.vue +305 -5
- package/src/components/CnDetailPage/CnDetailPage.md +4 -0
- package/src/components/CnDetailPage/CnDetailPage.vue +60 -1
- package/src/components/CnDetailWidgetHost/CnDetailWidgetHost.vue +2 -2
- package/src/components/CnFieldHelper/CnFieldHelper.vue +4 -2
- package/src/components/CnFormDialog/CnFormDialog.vue +290 -31
- package/src/components/CnHeaderWidget/CnHeaderWidget.vue +116 -6
- package/src/components/CnIndexPage/CnIndexPage.vue +87 -4
- package/src/components/CnIndexPage/selfModeActions.js +3 -3
- package/src/components/CnObjectListWidget/CnObjectListWidget.vue +46 -2
- package/src/components/CnResourceSelect/CnResourceSelect.vue +123 -12
- package/src/components/CnSetupWizard/CnSetupWizard.vue +392 -3
- package/src/components/CnStagesWidget/CnStagesWidget.vue +180 -2
- package/src/components/CnStagesWidget/stagesModel.js +5 -2
- package/src/components/CnStatWidget/CnStatWidget.vue +57 -3
- package/src/components/CnTabsWidget/CnTabsWidget.vue +15 -2
- package/src/components/CnTimelineWidget/CnTimelineWidget.vue +477 -0
- package/src/components/CnTimelineWidget/dashboardRegistration.js +32 -0
- package/src/components/CnTimelineWidget/index.js +4 -0
- package/src/components/CnWalkthrough/CnWalkthrough.vue +143 -10
- package/src/components/CnWidgetGrid/builtInWidgets.js +2 -0
- package/src/components/CnWidgetGrid/registerDashboardWidgets.js +1 -0
- package/src/components/CnWidgetWrapper/CnWidgetWrapper.md +4 -0
- package/src/components/CnWidgetWrapper/CnWidgetWrapper.vue +107 -1
- package/src/components/CnWizardDialog/CnWizardDialog.vue +20 -1
- package/src/components/index.js +2 -0
- package/src/composables/useDependencyCheck.js +61 -0
- package/src/composables/useWalkthrough.js +217 -5
- package/src/css/dashboard.css +49 -0
- package/src/css/detail-page.css +29 -4
- package/src/css/kpi-card.css +24 -1
- package/src/css/table.css +99 -6
- package/src/index.js +2 -0
- package/src/schemas/app-manifest-v2.schema.json +135 -3
- package/src/store/useObjectStore.js +8 -0
- package/src/utils/columnFilters.js +324 -0
- package/src/utils/groupAutocomplete.js +119 -0
- package/src/utils/libraryWidgetKeys.js +2 -0
- package/src/utils/pickerOptions.js +194 -0
- package/src/utils/schema.js +83 -7
- package/src/utils/schemaRefSlug.js +19 -3
- package/src/utils/timelineEvents.js +171 -0
- package/src/utils/validateManifestV2.compiled.js +2 -2
- package/src/utils/walkthroughSignals.js +94 -0
|
@@ -203,3 +203,7 @@ Static-manifest apps use `useAppManifest('myapp', bundledManifest)`, which fetch
|
|
|
203
203
|
| `softDependencyNotices` | Boolean | `false` | **Deprecated.** Restores the in-shell orange notices, one per unresolved optional dependency. Off by default: they stacked one per optional leaf and pushed the app's own content below the fold, for an audience who cannot act on them. Mount `CnLeafDependencySettings` in admin settings instead. Slated for removal. |
|
|
204
204
|
|
|
205
205
|
`unresolvedSoftDependencies` is unchanged and still exposed, so an app rendering its own surface from it keeps working.
|
|
206
|
+
|
|
207
|
+
### Without a navigation (`hideMenu`)
|
|
208
|
+
|
|
209
|
+
`hideMenu` (default `false`) renders neither the default CnAppNav nor the `#menu` slot, so the content starts at the left edge.
|
|
@@ -199,7 +199,13 @@
|
|
|
199
199
|
<!-- @binding {boolean} isOwner Whether the user owns this app (ADR-079 §3). -->
|
|
200
200
|
<!-- @binding {boolean} isAdmin Whether the user administers the instance; gates the Admin-settings link. -->
|
|
201
201
|
<!-- @binding {string} appId The app id used to build the Admin-settings target. -->
|
|
202
|
-
|
|
202
|
+
<!-- `hideMenu` renders no navigation at all, so the content starts
|
|
203
|
+
at the left edge. An EMPTY #menu override cannot do that: an
|
|
204
|
+
empty slot falls back to the default CnAppNav (ensureValidVNode),
|
|
205
|
+
which is why launchpad passed a hidden empty span. -->
|
|
206
|
+
<slot
|
|
207
|
+
v-if="!hideMenu"
|
|
208
|
+
name="menu"
|
|
203
209
|
:manifest="menuManifest"
|
|
204
210
|
:permissions="permissions"
|
|
205
211
|
:isOwner="isOwner"
|
|
@@ -509,7 +515,7 @@
|
|
|
509
515
|
:resume="walkthroughResume"
|
|
510
516
|
:translate="translate"
|
|
511
517
|
@complete="onWalkthroughComplete"
|
|
512
|
-
@
|
|
518
|
+
@progress="onWalkthroughProgress" />
|
|
513
519
|
</slot>
|
|
514
520
|
<!--
|
|
515
521
|
User-settings modal. Always mounted so descendants can
|
|
@@ -554,12 +560,27 @@
|
|
|
554
560
|
<p class="cn-app-root__walkthrough-hint">
|
|
555
561
|
{{ restartWalkthroughHint }}
|
|
556
562
|
</p>
|
|
557
|
-
<
|
|
558
|
-
<
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
+
<div class="cn-app-root__walkthrough-actions">
|
|
564
|
+
<NcButton
|
|
565
|
+
v-if="walkthroughProgressValue"
|
|
566
|
+
variant="primary"
|
|
567
|
+
data-testid="cn-walkthrough-continue"
|
|
568
|
+
@click="continueWalkthroughFromSettings">
|
|
569
|
+
<template #icon>
|
|
570
|
+
<Play :size="20" />
|
|
571
|
+
</template>
|
|
572
|
+
{{ continueWalkthroughLabel }}
|
|
573
|
+
</NcButton>
|
|
574
|
+
<NcButton
|
|
575
|
+
variant="secondary"
|
|
576
|
+
data-testid="cn-walkthrough-restart"
|
|
577
|
+
@click="restartWalkthroughFromSettings">
|
|
578
|
+
<template #icon>
|
|
579
|
+
<Restart :size="20" />
|
|
580
|
+
</template>
|
|
581
|
+
{{ walkthroughProgressValue ? startOverWalkthroughLabel : restartWalkthroughLabel }}
|
|
582
|
+
</NcButton>
|
|
583
|
+
</div>
|
|
563
584
|
</NcAppSettingsSection>
|
|
564
585
|
</slot>
|
|
565
586
|
<!--
|
|
@@ -638,11 +659,13 @@
|
|
|
638
659
|
import { getCurrentUser } from '@nextcloud/auth'
|
|
639
660
|
import axios from '@nextcloud/axios'
|
|
640
661
|
import { loadState } from '@nextcloud/initial-state'
|
|
662
|
+
import { translate as t } from '@nextcloud/l10n'
|
|
641
663
|
import { generateUrl } from '@nextcloud/router'
|
|
642
664
|
import { NcAppContent, NcAppSettingsDialog, NcAppSettingsSection, NcButton, NcContent, NcEmptyContent, NcLoadingIcon, NcNoteCard } from '@nextcloud/vue'
|
|
643
665
|
import { computed, reactive, shallowRef, watch } from 'vue'
|
|
644
666
|
import DatabaseSearchOutline from 'vue-material-design-icons/DatabaseSearchOutline.vue'
|
|
645
667
|
import OpenInNew from 'vue-material-design-icons/OpenInNew.vue'
|
|
668
|
+
import Play from 'vue-material-design-icons/Play.vue'
|
|
646
669
|
import Restart from 'vue-material-design-icons/Restart.vue'
|
|
647
670
|
import CnAiCompanion from '../CnAiCompanion/CnAiCompanion.vue'
|
|
648
671
|
import CnAppLoading from '../CnAppLoading/CnAppLoading.vue'
|
|
@@ -667,9 +690,12 @@ import { useSupportDialog } from '../../composables/useSupportDialog.js'
|
|
|
667
690
|
import { provideTenantContext } from '../../composables/useTenantContext.js'
|
|
668
691
|
import { useUserPreferences } from '../../composables/useUserPreferences.js'
|
|
669
692
|
import {
|
|
693
|
+
loadWalkthroughProgress,
|
|
670
694
|
loadWalkthroughSeenVersion,
|
|
671
695
|
normaliseSeenVersion,
|
|
696
|
+
persistWalkthroughProgress,
|
|
672
697
|
persistWalkthroughSeenVersion,
|
|
698
|
+
readLocalWalkthroughProgress,
|
|
673
699
|
readLocalWalkthroughSeenVersion,
|
|
674
700
|
useWalkthrough,
|
|
675
701
|
} from '../../composables/useWalkthrough.js'
|
|
@@ -680,6 +706,7 @@ import { BUILT_IN_FORMATTERS } from '../../utils/builtInFormatters.js'
|
|
|
680
706
|
import { DEFAULT_FORGE, resolveForge } from '../../utils/forge.js'
|
|
681
707
|
import { BUILT_IN_KB_PROVIDERS } from '../../utils/kbSearchProviders.js'
|
|
682
708
|
import { installModalStack, uninstallModalStack } from '../../utils/modalStack.js'
|
|
709
|
+
import { resolveFilterTokens } from '../../utils/resolveFilterTokens.js'
|
|
683
710
|
import { passesContextPredicates } from '../../utils/visibleIfContext.js'
|
|
684
711
|
|
|
685
712
|
/**
|
|
@@ -749,6 +776,7 @@ export default {
|
|
|
749
776
|
NcNoteCard,
|
|
750
777
|
DatabaseSearchOutline,
|
|
751
778
|
OpenInNew,
|
|
779
|
+
Play,
|
|
752
780
|
Restart,
|
|
753
781
|
CnAppNav,
|
|
754
782
|
CnAppLoading,
|
|
@@ -1028,6 +1056,13 @@ export default {
|
|
|
1028
1056
|
* the counts.
|
|
1029
1057
|
*/
|
|
1030
1058
|
cnMenuCounts: this.cnMenuCounts,
|
|
1059
|
+
/**
|
|
1060
|
+
* Reactive `{ [menuItemId]: number }` totals for menu entries
|
|
1061
|
+
* whose `count` is an object (`{ register, schema, filter? }`),
|
|
1062
|
+
* populated by `_hydrateMenuItemCounts()`. Read by
|
|
1063
|
+
* `CnAppNav.resolveCount()`.
|
|
1064
|
+
*/
|
|
1065
|
+
cnMenuItemCounts: this.cnMenuItemCounts,
|
|
1031
1066
|
}
|
|
1032
1067
|
},
|
|
1033
1068
|
|
|
@@ -1171,6 +1206,19 @@ export default {
|
|
|
1171
1206
|
required: true,
|
|
1172
1207
|
},
|
|
1173
1208
|
|
|
1209
|
+
/**
|
|
1210
|
+
* Render no app navigation at all: neither the default CnAppNav nor
|
|
1211
|
+
* the `#menu` slot, so the content starts at the left edge (a start
|
|
1212
|
+
* page without a menu). Off by default; the navigation renders as it
|
|
1213
|
+
* always has.
|
|
1214
|
+
*
|
|
1215
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-an-app-root-can-hide-its-menu
|
|
1216
|
+
*/
|
|
1217
|
+
hideMenu: {
|
|
1218
|
+
type: Boolean,
|
|
1219
|
+
default: false,
|
|
1220
|
+
},
|
|
1221
|
+
|
|
1174
1222
|
/**
|
|
1175
1223
|
* Human-readable name shown in the Nextcloud top bar. When set it
|
|
1176
1224
|
* overrides the technical `appId` so a virtual app shows its own name
|
|
@@ -1686,6 +1734,13 @@ export default {
|
|
|
1686
1734
|
* picked up by CnAppNav's reactive render.
|
|
1687
1735
|
*/
|
|
1688
1736
|
cnMenuCounts: reactive({}),
|
|
1737
|
+
/**
|
|
1738
|
+
* Reactive `{ [menuItemId]: number }` map of filtered totals, one
|
|
1739
|
+
* per menu entry whose `count` is an object. Provided to
|
|
1740
|
+
* descendants as `cnMenuItemCounts`. Populated by
|
|
1741
|
+
* `_hydrateMenuItemCounts()` at mount.
|
|
1742
|
+
*/
|
|
1743
|
+
cnMenuItemCounts: reactive({}),
|
|
1689
1744
|
/**
|
|
1690
1745
|
* Open state of the host NcAppSettingsDialog. Toggled
|
|
1691
1746
|
* to `true` by the provided `cnOpenUserSettings()`
|
|
@@ -1776,6 +1831,15 @@ export default {
|
|
|
1776
1831
|
* @type {string}
|
|
1777
1832
|
*/
|
|
1778
1833
|
walkthroughSeenVersionValue: readLocalWalkthroughSeenVersion(this.appId),
|
|
1834
|
+
/**
|
|
1835
|
+
* Where the user is in an unfinished tour (`{ tourId, stepId,
|
|
1836
|
+
* index, version }`), or null. Seeded from the local mirror, then
|
|
1837
|
+
* replaced by the per-user `<completionConfigKey>-progress`
|
|
1838
|
+
* preference. The tour resumes at this step on the next visit.
|
|
1839
|
+
*
|
|
1840
|
+
* @type {object|null}
|
|
1841
|
+
*/
|
|
1842
|
+
walkthroughProgressValue: readLocalWalkthroughProgress(this.appId),
|
|
1779
1843
|
/**
|
|
1780
1844
|
* Whether `walkthroughSeenVersionValue` is settled. Starts `true`
|
|
1781
1845
|
* when the manifest declares no `completionConfigKey` (the local
|
|
@@ -2529,13 +2593,15 @@ export default {
|
|
|
2529
2593
|
try {
|
|
2530
2594
|
const p = new URLSearchParams(window.location.search)
|
|
2531
2595
|
const tourId = p.get('cn_resume_tour')
|
|
2532
|
-
if (
|
|
2533
|
-
return
|
|
2596
|
+
if (tourId) {
|
|
2597
|
+
return { tourId, stepId: p.get('cn_resume_step') || '' }
|
|
2534
2598
|
}
|
|
2535
|
-
return { tourId, stepId: p.get('cn_resume_step') || '' }
|
|
2536
2599
|
} catch {
|
|
2537
|
-
|
|
2600
|
+
// No URL token; fall through to the remembered progress.
|
|
2538
2601
|
}
|
|
2602
|
+
// An unfinished tour continues at the step the user reached.
|
|
2603
|
+
const progress = this.walkthroughProgressValue
|
|
2604
|
+
return progress ? { tourId: progress.tourId, stepId: progress.stepId } : null
|
|
2539
2605
|
},
|
|
2540
2606
|
|
|
2541
2607
|
phase() {
|
|
@@ -2778,6 +2844,24 @@ export default {
|
|
|
2778
2844
|
return this.translate('Restart walkthrough')
|
|
2779
2845
|
},
|
|
2780
2846
|
|
|
2847
|
+
/**
|
|
2848
|
+
* Label for continuing an unfinished tour at the remembered step.
|
|
2849
|
+
*
|
|
2850
|
+
* @return {string}
|
|
2851
|
+
*/
|
|
2852
|
+
continueWalkthroughLabel() {
|
|
2853
|
+
return t('nextcloud-vue', 'Continue where you left off')
|
|
2854
|
+
},
|
|
2855
|
+
|
|
2856
|
+
/**
|
|
2857
|
+
* Label for restarting an unfinished tour from the first step.
|
|
2858
|
+
*
|
|
2859
|
+
* @return {string}
|
|
2860
|
+
*/
|
|
2861
|
+
startOverWalkthroughLabel() {
|
|
2862
|
+
return t('nextcloud-vue', 'Start over')
|
|
2863
|
+
},
|
|
2864
|
+
|
|
2781
2865
|
/**
|
|
2782
2866
|
* Resolve the active modal's Vue component from the registry.
|
|
2783
2867
|
* Returns null when no modal is open or the key no longer resolves.
|
|
@@ -2875,6 +2959,7 @@ export default {
|
|
|
2875
2959
|
this._validateRegistry()
|
|
2876
2960
|
this._warnCustomComponentsDeprecation()
|
|
2877
2961
|
this._hydrateMenuCounts()
|
|
2962
|
+
this._hydrateMenuItemCounts()
|
|
2878
2963
|
return
|
|
2879
2964
|
}
|
|
2880
2965
|
|
|
@@ -2903,6 +2988,7 @@ export default {
|
|
|
2903
2988
|
this._validateRegistry()
|
|
2904
2989
|
this._warnCustomComponentsDeprecation()
|
|
2905
2990
|
this._hydrateMenuCounts()
|
|
2991
|
+
this._hydrateMenuItemCounts()
|
|
2906
2992
|
},
|
|
2907
2993
|
|
|
2908
2994
|
beforeUnmount() {
|
|
@@ -3281,10 +3367,12 @@ export default {
|
|
|
3281
3367
|
return
|
|
3282
3368
|
}
|
|
3283
3369
|
try {
|
|
3284
|
-
|
|
3285
|
-
this.appId,
|
|
3286
|
-
this.walkthroughConfigKey,
|
|
3287
|
-
)
|
|
3370
|
+
const [seen, progress] = await Promise.all([
|
|
3371
|
+
loadWalkthroughSeenVersion(this.appId, this.walkthroughConfigKey),
|
|
3372
|
+
loadWalkthroughProgress(this.appId, this.walkthroughConfigKey),
|
|
3373
|
+
])
|
|
3374
|
+
this.walkthroughSeenVersionValue = seen
|
|
3375
|
+
this.walkthroughProgressValue = progress
|
|
3288
3376
|
} finally {
|
|
3289
3377
|
this.walkthroughSeenResolved = true
|
|
3290
3378
|
}
|
|
@@ -3308,12 +3396,68 @@ export default {
|
|
|
3308
3396
|
// Fire-and-forget: the loader never rejects and the local mirror is
|
|
3309
3397
|
// already written, so a failed PUT must not surface as an error.
|
|
3310
3398
|
persistWalkthroughSeenVersion(this.appId, this.walkthroughConfigKey, v)
|
|
3399
|
+
// A finished or skipped tour has nothing to continue.
|
|
3400
|
+
if (this.walkthroughProgressValue) {
|
|
3401
|
+
this.walkthroughProgressValue = null
|
|
3402
|
+
persistWalkthroughProgress(this.appId, this.walkthroughConfigKey, null)
|
|
3403
|
+
}
|
|
3311
3404
|
/**
|
|
3312
3405
|
* @event walkthrough-complete Emitted when the walkthrough finishes or is dismissed.
|
|
3313
3406
|
*/
|
|
3314
3407
|
this.$emit('walkthrough-complete')
|
|
3315
3408
|
},
|
|
3316
3409
|
|
|
3410
|
+
/**
|
|
3411
|
+
* Remember where the user is in the tour, so a reload or a restart
|
|
3412
|
+
* entry continues there (local mirror + per-user preference).
|
|
3413
|
+
*
|
|
3414
|
+
* @spec openspec/changes/walkthrough-advance-pause-resume/specs/cn-walkthrough/spec.md
|
|
3415
|
+
* @param {object} progress `{ tourId, stepId, index }` from CnWalkthrough.
|
|
3416
|
+
* @return {void}
|
|
3417
|
+
*/
|
|
3418
|
+
onWalkthroughProgress(progress) {
|
|
3419
|
+
if (!progress || !progress.tourId) {
|
|
3420
|
+
return
|
|
3421
|
+
}
|
|
3422
|
+
// The first step of a fresh tour is where a restart lands anyway,
|
|
3423
|
+
// so it costs no request.
|
|
3424
|
+
if (progress.index === 0 && !this.walkthroughProgressValue) {
|
|
3425
|
+
return
|
|
3426
|
+
}
|
|
3427
|
+
const value = {
|
|
3428
|
+
tourId: progress.tourId,
|
|
3429
|
+
stepId: progress.stepId || '',
|
|
3430
|
+
index: progress.index || 0,
|
|
3431
|
+
version: String((this.manifest && this.manifest.version) || ''),
|
|
3432
|
+
}
|
|
3433
|
+
this.walkthroughProgressValue = value
|
|
3434
|
+
persistWalkthroughProgress(this.appId, this.walkthroughConfigKey, value)
|
|
3435
|
+
},
|
|
3436
|
+
|
|
3437
|
+
/**
|
|
3438
|
+
* Continue an unfinished tour from the user-settings dialog: show a
|
|
3439
|
+
* paused tour again, or start the remembered tour at its step.
|
|
3440
|
+
*
|
|
3441
|
+
* @spec openspec/changes/walkthrough-advance-pause-resume/specs/cn-walkthrough/spec.md
|
|
3442
|
+
* @return {void}
|
|
3443
|
+
*/
|
|
3444
|
+
continueWalkthroughFromSettings() {
|
|
3445
|
+
this.userSettingsOpen = false
|
|
3446
|
+
if (!this.walkthroughEnabled) {
|
|
3447
|
+
return
|
|
3448
|
+
}
|
|
3449
|
+
setTimeout(() => {
|
|
3450
|
+
const wt = useWalkthrough(this.appId, this.manifest)
|
|
3451
|
+
if (wt.resumePaused()) {
|
|
3452
|
+
return
|
|
3453
|
+
}
|
|
3454
|
+
const progress = this.walkthroughProgressValue
|
|
3455
|
+
if (progress) {
|
|
3456
|
+
wt.resumeAt(progress.tourId, progress.stepId)
|
|
3457
|
+
}
|
|
3458
|
+
}, 50)
|
|
3459
|
+
},
|
|
3460
|
+
|
|
3317
3461
|
/**
|
|
3318
3462
|
* Replay the product tour from the user-settings dialog. Closes the
|
|
3319
3463
|
* dialog first, then restarts the first declared tour on the next tick
|
|
@@ -3501,6 +3645,63 @@ export default {
|
|
|
3501
3645
|
})
|
|
3502
3646
|
},
|
|
3503
3647
|
|
|
3648
|
+
/**
|
|
3649
|
+
* Fetch the total of every menu entry (top level and children) whose
|
|
3650
|
+
* `count` is an object `{ register, schema, filter? }`: one
|
|
3651
|
+
* `GET /api/objects/{register}/{schema}?_limit=1` per entry with the
|
|
3652
|
+
* filter's tokens (`@me`, `@today`, ...) resolved at fetch time, the
|
|
3653
|
+
* response `total` written to `cnMenuItemCounts[item.id]`. The
|
|
3654
|
+
* request goes straight through axios rather than the object store,
|
|
3655
|
+
* so the index page's whole-schema total in the store is left alone.
|
|
3656
|
+
* Failures leave the badge unrendered.
|
|
3657
|
+
*
|
|
3658
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-a-menu-entry-counts-a-filtered-list
|
|
3659
|
+
* @return {void}
|
|
3660
|
+
* @private
|
|
3661
|
+
*/
|
|
3662
|
+
_hydrateMenuItemCounts() {
|
|
3663
|
+
const collect = (items) => {
|
|
3664
|
+
const out = []
|
|
3665
|
+
for (const item of items ?? []) {
|
|
3666
|
+
const count = item?.count
|
|
3667
|
+
if (count && typeof count === 'object' && typeof item.id === 'string' && count.register && count.schema) {
|
|
3668
|
+
out.push(item)
|
|
3669
|
+
}
|
|
3670
|
+
if (Array.isArray(item?.children)) {
|
|
3671
|
+
out.push(...collect(item.children))
|
|
3672
|
+
}
|
|
3673
|
+
}
|
|
3674
|
+
return out
|
|
3675
|
+
}
|
|
3676
|
+
for (const item of collect(this.manifest?.menu)) {
|
|
3677
|
+
this._fetchMenuItemCount(item)
|
|
3678
|
+
}
|
|
3679
|
+
},
|
|
3680
|
+
|
|
3681
|
+
/**
|
|
3682
|
+
* One filtered-count request for a menu entry; see
|
|
3683
|
+
* `_hydrateMenuItemCounts`.
|
|
3684
|
+
*
|
|
3685
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-a-menu-entry-counts-a-filtered-list
|
|
3686
|
+
* @param {{ id: string, count: { register: string, schema: string, filter?: object } }} item The menu entry.
|
|
3687
|
+
* @return {Promise<void>}
|
|
3688
|
+
* @private
|
|
3689
|
+
*/
|
|
3690
|
+
async _fetchMenuItemCount(item) {
|
|
3691
|
+
try {
|
|
3692
|
+
const { register, schema, filter } = item.count
|
|
3693
|
+
const resolved = resolveFilterTokens(filter && typeof filter === 'object' ? filter : {}, {})
|
|
3694
|
+
const url = generateUrl(`/apps/openregister/api/objects/${encodeURIComponent(register)}/${encodeURIComponent(schema)}`)
|
|
3695
|
+
const { data } = await axios.get(url, { params: { _limit: 1, ...resolved } })
|
|
3696
|
+
const total = data?.total
|
|
3697
|
+
if (typeof total === 'number' && total >= 0) {
|
|
3698
|
+
this.cnMenuItemCounts[item.id] = total
|
|
3699
|
+
}
|
|
3700
|
+
} catch {
|
|
3701
|
+
// Non-fatal: the badge stays unrendered.
|
|
3702
|
+
}
|
|
3703
|
+
},
|
|
3704
|
+
|
|
3504
3705
|
/**
|
|
3505
3706
|
* Hydrate all menu counts with a single `POST /api/objects/counts`
|
|
3506
3707
|
* (OpenRegister batched-counts endpoint). Distributes each returned
|
|
@@ -3646,6 +3847,12 @@ export default {
|
|
|
3646
3847
|
color: var(--color-text-maxcontrast);
|
|
3647
3848
|
}
|
|
3648
3849
|
|
|
3850
|
+
.cn-app-root__walkthrough-actions {
|
|
3851
|
+
display: flex;
|
|
3852
|
+
flex-wrap: wrap;
|
|
3853
|
+
gap: 8px;
|
|
3854
|
+
}
|
|
3855
|
+
|
|
3649
3856
|
.cn-app-root__integrations-hint {
|
|
3650
3857
|
margin-bottom: 12px;
|
|
3651
3858
|
color: var(--color-text-maxcontrast);
|
|
@@ -69,12 +69,27 @@ export default {
|
|
|
69
69
|
components: { CnDetailCard, NcLoadingIcon },
|
|
70
70
|
|
|
71
71
|
props: {
|
|
72
|
-
/** OpenRegister register id (slug or uuid). */
|
|
73
|
-
register: { type: String,
|
|
74
|
-
/** OpenRegister schema id (slug or uuid). */
|
|
75
|
-
schema: { type: String,
|
|
76
|
-
/** Parent object id. */
|
|
77
|
-
objectId: { type: String,
|
|
72
|
+
/** OpenRegister register id (slug or uuid). Optional for `scope: "app"`. */
|
|
73
|
+
register: { type: String, default: '' },
|
|
74
|
+
/** OpenRegister schema id (slug or uuid). Optional for `scope: "app"`. */
|
|
75
|
+
schema: { type: String, default: '' },
|
|
76
|
+
/** Parent object id. Required for `scope: "object"` (the default); unused for `scope: "app"`. */
|
|
77
|
+
objectId: { type: String, default: '' },
|
|
78
|
+
/**
|
|
79
|
+
* What the card lists. `object` (the default) is one object's trail
|
|
80
|
+
* and needs `register`, `schema` and `objectId`. `app` is the
|
|
81
|
+
* app-wide feed: the entries of every object the caller may read
|
|
82
|
+
* (OpenRegister's `/audit-trails/readable`), narrowed to `register`
|
|
83
|
+
* and `schema` when those are set.
|
|
84
|
+
*
|
|
85
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-the-audit-trail-widget-reads-the-app-wide-feed
|
|
86
|
+
*/
|
|
87
|
+
scope: {
|
|
88
|
+
type: String,
|
|
89
|
+
default: 'object',
|
|
90
|
+
validator: (value) => ['object', 'app'].includes(value),
|
|
91
|
+
},
|
|
92
|
+
|
|
78
93
|
/** Rendering surface — passed for AD-19 surface fallback consumers. */
|
|
79
94
|
surface: {
|
|
80
95
|
type: String,
|
|
@@ -116,13 +131,38 @@ export default {
|
|
|
116
131
|
displayedEntries() {
|
|
117
132
|
return this.entries.slice(0, this.maxDisplay)
|
|
118
133
|
},
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* The path the card reads (prefixed at fetch time), or '' when it has nothing to read: the
|
|
137
|
+
* object's own trail, or the app-wide readable feed narrowed to the
|
|
138
|
+
* register and schema when set.
|
|
139
|
+
*
|
|
140
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-the-audit-trail-widget-reads-the-app-wide-feed
|
|
141
|
+
* @return {string}
|
|
142
|
+
*/
|
|
143
|
+
fetchUrl() {
|
|
144
|
+
const params = new URLSearchParams({ limit: String(this.maxDisplay) })
|
|
145
|
+
if (this.scope === 'app') {
|
|
146
|
+
if (this.register) {
|
|
147
|
+
params.set('register', this.register)
|
|
148
|
+
}
|
|
149
|
+
if (this.schema) {
|
|
150
|
+
params.set('schema', this.schema)
|
|
151
|
+
}
|
|
152
|
+
return `${this.apiBase}/audit-trails/readable?${params.toString()}`
|
|
153
|
+
}
|
|
154
|
+
if (!this.register || !this.schema || !this.objectId) {
|
|
155
|
+
return ''
|
|
156
|
+
}
|
|
157
|
+
return `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/audit-trail?${params.toString()}`
|
|
158
|
+
},
|
|
119
159
|
},
|
|
120
160
|
|
|
121
161
|
watch: {
|
|
122
|
-
|
|
162
|
+
fetchUrl: {
|
|
123
163
|
immediate: true,
|
|
124
|
-
handler(
|
|
125
|
-
if (
|
|
164
|
+
handler(url) {
|
|
165
|
+
if (url) {
|
|
126
166
|
this.fetchEntries()
|
|
127
167
|
}
|
|
128
168
|
},
|
|
@@ -130,20 +170,25 @@ export default {
|
|
|
130
170
|
},
|
|
131
171
|
|
|
132
172
|
methods: {
|
|
173
|
+
/**
|
|
174
|
+
* Read the entries from `fetchUrl`. The readable feed answers
|
|
175
|
+
* `{ rows, nextCursor }`, the object trail `{ results }`.
|
|
176
|
+
*
|
|
177
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-the-audit-trail-widget-reads-the-app-wide-feed
|
|
178
|
+
* @return {Promise<void>}
|
|
179
|
+
*/
|
|
133
180
|
async fetchEntries() {
|
|
134
|
-
|
|
181
|
+
const url = this.fetchUrl
|
|
182
|
+
if (!url) {
|
|
135
183
|
return
|
|
136
184
|
}
|
|
137
185
|
this.loading = true
|
|
138
186
|
try {
|
|
139
|
-
const
|
|
140
|
-
const response = await fetch(
|
|
141
|
-
prefixUrl(`${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/audit-trail?${params.toString()}`),
|
|
142
|
-
{ headers: buildHeaders() },
|
|
143
|
-
)
|
|
187
|
+
const response = await fetch(prefixUrl(url), { headers: buildHeaders() })
|
|
144
188
|
if (response.ok) {
|
|
145
189
|
const data = await response.json()
|
|
146
|
-
|
|
190
|
+
const list = data.results || data.rows || data
|
|
191
|
+
this.entries = Array.isArray(list) ? list : []
|
|
147
192
|
} else {
|
|
148
193
|
this.entries = []
|
|
149
194
|
}
|
|
@@ -5,10 +5,11 @@
|
|
|
5
5
|
|
|
6
6
|
<template>
|
|
7
7
|
<CnAuditTrailCard
|
|
8
|
-
v-if="resolvedRegister && resolvedSchema && resolvedObjectId"
|
|
8
|
+
v-if="resolvedScope === 'app' || (resolvedRegister && resolvedSchema && resolvedObjectId)"
|
|
9
9
|
:register="resolvedRegister"
|
|
10
10
|
:schema="resolvedSchema"
|
|
11
11
|
:objectId="resolvedObjectId"
|
|
12
|
+
:scope="resolvedScope"
|
|
12
13
|
:title="resolvedTitle"
|
|
13
14
|
:maxDisplay="resolvedMaxDisplay" />
|
|
14
15
|
</template>
|
|
@@ -70,6 +71,15 @@ export default {
|
|
|
70
71
|
title: { type: String, default: '' },
|
|
71
72
|
/** Maximum audit rows to render (0 falls back to the card default). */
|
|
72
73
|
maxDisplay: { type: Number, default: 0 },
|
|
74
|
+
/**
|
|
75
|
+
* `app` lists the app-wide feed (every object the caller may read,
|
|
76
|
+
* narrowed to `register` / `schema` when set) and needs no object;
|
|
77
|
+
* `object` (the default) is one object's trail. Also read from
|
|
78
|
+
* `content.scope`.
|
|
79
|
+
*
|
|
80
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-the-audit-trail-widget-reads-the-app-wide-feed
|
|
81
|
+
*/
|
|
82
|
+
scope: { type: String, default: '' },
|
|
73
83
|
/** Stored widget content blob (CnDashboardPage registry branch): `{ title, maxDisplay, register?, schema?, objectId? }`. */
|
|
74
84
|
content: { type: Object, default: () => ({}) },
|
|
75
85
|
},
|
|
@@ -115,6 +125,17 @@ export default {
|
|
|
115
125
|
return typeof s === 'string' ? s : (s && (s.slug || s.name || s.id)) || ''
|
|
116
126
|
},
|
|
117
127
|
|
|
128
|
+
/**
|
|
129
|
+
* The feed scope: explicit prop → content → `object`.
|
|
130
|
+
*
|
|
131
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-the-audit-trail-widget-reads-the-app-wide-feed
|
|
132
|
+
* @return {('object'|'app')}
|
|
133
|
+
*/
|
|
134
|
+
resolvedScope() {
|
|
135
|
+
const s = this.scope || this.content.scope
|
|
136
|
+
return s === 'app' ? 'app' : 'object'
|
|
137
|
+
},
|
|
138
|
+
|
|
118
139
|
/**
|
|
119
140
|
* The card title: explicit prop → content → '' (card default).
|
|
120
141
|
*
|
|
@@ -177,6 +177,9 @@ import { safeHref } from '../../utils/safeHref.js'
|
|
|
177
177
|
import { formatValue } from '../../utils/schema.js'
|
|
178
178
|
import { CnStatusBadge } from '../CnStatusBadge/index.js'
|
|
179
179
|
|
|
180
|
+
/** A uuid in any version, the shape OpenRegister ids take. */
|
|
181
|
+
const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i
|
|
182
|
+
|
|
180
183
|
/**
|
|
181
184
|
* Module-level set of column keys already warned about for a
|
|
182
185
|
* `widget:"link"` declaration with no resolvable target — guarantees
|
|
@@ -483,13 +486,20 @@ export default {
|
|
|
483
486
|
*
|
|
484
487
|
* @return {string}
|
|
485
488
|
* @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-avatar-and-date-cells
|
|
489
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-small-opt-ins-from-the-decidiq-and-learniq-lanes
|
|
486
490
|
*/
|
|
487
491
|
dateLabel() {
|
|
488
492
|
const date = parseDateValue(this.value)
|
|
489
493
|
if (date === null) {
|
|
490
494
|
return ''
|
|
491
495
|
}
|
|
492
|
-
|
|
496
|
+
// `widgetProps.showTime: true` adds the time of day ("5 Oct 2026,
|
|
497
|
+
// 08:30"); `widgetProps.timeOnly: true` shows just the time
|
|
498
|
+
// ("08:30"), for a timetable row. Default: the date alone.
|
|
499
|
+
const props = this.widgetProps || {}
|
|
500
|
+
const options = props.timeOnly === true
|
|
501
|
+
? { hour: '2-digit', minute: '2-digit' }
|
|
502
|
+
: { day: 'numeric', month: 'short', year: 'numeric', ...(props.showTime === true ? { hour: '2-digit', minute: '2-digit' } : {}) }
|
|
493
503
|
let locale
|
|
494
504
|
try {
|
|
495
505
|
locale = getCanonicalLocale()
|
|
@@ -738,6 +748,27 @@ export default {
|
|
|
738
748
|
return undefined
|
|
739
749
|
},
|
|
740
750
|
|
|
751
|
+
/**
|
|
752
|
+
* Whether the cell draws a uuid, and so takes the monospace uuid
|
|
753
|
+
* style. The property's `format: "uuid"` alone used to decide this,
|
|
754
|
+
* so a reference that a formatter or a widget had resolved to its
|
|
755
|
+
* name was still drawn as code. Now the value has to be a uuid AND
|
|
756
|
+
* nothing resolves it: a resolving widget or formatter, or a value
|
|
757
|
+
* that is not a uuid, renders in the normal text style.
|
|
758
|
+
*
|
|
759
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-a-resolved-reference-is-not-drawn-as-a-uuid
|
|
760
|
+
* @return {boolean}
|
|
761
|
+
*/
|
|
762
|
+
showsUuid() {
|
|
763
|
+
if (this.property?.format !== 'uuid') {
|
|
764
|
+
return false
|
|
765
|
+
}
|
|
766
|
+
if (this.widgetComponent || this.widget || this.hasFormatter) {
|
|
767
|
+
return false
|
|
768
|
+
}
|
|
769
|
+
return typeof this.value === 'string' && UUID_PATTERN.test(this.value)
|
|
770
|
+
},
|
|
771
|
+
|
|
741
772
|
cellClass() {
|
|
742
773
|
const classes = []
|
|
743
774
|
if (this.propertyType === 'boolean') {
|
|
@@ -749,7 +780,7 @@ export default {
|
|
|
749
780
|
if (this.property?.format === 'date-time' || this.property?.format === 'date') {
|
|
750
781
|
classes.push('cn-cell-renderer--date')
|
|
751
782
|
}
|
|
752
|
-
if (this.
|
|
783
|
+
if (this.showsUuid) {
|
|
753
784
|
classes.push('cn-cell-renderer--uuid')
|
|
754
785
|
}
|
|
755
786
|
if (this.propertyType === 'integer' || this.propertyType === 'number') {
|