@xen-orchestra/web-core 0.29.0 → 0.31.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/css/typography/_utils.pcss +11 -0
- package/lib/assets/no-result.svg +276 -80
- package/lib/components/backup-state/VtsBackupState.vue +2 -1
- package/lib/components/console/VtsRemoteConsole.vue +6 -2
- package/lib/components/data-table/VtsDataTable.vue +11 -6
- package/lib/components/quick-info-card/VtsQuickInfoCard.vue +2 -2
- package/lib/components/quick-info-row/VtsQuickInfoRow.vue +1 -1
- package/lib/components/select/VtsSelect.vue +1 -1
- package/lib/components/state-hero/VtsStateHero.vue +107 -47
- package/lib/components/task/VtsQuickTaskList.vue +1 -1
- package/lib/components/ui/card/UiCard.vue +6 -1
- package/lib/components/ui/collapsible-list/UiCollapsibleList.vue +5 -2
- package/lib/components/ui/panel/UiPanel.vue +1 -1
- package/lib/components/ui/table-pagination/UiTablePagination.vue +2 -2
- package/lib/composables/tree-filter.composable.ts +4 -2
- package/lib/icons/index.ts +1 -1
- package/lib/icons/object-icons.ts +33 -2
- package/lib/locales/cs.json +64 -18
- package/lib/locales/de.json +1 -1
- package/lib/locales/en.json +57 -3
- package/lib/locales/es.json +73 -9
- package/lib/locales/fa.json +1 -1
- package/lib/locales/fr.json +59 -5
- package/lib/locales/it.json +9 -4
- package/lib/locales/nl.json +47 -1
- package/lib/locales/pt_BR.json +32 -2
- package/lib/locales/ru.json +83 -1
- package/lib/locales/sv.json +1 -1
- package/lib/locales/uk.json +339 -1
- package/lib/types/value-matcher.d.ts +3 -0
- package/lib/utils/speed.util.ts +12 -0
- package/lib/utils/time.util.ts +57 -0
- package/package.json +1 -1
- package/lib/components/state-hero/VtsAllDoneHero.vue +0 -16
- package/lib/components/state-hero/VtsAllGoodHero.vue +0 -16
- package/lib/components/state-hero/VtsComingSoonHero.vue +0 -16
- package/lib/components/state-hero/VtsErrorNoDataHero.vue +0 -14
- package/lib/components/state-hero/VtsLoadingHero.vue +0 -57
- package/lib/components/state-hero/VtsNoDataHero.vue +0 -14
- package/lib/components/state-hero/VtsNoSelectionHero.vue +0 -16
- package/lib/components/state-hero/VtsObjectNotFoundHero.vue +0 -17
- package/lib/components/state-hero/VtsOfflineHero.vue +0 -16
- package/lib/components/state-hero/VtsPageNotFoundHero.vue +0 -33
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div :class="[
|
|
2
|
+
<div :class="[className, { horizontal, error, success, 'no-background': noBackground }]" class="vts-state-hero">
|
|
3
3
|
<UiLoader v-if="busy" class="loader" />
|
|
4
|
-
<img v-else-if="imageSrc" :src="imageSrc" alt="" class="image" />
|
|
4
|
+
<img v-else-if="imageSrc" :src="imageSrc" :alt="type" class="image" />
|
|
5
5
|
<div v-if="slots.default" :class="typoClass" class="content">
|
|
6
6
|
<slot />
|
|
7
7
|
</div>
|
|
@@ -10,23 +10,28 @@
|
|
|
10
10
|
|
|
11
11
|
<script lang="ts" setup>
|
|
12
12
|
import UiLoader from '@core/components/ui/loader/UiLoader.vue'
|
|
13
|
+
import { toVariants } from '@core/utils/to-variants.util.ts'
|
|
13
14
|
import { computed } from 'vue'
|
|
14
15
|
|
|
15
|
-
export type
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
export type StateHeroFormat = 'page' | 'card' | 'panel' | 'table'
|
|
17
|
+
|
|
18
|
+
type StateHeroType =
|
|
19
|
+
| 'no-result'
|
|
20
|
+
| 'under-construction'
|
|
21
|
+
| 'no-data'
|
|
22
|
+
| 'no-selection'
|
|
23
|
+
| 'error'
|
|
24
|
+
| 'not-found'
|
|
25
|
+
| 'offline'
|
|
26
|
+
| 'all-good'
|
|
27
|
+
| 'all-done'
|
|
28
|
+
|
|
29
|
+
const { format, type, size, busy } = defineProps<{
|
|
30
|
+
format: StateHeroFormat
|
|
31
|
+
type?: StateHeroType
|
|
32
|
+
size: 'extra-small' | 'small' | 'medium' | 'large'
|
|
33
|
+
horizontal?: boolean
|
|
19
34
|
busy?: boolean
|
|
20
|
-
image?:
|
|
21
|
-
| 'no-result'
|
|
22
|
-
| 'under-construction'
|
|
23
|
-
| 'no-data'
|
|
24
|
-
| 'no-selection'
|
|
25
|
-
| 'error'
|
|
26
|
-
| 'not-found'
|
|
27
|
-
| 'offline'
|
|
28
|
-
| 'all-good'
|
|
29
|
-
| 'all-done'
|
|
30
35
|
noBackground?: boolean
|
|
31
36
|
}>()
|
|
32
37
|
|
|
@@ -34,15 +39,20 @@ const slots = defineSlots<{
|
|
|
34
39
|
default?(): any
|
|
35
40
|
}>()
|
|
36
41
|
|
|
37
|
-
const typoClass = computed(() => (
|
|
38
|
-
|
|
42
|
+
const typoClass = computed(() => (format === 'page' ? 'typo-h2' : 'typo-h4'))
|
|
43
|
+
|
|
44
|
+
const className = computed(() => toVariants({ size, format }))
|
|
45
|
+
|
|
46
|
+
const error = computed(() => !busy && type === 'error')
|
|
47
|
+
|
|
48
|
+
const success = computed(() => !busy && (type === 'all-good' || type === 'all-done'))
|
|
39
49
|
|
|
40
50
|
const imageSrc = computed(() => {
|
|
41
|
-
if (!
|
|
51
|
+
if (!type) {
|
|
42
52
|
return undefined
|
|
43
53
|
}
|
|
44
54
|
|
|
45
|
-
return new URL(`../../assets/${
|
|
55
|
+
return new URL(`../../assets/${type}.svg`, import.meta.url).href
|
|
46
56
|
})
|
|
47
57
|
</script>
|
|
48
58
|
|
|
@@ -50,33 +60,54 @@ const imageSrc = computed(() => {
|
|
|
50
60
|
.vts-state-hero {
|
|
51
61
|
flex: 1;
|
|
52
62
|
display: flex;
|
|
53
|
-
flex-direction: column;
|
|
54
63
|
align-items: center;
|
|
55
64
|
justify-content: center;
|
|
65
|
+
gap: 2.4rem;
|
|
56
66
|
|
|
57
|
-
|
|
58
|
-
|
|
67
|
+
&:not(.horizontal) {
|
|
68
|
+
flex-direction: column;
|
|
59
69
|
|
|
60
70
|
.content {
|
|
61
|
-
|
|
71
|
+
align-items: center;
|
|
62
72
|
}
|
|
63
73
|
}
|
|
64
74
|
|
|
75
|
+
.image {
|
|
76
|
+
order: 2;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.content {
|
|
80
|
+
display: flex;
|
|
81
|
+
flex-direction: column;
|
|
82
|
+
gap: 1.6rem;
|
|
83
|
+
}
|
|
84
|
+
|
|
65
85
|
.loader,
|
|
66
86
|
.content {
|
|
87
|
+
order: 3;
|
|
67
88
|
color: var(--color-brand-txt-base);
|
|
68
89
|
}
|
|
69
90
|
|
|
70
|
-
|
|
71
|
-
|
|
91
|
+
&.success {
|
|
92
|
+
.content {
|
|
93
|
+
color: var(--color-success-txt-base);
|
|
94
|
+
}
|
|
72
95
|
}
|
|
73
96
|
|
|
74
|
-
|
|
75
|
-
|
|
97
|
+
&.error {
|
|
98
|
+
background-color: var(--color-danger-background-selected);
|
|
99
|
+
|
|
100
|
+
&.no-background {
|
|
101
|
+
background-color: transparent;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.content {
|
|
105
|
+
color: var(--color-danger-txt-base);
|
|
106
|
+
}
|
|
76
107
|
}
|
|
77
108
|
|
|
78
|
-
&.
|
|
79
|
-
gap:
|
|
109
|
+
&.format--card {
|
|
110
|
+
gap: 2rem;
|
|
80
111
|
|
|
81
112
|
.content {
|
|
82
113
|
order: 3;
|
|
@@ -84,36 +115,31 @@ const imageSrc = computed(() => {
|
|
|
84
115
|
|
|
85
116
|
.loader {
|
|
86
117
|
order: 1;
|
|
87
|
-
font-size: 10rem;
|
|
88
118
|
}
|
|
89
119
|
|
|
90
120
|
.image {
|
|
91
121
|
order: 2;
|
|
92
|
-
width: 90%;
|
|
93
|
-
max-height: none;
|
|
94
122
|
}
|
|
95
123
|
}
|
|
96
124
|
|
|
97
|
-
&.
|
|
98
|
-
|
|
125
|
+
&.format--table {
|
|
126
|
+
padding: 4rem;
|
|
127
|
+
gap: 2.4rem;
|
|
99
128
|
|
|
100
129
|
.content {
|
|
101
130
|
order: 3;
|
|
102
131
|
}
|
|
103
132
|
|
|
104
133
|
.loader {
|
|
105
|
-
font-size: 6rem;
|
|
106
134
|
order: 1;
|
|
107
135
|
}
|
|
108
136
|
|
|
109
137
|
.image {
|
|
110
138
|
order: 2;
|
|
111
|
-
width: 70%;
|
|
112
|
-
max-height: 20rem;
|
|
113
139
|
}
|
|
114
140
|
}
|
|
115
141
|
|
|
116
|
-
&.panel {
|
|
142
|
+
&.format--panel {
|
|
117
143
|
gap: 4rem;
|
|
118
144
|
justify-content: unset;
|
|
119
145
|
padding-top: 8rem;
|
|
@@ -124,31 +150,65 @@ const imageSrc = computed(() => {
|
|
|
124
150
|
|
|
125
151
|
.loader {
|
|
126
152
|
order: 3;
|
|
127
|
-
font-size: 6.4rem;
|
|
128
153
|
}
|
|
129
154
|
|
|
130
155
|
.image {
|
|
131
156
|
order: 2;
|
|
132
|
-
width: 80%;
|
|
133
157
|
}
|
|
134
158
|
}
|
|
135
159
|
|
|
136
|
-
&.
|
|
137
|
-
|
|
138
|
-
gap: 2.4rem;
|
|
160
|
+
&.format--page {
|
|
161
|
+
gap: 10rem;
|
|
139
162
|
|
|
140
163
|
.content {
|
|
141
164
|
order: 3;
|
|
142
165
|
}
|
|
143
166
|
|
|
167
|
+
.loader {
|
|
168
|
+
order: 1;
|
|
169
|
+
}
|
|
170
|
+
|
|
144
171
|
.image {
|
|
145
172
|
order: 2;
|
|
146
|
-
max-height: 20rem;
|
|
147
173
|
}
|
|
174
|
+
}
|
|
148
175
|
|
|
176
|
+
&.size--extra-small {
|
|
149
177
|
.loader {
|
|
150
|
-
|
|
151
|
-
|
|
178
|
+
font-size: 1.6rem;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.image {
|
|
182
|
+
max-height: 14rem;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
&.size--small {
|
|
187
|
+
.loader {
|
|
188
|
+
font-size: 2.4rem;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.image {
|
|
192
|
+
max-height: 18rem;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
&.size--medium {
|
|
197
|
+
.loader {
|
|
198
|
+
font-size: 6.4rem;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
.image {
|
|
202
|
+
max-height: 30rem;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
&.size--large {
|
|
207
|
+
.loader {
|
|
208
|
+
font-size: 9.6rem;
|
|
209
|
+
}
|
|
210
|
+
.image {
|
|
211
|
+
max-height: 50rem;
|
|
152
212
|
}
|
|
153
213
|
}
|
|
154
214
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="ui-card" :class="{ horizontal }">
|
|
2
|
+
<div class="ui-card" :class="{ horizontal, 'has-error': hasError }">
|
|
3
3
|
<slot />
|
|
4
4
|
</div>
|
|
5
5
|
</template>
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
<script lang="ts" setup>
|
|
8
8
|
defineProps<{
|
|
9
9
|
horizontal?: boolean
|
|
10
|
+
hasError?: boolean
|
|
10
11
|
}>()
|
|
11
12
|
|
|
12
13
|
defineSlots<{
|
|
@@ -39,5 +40,9 @@ defineSlots<{
|
|
|
39
40
|
&.horizontal {
|
|
40
41
|
flex-direction: row;
|
|
41
42
|
}
|
|
43
|
+
|
|
44
|
+
&.has-error {
|
|
45
|
+
background-color: var(--color-danger-background-selected);
|
|
46
|
+
}
|
|
42
47
|
}
|
|
43
48
|
</style>
|
|
@@ -5,9 +5,8 @@
|
|
|
5
5
|
<slot />
|
|
6
6
|
</component>
|
|
7
7
|
<div v-if="hasMoreItems" class="footer">
|
|
8
|
-
<span v-if="!isExpanded" class="typo-body-regular-small">{{ t('n-more', { n: remainingItems }) }}</span>
|
|
9
8
|
<UiButton size="small" accent="brand" variant="tertiary" @click="isExpanded = !isExpanded">
|
|
10
|
-
{{ isExpanded ? t('see-less') : t('see-
|
|
9
|
+
{{ isExpanded ? t('see-less') : t('see-n-more', { n: remainingItems }) }}
|
|
11
10
|
</UiButton>
|
|
12
11
|
</div>
|
|
13
12
|
</div>
|
|
@@ -61,6 +60,10 @@ useStyleTag(style)
|
|
|
61
60
|
flex-direction: column;
|
|
62
61
|
gap: 0.8rem;
|
|
63
62
|
width: 100%;
|
|
63
|
+
|
|
64
|
+
:deep(li) {
|
|
65
|
+
line-height: 1;
|
|
66
|
+
}
|
|
64
67
|
}
|
|
65
68
|
|
|
66
69
|
.footer {
|
|
@@ -91,13 +91,13 @@ const { id: showBySelectId } = useFormSelect([12, 24, 48, -1], {
|
|
|
91
91
|
|
|
92
92
|
/* Workaround: we don't have "small" select yet */
|
|
93
93
|
.show-by-select {
|
|
94
|
-
width:
|
|
94
|
+
width: 7rem;
|
|
95
95
|
|
|
96
96
|
&:deep(.ui-input) {
|
|
97
97
|
height: 3rem;
|
|
98
98
|
padding-inline: 0.8rem;
|
|
99
99
|
gap: 0.8rem;
|
|
100
|
-
min-width:
|
|
100
|
+
min-width: 7rem;
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
&:deep(.input) {
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import type { TreeNodeBase } from '@core/composables/tree/tree-node-base'
|
|
2
|
+
import { refDebounced } from '@vueuse/shared'
|
|
2
3
|
import { computed, ref } from 'vue'
|
|
3
4
|
|
|
4
5
|
export function useTreeFilter() {
|
|
5
6
|
const filter = ref('')
|
|
6
|
-
const
|
|
7
|
+
const debouncedFilter = refDebounced(filter, 500)
|
|
8
|
+
const hasFilter = computed(() => debouncedFilter.value.trim().length > 0)
|
|
7
9
|
|
|
8
10
|
const predicate = (node: TreeNodeBase) =>
|
|
9
|
-
hasFilter.value ? node.label.toLocaleLowerCase().includes(
|
|
11
|
+
hasFilter.value ? node.label.toLocaleLowerCase().includes(debouncedFilter.value.toLocaleLowerCase()) : undefined
|
|
10
12
|
|
|
11
13
|
return { filter, predicate }
|
|
12
14
|
}
|
package/lib/icons/index.ts
CHANGED
|
@@ -12,7 +12,7 @@ export const icons = defineIconPack({
|
|
|
12
12
|
|
|
13
13
|
export type IconName = Exclude<keyof typeof icons, typeof ICON_SYMBOL>
|
|
14
14
|
|
|
15
|
-
export type ObjectIconName = Extract<IconName, `object:${string}`>
|
|
15
|
+
export type ObjectIconName = Extract<IconName, `object:${string}:${string}`>
|
|
16
16
|
|
|
17
17
|
export function icon<TName extends IconName>(name: TName): TName {
|
|
18
18
|
return name
|
|
@@ -3,9 +3,12 @@ import { defineIcon } from '@core/packages/icon/define-icon.ts'
|
|
|
3
3
|
import type { IconTransforms } from '@core/packages/icon/types.ts'
|
|
4
4
|
import { createMapper } from '@core/packages/mapper/create-mapper.ts'
|
|
5
5
|
import {
|
|
6
|
+
faArrowLeft,
|
|
6
7
|
faBan,
|
|
8
|
+
faBoxArchive,
|
|
7
9
|
faCheck,
|
|
8
10
|
faCircle,
|
|
11
|
+
faClock,
|
|
9
12
|
faDatabase,
|
|
10
13
|
faDesktop,
|
|
11
14
|
faMinus,
|
|
@@ -17,7 +20,6 @@ import {
|
|
|
17
20
|
faServer,
|
|
18
21
|
faStop,
|
|
19
22
|
faTriangleExclamation,
|
|
20
|
-
faWarehouse,
|
|
21
23
|
faXmark,
|
|
22
24
|
} from '@fortawesome/free-solid-svg-icons'
|
|
23
25
|
|
|
@@ -148,6 +150,32 @@ function getMainColor(state: string) {
|
|
|
148
150
|
: 'var(--color-neutral-txt-primary)'
|
|
149
151
|
}
|
|
150
152
|
|
|
153
|
+
const backupIcon = defineIcon({ icon: faBoxArchive })
|
|
154
|
+
|
|
155
|
+
const backupRepository = defineIcon([
|
|
156
|
+
{ icon: backupIcon, translate: [0, -4], borderColor: defaultTransforms.borderColor, size: 10 },
|
|
157
|
+
{ icon: backupIcon, translate: [-4, 4], borderColor: defaultTransforms.borderColor, size: 10 },
|
|
158
|
+
{ icon: backupIcon, translate: [4, 4], borderColor: defaultTransforms.borderColor, size: 10 },
|
|
159
|
+
])
|
|
160
|
+
|
|
161
|
+
const backupJob = defineIcon([
|
|
162
|
+
{ icon: backupIcon, borderColor: defaultTransforms.borderColor },
|
|
163
|
+
{ icon: faCircle, translate: [6, 6], borderColor: defaultTransforms.borderColor, size: 12 },
|
|
164
|
+
{ icon: faArrowLeft, translate: [6, 6], color: 'var(--color-neutral-background-primary)', size: 8 },
|
|
165
|
+
])
|
|
166
|
+
|
|
167
|
+
const backupSchedule = defineIcon([
|
|
168
|
+
{ icon: backupIcon, borderColor: defaultTransforms.borderColor },
|
|
169
|
+
{ icon: faCircle, translate: [6, 6], size: 12, color: 'var(--color-neutral-background-primary)' },
|
|
170
|
+
{ icon: faClock, translate: [6, 6], size: 11 },
|
|
171
|
+
])
|
|
172
|
+
|
|
173
|
+
const backupLog = defineIcon([
|
|
174
|
+
{ icon: backupIcon, borderColor: defaultTransforms.borderColor },
|
|
175
|
+
{ icon: faCircle, translate: [6, 6], borderColor: defaultTransforms.borderColor, size: 12 },
|
|
176
|
+
{ icon: faPlay, translate: [6.5, 6], color: 'var(--color-neutral-background-primary)', size: 6 },
|
|
177
|
+
])
|
|
178
|
+
|
|
151
179
|
export const objectIcons = defineIconPack({
|
|
152
180
|
vm: defineIcon([['running', 'halted', 'suspended', 'paused', 'muted']], state => [
|
|
153
181
|
{
|
|
@@ -179,9 +207,12 @@ export const objectIcons = defineIconPack({
|
|
|
179
207
|
]),
|
|
180
208
|
'backup-repository': defineIcon([['connected', 'disconnected']], state => [
|
|
181
209
|
{
|
|
182
|
-
icon:
|
|
210
|
+
icon: backupRepository,
|
|
183
211
|
color: getMainColor(state),
|
|
184
212
|
},
|
|
185
213
|
{ icon: getStatusIcon(state) },
|
|
186
214
|
]),
|
|
215
|
+
'backup-job': backupJob,
|
|
216
|
+
'backup-schedule': backupSchedule,
|
|
217
|
+
'backup-log': backupLog,
|
|
187
218
|
})
|