@xen-orchestra/web-core 0.9.0 → 0.10.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,29 @@
1
+ <template>
2
+ <UiInfo :accent="currentStatus.accent">
3
+ {{ currentStatus.text }}
4
+ </UiInfo>
5
+ </template>
6
+
7
+ <script setup lang="ts">
8
+ import UiInfo, { type InfoAccent } from '@core/components/ui/info/UiInfo.vue'
9
+ import { computed, type ComputedRef } from 'vue'
10
+ import { useI18n } from 'vue-i18n'
11
+
12
+ type ConnectionStatus = 'connected' | 'disconnected' | 'partially-connected' | 'disconnected-from-physical-device'
13
+ type ConnectionStatusesMap = Record<ConnectionStatus, { text: string; accent: InfoAccent }>
14
+
15
+ const { status } = defineProps<{
16
+ status: ConnectionStatus
17
+ }>()
18
+
19
+ const { t } = useI18n()
20
+
21
+ const statuses: ComputedRef<ConnectionStatusesMap> = computed(() => ({
22
+ connected: { text: t('connected'), accent: 'success' },
23
+ disconnected: { text: t('disconnected'), accent: 'danger' },
24
+ 'partially-connected': { text: t('partially-connected'), accent: 'warning' },
25
+ 'disconnected-from-physical-device': { text: t('disconnected-from-physical-device'), accent: 'warning' },
26
+ }))
27
+
28
+ const currentStatus = computed(() => statuses.value[status])
29
+ </script>
@@ -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>
@@ -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 {
@@ -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>
@@ -21,6 +21,7 @@
21
21
  "core.quick-actions": "Quick actions",
22
22
 
23
23
  "core.search": "Search",
24
+ "core.show-by": "Show by",
24
25
 
25
26
  "core.query-search-bar.label": "Search Engine",
26
27
  "core.query-search-bar.placeholder": "Write your query…",
@@ -29,6 +30,7 @@
29
30
  "core.select.all": "Select all",
30
31
  "core.select.none": "Select none",
31
32
  "core.select.unselect": "Unselect all",
33
+ "core.select.n-object-of": "{from} - {to} of {total} objects",
32
34
  "core.select.n-selected-of": "{count} selected of {total} objects",
33
35
  "core.sidebar.close": "Close sidebar",
34
36
  "core.sidebar.lock": "Lock sidebar open",
@@ -43,7 +45,10 @@
43
45
  "dark-mode.auto": "Auto dark mode",
44
46
 
45
47
  "access-forum": "Access forum",
48
+ "connected": "Connected",
46
49
  "dashboard": "Dashboard",
50
+ "disconnected": "Disconnected",
51
+ "disconnected-from-physical-device": "Disconnected from physical device",
47
52
  "documentation-name": "{name} documentation",
48
53
  "error-no-data": "Error, can't collect data.",
49
54
  "exit-fullscreen": "Exit fullscreen",
@@ -61,6 +66,7 @@
61
66
  "open-console-in-new-tab": "Open console in new tab",
62
67
  "other": "Other",
63
68
  "page-not-found": "This page is not to be found…",
69
+ "partially-connected": "Partially connected",
64
70
  "patches": "Patches",
65
71
  "power-on-vm-for-console": "Power on your VM to access its console",
66
72
  "power-on-host-for-console": "Power on your host to access its console",
@@ -21,6 +21,7 @@
21
21
  "core.quick-actions": "Actions rapides",
22
22
 
23
23
  "core.search": "Rechercher",
24
+ "core.show-by": "Afficher par",
24
25
 
25
26
  "core.query-search-bar.label": "Moteur de recherche",
26
27
  "core.query-search-bar.placeholder": "Écrivez votre requête…",
@@ -29,6 +30,7 @@
29
30
  "core.select.all": "Tout sélectionner",
30
31
  "core.select.none": "Tout désélectionner",
31
32
  "core.select.unselect": "Tout désélectionner",
33
+ "core.select.n-object-of": "{from} - {to} de {total} objets",
32
34
  "core.select.n-selected-of": "{count} objet sélectionné sur {total} | {count} objet sélectionné sur {total} | {count} objets sélectionnés sur {total}",
33
35
  "core.sidebar.close": "Fermer la barre latérale",
34
36
  "core.sidebar.lock": "Verrouiller la barre latérale",
@@ -43,7 +45,10 @@
43
45
  "dark-mode.auto": "Mode sombre automatique",
44
46
 
45
47
  "access-forum": "Accès au forum",
48
+ "connected": "Connecté",
46
49
  "dashboard": "Tableau de bord",
50
+ "disconnected": "Déconnecté",
51
+ "disconnected-from-physical-device": "Déconnecté de l'appareil physique",
47
52
  "documentation-name": "Documentation {name}",
48
53
  "error-no-data": "Erreur, impossible de collecter les données.",
49
54
  "exit-fullscreen": "Quitter le plein écran",
@@ -61,6 +66,7 @@
61
66
  "open-console-in-new-tab": "Ouvrir la console dans un nouvel onglet",
62
67
  "other": "Autre",
63
68
  "page-not-found": "Cette page est introuvable…",
69
+ "partially-connected": "Partiellement connecté",
64
70
  "patches": "Patches",
65
71
  "power-on-vm-for-console": "Allumez votre VM pour accéder à sa console",
66
72
  "power-on-host-for-console": "Allumez votre hôte pour accéder à sa console",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@xen-orchestra/web-core",
3
3
  "type": "module",
4
- "version": "0.9.0",
4
+ "version": "0.10.0",
5
5
  "private": false,
6
6
  "exports": {
7
7
  "./*": {