@xen-orchestra/web-core 0.1.0 → 0.2.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 (82) hide show
  1. package/lib/assets/css/_colors.pcss +148 -116
  2. package/lib/assets/css/_context.pcss +44 -44
  3. package/lib/assets/css/base.pcss +9 -8
  4. package/lib/assets/no-data.svg +67 -0
  5. package/lib/components/CardNumbers.vue +5 -5
  6. package/lib/components/LegendTitle.vue +3 -3
  7. package/lib/components/PowerStateIcon.vue +6 -6
  8. package/lib/components/UiCard.vue +2 -2
  9. package/lib/components/UiTag.vue +39 -31
  10. package/lib/components/backup-item/BackupItem.vue +5 -2
  11. package/lib/components/backup-state/BackupState.vue +4 -5
  12. package/lib/components/button/ButtonIcon.vue +40 -40
  13. package/lib/components/button/UiButton.vue +356 -93
  14. package/lib/components/card/CardSubtitle.vue +2 -2
  15. package/lib/components/card/CardTitle.vue +9 -4
  16. package/lib/components/cell-object/CellObject.vue +4 -4
  17. package/lib/components/cell-text/CellText.vue +3 -3
  18. package/lib/components/chip/ChipIcon.vue +6 -5
  19. package/lib/components/chip/UiChip.vue +20 -20
  20. package/lib/components/counter/VtsCounter.vue +147 -0
  21. package/lib/components/divider/Divider.vue +2 -2
  22. package/lib/components/donut-chart/DonutChart.vue +9 -9
  23. package/lib/components/dropdown/DropdownItem.vue +53 -73
  24. package/lib/components/dropdown/DropdownList.vue +1 -1
  25. package/lib/components/dropdown/DropdownTitle.vue +6 -6
  26. package/lib/components/head-bar/HeadBar.vue +6 -6
  27. package/lib/components/icon/ComplexIcon.vue +1 -1
  28. package/lib/components/icon/ObjectIcon.vue +19 -19
  29. package/lib/components/icon/VtsIcon.vue +96 -0
  30. package/lib/components/info/VtsInfo.vue +55 -0
  31. package/lib/components/input/UiInput.vue +22 -16
  32. package/lib/components/layout/LayoutSidebar.vue +3 -3
  33. package/lib/components/legend/LegendItem.vue +11 -11
  34. package/lib/components/menu/MenuItem.vue +4 -4
  35. package/lib/components/menu/MenuList.vue +6 -6
  36. package/lib/components/menu/MenuSeparator.vue +2 -2
  37. package/lib/components/menu/MenuTrigger.vue +6 -6
  38. package/lib/components/object-link/ObjectLink.vue +12 -12
  39. package/lib/components/query-search-bar/QuerySearchBar.vue +10 -3
  40. package/lib/components/stacked-bar/StackedBar.vue +2 -2
  41. package/lib/components/stacked-bar/StackedBarSegment.vue +6 -5
  42. package/lib/components/state-hero/NoDataHero.vue +11 -0
  43. package/lib/components/state-hero/StateHero.vue +6 -3
  44. package/lib/components/tab/TabItem.vue +11 -11
  45. package/lib/components/tab/TabList.vue +2 -2
  46. package/lib/components/table/ColumnTitle.vue +19 -16
  47. package/lib/components/table/UiTable.vue +5 -5
  48. package/lib/components/task/QuickTaskItem.vue +6 -6
  49. package/lib/components/task/QuickTaskList.vue +1 -1
  50. package/lib/components/task/QuickTaskPanel.vue +1 -1
  51. package/lib/components/task/QuickTaskTabBar.vue +22 -4
  52. package/lib/components/tooltip/TooltipItem.vue +15 -9
  53. package/lib/components/tree/TreeItemError.vue +1 -1
  54. package/lib/components/tree/TreeItemLabel.vue +12 -12
  55. package/lib/components/tree/TreeLine.vue +2 -2
  56. package/lib/components/tree/TreeLoadingItem.vue +4 -8
  57. package/lib/components/user/UserLink.vue +8 -8
  58. package/lib/components/user/UserLogo.vue +2 -2
  59. package/lib/composables/hide-route-query.composable.ts +10 -0
  60. package/lib/composables/route-query/actions/handle-delete.ts +9 -6
  61. package/lib/composables/route-query/actions/handle-set.ts +6 -4
  62. package/lib/composables/route-query/types.ts +10 -1
  63. package/lib/composables/sort-route-query.composable.ts +18 -0
  64. package/lib/composables/table/create-base-definition.ts +20 -0
  65. package/lib/composables/table/create-define-column.ts +26 -0
  66. package/lib/composables/table/create-sorting-definition.ts +48 -0
  67. package/lib/composables/table/create-visibility-definition.ts +44 -0
  68. package/lib/composables/table/type.ts +112 -0
  69. package/lib/composables/table.composable.ts +76 -0
  70. package/lib/layouts/CoreLayout.vue +3 -3
  71. package/lib/locales/en.json +1 -0
  72. package/lib/locales/fr.json +1 -0
  73. package/lib/types/backup.type.ts +1 -1
  74. package/lib/types/button.type.ts +1 -1
  75. package/lib/types/color.type.ts +2 -4
  76. package/lib/types/size.type.ts +0 -2
  77. package/lib/types/utility.type.ts +2 -0
  78. package/lib/utils/to-variants.util.ts +9 -0
  79. package/package.json +3 -3
  80. package/lib/components/UiCounter.vue +0 -89
  81. package/lib/components/icon/UiIcon.vue +0 -47
  82. package/lib/components/icon/VmIcon.vue +0 -30
@@ -17,7 +17,7 @@ withDefaults(
17
17
  <style lang="postcss" scoped>
18
18
  /* COLOR VARIANTS */
19
19
  .user-logo {
20
- --border-color: var(--color-purple-base);
20
+ --border-color: var(--color-normal-txt-base);
21
21
  }
22
22
 
23
23
  /* SIZE VARIANTS */
@@ -49,7 +49,7 @@ withDefaults(
49
49
  display: block;
50
50
  width: var(--size);
51
51
  height: var(--size);
52
- background: var(--color-grey-100) url('../../assets/user.png') no-repeat var(--background-position) /
52
+ background: var(--color-neutral-txt-primary) url('../../assets/user.png') no-repeat var(--background-position) /
53
53
  var(--background-size);
54
54
  border: var(--border-size) solid var(--border-color);
55
55
  border-radius: 20rem;
@@ -0,0 +1,10 @@
1
+ import { useRouteQuery } from '@core/composables/route-query.composable'
2
+
3
+ export function useHideRouteQuery(id: string) {
4
+ return useRouteQuery(id, {
5
+ toData: query => new Set(query ? query.split(',') : undefined),
6
+ toQuery: data => Array.from(data).join(','),
7
+ })
8
+ }
9
+
10
+ export type HideRouteQuery = ReturnType<typeof useHideRouteQuery>
@@ -4,13 +4,16 @@ export function handleDelete(source: WritableComputedRef<any>, value: any) {
4
4
  if (Array.isArray(source.value)) {
5
5
  source.value = [...source.value].splice(value, 1)
6
6
  } else if (source.value instanceof Set) {
7
- source.value = new Set(source.value)
8
- source.value.delete(value)
7
+ const newSet = new Set(source.value)
8
+ newSet.delete(value)
9
+ source.value = newSet
9
10
  } else if (source.value instanceof Map) {
10
- source.value = new Map(source.value)
11
- source.value.delete(value)
11
+ const newMap = new Map(source.value)
12
+ newMap.delete(value)
13
+ source.value = newMap
12
14
  } else if (typeof source.value === 'object' && source.value !== null) {
13
- source.value = { ...source.value }
14
- delete source.value[value]
15
+ const newObject = { ...source.value }
16
+ delete newObject[value]
17
+ source.value = newObject
15
18
  }
16
19
  }
@@ -2,11 +2,13 @@ import type { WritableComputedRef } from 'vue'
2
2
 
3
3
  export function handleSet(source: WritableComputedRef<any>, key: any, value: any) {
4
4
  if (Array.isArray(source.value)) {
5
- source.value = [...source.value]
6
- source.value[key] = value
5
+ const newArray = source.value.slice()
6
+ newArray[key] = value
7
+ source.value = newArray
7
8
  } else if (source.value instanceof Map) {
8
- source.value = new Map(source.value)
9
- source.value.set(key, value)
9
+ const newMap = new Map(source.value)
10
+ newMap.set(key, value)
11
+ source.value = newMap
10
12
  } else if (typeof source.value === 'object') {
11
13
  if (source.value === null) {
12
14
  return
@@ -39,4 +39,13 @@ export type GuessActions<TData> =
39
39
  ? MapActions<TKey, TValue>
40
40
  : EmptyObject
41
41
 
42
- export type RouteQuery<TData> = WritableComputedRef<TData> & GuessActions<TData>
42
+ export type RouteQuery<TData> = WritableComputedRef<
43
+ TData extends Set<infer V>
44
+ ? ReadonlySet<V>
45
+ : TData extends Map<infer K, infer V>
46
+ ? ReadonlyMap<K, V>
47
+ : TData extends object
48
+ ? Readonly<TData>
49
+ : TData
50
+ > &
51
+ GuessActions<TData>
@@ -0,0 +1,18 @@
1
+ import { useRouteQuery } from '@core/composables/route-query.composable'
2
+
3
+ export function useSortRouteQuery(id: string) {
4
+ return useRouteQuery(id, {
5
+ toData: query => {
6
+ if (!query) {
7
+ return undefined
8
+ }
9
+
10
+ const [id, direction] = query.split(',') as [string, 'asc' | 'desc']
11
+
12
+ return { id, direction }
13
+ },
14
+ toQuery: data => (data ? [data.id, data.direction].join(',') : ''),
15
+ })
16
+ }
17
+
18
+ export type SortRouteQuery = ReturnType<typeof useSortRouteQuery>
@@ -0,0 +1,20 @@
1
+ import type { BaseDefinition, ColumnOptions } from '@core/composables/table/type'
2
+
3
+ export function createBaseDefinition<TId extends string, TRecord>(
4
+ columnId: TId,
5
+ optionsOrGetter: any,
6
+ options: ColumnOptions<any, any, any>
7
+ ): BaseDefinition<TId, TRecord, any> {
8
+ const getter =
9
+ typeof optionsOrGetter === 'function'
10
+ ? optionsOrGetter
11
+ : typeof optionsOrGetter === 'string'
12
+ ? (item: TRecord) => item[optionsOrGetter as keyof TRecord]
13
+ : (item: TRecord) => item[columnId as unknown as keyof TRecord]
14
+
15
+ return {
16
+ id: columnId,
17
+ label: options.label,
18
+ getter,
19
+ }
20
+ }
@@ -0,0 +1,26 @@
1
+ import type { HideRouteQuery } from '@core/composables/hide-route-query.composable'
2
+ import type { SortRouteQuery } from '@core/composables/sort-route-query.composable'
3
+ import { createBaseDefinition } from '@core/composables/table/create-base-definition'
4
+ import { createSortingDefinition } from '@core/composables/table/create-sorting-definition'
5
+ import { createVisibilityDefinition } from '@core/composables/table/create-visibility-definition'
6
+ import type { ColumnDefinition, ColumnOptions, DefineColumn } from '@core/composables/table/type'
7
+ import { reactive } from 'vue'
8
+
9
+ export function createDefineColumn<TRecord>(
10
+ hideRouteQuery: HideRouteQuery,
11
+ sortRouteQuery: SortRouteQuery
12
+ ): DefineColumn<TRecord> {
13
+ return function defineColumn<TId extends string>(
14
+ columnId: TId,
15
+ optionsOrGetter: any,
16
+ optionsOrNone?: any
17
+ ): ColumnDefinition<TId, TRecord, any, any, any> {
18
+ const options = (optionsOrNone ?? optionsOrGetter) as ColumnOptions<any, any, any>
19
+
20
+ return reactive({
21
+ ...createBaseDefinition(columnId, optionsOrGetter, options),
22
+ ...createVisibilityDefinition(columnId, hideRouteQuery, options.isHideable),
23
+ ...createSortingDefinition(columnId, sortRouteQuery, options.compareFn),
24
+ })
25
+ }
26
+ }
@@ -0,0 +1,48 @@
1
+ import type { SortRouteQuery } from '@core/composables/sort-route-query.composable'
2
+ import type { CompareFn, SortingDefinition } from '@core/composables/table/type'
3
+ import { computed } from 'vue'
4
+
5
+ export function createSortingDefinition<TCompareReturn extends number | unknown>(
6
+ columnId: string,
7
+ sortRouteQuery: SortRouteQuery,
8
+ compareFn: CompareFn<any, TCompareReturn> | undefined
9
+ ): SortingDefinition<any, TCompareReturn> {
10
+ if (compareFn === undefined) {
11
+ return {
12
+ isSortable: false,
13
+ } as SortingDefinition<any, TCompareReturn>
14
+ }
15
+
16
+ const isSorted = computed(() => sortRouteQuery.value?.id === columnId)
17
+
18
+ const isSortedAsc = computed(() => isSorted.value && sortRouteQuery.value?.direction === 'asc')
19
+
20
+ const isSortedDesc = computed(() => isSorted.value && sortRouteQuery.value?.direction === 'desc')
21
+
22
+ function sort(direction: 'asc' | 'desc' | false, toggleOffIfSameDirection = false) {
23
+ const shouldToggleOff =
24
+ direction === false ||
25
+ (toggleOffIfSameDirection && isSorted.value && sortRouteQuery.value?.direction === direction)
26
+
27
+ sortRouteQuery.value = shouldToggleOff ? undefined : { id: columnId, direction }
28
+ }
29
+
30
+ function sortAsc(toggleOffIfSameDirection = false) {
31
+ sort('asc', toggleOffIfSameDirection)
32
+ }
33
+
34
+ function sortDesc(toggleOffIfSameDirection = false) {
35
+ sort('desc', toggleOffIfSameDirection)
36
+ }
37
+
38
+ return {
39
+ isSortable: true,
40
+ isSorted,
41
+ isSortedAsc,
42
+ isSortedDesc,
43
+ sort,
44
+ sortAsc,
45
+ sortDesc,
46
+ compareFn,
47
+ } as SortingDefinition<any, TCompareReturn>
48
+ }
@@ -0,0 +1,44 @@
1
+ import type { HideRouteQuery } from '@core/composables/hide-route-query.composable'
2
+ import type { VisibilityDefinition } from '@core/composables/table/type'
3
+ import { computed } from 'vue'
4
+
5
+ export function createVisibilityDefinition<THideable extends boolean | undefined>(
6
+ columnId: string,
7
+ hideRouteQuery: HideRouteQuery,
8
+ isHideable: THideable
9
+ ): VisibilityDefinition<THideable> {
10
+ if (isHideable === false) {
11
+ return {
12
+ isHideable: false,
13
+ isVisible: true,
14
+ } as VisibilityDefinition<THideable>
15
+ }
16
+
17
+ const isVisible = computed(() => !hideRouteQuery.value.has(columnId))
18
+
19
+ function show() {
20
+ hideRouteQuery.delete(columnId)
21
+ }
22
+
23
+ function hide() {
24
+ hideRouteQuery.add(columnId)
25
+ }
26
+
27
+ function toggle(value?: boolean) {
28
+ const shouldBeVisible = value ?? !isVisible.value
29
+
30
+ if (shouldBeVisible) {
31
+ show()
32
+ } else {
33
+ hide()
34
+ }
35
+ }
36
+
37
+ return {
38
+ isHideable: true,
39
+ isVisible,
40
+ show,
41
+ hide,
42
+ toggle,
43
+ } as VisibilityDefinition<THideable>
44
+ }
@@ -0,0 +1,112 @@
1
+ import type { StringKeyOf } from '@core/types/utility.type'
2
+ import type { ComputedRef, UnwrapRef } from 'vue'
3
+
4
+ export type CompareFn<TValue, TCompareReturn> = (a: TValue, b: TValue) => TCompareReturn
5
+
6
+ type Getter<TRecord, TValue> = (item: TRecord) => TValue
7
+
8
+ export type ColumnOptions<TValue, THideable extends boolean | unknown, TCompareReturn extends number | unknown> = {
9
+ label: string
10
+ isHideable?: THideable
11
+ compareFn?: CompareFn<TValue, TCompareReturn>
12
+ }
13
+
14
+ export type BaseDefinition<TId, TRecord, TValue> = {
15
+ id: TId
16
+ label: string
17
+ getter: Getter<TRecord, TValue>
18
+ }
19
+
20
+ export type VisibilityDefinition<THideable extends boolean | unknown> = THideable extends false
21
+ ? {
22
+ isHideable: false
23
+ isVisible: true
24
+ }
25
+ : {
26
+ isHideable: true
27
+ isVisible: ComputedRef<boolean>
28
+ show(): void
29
+ hide(): void
30
+ toggle(value?: boolean): void
31
+ }
32
+
33
+ export type SortingDefinition<TValue, TCompareReturn extends number | unknown> = TCompareReturn extends number
34
+ ? {
35
+ isSortable: true
36
+ isSorted: ComputedRef<boolean>
37
+ isSortedAsc: ComputedRef<boolean>
38
+ isSortedDesc: ComputedRef<boolean>
39
+ sort(direction: 'asc' | 'desc' | false, toggleOffIfSameDirection?: boolean): void
40
+ sortAsc(toggleOffIfSameDirection?: boolean): void
41
+ sortDesc(toggleOffIfSameDirection?: boolean): void
42
+ compareFn: (a: TValue, b: TValue) => TCompareReturn
43
+ }
44
+ : {
45
+ isSortable: false
46
+ }
47
+
48
+ export type ColumnDefinition<
49
+ TId,
50
+ TRecord,
51
+ TValue,
52
+ THideable extends boolean | unknown,
53
+ TCompareReturn extends number | unknown,
54
+ > = UnwrapRef<
55
+ BaseDefinition<TId, TRecord, TValue> & VisibilityDefinition<THideable> & SortingDefinition<TValue, TCompareReturn>
56
+ >
57
+
58
+ export type DefineColumn<TRecord> = {
59
+ <
60
+ const TId extends StringKeyOf<TRecord>,
61
+ TCompareReturn extends number | unknown,
62
+ THideable extends boolean | unknown,
63
+ >(
64
+ columnId: TId,
65
+ options: ColumnOptions<TRecord[TId], THideable, TCompareReturn>
66
+ ): ColumnDefinition<TId, TRecord, TRecord[TId], THideable, TCompareReturn>
67
+
68
+ <
69
+ const TId extends string,
70
+ TProperty extends keyof TRecord,
71
+ TCompareReturn extends number | unknown,
72
+ THideable extends boolean | unknown,
73
+ >(
74
+ columnId: TId,
75
+ property: TProperty,
76
+ options: ColumnOptions<TRecord[TProperty], THideable, TCompareReturn>
77
+ ): ColumnDefinition<TId, TRecord, TRecord[TProperty], THideable, TCompareReturn>
78
+
79
+ <const TId extends string, TOutput, TCompareReturn extends number | unknown, THideable extends boolean | unknown>(
80
+ columnId: TId,
81
+ getter: Getter<TRecord, TOutput>,
82
+ options: ColumnOptions<TOutput, THideable, TCompareReturn>
83
+ ): ColumnDefinition<TId, TRecord, TOutput, THideable, TCompareReturn>
84
+ }
85
+
86
+ export type TableOptions<TRecord, TRowId, TDefinition extends ColumnDefinition<any, any, any, any, any>> = {
87
+ rowId: (item: TRecord) => TRowId
88
+ columns: (define: DefineColumn<TRecord>) => TDefinition[]
89
+ }
90
+
91
+ export type RowColumn<TColumnDefinition extends ColumnDefinition<any, any, any, any, any>> =
92
+ TColumnDefinition extends ColumnDefinition<infer TColumnId, any, infer TColumnValue, any, any>
93
+ ? {
94
+ id: TColumnId
95
+ value: TColumnValue
96
+ }
97
+ : never
98
+
99
+ export type Row<TRowId, TDefinitions extends ColumnDefinition<any, any, any, any, any>[]> = {
100
+ id: TRowId
101
+ value: TDefinitions extends ColumnDefinition<any, infer TRecord, any, any, any> ? TRecord : never
102
+ visibleColumns: { [TIndex in keyof TDefinitions]: RowColumn<TDefinitions[TIndex]> }
103
+ }
104
+
105
+ export type Table<TRowId, TDefinitions extends ColumnDefinition<any, any, any, any, any>[]> = {
106
+ columns: ComputedRef<TDefinitions>
107
+ visibleColumns: ComputedRef<TDefinitions[number][]>
108
+ columnsById: ComputedRef<{
109
+ [TColumn in TDefinitions[number] as TColumn['id']]: TColumn
110
+ }>
111
+ rows: ComputedRef<Row<TRowId, TDefinitions>[]>
112
+ }
@@ -0,0 +1,76 @@
1
+ import { useHideRouteQuery } from '@core/composables/hide-route-query.composable'
2
+ import { useSortRouteQuery } from '@core/composables/sort-route-query.composable'
3
+ import { createDefineColumn } from '@core/composables/table/create-define-column'
4
+ import type { ColumnDefinition, Table, TableOptions } from '@core/composables/table/type'
5
+ import type { MaybeRefOrGetter } from 'vue'
6
+ import { computed, reactive, toValue } from 'vue'
7
+
8
+ export function useTable<TRecord, TRowId, const TDefinitions extends ColumnDefinition<any, TRecord, any, any, any>>(
9
+ id: string,
10
+ records: MaybeRefOrGetter<TRecord[]>,
11
+ options: TableOptions<TRecord, TRowId, TDefinitions>
12
+ ): Table<TRowId, TDefinitions[]> {
13
+ const hideRouteQuery = useHideRouteQuery(`table.${id}.hide`)
14
+
15
+ const sortRouteQuery = useSortRouteQuery(`table.${id}.sort`)
16
+
17
+ const defineColumn = createDefineColumn<TRecord>(hideRouteQuery, sortRouteQuery)
18
+
19
+ const columns = options.columns(defineColumn)
20
+
21
+ const columnsById = Object.fromEntries(columns.map(column => [column.id, column])) as Record<
22
+ string,
23
+ ColumnDefinition<any, TRecord, any, any, any>
24
+ >
25
+
26
+ const visibleColumns = computed(() => columns.filter(column => column.isVisible))
27
+
28
+ const rows = computed(() =>
29
+ toValue(records).map(record => {
30
+ const rowId = options.rowId(record)
31
+
32
+ const visibleRowColumns = computed(() =>
33
+ visibleColumns.value.map(column => ({
34
+ id: column.id,
35
+ value: column.getter(record),
36
+ }))
37
+ )
38
+
39
+ return reactive({
40
+ id: rowId,
41
+ value: record,
42
+ visibleColumns: visibleRowColumns,
43
+ })
44
+ })
45
+ )
46
+
47
+ const sortedRows = computed(() => {
48
+ const sort = sortRouteQuery.value
49
+
50
+ if (sort === undefined) {
51
+ return rows.value
52
+ }
53
+
54
+ const sortColumn = columnsById[sort.id]
55
+
56
+ if (sortColumn === undefined || !sortColumn.isSortable) {
57
+ return rows.value
58
+ }
59
+
60
+ const compareFn = sortColumn.compareFn
61
+
62
+ return rows.value.slice().sort((row1, row2) => {
63
+ const value1 = sortColumn.getter(row1.value as TRecord)
64
+ const value2 = sortColumn.getter(row2.value as TRecord)
65
+
66
+ return sort.direction === 'asc' ? compareFn(value1, value2) : compareFn(value2, value1)
67
+ })
68
+ })
69
+
70
+ return {
71
+ columns: computed(() => columns),
72
+ columnsById: computed(() => columnsById),
73
+ visibleColumns,
74
+ rows: sortedRows,
75
+ } as Table<TRowId, TDefinitions[]>
76
+ }
@@ -61,8 +61,8 @@ const sidebarStore = useSidebarStore()
61
61
  display: flex;
62
62
  align-items: center;
63
63
  height: 5.6rem;
64
- background-color: var(--background-color-secondary);
65
- border-bottom: 0.1rem solid var(--color-grey-500);
64
+ background-color: var(--color-neutral-background-secondary);
65
+ border-bottom: 0.1rem solid var(--color-neutral-border);
66
66
  flex-shrink: 0;
67
67
  gap: 1.6rem;
68
68
  padding: 0 1.6rem;
@@ -77,6 +77,6 @@ const sidebarStore = useSidebarStore()
77
77
  overflow: auto;
78
78
  display: flex;
79
79
  flex-direction: column;
80
- background-color: var(--background-color-secondary);
80
+ background-color: var(--color-neutral-background-secondary);
81
81
  }
82
82
  </style>
@@ -47,6 +47,7 @@
47
47
  "master": "Primary host",
48
48
  "n-vms": "1 VM | {n} VMs",
49
49
  "network": "Network",
50
+ "no-data": "No data",
50
51
  "object-not-found": "Object {id} can't be found…",
51
52
  "patches": "Patches",
52
53
  "power-on-for-console": "Power on your VM to access its console",
@@ -47,6 +47,7 @@
47
47
  "master": "Hôte primaire",
48
48
  "n-vms": "1 VM | {n} VMs",
49
49
  "network": "Réseau",
50
+ "no-data": "Aucune donnée",
50
51
  "object-not-found": "L'objet {id} est introuvable…",
51
52
  "patches": "Patches",
52
53
  "power-on-for-console": "Allumez votre VM pour accéder à sa console",
@@ -6,6 +6,6 @@ export type BackupStates = BackupState[]
6
6
 
7
7
  export type Backup = {
8
8
  label: string
9
- route: RouteLocationRaw
9
+ route?: RouteLocationRaw
10
10
  states: BackupStates
11
11
  }
@@ -1,3 +1,3 @@
1
1
  export type ButtonLevel = 'primary' | 'secondary' | 'tertiary'
2
2
 
3
- export type ButtonSize = 'extra-small' | 'small' | 'medium'
3
+ export type ButtonSize = 'small' | 'medium' | 'large'
@@ -1,5 +1,3 @@
1
- export type Color = 'info' | 'error' | 'danger' | 'warning' | 'success'
1
+ export type Color = 'normal' | 'success' | 'warning' | 'danger'
2
2
 
3
- export type CounterColor = Color | 'black'
4
-
5
- export type TagColor = Color | 'grey'
3
+ export type TagColor = 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'disabled'
@@ -1,3 +1 @@
1
- export type CounterSize = 'small' | 'medium'
2
-
3
1
  export type UserLogoSize = 'extra-small' | 'small' | 'medium'
@@ -7,3 +7,5 @@ declare const __brand: unique symbol
7
7
  export type Branded<TBrand extends string, TType = string> = TType & { [__brand]: TBrand }
8
8
 
9
9
  export type EmptyObject = Record<string, never>
10
+
11
+ export type StringKeyOf<T> = Extract<keyof T, string>
@@ -0,0 +1,9 @@
1
+ export function toVariants(variants: object): string[] {
2
+ return Object.entries(variants).flatMap(([key, value]) => {
3
+ if (!value) {
4
+ return []
5
+ }
6
+
7
+ return value === true ? key : `${key}--${value}`
8
+ })
9
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@xen-orchestra/web-core",
3
3
  "type": "module",
4
- "version": "0.1.0",
4
+ "version": "0.2.0",
5
5
  "private": false,
6
6
  "exports": {
7
7
  "./*": {
@@ -24,7 +24,7 @@
24
24
  },
25
25
  "peerDependencies": {
26
26
  "pinia": "^2.1.7",
27
- "vue": "^3.4.13",
27
+ "vue": "~3.4.13",
28
28
  "vue-i18n": "^9.9.0",
29
29
  "vue-router": "^4.4.0"
30
30
  },
@@ -33,7 +33,7 @@
33
33
  "@types/novnc__novnc": "^1.5.0",
34
34
  "@vue/tsconfig": "^0.5.1",
35
35
  "pinia": "^2.1.7",
36
- "vue": "^3.4.13",
36
+ "vue": "~3.4.13",
37
37
  "vue-i18n": "^9.9.0",
38
38
  "vue-router": "^4.4.0"
39
39
  },
@@ -1,89 +0,0 @@
1
- <!-- v1.0 -->
2
- <template>
3
- <span :class="classNames" class="ui-counter typo">
4
- <span class="inner">{{ value }}</span>
5
- </span>
6
- </template>
7
-
8
- <script lang="ts" setup>
9
- import type { CounterColor } from '@core/types/color.type'
10
- import type { CounterSize } from '@core/types/size.type'
11
- import { computed } from 'vue'
12
-
13
- const props = withDefaults(
14
- defineProps<{
15
- value: number | string
16
- color?: CounterColor
17
- size?: CounterSize
18
- }>(),
19
- { size: 'small' }
20
- )
21
-
22
- const fontClasses = {
23
- small: 'p4-semi-bold',
24
- medium: 'p1-medium',
25
- }
26
-
27
- const classNames = computed(() => {
28
- return [props.color, props.size, fontClasses[props.size]]
29
- })
30
- </script>
31
-
32
- <style lang="postcss" scoped>
33
- /* COLOR VARIANTS */
34
- .ui-counter {
35
- --background-color: var(--color-grey-300);
36
-
37
- &.info {
38
- --background-color: var(--color-purple-base);
39
- }
40
-
41
- &.success {
42
- --background-color: var(--color-green-base);
43
- }
44
-
45
- &.warning {
46
- --background-color: var(--color-orange-base);
47
- }
48
-
49
- &:is(.error, .danger) {
50
- --background-color: var(--color-red-base);
51
- }
52
-
53
- &.black {
54
- --background-color: var(--color-grey-100);
55
- }
56
- }
57
-
58
- /* SIZE VARIANTS */
59
- .ui-counter {
60
- &.small {
61
- --height: 1.5rem;
62
- --padding: 0 0.4rem;
63
- }
64
-
65
- &.medium {
66
- --height: 2.4rem;
67
- --padding: 0 0.6rem;
68
- }
69
- }
70
-
71
- /* IMPLEMENTATION */
72
- .ui-counter {
73
- display: inline-flex;
74
- align-items: center;
75
- justify-content: center;
76
- vertical-align: middle;
77
- text-transform: lowercase;
78
- color: var(--color-grey-600);
79
- height: var(--height);
80
- min-width: var(--height);
81
- padding: var(--padding);
82
- background-color: var(--background-color);
83
- border-radius: calc(var(--height) / 2);
84
-
85
- .inner {
86
- line-height: 0;
87
- }
88
- }
89
- </style>