@conduction/nextcloud-vue 2.99.0 → 2.101.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 +6 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js.map +1 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js +2 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js.map +1 -1
- package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue.js +1 -1
- package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue2.js +22 -1
- package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue2.js.map +1 -1
- package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue3.js +26 -16
- package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue3.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue.js +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +51 -7
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +104 -73
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +25 -8
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +5 -3
- 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 +11 -8
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js +13 -4
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js.map +1 -1
- package/dist/esm/components/CnExportsWidget/CnExportsWidget.vue.js +9 -0
- package/dist/esm/components/CnExportsWidget/CnExportsWidget.vue.js.map +1 -0
- package/dist/esm/components/CnExportsWidget/CnExportsWidget.vue2.js +139 -0
- package/dist/esm/components/CnExportsWidget/CnExportsWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnExportsWidget/CnExportsWidget.vue3.js +76 -0
- package/dist/esm/components/CnExportsWidget/CnExportsWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue.js +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js +54 -3
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js +16 -2
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue.js +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +160 -2
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +206 -94
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/filesReview.js +61 -0
- package/dist/esm/components/CnFilesBrowser/filesReview.js.map +1 -0
- package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue.js +1 -1
- package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue2.js +42 -7
- package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue2.js.map +1 -1
- package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue3.js +121 -57
- package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue3.js.map +1 -1
- package/dist/esm/components/CnFlowsPage/CnFlowEditorPage.vue2.js +10 -0
- package/dist/esm/components/CnFlowsPage/CnFlowEditorPage.vue2.js.map +1 -1
- package/dist/esm/components/CnFlowsPage/CnFlowEditorPage.vue3.js +2 -1
- package/dist/esm/components/CnFlowsPage/CnFlowEditorPage.vue3.js.map +1 -1
- package/dist/esm/components/CnGroupedCardsWidget/CnGroupedCardsWidget.vue.js +9 -0
- package/dist/esm/components/CnGroupedCardsWidget/CnGroupedCardsWidget.vue.js.map +1 -0
- package/dist/esm/components/CnGroupedCardsWidget/CnGroupedCardsWidget.vue2.js +279 -0
- package/dist/esm/components/CnGroupedCardsWidget/CnGroupedCardsWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnGroupedCardsWidget/CnGroupedCardsWidget.vue3.js +122 -0
- package/dist/esm/components/CnGroupedCardsWidget/CnGroupedCardsWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnGroupedCardsWidget/index.js +29 -0
- package/dist/esm/components/CnGroupedCardsWidget/index.js.map +1 -0
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +387 -78
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +317 -209
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/useNamedSource.js +4 -1
- package/dist/esm/components/CnIndexPage/useNamedSource.js.map +1 -1
- package/dist/esm/components/CnMapWidget/CnMapWidget.vue.js +1 -1
- package/dist/esm/components/CnMapWidget/CnMapWidget.vue2.js +15 -0
- package/dist/esm/components/CnMapWidget/CnMapWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnMapWidget/CnMapWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue.js +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +14 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js +14 -6
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue.js +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js +10 -0
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js +6 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js.map +1 -1
- package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue.js +1 -1
- package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue2.js +91 -4
- package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue2.js.map +1 -1
- package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue3.js +63 -38
- package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue3.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +68 -7
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js +256 -240
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue.js +9 -0
- package/dist/esm/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue.js.map +1 -0
- package/dist/esm/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue2.js +175 -0
- package/dist/esm/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue3.js +77 -0
- package/dist/esm/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnSettingsFieldsSection/CnSettingsFieldsSection.vue.js +1 -1
- package/dist/esm/components/CnSettingsFieldsSection/CnSettingsFieldsSection.vue2.js +38 -9
- package/dist/esm/components/CnSettingsFieldsSection/CnSettingsFieldsSection.vue2.js.map +1 -1
- package/dist/esm/components/CnSettingsFieldsSection/CnSettingsFieldsSection.vue3.js.map +1 -1
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue.js +1 -1
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js +51 -4
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js.map +1 -1
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js +40 -25
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js.map +1 -1
- package/dist/esm/components/CnWidgetGrid/builtInWidgets.js +4 -0
- 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/CnWizardDialog/CnWizardDialog.vue.js +1 -1
- package/dist/esm/components/CnWizardDialog/CnWizardDialog.vue2.js +7 -7
- package/dist/esm/components/CnWizardDialog/CnWizardDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnWizardDialog/CnWizardDialog.vue3.js.map +1 -1
- package/dist/esm/composables/indexSources.js +167 -20
- package/dist/esm/composables/indexSources.js.map +1 -1
- package/dist/esm/composables/useEndpointSource.js +28 -6
- package/dist/esm/composables/useEndpointSource.js.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/l10n/en.json.js +43 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +41 -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 +1101 -396
- package/dist/esm/utils/languageMapText.js +50 -0
- package/dist/esm/utils/languageMapText.js.map +1 -0
- package/dist/esm/utils/libraryWidgetKeys.js +3 -0
- package/dist/esm/utils/libraryWidgetKeys.js.map +1 -1
- package/dist/esm/utils/mapList.js +71 -0
- package/dist/esm/utils/mapList.js.map +1 -0
- package/dist/esm/utils/validateManifestV2.compiled.js +3 -3
- package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +9996 -7378
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +1101 -396
- package/l10n/en.json +43 -1
- package/l10n/nl.json +41 -1
- package/package.json +1 -1
- package/src/components/CnAdminSettingsShell/CnAdminSettingsShell.vue +7 -1
- package/src/components/CnChoiceCards/CnChoiceCards.md +39 -0
- package/src/components/CnChoiceCards/CnChoiceCards.vue +93 -16
- package/src/components/CnDashboardPage/CnDashboardPage.vue +89 -20
- package/src/components/CnDetailPage/CnDetailPage.vue +28 -9
- package/src/components/CnDetailWidgetHost/CnDetailWidgetHost.vue +13 -4
- package/src/components/CnExportsWidget/CnExportsWidget.vue +233 -0
- package/src/components/CnExportsWidget/index.js +7 -0
- package/src/components/CnFactsWidget/CnFactsWidget.vue +65 -3
- package/src/components/CnFilesBrowser/CnFilesBrowser.vue +324 -0
- package/src/components/CnFilesBrowser/filesReview.js +57 -0
- package/src/components/CnFlowsPage/CnFlowBoard.vue +77 -2
- package/src/components/CnFlowsPage/CnFlowEditorPage.vue +11 -0
- package/src/components/CnGroupedCardsWidget/CnGroupedCardsWidget.vue +433 -0
- package/src/components/CnGroupedCardsWidget/index.js +28 -0
- package/src/components/CnIndexPage/CnIndexPage.vue +376 -11
- package/src/components/CnIndexPage/useNamedSource.js +4 -1
- package/src/components/CnMapWidget/CnMapWidget.vue +37 -0
- package/src/components/CnObjectListWidget/CnObjectListWidget.vue +29 -1
- package/src/components/CnObjectSidebar/CnFilesTab.vue +15 -0
- package/src/components/CnOrderedListField/CnOrderedListField.vue +151 -5
- package/src/components/CnRecordListWidget/CnRecordListWidget.vue +114 -7
- package/src/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue +272 -0
- package/src/components/CnSavedViewAlertWidget/index.js +7 -0
- package/src/components/CnSettingsFieldsSection/CnSettingsFieldsSection.vue +38 -9
- package/src/components/CnSetupWizard/CnSetupWizard.vue +72 -5
- package/src/components/CnWidgetGrid/builtInWidgets.js +4 -0
- package/src/components/CnWidgetGrid/registerDashboardWidgets.js +1 -0
- package/src/components/CnWizardDialog/CnWizardDialog.vue +7 -7
- package/src/components/index.js +3 -0
- package/src/composables/indexSources.js +166 -19
- package/src/composables/useEndpointSource.js +28 -6
- package/src/css/detail-page.css +15 -0
- package/src/css/dialog.css +48 -0
- package/src/css/index-page.css +117 -0
- package/src/css/look-board.css +127 -1
- package/src/index.js +1 -0
- package/src/schemas/app-manifest-v2.schema.json +55 -1
- package/src/utils/languageMapText.js +46 -0
- package/src/utils/libraryWidgetKeys.js +3 -0
- package/src/utils/mapList.js +67 -0
- package/src/utils/validateManifestV2.compiled.js +3 -3
|
@@ -13,12 +13,12 @@
|
|
|
13
13
|
region (WCAG 2.4.6 / 1.3.1). -->
|
|
14
14
|
<slot
|
|
15
15
|
name="header"
|
|
16
|
-
:title="
|
|
16
|
+
:title="shownTitle"
|
|
17
17
|
:description="headerDescription"
|
|
18
18
|
:icon="resolvedIcon"
|
|
19
19
|
:showTitle="showTitle">
|
|
20
20
|
<CnPageHeader
|
|
21
|
-
:title="
|
|
21
|
+
:title="shownTitle"
|
|
22
22
|
:description="headerDescription"
|
|
23
23
|
:icon="showTitleIcon && !isBoardLook ? resolvedIcon : ''"
|
|
24
24
|
:breadcrumb="presented('breadcrumb')"
|
|
@@ -747,6 +747,7 @@
|
|
|
747
747
|
:sortOrder="effectiveSortOrder"
|
|
748
748
|
:sortKeys="effectiveSortKeys"
|
|
749
749
|
:selectable="selectable"
|
|
750
|
+
:hideHeader="hideTableHeader"
|
|
750
751
|
:rowClickToView="rowClickOpens"
|
|
751
752
|
:selectedIds="internalSelectedIds"
|
|
752
753
|
:rowKey="rowKey"
|
|
@@ -845,9 +846,64 @@
|
|
|
845
846
|
filter / sidebar / quick-filter machinery as table and cards.
|
|
846
847
|
A marker click routes back through onRowClick for identical
|
|
847
848
|
detail-page navigation. -->
|
|
849
|
+
<!-- Map with a numbered list beside it (`mapConfig.list`,
|
|
850
|
+
DqZakenKaart): one framed card, the list numbered as the pins
|
|
851
|
+
are, the row under the pointer marked on both sides, and the
|
|
852
|
+
rows without a place counted under the list with a way to
|
|
853
|
+
the table. -->
|
|
854
|
+
<div v-else-if="currentViewMode === 'map' && mapListEnabled"
|
|
855
|
+
class="cn-index-page__map-card"
|
|
856
|
+
data-testid="cn-index-map-card">
|
|
857
|
+
<CnMapWidget
|
|
858
|
+
class="cn-index-page__map"
|
|
859
|
+
:center="mapCenter"
|
|
860
|
+
:zoom="mapZoom"
|
|
861
|
+
:layers="mapLayers"
|
|
862
|
+
:basemaps="mapBasemaps"
|
|
863
|
+
:markers="mapMarkers"
|
|
864
|
+
:clustering="mapClustering"
|
|
865
|
+
:autoFit="true"
|
|
866
|
+
height="100%"
|
|
867
|
+
@markerClick="onMarkerClick" />
|
|
868
|
+
<div class="cn-index-page__map-side">
|
|
869
|
+
<ol class="cn-index-page__map-list" :aria-label="mapListLabel" data-testid="cn-index-map-list">
|
|
870
|
+
<li v-for="item in mapList.items"
|
|
871
|
+
:key="item.key"
|
|
872
|
+
class="cn-index-page__map-item"
|
|
873
|
+
:class="{ 'cn-index-page__map-item--active': activeMapKey === item.key }"
|
|
874
|
+
data-testid="cn-index-map-item"
|
|
875
|
+
@mouseenter="activeMapKey = item.key"
|
|
876
|
+
@mouseleave="activeMapKey = ''"
|
|
877
|
+
@focusin="activeMapKey = item.key">
|
|
878
|
+
<span class="cn-index-page__map-number" aria-hidden="true">{{ item.n }}</span>
|
|
879
|
+
<div class="cn-index-page__map-text">
|
|
880
|
+
<button type="button" class="cn-index-page__map-title" @click="onRowClick(item.row)">
|
|
881
|
+
{{ item.title }}
|
|
882
|
+
</button>
|
|
883
|
+
<span v-if="item.sub" class="cn-index-page__map-sub">{{ item.sub }}</span>
|
|
884
|
+
<span v-if="item.pills.length > 0 || item.due" class="cn-index-page__map-pills">
|
|
885
|
+
<CnStatusBadge v-for="(pill, index) in item.pills"
|
|
886
|
+
:key="index"
|
|
887
|
+
:label="pill.label"
|
|
888
|
+
:variant="pill.variant" />
|
|
889
|
+
<span v-if="item.due" class="cn-index-page__map-due">{{ item.due }}</span>
|
|
890
|
+
</span>
|
|
891
|
+
</div>
|
|
892
|
+
</li>
|
|
893
|
+
</ol>
|
|
894
|
+
<div v-if="mapList.missing.length > 0" class="cn-index-page__map-missing" data-testid="cn-index-map-missing">
|
|
895
|
+
<strong>{{ mapMissingTitle }}</strong>
|
|
896
|
+
<NcButton variant="tertiary-no-background" data-testid="cn-index-map-missing-table" @click="onViewModeChange('table')">
|
|
897
|
+
{{ mapMissingLink }}
|
|
898
|
+
</NcButton>
|
|
899
|
+
</div>
|
|
900
|
+
</div>
|
|
901
|
+
</div>
|
|
902
|
+
|
|
848
903
|
<CnMapWidget
|
|
849
904
|
v-else-if="currentViewMode === 'map'"
|
|
850
905
|
class="cn-index-page__map"
|
|
906
|
+
:zoom="mapZoom"
|
|
851
907
|
:center="mapCenter"
|
|
852
908
|
:layers="mapLayers"
|
|
853
909
|
:basemaps="mapBasemaps"
|
|
@@ -1194,6 +1250,7 @@ import CnQuickEditDialog from '../../dialogs/CnQuickEditDialog.vue'
|
|
|
1194
1250
|
import CnBuildiqEditButton from '../CnBuildiqEditButton/CnBuildiqEditButton.vue'
|
|
1195
1251
|
import CnEmptyContent from '../CnEmptyContent/CnEmptyContent.vue'
|
|
1196
1252
|
import CnFollowToggle from '../CnFollowToggle/CnFollowToggle.vue'
|
|
1253
|
+
import CnStatusBadge from '../CnStatusBadge/CnStatusBadge.vue'
|
|
1197
1254
|
import CnIndexPageWidgets from './CnIndexPageWidgets.vue'
|
|
1198
1255
|
import { useContextMenu } from '../../composables/index.js'
|
|
1199
1256
|
import { useLook } from '../../composables/useLook.js'
|
|
@@ -1223,6 +1280,7 @@ import { lensUnavailableText } from '../../utils/lensAvailability.js'
|
|
|
1223
1280
|
import { isModifiedClick, openRowTarget } from '../../utils/linkNavigation.js'
|
|
1224
1281
|
import { resolveClaimedTeams, resolveClaimTokens, splitViewsIntoTabs, viewAsTab, viewIdOf } from '../../utils/listLenses.js'
|
|
1225
1282
|
import { LIST_SHORTCUTS, listPaletteCommands, shortcutFor } from '../../utils/listShortcuts.js'
|
|
1283
|
+
import { mapListItems } from '../../utils/mapList.js'
|
|
1226
1284
|
import { multiKeySort } from '../../utils/multiKeySort.js'
|
|
1227
1285
|
import { fetchGroups } from '../../utils/nextcloudDirectory.js'
|
|
1228
1286
|
import { OBJECTS_CHANGED_EVENT } from '../../utils/objectSignals.js'
|
|
@@ -1508,6 +1566,7 @@ export default {
|
|
|
1508
1566
|
|
|
1509
1567
|
components: {
|
|
1510
1568
|
CnIndexPageWidgets,
|
|
1569
|
+
CnStatusBadge,
|
|
1511
1570
|
NcNoteCard,
|
|
1512
1571
|
CnBuildiqEditButton,
|
|
1513
1572
|
CnFollowToggle,
|
|
@@ -1576,8 +1635,33 @@ export default {
|
|
|
1576
1635
|
* Falls back to an empty object so `CnIndexPage` works standalone
|
|
1577
1636
|
* (unit tests, isolated mount) without `CnAppRoot`.
|
|
1578
1637
|
*/
|
|
1638
|
+
/**
|
|
1639
|
+
* The list a side-panel widget reads (`cnIndexList`): the applied saved
|
|
1640
|
+
* view, the list's total, and a way to hand back a view that changed
|
|
1641
|
+
* (the saved-view alert widget). Getters, so a widget follows the page.
|
|
1642
|
+
*
|
|
1643
|
+
* @return {object}
|
|
1644
|
+
*/
|
|
1645
|
+
provide() {
|
|
1646
|
+
return {
|
|
1647
|
+
cnIndexList: Object.defineProperties({}, {
|
|
1648
|
+
appliedView: { enumerable: true, get: () => this.appliedSavedView },
|
|
1649
|
+
total: {
|
|
1650
|
+
enumerable: true,
|
|
1651
|
+
get: () => {
|
|
1652
|
+
const total = this.effectivePagination && this.effectivePagination.total
|
|
1653
|
+
return typeof total === 'number' ? total : undefined
|
|
1654
|
+
},
|
|
1655
|
+
},
|
|
1656
|
+
replaceSavedView: { enumerable: true, value: (view) => this.replaceSavedView(view) },
|
|
1657
|
+
}),
|
|
1658
|
+
}
|
|
1659
|
+
},
|
|
1660
|
+
|
|
1579
1661
|
inject: {
|
|
1580
1662
|
cnCustomComponents: { default: () => ({}) },
|
|
1663
|
+
/** The permissions the user holds, provided by CnAppRoot; for gated page tabs. */
|
|
1664
|
+
cnPermissions: { default: () => [] },
|
|
1581
1665
|
/** The app id CnAppRoot provides, for the plural form of `countSubtitle`. */
|
|
1582
1666
|
cnAppId: { default: '' },
|
|
1583
1667
|
/**
|
|
@@ -1668,7 +1752,9 @@ export default {
|
|
|
1668
1752
|
|
|
1669
1753
|
/**
|
|
1670
1754
|
* A note after the breadcrumb and a middle dot (manifest `config.headerMeta`),
|
|
1671
|
-
* such as "{total} open": `{total}` and `{shown}` are the list's counts
|
|
1755
|
+
* such as "{total} open": `{total}` and `{shown}` are the list's counts,
|
|
1756
|
+
* and `{count:<name>}` the count of a list named in `headerMetaCounts`
|
|
1757
|
+
* ("{total} contracten bij {count:suppliers} leveranciers").
|
|
1672
1758
|
*
|
|
1673
1759
|
* @spec openspec/changes/page-header-breadcrumb/specs/page-header/spec.md#requirement-a-list-dashboard-or-settings-page-can-show-a-breadcrumb-and-a-meta-note
|
|
1674
1760
|
*/
|
|
@@ -1677,12 +1763,29 @@ export default {
|
|
|
1677
1763
|
default: '',
|
|
1678
1764
|
},
|
|
1679
1765
|
|
|
1766
|
+
/**
|
|
1767
|
+
* The other lists `headerMeta` counts (manifest `config.headerMetaCounts`):
|
|
1768
|
+
* `{ <name>: { register, schema, filter? } }`, each read as one list
|
|
1769
|
+
* total and filled in for `{count:<name>}`. While a count loads, or when
|
|
1770
|
+
* it fails, the note is left out rather than shown with a gap.
|
|
1771
|
+
*
|
|
1772
|
+
* @type {Record<string, {register: string, schema: string, filter?: object}>|null}
|
|
1773
|
+
*/
|
|
1774
|
+
headerMetaCounts: {
|
|
1775
|
+
type: Object,
|
|
1776
|
+
default: null,
|
|
1777
|
+
},
|
|
1778
|
+
|
|
1680
1779
|
/**
|
|
1681
1780
|
* Tabs to sibling pages above the toolbar (manifest `config.pageTabs`),
|
|
1682
1781
|
* each `{ id?, label, route?, params?, query?, href?, countFrom?: {
|
|
1683
|
-
* register, schema, filter? } }`: DqPrivacy's
|
|
1684
|
-
* Datalekken". The current page's tab is marked;
|
|
1685
|
-
* count of that list.
|
|
1782
|
+
* register, schema, filter? }, adminOnly?, permission? }`: DqPrivacy's
|
|
1783
|
+
* "AVG-verzoeken | Datalekken". The current page's tab is marked;
|
|
1784
|
+
* `countFrom` adds the count of that list. A tab with `adminOnly` shows
|
|
1785
|
+
* only to an instance admin, one with `permission` only to a user who
|
|
1786
|
+
* holds it. That hides the tab and nothing more: the page it points to
|
|
1787
|
+
* must still refuse the user on the server. Wins over a named source's
|
|
1788
|
+
* own page tabs.
|
|
1686
1789
|
*
|
|
1687
1790
|
* @type {Array<object>|null}
|
|
1688
1791
|
* @spec openspec/changes/index-page-tabs-notice/specs/index-page/spec.md#requirement-an-index-page-can-link-its-sibling-pages-as-tabs
|
|
@@ -1852,7 +1955,9 @@ export default {
|
|
|
1852
1955
|
* variant?, icon?, format?, id? }`: `action` is `add` (the Add flow;
|
|
1853
1956
|
* its label defaults to the Add label), `export` (the export leaf in
|
|
1854
1957
|
* `format`, `csv` by default, else the export dialog), `import`,
|
|
1855
|
-
* `refresh`,
|
|
1958
|
+
* `refresh`, `save-view` (the save-current-view dialog: the board's
|
|
1959
|
+
* "Zoekopdracht opslaan", label "Save view" by default), or the id of a
|
|
1960
|
+
* `headerActions` entry; `variant` is
|
|
1856
1961
|
* `primary` or `secondary` (the default). Shown only with
|
|
1857
1962
|
* `showTitle`. When they show, the actions bar drops its Views and
|
|
1858
1963
|
* Actions menus, and the Add button and Export menu when a button
|
|
@@ -2164,6 +2269,16 @@ export default {
|
|
|
2164
2269
|
default: true,
|
|
2165
2270
|
},
|
|
2166
2271
|
|
|
2272
|
+
/**
|
|
2273
|
+
* Draw the table without its column-header row (manifest
|
|
2274
|
+
* `config.hideTableHeader`), for a list the board draws as plain rows
|
|
2275
|
+
* (DqTeamwachtrij). Pair it with `selectable: false` for no checkboxes.
|
|
2276
|
+
*/
|
|
2277
|
+
hideTableHeader: {
|
|
2278
|
+
type: Boolean,
|
|
2279
|
+
default: false,
|
|
2280
|
+
},
|
|
2281
|
+
|
|
2167
2282
|
/**
|
|
2168
2283
|
* When true, a row/card click emits `row-click` (to open/navigate) even
|
|
2169
2284
|
* while `selectable` — selection then happens via the checkbox only.
|
|
@@ -2307,8 +2422,15 @@ export default {
|
|
|
2307
2422
|
* - `popupField` — object property rendered in the marker popup.
|
|
2308
2423
|
* - `center` — optional `[lat, lng]` fallback centre when the filtered set
|
|
2309
2424
|
* has no plottable rows.
|
|
2425
|
+
* - `zoom` — the map's initial zoom level.
|
|
2426
|
+
* - `list` — a numbered list beside the map, map and list in one card
|
|
2427
|
+
* (DqZakenKaart): `{ title, sub?, pills?: [{ path?, text?, map?,
|
|
2428
|
+
* colorMap? }], due? }`, field templates read per row. The pins carry the
|
|
2429
|
+
* list's numbers, the row under the pointer is marked on both, the rows
|
|
2430
|
+
* without a place are counted under the list with a link to the table,
|
|
2431
|
+
* and the page's count line adds how many are on the map.
|
|
2310
2432
|
*
|
|
2311
|
-
* @type {{ latField?: string, lngField?: string, geoField?: string, popupField?: string, center?: [number, number] }}
|
|
2433
|
+
* @type {{ latField?: string, lngField?: string, geoField?: string, popupField?: string, center?: [number, number], zoom?: number, list?: object }}
|
|
2312
2434
|
*/
|
|
2313
2435
|
mapConfig: {
|
|
2314
2436
|
type: Object,
|
|
@@ -3722,6 +3844,10 @@ export default {
|
|
|
3722
3844
|
filterStripCounts: null,
|
|
3723
3845
|
/** The `countFrom` counts of the manifest page tabs, by index. */
|
|
3724
3846
|
pageTabCounts: {},
|
|
3847
|
+
/** The `headerMetaCounts` totals, by name; a failed one is null. */
|
|
3848
|
+
headerMetaCountValues: {},
|
|
3849
|
+
/** The row the pointer is on in the map list, by key; '' for none. */
|
|
3850
|
+
activeMapKey: '',
|
|
3725
3851
|
/** The tabs `quickFiltersFrom` produced, or null before they load. */
|
|
3726
3852
|
generatedQuickFilters: null,
|
|
3727
3853
|
/** Count per saved-view id, for the views control; null = none. */
|
|
@@ -5480,6 +5606,8 @@ export default {
|
|
|
5480
5606
|
*/
|
|
5481
5607
|
mapMarkers() {
|
|
5482
5608
|
const features = []
|
|
5609
|
+
// With the list beside the map, a pin carries the row's number there.
|
|
5610
|
+
const numbers = this.mapListEnabled ? new Map(this.mapList.items.map((item) => [item.row, item.n])) : null
|
|
5483
5611
|
for (const row of this.displayObjects) {
|
|
5484
5612
|
const geometry = this.resolveRowGeometry(row)
|
|
5485
5613
|
if (!geometry) {
|
|
@@ -5491,6 +5619,7 @@ export default {
|
|
|
5491
5619
|
properties: {
|
|
5492
5620
|
[this.rowKey]: row[this.rowKey],
|
|
5493
5621
|
...(this.mapConfig.popupField ? { [this.mapConfig.popupField]: row[this.mapConfig.popupField] } : {}),
|
|
5622
|
+
...(numbers && numbers.has(row) ? { markerNumber: numbers.get(row), markerActive: this.activeMapKey === String(row[this.rowKey]) } : {}),
|
|
5494
5623
|
},
|
|
5495
5624
|
})
|
|
5496
5625
|
}
|
|
@@ -5517,6 +5646,57 @@ export default {
|
|
|
5517
5646
|
return this.mapConfig.clustering !== false
|
|
5518
5647
|
},
|
|
5519
5648
|
|
|
5649
|
+
/** @return {number|undefined} The map's initial zoom (`mapConfig.zoom`), when a number. */
|
|
5650
|
+
mapZoom() {
|
|
5651
|
+
const zoom = this.mapConfig && this.mapConfig.zoom
|
|
5652
|
+
return typeof zoom === 'number' && Number.isFinite(zoom) ? zoom : undefined
|
|
5653
|
+
},
|
|
5654
|
+
|
|
5655
|
+
/** @return {boolean} Whether the map draws its numbered list (`mapConfig.list`). */
|
|
5656
|
+
mapListEnabled() {
|
|
5657
|
+
const list = this.mapConfig && this.mapConfig.list
|
|
5658
|
+
return Boolean(list && typeof list === 'object' && typeof list.title === 'string' && list.title !== '')
|
|
5659
|
+
},
|
|
5660
|
+
|
|
5661
|
+
/**
|
|
5662
|
+
* The map list's entries, numbered as the pins, and the rows without a
|
|
5663
|
+
* place. Templates go through the host's translate first.
|
|
5664
|
+
*
|
|
5665
|
+
* @return {{items: Array<object>, missing: Array<object>}}
|
|
5666
|
+
*/
|
|
5667
|
+
mapList() {
|
|
5668
|
+
if (!this.mapListEnabled) {
|
|
5669
|
+
return { items: [], missing: [] }
|
|
5670
|
+
}
|
|
5671
|
+
const list = this.mapConfig.list
|
|
5672
|
+
const translated = {
|
|
5673
|
+
...list,
|
|
5674
|
+
title: this.cnTranslate(list.title),
|
|
5675
|
+
sub: list.sub ? this.cnTranslate(list.sub) : '',
|
|
5676
|
+
due: list.due ? this.cnTranslate(list.due) : '',
|
|
5677
|
+
}
|
|
5678
|
+
return mapListItems(this.displayObjects, translated, {
|
|
5679
|
+
rowKey: this.rowKey,
|
|
5680
|
+
located: (row) => Boolean(this.resolveRowGeometry(row)),
|
|
5681
|
+
translate: (text) => this.cnTranslate(text),
|
|
5682
|
+
})
|
|
5683
|
+
},
|
|
5684
|
+
|
|
5685
|
+
/** @return {string} The list's accessible name. */
|
|
5686
|
+
mapListLabel() {
|
|
5687
|
+
return t('nextcloud-vue', 'On the map')
|
|
5688
|
+
},
|
|
5689
|
+
|
|
5690
|
+
/** @return {string} The card under the list, for the rows without a place. */
|
|
5691
|
+
mapMissingTitle() {
|
|
5692
|
+
return n('nextcloud-vue', '%n without an address', '%n without an address', this.mapList.missing.length)
|
|
5693
|
+
},
|
|
5694
|
+
|
|
5695
|
+
/** @return {string} The link from that card to the table. */
|
|
5696
|
+
mapMissingLink() {
|
|
5697
|
+
return t('nextcloud-vue', 'Show them in the table')
|
|
5698
|
+
},
|
|
5699
|
+
|
|
5520
5700
|
/**
|
|
5521
5701
|
* Extra (non-background) map layers — WMS / WFS / GeoJSON overlays declared in
|
|
5522
5702
|
* `mapConfig.layers`. The background map comes from `mapBasemaps` instead, so
|
|
@@ -5617,9 +5797,51 @@ export default {
|
|
|
5617
5797
|
if (this.selfFetchFailed) {
|
|
5618
5798
|
return { ...this.list.pagination.value, total: 0, page: 1, pages: 1 }
|
|
5619
5799
|
}
|
|
5800
|
+
// A named source that reports its own total (the search source)
|
|
5801
|
+
// gives the count line its number.
|
|
5802
|
+
if (this.isNamedSource && this.namedSource && typeof this.namedSource.total === 'function') {
|
|
5803
|
+
return { ...(this.pagination || {}), total: this.namedSource.total() }
|
|
5804
|
+
}
|
|
5620
5805
|
return this.isSelfFetchMode ? this.list.pagination.value : this.pagination
|
|
5621
5806
|
},
|
|
5622
5807
|
|
|
5808
|
+
/**
|
|
5809
|
+
* The saved view the page has applied, or null.
|
|
5810
|
+
*
|
|
5811
|
+
* @return {object|null}
|
|
5812
|
+
*/
|
|
5813
|
+
appliedSavedView() {
|
|
5814
|
+
const id = this.appliedSavedViewId
|
|
5815
|
+
if (!id) {
|
|
5816
|
+
return null
|
|
5817
|
+
}
|
|
5818
|
+
return (this.savedViews || []).find((view) => view && (String(view.id) === id || String(view.slug) === id || String(view.uuid) === id)) || null
|
|
5819
|
+
},
|
|
5820
|
+
|
|
5821
|
+
/**
|
|
5822
|
+
* The term a named source searched for, for `{term}` in the title and
|
|
5823
|
+
* the count line ("Zoeken: Lindelaan"), or ''.
|
|
5824
|
+
*
|
|
5825
|
+
* @return {string}
|
|
5826
|
+
*/
|
|
5827
|
+
sourceTerm() {
|
|
5828
|
+
return this.isNamedSource && this.namedSource && typeof this.namedSource.term === 'function' ? String(this.namedSource.term() || '') : ''
|
|
5829
|
+
},
|
|
5830
|
+
|
|
5831
|
+
/**
|
|
5832
|
+
* The page title with `{term}` filled in.
|
|
5833
|
+
*
|
|
5834
|
+
* @return {string}
|
|
5835
|
+
*/
|
|
5836
|
+
shownTitle() {
|
|
5837
|
+
const title = this.presented('title')
|
|
5838
|
+
// A title with the term is translated here, before the term goes in,
|
|
5839
|
+
// so its catalogue entry is found ("Zoeken: {term}").
|
|
5840
|
+
return typeof title === 'string' && title.includes('{term}')
|
|
5841
|
+
? this.cnTranslate(title).replace(/\{term\}/g, this.sourceTerm)
|
|
5842
|
+
: title
|
|
5843
|
+
},
|
|
5844
|
+
|
|
5623
5845
|
/**
|
|
5624
5846
|
* Whether the table marks unread rows. The boards draw every row alike,
|
|
5625
5847
|
* so under the board look only a page that offers the Unread lens
|
|
@@ -6202,9 +6424,13 @@ export default {
|
|
|
6202
6424
|
if (!Array.isArray(this.pageTabs) || this.pageTabs.length === 0) {
|
|
6203
6425
|
return this.sourcePageTabs
|
|
6204
6426
|
}
|
|
6427
|
+
// The index is the tab's place in `pageTabs`, which is how its count
|
|
6428
|
+
// is keyed, so the tabs are numbered before any is left out.
|
|
6205
6429
|
return this.pageTabs
|
|
6206
|
-
.
|
|
6207
|
-
.
|
|
6430
|
+
.map((tab, index) => ({ tab, index }))
|
|
6431
|
+
.filter(({ tab }) => tab && typeof tab.label === 'string' && tab.label !== '' && (tab.route || tab.to || tab.href))
|
|
6432
|
+
.filter(({ tab }) => this.pageTabVisible(tab))
|
|
6433
|
+
.map(({ tab, index }) => {
|
|
6208
6434
|
const to = tab.route
|
|
6209
6435
|
? { name: tab.route, ...(tab.params ? { params: tab.params } : {}), ...(tab.query ? { query: tab.query } : {}) }
|
|
6210
6436
|
: (tab.to || tab.href)
|
|
@@ -6356,6 +6582,9 @@ export default {
|
|
|
6356
6582
|
if (label === '' && button.action === 'actions-menu') {
|
|
6357
6583
|
label = t('nextcloud-vue', 'Actions')
|
|
6358
6584
|
}
|
|
6585
|
+
if (label === '' && button.action === 'save-view') {
|
|
6586
|
+
label = t('nextcloud-vue', 'Save view')
|
|
6587
|
+
}
|
|
6359
6588
|
return {
|
|
6360
6589
|
key: String(button.id || button.action || index),
|
|
6361
6590
|
label,
|
|
@@ -6646,12 +6875,60 @@ export default {
|
|
|
6646
6875
|
return ''
|
|
6647
6876
|
}
|
|
6648
6877
|
const total = this.effectivePagination?.total
|
|
6649
|
-
|
|
6878
|
+
let missing = false
|
|
6879
|
+
const text = this.cnTranslate(headerMeta)
|
|
6650
6880
|
.replace('{shown}', String(this.effectiveObjects.length))
|
|
6651
6881
|
.replace('{total}', typeof total === 'number' ? String(total) : '')
|
|
6882
|
+
.replace(/\{count:([\w-]+)\}/g, (match, name) => {
|
|
6883
|
+
const value = this.headerMetaCountValues[name]
|
|
6884
|
+
if (typeof value !== 'number') {
|
|
6885
|
+
missing = true
|
|
6886
|
+
return ''
|
|
6887
|
+
}
|
|
6888
|
+
return String(value)
|
|
6889
|
+
})
|
|
6890
|
+
return missing ? '' : text
|
|
6652
6891
|
},
|
|
6653
6892
|
|
|
6893
|
+
/**
|
|
6894
|
+
* Whether the header note carries a count, so the board leaves out its
|
|
6895
|
+
* own "{shown} of {total}" line (DqPrivacy, DqContracten).
|
|
6896
|
+
*
|
|
6897
|
+
* @return {boolean}
|
|
6898
|
+
*/
|
|
6899
|
+
headerMetaCarriesCount() {
|
|
6900
|
+
const headerMeta = this.presented('headerMeta')
|
|
6901
|
+
return typeof headerMeta === 'string' && /\{(shown|total|count:[\w-]+)\}/.test(headerMeta)
|
|
6902
|
+
},
|
|
6903
|
+
|
|
6904
|
+
/**
|
|
6905
|
+
* What the header note's other counts depend on, as one key.
|
|
6906
|
+
*
|
|
6907
|
+
* @return {string}
|
|
6908
|
+
*/
|
|
6909
|
+
headerMetaCountKey() {
|
|
6910
|
+
const sources = this.headerMetaCounts && typeof this.headerMetaCounts === 'object' ? this.headerMetaCounts : {}
|
|
6911
|
+
const valid = Object.entries(sources).filter(([, from]) => from && from.register && from.schema)
|
|
6912
|
+
return valid.length > 0 ? JSON.stringify(valid) : ''
|
|
6913
|
+
},
|
|
6914
|
+
|
|
6915
|
+
/**
|
|
6916
|
+
* The header's description line, and on the map with its list the
|
|
6917
|
+
* number of rows on the map after a middle dot ("· 5 met een adres op
|
|
6918
|
+
* de kaart", DqZakenKaart).
|
|
6919
|
+
*
|
|
6920
|
+
* @return {string}
|
|
6921
|
+
*/
|
|
6654
6922
|
headerDescription() {
|
|
6923
|
+
const base = this.headerDescriptionBase
|
|
6924
|
+
if (this.currentViewMode !== 'map' || !this.mapListEnabled) {
|
|
6925
|
+
return base
|
|
6926
|
+
}
|
|
6927
|
+
const onMap = n('nextcloud-vue', '%n with an address on the map', '%n with an address on the map', this.mapList.items.length)
|
|
6928
|
+
return base ? `${base} · ${onMap}` : onMap
|
|
6929
|
+
},
|
|
6930
|
+
|
|
6931
|
+
headerDescriptionBase() {
|
|
6655
6932
|
const total = this.effectivePagination?.total
|
|
6656
6933
|
// Board look: the count line is a template over the rows on this page
|
|
6657
6934
|
// and all rows, "{shown} of {total}" unless the page says otherwise.
|
|
@@ -6661,6 +6938,10 @@ export default {
|
|
|
6661
6938
|
// reads "14 van 14" in Dutch; a page's own template goes
|
|
6662
6939
|
// through the app's label lookup.
|
|
6663
6940
|
const countText = this.presented('countText')
|
|
6941
|
+
// The note after the breadcrumb already says how many there are.
|
|
6942
|
+
if (!countText && !this.countSubtitle && this.headerMetaCarriesCount) {
|
|
6943
|
+
return this.description
|
|
6944
|
+
}
|
|
6664
6945
|
if (!countText && !this.countSubtitle) {
|
|
6665
6946
|
return t('nextcloud-vue', '{shown} of {total}', { shown, total })
|
|
6666
6947
|
}
|
|
@@ -6668,6 +6949,7 @@ export default {
|
|
|
6668
6949
|
return this.cnTranslate(countText)
|
|
6669
6950
|
.replace('{shown}', String(shown))
|
|
6670
6951
|
.replace('{total}', String(total))
|
|
6952
|
+
.replace(/\{term\}/g, this.sourceTerm)
|
|
6671
6953
|
}
|
|
6672
6954
|
return this.countLine(this.countSubtitle, total, shown)
|
|
6673
6955
|
}
|
|
@@ -6907,6 +7189,13 @@ export default {
|
|
|
6907
7189
|
},
|
|
6908
7190
|
},
|
|
6909
7191
|
|
|
7192
|
+
headerMetaCountKey: {
|
|
7193
|
+
immediate: true,
|
|
7194
|
+
handler() {
|
|
7195
|
+
this.loadHeaderMetaCounts()
|
|
7196
|
+
},
|
|
7197
|
+
},
|
|
7198
|
+
|
|
6910
7199
|
pageTabCountKey: {
|
|
6911
7200
|
immediate: true,
|
|
6912
7201
|
/** @spec openspec/changes/index-page-tabs-notice/specs/index-page/spec.md#requirement-an-index-page-can-link-its-sibling-pages-as-tabs */
|
|
@@ -7326,6 +7615,65 @@ export default {
|
|
|
7326
7615
|
]
|
|
7327
7616
|
},
|
|
7328
7617
|
|
|
7618
|
+
/**
|
|
7619
|
+
* Whether Nextcloud says the user administers this instance; false
|
|
7620
|
+
* when the user cannot be read.
|
|
7621
|
+
*
|
|
7622
|
+
* @return {boolean}
|
|
7623
|
+
*/
|
|
7624
|
+
viewerIsAdmin() {
|
|
7625
|
+
try {
|
|
7626
|
+
return getCurrentUser()?.isAdmin === true
|
|
7627
|
+
} catch {
|
|
7628
|
+
return false
|
|
7629
|
+
}
|
|
7630
|
+
},
|
|
7631
|
+
|
|
7632
|
+
/**
|
|
7633
|
+
* Whether a manifest page tab shows to this user: an `adminOnly` tab to
|
|
7634
|
+
* an instance admin, a tab with a `permission` to a user who holds it
|
|
7635
|
+
* (as a menu entry: with no permissions known, it shows). This only
|
|
7636
|
+
* decides whether the tab is drawn. It is not access control; the
|
|
7637
|
+
* page behind the tab must enforce its own access on the server.
|
|
7638
|
+
*
|
|
7639
|
+
* @param {object} tab The tab declaration.
|
|
7640
|
+
* @return {boolean} True when the tab is drawn.
|
|
7641
|
+
*/
|
|
7642
|
+
pageTabVisible(tab) {
|
|
7643
|
+
if (tab.adminOnly === true && !this.viewerIsAdmin()) {
|
|
7644
|
+
return false
|
|
7645
|
+
}
|
|
7646
|
+
if (tab.permission) {
|
|
7647
|
+
const held = Array.isArray(this.cnPermissions) ? this.cnPermissions : []
|
|
7648
|
+
if (held.length > 0 && !held.includes(tab.permission)) {
|
|
7649
|
+
return false
|
|
7650
|
+
}
|
|
7651
|
+
}
|
|
7652
|
+
return true
|
|
7653
|
+
},
|
|
7654
|
+
|
|
7655
|
+
/**
|
|
7656
|
+
* Read the totals of the lists `headerMetaCounts` names, one list
|
|
7657
|
+
* request each. A failed count is null and leaves the note out.
|
|
7658
|
+
*
|
|
7659
|
+
* @return {Promise<void>}
|
|
7660
|
+
*/
|
|
7661
|
+
async loadHeaderMetaCounts() {
|
|
7662
|
+
const key = this.headerMetaCountKey
|
|
7663
|
+
if (key === '') {
|
|
7664
|
+
this.headerMetaCountValues = {}
|
|
7665
|
+
return
|
|
7666
|
+
}
|
|
7667
|
+
const ctx = typeof this.selfFetchTokenCtx === 'function' ? this.selfFetchTokenCtx() : {}
|
|
7668
|
+
const values = {}
|
|
7669
|
+
await Promise.all(JSON.parse(key).map(async ([name, from]) => {
|
|
7670
|
+
values[name] = await fetchListTotal(from.register, from.schema, from.filter || {}, ctx).catch(() => null)
|
|
7671
|
+
}))
|
|
7672
|
+
if (key === this.headerMetaCountKey) {
|
|
7673
|
+
this.headerMetaCountValues = values
|
|
7674
|
+
}
|
|
7675
|
+
},
|
|
7676
|
+
|
|
7329
7677
|
/**
|
|
7330
7678
|
* Count the lists behind the manifest page tabs (`countFrom`), one list
|
|
7331
7679
|
* request each. A failed count shows no number.
|
|
@@ -8048,6 +8396,8 @@ export default {
|
|
|
8048
8396
|
this.showImportDialog = true
|
|
8049
8397
|
} else if (button.action === 'refresh') {
|
|
8050
8398
|
this.onRefreshEvent()
|
|
8399
|
+
} else if (button.action === 'save-view') {
|
|
8400
|
+
this.showSaveViewDialog = true
|
|
8051
8401
|
} else {
|
|
8052
8402
|
this.onHeaderAction({ action: button.action, id: button.action })
|
|
8053
8403
|
}
|
|
@@ -10058,6 +10408,21 @@ export default {
|
|
|
10058
10408
|
}
|
|
10059
10409
|
},
|
|
10060
10410
|
|
|
10411
|
+
/**
|
|
10412
|
+
* Put a saved view that changed elsewhere (its alert) back in the list,
|
|
10413
|
+
* matched on its id or uuid.
|
|
10414
|
+
*
|
|
10415
|
+
* @param {object} view The saved view as the server returned it.
|
|
10416
|
+
* @return {void}
|
|
10417
|
+
*/
|
|
10418
|
+
replaceSavedView(view) {
|
|
10419
|
+
if (!view || typeof view !== 'object') {
|
|
10420
|
+
return
|
|
10421
|
+
}
|
|
10422
|
+
const same = (other) => other && ((view.id !== undefined && other.id === view.id) || (view.uuid && other.uuid === view.uuid))
|
|
10423
|
+
this.savedViews = (this.savedViews || []).map((other) => (same(other) ? view : other))
|
|
10424
|
+
},
|
|
10425
|
+
|
|
10061
10426
|
async onSaveViewConfirm({ name, isPublic, sharedWith, presentation }) {
|
|
10062
10427
|
const state = this.isSelfFetchMode
|
|
10063
10428
|
? this.currentViewState()
|
|
@@ -75,7 +75,10 @@ export function useNamedSource(props, options = {}) {
|
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
const
|
|
78
|
+
const cnTranslate = inject('cnTranslate', null)
|
|
79
|
+
const source = resolveIndexSource(props.entitySource, props.sourceConfig, {
|
|
80
|
+
translate: (text) => (typeof cnTranslate === 'function' ? cnTranslate(text) : text),
|
|
81
|
+
})
|
|
79
82
|
|
|
80
83
|
// An unknown source name resolves to null and was already warned about.
|
|
81
84
|
// The page then behaves as an empty index rather than throwing.
|
|
@@ -865,6 +865,21 @@ export default {
|
|
|
865
865
|
const color = (feature.properties && feature.properties.markerColor)
|
|
866
866
|
|| (this.cfg.markers && this.cfg.markers.iconColor)
|
|
867
867
|
|| 'var(--color-primary-element, #2196F3)'
|
|
868
|
+
// A numbered pin, the number the list beside the map shows for the
|
|
869
|
+
// same row (an index map with `mapConfig.list`); the active row's
|
|
870
|
+
// pin draws darker.
|
|
871
|
+
const number = feature.properties && Number(feature.properties.markerNumber)
|
|
872
|
+
if (Number.isInteger(number) && number > 0) {
|
|
873
|
+
const active = feature.properties.markerActive === true
|
|
874
|
+
return L.marker(latlng, {
|
|
875
|
+
icon: L.divIcon({
|
|
876
|
+
className: active ? 'cn-map-widget__pin cn-map-widget__pin--active' : 'cn-map-widget__pin',
|
|
877
|
+
html: `<span>${number}</span>`,
|
|
878
|
+
iconSize: [26, 26],
|
|
879
|
+
iconAnchor: [13, 13],
|
|
880
|
+
}),
|
|
881
|
+
})
|
|
882
|
+
}
|
|
868
883
|
if (this.cfg.markers && this.cfg.markers.iconUrl) {
|
|
869
884
|
return L.marker(latlng, {
|
|
870
885
|
icon: L.icon({ iconUrl: this.cfg.markers.iconUrl, iconSize: [25, 41], iconAnchor: [12, 41] }),
|
|
@@ -1479,3 +1494,25 @@ export default {
|
|
|
1479
1494
|
background: var(--color-background-hover);
|
|
1480
1495
|
}
|
|
1481
1496
|
</style>
|
|
1497
|
+
|
|
1498
|
+
<style>
|
|
1499
|
+
/* A numbered pin (`properties.markerNumber`): a 26px primary circle with its
|
|
1500
|
+
number in white, the active one darker. Unscoped, because Leaflet creates
|
|
1501
|
+
the marker element outside the template. */
|
|
1502
|
+
.cn-map-widget__pin {
|
|
1503
|
+
display: flex;
|
|
1504
|
+
align-items: center;
|
|
1505
|
+
justify-content: center;
|
|
1506
|
+
border: 2px solid var(--color-main-background);
|
|
1507
|
+
border-radius: 50%;
|
|
1508
|
+
background: var(--color-primary-element);
|
|
1509
|
+
color: var(--color-primary-element-text);
|
|
1510
|
+
font-size: 13px;
|
|
1511
|
+
font-weight: 700;
|
|
1512
|
+
box-sizing: border-box;
|
|
1513
|
+
}
|
|
1514
|
+
|
|
1515
|
+
.cn-map-widget__pin--active {
|
|
1516
|
+
background: var(--color-primary-element-light-text);
|
|
1517
|
+
}
|
|
1518
|
+
</style>
|