@conduction/nextcloud-vue 2.137.0 → 2.139.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/CnCellRenderer/CnCellRenderer.vue.js +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js +6 -4
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js.map +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js.map +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue.js +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailCard/CnDetailCard.vue.js +1 -1
- package/dist/esm/components/CnDetailCard/CnDetailCard.vue2.js +6 -0
- package/dist/esm/components/CnDetailCard/CnDetailCard.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailCard/CnDetailCard.vue3.js +24 -7
- package/dist/esm/components/CnDetailCard/CnDetailCard.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue.js +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js +2 -0
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js.map +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue.js +1 -1
- 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/CnFilesBrowser/CnFilesBrowser.vue.js +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +43 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +133 -6
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +25 -17
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue2.js +2 -0
- package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue3.js +13 -2
- package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue3.js.map +1 -1
- package/dist/esm/components/CnMailTab/dashboardRegistration.js +4 -0
- package/dist/esm/components/CnMailTab/dashboardRegistration.js.map +1 -1
- package/dist/esm/components/CnNotificationMatrix/CnNotificationMatrix.vue.js +1 -1
- package/dist/esm/components/CnNotificationMatrix/CnNotificationMatrix.vue2.js.map +1 -1
- package/dist/esm/components/CnNotificationMatrix/CnNotificationMatrix.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue.js +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue.js +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js +2 -0
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js +2 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js.map +1 -1
- package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue.js +1 -1
- package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue2.js +6 -0
- package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue2.js.map +1 -1
- package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue3.js +3 -3
- package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue3.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +16 -0
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js +11 -5
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnSavedViewMenuSettings/CnSavedViewMenuSettings.vue.js +1 -1
- package/dist/esm/components/CnSavedViewMenuSettings/CnSavedViewMenuSettings.vue2.js.map +1 -1
- package/dist/esm/components/CnSavedViewMenuSettings/CnSavedViewMenuSettings.vue3.js +1 -0
- package/dist/esm/components/CnSavedViewMenuSettings/CnSavedViewMenuSettings.vue3.js.map +1 -1
- package/dist/esm/components/CnUserSettingsDialog/CnUserSettingsDialog.vue.js +1 -1
- package/dist/esm/components/CnUserSettingsDialog/CnUserSettingsDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnUserSettingsDialog/CnUserSettingsDialog.vue3.js.map +1 -1
- package/dist/esm/composables/indexSources.js +78 -12
- package/dist/esm/composables/indexSources.js.map +1 -1
- package/dist/esm/l10n/en.json.js +12 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +12 -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 +685 -512
- package/dist/esm/utils/resolveFilterTokens.js +9 -0
- package/dist/esm/utils/resolveFilterTokens.js.map +1 -1
- package/dist/esm/utils/sentinelTokens.js +1 -1
- package/dist/esm/utils/sentinelTokens.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +580 -236
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +685 -512
- package/l10n/en.json +12 -1
- package/l10n/nl.json +12 -1
- package/package.json +1 -1
- package/src/components/CnCellRenderer/CnCellRenderer.vue +6 -4
- package/src/components/CnChartWidget/CnChartWidget.vue +4 -0
- package/src/components/CnDetailCard/CnDetailCard.md +1 -0
- package/src/components/CnDetailCard/CnDetailCard.vue +25 -1
- package/src/components/CnDetailWidgetHost/CnDetailWidgetHost.vue +2 -0
- package/src/components/CnFactsWidget/CnFactsWidget.vue +6 -4
- package/src/components/CnFilesBrowser/CnFilesBrowser.vue +54 -1
- package/src/components/CnIndexPage/CnIndexPage.vue +135 -7
- package/src/components/CnIndexSidebar/CnIndexSidebar.vue +10 -2
- package/src/components/CnMailTab/dashboardRegistration.js +4 -0
- package/src/components/CnNotificationMatrix/CnNotificationMatrix.vue +4 -0
- package/src/components/CnObjectListWidget/CnObjectListWidget.vue +1 -1
- package/src/components/CnObjectSidebar/CnFilesTab.vue +3 -0
- package/src/components/CnOrderedListField/CnOrderedListField.vue +11 -1
- package/src/components/CnRecordListWidget/CnRecordListWidget.vue +22 -3
- package/src/components/CnSavedViewMenuSettings/CnSavedViewMenuSettings.vue +1 -0
- package/src/components/CnUserSettingsDialog/CnUserSettingsDialog.vue +3 -0
- package/src/composables/indexSources.js +78 -12
- package/src/css/dialog.css +26 -0
- package/src/css/index-page.css +5 -0
- package/src/css/look-board-detail.css +36 -0
- package/src/css/look-board-index.css +21 -0
- package/src/css/look-board.css +47 -0
- package/src/utils/resolveFilterTokens.js +9 -0
- package/src/utils/sentinelTokens.js +1 -1
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { translate, getCanonicalLocale } from '@nextcloud/l10n';
|
|
2
2
|
import { generateUrl, generateOcsUrl } from '@nextcloud/router';
|
|
3
3
|
import { reactive } from 'vue';
|
|
4
|
+
import AccountOutline from 'vue-material-design-icons/AccountOutline.vue';
|
|
4
5
|
import CalendarClock from 'vue-material-design-icons/CalendarClock.vue';
|
|
5
6
|
import Cancel from 'vue-material-design-icons/Cancel.vue';
|
|
6
7
|
import Check from 'vue-material-design-icons/Check.vue';
|
|
8
|
+
import EmailOutline from 'vue-material-design-icons/EmailOutline.vue';
|
|
7
9
|
import HandBackRight from 'vue-material-design-icons/HandBackRight.vue';
|
|
8
10
|
import LightningBolt from 'vue-material-design-icons/LightningBolt.vue';
|
|
9
11
|
import Pencil from 'vue-material-design-icons/Pencil.vue';
|
|
@@ -14,6 +16,7 @@ import { fillTemplate } from '../utils/fillTemplate.js';
|
|
|
14
16
|
import { flowRunStatuses, FLOW_RUN_ERROR_STATUSES } from '../utils/flowRunStatus.js';
|
|
15
17
|
import { fetchUsers, fetchGroupMembers, fetchStatuses, fetchPresence } from '../utils/nextcloudDirectory.js';
|
|
16
18
|
import { readPath } from '../utils/readPath.js';
|
|
19
|
+
import { resolveNextcloudUser } from '../utils/userAutocomplete.js';
|
|
17
20
|
import { useFlowStore } from './useFlowStore.js';
|
|
18
21
|
import { useOrganisationStore, organisationRecord } from './useOrganisationStore.js';
|
|
19
22
|
import { useTaskInboxStore } from './useTaskInboxStore.js';
|
|
@@ -1089,7 +1092,7 @@ function fillRowTemplate(template, row) {
|
|
|
1089
1092
|
* and its count (DqZoekresultaten).
|
|
1090
1093
|
*
|
|
1091
1094
|
* `sourceConfig.kinds` lists what is searched:
|
|
1092
|
-
* `{ id, label, register, schema, titleField?, subtitleField?, statusField?, statusResolve?, linkedField?, linkedTemplate?, href?, limit? }`
|
|
1095
|
+
* `{ id, label, register, schema, titleField?, subtitleField?, subtitleTemplate?, statusField?, statusResolve?, linkedField?, linkedTemplate?, linkedUser?, href?, limit? }`
|
|
1093
1096
|
* for objects (OpenRegister's `_search`, so the reader sees what they may
|
|
1094
1097
|
* read), or `{ id, label, files: true, limit? }` for the reader's files
|
|
1095
1098
|
* (Nextcloud's unified search). The term is `sourceConfig.term`, else the
|
|
@@ -1103,6 +1106,10 @@ function fillRowTemplate(template, row) {
|
|
|
1103
1106
|
* coloured by `sourceConfig.statusColorMap`. `linkedTemplate` (a field
|
|
1104
1107
|
* template, "{case.title}") or `linkedField` (a path) fills the "Linked"
|
|
1105
1108
|
* column, drawn when a kind declares one; `sourceConfig.linkedLabel` names it.
|
|
1109
|
+
* `subtitleTemplate` ("Case {identifier}", translated) fills the line under a
|
|
1110
|
+
* result, else `subtitleField`.
|
|
1111
|
+
* `linkedUser: true` reads that value as a user id and shows the user's
|
|
1112
|
+
* display name. `sourceConfig.columnWidths` sets a width per column key.
|
|
1106
1113
|
* The page's title and count line can name the term as `{term}`, and the
|
|
1107
1114
|
* count is the active kind's total. Kind, link and status are filterable.
|
|
1108
1115
|
*
|
|
@@ -1112,6 +1119,23 @@ function fillRowTemplate(template, row) {
|
|
|
1112
1119
|
* @return {object} The source adapter.
|
|
1113
1120
|
* @spec openspec/changes/index-search-source/specs/index-page/spec.md#requirement-an-index-page-can-search-several-schemas-and-files
|
|
1114
1121
|
*/
|
|
1122
|
+
/**
|
|
1123
|
+
* Columns with the widths a page names per column key
|
|
1124
|
+
* (`sourceConfig.columnWidths`, `{ title: '250px' }`); a column it does not
|
|
1125
|
+
* name keeps none.
|
|
1126
|
+
*
|
|
1127
|
+
* @param {Array<object>} columns The columns.
|
|
1128
|
+
* @param {object|undefined} widths The widths by key.
|
|
1129
|
+
* @return {Array<object>} The columns.
|
|
1130
|
+
* @spec openspec/changes/search-linked-user-and-widths/specs/search-linked-user-and-widths/spec.md
|
|
1131
|
+
*/
|
|
1132
|
+
function withColumnWidths(columns, widths) {
|
|
1133
|
+
if (!widths || typeof widths !== 'object') {
|
|
1134
|
+
return columns
|
|
1135
|
+
}
|
|
1136
|
+
return columns.map((col) => (typeof widths[col.key] === 'string' && widths[col.key] !== '' ? { ...col, width: widths[col.key] } : col))
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1115
1139
|
function searchSource(config = {}, context = {}) {
|
|
1116
1140
|
const translate$1 = typeof context.translate === 'function' ? context.translate : (text) => text;
|
|
1117
1141
|
const kinds = (Array.isArray(config && config.kinds) ? config.kinds : [])
|
|
@@ -1200,12 +1224,27 @@ function searchSource(config = {}, context = {}) {
|
|
|
1200
1224
|
return ''
|
|
1201
1225
|
};
|
|
1202
1226
|
|
|
1227
|
+
const subtitleOf = (kind, object) => {
|
|
1228
|
+
if (kind.subtitleTemplate) {
|
|
1229
|
+
return fillTemplate(translate$1(kind.subtitleTemplate), object)
|
|
1230
|
+
}
|
|
1231
|
+
return kind.subtitleField ? String(readPath(object, kind.subtitleField) ?? '') : ''
|
|
1232
|
+
};
|
|
1233
|
+
|
|
1234
|
+
// `linkedUser`: the Linked cell holds a user id; name the user instead.
|
|
1235
|
+
const linkedUserNames = async (kind, objects) => {
|
|
1236
|
+
const ids = [...new Set(objects.map((object) => linkedOf(kind, object)).filter((id) => id !== ''))];
|
|
1237
|
+
const options = await Promise.all(ids.map((id) => resolveNextcloudUser(id).catch(() => null)));
|
|
1238
|
+
return new Map(ids.map((id, index) => [id, (options[index] && options[index].label) || id]))
|
|
1239
|
+
};
|
|
1240
|
+
|
|
1203
1241
|
const searchObjects = async (axios, kind, term) => {
|
|
1204
1242
|
const url = generateUrl('/apps/openregister/api/objects/{register}/{schema}', { register: kind.register, schema: kind.schema });
|
|
1205
1243
|
const res = await axios.get(url, { params: { _search: term, _limit: kind.limit || 20 } });
|
|
1206
1244
|
const body = (res && res.data) || {};
|
|
1207
1245
|
const results = Array.isArray(body.results) ? body.results : (Array.isArray(body) ? body : []);
|
|
1208
1246
|
const labels = kind.statusResolve && kind.statusField ? await statusLabels(kind) : null;
|
|
1247
|
+
const userNames = kind.linkedUser === true ? await linkedUserNames(kind, results) : null;
|
|
1209
1248
|
return {
|
|
1210
1249
|
total: typeof body.total === 'number' ? body.total : results.length,
|
|
1211
1250
|
rows: results.map((object) => {
|
|
@@ -1220,9 +1259,9 @@ function searchSource(config = {}, context = {}) {
|
|
|
1220
1259
|
kindLabel: kind.label,
|
|
1221
1260
|
kindText: kindTextOf(kind, object),
|
|
1222
1261
|
title: String(readPath(object, kind.titleField || 'title') ?? object.name ?? id ?? ''),
|
|
1223
|
-
subtitle: kind
|
|
1262
|
+
subtitle: subtitleOf(kind, object),
|
|
1224
1263
|
status,
|
|
1225
|
-
linked: linkedOf(kind, object),
|
|
1264
|
+
linked: userNames ? (userNames.get(linkedOf(kind, object)) || linkedOf(kind, object)) : linkedOf(kind, object),
|
|
1226
1265
|
href: kind.href ? generateUrl(fillRowTemplate(kind.href, { ...object, id })) : '',
|
|
1227
1266
|
object,
|
|
1228
1267
|
}
|
|
@@ -1330,7 +1369,7 @@ function searchSource(config = {}, context = {}) {
|
|
|
1330
1369
|
*/
|
|
1331
1370
|
loading: () => state.loading,
|
|
1332
1371
|
|
|
1333
|
-
columns: [
|
|
1372
|
+
columns: withColumnWidths([
|
|
1334
1373
|
{ key: 'title', label: translate('nextcloud-vue', 'Result'), secondary: 'subtitle', sortable: true },
|
|
1335
1374
|
// `kindAsText`: what one row is, as plain text ("Zaak", "Lantaarnpaal",
|
|
1336
1375
|
// DqZoekresultaten), instead of the plural kind as a pill.
|
|
@@ -1345,7 +1384,7 @@ function searchSource(config = {}, context = {}) {
|
|
|
1345
1384
|
widgetProps: { colorMap: (config && config.statusColorMap) || {} },
|
|
1346
1385
|
sortable: true,
|
|
1347
1386
|
},
|
|
1348
|
-
],
|
|
1387
|
+
], config && config.columnWidths),
|
|
1349
1388
|
|
|
1350
1389
|
/**
|
|
1351
1390
|
* Every column header carries a filter button (DqZoekresultaten); the
|
|
@@ -1407,14 +1446,24 @@ function searchSource(config = {}, context = {}) {
|
|
|
1407
1446
|
* the pager asks for.
|
|
1408
1447
|
*
|
|
1409
1448
|
* @param {Array<object>} members The members, by name.
|
|
1410
|
-
* @param {object} config `search`, `sortKey`, `sortOrder`, `limit`, `offset`.
|
|
1449
|
+
* @param {object} config `search`, `nameLike`, `rolesLike`, `emailLike`, `today`, `sortKey`, `sortOrder`, `limit`, `offset`.
|
|
1411
1450
|
* @return {{rows: Array<object>, total: number}} The page and how many match.
|
|
1412
1451
|
*/
|
|
1413
1452
|
function membersPage(members, config = {}) {
|
|
1453
|
+
const has = (member, fields, text) => fields.some((field) => String(member[field] || '').toLowerCase().includes(text));
|
|
1414
1454
|
const term = String(config.search || '').trim().toLowerCase();
|
|
1415
|
-
let rows = term === ''
|
|
1416
|
-
|
|
1417
|
-
|
|
1455
|
+
let rows = term === '' ? members.slice() : members.filter((member) => has(member, ['displayname', 'function', 'roles', 'email'], term));
|
|
1456
|
+
// The table heads' filters: text contains, and the Today values picked.
|
|
1457
|
+
for (const [param, fields] of [['nameLike', ['displayname', 'function']], ['rolesLike', ['roles']], ['emailLike', ['email']]]) {
|
|
1458
|
+
const text = String(config[param] || '').trim().toLowerCase();
|
|
1459
|
+
if (text !== '') {
|
|
1460
|
+
rows = rows.filter((member) => has(member, fields, text));
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
const today = (Array.isArray(config.today) ? config.today : (config.today ? [config.today] : [])).map(String);
|
|
1464
|
+
if (today.length > 0) {
|
|
1465
|
+
rows = rows.filter((member) => today.includes(member.today));
|
|
1466
|
+
}
|
|
1418
1467
|
if (config.sortKey) {
|
|
1419
1468
|
const sign = config.sortOrder === 'desc' ? -1 : 1;
|
|
1420
1469
|
rows = rows.sort((a, b) => sign * String(a[config.sortKey] ?? '').localeCompare(String(b[config.sortKey] ?? '')));
|
|
@@ -1476,10 +1525,11 @@ function usersSource() {
|
|
|
1476
1525
|
*/
|
|
1477
1526
|
load: async (config) => {
|
|
1478
1527
|
const group = String((config && (config.group || config.defaultGroup)) || '');
|
|
1479
|
-
const { search, sortKey, sortOrder, limit, offset, ...request } = config || {};
|
|
1528
|
+
const { search, sortKey, sortOrder, limit, offset, nameLike, rolesLike, emailLike, today, ...request } = config || {};
|
|
1480
1529
|
const key = JSON.stringify({ ...request, group });
|
|
1481
|
-
|
|
1482
|
-
|
|
1530
|
+
const narrows = [offset, search, sortKey, nameLike, rolesLike, emailLike, today].some((value) => value !== undefined);
|
|
1531
|
+
// A new page, term, order or head filter of the members already read: no request.
|
|
1532
|
+
if (key === membersKey && narrows) {
|
|
1483
1533
|
const page = membersPage(readMembers, config);
|
|
1484
1534
|
state.rows = page.rows;
|
|
1485
1535
|
state.total = page.total;
|
|
@@ -1575,8 +1625,24 @@ function usersSource() {
|
|
|
1575
1625
|
|
|
1576
1626
|
searchFields: {
|
|
1577
1627
|
group: { param: 'group', single: true },
|
|
1628
|
+
'displayname[like]': { param: 'nameLike', single: true },
|
|
1629
|
+
'roles[like]': { param: 'rolesLike', single: true },
|
|
1630
|
+
'email[like]': { param: 'emailLike', single: true },
|
|
1631
|
+
today: { param: 'today' },
|
|
1578
1632
|
},
|
|
1579
1633
|
|
|
1634
|
+
/** A filter button on every head (DqAfdelingen); the members read are narrowed here. */
|
|
1635
|
+
headerFilters: true,
|
|
1636
|
+
|
|
1637
|
+
/**
|
|
1638
|
+
* A member's row menu (DqAfdelingen): their Nextcloud profile, and an
|
|
1639
|
+
* e-mail when they have an address. Both are links.
|
|
1640
|
+
*/
|
|
1641
|
+
rowActions: [
|
|
1642
|
+
{ id: 'open-profile', label: translate('nextcloud-vue', 'Open profile'), icon: AccountOutline, href: (row) => generateUrl(`/u/${encodeURIComponent(row.id)}`) },
|
|
1643
|
+
{ id: 'send-email', label: translate('nextcloud-vue', 'Send email'), icon: EmailOutline, href: (row) => `mailto:${row.email}`, visible: (row) => Boolean(row && row.email) },
|
|
1644
|
+
],
|
|
1645
|
+
|
|
1580
1646
|
showAdd: false,
|
|
1581
1647
|
}
|
|
1582
1648
|
}
|