@xen-orchestra/web-core 0.9.0 → 0.11.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 (34) hide show
  1. package/lib/components/charts/LinearChart.md +33 -0
  2. package/lib/components/charts/LinearChart.vue +77 -0
  3. package/lib/components/connection-status/VtsConnectionStatus.vue +33 -0
  4. package/lib/components/console/VtsActionsConsole.vue +26 -12
  5. package/lib/components/console/VtsRemoteConsole.vue +58 -16
  6. package/lib/components/data-table/VtsDataTable.vue +58 -0
  7. package/lib/components/menu/MenuItem.vue +9 -13
  8. package/lib/components/menu/MenuList.vue +15 -13
  9. package/lib/components/tab/TabItem.vue +3 -4
  10. package/lib/components/tab/TabList.vue +5 -9
  11. package/lib/components/table/ColumnTitle.vue +1 -1
  12. package/lib/components/ui/account-menu-button/UiAccountMenuButton.vue +2 -3
  13. package/lib/components/ui/button/UiButton.vue +11 -17
  14. package/lib/components/ui/checkbox/UiCheckbox.vue +11 -15
  15. package/lib/components/ui/dropdown-button/UiDropdownButton.vue +9 -13
  16. package/lib/components/ui/info/UiInfo.vue +9 -11
  17. package/lib/components/ui/input/UiInput.vue +1 -0
  18. package/lib/components/ui/label/UiLabel.vue +11 -19
  19. package/lib/components/ui/radio-button/UiRadioButton.vue +12 -15
  20. package/lib/components/ui/table-pagination/PaginationButton.vue +33 -0
  21. package/lib/components/ui/table-pagination/UiTablePagination.vue +178 -0
  22. package/lib/components/ui/toggle/UiToggle.vue +6 -10
  23. package/lib/composables/chart-theme.composable.ts +382 -0
  24. package/lib/composables/disabled.composable.ts +15 -0
  25. package/lib/composables/route-query/types.ts +3 -2
  26. package/lib/i18n.ts +53 -0
  27. package/lib/layouts/CoreLayout.vue +20 -13
  28. package/lib/locales/en.json +6 -0
  29. package/lib/locales/es.json +97 -0
  30. package/lib/locales/fr.json +6 -0
  31. package/lib/types/chart.ts +9 -0
  32. package/lib/utils/injection-keys.util.ts +5 -0
  33. package/package.json +7 -2
  34. package/lib/context.ts +0 -10
@@ -0,0 +1,382 @@
1
+ import { useUiStore } from '@core/stores/ui.store'
2
+ import { storeToRefs } from 'pinia'
3
+ import { computed, provide, ref, watch } from 'vue'
4
+ import { THEME_KEY } from 'vue-echarts'
5
+
6
+ export const useChartTheme = () => {
7
+ const { colorMode } = storeToRefs(useUiStore())
8
+
9
+ const style = window.getComputedStyle(window.document.documentElement)
10
+
11
+ const getColors = () => ({
12
+ background: style.getPropertyValue('--color-neutral-background-primary'),
13
+ text: style.getPropertyValue('--color-neutral-txt-secondary'),
14
+ splitLine: style.getPropertyValue('--color-neutral-border'),
15
+ primary: style.getPropertyValue('--color-normal-txt-base'),
16
+ secondary: style.getPropertyValue('--color-warning-txt-base'),
17
+ })
18
+
19
+ const colors = ref(getColors())
20
+
21
+ watch(colorMode, () => (colors.value = getColors()), { flush: 'post' })
22
+
23
+ provide(
24
+ THEME_KEY,
25
+ computed(() => ({
26
+ color: [colors.value.primary, colors.value.secondary],
27
+ backgroundColor: colors.value.background,
28
+ textStyle: {},
29
+ grid: {
30
+ top: 40,
31
+ left: 80,
32
+ right: 20,
33
+ },
34
+ line: {
35
+ itemStyle: {
36
+ borderWidth: 2,
37
+ },
38
+ lineStyle: {
39
+ width: 2,
40
+ },
41
+ showSymbol: false,
42
+ symbolSize: 10,
43
+ symbol: 'circle',
44
+ smooth: false,
45
+ },
46
+ radar: {
47
+ itemStyle: {
48
+ borderWidth: 2,
49
+ },
50
+ lineStyle: {
51
+ width: 2,
52
+ },
53
+ symbolSize: 10,
54
+ symbol: 'circle',
55
+ smooth: false,
56
+ },
57
+ bar: {
58
+ itemStyle: {
59
+ barBorderWidth: 0,
60
+ barBorderColor: '#cccccc',
61
+ },
62
+ },
63
+ pie: {
64
+ itemStyle: {
65
+ borderWidth: 0,
66
+ borderColor: '#cccccc',
67
+ },
68
+ },
69
+ scatter: {
70
+ itemStyle: {
71
+ borderWidth: 0,
72
+ borderColor: '#cccccc',
73
+ },
74
+ },
75
+ boxplot: {
76
+ itemStyle: {
77
+ borderWidth: 0,
78
+ borderColor: '#cccccc',
79
+ },
80
+ },
81
+ parallel: {
82
+ itemStyle: {
83
+ borderWidth: 0,
84
+ borderColor: '#cccccc',
85
+ },
86
+ },
87
+ sankey: {
88
+ itemStyle: {
89
+ borderWidth: 0,
90
+ borderColor: '#cccccc',
91
+ },
92
+ },
93
+ funnel: {
94
+ itemStyle: {
95
+ borderWidth: 0,
96
+ borderColor: '#cccccc',
97
+ },
98
+ },
99
+ gauge: {
100
+ itemStyle: {
101
+ borderWidth: 0,
102
+ borderColor: '#cccccc',
103
+ },
104
+ },
105
+ candlestick: {
106
+ itemStyle: {
107
+ color: '#eb8146',
108
+ color0: 'transparent',
109
+ borderColor: '#d95850',
110
+ borderColor0: '#58c470',
111
+ borderWidth: '2',
112
+ },
113
+ },
114
+ graph: {
115
+ itemStyle: {
116
+ borderWidth: 0,
117
+ borderColor: '#cccccc',
118
+ },
119
+ lineStyle: {
120
+ width: 1,
121
+ color: '#aaaaaa',
122
+ },
123
+ symbolSize: '10',
124
+ symbol: 'emptyArrow',
125
+ smooth: true,
126
+ color: ['#893448', '#d95850', '#eb8146', '#ffb248', '#f2d643', '#ebdba4'],
127
+ label: {
128
+ color: '#ffffff',
129
+ },
130
+ },
131
+ map: {
132
+ itemStyle: {
133
+ areaColor: '#f3f3f3',
134
+ borderColor: '#999999',
135
+ borderWidth: 0.5,
136
+ },
137
+ label: {
138
+ color: '#893448',
139
+ },
140
+ emphasis: {
141
+ itemStyle: {
142
+ areaColor: '#ffb248',
143
+ borderColor: '#eb8146',
144
+ borderWidth: 1,
145
+ },
146
+ label: {
147
+ color: '#893448',
148
+ },
149
+ },
150
+ },
151
+ geo: {
152
+ itemStyle: {
153
+ areaColor: '#f3f3f3',
154
+ borderColor: '#999999',
155
+ borderWidth: 0.5,
156
+ },
157
+ label: {
158
+ color: '#893448',
159
+ },
160
+ emphasis: {
161
+ itemStyle: {
162
+ areaColor: '#ffb248',
163
+ borderColor: '#eb8146',
164
+ borderWidth: 1,
165
+ },
166
+ label: {
167
+ color: '#893448',
168
+ },
169
+ },
170
+ },
171
+ categoryAxis: {
172
+ axisLine: {
173
+ show: true,
174
+ lineStyle: {
175
+ color: '#aaaaaa',
176
+ },
177
+ },
178
+ axisTick: {
179
+ show: false,
180
+ lineStyle: {
181
+ color: '#333',
182
+ },
183
+ },
184
+ axisLabel: {
185
+ show: true,
186
+ color: '#999999',
187
+ },
188
+ splitLine: {
189
+ show: true,
190
+ lineStyle: {
191
+ color: [colors.value.splitLine],
192
+ },
193
+ },
194
+ splitArea: {
195
+ show: false,
196
+ areaStyle: {
197
+ color: ['rgba(250,250,250,0.05)', 'rgba(200,200,200,0.02)'],
198
+ },
199
+ },
200
+ },
201
+ valueAxis: {
202
+ axisLine: {
203
+ show: false,
204
+ // lineStyle: {
205
+ // color: "#aaaaaa",
206
+ // },
207
+ },
208
+ axisTick: {
209
+ show: false,
210
+ // lineStyle: {
211
+ // color: "#333",
212
+ // },
213
+ },
214
+ axisLabel: {
215
+ show: true,
216
+ color: colors.value.text,
217
+ },
218
+ splitLine: {
219
+ show: true,
220
+ lineStyle: {
221
+ color: [colors.value.splitLine],
222
+ },
223
+ },
224
+ splitArea: {
225
+ show: false,
226
+ areaStyle: {
227
+ color: ['rgba(250,250,250,0.05)', 'rgba(200,200,200,0.02)'],
228
+ },
229
+ },
230
+ },
231
+ logAxis: {
232
+ axisLine: {
233
+ show: true,
234
+ lineStyle: {
235
+ color: '#aaaaaa',
236
+ },
237
+ },
238
+ axisTick: {
239
+ show: false,
240
+ lineStyle: {
241
+ color: '#333',
242
+ },
243
+ },
244
+ axisLabel: {
245
+ show: true,
246
+ color: '#999999',
247
+ },
248
+ splitLine: {
249
+ show: true,
250
+ lineStyle: {
251
+ color: [colors.value.splitLine],
252
+ },
253
+ },
254
+ splitArea: {
255
+ show: false,
256
+ areaStyle: {
257
+ color: ['rgba(250,250,250,0.05)', 'rgba(200,200,200,0.02)'],
258
+ },
259
+ },
260
+ },
261
+ timeAxis: {
262
+ axisLine: {
263
+ show: false,
264
+ // lineStyle: {
265
+ // color: "#aaaaaa",
266
+ // },
267
+ },
268
+ axisTick: {
269
+ show: false,
270
+ // lineStyle: {
271
+ // color: "#333",
272
+ // },
273
+ },
274
+ axisLabel: {
275
+ show: true,
276
+ color: colors.value.text,
277
+ },
278
+ splitLine: {
279
+ show: true,
280
+ lineStyle: {
281
+ type: 'dashed',
282
+ color: [colors.value.splitLine],
283
+ },
284
+ },
285
+ splitArea: {
286
+ show: false,
287
+ areaStyle: {
288
+ color: ['rgba(250,250,250,0.05)', 'rgba(200,200,200,0.02)'],
289
+ },
290
+ },
291
+ },
292
+ toolbox: {
293
+ iconStyle: {
294
+ borderColor: '#999999',
295
+ },
296
+ emphasis: {
297
+ iconStyle: {
298
+ borderColor: '#666666',
299
+ },
300
+ },
301
+ },
302
+ legend: {
303
+ left: 'right',
304
+ top: 'bottom',
305
+ textStyle: {
306
+ color: colors.value.text,
307
+ },
308
+ },
309
+ tooltip: {
310
+ trigger: 'axis',
311
+ axisPointer: {
312
+ lineStyle: {
313
+ color: '#8F84FF',
314
+ width: 1,
315
+ },
316
+ crossStyle: {
317
+ color: '#8F84FF',
318
+ width: 1,
319
+ },
320
+ },
321
+ },
322
+ timeline: {
323
+ lineStyle: {
324
+ color: '#893448',
325
+ width: 1,
326
+ },
327
+ itemStyle: {
328
+ color: '#893448',
329
+ borderWidth: 1,
330
+ },
331
+ controlStyle: {
332
+ color: '#893448',
333
+ borderColor: '#893448',
334
+ borderWidth: 0.5,
335
+ },
336
+ checkpointStyle: {
337
+ color: '#eb8146',
338
+ borderColor: '#ffb248',
339
+ },
340
+ label: {
341
+ color: '#893448',
342
+ },
343
+ emphasis: {
344
+ itemStyle: {
345
+ color: '#ffb248',
346
+ },
347
+ controlStyle: {
348
+ color: '#893448',
349
+ borderColor: '#893448',
350
+ borderWidth: 0.5,
351
+ },
352
+ label: {
353
+ color: '#893448',
354
+ },
355
+ },
356
+ },
357
+ visualMap: {
358
+ color: ['#893448', '#d95850', '#eb8146', '#ffb248', '#f2d643', 'rgb(247,238,173)'],
359
+ },
360
+ dataZoom: {
361
+ backgroundColor: 'rgba(255,255,255,0)',
362
+ dataBackgroundColor: 'rgba(255,178,72,0.5)',
363
+ fillerColor: 'rgba(255,178,72,0.15)',
364
+ handleColor: '#ffb248',
365
+ handleSize: '100%',
366
+ textStyle: {
367
+ color: '#333',
368
+ },
369
+ },
370
+ markPoint: {
371
+ label: {
372
+ color: '#ffffff',
373
+ },
374
+ emphasis: {
375
+ label: {
376
+ color: '#ffffff',
377
+ },
378
+ },
379
+ },
380
+ }))
381
+ )
382
+ }
@@ -0,0 +1,15 @@
1
+ import { IK_DISABLED } from '@core/utils/injection-keys.util'
2
+ import { computed, inject, type MaybeRefOrGetter, provide, toValue } from 'vue'
3
+
4
+ export function useDisabled(condition?: MaybeRefOrGetter<boolean>) {
5
+ const previousValue = inject(
6
+ IK_DISABLED,
7
+ computed(() => false)
8
+ )
9
+
10
+ const currentValue = computed(() => previousValue.value || toValue(condition ?? false))
11
+
12
+ provide(IK_DISABLED, currentValue)
13
+
14
+ return currentValue
15
+ }
@@ -28,8 +28,9 @@ export type BooleanActions = { toggle: (value?: boolean) => void }
28
28
 
29
29
  export type Actions = SetActions<any> & MapActions<any, any> & ArrayActions<any> & BooleanActions
30
30
 
31
- export type GuessActions<TData> =
32
- TData extends Set<infer TValue>
31
+ export type GuessActions<TData> = TData extends string | number
32
+ ? EmptyObject
33
+ : TData extends Set<infer TValue>
33
34
  ? SetActions<TValue>
34
35
  : TData extends (infer TValue)[]
35
36
  ? ArrayActions<TValue>
package/lib/i18n.ts CHANGED
@@ -13,6 +13,10 @@ export const locales: Locales = {
13
13
  code: 'en',
14
14
  name: 'English',
15
15
  },
16
+ es: {
17
+ code: 'es',
18
+ name: 'Español',
19
+ },
16
20
  fr: {
17
21
  code: 'fr',
18
22
  name: 'Français',
@@ -87,6 +91,48 @@ export default createI18n({
87
91
  minute: '2-digit',
88
92
  },
89
93
  },
94
+ es: {
95
+ date_short: {
96
+ year: 'numeric',
97
+ month: 'numeric',
98
+ day: 'numeric',
99
+ },
100
+ date_medium: {
101
+ year: 'numeric',
102
+ month: 'short',
103
+ day: 'numeric',
104
+ },
105
+ date_long: {
106
+ year: 'numeric',
107
+ month: 'long',
108
+ day: 'numeric',
109
+ },
110
+ datetime_short: {
111
+ year: 'numeric',
112
+ month: 'numeric',
113
+ day: 'numeric',
114
+ hour: '2-digit',
115
+ minute: '2-digit',
116
+ },
117
+ datetime_medium: {
118
+ year: 'numeric',
119
+ month: 'short',
120
+ day: 'numeric',
121
+ hour: '2-digit',
122
+ minute: '2-digit',
123
+ },
124
+ datetime_long: {
125
+ year: 'numeric',
126
+ month: 'long',
127
+ day: 'numeric',
128
+ hour: '2-digit',
129
+ minute: '2-digit',
130
+ },
131
+ time: {
132
+ hour: '2-digit',
133
+ minute: '2-digit',
134
+ },
135
+ },
90
136
  fr: {
91
137
  date_short: {
92
138
  year: 'numeric',
@@ -222,6 +268,13 @@ export default createI18n({
222
268
  maximumFractionDigits: 2,
223
269
  },
224
270
  },
271
+ es: {
272
+ percent: {
273
+ style: 'percent',
274
+ minimumFractionDigits: 0,
275
+ maximumFractionDigits: 2,
276
+ },
277
+ },
225
278
  fr: {
226
279
  percent: {
227
280
  style: 'percent',
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <div class="core-layout">
3
- <header class="header">
3
+ <header v-if="uiStore.hasUi" class="header">
4
4
  <slot name="app-logo" />
5
5
  <UiButtonIcon
6
6
  v-tooltip="{
@@ -16,18 +16,23 @@
16
16
  <slot name="app-header" />
17
17
  </header>
18
18
  <div class="container">
19
- <VtsBackdrop v-if="sidebarStore.isExpanded && !sidebarStore.isLocked" @click="sidebarStore.toggleExpand(false)" />
20
- <VtsLayoutSidebar class="sidebar">
21
- <template #header>
22
- <slot name="sidebar-header" />
23
- </template>
24
- <template #default>
25
- <slot name="sidebar-content" />
26
- </template>
27
- <template #footer>
28
- <slot name="sidebar-footer" />
29
- </template>
30
- </VtsLayoutSidebar>
19
+ <template v-if="uiStore.hasUi">
20
+ <VtsBackdrop
21
+ v-if="sidebarStore.isExpanded && !sidebarStore.isLocked"
22
+ @click="sidebarStore.toggleExpand(false)"
23
+ />
24
+ <VtsLayoutSidebar class="sidebar">
25
+ <template #header>
26
+ <slot name="sidebar-header" />
27
+ </template>
28
+ <template #default>
29
+ <slot name="sidebar-content" />
30
+ </template>
31
+ <template #footer>
32
+ <slot name="sidebar-footer" />
33
+ </template>
34
+ </VtsLayoutSidebar>
35
+ </template>
31
36
  <main class="main-container">
32
37
  <slot name="content" />
33
38
  </main>
@@ -41,8 +46,10 @@ import VtsLayoutSidebar from '@core/components/layout/VtsLayoutSidebar.vue'
41
46
  import UiButtonIcon from '@core/components/ui/button-icon/UiButtonIcon.vue'
42
47
  import { vTooltip } from '@core/directives/tooltip.directive'
43
48
  import { useSidebarStore } from '@core/stores/sidebar.store'
49
+ import { useUiStore } from '@core/stores/ui.store'
44
50
  import { faAngleDoubleLeft, faBars } from '@fortawesome/free-solid-svg-icons'
45
51
 
52
+ const uiStore = useUiStore()
46
53
  const sidebarStore = useSidebarStore()
47
54
  </script>
48
55
 
@@ -21,6 +21,7 @@
21
21
  "core.quick-actions": "Quick actions",
22
22
 
23
23
  "core.search": "Search",
24
+ "core.show-by": "Show by",
24
25
 
25
26
  "core.query-search-bar.label": "Search Engine",
26
27
  "core.query-search-bar.placeholder": "Write your query…",
@@ -29,6 +30,7 @@
29
30
  "core.select.all": "Select all",
30
31
  "core.select.none": "Select none",
31
32
  "core.select.unselect": "Unselect all",
33
+ "core.select.n-object-of": "{from} - {to} of {total} objects",
32
34
  "core.select.n-selected-of": "{count} selected of {total} objects",
33
35
  "core.sidebar.close": "Close sidebar",
34
36
  "core.sidebar.lock": "Lock sidebar open",
@@ -43,7 +45,10 @@
43
45
  "dark-mode.auto": "Auto dark mode",
44
46
 
45
47
  "access-forum": "Access forum",
48
+ "connected": "Connected",
46
49
  "dashboard": "Dashboard",
50
+ "disconnected": "Disconnected",
51
+ "disconnected-from-physical-device": "Disconnected from physical device",
47
52
  "documentation-name": "{name} documentation",
48
53
  "error-no-data": "Error, can't collect data.",
49
54
  "exit-fullscreen": "Exit fullscreen",
@@ -61,6 +66,7 @@
61
66
  "open-console-in-new-tab": "Open console in new tab",
62
67
  "other": "Other",
63
68
  "page-not-found": "This page is not to be found…",
69
+ "partially-connected": "Partially connected",
64
70
  "patches": "Patches",
65
71
  "power-on-vm-for-console": "Power on your VM to access its console",
66
72
  "power-on-host-for-console": "Power on your host to access its console",
@@ -0,0 +1,97 @@
1
+ {
2
+ "alarms": "Alarmas",
3
+
4
+ "bytes.ki": "Kio",
5
+ "bytes.mi": "Mio",
6
+ "bytes.gi": "Gio",
7
+
8
+ "coming-soon": "¡Vendrá pronto!",
9
+ "console": "Consola",
10
+ "console-actions": "Acciones de la cónsola",
11
+ "console-clipboard": "Portapales de la cónsola",
12
+
13
+ "core.copied": "Copiar",
14
+ "core.copy-id": "Copiar la ID",
15
+ "core.close": "Cerrar",
16
+ "core.current": "Actual",
17
+ "core.filter": "Filtrar",
18
+ "core.group": "Grupar",
19
+ "core.hide": "Ocultar",
20
+ "core.open": "Abrir",
21
+ "core.quick-actions": "Acciones rápidas",
22
+
23
+ "core.search": "Buscar",
24
+ "core.show-by": "Mostrar por...",
25
+
26
+ "core.query-search-bar.label": "Buscador",
27
+ "core.query-search-bar.placeholder": "Entre su búsqueda",
28
+ "core.query-search-bar.use-query-builder": "Utilizar la constructora de búsquedas",
29
+
30
+ "core.select.all": "Selectionar todos",
31
+ "core.select.none": "Selectionar ninguno",
32
+ "core.select.unselect": "Deseleccionar todos",
33
+ "core.select.n-object-of": "{from} - {to} de {total} objectos",
34
+ "core.select.n-selected-of": "{count} objectos selectionados de un total de {total}",
35
+ "core.sidebar.close": "Cerrar la barra lateral",
36
+ "core.sidebar.lock": "Bloquear abierta la barra lateral",
37
+ "core.sidebar.open": "Abrir la barra lateral",
38
+ "core.sidebar.unlock": "Desbloquear la barra lateral",
39
+
40
+ "core.sort.ascending": "Ordenar",
41
+ "core.sort.descending": "Ordenar descendentemente",
42
+
43
+ "dark-mode.enable": "Activar modo oscuro",
44
+ "dark-mode.disable": "Desactivar modo oscuro",
45
+ "dark-mode.auto": "Modo oscuro automática",
46
+
47
+ "access-forum": "Acceso al foro",
48
+ "connected": "Conectado",
49
+ "dashboard": "Panel",
50
+ "disconnected": "Disconectado",
51
+ "disconnected-from-physical-device": "Disconectado del aparato físico",
52
+ "documentation-name": "Documentación {name}",
53
+ "error-no-data": "Error, imposible recoger datos.",
54
+ "exit-fullscreen": "Salir de pantala completa",
55
+ "fullscreen": "Pantalla completa",
56
+ "gateway": "Puerta de enlace",
57
+ "hosts": "Servidores",
58
+ "learn-more": "Saber más",
59
+ "loading-in-progress": "Cargando…",
60
+ "log-out": "Desconectarse",
61
+ "master": "Servidor principal",
62
+ "n-vms": "1 VM | {n} VMs",
63
+ "network": "Red",
64
+ "no-data": "No hay datos",
65
+ "object-not-found": "No se encuentra el objecto {id}…",
66
+ "open-console-in-new-tab": "Abrir la cónsola en una nueva pestaña",
67
+ "other": "Otro",
68
+ "page-not-found": "No se encuentra esta página",
69
+ "partially-connected": "Parcialmente connectado",
70
+ "patches": "Parches",
71
+ "power-on-vm-for-console": "Poner la MV en marcha para acceder a su cónsola",
72
+ "power-on-host-for-console": "Poner en marcha el servidor para acceder a su cónsola",
73
+ "professional-support": "Soporte profesional",
74
+ "receive": "Recibir",
75
+ "running-vm": "MV en marcha | MVs en marcha",
76
+ "see-all": "Ver todos",
77
+ "select-to-see-details": "Elegir un elemento para ver las detalles",
78
+ "send": "Enviar",
79
+ "send-ctrl-alt-del": "Enviar Ctrl+Alt+Supr",
80
+ "speed": "Velocidad",
81
+ "stats": "Stats",
82
+ "storage": "Amacenamiento",
83
+ "system": "Sistema",
84
+
85
+ "tasks": "Tareas",
86
+ "tasks.n-subtasks": "{n} subtarea | {n} subtareas",
87
+ "tasks.no-tasks": "Ninguna tarea",
88
+ "tasks.quick-view": "Vista rápida de tareas",
89
+ "tasks.quick-view.all": "Todas",
90
+ "tasks.quick-view.done": "Terminadas",
91
+ "tasks.quick-view.failed": "Falladas",
92
+ "tasks.quick-view.in-progress": "En progreso",
93
+
94
+ "total": "Total",
95
+ "total-cpus": "Total CPUs",
96
+ "vms": "VMs"
97
+ }