@xen-orchestra/web-core 0.28.0 → 0.30.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/console/VtsRemoteConsole.vue +6 -2
- package/lib/components/data-table/VtsDataTable.vue +11 -6
- package/lib/components/progress-bar/VtsProgressBar.vue +54 -0
- package/lib/components/progress-bar-group/VtsProgressBarGroup.vue +76 -0
- 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 +1 -2
- package/lib/components/ui/data-ruler/UiDataRuler.vue +54 -6
- package/lib/components/ui/progress-bar/UiProgressBar.vue +14 -70
- 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 +1 -1
- package/lib/locales/de.json +1 -1
- package/lib/locales/en.json +24 -2
- package/lib/locales/es.json +1 -1
- package/lib/locales/fa.json +1 -1
- package/lib/locales/fr.json +24 -2
- package/lib/locales/it.json +1 -1
- package/lib/locales/nl.json +1 -1
- package/lib/locales/sv.json +1 -1
- package/lib/packages/progress/use-progress-group.ts +1 -1
- package/lib/utils/progress.util.ts +72 -0
- package/lib/utils/size.util.ts +6 -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
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
</div>
|
|
29
29
|
</template>
|
|
30
30
|
<UiDropdown v-if="isLoading || options.length === 0" accent="normal" disabled>
|
|
31
|
-
{{ isLoading ? t('loading
|
|
31
|
+
{{ isLoading ? t('loading') : t('no-results') }}
|
|
32
32
|
</UiDropdown>
|
|
33
33
|
<template v-for="option of options" :key="option.id">
|
|
34
34
|
<slot :option="option as FormSelectIdToOption<TSelectId>">
|
|
@@ -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>
|
|
@@ -1,24 +1,72 @@
|
|
|
1
1
|
<!-- v1 -->
|
|
2
2
|
<template>
|
|
3
3
|
<div class="ui-data-ruler typo-body-regular-small">
|
|
4
|
-
<span>{{
|
|
5
|
-
<span>{{
|
|
6
|
-
<span
|
|
4
|
+
<span>{{ n(0, 'percent') }}</span>
|
|
5
|
+
<span>{{ n(max / 200, 'percent') }}</span>
|
|
6
|
+
<span class="max">
|
|
7
|
+
<VtsIcon
|
|
8
|
+
v-if="warning?.accent || warning?.tooltip"
|
|
9
|
+
v-tooltip="warning.tooltip ?? false"
|
|
10
|
+
:class="warning.accent ?? 'warning'"
|
|
11
|
+
class="icon"
|
|
12
|
+
name="fa:exclamation-circle"
|
|
13
|
+
size="small"
|
|
14
|
+
/>
|
|
15
|
+
{{ n(max / 100, 'percent') }}</span
|
|
16
|
+
>
|
|
7
17
|
</div>
|
|
8
18
|
</template>
|
|
9
19
|
|
|
10
20
|
<script lang="ts" setup>
|
|
21
|
+
import VtsIcon from '@core/components/icon/VtsIcon.vue'
|
|
22
|
+
import { vTooltip } from '@core/directives/tooltip.directive.ts'
|
|
11
23
|
import { useI18n } from 'vue-i18n'
|
|
12
24
|
|
|
13
|
-
const {
|
|
25
|
+
const { max = 100 } = defineProps<{
|
|
26
|
+
max?: number
|
|
27
|
+
warning?: {
|
|
28
|
+
accent?: 'info' | 'warning' | 'danger'
|
|
29
|
+
tooltip?: string
|
|
30
|
+
}
|
|
31
|
+
}>()
|
|
32
|
+
|
|
33
|
+
const { n } = useI18n()
|
|
14
34
|
</script>
|
|
15
35
|
|
|
16
36
|
<style lang="postcss" scoped>
|
|
17
37
|
.ui-data-ruler {
|
|
18
|
-
display:
|
|
38
|
+
display: grid;
|
|
39
|
+
grid-template-columns: 1fr auto 1fr;
|
|
19
40
|
align-items: center;
|
|
20
|
-
justify-content: space-between;
|
|
21
41
|
gap: 1rem;
|
|
22
42
|
color: var(--color-neutral-txt-secondary);
|
|
43
|
+
|
|
44
|
+
.icon {
|
|
45
|
+
&.warning {
|
|
46
|
+
color: var(--color-warning-item-base);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
&.danger {
|
|
50
|
+
color: var(--color-danger-item-base);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.max {
|
|
55
|
+
display: flex;
|
|
56
|
+
align-items: center;
|
|
57
|
+
gap: 0.8rem;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
& > span:first-child {
|
|
61
|
+
justify-self: start;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
& > span:nth-child(2) {
|
|
65
|
+
justify-self: center;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
& > span:last-child {
|
|
69
|
+
justify-self: end;
|
|
70
|
+
}
|
|
23
71
|
}
|
|
24
72
|
</style>
|
|
@@ -1,19 +1,12 @@
|
|
|
1
1
|
<!-- v2 -->
|
|
2
2
|
<template>
|
|
3
|
-
<div class="ui-progress-bar"
|
|
3
|
+
<div :class="className" class="ui-progress-bar">
|
|
4
4
|
<div class="progress-bar">
|
|
5
|
-
<div
|
|
5
|
+
<div :style="{ width: fillWidth }" class="fill" />
|
|
6
6
|
</div>
|
|
7
|
-
<
|
|
8
|
-
<
|
|
9
|
-
|
|
10
|
-
</div>
|
|
11
|
-
<VtsLegendList class="legend">
|
|
12
|
-
<UiLegend v-if="displayMode === 'percent'" :accent :value="Math.round(percentage)" unit="%">
|
|
13
|
-
{{ legend }}
|
|
14
|
-
</UiLegend>
|
|
15
|
-
<UiLegend v-else :accent :value="legendValue">
|
|
16
|
-
{{ legend }}
|
|
7
|
+
<VtsLegendList v-if="legend" class="legend">
|
|
8
|
+
<UiLegend :accent :value="legend.value">
|
|
9
|
+
{{ legend.label }}
|
|
17
10
|
</UiLegend>
|
|
18
11
|
</VtsLegendList>
|
|
19
12
|
</div>
|
|
@@ -22,61 +15,20 @@
|
|
|
22
15
|
<script lang="ts" setup>
|
|
23
16
|
import VtsLegendList from '@core/components/legend-list/VtsLegendList.vue'
|
|
24
17
|
import UiLegend from '@core/components/ui/legend/UiLegend.vue'
|
|
25
|
-
import { formatSizeRaw } from '@core/utils/size.util.ts'
|
|
26
18
|
import { toVariants } from '@core/utils/to-variants.util'
|
|
27
|
-
import { useClamp, useMax } from '@vueuse/math'
|
|
28
19
|
import { computed } from 'vue'
|
|
29
|
-
import { useI18n } from 'vue-i18n'
|
|
30
|
-
|
|
31
|
-
interface Props {
|
|
32
|
-
legend: string
|
|
33
|
-
value: number
|
|
34
|
-
showSteps?: boolean
|
|
35
|
-
}
|
|
36
|
-
interface PercentageProps {
|
|
37
|
-
max?: number
|
|
38
|
-
displayMode: 'percent'
|
|
39
|
-
}
|
|
40
|
-
interface ValueProps {
|
|
41
|
-
max: number
|
|
42
|
-
displayMode: 'value'
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const { value: _value, max: _max, showSteps, displayMode } = defineProps<Props & (PercentageProps | ValueProps)>()
|
|
46
|
-
|
|
47
|
-
const { n } = useI18n()
|
|
48
20
|
|
|
49
|
-
|
|
21
|
+
export type ProgressBarAccent = 'info' | 'warning' | 'danger'
|
|
50
22
|
|
|
51
|
-
|
|
23
|
+
export type ProgressBarLegend = { label: string; value?: string | number }
|
|
52
24
|
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
const accent = computed(() => {
|
|
60
|
-
if (percentage.value >= 90) {
|
|
61
|
-
return 'danger'
|
|
62
|
-
}
|
|
25
|
+
const { accent, legend } = defineProps<{
|
|
26
|
+
accent: ProgressBarAccent
|
|
27
|
+
fillWidth: string
|
|
28
|
+
legend?: ProgressBarLegend
|
|
29
|
+
}>()
|
|
63
30
|
|
|
64
|
-
|
|
65
|
-
return 'warning'
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
return 'info'
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
const className = computed(() => toVariants({ accent: accent.value }))
|
|
72
|
-
|
|
73
|
-
const formattedValue = computed(() => formatSizeRaw(value.value, 1))
|
|
74
|
-
|
|
75
|
-
const formattedMax = computed(() => formatSizeRaw(max.value, 0))
|
|
76
|
-
|
|
77
|
-
const legendValue = computed(() => {
|
|
78
|
-
return `${formattedValue.value.value} ${formattedValue.value.prefix} / ${formattedMax.value.value} ${formattedMax.value.prefix}`
|
|
79
|
-
})
|
|
31
|
+
const className = computed(() => toVariants({ accent }))
|
|
80
32
|
</script>
|
|
81
33
|
|
|
82
34
|
<style lang="postcss" scoped>
|
|
@@ -87,30 +39,22 @@ const legendValue = computed(() => {
|
|
|
87
39
|
|
|
88
40
|
.progress-bar {
|
|
89
41
|
width: 100%;
|
|
90
|
-
height: 1.2rem;
|
|
91
42
|
border-radius: 0.4rem;
|
|
92
43
|
overflow: hidden;
|
|
93
44
|
background-color: var(--color-neutral-background-disabled);
|
|
94
45
|
|
|
95
46
|
.fill {
|
|
96
47
|
width: 0;
|
|
97
|
-
height:
|
|
48
|
+
height: 1.2rem;
|
|
98
49
|
transition: width 0.25s ease-in-out;
|
|
99
50
|
}
|
|
100
51
|
}
|
|
101
52
|
|
|
102
|
-
.steps {
|
|
103
|
-
color: var(--color-neutral-txt-secondary);
|
|
104
|
-
display: flex;
|
|
105
|
-
justify-content: space-between;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
53
|
.legend {
|
|
109
54
|
margin-inline-start: auto;
|
|
110
55
|
}
|
|
111
56
|
|
|
112
57
|
/* ACCENT */
|
|
113
|
-
|
|
114
58
|
&.accent--info {
|
|
115
59
|
.fill {
|
|
116
60
|
background-color: var(--color-info-item-base);
|
|
@@ -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
|
})
|
package/lib/locales/cs.json
CHANGED
|
@@ -313,7 +313,7 @@
|
|
|
313
313
|
"load-average": "Průměrné vytížení",
|
|
314
314
|
"load-now": "Načíst nyní",
|
|
315
315
|
"loading-hosts": "Načítání hostitelů…",
|
|
316
|
-
"loading
|
|
316
|
+
"loading": "Probíhá načítání…",
|
|
317
317
|
"locking-mode": "Režim zamykání",
|
|
318
318
|
"locking-mode-default": "Výchozí režim zamykání",
|
|
319
319
|
"log-out": "Odhlásit",
|
package/lib/locales/de.json
CHANGED
|
@@ -310,7 +310,7 @@
|
|
|
310
310
|
"load-average": "Durchschnittsauslastung",
|
|
311
311
|
"load-now": "Jetzt laden",
|
|
312
312
|
"loading-hosts": "Lade Hosts…",
|
|
313
|
-
"loading
|
|
313
|
+
"loading": "Ladevorgang läuft…",
|
|
314
314
|
"locking-mode": "Sperrmodus",
|
|
315
315
|
"locking-mode-default": "Standard-Sperrmodus",
|
|
316
316
|
"log-out": "Abmelden",
|