@xen-orchestra/web-core 0.20.1 → 0.22.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 (116) hide show
  1. package/lib/assets/css/_typography.pcss +6 -0
  2. package/lib/assets/no-selection-old.svg +70 -0
  3. package/lib/assets/no-selection.svg +85 -70
  4. package/lib/components/backup-state/VtsBackupState.vue +20 -17
  5. package/lib/components/card/VtsCardRowKeyValue.vue +4 -0
  6. package/lib/components/cell-object/VtsCellObject.vue +4 -1
  7. package/lib/components/console/VtsActionsConsole.vue +7 -4
  8. package/lib/components/console/VtsClipboardConsole.vue +9 -6
  9. package/lib/components/copy-button/VtsCopyButton.vue +9 -15
  10. package/lib/components/dropdown/DropdownTitle.vue +5 -2
  11. package/lib/components/icon/NewVtsIcon.vue +49 -0
  12. package/lib/components/input-group/VtsInputGroup.vue +41 -0
  13. package/lib/components/input-wrapper/VtsInputWrapper.vue +2 -2
  14. package/lib/components/layout/VtsLayoutSidebar.vue +6 -3
  15. package/lib/components/linear-chart/VtsLinearChart.vue +4 -0
  16. package/lib/components/object-icon/VtsObjectIcon.vue +22 -0
  17. package/lib/components/quick-info-card/VtsQuickInfoCard.vue +4 -1
  18. package/lib/components/select/VtsOption.vue +10 -6
  19. package/lib/components/select/VtsSelect.vue +74 -50
  20. package/lib/components/state-hero/VtsAllDoneHero.vue +4 -1
  21. package/lib/components/state-hero/VtsAllGoodHero.vue +4 -1
  22. package/lib/components/state-hero/VtsComingSoonHero.vue +4 -1
  23. package/lib/components/state-hero/VtsErrorNoDataHero.vue +4 -1
  24. package/lib/components/state-hero/VtsLoadingHero.vue +4 -1
  25. package/lib/components/state-hero/VtsNoDataHero.vue +4 -1
  26. package/lib/components/state-hero/VtsNoSelectionHero.vue +4 -1
  27. package/lib/components/state-hero/VtsObjectNotFoundHero.vue +4 -1
  28. package/lib/components/state-hero/VtsOfflineHero.vue +4 -1
  29. package/lib/components/state-hero/VtsPageNotFoundHero.vue +4 -1
  30. package/lib/components/table/ColumnTitle.vue +2 -2
  31. package/lib/components/task/VtsQuickTaskButton.vue +4 -1
  32. package/lib/components/task/VtsQuickTaskList.vue +5 -2
  33. package/lib/components/task/VtsQuickTaskTabBar.vue +8 -5
  34. package/lib/components/ui/card-numbers/UiCardNumbers.vue +4 -1
  35. package/lib/components/ui/character-limit/UiCharacterLimit.vue +4 -1
  36. package/lib/components/ui/input/UiInput.vue +2 -2
  37. package/lib/components/ui/label/UiLabel.vue +4 -1
  38. package/lib/components/ui/panel/UiPanel.vue +16 -3
  39. package/lib/components/ui/progress-bar/UiProgressBar.vue +5 -2
  40. package/lib/components/ui/query-search-bar/UiQuerySearchBar.vue +9 -6
  41. package/lib/components/ui/quick-task-item/UiQuickTaskItem.vue +6 -3
  42. package/lib/components/ui/quoteCode/UiQuoteCode.vue +104 -0
  43. package/lib/components/ui/stacked-bar/StackedBarSegment.vue +4 -1
  44. package/lib/components/ui/table-pagination/UiTablePagination.vue +6 -3
  45. package/lib/components/ui/text-area/UiTextarea.vue +4 -1
  46. package/lib/components/ui/top-bottom-table/UiTopBottomTable.vue +6 -3
  47. package/lib/components/ui/tree-item-label/UiTreeItemLabel.vue +4 -1
  48. package/lib/composables/local-time-ago.composable.ts +53 -0
  49. package/lib/composables/locale-time-ago.composable.ts +53 -0
  50. package/lib/icons/fa-icons.ts +164 -0
  51. package/lib/icons/index.ts +15 -0
  52. package/lib/icons/legacy-icons.ts +80 -0
  53. package/lib/icons/object-icons.ts +187 -0
  54. package/lib/layouts/CoreLayout.vue +7 -3
  55. package/lib/locales/cs.json +0 -1
  56. package/lib/locales/de.json +1 -1
  57. package/lib/locales/en.json +40 -4
  58. package/lib/locales/es.json +1 -1
  59. package/lib/locales/fr.json +39 -3
  60. package/lib/locales/it.json +1 -1
  61. package/lib/locales/nl.json +1 -1
  62. package/lib/locales/ru.json +1 -1
  63. package/lib/locales/sv.json +1 -2
  64. package/lib/packages/collection/README.md +23 -18
  65. package/lib/packages/collection/create-collection.ts +22 -21
  66. package/lib/packages/collection/create-item.ts +21 -20
  67. package/lib/packages/collection/create-use-subset.ts +23 -0
  68. package/lib/packages/collection/guess-item-id.ts +26 -16
  69. package/lib/packages/collection/index.ts +4 -0
  70. package/lib/packages/collection/types.ts +65 -37
  71. package/lib/packages/collection/use-collection.ts +68 -18
  72. package/lib/packages/collection/use-flag-registry.ts +38 -17
  73. package/lib/packages/form-select/guess-label.ts +45 -0
  74. package/lib/packages/form-select/guess-value.ts +23 -0
  75. package/lib/packages/form-select/index.ts +6 -0
  76. package/lib/packages/form-select/normalize-search-term.ts +11 -0
  77. package/lib/packages/form-select/types.ts +90 -42
  78. package/lib/packages/form-select/use-form-option-controller.ts +7 -3
  79. package/lib/packages/form-select/use-form-select-controller.ts +38 -27
  80. package/lib/packages/form-select/use-form-select-keyboard-navigation.ts +1 -1
  81. package/lib/packages/form-select/use-form-select.ts +308 -130
  82. package/lib/packages/icon/DisplayIcon.vue +25 -0
  83. package/lib/packages/icon/DisplayIconAny.vue +16 -0
  84. package/lib/packages/icon/DisplayIconSingle.vue +35 -0
  85. package/lib/packages/icon/DisplayIconStack.vue +34 -0
  86. package/lib/packages/icon/README.md +286 -0
  87. package/lib/packages/icon/create-icon-bindings.ts +27 -0
  88. package/lib/packages/icon/define-icon-pack.ts +23 -0
  89. package/lib/packages/icon/define-icon-single.ts +17 -0
  90. package/lib/packages/icon/define-icon-stack.ts +20 -0
  91. package/lib/packages/icon/define-icon.ts +40 -0
  92. package/lib/packages/icon/generate-icon-variants.ts +17 -0
  93. package/lib/packages/icon/index.ts +8 -0
  94. package/lib/packages/icon/is-icon-stack.ts +5 -0
  95. package/lib/packages/icon/merge-icons.ts +25 -0
  96. package/lib/packages/icon/merge-transforms.ts +12 -0
  97. package/lib/packages/icon/normalize-icon.ts +25 -0
  98. package/lib/packages/icon/to-tuple.ts +7 -0
  99. package/lib/packages/icon/types.ts +72 -0
  100. package/lib/packages/job/README.md +2 -2
  101. package/lib/packages/mapper/README.md +166 -0
  102. package/lib/packages/mapper/convert-to-map.ts +5 -0
  103. package/lib/packages/mapper/create-mapper.ts +30 -0
  104. package/lib/packages/mapper/index.ts +4 -0
  105. package/lib/packages/mapper/types.ts +1 -0
  106. package/lib/packages/mapper/use-mapper.ts +31 -0
  107. package/lib/stores/sidebar.store.ts +1 -1
  108. package/lib/types/chart.ts +2 -2
  109. package/lib/types/utility.type.ts +9 -0
  110. package/lib/utils/object.util.ts +16 -0
  111. package/lib/utils/size.util.ts +14 -3
  112. package/package.json +2 -1
  113. package/lib/assets/zoom.svg +0 -85
  114. package/lib/components/backup-item/VtsBackupItem.vue +0 -47
  115. package/lib/composables/mapper.composable.md +0 -74
  116. package/lib/composables/mapper.composable.ts +0 -18
@@ -0,0 +1,166 @@
1
+ # Mapper System
2
+
3
+ A system for mapping values from one type to another with support for reactive sources.
4
+
5
+ ## Core Concepts
6
+
7
+ - **Mapping**: A structure that defines transformations from a source type to a destination type
8
+ - **Source**: The value to be transformed, which can be reactive
9
+ - **Default Source**: A fallback value to use when the source is undefined or not found in the mapping
10
+
11
+ ## Usage
12
+
13
+ ### `useMapper` Composable
14
+
15
+ ```typescript
16
+ const mappedValue = useMapper(sourceValue, mapping, defaultValue)
17
+ ```
18
+
19
+ | | Required | Type | Description |
20
+ | -------------- | :------: | ------------------------- | ------------------------------------------------------------------ |
21
+ | `sourceValue` | ✓ | `MaybeRefOrGetter<TFrom>` | The source value to be mapped (ref, getter function, or raw value) |
22
+ | `mapping` | ✓ | `Mapping<TFrom, TTo>` | The mapping between source and destination values |
23
+ | `defaultValue` | ✓ | `MaybeRefOrGetter<TFrom>` | Default source value to use when source is undefined/not found |
24
+
25
+ #### Return Value
26
+
27
+ | | Type | Description |
28
+ | ------------- | ------------------ | --------------------------------------------- |
29
+ | `mappedValue` | `ComputedRef<TTo>` | A computed reference of the transformed value |
30
+
31
+ ### `createMapper` Function
32
+
33
+ Creates a reusable mapper function from a mapping configuration.
34
+
35
+ ```typescript
36
+ const getValueFor = createMapper(mapping, defaultValue)
37
+ const mappedValue = getValueFor(sourceValue)
38
+ ```
39
+
40
+ | | Required | Type | Description |
41
+ | -------------- | :------: | --------------------------------------- | ---------------------------------------------------- |
42
+ | `mapping` | ✓ | `MaybeRefOrGetter<Mapping<TFrom, TTo>>` | The mapping between source and destination values |
43
+ | `defaultValue` | ✓ | `MaybeRefOrGetter<TFrom>` | Default source value to use when source is undefined |
44
+
45
+ #### Return Value
46
+
47
+ | | Type | Description |
48
+ | -------- | ------------------------ | ------------------------------------------------------ |
49
+ | `mapper` | `(source: TFrom) => TTo` | Function that maps a source value to destination value |
50
+
51
+ ## Mapping Types
52
+
53
+ The `mapping` parameter supports several formats:
54
+
55
+ 1. **Object Literal**: For when `TFrom` extends `PropertyKey` (string, number, or symbol)
56
+
57
+ ```typescript
58
+ const mapping = {
59
+ red: 'crimson',
60
+ blue: 'navy',
61
+ green: 'forest',
62
+ }
63
+ ```
64
+
65
+ 2. **Map Instance**: For complex or non-serializable source keys
66
+
67
+ ```typescript
68
+ const mapping = new Map([
69
+ [ADMIN_SYMBOL, { level: 3, canEdit: true }],
70
+ [EDITOR_SYMBOL, { level: 2, canEdit: true }],
71
+ [VIEWER_SYMBOL, { level: 1, canEdit: false }],
72
+ ])
73
+ ```
74
+
75
+ 3. **Tuple Array**: For boolean or enum values
76
+ ```typescript
77
+ const mapping = [
78
+ [true, 'Active'],
79
+ [false, 'Inactive'],
80
+ [undefined, 'Unknown'],
81
+ ]
82
+ ```
83
+
84
+ ## Basic Example
85
+
86
+ ```vue
87
+ <template>
88
+ <div>
89
+ <div>Current status: {{ status }}</div>
90
+ <div>Status color: {{ statusColor }}</div>
91
+
92
+ <button @click="status = 'success'">Success</button>
93
+ <button @click="status = 'error'">Error</button>
94
+ <button @click="status = 'warning'">Warning</button>
95
+ <button @click="status = 'info'">Info</button>
96
+ <button @click="status = 'foobar'">Unknown</button>
97
+ <button @click="status = undefined">Reset</button>
98
+ </div>
99
+ </template>
100
+
101
+ <script lang="ts" setup>
102
+ import { useMapper } from '@core/packages/mapper/use-mapper.ts'
103
+ import { ref } from 'vue'
104
+
105
+ type Status = 'success' | 'error' | 'warning' | 'info'
106
+
107
+ const status = ref<Status | undefined>(undefined)
108
+
109
+ const statusColor = useMapper(
110
+ status,
111
+ {
112
+ success: 'green',
113
+ error: 'red',
114
+ warning: 'orange',
115
+ info: 'blue',
116
+ },
117
+ 'info' // Default source value when status is undefined or not found
118
+ )
119
+ </script>
120
+ ```
121
+
122
+ ## Reactive Mapping
123
+
124
+ Both the source value and the mapping object can be reactive:
125
+
126
+ ```vue
127
+ <template>
128
+ <div>
129
+ <div>Current status: {{ deviceStatusText }}</div>
130
+
131
+ <button type="button" @click="deviceStatus = 'yes'">Yes</button>
132
+ <button type="button" @click="deviceStatus = 'no'">No</button>
133
+
134
+ <div>
135
+ <button type="button" @click="currentMapping = 1 - currentMapping">Toggle mapping</button>
136
+ </div>
137
+ </div>
138
+ </template>
139
+
140
+ <script lang="ts" setup>
141
+ import { useMapper } from '@core/packages/mapper/use-mapper.ts'
142
+ import { computed, ref } from 'vue'
143
+
144
+ const deviceStatus = ref('online')
145
+
146
+ const mappings = [
147
+ {
148
+ yes: 'Yes',
149
+ no: 'No',
150
+ },
151
+ {
152
+ yes: 'Yep!',
153
+ no: 'Nope!',
154
+ },
155
+ ]
156
+
157
+ const currentMapping = ref(0)
158
+
159
+ // If the mapping changes, the computed result will update
160
+ const deviceStatusText = useMapper(
161
+ deviceStatus,
162
+ computed(() => mappings[currentMapping.value]),
163
+ 'no'
164
+ )
165
+ </script>
166
+ ```
@@ -0,0 +1,5 @@
1
+ import type { AnyMapping } from './types.ts'
2
+
3
+ export function convertToMap(mapping: AnyMapping): Map<unknown, unknown> {
4
+ return mapping instanceof Map ? mapping : Array.isArray(mapping) ? new Map(mapping) : new Map(Object.entries(mapping))
5
+ }
@@ -0,0 +1,30 @@
1
+ import type { AnyMapping } from './types.ts'
2
+ import { computed, type MaybeRefOrGetter, toValue } from 'vue'
3
+ import { convertToMap } from './convert-to-map.ts'
4
+
5
+ export function createMapper<const TFrom extends PropertyKey, const TTo>(
6
+ mapping: MaybeRefOrGetter<Record<TFrom, TTo>>,
7
+ defaultSource: NoInfer<MaybeRefOrGetter<TFrom>>
8
+ ): (source: undefined | TFrom) => TTo
9
+
10
+ export function createMapper<const TFrom, const TTo>(
11
+ mapping: MaybeRefOrGetter<Map<TFrom, TTo>>,
12
+ defaultSource: NoInfer<MaybeRefOrGetter<TFrom>>
13
+ ): (source: undefined | TFrom) => TTo
14
+
15
+ export function createMapper<const TFrom, const TTo>(
16
+ mapping: MaybeRefOrGetter<[TFrom, TTo][]>,
17
+ defaultSource: NoInfer<MaybeRefOrGetter<TFrom>>
18
+ ): (source: undefined | TFrom) => TTo
19
+
20
+ export function createMapper(mapping: MaybeRefOrGetter<AnyMapping>, defaultSource: MaybeRefOrGetter) {
21
+ const map = computed(() => convertToMap(toValue(mapping)))
22
+
23
+ return function get(source: unknown) {
24
+ if (map.value.has(source)) {
25
+ return map.value.get(source)!
26
+ }
27
+
28
+ return map.value.get(toValue(defaultSource))!
29
+ }
30
+ }
@@ -0,0 +1,4 @@
1
+ export * from './convert-to-map.ts'
2
+ export * from './create-mapper.ts'
3
+ export * from './types.ts'
4
+ export * from './use-mapper.ts'
@@ -0,0 +1 @@
1
+ export type AnyMapping = Record<PropertyKey, any> | Map<any, any> | [any, any][]
@@ -0,0 +1,31 @@
1
+ import type { AnyMapping } from './types.ts'
2
+ import { computed, type ComputedRef, type MaybeRefOrGetter, toValue } from 'vue'
3
+ import { createMapper } from './create-mapper.ts'
4
+
5
+ export function useMapper<const TFrom extends PropertyKey, const TTo>(
6
+ source: MaybeRefOrGetter<TFrom | undefined>,
7
+ mapping: MaybeRefOrGetter<Record<TFrom, TTo>>,
8
+ defaultSource: NoInfer<MaybeRefOrGetter<TFrom>>
9
+ ): ComputedRef<TTo>
10
+
11
+ export function useMapper<const TFrom, const TTo>(
12
+ source: MaybeRefOrGetter<TFrom | undefined>,
13
+ mapping: MaybeRefOrGetter<Map<TFrom, TTo>>,
14
+ defaultSource: NoInfer<MaybeRefOrGetter<TFrom>>
15
+ ): ComputedRef<TTo>
16
+
17
+ export function useMapper<const TFrom, const TTo>(
18
+ source: MaybeRefOrGetter<TFrom | undefined>,
19
+ mapping: MaybeRefOrGetter<[TFrom, TTo][]>,
20
+ defaultSource: NoInfer<MaybeRefOrGetter<TFrom>>
21
+ ): ComputedRef<TTo>
22
+
23
+ export function useMapper(
24
+ source: MaybeRefOrGetter,
25
+ mapping: MaybeRefOrGetter<AnyMapping>,
26
+ defaultSource: MaybeRefOrGetter
27
+ ): ComputedRef {
28
+ const mapper = createMapper(mapping, defaultSource)
29
+
30
+ return computed(() => mapper(toValue(source)))
31
+ }
@@ -53,7 +53,7 @@ export const useSidebarStore = defineStore('layout', () => {
53
53
  watch(
54
54
  () => uiStore.isMobile,
55
55
  isMobile => {
56
- // keep the state of desktop expention
56
+ // keep the state of desktop expansion
57
57
  if (isMobile) {
58
58
  desktopState = isExpanded.value
59
59
  }
@@ -2,8 +2,8 @@ export type LinearChartData = {
2
2
  label: string
3
3
  data: {
4
4
  timestamp: number
5
- value: number
5
+ value: number | null
6
6
  }[]
7
7
  }[]
8
8
 
9
- export type ValueFormatter = (value: number) => string
9
+ export type ValueFormatter = (value: number | null) => string
@@ -9,3 +9,12 @@ export type Branded<TBrand extends string, TType = string> = TType & { [__brand]
9
9
  export type EmptyObject = Record<string, never>
10
10
 
11
11
  export type StringKeyOf<T> = Extract<keyof T, string>
12
+
13
+ export type KeyOfByValue<T, TValue> =
14
+ T extends Record<PropertyKey, unknown>
15
+ ? keyof {
16
+ [K in keyof T as T[K] extends TValue ? K : never]: T[K]
17
+ }
18
+ : never
19
+
20
+ export type ArrayFilterPredicate<T> = (value: T, index: number, array: T[]) => boolean
@@ -0,0 +1,16 @@
1
+ export function objectEntries<T, K extends string = string>(obj: { [Key in K]: T } | ArrayLike<T>): [K, T][] {
2
+ return Object.entries(obj) as [K, T][]
3
+ }
4
+
5
+ export function objectFromEntries<T = any, K extends PropertyKey = PropertyKey>(
6
+ entries: Iterable<readonly [K, T]>
7
+ ): { [Key in K]: T } {
8
+ return Object.fromEntries(entries) as { [Key in K]: T }
9
+ }
10
+
11
+ export function hasObjectProperty<TSource, TProperty extends PropertyKey>(
12
+ source: TSource,
13
+ property: TProperty
14
+ ): source is TSource & Record<TProperty, unknown> {
15
+ return typeof source === 'object' && source !== null && Object.prototype.hasOwnProperty.call(source, property)
16
+ }
@@ -1,13 +1,24 @@
1
- import { parse, Scale, raw } from 'human-format'
1
+ import { parse, raw, Scale, type Info } from 'human-format'
2
2
 
3
3
  const scale = Scale.create(['', 'KiB', 'MiB', 'GiB', 'TiB'], 1024)
4
4
 
5
- export const formatSizeRaw = (bytes: number | undefined, decimals: number) => {
5
+ export function formatSizeRaw(bytes: number, decimals: number): Info<Scale<'B' | 'KiB' | 'MiB' | 'GiB' | 'TiB'>>
6
+ export function formatSizeRaw(bytes: undefined, decimals: number): undefined
7
+ export function formatSizeRaw(
8
+ bytes: undefined | number,
9
+ decimals: number
10
+ ): undefined | Info<Scale<'B' | 'KiB' | 'MiB' | 'GiB' | 'TiB'>>
11
+ export function formatSizeRaw(
12
+ bytes: number | undefined,
13
+ decimals: number
14
+ ): Info<Scale<'B' | 'KiB' | 'MiB' | 'GiB' | 'TiB'>> | undefined {
6
15
  if (bytes === undefined) {
7
16
  return undefined
8
17
  }
9
18
 
10
- return raw(bytes, { maxDecimals: decimals, scale })
19
+ const result = raw(bytes, { maxDecimals: decimals, scale })
20
+
21
+ return { ...result, prefix: result.prefix === '' ? 'B' : result.prefix }
11
22
  }
12
23
 
13
24
  export const formatSizeParse = (size: number | undefined, unit?: string) => {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@xen-orchestra/web-core",
3
3
  "type": "module",
4
- "version": "0.20.1",
4
+ "version": "0.22.0",
5
5
  "private": false,
6
6
  "exports": {
7
7
  "./*": {
@@ -27,6 +27,7 @@
27
27
  "iterable-backoff": "^0.1.0",
28
28
  "lodash-es": "^4.17.21",
29
29
  "placement.js": "^1.0.0-beta.5",
30
+ "simple-icons": "^14.14.0",
30
31
  "vue-echarts": "^6.6.8"
31
32
  },
32
33
  "peerDependencies": {
@@ -1,85 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <svg id="Zoom" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 397.13 396.85">
3
- <defs>
4
- <style>
5
- .cls-1 {
6
- fill: #eaea92;
7
- }
8
-
9
- .cls-2, .cls-3, .cls-4 {
10
- fill: #8f84ff;
11
- }
12
-
13
- .cls-2, .cls-5 {
14
- opacity: .3;
15
- }
16
-
17
- .cls-6, .cls-5 {
18
- fill: #fff;
19
- }
20
-
21
- .cls-3 {
22
- opacity: .14;
23
- }
24
-
25
- .cls-7 {
26
- fill: #181849;
27
- }
28
-
29
- .cls-8 {
30
- fill: #1a1b38;
31
- }
32
- </style>
33
- </defs>
34
- <path class="cls-4" d="M129.55,173.68c-6.44,2.53-12.65,5.45-18.79,8.51-6.13,3.06-12.16,6.31-18.12,9.68-5.96,3.37-11.83,6.88-17.56,10.64-2.87,1.87-5.7,3.82-8.49,5.83-2.79,2.02-5.54,4.09-8.18,6.36-1.46,1.25-1.62,3.44-.37,4.9.95,1.11,2.47,1.47,3.78,1.02,3.29-1.14,6.47-2.48,9.62-3.87,3.14-1.4,6.25-2.86,9.31-4.4,6.13-3.06,12.13-6.36,18.04-9.82,5.91-3.45,11.75-7.02,17.48-10.78,5.73-3.76,11.39-7.66,16.81-11.95,1.55-1.22,1.81-3.47.59-5.02-1-1.26-2.68-1.67-4.11-1.11Z"/>
35
- <path class="cls-3" d="M194.07,50.23c74.01-2.19,138.12,51.52,147.8,121.98,10.59,77.04-47.69,146.36-119.41,157.46-89.2,13.81-175.73-66.08-167.96-152.75,5.85-65.3,64.33-124.47,139.57-126.69Z"/>
36
- <path class="cls-8" d="M90.67,198.68c.14.05.25.11.35.19.1.02.2.04.3.06.46.09.46.85,0,.93-.1.02-.2.04-.3.06-.1.08-.21.14-.35.19-.46.16-.93-.25-.93-.71,0-.46.47-.87.93-.71Z"/>
37
- <path class="cls-4" d="M162.94,225.43h0c-1.62-2.75-4.97-4.27-8.07-3.67l-48.48,9.41c-3.68.71-5.75,4.14-4.62,7.64l32.93,102.68c1.12,3.51,5.02,5.77,8.7,5.06l153.84-29.87c3.68-.71,5.75-4.14,4.62-7.64l-27.66-86.24c-1.12-3.51-5.02-5.77-8.7-5.06l-83.71,16.25c-7.25,1.41-15.06-2.14-18.85-8.56Z"/>
38
- <polygon class="cls-6" points="299.39 311.24 138.65 342.45 108.5 236.07 269.23 204.87 299.39 311.24"/>
39
- <polygon class="cls-1" points="299.39 311.24 138.65 342.45 111.03 235.58 269.23 204.87 299.39 311.24"/>
40
- <polygon class="cls-6" points="299.39 311.24 138.65 342.45 111.46 231.94 272.2 200.73 299.39 311.24"/>
41
- <polygon class="cls-6" points="299.39 311.24 138.65 342.45 114.8 231.29 272.2 200.73 299.39 311.24"/>
42
- <polygon class="cls-1" points="299.39 280.37 138.65 311.57 115.44 197.14 276.18 165.94 299.39 280.37"/>
43
- <polygon class="cls-1" points="299.39 311.24 138.65 342.45 120.12 229.37 279.82 198.36 299.39 311.24"/>
44
- <polygon class="cls-6" points="300.96 307.85 138.65 342.45 121.79 229.06 282.81 198.64 300.96 307.85"/>
45
- <polygon class="cls-1" points="299.39 311.24 138.65 342.45 124.91 231.07 285.65 199.87 299.39 311.24"/>
46
- <polygon class="cls-6" points="299.39 311.24 138.65 342.45 126.31 231.78 287.04 200.57 299.39 311.24"/>
47
- <path class="cls-4" d="M199.21,225.47h0c-.69-3-3.38-4.71-6.48-4.1l-48.48,9.41c-3.68.71-6.66,4.39-6.67,8.21l-.11,101.8c0,3.82,2.97,6.33,6.65,5.62l153.84-29.87c3.68-.71,6.66-4.39,6.67-8.21l.09-83.92c0-3.82-2.97-6.33-6.65-5.62l-83.71,16.25c-7.25,1.41-13.53-2.57-15.15-9.58Z"/>
48
- <path class="cls-2" d="M153.88,195.95c26.94,15.96,61.72,7.06,77.68-19.88,15.96-26.94,7.06-61.72-19.88-77.68-26.94-15.96-61.72-7.07-77.68,19.87-15.96,26.94-7.06,61.72,19.88,77.68Z"/>
49
- <path class="cls-5" d="M181.76,90.48l27.36,106.91c.76-.4,1.52-.82,2.26-1.25,4.76-2.77,9.13-6.25,12.98-10.41h0s-23.63-92.34-23.63-92.34c-6.21-2.08-12.62-3.03-18.97-2.91Z"/>
50
- <path class="cls-5" d="M147.71,102.6l25.72,100.51c8.64,1.45,17.42.84,25.66-1.64l-28.09-109.76c-8.42,1.78-16.41,5.47-23.3,10.89Z"/>
51
- <path class="cls-4" d="M212.83,199.46c-28.88,16.6-65.74,6.64-82.34-22.24-16.6-28.88-6.64-65.74,22.24-82.34,28.88-16.6,65.74-6.64,82.34,22.24,16.6,28.88,6.64,65.75-22.23,82.34ZM210.38,195.19c26.52-15.24,35.66-49.09,20.42-75.62-15.24-26.51-49.09-35.66-75.61-20.42-26.52,15.24-35.66,49.09-20.42,75.61,15.24,26.52,49.09,35.67,75.61,20.43Z"/>
52
- <path class="cls-4" d="M133.07,179.81c-5.43,4.3-11.08,8.19-16.81,11.95-5.74,3.76-11.58,7.33-17.49,10.78-.95.56-1.91,1.11-2.87,1.66-4.98,2.86-10.02,5.59-15.17,8.16-3.06,1.54-6.17,3-9.31,4.4-3.15,1.39-6.33,2.73-9.62,3.87-1.3.45-2.82.09-3.77-1.02-1.25-1.46-1.08-3.65.37-4.9,2.65-2.27,5.4-4.34,8.19-6.36,2.79-2.01,5.61-3.96,8.48-5.83,5.74-3.76,11.61-7.28,17.57-10.65,1.23-.69,2.46-1.38,3.7-2.07,4.75-2.63,9.55-5.18,14.42-7.61,6.13-3.06,12.34-5.98,18.78-8.51,1.43-.56,3.12-.15,4.11,1.11,1.23,1.55.97,3.8-.58,5.02Z"/>
53
- <path class="cls-6" d="M278.46,132.05l-3,1.68,1.68,3-3,1.68,1.68,3-3,1.68,1.68,3-3,1.68,1.68,3-3,1.68,1.68,3-3,1.68,1.68,3-3,1.68,1.68,3-3,1.68,1.68,3-3,1.68,1.68,3-3,1.68,1.68,3-3,1.68,1.68,3,51.04-28.52-1.68-3-1.68-3-3,1.68-1.68-3-3,1.68-1.68-3-3,1.68-1.68-3,6.01-3.36-1.68-3,6.01-3.36-1.68-3,3-1.68-3.35-6-3,1.68-1.68-3-6.01,3.36,1.68,3-6.01,3.36,1.68,3-3,1.68-6.71-12.01-3,1.68-3,1.68,1.68,3Z"/>
54
- <rect class="cls-8" x="259.33" y="166.05" width="58.47" height="3.44" transform="translate(-45.17 162.06) rotate(-29.19)"/>
55
- <rect class="cls-8" x="264.16" y="174.79" width="3.44" height="3.44" transform="translate(-52.32 152.1) rotate(-29.19)"/>
56
- <rect class="cls-8" x="265.48" y="170.11" width="3.44" height="3.44" transform="translate(-49.87 152.15) rotate(-29.19)"/>
57
- <rect class="cls-8" x="266.81" y="165.43" width="3.44" height="3.44" transform="translate(-47.42 152.2) rotate(-29.19)"/>
58
- <rect class="cls-8" x="268.13" y="160.75" width="3.44" height="3.44" transform="translate(-44.97 152.26) rotate(-29.19)"/>
59
- <rect class="cls-8" x="269.46" y="156.07" width="3.44" height="3.44" transform="translate(-42.52 152.31) rotate(-29.19)"/>
60
- <rect class="cls-8" x="270.78" y="151.39" width="3.44" height="3.44" transform="translate(-40.07 152.36) rotate(-29.19)"/>
61
- <rect class="cls-8" x="272.11" y="146.71" width="3.44" height="3.44" transform="translate(-37.62 152.41) rotate(-29.19)"/>
62
- <rect class="cls-8" x="273.43" y="142.03" width="3.44" height="3.44" transform="translate(-35.16 152.46) rotate(-29.19)"/>
63
- <rect class="cls-8" x="274.76" y="137.35" width="3.44" height="3.44" transform="translate(-32.71 152.52) rotate(-29.19)"/>
64
- <rect class="cls-8" x="276.08" y="132.67" width="3.44" height="3.44" transform="translate(-30.26 152.57) rotate(-29.19)"/>
65
- <rect class="cls-8" x="277.41" y="127.99" width="3.44" height="3.44" transform="translate(-27.81 152.62) rotate(-29.19)"/>
66
- <rect class="cls-8" x="283.77" y="125.44" width="3.44" height="17.19" transform="translate(-29.11 156.27) rotate(-29.19)"/>
67
- <rect class="cls-8" x="290.12" y="136.64" width="3.44" height="3.44" transform="translate(-30.42 159.92) rotate(-29.19)"/>
68
- <rect class="cls-8" x="295.15" y="145.65" width="3.44" height="3.44" transform="translate(-34.17 163.52) rotate(-29.19)"/>
69
- <rect class="cls-8" x="296.26" y="140.13" width="6.88" height="3.44" transform="translate(-31.12 164.2) rotate(-29.19)"/>
70
- <rect class="cls-8" x="300.59" y="133.77" width="6.88" height="3.44" transform="translate(-27.47 165.5) rotate(-29.19)"/>
71
- <rect class="cls-8" x="304.3" y="125.04" width="3.44" height="6.88" transform="translate(-23.79 165.58) rotate(-29.19)"/>
72
- <rect class="cls-8" x="291.23" y="131.13" width="6.88" height="3.44" transform="translate(-27.37 160.6) rotate(-29.19)"/>
73
- <rect class="cls-8" x="295.56" y="124.77" width="6.88" height="3.44" transform="translate(-23.72 161.9) rotate(-29.19)"/>
74
- <rect class="cls-8" x="299.83" y="146.97" width="3.44" height="3.44" transform="translate(-34.22 165.97) rotate(-29.19)"/>
75
- <rect class="cls-8" x="304.51" y="148.3" width="3.44" height="3.44" transform="translate(-34.27 168.42) rotate(-29.19)"/>
76
- <rect class="cls-8" x="309.19" y="149.62" width="3.44" height="3.44" transform="translate(-34.33 170.87) rotate(-29.19)"/>
77
- <polygon class="cls-7" points="173.4 252.35 171.52 258.69 165.18 260.57 171.52 262.45 173.4 268.79 175.28 262.45 181.62 260.57 175.28 258.69 173.4 252.35"/>
78
- <polygon class="cls-7" points="283.94 292.49 282.82 296.27 279.05 297.39 282.82 298.51 283.94 302.28 285.06 298.51 288.84 297.39 285.06 296.27 283.94 292.49"/>
79
- <polygon class="cls-7" points="244.55 182.48 242.67 188.82 236.33 190.7 242.67 192.58 244.55 198.92 246.43 192.58 252.77 190.7 246.43 188.82 244.55 182.48"/>
80
- <path class="cls-6" d="M222.84,291.45c.62.17,1.24.34,1.85.5-6.22,2.4-12.01,4.07-16.61,4.88-5.54.98-9.34.71-10.07-1.05-.72-1.73,1.57-4.54,6.04-7.74.07.37.13.76.23,1.13-3.52,2.54-5.25,4.66-4.7,5.96.55,1.32,3.47,1.51,7.85.77,4.11-.7,9.5-2.23,15.42-4.45Z"/>
81
- <path class="cls-6" d="M247.13,280.34c-4.49,3.29-11.25,6.99-19.08,10.26-.52.22-1.04.43-1.56.64-.61-.15-1.23-.32-1.85-.48.98-.38,1.98-.79,2.98-1.2,8.13-3.39,15.07-7.18,19.31-10.34,3.21-2.39,4.88-4.43,4.36-5.67-.51-1.22-3.06-1.48-6.92-.91-.19-.32-.39-.64-.6-.95,5-.77,8.4-.43,9.08,1.21.7,1.67-1.53,4.38-5.72,7.45Z"/>
82
- <path class="cls-6" d="M253.1,292.89c-.49,1.74-3.92,2.49-9.11,2.3-5.1-.19-11.91-1.29-19.31-3.23-.61-.16-1.23-.33-1.85-.5-.06-.02-.12-.03-.18-.05-7.81-2.19-14.68-4.89-19.52-7.5-4.95-2.67-7.77-5.24-7.25-7.07.51-1.8,4.05-2.59,9.54-2.32-.17.33-.37.68-.52,1.03-4.33-.19-7,.4-7.39,1.76-.39,1.38,1.79,3.34,5.68,5.47,4.62,2.53,11.67,5.28,19.76,7.55.56.16,1.11.31,1.66.46.62.17,1.24.33,1.85.48,7.1,1.79,13.5,2.8,18.05,2.93,4,.12,6.57-.45,6.94-1.74.36-1.28-1.48-3.06-4.86-5.01.05-.37.09-.74.12-1.11,4.4,2.49,6.85,4.87,6.37,6.58Z"/>
83
- <path class="cls-6" d="M232.63,304.23c-11.71,3.96-24.46-2.36-28.41-14.07-3.95-11.71,2.36-24.46,14.07-28.41,11.71-3.96,24.46,2.36,28.41,14.07,3.95,11.71-2.36,24.46-14.07,28.41ZM218.74,263.1c-10.97,3.7-16.88,15.64-13.17,26.61,3.7,10.97,15.64,16.88,26.6,13.17,10.97-3.7,16.88-15.64,13.17-26.61-3.7-10.97-15.64-16.88-26.6-13.17Z"/>
84
- <path class="cls-6" d="M248.48,286.34c.29-1.97.33-3.99.1-6.02,4.16-3.22,5.87-5.83,5.06-7.76-.77-1.86-3.62-2.5-8.47-1.94-5.59-8.92-16.77-13.2-27.17-9.69-6.43,2.17-11.29,6.9-13.84,12.67-5.46-.11-8.52.9-9.11,2.99-.62,2.19,1.8,4.81,7.16,7.78.07,1.19.23,2.39.49,3.58-4.5,3.38-6.36,6.12-5.5,8.16.87,2.08,4.33,2.65,10.29,1.68,5.97,7.23,16.01,10.42,25.41,7.25,5-1.69,9.05-4.92,11.8-8.98,2.85.06,5.06-.17,6.61-.69,1.46-.49,2.34-1.25,2.62-2.25.54-1.94-1.29-4.21-5.45-6.78ZM206.39,289.43c-.37-1.11-.62-2.22-.8-3.34,4.12,1.95,9.09,3.83,14.46,5.45-3.99,1.4-7.77,2.49-10.97,3.16-1.13-1.57-2.05-3.34-2.7-5.26ZM242.76,293.22c-3.78-.26-8.45-1.02-13.52-2.19,6.28-2.67,11.96-5.65,16.33-8.56.1,3.82-.92,7.54-2.82,10.75ZM250.48,273.88c.15.35-.26,1.46-2.47,3.36-.15-.57-.31-1.14-.5-1.7-.27-.79-.57-1.55-.91-2.29,2.73-.18,3.74.29,3.88.62ZM219.02,263.92c10.51-3.55,21.96,2.11,25.51,12.63.31.93.53,1.87.7,2.81-4.39,3.05-10.83,6.43-17.96,9.4-.88.37-1.79.73-2.7,1.09-.46-.12-.91-.25-1.37-.38-6.82-1.91-13.19-4.27-17.85-6.58.05-8.36,5.32-16.16,13.67-18.98ZM198.35,277.52c.13-.45,1.31-1.13,4.8-1.16-.47,1.57-.78,3.19-.91,4.85-3.29-1.99-4.01-3.26-3.89-3.69ZM200.37,294.8c-.18-.44.34-1.73,3.16-3.98.57,1.59,1.29,3.08,2.15,4.46-3.79.48-5.15-.07-5.32-.48ZM231.89,302.06c-7.53,2.54-15.53.34-20.77-4.97,2.79-.63,5.82-1.5,9.01-2.57,1.5-.51,3.04-1.06,4.6-1.66,5.84,1.52,11.44,2.55,16.17,2.98-2.3,2.78-5.36,4.99-9.02,6.22ZM250.63,292.2c-.11.38-1.18,1.02-4.32,1.11.65-1.31,1.17-2.67,1.56-4.08,2.34,1.59,2.86,2.61,2.76,2.97Z"/>
85
- </svg>
@@ -1,47 +0,0 @@
1
- <template>
2
- <div class="vts-backup-item">
3
- <RouterLink v-if="backup.route !== undefined" :to="backup.route">
4
- {{ backup.label }}
5
- </RouterLink>
6
- <p v-else class="typo-body-bold">
7
- {{ backup.label }}
8
- </p>
9
- <div class="states">
10
- <VtsBackupState v-for="(state, index) in backup.states" :key="index" :state />
11
- </div>
12
- </div>
13
- </template>
14
-
15
- <script lang="ts" setup>
16
- import VtsBackupState, { type BackupState } from '@core/components/backup-state/VtsBackupState.vue'
17
- import type { RouteLocationRaw } from 'vue-router'
18
-
19
- export type BackupStates = BackupState[]
20
-
21
- export type Backup = {
22
- label: string
23
- route?: RouteLocationRaw
24
- states: BackupStates
25
- }
26
-
27
- defineProps<{
28
- backup: Backup
29
- }>()
30
- </script>
31
-
32
- <style lang="postcss" scoped>
33
- .vts-backup-item {
34
- padding: 0.8rem 0.4rem;
35
- border-top: 0.1rem solid var(--color-neutral-border);
36
- display: flex;
37
- align-items: center;
38
- gap: 0.2rem;
39
-
40
- .states {
41
- margin-inline-start: auto;
42
- display: flex;
43
- align-items: center;
44
- gap: 0.2rem;
45
- }
46
- }
47
- </style>
@@ -1,74 +0,0 @@
1
- # `useMapper` composable
2
-
3
- This composable maps values from one type to another using a mapping record. It takes a source value, a mapping object, and a default value to use when the source value is undefined or not found in the mapping.
4
-
5
- ## Usage
6
-
7
- ```ts
8
- const mappedValue = useMapper(sourceValue, mapping, defaultValue)
9
- ```
10
-
11
- | | Required | Type | Default | |
12
- | -------------- | :------: | ------------------------- | ------- | --------------------------------------------------------------------------------- |
13
- | `sourceValue` | ✓ | `MaybeRefOrGetter<TFrom>` | | The source value to be mapped. Can be a ref, a getter function, or a raw value |
14
- | `mapping` | ✓ | `Record<TFrom, TTo>` | | An object mapping source values to destination values |
15
- | `defaultValue` | ✓ | `MaybeRefOrGetter<TTo>` | | The default value to use when the source is undefined or not found in the mapping |
16
-
17
- ## Return value
18
-
19
- | | Type | |
20
- | ------------- | ------------------ | ------------------------------------------------ |
21
- | `mappedValue` | `ComputedRef<TTo>` | A computed reference containing the mapped value |
22
-
23
- ## Example
24
-
25
- ```vue
26
- <template>
27
- <div>
28
- <p>Selected car color: {{ carColor }}</p>
29
- <p>Recommended wall color: {{ wallColor }}</p>
30
-
31
- <button @click="carColor = 'red'">Red Car</button>
32
- <button @click="carColor = 'blue'">Blue Car</button>
33
- <button @click="carColor = 'black'">Black Car</button>
34
- <button @click="carColor = 'green'">Green Car</button>
35
- <button @click="carColor = 'silver'">Silver Car</button>
36
- <button @click="carColor = undefined">No Car</button>
37
- </div>
38
- </template>
39
-
40
- <script lang="ts" setup>
41
- import { useMapper } from '@/composables/mapper'
42
- import { ref } from 'vue'
43
-
44
- // Source type
45
- type CarColor = 'red' | 'blue' | 'black' | 'green' | 'silver'
46
-
47
- // Destination type
48
- type WallColor = 'beige' | 'lightGray' | 'cream' | 'white'
49
-
50
- // Create a ref for the source value
51
- const carColor = ref<CarColor | undefined>(undefined)
52
-
53
- // Create a computed property that maps car color to wall color
54
- const wallColor = useMapper<CarColor, WallColor>(
55
- carColor,
56
- {
57
- red: 'beige',
58
- blue: 'lightGray',
59
- black: 'cream',
60
- green: 'beige',
61
- silver: 'lightGray',
62
- },
63
- 'white'
64
- )
65
- </script>
66
- ```
67
-
68
- In this example:
69
-
70
- - When `carColor.value` is `'red'` or `'green'`, `wallColor.value` will be `'beige'`
71
- - When `carColor.value` is `'blue'` or `'silver'`, `wallColor.value` will be `'lightGray'`
72
- - When `carColor.value` is `'black'`, `wallColor.value` will be `'cream'`
73
- - When `carColor.value` is `undefined` or any value not in the mapping, `wallColor.value` will be
74
- `'white'` (the default value)
@@ -1,18 +0,0 @@
1
- import { computed, type ComputedRef, type MaybeRefOrGetter, toValue } from 'vue'
2
-
3
- export function useMapper<TFrom extends string | number, TTo>(
4
- _source: MaybeRefOrGetter<TFrom | undefined>,
5
- mapping: Record<TFrom, TTo>,
6
- _defaultValue: MaybeRefOrGetter<TTo>
7
- ): ComputedRef<TTo> {
8
- return computed(() => {
9
- const source = toValue(_source)
10
- const defaultValue = toValue(_defaultValue)
11
-
12
- if (source === undefined) {
13
- return defaultValue
14
- }
15
-
16
- return Object.prototype.hasOwnProperty.call(mapping, source) ? mapping[source] : defaultValue
17
- })
18
- }