@conduction/nextcloud-vue 2.56.0-beta.5 → 2.56.0-beta.6

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.
@@ -322,6 +322,26 @@ const CORE_TABS = ['files', 'notes', 'tags', 'tasks', 'auditTrail', 'shares']
322
322
  /** One-time guard so the legacy-path deprecation warning logs only once. */
323
323
  let legacyWarned = false
324
324
 
325
+ /**
326
+ * Schema titles by numeric schema id, shared by every widget on the page so a
327
+ * schema is asked for once. OpenRegister's `/uses` and `/used` answer
328
+ * `@self.schema` as that id ("120"), which is not a word anyone can read.
329
+ *
330
+ * @type {Map<string, Promise<string>>}
331
+ */
332
+ const schemaTitleCache = new Map()
333
+
334
+ /**
335
+ * Whether a value is a bare number, the way OpenRegister names a schema by id.
336
+ *
337
+ * @param {string|number|undefined|null} value The value.
338
+ * @return {boolean}
339
+ */
340
+ function isNumericId(value) {
341
+ return (typeof value === 'number' && Number.isFinite(value))
342
+ || (typeof value === 'string' && /^\d+$/.test(value.trim()))
343
+ }
344
+
325
345
  /**
326
346
  * Leaf groups surfaced by the aggregated `/relations` endpoint, in tab order.
327
347
  * `responseKey` is the key in the `/relations` payload; `integrationId` is the
@@ -404,6 +424,14 @@ export default {
404
424
  NcEmptyContent,
405
425
  },
406
426
 
427
+ inject: {
428
+ /**
429
+ * The host app's translator (CnAppRoot provides it), so a schema title
430
+ * reads in the app's language. Without it a title reads as stored.
431
+ */
432
+ cnTranslate: { default: () => (key) => key },
433
+ },
434
+
407
435
  props: {
408
436
  /** Widget title shown in the header. */
409
437
  title: {
@@ -667,6 +695,8 @@ export default {
667
695
  * @type {HTMLInputElement|null}
668
696
  */
669
697
  fileInputEl: null,
698
+ /** Schema titles by numeric schema id, for object rows. */
699
+ schemaTitles: {},
670
700
  /** Whether any section/tab is currently fetching. */
671
701
  loading: false,
672
702
  /** True once the first fetch has completed (gates the empty state). */
@@ -1359,9 +1389,74 @@ export default {
1359
1389
  self.name,
1360
1390
  raw.summary,
1361
1391
  raw.description,
1362
- ].find((v) => typeof v === 'string' && v.trim() && !isUuid(v)) || self.schema || String(id)
1363
- const meta = self.schema || raw.schema || ''
1364
- return { id, label, meta: typeof meta === 'string' ? meta : '', raw }
1392
+ ].find((v) => typeof v === 'string' && v.trim() && !isUuid(v))
1393
+ || [raw.givenName, raw.familyName].filter((v) => typeof v === 'string' && v.trim()).join(' ')
1394
+ // OpenRegister names the schema by numeric id: show its title, never the number.
1395
+ const schema = this.schemaName(self.schema || raw.schema)
1396
+ const finalLabel = label || schema || String(id)
1397
+ return { id, label: finalLabel, meta: schema === finalLabel ? '' : schema, raw }
1398
+ },
1399
+
1400
+ /**
1401
+ * How a row names its schema: the translated title for a numeric id
1402
+ * (empty until it is read, or when it cannot be), a slug as it is.
1403
+ *
1404
+ * @param {string|number|undefined|null} schema - `@self.schema` of the related object.
1405
+ * @return {string}
1406
+ */
1407
+ schemaName(schema) {
1408
+ if (isNumericId(schema)) {
1409
+ const title = this.schemaTitles[String(schema).trim()]
1410
+ return title ? this.cnTranslate(title) : ''
1411
+ }
1412
+ return typeof schema === 'string' ? schema : ''
1413
+ },
1414
+
1415
+ /**
1416
+ * Read the titles of the numeric schema ids in these envelopes once,
1417
+ * before the rows are built, so no row shows a number first.
1418
+ *
1419
+ * @param {Array<object|null>} envelopes - The `{ results }` payloads.
1420
+ * @return {Promise<void>}
1421
+ */
1422
+ async resolveSchemaTitles(envelopes) {
1423
+ const ids = new Set()
1424
+ for (const envelope of envelopes) {
1425
+ for (const raw of ((envelope && envelope.results) || [])) {
1426
+ const schema = (raw && (raw['@self'] || {}).schema) ?? (raw && raw.schema)
1427
+ if (isNumericId(schema)) {
1428
+ ids.add(String(schema).trim())
1429
+ }
1430
+ }
1431
+ }
1432
+ const titles = { ...this.schemaTitles }
1433
+ await Promise.all([...ids].filter((id) => !(id in titles)).map(async (id) => {
1434
+ if (!schemaTitleCache.has(id)) {
1435
+ schemaTitleCache.set(id, this.fetchSchemaTitle(id))
1436
+ }
1437
+ titles[id] = await schemaTitleCache.get(id)
1438
+ }))
1439
+ this.schemaTitles = titles
1440
+ },
1441
+
1442
+ /**
1443
+ * GET one schema's title; '' when it cannot be read.
1444
+ *
1445
+ * @param {string} id - The numeric schema id.
1446
+ * @return {Promise<string>}
1447
+ */
1448
+ async fetchSchemaTitle(id) {
1449
+ try {
1450
+ const response = await fetch(generateUrl('/apps/openregister/api/schemas/{id}', { id }), { method: 'GET', headers: buildHeaders() })
1451
+ if (!response.ok) {
1452
+ return ''
1453
+ }
1454
+ const schema = await response.json()
1455
+ const title = schema && (schema.title || schema.slug)
1456
+ return typeof title === 'string' ? title : ''
1457
+ } catch {
1458
+ return ''
1459
+ }
1365
1460
  },
1366
1461
 
1367
1462
  /**
@@ -1465,6 +1560,7 @@ export default {
1465
1560
  const groups = []
1466
1561
 
1467
1562
  if (this.showObjects) {
1563
+ await this.resolveSchemaTitles([uses, used, contracts])
1468
1564
  const objectItems = this.mergeObjectResults([uses, used, contracts])
1469
1565
  groups.push({ key: 'objects', label: this.objectsLabel, icon: 'FileTreeOutline', integrationId: '', items: objectItems, total: objectItems.length })
1470
1566
  }
@@ -1590,6 +1686,7 @@ export default {
1590
1686
  calls.push(store.fetchContracts(type, id))
1591
1687
  }
1592
1688
  const groups = await Promise.all(calls)
1689
+ await this.resolveSchemaTitles(groups.map((results) => ({ results: results || [] })))
1593
1690
  const seen = new Set()
1594
1691
  const merged = []
1595
1692
  for (const group of groups) {