@xen-orchestra/web-core 0.32.0 → 0.34.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.
@@ -0,0 +1,46 @@
1
+ <template>
2
+ <template v-for="(value, label) in fields" :key="label">
3
+ <VtsCardRowKeyValue v-if="isPrimitiveOrBooleanString(value)">
4
+ <template #key>
5
+ <span class="label">{{ label }}</span>
6
+ </template>
7
+ <template #value>
8
+ <template v-if="isBooleanLike(value)">
9
+ <VtsEnabledState :enabled="toBoolean(value)" />
10
+ </template>
11
+ <template v-else>
12
+ {{ value }}
13
+ </template>
14
+ </template>
15
+ <template v-if="!isBooleanLike(value)" #addons>
16
+ <VtsCopyButton :value="String(value)" />
17
+ </template>
18
+ </VtsCardRowKeyValue>
19
+ <VtsLabelValueList v-else :fields="value" />
20
+ </template>
21
+ </template>
22
+
23
+ <script lang="ts" setup>
24
+ import VtsCardRowKeyValue from '@core/components/card/VtsCardRowKeyValue.vue'
25
+ import VtsCopyButton from '@core/components/copy-button/VtsCopyButton.vue'
26
+ import VtsEnabledState from '@core/components/enabled-state/VtsEnabledState.vue'
27
+
28
+ defineProps<{
29
+ fields: Record<string, unknown> | unknown
30
+ }>()
31
+
32
+ const isBooleanString = (value: unknown): value is string => value === 'true' || value === 'false'
33
+
34
+ const isBooleanLike = (value: unknown): boolean => typeof value === 'boolean' || isBooleanString(value)
35
+
36
+ const toBoolean = (value: unknown): boolean => value === true || value === 'true'
37
+
38
+ const isPrimitiveOrBooleanString = (value: unknown): boolean =>
39
+ ['number', 'string'].includes(typeof value) || isBooleanString(value)
40
+ </script>
41
+
42
+ <style lang="postcss" scoped>
43
+ .label {
44
+ text-transform: capitalize;
45
+ }
46
+ </style>
@@ -88,13 +88,12 @@ const open = (event: MouseEvent) => {
88
88
  .menu-list {
89
89
  display: inline-flex;
90
90
  flex-direction: column;
91
- padding: 0.4rem;
92
91
  cursor: default;
93
92
  color: var(--color-neutral-txt-primary);
94
93
  border-radius: 0.4rem;
95
94
  background-color: var(--color-neutral-background-primary);
96
- gap: 0.2rem;
97
95
  z-index: 1010;
96
+ overflow: scroll;
98
97
 
99
98
  &.horizontal {
100
99
  flex-direction: row;
@@ -20,17 +20,11 @@ defineProps<{
20
20
 
21
21
  <style lang="postcss" scoped>
22
22
  .menu-trigger {
23
- font-size: 1.6rem;
24
- font-weight: 400;
25
23
  display: flex;
26
24
  align-items: center;
27
- height: 4.4rem;
28
- padding-right: 1.5rem;
29
- padding-left: 1.5rem;
30
- white-space: nowrap;
31
- border-radius: 0.8rem;
32
- gap: 1rem;
33
- background-color: var(--color-neutral-background-primary);
25
+ padding-inline: 1.6rem;
26
+ gap: 0.8rem;
27
+ height: 4.5rem;
34
28
 
35
29
  &.disabled {
36
30
  color: var(--color-neutral-txt-secondary);
@@ -40,12 +34,12 @@ defineProps<{
40
34
  cursor: pointer;
41
35
 
42
36
  &:hover {
43
- background-color: var(--color-brand-background-selected);
37
+ background-color: var(--color-brand-background-hover);
44
38
  }
45
39
 
46
40
  &:active,
47
41
  &.active {
48
- background-color: var(--color-brand-background-hover);
42
+ background-color: var(--color-brand-background-active);
49
43
  }
50
44
  }
51
45
  }
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <div class="vts-progress-bar">
3
- <UiDataRuler :max="percentageCap" :warning="threshold.payload" />
3
+ <UiDataRuler v-if="!noruler" :max="percentageCap" :warning="threshold.payload" />
4
4
  <UiProgressBar :accent="threshold.payload.accent ?? 'info'" :fill-width :legend />
5
5
  </div>
6
6
  </template>
@@ -28,9 +28,10 @@ const {
28
28
  } = defineProps<{
29
29
  current: number
30
30
  total: number
31
- label: string
31
+ label?: string
32
32
  legendType?: ProgressBarLegendType
33
33
  thresholds?: ProgressBarThresholdConfig
34
+ noruler?: boolean
34
35
  }>()
35
36
 
36
37
  const progress = useProgress(
@@ -40,7 +41,11 @@ const progress = useProgress(
40
41
 
41
42
  const { percentageCap, percentage, fillWidth } = progress
42
43
 
43
- const legend = useProgressToLegend(() => legendType, label, progress)
44
+ const legend = useProgressToLegend(
45
+ () => legendType,
46
+ () => label,
47
+ progress
48
+ )
44
49
 
45
50
  const threshold = useThreshold(percentage, () => thresholds)
46
51
  </script>
@@ -0,0 +1,79 @@
1
+ <!-- v2 -->
2
+ <template>
3
+ <nav class="ui-breadcrumb" :class="className" :aria-label="t('aria.breadcrumb.label')">
4
+ <ol>
5
+ <li v-for="child in slots.default()" :key="child.ctx.uid">
6
+ <component :is="child" />
7
+ </li>
8
+ </ol>
9
+ </nav>
10
+ </template>
11
+
12
+ <script lang="ts" setup>
13
+ import { useMapper } from '@core/packages/mapper'
14
+ import { toVariants } from '@core/utils/to-variants.util.ts'
15
+ import { computed } from 'vue'
16
+ import { useI18n } from 'vue-i18n'
17
+
18
+ const { size } = defineProps<{
19
+ size: 'small' | 'medium'
20
+ }>()
21
+
22
+ const slots = defineSlots<{
23
+ default(): any
24
+ }>()
25
+
26
+ const { t } = useI18n()
27
+
28
+ const fontWeight = useMapper(
29
+ () => size,
30
+ {
31
+ small: 'typo-body-bold-small',
32
+ medium: 'typo-body-bold',
33
+ },
34
+ 'medium'
35
+ )
36
+
37
+ const className = computed(() => [toVariants({ size }), fontWeight.value])
38
+ </script>
39
+
40
+ <style lang="postcss" scoped>
41
+ .ui-breadcrumb {
42
+ ol {
43
+ display: flex;
44
+ align-items: center;
45
+ gap: 0.8rem;
46
+ flex-wrap: wrap;
47
+ }
48
+
49
+ li {
50
+ display: flex;
51
+ align-items: center;
52
+ color: var(--color-neutral-txt-primary);
53
+ }
54
+
55
+ li:not(:last-child)::after {
56
+ content: '';
57
+ display: inline-block;
58
+ margin-inline: 0.8rem 0.4rem;
59
+ border-inline-end: 0.2rem solid var(--color-neutral-txt-secondary);
60
+ border-block-start: 0.2rem solid var(--color-neutral-txt-secondary);
61
+ transform: rotate(45deg);
62
+ vertical-align: middle;
63
+ }
64
+
65
+ &.size--small {
66
+ li:not(:last-child)::after {
67
+ width: 0.7rem;
68
+ height: 0.7rem;
69
+ }
70
+ }
71
+
72
+ &.size--medium {
73
+ li:not(:last-child)::after {
74
+ width: 0.9rem;
75
+ height: 0.9rem;
76
+ }
77
+ }
78
+ }
79
+ </style>
@@ -1,8 +1,6 @@
1
1
  <!-- v5 -->
2
2
  <template>
3
3
  <div :class="toVariants({ accent, disabled })" class="ui-input" @click.self="focus()">
4
- <UiLoader v-if="isSearching" />
5
- <VtsIcon v-else :name="icon" size="medium" class="left-icon" />
6
4
  <input
7
5
  :id="wrapperController?.id ?? id"
8
6
  ref="inputRef"
@@ -31,7 +29,6 @@
31
29
  import VtsIcon from '@core/components/icon/VtsIcon.vue'
32
30
  import UiButtonIcon from '@core/components/ui/button-icon/UiButtonIcon.vue'
33
31
  import type { LabelAccent } from '@core/components/ui/label/UiLabel.vue'
34
- import UiLoader from '@core/components/ui/loader/UiLoader.vue'
35
32
  import type { IconName } from '@core/icons'
36
33
  import { useMapper } from '@core/packages/mapper/use-mapper.ts'
37
34
  import { IK_INPUT_WRAPPER_CONTROLLER } from '@core/utils/injection-keys.util'
@@ -59,7 +56,6 @@ const {
59
56
  icon?: IconName
60
57
  rightIcon?: IconName
61
58
  clearable?: boolean
62
- isSearching?: boolean
63
59
  }>()
64
60
 
65
61
  const modelValue = defineModel<string | number>({ required: true })
@@ -117,14 +113,9 @@ defineExpose({ focus })
117
113
  min-width: 15rem;
118
114
  padding-inline: 1.6rem;
119
115
 
120
- .left-icon,
121
116
  .right-icon {
122
117
  pointer-events: none;
123
- color: var(--color-neutral-txt-secondary);
124
- }
125
-
126
- &:not(.disabled) .right-icon {
127
- color: var(--color-brand-item-base);
118
+ color: var(--color-brand-txt-base);
128
119
  }
129
120
 
130
121
  .input {
@@ -136,6 +127,10 @@ defineExpose({ focus })
136
127
  &::placeholder {
137
128
  color: var(--color-neutral-txt-secondary);
138
129
  }
130
+
131
+ &::-webkit-search-cancel-button {
132
+ -webkit-appearance: none;
133
+ }
139
134
  }
140
135
 
141
136
  /* VARIANT */
@@ -5,7 +5,9 @@
5
5
  <slot name="icon">
6
6
  <VtsIcon :name="icon" size="medium" />
7
7
  </slot>
8
- <span class="text-ellipsis"><slot /></span>
8
+ <span class="text-ellipsis">
9
+ <slot />
10
+ </span>
9
11
  </span>
10
12
  </template>
11
13
 
@@ -1,14 +1,24 @@
1
1
  <!-- v1 -->
2
2
  <template>
3
- <div class="ui-tags-list">
3
+ <div class="ui-tags-list" :class="{ nowrap }">
4
4
  <slot />
5
5
  </div>
6
6
  </template>
7
7
 
8
+ <script lang="ts" setup>
9
+ defineProps<{
10
+ nowrap?: boolean
11
+ }>()
12
+ </script>
13
+
8
14
  <style lang="postcss" scoped>
9
15
  .ui-tags-list {
10
16
  display: flex;
11
17
  flex-wrap: wrap;
12
18
  gap: 0.4rem;
13
19
  }
20
+
21
+ .nowrap {
22
+ flex-wrap: nowrap;
23
+ }
14
24
  </style>
@@ -1,13 +1,14 @@
1
1
  import { defineIconPack } from '@core/packages/icon/define-icon-pack.ts'
2
2
  import {
3
3
  faBuilding,
4
+ faCopy,
4
5
  faFile,
5
6
  faFolderClosed,
6
7
  faFolderOpen,
7
8
  faSquareCheck,
8
- faCopy,
9
9
  } from '@fortawesome/free-regular-svg-icons'
10
10
  import {
11
+ faA,
11
12
  faAlignLeft,
12
13
  faAngleDoubleLeft,
13
14
  faAngleDoubleRight,
@@ -37,6 +38,7 @@ import {
37
38
  faCircleMinus,
38
39
  faCircleNotch,
39
40
  faCirclePlay,
41
+ faCircleUser,
40
42
  faCircleXmark,
41
43
  faCity,
42
44
  faClock,
@@ -63,6 +65,7 @@ import {
63
65
  faFloppyDisk,
64
66
  faFont,
65
67
  faGear,
68
+ faHardDrive,
66
69
  faHashtag,
67
70
  faHeadset,
68
71
  faInfo,
@@ -75,6 +78,7 @@ import {
75
78
  faLockOpen,
76
79
  faMagnifyingGlass,
77
80
  faMemory,
81
+ faMessage,
78
82
  faMicrochip,
79
83
  faMinus,
80
84
  faMoon,
@@ -85,6 +89,7 @@ import {
85
89
  faPlug,
86
90
  faPlus,
87
91
  faPowerOff,
92
+ faPuzzlePiece,
88
93
  faRemove,
89
94
  faRepeat,
90
95
  faRotateLeft,
@@ -108,6 +113,7 @@ import {
108
113
  } from '@fortawesome/free-solid-svg-icons'
109
114
 
110
115
  export const faIcons = defineIconPack({
116
+ a: { icon: faA },
111
117
  'align-left': { icon: faAlignLeft },
112
118
  'angle-double-left': { icon: faAngleDoubleLeft },
113
119
  'angle-double-right': { icon: faAngleDoubleRight },
@@ -126,6 +132,7 @@ export const faIcons = defineIconPack({
126
132
  book: { icon: faBook },
127
133
  building: { icon: faBuilding },
128
134
  camera: { icon: faCamera },
135
+ calendar: { icon: faCalendar },
129
136
  'caret-down': { icon: faCaretDown },
130
137
  'caret-up': { icon: faCaretUp },
131
138
  check: { icon: faCheck },
@@ -137,9 +144,11 @@ export const faIcons = defineIconPack({
137
144
  'circle-minus': { icon: faCircleMinus },
138
145
  'circle-notch': { icon: faCircleNotch },
139
146
  'circle-play': { icon: faCirclePlay },
147
+ 'circle-user': { icon: faCircleUser },
140
148
  'circle-xmark': { icon: faCircleXmark },
141
149
  city: { icon: faCity },
142
150
  close: { icon: faClose },
151
+ clock: { icon: faClock },
143
152
  code: { icon: faCode },
144
153
  comments: { icon: faComments },
145
154
  copy: { icon: faCopy },
@@ -167,6 +176,7 @@ export const faIcons = defineIconPack({
167
176
  'folder-open': { icon: faFolderOpen },
168
177
  font: { icon: faFont },
169
178
  gear: { icon: faGear },
179
+ 'hard-drive': { icon: faHardDrive },
170
180
  hashtag: { icon: faHashtag },
171
181
  headset: { icon: faHeadset },
172
182
  info: { icon: faInfo },
@@ -179,6 +189,7 @@ export const faIcons = defineIconPack({
179
189
  'lock-open': { icon: faLockOpen },
180
190
  'magnifying-glass': { icon: faMagnifyingGlass },
181
191
  memory: { icon: faMemory },
192
+ message: { icon: faMessage },
182
193
  microchip: { icon: faMicrochip },
183
194
  minus: { icon: faMinus },
184
195
  moon: { icon: faMoon },
@@ -202,6 +213,7 @@ export const faIcons = defineIconPack({
202
213
  star: { icon: faStar },
203
214
  stop: { icon: faStop },
204
215
  tags: { icon: faTags },
216
+ template: { icon: faPuzzlePiece },
205
217
  time: { icon: faClock },
206
218
  'thumb-tack': { icon: faThumbTack },
207
219
  'thumb-tack-slash': { icon: faThumbTackSlash },
@@ -44,10 +44,17 @@ export const legacyIcons = defineIconPack({
44
44
  icon: accent === 'success' ? faCheck : faExclamation,
45
45
  },
46
46
  ]),
47
- halted: {
48
- icon: faStop,
49
- color: 'var(--color-danger-item-base)',
50
- },
47
+ halted: [
48
+ {
49
+ icon: faCircle,
50
+ color: 'var(--color-danger-item-base)',
51
+ },
52
+ {
53
+ icon: faStop,
54
+ color: 'var(--color-danger-txt-item)',
55
+ size: 8,
56
+ },
57
+ ],
51
58
  info: {
52
59
  icon: faCircleInfo,
53
60
  color: 'var(--color-info-item-base)',
@@ -68,10 +75,17 @@ export const legacyIcons = defineIconPack({
68
75
  size: 8,
69
76
  },
70
77
  ],
71
- running: {
72
- icon: faPlay,
73
- color: 'var(--color-success-item-base)',
74
- },
78
+ running: [
79
+ {
80
+ icon: faCircle,
81
+ color: 'var(--color-success-item-base)',
82
+ },
83
+ {
84
+ icon: faPlay,
85
+ color: 'var(--color-success-txt-item)',
86
+ size: 8,
87
+ },
88
+ ],
75
89
  status: defineIcon([['info', 'success', 'warning', 'danger', 'muted']], accent => [
76
90
  {
77
91
  icon: faCircle,
@@ -87,4 +101,15 @@ export const legacyIcons = defineIconPack({
87
101
  icon: faMoon,
88
102
  color: 'var(--color-info-item-base)',
89
103
  },
104
+ checked: [
105
+ {
106
+ icon: faCircle,
107
+ color: 'var(--color-success-item-base)',
108
+ },
109
+ {
110
+ icon: faCheck,
111
+ color: 'var(--color-success-txt-item)',
112
+ size: 8,
113
+ },
114
+ ],
90
115
  })