@xen-orchestra/web-core 0.26.1 → 0.28.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 (86) hide show
  1. package/lib/components/card/VtsCardRowKeyValue.vue +1 -0
  2. package/lib/components/cell-object/VtsCellObject.vue +1 -2
  3. package/lib/components/console/VtsActionsConsole.vue +3 -9
  4. package/lib/components/copy-button/VtsCopyButton.vue +1 -3
  5. package/lib/components/dropdown/DropdownTitle.vue +3 -3
  6. package/lib/components/icon/VtsIcon.vue +32 -76
  7. package/lib/components/input-wrapper/VtsInputWrapper.vue +2 -2
  8. package/lib/components/layout/VtsLayoutSidebar.vue +1 -2
  9. package/lib/components/menu/MenuItem.vue +4 -5
  10. package/lib/components/menu/MenuTrigger.vue +3 -3
  11. package/lib/components/object-icon/VtsObjectIcon.vue +2 -2
  12. package/lib/components/resources/VtsResource.vue +3 -3
  13. package/lib/components/select/VtsSelect.vue +4 -5
  14. package/lib/components/table/ColumnTitle.vue +11 -12
  15. package/lib/components/task/VtsQuickTaskButton.vue +1 -2
  16. package/lib/components/tree/VtsTreeLoadingItem.vue +3 -3
  17. package/lib/components/ui/alarm-item/UiAlarmItem.vue +1 -2
  18. package/lib/components/ui/alert/UiAlert.vue +14 -13
  19. package/lib/components/ui/button/UiButton.vue +4 -5
  20. package/lib/components/ui/button-icon/UiButtonIcon.vue +3 -3
  21. package/lib/components/ui/checkbox/UiCheckbox.vue +2 -9
  22. package/lib/components/ui/chip/ChipIcon.vue +3 -3
  23. package/lib/components/ui/chip/ChipRemoveIcon.vue +1 -2
  24. package/lib/components/ui/chip/UiChip.vue +2 -2
  25. package/lib/components/ui/circle-progress-bar/UiCircleProgressBar.vue +7 -4
  26. package/lib/components/ui/collapsible-list/UiCollapsibleList.vue +73 -0
  27. package/lib/components/ui/donut-chart/UiDonutChart.vue +30 -17
  28. package/lib/components/ui/dropdown/UiDropdown.vue +5 -7
  29. package/lib/components/ui/dropdown-button/UiDropdownButton.vue +4 -5
  30. package/lib/components/ui/head-bar/UiHeadBar.vue +6 -11
  31. package/lib/components/ui/info/UiInfo.vue +14 -20
  32. package/lib/components/ui/input/UiInput.vue +6 -7
  33. package/lib/components/ui/label/UiLabel.vue +3 -3
  34. package/lib/components/ui/legend/UiLegend.vue +3 -3
  35. package/lib/components/ui/legend-title/UiLegendTitle.vue +7 -3
  36. package/lib/components/ui/link/UiLink.vue +4 -5
  37. package/lib/components/ui/{quoteCode/UiQuoteCode.vue → log-entry-viewer/UiLogEntryViewer.vue} +58 -21
  38. package/lib/components/ui/object-link/UiObjectLink.vue +4 -4
  39. package/lib/components/ui/query-search-bar/UiQuerySearchBar.vue +3 -4
  40. package/lib/components/ui/quick-task-item/UiQuickTaskItem.vue +3 -4
  41. package/lib/components/ui/radio-button/UiRadioButton.vue +1 -2
  42. package/lib/components/ui/table-pagination/PaginationButton.vue +2 -25
  43. package/lib/components/ui/table-pagination/UiTablePagination.vue +56 -95
  44. package/lib/components/ui/tag/UiTag.vue +3 -3
  45. package/lib/components/ui/text-area/UiTextarea.vue +2 -2
  46. package/lib/components/ui/toaster/UiToaster.vue +15 -13
  47. package/lib/components/ui/tree-item-label/UiTreeItemLabel.vue +4 -5
  48. package/lib/composables/default-tab.composable.md +42 -0
  49. package/lib/composables/default-tab.composable.ts +26 -0
  50. package/lib/composables/link-component.composable.ts +3 -2
  51. package/lib/composables/pagination.composable.ts +5 -0
  52. package/lib/i18n.ts +4 -0
  53. package/lib/icons/fa-icons.ts +48 -2
  54. package/lib/icons/index.ts +4 -0
  55. package/lib/icons/legacy-icons.ts +10 -0
  56. package/lib/icons/object-icons.ts +1 -1
  57. package/lib/layouts/CoreLayout.vue +1 -2
  58. package/lib/locales/cs.json +29 -10
  59. package/lib/locales/de.json +70 -7
  60. package/lib/locales/en.json +25 -0
  61. package/lib/locales/es.json +3 -3
  62. package/lib/locales/fr.json +25 -0
  63. package/lib/locales/it.json +17 -5
  64. package/lib/locales/nl.json +28 -10
  65. package/lib/locales/pt_BR.json +67 -0
  66. package/lib/locales/sv.json +17 -0
  67. package/lib/packages/form-select/types.ts +3 -0
  68. package/lib/packages/form-select/use-form-option-controller.ts +5 -6
  69. package/lib/packages/form-select/use-form-select-controller.ts +1 -0
  70. package/lib/packages/form-select/use-form-select.ts +153 -109
  71. package/lib/packages/icon/DisplayIcon.vue +1 -0
  72. package/lib/packages/progress/README.md +62 -0
  73. package/lib/packages/progress/types.ts +19 -0
  74. package/lib/packages/progress/use-progress-group.ts +68 -0
  75. package/lib/packages/progress/use-progress.ts +22 -0
  76. package/lib/packages/remote-resource/README.md +115 -0
  77. package/lib/packages/remote-resource/define-remote-resource.ts +294 -0
  78. package/lib/packages/remote-resource/types.ts +28 -0
  79. package/lib/packages/threshold/README.md +30 -0
  80. package/lib/packages/threshold/type.ts +3 -0
  81. package/lib/packages/threshold/use-threshold.ts +19 -0
  82. package/lib/types/object-icon.type.ts +0 -40
  83. package/package.json +2 -2
  84. package/lib/components/icon/NewVtsIcon.vue +0 -49
  85. package/lib/components/ui/complex-icon/UiComplexIcon.vue +0 -45
  86. package/lib/components/ui/object-icon/UiObjectIcon.vue +0 -251
@@ -0,0 +1,115 @@
1
+ # `defineRemoteResource` documentation
2
+
3
+ This utility will create a function that can be used to fetch data from a remote resource (i.e., an API endpoint)
4
+
5
+ When called, a subscription to the resource is registered.
6
+
7
+ If multiple Components call that same function, a subscription will be registered for each of them.
8
+
9
+ They will share the same data and state, which means that the data will be fetched only once and shared across all Components.
10
+
11
+ The fetch will start automatically when at least one Component is using the resource, then, when the last Component releases the resource, the polling will stop.
12
+
13
+ The data is cached for a certain duration, so if a Component remounts in the frame time, the data will be retrieved from the cache to be displayed immediately, while the data is being fetched again in the background.
14
+
15
+ ## Basic usage
16
+
17
+ ```typescript
18
+ const useMyResource = defineRemoteResource({
19
+ url: '/api/path/to/resource',
20
+ })
21
+ ```
22
+
23
+ By default, the initial data (`TData`) will be `undefined`, the returned state will be `{ data: Ref<TData> }` and when new data is received, it will just replace the previous one.
24
+
25
+ ```typescript
26
+ const { data } = useMyResource()
27
+ ```
28
+
29
+ ## Initial data, state and received data handling
30
+
31
+ The initial data, the state and what happen when data is retrieved can be customized by passing the `initialData`, `state` and `onDataReceived` properties:
32
+
33
+ ```typescript
34
+ const useMyResource = defineRemoteResource({
35
+ url: '/api/path/to/resource',
36
+ initialData: () => {} as Partial<MyResource>,
37
+ state: (data) => {
38
+ return {
39
+ myResource: data,
40
+ customProp: computed(() => data.foobar)
41
+ }
42
+ },
43
+ onDataReceived: (currentData, receivedData) => {
44
+ deepMerge(currentData.value, receivedData)
45
+ }
46
+ }
47
+
48
+ const { myResource, customProp } = useMyResource()
49
+ ```
50
+
51
+ ## Context
52
+
53
+ The context is available in the `$context` property of the returned state.
54
+
55
+ It contains the following properties:
56
+
57
+ | Property | Type | Description |
58
+ | ------------- | --------------------------------- | ---------------------------------------------------------------------------------- |
59
+ | `scope` | `EffectScope` | The Vue effect scope used to be shared across the resource and its dependencies |
60
+ | `args` | `any[]` | The arguments passed to the `useMyResource` function |
61
+ | `isReady` | `ComputedRef<boolean>` | Indicates if the resource is ready (i.e., the data has been fetched at least once) |
62
+ | `hasError` | `ComputedRef<boolean>` | Indicates if an error occurred during the last fetch |
63
+ | `lastError` | `ComputedRef<Error \| undefined>` | The last error that occurred during the fetch, if any |
64
+ | `isEnabled` | `Ref<boolean>` | Whether the resource is enabled (execute the request) or not |
65
+ | `enable` | `() => void` | Function to manually enable the resource |
66
+ | `disable` | `() => void` | Function to manually disable the resource |
67
+ | `forceReload` | `() => void` | Function to manually reload the resource |
68
+
69
+ ```typescript
70
+ const { myResource, $context } = useMyResource()
71
+ ```
72
+
73
+ It's also passed as the second argument of the `state` builder and can be used to extend the resource state.
74
+
75
+ ```typescript
76
+ const useMyResource = defineRemoteResource({
77
+ url: '/api/path/to/resource',
78
+ state: (data, context) => ({
79
+ myResource: data,
80
+ isMyResourceReady: context.isReady,
81
+ }),
82
+ })
83
+
84
+ const { myResource, isMyResourceReady } = useMyResource()
85
+ ```
86
+
87
+ ## Dynamic URLs
88
+
89
+ You can define a dynamic URL by using a function that returns the URL string.
90
+
91
+ ```typescript
92
+ const useMyResource = defineRemoteResource({
93
+ url: (id: string) => `/api/path/to/resource/${id}`,
94
+ })
95
+
96
+ const { id } = defineProps<{
97
+ id: string
98
+ }>()
99
+
100
+ const { data } = useMyResource(() => id)
101
+ ```
102
+
103
+ ## Polling and caching
104
+
105
+ By default, the resource will poll for updates every 30 seconds and cache the result for 10 seconds.
106
+
107
+ This can be customized by passing the `pollingIntervalMs` and `cacheDurationMs` properties:
108
+
109
+ ```typescript
110
+ const useMyResource = defineRemoteResource({
111
+ url: '/api/path/to/resource',
112
+ pollingIntervalMs: 60_000, // Poll every 60 seconds
113
+ cacheDurationMs: 5 * 60_000, // Cache for 5 minutes
114
+ })
115
+ ```
@@ -0,0 +1,294 @@
1
+ import type { ResourceContext, UseRemoteResource } from '@core/packages/remote-resource/types.ts'
2
+ import type { VoidFunction } from '@core/types/utility.type.ts'
3
+ import { ifElse } from '@core/utils/if-else.utils.ts'
4
+ import { type MaybeRef, noop, useTimeoutPoll } from '@vueuse/core'
5
+ import { merge } from 'lodash-es'
6
+ import readNDJSONStream from 'ndjson-readablestream'
7
+ import {
8
+ computed,
9
+ type ComputedRef,
10
+ type EffectScope,
11
+ getCurrentScope,
12
+ type MaybeRefOrGetter,
13
+ onScopeDispose,
14
+ reactive,
15
+ type Ref,
16
+ ref,
17
+ toRef,
18
+ toValue,
19
+ watch,
20
+ } from 'vue'
21
+
22
+ const DEFAULT_CACHE_DURATION_MS = 10_000
23
+
24
+ const DEFAULT_POLLING_INTERVAL_MS = 30_000
25
+
26
+ export function defineRemoteResource<
27
+ TData,
28
+ TState extends object = { data: Ref<TData> },
29
+ TArgs extends any[] = [],
30
+ >(config: {
31
+ url: string | ((...args: TArgs) => string)
32
+ initialData: () => TData
33
+ state?: (data: Ref<NoInfer<TData>>, context: ResourceContext<TArgs>) => TState
34
+ onDataReceived?: (data: Ref<NoInfer<TData>>, receivedData: any) => void
35
+ cacheDurationMs?: number
36
+ pollingIntervalMs?: number
37
+ stream?: boolean
38
+ }): UseRemoteResource<TState, TArgs>
39
+
40
+ export function defineRemoteResource<TData, TState extends object, TArgs extends any[] = []>(config: {
41
+ url: string | ((...args: TArgs) => string)
42
+ state?: (data: Ref<TData | undefined>, context: ResourceContext<TArgs>) => TState
43
+ onDataReceived?: (data: Ref<TData | undefined>, receivedData: any) => void
44
+ cacheDurationMs?: number
45
+ pollingIntervalMs?: number
46
+ stream?: boolean
47
+ }): UseRemoteResource<TState, TArgs>
48
+
49
+ export function defineRemoteResource<
50
+ TData,
51
+ TState extends object = { data: Ref<TData> },
52
+ TArgs extends any[] = [],
53
+ >(config: {
54
+ url: string | ((...args: TArgs) => string)
55
+ initialData?: () => TData
56
+ state?: (data: Ref<TData>, context: ResourceContext<TArgs>) => TState
57
+ onDataReceived?: (data: Ref<NoInfer<TData>>, receivedData: any) => void
58
+ cacheDurationMs?: number
59
+ pollingIntervalMs?: number
60
+ stream?: boolean
61
+ }) {
62
+ const cache = new Map<
63
+ string,
64
+ {
65
+ count: number
66
+ pause: VoidFunction
67
+ resume: VoidFunction
68
+ state: object
69
+ isReady: Ref<boolean>
70
+ isFetching: Ref<boolean>
71
+ lastError: Ref<Error | undefined>
72
+ hasError: ComputedRef<boolean>
73
+ }
74
+ >()
75
+
76
+ const buildUrl = typeof config.url === 'string' ? () => config.url as string : config.url
77
+
78
+ const buildData = config.initialData ?? (() => undefined as TData | undefined)
79
+
80
+ const buildState = config.state ?? ((data: Ref<TData>) => ({ data }))
81
+
82
+ const cacheDuration = config.cacheDurationMs ?? DEFAULT_CACHE_DURATION_MS
83
+
84
+ const pollingInterval = config.pollingIntervalMs ?? DEFAULT_POLLING_INTERVAL_MS
85
+
86
+ const onDataReceived =
87
+ config.onDataReceived ??
88
+ ((data: Ref<TData>, receivedData: any) => {
89
+ if (!config.stream || data.value === undefined) {
90
+ data.value = receivedData
91
+ return
92
+ }
93
+
94
+ if (Array.isArray(data.value) && Array.isArray(receivedData)) {
95
+ data.value.push(...receivedData)
96
+ return
97
+ }
98
+
99
+ merge(data.value, receivedData)
100
+ })
101
+
102
+ function subscribeToUrl(url: string) {
103
+ const entry = cache.get(url)
104
+
105
+ if (!entry) {
106
+ return
107
+ }
108
+
109
+ entry.count += 1
110
+
111
+ if (entry.count === 1) {
112
+ entry.resume()
113
+ }
114
+ }
115
+
116
+ function unsubscribeFromUrl(url: string) {
117
+ const entry = cache.get(url)
118
+
119
+ if (!entry) {
120
+ return
121
+ }
122
+
123
+ entry.count -= 1
124
+
125
+ if (entry.count > 0) {
126
+ return
127
+ }
128
+
129
+ entry.pause()
130
+
131
+ setTimeout(() => {
132
+ cache.delete(url)
133
+ }, cacheDuration)
134
+ }
135
+
136
+ function registerUrl(url: string, context: ResourceContext<TArgs>) {
137
+ if (cache.has(url)) {
138
+ return
139
+ }
140
+
141
+ const isReady = ref(false)
142
+
143
+ const isFetching = ref(false)
144
+
145
+ const lastError = ref<Error>()
146
+
147
+ const hasError = computed(() => lastError.value !== undefined)
148
+
149
+ const data = ref(buildData()) as Ref<TData>
150
+
151
+ async function execute() {
152
+ try {
153
+ isFetching.value = true
154
+
155
+ const response = await fetch(url)
156
+
157
+ if (!response.ok) {
158
+ lastError.value = Error(`Failed to fetch: ${response.statusText}`)
159
+ return
160
+ }
161
+
162
+ if (!response.body) {
163
+ return
164
+ }
165
+
166
+ if (config.stream) {
167
+ for await (const event of readNDJSONStream(response.body)) {
168
+ onDataReceived(data, event)
169
+ }
170
+ } else {
171
+ onDataReceived(data, await response.json())
172
+ }
173
+
174
+ isReady.value = true
175
+ } catch (error) {
176
+ lastError.value = error instanceof Error ? error : new Error(String(error))
177
+ } finally {
178
+ isFetching.value = false
179
+ }
180
+ }
181
+
182
+ let pause: VoidFunction = noop
183
+ let resume: VoidFunction = execute
184
+
185
+ if (pollingInterval > 0) {
186
+ const timeoutPoll = useTimeoutPoll(execute, pollingInterval, {
187
+ immediateCallback: true,
188
+ immediate: false,
189
+ })
190
+
191
+ pause = timeoutPoll.pause
192
+ resume = timeoutPoll.resume
193
+ }
194
+
195
+ const state = buildState(data, context)
196
+
197
+ cache.set(url, {
198
+ count: 0,
199
+ pause,
200
+ resume,
201
+ state,
202
+ isReady,
203
+ isFetching,
204
+ lastError,
205
+ hasError,
206
+ })
207
+ }
208
+
209
+ function initializeUrl(url: ComputedRef<string>, context: ResourceContext<TArgs>) {
210
+ watch(
211
+ url,
212
+ (toUrl, fromUrl) => {
213
+ registerUrl(toUrl, context)
214
+
215
+ if (context.isEnabled.value) {
216
+ subscribeToUrl(toUrl)
217
+ }
218
+
219
+ if (fromUrl) {
220
+ unsubscribeFromUrl(fromUrl)
221
+ }
222
+ },
223
+ { immediate: true }
224
+ )
225
+ }
226
+
227
+ return function useRemoteResource(
228
+ optionsOrParentContext?: { isEnabled?: MaybeRef<boolean>; scope?: EffectScope },
229
+ ...args: { [K in keyof TArgs]: MaybeRefOrGetter<TArgs[K]> }
230
+ ) {
231
+ const scope = optionsOrParentContext?.scope ?? getCurrentScope()
232
+
233
+ if (!scope) {
234
+ throw new Error('No effect scope found. Please provide a scope or use this function within a Vue component.')
235
+ }
236
+
237
+ const isEnabled = toRef(optionsOrParentContext?.isEnabled ?? true)
238
+
239
+ return scope.run(() => {
240
+ const url = computed(() => buildUrl(...(args.map(arg => toValue(arg)) as TArgs)))
241
+
242
+ onScopeDispose(() => {
243
+ unsubscribeFromUrl(url.value)
244
+ })
245
+
246
+ const context: ResourceContext<TArgs> = {
247
+ scope,
248
+ args,
249
+ isReady: computed(() => cache.get(url.value)?.isReady.value ?? false),
250
+ isFetching: computed(() => cache.get(url.value)?.isFetching?.value ?? false),
251
+ lastError: computed(() => cache.get(url.value)?.lastError.value),
252
+ hasError: computed(() => cache.get(url.value)?.hasError.value ?? false),
253
+ isEnabled,
254
+ enable: () => {
255
+ isEnabled.value = true
256
+ },
257
+ disable: () => {
258
+ isEnabled.value = false
259
+ },
260
+ forceReload: () => {
261
+ cache.get(url.value)?.pause()
262
+ cache.get(url.value)?.resume()
263
+ },
264
+ }
265
+
266
+ initializeUrl(url, context)
267
+
268
+ const state = reactive({} as TState)
269
+
270
+ ifElse(
271
+ isEnabled,
272
+ () => subscribeToUrl(url.value),
273
+ () => unsubscribeFromUrl(url.value)
274
+ )
275
+
276
+ watch(
277
+ url,
278
+ () => {
279
+ Object.assign(state, cache.get(url.value)!.state)
280
+ },
281
+ { immediate: true }
282
+ )
283
+
284
+ return {
285
+ ...Object.fromEntries(
286
+ Object.entries(state).map(([key, value]) =>
287
+ typeof value === 'function' ? [key, value] : [key, toRef(state, key as any)]
288
+ )
289
+ ),
290
+ $context: context,
291
+ }
292
+ })!
293
+ }
294
+ }
@@ -0,0 +1,28 @@
1
+ import type { MaybeRef } from '@vueuse/core'
2
+ import type { MaybeRefOrGetter } from '@vueuse/shared'
3
+ import type { ComputedRef, EffectScope, Ref, ToRef } from 'vue'
4
+
5
+ export type ResourceContext<TArgs extends any[]> = {
6
+ scope: EffectScope
7
+ args: { [K in keyof TArgs]: MaybeRefOrGetter<TArgs[K]> }
8
+ isReady: ComputedRef<boolean>
9
+ isFetching: ComputedRef<boolean>
10
+ hasError: ComputedRef<boolean>
11
+ lastError: ComputedRef<Error | undefined>
12
+ isEnabled: Ref<boolean>
13
+ enable: () => void
14
+ disable: () => void
15
+ forceReload: () => void
16
+ }
17
+
18
+ export type UseRemoteResource<TState, TArgs extends any[]> = (
19
+ optionsOrParentContext?: {
20
+ isEnabled?: MaybeRef<boolean>
21
+ scope?: EffectScope
22
+ },
23
+ ...args: { [K in keyof TArgs]: MaybeRefOrGetter<TArgs[K]> }
24
+ ) => {
25
+ [K in keyof TState]: TState[K] extends (...args: any[]) => any ? TState[K] : ToRef<TState[K]>
26
+ } & {
27
+ $context: ResourceContext<TArgs>
28
+ }
@@ -0,0 +1,30 @@
1
+ # `useThreshold`
2
+
3
+ `useThreshold` composable allows defining payloads for different thresholds.
4
+
5
+ It returns the payload of the highest matching threshold for that value.
6
+
7
+ ## Arguments
8
+
9
+ | Argument | Type | Required | Description |
10
+ | -------------- | -------------------------------------------------------------------- | :------: | ------------------------------------- |
11
+ | `currentValue` | `MaybeRefOrGetter<number>` | ✓ | The value to check against thresholds |
12
+ | `config` | `MaybeRefOrGetter<Record<number, TPayload> & { default: TPayload }>` | ✓ | The thresholds configuration |
13
+
14
+ ## Returns
15
+
16
+ `ComputedRef<{ value: number | undefined; payload: TPayload }>`
17
+
18
+ ## Example
19
+
20
+ ```ts
21
+ const threshold = useThreshold(value, {
22
+ 50: 'orange',
23
+ 100: 'red',
24
+ default: 'green',
25
+ })
26
+
27
+ // value = 20 → threshold = { value: undefined, payload: 'green' }
28
+ // value = 70 → threshold = { value: 50, payload: 'orange' }
29
+ // value = 130 → threshold = { value: 100, payload: 'red' }
30
+ ```
@@ -0,0 +1,3 @@
1
+ export type ThresholdConfig<TPayload> = Record<number, TPayload> & { default: TPayload }
2
+
3
+ export type ThresholdResult<TPayload> = { value: number | undefined; payload: TPayload }
@@ -0,0 +1,19 @@
1
+ import type { ThresholdConfig, ThresholdResult } from '@core/packages/threshold/type.ts'
2
+ import { computed, type ComputedRef, type MaybeRefOrGetter, toValue } from 'vue'
3
+
4
+ export function useThreshold<TPayload>(
5
+ rawCurrentValue: MaybeRefOrGetter<number>,
6
+ rawConfig: MaybeRefOrGetter<ThresholdConfig<TPayload>>
7
+ ): ComputedRef<ThresholdResult<TPayload>> {
8
+ const currentValue = computed(() => toValue(rawCurrentValue))
9
+
10
+ const config = computed(() => toValue(rawConfig))
11
+
12
+ return computed(
13
+ () =>
14
+ Object.entries(config.value)
15
+ .map(([value, payload]) => ({ value: value === 'default' ? -Infinity : Number(value), payload }))
16
+ .sort((a, b) => b.value - a.value)
17
+ .find(threshold => currentValue.value >= threshold.value)!
18
+ )
19
+ }
@@ -1,43 +1,3 @@
1
- import type { IconDefinition } from '@fortawesome/fontawesome-common-types'
2
-
3
- export type ObjectIconSize = 'extra-small' | 'small' | 'medium'
4
-
5
1
  export type VmState = 'running' | 'halted' | 'paused' | 'suspended'
6
2
 
7
3
  export type HostState = 'running' | 'halted' | 'maintenance'
8
-
9
- export type SrState = 'connected' | 'partially-connected' | 'disconnected'
10
-
11
- export type BackupRepositoryState = 'connected' | 'disconnected'
12
-
13
- export type NetworkState = 'connected' | 'disconnected'
14
-
15
- export type SupportedStateByType = {
16
- host: HostState
17
- vm: VmState
18
- sr: SrState
19
- 'backup-repository': BackupRepositoryState
20
- network: NetworkState
21
- }
22
-
23
- export type SupportedType = keyof SupportedStateByType
24
-
25
- export type SupportedState<TType extends SupportedType> = SupportedStateByType[TType]
26
-
27
- export type StatusConfig = {
28
- icon: IconDefinition
29
- color: `--${string}`
30
- translate: {
31
- x: [number, number, number]
32
- y: [number, number, number]
33
- }
34
- }
35
-
36
- export type TypeConfig<TType extends SupportedType> = {
37
- mainIcon: IconDefinition
38
- states: Record<SupportedState<TType>, StatusConfig>
39
- }
40
-
41
- export type ObjectIconConfig = {
42
- [K in SupportedType]: TypeConfig<K>
43
- }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@xen-orchestra/web-core",
3
3
  "type": "module",
4
- "version": "0.26.1",
4
+ "version": "0.28.0",
5
5
  "private": false,
6
6
  "exports": {
7
7
  "./*": {
@@ -26,7 +26,7 @@
26
26
  "human-format": "^1.2.1",
27
27
  "iterable-backoff": "^0.1.0",
28
28
  "lodash-es": "^4.17.21",
29
- "ndjson-readablestream": "^1.2.0",
29
+ "ndjson-readablestream": "^1.3.0",
30
30
  "placement.js": "^1.0.0-beta.5",
31
31
  "simple-icons": "^14.14.0",
32
32
  "vue-echarts": "^6.6.8"
@@ -1,49 +0,0 @@
1
- <template>
2
- <DisplayIcon v-if="icon" class="vts-icon" :class="className" :icon />
3
- </template>
4
-
5
- <script lang="ts" setup>
6
- import { type IconName, icons } from '@core/icons'
7
- import { DisplayIcon } from '@core/packages/icon'
8
- import { toVariants } from '@core/utils/to-variants.util.ts'
9
- import { computed } from 'vue'
10
-
11
- export type IconSize = 'small' | 'medium' | 'large' | 'current'
12
-
13
- const { size, name } = defineProps<{
14
- size: IconSize
15
- name: IconName
16
- }>()
17
-
18
- const className = computed(() =>
19
- toVariants({
20
- size: size === 'current' ? undefined : size,
21
- })
22
- )
23
-
24
- const icon = computed(() => {
25
- const icon = icons[name]
26
-
27
- if (icon === undefined) {
28
- console.warn(`Icon "${name}" not found.`)
29
- }
30
-
31
- return icon
32
- })
33
- </script>
34
-
35
- <style lang="postcss" scoped>
36
- .vts-icon {
37
- &.size--small {
38
- font-size: 1.2rem;
39
- }
40
-
41
- &.size--medium {
42
- font-size: 1.6rem;
43
- }
44
-
45
- &.size--large {
46
- font-size: 2rem;
47
- }
48
- }
49
- </style>
@@ -1,45 +0,0 @@
1
- <!-- v2 -->
2
- <template>
3
- <FontAwesomeLayers :class="toVariants({ size })" class="ui-complex-icon">
4
- <slot />
5
- </FontAwesomeLayers>
6
- </template>
7
-
8
- <script lang="ts" setup>
9
- import { toVariants } from '@core/utils/to-variants.util'
10
- import { FontAwesomeLayers } from '@fortawesome/vue-fontawesome'
11
-
12
- defineProps<{
13
- size: 'small' | 'medium' | 'large'
14
- }>()
15
- </script>
16
-
17
- <style lang="postcss" scoped>
18
- .ui-complex-icon {
19
- :nth-child(2) {
20
- font-size: 0.5em;
21
- transform: translate(100%, 80%);
22
-
23
- :deep(path) {
24
- stroke: var(--color-neutral-background-primary);
25
- stroke-width: 100px;
26
- stroke-linejoin: round;
27
- paint-order: stroke;
28
- }
29
- }
30
-
31
- /*SIZE VARIANTS*/
32
-
33
- &.size--small {
34
- font-size: 1.2rem;
35
- }
36
-
37
- &.size--medium {
38
- font-size: 1.6rem;
39
- }
40
-
41
- &.size--large {
42
- font-size: 2rem;
43
- }
44
- }
45
- </style>