@conduction/nextcloud-vue 2.61.0 → 2.63.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 +394 -27
- package/dist/esm/components/CnAppNav/CnAppNav.vue2.js.map +1 -1
- package/dist/esm/components/CnAppNav/CnAppNav.vue3.js.map +1 -1
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js +99 -9
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js.map +1 -1
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js +39 -18
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js.map +1 -1
- package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue2.js +79 -2
- package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue3.js +38 -25
- package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnBrandStripe/CnBrandStripe.vue2.js +21 -1
- package/dist/esm/components/CnBrandStripe/CnBrandStripe.vue2.js.map +1 -1
- package/dist/esm/components/CnBrandStripe/CnBrandStripe.vue3.js +4 -1
- package/dist/esm/components/CnBrandStripe/CnBrandStripe.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 +30 -6
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +2 -2
- 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 +256 -23
- package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue3.js +119 -51
- package/dist/esm/components/CnDataTable/CnDataTable.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/CnIndexPage/CnIndexPage.vue2.js +51 -2
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +5 -1
- 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/CnLinkCardsPage/CnLinkCardsPage.vue2.js.map +1 -1
- package/dist/esm/components/CnLinkCardsPage/CnLinkCardsPage.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +36 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js +4 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js +53 -0
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js +22 -5
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js.map +1 -1
- package/dist/esm/components/CnReportsPage/CnReportsPage.vue2.js.map +1 -1
- package/dist/esm/components/CnReportsPage/CnReportsPage.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/CnStorePage/CnStorePage.vue2.js.map +1 -1
- package/dist/esm/components/CnStorePage/CnStorePage.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/CnWikiPage/CnWikiPage.vue2.js.map +1 -1
- package/dist/esm/components/CnWikiPage/CnWikiPage.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 +48 -0
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +48 -0
- package/dist/esm/l10n/nl.json.js.map +1 -1
- package/dist/esm/nextcloud-vue.css +557 -9
- 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/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 +9779 -5236
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +557 -9
- package/l10n/en.json +48 -0
- package/l10n/nl.json +48 -0
- package/package.json +3 -2
- package/scripts/manifest-schema-hash.js +41 -0
- package/scripts/record-manifest-schema-hash.js +52 -0
- package/src/components/CnAdminActionCard/CnAdminActionCard.vue +234 -0
- package/src/components/CnAdminActionCard/index.js +4 -0
- package/src/components/CnAppNav/CnAppNav.vue +394 -27
- package/src/components/CnAppRoot/CnAppRoot.vue +129 -15
- package/src/components/CnBannerWidget/CnBannerWidget.vue +113 -2
- package/src/components/CnBrandStripe/CnBrandStripe.md +16 -0
- package/src/components/CnBrandStripe/CnBrandStripe.vue +58 -5
- package/src/components/CnChoiceCards/CnChoiceCards.vue +56 -31
- package/src/components/CnDashboardPage/CnDashboardPage.vue +32 -8
- package/src/components/CnDataTable/CnColumnFilterPopover.vue +524 -0
- package/src/components/CnDataTable/CnDataTable.md +4 -1
- package/src/components/CnDataTable/CnDataTable.vue +302 -21
- 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/CnIndexPage/CnIndexPage.vue +55 -2
- package/src/components/CnIndexPage/selfModeActions.js +3 -3
- package/src/components/CnLinkCardsPage/CnLinkCardsPage.vue +35 -2
- package/src/components/CnObjectListWidget/CnObjectListWidget.vue +39 -1
- package/src/components/CnObjectSidebar/CnFilesTab.vue +65 -0
- package/src/components/CnReportsPage/CnReportsPage.vue +7 -0
- package/src/components/CnResourceSelect/CnResourceSelect.vue +123 -12
- package/src/components/CnSetupWizard/CnSetupWizard.vue +392 -3
- package/src/components/CnStorePage/CnStorePage.vue +7 -0
- 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/CnWikiPage/CnWikiPage.vue +7 -0
- 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 +19 -0
- package/src/css/table.css +82 -2
- package/src/index.js +2 -0
- package/src/public/index.js +5 -0
- package/src/schemas/app-manifest-v2.schema.json +23 -1
- 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/timelineEvents.js +171 -0
- package/src/utils/validateManifestV2.compiled.js +2 -2
- package/src/utils/walkthroughSignals.js +94 -0
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
import axios__default from '@nextcloud/axios';
|
|
2
|
-
import { translate } from '@nextcloud/l10n';
|
|
2
|
+
import { translate, translatePlural } from '@nextcloud/l10n';
|
|
3
3
|
import { generateUrl } from '@nextcloud/router';
|
|
4
4
|
import { NcLoadingIcon, NcCheckboxRadioSwitch } from '@nextcloud/vue';
|
|
5
|
+
import FilterIcon from 'vue-material-design-icons/Filter.vue';
|
|
6
|
+
import FilterOutline from 'vue-material-design-icons/FilterOutline.vue';
|
|
7
|
+
import __sfc_main$1 from './CnColumnFilterPopover.vue.js';
|
|
5
8
|
import { useClickDragGuard } from '../../composables/useClickDragGuard.js';
|
|
9
|
+
import { columnFilterDef, columnFilterState, isColumnFilterActive, columnFilterParams, clearedColumnFilterParams, isColumnSortable } from '../../utils/columnFilters.js';
|
|
6
10
|
import { resolveHref, openRowTarget, followLinkClick } from '../../utils/linkNavigation.js';
|
|
7
11
|
import { nextSortState } from '../../utils/multiColumnSort.js';
|
|
8
12
|
import { preventMiddleClickAutoscroll, isRowMiddleClick, isNewTabHandled, markNewTabHandled, isNewTabClick } from '../../utils/rowAuxClick.js';
|
|
9
13
|
import { DEFAULT_ROW_INDICATOR_CAP, resolveRowIndicators } from '../../utils/rowIndicators.js';
|
|
10
14
|
import { columnsFromSchema } from '../../utils/schema.js';
|
|
11
15
|
import __sfc_main from '../CnCellRenderer/CnCellRenderer.vue.js';
|
|
12
|
-
import __sfc_main$
|
|
13
|
-
import __sfc_main$
|
|
16
|
+
import __sfc_main$2 from '../CnIcon/CnIcon.vue.js';
|
|
17
|
+
import __sfc_main$3 from '../CnLockIndicator/CnLockIndicator.vue.js';
|
|
14
18
|
|
|
15
19
|
/**
|
|
16
20
|
* CnDataTable — Generic sortable data table for list views.
|
|
@@ -20,15 +24,12 @@ import __sfc_main$2 from '../CnLockIndicator/CnLockIndicator.vue.js';
|
|
|
20
24
|
* row selection, custom cell rendering via scoped slots, loading states,
|
|
21
25
|
* and empty states.
|
|
22
26
|
*
|
|
23
|
-
* Sorting: a plain click on a sortable header is single-sort (cycle asc →
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* event payload is extended, not replaced: `{key, order}` still mirrors the
|
|
30
|
-
* primary key exactly as before; a new `keys` field carries the full
|
|
31
|
-
* ordered list. See `src/utils/multiColumnSort.js` for the state machine.
|
|
27
|
+
* Sorting: a plain click on a sortable header is single-sort (cycle asc → desc → cleared), unchanged from before.
|
|
28
|
+
* Shift+click (or Shift+Enter on a focused header) appends the column as a secondary/tertiary sort key, capped at 3, with numbered priority badges (1, 2, 3) once two or more rendered, sortable columns are sorted.
|
|
29
|
+
* A sort key whose column is not rendered, or not sortable, still sorts, but is not counted or numbered.
|
|
30
|
+
* Pass `sortKeys: [{key, order}, ...]` for multi-sort (falls back to the legacy `sortKey`/`sortOrder` props when empty).
|
|
31
|
+
* The `sort` event payload is extended, not replaced: `{key, order}` still mirrors the primary key exactly as before; a new `keys` field carries the full ordered list.
|
|
32
|
+
* See `src/utils/multiColumnSort.js` for the state machine.
|
|
32
33
|
*
|
|
33
34
|
* When a `schema` prop is provided, columns are auto-generated from schema
|
|
34
35
|
* properties and cells render through CnCellRenderer for type-aware formatting
|
|
@@ -71,8 +72,11 @@ var script = {
|
|
|
71
72
|
NcLoadingIcon,
|
|
72
73
|
NcCheckboxRadioSwitch,
|
|
73
74
|
CnCellRenderer: __sfc_main,
|
|
74
|
-
|
|
75
|
-
|
|
75
|
+
CnColumnFilterPopover: __sfc_main$1,
|
|
76
|
+
CnIcon: __sfc_main$2,
|
|
77
|
+
CnLockIndicator: __sfc_main$3,
|
|
78
|
+
FilterIcon,
|
|
79
|
+
FilterOutline,
|
|
76
80
|
},
|
|
77
81
|
|
|
78
82
|
inject: {
|
|
@@ -441,9 +445,39 @@ var script = {
|
|
|
441
445
|
type: Boolean,
|
|
442
446
|
default: false,
|
|
443
447
|
},
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* Show a filter button in every header whose column can filter (see
|
|
451
|
+
* `columnFilterDef`): enum, boolean, text, number, date and reference
|
|
452
|
+
* columns backed by a schema property. A column opts out with
|
|
453
|
+
* `filterable: false`. Applying a filter emits `column-filter`; the
|
|
454
|
+
* host owns the filter state and passes it back as `activeFilters`.
|
|
455
|
+
*
|
|
456
|
+
* @spec openspec/changes/table-header-sort-and-filter/specs/cn-data-table/spec.md#requirement-every-backed-column-filters-from-its-header
|
|
457
|
+
*/
|
|
458
|
+
filterable: {
|
|
459
|
+
type: Boolean,
|
|
460
|
+
default: false,
|
|
461
|
+
},
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* The active filter map, `{ paramKey: values[] }`: the same map the
|
|
465
|
+
* facet sidebar writes, so a header filter and a sidebar filter on one
|
|
466
|
+
* field show the same state.
|
|
467
|
+
*/
|
|
468
|
+
activeFilters: {
|
|
469
|
+
type: Object,
|
|
470
|
+
default: () => ({}),
|
|
471
|
+
},
|
|
472
|
+
|
|
473
|
+
/** Register slug a reference column's filter searches in when the column names none. */
|
|
474
|
+
filterRegister: {
|
|
475
|
+
type: String,
|
|
476
|
+
default: '',
|
|
477
|
+
},
|
|
444
478
|
},
|
|
445
479
|
|
|
446
|
-
emits: ['row-click', 'row-aux-click', 'row-context-menu', 'select', 'select-all', 'sort', 'view-all'],
|
|
480
|
+
emits: ['row-click', 'row-aux-click', 'row-context-menu', 'select', 'select-all', 'sort', 'view-all', 'column-filter'],
|
|
447
481
|
|
|
448
482
|
setup() {
|
|
449
483
|
// Tell a deliberate row click apart from a text-selection drag.
|
|
@@ -452,6 +486,10 @@ var script = {
|
|
|
452
486
|
|
|
453
487
|
data() {
|
|
454
488
|
return {
|
|
489
|
+
/** Key of the column whose filter panel is open, or ''. */
|
|
490
|
+
openFilterKey: '',
|
|
491
|
+
/** The open filter button's bounding rect, to place the panel. */
|
|
492
|
+
filterAnchorRect: null,
|
|
455
493
|
/**
|
|
456
494
|
* Resolved aggregate-column values, keyed by `String(row[rowKey])`
|
|
457
495
|
* then by column key. Populated by `loadAggregates()` for columns
|
|
@@ -569,8 +607,12 @@ var script = {
|
|
|
569
607
|
overrides: this.columnOverrides,
|
|
570
608
|
})
|
|
571
609
|
: this.columns;
|
|
610
|
+
// Every column backed by a schema property sorts unless it says
|
|
611
|
+
// `sortable: false`; object columns from a manifest used to need an
|
|
612
|
+
// explicit flag and so could not sort at all.
|
|
613
|
+
const withSort = (c) => (c && typeof c === 'object' ? { ...c, sortable: isColumnSortable(c, this.schema) } : c);
|
|
572
614
|
if (!(cols || []).some((c) => typeof c === 'string')) {
|
|
573
|
-
return cols || []
|
|
615
|
+
return (cols || []).map(withSort)
|
|
574
616
|
}
|
|
575
617
|
const schemaCols = this.schema
|
|
576
618
|
? columnsFromSchema(this.schema, { overrides: this.columnOverrides })
|
|
@@ -578,7 +620,7 @@ var script = {
|
|
|
578
620
|
const byKey = new Map(schemaCols.map((c) => [c.key, c]));
|
|
579
621
|
return (cols || []).map((c) => {
|
|
580
622
|
if (typeof c !== 'string') {
|
|
581
|
-
return c
|
|
623
|
+
return withSort(c)
|
|
582
624
|
}
|
|
583
625
|
return byKey.get(c) || { key: c, label: c, sortable: true }
|
|
584
626
|
})
|
|
@@ -619,6 +661,40 @@ var script = {
|
|
|
619
661
|
return links
|
|
620
662
|
},
|
|
621
663
|
|
|
664
|
+
/**
|
|
665
|
+
* The column whose filter panel is open, or null.
|
|
666
|
+
*
|
|
667
|
+
* @return {object|null}
|
|
668
|
+
*/
|
|
669
|
+
openFilterColumn() {
|
|
670
|
+
if (!this.openFilterKey) {
|
|
671
|
+
return null
|
|
672
|
+
}
|
|
673
|
+
return this.effectiveColumns.find((c) => c && c.key === this.openFilterKey && this.filterDefFor(c)) || null
|
|
674
|
+
},
|
|
675
|
+
|
|
676
|
+
/**
|
|
677
|
+
* One chip per column with an active header filter.
|
|
678
|
+
*
|
|
679
|
+
* @return {Array<{key: string, col: object, text: string, removeLabel: string}>}
|
|
680
|
+
*/
|
|
681
|
+
activeColumnFilterChips() {
|
|
682
|
+
if (!this.filterable) {
|
|
683
|
+
return []
|
|
684
|
+
}
|
|
685
|
+
return this.effectiveColumns
|
|
686
|
+
.filter((c) => c && this.isColumnFiltered(c))
|
|
687
|
+
.map((col) => {
|
|
688
|
+
const label = this.translateLabel(col.label);
|
|
689
|
+
const text = translate('nextcloud-vue', '{column}: {value}', { column: label, value: this.columnFilterSummary(col) });
|
|
690
|
+
return { key: col.key, col, text, removeLabel: translate('nextcloud-vue', 'Remove filter {column}', { column: label }) }
|
|
691
|
+
})
|
|
692
|
+
},
|
|
693
|
+
|
|
694
|
+
activeFiltersLabel() {
|
|
695
|
+
return translate('nextcloud-vue', 'Active filters')
|
|
696
|
+
},
|
|
697
|
+
|
|
622
698
|
effectiveSortKeys() {
|
|
623
699
|
if (this.sortKeys && this.sortKeys.length > 0) {
|
|
624
700
|
return this.sortKeys
|
|
@@ -629,6 +705,23 @@ var script = {
|
|
|
629
705
|
return []
|
|
630
706
|
},
|
|
631
707
|
|
|
708
|
+
/**
|
|
709
|
+
* The active sort keys whose column renders a sort indicator, in priority order and deduplicated by first occurrence. Only these are counted and numbered by the priority badge.
|
|
710
|
+
*
|
|
711
|
+
* @return {Array<{key: string, order: 'asc'|'desc'}>}
|
|
712
|
+
*/
|
|
713
|
+
renderedSortKeys() {
|
|
714
|
+
const shown = new Set(this.effectiveColumns.filter((c) => c && c.sortable).map((c) => c.key));
|
|
715
|
+
const seen = new Set();
|
|
716
|
+
return this.effectiveSortKeys.filter((k) => {
|
|
717
|
+
if (!k || !shown.has(k.key) || seen.has(k.key)) {
|
|
718
|
+
return false
|
|
719
|
+
}
|
|
720
|
+
seen.add(k.key);
|
|
721
|
+
return true
|
|
722
|
+
})
|
|
723
|
+
},
|
|
724
|
+
|
|
632
725
|
totalColumns() {
|
|
633
726
|
let count = this.effectiveColumns.length;
|
|
634
727
|
if (this.selectable) {
|
|
@@ -1224,7 +1317,7 @@ var script = {
|
|
|
1224
1317
|
|
|
1225
1318
|
/**
|
|
1226
1319
|
* Index of `key` within `effectiveSortKeys`, or -1 when not active.
|
|
1227
|
-
* Used by the template for the arrow
|
|
1320
|
+
* Used by the template for the arrow.
|
|
1228
1321
|
*
|
|
1229
1322
|
* @param {string} key Column key.
|
|
1230
1323
|
* @return {number}
|
|
@@ -1234,11 +1327,22 @@ var script = {
|
|
|
1234
1327
|
},
|
|
1235
1328
|
|
|
1236
1329
|
/**
|
|
1237
|
-
*
|
|
1238
|
-
*
|
|
1239
|
-
*
|
|
1240
|
-
*
|
|
1241
|
-
|
|
1330
|
+
* The 1-based priority badge for `key` among the rendered sort keys, or null when fewer than two rendered columns are sorted or `key` is not one of them.
|
|
1331
|
+
*
|
|
1332
|
+
* @param {string} key Column key.
|
|
1333
|
+
* @return {number|null}
|
|
1334
|
+
*/
|
|
1335
|
+
sortBadgeFor(key) {
|
|
1336
|
+
if (this.renderedSortKeys.length < 2) {
|
|
1337
|
+
return null
|
|
1338
|
+
}
|
|
1339
|
+
const index = this.renderedSortKeys.findIndex((k) => k.key === key);
|
|
1340
|
+
return index === -1 ? null : index + 1
|
|
1341
|
+
},
|
|
1342
|
+
|
|
1343
|
+
/**
|
|
1344
|
+
* `aria-sort` value for a column header: `'ascending'`/`'descending'` for the PRIMARY (index 0) active sort key only, per WCAG guidance that `aria-sort` describes single-column sort state.
|
|
1345
|
+
* `null` omits the attribute entirely (unsorted, not sortable, or not the primary key).
|
|
1242
1346
|
*
|
|
1243
1347
|
* @param {object} col Column definition.
|
|
1244
1348
|
* @return {string|null}
|
|
@@ -1262,6 +1366,135 @@ var script = {
|
|
|
1262
1366
|
* @param {string} key Column key.
|
|
1263
1367
|
* @param {MouseEvent} [event] The originating click event.
|
|
1264
1368
|
*/
|
|
1369
|
+
/**
|
|
1370
|
+
* The filter definition for a column, or null when it does not filter
|
|
1371
|
+
* (header filters off, `filterable: false`, or nothing to filter on).
|
|
1372
|
+
*
|
|
1373
|
+
* @param {object} col The column.
|
|
1374
|
+
* @return {object|null}
|
|
1375
|
+
*/
|
|
1376
|
+
filterDefFor(col) {
|
|
1377
|
+
if (!this.filterable || !col) {
|
|
1378
|
+
return null
|
|
1379
|
+
}
|
|
1380
|
+
return columnFilterDef(col, this.schema)
|
|
1381
|
+
},
|
|
1382
|
+
|
|
1383
|
+
columnFilterStateFor(col) {
|
|
1384
|
+
return columnFilterState(this.filterDefFor(col), this.activeFilters)
|
|
1385
|
+
},
|
|
1386
|
+
|
|
1387
|
+
isColumnFiltered(col) {
|
|
1388
|
+
const def = this.filterDefFor(col);
|
|
1389
|
+
return !!def && isColumnFilterActive(def, this.activeFilters)
|
|
1390
|
+
},
|
|
1391
|
+
|
|
1392
|
+
filterButtonLabel(col) {
|
|
1393
|
+
const column = this.translateLabel(col.label);
|
|
1394
|
+
return this.isColumnFiltered(col)
|
|
1395
|
+
? translate('nextcloud-vue', 'Filter {column}, active', { column })
|
|
1396
|
+
: translate('nextcloud-vue', 'Filter {column}', { column })
|
|
1397
|
+
},
|
|
1398
|
+
|
|
1399
|
+
/**
|
|
1400
|
+
* Short text for an active filter: the picked labels, or the range.
|
|
1401
|
+
*
|
|
1402
|
+
* @param {object} col The column.
|
|
1403
|
+
* @return {string}
|
|
1404
|
+
*/
|
|
1405
|
+
columnFilterSummary(col) {
|
|
1406
|
+
const def = this.filterDefFor(col);
|
|
1407
|
+
const state = this.columnFilterStateFor(col);
|
|
1408
|
+
if (!def) {
|
|
1409
|
+
return ''
|
|
1410
|
+
}
|
|
1411
|
+
if (def.kind === 'enum') {
|
|
1412
|
+
const labels = Object.fromEntries((def.options || []).map((o) => [o.value, o.label]));
|
|
1413
|
+
return state.values.map((v) => this.translateLabel(labels[v] || v)).join(', ')
|
|
1414
|
+
}
|
|
1415
|
+
if (def.kind === 'reference') {
|
|
1416
|
+
return translatePlural('nextcloud-vue', '{count} selected', '{count} selected', state.values.length, { count: state.values.length })
|
|
1417
|
+
}
|
|
1418
|
+
if (def.kind === 'number' || def.kind === 'date') {
|
|
1419
|
+
if (state.from && state.to) {
|
|
1420
|
+
return translate('nextcloud-vue', '{from} to {to}', { from: state.from, to: state.to })
|
|
1421
|
+
}
|
|
1422
|
+
return state.from
|
|
1423
|
+
? translate('nextcloud-vue', 'from {value}', { value: state.from })
|
|
1424
|
+
: translate('nextcloud-vue', 'up to {value}', { value: state.to })
|
|
1425
|
+
}
|
|
1426
|
+
if (def.kind === 'boolean') {
|
|
1427
|
+
return state.value === 'true' ? translate('nextcloud-vue', 'Yes') : translate('nextcloud-vue', 'No')
|
|
1428
|
+
}
|
|
1429
|
+
return state.value
|
|
1430
|
+
},
|
|
1431
|
+
|
|
1432
|
+
/**
|
|
1433
|
+
* Open or close a column's filter panel under its button.
|
|
1434
|
+
*
|
|
1435
|
+
* @param {object} col The column.
|
|
1436
|
+
* @param {Event} event The click.
|
|
1437
|
+
* @return {void}
|
|
1438
|
+
*/
|
|
1439
|
+
toggleColumnFilter(col, event) {
|
|
1440
|
+
if (this.openFilterKey === col.key) {
|
|
1441
|
+
this.closeColumnFilter();
|
|
1442
|
+
return
|
|
1443
|
+
}
|
|
1444
|
+
const target = event && event.currentTarget;
|
|
1445
|
+
this.filterAnchorRect = target && typeof target.getBoundingClientRect === 'function'
|
|
1446
|
+
? target.getBoundingClientRect()
|
|
1447
|
+
: null;
|
|
1448
|
+
this.openFilterKey = col.key;
|
|
1449
|
+
},
|
|
1450
|
+
|
|
1451
|
+
/**
|
|
1452
|
+
* Close the open panel and give focus back to its button.
|
|
1453
|
+
*
|
|
1454
|
+
* @return {void}
|
|
1455
|
+
*/
|
|
1456
|
+
closeColumnFilter() {
|
|
1457
|
+
const key = this.openFilterKey;
|
|
1458
|
+
this.openFilterKey = '';
|
|
1459
|
+
if (!key) {
|
|
1460
|
+
return
|
|
1461
|
+
}
|
|
1462
|
+
this.$nextTick(() => {
|
|
1463
|
+
const ref = this.$refs['filterButton-' + key];
|
|
1464
|
+
const button = Array.isArray(ref) ? ref[0] : ref;
|
|
1465
|
+
if (button && typeof button.focus === 'function') {
|
|
1466
|
+
button.focus();
|
|
1467
|
+
}
|
|
1468
|
+
});
|
|
1469
|
+
},
|
|
1470
|
+
|
|
1471
|
+
/**
|
|
1472
|
+
* Apply a panel's state: emit the query parameters it stands for.
|
|
1473
|
+
*
|
|
1474
|
+
* @param {object} col The column.
|
|
1475
|
+
* @param {object} state The panel state.
|
|
1476
|
+
* @return {void}
|
|
1477
|
+
* @spec openspec/changes/table-header-sort-and-filter/specs/cn-data-table/spec.md#requirement-a-header-filter-speaks-the-sidebars-query-language
|
|
1478
|
+
*/
|
|
1479
|
+
applyColumnFilter(col, state) {
|
|
1480
|
+
const def = this.filterDefFor(col);
|
|
1481
|
+
if (def) {
|
|
1482
|
+
/**
|
|
1483
|
+
* @event column-filter A header filter was applied or cleared.
|
|
1484
|
+
* @type {{ key: string, params: object }} `params` maps each query parameter the column owns to its values; an empty list clears it.
|
|
1485
|
+
*/
|
|
1486
|
+
this.$emit('column-filter', { key: col.key, params: columnFilterParams(def, state) });
|
|
1487
|
+
}
|
|
1488
|
+
this.closeColumnFilter();
|
|
1489
|
+
},
|
|
1490
|
+
|
|
1491
|
+
clearColumnFilter(col) {
|
|
1492
|
+
const def = this.filterDefFor(col);
|
|
1493
|
+
if (def) {
|
|
1494
|
+
this.$emit('column-filter', { key: col.key, params: clearedColumnFilterParams(def) });
|
|
1495
|
+
}
|
|
1496
|
+
},
|
|
1497
|
+
|
|
1265
1498
|
onHeaderClick(key, event) {
|
|
1266
1499
|
this.applySort(key, !!(event && event.shiftKey));
|
|
1267
1500
|
},
|