@conduction/nextcloud-vue 2.76.0 → 2.77.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/CnAppNav/CnAppNav.vue2.js +18 -3
- package/dist/esm/components/CnAppNav/CnAppNav.vue2.js.map +1 -1
- package/dist/esm/components/CnAppNav/CnAppNav.vue3.js +49 -3
- package/dist/esm/components/CnAppNav/CnAppNav.vue3.js.map +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js +42 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js.map +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js +228 -203
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js.map +1 -1
- package/dist/esm/components/CnCellRenderer/CnGroupNameCell.vue.js +9 -0
- package/dist/esm/components/CnCellRenderer/CnGroupNameCell.vue.js.map +1 -0
- package/dist/esm/components/CnCellRenderer/CnGroupNameCell.vue2.js +50 -0
- package/dist/esm/components/CnCellRenderer/CnGroupNameCell.vue2.js.map +1 -0
- package/dist/esm/components/CnCellRenderer/CnGroupNameCell.vue3.js +13 -0
- package/dist/esm/components/CnCellRenderer/CnGroupNameCell.vue3.js.map +1 -0
- package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +41 -4
- package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue3.js +90 -51
- package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +16 -28
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +12 -24
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
- package/dist/esm/components/CnFavouriteToggle/CnFavouriteToggle.vue2.js +7 -2
- package/dist/esm/components/CnFavouriteToggle/CnFavouriteToggle.vue2.js.map +1 -1
- package/dist/esm/components/CnFavouriteToggle/CnFavouriteToggle.vue3.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +114 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +115 -62
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
- package/dist/esm/components/CnFollowToggle/CnFollowToggle.vue2.js +89 -7
- package/dist/esm/components/CnFollowToggle/CnFollowToggle.vue2.js.map +1 -1
- package/dist/esm/components/CnFollowToggle/CnFollowToggle.vue3.js +62 -30
- package/dist/esm/components/CnFollowToggle/CnFollowToggle.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +98 -13
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +13 -9
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js +199 -7
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js +155 -119
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js +6 -0
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js +4 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js.map +1 -1
- package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue2.js +13 -0
- package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue2.js.map +1 -1
- package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue3.js.map +1 -1
- package/dist/esm/composables/useListView.js +4 -0
- package/dist/esm/composables/useListView.js.map +1 -1
- package/dist/esm/index.js +2 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/l10n/en.json.js +25 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +25 -1
- package/dist/esm/l10n/nl.json.js.map +1 -1
- package/dist/esm/nextcloud-vue.css +288 -74
- package/dist/esm/store/plugins/interactions.js +20 -10
- package/dist/esm/store/plugins/interactions.js.map +1 -1
- package/dist/esm/store/useObjectStore.js +17 -0
- package/dist/esm/store/useObjectStore.js.map +1 -1
- package/dist/esm/utils/builtInFormatters.js +15 -7
- package/dist/esm/utils/builtInFormatters.js.map +1 -1
- package/dist/esm/utils/groupAutocomplete.js +63 -1
- package/dist/esm/utils/groupAutocomplete.js.map +1 -1
- package/dist/esm/utils/lensAvailability.js +90 -0
- package/dist/esm/utils/lensAvailability.js.map +1 -0
- package/dist/esm/utils/personalLenses.js +13 -6
- package/dist/esm/utils/personalLenses.js.map +1 -1
- package/dist/esm/utils/recordInteractions.js +31 -13
- package/dist/esm/utils/recordInteractions.js.map +1 -1
- package/dist/esm/utils/resolveFilterTokens.js +46 -3
- package/dist/esm/utils/resolveFilterTokens.js.map +1 -1
- package/dist/esm/utils/schema.js +1 -1
- package/dist/esm/utils/schema.js.map +1 -1
- package/dist/esm/utils/sentinelTokens.js +4 -4
- package/dist/esm/utils/sentinelTokens.js.map +1 -1
- package/dist/esm/utils/validateManifestV2.compiled.js +2 -2
- package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
- package/dist/esm/utils/widgetVisibility.js +46 -1
- package/dist/esm/utils/widgetVisibility.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +3873 -2674
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +288 -74
- package/l10n/en.json +25 -1
- package/l10n/nl.json +25 -1
- package/package.json +1 -1
- package/src/components/CnAppNav/CnAppNav.vue +44 -5
- package/src/components/CnCellRenderer/CnCellRenderer.vue +56 -1
- package/src/components/CnCellRenderer/CnGroupNameCell.vue +61 -0
- package/src/components/CnDataTable/CnDataTable.md +9 -0
- package/src/components/CnDataTable/CnDataTable.vue +80 -20
- package/src/components/CnDetailPage/CnDetailPage.vue +10 -27
- package/src/components/CnFavouriteToggle/CnFavouriteToggle.vue +7 -2
- package/src/components/CnFilesBrowser/CnFilesBrowser.vue +204 -5
- package/src/components/CnFollowToggle/CnFollowToggle.vue +118 -13
- package/src/components/CnIndexPage/CnIndexPage.md +36 -0
- package/src/components/CnIndexPage/CnIndexPage.vue +106 -19
- package/src/components/CnObjectDataWidget/CnObjectDataWidget.vue +226 -2
- package/src/components/CnObjectSidebar/CnFilesTab.vue +9 -0
- package/src/components/CnWidgetObjectTable/CnWidgetObjectTable.vue +13 -0
- package/src/composables/useListView.js +4 -0
- package/src/css/look-board-detail.css +40 -2
- package/src/css/table.css +82 -17
- package/src/index.js +2 -1
- package/src/schemas/app-manifest-v2.schema.json +11 -7
- package/src/store/plugins/interactions.js +20 -10
- package/src/store/useObjectStore.js +17 -0
- package/src/utils/builtInFormatters.js +15 -7
- package/src/utils/groupAutocomplete.js +75 -0
- package/src/utils/index.js +1 -1
- package/src/utils/lensAvailability.js +86 -0
- package/src/utils/personalLenses.js +13 -6
- package/src/utils/recordInteractions.js +31 -13
- package/src/utils/resolveFilterTokens.js +45 -2
- package/src/utils/schema.js +1 -1
- package/src/utils/sentinelTokens.js +4 -4
- package/src/utils/validateManifestV2.compiled.js +2 -2
- package/src/utils/widgetVisibility.js +45 -0
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
* SPDX-FileCopyrightText: 2026 Conduction B.V.
|
|
3
3
|
* SPDX-License-Identifier: EUPL-1.2
|
|
4
4
|
*
|
|
5
|
-
* The per-user interaction calls OpenRegister serves on a record:
|
|
6
|
-
* watch
|
|
5
|
+
* The per-user interaction calls OpenRegister serves on a record: follow
|
|
6
|
+
* (watch, with its notifications switch), the watchers list, the read state,
|
|
7
|
+
* and the deprecated favourite (a quiet follow since OpenRegister's
|
|
8
|
+
* `merge-follow-and-favourites`). Plain functions over `fetch`, shared
|
|
7
9
|
* by the interactions store plugin and by the toggles, so a toggle works with
|
|
8
10
|
* or without the plugin installed.
|
|
9
11
|
*
|
|
@@ -31,13 +33,18 @@ export function interactionUrl(register, schema, id, tail) {
|
|
|
31
33
|
/**
|
|
32
34
|
* Send one interaction call and normalise the answer. Never throws.
|
|
33
35
|
*
|
|
34
|
-
* @param {string}
|
|
35
|
-
* @param {string}
|
|
36
|
+
* @param {string} method HTTP method.
|
|
37
|
+
* @param {string} url Full URL.
|
|
38
|
+
* @param {object|null} [body] JSON body, or null for none.
|
|
36
39
|
* @return {Promise<{ok: boolean, status: number|null, data: (object|null), message: string}>} The outcome; `message` is the server's, or a network message.
|
|
37
40
|
*/
|
|
38
|
-
async function call(method, url) {
|
|
41
|
+
async function call(method, url, body = null) {
|
|
39
42
|
try {
|
|
40
|
-
const
|
|
43
|
+
const init = { method, headers: buildHeaders() }
|
|
44
|
+
if (body !== null) {
|
|
45
|
+
init.body = JSON.stringify(body)
|
|
46
|
+
}
|
|
47
|
+
const response = await fetch(prefixUrl(url), init)
|
|
41
48
|
if (!response.ok) {
|
|
42
49
|
const error = await parseResponseError(response, 'record')
|
|
43
50
|
// The server's own words win over the generic status text.
|
|
@@ -61,6 +68,9 @@ async function call(method, url) {
|
|
|
61
68
|
/**
|
|
62
69
|
* Star or unstar a record for the current user.
|
|
63
70
|
*
|
|
71
|
+
* @deprecated A star is a quiet follow since OpenRegister's
|
|
72
|
+
* `merge-follow-and-favourites`; use `setWatching(..., { notify: false })`.
|
|
73
|
+
*
|
|
64
74
|
* @param {string} register Register slug.
|
|
65
75
|
* @param {string} schema Schema slug.
|
|
66
76
|
* @param {string} id Object id.
|
|
@@ -72,16 +82,24 @@ export function setFavourite(register, schema, id, on) {
|
|
|
72
82
|
}
|
|
73
83
|
|
|
74
84
|
/**
|
|
75
|
-
* Follow or unfollow a record for the current user
|
|
85
|
+
* Follow or unfollow a record for the current user, optionally setting the
|
|
86
|
+
* follow's notifications switch.
|
|
76
87
|
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
* @param {
|
|
88
|
+
* `options.notify` is sent only when following and only when it is a boolean:
|
|
89
|
+
* left out, a new follow notifies and an existing follow keeps its setting.
|
|
90
|
+
*
|
|
91
|
+
* @param {string} register Register slug.
|
|
92
|
+
* @param {string} schema Schema slug.
|
|
93
|
+
* @param {string} id Object id.
|
|
94
|
+
* @param {boolean} on True to follow, false to unfollow.
|
|
95
|
+
* @param {object} [options] Options.
|
|
96
|
+
* @param {boolean} [options.notify] The notifications switch.
|
|
81
97
|
* @return {Promise<object>} The outcome (see `call`).
|
|
98
|
+
* @spec openspec/changes/one-follow-control/specs/record-follow/spec.md#requirement-one-follow-control-with-a-notifications-switch
|
|
82
99
|
*/
|
|
83
|
-
export function setWatching(register, schema, id, on) {
|
|
84
|
-
|
|
100
|
+
export function setWatching(register, schema, id, on, options = {}) {
|
|
101
|
+
const body = on && options && typeof options.notify === 'boolean' ? { notify: options.notify } : null
|
|
102
|
+
return call(on ? 'PUT' : 'DELETE', interactionUrl(register, schema, id, 'watch'), body)
|
|
85
103
|
}
|
|
86
104
|
|
|
87
105
|
/**
|
|
@@ -10,6 +10,13 @@
|
|
|
10
10
|
* Supported tokens:
|
|
11
11
|
* - `@me` → the current Nextcloud user id (`getCurrentUser()` from
|
|
12
12
|
* `@nextcloud/auth`; `window.OC.currentUser` fallback)
|
|
13
|
+
* - `@myGroups` → the ids of the Nextcloud groups the current user is
|
|
14
|
+
* in, as an ARRAY (an IN filter). `ctx.myGroups` wins;
|
|
15
|
+
* otherwise a reactive peek over `getCurrentUserGroups`.
|
|
16
|
+
* Stays UNRESOLVED while loading and when the user is
|
|
17
|
+
* in no group, so the caller waits instead of sending
|
|
18
|
+
* an empty IN list (which OpenRegister reads as "no
|
|
19
|
+
* constraint"). Spread in place inside an IN-list array.
|
|
13
20
|
* - `@now` → the current instant, ISO-8601
|
|
14
21
|
* - `@today` → today at 00:00, `YYYY-MM-DD` (date-prefix comparable)
|
|
15
22
|
* - `@today±Nd` → relative-date arithmetic at day granularity: N days
|
|
@@ -56,6 +63,34 @@
|
|
|
56
63
|
|
|
57
64
|
import { getCurrentUser } from '@nextcloud/auth'
|
|
58
65
|
import { TODAY_DELTA_RE } from './sentinelTokens.js'
|
|
66
|
+
import { peekCurrentUserGroups } from './widgetVisibility.js'
|
|
67
|
+
|
|
68
|
+
/** The filter token for the current user's group ids. */
|
|
69
|
+
export const MY_GROUPS_TOKEN = '@myGroups'
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Resolve `@myGroups`: the current user's group ids, or the token itself while
|
|
73
|
+
* they are loading or when there are none (an empty IN list would match every
|
|
74
|
+
* row, so "no team" must mean "wait", never "everything").
|
|
75
|
+
*
|
|
76
|
+
* @spec openspec/changes/nextcloud-group-surfaces/specs/schema-utilities/spec.md#requirement-mygroups-resolves-to-the-current-users-group-ids
|
|
77
|
+
* @param {{myGroups?: string[]}} [ctx] Optional context; `ctx.myGroups` wins.
|
|
78
|
+
* @return {string[]|string} The group ids, or `'@myGroups'` when unresolved.
|
|
79
|
+
*/
|
|
80
|
+
function resolveMyGroups(ctx) {
|
|
81
|
+
let groups = ctx && Array.isArray(ctx.myGroups) ? ctx.myGroups : null
|
|
82
|
+
if (groups === null) {
|
|
83
|
+
try {
|
|
84
|
+
groups = peekCurrentUserGroups()
|
|
85
|
+
} catch {
|
|
86
|
+
groups = null
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
const ids = Array.isArray(groups)
|
|
90
|
+
? groups.filter((g) => typeof g === 'string' && g !== '')
|
|
91
|
+
: []
|
|
92
|
+
return ids.length > 0 ? [...ids] : MY_GROUPS_TOKEN
|
|
93
|
+
}
|
|
59
94
|
|
|
60
95
|
/**
|
|
61
96
|
* Format a Date as `YYYY-MM-DD` (local).
|
|
@@ -73,7 +108,7 @@ function ymd(d) {
|
|
|
73
108
|
* Resolve a single filter value if it is a dynamic `@`-token, else pass through.
|
|
74
109
|
*
|
|
75
110
|
* @param {unknown} v The candidate value.
|
|
76
|
-
* @param {{objectId?: (string|number), object?: object, workspace?: object, config?: object, range?: object}} [ctx] Optional
|
|
111
|
+
* @param {{objectId?: (string|number), object?: object, workspace?: object, config?: object, range?: object, myGroups?: string[]}} [ctx] Optional
|
|
77
112
|
* context for `@objectId` / `@object.<field>` (detail page),
|
|
78
113
|
* `@workspace.<key>` (page-level workspace state), and `@config.<key>`
|
|
79
114
|
* (page-level app config) tokens.
|
|
@@ -84,6 +119,9 @@ export function resolveFilterValue(v, ctx) {
|
|
|
84
119
|
return v
|
|
85
120
|
}
|
|
86
121
|
const now = new Date()
|
|
122
|
+
if (v === MY_GROUPS_TOKEN) {
|
|
123
|
+
return resolveMyGroups(ctx)
|
|
124
|
+
}
|
|
87
125
|
if (v === '@objectId') {
|
|
88
126
|
return (ctx && ctx.objectId !== undefined && ctx.objectId !== null) ? String(ctx.objectId) : v
|
|
89
127
|
}
|
|
@@ -313,8 +351,13 @@ export function resolveFilterTokens(filter, ctx) {
|
|
|
313
351
|
if (!filter || typeof filter !== 'object') {
|
|
314
352
|
return filter
|
|
315
353
|
}
|
|
354
|
+
// An item that resolves to a list (`@myGroups`) is spread in place, so
|
|
355
|
+
// `['@myGroups', 'archive']` stays one flat IN list.
|
|
316
356
|
const resolveOne = (v) => (Array.isArray(v)
|
|
317
|
-
? v.
|
|
357
|
+
? v.flatMap((item) => {
|
|
358
|
+
const r = resolveFilterValue(item, ctx)
|
|
359
|
+
return Array.isArray(r) ? r : [r]
|
|
360
|
+
})
|
|
318
361
|
: resolveFilterValue(v, ctx))
|
|
319
362
|
const out = {}
|
|
320
363
|
for (const [k, v] of Object.entries(filter)) {
|
package/src/utils/schema.js
CHANGED
|
@@ -385,7 +385,7 @@ function isUserProp(prop) {
|
|
|
385
385
|
* @param {object} prop A schema property definition (or `items` for an array).
|
|
386
386
|
* @return {boolean} True when the property marks a Nextcloud group.
|
|
387
387
|
*/
|
|
388
|
-
function isGroupProp(prop) {
|
|
388
|
+
export function isGroupProp(prop) {
|
|
389
389
|
if (!prop || typeof prop !== 'object') {
|
|
390
390
|
return false
|
|
391
391
|
}
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
* A token is valid only in the context whose resolver runs on it:
|
|
27
27
|
*
|
|
28
28
|
* - **filter** — `resolveFilterTokens`, resolved at fetch time:
|
|
29
|
-
* `@me`, `@now`, `@today`, `@today±Nd`, `@monthStart`,
|
|
29
|
+
* `@me`, `@myGroups`, `@now`, `@today`, `@today±Nd`, `@monthStart`,
|
|
30
30
|
* `@quarterStart`, `@yearStart`.
|
|
31
31
|
* - **config** — `IAppConfig`-sourced: `@resolve:<key>`, `@config.<key>`
|
|
32
32
|
* (trailing `?` marks optional).
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
* @type {Readonly<Record<string, string>>}
|
|
68
68
|
*/
|
|
69
69
|
export const SENTINEL_TOKEN_PATTERNS = Object.freeze({
|
|
70
|
-
filter: '^@(?:me(?:\\.(?:displayName|email))?|now|today|monthStart|quarterStart|yearStart)$|^@today[+-][0-9]+d$',
|
|
70
|
+
filter: '^@(?:me(?:\\.(?:displayName|email))?|myGroups|now|today|monthStart|quarterStart|yearStart)$|^@today[+-][0-9]+d$',
|
|
71
71
|
config: '^@resolve:[a-z][a-z0-9_-]*$|^@config\\.[A-Za-z][A-Za-z0-9_.]*\\??$',
|
|
72
72
|
object: '^@objectId$|^@object\\.[A-Za-z][A-Za-z0-9_]*$',
|
|
73
73
|
workspace: '^@workspace\\.[A-Za-z][A-Za-z0-9_]*\\??$',
|
|
@@ -116,8 +116,8 @@ export const SENTINEL_CONTEXTS = Object.freeze([
|
|
|
116
116
|
export const SENTINEL_VOCABULARY = Object.freeze({
|
|
117
117
|
filter: {
|
|
118
118
|
resolver: 'resolveFilterTokens',
|
|
119
|
-
description: 'Relative fetch-time tokens (current user
|
|
120
|
-
members: ['@me', '@me.displayName', '@me.email', '@now', '@today', '@today±Nd', '@monthStart', '@quarterStart', '@yearStart'],
|
|
119
|
+
description: 'Relative fetch-time tokens (current user, the current user\'s groups as an IN list, relative dates).',
|
|
120
|
+
members: ['@me', '@me.displayName', '@me.email', '@myGroups', '@now', '@today', '@today±Nd', '@monthStart', '@quarterStart', '@yearStart'],
|
|
121
121
|
},
|
|
122
122
|
config: {
|
|
123
123
|
resolver: 'resolveManifestSentinels / resolveFilterTokens',
|