@xen-orchestra/web-core 0.10.0 → 0.12.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 +5 -1
  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/input/UiInput.vue +2 -0
  17. package/lib/components/ui/radio-button/UiRadioButton.vue +12 -15
  18. package/lib/components/ui/toggle/UiToggle.vue +6 -10
  19. package/lib/composables/chart-theme.composable.ts +382 -0
  20. package/lib/composables/disabled.composable.ts +15 -0
  21. package/lib/composables/route-query/types.ts +3 -2
  22. package/lib/composables/table/multi-select.composable.ts +32 -0
  23. package/lib/i18n.ts +53 -0
  24. package/lib/layouts/CoreLayout.vue +20 -13
  25. package/lib/locales/cs.json +9 -9
  26. package/lib/locales/de.json +41 -46
  27. package/lib/locales/en.json +52 -14
  28. package/lib/locales/es.json +97 -0
  29. package/lib/locales/fa.json +5 -4
  30. package/lib/locales/fr.json +54 -16
  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
@@ -1,16 +1,16 @@
1
1
  <!-- v3 -->
2
2
  <template>
3
- <label class="ui-checkbox" :class="classNames" v-bind="wrapperAttrs">
3
+ <label :class="classNames" class="ui-checkbox" v-bind="wrapperAttrs">
4
4
  <input
5
5
  v-model="checkboxModel"
6
6
  :class="{ indeterminate: isIndeterminate }"
7
7
  :disabled="isDisabled"
8
- type="checkbox"
9
8
  class="input"
9
+ type="checkbox"
10
10
  v-bind="attrs"
11
11
  />
12
12
  <span class="fake-checkbox">
13
- <VtsIcon :icon class="icon" accent="info" />
13
+ <VtsIcon :icon accent="info" class="icon" />
14
14
  </span>
15
15
  <span v-if="slots.default" class="typo p1-regular">
16
16
  <slot />
@@ -24,8 +24,7 @@
24
24
  <script lang="ts" setup>
25
25
  import VtsIcon from '@core/components/icon/VtsIcon.vue'
26
26
  import UiInfo from '@core/components/ui/info/UiInfo.vue'
27
- import { useContext } from '@core/composables/context.composable'
28
- import { DisabledContext } from '@core/context'
27
+ import { useDisabled } from '@core/composables/disabled.composable'
29
28
  import { toVariants } from '@core/utils/to-variants.util'
30
29
  import { faCheck, faMinus } from '@fortawesome/free-solid-svg-icons'
31
30
  import { computed, type LabelHTMLAttributes, useAttrs } from 'vue'
@@ -34,23 +33,20 @@ type CheckboxAccent = 'info' | 'success' | 'warning' | 'danger'
34
33
 
35
34
  defineOptions({ inheritAttrs: false })
36
35
 
37
- const props = withDefaults(
38
- defineProps<{
39
- accent: CheckboxAccent
40
- disabled?: boolean
41
- wrapperAttrs?: LabelHTMLAttributes
42
- }>(),
43
- { disabled: undefined }
44
- )
36
+ const props = defineProps<{
37
+ accent: CheckboxAccent
38
+ disabled?: boolean
39
+ wrapperAttrs?: LabelHTMLAttributes
40
+ }>()
45
41
 
46
- const checkboxModel = defineModel<boolean | undefined>({ default: undefined })
42
+ const checkboxModel = defineModel<boolean | undefined | string[]>({ default: undefined })
47
43
 
48
44
  const slots = defineSlots<{
49
45
  default?(): any
50
46
  info?(): any
51
47
  }>()
52
48
 
53
- const isDisabled = useContext(DisabledContext, () => props.disabled)
49
+ const isDisabled = useDisabled(() => props.disabled)
54
50
 
55
51
  const classNames = computed(() => [
56
52
  toVariants({
@@ -1,6 +1,6 @@
1
1
  <!-- v3 -->
2
2
  <template>
3
- <button type="button" class="ui-dropdown-item" :class="{ selected }" :disabled="isDisabled">
3
+ <button :class="{ selected }" :disabled="isDisabled" class="ui-dropdown-item" type="button">
4
4
  <VtsIcon :icon accent="current" class="left-icon" fixed-width />
5
5
  <span class="typo p1-regular label">
6
6
  <slot />
@@ -11,24 +11,20 @@
11
11
 
12
12
  <script lang="ts" setup>
13
13
  import VtsIcon from '@core/components/icon/VtsIcon.vue'
14
- import { useContext } from '@core/composables/context.composable'
15
- import { DisabledContext } from '@core/context'
14
+ import { useDisabled } from '@core/composables/disabled.composable'
16
15
  import type { IconDefinition } from '@fortawesome/fontawesome-common-types'
17
16
  import { faAngleDown } from '@fortawesome/free-solid-svg-icons'
18
17
 
19
- const props = withDefaults(
20
- defineProps<{
21
- disabled?: boolean
22
- selected?: boolean
23
- icon?: IconDefinition
24
- }>(),
25
- { disabled: undefined }
26
- )
18
+ const { disabled, selected, icon } = defineProps<{
19
+ disabled?: boolean
20
+ selected?: boolean
21
+ icon?: IconDefinition
22
+ }>()
27
23
 
28
- const isDisabled = useContext(DisabledContext, () => props.disabled)
24
+ const isDisabled = useDisabled(() => disabled)
29
25
  </script>
30
26
 
31
- <style scoped lang="postcss">
27
+ <style lang="postcss" scoped>
32
28
  .ui-dropdown-item {
33
29
  display: inline-flex;
34
30
  align-items: center;
@@ -69,7 +69,9 @@ const labelAccent = computed(() => (accent === 'info' ? 'neutral' : accent))
69
69
  position: relative;
70
70
  display: flex;
71
71
  flex-direction: column;
72
+ flex: 1;
72
73
  gap: 0.4rem;
74
+ flex: 1;
73
75
 
74
76
  .input {
75
77
  border-radius: 0.4rem;
@@ -2,7 +2,7 @@
2
2
  <template>
3
3
  <label :class="variant" class="ui-radio-button typo p1-regular">
4
4
  <span class="radio-container">
5
- <input v-model="model" :value :disabled="isDisabled" class="input" type="radio" />
5
+ <input v-model="model" :disabled="isDisabled" :value class="input" type="radio" />
6
6
  <VtsIcon :icon="faCircle" accent="current" class="radio-icon" />
7
7
  </span>
8
8
  <slot />
@@ -11,31 +11,26 @@
11
11
 
12
12
  <script lang="ts" setup>
13
13
  import VtsIcon from '@core/components/icon/VtsIcon.vue'
14
- import { useContext } from '@core/composables/context.composable'
15
- import { DisabledContext } from '@core/context'
14
+ import { useDisabled } from '@core/composables/disabled.composable'
16
15
  import { toVariants } from '@core/utils/to-variants.util'
17
16
  import { faCircle } from '@fortawesome/free-solid-svg-icons'
18
17
  import { computed } from 'vue'
19
18
 
20
- const props = withDefaults(
21
- defineProps<{
22
- accent: 'info' | 'success' | 'warning' | 'danger'
23
- value: any
24
- disabled?: boolean
25
- }>(),
26
- {
27
- disabled: undefined,
28
- }
29
- )
19
+ const { accent, value, disabled } = defineProps<{
20
+ accent: 'info' | 'success' | 'warning' | 'danger'
21
+ value: any
22
+ disabled?: boolean
23
+ }>()
24
+
30
25
  const model = defineModel<boolean>()
31
26
 
32
27
  defineSlots<{
33
28
  default(): any
34
29
  }>()
35
30
 
36
- const variant = computed(() => toVariants({ accent: props.accent }))
31
+ const variant = computed(() => toVariants({ accent }))
37
32
 
38
- const isDisabled = useContext(DisabledContext, () => props.disabled)
33
+ const isDisabled = useDisabled(() => disabled)
39
34
  </script>
40
35
 
41
36
  <style lang="postcss" scoped>
@@ -60,6 +55,7 @@ const isDisabled = useContext(DisabledContext, () => props.disabled)
60
55
 
61
56
  &:has(input:focus-visible) {
62
57
  outline: none;
58
+
63
59
  &::after {
64
60
  position: absolute;
65
61
  content: '';
@@ -68,6 +64,7 @@ const isDisabled = useContext(DisabledContext, () => props.disabled)
68
64
  border-radius: 0.4rem;
69
65
  }
70
66
  }
67
+
71
68
  &:has(.input:disabled) {
72
69
  cursor: not-allowed;
73
70
 
@@ -13,16 +13,12 @@
13
13
 
14
14
  <script lang="ts" setup>
15
15
  import UiLoader from '@core/components/ui/loader/UiLoader.vue'
16
- import { useContext } from '@core/composables/context.composable'
17
- import { DisabledContext } from '@core/context'
16
+ import { useDisabled } from '@core/composables/disabled.composable'
18
17
 
19
- const props = withDefaults(
20
- defineProps<{
21
- disabled?: boolean
22
- busy?: boolean
23
- }>(),
24
- { disabled: undefined }
25
- )
18
+ const { busy, disabled } = defineProps<{
19
+ disabled?: boolean
20
+ busy?: boolean
21
+ }>()
26
22
 
27
23
  const checked = defineModel<boolean>()
28
24
 
@@ -30,7 +26,7 @@ defineSlots<{
30
26
  default(): any
31
27
  }>()
32
28
 
33
- const isDisabled = useContext(DisabledContext, () => props.disabled)
29
+ const isDisabled = useDisabled(() => disabled)
34
30
  </script>
35
31
 
36
32
  <style lang="postcss" scoped>
@@ -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>
@@ -0,0 +1,32 @@
1
+ import { computed, ref, unref, type MaybeRef, type Ref } from 'vue'
2
+
3
+ export default function useMultiSelect<T>(usableIds: MaybeRef<T[]>, selectableIds?: MaybeRef<T[]>) {
4
+ const $selected = ref(new Set()) as Ref<Set<T>>
5
+
6
+ const selected = computed({
7
+ get() {
8
+ return unref(usableIds).filter(usableId => $selected.value.has(usableId))
9
+ },
10
+ set(ids: T[]) {
11
+ $selected.value = new Set(ids)
12
+ },
13
+ })
14
+
15
+ const areAllSelected = computed({
16
+ get() {
17
+ return (unref(selectableIds) ?? unref(usableIds)).every(id => $selected.value.has(id))
18
+ },
19
+ set(value: boolean) {
20
+ if (value) {
21
+ $selected.value = new Set(unref(selectableIds) ?? unref(usableIds))
22
+ } else {
23
+ $selected.value = new Set()
24
+ }
25
+ },
26
+ })
27
+
28
+ return {
29
+ selected,
30
+ areAllSelected,
31
+ }
32
+ }