@xen-orchestra/web-core 0.15.0 → 0.16.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.
- package/lib/components/connection-status/VtsConnectionStatus.vue +3 -0
- package/lib/components/console/VtsClipboardConsole.vue +2 -2
- package/lib/components/ui/character-limit/UiCharacterLimit.vue +35 -0
- package/lib/components/ui/input/UiInput.vue +7 -8
- package/lib/components/ui/query-search-bar/UiQuerySearchBar.vue +1 -1
- package/lib/components/ui/{input → text-area}/UiTextarea.vue +54 -12
- package/lib/locales/en.json +12 -0
- package/lib/locales/fr.json +12 -0
- package/package.json +1 -1
|
@@ -14,6 +14,7 @@ export type ConnectionStatus =
|
|
|
14
14
|
| 'disconnected'
|
|
15
15
|
| 'partially-connected'
|
|
16
16
|
| 'disconnected-from-physical-device'
|
|
17
|
+
| 'physically-disconnected'
|
|
17
18
|
type ConnectionStatusesMap = Record<ConnectionStatus, { text: string; accent: InfoAccent }>
|
|
18
19
|
|
|
19
20
|
const { status } = defineProps<{
|
|
@@ -27,6 +28,8 @@ const statuses: ComputedRef<ConnectionStatusesMap> = computed(() => ({
|
|
|
27
28
|
disconnected: { text: t('disconnected'), accent: 'danger' },
|
|
28
29
|
'partially-connected': { text: t('partially-connected'), accent: 'warning' },
|
|
29
30
|
'disconnected-from-physical-device': { text: t('disconnected-from-physical-device'), accent: 'warning' },
|
|
31
|
+
// This status is used in host pif side panel
|
|
32
|
+
'physically-disconnected': { text: t('disconnected-from-physical-device'), accent: 'danger' },
|
|
30
33
|
}))
|
|
31
34
|
|
|
32
35
|
const currentStatus = computed(() => statuses.value[status])
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="vts-clipboard-console">
|
|
3
3
|
<UiCardTitle>{{ $t('console-clipboard') }}</UiCardTitle>
|
|
4
|
-
<UiTextarea v-tooltip="$t('coming-soon')" accent="
|
|
4
|
+
<UiTextarea v-tooltip="$t('coming-soon')" accent="brand" disabled :model-value="modelValue" />
|
|
5
5
|
<div class="buttons-container">
|
|
6
6
|
<UiButton v-tooltip="$t('coming-soon')" accent="brand" variant="primary" size="medium" disabled>
|
|
7
7
|
{{ $t('send') }}
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
<script setup lang="ts">
|
|
17
17
|
import UiButton from '@core/components/ui/button/UiButton.vue'
|
|
18
18
|
import UiCardTitle from '@core/components/ui/card-title/UiCardTitle.vue'
|
|
19
|
-
import UiTextarea from '@core/components/ui/
|
|
19
|
+
import UiTextarea from '@core/components/ui/text-area/UiTextarea.vue'
|
|
20
20
|
import { vTooltip } from '@core/directives/tooltip.directive'
|
|
21
21
|
import { ref } from 'vue'
|
|
22
22
|
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<!-- v1 -->
|
|
2
|
+
<template>
|
|
3
|
+
<span class="ui-character-limit" :class="classes">
|
|
4
|
+
{{ $t('core.character-limit', { count, max }) }}
|
|
5
|
+
</span>
|
|
6
|
+
</template>
|
|
7
|
+
|
|
8
|
+
<script lang="ts" setup>
|
|
9
|
+
import { computed } from 'vue'
|
|
10
|
+
|
|
11
|
+
const { count, max } = defineProps<{
|
|
12
|
+
count: number
|
|
13
|
+
max: number
|
|
14
|
+
}>()
|
|
15
|
+
|
|
16
|
+
const isTooLong = computed(() => count > max)
|
|
17
|
+
|
|
18
|
+
const classes = computed(() => {
|
|
19
|
+
if (isTooLong.value) {
|
|
20
|
+
return ['has-error', 'typo-body-bold-small']
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return 'typo-body-regular-small'
|
|
24
|
+
})
|
|
25
|
+
</script>
|
|
26
|
+
|
|
27
|
+
<style lang="postcss" scoped>
|
|
28
|
+
.ui-character-limit {
|
|
29
|
+
color: var(--color-neutral-txt-secondary);
|
|
30
|
+
|
|
31
|
+
&.has-error {
|
|
32
|
+
color: var(--color-danger-txt-base);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
</style>
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
@click="modelValue = ''"
|
|
23
23
|
/>
|
|
24
24
|
</div>
|
|
25
|
-
<UiInfo v-if="slots.info || info" :accent>
|
|
25
|
+
<UiInfo v-if="slots.info || info" :accent="accent === 'brand' ? 'info' : accent">
|
|
26
26
|
<slot name="info">{{ info }}</slot>
|
|
27
27
|
</UiInfo>
|
|
28
28
|
</div>
|
|
@@ -37,7 +37,7 @@ import type { IconDefinition } from '@fortawesome/fontawesome-common-types'
|
|
|
37
37
|
import { faXmark } from '@fortawesome/free-solid-svg-icons'
|
|
38
38
|
import { computed, useAttrs, useId } from 'vue'
|
|
39
39
|
|
|
40
|
-
type InputAccent = '
|
|
40
|
+
type InputAccent = 'brand' | 'warning' | 'danger'
|
|
41
41
|
type InputType = 'text' | 'number' | 'password' | 'search'
|
|
42
42
|
|
|
43
43
|
defineOptions({
|
|
@@ -67,7 +67,7 @@ const slots = defineSlots<{
|
|
|
67
67
|
|
|
68
68
|
const attrs = useAttrs()
|
|
69
69
|
|
|
70
|
-
const labelAccent = computed(() => (accent === '
|
|
70
|
+
const labelAccent = computed(() => (accent === 'brand' ? 'neutral' : accent))
|
|
71
71
|
</script>
|
|
72
72
|
|
|
73
73
|
<style lang="postcss" scoped>
|
|
@@ -76,7 +76,6 @@ const labelAccent = computed(() => (accent === 'info' ? 'neutral' : accent))
|
|
|
76
76
|
position: relative;
|
|
77
77
|
display: flex;
|
|
78
78
|
flex-direction: column;
|
|
79
|
-
flex: 1;
|
|
80
79
|
gap: 0.4rem;
|
|
81
80
|
flex: 1;
|
|
82
81
|
|
|
@@ -107,20 +106,20 @@ const labelAccent = computed(() => (accent === 'info' ? 'neutral' : accent))
|
|
|
107
106
|
|
|
108
107
|
/* VARIANT */
|
|
109
108
|
|
|
110
|
-
&.accent--
|
|
109
|
+
&.accent--brand {
|
|
111
110
|
.input {
|
|
112
111
|
border-color: var(--color-neutral-border);
|
|
113
112
|
|
|
114
113
|
&:hover {
|
|
115
|
-
border-color: var(--color-
|
|
114
|
+
border-color: var(--color-brand-item-hover);
|
|
116
115
|
}
|
|
117
116
|
|
|
118
117
|
&:focus {
|
|
119
|
-
border-color: var(--color-
|
|
118
|
+
border-color: var(--color-brand-item-base);
|
|
120
119
|
}
|
|
121
120
|
|
|
122
121
|
&:active {
|
|
123
|
-
border-color: var(--color-
|
|
122
|
+
border-color: var(--color-brand-item-active);
|
|
124
123
|
}
|
|
125
124
|
|
|
126
125
|
&:disabled {
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
:id
|
|
9
9
|
v-model="value"
|
|
10
10
|
type="text"
|
|
11
|
-
accent="
|
|
11
|
+
accent="brand"
|
|
12
12
|
:aria-label="uiStore.isMobile ? $t('core.query-search-bar.label') : undefined"
|
|
13
13
|
:icon="uiStore.isDesktop ? faMagnifyingGlass : undefined"
|
|
14
14
|
:placeholder="$t('core.query-search-bar.placeholder')"
|
|
@@ -1,25 +1,41 @@
|
|
|
1
1
|
<!-- v2 -->
|
|
2
2
|
<template>
|
|
3
|
-
<div class="ui-textarea" :class="toVariants({ accent })">
|
|
4
|
-
<UiLabel v-if="slots.default" :accent="labelAccent" :required :icon :href
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
<div class="ui-textarea" :class="toVariants({ accent: hasMaxCharactersError ? 'danger' : accent })">
|
|
4
|
+
<UiLabel v-if="slots.default" :accent="labelAccent" :required :icon :href :for="id">
|
|
5
|
+
<slot />
|
|
6
|
+
</UiLabel>
|
|
7
|
+
<textarea v-bind="attrs" :id ref="textarea" v-model="model" :disabled class="textarea" />
|
|
8
|
+
<UiCharacterLimit v-if="maxCharacters" :count="model.trim().length" :max="maxCharacters" />
|
|
9
|
+
<UiInfo v-if="isExceedingMaxCharacters" accent="danger">
|
|
10
|
+
{{ $t('core.textarea.exceeds-max-characters', { max: maxCharacters }) }}
|
|
11
|
+
</UiInfo>
|
|
12
|
+
<UiInfo v-if="slots.info" :accent="accent === 'brand' ? 'info' : accent">
|
|
13
|
+
<slot name="info" />
|
|
14
|
+
</UiInfo>
|
|
7
15
|
</div>
|
|
8
16
|
</template>
|
|
9
17
|
|
|
10
18
|
<script lang="ts" setup>
|
|
19
|
+
import UiCharacterLimit from '@core/components/ui/character-limit/UiCharacterLimit.vue'
|
|
11
20
|
import UiInfo from '@core/components/ui/info/UiInfo.vue'
|
|
12
21
|
import UiLabel from '@core/components/ui/label/UiLabel.vue'
|
|
13
22
|
import { toVariants } from '@core/utils/to-variants.util'
|
|
14
23
|
import type { IconDefinition } from '@fortawesome/fontawesome-common-types'
|
|
15
|
-
import {
|
|
24
|
+
import { useFocus } from '@vueuse/core'
|
|
25
|
+
import { computed, useAttrs, useId, useTemplateRef } from 'vue'
|
|
16
26
|
|
|
17
27
|
defineOptions({
|
|
18
28
|
inheritAttrs: false,
|
|
19
29
|
})
|
|
20
30
|
|
|
21
|
-
const
|
|
22
|
-
accent
|
|
31
|
+
const {
|
|
32
|
+
accent,
|
|
33
|
+
maxCharacters,
|
|
34
|
+
id = useId(),
|
|
35
|
+
} = defineProps<{
|
|
36
|
+
accent: 'brand' | 'warning' | 'danger'
|
|
37
|
+
id?: string
|
|
38
|
+
maxCharacters?: number
|
|
23
39
|
disabled?: boolean
|
|
24
40
|
href?: string
|
|
25
41
|
icon?: IconDefinition
|
|
@@ -35,7 +51,24 @@ const slots = defineSlots<{
|
|
|
35
51
|
|
|
36
52
|
const attrs = useAttrs()
|
|
37
53
|
|
|
38
|
-
const
|
|
54
|
+
const textAreaElement = useTemplateRef('textarea')
|
|
55
|
+
|
|
56
|
+
const { focused } = useFocus(textAreaElement)
|
|
57
|
+
|
|
58
|
+
// WIP: To update when using VeeValidate and custom validation rules
|
|
59
|
+
const isExceedingMaxCharacters = computed(() =>
|
|
60
|
+
maxCharacters !== undefined ? model.value.trim().length > maxCharacters : false
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
const hasMaxCharactersError = computed(() => !focused.value && isExceedingMaxCharacters.value)
|
|
64
|
+
|
|
65
|
+
const labelAccent = computed(() => {
|
|
66
|
+
if (hasMaxCharactersError.value) {
|
|
67
|
+
return 'danger'
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return accent === 'brand' ? 'neutral' : accent
|
|
71
|
+
})
|
|
39
72
|
</script>
|
|
40
73
|
|
|
41
74
|
<style lang="postcss" scoped>
|
|
@@ -54,20 +87,23 @@ const labelAccent = computed(() => (props.accent === 'info' ? 'neutral' : props.
|
|
|
54
87
|
width: 100%;
|
|
55
88
|
}
|
|
56
89
|
|
|
57
|
-
&.accent--
|
|
90
|
+
&.accent--brand {
|
|
58
91
|
.textarea {
|
|
59
92
|
border-color: var(--color-neutral-border);
|
|
60
93
|
|
|
61
94
|
&:hover {
|
|
62
|
-
border-color: var(--color-
|
|
95
|
+
border-color: var(--color-brand-item-hover);
|
|
63
96
|
}
|
|
97
|
+
|
|
64
98
|
&:active {
|
|
65
|
-
border-color: var(--color-
|
|
99
|
+
border-color: var(--color-brand-item-active);
|
|
66
100
|
}
|
|
101
|
+
|
|
67
102
|
&:focus:not(:active) {
|
|
68
103
|
border-width: 0.2rem;
|
|
69
|
-
border-color: var(--color-
|
|
104
|
+
border-color: var(--color-brand-item-base);
|
|
70
105
|
}
|
|
106
|
+
|
|
71
107
|
&:disabled {
|
|
72
108
|
background-color: var(--color-neutral-background-disabled);
|
|
73
109
|
border-color: var(--color-neutral-border);
|
|
@@ -82,13 +118,16 @@ const labelAccent = computed(() => (props.accent === 'info' ? 'neutral' : props.
|
|
|
82
118
|
&:hover {
|
|
83
119
|
border-color: var(--color-warning-item-hover);
|
|
84
120
|
}
|
|
121
|
+
|
|
85
122
|
&:active {
|
|
86
123
|
border-color: var(--color-warning-item-active);
|
|
87
124
|
}
|
|
125
|
+
|
|
88
126
|
&:focus:not(:active) {
|
|
89
127
|
border-width: 0.2rem;
|
|
90
128
|
border-color: var(--color-warning-item-base);
|
|
91
129
|
}
|
|
130
|
+
|
|
92
131
|
&:disabled {
|
|
93
132
|
background-color: var(--color-neutral-background-disabled);
|
|
94
133
|
border-color: var(--color-neutral-border);
|
|
@@ -103,13 +142,16 @@ const labelAccent = computed(() => (props.accent === 'info' ? 'neutral' : props.
|
|
|
103
142
|
&:hover {
|
|
104
143
|
border-color: var(--color-danger-item-hover);
|
|
105
144
|
}
|
|
145
|
+
|
|
106
146
|
&:active {
|
|
107
147
|
border-color: var(--color-danger-item-active);
|
|
108
148
|
}
|
|
149
|
+
|
|
109
150
|
&:focus:not(:active) {
|
|
110
151
|
border-width: 0.2rem;
|
|
111
152
|
border-color: var(--color-danger-item-base);
|
|
112
153
|
}
|
|
154
|
+
|
|
113
155
|
&:disabled {
|
|
114
156
|
background-color: var(--color-neutral-background-disabled);
|
|
115
157
|
border-color: var(--color-neutral-border);
|
package/lib/locales/en.json
CHANGED
|
@@ -44,6 +44,9 @@
|
|
|
44
44
|
"backups.vms-protection.protected": "In at least 1 job & protected",
|
|
45
45
|
"backups.vms-protection.tooltip": "A VM is protected if it's in a backup job, with an enabled schedule, and the last run succeeded",
|
|
46
46
|
"backups.vms-protection.unprotected": "In at least 1 job but unprotected",
|
|
47
|
+
"bond": "Bond",
|
|
48
|
+
"bond-devices": "Bond devices",
|
|
49
|
+
"bond-status": "Bond status",
|
|
47
50
|
"bytes.gi": "GiB",
|
|
48
51
|
"bytes.ki": "KiB",
|
|
49
52
|
"bytes.mi": "MiB",
|
|
@@ -66,6 +69,7 @@
|
|
|
66
69
|
"console-unavailable": "Console unavailable",
|
|
67
70
|
"copy": "Copy",
|
|
68
71
|
"copy-info-json": "Copy information into JSON",
|
|
72
|
+
"core.character-limit": "{count}/{max} character | {count}/{max} characters",
|
|
69
73
|
"core.close": "Close",
|
|
70
74
|
"core.copied": "Copied",
|
|
71
75
|
"core.copy-id": "Copy ID",
|
|
@@ -91,6 +95,7 @@
|
|
|
91
95
|
"core.sidebar.unlock": "Unlock sidebar",
|
|
92
96
|
"core.sort.ascending": "Sort ascending",
|
|
93
97
|
"core.sort.descending": "Sort descending",
|
|
98
|
+
"core.textarea.exceeds-max-characters": "Field value must be {max} characters or less.",
|
|
94
99
|
"cpu-provisioning": "CPU provisioning",
|
|
95
100
|
"cpu-provisioning-warning": "The number of vCPUs allocated exceeds the number of physical CPUs available. System performance could be affected",
|
|
96
101
|
"cpu-usage": "CPU usage",
|
|
@@ -238,6 +243,7 @@
|
|
|
238
243
|
"log-out": "Log out",
|
|
239
244
|
"login": "Login",
|
|
240
245
|
"login-only-on-master": "Login is only possible on the master host",
|
|
246
|
+
"mac-address": "MAC address",
|
|
241
247
|
"mac-addresses": "MAC addresses",
|
|
242
248
|
"management": "Management",
|
|
243
249
|
"master": "Primary host",
|
|
@@ -257,6 +263,7 @@
|
|
|
257
263
|
"network": "Network",
|
|
258
264
|
"network-block-device": "Network block device",
|
|
259
265
|
"network-download": "Download",
|
|
266
|
+
"network-information": "Network information",
|
|
260
267
|
"network-throughput": "Network throughput",
|
|
261
268
|
"network-upload": "Upload",
|
|
262
269
|
"networks": "Networks",
|
|
@@ -290,6 +297,9 @@
|
|
|
290
297
|
"password-invalid": "Password invalid",
|
|
291
298
|
"patches": "Patches",
|
|
292
299
|
"pause": "Pause",
|
|
300
|
+
"physical-interface-status": "Physical interface status",
|
|
301
|
+
"pif": "PIF",
|
|
302
|
+
"pif-status": "PIF status",
|
|
293
303
|
"pifs": "PIFs",
|
|
294
304
|
"pifs-status": "PIFs status",
|
|
295
305
|
"please-confirm": "Please confirm",
|
|
@@ -306,6 +316,7 @@
|
|
|
306
316
|
"power-on-vm-for-console": "Power on your VM to access its console",
|
|
307
317
|
"power-state": "Power state",
|
|
308
318
|
"professional-support": "Professional support",
|
|
319
|
+
"properties": "Properties",
|
|
309
320
|
"property": "Property",
|
|
310
321
|
"ram-usage": "RAM usage",
|
|
311
322
|
"reboot": "Reboot",
|
|
@@ -363,6 +374,7 @@
|
|
|
363
374
|
"switch-theme": "Switch theme",
|
|
364
375
|
"system": "System",
|
|
365
376
|
"table-actions": "Table actions",
|
|
377
|
+
"tags": "Tags",
|
|
366
378
|
"task.estimated-end": "Estimated end",
|
|
367
379
|
"task.progress": "Progress",
|
|
368
380
|
"task.started": "Started",
|
package/lib/locales/fr.json
CHANGED
|
@@ -44,6 +44,9 @@
|
|
|
44
44
|
"backups.vms-protection.protected": "Dans au moins 1 job et protégé",
|
|
45
45
|
"backups.vms-protection.tooltip": "Une VM est protégée si elle se trouve dans un job, avec une planification activée, et si la dernière exécution a réussi",
|
|
46
46
|
"backups.vms-protection.unprotected": "Dans au moins 1 job mais sans protection",
|
|
47
|
+
"bond": "Bond",
|
|
48
|
+
"bond-devices": "Devices du bond",
|
|
49
|
+
"bond-status": "Statut du bond",
|
|
47
50
|
"bytes.gi": "Gio",
|
|
48
51
|
"bytes.ki": "Kio",
|
|
49
52
|
"bytes.mi": "Mio",
|
|
@@ -66,6 +69,7 @@
|
|
|
66
69
|
"console-unavailable": "Console indisponible",
|
|
67
70
|
"copy": "Copier",
|
|
68
71
|
"copy-info-json": "Copier les informations en JSON",
|
|
72
|
+
"core.character-limit": "{count}/{max} caractère | {count}/{max} caractères",
|
|
69
73
|
"core.close": "Fermer",
|
|
70
74
|
"core.copied": "Copié",
|
|
71
75
|
"core.copy-id": "Copier l'ID",
|
|
@@ -91,6 +95,7 @@
|
|
|
91
95
|
"core.sidebar.unlock": "Déverrouiller la barre latérale",
|
|
92
96
|
"core.sort.ascending": "Trier par ordre croissant",
|
|
93
97
|
"core.sort.descending": "Trier par ordre décroissant",
|
|
98
|
+
"core.textarea.exceeds-max-characters": "Le champ doit contenir {max} caractères ou moins.",
|
|
94
99
|
"cpu-provisioning": "Provisionnement CPU",
|
|
95
100
|
"cpu-provisioning-warning": "Le nombre de vCPU alloués dépasse le nombre de CPU physique disponible. Les performances du système pourraient être affectées",
|
|
96
101
|
"cpu-usage": "Utilisation CPU",
|
|
@@ -238,6 +243,7 @@
|
|
|
238
243
|
"log-out": "Se déconnecter",
|
|
239
244
|
"login": "Connexion",
|
|
240
245
|
"login-only-on-master": "La connexion n'est possible que sur l'hôte primaire",
|
|
246
|
+
"mac-address": "Adresse MAC",
|
|
241
247
|
"mac-addresses": "Adresses MAC",
|
|
242
248
|
"management": "Gestion",
|
|
243
249
|
"master": "Hôte primaire",
|
|
@@ -257,6 +263,7 @@
|
|
|
257
263
|
"network": "Réseau",
|
|
258
264
|
"network-block-device": "Protocole NBD (Network Block Device)",
|
|
259
265
|
"network-download": "Descendant",
|
|
266
|
+
"network-information": "Informations du réseau",
|
|
260
267
|
"network-throughput": "Débit du réseau",
|
|
261
268
|
"network-upload": "Montant",
|
|
262
269
|
"networks": "Réseaux",
|
|
@@ -290,6 +297,9 @@
|
|
|
290
297
|
"password-invalid": "Mot de passe incorrect",
|
|
291
298
|
"patches": "Patches",
|
|
292
299
|
"pause": "Pause",
|
|
300
|
+
"physical-interface-status": "Statut de l'interface physique",
|
|
301
|
+
"pif": "PIF",
|
|
302
|
+
"pif-status": "Statut du PIF",
|
|
293
303
|
"pifs": "PIFs",
|
|
294
304
|
"pifs-status": "Statut des PIFs",
|
|
295
305
|
"please-confirm": "Veuillez confirmer",
|
|
@@ -306,6 +316,7 @@
|
|
|
306
316
|
"power-on-vm-for-console": "Allumez votre VM pour accéder à sa console",
|
|
307
317
|
"power-state": "État d'alimentation",
|
|
308
318
|
"professional-support": "Support professionnel",
|
|
319
|
+
"properties": "Propriétés",
|
|
309
320
|
"property": "Propriété",
|
|
310
321
|
"ram-usage": "Utilisation de la RAM",
|
|
311
322
|
"reboot": "Redémarrer",
|
|
@@ -363,6 +374,7 @@
|
|
|
363
374
|
"switch-theme": "Changer de thème",
|
|
364
375
|
"system": "Système",
|
|
365
376
|
"table-actions": "Actions du tableau",
|
|
377
|
+
"tags": "Tags",
|
|
366
378
|
"task.estimated-end": "Fin estimée",
|
|
367
379
|
"task.progress": "Progression",
|
|
368
380
|
"task.started": "Démarré",
|