@xen-orchestra/web-core 0.9.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/lib/components/charts/LinearChart.md +33 -0
  2. package/lib/components/charts/LinearChart.vue +77 -0
  3. package/lib/components/connection-status/VtsConnectionStatus.vue +33 -0
  4. package/lib/components/console/VtsActionsConsole.vue +26 -12
  5. package/lib/components/console/VtsRemoteConsole.vue +58 -16
  6. package/lib/components/data-table/VtsDataTable.vue +58 -0
  7. package/lib/components/menu/MenuItem.vue +9 -13
  8. package/lib/components/menu/MenuList.vue +15 -13
  9. package/lib/components/tab/TabItem.vue +3 -4
  10. package/lib/components/tab/TabList.vue +5 -9
  11. package/lib/components/table/ColumnTitle.vue +1 -1
  12. package/lib/components/ui/account-menu-button/UiAccountMenuButton.vue +2 -3
  13. package/lib/components/ui/button/UiButton.vue +11 -17
  14. package/lib/components/ui/checkbox/UiCheckbox.vue +11 -15
  15. package/lib/components/ui/dropdown-button/UiDropdownButton.vue +9 -13
  16. package/lib/components/ui/info/UiInfo.vue +9 -11
  17. package/lib/components/ui/input/UiInput.vue +1 -0
  18. package/lib/components/ui/label/UiLabel.vue +11 -19
  19. package/lib/components/ui/radio-button/UiRadioButton.vue +12 -15
  20. package/lib/components/ui/table-pagination/PaginationButton.vue +33 -0
  21. package/lib/components/ui/table-pagination/UiTablePagination.vue +178 -0
  22. package/lib/components/ui/toggle/UiToggle.vue +6 -10
  23. package/lib/composables/chart-theme.composable.ts +382 -0
  24. package/lib/composables/disabled.composable.ts +15 -0
  25. package/lib/composables/route-query/types.ts +3 -2
  26. package/lib/i18n.ts +53 -0
  27. package/lib/layouts/CoreLayout.vue +20 -13
  28. package/lib/locales/en.json +6 -0
  29. package/lib/locales/es.json +97 -0
  30. package/lib/locales/fr.json +6 -0
  31. package/lib/types/chart.ts +9 -0
  32. package/lib/utils/injection-keys.util.ts +5 -0
  33. package/package.json +7 -2
  34. package/lib/context.ts +0 -10
@@ -1,16 +1,16 @@
1
1
  <!-- v3 -->
2
2
  <template>
3
- <label class="ui-checkbox" :class="classNames" v-bind="wrapperAttrs">
3
+ <label :class="classNames" class="ui-checkbox" v-bind="wrapperAttrs">
4
4
  <input
5
5
  v-model="checkboxModel"
6
6
  :class="{ indeterminate: isIndeterminate }"
7
7
  :disabled="isDisabled"
8
- type="checkbox"
9
8
  class="input"
9
+ type="checkbox"
10
10
  v-bind="attrs"
11
11
  />
12
12
  <span class="fake-checkbox">
13
- <VtsIcon :icon class="icon" accent="info" />
13
+ <VtsIcon :icon accent="info" class="icon" />
14
14
  </span>
15
15
  <span v-if="slots.default" class="typo p1-regular">
16
16
  <slot />
@@ -24,8 +24,7 @@
24
24
  <script lang="ts" setup>
25
25
  import VtsIcon from '@core/components/icon/VtsIcon.vue'
26
26
  import UiInfo from '@core/components/ui/info/UiInfo.vue'
27
- import { useContext } from '@core/composables/context.composable'
28
- import { DisabledContext } from '@core/context'
27
+ import { useDisabled } from '@core/composables/disabled.composable'
29
28
  import { toVariants } from '@core/utils/to-variants.util'
30
29
  import { faCheck, faMinus } from '@fortawesome/free-solid-svg-icons'
31
30
  import { computed, type LabelHTMLAttributes, useAttrs } from 'vue'
@@ -34,23 +33,20 @@ type CheckboxAccent = 'info' | 'success' | 'warning' | 'danger'
34
33
 
35
34
  defineOptions({ inheritAttrs: false })
36
35
 
37
- const props = withDefaults(
38
- defineProps<{
39
- accent: CheckboxAccent
40
- disabled?: boolean
41
- wrapperAttrs?: LabelHTMLAttributes
42
- }>(),
43
- { disabled: undefined }
44
- )
36
+ const props = defineProps<{
37
+ accent: CheckboxAccent
38
+ disabled?: boolean
39
+ wrapperAttrs?: LabelHTMLAttributes
40
+ }>()
45
41
 
46
- const checkboxModel = defineModel<boolean | undefined>({ default: undefined })
42
+ const checkboxModel = defineModel<boolean | undefined | string[]>({ default: undefined })
47
43
 
48
44
  const slots = defineSlots<{
49
45
  default?(): any
50
46
  info?(): any
51
47
  }>()
52
48
 
53
- const isDisabled = useContext(DisabledContext, () => props.disabled)
49
+ const isDisabled = useDisabled(() => props.disabled)
54
50
 
55
51
  const classNames = computed(() => [
56
52
  toVariants({
@@ -1,6 +1,6 @@
1
1
  <!-- v3 -->
2
2
  <template>
3
- <button type="button" class="ui-dropdown-item" :class="{ selected }" :disabled="isDisabled">
3
+ <button :class="{ selected }" :disabled="isDisabled" class="ui-dropdown-item" type="button">
4
4
  <VtsIcon :icon accent="current" class="left-icon" fixed-width />
5
5
  <span class="typo p1-regular label">
6
6
  <slot />
@@ -11,24 +11,20 @@
11
11
 
12
12
  <script lang="ts" setup>
13
13
  import VtsIcon from '@core/components/icon/VtsIcon.vue'
14
- import { useContext } from '@core/composables/context.composable'
15
- import { DisabledContext } from '@core/context'
14
+ import { useDisabled } from '@core/composables/disabled.composable'
16
15
  import type { IconDefinition } from '@fortawesome/fontawesome-common-types'
17
16
  import { faAngleDown } from '@fortawesome/free-solid-svg-icons'
18
17
 
19
- const props = withDefaults(
20
- defineProps<{
21
- disabled?: boolean
22
- selected?: boolean
23
- icon?: IconDefinition
24
- }>(),
25
- { disabled: undefined }
26
- )
18
+ const { disabled, selected, icon } = defineProps<{
19
+ disabled?: boolean
20
+ selected?: boolean
21
+ icon?: IconDefinition
22
+ }>()
27
23
 
28
- const isDisabled = useContext(DisabledContext, () => props.disabled)
24
+ const isDisabled = useDisabled(() => disabled)
29
25
  </script>
30
26
 
31
- <style scoped lang="postcss">
27
+ <style lang="postcss" scoped>
32
28
  .ui-dropdown-item {
33
29
  display: inline-flex;
34
30
  align-items: center;
@@ -2,7 +2,7 @@
2
2
  <template>
3
3
  <div class="ui-info">
4
4
  <VtsIcon :accent class="icon" :icon="faCircle" :overlay-icon="icon" />
5
- <p class="message">
5
+ <p v-tooltip="!wrap" class="typo p3-regular" :class="{ 'text-ellipsis': !wrap }">
6
6
  <slot />
7
7
  </p>
8
8
  </div>
@@ -10,6 +10,7 @@
10
10
 
11
11
  <script lang="ts" setup>
12
12
  import VtsIcon from '@core/components/icon/VtsIcon.vue'
13
+ import { vTooltip } from '@core/directives/tooltip.directive'
13
14
  import {
14
15
  faCheck,
15
16
  faCircle,
@@ -20,24 +21,25 @@ import {
20
21
  } from '@fortawesome/free-solid-svg-icons'
21
22
  import { computed } from 'vue'
22
23
 
23
- type Props = {
24
- accent: 'info' | 'success' | 'warning' | 'danger'
25
- }
24
+ export type InfoAccent = 'info' | 'success' | 'warning' | 'danger'
26
25
 
27
- const props = defineProps<Props>()
26
+ const { accent } = defineProps<{
27
+ accent: InfoAccent
28
+ wrap?: boolean
29
+ }>()
28
30
 
29
31
  defineSlots<{
30
32
  default(): any
31
33
  }>()
32
34
 
33
- const iconByAccent: Record<Props['accent'], IconDefinition> = {
35
+ const iconByAccent: Record<InfoAccent, IconDefinition> = {
34
36
  info: faInfo,
35
37
  success: faCheck,
36
38
  warning: faExclamation,
37
39
  danger: faXmark,
38
40
  }
39
41
 
40
- const icon = computed(() => iconByAccent[props.accent])
42
+ const icon = computed(() => iconByAccent[accent])
41
43
  </script>
42
44
 
43
45
  <style lang="postcss" scoped>
@@ -49,9 +51,5 @@ const icon = computed(() => iconByAccent[props.accent])
49
51
  .icon {
50
52
  font-size: 1.6rem;
51
53
  }
52
-
53
- .message {
54
- font-size: 1.2rem;
55
- }
56
54
  }
57
55
  </style>
@@ -70,6 +70,7 @@ const labelAccent = computed(() => (accent === 'info' ? 'neutral' : accent))
70
70
  display: flex;
71
71
  flex-direction: column;
72
72
  gap: 0.4rem;
73
+ flex: 1;
73
74
 
74
75
  .input {
75
76
  border-radius: 0.4rem;
@@ -1,24 +1,23 @@
1
- <!-- WIP -->
1
+ <!-- v1 -->
2
2
  <template>
3
3
  <div :class="toVariants({ accent })" class="ui-label">
4
- <VtsIcon accent="current" :icon class="left-icon" />
5
- <span :class="{ required }" class="typo c2-semi-bold label"><slot /></span>
6
- <!-- @TODO: Replace it by the VtsLink component when available -->
7
- <a v-if="href" :href class="link">
8
- <span class="typo p3-regular-underline">{{ $t('learn-more') }}</span>
9
- <VtsIcon accent="current" :icon="faUpRightFromSquare" class="link-icon" />
10
- </a>
4
+ <VtsIcon accent="current" :icon class="icon" />
5
+ <label :for="htmlFor" :class="{ required }" class="typo c2-semi-bold label">
6
+ <slot />
7
+ </label>
8
+ <UiLink v-if="href" class="learn-more-link" size="small" :href>{{ $t('learn-more') }}</UiLink>
11
9
  </div>
12
10
  </template>
13
11
 
14
12
  <script lang="ts" setup>
15
13
  import VtsIcon from '@core/components/icon/VtsIcon.vue'
14
+ import UiLink from '@core/components/ui/link/UiLink.vue'
16
15
  import { toVariants } from '@core/utils/to-variants.util'
17
16
  import type { IconDefinition } from '@fortawesome/fontawesome-common-types'
18
- import { faUpRightFromSquare } from '@fortawesome/free-solid-svg-icons'
19
17
 
20
- defineProps<{
18
+ const { for: htmlFor } = defineProps<{
21
19
  accent: 'neutral' | 'warning' | 'danger'
20
+ for?: string
22
21
  icon?: IconDefinition
23
22
  required?: boolean
24
23
  href?: string
@@ -30,7 +29,7 @@ defineProps<{
30
29
  display: flex;
31
30
  align-items: center;
32
31
 
33
- .left-icon {
32
+ .icon {
34
33
  margin-right: 0.8rem;
35
34
  }
36
35
 
@@ -42,17 +41,10 @@ defineProps<{
42
41
  }
43
42
  }
44
43
 
45
- .link {
46
- display: flex;
47
- align-items: center;
48
- gap: 0.8rem;
44
+ .learn-more-link {
49
45
  margin-left: auto;
50
46
  }
51
47
 
52
- .link-icon {
53
- font-size: 0.8rem;
54
- }
55
-
56
48
  /* ACCENT VARIANTS */
57
49
 
58
50
  &.accent--neutral {
@@ -2,7 +2,7 @@
2
2
  <template>
3
3
  <label :class="variant" class="ui-radio-button typo p1-regular">
4
4
  <span class="radio-container">
5
- <input v-model="model" :value :disabled="isDisabled" class="input" type="radio" />
5
+ <input v-model="model" :disabled="isDisabled" :value class="input" type="radio" />
6
6
  <VtsIcon :icon="faCircle" accent="current" class="radio-icon" />
7
7
  </span>
8
8
  <slot />
@@ -11,31 +11,26 @@
11
11
 
12
12
  <script lang="ts" setup>
13
13
  import VtsIcon from '@core/components/icon/VtsIcon.vue'
14
- import { useContext } from '@core/composables/context.composable'
15
- import { DisabledContext } from '@core/context'
14
+ import { useDisabled } from '@core/composables/disabled.composable'
16
15
  import { toVariants } from '@core/utils/to-variants.util'
17
16
  import { faCircle } from '@fortawesome/free-solid-svg-icons'
18
17
  import { computed } from 'vue'
19
18
 
20
- const props = withDefaults(
21
- defineProps<{
22
- accent: 'info' | 'success' | 'warning' | 'danger'
23
- value: any
24
- disabled?: boolean
25
- }>(),
26
- {
27
- disabled: undefined,
28
- }
29
- )
19
+ const { accent, value, disabled } = defineProps<{
20
+ accent: 'info' | 'success' | 'warning' | 'danger'
21
+ value: any
22
+ disabled?: boolean
23
+ }>()
24
+
30
25
  const model = defineModel<boolean>()
31
26
 
32
27
  defineSlots<{
33
28
  default(): any
34
29
  }>()
35
30
 
36
- const variant = computed(() => toVariants({ accent: props.accent }))
31
+ const variant = computed(() => toVariants({ accent }))
37
32
 
38
- const isDisabled = useContext(DisabledContext, () => props.disabled)
33
+ const isDisabled = useDisabled(() => disabled)
39
34
  </script>
40
35
 
41
36
  <style lang="postcss" scoped>
@@ -60,6 +55,7 @@ const isDisabled = useContext(DisabledContext, () => props.disabled)
60
55
 
61
56
  &:has(input:focus-visible) {
62
57
  outline: none;
58
+
63
59
  &::after {
64
60
  position: absolute;
65
61
  content: '';
@@ -68,6 +64,7 @@ const isDisabled = useContext(DisabledContext, () => props.disabled)
68
64
  border-radius: 0.4rem;
69
65
  }
70
66
  }
67
+
71
68
  &:has(.input:disabled) {
72
69
  cursor: not-allowed;
73
70
 
@@ -0,0 +1,33 @@
1
+ <template>
2
+ <UiButtonIcon :disabled accent="info" class="pagination-button" size="small" :icon />
3
+ </template>
4
+
5
+ <script setup lang="ts">
6
+ import UiButtonIcon from '@core/components/ui/button-icon/UiButtonIcon.vue'
7
+ import type { IconDefinition } from '@fortawesome/fontawesome-common-types'
8
+
9
+ const { disabled, icon } = defineProps<{
10
+ disabled: boolean
11
+ icon: IconDefinition
12
+ }>()
13
+ </script>
14
+
15
+ <style scoped lang="postcss">
16
+ .pagination-button.accent--info {
17
+ border: 0.1rem solid var(--color-neutral-border);
18
+ font-size: 1rem;
19
+
20
+ &:hover {
21
+ border-color: var(--color-info-item-hover);
22
+ }
23
+
24
+ &:active {
25
+ border-color: var(--color-info-item-active);
26
+ }
27
+
28
+ &:disabled {
29
+ background-color: var(--color-neutral-background-disabled);
30
+ border-color: transparent;
31
+ }
32
+ }
33
+ </style>
@@ -0,0 +1,178 @@
1
+ <!-- v2 -->
2
+ <template>
3
+ <div class="ui-table-pagination">
4
+ <div class="buttons-container">
5
+ <PaginationButton :disabled="isFirstPage || disabled" :icon="faAngleDoubleLeft" @click="goToFirstPage()" />
6
+ <PaginationButton :disabled="isFirstPage || disabled" :icon="faAngleLeft" @click="goToPreviousPage()" />
7
+ <PaginationButton :disabled="isLastPage || disabled" :icon="faAngleRight" @click="goToNextPage()" />
8
+ <PaginationButton :disabled="isLastPage || disabled" :icon="faAngleDoubleRight" @click="goToLastPage()" />
9
+ </div>
10
+ <span class="typo p3-regular label">
11
+ {{ $t('core.select.n-object-of', { from: startIndex, to: endIndex, total: totalItems }) }}
12
+ </span>
13
+ <span class="typo p3-regular label show">{{ $t('core.show-by') }}</span>
14
+ <div class="dropdown-wrapper">
15
+ <select v-model="pageSize" :disabled class="dropdown typo c3-regular" @change="goToFirstPage">
16
+ <option v-for="option in pageSizeOptions" :key="option" :value="option" class="typo p2-medium">
17
+ {{ option }}
18
+ </option>
19
+ </select>
20
+ <VtsIcon class="icon" accent="current" :icon="faAngleDown" />
21
+ </div>
22
+ </div>
23
+ </template>
24
+
25
+ <script setup lang="ts">
26
+ import VtsIcon from '@core/components/icon/VtsIcon.vue'
27
+ import PaginationButton from '@core/components/ui/table-pagination/PaginationButton.vue'
28
+ import {
29
+ faAngleDoubleLeft,
30
+ faAngleDoubleRight,
31
+ faAngleDown,
32
+ faAngleLeft,
33
+ faAngleRight,
34
+ } from '@fortawesome/free-solid-svg-icons'
35
+ import { useOffsetPagination } from '@vueuse/core'
36
+ import { computed, ref, watch } from 'vue'
37
+
38
+ export type PaginationPayload = {
39
+ currentPage: number
40
+ pageSize: number
41
+ startIndex: number
42
+ endIndex: number
43
+ }
44
+
45
+ const { totalItems, disabled = false } = defineProps<{
46
+ totalItems: number
47
+ disabled?: boolean
48
+ }>()
49
+
50
+ const emit = defineEmits<{
51
+ change: [payload: PaginationPayload]
52
+ }>()
53
+
54
+ const pageSize = ref(50)
55
+ const pageSizeOptions = [10, 50, 100, 150, 200]
56
+ const {
57
+ currentPage,
58
+ currentPageSize,
59
+ pageCount,
60
+ isFirstPage,
61
+ isLastPage,
62
+ prev: goToPreviousPage,
63
+ next: goToNextPage,
64
+ } = useOffsetPagination({
65
+ total: () => totalItems,
66
+ pageSize,
67
+ })
68
+ const startIndex = computed(() => (currentPage.value - 1) * currentPageSize.value + 1)
69
+ const endIndex = computed(() => Math.min(currentPage.value * currentPageSize.value, totalItems))
70
+
71
+ const goToFirstPage = () => {
72
+ currentPage.value = 1
73
+ }
74
+ const goToLastPage = () => {
75
+ currentPage.value = pageCount.value
76
+ }
77
+
78
+ watch([currentPage, currentPageSize], ([newPage, newPageSize]) => {
79
+ emit('change', {
80
+ currentPage: newPage,
81
+ pageSize: newPageSize,
82
+ startIndex: startIndex.value,
83
+ endIndex: endIndex.value,
84
+ })
85
+ })
86
+ </script>
87
+
88
+ <style scoped lang="postcss">
89
+ .ui-table-pagination {
90
+ display: flex;
91
+ align-items: center;
92
+ gap: 0.8rem;
93
+
94
+ .buttons-container {
95
+ display: flex;
96
+ gap: 0.2rem;
97
+ }
98
+
99
+ .label {
100
+ color: var(--color-neutral-txt-secondary);
101
+ }
102
+
103
+ .show::before {
104
+ content: '-';
105
+ margin-right: 0.8rem;
106
+ }
107
+
108
+ .dropdown-wrapper {
109
+ position: relative;
110
+
111
+ .dropdown {
112
+ cursor: pointer;
113
+ padding: 0.2rem 0.6rem;
114
+ height: 2.6rem;
115
+ width: 4.8rem;
116
+ appearance: none;
117
+ border-radius: 0.4rem;
118
+ color: var(--color-info-txt-base);
119
+ border: 0.1rem solid var(--color-neutral-border);
120
+ background-color: var(--color-neutral-background-primary);
121
+
122
+ &:hover {
123
+ border-color: var(--color-info-item-hover);
124
+ background-color: var(--color-info-background-hover);
125
+ color: var(--color-info-txt-hover);
126
+
127
+ + .icon {
128
+ color: var(--color-info-txt-hover);
129
+ }
130
+ }
131
+
132
+ &:disabled {
133
+ cursor: not-allowed;
134
+ background-color: var(--color-neutral-background-disabled);
135
+ color: var(--color-neutral-txt-secondary);
136
+ border-color: transparent;
137
+
138
+ + .icon {
139
+ color: var(--color-neutral-txt-secondary);
140
+ }
141
+ }
142
+
143
+ &:active {
144
+ background-color: var(--color-info-background-active);
145
+ border-color: var(--color-info-item-active);
146
+ }
147
+
148
+ &:focus-visible {
149
+ outline: 0.1rem solid var(--color-info-item-base);
150
+ border: 0.1rem solid var(--color-info-item-base);
151
+ color: var(--color-info-txt-base);
152
+ background-color: var(--color-info-background-selected);
153
+
154
+ + .icon {
155
+ color: var(--color-info-txt-base);
156
+ }
157
+ }
158
+
159
+ option {
160
+ background-color: var(--color-neutral-background-primary);
161
+ border: 0.1rem solid var(--color-neutral-border);
162
+ border-radius: 0.4rem;
163
+ color: var(--color-neutral-txt-primary);
164
+ }
165
+ }
166
+
167
+ .icon {
168
+ position: absolute;
169
+ top: 50%;
170
+ right: 0.8rem;
171
+ transform: translateY(-50%);
172
+ pointer-events: none;
173
+ font-size: 1rem;
174
+ color: var(--color-info-txt-base);
175
+ }
176
+ }
177
+ }
178
+ </style>
@@ -13,16 +13,12 @@
13
13
 
14
14
  <script lang="ts" setup>
15
15
  import UiLoader from '@core/components/ui/loader/UiLoader.vue'
16
- import { useContext } from '@core/composables/context.composable'
17
- import { DisabledContext } from '@core/context'
16
+ import { useDisabled } from '@core/composables/disabled.composable'
18
17
 
19
- const props = withDefaults(
20
- defineProps<{
21
- disabled?: boolean
22
- busy?: boolean
23
- }>(),
24
- { disabled: undefined }
25
- )
18
+ const { busy, disabled } = defineProps<{
19
+ disabled?: boolean
20
+ busy?: boolean
21
+ }>()
26
22
 
27
23
  const checked = defineModel<boolean>()
28
24
 
@@ -30,7 +26,7 @@ defineSlots<{
30
26
  default(): any
31
27
  }>()
32
28
 
33
- const isDisabled = useContext(DisabledContext, () => props.disabled)
29
+ const isDisabled = useDisabled(() => disabled)
34
30
  </script>
35
31
 
36
32
  <style lang="postcss" scoped>