@xen-orchestra/web-core 0.8.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.
- package/lib/components/connection-status/VtsConnectionStatus.vue +29 -0
- package/lib/components/ui/info/UiInfo.vue +9 -11
- package/lib/components/ui/input/UiInput.vue +121 -92
- package/lib/components/ui/label/UiLabel.vue +11 -19
- package/lib/components/ui/query-search-bar/UiQuerySearchBar.vue +2 -0
- package/lib/components/ui/table-pagination/PaginationButton.vue +33 -0
- package/lib/components/ui/table-pagination/UiTablePagination.vue +178 -0
- package/lib/locales/en.json +6 -0
- package/lib/locales/fr.json +6 -0
- package/package.json +1 -1
|
@@ -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="
|
|
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
|
|
24
|
-
accent: 'info' | 'success' | 'warning' | 'danger'
|
|
25
|
-
}
|
|
24
|
+
export type InfoAccent = 'info' | 'success' | 'warning' | 'danger'
|
|
26
25
|
|
|
27
|
-
const
|
|
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<
|
|
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[
|
|
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,141 +1,170 @@
|
|
|
1
|
-
<!--
|
|
1
|
+
<!-- v5 -->
|
|
2
2
|
<template>
|
|
3
|
-
<div class="ui-input">
|
|
4
|
-
<
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
:icon="
|
|
9
|
-
class="
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
3
|
+
<div class="ui-input" :class="toVariants({ accent })">
|
|
4
|
+
<UiLabel v-if="slots.default || label" :accent="labelAccent" :required :icon="labelIcon" :href :for="id">
|
|
5
|
+
<slot>{{ label }}</slot>
|
|
6
|
+
</UiLabel>
|
|
7
|
+
<div>
|
|
8
|
+
<VtsIcon :icon accent="current" class="before" />
|
|
9
|
+
<input :id v-model.trim="modelValue" class="typo p1-regular input text-ellipsis" :type :disabled v-bind="attrs" />
|
|
10
|
+
<VtsIcon
|
|
11
|
+
v-if="!attrs.disabled && modelValue && clearable"
|
|
12
|
+
:icon="faXmark"
|
|
13
|
+
class="after"
|
|
14
|
+
accent="info"
|
|
15
|
+
@click="modelValue = ''"
|
|
16
|
+
/>
|
|
17
|
+
</div>
|
|
18
|
+
<UiInfo v-if="slots.info || info" :accent>
|
|
19
|
+
<slot name="info">{{ info }}</slot>
|
|
20
|
+
</UiInfo>
|
|
13
21
|
</div>
|
|
14
22
|
</template>
|
|
15
23
|
|
|
16
24
|
<script lang="ts" setup>
|
|
17
25
|
import VtsIcon from '@core/components/icon/VtsIcon.vue'
|
|
18
|
-
import
|
|
26
|
+
import UiInfo from '@core/components/ui/info/UiInfo.vue'
|
|
27
|
+
import UiLabel from '@core/components/ui/label/UiLabel.vue'
|
|
28
|
+
import { toVariants } from '@core/utils/to-variants.util'
|
|
19
29
|
import type { IconDefinition } from '@fortawesome/fontawesome-common-types'
|
|
20
30
|
import { faXmark } from '@fortawesome/free-solid-svg-icons'
|
|
21
|
-
import { computed, useAttrs } from 'vue'
|
|
31
|
+
import { computed, useAttrs, useId } from 'vue'
|
|
32
|
+
|
|
33
|
+
type InputAccent = 'info' | 'warning' | 'danger'
|
|
34
|
+
type InputType = 'text' | 'number' | 'password' | 'search'
|
|
22
35
|
|
|
23
36
|
defineOptions({
|
|
24
37
|
inheritAttrs: false,
|
|
25
38
|
})
|
|
26
39
|
|
|
27
|
-
defineProps<{
|
|
40
|
+
const { accent, id = useId() } = defineProps<{
|
|
41
|
+
accent: InputAccent
|
|
42
|
+
label?: string
|
|
43
|
+
info?: string
|
|
44
|
+
id?: string
|
|
45
|
+
disabled?: boolean
|
|
46
|
+
clearable?: boolean
|
|
47
|
+
href?: string
|
|
48
|
+
required?: boolean
|
|
49
|
+
labelIcon?: IconDefinition
|
|
28
50
|
icon?: IconDefinition
|
|
51
|
+
type?: InputType
|
|
29
52
|
}>()
|
|
30
53
|
|
|
31
|
-
const modelValue = defineModel<string>({ required: true })
|
|
54
|
+
const modelValue = defineModel<string | number>({ required: true })
|
|
55
|
+
|
|
56
|
+
const slots = defineSlots<{
|
|
57
|
+
default?(): any
|
|
58
|
+
info?(): any
|
|
59
|
+
}>()
|
|
32
60
|
|
|
33
61
|
const attrs = useAttrs()
|
|
34
62
|
|
|
35
|
-
const
|
|
63
|
+
const labelAccent = computed(() => (accent === 'info' ? 'neutral' : accent))
|
|
36
64
|
</script>
|
|
37
65
|
|
|
38
66
|
<style lang="postcss" scoped>
|
|
39
|
-
/*
|
|
40
|
-
.input {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
67
|
+
/* IMPLEMENTATION */
|
|
68
|
+
.ui-input {
|
|
69
|
+
position: relative;
|
|
70
|
+
display: flex;
|
|
71
|
+
flex-direction: column;
|
|
72
|
+
gap: 0.4rem;
|
|
73
|
+
|
|
74
|
+
.input {
|
|
75
|
+
border-radius: 0.4rem;
|
|
76
|
+
border-width: 0.1rem;
|
|
77
|
+
border-style: solid;
|
|
78
|
+
background-color: var(--color-neutral-background-primary);
|
|
79
|
+
color: var(--color-neutral-txt-primary);
|
|
80
|
+
height: 4rem;
|
|
81
|
+
outline: none;
|
|
82
|
+
width: 100%;
|
|
83
|
+
padding-block: 0.8rem;
|
|
84
|
+
padding-inline: 1.6rem;
|
|
85
|
+
|
|
86
|
+
&::placeholder {
|
|
87
|
+
color: var(--color-neutral-txt-secondary);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
&:focus {
|
|
91
|
+
border-width: 0.2rem;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
&:has(+ .after) {
|
|
95
|
+
padding-inline-end: 4.8rem;
|
|
96
|
+
}
|
|
44
97
|
}
|
|
45
98
|
|
|
46
|
-
|
|
47
|
-
--border-color: var(--color-info-item-hover);
|
|
48
|
-
--background-color: var(--color-neutral-background-primary);
|
|
49
|
-
}
|
|
99
|
+
/* VARIANT */
|
|
50
100
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
101
|
+
&.accent--info {
|
|
102
|
+
.input {
|
|
103
|
+
border-color: var(--color-neutral-border);
|
|
55
104
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
105
|
+
&:hover {
|
|
106
|
+
border-color: var(--color-info-item-hover);
|
|
107
|
+
}
|
|
60
108
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
65
|
-
}
|
|
109
|
+
&:focus {
|
|
110
|
+
border-color: var(--color-info-item-base);
|
|
111
|
+
}
|
|
66
112
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
113
|
+
&:active {
|
|
114
|
+
border-color: var(--color-info-item-active);
|
|
115
|
+
}
|
|
70
116
|
|
|
71
|
-
|
|
72
|
-
|
|
117
|
+
&:disabled {
|
|
118
|
+
border-color: var(--color-neutral-border);
|
|
119
|
+
background-color: var(--color-neutral-background-disabled);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
73
122
|
}
|
|
74
123
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
124
|
+
&.accent--warning {
|
|
125
|
+
.input {
|
|
126
|
+
border-color: var(--color-warning-item-base);
|
|
78
127
|
|
|
79
|
-
|
|
80
|
-
|
|
128
|
+
&:disabled {
|
|
129
|
+
border-color: var(--color-neutral-border);
|
|
130
|
+
background-color: var(--color-neutral-background-disabled);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
81
133
|
}
|
|
82
134
|
|
|
83
|
-
|
|
84
|
-
|
|
135
|
+
&.accent--danger {
|
|
136
|
+
.input {
|
|
137
|
+
border-color: var(--color-danger-item-base);
|
|
138
|
+
|
|
139
|
+
&:disabled {
|
|
140
|
+
border-color: var(--color-neutral-border);
|
|
141
|
+
background-color: var(--color-neutral-background-disabled);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
85
144
|
}
|
|
86
|
-
}
|
|
87
145
|
|
|
88
|
-
/*
|
|
89
|
-
.ui-input {
|
|
90
|
-
position: relative;
|
|
146
|
+
/* ICON POSITION */
|
|
91
147
|
|
|
92
148
|
.before + .input {
|
|
93
149
|
padding-inline-start: 4.8rem;
|
|
94
150
|
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
.input {
|
|
98
|
-
border: var(--border-width) solid var(--border-color);
|
|
99
|
-
border-radius: 0.8rem;
|
|
100
|
-
outline: none;
|
|
101
|
-
width: 100%;
|
|
102
|
-
height: 4rem;
|
|
103
|
-
padding: 0.8rem 1.6rem;
|
|
104
|
-
color: var(--color-neutral-txt-primary);
|
|
105
|
-
background-color: var(--background-color);
|
|
106
|
-
|
|
107
|
-
&:has(+ .after) {
|
|
108
|
-
padding-inline-end: 4.8rem;
|
|
109
|
-
}
|
|
110
151
|
|
|
111
|
-
|
|
112
|
-
|
|
152
|
+
.before,
|
|
153
|
+
.after {
|
|
154
|
+
position: absolute;
|
|
155
|
+
inset-block: 1.2rem;
|
|
113
156
|
}
|
|
114
157
|
|
|
115
|
-
|
|
158
|
+
.before {
|
|
116
159
|
color: var(--color-neutral-txt-secondary);
|
|
160
|
+
inset-inline-start: 1.6rem;
|
|
161
|
+
pointer-events: none;
|
|
162
|
+
z-index: 1;
|
|
117
163
|
}
|
|
118
164
|
|
|
119
|
-
|
|
120
|
-
|
|
165
|
+
.after {
|
|
166
|
+
inset-inline-end: 1.6rem;
|
|
167
|
+
cursor: pointer;
|
|
121
168
|
}
|
|
122
169
|
}
|
|
123
|
-
|
|
124
|
-
.before,
|
|
125
|
-
.after {
|
|
126
|
-
position: absolute;
|
|
127
|
-
inset-block: 1.2rem;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
.before {
|
|
131
|
-
color: var(--color-neutral-txt-secondary);
|
|
132
|
-
inset-inline-start: 1.6rem;
|
|
133
|
-
pointer-events: none;
|
|
134
|
-
z-index: 1;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
.after {
|
|
138
|
-
inset-inline-end: 1.6rem;
|
|
139
|
-
cursor: pointer;
|
|
140
|
-
}
|
|
141
170
|
</style>
|
|
@@ -1,24 +1,23 @@
|
|
|
1
|
-
<!--
|
|
1
|
+
<!-- v1 -->
|
|
2
2
|
<template>
|
|
3
3
|
<div :class="toVariants({ accent })" class="ui-label">
|
|
4
|
-
<VtsIcon accent="current" :icon class="
|
|
5
|
-
<
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
.
|
|
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 {
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
<UiInput
|
|
8
8
|
:id
|
|
9
9
|
v-model="value"
|
|
10
|
+
type="text"
|
|
11
|
+
accent="info"
|
|
10
12
|
:aria-label="uiStore.isMobile ? $t('core.query-search-bar.label') : undefined"
|
|
11
13
|
:icon="uiStore.isDesktop ? faMagnifyingGlass : undefined"
|
|
12
14
|
:placeholder="$t('core.query-search-bar.placeholder')"
|
|
@@ -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>
|
package/lib/locales/en.json
CHANGED
|
@@ -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",
|
package/lib/locales/fr.json
CHANGED
|
@@ -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",
|