@conduction/nextcloud-vue 2.56.0-beta.7 → 2.56.0-beta.8
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 +41 -1
- package/dist/esm/components/CnAppNav/CnAppNav.vue2.js.map +1 -1
- package/dist/esm/components/CnAppNav/CnAppNav.vue3.js.map +1 -1
- package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue2.js +9 -2
- package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +10 -2
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +6 -5
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
- package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue2.js +3 -1
- package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnLinkCardsPage/CnLinkCardsPage.vue.js +10 -0
- package/dist/esm/components/CnLinkCardsPage/CnLinkCardsPage.vue.js.map +1 -0
- package/dist/esm/components/CnLinkCardsPage/CnLinkCardsPage.vue2.js +316 -0
- package/dist/esm/components/CnLinkCardsPage/CnLinkCardsPage.vue2.js.map +1 -0
- package/dist/esm/components/CnLinkCardsPage/CnLinkCardsPage.vue3.js +105 -0
- package/dist/esm/components/CnLinkCardsPage/CnLinkCardsPage.vue3.js.map +1 -0
- package/dist/esm/components/CnPageRenderer/pageTypes.js +1 -0
- package/dist/esm/components/CnPageRenderer/pageTypes.js.map +1 -1
- package/dist/esm/index.js +6 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/l10n/en.json.js +1 -0
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +1 -0
- package/dist/esm/l10n/nl.json.js.map +1 -1
- package/dist/esm/nextcloud-vue.css +92 -2
- package/dist/esm/utils/headers.js +28 -2
- package/dist/esm/utils/headers.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/nextcloud-vue.cjs.js +8741 -8229
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +92 -2
- package/l10n/en.json +1 -0
- package/l10n/nl.json +1 -0
- package/package.json +1 -1
- package/scripts/.jsdoc-baselines.json +1 -0
- package/src/components/CnAppNav/CnAppNav.vue +41 -1
- package/src/components/CnBannerWidget/CnBannerWidget.vue +9 -2
- package/src/components/CnDashboardPage/CnDashboardPage.vue +10 -2
- package/src/components/CnDetailPage/CnDetailPage.vue +4 -1
- package/src/components/CnHeaderWidget/CnHeaderWidget.vue +3 -1
- package/src/components/CnLinkCardsPage/CnLinkCardsPage.vue +484 -0
- package/src/components/CnLinkCardsPage/index.js +4 -0
- package/src/components/CnPageRenderer/pageTypes.js +1 -0
- package/src/components/index.js +1 -0
- package/src/css/detail-page.css +10 -2
- package/src/index.js +7 -0
- package/src/schemas/app-manifest-v2.schema.json +44 -2
- package/src/types/manifest.d.ts +1 -1
- package/src/utils/headers.js +28 -2
- package/src/utils/validateManifestV2.compiled.js +2 -2
|
@@ -2660,9 +2660,17 @@
|
|
|
2660
2660
|
font-weight: 700;
|
|
2661
2661
|
line-height: 1.3;
|
|
2662
2662
|
color: var(--color-main-text);
|
|
2663
|
-
|
|
2663
|
+
/* Two lines, then an ellipsis. One line cut a long case title short on a
|
|
2664
|
+
page with room to spare, and the title is the one thing that says which
|
|
2665
|
+
record this is. The element carries the full text as its `title`, so a
|
|
2666
|
+
title cut after two lines is still reachable. `overflow-wrap` breaks a
|
|
2667
|
+
word longer than the line, which nowrap used to hide. */
|
|
2668
|
+
display: -webkit-box;
|
|
2669
|
+
-webkit-box-orient: vertical;
|
|
2670
|
+
-webkit-line-clamp: 2;
|
|
2671
|
+
line-clamp: 2;
|
|
2664
2672
|
overflow: hidden;
|
|
2665
|
-
|
|
2673
|
+
overflow-wrap: anywhere;
|
|
2666
2674
|
}
|
|
2667
2675
|
|
|
2668
2676
|
.cn-detail-page__subtitle {
|
|
@@ -32005,6 +32013,88 @@ a.cn-integration-card__title[data-v-f7e9bbfa]:hover {
|
|
|
32005
32013
|
}
|
|
32006
32014
|
|
|
32007
32015
|
|
|
32016
|
+
.cn-link-cards-page[data-v-2f9a546b] {
|
|
32017
|
+
display: flex;
|
|
32018
|
+
flex-direction: column;
|
|
32019
|
+
gap: calc(6 * var(--default-grid-baseline));
|
|
32020
|
+
padding: calc(5 * var(--default-grid-baseline));
|
|
32021
|
+
}
|
|
32022
|
+
.cn-link-cards-page__title[data-v-2f9a546b] {
|
|
32023
|
+
margin: 0 0 var(--default-grid-baseline);
|
|
32024
|
+
}
|
|
32025
|
+
.cn-link-cards-page__description[data-v-2f9a546b],
|
|
32026
|
+
.cn-link-cards-page__empty[data-v-2f9a546b] {
|
|
32027
|
+
color: var(--color-text-maxcontrast);
|
|
32028
|
+
margin: 0;
|
|
32029
|
+
max-width: 70ch;
|
|
32030
|
+
}
|
|
32031
|
+
.cn-link-cards-page__group[data-v-2f9a546b] {
|
|
32032
|
+
display: flex;
|
|
32033
|
+
flex-direction: column;
|
|
32034
|
+
gap: calc(3 * var(--default-grid-baseline));
|
|
32035
|
+
}
|
|
32036
|
+
.cn-link-cards-page__caption[data-v-2f9a546b] {
|
|
32037
|
+
color: var(--color-text-maxcontrast);
|
|
32038
|
+
font-size: 0.85em;
|
|
32039
|
+
font-weight: 600;
|
|
32040
|
+
letter-spacing: 0.06em;
|
|
32041
|
+
margin: 0;
|
|
32042
|
+
text-transform: uppercase;
|
|
32043
|
+
}
|
|
32044
|
+
.cn-link-cards-page__grid[data-v-2f9a546b] {
|
|
32045
|
+
display: grid;
|
|
32046
|
+
gap: calc(3 * var(--default-grid-baseline));
|
|
32047
|
+
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
|
|
32048
|
+
list-style: none;
|
|
32049
|
+
margin: 0;
|
|
32050
|
+
padding: 0;
|
|
32051
|
+
}
|
|
32052
|
+
.cn-link-cards-page__cell[data-v-2f9a546b] {
|
|
32053
|
+
display: flex;
|
|
32054
|
+
}
|
|
32055
|
+
.cn-link-cards-page__card[data-v-2f9a546b] {
|
|
32056
|
+
align-items: flex-start;
|
|
32057
|
+
background: var(--color-main-background);
|
|
32058
|
+
border: 1px solid var(--color-border-dark);
|
|
32059
|
+
border-radius: var(--border-radius-large);
|
|
32060
|
+
color: var(--color-main-text);
|
|
32061
|
+
display: flex;
|
|
32062
|
+
flex: 1;
|
|
32063
|
+
gap: calc(3 * var(--default-grid-baseline));
|
|
32064
|
+
min-width: 0;
|
|
32065
|
+
padding: calc(4 * var(--default-grid-baseline));
|
|
32066
|
+
text-decoration: none;
|
|
32067
|
+
}
|
|
32068
|
+
.cn-link-cards-page__card[data-v-2f9a546b]:hover {
|
|
32069
|
+
background: var(--color-background-hover);
|
|
32070
|
+
border-color: var(--color-primary-element);
|
|
32071
|
+
}
|
|
32072
|
+
.cn-link-cards-page__card[data-v-2f9a546b]:focus-visible {
|
|
32073
|
+
border-color: var(--color-primary-element);
|
|
32074
|
+
outline: 2px solid var(--color-primary-element);
|
|
32075
|
+
outline-offset: 2px;
|
|
32076
|
+
}
|
|
32077
|
+
.cn-link-cards-page__icon[data-v-2f9a546b] {
|
|
32078
|
+
color: var(--color-primary-element);
|
|
32079
|
+
flex: none;
|
|
32080
|
+
}
|
|
32081
|
+
.cn-link-cards-page__body[data-v-2f9a546b] {
|
|
32082
|
+
display: flex;
|
|
32083
|
+
flex-direction: column;
|
|
32084
|
+
gap: var(--default-grid-baseline);
|
|
32085
|
+
min-width: 0;
|
|
32086
|
+
}
|
|
32087
|
+
.cn-link-cards-page__label[data-v-2f9a546b] {
|
|
32088
|
+
font-weight: 600;
|
|
32089
|
+
overflow-wrap: anywhere;
|
|
32090
|
+
}
|
|
32091
|
+
.cn-link-cards-page__card-description[data-v-2f9a546b] {
|
|
32092
|
+
color: var(--color-text-maxcontrast);
|
|
32093
|
+
font-size: 0.9em;
|
|
32094
|
+
line-height: 1.4;
|
|
32095
|
+
}
|
|
32096
|
+
|
|
32097
|
+
|
|
32008
32098
|
/* NcDialog supplies the padding and the heading (via `name`); this div keeps only
|
|
32009
32099
|
the body's own column layout. */
|
|
32010
32100
|
.cn-page-config[data-v-9e9a9cf8] {
|
|
@@ -130,10 +130,15 @@ function capitalize(str) {
|
|
|
130
130
|
*
|
|
131
131
|
* Array values are serialized with PHP bracket notation (`key[]=a&key[]=b`)
|
|
132
132
|
* so the Nextcloud/OpenRegister backend parses them as an array — a plain
|
|
133
|
-
* repeated `key=a&key=b` collapses to the last value in PHP.
|
|
134
|
-
*
|
|
133
|
+
* repeated `key=a&key=b` collapses to the last value in PHP. A plain object
|
|
134
|
+
* under a filter key is a set of operators and goes out in bracket form
|
|
135
|
+
* (`{ deadline: { lt: 'x' } }` becomes `deadline[lt]=x`); a key already
|
|
136
|
+
* written that way (`'deadline[lt]'`) passes through unchanged. Reserved keys
|
|
137
|
+
* that start with `_` keep their JSON form (`_order`). Skips
|
|
135
138
|
* null/undefined/empty values.
|
|
136
139
|
*
|
|
140
|
+
* @spec openspec/changes/link-cards-page/specs/link-cards-page/spec.md#requirement-a-filter-operator-is-serialised-in-bracket-form
|
|
141
|
+
*
|
|
137
142
|
* @param {object} params Key-value pairs for query parameters
|
|
138
143
|
* @return {string} Query string including leading '?' or empty string
|
|
139
144
|
*/
|
|
@@ -159,6 +164,27 @@ function buildQueryString(params = {}) {
|
|
|
159
164
|
queryParams.append(arrayKey, String(item));
|
|
160
165
|
}
|
|
161
166
|
}
|
|
167
|
+
} else if (typeof value === 'object' && !key.startsWith('_')) {
|
|
168
|
+
// A filter operator: `{ deadline: { lt: '2026-10-06' } }` goes out
|
|
169
|
+
// as `deadline[lt]=2026-10-06`, the form OpenRegister reads. As
|
|
170
|
+
// JSON it reached the database as the literal value and a date
|
|
171
|
+
// column answered 500. Reserved `_` keys (`_order`) keep JSON.
|
|
172
|
+
for (const [op, operand] of Object.entries(value)) {
|
|
173
|
+
if (operand === undefined || operand === null || operand === '') {
|
|
174
|
+
continue
|
|
175
|
+
}
|
|
176
|
+
if (Array.isArray(operand)) {
|
|
177
|
+
for (const item of operand) {
|
|
178
|
+
if (item !== undefined && item !== null && item !== '') {
|
|
179
|
+
queryParams.append(`${key}[${op}][]`, String(item));
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
} else if (typeof operand === 'object') {
|
|
183
|
+
queryParams.set(`${key}[${op}]`, JSON.stringify(operand));
|
|
184
|
+
} else {
|
|
185
|
+
queryParams.set(`${key}[${op}]`, String(operand));
|
|
186
|
+
}
|
|
187
|
+
}
|
|
162
188
|
} else if (typeof value === 'object') {
|
|
163
189
|
queryParams.set(key, JSON.stringify(value));
|
|
164
190
|
} else {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"headers.js","sources":["../../../src/utils/headers.js"],"sourcesContent":["import { generateUrl } from '@nextcloud/router'\n\n/**\n * Prefix an app-absolute URL path the way `generateUrl()` would: the instance\n * webroot, plus `/index.php` unless Nextcloud reports working URL rewriting.\n *\n * On an instance without pretty URLs the bare `/apps/<app>/api/...` form is\n * not routed at all and answers the web server's own 404, which is why every\n * internal API path has to pass through here or through `generateUrl()`.\n *\n * Only the PREFIX comes from `generateUrl()`: the path itself is appended\n * untouched, because `generateUrl()` URL-encodes any `{placeholder}` it cannot\n * fill, and callers pass templates filled later and JSON query values.\n *\n * Idempotent, and inert on anything that is not an app-absolute path, since it\n * is wrapped around hundreds of call sites: an absolute or protocol-relative\n * URL, a scheme (`data:`, `blob:`, `mailto:`), a document-relative path, or a\n * path already carrying the webroot or `/index.php` comes back unchanged.\n * `/ocs/`, `/remote.php` and `/public.php` get the webroot only, as they are\n * never served behind `/index.php`.\n *\n * @param {string} path URL path (e.g. '/apps/openregister/api/objects')\n * @return {string} The path as the instance routes it\n */\nexport function prefixUrl(path) {\n\tif (typeof path !== 'string' || path === '') {\n\t\treturn path\n\t}\n\t// Absolute URL, protocol-relative URL, or any scheme (data:, blob:, mailto:).\n\tif (/^[a-z][a-z0-9+.-]*:/i.test(path) || path.startsWith('//')) {\n\t\treturn path\n\t}\n\t// Only app-absolute paths are ours to prefix.\n\tif (!path.startsWith('/')) {\n\t\treturn path\n\t}\n\t// `generateUrl('/')` is `<webroot>[/index.php]/`; the webroot is that minus `/index.php`.\n\tconst prefix = generateUrl('/', {}).replace(/\\/$/, '')\n\tconst root = prefix.replace(/\\/index\\.php$/, '')\n\tif (path.startsWith('/index.php') || (root && (path === root || path.startsWith(root + '/')))) {\n\t\treturn path\n\t}\n\tif (/^\\/(ocs|remote\\.php|public\\.php)(\\/|$)/.test(path)) {\n\t\treturn root + path\n\t}\n\treturn prefix + path\n}\n\n/**\n * Build standard Nextcloud request headers for API calls.\n *\n * Includes the CSRF request token and OCS API request header\n * required by Nextcloud's API layer.\n *\n * Two call shapes are supported:\n *\n * 1. **Positional (back-compat)** — `buildHeaders(contentType)`.\n * Returns the same object the v1 signature did.\n *\n * 2. **Options object** — `buildHeaders({ contentType?, organisationUuid?, targetLanguage? })`.\n * When `organisationUuid` is a non-empty string the returned object\n * includes `X-OpenRegister-Organisation: <uuid>`. The header is the\n * FE side of the `multi-tenancy-context` capability and is consumed\n * by OR's MultiTenancyTrait.\n * When `targetLanguage` is a non-empty BCP-47 string the returned\n * object includes `X-Translation-Target-Language: <bcp47>`. The\n * header is the FE side of the `i18n-source-of-truth` write\n * contract — OR stamps the value into `_translations[<bcp47>]`\n * instead of overwriting the source row. See the\n * `i18n-language-negotiation-getters` change.\n *\n * @param {string|object} [opts] Content-Type string (back-compat) or options object.\n * @param {string} [opts.contentType] Content-Type header value\n * @param {string} [opts.organisationUuid] Active organisation UUID for the request\n * @param {string} [opts.targetLanguage] BCP-47 target language for translation writes\n * @return {object} Headers object for use with fetch()\n */\nexport function buildHeaders(opts = 'application/json') {\n\tlet contentType = 'application/json'\n\tlet organisationUuid = null\n\tlet targetLanguage = null\n\n\tif (typeof opts === 'string') {\n\t\t// v1 positional signature: buildHeaders(contentType)\n\t\tcontentType = opts\n\t} else if (opts === null) {\n\t\t// v1 positional signature: buildHeaders(null) — explicit \"no Content-Type\"\n\t\tcontentType = null\n\t} else if (opts && typeof opts === 'object') {\n\t\t// Options-object signature\n\t\tif (Object.hasOwn(opts, 'contentType')) {\n\t\t\tcontentType = opts.contentType\n\t\t}\n\t\tif (typeof opts.organisationUuid === 'string' && opts.organisationUuid.length > 0) {\n\t\t\torganisationUuid = opts.organisationUuid\n\t\t}\n\t\tif (typeof opts.targetLanguage === 'string' && opts.targetLanguage.length > 0) {\n\t\t\ttargetLanguage = opts.targetLanguage\n\t\t}\n\t}\n\n\tconst headers = {\n\t\trequesttoken: typeof OC !== 'undefined' ? OC.requestToken : '',\n\t\t'OCS-APIREQUEST': 'true',\n\t}\n\tif (contentType) {\n\t\theaders['Content-Type'] = contentType\n\t}\n\tif (organisationUuid) {\n\t\theaders['X-OpenRegister-Organisation'] = organisationUuid\n\t}\n\tif (targetLanguage) {\n\t\theaders['X-Translation-Target-Language'] = targetLanguage\n\t}\n\treturn headers\n}\n\n/**\n * Capitalize the first letter of a string.\n *\n * @param {string} str Input string\n * @return {string} Capitalized string\n */\nexport function capitalize(str) {\n\treturn str.charAt(0).toUpperCase() + str.slice(1)\n}\n\n/**\n * Build a query string from a params object.\n *\n * Array values are serialized with PHP bracket notation (`key[]=a&key[]=b`)\n * so the Nextcloud/OpenRegister backend parses them as an array — a plain\n * repeated `key=a&key=b` collapses to the last value in PHP. Also handles\n * _order serialization (JSON.stringify for objects) and skips\n * null/undefined/empty values.\n *\n * @param {object} params Key-value pairs for query parameters\n * @return {string} Query string including leading '?' or empty string\n */\nexport function buildQueryString(params = {}) {\n\tconst queryParams = new URLSearchParams()\n\n\tfor (const [key, value] of Object.entries(params)) {\n\t\tif (value === undefined || value === null || value === '') {\n\t\t\tcontinue\n\t\t}\n\t\tif (Array.isArray(value) && value.length === 0) {\n\t\t\tcontinue\n\t\t}\n\t\tif (typeof value === 'object' && !Array.isArray(value) && Object.keys(value).length === 0) {\n\t\t\tcontinue\n\t\t}\n\t\tif (Array.isArray(value)) {\n\t\t\t// PHP needs `key[]` to receive repeated params as an array;\n\t\t\t// without the brackets only the last value survives server-side.\n\t\t\tconst arrayKey = key.endsWith('[]') ? key : `${key}[]`\n\t\t\tfor (const item of value) {\n\t\t\t\tif (item !== undefined && item !== null && item !== '') {\n\t\t\t\t\tqueryParams.append(arrayKey, String(item))\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (typeof value === 'object') {\n\t\t\tqueryParams.set(key, JSON.stringify(value))\n\t\t} else {\n\t\t\tqueryParams.set(key, String(value))\n\t\t}\n\t}\n\n\tconst str = queryParams.toString()\n\treturn str ? '?' + str : ''\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"headers.js","sources":["../../../src/utils/headers.js"],"sourcesContent":["import { generateUrl } from '@nextcloud/router'\n\n/**\n * Prefix an app-absolute URL path the way `generateUrl()` would: the instance\n * webroot, plus `/index.php` unless Nextcloud reports working URL rewriting.\n *\n * On an instance without pretty URLs the bare `/apps/<app>/api/...` form is\n * not routed at all and answers the web server's own 404, which is why every\n * internal API path has to pass through here or through `generateUrl()`.\n *\n * Only the PREFIX comes from `generateUrl()`: the path itself is appended\n * untouched, because `generateUrl()` URL-encodes any `{placeholder}` it cannot\n * fill, and callers pass templates filled later and JSON query values.\n *\n * Idempotent, and inert on anything that is not an app-absolute path, since it\n * is wrapped around hundreds of call sites: an absolute or protocol-relative\n * URL, a scheme (`data:`, `blob:`, `mailto:`), a document-relative path, or a\n * path already carrying the webroot or `/index.php` comes back unchanged.\n * `/ocs/`, `/remote.php` and `/public.php` get the webroot only, as they are\n * never served behind `/index.php`.\n *\n * @param {string} path URL path (e.g. '/apps/openregister/api/objects')\n * @return {string} The path as the instance routes it\n */\nexport function prefixUrl(path) {\n\tif (typeof path !== 'string' || path === '') {\n\t\treturn path\n\t}\n\t// Absolute URL, protocol-relative URL, or any scheme (data:, blob:, mailto:).\n\tif (/^[a-z][a-z0-9+.-]*:/i.test(path) || path.startsWith('//')) {\n\t\treturn path\n\t}\n\t// Only app-absolute paths are ours to prefix.\n\tif (!path.startsWith('/')) {\n\t\treturn path\n\t}\n\t// `generateUrl('/')` is `<webroot>[/index.php]/`; the webroot is that minus `/index.php`.\n\tconst prefix = generateUrl('/', {}).replace(/\\/$/, '')\n\tconst root = prefix.replace(/\\/index\\.php$/, '')\n\tif (path.startsWith('/index.php') || (root && (path === root || path.startsWith(root + '/')))) {\n\t\treturn path\n\t}\n\tif (/^\\/(ocs|remote\\.php|public\\.php)(\\/|$)/.test(path)) {\n\t\treturn root + path\n\t}\n\treturn prefix + path\n}\n\n/**\n * Build standard Nextcloud request headers for API calls.\n *\n * Includes the CSRF request token and OCS API request header\n * required by Nextcloud's API layer.\n *\n * Two call shapes are supported:\n *\n * 1. **Positional (back-compat)** — `buildHeaders(contentType)`.\n * Returns the same object the v1 signature did.\n *\n * 2. **Options object** — `buildHeaders({ contentType?, organisationUuid?, targetLanguage? })`.\n * When `organisationUuid` is a non-empty string the returned object\n * includes `X-OpenRegister-Organisation: <uuid>`. The header is the\n * FE side of the `multi-tenancy-context` capability and is consumed\n * by OR's MultiTenancyTrait.\n * When `targetLanguage` is a non-empty BCP-47 string the returned\n * object includes `X-Translation-Target-Language: <bcp47>`. The\n * header is the FE side of the `i18n-source-of-truth` write\n * contract — OR stamps the value into `_translations[<bcp47>]`\n * instead of overwriting the source row. See the\n * `i18n-language-negotiation-getters` change.\n *\n * @param {string|object} [opts] Content-Type string (back-compat) or options object.\n * @param {string} [opts.contentType] Content-Type header value\n * @param {string} [opts.organisationUuid] Active organisation UUID for the request\n * @param {string} [opts.targetLanguage] BCP-47 target language for translation writes\n * @return {object} Headers object for use with fetch()\n */\nexport function buildHeaders(opts = 'application/json') {\n\tlet contentType = 'application/json'\n\tlet organisationUuid = null\n\tlet targetLanguage = null\n\n\tif (typeof opts === 'string') {\n\t\t// v1 positional signature: buildHeaders(contentType)\n\t\tcontentType = opts\n\t} else if (opts === null) {\n\t\t// v1 positional signature: buildHeaders(null) — explicit \"no Content-Type\"\n\t\tcontentType = null\n\t} else if (opts && typeof opts === 'object') {\n\t\t// Options-object signature\n\t\tif (Object.hasOwn(opts, 'contentType')) {\n\t\t\tcontentType = opts.contentType\n\t\t}\n\t\tif (typeof opts.organisationUuid === 'string' && opts.organisationUuid.length > 0) {\n\t\t\torganisationUuid = opts.organisationUuid\n\t\t}\n\t\tif (typeof opts.targetLanguage === 'string' && opts.targetLanguage.length > 0) {\n\t\t\ttargetLanguage = opts.targetLanguage\n\t\t}\n\t}\n\n\tconst headers = {\n\t\trequesttoken: typeof OC !== 'undefined' ? OC.requestToken : '',\n\t\t'OCS-APIREQUEST': 'true',\n\t}\n\tif (contentType) {\n\t\theaders['Content-Type'] = contentType\n\t}\n\tif (organisationUuid) {\n\t\theaders['X-OpenRegister-Organisation'] = organisationUuid\n\t}\n\tif (targetLanguage) {\n\t\theaders['X-Translation-Target-Language'] = targetLanguage\n\t}\n\treturn headers\n}\n\n/**\n * Capitalize the first letter of a string.\n *\n * @param {string} str Input string\n * @return {string} Capitalized string\n */\nexport function capitalize(str) {\n\treturn str.charAt(0).toUpperCase() + str.slice(1)\n}\n\n/**\n * Build a query string from a params object.\n *\n * Array values are serialized with PHP bracket notation (`key[]=a&key[]=b`)\n * so the Nextcloud/OpenRegister backend parses them as an array — a plain\n * repeated `key=a&key=b` collapses to the last value in PHP. A plain object\n * under a filter key is a set of operators and goes out in bracket form\n * (`{ deadline: { lt: 'x' } }` becomes `deadline[lt]=x`); a key already\n * written that way (`'deadline[lt]'`) passes through unchanged. Reserved keys\n * that start with `_` keep their JSON form (`_order`). Skips\n * null/undefined/empty values.\n *\n * @spec openspec/changes/link-cards-page/specs/link-cards-page/spec.md#requirement-a-filter-operator-is-serialised-in-bracket-form\n *\n * @param {object} params Key-value pairs for query parameters\n * @return {string} Query string including leading '?' or empty string\n */\nexport function buildQueryString(params = {}) {\n\tconst queryParams = new URLSearchParams()\n\n\tfor (const [key, value] of Object.entries(params)) {\n\t\tif (value === undefined || value === null || value === '') {\n\t\t\tcontinue\n\t\t}\n\t\tif (Array.isArray(value) && value.length === 0) {\n\t\t\tcontinue\n\t\t}\n\t\tif (typeof value === 'object' && !Array.isArray(value) && Object.keys(value).length === 0) {\n\t\t\tcontinue\n\t\t}\n\t\tif (Array.isArray(value)) {\n\t\t\t// PHP needs `key[]` to receive repeated params as an array;\n\t\t\t// without the brackets only the last value survives server-side.\n\t\t\tconst arrayKey = key.endsWith('[]') ? key : `${key}[]`\n\t\t\tfor (const item of value) {\n\t\t\t\tif (item !== undefined && item !== null && item !== '') {\n\t\t\t\t\tqueryParams.append(arrayKey, String(item))\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (typeof value === 'object' && !key.startsWith('_')) {\n\t\t\t// A filter operator: `{ deadline: { lt: '2026-10-06' } }` goes out\n\t\t\t// as `deadline[lt]=2026-10-06`, the form OpenRegister reads. As\n\t\t\t// JSON it reached the database as the literal value and a date\n\t\t\t// column answered 500. Reserved `_` keys (`_order`) keep JSON.\n\t\t\tfor (const [op, operand] of Object.entries(value)) {\n\t\t\t\tif (operand === undefined || operand === null || operand === '') {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif (Array.isArray(operand)) {\n\t\t\t\t\tfor (const item of operand) {\n\t\t\t\t\t\tif (item !== undefined && item !== null && item !== '') {\n\t\t\t\t\t\t\tqueryParams.append(`${key}[${op}][]`, String(item))\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else if (typeof operand === 'object') {\n\t\t\t\t\tqueryParams.set(`${key}[${op}]`, JSON.stringify(operand))\n\t\t\t\t} else {\n\t\t\t\t\tqueryParams.set(`${key}[${op}]`, String(operand))\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (typeof value === 'object') {\n\t\t\tqueryParams.set(key, JSON.stringify(value))\n\t\t} else {\n\t\t\tqueryParams.set(key, String(value))\n\t\t}\n\t}\n\n\tconst str = queryParams.toString()\n\treturn str ? '?' + str : ''\n}\n"],"names":[],"mappings":"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"}
|