@conduction/nextcloud-vue 2.92.0 → 2.94.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/CnActionsMenu/CnActionsMenu.vue2.js +1 -1
- package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue2.js.map +1 -1
- package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue3.js +2 -1
- package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue3.js.map +1 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue.js +1 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js +28 -8
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js.map +1 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js +37 -2
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js.map +1 -1
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js +57 -4
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js.map +1 -1
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js +44 -17
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js.map +1 -1
- package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue.js +1 -1
- package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue2.js +44 -2
- package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue2.js.map +1 -1
- package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue3.js +140 -59
- package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue3.js.map +1 -1
- package/dist/esm/components/CnCountdownWidget/CnCountdownWidget.vue.js +1 -1
- package/dist/esm/components/CnCountdownWidget/CnCountdownWidget.vue2.js +139 -3
- package/dist/esm/components/CnCountdownWidget/CnCountdownWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnCountdownWidget/CnCountdownWidget.vue3.js +60 -12
- package/dist/esm/components/CnCountdownWidget/CnCountdownWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue.js +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +111 -42
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +117 -73
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +34 -39
- package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue3.js +7 -7
- package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +5 -3
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue.js +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js +6 -4
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnFeaturesAndRoadmapPage/CnFeaturesAndRoadmapPage.vue2.js +46 -0
- package/dist/esm/components/CnFeaturesAndRoadmapPage/CnFeaturesAndRoadmapPage.vue2.js.map +1 -1
- package/dist/esm/components/CnFeaturesAndRoadmapPage/CnFeaturesAndRoadmapPage.vue3.js +6 -2
- package/dist/esm/components/CnFeaturesAndRoadmapPage/CnFeaturesAndRoadmapPage.vue3.js.map +1 -1
- package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue.js +1 -1
- package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue2.js +82 -9
- package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue2.js.map +1 -1
- package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue3.js +104 -90
- package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue3.js.map +1 -1
- package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue.js +9 -0
- package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue.js.map +1 -0
- package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue2.js +355 -0
- package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue2.js.map +1 -0
- package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue3.js +462 -0
- package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue3.js.map +1 -0
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue.js +1 -1
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js +21 -0
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue3.js +402 -391
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue3.js.map +1 -1
- package/dist/esm/components/CnIcon/semanticIcons.js +2 -2
- package/dist/esm/components/CnIcon/semanticIcons.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +141 -7
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +5 -2
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue.js +1 -1
- package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue2.js +22 -1
- package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue3.js +20 -14
- package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnNotificationPreferences/CnNotificationPreferences.vue.js +1 -1
- package/dist/esm/components/CnNotificationPreferences/CnNotificationPreferences.vue2.js +2 -0
- package/dist/esm/components/CnNotificationPreferences/CnNotificationPreferences.vue2.js.map +1 -1
- package/dist/esm/components/CnNotificationPreferences/CnNotificationPreferences.vue3.js +15 -5
- package/dist/esm/components/CnNotificationPreferences/CnNotificationPreferences.vue3.js.map +1 -1
- package/dist/esm/components/CnPageHeader/CnHeaderTrail.vue.js +8 -0
- package/dist/esm/components/CnPageHeader/CnHeaderTrail.vue.js.map +1 -0
- package/dist/esm/components/CnPageHeader/CnHeaderTrail.vue2.js +114 -0
- package/dist/esm/components/CnPageHeader/CnHeaderTrail.vue2.js.map +1 -0
- package/dist/esm/components/CnPageHeader/CnHeaderTrail.vue3.js +45 -0
- package/dist/esm/components/CnPageHeader/CnHeaderTrail.vue3.js.map +1 -0
- package/dist/esm/components/CnPageHeader/CnPageHeader.vue2.js +38 -2
- package/dist/esm/components/CnPageHeader/CnPageHeader.vue2.js.map +1 -1
- package/dist/esm/components/CnPageHeader/CnPageHeader.vue3.js +12 -2
- package/dist/esm/components/CnPageHeader/CnPageHeader.vue3.js.map +1 -1
- package/dist/esm/components/CnPagination/CnPagination.vue2.js.map +1 -1
- package/dist/esm/components/CnPagination/CnPagination.vue3.js +56 -51
- package/dist/esm/components/CnPagination/CnPagination.vue3.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +3 -3
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnRoadmapTab/CnRoadmapTab.vue.js +1 -1
- package/dist/esm/components/CnRoadmapTab/CnRoadmapTab.vue2.js +8 -30
- package/dist/esm/components/CnRoadmapTab/CnRoadmapTab.vue2.js.map +1 -1
- package/dist/esm/components/CnRoadmapTab/CnRoadmapTab.vue3.js.map +1 -1
- package/dist/esm/components/CnSettingsPage/CnSettingsPage.vue.js +1 -1
- package/dist/esm/components/CnSettingsPage/CnSettingsPage.vue2.js +24 -0
- package/dist/esm/components/CnSettingsPage/CnSettingsPage.vue2.js.map +1 -1
- package/dist/esm/components/CnSettingsPage/CnSettingsPage.vue3.js +3 -1
- package/dist/esm/components/CnSettingsPage/CnSettingsPage.vue3.js.map +1 -1
- package/dist/esm/components/CnTabs/CnTabs.vue.js +1 -1
- package/dist/esm/components/CnTabs/CnTabs.vue2.js +39 -2
- package/dist/esm/components/CnTabs/CnTabs.vue2.js.map +1 -1
- package/dist/esm/components/CnTabs/CnTabs.vue3.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue.js +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +85 -8
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js +37 -9
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnUserSettingsDialog/CnUserSettingsDialog.vue.js +9 -0
- package/dist/esm/components/CnUserSettingsDialog/CnUserSettingsDialog.vue.js.map +1 -0
- package/dist/esm/components/CnUserSettingsDialog/CnUserSettingsDialog.vue2.js +164 -0
- package/dist/esm/components/CnUserSettingsDialog/CnUserSettingsDialog.vue2.js.map +1 -0
- package/dist/esm/components/CnUserSettingsDialog/CnUserSettingsDialog.vue3.js +93 -0
- package/dist/esm/components/CnUserSettingsDialog/CnUserSettingsDialog.vue3.js.map +1 -0
- package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue.js +1 -1
- package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue2.js.map +1 -1
- package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue3.js +4 -3
- package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue3.js.map +1 -1
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue.js +1 -1
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue2.js +32 -0
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue2.js.map +1 -1
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue3.js +31 -20
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue3.js.map +1 -1
- package/dist/esm/composables/indexSources.js +9 -0
- package/dist/esm/composables/indexSources.js.map +1 -1
- package/dist/esm/l10n/en.json.js +24 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +24 -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 +1190 -410
- package/dist/esm/utils/dueText.js +49 -8
- package/dist/esm/utils/dueText.js.map +1 -1
- package/dist/esm/utils/featureCatalog.js +135 -0
- package/dist/esm/utils/featureCatalog.js.map +1 -0
- package/dist/esm/utils/fillTemplate.js +74 -3
- package/dist/esm/utils/fillTemplate.js.map +1 -1
- package/dist/esm/utils/headerMeta.js +62 -12
- package/dist/esm/utils/headerMeta.js.map +1 -1
- package/dist/esm/utils/roadmapIssues.js +86 -0
- package/dist/esm/utils/roadmapIssues.js.map +1 -0
- package/dist/esm/utils/userDisplayName.js +47 -0
- package/dist/esm/utils/userDisplayName.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 +16229 -13423
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +1190 -410
- package/l10n/en.json +24 -1
- package/l10n/nl.json +24 -1
- package/package.json +1 -1
- package/src/components/CnActionsMenu/CnActionsMenu.vue +3 -1
- package/src/components/CnAdminSettingsShell/CnAdminSettingsShell.vue +39 -1
- package/src/components/CnAppRoot/CnAppRoot.md +2 -0
- package/src/components/CnAppRoot/CnAppRoot.vue +66 -5
- package/src/components/CnChoiceCards/CnChoiceCards.md +27 -0
- package/src/components/CnChoiceCards/CnChoiceCards.vue +168 -3
- package/src/components/CnCountdownWidget/CnCountdownWidget.vue +222 -6
- package/src/components/CnDashboardPage/CnDashboardPage.vue +141 -8
- package/src/components/CnDataTable/CnDataTable.md +1 -0
- package/src/components/CnDataTable/CnDataTable.vue +41 -46
- package/src/components/CnDetailPage/CnDetailPage.vue +5 -3
- package/src/components/CnFactsWidget/CnFactsWidget.vue +6 -4
- package/src/components/CnFeaturesAndRoadmapPage/CnFeaturesAndRoadmapPage.vue +51 -1
- package/src/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue +98 -13
- package/src/components/CnFeaturesBoard/CnFeaturesBoard.vue +1053 -0
- package/src/components/CnFormDialog/CnFormDialog.vue +606 -562
- package/src/components/CnIndexPage/CnIndexPage.vue +144 -7
- package/src/components/CnNcWidgetWidget/CnNcWidgetWidget.vue +23 -2
- package/src/components/CnNotificationPreferences/CnNotificationPreferences.vue +5 -0
- package/src/components/CnPageHeader/CnHeaderTrail.vue +140 -0
- package/src/components/CnPageHeader/CnPageHeader.md +11 -0
- package/src/components/CnPageHeader/CnPageHeader.vue +42 -0
- package/src/components/CnPagination/CnPagination.vue +10 -2
- package/src/components/CnRecordListWidget/CnRecordListWidget.vue +3 -3
- package/src/components/CnRoadmapTab/CnRoadmapTab.vue +6 -28
- package/src/components/CnSettingsPage/CnSettingsPage.vue +26 -0
- package/src/components/CnTabs/CnTabs.vue +39 -2
- package/src/components/CnTabsWidget/CnTabsWidget.vue +106 -13
- package/src/components/CnUserSettingsDialog/CnUserSettingsDialog.vue +305 -0
- package/src/components/CnVersionInfoCard/CnVersionInfoCard.vue +4 -3
- package/src/components/CnWidgetWrapper/CnWidgetWrapper.md +8 -0
- package/src/components/CnWidgetWrapper/CnWidgetWrapper.vue +43 -2
- package/src/composables/indexSources.js +9 -0
- package/src/css/dialog.css +61 -0
- package/src/css/look-board-detail.css +8 -0
- package/src/css/look-board-index.css +27 -1
- package/src/css/look-board.css +60 -0
- package/src/css/page-header.css +16 -0
- package/src/schemas/app-manifest-v2.schema.json +30 -17
- package/src/utils/dueText.js +49 -8
- package/src/utils/featureCatalog.js +132 -0
- package/src/utils/fillTemplate.js +73 -2
- package/src/utils/headerMeta.js +62 -12
- package/src/utils/roadmapIssues.js +82 -0
- package/src/utils/userDisplayName.js +54 -0
- package/src/utils/validateManifestV2.compiled.js +3 -3
|
@@ -130,7 +130,7 @@
|
|
|
130
130
|
col.class || '',
|
|
131
131
|
pinClass(leadingCount + colIndex),
|
|
132
132
|
isGrowColumn(col) ? 'cn-table-col--grow' : '',
|
|
133
|
-
colIndex ===
|
|
133
|
+
colIndex === titleColumnIndex ? 'cn-table-head--title' : '',
|
|
134
134
|
]"
|
|
135
135
|
:style="{ ...(col.width ? { width: col.width } : {}), ...pinStyle(leadingCount + colIndex) }"
|
|
136
136
|
:aria-sort="ariaSortFor(col)"
|
|
@@ -259,7 +259,7 @@
|
|
|
259
259
|
<td
|
|
260
260
|
v-for="(col, colIndex) in effectiveColumns"
|
|
261
261
|
:key="col.key"
|
|
262
|
-
:class="[col.class || '', col.cellClass || '', cellClass ? cellClass(row, col) : '', pinClass(leadingCount + colIndex), colIndex ===
|
|
262
|
+
:class="[col.class || '', col.cellClass || '', cellClass ? cellClass(row, col) : '', pinClass(leadingCount + colIndex), colIndex === titleColumnIndex ? 'cn-table-col--title' : '', isGrowColumn(col) ? 'cn-table-col--grow' : '']"
|
|
263
263
|
:style="{ ...(col.width ? { maxWidth: col.width } : {}), ...pinStyle(leadingCount + colIndex) }"
|
|
264
264
|
@mouseenter="titleWhenClipped">
|
|
265
265
|
<!-- A row with a `rowClickRoute` is a real link: this anchor
|
|
@@ -267,7 +267,7 @@
|
|
|
267
267
|
the URL, a middle or ctrl click opens a new tab natively,
|
|
268
268
|
and the row is reachable with Tab. The row's own click
|
|
269
269
|
handlers treat it as a nested control and leave it be. -->
|
|
270
|
-
<a v-if="colIndex ===
|
|
270
|
+
<a v-if="colIndex === titleColumnIndex && rowLinks[String(row[rowKey])]"
|
|
271
271
|
class="cn-table-row__link"
|
|
272
272
|
:href="rowLinks[String(row[rowKey])].href"
|
|
273
273
|
:aria-label="rowLinkLabel(row, col)"
|
|
@@ -281,9 +281,9 @@
|
|
|
281
281
|
the record is locked. It renders nothing when unlocked,
|
|
282
282
|
so an unlocked table is byte-for-byte what it was. -->
|
|
283
283
|
<CnUnreadMarker
|
|
284
|
-
v-if="colIndex ===
|
|
284
|
+
v-if="colIndex === titleColumnIndex && isUnreadRow(row)" />
|
|
285
285
|
<CnLockIndicator
|
|
286
|
-
v-if="colIndex ===
|
|
286
|
+
v-if="colIndex === titleColumnIndex"
|
|
287
287
|
:object="row"
|
|
288
288
|
:size="16" />
|
|
289
289
|
<!-- Declared state indicators ride the first data cell
|
|
@@ -293,7 +293,7 @@
|
|
|
293
293
|
however the record is shaped. Past the cap the rest move
|
|
294
294
|
into the row menu, because a row of nine icons is not a
|
|
295
295
|
row anyone can triage at a glance. -->
|
|
296
|
-
<span v-if="colIndex ===
|
|
296
|
+
<span v-if="colIndex === titleColumnIndex && indicatorsFor(row).shown.length > 0"
|
|
297
297
|
class="cn-table-row-indicators"
|
|
298
298
|
data-testid="cn-row-indicators">
|
|
299
299
|
<span v-for="indicator in indicatorsFor(row).shown"
|
|
@@ -338,7 +338,7 @@
|
|
|
338
338
|
file names it (OpenRegister `@self.matchedFile`): plain text,
|
|
339
339
|
file name only, under the first cell. -->
|
|
340
340
|
<span
|
|
341
|
-
v-if="colIndex ===
|
|
341
|
+
v-if="colIndex === titleColumnIndex && matchedFileOf(row)"
|
|
342
342
|
class="cn-table-cell__secondary cn-table-cell__matched-file"
|
|
343
343
|
data-testid="cn-row-matched-file">{{ matchedFileLabel(row) }}</span>
|
|
344
344
|
</td>
|
|
@@ -404,7 +404,7 @@ import CnColumnFilterPopover from './CnColumnFilterPopover.vue'
|
|
|
404
404
|
import { useClickDragGuard } from '../../composables/useClickDragGuard.js'
|
|
405
405
|
import { normalizeLook } from '../../composables/useLook.js'
|
|
406
406
|
import { clearedColumnFilterParams, columnFilterDef, columnFilterParams, columnFilterState, isColumnFilterActive, isColumnSortable } from '../../utils/columnFilters.js'
|
|
407
|
-
import { fillTemplate } from '../../utils/fillTemplate.js'
|
|
407
|
+
import { fillTemplate, joinTemplateParts } from '../../utils/fillTemplate.js'
|
|
408
408
|
import { lensUnavailableText, readLensReports } from '../../utils/lensAvailability.js'
|
|
409
409
|
import { followLinkClick, openRowTarget, resolveHref } from '../../utils/linkNavigation.js'
|
|
410
410
|
import { nextSortState } from '../../utils/multiColumnSort.js'
|
|
@@ -421,40 +421,6 @@ import { CnUnreadMarker } from '../CnUnreadMarker/index.js'
|
|
|
421
421
|
// consuming app does not pull in the library's global css/index.css.
|
|
422
422
|
import '../../css/table.css'
|
|
423
423
|
|
|
424
|
-
/**
|
|
425
|
-
* Fill a `secondary` template such as `"{identifier} · {requester}"`.
|
|
426
|
-
*
|
|
427
|
-
* A field without a value takes its separator with it: the text between two
|
|
428
|
-
* fields belongs to the field after it, so an empty requester leaves
|
|
429
|
-
* "2026-0002", not "2026-0002 ·", and an empty first field does not leave a
|
|
430
|
-
* leading separator either. Text before the first field and after the last
|
|
431
|
-
* one is kept as written. A template whose fields all have values fills
|
|
432
|
-
* exactly as before.
|
|
433
|
-
*
|
|
434
|
-
* @spec openspec/changes/zuiddrecht-pixel-gaps-3/specs/zuiddrecht-pixel-gaps-3/spec.md#requirement-an-empty-field-takes-its-separator-with-it
|
|
435
|
-
* @param {string} template The template, with `{field}` placeholders.
|
|
436
|
-
* @param {(key: string) => string} valueOf The text of a field ('' when empty).
|
|
437
|
-
* @return {string} The filled template.
|
|
438
|
-
*/
|
|
439
|
-
function fillSecondaryTemplate(template, valueOf) {
|
|
440
|
-
// split() with a capture group alternates literal, field, literal, …
|
|
441
|
-
const parts = template.split(/\{([^}]+)\}/)
|
|
442
|
-
const lead = parts[0]
|
|
443
|
-
const tail = parts[parts.length - 1]
|
|
444
|
-
let body = ''
|
|
445
|
-
for (let i = 1; i < parts.length; i += 2) {
|
|
446
|
-
const value = valueOf(parts[i].trim())
|
|
447
|
-
if (value === '') {
|
|
448
|
-
continue
|
|
449
|
-
}
|
|
450
|
-
// The literal before this field: the separator, unless nothing has
|
|
451
|
-
// been written yet (then there is nothing to separate from).
|
|
452
|
-
const separator = i === 1 ? '' : parts[i - 1]
|
|
453
|
-
body += (body === '' ? '' : separator) + value
|
|
454
|
-
}
|
|
455
|
-
return lead + body + tail
|
|
456
|
-
}
|
|
457
|
-
|
|
458
424
|
/**
|
|
459
425
|
* CnDataTable — Generic sortable data table for list views.
|
|
460
426
|
*
|
|
@@ -566,7 +532,10 @@ export default {
|
|
|
566
532
|
* formats through `fillTemplate`), or a function of the row. Empty fields leave their placeholder blank; a line that
|
|
567
533
|
* resolves to nothing is not drawn.
|
|
568
534
|
*
|
|
569
|
-
*
|
|
535
|
+
* `link: true` makes that column the one that names the row: it carries
|
|
536
|
+
* the row link and the title look. Without it the first column does.
|
|
537
|
+
*
|
|
538
|
+
* @type {Array<{key: string, label: string, description: string, sortable: boolean, width: string, class: string, cellClass: string, link: boolean, secondary: (string|((row: object) => string))}|string>}
|
|
570
539
|
*/
|
|
571
540
|
columns: {
|
|
572
541
|
type: Array,
|
|
@@ -776,6 +745,17 @@ export default {
|
|
|
776
745
|
default: '',
|
|
777
746
|
},
|
|
778
747
|
|
|
748
|
+
/**
|
|
749
|
+
* Draw an unread record (`@self.unread`) in bold with the unread dot.
|
|
750
|
+
* Off, every row reads alike whatever its read state.
|
|
751
|
+
*
|
|
752
|
+
* @spec openspec/changes/screens-index-board-gaps/specs/index-list-board-look/spec.md#requirement-unread-rows-are-marked-only-where-the-reader-asked-for-them
|
|
753
|
+
*/
|
|
754
|
+
showUnread: {
|
|
755
|
+
type: Boolean,
|
|
756
|
+
default: true,
|
|
757
|
+
},
|
|
758
|
+
|
|
779
759
|
/**
|
|
780
760
|
* How the board look draws the title column: `link` (the default) is
|
|
781
761
|
* the 15px weight 600 underlined title of the DqZaken board; `plain` is
|
|
@@ -1079,6 +1059,20 @@ export default {
|
|
|
1079
1059
|
* @return {string|null} The column key, or null when not fitting.
|
|
1080
1060
|
* @spec openspec/changes/narrow-object-table-widgets/specs/narrow-object-table-widgets/spec.md#requirement-a-narrow-object-table-keeps-its-trailing-columns-in-view
|
|
1081
1061
|
*/
|
|
1062
|
+
/**
|
|
1063
|
+
* The column that names the row: it carries the row link, the title
|
|
1064
|
+
* look and the unread, lock and indicator marks. The first column with
|
|
1065
|
+
* `link: true`, else the first column (DqTeamwachtrij puts the waiting
|
|
1066
|
+
* time first and links the case title in the second).
|
|
1067
|
+
*
|
|
1068
|
+
* @return {number} The index in `effectiveColumns`.
|
|
1069
|
+
* @spec openspec/changes/screens-index-board-gaps/specs/index-list-board-look/spec.md#requirement-a-column-can-carry-the-row-link
|
|
1070
|
+
*/
|
|
1071
|
+
titleColumnIndex() {
|
|
1072
|
+
const index = this.effectiveColumns.findIndex((c) => c && c.link === true)
|
|
1073
|
+
return index === -1 ? 0 : index
|
|
1074
|
+
},
|
|
1075
|
+
|
|
1082
1076
|
growColumnKey() {
|
|
1083
1077
|
if (!this.fitWidth || this.effectiveColumns.length === 0) {
|
|
1084
1078
|
return null
|
|
@@ -1399,13 +1393,14 @@ export default {
|
|
|
1399
1393
|
|
|
1400
1394
|
/**
|
|
1401
1395
|
* Whether a row's record changed since the user last looked
|
|
1402
|
-
* (`@self.unread`). A row without the marker
|
|
1396
|
+
* (`@self.unread`), when `showUnread` is on. A row without the marker
|
|
1397
|
+
* renders as it always did.
|
|
1403
1398
|
*
|
|
1404
1399
|
* @param {object} row The row.
|
|
1405
1400
|
* @return {boolean} True when the row is unread.
|
|
1406
1401
|
*/
|
|
1407
1402
|
isUnreadRow(row) {
|
|
1408
|
-
return !!(row && row['@self'] && row['@self'].unread === true)
|
|
1403
|
+
return this.showUnread && !!(row && row['@self'] && row['@self'].unread === true)
|
|
1409
1404
|
},
|
|
1410
1405
|
|
|
1411
1406
|
/**
|
|
@@ -1790,7 +1785,7 @@ export default {
|
|
|
1790
1785
|
return ''
|
|
1791
1786
|
}
|
|
1792
1787
|
if (spec.includes('{')) {
|
|
1793
|
-
const filled =
|
|
1788
|
+
const filled = joinTemplateParts(spec, (key) => (key.includes('|')
|
|
1794
1789
|
? fillTemplate(`{${key}}`, row)
|
|
1795
1790
|
: this.secondaryFieldText(row, key)))
|
|
1796
1791
|
// A template whose every field is empty leaves only separators:
|
|
@@ -2631,8 +2631,10 @@ export default {
|
|
|
2631
2631
|
/**
|
|
2632
2632
|
* The meta line on row 2 of the board look's header (manifest
|
|
2633
2633
|
* `config.headerMeta`): a field template such as `"via {channel}"`.
|
|
2634
|
-
* Every `{path}` is read from the record
|
|
2635
|
-
*
|
|
2634
|
+
* Every `{path}` is read from the record (an enum field as its label);
|
|
2635
|
+
* `{path|format}` formats it (`weekday`, `longdate`, `time`, `user`,
|
|
2636
|
+
* `currency:EUR`, ...). An empty token drops itself and its separator;
|
|
2637
|
+
* a line with no value at all is dropped. Only the board look draws it.
|
|
2636
2638
|
*
|
|
2637
2639
|
* @spec openspec/changes/screens-detail-page-parity/specs/detail-page-board-look/spec.md#requirement-the-detail-header-is-two-rows-on-the-ground
|
|
2638
2640
|
*/
|
|
@@ -2991,7 +2993,7 @@ export default {
|
|
|
2991
2993
|
* @spec openspec/changes/screens-detail-page-parity/specs/detail-page-board-look/spec.md#requirement-the-detail-header-is-two-rows-on-the-ground
|
|
2992
2994
|
*/
|
|
2993
2995
|
headerMetaText() {
|
|
2994
|
-
return resolveHeaderMeta(this.headerMeta ? this.effectiveTranslate(this.headerMeta) : '', this.resolvedObject)
|
|
2996
|
+
return resolveHeaderMeta(this.headerMeta ? this.effectiveTranslate(this.headerMeta) : '', this.resolvedObject, { schema: this.currentSchema, translate: this.effectiveTranslate })
|
|
2995
2997
|
},
|
|
2996
2998
|
|
|
2997
2999
|
/**
|
|
@@ -257,7 +257,7 @@ export default {
|
|
|
257
257
|
/**
|
|
258
258
|
* The widget configuration.
|
|
259
259
|
*
|
|
260
|
-
* - `fields` — the entries, in order. Each is `{ path, label?, as?, format?, map?, itemPath?, parts?, separator?, route?, variant?, variantMap?, colorMap?, icon?, copy?, reveal?, text?, title?, subtitle?, initialsPath?, tone? }`.
|
|
260
|
+
* - `fields` — the entries, in order. Each is `{ path, label?, as?, from?, format?, map?, itemPath?, parts?, separator?, route?, variant?, variantMap?, colorMap?, icon?, copy?, reveal?, text?, title?, subtitle?, initialsPath?, tone? }`.
|
|
261
261
|
* `as` is `row` (default when `label` or `icon` is set), `title`, `line`, `text` (a line in the normal ink), `lead` (an icon tile or initials beside `title` and `subtitle`) or `pill`.
|
|
262
262
|
* A row's `format` may also be `email`, `phone` or `url` (a link) or `masked` (the last four characters; `reveal: true` adds Show). `copy: true` adds a copy button; `icon` replaces the label.
|
|
263
263
|
* A part may be `{ text }`, a constant; a `line` or `text` entry without `path` or `parts` shows its `text`.
|
|
@@ -265,7 +265,7 @@ export default {
|
|
|
265
265
|
* - `action` — an action drawn as a button under the facts; `headerAction` — one drawn in the card header (reported through the `header` event).
|
|
266
266
|
* `format` is `text` (default), `date` (board short date), `date-long` (always with the year), `list` (an array joined by ", ", each item read at `itemPath`) or `currency` (a money amount in the reader's language, "€ 1.234,50": the code in `currency`, else the record's `currencyField`, else the app's reporting currency, else EUR; `decimals` defaults to 2).
|
|
267
267
|
* `map` turns a raw value into a label (translated). `parts` (on a `line`) lists paths, or `{ path, label?, format? }`, joined by `separator` (default " · "); empty parts are dropped.
|
|
268
|
-
* - `source` — `{ register, schema, id }` or `{ url }`; omitted = the current object.
|
|
268
|
+
* - `source` — `{ register, schema, id }` or `{ url }`; omitted = the current object. An entry with `from: "object"` reads the current object even then (a client card that also shows the ticket's channel).
|
|
269
269
|
* - `link` — `{ label, route? | href? }` at the foot.
|
|
270
270
|
* - `hideEmpty` — drop an entry whose value is empty (default true).
|
|
271
271
|
* - `emptyText` — shown when no entry has a value.
|
|
@@ -370,8 +370,8 @@ export default {
|
|
|
370
370
|
* @return {Array<object>}
|
|
371
371
|
*/
|
|
372
372
|
blocks() {
|
|
373
|
-
const
|
|
374
|
-
if (!
|
|
373
|
+
const sourceRecord = this.record
|
|
374
|
+
if (!sourceRecord) {
|
|
375
375
|
return []
|
|
376
376
|
}
|
|
377
377
|
const fields = Array.isArray(this.content?.fields) ? this.content.fields : []
|
|
@@ -381,6 +381,8 @@ export default {
|
|
|
381
381
|
if (!field || typeof field !== 'object') {
|
|
382
382
|
return
|
|
383
383
|
}
|
|
384
|
+
// `from: "object"` reads the page's own object while the card shows a `source`.
|
|
385
|
+
const record = field.from === 'object' && this.objectData ? this.objectData : sourceRecord
|
|
384
386
|
const kind = this.kindOf(field)
|
|
385
387
|
const key = String(field.key || field.path || `${kind}-${index}`).replace(/[^\w-]/g, '-')
|
|
386
388
|
const value = this.entryValue(record, field, kind)
|
|
@@ -29,7 +29,11 @@
|
|
|
29
29
|
:llmSkillsUrl="resolvedLlmSkillsUrl"
|
|
30
30
|
:suggestUrl="resolvedSuggestUrl"
|
|
31
31
|
:documentationUrl="resolvedDocumentationUrl"
|
|
32
|
-
:capabilityComparison="resolvedCapabilityComparison"
|
|
32
|
+
:capabilityComparison="resolvedCapabilityComparison"
|
|
33
|
+
:categories="categories || {}"
|
|
34
|
+
:board="board || {}"
|
|
35
|
+
:title="title"
|
|
36
|
+
:appVersion="resolvedAppVersion" />
|
|
33
37
|
</template>
|
|
34
38
|
|
|
35
39
|
<script>
|
|
@@ -188,6 +192,47 @@ export default {
|
|
|
188
192
|
default: null,
|
|
189
193
|
},
|
|
190
194
|
|
|
195
|
+
/**
|
|
196
|
+
* Feature category key to caption, for the board look's groups.
|
|
197
|
+
* Manifest `config.categories`.
|
|
198
|
+
*
|
|
199
|
+
* @type {object|null}
|
|
200
|
+
*/
|
|
201
|
+
categories: {
|
|
202
|
+
type: Object,
|
|
203
|
+
default: null,
|
|
204
|
+
},
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Board look options (`layout`, `tabs`, `filter`, `statusLabels`,
|
|
208
|
+
* `next`, `issueLabels`, `subtitle`, `notice`, `documentationButton`,
|
|
209
|
+
* `suggestButton`). Manifest `config.board`; see CnFeaturesBoard.
|
|
210
|
+
*
|
|
211
|
+
* @type {object|null}
|
|
212
|
+
*/
|
|
213
|
+
board: {
|
|
214
|
+
type: Object,
|
|
215
|
+
default: null,
|
|
216
|
+
},
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Page title, lifted from the manifest page's `title`. Shown in the
|
|
220
|
+
* board look.
|
|
221
|
+
*/
|
|
222
|
+
title: {
|
|
223
|
+
type: String,
|
|
224
|
+
default: '',
|
|
225
|
+
},
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* The app version for the board look's subtitle. Manifest config >
|
|
229
|
+
* initialState (`features_roadmap_app_version`) > ''.
|
|
230
|
+
*/
|
|
231
|
+
appVersion: {
|
|
232
|
+
type: String,
|
|
233
|
+
default: '',
|
|
234
|
+
},
|
|
235
|
+
|
|
191
236
|
/**
|
|
192
237
|
* Override for the appId used to namespace loadState lookups.
|
|
193
238
|
* Tests pass an explicit value; production reads it from the
|
|
@@ -283,6 +328,11 @@ export default {
|
|
|
283
328
|
|| readInitialState(this.effectiveAppId, 'features_roadmap_suggest_url', '')
|
|
284
329
|
},
|
|
285
330
|
|
|
331
|
+
resolvedAppVersion() {
|
|
332
|
+
return this.appVersion
|
|
333
|
+
|| readInitialState(this.effectiveAppId, 'features_roadmap_app_version', '')
|
|
334
|
+
},
|
|
335
|
+
|
|
286
336
|
resolvedDocumentationUrl() {
|
|
287
337
|
return this.documentationUrl
|
|
288
338
|
|| readInitialState(this.effectiveAppId, 'features_roadmap_documentation_url', '')
|
|
@@ -7,6 +7,19 @@
|
|
|
7
7
|
</template>
|
|
8
8
|
</NcEmptyContent>
|
|
9
9
|
</div>
|
|
10
|
+
<CnFeaturesBoard
|
|
11
|
+
v-else-if="isBoardLook"
|
|
12
|
+
:features="features"
|
|
13
|
+
:categories="categories"
|
|
14
|
+
:repo="repo"
|
|
15
|
+
:title="title"
|
|
16
|
+
:appVersion="appVersion"
|
|
17
|
+
:documentationUrl="resolvedDocumentationUrl"
|
|
18
|
+
:suggestUrl="resolvedSuggestUrl"
|
|
19
|
+
:openbuiltUrl="resolvedOpenbuiltUrl"
|
|
20
|
+
:llmSkillsUrl="resolvedLlmSkillsUrl"
|
|
21
|
+
v-bind="boardOptions"
|
|
22
|
+
@support="openSupportDialog" />
|
|
10
23
|
<template v-else>
|
|
11
24
|
<header class="cn-features-and-roadmap-view__header">
|
|
12
25
|
<h2 class="cn-features-and-roadmap-view__title">
|
|
@@ -57,19 +70,18 @@
|
|
|
57
70
|
:comparison="capabilityComparison" />
|
|
58
71
|
<CnRoadmapTab v-else :repo="repo" />
|
|
59
72
|
</main>
|
|
60
|
-
|
|
61
|
-
<CnSupportDialog
|
|
62
|
-
v-if="showSupportDialog"
|
|
63
|
-
:appName="resolvedAppName"
|
|
64
|
-
:appSlug="resolvedAppSlug"
|
|
65
|
-
:appStoreUrl="resolvedAppStoreUrl"
|
|
66
|
-
:featureRequestUrl="resolvedFeatureRequestUrl"
|
|
67
|
-
:donateUrl="donateUrl"
|
|
68
|
-
:supportUrl="supportUrl"
|
|
69
|
-
:founderName="founderName"
|
|
70
|
-
:founderTitle="founderTitle"
|
|
71
|
-
@close="showSupportDialog = false" />
|
|
72
73
|
</template>
|
|
74
|
+
<CnSupportDialog
|
|
75
|
+
v-if="showSupportDialog && !disabled"
|
|
76
|
+
:appName="resolvedAppName"
|
|
77
|
+
:appSlug="resolvedAppSlug"
|
|
78
|
+
:appStoreUrl="resolvedAppStoreUrl"
|
|
79
|
+
:featureRequestUrl="resolvedFeatureRequestUrl"
|
|
80
|
+
:donateUrl="donateUrl"
|
|
81
|
+
:supportUrl="supportUrl"
|
|
82
|
+
:founderName="founderName"
|
|
83
|
+
:founderTitle="founderTitle"
|
|
84
|
+
@close="showSupportDialog = false" />
|
|
73
85
|
</div>
|
|
74
86
|
</template>
|
|
75
87
|
|
|
@@ -111,9 +123,11 @@ import RoadVariant from 'vue-material-design-icons/RoadVariant.vue'
|
|
|
111
123
|
import TableSearch from 'vue-material-design-icons/TableSearch.vue'
|
|
112
124
|
import CnCapabilityTable from '../CnCapabilityTable/CnCapabilityTable.vue'
|
|
113
125
|
import CnFeaturesAndRoadmapSidebar from '../CnFeaturesAndRoadmapSidebar/CnFeaturesAndRoadmapSidebar.vue'
|
|
126
|
+
import CnFeaturesBoard from '../CnFeaturesBoard/CnFeaturesBoard.vue'
|
|
114
127
|
import CnFeaturesTab from '../CnFeaturesTab/CnFeaturesTab.vue'
|
|
115
128
|
import CnRoadmapTab from '../CnRoadmapTab/CnRoadmapTab.vue'
|
|
116
129
|
import CnSupportDialog from '../CnSupportDialog/CnSupportDialog.vue'
|
|
130
|
+
import { normalizeLook } from '../../composables/useLook.js'
|
|
117
131
|
import { warnCapabilityComparisonDeprecated } from '../../utils/capabilityComparison.js'
|
|
118
132
|
import { buildFeatureRequestUrl, DEFAULT_FORGE } from '../../utils/forge.js'
|
|
119
133
|
|
|
@@ -137,6 +151,7 @@ export default {
|
|
|
137
151
|
RoadVariant,
|
|
138
152
|
TableSearch,
|
|
139
153
|
CnCapabilityTable,
|
|
154
|
+
CnFeaturesBoard,
|
|
140
155
|
CnFeaturesTab,
|
|
141
156
|
CnRoadmapTab,
|
|
142
157
|
CnSupportDialog,
|
|
@@ -158,6 +173,8 @@ export default {
|
|
|
158
173
|
* unmount. Same holder CnIndexPage uses.
|
|
159
174
|
*/
|
|
160
175
|
cnIndexSidebarConfig: { default: () => ({ value: null }) },
|
|
176
|
+
/** The app's look, provided by CnAppRoot (`nextcloud` or `board`). */
|
|
177
|
+
cnLook: { default: 'nextcloud' },
|
|
161
178
|
},
|
|
162
179
|
|
|
163
180
|
props: {
|
|
@@ -192,6 +209,46 @@ export default {
|
|
|
192
209
|
default: () => [],
|
|
193
210
|
},
|
|
194
211
|
|
|
212
|
+
/**
|
|
213
|
+
* Feature category key to caption, in the order the board look shows
|
|
214
|
+
* the groups. A feature names its group with `category`.
|
|
215
|
+
*
|
|
216
|
+
* @type {object}
|
|
217
|
+
*/
|
|
218
|
+
categories: {
|
|
219
|
+
type: Object,
|
|
220
|
+
default: () => ({}),
|
|
221
|
+
},
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Board look options, passed to CnFeaturesBoard: `layout` (`cards` or
|
|
225
|
+
* `rows`), `tabs`, `filter` (`chips` or `segmented`), `statusLabels`,
|
|
226
|
+
* `next`, `issueLabels`, `subtitle`, `notice`, `documentationButton`
|
|
227
|
+
* and `suggestButton`. Ignored in the default look.
|
|
228
|
+
*
|
|
229
|
+
* @type {object}
|
|
230
|
+
*/
|
|
231
|
+
board: {
|
|
232
|
+
type: Object,
|
|
233
|
+
default: () => ({}),
|
|
234
|
+
},
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Page title in the board look. Empty reads "Features and roadmap".
|
|
238
|
+
*/
|
|
239
|
+
title: {
|
|
240
|
+
type: String,
|
|
241
|
+
default: '',
|
|
242
|
+
},
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* The app version, for `{appVersion}` in the board look's subtitle.
|
|
246
|
+
*/
|
|
247
|
+
appVersion: {
|
|
248
|
+
type: String,
|
|
249
|
+
default: '',
|
|
250
|
+
},
|
|
251
|
+
|
|
195
252
|
/**
|
|
196
253
|
* Admin opt-out flag — when true the entire view collapses to a
|
|
197
254
|
* single "disabled by admin" empty state.
|
|
@@ -387,6 +444,32 @@ export default {
|
|
|
387
444
|
},
|
|
388
445
|
|
|
389
446
|
computed: {
|
|
447
|
+
/**
|
|
448
|
+
* Whether the page is drawn in the board look.
|
|
449
|
+
*
|
|
450
|
+
* @return {boolean}
|
|
451
|
+
*/
|
|
452
|
+
isBoardLook() {
|
|
453
|
+
return normalizeLook(this.cnLook) === 'board'
|
|
454
|
+
},
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* The board options CnFeaturesBoard declares, so an unknown key in the
|
|
458
|
+
* manifest never lands on its root element as an attribute.
|
|
459
|
+
*
|
|
460
|
+
* @return {object}
|
|
461
|
+
*/
|
|
462
|
+
boardOptions() {
|
|
463
|
+
const keys = ['layout', 'tabs', 'filter', 'statusLabels', 'next', 'issueLabels', 'subtitle', 'notice', 'documentationButton', 'suggestButton']
|
|
464
|
+
const options = {}
|
|
465
|
+
for (const key of keys) {
|
|
466
|
+
if (this.board && this.board[key] !== undefined && this.board[key] !== null) {
|
|
467
|
+
options[key] = this.board[key]
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
return options
|
|
471
|
+
},
|
|
472
|
+
|
|
390
473
|
/**
|
|
391
474
|
* The stops the header toggle cycles through. Without a capability
|
|
392
475
|
* comparison this is the two-stop list every consumer has today, and
|
|
@@ -580,7 +663,9 @@ export default {
|
|
|
580
663
|
if (!this.cnHostsIndexSidebar || !this.cnIndexSidebarConfig) {
|
|
581
664
|
return
|
|
582
665
|
}
|
|
583
|
-
|
|
666
|
+
// The board look has no right-hand column: its links sit in the
|
|
667
|
+
// board's Actions menu.
|
|
668
|
+
if (this.disabled || this.isBoardLook) {
|
|
584
669
|
this.cnIndexSidebarConfig.value = null
|
|
585
670
|
return
|
|
586
671
|
}
|