@conduction/nextcloud-vue 2.100.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/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/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/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/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 +251 -71
- 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/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/CnSetupWizard/CnSetupWizard.vue.js +1 -1
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js +35 -2
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js.map +1 -1
- 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/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 +37 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +35 -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 +769 -251
- 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 +8977 -6843
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +769 -251
- package/l10n/en.json +37 -1
- package/l10n/nl.json +35 -1
- package/package.json +1 -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/CnExportsWidget/CnExportsWidget.vue +233 -0
- package/src/components/CnExportsWidget/index.js +7 -0
- package/src/components/CnFilesBrowser/CnFilesBrowser.vue +324 -0
- package/src/components/CnFilesBrowser/filesReview.js +57 -0
- package/src/components/CnGroupedCardsWidget/CnGroupedCardsWidget.vue +433 -0
- package/src/components/CnGroupedCardsWidget/index.js +28 -0
- package/src/components/CnIndexPage/CnIndexPage.vue +240 -4
- 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/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue +272 -0
- package/src/components/CnSavedViewAlertWidget/index.js +7 -0
- package/src/components/CnSetupWizard/CnSetupWizard.vue +35 -2
- package/src/components/CnWidgetGrid/builtInWidgets.js +4 -0
- package/src/components/CnWidgetGrid/registerDashboardWidgets.js +1 -0
- package/src/components/index.js +3 -0
- package/src/composables/indexSources.js +166 -19
- package/src/composables/useEndpointSource.js +28 -6
- package/src/css/index-page.css +117 -0
- package/src/css/look-board.css +44 -0
- package/src/index.js +1 -0
- package/src/schemas/app-manifest-v2.schema.json +31 -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,6 +1635,29 @@ 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: () => ({}) },
|
|
1581
1663
|
/** The permissions the user holds, provided by CnAppRoot; for gated page tabs. */
|
|
@@ -1873,7 +1955,9 @@ export default {
|
|
|
1873
1955
|
* variant?, icon?, format?, id? }`: `action` is `add` (the Add flow;
|
|
1874
1956
|
* its label defaults to the Add label), `export` (the export leaf in
|
|
1875
1957
|
* `format`, `csv` by default, else the export dialog), `import`,
|
|
1876
|
-
* `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
|
|
1877
1961
|
* `primary` or `secondary` (the default). Shown only with
|
|
1878
1962
|
* `showTitle`. When they show, the actions bar drops its Views and
|
|
1879
1963
|
* Actions menus, and the Add button and Export menu when a button
|
|
@@ -2185,6 +2269,16 @@ export default {
|
|
|
2185
2269
|
default: true,
|
|
2186
2270
|
},
|
|
2187
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
|
+
|
|
2188
2282
|
/**
|
|
2189
2283
|
* When true, a row/card click emits `row-click` (to open/navigate) even
|
|
2190
2284
|
* while `selectable` — selection then happens via the checkbox only.
|
|
@@ -2328,8 +2422,15 @@ export default {
|
|
|
2328
2422
|
* - `popupField` — object property rendered in the marker popup.
|
|
2329
2423
|
* - `center` — optional `[lat, lng]` fallback centre when the filtered set
|
|
2330
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.
|
|
2331
2432
|
*
|
|
2332
|
-
* @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 }}
|
|
2333
2434
|
*/
|
|
2334
2435
|
mapConfig: {
|
|
2335
2436
|
type: Object,
|
|
@@ -3745,6 +3846,8 @@ export default {
|
|
|
3745
3846
|
pageTabCounts: {},
|
|
3746
3847
|
/** The `headerMetaCounts` totals, by name; a failed one is null. */
|
|
3747
3848
|
headerMetaCountValues: {},
|
|
3849
|
+
/** The row the pointer is on in the map list, by key; '' for none. */
|
|
3850
|
+
activeMapKey: '',
|
|
3748
3851
|
/** The tabs `quickFiltersFrom` produced, or null before they load. */
|
|
3749
3852
|
generatedQuickFilters: null,
|
|
3750
3853
|
/** Count per saved-view id, for the views control; null = none. */
|
|
@@ -5503,6 +5606,8 @@ export default {
|
|
|
5503
5606
|
*/
|
|
5504
5607
|
mapMarkers() {
|
|
5505
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
|
|
5506
5611
|
for (const row of this.displayObjects) {
|
|
5507
5612
|
const geometry = this.resolveRowGeometry(row)
|
|
5508
5613
|
if (!geometry) {
|
|
@@ -5514,6 +5619,7 @@ export default {
|
|
|
5514
5619
|
properties: {
|
|
5515
5620
|
[this.rowKey]: row[this.rowKey],
|
|
5516
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]) } : {}),
|
|
5517
5623
|
},
|
|
5518
5624
|
})
|
|
5519
5625
|
}
|
|
@@ -5540,6 +5646,57 @@ export default {
|
|
|
5540
5646
|
return this.mapConfig.clustering !== false
|
|
5541
5647
|
},
|
|
5542
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
|
+
|
|
5543
5700
|
/**
|
|
5544
5701
|
* Extra (non-background) map layers — WMS / WFS / GeoJSON overlays declared in
|
|
5545
5702
|
* `mapConfig.layers`. The background map comes from `mapBasemaps` instead, so
|
|
@@ -5640,9 +5797,51 @@ export default {
|
|
|
5640
5797
|
if (this.selfFetchFailed) {
|
|
5641
5798
|
return { ...this.list.pagination.value, total: 0, page: 1, pages: 1 }
|
|
5642
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
|
+
}
|
|
5643
5805
|
return this.isSelfFetchMode ? this.list.pagination.value : this.pagination
|
|
5644
5806
|
},
|
|
5645
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
|
+
|
|
5646
5845
|
/**
|
|
5647
5846
|
* Whether the table marks unread rows. The boards draw every row alike,
|
|
5648
5847
|
* so under the board look only a page that offers the Unread lens
|
|
@@ -6383,6 +6582,9 @@ export default {
|
|
|
6383
6582
|
if (label === '' && button.action === 'actions-menu') {
|
|
6384
6583
|
label = t('nextcloud-vue', 'Actions')
|
|
6385
6584
|
}
|
|
6585
|
+
if (label === '' && button.action === 'save-view') {
|
|
6586
|
+
label = t('nextcloud-vue', 'Save view')
|
|
6587
|
+
}
|
|
6386
6588
|
return {
|
|
6387
6589
|
key: String(button.id || button.action || index),
|
|
6388
6590
|
label,
|
|
@@ -6710,7 +6912,23 @@ export default {
|
|
|
6710
6912
|
return valid.length > 0 ? JSON.stringify(valid) : ''
|
|
6711
6913
|
},
|
|
6712
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
|
+
*/
|
|
6713
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() {
|
|
6714
6932
|
const total = this.effectivePagination?.total
|
|
6715
6933
|
// Board look: the count line is a template over the rows on this page
|
|
6716
6934
|
// and all rows, "{shown} of {total}" unless the page says otherwise.
|
|
@@ -6731,6 +6949,7 @@ export default {
|
|
|
6731
6949
|
return this.cnTranslate(countText)
|
|
6732
6950
|
.replace('{shown}', String(shown))
|
|
6733
6951
|
.replace('{total}', String(total))
|
|
6952
|
+
.replace(/\{term\}/g, this.sourceTerm)
|
|
6734
6953
|
}
|
|
6735
6954
|
return this.countLine(this.countSubtitle, total, shown)
|
|
6736
6955
|
}
|
|
@@ -8177,6 +8396,8 @@ export default {
|
|
|
8177
8396
|
this.showImportDialog = true
|
|
8178
8397
|
} else if (button.action === 'refresh') {
|
|
8179
8398
|
this.onRefreshEvent()
|
|
8399
|
+
} else if (button.action === 'save-view') {
|
|
8400
|
+
this.showSaveViewDialog = true
|
|
8180
8401
|
} else {
|
|
8181
8402
|
this.onHeaderAction({ action: button.action, id: button.action })
|
|
8182
8403
|
}
|
|
@@ -10187,6 +10408,21 @@ export default {
|
|
|
10187
10408
|
}
|
|
10188
10409
|
},
|
|
10189
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
|
+
|
|
10190
10426
|
async onSaveViewConfirm({ name, isPublic, sharedWith, presentation }) {
|
|
10191
10427
|
const state = this.isSelfFetchMode
|
|
10192
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>
|
|
@@ -233,6 +233,15 @@
|
|
|
233
233
|
{{ moreLabel }}
|
|
234
234
|
</p>
|
|
235
235
|
</template>
|
|
236
|
+
<!-- `content.footnote`: a line under the table ("Awb 4:17 en 4:18"),
|
|
237
|
+
through the host translate. Not while the list waits for its
|
|
238
|
+
context or failed to load. -->
|
|
239
|
+
<p
|
|
240
|
+
v-if="resolvedFootnote && !waitingForContext && !error"
|
|
241
|
+
class="cn-object-list-widget__footnote"
|
|
242
|
+
data-testid="cn-object-list-widget-footnote">
|
|
243
|
+
{{ resolvedFootnote }}
|
|
244
|
+
</p>
|
|
236
245
|
<!-- Create affordance (ADR-062): every collection carries its Add at
|
|
237
246
|
the bottom of the widget; the host card's Actions menu calls the
|
|
238
247
|
same openCreate() through the public method. Suppressed while the
|
|
@@ -430,8 +439,10 @@ export default {
|
|
|
430
439
|
* `hideHeader: true` drops the table's column header row (CnDataTable's
|
|
431
440
|
* `hideHeader`), for a short list that reads as rows, not as a table.
|
|
432
441
|
*
|
|
442
|
+
* `footnote` is a line under the table, through the host translate.
|
|
443
|
+
*
|
|
433
444
|
* @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-small-opt-ins-from-the-decidiq-and-learniq-lanes
|
|
434
|
-
* @type {{register?: string, schema?: string, filter?: object, sort?: {field?: string, dir?: string}, limit?: number, extend?: Array<string>, columns?: Array, rowActions?: Array<object>, dropZone?: object, upload?: boolean, groupBy?: string, groupLabel?: string, groupLabelResolve?: {register: string, schema: string, labelField?: string}, selectable?: boolean, bulkActions?: Array<object>, sortable?: boolean, facet?: {field: string, label?: string}, rowRoute?: string, prompt?: string, emptyText?: string, viewAllRoute?: string, viewAllQuery?: object, hideHeader?: boolean}}
|
|
445
|
+
* @type {{register?: string, schema?: string, filter?: object, sort?: {field?: string, dir?: string}, limit?: number, extend?: Array<string>, columns?: Array, rowActions?: Array<object>, dropZone?: object, upload?: boolean, groupBy?: string, groupLabel?: string, groupLabelResolve?: {register: string, schema: string, labelField?: string}, selectable?: boolean, bulkActions?: Array<object>, sortable?: boolean, facet?: {field: string, label?: string}, rowRoute?: string, prompt?: string, emptyText?: string, footnote?: string, viewAllRoute?: string, viewAllQuery?: object, hideHeader?: boolean}}
|
|
435
446
|
*/
|
|
436
447
|
content: {
|
|
437
448
|
type: Object,
|
|
@@ -918,6 +929,17 @@ export default {
|
|
|
918
929
|
return this.emptyText ? fn(this.emptyText) : this.emptyText
|
|
919
930
|
},
|
|
920
931
|
|
|
932
|
+
/**
|
|
933
|
+
* `content.footnote` run through the host translate function, or ''.
|
|
934
|
+
*
|
|
935
|
+
* @return {string}
|
|
936
|
+
*/
|
|
937
|
+
resolvedFootnote() {
|
|
938
|
+
const note = typeof this.content.footnote === 'string' ? this.content.footnote : ''
|
|
939
|
+
const fn = typeof this.cnTranslate === 'function' ? this.cnTranslate : (k) => k
|
|
940
|
+
return note ? fn(note) : ''
|
|
941
|
+
},
|
|
942
|
+
|
|
921
943
|
/**
|
|
922
944
|
* The rows actually rendered: capped to what fits the host grid cell
|
|
923
945
|
* (ADR-062 — content adapts to the cell, never a nested scrollbar).
|
|
@@ -2027,6 +2049,12 @@ export default {
|
|
|
2027
2049
|
padding: 4px;
|
|
2028
2050
|
}
|
|
2029
2051
|
|
|
2052
|
+
.cn-object-list-widget__footnote {
|
|
2053
|
+
color: var(--color-text-maxcontrast);
|
|
2054
|
+
font-size: 13px;
|
|
2055
|
+
margin: 8px 0 0;
|
|
2056
|
+
}
|
|
2057
|
+
|
|
2030
2058
|
/* Footer Add — same pattern as the integration leaves' footer action
|
|
2031
2059
|
("Open in Calendar"): full-width, centered, divider-topped, pinned to
|
|
2032
2060
|
the card bottom. */
|
|
@@ -15,6 +15,11 @@
|
|
|
15
15
|
:dropHint="dropHint"
|
|
16
16
|
:rowActions="rowActions"
|
|
17
17
|
:newActions="newActions"
|
|
18
|
+
:headerActions="headerActions"
|
|
19
|
+
:rowButton="rowButton"
|
|
20
|
+
:reviewSummary="reviewSummary"
|
|
21
|
+
:footnote="footnote"
|
|
22
|
+
:nameSecondary="nameSecondary"
|
|
18
23
|
:linkedItems="linkedItems"
|
|
19
24
|
:columns="columns"
|
|
20
25
|
:rowData="rowDataSource"
|
|
@@ -420,6 +425,16 @@ export default {
|
|
|
420
425
|
* @type {string[]}
|
|
421
426
|
*/
|
|
422
427
|
facets: { type: Array, default: () => [] },
|
|
428
|
+
/** Forwarded to CnFilesBrowser: the host's own buttons in the bar. */
|
|
429
|
+
headerActions: { type: Array, default: () => [] },
|
|
430
|
+
/** Forwarded to CnFilesBrowser: one visible button on every file row. */
|
|
431
|
+
rowButton: { type: Object, default: null },
|
|
432
|
+
/** Forwarded to CnFilesBrowser: the review summary above the list. */
|
|
433
|
+
reviewSummary: { type: Object, default: null },
|
|
434
|
+
/** Forwarded to CnFilesBrowser: the host's own line under the list. */
|
|
435
|
+
footnote: { type: String, default: '' },
|
|
436
|
+
/** Forwarded to CnFilesBrowser: the second line under each file's name. */
|
|
437
|
+
nameSecondary: { type: String, default: '' },
|
|
423
438
|
/** A dotted path to the list of records in the `rowDataUrl` answer; empty reads the answer itself. */
|
|
424
439
|
rowDataPath: { type: String, default: '' },
|
|
425
440
|
/** The record field that holds the Nextcloud file id. */
|