@xen-orchestra/web-core 0.55.0 → 0.57.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/assets/css/base.pcss +5 -0
- package/lib/components/card-object-title/VtsCardObjectTitle.vue +36 -0
- package/lib/components/code-snippet/VtsCodeSnippet.vue +11 -5
- package/lib/components/drawer/VtsDrawer.vue +5 -1
- package/lib/components/drawer/VtsDrawerButton.vue +4 -3
- package/lib/components/drawer/VtsDrawerConfirmButton.vue +4 -2
- package/lib/components/icon/VtsIcon.vue +3 -1
- package/lib/components/input-wrapper/VtsInputWrapper.vue +2 -2
- package/lib/components/layout/VtsContentSidePanel.vue +41 -0
- package/lib/components/layout/VtsLayoutSidebar.vue +116 -43
- package/lib/components/menu/MenuItem.vue +9 -1
- package/lib/components/menu/MenuList.vue +4 -2
- package/lib/components/menu/VtsActionsMenu.vue +48 -14
- package/lib/components/modal/VtsActionModal.vue +44 -9
- package/lib/components/modal/VtsBlockedModal.vue +1 -1
- package/lib/components/modal/VtsDeleteModal.vue +1 -1
- package/lib/components/operation-card/VtsOperationCard.vue +2 -1
- package/lib/components/overlay/VtsOverlayButton.vue +35 -0
- package/lib/components/overlay/VtsOverlayCancelButton.vue +16 -0
- package/lib/components/overlay/VtsOverlayConfirmButton.vue +25 -0
- package/lib/components/overlay/VtsOverlayList.vue +82 -0
- package/lib/components/panel/VtsPanel.vue +80 -0
- package/lib/components/panel/VtsSidePanel.vue +140 -0
- package/lib/components/progress-bar/VtsProgressBar.vue +5 -3
- package/lib/components/select/VtsSelect.vue +1 -3
- package/lib/components/space-card/VtsSpaceCard.vue +1 -1
- package/lib/components/state-hero/VtsStateHero.vue +9 -17
- package/lib/components/table/VtsTable.vue +2 -1
- package/lib/components/table/cells/VtsActionCell.vue +7 -0
- package/lib/components/table/cells/VtsLinkCell.vue +3 -1
- package/lib/components/table/cells/VtsProgressBarCell.vue +1 -1
- package/lib/components/table/cells/VtsUserNameCell.vue +29 -0
- package/lib/components/task/VtsQuickTaskButton.vue +1 -1
- package/lib/components/task/VtsQuickTaskList.vue +1 -1
- package/lib/components/tree/VtsTreeItem.vue +13 -7
- package/lib/components/tree/VtsTreeList.vue +6 -3
- package/lib/components/tree/VtsTreeLoadingItem.vue +3 -3
- package/lib/components/ui/head-bar/UiHeadBar.vue +2 -2
- package/lib/components/ui/input/UiInput.vue +56 -10
- package/lib/components/ui/link/UiLink.vue +3 -1
- package/lib/components/ui/panel/UiPanel.vue +7 -24
- package/lib/components/ui/query-search-bar/UiQuerySearchBar.vue +1 -15
- package/lib/components/ui/quick-task-item/UiQuickTaskItem.vue +1 -1
- package/lib/components/ui/quick-task-panel/UiQuickTaskPanel.vue +1 -1
- package/lib/components/ui/task-item/UiTaskItem.vue +14 -6
- package/lib/components/ui/task-list/UiTaskList.vue +1 -1
- package/lib/components/ui/text-area/UiTextarea.vue +12 -14
- package/lib/components/ui/tree-item-label/UiTreeItemLabel.vue +1 -1
- package/lib/components/vif-connection-toggle-modal/VtsVifConnectionToggleModal.vue +43 -0
- package/lib/composables/table/multi-select.composable.md +33 -0
- package/lib/composables/table-state.composable.ts +1 -1
- package/lib/icons/action-icons.ts +14 -0
- package/lib/layouts/CoreLayout.vue +74 -62
- package/lib/locales/cs.json +56 -1
- package/lib/locales/de.json +3 -2
- package/lib/locales/en.json +85 -4
- package/lib/locales/es.json +11 -1
- package/lib/locales/fa.json +0 -1
- package/lib/locales/fr.json +85 -4
- package/lib/locales/it.json +0 -1
- package/lib/locales/ko.json +2 -0
- package/lib/locales/nl.json +2 -1
- package/lib/locales/pt-BR.json +0 -1
- package/lib/locales/pt.json +0 -1
- package/lib/locales/ru.json +0 -1
- package/lib/locales/sk.json +56 -1
- package/lib/locales/sv.json +3 -2
- package/lib/locales/uk.json +0 -1
- package/lib/locales/zh-Hans.json +79 -4
- package/lib/packages/form-validation/custom-rules/ip-addresses.rule.ts +15 -0
- package/lib/packages/form-validation/custom-rules/ip.regex.ts +26 -0
- package/lib/packages/form-validation/custom-rules/ipv4-or-cidr.rule.ts +2 -3
- package/lib/packages/form-validation/index.ts +2 -0
- package/lib/packages/hide-permanently/README.md +60 -0
- package/lib/packages/hide-permanently/types.ts +3 -0
- package/lib/packages/hide-permanently/use-hide-permanently.ts +15 -0
- package/lib/packages/overlay/OverlayComponent.vue +18 -0
- package/lib/packages/overlay/README.md +285 -0
- package/lib/packages/overlay/create-event-handler.ts +80 -0
- package/lib/packages/overlay/injection-keys.ts +3 -0
- package/lib/packages/overlay/is-thenable.ts +3 -0
- package/lib/packages/overlay/symbols.ts +5 -0
- package/lib/packages/overlay/types.ts +94 -0
- package/lib/packages/overlay/use-overlay-escape.ts +34 -0
- package/lib/packages/overlay/use-overlay-store.ts +33 -0
- package/lib/packages/overlay/use-overlay-trigger.ts +33 -0
- package/lib/packages/overlay/use-overlay.ts +99 -0
- package/lib/packages/progress/use-progress.ts +12 -2
- package/lib/packages/remote-resource/define-remote-resource.ts +64 -29
- package/lib/packages/sidebar/index.ts +2 -0
- package/lib/packages/sidebar/sidebar.store.ts +55 -0
- package/lib/packages/sidebar/types.ts +21 -0
- package/lib/packages/sidebar/use-sidebar-resize.ts +47 -0
- package/lib/packages/sidebar/use-sidebar-responsive-expand.ts +19 -0
- package/lib/packages/tree/types.ts +6 -0
- package/lib/packages/tree/use-tree.ts +38 -37
- package/lib/stores/panel.store.ts +56 -5
- package/lib/tables/column-definitions/action-column.ts +21 -9
- package/lib/tables/column-definitions/user-name-column.ts +10 -0
- package/lib/tables/column-sets/server-columns.ts +2 -2
- package/lib/tables/column-sets/user-columns.ts +16 -0
- package/lib/tables/column-sets/vm-columns.ts +2 -3
- package/lib/types/object.type.ts +9 -1
- package/lib/types/state-hero.type.ts +19 -0
- package/lib/types/task.type.ts +5 -12
- package/lib/types/vue-virtual-scroller.d.ts +8 -2
- package/lib/utils/injection-keys.util.ts +4 -2
- package/lib/utils/ip-address.utils.ts +7 -0
- package/lib/utils/sr.utils.ts +4 -0
- package/package.json +2 -1
- package/lib/stores/sidebar.store.ts +0 -79
|
@@ -6,12 +6,15 @@
|
|
|
6
6
|
|
|
7
7
|
<script lang="ts" setup>
|
|
8
8
|
import { IK_TREE_LIST_DEPTH } from '@core/utils/injection-keys.util'
|
|
9
|
-
import { inject, provide } from 'vue'
|
|
9
|
+
import { computed, inject, provide, ref } from 'vue'
|
|
10
10
|
|
|
11
11
|
defineSlots<{
|
|
12
12
|
default(): any
|
|
13
13
|
}>()
|
|
14
14
|
|
|
15
|
-
const depth = inject(IK_TREE_LIST_DEPTH, 0)
|
|
16
|
-
provide(
|
|
15
|
+
const depth = inject(IK_TREE_LIST_DEPTH, ref(0))
|
|
16
|
+
provide(
|
|
17
|
+
IK_TREE_LIST_DEPTH,
|
|
18
|
+
computed(() => depth.value + 1)
|
|
19
|
+
)
|
|
17
20
|
</script>
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<div class="label-placeholder">
|
|
4
4
|
<div class="link-placeholder">
|
|
5
5
|
<template v-if="depth > 1">
|
|
6
|
-
<VtsTreeLine v-for="i in depth - 1" :key="i" :right="i === depth - 1"
|
|
6
|
+
<VtsTreeLine v-for="i in depth - 1" :key="i" :right="i === depth - 1" />
|
|
7
7
|
</template>
|
|
8
8
|
<VtsIcon :name="icon" size="medium" />
|
|
9
9
|
<div class="loader"> </div>
|
|
@@ -17,13 +17,13 @@ import VtsIcon from '@core/components/icon/VtsIcon.vue'
|
|
|
17
17
|
import VtsTreeLine from '@core/components/tree/VtsTreeLine.vue'
|
|
18
18
|
import type { IconName } from '@core/icons'
|
|
19
19
|
import { IK_TREE_LIST_DEPTH } from '@core/utils/injection-keys.util'
|
|
20
|
-
import { inject } from 'vue'
|
|
20
|
+
import { inject, ref } from 'vue'
|
|
21
21
|
|
|
22
22
|
defineProps<{
|
|
23
23
|
icon: IconName
|
|
24
24
|
}>()
|
|
25
25
|
|
|
26
|
-
const depth = inject(IK_TREE_LIST_DEPTH, 0)
|
|
26
|
+
const depth = inject(IK_TREE_LIST_DEPTH, ref(0))
|
|
27
27
|
</script>
|
|
28
28
|
|
|
29
29
|
<style lang="postcss" scoped>
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<div class="ui-head-bar">
|
|
4
4
|
<div class="label-wrapper">
|
|
5
5
|
<slot name="icon">
|
|
6
|
-
<VtsIcon :name="icon" size="
|
|
6
|
+
<VtsIcon :name="icon" size="large" />
|
|
7
7
|
</slot>
|
|
8
8
|
<h4 v-tooltip class="typo-h4 label text-ellipsis">
|
|
9
9
|
<slot />
|
|
@@ -37,7 +37,7 @@ const slots = defineSlots<{
|
|
|
37
37
|
|
|
38
38
|
<style lang="postcss" scoped>
|
|
39
39
|
.ui-head-bar {
|
|
40
|
-
min-height:
|
|
40
|
+
min-height: 6rem;
|
|
41
41
|
padding: 0.8rem 1.6rem;
|
|
42
42
|
display: flex;
|
|
43
43
|
gap: 1.6rem;
|
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
<!--
|
|
1
|
+
<!-- v9 -->
|
|
2
2
|
<template>
|
|
3
|
-
<div :class="toVariants({ accent, disabled })" class="ui-input" @click.self="focus()">
|
|
3
|
+
<div :class="toVariants({ accent, disabled, selected })" class="ui-input" @click.self="focus()">
|
|
4
|
+
<span v-if="slots.prefix || prefix" class="prefix">
|
|
5
|
+
<slot name="prefix">
|
|
6
|
+
{{ prefix }}
|
|
7
|
+
</slot>
|
|
8
|
+
</span>
|
|
4
9
|
<span v-if="readonly" class="typo-body-regular input text-ellipsis">
|
|
5
10
|
<input ref="inputRef" class="readonly-input" readonly type="text" />
|
|
6
11
|
{{ modelValue }}
|
|
@@ -19,14 +24,19 @@
|
|
|
19
24
|
/>
|
|
20
25
|
<UiButtonIcon
|
|
21
26
|
v-if="!disabled && modelValue && clearable"
|
|
22
|
-
icon="fa:xmark"
|
|
23
|
-
accent="brand"
|
|
24
27
|
size="small"
|
|
28
|
+
icon="action:close-cancel-clear"
|
|
29
|
+
accent="brand"
|
|
25
30
|
@click="clear()"
|
|
26
31
|
/>
|
|
27
32
|
<slot v-if="slots['right-icon'] || rightIcon" name="right-icon">
|
|
28
33
|
<VtsIcon :name="rightIcon" size="medium" class="right-icon" />
|
|
29
34
|
</slot>
|
|
35
|
+
<span v-if="slots.suffix || suffix" class="suffix">
|
|
36
|
+
<slot name="suffix">
|
|
37
|
+
{{ suffix }}
|
|
38
|
+
</slot>
|
|
39
|
+
</span>
|
|
30
40
|
</div>
|
|
31
41
|
</template>
|
|
32
42
|
|
|
@@ -52,16 +62,20 @@ const {
|
|
|
52
62
|
required,
|
|
53
63
|
disabled,
|
|
54
64
|
id,
|
|
65
|
+
detached,
|
|
55
66
|
} = defineProps<{
|
|
56
67
|
accent: InputAccent
|
|
57
68
|
id?: string
|
|
58
69
|
required?: boolean
|
|
59
70
|
disabled?: boolean
|
|
71
|
+
selected?: boolean
|
|
60
72
|
readonly?: boolean
|
|
73
|
+
detached?: boolean
|
|
61
74
|
type?: InputType
|
|
62
|
-
icon?: IconName
|
|
63
75
|
rightIcon?: IconName
|
|
64
76
|
clearable?: boolean
|
|
77
|
+
prefix?: string
|
|
78
|
+
suffix?: string
|
|
65
79
|
}>()
|
|
66
80
|
|
|
67
81
|
const emit = defineEmits<{
|
|
@@ -72,6 +86,8 @@ const modelValue = defineModel<string | number | undefined>({ required: true })
|
|
|
72
86
|
|
|
73
87
|
const slots = defineSlots<{
|
|
74
88
|
'right-icon'?(): any
|
|
89
|
+
prefix?(): any
|
|
90
|
+
suffix?(): any
|
|
75
91
|
}>()
|
|
76
92
|
|
|
77
93
|
function handleInput(event: Event) {
|
|
@@ -82,7 +98,7 @@ const attrs = useAttrs()
|
|
|
82
98
|
|
|
83
99
|
const inputRef = ref<HTMLInputElement>()
|
|
84
100
|
|
|
85
|
-
const wrapperController = inject(IK_INPUT_WRAPPER_CONTROLLER, undefined)
|
|
101
|
+
const wrapperController = detached ? undefined : inject(IK_INPUT_WRAPPER_CONTROLLER, undefined)
|
|
86
102
|
|
|
87
103
|
const accent = useMapper<LabelAccent, InputAccent>(
|
|
88
104
|
() => wrapperController?.labelAccent,
|
|
@@ -133,6 +149,31 @@ defineExpose({ focus })
|
|
|
133
149
|
color: var(--color-brand-txt-base);
|
|
134
150
|
}
|
|
135
151
|
|
|
152
|
+
.prefix,
|
|
153
|
+
.suffix {
|
|
154
|
+
display: flex;
|
|
155
|
+
align-items: center;
|
|
156
|
+
justify-content: center;
|
|
157
|
+
align-self: stretch;
|
|
158
|
+
background-color: var(--color-neutral-background-secondary);
|
|
159
|
+
padding: 0.8rem 1.6rem;
|
|
160
|
+
color: var(--color-neutral-txt-secondary);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.prefix {
|
|
164
|
+
border-end-start-radius: 0.4rem;
|
|
165
|
+
border-start-start-radius: 0.4rem;
|
|
166
|
+
border-inline-end: 0.1rem solid var(--color-neutral-border);
|
|
167
|
+
margin-inline-start: -1.6rem;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.suffix {
|
|
171
|
+
border-end-end-radius: 0.4rem;
|
|
172
|
+
border-start-end-radius: 0.4rem;
|
|
173
|
+
border-inline-start: 0.1rem solid var(--color-neutral-border);
|
|
174
|
+
margin-inline-end: -1.6rem;
|
|
175
|
+
}
|
|
176
|
+
|
|
136
177
|
&.disabled .right-icon {
|
|
137
178
|
color: var(--color-neutral-txt-secondary);
|
|
138
179
|
}
|
|
@@ -161,12 +202,9 @@ defineExpose({ focus })
|
|
|
161
202
|
/* VARIANT */
|
|
162
203
|
|
|
163
204
|
&.accent--brand {
|
|
205
|
+
--selected-color: var(--color-brand-item-base);
|
|
164
206
|
border-color: var(--color-neutral-border);
|
|
165
207
|
|
|
166
|
-
&:focus-within {
|
|
167
|
-
border-color: var(--color-brand-item-base);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
208
|
&:hover {
|
|
171
209
|
border-color: var(--color-brand-item-hover);
|
|
172
210
|
}
|
|
@@ -182,6 +220,7 @@ defineExpose({ focus })
|
|
|
182
220
|
}
|
|
183
221
|
|
|
184
222
|
&.accent--warning {
|
|
223
|
+
--selected-color: var(--color-warning-item-base);
|
|
185
224
|
border-color: var(--color-warning-item-base);
|
|
186
225
|
|
|
187
226
|
&:hover {
|
|
@@ -199,6 +238,7 @@ defineExpose({ focus })
|
|
|
199
238
|
}
|
|
200
239
|
|
|
201
240
|
&.accent--danger {
|
|
241
|
+
--selected-color: var(--color-danger-item-base);
|
|
202
242
|
border-color: var(--color-danger-item-base);
|
|
203
243
|
|
|
204
244
|
&:hover {
|
|
@@ -214,5 +254,11 @@ defineExpose({ focus })
|
|
|
214
254
|
background-color: var(--color-neutral-background-disabled);
|
|
215
255
|
}
|
|
216
256
|
}
|
|
257
|
+
|
|
258
|
+
&:focus-within,
|
|
259
|
+
&.selected {
|
|
260
|
+
border-color: var(--selected-color);
|
|
261
|
+
border-width: 0.2rem;
|
|
262
|
+
}
|
|
217
263
|
}
|
|
218
264
|
</style>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<!-- v6 -->
|
|
2
2
|
<template>
|
|
3
3
|
<component :is="component" :class="classes" class="ui-link" v-bind="attributes">
|
|
4
|
-
<VtsIcon :name="icon" size="medium" />
|
|
4
|
+
<VtsIcon :name="icon" :busy :busy-tooltip size="medium" />
|
|
5
5
|
<slot />
|
|
6
6
|
<VtsIcon v-if="attributes.target === '_blank'" name="action:open-in-new-tab" size="medium" class="external-icon" />
|
|
7
7
|
<VtsIcon v-if="isPrimary" v-tooltip="primaryTooltip" name="status:primary-circle" size="medium" />
|
|
@@ -19,6 +19,8 @@ const props = defineProps<
|
|
|
19
19
|
LinkOptions & {
|
|
20
20
|
size: 'small' | 'medium'
|
|
21
21
|
icon?: IconName
|
|
22
|
+
busy?: boolean
|
|
23
|
+
busyTooltip?: string
|
|
22
24
|
isPrimary?: boolean
|
|
23
25
|
primaryTooltip?: string
|
|
24
26
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
<!--
|
|
1
|
+
<!-- v5 -->
|
|
2
2
|
<template>
|
|
3
|
-
<div class="ui-panel" :class="{ error
|
|
3
|
+
<div class="ui-panel" :class="{ error }">
|
|
4
4
|
<div v-if="slots.header" class="header">
|
|
5
5
|
<slot name="header" />
|
|
6
6
|
</div>
|
|
@@ -11,8 +11,6 @@
|
|
|
11
11
|
</template>
|
|
12
12
|
|
|
13
13
|
<script setup lang="ts">
|
|
14
|
-
import { useUiStore } from '@core/stores/ui.store'
|
|
15
|
-
|
|
16
14
|
defineProps<{
|
|
17
15
|
error?: boolean
|
|
18
16
|
}>()
|
|
@@ -21,31 +19,25 @@ const slots = defineSlots<{
|
|
|
21
19
|
default(): any
|
|
22
20
|
header?(): any
|
|
23
21
|
}>()
|
|
24
|
-
|
|
25
|
-
const uiStore = useUiStore()
|
|
26
22
|
</script>
|
|
27
23
|
|
|
28
24
|
<style scoped lang="postcss">
|
|
29
25
|
.ui-panel {
|
|
30
|
-
position: sticky;
|
|
31
|
-
top: 0;
|
|
32
26
|
display: flex;
|
|
33
27
|
flex-direction: column;
|
|
34
28
|
border-inline-start: 0.1rem solid var(--color-neutral-border);
|
|
29
|
+
border-block-end: 0.1rem solid var(--color-neutral-border);
|
|
30
|
+
border-end-start-radius: 0.8rem;
|
|
35
31
|
background-color: var(--color-neutral-background-secondary);
|
|
36
32
|
|
|
37
|
-
&:not(.mobile-drawer) {
|
|
38
|
-
min-height: calc(100dvh - 16rem);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
33
|
.header {
|
|
34
|
+
flex-shrink: 0;
|
|
35
|
+
padding: 0.4rem 1.6rem;
|
|
42
36
|
border-bottom: 0.1rem solid var(--color-neutral-border);
|
|
43
37
|
background-color: var(--color-neutral-background-primary);
|
|
44
38
|
display: flex;
|
|
45
|
-
justify-content: flex-end;
|
|
46
39
|
align-items: center;
|
|
47
40
|
gap: 1.6rem;
|
|
48
|
-
padding: 0.4rem 1.6rem;
|
|
49
41
|
}
|
|
50
42
|
|
|
51
43
|
.content {
|
|
@@ -53,20 +45,11 @@ const uiStore = useUiStore()
|
|
|
53
45
|
flex-direction: column;
|
|
54
46
|
padding: 0.8rem;
|
|
55
47
|
gap: 0.8rem;
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
&.mobile-drawer {
|
|
59
|
-
.content {
|
|
60
|
-
overflow: auto;
|
|
61
|
-
}
|
|
48
|
+
scrollbar-width: thin;
|
|
62
49
|
}
|
|
63
50
|
|
|
64
51
|
&.error {
|
|
65
52
|
background-color: var(--color-danger-background-selected);
|
|
66
|
-
|
|
67
|
-
.content {
|
|
68
|
-
padding-top: 15rem;
|
|
69
|
-
}
|
|
70
53
|
}
|
|
71
54
|
}
|
|
72
55
|
</style>
|
|
@@ -10,24 +10,12 @@
|
|
|
10
10
|
type="text"
|
|
11
11
|
accent="brand"
|
|
12
12
|
:aria-label="uiStore.isSmall ? t('query-search-bar:label') : undefined"
|
|
13
|
-
:icon="!uiStore.isSmall ? 'fa:magnifying-glass' : undefined"
|
|
14
13
|
:placeholder="t('query-search-bar:placeholder')"
|
|
15
14
|
/>
|
|
16
15
|
<template v-if="!uiStore.isSmall">
|
|
17
|
-
<UiButton size="medium" accent="brand" variant="
|
|
16
|
+
<UiButton size="medium" accent="brand" variant="secondary" type="submit" class="action-button">
|
|
18
17
|
{{ t('action:search') }}
|
|
19
18
|
</UiButton>
|
|
20
|
-
<VtsDivider type="stretch" />
|
|
21
|
-
<UiButton
|
|
22
|
-
v-tooltip="t('coming-soon!')"
|
|
23
|
-
size="medium"
|
|
24
|
-
accent="brand"
|
|
25
|
-
variant="secondary"
|
|
26
|
-
disabled
|
|
27
|
-
class="action-button"
|
|
28
|
-
>
|
|
29
|
-
{{ t('query-search-bar:use-query-builder') }}
|
|
30
|
-
</UiButton>
|
|
31
19
|
</template>
|
|
32
20
|
|
|
33
21
|
<!-- Mobile icons: search + filter -->
|
|
@@ -39,11 +27,9 @@
|
|
|
39
27
|
</template>
|
|
40
28
|
|
|
41
29
|
<script lang="ts" setup>
|
|
42
|
-
import VtsDivider from '@core/components/divider/VtsDivider.vue'
|
|
43
30
|
import UiButton from '@core/components/ui/button/UiButton.vue'
|
|
44
31
|
import UiButtonIcon from '@core/components/ui/button-icon/UiButtonIcon.vue'
|
|
45
32
|
import UiInput from '@core/components/ui/input/UiInput.vue'
|
|
46
|
-
import { vTooltip } from '@core/directives/tooltip.directive'
|
|
47
33
|
import { useUiStore } from '@core/stores/ui.store'
|
|
48
34
|
import { uniqueId } from '@core/utils/unique-id.util'
|
|
49
35
|
import { ref } from 'vue'
|
|
@@ -34,7 +34,7 @@ import VtsIcon from '@core/components/icon/VtsIcon.vue'
|
|
|
34
34
|
import VtsQuickTaskList from '@core/components/task/VtsQuickTaskList.vue'
|
|
35
35
|
import UiButtonIcon from '@core/components/ui/button-icon/UiButtonIcon.vue'
|
|
36
36
|
import UiTag from '@core/components/ui/tag/UiTag.vue'
|
|
37
|
-
import type { Task } from '@core/
|
|
37
|
+
import type { Task } from '@core/components/ui/task-item/UiTaskItem.vue'
|
|
38
38
|
import { useToggle } from '@vueuse/core'
|
|
39
39
|
import { computed } from 'vue'
|
|
40
40
|
import { useI18n } from 'vue-i18n'
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
<script lang="ts" setup>
|
|
16
16
|
import VtsQuickTaskList from '@core/components/task/VtsQuickTaskList.vue'
|
|
17
17
|
import VtsQuickTaskTabBar, { type TaskTab } from '@core/components/task/VtsQuickTaskTabBar.vue'
|
|
18
|
+
import type { Task } from '@core/components/ui/task-item/UiTaskItem.vue'
|
|
18
19
|
import { useUiStore } from '@core/stores/ui.store'
|
|
19
|
-
import type { Task } from '@core/types/task.type.ts'
|
|
20
20
|
import { computed, ref } from 'vue'
|
|
21
21
|
|
|
22
22
|
const props = defineProps<{
|
|
@@ -21,10 +21,13 @@
|
|
|
21
21
|
</div>
|
|
22
22
|
|
|
23
23
|
<div class="main-content">
|
|
24
|
-
<div v-if="task.name" class="content-left">
|
|
25
|
-
<
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
<div v-if="task.nameParts || task.name" class="content-left">
|
|
25
|
+
<template v-if="task.nameParts">
|
|
26
|
+
<template v-for="(part, index) in task.nameParts" :key="index">
|
|
27
|
+
<UiLink size="medium" :to="part.to">{{ part.text }}</UiLink>
|
|
28
|
+
</template>
|
|
29
|
+
</template>
|
|
30
|
+
<UiLink v-else size="small">{{ task.name }}</UiLink>
|
|
28
31
|
<div v-if="shouldShowInfos || hasSubTasks" class="infos">
|
|
29
32
|
<UiCounter v-if="hasSubTasks" :value="subTasksCount" accent="brand" variant="secondary" size="small" />
|
|
30
33
|
<UiInfo v-if="hasInfos" accent="info" />
|
|
@@ -41,7 +44,7 @@
|
|
|
41
44
|
<UiCircleProgressBar :accent="progressAccent" size="small" :value="progress" />
|
|
42
45
|
</div>
|
|
43
46
|
<div class="actions">
|
|
44
|
-
<UiButtonIcon icon="fa:eye" size="
|
|
47
|
+
<UiButtonIcon icon="fa:eye" size="small" accent="brand" @click="emit('select', task.id)" />
|
|
45
48
|
</div>
|
|
46
49
|
</div>
|
|
47
50
|
</div>
|
|
@@ -61,6 +64,7 @@ import UiLink from '@core/components/ui/link/UiLink.vue'
|
|
|
61
64
|
import UiTaskList from '@core/components/ui/task-list/UiTaskList.vue'
|
|
62
65
|
import { useTimeAgo } from '@core/composables/locale-time-ago.composable.ts'
|
|
63
66
|
import { vTooltip } from '@core/directives/tooltip.directive'
|
|
67
|
+
import type { TaskObjectSegment, TaskStatus } from '@core/types/task.type.ts'
|
|
64
68
|
import { logicOr } from '@vueuse/math'
|
|
65
69
|
import { computed } from 'vue'
|
|
66
70
|
import { useI18n } from 'vue-i18n'
|
|
@@ -69,9 +73,13 @@ export type Task = {
|
|
|
69
73
|
id: string
|
|
70
74
|
infos?: { data: unknown; message: string }[]
|
|
71
75
|
name?: string
|
|
76
|
+
nameParts?: TaskObjectSegment[]
|
|
72
77
|
progress?: number
|
|
78
|
+
tag?: string
|
|
79
|
+
userName?: string
|
|
80
|
+
start?: number
|
|
73
81
|
end?: number
|
|
74
|
-
status:
|
|
82
|
+
status: TaskStatus
|
|
75
83
|
subtasks?: Task[]
|
|
76
84
|
warnings?: { data: unknown; message: string }[]
|
|
77
85
|
}
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
|
|
17
17
|
<script lang="ts" setup>
|
|
18
18
|
import UiTaskItem from '@core/components/ui/task-item/UiTaskItem.vue'
|
|
19
|
+
import type { Task } from '@core/components/ui/task-item/UiTaskItem.vue'
|
|
19
20
|
import { useCollection } from '@core/packages/collection'
|
|
20
|
-
import type { Task } from '@core/types/task.type.ts'
|
|
21
21
|
|
|
22
22
|
const { tasks, depth = 0 } = defineProps<{
|
|
23
23
|
tasks: Task[]
|
|
@@ -1,16 +1,19 @@
|
|
|
1
|
-
<!--
|
|
1
|
+
<!-- v5 -->
|
|
2
2
|
<template>
|
|
3
|
-
<div class="ui-textarea" :class="toVariants({ accent:
|
|
3
|
+
<div class="ui-textarea" :class="toVariants({ accent: isExceedingMaxCharacters ? 'danger' : accent })">
|
|
4
4
|
<UiLabel v-if="slots.default" :accent="labelAccent" :required :href :for="id">
|
|
5
5
|
<slot />
|
|
6
6
|
</UiLabel>
|
|
7
7
|
<textarea v-bind="attrs" :id ref="textarea" v-model="model" :disabled class="textarea" />
|
|
8
8
|
<UiCharacterLimit v-if="maxCharacters" :count="model.trim().length" :max="maxCharacters" />
|
|
9
|
+
<UiInfo v-if="slots.info" accent="info">
|
|
10
|
+
<slot name="info" />
|
|
11
|
+
</UiInfo>
|
|
9
12
|
<UiInfo v-if="isExceedingMaxCharacters" accent="danger">
|
|
10
13
|
{{ t('field:exceeds-max-characters', { max: maxCharacters }) }}
|
|
11
14
|
</UiInfo>
|
|
12
|
-
<UiInfo v-if="slots.
|
|
13
|
-
<slot name="
|
|
15
|
+
<UiInfo v-if="slots.message && labelAccent !== 'neutral'" :accent="labelAccent">
|
|
16
|
+
<slot name="message" />
|
|
14
17
|
</UiInfo>
|
|
15
18
|
</div>
|
|
16
19
|
</template>
|
|
@@ -46,6 +49,7 @@ const model = defineModel<string>({ required: true })
|
|
|
46
49
|
const slots = defineSlots<{
|
|
47
50
|
default?(): any
|
|
48
51
|
info?(): any
|
|
52
|
+
message?(): any
|
|
49
53
|
}>()
|
|
50
54
|
|
|
51
55
|
const { t } = useI18n()
|
|
@@ -58,16 +62,10 @@ const { focused } = useFocus(textAreaElement)
|
|
|
58
62
|
|
|
59
63
|
// WIP: To update when using VeeValidate and custom validation rules
|
|
60
64
|
const isExceedingMaxCharacters = computed(() =>
|
|
61
|
-
maxCharacters !== undefined ? model.value.trim().length > maxCharacters : false
|
|
65
|
+
maxCharacters !== undefined ? !focused.value && model.value.trim().length > maxCharacters : false
|
|
62
66
|
)
|
|
63
67
|
|
|
64
|
-
const hasMaxCharactersError = computed(() => !focused.value && isExceedingMaxCharacters.value)
|
|
65
|
-
|
|
66
68
|
const labelAccent = computed(() => {
|
|
67
|
-
if (hasMaxCharactersError.value) {
|
|
68
|
-
return 'danger'
|
|
69
|
-
}
|
|
70
|
-
|
|
71
69
|
return accent === 'brand' ? 'neutral' : accent
|
|
72
70
|
})
|
|
73
71
|
</script>
|
|
@@ -101,8 +99,8 @@ const labelAccent = computed(() => {
|
|
|
101
99
|
}
|
|
102
100
|
|
|
103
101
|
&:focus:not(:active) {
|
|
104
|
-
border-width: 0.2rem;
|
|
105
102
|
border-color: var(--color-brand-item-base);
|
|
103
|
+
box-shadow: inset 0 0 0 0.1rem var(--color-brand-item-base);
|
|
106
104
|
}
|
|
107
105
|
|
|
108
106
|
&:disabled {
|
|
@@ -125,8 +123,8 @@ const labelAccent = computed(() => {
|
|
|
125
123
|
}
|
|
126
124
|
|
|
127
125
|
&:focus:not(:active) {
|
|
128
|
-
border-width: 0.2rem;
|
|
129
126
|
border-color: var(--color-warning-item-base);
|
|
127
|
+
box-shadow: inset 0 0 0 0.1rem var(--color-warning-item-base);
|
|
130
128
|
}
|
|
131
129
|
|
|
132
130
|
&:disabled {
|
|
@@ -149,8 +147,8 @@ const labelAccent = computed(() => {
|
|
|
149
147
|
}
|
|
150
148
|
|
|
151
149
|
&:focus:not(:active) {
|
|
152
|
-
border-width: 0.2rem;
|
|
153
150
|
border-color: var(--color-danger-item-base);
|
|
151
|
+
box-shadow: inset 0 0 0 0.1rem var(--color-danger-item-base);
|
|
154
152
|
}
|
|
155
153
|
|
|
156
154
|
&:disabled {
|
|
@@ -72,7 +72,7 @@ const hasToggle = inject(IK_TREE_ITEM_HAS_CHILDREN, ref(false))
|
|
|
72
72
|
|
|
73
73
|
const isExpanded = inject(IK_TREE_ITEM_EXPANDED, ref(true))
|
|
74
74
|
|
|
75
|
-
const depth = inject(IK_TREE_LIST_DEPTH, 0)
|
|
75
|
+
const depth = inject(IK_TREE_LIST_DEPTH, ref(0))
|
|
76
76
|
</script>
|
|
77
77
|
|
|
78
78
|
<style lang="postcss" scoped>
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<VtsModal accent="info" icon="status:info-picto" dismissible>
|
|
3
|
+
<template #title>
|
|
4
|
+
{{ connection.title }}
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<template v-if="action === CONNECTION_ACTION.DISCONNECT" #content>
|
|
8
|
+
{{ t('vif-disconnect-info') }}
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<template #buttons>
|
|
12
|
+
<VtsModalCancelButton>{{ t('action:go-back') }}</VtsModalCancelButton>
|
|
13
|
+
<VtsModalConfirmButton>
|
|
14
|
+
{{ connection.action }}
|
|
15
|
+
</VtsModalConfirmButton>
|
|
16
|
+
</template>
|
|
17
|
+
</VtsModal>
|
|
18
|
+
</template>
|
|
19
|
+
|
|
20
|
+
<script lang="ts" setup>
|
|
21
|
+
import VtsModal from '@core/components/modal/VtsModal.vue'
|
|
22
|
+
import VtsModalCancelButton from '@core/components/modal/VtsModalCancelButton.vue'
|
|
23
|
+
import VtsModalConfirmButton from '@core/components/modal/VtsModalConfirmButton.vue'
|
|
24
|
+
import { useMapper } from '@core/packages/mapper'
|
|
25
|
+
import { CONNECTION_ACTION, type ConnectionAction } from '@core/types/connection.ts'
|
|
26
|
+
import { useI18n } from 'vue-i18n'
|
|
27
|
+
|
|
28
|
+
const { action, count } = defineProps<{
|
|
29
|
+
action: ConnectionAction
|
|
30
|
+
count: number
|
|
31
|
+
}>()
|
|
32
|
+
|
|
33
|
+
const { t } = useI18n()
|
|
34
|
+
|
|
35
|
+
const connection = useMapper(
|
|
36
|
+
() => action,
|
|
37
|
+
() => ({
|
|
38
|
+
connect: { title: t('vif-connect-title', { n: count }), action: t('action:connect-n-vifs', { n: count }) },
|
|
39
|
+
disconnect: { title: t('vif-disconnect-title', { n: count }), action: t('action:disconnect-n-vifs', { n: count }) },
|
|
40
|
+
}),
|
|
41
|
+
'connect'
|
|
42
|
+
)
|
|
43
|
+
</script>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# useMultiSelect composable
|
|
2
|
+
|
|
3
|
+
```vue
|
|
4
|
+
<template>
|
|
5
|
+
<table>
|
|
6
|
+
<thead>
|
|
7
|
+
<tr>
|
|
8
|
+
<th>
|
|
9
|
+
<input type="checkbox" v-model="areAllSelected" />
|
|
10
|
+
</th>
|
|
11
|
+
<th>Name</th>
|
|
12
|
+
</tr>
|
|
13
|
+
</thead>
|
|
14
|
+
<tbody>
|
|
15
|
+
<tr v-for="item in items">
|
|
16
|
+
<td>
|
|
17
|
+
<input type="checkbox" :value="item.id" v-model="selected" />
|
|
18
|
+
</td>
|
|
19
|
+
<td>{{ item.name }}</td>
|
|
20
|
+
</tr>
|
|
21
|
+
</tbody>
|
|
22
|
+
</table>
|
|
23
|
+
|
|
24
|
+
<!-- You can use something else than a "Select All" checkbox -->
|
|
25
|
+
<button @click="areAllSelected = !areAllSelected">Toggle all selected</button>
|
|
26
|
+
</template>
|
|
27
|
+
|
|
28
|
+
<script lang="ts" setup>
|
|
29
|
+
import useMultiSelect from './multi-select.composable'
|
|
30
|
+
|
|
31
|
+
const { selected, areAllSelected } = useMultiSelect()
|
|
32
|
+
</script>
|
|
33
|
+
```
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { StateHeroType } from '@core/components/state-hero/VtsStateHero.vue'
|
|
2
1
|
import type { TableState } from '@core/components/table/VtsTable.vue'
|
|
2
|
+
import type { StateHeroType } from '@core/types/state-hero.type.ts'
|
|
3
3
|
import { computed, toValue, type MaybeRefOrGetter } from 'vue'
|
|
4
4
|
import { useI18n } from 'vue-i18n'
|
|
5
5
|
|
|
@@ -4,9 +4,11 @@ import { faCopy, faSquare as checkboxEmpty, type IconDefinition } from '@fortawe
|
|
|
4
4
|
import {
|
|
5
5
|
faAdd,
|
|
6
6
|
faArrowCircleRight,
|
|
7
|
+
faArrowDownLong,
|
|
7
8
|
faArrowRight,
|
|
8
9
|
faArrowRotateLeft,
|
|
9
10
|
faArrowRotateRight,
|
|
11
|
+
faArrowUpLong,
|
|
10
12
|
faArrowUpRightFromSquare,
|
|
11
13
|
faBan,
|
|
12
14
|
faBars,
|
|
@@ -146,6 +148,18 @@ export const actionIcons = defineIconPack({
|
|
|
146
148
|
color: 'var(--color-neutral-txt-primary)',
|
|
147
149
|
rotate: 90,
|
|
148
150
|
},
|
|
151
|
+
'import-export': [
|
|
152
|
+
{
|
|
153
|
+
icon: faArrowUpLong,
|
|
154
|
+
color: 'var(--color-neutral-txt-primary)',
|
|
155
|
+
translate: [-5, 0],
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
icon: faArrowDownLong,
|
|
159
|
+
color: 'var(--color-neutral-txt-primary)',
|
|
160
|
+
translate: [5, 0],
|
|
161
|
+
},
|
|
162
|
+
],
|
|
149
163
|
reboot: constructIcon(faArrowRotateRight),
|
|
150
164
|
'force-reboot': [
|
|
151
165
|
constructIcon(faArrowRotateRight),
|