@xen-orchestra/web-core 0.19.0 → 0.20.1

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.
Files changed (56) hide show
  1. package/lib/assets/all-done.svg +62 -0
  2. package/lib/assets/all-good.svg +113 -0
  3. package/lib/assets/error.svg +57 -372
  4. package/lib/assets/no-data.svg +190 -65
  5. package/lib/assets/not-found.svg +446 -126
  6. package/lib/assets/offline.svg +118 -0
  7. package/lib/assets/under-construction.svg +245 -193
  8. package/lib/assets/zoom.svg +85 -0
  9. package/lib/components/backdrop/VtsBackdrop.vue +1 -1
  10. package/lib/components/column/VtsColumn.vue +21 -0
  11. package/lib/components/columns/VtsColumns.vue +38 -0
  12. package/lib/components/copy-button/VtsCopyButton.vue +29 -0
  13. package/lib/components/enabled-state/VtsEnabledState.vue +23 -0
  14. package/lib/components/layout/VtsLayoutSidebar.vue +1 -1
  15. package/lib/components/quick-info-column/VtsQuickInfoColumn.vue +1 -1
  16. package/lib/components/quick-info-row/VtsQuickInfoRow.vue +26 -7
  17. package/lib/components/relative-time/VtsRelativeTime.vue +18 -0
  18. package/lib/components/select/VtsOption.vue +24 -0
  19. package/lib/components/select/VtsSelect.vue +96 -0
  20. package/lib/components/state-hero/VtsAllDoneHero.vue +13 -0
  21. package/lib/components/state-hero/VtsAllGoodHero.vue +13 -0
  22. package/lib/components/state-hero/VtsLoadingHero.vue +45 -4
  23. package/lib/components/state-hero/VtsOfflineHero.vue +13 -0
  24. package/lib/components/state-hero/VtsStateHero.vue +10 -1
  25. package/lib/components/tree/VtsTreeItem.vue +11 -1
  26. package/lib/components/ui/card-numbers/UiCardNumbers.vue +15 -36
  27. package/lib/components/ui/dropdown/UiDropdownList.vue +10 -2
  28. package/lib/components/ui/head-bar/UiHeadBar.vue +2 -2
  29. package/lib/composables/relative-time.composable.ts +1 -1
  30. package/lib/locales/cs.json +74 -8
  31. package/lib/locales/de.json +4 -0
  32. package/lib/locales/en.json +67 -1
  33. package/lib/locales/es.json +8 -5
  34. package/lib/locales/fa.json +0 -1
  35. package/lib/locales/fr.json +69 -3
  36. package/lib/locales/nl.json +50 -9
  37. package/lib/locales/ru.json +27 -0
  38. package/lib/locales/sv.json +77 -13
  39. package/lib/packages/collection/README.md +38 -33
  40. package/lib/packages/collection/create-collection.ts +27 -13
  41. package/lib/packages/collection/create-item.ts +39 -0
  42. package/lib/packages/collection/guess-item-id.ts +26 -0
  43. package/lib/packages/collection/index.ts +0 -3
  44. package/lib/packages/collection/types.ts +46 -18
  45. package/lib/packages/collection/use-collection.ts +39 -7
  46. package/lib/packages/collection/use-flag-registry.ts +22 -5
  47. package/lib/packages/form-select/README.md +96 -0
  48. package/lib/packages/form-select/index.ts +2 -0
  49. package/lib/packages/form-select/types.ts +75 -0
  50. package/lib/packages/form-select/use-form-option-controller.ts +50 -0
  51. package/lib/packages/form-select/use-form-select-controller.ts +205 -0
  52. package/lib/packages/form-select/use-form-select-keyboard-navigation.ts +157 -0
  53. package/lib/packages/form-select/use-form-select.ts +193 -0
  54. package/lib/stores/sidebar.store.ts +14 -1
  55. package/package.json +1 -1
  56. package/lib/packages/collection/build-item.ts +0 -45
@@ -47,14 +47,17 @@
47
47
  "backups.vms-protection.protected": "I minst ett jobb och skyddad",
48
48
  "backups.vms-protection.tooltip": "En VM är skyddad om den är med i ett säkerhetskopieringsjobb, med ett aktivt schema och den senaste körningen lyckades",
49
49
  "backups.vms-protection.unprotected": "Med i minst 1 jobb men oskyddad",
50
+ "best-effort": "bästa möjliga insats",
50
51
  "bios-default": "bios (standardinställt)",
52
+ "bios-info": "BIOS-info",
51
53
  "bond": "Bindning",
52
54
  "bond-devices": "Bindningsenheter",
53
55
  "bond-status": "Bindnings-status",
54
56
  "boot-firmware": "Boot-programvara",
55
- "boot-firmware-bios": "Den här mallen innehåller redan Bios-strängar",
57
+ "boot-firmware-bios": "Den här mallen innehåller redan BIOS-strängar",
56
58
  "boot-firmware-uefi": "Boot-programvaran är UEFI",
57
59
  "boot-vm": "Starta VM",
60
+ "build-number": "Versionsnummer",
58
61
  "bytes.gi": "GiB",
59
62
  "bytes.ki": "KiB",
60
63
  "bytes.mi": "MiB",
@@ -76,10 +79,12 @@
76
79
  "console-actions": "Konsolverktyg",
77
80
  "console-clipboard": "Konsolurklipp",
78
81
  "console-unavailable": "Konsolen är inte tillgänglig",
82
+ "control-domain-memory": "Kontrolldomänens minne",
79
83
  "copy": "Kopiera",
80
84
  "copy-all": "Kopiera allt",
81
85
  "copy-host": "Kopiera värddator",
82
86
  "copy-info-json": "Kopiera informationen till JSON",
87
+ "core-socket": "Kärna (sockel)",
83
88
  "core.character-limit": "{count}/{max} tecken | {count}/{max} tecken",
84
89
  "core.close": "Stäng",
85
90
  "core.copied": "Kopierad",
@@ -110,15 +115,21 @@
110
115
  "core.sort.descending": "Sotera fallande",
111
116
  "core.textarea.exceeds-max-characters": "Fältet får enbart vara {max} tecken eller färre.",
112
117
  "cores-with-sockets": "Kärnor (sockets)",
118
+ "cpu-cap": "CPU-gräns",
119
+ "cpu-mask": "CPU-mask",
120
+ "cpu-model": "CPU-modell",
113
121
  "cpu-provisioning": "CPU-provisionering",
114
122
  "cpu-provisioning-warning": "Antalet vCPU:er som allokerats överskrider antalet fysiska CPU:er. Systemets prestanda kan påverkas",
115
123
  "cpu-usage": "CPU-nyttjande",
124
+ "cpu-weight": "CPU-vikt",
125
+ "cpus": "CPU:er",
116
126
  "create": "Skapa",
117
127
  "custom-config": "Skräddarsydd konfiguration",
118
128
  "dark-mode.auto": "Automatiskt mörkt läge",
119
129
  "dark-mode.disable": "Inaktivera mörkt läge",
120
130
  "dark-mode.enable": "Aktivera mörkt läge",
121
131
  "dashboard": "Kontrollpanel",
132
+ "default-behavior": "Standardbeteende",
122
133
  "default-locking-mode": "Standard låsläge",
123
134
  "delete": "Radera",
124
135
  "delete-vms": "Radera 1 VM | Radera {n} VMar",
@@ -153,6 +164,7 @@
153
164
  "error-no-data": "Fel, kan inte samla data.",
154
165
  "error-occurred": "Ett fel har uppstått",
155
166
  "exit-fullscreen": "Stäng fullskärm",
167
+ "expiration-date": "Utgångsdatum",
156
168
  "export": "Exportera",
157
169
  "export-n-vms": "Exportera 1 VM | Exportera {n} VMar",
158
170
  "export-n-vms-manually": "Exportera 1 VM manuellt | Exportera {n} VMar manuellt",
@@ -184,10 +196,15 @@
184
196
  "fullscreen": "Fullskärm",
185
197
  "fullscreen-leave": "Lämna fullskärm",
186
198
  "gateway": "Gateway",
199
+ "general-information": "Generell information",
187
200
  "go-back": "Gå tillbaka",
201
+ "gpus": "GPU:er",
202
+ "graphics-display": "Grafik & Skärm",
188
203
  "gzip": "gzip",
189
204
  "hardware": "Hårdvara",
205
+ "hardware-specifications": "Hårdvaruspecifikationer",
190
206
  "here": "Här",
207
+ "high-availability": "Hög tillgänglighet (HA)",
191
208
  "host": "Host",
192
209
  "host-description": "Host-beskrivning",
193
210
  "host-internal-networks": "Host-interna nätverk",
@@ -203,6 +220,7 @@
203
220
  "hosts-status.running": "Igång",
204
221
  "hosts-status.unknown": "Okänt",
205
222
  "hosts-status.unknown.tooltip": "Host-data är otillgängligt",
223
+ "hyper-threading": "Multitrådning (SMT)",
206
224
  "id": "Id",
207
225
  "in-last-three-jobs": "I de senaste tre jobben",
208
226
  "install-settings": "Installationsinställningar",
@@ -212,6 +230,7 @@
212
230
  "ip-addresses": "IP-adresser",
213
231
  "ip-mode": "IP-läge",
214
232
  "is-primary-host": "{name} är den primära hosten",
233
+ "iscsi-iqn": "iSCSI IQN",
215
234
  "iso-dvd": "ISO/DVD",
216
235
  "job.vm-copy.bad-power-state": "VMen måste vara stoppad",
217
236
  "job.vm-copy.in-progress": "Kopiering pågår…",
@@ -262,6 +281,9 @@
262
281
  "language": "Språk",
263
282
  "last-week": "Föregående vecka",
264
283
  "learn-more": "Läs mer",
284
+ "license-socket": "Licensiera sockel",
285
+ "license-type": "Licenstyp",
286
+ "licensing": "Licensiering",
265
287
  "load-average": "Genomsnittslast",
266
288
  "load-now": "Ladda nu",
267
289
  "loading-hosts": "Ladda hostar…",
@@ -273,16 +295,26 @@
273
295
  "login-only-on-master": "Det går endast att logga in mot huvudhosten",
274
296
  "mac-address": "MAC-adress",
275
297
  "mac-addresses": "MAC-adresser",
298
+ "manage-citrix-pv-drivers-via-windows-update": "Hantera Citrix PV-drivrutiner genom Windows Update",
276
299
  "management": "Hantering",
300
+ "management-agent-version": "Hantera agentversion",
301
+ "manufacturer-info": "Tillverkarinfo",
277
302
  "master": "Primärhost",
303
+ "maximum-cpu-limit": "Maximal CPU-begränsning",
304
+ "maximum-dynamic-memory": "Maximalt dynamiskt minne",
305
+ "maximum-static-memory": "Maximalt statiskt minne",
278
306
  "memory": "Minne",
279
307
  "memory-usage": "Minnesanvändning",
280
308
  "migrate": "Migrera",
281
309
  "migrate-n-vms": "Migrera 1 VM | Migrera {n} VMar",
310
+ "minimum-cpu-limit": "Minimal CPU-begränsning",
311
+ "minimum-dynamic-memory": "Minimalt dynamiskt minne",
312
+ "minimum-static-memory": "Minimalt statiskt minne",
282
313
  "missing-patches": "Saknar uppdateringar",
283
314
  "more-actions": "Fler åtgärder",
284
315
  "mtu": "MTU",
285
316
  "multi-creation": "Multi-skapande",
317
+ "multi-pathing": "Multianslutning",
286
318
  "n-gb-left": "{n} GB kvar",
287
319
  "n-gb-required": "{n} GB behövs",
288
320
  "n-hosts": "1 host | {n} hostar",
@@ -290,6 +322,7 @@
290
322
  "n-missing": "{n} saknas",
291
323
  "n-vms": "1 VM | {n} VM:ar",
292
324
  "name": "Namn",
325
+ "nested-virtualization": "Nästlad virtualisering",
293
326
  "netmask": "Nätmaskadress",
294
327
  "network": "Nätverk",
295
328
  "network-block-device": "Nätverksblockenhet",
@@ -298,6 +331,7 @@
298
331
  "network-information": "Nätverksinformation",
299
332
  "network-throughput": "Nätverksflöde",
300
333
  "network-upload": "Ladda upp",
334
+ "networking": "Nätverk",
301
335
  "networks": "Nätverk",
302
336
  "new": "Ny",
303
337
  "new-features-are-coming": "Nya funktioner kommer snart!",
@@ -308,6 +342,7 @@
308
342
  "new-vm.name": "VM-namn",
309
343
  "news": "Nyheter",
310
344
  "news-name": "{name} nyheter",
345
+ "nic-type": "NIC-typ",
311
346
  "no-alarm-triggered": "Inga larm",
312
347
  "no-config": "Ingen konfiguration",
313
348
  "no-data": "Ingen data",
@@ -321,6 +356,7 @@
321
356
  "no-vif-detected": "Ingen VIF hittades",
322
357
  "none": "Inga",
323
358
  "not-found": "Hittades inte",
359
+ "not-yet-available": "Informationen är inte tillgänglig än",
324
360
  "object": "Objekt",
325
361
  "object-not-found": "Objektet {id} kan inte hittas…",
326
362
  "off": "Av",
@@ -329,6 +365,8 @@
329
365
  "on-object": "på {object}",
330
366
  "open-console-in-new-tab": "Öppna konsolen i ny tabb",
331
367
  "or": "Eller",
368
+ "os-kernel": "OS-kärna",
369
+ "os-name": "OS-namn",
332
370
  "other": "Annat",
333
371
  "page-not-found": "Den här sidan kan inte hittas…",
334
372
  "partially-connected": "Delvis ansluten",
@@ -343,6 +381,7 @@
343
381
  "pifs": "PIFar",
344
382
  "pifs-status": "PIF status",
345
383
  "please-confirm": "Vänligen bekräfta",
384
+ "pool": "Pool",
346
385
  "pool-cpu-usage": "Användning av CPU-pool",
347
386
  "pool-ram-usage": "Användning av RAM-pool",
348
387
  "pools": "Pooler",
@@ -353,14 +392,19 @@
353
392
  "pools-status.unreachable": "Onåbar",
354
393
  "pools-status.unreachable.tooltip": "Konfigurerade servrar som inte kan nås",
355
394
  "power-on-host-for-console": "Starta din host för att ansluta till konsolen",
395
+ "power-on-mode": "Strömpåslagningsläge",
356
396
  "power-on-vm-for-console": "Starta din VM för att ansluta till konsolen",
357
397
  "power-state": "Strömläge",
398
+ "primary-host": "Primär host",
358
399
  "professional-support": "Professionell support",
359
400
  "properties": "Egenskaper",
360
401
  "property": "Egenskap",
402
+ "protect-from-accidental-deletion": "Skydda från oönskad borttagning",
403
+ "protect-from-accidental-shutdown": "Skydda från oönskad nedstängning",
361
404
  "pxe": "PXE",
362
405
  "quick-info": "Snabbinfo",
363
406
  "ram": "RAM",
407
+ "ram-provisioning": "RAM provisionering",
364
408
  "ram-usage": "RAM-användning",
365
409
  "reboot": "Starta om",
366
410
  "receive": "Ta emot",
@@ -374,19 +418,23 @@
374
418
  "relative-time.past": "{str} sedan",
375
419
  "relative-time.second": "1 sekund | {n} sekunder",
376
420
  "relative-time.year": "1 år | {n} år",
421
+ "remote-syslog": "Fjärr-syslog",
422
+ "resource-management": "Resurshantering",
377
423
  "resources-overview": "Resursöversikt",
378
424
  "resume": "Återuppta",
379
425
  "running-vm": "Startad VM | Startade VMar",
380
426
  "s3-backup-repository": "S3 säkerhetskopieringsförvar",
381
427
  "save": "Spara",
382
428
  "scan-pifs": "Skanna PIF",
429
+ "scheduler-granularity": "Schemaläggningsgrad",
430
+ "secure-boot": "Säker boot",
383
431
  "see-all": "Se alla",
384
- "select-compression": "Välj en komprimering",
385
- "select-destination-host": "Välj en destinationshost",
432
+ "select-compression": "Välj komprimering",
433
+ "select-destination-host": "Välj en destinations-host",
386
434
  "select-host": "Välj host",
387
435
  "select-to-see-details": "Välj ett objekt för att se detaljer",
388
436
  "select.network": "Välj ett nätverk",
389
- "select.storage": "Välj en lagring",
437
+ "select.storage": "Välj lagring",
390
438
  "selected-vms-in-execution": "Vissa av de markerade VMarna är igång",
391
439
  "send": "Skicka",
392
440
  "send-ctrl-alt-del": "Skicka Ctrl+Alt+Del",
@@ -398,6 +446,7 @@
398
446
  "size": "Storlek",
399
447
  "snapshot": "Snapshot",
400
448
  "sockets-with-cores-per-socket": "{nSockets} socklar × {nCores} kärnor/sockel",
449
+ "software-tooling": "Mjukvara & verktyg",
401
450
  "sort-by": "Sortera efter",
402
451
  "speed": "Hastighet",
403
452
  "sr": "SR",
@@ -409,6 +458,7 @@
409
458
  "stacked-cpu-usage": "Staplad CPU-användning",
410
459
  "stacked-ram-usage": "Staplad RAM-användning",
411
460
  "start": "Starta",
461
+ "start-delay": "Startfördröjning",
412
462
  "start-on-host": "Starta på specifik host",
413
463
  "started": "Startad",
414
464
  "state": "Status",
@@ -417,14 +467,17 @@
417
467
  "stats": "Statistik",
418
468
  "status": "Status",
419
469
  "storage": "Lagring",
470
+ "storage-configuration": "Lagringskonfiguration",
420
471
  "storage-repositories": "Lagringsförvar",
421
472
  "storage-repository": "Lagringsförvar",
422
- "storage-usage": "Lagringsanvändande",
473
+ "storage-usage": "Lagringsanvändning",
423
474
  "summary": "Summering",
424
475
  "support": "Support",
425
476
  "suspend": "Suspendera",
477
+ "suspend-storage-repository": "Suspendera lagringsförvar",
426
478
  "switch-theme": "Byt tema",
427
479
  "system": "System",
480
+ "system-disks-health": "Systemdiskhälsa",
428
481
  "table-actions": "Tabellåtgärder",
429
482
  "tags": "Taggar",
430
483
  "task.estimated-end": "Estimerad sluttid",
@@ -432,7 +485,7 @@
432
485
  "task.started": "Startad",
433
486
  "tasks": "Uppgifter",
434
487
  "tasks.n-subtasks": "{n} underuppgift | {n} underuppgifter",
435
- "tasks.no-tasks": "In uppgifter",
488
+ "tasks.no-tasks": "Inga uppgifter",
436
489
  "tasks.quick-view": "Uppgifter snabbvy",
437
490
  "tasks.quick-view.all": "Alla",
438
491
  "tasks.quick-view.done": "Klar",
@@ -442,10 +495,13 @@
442
495
  "theme-auto": "Auto",
443
496
  "theme-dark": "Mörkt",
444
497
  "theme-light": "Ljust",
498
+ "this-host": "Den här hosten",
445
499
  "this-vm-cant-be-migrated": "Denna VM kan inte migreras",
500
+ "toolstack-uptime": "Verktygslagrets upptid",
446
501
  "top-#": "Topp {n}",
447
502
  "topology": "Topologi",
448
503
  "total": "Totalt",
504
+ "total-assigned": "Totalt tilldelat",
449
505
  "total-cpus": "Totalt antal CPUer",
450
506
  "total-free": "Totalt ledigt",
451
507
  "total-free:": "Totalt ledigt:",
@@ -462,22 +518,30 @@
462
518
  "user-config": "Användarkonfiguration",
463
519
  "uuid": "UUID",
464
520
  "vcpus": "vCPUer",
521
+ "vcpus-assigned": "vCPUs tilldelade",
465
522
  "vcpus-used": "vCPUer använt",
466
523
  "vdis": "VDI | VDI | VDIer",
467
524
  "version": "Version",
525
+ "vga": "VGA",
526
+ "video-ram": "Video RAM",
468
527
  "vif": "VIF",
469
528
  "vif-device": "VIF #{device}",
470
529
  "vif-status": "VIF-status",
471
530
  "vifs": "VIFar",
531
+ "viridian": "Viridian",
532
+ "virtual-tpm": "Virtuell TPM (VTPM)",
533
+ "virtualization-boot-settings": "Virtualisering & boot-inställningar",
534
+ "virtualization-mode": "Virtualiseringsläge",
472
535
  "vlan": "VLAN",
473
536
  "vm": "VM",
474
- "vm-description": "VM beskrivning",
475
- "vm-is-running": "Vmen är startad",
537
+ "vm-description": "VM-beskrivning",
538
+ "vm-is-running": "VMen är startad",
539
+ "vm-limit-topology": "VM-begränsningstopologi",
540
+ "vm-management": "VM-hantering",
476
541
  "vm.active": "Aktiv",
477
542
  "vm.inactive": "Inaktiv",
478
- "vmSocketsWithCoresPerSocket": "{nSockets} socklar × {nCores} kärnor/sockel",
479
543
  "vms": "VMar",
480
- "vms-status": "VM status",
544
+ "vms-status": "VM-status",
481
545
  "vms-status.halted": "Stannad",
482
546
  "vms-status.inactive": "Inaktiv",
483
547
  "vms-status.inactive.tooltip": "Avstängd eller suspenderad",
@@ -485,15 +549,15 @@
485
549
  "vms-status.running": "Igång",
486
550
  "vms-status.suspended": "Suspenderad",
487
551
  "vms-status.unknown": "Okänt",
488
- "vms-status.unknown.tooltip": "För vilken XO har förlorat kontakten med poolen",
552
+ "vms-status.unknown.tooltip": "Där XO har förlorat kontakten med poolen",
489
553
  "xo-backups": "XO-backuper",
490
554
  "xo-lite-under-construction": "XOLite är under uppbyggnad",
491
555
  "xo-replications": "XO-replikeringar",
492
556
  "xoa-admin-account": "XOA admin-konto",
493
- "xoa-deploy": "XOA driftsättning",
557
+ "xoa-deploy": "XOA-driftsättning",
494
558
  "xoa-deploy-failed": "Ledsen, driftsättning misslyckades!",
495
559
  "xoa-deploy-retry": "Försök att driftsätta XOA igen",
496
- "xoa-deploy-successful": "Driftsättning a XOA lyckades!",
560
+ "xoa-deploy-successful": "Driftsättning av XOA lyckades!",
497
561
  "xoa-ip": "XOA IP-adress",
498
562
  "xoa-password-confirm-different": "Bekräftelse av XOA-lösenord stämmer inte överens",
499
563
  "xoa-ssh-account": "XOA SSH-konto",
@@ -6,11 +6,11 @@ The `useCollection` composable helps you manage a collection of items with flags
6
6
 
7
7
  ```typescript
8
8
  const { items, useSubset, useFlag } = useCollection(sources, {
9
- identifier: source => source.id,
10
9
  flags: ['selected', 'active', { highlighted: { multiple: false } }],
11
10
  properties: source => ({
12
- isAvailable: computed(() => source.status === 'available'),
13
- fullName: computed(() => `${source.firstName} ${source.lastName}`),
11
+ id: source.theId, // Required if TSource doesn't have an `id` property
12
+ isAvailable: source.status === 'available',
13
+ fullName: `${source.firstName} ${source.lastName}`,
14
14
  }),
15
15
  })
16
16
  ```
@@ -19,22 +19,27 @@ const { items, useSubset, useFlag } = useCollection(sources, {
19
19
 
20
20
  - **Collection Item**: An object with a unique identifier, a reference to its source object, flags, computed properties, and methods to manipulate flags
21
21
  - **Flags**: Boolean states attached to items (like 'selected', 'active', 'highlighted')
22
- - **Properties**: Computed values derived from the source object
22
+ - **Properties**: Additional custom values
23
23
 
24
24
  ## `useCollection` parameters
25
25
 
26
- | Name | Type | Required | Description |
27
- | --------- | --------------------------------- | :------: | ---------------------------------------------------- |
28
- | `sources` | `MaybeRefOrGetter<TSource[]>` | ✓ | Array of source objects for the collection |
29
- | `options` | `CollectionOptions<TSource, TId>` | | Configuration options for the collection (see below) |
26
+ | Name | Type | Required | Description |
27
+ | --------- | ------------------------------------------------ | :------: | ---------------------------------------------------- |
28
+ | `sources` | `MaybeRefOrGetter<TSource[]>` | ✓ | Array of source objects for the collection |
29
+ | `options` | `CollectionOptions<TSource, TFlag, TProperties>` | ~ | Configuration options for the collection (see below) |
30
30
 
31
31
  ### `options` object
32
32
 
33
- | Name | Type | Required | Description |
34
- | ------------ | -------------------------------------------------- | :------: | -------------------------------------------------------- |
35
- | `identifier` | `(source: TSource) => TId` || Function to extract a unique identifier from each source |
36
- | `flags` | `FlagsConfig<TFlag>` | | Flags that can be applied to items in the collection |
37
- | `properties` | `(source: TSource) => Record<string, ComputedRef>` | | Function that returns computed properties for each item |
33
+ | Name | Type | Required | Description |
34
+ | ------------ | ---------------------------------------------- | :------: | --------------------------------------------------------------------- |
35
+ | `flags` | `FlagsConfig<TFlag>` | | Flags that can be applied to items in the collection |
36
+ | `properties` | `(source: TSource) => Record<string, unknown>` | ~ | Function that returns additional properties for each item (see below) |
37
+
38
+ ### Item ID
39
+
40
+ The item ID will be retrieved automatically from `TSource.id`
41
+
42
+ If `TSource` doesn't provide an `id`, then `options.properties` will be required and must return at least an `id`
38
43
 
39
44
  ### `FlagsConfig` type
40
45
 
@@ -44,17 +49,17 @@ type FlagsConfig<TFlag extends string> = TFlag[] | { [K in TFlag]: { multiple?:
44
49
 
45
50
  Values for `multiple`:
46
51
 
47
- - `true` (default): multiple items can have the same flag.
52
+ - `true` (default): multiple items can share the same flag.
48
53
  - `false`: only one item can have the flag at a time (exclusive selection). Setting the flag on one item will automatically unset it on all other items.
49
54
 
50
55
  ## Return Value
51
56
 
52
- | Name | Type | Description |
53
- | ----------- | ------------------------------------------- | -------------------------------------------------------- |
54
- | `items` | `ComputedRef<CollectionItem[]>` | Array of collection items with flags and properties |
55
- | `useSubset` | `(filter: (item) => boolean) => Collection` | Creates a new collection that's a subset of the original |
56
- | `useFlag` | `(flag: TFlag) => UseFlag` | Utilities for working with a specific flag |
57
- | `count` | `ComputedRef<number>` | Number of items in the collection |
57
+ | Name | Type | Description |
58
+ | ----------- | ------------------------------------------- | --------------------------------------------------- |
59
+ | `items` | `ComputedRef<CollectionItem[]>` | Array of collection items with flags and properties |
60
+ | `useSubset` | `(filter: (item) => boolean) => Collection` | Creates a sub collection matching the filter |
61
+ | `useFlag` | `(flag: TFlag) => UseFlagReturn` | Utilities for working with a specific flag |
62
+ | `count` | `ComputedRef<number>` | Number of items in the collection |
58
63
 
59
64
  ### `CollectionItem` object
60
65
 
@@ -66,18 +71,19 @@ Values for `multiple`:
66
71
  | `properties` | `TProperties` | Object containing all computed properties for this item |
67
72
  | `toggleFlag` | `(flag, forcedValue?) => void` | Method to toggle a flag on this item |
68
73
 
69
- ### Return value of `useFlag(flag)`
74
+ ### UseFlagReturn object
70
75
 
71
- | Name | Type | Description |
72
- | ----------- | ------------------------------- | ------------------------------------------------------ |
73
- | `items` | `ComputedRef<CollectionItem[]>` | Array of items that have this flag set |
74
- | `ids` | `ComputedRef<TId[]>` | Array of IDs of items that have this flag set |
75
- | `count` | `ComputedRef<number>` | Number of items that have this flag set |
76
- | `areAllOn` | `ComputedRef<boolean>` | Whether all items in the collection have this flag set |
77
- | `areSomeOn` | `ComputedRef<boolean>` | Whether at least one item has this flag set |
78
- | `areNoneOn` | `ComputedRef<boolean>` | Whether no items have this flag set |
79
- | `toggle` | `(id, forcedValue?) => void` | Toggle this flag on a specific item |
80
- | `toggleAll` | `(forcedValue?) => void` | Toggle this flag on all items in the collection |
76
+ | Name | Type | Description |
77
+ | ----------- | ------------------------------------------- | ------------------------------------------------------ |
78
+ | `items` | `ComputedRef<CollectionItem[]>` | Array of items that have this flag set |
79
+ | `ids` | `ComputedRef<TId[]>` | Array of IDs of items that have this flag set |
80
+ | `count` | `ComputedRef<number>` | Number of items that have this flag set |
81
+ | `areAllOn` | `ComputedRef<boolean>` | Whether all items in the collection have this flag set |
82
+ | `areSomeOn` | `ComputedRef<boolean>` | Whether at least one item has this flag set |
83
+ | `areNoneOn` | `ComputedRef<boolean>` | Whether no items have this flag set |
84
+ | `toggle` | `(id, forcedValue?) => void` | Toggle this flag on a specific item |
85
+ | `toggleAll` | `(forcedValue?) => void` | Toggle this flag on all items in the collection |
86
+ | `useSubset` | `(filter: (item) => boolean) => Collection` | Creates a sub collection matching the filter |
81
87
 
82
88
  ## Flag Operations
83
89
 
@@ -136,10 +142,9 @@ const {
136
142
  useSubset,
137
143
  count,
138
144
  } = useCollection(rawUsers, {
139
- identifier: user => user.id,
140
145
  flags: ['selected'],
141
146
  properties: user => ({
142
- fullName: computed(() => `${user.firstName} ${user.lastName} (${user.group})`),
147
+ fullName: `${user.firstName} ${user.lastName} (${user.group})`,
143
148
  }),
144
149
  })
145
150
 
@@ -1,14 +1,21 @@
1
- import type { CollectionItem, FlagRegistry } from '@core/packages/collection'
1
+ import type {
2
+ Collection,
3
+ CollectionConfigProperties,
4
+ CollectionItem,
5
+ FlagRegistry,
6
+ GuessItemId,
7
+ UseFlagReturn,
8
+ } from '@core/packages/collection/types.ts'
2
9
  import { useArrayFilter, useArrayMap } from '@vueuse/core'
3
10
  import { computed, type ComputedRef } from 'vue'
4
11
 
5
- export function createCollection<
6
- TSource,
7
- TId extends PropertyKey,
8
- TFlag extends string,
9
- TProperties extends Record<string, any>,
10
- >(items: ComputedRef<CollectionItem<TSource, TId, TFlag, TProperties>[]>, flagRegistry: FlagRegistry<TFlag>) {
11
- function useFlag(flag: TFlag) {
12
+ export function createCollection<TSource, TFlag extends string, TProperties extends CollectionConfigProperties>(
13
+ items: ComputedRef<CollectionItem<TSource, TFlag, TProperties>[]>,
14
+ flagRegistry: FlagRegistry<TFlag>
15
+ ): Collection<TSource, TFlag, TProperties> {
16
+ function useFlag(flag: TFlag): UseFlagReturn<TSource, TFlag, TProperties> {
17
+ flagRegistry.assertFlag(flag)
18
+
12
19
  const flaggedItems = useArrayFilter(items, item => item.flags[flag])
13
20
 
14
21
  const ids = useArrayMap(flaggedItems, item => item.id)
@@ -21,7 +28,7 @@ export function createCollection<
21
28
 
22
29
  const areNoneOn = computed(() => count.value === 0)
23
30
 
24
- function toggle(id: TId, forcedValue?: boolean) {
31
+ function toggle(id: GuessItemId<TSource, TProperties>, forcedValue?: boolean) {
25
32
  flagRegistry.toggleFlag(id, flag, forcedValue)
26
33
  }
27
34
 
@@ -31,6 +38,12 @@ export function createCollection<
31
38
  }
32
39
  }
33
40
 
41
+ function useSubset(
42
+ filter: (item: CollectionItem<TSource, TFlag, TProperties>) => boolean
43
+ ): Collection<TSource, TFlag, TProperties> {
44
+ return createCollection(useArrayFilter(flaggedItems, filter), flagRegistry)
45
+ }
46
+
34
47
  return {
35
48
  items: flaggedItems,
36
49
  ids,
@@ -40,13 +53,14 @@ export function createCollection<
40
53
  areNoneOn,
41
54
  toggle,
42
55
  toggleAll,
56
+ useSubset,
43
57
  }
44
58
  }
45
59
 
46
- function useSubset(filter: (item: CollectionItem<TSource, TId, TFlag, TProperties>) => boolean) {
47
- const filteredItems = useArrayFilter(items, item => filter(item))
48
-
49
- return createCollection(filteredItems, flagRegistry)
60
+ function useSubset(
61
+ filter: (item: CollectionItem<TSource, TFlag, TProperties>) => boolean
62
+ ): Collection<TSource, TFlag, TProperties> {
63
+ return createCollection(useArrayFilter(items, filter), flagRegistry)
50
64
  }
51
65
 
52
66
  const count = computed(() => items.value.length)
@@ -0,0 +1,39 @@
1
+ import { guessItemId } from '@core/packages/collection/guess-item-id.ts'
2
+ import type { CollectionConfigProperties, CollectionItem, FlagRegistry } from '@core/packages/collection/types.ts'
3
+ import { reactive } from 'vue'
4
+
5
+ export function createItem<TSource, TFlag extends string, TProperties extends CollectionConfigProperties>(
6
+ source: TSource,
7
+ getProperties: undefined | ((source: TSource) => TProperties),
8
+ flagRegistry: FlagRegistry<TFlag>
9
+ ): CollectionItem<TSource, TFlag, TProperties> {
10
+ const properties = reactive(getProperties?.(source) ?? ({} as TProperties))
11
+
12
+ const id = guessItemId(source, properties)
13
+
14
+ return {
15
+ id,
16
+ source,
17
+ toggleFlag(flag: TFlag, forcedValue?: boolean) {
18
+ flagRegistry.toggleFlag(id, flag, forcedValue)
19
+ },
20
+ flags: new Proxy({} as Record<TFlag, boolean>, {
21
+ has(_, flag: TFlag) {
22
+ return flagRegistry.isFlagDefined(flag)
23
+ },
24
+ get(_, flag: TFlag) {
25
+ if (!flagRegistry.isFlagDefined(flag)) {
26
+ return undefined
27
+ }
28
+
29
+ return flagRegistry.isFlagged(id, flag)
30
+ },
31
+ set(_, flag: TFlag, value: boolean) {
32
+ flagRegistry.toggleFlag(id, flag, value)
33
+
34
+ return true
35
+ },
36
+ }),
37
+ properties,
38
+ }
39
+ }
@@ -0,0 +1,26 @@
1
+ import type { CollectionConfigProperties, GuessItemId } from '@core/packages/collection/types.ts'
2
+
3
+ function assertValidId(id: unknown): asserts id is PropertyKey {
4
+ const type = typeof id
5
+
6
+ if (!['string', 'number', 'symbol'].includes(type)) {
7
+ throw new TypeError(`Invalid ID type: ${type}. Expected string, number, or bigint.`)
8
+ }
9
+ }
10
+
11
+ export function guessItemId<TSource, TProperties extends CollectionConfigProperties>(
12
+ source: TSource,
13
+ properties: TProperties | undefined
14
+ ) {
15
+ let id
16
+
17
+ if (typeof properties === 'object' && properties !== null && 'id' in properties) {
18
+ id = properties.id
19
+ } else if (typeof source === 'object' && source !== null && 'id' in source) {
20
+ id = source.id
21
+ }
22
+
23
+ assertValidId(id)
24
+
25
+ return id as GuessItemId<TSource, TProperties>
26
+ }
@@ -1,5 +1,2 @@
1
- export * from './build-item.ts'
2
- export * from './create-collection.ts'
3
1
  export * from './types.ts'
4
2
  export * from './use-collection.ts'
5
- export * from './use-flag-registry.ts'