@conduction/nextcloud-vue 2.142.0 → 2.144.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/CnActionDialog/CnActionDialog.vue.js +1 -1
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue2.js +7 -2
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue3.js.map +1 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue.js +1 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js +27 -0
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js.map +1 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js +1 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js.map +1 -1
- package/dist/esm/components/CnAiCompanion/CnAiChatPanel.vue2.js.map +1 -1
- package/dist/esm/components/CnAiCompanion/CnAiChatPanel.vue3.js +2 -1
- package/dist/esm/components/CnAiCompanion/CnAiChatPanel.vue3.js.map +1 -1
- package/dist/esm/components/CnAiCompanion/CnAiInput.vue2.js +9 -0
- package/dist/esm/components/CnAiCompanion/CnAiInput.vue2.js.map +1 -1
- package/dist/esm/components/CnAiCompanion/CnAiInput.vue3.js +21 -22
- package/dist/esm/components/CnAiCompanion/CnAiInput.vue3.js.map +1 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue.js +1 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js +29 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js.map +1 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue3.js +28 -13
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue3.js.map +1 -1
- package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue.js +1 -1
- package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue3.js +2 -1
- package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnChecklistRunWidget/CnChecklistRunWidget.vue.js +1 -1
- package/dist/esm/components/CnChecklistRunWidget/CnChecklistRunWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnChecklistRunWidget/CnChecklistRunWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue.js +1 -1
- package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue2.js.map +1 -1
- package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue3.js.map +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue.js +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue2.js.map +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue3.js +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue.js +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/CnEventsCard/CnEventsCard.vue.js +1 -1
- package/dist/esm/components/CnEventsCard/CnEventsCard.vue2.js +9 -0
- package/dist/esm/components/CnEventsCard/CnEventsCard.vue2.js.map +1 -1
- package/dist/esm/components/CnEventsCard/CnEventsCard.vue3.js +24 -13
- package/dist/esm/components/CnEventsCard/CnEventsCard.vue3.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue.js +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +29 -3
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +4 -2
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/filesBrowser.js +17 -4
- package/dist/esm/components/CnFilesBrowser/filesBrowser.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/filesBrowserColumns.js +21 -1
- package/dist/esm/components/CnFilesBrowser/filesBrowserColumns.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +18 -2
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnNotesCard/CnNotesCard.vue.js +1 -1
- package/dist/esm/components/CnNotesCard/CnNotesCard.vue2.js +3 -0
- package/dist/esm/components/CnNotesCard/CnNotesCard.vue2.js.map +1 -1
- package/dist/esm/components/CnNotesCard/CnNotesCard.vue3.js +19 -14
- package/dist/esm/components/CnNotesCard/CnNotesCard.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectPartiesWidget/CnObjectPartiesWidget.vue.js +1 -1
- package/dist/esm/components/CnObjectPartiesWidget/CnObjectPartiesWidget.vue2.js +30 -0
- package/dist/esm/components/CnObjectPartiesWidget/CnObjectPartiesWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectPartiesWidget/CnObjectPartiesWidget.vue3.js +158 -102
- package/dist/esm/components/CnObjectPartiesWidget/CnObjectPartiesWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnPageHeader/CnHeaderTrail.vue2.js +6 -1
- package/dist/esm/components/CnPageHeader/CnHeaderTrail.vue2.js.map +1 -1
- package/dist/esm/components/CnPageHeader/CnHeaderTrail.vue3.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +12 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js +2 -2
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnRetentionWidget/CnRetentionWidget.vue.js +1 -1
- package/dist/esm/components/CnRetentionWidget/CnRetentionWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnRetentionWidget/CnRetentionWidget.vue3.js +12 -0
- package/dist/esm/components/CnRetentionWidget/CnRetentionWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue.js +1 -1
- package/dist/esm/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue.js +1 -1
- package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue2.js +110 -2
- package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue3.js +146 -80
- package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue.js +1 -1
- package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue2.js +4 -0
- package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue2.js.map +1 -1
- package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue3.js +18 -8
- package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/calendar/CnCalendarCard.vue.js +1 -1
- package/dist/esm/integrations/builtin/calendar/CnCalendarCard.vue2.js +45 -0
- package/dist/esm/integrations/builtin/calendar/CnCalendarCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/calendar/CnCalendarCard.vue3.js +67 -34
- package/dist/esm/integrations/builtin/calendar/CnCalendarCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/calendar/CnCalendarTab.vue.js +1 -1
- package/dist/esm/integrations/builtin/calendar/CnCalendarTab.vue2.js +3 -22
- package/dist/esm/integrations/builtin/calendar/CnCalendarTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/calendar/CnCalendarTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/calendar/eventStatus.js +67 -0
- package/dist/esm/integrations/builtin/calendar/eventStatus.js.map +1 -0
- package/dist/esm/integrations/builtin/deck/CnDeckCard.vue.js +1 -1
- package/dist/esm/integrations/builtin/deck/CnDeckCard.vue2.js +39 -0
- package/dist/esm/integrations/builtin/deck/CnDeckCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/deck/CnDeckCard.vue3.js +81 -32
- package/dist/esm/integrations/builtin/deck/CnDeckCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/deck/CnDeckTab.vue.js +1 -1
- package/dist/esm/integrations/builtin/deck/CnDeckTab.vue2.js +5 -6
- package/dist/esm/integrations/builtin/deck/CnDeckTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/deck/CnDeckTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/deck/deckCardParts.js +59 -0
- package/dist/esm/integrations/builtin/deck/deckCardParts.js.map +1 -0
- package/dist/esm/l10n/en.json.js +6 -0
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +7 -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 +1264 -597
- package/dist/esm/utils/fetchFilterCounts.js +5 -2
- package/dist/esm/utils/fetchFilterCounts.js.map +1 -1
- package/dist/esm/utils/nextcloudDirectory.js +19 -6
- package/dist/esm/utils/nextcloudDirectory.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +1619 -849
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +1264 -597
- package/l10n/en.json +6 -0
- package/l10n/nl.json +7 -1
- package/package.json +1 -1
- package/src/components/CnActionDialog/CnActionDialog.vue +28 -3
- package/src/components/CnAdminSettingsShell/CnAdminSettingsShell.vue +28 -1
- package/src/components/CnAiCompanion/CnAiChatPanel.vue +12 -0
- package/src/components/CnAiCompanion/CnAiInput.vue +32 -1
- package/src/components/CnAuditTrailCard/CnAuditTrailCard.vue +34 -4
- package/src/components/CnAuditTrailWidget/CnAuditTrailWidget.vue +1 -0
- package/src/components/CnChecklistRunWidget/CnChecklistRunWidget.vue +8 -0
- package/src/components/CnChoiceCards/CnChoiceCards.vue +1 -0
- package/src/components/CnConversationThread/CnConversationThread.vue +5 -2
- package/src/components/CnDetailWidgetHost/CnDetailWidgetHost.vue +1 -0
- package/src/components/CnEventsCard/CnEventsCard.vue +27 -5
- package/src/components/CnFilesBrowser/CnFilesBrowser.vue +43 -4
- package/src/components/CnFilesBrowser/filesBrowser.js +17 -4
- package/src/components/CnFilesBrowser/filesBrowserColumns.js +20 -1
- package/src/components/CnIndexPage/CnIndexPage.vue +18 -2
- package/src/components/CnNotesCard/CnNotesCard.vue +8 -0
- package/src/components/CnObjectPartiesWidget/CnObjectPartiesWidget.vue +114 -46
- package/src/components/CnPageHeader/CnHeaderTrail.vue +6 -1
- package/src/components/CnRecordListWidget/CnRecordListWidget.vue +21 -1
- package/src/components/CnRetentionWidget/CnRetentionWidget.vue +26 -1
- package/src/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue +6 -0
- package/src/components/CnTasksWidget/CnTasksWidget.vue +170 -13
- package/src/components/CnTimelineWidget/CnTimelineManage.vue +10 -1
- package/src/css/dialog.css +25 -1
- package/src/css/kpi-card.css +3 -0
- package/src/css/look-board-detail.css +348 -0
- package/src/css/look-board-index.css +56 -1
- package/src/css/look-board.css +98 -1
- package/src/integrations/builtin/calendar/CnCalendarCard.vue +76 -11
- package/src/integrations/builtin/calendar/CnCalendarTab.vue +3 -22
- package/src/integrations/builtin/calendar/__tests__/CnCalendarCardBoardRows.spec.js +52 -0
- package/src/integrations/builtin/calendar/eventStatus.js +63 -0
- package/src/integrations/builtin/deck/CnDeckCard.vue +66 -0
- package/src/integrations/builtin/deck/CnDeckTab.vue +5 -6
- package/src/integrations/builtin/deck/__tests__/CnDeckCardBoardRows.spec.js +49 -0
- package/src/integrations/builtin/deck/deckCardParts.js +56 -0
- package/src/utils/fetchFilterCounts.js +5 -2
- package/src/utils/nextcloudDirectory.js +19 -6
|
@@ -47,17 +47,42 @@
|
|
|
47
47
|
<table v-else class="cn-tasks-widget__table" data-testid="cn-tasks-widget-table">
|
|
48
48
|
<thead>
|
|
49
49
|
<tr>
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
50
|
+
<!-- `content.sortable` / `content.filterable`: a head sorts by its
|
|
51
|
+
column and filters on its values (DqZaakTaken). -->
|
|
52
|
+
<th v-for="column in headColumns"
|
|
53
|
+
:key="column.key"
|
|
54
|
+
scope="col"
|
|
55
|
+
:aria-sort="headSort.key === column.key ? (headSort.dir === 'asc' ? 'ascending' : 'descending') : null"
|
|
56
|
+
:data-testid="`cn-tasks-widget-head-${column.key}`">
|
|
57
|
+
<span v-if="content.sortable === true || content.filterable === true" class="cn-tasks-widget__head">
|
|
58
|
+
<button v-if="content.sortable === true"
|
|
59
|
+
type="button"
|
|
60
|
+
class="cn-tasks-widget__head-sort"
|
|
61
|
+
:data-testid="`cn-tasks-widget-sort-${column.key}`"
|
|
62
|
+
@click="sortBy(column.key)">
|
|
63
|
+
{{ column.label }}
|
|
64
|
+
<ChevronUp v-if="headSort.key === column.key && headSort.dir === 'asc'" :size="14" />
|
|
65
|
+
<ChevronDown v-else :size="14" />
|
|
66
|
+
</button>
|
|
67
|
+
<template v-else>{{ column.label }}</template>
|
|
68
|
+
<NcActions v-if="content.filterable === true"
|
|
69
|
+
class="cn-tasks-widget__head-filter"
|
|
70
|
+
:aria-label="tr('Filter by {column}').replace('{column}', column.label)"
|
|
71
|
+
:data-testid="`cn-tasks-widget-filter-${column.key}`">
|
|
72
|
+
<template #icon>
|
|
73
|
+
<FilterOutline :size="14" />
|
|
74
|
+
</template>
|
|
75
|
+
<NcActionCheckbox v-for="option in headOptions(column.key)"
|
|
76
|
+
:key="option.value"
|
|
77
|
+
:modelValue="(headFilters[column.key] || []).includes(option.value)"
|
|
78
|
+
@update:modelValue="toggleHeadFilter(column.key, option.value)">
|
|
79
|
+
{{ option.label }}
|
|
80
|
+
</NcActionCheckbox>
|
|
81
|
+
</NcActions>
|
|
82
|
+
</span>
|
|
83
|
+
<template v-else>
|
|
84
|
+
{{ column.label }}
|
|
85
|
+
</template>
|
|
61
86
|
</th>
|
|
62
87
|
<th scope="col">
|
|
63
88
|
<span class="hidden-visually">{{ tr('Task actions') }}</span>
|
|
@@ -375,10 +400,13 @@ import axios from '@nextcloud/axios'
|
|
|
375
400
|
import { showError, showSuccess } from '@nextcloud/dialogs'
|
|
376
401
|
import { translate as t } from '@nextcloud/l10n'
|
|
377
402
|
import { generateUrl } from '@nextcloud/router'
|
|
378
|
-
import { NcActionButton, NcActions, NcAvatar, NcButton, NcLoadingIcon, NcTextField } from '@nextcloud/vue'
|
|
403
|
+
import { NcActionButton, NcActionCheckbox, NcActions, NcAvatar, NcButton, NcLoadingIcon, NcTextField } from '@nextcloud/vue'
|
|
379
404
|
import { inject, ref } from 'vue'
|
|
380
405
|
import CheckCircle from 'vue-material-design-icons/CheckCircle.vue'
|
|
406
|
+
import ChevronDown from 'vue-material-design-icons/ChevronDown.vue'
|
|
407
|
+
import ChevronUp from 'vue-material-design-icons/ChevronUp.vue'
|
|
381
408
|
import CircleOutline from 'vue-material-design-icons/CircleOutline.vue'
|
|
409
|
+
import FilterOutline from 'vue-material-design-icons/FilterOutline.vue'
|
|
382
410
|
import CnStatusBadge from '../CnStatusBadge/CnStatusBadge.vue'
|
|
383
411
|
import CnTaskFormDialog from '../CnTaskFormDialog/CnTaskFormDialog.vue'
|
|
384
412
|
import CnTaskWorkCard from './CnTaskWorkCard.vue'
|
|
@@ -458,12 +486,16 @@ export default {
|
|
|
458
486
|
|
|
459
487
|
components: {
|
|
460
488
|
CheckCircle,
|
|
489
|
+
ChevronDown,
|
|
490
|
+
ChevronUp,
|
|
461
491
|
CircleOutline,
|
|
462
492
|
CnStatusBadge,
|
|
463
493
|
CnTaskFormDialog,
|
|
464
494
|
CnTaskWorkCard,
|
|
495
|
+
FilterOutline,
|
|
465
496
|
NcActions,
|
|
466
497
|
NcActionButton,
|
|
498
|
+
NcActionCheckbox,
|
|
467
499
|
NcAvatar,
|
|
468
500
|
NcButton,
|
|
469
501
|
NcLoadingIcon,
|
|
@@ -618,6 +650,10 @@ export default {
|
|
|
618
650
|
data() {
|
|
619
651
|
return {
|
|
620
652
|
pollTimer: null,
|
|
653
|
+
/** The table's head sort, `{ key, dir }`; no key keeps open tasks first. */
|
|
654
|
+
headSort: { key: '', dir: 'asc' },
|
|
655
|
+
/** The table's head filters, `{ column: values[] }`. */
|
|
656
|
+
headFilters: {},
|
|
621
657
|
/** Uuids of the tasks a checkbox is completing, until the next read. */
|
|
622
658
|
completing: [],
|
|
623
659
|
/** Whether the table's create form is open. */
|
|
@@ -777,7 +813,26 @@ export default {
|
|
|
777
813
|
* @spec openspec/changes/record-task-table/specs/record-task-table/spec.md#requirement-a-records-tasks-show-as-a-table-with-their-summary-and-new-task-in-the-header
|
|
778
814
|
*/
|
|
779
815
|
tableRows() {
|
|
780
|
-
|
|
816
|
+
const kept = this.rows.filter((task) => Object.entries(this.headFilters).every(([key, values]) => values.length === 0 || values.includes(this.headValue(task, key))))
|
|
817
|
+
if (this.headSort.key) {
|
|
818
|
+
const dir = this.headSort.dir === 'desc' ? -1 : 1
|
|
819
|
+
return [...kept].sort((a, b) => {
|
|
820
|
+
const x = this.headSortValue(a, this.headSort.key)
|
|
821
|
+
const y = this.headSortValue(b, this.headSort.key)
|
|
822
|
+
return (x < y ? -1 : (x > y ? 1 : 0)) * dir
|
|
823
|
+
})
|
|
824
|
+
}
|
|
825
|
+
return [...kept.filter((task) => task.isTerminal !== true), ...kept.filter((task) => task.isTerminal === true)]
|
|
826
|
+
},
|
|
827
|
+
|
|
828
|
+
/** @return {Array<{key: string, label: string}>} The table's data columns. */
|
|
829
|
+
headColumns() {
|
|
830
|
+
return [
|
|
831
|
+
{ key: 'title', label: this.tr('Task') },
|
|
832
|
+
{ key: 'handler', label: this.tr('Handler') },
|
|
833
|
+
{ key: 'due', label: this.tr('Task deadline') },
|
|
834
|
+
{ key: 'state', label: this.tr('Status') },
|
|
835
|
+
]
|
|
781
836
|
},
|
|
782
837
|
|
|
783
838
|
/**
|
|
@@ -1158,6 +1213,84 @@ export default {
|
|
|
1158
1213
|
* @param {object} task The task row.
|
|
1159
1214
|
* @return {string} The name.
|
|
1160
1215
|
*/
|
|
1216
|
+
/**
|
|
1217
|
+
* A row's value in a column, as a head filter keeps it.
|
|
1218
|
+
*
|
|
1219
|
+
* @param {object} task The task row.
|
|
1220
|
+
* @param {string} key The column.
|
|
1221
|
+
* @return {string}
|
|
1222
|
+
*/
|
|
1223
|
+
headValue(task, key) {
|
|
1224
|
+
if (key === 'title') {
|
|
1225
|
+
return this.titleOf(task)
|
|
1226
|
+
}
|
|
1227
|
+
if (key === 'handler') {
|
|
1228
|
+
return String(task.assignee || '')
|
|
1229
|
+
}
|
|
1230
|
+
if (key === 'due') {
|
|
1231
|
+
return this.content.dueFormat === 'date' ? this.dueDate(task) : this.dueLabel(task)
|
|
1232
|
+
}
|
|
1233
|
+
return String(task.state || '')
|
|
1234
|
+
},
|
|
1235
|
+
|
|
1236
|
+
/**
|
|
1237
|
+
* A row's value in a column, as its head sorts it: the deadline by date.
|
|
1238
|
+
*
|
|
1239
|
+
* @param {object} task The task row.
|
|
1240
|
+
* @param {string} key The column.
|
|
1241
|
+
* @return {string|number}
|
|
1242
|
+
*/
|
|
1243
|
+
headSortValue(task, key) {
|
|
1244
|
+
if (key === 'due') {
|
|
1245
|
+
const time = Date.parse(task.dueAt || task.dueDate || '')
|
|
1246
|
+
return Number.isNaN(time) ? Number.POSITIVE_INFINITY : time
|
|
1247
|
+
}
|
|
1248
|
+
if (key === 'handler') {
|
|
1249
|
+
return this.handlerName(task).toLowerCase()
|
|
1250
|
+
}
|
|
1251
|
+
if (key === 'state') {
|
|
1252
|
+
return this.stateLabel(task).toLowerCase()
|
|
1253
|
+
}
|
|
1254
|
+
return this.titleOf(task).toLowerCase()
|
|
1255
|
+
},
|
|
1256
|
+
|
|
1257
|
+
/**
|
|
1258
|
+
* The values a column's head filter offers, one per value the rows hold.
|
|
1259
|
+
*
|
|
1260
|
+
* @param {string} key The column.
|
|
1261
|
+
* @return {Array<{value: string, label: string}>}
|
|
1262
|
+
*/
|
|
1263
|
+
headOptions(key) {
|
|
1264
|
+
const seen = new Map()
|
|
1265
|
+
for (const task of this.rows) {
|
|
1266
|
+
const value = this.headValue(task, key)
|
|
1267
|
+
if (value !== '' && !seen.has(value)) {
|
|
1268
|
+
seen.set(value, key === 'handler' ? this.handlerName(task) : (key === 'state' ? this.stateLabel(task) : value))
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
return [...seen].map(([value, label]) => ({ value, label }))
|
|
1272
|
+
},
|
|
1273
|
+
|
|
1274
|
+
/**
|
|
1275
|
+
* Sort by a column: ascending first, then descending.
|
|
1276
|
+
*
|
|
1277
|
+
* @param {string} key The column.
|
|
1278
|
+
*/
|
|
1279
|
+
sortBy(key) {
|
|
1280
|
+
this.headSort = this.headSort.key === key && this.headSort.dir === 'asc' ? { key, dir: 'desc' } : { key, dir: 'asc' }
|
|
1281
|
+
},
|
|
1282
|
+
|
|
1283
|
+
/**
|
|
1284
|
+
* Keep or drop one value of a column's head filter.
|
|
1285
|
+
*
|
|
1286
|
+
* @param {string} key The column.
|
|
1287
|
+
* @param {string} value The value.
|
|
1288
|
+
*/
|
|
1289
|
+
toggleHeadFilter(key, value) {
|
|
1290
|
+
const current = this.headFilters[key] || []
|
|
1291
|
+
this.headFilters = { ...this.headFilters, [key]: current.includes(value) ? current.filter((v) => v !== value) : [...current, value] }
|
|
1292
|
+
},
|
|
1293
|
+
|
|
1161
1294
|
handlerName(task) {
|
|
1162
1295
|
return userDisplayName(task.assignee) || String(task.assignee || '')
|
|
1163
1296
|
},
|
|
@@ -1594,6 +1727,30 @@ function recordUuid(configured, objectId) {
|
|
|
1594
1727
|
font-size: 14px;
|
|
1595
1728
|
}
|
|
1596
1729
|
|
|
1730
|
+
.cn-tasks-widget__head {
|
|
1731
|
+
display: inline-flex;
|
|
1732
|
+
align-items: center;
|
|
1733
|
+
gap: 4px;
|
|
1734
|
+
}
|
|
1735
|
+
|
|
1736
|
+
.cn-tasks-widget__head-sort {
|
|
1737
|
+
display: inline-flex;
|
|
1738
|
+
align-items: center;
|
|
1739
|
+
gap: 4px;
|
|
1740
|
+
min-height: 0;
|
|
1741
|
+
margin: 0;
|
|
1742
|
+
padding: 0;
|
|
1743
|
+
border: 0;
|
|
1744
|
+
background: transparent;
|
|
1745
|
+
color: inherit;
|
|
1746
|
+
font: inherit;
|
|
1747
|
+
cursor: pointer;
|
|
1748
|
+
}
|
|
1749
|
+
|
|
1750
|
+
.cn-tasks-widget__head-filter {
|
|
1751
|
+
--button-size: 22px;
|
|
1752
|
+
}
|
|
1753
|
+
|
|
1597
1754
|
.cn-tasks-widget__table th {
|
|
1598
1755
|
padding: 12px 16px;
|
|
1599
1756
|
background: color-mix(in srgb, var(--color-background-hover) 40%, var(--color-main-background));
|
|
@@ -199,13 +199,18 @@
|
|
|
199
199
|
{{ t('nextcloud-vue', 'Goes on the timeline above, internal unless you make it visible') }}
|
|
200
200
|
</p>
|
|
201
201
|
</template>
|
|
202
|
+
<label v-if="textBlocks.length" class="cn-timeline-manage__draft-label" :for="blockId">
|
|
203
|
+
{{ t('nextcloud-vue', 'Template') }}
|
|
204
|
+
</label>
|
|
202
205
|
<NcSelect v-if="textBlocks.length"
|
|
203
206
|
v-model="chosenBlock"
|
|
204
207
|
class="cn-timeline-manage__filter"
|
|
205
208
|
:options="blockOptions"
|
|
206
209
|
:clearable="true"
|
|
207
210
|
label="label"
|
|
208
|
-
:
|
|
211
|
+
:inputId="blockId"
|
|
212
|
+
:labelOutside="true"
|
|
213
|
+
:ariaLabelCombobox="t('nextcloud-vue', 'Template')"
|
|
209
214
|
:placeholder="t('nextcloud-vue', 'Write your own')"
|
|
210
215
|
data-testid="cn-timeline-block"
|
|
211
216
|
@update:modelValue="pickBlock" />
|
|
@@ -437,6 +442,10 @@ export default {
|
|
|
437
442
|
return `cn-timeline-draft-${this.uid}`
|
|
438
443
|
},
|
|
439
444
|
|
|
445
|
+
blockId() {
|
|
446
|
+
return `cn-timeline-block-${this.uid}`
|
|
447
|
+
},
|
|
448
|
+
|
|
440
449
|
/**
|
|
441
450
|
* The kind options, the plain note first. A note is an entry with NO
|
|
442
451
|
* kind, so "Note" filters on its absence.
|
package/src/css/dialog.css
CHANGED
|
@@ -168,13 +168,22 @@ body:has(.cn-look-board):not(:has(.cn-look-nextcloud)) .modal-mask {
|
|
|
168
168
|
goes to those tokens too (DqOverdragen, DqDocumentGenereren). */
|
|
169
169
|
.cn-dialog-header__subtitle {
|
|
170
170
|
--nldesign-component-paragraph-font-size: 14px;
|
|
171
|
+
--nldesign-component-paragraph-line-height: 1.5;
|
|
171
172
|
--nldesign-component-paragraph-color: var(--color-text-maxcontrast);
|
|
172
173
|
--nldesign-color-on-surface: var(--color-text-maxcontrast);
|
|
173
174
|
margin: 4px 0 0;
|
|
174
175
|
font-size: 14px;
|
|
176
|
+
line-height: 1.5;
|
|
175
177
|
color: var(--color-text-maxcontrast);
|
|
176
178
|
}
|
|
177
179
|
|
|
180
|
+
/* The saved-view edit and share forms start 22px under the subtitle, as
|
|
181
|
+
the Dq dialog boards draw a first field: the body's 16px gap and 6px. */
|
|
182
|
+
.cn-dialog-board .dialog__content .cn-edit-view,
|
|
183
|
+
.cn-dialog-board .dialog__content .cn-share-view {
|
|
184
|
+
padding-top: 6px;
|
|
185
|
+
}
|
|
186
|
+
|
|
178
187
|
/* The close button is a 36px circle. NcButton sizes an icon-only button by
|
|
179
188
|
--button-size with `!important`, so the size goes through that; the radius
|
|
180
189
|
also goes to the nldesign theme's button radius token. */
|
|
@@ -207,9 +216,15 @@ body:has(.cn-look-board):not(:has(.cn-look-nextcloud)) .modal-mask {
|
|
|
207
216
|
/* A choice card with a checkbox (CnAssignDialog's toggles) is as tight as
|
|
208
217
|
the board draws it (DqOverdragen, 76px for a label and a two-line note):
|
|
209
218
|
10px 14px padding, the checkbox row at the 24px minimum target instead of
|
|
210
|
-
NcCheckboxRadioSwitch's 34px, the note at 1.2 line height
|
|
219
|
+
NcCheckboxRadioSwitch's 34px, the note at 1.2 line height; the card's
|
|
220
|
+
corners 8px and the label on an 18px line, as the board draws them. */
|
|
211
221
|
.cn-dialog-board .cn-assign-dialog__toggle {
|
|
212
222
|
padding: 10px 14px;
|
|
223
|
+
border-radius: 8px;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.cn-dialog-board .cn-assign-dialog__toggle .checkbox-content__text {
|
|
227
|
+
line-height: 18px;
|
|
213
228
|
}
|
|
214
229
|
|
|
215
230
|
.cn-dialog-board .cn-assign-dialog__toggle .checkbox-radio-switch-checkbox .checkbox-content,
|
|
@@ -539,6 +554,15 @@ body:has(.cn-look-board):not(:has(.cn-look-nextcloud)) .modal-mask {
|
|
|
539
554
|
}
|
|
540
555
|
}
|
|
541
556
|
|
|
557
|
+
/* A choice legend in a board dialog is 14px/600 on the normal line height, as
|
|
558
|
+
the dialog boards draw it (DqDocumentGenereren "Sjabloon").
|
|
559
|
+
@spec openspec/changes/board-choice-legend-type/specs/board-choice-legend-type/spec.md#requirement-a-board-dialogs-choice-legend-is-14px-600-on-the-normal-line-height */
|
|
560
|
+
.cn-dialog-board .cn-choice-cards__legend {
|
|
561
|
+
font-size: 14px;
|
|
562
|
+
font-weight: 600;
|
|
563
|
+
line-height: normal;
|
|
564
|
+
}
|
|
565
|
+
|
|
542
566
|
/* Above a phone the boards top-align a dialog (DqNieuweZaak, DqUwWachtrij,
|
|
543
567
|
DqVolgendeStap: the top edge sits about 90px down at 1440 wide) instead of
|
|
544
568
|
centring it. `--cn-dialog-top` moves it. */
|
package/src/css/kpi-card.css
CHANGED
|
@@ -547,6 +547,9 @@ a.cn-kpi-card--board * {
|
|
|
547
547
|
.cn-kpi-card--board.cn-kpi-card--stacked:has(.cn-kpi-card__title--badge-end) {
|
|
548
548
|
--cn-kpi-stacked-padding: 20px 22px;
|
|
549
549
|
--cn-kpi-stacked-gap: 8px;
|
|
550
|
+
/* Its label is set at 600, as every board draws this tile (DqDashboard,
|
|
551
|
+
DqMijnTeam, DqPersoonlijkeInstellingen); the plain stacked tile keeps 400. */
|
|
552
|
+
--cn-kpi-stacked-title-weight: 600;
|
|
550
553
|
}
|
|
551
554
|
|
|
552
555
|
.cn-kpi-card--board.cn-kpi-card--stacked:has(.cn-kpi-card__title--badge-end) .cn-kpi-card__value {
|