@xen-orchestra/web-core 0.31.0 → 0.32.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.
Files changed (66) hide show
  1. package/lib/assets/css/_colors.pcss +8 -0
  2. package/lib/components/backdrop/VtsBackdrop.vue +9 -1
  3. package/lib/components/button-group/VtsButtonGroup.vue +5 -1
  4. package/lib/components/menu/MenuList.vue +1 -0
  5. package/lib/components/modal/VtsModal.vue +82 -0
  6. package/lib/components/modal/VtsModalButton.vue +36 -0
  7. package/lib/components/modal/VtsModalCancelButton.vue +37 -0
  8. package/lib/components/modal/VtsModalConfirmButton.vue +21 -0
  9. package/lib/components/modal/VtsModalList.vue +34 -0
  10. package/lib/components/object-icon/VtsObjectIcon.vue +3 -8
  11. package/lib/components/status/VtsStatus.vue +66 -0
  12. package/lib/components/task/VtsQuickTaskButton.vue +3 -2
  13. package/lib/components/task/VtsQuickTaskList.vue +17 -5
  14. package/lib/components/tree/VtsTreeItem.vue +2 -2
  15. package/lib/components/ui/button/UiButton.vue +13 -67
  16. package/lib/components/ui/input/UiInput.vue +4 -1
  17. package/lib/components/ui/modal/UiModal.vue +164 -0
  18. package/lib/components/ui/quick-task-item/UiQuickTaskItem.vue +2 -2
  19. package/lib/composables/context.composable.ts +3 -5
  20. package/lib/composables/link-component.composable.ts +3 -2
  21. package/lib/composables/pagination.composable.ts +3 -2
  22. package/lib/composables/tree-filter.composable.ts +5 -3
  23. package/lib/icons/fa-icons.ts +4 -0
  24. package/lib/icons/index.ts +17 -0
  25. package/lib/locales/en.json +14 -1
  26. package/lib/locales/fr.json +14 -1
  27. package/lib/packages/collection/use-collection.ts +3 -2
  28. package/lib/packages/form-select/use-form-option-controller.ts +3 -2
  29. package/lib/packages/form-select/use-form-select.ts +8 -7
  30. package/lib/packages/menu/action.ts +4 -3
  31. package/lib/packages/menu/link.ts +5 -4
  32. package/lib/packages/menu/router-link.ts +3 -2
  33. package/lib/packages/menu/toggle-target.ts +3 -2
  34. package/lib/packages/modal/ModalProvider.vue +17 -0
  35. package/lib/packages/modal/README.md +253 -0
  36. package/lib/packages/modal/create-modal-opener.ts +103 -0
  37. package/lib/packages/modal/modal.store.ts +22 -0
  38. package/lib/packages/modal/types.ts +92 -0
  39. package/lib/packages/modal/use-modal.ts +53 -0
  40. package/lib/packages/progress/use-progress.ts +4 -3
  41. package/lib/packages/table/README.md +336 -0
  42. package/lib/packages/table/apply-extensions.ts +26 -0
  43. package/lib/packages/table/define-columns.ts +62 -0
  44. package/lib/packages/table/define-renderer/define-table-cell-renderer.ts +27 -0
  45. package/lib/packages/table/define-renderer/define-table-renderer.ts +47 -0
  46. package/lib/packages/table/define-renderer/define-table-row-renderer.ts +29 -0
  47. package/lib/packages/table/define-renderer/define-table-section-renderer.ts +29 -0
  48. package/lib/packages/table/define-table/define-multi-source-table.ts +39 -0
  49. package/lib/packages/table/define-table/define-table.ts +13 -0
  50. package/lib/packages/table/define-table/define-typed-table.ts +18 -0
  51. package/lib/packages/table/index.ts +11 -0
  52. package/lib/packages/table/transform-sources.ts +13 -0
  53. package/lib/packages/table/types/extensions.ts +16 -0
  54. package/lib/packages/table/types/index.ts +47 -0
  55. package/lib/packages/table/types/table-cell.ts +18 -0
  56. package/lib/packages/table/types/table-row.ts +20 -0
  57. package/lib/packages/table/types/table-section.ts +19 -0
  58. package/lib/packages/table/types/table.ts +28 -0
  59. package/lib/packages/threshold/use-threshold.ts +4 -3
  60. package/lib/types/vue-virtual-scroller.d.ts +101 -0
  61. package/lib/utils/injection-keys.util.ts +3 -0
  62. package/lib/utils/progress.util.ts +2 -1
  63. package/lib/utils/to-computed.util.ts +15 -0
  64. package/package.json +3 -2
  65. package/lib/components/backup-state/VtsBackupState.vue +0 -37
  66. package/lib/components/connection-status/VtsConnectionStatus.vue +0 -36
@@ -0,0 +1,164 @@
1
+ <!-- v2 -->
2
+ <template>
3
+ <form :class="className" class="ui-modal" @click.self="emit('dismiss')">
4
+ <div class="modal">
5
+ <UiButtonIcon
6
+ v-if="onDismiss"
7
+ :accent="closeIconAccent"
8
+ :target-scale="2"
9
+ class="dismiss-button"
10
+ icon="fa:xmark"
11
+ size="small"
12
+ @click="emit('dismiss')"
13
+ />
14
+ <main class="main">
15
+ <VtsIcon v-if="icon" :name="icon" class="icon" size="current" />
16
+ <div v-if="slots.title" class="typo-h4">
17
+ <slot name="title" />
18
+ </div>
19
+ <div class="content">
20
+ <slot name="content" />
21
+ </div>
22
+ </main>
23
+ <VtsButtonGroup v-if="slots.buttons" class="buttons">
24
+ <slot name="buttons" />
25
+ </VtsButtonGroup>
26
+ </div>
27
+ </form>
28
+ </template>
29
+
30
+ <script lang="ts" setup>
31
+ import VtsButtonGroup from '@core/components/button-group/VtsButtonGroup.vue'
32
+ import VtsIcon from '@core/components/icon/VtsIcon.vue'
33
+ import UiButtonIcon from '@core/components/ui/button-icon/UiButtonIcon.vue'
34
+ import type { IconName } from '@core/icons'
35
+ import { useMapper } from '@core/packages/mapper'
36
+ import { toVariants } from '@core/utils/to-variants.util.ts'
37
+ import { computed } from 'vue'
38
+
39
+ export type ModalAccent = 'info' | 'success' | 'warning' | 'danger'
40
+
41
+ const { accent } = defineProps<{
42
+ accent: ModalAccent
43
+ icon?: IconName
44
+ onDismiss?: () => void
45
+ }>()
46
+
47
+ const emit = defineEmits<{
48
+ dismiss: []
49
+ }>()
50
+
51
+ const slots = defineSlots<{
52
+ content(): any
53
+ buttons?(): any
54
+ title?(): any
55
+ }>()
56
+
57
+ const closeIconAccent = useMapper(
58
+ () => accent,
59
+ {
60
+ info: 'brand',
61
+ success: 'brand',
62
+ warning: 'warning',
63
+ danger: 'danger',
64
+ },
65
+ 'info'
66
+ )
67
+
68
+ const className = computed(() => toVariants({ accent }))
69
+ </script>
70
+
71
+ <style lang="postcss" scoped>
72
+ .ui-modal {
73
+ position: fixed;
74
+ inset: 0;
75
+ display: flex;
76
+ justify-content: center;
77
+ align-items: center;
78
+
79
+ .modal {
80
+ display: flex;
81
+ flex-direction: column;
82
+ min-width: min(40rem, calc(100% - 2rem));
83
+ max-width: min(95vw, 120rem);
84
+ max-height: min(90vh, 80rem);
85
+ padding: 3.2rem 2.4rem 2.4rem;
86
+ gap: 2.4rem;
87
+ border-radius: 1rem;
88
+ overflow: auto;
89
+
90
+ &:not(:has(.buttons)) {
91
+ padding-bottom: 3.2rem;
92
+ }
93
+
94
+ .dismiss-button {
95
+ position: absolute;
96
+ top: 2.4rem;
97
+ right: 2.4rem;
98
+ z-index: 1;
99
+ }
100
+
101
+ &:not(:has(.icon)) .dismiss-button {
102
+ top: 1rem;
103
+ right: 1rem;
104
+ }
105
+
106
+ .main {
107
+ display: flex;
108
+ flex-direction: column;
109
+ align-items: center;
110
+ gap: 2.4rem;
111
+ text-align: center;
112
+ overflow: auto;
113
+
114
+ .icon {
115
+ font-size: 4.8rem;
116
+ }
117
+
118
+ .content {
119
+ width: 100%;
120
+ }
121
+ }
122
+ }
123
+
124
+ &.accent--info {
125
+ .modal {
126
+ background-color: var(--color-info-background-selected);
127
+ }
128
+
129
+ .main .icon {
130
+ color: var(--color-info-txt-base);
131
+ }
132
+ }
133
+
134
+ &.accent--success {
135
+ .modal {
136
+ background-color: var(--color-success-background-selected);
137
+ }
138
+
139
+ .main .icon {
140
+ color: var(--color-success-txt-base);
141
+ }
142
+ }
143
+
144
+ &.accent--warning {
145
+ .modal {
146
+ background-color: var(--color-warning-background-selected);
147
+ }
148
+
149
+ .main .icon {
150
+ color: var(--color-warning-txt-base);
151
+ }
152
+ }
153
+
154
+ &.accent--danger {
155
+ .modal {
156
+ background-color: var(--color-danger-background-selected);
157
+ }
158
+
159
+ .main .icon {
160
+ color: var(--color-danger-txt-base);
161
+ }
162
+ }
163
+ }
164
+ </style>
@@ -1,6 +1,6 @@
1
1
  <!-- WIP -->
2
2
  <template>
3
- <li class="ui-quick-task-item">
3
+ <div class="ui-quick-task-item">
4
4
  <div v-if="hasSubTasks" class="toggle" @click="toggleExpand()">
5
5
  <UiButtonIcon accent="brand" :icon="isExpanded ? 'fa:angle-down' : 'fa:angle-right'" size="small" />
6
6
  </div>
@@ -26,7 +26,7 @@
26
26
  </div>
27
27
  <VtsQuickTaskList v-if="hasSubTasks && isExpanded" :tasks="subTasks" sublist />
28
28
  </div>
29
- </li>
29
+ </div>
30
30
  </template>
31
31
 
32
32
  <script lang="ts" setup>
@@ -1,5 +1,6 @@
1
+ import { toComputed } from '@core/utils/to-computed.util'
1
2
  import type { ComputedRef, InjectionKey, MaybeRefOrGetter } from 'vue'
2
- import { computed, inject, provide, toValue } from 'vue'
3
+ import { inject, provide, toValue } from 'vue'
3
4
 
4
5
  export const createContext = <T, Output = ComputedRef<T>>(
5
6
  initialValue: MaybeRefOrGetter<T>,
@@ -27,8 +28,5 @@ export const useContext = <Ctx extends Context, T extends ContextValue<Ctx>>(
27
28
  const updatedValue = () => toValue(newValue) ?? toValue(currentValue) ?? context.initialValue
28
29
  provide(context.id, updatedValue)
29
30
 
30
- return context.builder(
31
- computed(() => toValue(updatedValue)),
32
- computed(() => toValue(currentValue))
33
- )
31
+ return context.builder(toComputed(updatedValue), toComputed(currentValue))
34
32
  }
@@ -1,5 +1,6 @@
1
+ import { toComputed } from '@core/utils/to-computed.util'
1
2
  import type { MaybeRefOrGetter } from 'vue'
2
- import { computed, toValue } from 'vue'
3
+ import { computed } from 'vue'
3
4
  import type { RouteLocationAsPathGeneric, RouteLocationAsRelativeGeneric, RouteLocationAsString } from 'vue-router'
4
5
 
5
6
  export type LinkOptions = {
@@ -11,7 +12,7 @@ export type LinkOptions = {
11
12
  }
12
13
 
13
14
  export function useLinkComponent(defaultComponent: string, options: MaybeRefOrGetter<LinkOptions>) {
14
- const config = computed(() => toValue(options))
15
+ const config = toComputed(options)
15
16
 
16
17
  const isDisabled = computed(() => config.value.disabled || (!config.value.to && !config.value.href))
17
18
 
@@ -1,11 +1,12 @@
1
1
  import type { TablePaginationSize } from '@core/components/ui/table-pagination/UiTablePagination.vue'
2
2
  import { useRouteQuery } from '@core/composables/route-query.composable'
3
3
  import { useUiStore } from '@core/stores/ui.store.ts'
4
+ import { toComputed } from '@core/utils/to-computed.util'
4
5
  import { clamp, useLocalStorage } from '@vueuse/core'
5
- import { computed, type MaybeRefOrGetter, toValue } from 'vue'
6
+ import { computed, type MaybeRefOrGetter } from 'vue'
6
7
 
7
8
  export function usePagination<T>(id: string, _records: MaybeRefOrGetter<T[]>) {
8
- const records = computed(() => toValue(_records))
9
+ const records = toComputed(_records)
9
10
 
10
11
  const showBy = useLocalStorage(`${id}.per-page`, 24)
11
12
 
@@ -5,10 +5,12 @@ import { computed, ref } from 'vue'
5
5
  export function useTreeFilter() {
6
6
  const filter = ref('')
7
7
  const debouncedFilter = refDebounced(filter, 500)
8
- const hasFilter = computed(() => debouncedFilter.value.trim().length > 0)
9
-
8
+ const hasFilter = computed(() => filter.value.trim().length > 0)
9
+ const isSearching = computed(() =>
10
+ filter.value.trim().length === 0 ? false : filter.value !== debouncedFilter.value
11
+ )
10
12
  const predicate = (node: TreeNodeBase) =>
11
13
  hasFilter.value ? node.label.toLocaleLowerCase().includes(debouncedFilter.value.toLocaleLowerCase()) : undefined
12
14
 
13
- return { filter, predicate }
15
+ return { filter, predicate, isSearching }
14
16
  }
@@ -24,6 +24,7 @@ import {
24
24
  faBars,
25
25
  faBarsProgress,
26
26
  faBook,
27
+ faCalendar,
27
28
  faCamera,
28
29
  faCaretDown,
29
30
  faCaretUp,
@@ -38,6 +39,7 @@ import {
38
39
  faCirclePlay,
39
40
  faCircleXmark,
40
41
  faCity,
42
+ faClock,
41
43
  faClose,
42
44
  faCode,
43
45
  faComments,
@@ -142,6 +144,7 @@ export const faIcons = defineIconPack({
142
144
  comments: { icon: faComments },
143
145
  copy: { icon: faCopy },
144
146
  database: { icon: faDatabase },
147
+ date: { icon: faCalendar },
145
148
  desktop: { icon: faDesktop },
146
149
  display: { icon: faDisplay },
147
150
  'down-left-and-up-right-to-center': { icon: faDownLeftAndUpRightToCenter },
@@ -199,6 +202,7 @@ export const faIcons = defineIconPack({
199
202
  star: { icon: faStar },
200
203
  stop: { icon: faStop },
201
204
  tags: { icon: faTags },
205
+ time: { icon: faClock },
202
206
  'thumb-tack': { icon: faThumbTack },
203
207
  'thumb-tack-slash': { icon: faThumbTackSlash },
204
208
  trash: { icon: faTrash },
@@ -17,3 +17,20 @@ export type ObjectIconName = Extract<IconName, `object:${string}:${string}`>
17
17
  export function icon<TName extends IconName>(name: TName): TName {
18
18
  return name
19
19
  }
20
+
21
+ export type ObjectStateByType = {
22
+ [TName in IconName as TName extends `object:${infer TType}:${string}`
23
+ ? TType
24
+ : never]: TName extends `object:${string}:${infer TType}` ? TType : never
25
+ }
26
+
27
+ export type ObjectType = keyof ObjectStateByType
28
+
29
+ export type ObjectState<TType extends ObjectType> = ObjectStateByType[TType]
30
+
31
+ export function objectIcon<TType extends ObjectType, TState extends ObjectState<TType>>(
32
+ type: TType,
33
+ state: TState
34
+ ): IconName {
35
+ return `object:${type}:${state}` as IconName
36
+ }
@@ -30,6 +30,8 @@
30
30
  "all-quiet-launchpad": "All quiet on the launchpad",
31
31
  "allow-self-signed-ssl": "You may need to allow self-signed SSL certificates in your browser",
32
32
  "api-error-details": "API Error details",
33
+ "api-info-details": "API Info details",
34
+ "api-warning-details": "API Warning details",
33
35
  "appearance": "Appearance",
34
36
  "ascending": "ascending",
35
37
  "auto-generated": "Automatically generated",
@@ -199,13 +201,15 @@
199
201
  "do-you-have-needs": "You have needs and/or expectations? Let us know",
200
202
  "documentation": "Documentation",
201
203
  "documentation-name": "{name} documentation",
204
+ "duration": "Duration",
202
205
  "edit": "Edit",
203
206
  "edit-config": "Edit config",
204
207
  "enabled": "Enabled",
208
+ "end-date": "End date",
205
209
  "end-of-life": "End of life",
206
210
  "engines-off": "Engines off, orbit stable",
207
211
  "eol": "EOL",
208
- "error": "Error",
212
+ "error": "Error | Errors",
209
213
  "error-no-data": "Error, can't collect data.",
210
214
  "error-occurred": "An error has occurred",
211
215
  "excluded-vms-tags": "Excluded VMs tags",
@@ -278,6 +282,7 @@
278
282
  "id": "ID",
279
283
  "in-last-three-jobs": "In their last three jobs",
280
284
  "in-progress": "In progress",
285
+ "info": "Info | Infos",
281
286
  "install-settings": "Install settings",
282
287
  "interfaces": "Interface | Interface | Interfaces",
283
288
  "interrupted": "Interrupted",
@@ -367,6 +372,7 @@
367
372
  "memory": "Memory",
368
373
  "memory-usage": "Memory usage",
369
374
  "merge-backups-synchronously": "Merge backups synchronously",
375
+ "message": "Message",
370
376
  "migrate": "Migrate",
371
377
  "migrate-n-vms": "Migrate 1 VM | Migrate {n} VMs",
372
378
  "migration-compression": "Migration compression",
@@ -412,6 +418,7 @@
412
418
  "no-alarm-triggered": "No alarm triggered",
413
419
  "no-alarms-detected": "No alarms detected",
414
420
  "no-backup-available": "No backup available",
421
+ "no-backup-run-available": "No backup run available",
415
422
  "no-config": "No configuration",
416
423
  "no-data": "No data",
417
424
  "no-data-to-calculate": "No data to calculate",
@@ -523,6 +530,7 @@
523
530
  "root-by-default": "\"root\" by default.",
524
531
  "run": "Run",
525
532
  "running-vm": "Running VM | Running VMs",
533
+ "runs": "Runs",
526
534
  "s3-backup-repository": "S3 backup repository",
527
535
  "save": "Save",
528
536
  "scan-pifs": "Scan PIFs",
@@ -571,6 +579,7 @@
571
579
  "stacked-ram-usage": "Stacked RAM usage",
572
580
  "start": "Start",
573
581
  "start-console": "Start your {type} to access the console and resume operations!",
582
+ "start-date": "Start date",
574
583
  "start-delay": "Start delay",
575
584
  "start-host": "Start the host to resume operations, or check back later once it’s powered on.",
576
585
  "start-on-host": "Start on specific host",
@@ -596,6 +605,7 @@
596
605
  "system-disks-health": "System disks health",
597
606
  "table-actions": "Table actions",
598
607
  "tags": "Tags",
608
+ "task": "Task",
599
609
  "task.estimated-end": "Estimated end",
600
610
  "task.progress": "Progress",
601
611
  "task.started": "Started",
@@ -628,12 +638,14 @@
628
638
  "total-storage-repository": "Total storage repository",
629
639
  "total-used": "Total used",
630
640
  "total-used:": "Total used:",
641
+ "transfer-size": "Transfer size",
631
642
  "unable-to-connect-to": "Unable to connect to {ip}",
632
643
  "unable-to-connect-to-the-pool": "Unable to connect to the pool",
633
644
  "unknown": "Unknown",
634
645
  "unlocked": "Unlocked",
635
646
  "unreachable-hosts": "Unreachable hosts",
636
647
  "unreachable-hosts-reload-page": "Done, reload the page",
648
+ "untranslated-text-helper": "By default, untranslated texts will be displayed in english.",
637
649
  "up-to-date": "Up-to-date",
638
650
  "update": "Update",
639
651
  "used": "Used",
@@ -684,6 +696,7 @@
684
696
  "vms-status.unknown": "Unknown",
685
697
  "vms-status.unknown.tooltip": "For which XO has lost connection to the pool",
686
698
  "vms-tags": "VMs tags",
699
+ "warning": "Warning | Warnings",
687
700
  "write": "Write",
688
701
  "xo-backups": "XO backups",
689
702
  "xo-lite-under-construction": "XOLite is under construction",
@@ -30,6 +30,8 @@
30
30
  "all-quiet-launchpad": "Tout est calme sur la rampe de lancement",
31
31
  "allow-self-signed-ssl": "Vous devrez peut-être autoriser les certificats SSL auto-signés depuis votre navigateur",
32
32
  "api-error-details": "Details de l'erreur API",
33
+ "api-info-details": "Details de l'information API",
34
+ "api-warning-details": "Details de l'avertissement API",
33
35
  "appearance": "Apparence",
34
36
  "ascending": "ascendant",
35
37
  "auto-generated": "Généré automatiquement",
@@ -199,13 +201,15 @@
199
201
  "do-you-have-needs": "Vous avez des besoins et/ou des attentes ? Faites le nous savoir",
200
202
  "documentation": "Documentation",
201
203
  "documentation-name": "Documentation {name}",
204
+ "duration": "Durée",
202
205
  "edit": "Modifier",
203
206
  "edit-config": "Modifier config",
204
207
  "enabled": "Activé",
208
+ "end-date": "Date de fin",
205
209
  "end-of-life": "Fin de vie",
206
210
  "engines-off": "Moteurs arrêtés, orbite stable",
207
211
  "eol": "EOL",
208
- "error": "Erreur",
212
+ "error": "Erreur | Erreurs",
209
213
  "error-no-data": "Erreur, impossible de collecter les données.",
210
214
  "error-occurred": "Une erreur est survenue",
211
215
  "excluded-vms-tags": "Tags des VMs exclus",
@@ -278,6 +282,7 @@
278
282
  "id": "ID",
279
283
  "in-last-three-jobs": "Dans leurs trois derniers jobs",
280
284
  "in-progress": "En cours",
285
+ "info": "Info | Infos",
281
286
  "install-settings": "Paramètres d'installation",
282
287
  "interfaces": "Interface | Interface | Interfaces",
283
288
  "interrupted": "Interrompu",
@@ -367,6 +372,7 @@
367
372
  "memory": "Mémoire",
368
373
  "memory-usage": "Utilisation de la mémoire",
369
374
  "merge-backups-synchronously": "Fusionner les sauvegardes de manière synchrone",
375
+ "message": "Message",
370
376
  "migrate": "Migrer",
371
377
  "migrate-n-vms": "Migrer 1 VM | Migrer {n} VMs",
372
378
  "migration-compression": "Compression des migrations",
@@ -412,6 +418,7 @@
412
418
  "no-alarm-triggered": "Aucune alarme déclenchée",
413
419
  "no-alarms-detected": "Aucune alarme détectée",
414
420
  "no-backup-available": "Aucune sauvegarde disponible",
421
+ "no-backup-run-available": "Aucune exécution de sauvegarde disponible",
415
422
  "no-config": "Aucune configuration",
416
423
  "no-data": "Aucune donnée",
417
424
  "no-data-to-calculate": "Aucune donnée à calculer",
@@ -523,6 +530,7 @@
523
530
  "root-by-default": "\"root\" par défaut.",
524
531
  "run": "Run",
525
532
  "running-vm": "VM en cours d'exécution | VMs en cours d'exécution",
533
+ "runs": "Runs",
526
534
  "s3-backup-repository": "Dépot de sauvegarde S3",
527
535
  "save": "Enregistrer",
528
536
  "scan-pifs": "Scan PIFs",
@@ -571,6 +579,7 @@
571
579
  "stacked-ram-usage": "Utilisation RAM empilée",
572
580
  "start": "Démarrer",
573
581
  "start-console": "Démarrez votre {type} pour accéder à la console et reprendre les opérations !",
582
+ "start-date": "Date de début",
574
583
  "start-delay": "Départ différé",
575
584
  "start-host": "Démarrez l’hôte pour reprendre les opérations, ou revenez plus tard une fois qu’il sera allumé.",
576
585
  "start-on-host": "Démarrer sur un hôte spécifique",
@@ -596,6 +605,7 @@
596
605
  "system-disks-health": "Santé des disques système",
597
606
  "table-actions": "Actions du tableau",
598
607
  "tags": "Tags",
608
+ "task": "Tâche",
599
609
  "task.estimated-end": "Fin estimée",
600
610
  "task.progress": "Progression",
601
611
  "task.started": "Démarré",
@@ -628,12 +638,14 @@
628
638
  "total-storage-repository": "Total dépot de stockage",
629
639
  "total-used": "Total utilisé",
630
640
  "total-used:": "Total utilisé :",
641
+ "transfer-size": "Taille transférée",
631
642
  "unable-to-connect-to": "Impossible de se connecter à {ip}",
632
643
  "unable-to-connect-to-the-pool": "Impossible de se connecter au Pool",
633
644
  "unknown": "Inconnu",
634
645
  "unlocked": "Débloqué",
635
646
  "unreachable-hosts": "Hôtes inaccessibles",
636
647
  "unreachable-hosts-reload-page": "C'est fait. Rafraîchir la page",
648
+ "untranslated-text-helper": "Par défaut, les textes non traduits seront affichés en anglais.",
637
649
  "up-to-date": "À jour",
638
650
  "update": "Mettre à jour",
639
651
  "used": "Utilisé",
@@ -684,6 +696,7 @@
684
696
  "vms-status.unknown": "Inconnu",
685
697
  "vms-status.unknown.tooltip": "Dont XO a perdu la connexion avec le pool",
686
698
  "vms-tags": "Tags des VMs",
699
+ "warning": "Avertissement | Avertissements",
687
700
  "write": "Écriture",
688
701
  "xo-backups": "Sauvegardes XO",
689
702
  "xo-lite-under-construction": "XOLite est en construction",
@@ -1,5 +1,6 @@
1
1
  import { guessItemId } from '@core/packages/collection/guess-item-id.ts'
2
2
  import type { EmptyObject } from '@core/types/utility.type.ts'
3
+ import { toComputed } from '@core/utils/to-computed.util.ts'
3
4
  import type {
4
5
  Collection,
5
6
  CollectionConfigFlags,
@@ -8,7 +9,7 @@ import type {
8
9
  ExtractSourceId,
9
10
  GetItemId,
10
11
  } from './types.ts'
11
- import { computed, type MaybeRefOrGetter, toValue } from 'vue'
12
+ import { computed, type MaybeRefOrGetter } from 'vue'
12
13
  import { createCollection } from './create-collection.ts'
13
14
  import { createItem } from './create-item.ts'
14
15
  import { useFlagRegistry } from './use-flag-registry.ts'
@@ -82,7 +83,7 @@ export function useCollection<
82
83
  ): Collection<TSource, TFlag, TProperties, $TId> {
83
84
  const flagRegistry = useFlagRegistry<TFlag, $TId>(config?.flags)
84
85
 
85
- const sources = computed(() => toValue(_sources))
86
+ const sources = toComputed(_sources)
86
87
 
87
88
  const items = computed(() =>
88
89
  sources.value.map(source => {
@@ -1,5 +1,6 @@
1
+ import { toComputed } from '@core/utils/to-computed.util.ts'
1
2
  import { unrefElement, useEventListener } from '@vueuse/core'
2
- import { computed, inject, type MaybeRefOrGetter, ref, toValue, watchEffect } from 'vue'
3
+ import { inject, type MaybeRefOrGetter, ref, watchEffect } from 'vue'
3
4
  import { type FormOption, IK_FORM_SELECT_CONTROLLER } from './types.ts'
4
5
 
5
6
  export function useFormOptionController<TOption extends FormOption>(_option: MaybeRefOrGetter<TOption>) {
@@ -9,7 +10,7 @@ export function useFormOptionController<TOption extends FormOption>(_option: May
9
10
  throw new Error('useFormOption needs a FormSelectController to be injected')
10
11
  }
11
12
 
12
- const option = computed(() => toValue(_option))
13
+ const option = toComputed(_option)
13
14
 
14
15
  const elementRef = ref<HTMLDivElement>()
15
16
 
@@ -7,6 +7,7 @@ import {
7
7
  } from '@core/packages/collection'
8
8
  import type { EmptyObject, MaybeArray } from '@core/types/utility.type.ts'
9
9
  import { toArray } from '@core/utils/to-array.utils.ts'
10
+ import { toComputed } from '@core/utils/to-computed.util.ts'
10
11
  import { computed, type ComputedRef, type MaybeRefOrGetter, provide, ref, type Ref, toRaw, toValue, watch } from 'vue'
11
12
  import { guessLabel } from './guess-label.ts'
12
13
  import { guessValue } from './guess-value.ts'
@@ -259,19 +260,19 @@ export function useFormSelect<
259
260
 
260
261
  const normalizedSearchTerm = computed(() => normalizeSearchTerm(searchTerm))
261
262
 
262
- const isMultiple = computed(() => toValue(config?.multiple) ?? false) as ComputedRef<TMultiple>
263
+ const isMultiple = toComputed(config?.multiple, false) as ComputedRef<TMultiple>
263
264
 
264
- const isDisabled = computed(() => toValue(config?.disabled) ?? false)
265
+ const isDisabled = toComputed(config?.disabled, false)
265
266
 
266
- const isLoading = computed(() => toValue(config?.loading) ?? false)
267
+ const isLoading = toComputed(config?.loading, false)
267
268
 
268
- const isRequired = computed(() => toValue(config?.required) ?? false)
269
+ const isRequired = toComputed(config?.required, false)
269
270
 
270
- const placeholder = computed(() => toValue(config?.placeholder) ?? '')
271
+ const placeholder = toComputed(config?.placeholder, '')
271
272
 
272
- const searchPlaceholder = computed(() => toValue(config?.searchPlaceholder) ?? '')
273
+ const searchPlaceholder = toComputed(config?.searchPlaceholder, '')
273
274
 
274
- const isSearchable = computed(() => toValue(config?.searchable) ?? false)
275
+ const isSearchable = toComputed(config?.searchable, false)
275
276
 
276
277
  const sources = computed(() =>
277
278
  config?.emptyOption !== undefined ? [EMPTY_OPTION, ...toValue(baseSources)] : toValue(baseSources)
@@ -1,5 +1,6 @@
1
1
  import { BaseItem, type Menu, type MenuLike, parseConfigHolder } from '@core/packages/menu'
2
- import { computed, type MaybeRefOrGetter, reactive, ref, toValue } from 'vue'
2
+ import { toComputed } from '@core/utils/to-computed.util'
3
+ import { computed, type MaybeRefOrGetter, reactive, ref } from 'vue'
3
4
 
4
5
  export interface MenuActionConfig {
5
6
  handler: () => any
@@ -33,7 +34,7 @@ export class MenuAction extends BaseItem {
33
34
  }
34
35
 
35
36
  get busyConfig() {
36
- return computed(() => toValue(this.config.busy) ?? false)
37
+ return toComputed(this.config.busy, false)
37
38
  }
38
39
 
39
40
  get isBusy() {
@@ -45,7 +46,7 @@ export class MenuAction extends BaseItem {
45
46
  }
46
47
 
47
48
  get disabledConfig() {
48
- return computed(() => toValue(this.config.disabled) ?? false)
49
+ return toComputed(this.config.disabled, false)
49
50
  }
50
51
 
51
52
  get isDisabled() {
@@ -1,5 +1,6 @@
1
1
  import { BaseItem, type Menu, type MenuLike, parseConfigHolder } from '@core/packages/menu'
2
- import { computed, type MaybeRefOrGetter, reactive, toValue } from 'vue'
2
+ import { toComputed } from '@core/utils/to-computed.util'
3
+ import { type MaybeRefOrGetter, reactive } from 'vue'
3
4
 
4
5
  export interface MenuLinkConfig {
5
6
  href: MaybeRefOrGetter<string>
@@ -34,9 +35,9 @@ export class MenuLink extends BaseItem {
34
35
  as: 'a',
35
36
  onMouseenter: () => this.activate(),
36
37
  onClick: () => this.deactivate(),
37
- href: computed(() => toValue(this.config.href)),
38
- rel: computed(() => toValue(this.config.rel) ?? 'noreferrer noopener'),
39
- target: computed(() => toValue(this.config.target) ?? '_blank'),
38
+ href: toComputed(this.config.href),
39
+ rel: toComputed(this.config.rel, 'noreferrer noopener'),
40
+ target: toComputed(this.config.target, '_blank'),
40
41
  'data-menu-id': this.menu.context.id,
41
42
  })
42
43
  }
@@ -1,5 +1,6 @@
1
1
  import { BaseItem, type Menu, type MenuLike, parseConfigHolder } from '@core/packages/menu'
2
- import { computed, markRaw, type MaybeRefOrGetter, reactive, toValue } from 'vue'
2
+ import { toComputed } from '@core/utils/to-computed.util'
3
+ import { markRaw, type MaybeRefOrGetter, reactive } from 'vue'
3
4
  import { type RouteLocationRaw, RouterLink } from 'vue-router'
4
5
 
5
6
  export interface MenuRouterLinkConfig {
@@ -31,7 +32,7 @@ export class MenuRouterLink extends BaseItem {
31
32
  as: markRaw(RouterLink),
32
33
  onMouseenter: () => this.activate(),
33
34
  onClick: () => this.deactivate(),
34
- to: computed(() => toValue(this.config.to)),
35
+ to: toComputed(this.config.to),
35
36
  'data-menu-id': this.menu.context.id,
36
37
  })
37
38
  }
@@ -1,7 +1,8 @@
1
1
  import type { MenuToggleTrigger } from '@core/packages/menu'
2
+ import { toComputed } from '@core/utils/to-computed.util'
2
3
  import { autoUpdate, flip, type Placement, shift, useFloating, type UseFloatingReturn } from '@floating-ui/vue'
3
4
  import { unrefElement } from '@vueuse/core'
4
- import { computed, reactive, ref, type Ref, toValue, type UnwrapRef } from 'vue'
5
+ import { computed, reactive, ref, type Ref, type UnwrapRef } from 'vue'
5
6
 
6
7
  export interface MenuToggleTargetConfig {
7
8
  placement?: Placement
@@ -26,7 +27,7 @@ export class MenuToggleTarget {
26
27
  public config: MenuToggleTargetConfig
27
28
  ) {
28
29
  const { floatingStyles } = useFloating(trigger.element, this.element, {
29
- placement: computed(() => toValue(config.placement) ?? 'bottom-start'),
30
+ placement: toComputed(config.placement, 'bottom-start'),
30
31
  open: trigger.isOpen,
31
32
  whileElementsMounted: autoUpdate,
32
33
  middleware: [shift(), flip()],