@xen-orchestra/web-core 0.52.0 → 0.53.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/console/VtsRemoteConsole.vue +7 -3
- package/lib/components/form/VtsForm.vue +15 -0
- package/lib/components/status/VtsStatus.vue +1 -7
- package/lib/components/table/cells/VtsTagCell.vue +2 -4
- package/lib/components/tag/VtsTag.vue +30 -0
- package/lib/components/ui/chip/UiChip.vue +52 -29
- package/lib/components/ui/info/UiInfo.vue +17 -6
- package/lib/components/ui/link/UiLink.vue +6 -2
- package/lib/components/ui/tag/UiTag.vue +10 -17
- package/lib/components/ui/tag/UiTertiaryTag.vue +39 -0
- package/lib/icons/action-icons.ts +1 -1
- package/lib/locales/en.json +4 -0
- package/lib/locales/fr.json +4 -0
- package/lib/packages/form-validation/README.md +273 -0
- package/lib/packages/form-validation/custom-rules/out-of-range.rule.ts +15 -0
- package/lib/packages/form-validation/index.ts +8 -0
- package/lib/packages/form-validation/merge-validation-configs.ts +46 -0
- package/lib/packages/form-validation/types.ts +104 -0
- package/lib/packages/form-validation/use-form-validation.ts +196 -0
- package/lib/packages/modal/types.ts +1 -2
- package/lib/packages/remote-resource/define-remote-resource.ts +2 -1
- package/lib/packages/remote-resource/types.ts +1 -3
- package/lib/packages/request/define-request.ts +1 -2
- package/lib/packages/validated-form/README.md +389 -0
- package/lib/packages/validated-form/index.ts +2 -0
- package/lib/packages/validated-form/use-multi-step-validated-form.ts +203 -0
- package/lib/packages/validated-form/use-validated-form.ts +180 -0
- package/lib/utils/parse-tag.util.ts +22 -0
- package/package.json +11 -8
- package/tsconfig.json +2 -3
- package/lib/components/ui/chip/ChipIcon.vue +0 -21
- package/lib/components/ui/chip/ChipRemoveIcon.vue +0 -16
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
<script lang="ts" setup>
|
|
9
9
|
import VtsStateHero from '@core/components/state-hero/VtsStateHero.vue'
|
|
10
10
|
import { useUiStore } from '@core/stores/ui.store'
|
|
11
|
-
import
|
|
11
|
+
import type NoVncClient from '@novnc/novnc/lib/rfb'
|
|
12
|
+
import _RFB from '@novnc/novnc/lib/rfb'
|
|
12
13
|
import { whenever } from '@vueuse/core'
|
|
13
14
|
import { promiseTimeout } from '@vueuse/shared'
|
|
14
15
|
import { fibonacci } from 'iterable-backoff'
|
|
@@ -30,7 +31,10 @@ const FIBONACCI_MS_ARRAY: number[] = Array.from(fibonacci().toMs().take(N_TOTAL_
|
|
|
30
31
|
const consoleContainer = useTemplateRef<HTMLDivElement | null>('console-container')
|
|
31
32
|
const isReady = ref(false)
|
|
32
33
|
|
|
33
|
-
|
|
34
|
+
// See https://rolldown.rs/in-depth/bundling-cjs#ambiguous-default-import-from-cjs-modules
|
|
35
|
+
const VncClient = typeof _RFB === 'object' && _RFB !== null && (_RFB as any).__esModule ? (_RFB as any).default : _RFB
|
|
36
|
+
|
|
37
|
+
let vncClient: NoVncClient | undefined
|
|
34
38
|
let nConnectionAttempts = 0
|
|
35
39
|
|
|
36
40
|
function handleDisconnectionEvent() {
|
|
@@ -80,7 +84,7 @@ async function createVncConnection() {
|
|
|
80
84
|
|
|
81
85
|
vncClient = new VncClient(consoleContainer.value!, url.toString(), {
|
|
82
86
|
wsProtocols: ['binary'],
|
|
83
|
-
})
|
|
87
|
+
}) as NoVncClient
|
|
84
88
|
vncClient.scaleViewport = true
|
|
85
89
|
vncClient.background = 'transparent'
|
|
86
90
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<UiInfo v-tooltip="iconOnly ? currentStatus.text : false"
|
|
2
|
+
<UiInfo v-tooltip="iconOnly ? currentStatus.text : false" :accent="currentStatus.accent">
|
|
3
3
|
<template v-if="!iconOnly">{{ currentStatus.text }}</template>
|
|
4
4
|
</UiInfo>
|
|
5
5
|
</template>
|
|
@@ -62,9 +62,3 @@ const currentStatus = useMapper<Status, { text: string; accent: InfoAccent }>(
|
|
|
62
62
|
false
|
|
63
63
|
)
|
|
64
64
|
</script>
|
|
65
|
-
|
|
66
|
-
<style lang="postcss" scoped>
|
|
67
|
-
.vts-status {
|
|
68
|
-
align-items: center;
|
|
69
|
-
}
|
|
70
|
-
</style>
|
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<UiTableCell>
|
|
3
3
|
<UiTagsList>
|
|
4
|
-
<
|
|
5
|
-
{{ tagItem }}
|
|
6
|
-
</UiTag>
|
|
4
|
+
<VtsTag v-for="tagItem of tags" :key="tagItem" :value="tagItem" />
|
|
7
5
|
</UiTagsList>
|
|
8
6
|
</UiTableCell>
|
|
9
7
|
</template>
|
|
10
8
|
|
|
11
9
|
<script setup lang="ts">
|
|
10
|
+
import VtsTag from '@core/components/tag/VtsTag.vue'
|
|
12
11
|
import UiTableCell from '@core/components/ui/table-cell/UiTableCell.vue'
|
|
13
|
-
import UiTag from '@core/components/ui/tag/UiTag.vue'
|
|
14
12
|
import UiTagsList from '@core/components/ui/tag/UiTagsList.vue'
|
|
15
13
|
import type { MaybeArray } from '@core/types/utility.type'
|
|
16
14
|
import { toArray } from '@core/utils/to-array.utils'
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<UiTertiaryTag v-if="parsedTag" :accent>
|
|
3
|
+
<template #term>{{ parsedTag.term }}</template>
|
|
4
|
+
{{ parsedTag.label }}
|
|
5
|
+
</UiTertiaryTag>
|
|
6
|
+
<UiTag v-else :accent :variant>
|
|
7
|
+
{{ value }}
|
|
8
|
+
</UiTag>
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<script lang="ts" setup>
|
|
12
|
+
import UiTag, { type TagAccent } from '@core/components/ui/tag/UiTag.vue'
|
|
13
|
+
import UiTertiaryTag from '@core/components/ui/tag/UiTertiaryTag.vue'
|
|
14
|
+
import { parseTag } from '@core/utils/parse-tag.util'
|
|
15
|
+
import { computed } from 'vue'
|
|
16
|
+
|
|
17
|
+
type TagVariant = 'primary' | 'secondary'
|
|
18
|
+
|
|
19
|
+
const {
|
|
20
|
+
value,
|
|
21
|
+
accent = 'info',
|
|
22
|
+
variant = 'secondary',
|
|
23
|
+
} = defineProps<{
|
|
24
|
+
value: string
|
|
25
|
+
accent?: TagAccent
|
|
26
|
+
variant?: TagVariant
|
|
27
|
+
}>()
|
|
28
|
+
|
|
29
|
+
const parsedTag = computed(() => parseTag(value))
|
|
30
|
+
</script>
|
|
@@ -1,31 +1,28 @@
|
|
|
1
|
-
<!--
|
|
1
|
+
<!-- v8 -->
|
|
2
2
|
<template>
|
|
3
|
-
<span :class="classNames" class="ui-chip typo-body-regular-small"
|
|
4
|
-
<
|
|
5
|
-
<span class="content text-ellipsis">
|
|
3
|
+
<span :class="classNames" class="ui-chip typo-body-regular-small">
|
|
4
|
+
<span class="text-ellipsis">
|
|
6
5
|
<slot />
|
|
7
6
|
</span>
|
|
8
|
-
<
|
|
7
|
+
<button v-if="!disabled" class="icon" type="button" @click.stop="emit('remove')">
|
|
8
|
+
<VtsIcon name="action:close-cancel-clear" size="medium" />
|
|
9
|
+
</button>
|
|
9
10
|
</span>
|
|
10
11
|
</template>
|
|
11
12
|
|
|
12
13
|
<script lang="ts" setup>
|
|
13
|
-
import
|
|
14
|
-
import ChipRemoveIcon from '@core/components/ui/chip/ChipRemoveIcon.vue'
|
|
15
|
-
import type { IconName } from '@core/icons'
|
|
14
|
+
import VtsIcon from '@core/components/icon/VtsIcon.vue'
|
|
16
15
|
import { toVariants } from '@core/utils/to-variants.util'
|
|
17
16
|
import { computed } from 'vue'
|
|
18
17
|
|
|
19
18
|
export type ChipAccent = 'info' | 'success' | 'warning' | 'danger'
|
|
20
19
|
|
|
21
|
-
const
|
|
20
|
+
const { accent, disabled } = defineProps<{
|
|
22
21
|
accent: ChipAccent
|
|
23
|
-
icon?: IconName
|
|
24
22
|
disabled?: boolean
|
|
25
23
|
}>()
|
|
26
24
|
|
|
27
25
|
const emit = defineEmits<{
|
|
28
|
-
edit: []
|
|
29
26
|
remove: []
|
|
30
27
|
}>()
|
|
31
28
|
|
|
@@ -36,8 +33,8 @@ defineSlots<{
|
|
|
36
33
|
const classNames = computed(() => {
|
|
37
34
|
return [
|
|
38
35
|
toVariants({
|
|
39
|
-
accent
|
|
40
|
-
muted:
|
|
36
|
+
accent,
|
|
37
|
+
muted: disabled,
|
|
41
38
|
}),
|
|
42
39
|
]
|
|
43
40
|
})
|
|
@@ -45,37 +42,51 @@ const classNames = computed(() => {
|
|
|
45
42
|
|
|
46
43
|
<style lang="postcss" scoped>
|
|
47
44
|
.ui-chip {
|
|
48
|
-
display: flex;
|
|
45
|
+
display: inline-flex;
|
|
49
46
|
align-items: center;
|
|
50
|
-
gap: 0.
|
|
51
|
-
padding: 0.4rem
|
|
47
|
+
gap: 0.4rem;
|
|
48
|
+
padding: 0.4rem 1.2rem;
|
|
52
49
|
border-radius: 10rem;
|
|
53
50
|
color: var(--color-neutral-txt-primary);
|
|
54
|
-
cursor: pointer;
|
|
55
51
|
min-height: 2.4rem;
|
|
56
52
|
vertical-align: middle;
|
|
57
53
|
white-space: nowrap;
|
|
58
|
-
min-width: 0;
|
|
59
54
|
|
|
60
55
|
&.muted {
|
|
61
56
|
color: var(--color-neutral-txt-secondary);
|
|
62
57
|
pointer-events: none;
|
|
63
58
|
}
|
|
64
59
|
|
|
65
|
-
.
|
|
66
|
-
|
|
60
|
+
.icon {
|
|
61
|
+
border-radius: 0 10rem 10rem 0;
|
|
62
|
+
padding: 0.4rem;
|
|
63
|
+
margin: -0.4rem -1.2rem -0.4rem 0;
|
|
64
|
+
align-self: stretch;
|
|
65
|
+
display: flex;
|
|
66
|
+
align-items: center;
|
|
67
|
+
justify-content: center;
|
|
68
|
+
cursor: pointer;
|
|
69
|
+
background-color: transparent;
|
|
70
|
+
border: none;
|
|
67
71
|
}
|
|
68
72
|
|
|
73
|
+
.icon:focus-visible {
|
|
74
|
+
outline: 0.2rem solid var(--color-brand-txt-base);
|
|
75
|
+
outline-offset: 0.2rem;
|
|
76
|
+
}
|
|
69
77
|
/* COLOR VARIANTS */
|
|
70
|
-
|
|
71
78
|
&.accent--info {
|
|
72
79
|
background-color: var(--color-info-background-selected);
|
|
73
80
|
|
|
74
|
-
|
|
81
|
+
.icon {
|
|
82
|
+
color: var(--color-info-txt-hover);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.icon:hover {
|
|
75
86
|
background-color: var(--color-info-background-hover);
|
|
76
87
|
}
|
|
77
88
|
|
|
78
|
-
|
|
89
|
+
.icon:active {
|
|
79
90
|
background-color: var(--color-info-background-active);
|
|
80
91
|
}
|
|
81
92
|
|
|
@@ -87,11 +98,15 @@ const classNames = computed(() => {
|
|
|
87
98
|
&.accent--success {
|
|
88
99
|
background-color: var(--color-success-background-selected);
|
|
89
100
|
|
|
90
|
-
|
|
101
|
+
.icon {
|
|
102
|
+
color: var(--color-success-txt-hover);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.icon:hover {
|
|
91
106
|
background-color: var(--color-success-background-hover);
|
|
92
107
|
}
|
|
93
108
|
|
|
94
|
-
|
|
109
|
+
.icon:active {
|
|
95
110
|
background-color: var(--color-success-background-active);
|
|
96
111
|
}
|
|
97
112
|
|
|
@@ -103,11 +118,15 @@ const classNames = computed(() => {
|
|
|
103
118
|
&.accent--warning {
|
|
104
119
|
background-color: var(--color-warning-background-selected);
|
|
105
120
|
|
|
106
|
-
|
|
121
|
+
.icon {
|
|
122
|
+
color: var(--color-warning-txt-hover);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.icon:hover {
|
|
107
126
|
background-color: var(--color-warning-background-hover);
|
|
108
127
|
}
|
|
109
128
|
|
|
110
|
-
|
|
129
|
+
.icon:active {
|
|
111
130
|
background-color: var(--color-warning-background-active);
|
|
112
131
|
}
|
|
113
132
|
|
|
@@ -119,11 +138,15 @@ const classNames = computed(() => {
|
|
|
119
138
|
&.accent--danger {
|
|
120
139
|
background-color: var(--color-danger-background-selected);
|
|
121
140
|
|
|
122
|
-
|
|
141
|
+
.icon {
|
|
142
|
+
color: var(--color-danger-txt-hover);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.icon:hover {
|
|
123
146
|
background-color: var(--color-danger-background-hover);
|
|
124
147
|
}
|
|
125
148
|
|
|
126
|
-
|
|
149
|
+
.icon:active {
|
|
127
150
|
background-color: var(--color-danger-background-active);
|
|
128
151
|
}
|
|
129
152
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
<!--
|
|
1
|
+
<!-- v6 -->
|
|
2
2
|
<template>
|
|
3
3
|
<div class="ui-info">
|
|
4
|
-
<VtsIcon class="icon" :name="icon" size
|
|
5
|
-
<p v-tooltip="!wrap" class="
|
|
4
|
+
<VtsIcon class="icon" :name="icon" :size />
|
|
5
|
+
<p v-tooltip="!wrap" class="label" :class="[textSize, { 'text-ellipsis': !wrap }]">
|
|
6
6
|
<slot />
|
|
7
7
|
</p>
|
|
8
8
|
</div>
|
|
@@ -15,10 +15,12 @@ import type { IconName } from '@core/icons'
|
|
|
15
15
|
import { useMapper } from '@core/packages/mapper'
|
|
16
16
|
|
|
17
17
|
export type InfoAccent = 'info' | 'success' | 'warning' | 'danger' | 'muted'
|
|
18
|
+
type Size = 'small' | 'medium'
|
|
18
19
|
|
|
19
|
-
const { accent } = defineProps<{
|
|
20
|
+
const { accent, size = 'medium' } = defineProps<{
|
|
20
21
|
accent: InfoAccent
|
|
21
22
|
wrap?: boolean
|
|
23
|
+
size?: Size
|
|
22
24
|
}>()
|
|
23
25
|
|
|
24
26
|
defineSlots<{
|
|
@@ -36,16 +38,25 @@ const icon = useMapper<InfoAccent, IconName>(
|
|
|
36
38
|
},
|
|
37
39
|
'muted'
|
|
38
40
|
)
|
|
41
|
+
|
|
42
|
+
const textSize = useMapper<Size, any>(
|
|
43
|
+
() => size,
|
|
44
|
+
{
|
|
45
|
+
small: 'typo-body-regular-small',
|
|
46
|
+
medium: 'typo-body-regular',
|
|
47
|
+
},
|
|
48
|
+
'medium'
|
|
49
|
+
)
|
|
39
50
|
</script>
|
|
40
51
|
|
|
41
52
|
<style lang="postcss" scoped>
|
|
42
53
|
.ui-info {
|
|
43
|
-
align-items:
|
|
54
|
+
align-items: baseline;
|
|
44
55
|
display: flex;
|
|
45
56
|
gap: 0.8rem;
|
|
46
57
|
|
|
47
58
|
.icon {
|
|
48
|
-
|
|
59
|
+
transform: translateY(0.2ex);
|
|
49
60
|
}
|
|
50
61
|
|
|
51
62
|
.label:empty {
|
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
<!--
|
|
1
|
+
<!-- v6 -->
|
|
2
2
|
<template>
|
|
3
3
|
<component :is="component" :class="classes" class="ui-link" v-bind="attributes">
|
|
4
4
|
<VtsIcon :name="icon" size="medium" />
|
|
5
5
|
<slot />
|
|
6
|
-
<VtsIcon v-if="attributes.target === '_blank'" name="
|
|
6
|
+
<VtsIcon v-if="attributes.target === '_blank'" name="action:open-in-new-tab" size="medium" class="external-icon" />
|
|
7
|
+
<VtsIcon v-if="isPrimary" v-tooltip="primaryTooltip" name="status:primary-circle" size="medium" />
|
|
7
8
|
</component>
|
|
8
9
|
</template>
|
|
9
10
|
|
|
10
11
|
<script lang="ts" setup>
|
|
11
12
|
import VtsIcon from '@core/components/icon/VtsIcon.vue'
|
|
12
13
|
import { type LinkOptions, useLinkComponent } from '@core/composables/link-component.composable'
|
|
14
|
+
import { vTooltip } from '@core/directives/tooltip.directive'
|
|
13
15
|
import type { IconName } from '@core/icons'
|
|
14
16
|
import { computed } from 'vue'
|
|
15
17
|
|
|
@@ -17,6 +19,8 @@ const props = defineProps<
|
|
|
17
19
|
LinkOptions & {
|
|
18
20
|
size: 'small' | 'medium'
|
|
19
21
|
icon?: IconName
|
|
22
|
+
isPrimary?: boolean
|
|
23
|
+
primaryTooltip?: string
|
|
20
24
|
}
|
|
21
25
|
>()
|
|
22
26
|
|
|
@@ -1,34 +1,27 @@
|
|
|
1
|
-
<!--
|
|
2
|
-
<!-- TODO: implement tertiary variant to bump to v4 -->
|
|
1
|
+
<!-- v5 -->
|
|
3
2
|
<template>
|
|
4
|
-
<span :class="
|
|
5
|
-
<slot
|
|
6
|
-
<VtsIcon :name="icon" size="medium" />
|
|
7
|
-
</slot>
|
|
8
|
-
<span>
|
|
9
|
-
<slot />
|
|
10
|
-
</span>
|
|
3
|
+
<span :class="className" class="ui-tag typo-body-regular-small">
|
|
4
|
+
<slot />
|
|
11
5
|
</span>
|
|
12
6
|
</template>
|
|
13
7
|
|
|
14
8
|
<script lang="ts" setup>
|
|
15
|
-
import VtsIcon from '@core/components/icon/VtsIcon.vue'
|
|
16
|
-
import type { IconName } from '@core/icons'
|
|
17
9
|
import { toVariants } from '@core/utils/to-variants.util'
|
|
10
|
+
import { computed } from 'vue'
|
|
18
11
|
|
|
19
|
-
type TagAccent = 'info' | 'neutral' | 'success' | 'warning' | 'danger' | 'muted'
|
|
12
|
+
export type TagAccent = 'info' | 'neutral' | 'success' | 'warning' | 'danger' | 'muted'
|
|
20
13
|
type TagVariant = 'primary' | 'secondary'
|
|
21
14
|
|
|
22
|
-
defineProps<{
|
|
15
|
+
const { accent, variant } = defineProps<{
|
|
23
16
|
accent: TagAccent
|
|
24
17
|
variant: TagVariant
|
|
25
|
-
icon?: IconName
|
|
26
18
|
}>()
|
|
27
19
|
|
|
28
20
|
defineSlots<{
|
|
29
21
|
default(): any
|
|
30
|
-
icon?(): any
|
|
31
22
|
}>()
|
|
23
|
+
|
|
24
|
+
const className = computed(() => toVariants({ accent, variant }))
|
|
32
25
|
</script>
|
|
33
26
|
|
|
34
27
|
<style lang="postcss" scoped>
|
|
@@ -39,9 +32,9 @@ defineSlots<{
|
|
|
39
32
|
gap: 0.8rem;
|
|
40
33
|
white-space: normal;
|
|
41
34
|
word-break: break-word;
|
|
42
|
-
padding: 0.
|
|
43
|
-
border-radius: 0.4rem;
|
|
35
|
+
padding: 0.35rem 0.8rem;
|
|
44
36
|
vertical-align: middle;
|
|
37
|
+
border-radius: 0.4rem;
|
|
45
38
|
|
|
46
39
|
/* COLOR VARIANTS */
|
|
47
40
|
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<!-- v1 -->
|
|
2
|
+
<template>
|
|
3
|
+
<span class="ui-tertiary-tag">
|
|
4
|
+
<UiTag :accent variant="primary" class="radius-left">
|
|
5
|
+
<slot name="term" />
|
|
6
|
+
</UiTag>
|
|
7
|
+
<UiTag :accent variant="secondary" class="radius-right">
|
|
8
|
+
<slot />
|
|
9
|
+
</UiTag>
|
|
10
|
+
</span>
|
|
11
|
+
</template>
|
|
12
|
+
|
|
13
|
+
<script lang="ts" setup>
|
|
14
|
+
import UiTag, { type TagAccent } from '@core/components/ui/tag/UiTag.vue'
|
|
15
|
+
|
|
16
|
+
defineProps<{
|
|
17
|
+
accent: TagAccent
|
|
18
|
+
}>()
|
|
19
|
+
|
|
20
|
+
defineSlots<{
|
|
21
|
+
default(): any
|
|
22
|
+
term(): any
|
|
23
|
+
}>()
|
|
24
|
+
</script>
|
|
25
|
+
|
|
26
|
+
<style lang="postcss" scoped>
|
|
27
|
+
.ui-tertiary-tag {
|
|
28
|
+
display: inline-flex;
|
|
29
|
+
flex-direction: row;
|
|
30
|
+
|
|
31
|
+
:deep(.radius-left) {
|
|
32
|
+
border-radius: 0.4rem 0 0 0.4rem;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
:deep(.radius-right) {
|
|
36
|
+
border-radius: 0 0.4rem 0.4rem 0;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
</style>
|
package/lib/locales/en.json
CHANGED
|
@@ -326,6 +326,10 @@
|
|
|
326
326
|
"for-replication": "For replication",
|
|
327
327
|
"force-reboot-blocked": "Force reboot Blocked",
|
|
328
328
|
"force-shutdown-blocked": "Force shutdown Blocked",
|
|
329
|
+
"form:error:field-required": "{field} is required",
|
|
330
|
+
"form:error:integer": "Must be an integer",
|
|
331
|
+
"form:error:required": "This field is required",
|
|
332
|
+
"form:warning:out-of-range": "Should be between {min} and {max}",
|
|
329
333
|
"format": "Format",
|
|
330
334
|
"free-space": "Free space",
|
|
331
335
|
"fullscreen": "Fullscreen",
|
package/lib/locales/fr.json
CHANGED
|
@@ -326,6 +326,10 @@
|
|
|
326
326
|
"for-replication": "Pour la réplication",
|
|
327
327
|
"force-reboot-blocked": "Redémarrage forcé bloqué",
|
|
328
328
|
"force-shutdown-blocked": "Arrêt forcé bloqué",
|
|
329
|
+
"form:error:field-required": "Le champ {field} est requis",
|
|
330
|
+
"form:error:integer": "Doit être un entier",
|
|
331
|
+
"form:error:required": "Ce champ est requis",
|
|
332
|
+
"form:warning:out-of-range": "Devrait être compris entre {min} et {max}",
|
|
329
333
|
"format": "Format",
|
|
330
334
|
"free-space": "Espace libre",
|
|
331
335
|
"fullscreen": "Plein écran",
|