@xen-orchestra/web-core 0.48.2 → 0.50.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.
- package/lib/assets/creating.svg +566 -0
- package/lib/components/delete-button/VtsDeleteButton.vue +27 -0
- package/lib/components/menu/VtsActionsMenu.vue +53 -0
- package/lib/components/modal/VtsModalList.vue +1 -1
- package/lib/components/operation-card/VtsOperationCard.vue +51 -0
- package/lib/components/operation-error-card/VtsOperationErrorCard.vue +38 -0
- package/lib/components/operation-pending-card/VtsOperationPendingCard.vue +23 -0
- package/lib/components/state-hero/VtsStateHero.vue +1 -0
- package/lib/components/table/cells/VtsActionCell.vue +44 -0
- package/lib/composables/default-tab.composable.md +17 -11
- package/lib/composables/default-tab.composable.ts +10 -4
- package/lib/locales/cs.json +25 -9
- package/lib/locales/da.json +3 -3
- package/lib/locales/de.json +5 -6
- package/lib/locales/en.json +45 -7
- package/lib/locales/es.json +276 -195
- package/lib/locales/fa.json +3 -3
- package/lib/locales/fi.json +1 -1
- package/lib/locales/fr.json +44 -6
- package/lib/locales/it.json +5 -4
- package/lib/locales/ko.json +3 -1
- package/lib/locales/nb-NO.json +2 -2
- package/lib/locales/nl.json +23 -7
- package/lib/locales/pl.json +1 -1
- package/lib/locales/pt-BR.json +5 -6
- package/lib/locales/pt.json +5 -6
- package/lib/locales/ru.json +60 -13
- package/lib/locales/sk.json +216 -17
- package/lib/locales/sv.json +5 -6
- package/lib/locales/uk.json +1 -1
- package/lib/locales/zh-Hans.json +23 -7
- package/lib/packages/form-bindings/README.md +102 -0
- package/lib/packages/form-bindings/index.ts +1 -0
- package/lib/packages/form-bindings/use-form-bindings.ts +61 -0
- package/lib/packages/remote-resource/define-remote-resource.ts +6 -1
- package/lib/packages/remote-resource/sse.store.ts +1 -1
- package/lib/packages/table/define-columns.ts +4 -3
- package/lib/tables/column-definitions/action-column.ts +21 -0
- package/lib/tables/column-definitions/button-icon-column.ts +2 -2
- package/lib/tables/column-definitions/text-column.ts +1 -1
- package/lib/tables/column-sets/vdi-columns.ts +2 -2
- package/lib/tables/column-sets/vif-columns.ts +2 -2
- package/package.json +3 -3
package/lib/locales/uk.json
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"action:copy-info-json": "Копіювати інформацію в JSON",
|
|
22
22
|
"action:create": "Створити",
|
|
23
23
|
"action:delete": "Видалити",
|
|
24
|
-
"action:delete-vms": "Видалено 1 VM | Видалено {n} VMs",
|
|
24
|
+
"action:delete-n-vms": "Видалено 1 VM | Видалено {n} VMs",
|
|
25
25
|
"action:deploy": "Розгорнути",
|
|
26
26
|
"action:deploy-xoa": "Розгорнути XOA",
|
|
27
27
|
"action:edit": "Редагувати",
|
package/lib/locales/zh-Hans.json
CHANGED
|
@@ -29,9 +29,10 @@
|
|
|
29
29
|
"action:delete": "删除",
|
|
30
30
|
"action:delete-filter": "删除筛选器",
|
|
31
31
|
"action:delete-group": "删除群组",
|
|
32
|
-
"action:delete-vms": "删除1台虚拟机 | 删除{n}台虚拟机",
|
|
32
|
+
"action:delete-n-vms": "删除1台虚拟机 | 删除{n}台虚拟机",
|
|
33
33
|
"action:deploy": "部署",
|
|
34
34
|
"action:deploy-xoa": "部署XOA",
|
|
35
|
+
"action:download-bugtools-archive": "下载 bugtools 压缩包",
|
|
35
36
|
"action:duplicate": "复制",
|
|
36
37
|
"action:edit": "编辑",
|
|
37
38
|
"action:edit-config": "编辑配置",
|
|
@@ -150,6 +151,7 @@
|
|
|
150
151
|
"backup:full-replication": "全量复制",
|
|
151
152
|
"backup:incremental": "增量备份",
|
|
152
153
|
"backup:incremental-replication": "增量复制",
|
|
154
|
+
"backup:last-replication": "最后一次复制",
|
|
153
155
|
"backup:mirror:full": "镜像全量备份",
|
|
154
156
|
"backup:mirror:incremental": "镜像增量备份",
|
|
155
157
|
"backup:pool-metadata": "资源池元数据",
|
|
@@ -162,7 +164,7 @@
|
|
|
162
164
|
"backups:jobs:issues-ran-without-hitch": "所有备份作业均正常运行。",
|
|
163
165
|
"backups:jobs:last-seven-days": "近7天",
|
|
164
166
|
"backups:jobs:no-recent-run": "无近期运行记录",
|
|
165
|
-
"backups:jobs:running-good": "
|
|
167
|
+
"backups:jobs:running-good": "一切运行正常",
|
|
166
168
|
"backups:jobs:skipped-runs": "跳过运行,无错误",
|
|
167
169
|
"backups:jobs:status": "备份作业状态",
|
|
168
170
|
"backups:vms-protection": "虚拟机保护状态",
|
|
@@ -237,6 +239,7 @@
|
|
|
237
239
|
"crash-dump-storage-repository": "崩溃转储存储库",
|
|
238
240
|
"created-by": "创建者",
|
|
239
241
|
"created-on": "创建时间",
|
|
242
|
+
"creation-date": "创建日期",
|
|
240
243
|
"cron-pattern": "Cron表达式",
|
|
241
244
|
"current": "当前",
|
|
242
245
|
"current-attach": "当前挂载",
|
|
@@ -334,6 +337,7 @@
|
|
|
334
337
|
"id": "ID",
|
|
335
338
|
"in-last-three-runs": "最近3次运行",
|
|
336
339
|
"in-progress": "进行中",
|
|
340
|
+
"included": "已包含",
|
|
337
341
|
"info": "信息",
|
|
338
342
|
"infos": "信息",
|
|
339
343
|
"install-settings": "安装设置",
|
|
@@ -358,21 +362,20 @@
|
|
|
358
362
|
"job-name": "作业名称",
|
|
359
363
|
"job:arg:host-required": "主机为必填项",
|
|
360
364
|
"job:arg:missing-payload": "缺少有效负载",
|
|
361
|
-
"job:arg:name-
|
|
365
|
+
"job:arg:name-required": "名称标签为必填项",
|
|
362
366
|
"job:arg:password-required": "密码为必填项",
|
|
363
367
|
"job:arg:pool-id-required": "资源池ID为必填项",
|
|
364
368
|
"job:arg:sr-vdi-required": "存储库/虚拟磁盘为必填项",
|
|
365
369
|
"job:arg:template-uuid-required": "模板UUID为必填项",
|
|
366
370
|
"job:arg:username-required": "用户名为必填项",
|
|
367
|
-
"job:
|
|
371
|
+
"job:delete:in-progress": "删除中.…",
|
|
372
|
+
"job:create:in-progress": "创建中.…",
|
|
368
373
|
"job:vm-copy:bad-power-state": "虚拟机必须处于停止状态",
|
|
369
374
|
"job:vm-copy:in-progress": "复制中.…",
|
|
370
375
|
"job:vm-copy:missing-vm": "无虚拟机可复制",
|
|
371
|
-
"job:vm-create:in-progress": "创建中.…",
|
|
372
376
|
"job:vm-create:incomplete-install-mode": "安装模式不完整",
|
|
373
377
|
"job:vm-delete:bad-power-state": "虚拟机必须处于停止状态",
|
|
374
378
|
"job:vm-delete:blocked-operation": "虚拟机删除被阻止",
|
|
375
|
-
"job:vm-delete:in-progress": "删除中.…",
|
|
376
379
|
"job:vm-delete:missing-vm": "无虚拟机可删除",
|
|
377
380
|
"job:vm-export:in-progress": "导出中.…",
|
|
378
381
|
"job:vm-export:missing-compression": "必须指定压缩方式",
|
|
@@ -427,7 +430,9 @@
|
|
|
427
430
|
"last-n-backup-archives": "最后一个备份存档 | 最近 {n} 个备份存档",
|
|
428
431
|
"last-n-backup-runs": "最近一次备份运行 | 最近 {n} 次备份运行",
|
|
429
432
|
"last-n-runs": "最近1次运行 | 最近{n}次运行",
|
|
433
|
+
"last-revert": "最后一次还原",
|
|
430
434
|
"last-run-number": "最近运行 #{n}",
|
|
435
|
+
"last-snapshot": "最后一个快照",
|
|
431
436
|
"last-week": "上周",
|
|
432
437
|
"learn-more": "了解更多",
|
|
433
438
|
"lets-go!": "开始!",
|
|
@@ -436,7 +441,7 @@
|
|
|
436
441
|
"license-type": "许可证类型",
|
|
437
442
|
"licensing": "许可",
|
|
438
443
|
"load-average": "平均负载",
|
|
439
|
-
"loading": "
|
|
444
|
+
"loading": "加载中",
|
|
440
445
|
"loading-hosts": "加载主机中.…",
|
|
441
446
|
"local": "本地",
|
|
442
447
|
"locked": "已锁定",
|
|
@@ -452,11 +457,13 @@
|
|
|
452
457
|
"management-agent-not-detected": "未检测到管理代理",
|
|
453
458
|
"management-agent-version": "管理代理版本",
|
|
454
459
|
"management-ip": "管理IP",
|
|
460
|
+
"manual": "说明书",
|
|
455
461
|
"manufacturer-info": "厂商信息",
|
|
456
462
|
"master": "主主机",
|
|
457
463
|
"maximum-cpu-limit": "最大CPU限制",
|
|
458
464
|
"maximum-dynamic-memory": "最大动态内存",
|
|
459
465
|
"maximum-static-memory": "最大静态内存",
|
|
466
|
+
"memory": "内存",
|
|
460
467
|
"memory-usage": "内存使用率",
|
|
461
468
|
"merge-backups-synchronously": "同步合并备份",
|
|
462
469
|
"message": "消息",
|
|
@@ -552,6 +559,7 @@
|
|
|
552
559
|
"no-selected-vm-can-be-exported": "所选虚拟机均无法导出",
|
|
553
560
|
"no-selected-vm-can-be-migrated": "所选虚拟机均无法迁移",
|
|
554
561
|
"no-server-detected": "未检测到服务器",
|
|
562
|
+
"no-snapshot-detected": "未检测到快照",
|
|
555
563
|
"no-storage-repository-detected": "未检测到存储库",
|
|
556
564
|
"no-task": "无任务",
|
|
557
565
|
"no-task-detected": "未检测到任务",
|
|
@@ -563,6 +571,7 @@
|
|
|
563
571
|
"none": "无",
|
|
564
572
|
"normal": "正常",
|
|
565
573
|
"not-found": "未找到",
|
|
574
|
+
"not-included": "不包含在内",
|
|
566
575
|
"not-resident-on": "未驻留于",
|
|
567
576
|
"not-running": "未运行",
|
|
568
577
|
"not-yet-available": "信息暂不可用",
|
|
@@ -595,6 +604,7 @@
|
|
|
595
604
|
"other-properties": "其他属性",
|
|
596
605
|
"other-settings": "其他设置",
|
|
597
606
|
"page-not-found": "未找到此页面.…",
|
|
607
|
+
"page-please-wait": "握紧扶手,宇航员!页面即将升空。{newline}我们正在校准推进器、调试系统,很快就好,敬请期待!",
|
|
598
608
|
"pagination:all": "全部",
|
|
599
609
|
"partially-connected": "部分连接",
|
|
600
610
|
"password": "密码",
|
|
@@ -612,6 +622,7 @@
|
|
|
612
622
|
"pifs": "PIF",
|
|
613
623
|
"pifs-status": "PIF状态",
|
|
614
624
|
"please-confirm-to-continue": "此操作不可撤销,确定继续吗?",
|
|
625
|
+
"please-wait": "请稍后",
|
|
615
626
|
"pool": "资源池",
|
|
616
627
|
"pool-connection-error-auth-failed": "连接资源池失败,用户名或密码错误。",
|
|
617
628
|
"pool-connection-error-duplicate": "连接资源池失败,此资源池已连接。",
|
|
@@ -739,6 +750,7 @@
|
|
|
739
750
|
"skipped": "已跳过",
|
|
740
751
|
"smart-mode": "智能模式",
|
|
741
752
|
"snapshot": "快照",
|
|
753
|
+
"snapshot-created-on": "快照创建于",
|
|
742
754
|
"snapshot-mode": "快照模式",
|
|
743
755
|
"snapshots": "快照",
|
|
744
756
|
"sockets-with-cores-per-socket": "{nSockets}个插槽 × {nCores}核/插槽",
|
|
@@ -778,6 +790,7 @@
|
|
|
778
790
|
"status:suspended": "已挂起",
|
|
779
791
|
"status:unknown": "未知",
|
|
780
792
|
"status:unreachable": "不可达",
|
|
793
|
+
"step-n-of": "步骤 {current} / {total}",
|
|
781
794
|
"storage": "存储",
|
|
782
795
|
"storage-configuration": "存储配置",
|
|
783
796
|
"storage-format": "存储格式",
|
|
@@ -840,11 +853,13 @@
|
|
|
840
853
|
"total-used:": "总已用:",
|
|
841
854
|
"transfer-size": "传输大小",
|
|
842
855
|
"translation-tool": "翻译工具",
|
|
856
|
+
"trigger": "触发",
|
|
843
857
|
"unable-to-connect-to": "无法连接到 {ip}",
|
|
844
858
|
"unable-to-connect-to-the-pool": "无法连接资源池",
|
|
845
859
|
"unable-to-connect-to-xo-server": "无法连接到 XO 服务器。",
|
|
846
860
|
"unknown": "未知",
|
|
847
861
|
"unlocked": "已解锁",
|
|
862
|
+
"unnamed": "未命名",
|
|
848
863
|
"unreachable-hosts": "不可达主机",
|
|
849
864
|
"unreachable-hosts-reload-page": "完成,请刷新页面",
|
|
850
865
|
"untitled": "未命名",
|
|
@@ -853,6 +868,7 @@
|
|
|
853
868
|
"used": "已用",
|
|
854
869
|
"used-for-backup": "用于备份",
|
|
855
870
|
"used-space": "已用空间",
|
|
871
|
+
"used-space-on-sr": "SR 上的已用空间",
|
|
856
872
|
"user-config": "用户配置",
|
|
857
873
|
"username": "用户名",
|
|
858
874
|
"uuid": "UUID",
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# `useFormBindings` composable
|
|
2
|
+
|
|
3
|
+
`useFormBindings` generates reactive `v-model` bindings for each field of a reactive form data object, removing the need to manually write `modelValue`/`onUpdate:modelValue` props for every input.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
const bindings = useFormBindings(formData)
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Parameters
|
|
12
|
+
|
|
13
|
+
| Argument | Type | Required | Description |
|
|
14
|
+
| -------- | ----------------------------------- | :------: | ----------------------------------------------- |
|
|
15
|
+
| `source` | `T extends Record<string, unknown>` | ✓ | A reactive object holding the form field values |
|
|
16
|
+
|
|
17
|
+
## Return Value
|
|
18
|
+
|
|
19
|
+
| Property | Type | Description |
|
|
20
|
+
| ----------- | ---------------------------------------------------------- | ----------------------------------------------------- |
|
|
21
|
+
| `useField` | `(key, metadata?) => ComputedRef<ModelBinding & metadata>` | Creates a binding, optionally merged with extra props |
|
|
22
|
+
| `useSelect` | `(id, metadata?) => ComputedRef<{ id } & metadata>` | Creates a binding for a `VtsSelect`-like component |
|
|
23
|
+
|
|
24
|
+
### `ModelBinding<T>` object
|
|
25
|
+
|
|
26
|
+
Each field binding is a computed object with:
|
|
27
|
+
|
|
28
|
+
| Property | Type | Description |
|
|
29
|
+
| --------------------- | -------------------- | -------------------------------------- |
|
|
30
|
+
| `modelValue` | `T` | The current value of the field |
|
|
31
|
+
| `onUpdate:modelValue` | `(value: T) => void` | Setter — updates the field in `source` |
|
|
32
|
+
|
|
33
|
+
## `useField(key, metadata?)`
|
|
34
|
+
|
|
35
|
+
Returns the standard `ModelBinding` for the given key. Pass an optional `metadata` factory function to merge additional props into the binding (e.g. label, validation state, disabled state, etc.).
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
// Without metadata
|
|
39
|
+
const nameBindings = bindings.useField('name')
|
|
40
|
+
|
|
41
|
+
// With metadata
|
|
42
|
+
const nameBindings = bindings.useField('name', () => ({
|
|
43
|
+
label: t('name'),
|
|
44
|
+
required: true,
|
|
45
|
+
}))
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## `useSelect(id, metadata?)`
|
|
49
|
+
|
|
50
|
+
Returns a binding for a select component registered via `useFormSelect`. The `id` comes from the `useFormSelect` return value.
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
const { id: poolSelectId } = useFormSelect(pools, { ... })
|
|
54
|
+
|
|
55
|
+
const poolSelectBindings = bindings.useSelect(poolSelectId)
|
|
56
|
+
|
|
57
|
+
// With metadata
|
|
58
|
+
const poolSelectBindings = bindings.useSelect(poolSelectId, () => ({
|
|
59
|
+
label: t('pool'),
|
|
60
|
+
}))
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Example: With metadata (e.g. label + validation)
|
|
64
|
+
|
|
65
|
+
```vue
|
|
66
|
+
<template>
|
|
67
|
+
<VtsInput v-bind="nameBindings" />
|
|
68
|
+
</template>
|
|
69
|
+
|
|
70
|
+
<script lang="ts" setup>
|
|
71
|
+
import { useFormBindings } from '@core/packages/form-bindings'
|
|
72
|
+
import { reactive } from 'vue'
|
|
73
|
+
|
|
74
|
+
const formData = reactive({ name: '' })
|
|
75
|
+
|
|
76
|
+
const { useField } = useFormBindings(formData)
|
|
77
|
+
|
|
78
|
+
const nameBindings = useField('name', () => ({
|
|
79
|
+
label: 'Name',
|
|
80
|
+
error: formData.name === '' ? 'Name is required' : undefined,
|
|
81
|
+
}))
|
|
82
|
+
</script>
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Example: With a select component
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
import { useFormBindings } from '@core/packages/form-bindings'
|
|
89
|
+
import { useFormSelect } from '@core/packages/form-select'
|
|
90
|
+
import { reactive } from 'vue'
|
|
91
|
+
|
|
92
|
+
const formData = reactive({ pool: undefined as string | undefined })
|
|
93
|
+
|
|
94
|
+
const { id: poolSelectId } = useFormSelect(pools, {
|
|
95
|
+
model: toRef(formData, 'pool'),
|
|
96
|
+
option: { label: 'name_label', value: 'id' },
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
const { useSelect } = useFormBindings(formData)
|
|
100
|
+
|
|
101
|
+
const poolSelectBindings = useSelect(poolSelectId)
|
|
102
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './use-form-bindings.ts'
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { FormSelectId } from '@core/packages/form-select'
|
|
2
|
+
import { computed, type ComputedRef } from 'vue'
|
|
3
|
+
|
|
4
|
+
export type ModelBinding<T> = {
|
|
5
|
+
modelValue: T
|
|
6
|
+
'onUpdate:modelValue': (value: T) => void
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export type UseFormBindingsReturn<T extends Record<string, unknown>> = {
|
|
10
|
+
useField: {
|
|
11
|
+
<K extends keyof T>(key: K): ComputedRef<ModelBinding<T[K]>>
|
|
12
|
+
<K extends keyof T, E extends Record<string, unknown>>(
|
|
13
|
+
key: K,
|
|
14
|
+
metadata: () => E
|
|
15
|
+
): ComputedRef<ModelBinding<T[K]> & E>
|
|
16
|
+
}
|
|
17
|
+
useSelect: {
|
|
18
|
+
(id: FormSelectId): ComputedRef<{ id: FormSelectId }>
|
|
19
|
+
<E extends Record<string, unknown>>(id: FormSelectId, metadata: () => E): ComputedRef<{ id: FormSelectId } & E>
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function useFormBindings<T extends Record<string, unknown>>(source: T): UseFormBindingsReturn<T> {
|
|
24
|
+
function useField<K extends keyof T>(key: K): ComputedRef<ModelBinding<T[K]>>
|
|
25
|
+
function useField<K extends keyof T, E extends Record<string, unknown>>(
|
|
26
|
+
key: K,
|
|
27
|
+
metadata: () => E
|
|
28
|
+
): ComputedRef<ModelBinding<T[K]> & E>
|
|
29
|
+
function useField<K extends keyof T, E extends Record<string, unknown> = Record<string, unknown>>(
|
|
30
|
+
key: K,
|
|
31
|
+
metadata?: () => E
|
|
32
|
+
) {
|
|
33
|
+
return computed(() => ({
|
|
34
|
+
modelValue: source[key],
|
|
35
|
+
'onUpdate:modelValue': (value: T[K]) => {
|
|
36
|
+
source[key] = value
|
|
37
|
+
},
|
|
38
|
+
...metadata?.(),
|
|
39
|
+
}))
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function useSelect(id: FormSelectId): ComputedRef<{ id: FormSelectId }>
|
|
43
|
+
function useSelect<E extends Record<string, unknown>>(
|
|
44
|
+
id: FormSelectId,
|
|
45
|
+
metadata: () => E
|
|
46
|
+
): ComputedRef<{ id: FormSelectId } & E>
|
|
47
|
+
function useSelect<E extends Record<string, unknown> = Record<string, unknown>>(
|
|
48
|
+
id: FormSelectId,
|
|
49
|
+
metadata?: () => E
|
|
50
|
+
) {
|
|
51
|
+
return computed(() => ({
|
|
52
|
+
id,
|
|
53
|
+
...metadata?.(),
|
|
54
|
+
}))
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
useField,
|
|
59
|
+
useSelect,
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
toRef,
|
|
26
26
|
toValue,
|
|
27
27
|
watch,
|
|
28
|
+
effectScope,
|
|
28
29
|
} from 'vue'
|
|
29
30
|
|
|
30
31
|
const DEFAULT_CACHE_EXPIRATION_MS = 10_000
|
|
@@ -106,6 +107,7 @@ export function defineRemoteResource<
|
|
|
106
107
|
pause: VoidFunction
|
|
107
108
|
resume: VoidFunction
|
|
108
109
|
state: object
|
|
110
|
+
stateScope: EffectScope
|
|
109
111
|
isReady: Ref<boolean>
|
|
110
112
|
isFetching: Ref<boolean>
|
|
111
113
|
lastError: Ref<Error | undefined>
|
|
@@ -239,6 +241,7 @@ export function defineRemoteResource<
|
|
|
239
241
|
|
|
240
242
|
if (cacheExpiration !== false) {
|
|
241
243
|
setTimeout(() => {
|
|
244
|
+
cache.get(url)?.stateScope.stop()
|
|
242
245
|
cache.delete(url)
|
|
243
246
|
}, cacheExpiration)
|
|
244
247
|
}
|
|
@@ -340,13 +343,15 @@ export function defineRemoteResource<
|
|
|
340
343
|
resume = timeoutPoll.resume
|
|
341
344
|
}
|
|
342
345
|
|
|
343
|
-
const
|
|
346
|
+
const stateScope = effectScope(true)
|
|
347
|
+
const state = stateScope.run(() => buildState(data, context))!
|
|
344
348
|
|
|
345
349
|
cache.set(url, {
|
|
346
350
|
count: 0,
|
|
347
351
|
pause,
|
|
348
352
|
resume,
|
|
349
353
|
state,
|
|
354
|
+
stateScope,
|
|
350
355
|
isReady,
|
|
351
356
|
isFetching,
|
|
352
357
|
lastError,
|
|
@@ -49,7 +49,7 @@ export const useSseStore = defineStore('sse', () => {
|
|
|
49
49
|
return false
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
return now.value.getTime() - sse.value.lastPing >
|
|
52
|
+
return now.value.getTime() - sse.value.lastPing > 40_000
|
|
53
53
|
})
|
|
54
54
|
|
|
55
55
|
const hasErrorSse = computed(() => isError.value || sse.value.errorSse !== null)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AreAllPropertiesOptional, Columns } from '@core/packages/table/types.ts'
|
|
2
|
-
import { objectOmit } from '@vueuse/shared'
|
|
3
|
-
import { computed, defineComponent, Fragment, h, ref, type
|
|
2
|
+
import { objectOmit, toReactive } from '@vueuse/shared'
|
|
3
|
+
import { type Component, computed, defineComponent, Fragment, h, ref, type Ref, type VNode } from 'vue'
|
|
4
4
|
|
|
5
5
|
export function defineColumns<TSetupArgs extends any[], TColumns extends Columns>(
|
|
6
6
|
setup: (...args: TSetupArgs) => TColumns
|
|
@@ -85,7 +85,8 @@ export function defineColumns<TSetupArgs extends any[], TColumns extends Columns
|
|
|
85
85
|
},
|
|
86
86
|
},
|
|
87
87
|
setup(props) {
|
|
88
|
-
const bodyCellRenderers =
|
|
88
|
+
const bodyCellRenderers =
|
|
89
|
+
config.body(toReactive(computed(() => props.item)) as TBodyItem) ?? ({} as TBodyRenderers)
|
|
89
90
|
|
|
90
91
|
return () =>
|
|
91
92
|
visibleColumnIds.value.map(columnId => {
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ActionItem } from '@core/components/menu/VtsActionsMenu.vue'
|
|
2
|
+
import VtsActionCell from '@core/components/table/cells/VtsActionCell.vue'
|
|
3
|
+
import { defineColumn } from '@core/packages/table/define-column'
|
|
4
|
+
import type { ButtonIconConfig } from '@core/tables/column-definitions/button-icon-column.ts'
|
|
5
|
+
import { renderHeadCell } from '@core/tables/helpers/render-head-cell'
|
|
6
|
+
import type { HeaderConfig } from '@core/tables/types.ts'
|
|
7
|
+
import { h, toValue } from 'vue'
|
|
8
|
+
|
|
9
|
+
export type { ActionItem }
|
|
10
|
+
|
|
11
|
+
export const useActionColumn = defineColumn((config: HeaderConfig & Partial<ButtonIconConfig>) => ({
|
|
12
|
+
renderHead: () => renderHeadCell(config.headerIcon, config.headerLabel),
|
|
13
|
+
renderBody: (params: { onClick: () => void; actions?: ActionItem[] }) =>
|
|
14
|
+
h(VtsActionCell, {
|
|
15
|
+
buttonIcon: toValue(config.buttonIcon ?? 'fa:eye'),
|
|
16
|
+
buttonAccent: toValue(config.buttonAccent),
|
|
17
|
+
buttonSize: toValue(config.buttonSize),
|
|
18
|
+
actions: params.actions,
|
|
19
|
+
onClick: params.onClick,
|
|
20
|
+
}),
|
|
21
|
+
}))
|
|
@@ -7,9 +7,9 @@ import type { IconName } from '@core/icons'
|
|
|
7
7
|
import { defineColumn } from '@core/packages/table/define-column'
|
|
8
8
|
import { renderHeadCell } from '@core/tables/helpers/render-head-cell'
|
|
9
9
|
import type { HeaderConfig } from '@core/tables/types.ts'
|
|
10
|
-
import { h,
|
|
10
|
+
import { h, type MaybeRefOrGetter, toValue } from 'vue'
|
|
11
11
|
|
|
12
|
-
type ButtonIconConfig = {
|
|
12
|
+
export type ButtonIconConfig = {
|
|
13
13
|
buttonIcon: MaybeRefOrGetter<IconName>
|
|
14
14
|
buttonSize?: MaybeRefOrGetter<ButtonIconSize>
|
|
15
15
|
buttonAccent?: MaybeRefOrGetter<ButtonIconAccent>
|
|
@@ -6,6 +6,6 @@ import type { HeaderConfig } from '@core/tables/types.ts'
|
|
|
6
6
|
import { h } from 'vue'
|
|
7
7
|
|
|
8
8
|
export const useTextColumn = defineColumn((config?: HeaderConfig) => ({
|
|
9
|
-
renderHead: () => renderHeadCell(config?.headerIcon, config?.headerLabel),
|
|
9
|
+
renderHead: () => renderHeadCell(config?.headerIcon ?? 'fa:align-left', config?.headerLabel),
|
|
10
10
|
renderBody: (content: string, props?: TextCellProps) => h(VtsTextCell, props, () => content),
|
|
11
11
|
}))
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { defineColumns } from '@core/packages/table/define-columns.ts'
|
|
2
|
+
import { useActionColumn } from '@core/tables/column-definitions/action-column.ts'
|
|
2
3
|
import { useLinkColumn } from '@core/tables/column-definitions/link-column.ts'
|
|
3
4
|
import { useLiteralColumn } from '@core/tables/column-definitions/literal-column.ts'
|
|
4
5
|
import { useNumberColumn } from '@core/tables/column-definitions/number-column.ts'
|
|
5
6
|
import { useProgressBarColumn } from '@core/tables/column-definitions/progress-bar-column.ts'
|
|
6
|
-
import { useSelectItemColumn } from '@core/tables/column-definitions/select-item-column.ts'
|
|
7
7
|
import { useTruncatedTextColumn } from '@core/tables/column-definitions/truncated-text-column.ts'
|
|
8
8
|
import { useI18n } from 'vue-i18n'
|
|
9
9
|
|
|
@@ -16,6 +16,6 @@ export const useVdiColumns = defineColumns(() => {
|
|
|
16
16
|
usedSpace: useProgressBarColumn({ headerLabel: () => t('used-space') }),
|
|
17
17
|
size: useNumberColumn({ headerLabel: () => t('size') }),
|
|
18
18
|
format: useLiteralColumn({ headerLabel: () => t('format') }),
|
|
19
|
-
|
|
19
|
+
actions: useActionColumn({}),
|
|
20
20
|
}
|
|
21
21
|
})
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { defineColumns } from '@core/packages/table/define-columns.ts'
|
|
2
|
+
import { useActionColumn } from '@core/tables/column-definitions/action-column.ts'
|
|
2
3
|
import { useAddressColumn } from '@core/tables/column-definitions/address-column.ts'
|
|
3
4
|
import { useLinkColumn } from '@core/tables/column-definitions/link-column'
|
|
4
5
|
import { useNumberColumn } from '@core/tables/column-definitions/number-column.ts'
|
|
5
|
-
import { useSelectItemColumn } from '@core/tables/column-definitions/select-item-column'
|
|
6
6
|
import { useStatusColumn } from '@core/tables/column-definitions/status-column.ts'
|
|
7
7
|
import { useTextColumn } from '@core/tables/column-definitions/text-column.ts'
|
|
8
8
|
import { useI18n } from 'vue-i18n'
|
|
@@ -18,6 +18,6 @@ export const useVifColumns = defineColumns(() => {
|
|
|
18
18
|
macAddresses: useAddressColumn({ headerLabel: () => t('mac-addresses') }),
|
|
19
19
|
mtu: useNumberColumn({ headerLabel: () => t('mtu') }),
|
|
20
20
|
lockingMode: useTextColumn({ headerLabel: () => t('locking-mode') }),
|
|
21
|
-
|
|
21
|
+
actions: useActionColumn({}),
|
|
22
22
|
}
|
|
23
23
|
})
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xen-orchestra/web-core",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.50.0",
|
|
5
5
|
"private": false,
|
|
6
6
|
"exports": {
|
|
7
7
|
"./*": {
|
|
@@ -22,12 +22,12 @@
|
|
|
22
22
|
"@vueuse/math": "^13.0.0",
|
|
23
23
|
"@vueuse/router": "^13.0.0",
|
|
24
24
|
"@vueuse/shared": "^13.0.0",
|
|
25
|
-
"complex-matcher": "^1.1.
|
|
25
|
+
"complex-matcher": "^1.1.1",
|
|
26
26
|
"d3-time-format": "^4.1.0",
|
|
27
27
|
"echarts": "^5.6.0",
|
|
28
28
|
"human-format": "^1.2.1",
|
|
29
29
|
"iterable-backoff": "^0.1.0",
|
|
30
|
-
"lodash-es": "^4.
|
|
30
|
+
"lodash-es": "^4.18.0",
|
|
31
31
|
"ndjson-readablestream": "^1.3.0",
|
|
32
32
|
"placement.js": "^1.0.0-beta.5",
|
|
33
33
|
"simple-icons": "^14.14.0",
|