@xen-orchestra/web-core 0.0.3 → 0.0.4

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.
Files changed (39) hide show
  1. package/lib/assets/css/_typography.pcss +1 -0
  2. package/lib/assets/css/typography/_utils.pcss +6 -0
  3. package/lib/components/UiTag.vue +3 -7
  4. package/lib/components/backdrop/Backdrop.vue +11 -0
  5. package/lib/components/cell-object/CellObject.vue +54 -0
  6. package/lib/components/cell-text/CellText.vue +40 -0
  7. package/lib/components/chip/UiChip.vue +3 -4
  8. package/lib/components/console/RemoteConsole.vue +1 -1
  9. package/lib/components/divider/Divider.vue +25 -0
  10. package/lib/components/dropdown/DropdownItem.vue +1 -4
  11. package/lib/components/head-bar/HeadBar.vue +78 -0
  12. package/lib/components/input/UiInput.vue +133 -0
  13. package/lib/components/object-link/ObjectLink.vue +87 -0
  14. package/lib/components/search-bar/SearchBar.vue +60 -0
  15. package/lib/components/stacked-bar/StackedBarSegment.vue +2 -8
  16. package/lib/components/tab/TabList.vue +1 -0
  17. package/lib/components/table/UiTable.vue +6 -0
  18. package/lib/components/task/QuickTaskButton.vue +62 -0
  19. package/lib/components/task/QuickTaskItem.vue +91 -0
  20. package/lib/components/task/QuickTaskList.vue +48 -0
  21. package/lib/components/task/QuickTaskPanel.vue +65 -0
  22. package/lib/components/task/QuickTaskTabBar.vue +46 -0
  23. package/lib/components/tree/TreeItem.vue +8 -8
  24. package/lib/components/tree/TreeItemLabel.vue +28 -16
  25. package/lib/composables/tab-list.composable.ts +33 -0
  26. package/lib/composables/tree/branch.ts +5 -5
  27. package/lib/i18n.ts +53 -0
  28. package/lib/layouts/CoreLayout.vue +2 -11
  29. package/lib/locales/de.json +7 -1
  30. package/lib/locales/en.json +22 -1
  31. package/lib/locales/fa.json +46 -0
  32. package/lib/locales/fr.json +22 -1
  33. package/lib/types/tab.type.ts +17 -0
  34. package/lib/types/task.type.ts +13 -0
  35. package/lib/types/utility.type.ts +1 -1
  36. package/lib/utils/if-else.utils.ts +3 -3
  37. package/lib/utils/open-url.utils.ts +3 -0
  38. package/package.json +3 -3
  39. package/lib/components/UiSeparator.vue +0 -11
@@ -0,0 +1,62 @@
1
+ <template>
2
+ <ButtonIcon
3
+ ref="buttonRef"
4
+ v-tooltip="{ content: $t('tasks.quick-view'), placement: 'bottom-end' }"
5
+ :dot="hasNewTask"
6
+ :icon="faBarsProgress"
7
+ size="large"
8
+ @click="isPanelOpen = true"
9
+ />
10
+ <Teleport v-if="isPanelOpen" to="body">
11
+ <Backdrop @click="isPanelOpen = false" />
12
+ <QuickTaskPanel ref="panelRef" :loading :tasks />
13
+ </Teleport>
14
+ </template>
15
+
16
+ <script lang="ts" setup>
17
+ import Backdrop from '@core/components/backdrop/Backdrop.vue'
18
+ import ButtonIcon from '@core/components/button/ButtonIcon.vue'
19
+ import QuickTaskPanel from '@core/components/task/QuickTaskPanel.vue'
20
+ import { vTooltip } from '@core/directives/tooltip.directive'
21
+ import type { Task } from '@core/types/task.type'
22
+ import { faBarsProgress } from '@fortawesome/free-solid-svg-icons'
23
+ import { unrefElement, watchArray, whenever } from '@vueuse/core'
24
+ import placementJs from 'placement.js'
25
+ import { computed, nextTick, ref } from 'vue'
26
+
27
+ const props = defineProps<{
28
+ tasks: Task[]
29
+ loading?: boolean
30
+ }>()
31
+
32
+ const ids = computed(() => props.tasks.map(task => task.id))
33
+
34
+ const isPanelOpen = ref(false)
35
+ const hasNewTask = ref(false)
36
+
37
+ watchArray(ids, (_newList, _oldList, addedIds) => {
38
+ if (addedIds.length > 0 && !isPanelOpen.value) {
39
+ hasNewTask.value = true
40
+ }
41
+ })
42
+
43
+ const buttonRef = ref<HTMLButtonElement | null>(null)
44
+ const panelRef = ref<HTMLDivElement | null>(null)
45
+
46
+ whenever(isPanelOpen, async () => {
47
+ await nextTick()
48
+
49
+ const button = unrefElement(buttonRef)
50
+ const panel = unrefElement(panelRef)
51
+
52
+ if (!button || !panel) {
53
+ return
54
+ }
55
+
56
+ placementJs(button, panel, {
57
+ placement: 'bottom-end',
58
+ })
59
+
60
+ hasNewTask.value = false
61
+ })
62
+ </script>
@@ -0,0 +1,91 @@
1
+ <template>
2
+ <li class="vts-quick-task-item">
3
+ <div v-if="hasSubTasks" class="toggle" @click="toggleExpand()">
4
+ <ButtonIcon :icon="isExpanded ? faAngleDown : faAngleRight" size="small" />
5
+ </div>
6
+ <div class="content">
7
+ <div class="typo p1-medium">
8
+ {{ task.name }}
9
+ </div>
10
+ <div class="informations">
11
+ <div class="line-1">
12
+ <UiTag v-if="task.tag" color="grey">{{ task.tag }}</UiTag>
13
+ <div v-if="hasSubTasks" class="subtasks">
14
+ <UiIcon :icon="faCircleNotch" />
15
+ <span class="typo p4-medium">{{ $t('tasks.n-subtasks', { n: subTasksCount }) }}</span>
16
+ </div>
17
+ </div>
18
+ <div v-if="task.start" class="line-2 typo p4-regular">
19
+ {{ $d(task.start, 'datetime_short') }}
20
+ <template v-if="task.end">
21
+ <UiIcon :icon="faArrowRight" />
22
+ {{ $d(new Date(task.end), 'datetime_short') }}
23
+ </template>
24
+ </div>
25
+ </div>
26
+ <QuickTaskList v-if="hasSubTasks && isExpanded" :tasks="subTasks" sublist />
27
+ </div>
28
+ </li>
29
+ </template>
30
+
31
+ <script lang="ts" setup>
32
+ import ButtonIcon from '@core/components/button/ButtonIcon.vue'
33
+ import UiIcon from '@core/components/icon/UiIcon.vue'
34
+ import QuickTaskList from '@core/components/task/QuickTaskList.vue'
35
+ import UiTag from '@core/components/UiTag.vue'
36
+ import type { Task } from '@core/types/task.type'
37
+ import { faAngleDown, faAngleRight, faArrowRight, faCircleNotch } from '@fortawesome/free-solid-svg-icons'
38
+ import { useToggle } from '@vueuse/core'
39
+ import { computed } from 'vue'
40
+
41
+ const props = defineProps<{
42
+ task: Task
43
+ }>()
44
+
45
+ const [isExpanded, toggleExpand] = useToggle()
46
+
47
+ const subTasks = computed(() => props.task.subtasks ?? [])
48
+ const subTasksCount = computed(() => subTasks.value.length)
49
+ const hasSubTasks = computed(() => subTasksCount.value > 0)
50
+ </script>
51
+
52
+ <style lang="postcss" scoped>
53
+ .vts-quick-task-item {
54
+ display: flex;
55
+
56
+ &:not(:last-child) {
57
+ border-bottom: 0.1rem solid var(--color-grey-500);
58
+ }
59
+ }
60
+
61
+ .toggle {
62
+ padding: 0.4rem 0;
63
+ }
64
+
65
+ .content {
66
+ flex: 1;
67
+ padding: 0.4rem 0.4rem 0.4rem 0.8rem;
68
+ }
69
+
70
+ .informations {
71
+ display: flex;
72
+ flex-direction: column;
73
+ gap: 0.4rem;
74
+ }
75
+
76
+ .line-1 {
77
+ display: flex;
78
+ align-items: center;
79
+ gap: 0.2rem 0.8rem;
80
+ }
81
+
82
+ .line-2 {
83
+ color: var(--color-grey-200);
84
+ }
85
+
86
+ .subtasks {
87
+ display: flex;
88
+ align-items: center;
89
+ gap: 0.4rem;
90
+ }
91
+ </style>
@@ -0,0 +1,48 @@
1
+ <template>
2
+ <ul :class="{ sublist }" class="vts-quick-task-list">
3
+ <li v-if="loading">
4
+ <div class="loading">
5
+ <UiSpinner />
6
+ <div>{{ $t('loading-in-progress') }}</div>
7
+ </div>
8
+ </li>
9
+ <template v-else>
10
+ <li v-if="tasks.length === 0" class="typo p1-medium">{{ $t('tasks.no-tasks') }}</li>
11
+ <QuickTaskItem v-for="task of tasks" :key="task.id" :task />
12
+ </template>
13
+ </ul>
14
+ </template>
15
+
16
+ <script lang="ts" setup>
17
+ import QuickTaskItem from '@core/components/task/QuickTaskItem.vue'
18
+ import UiSpinner from '@core/components/UiSpinner.vue'
19
+ import type { Task } from '@core/types/task.type'
20
+
21
+ defineProps<{
22
+ tasks: Task[]
23
+ sublist?: boolean
24
+ loading?: boolean
25
+ }>()
26
+ </script>
27
+
28
+ <style lang="postcss" scoped>
29
+ .vts-quick-task-list {
30
+ display: flex;
31
+ flex-direction: column;
32
+ background-color: var(--background-color-primary);
33
+ padding: 1rem 0;
34
+
35
+ &:not(.sublist) {
36
+ padding: 1.6rem 2rem;
37
+ max-height: 40rem;
38
+ overflow: auto;
39
+ }
40
+ }
41
+
42
+ .loading {
43
+ display: flex;
44
+ align-items: center;
45
+ justify-content: center;
46
+ gap: 1rem;
47
+ }
48
+ </style>
@@ -0,0 +1,65 @@
1
+ <template>
2
+ <div :class="{ mobile: isMobile }" class="vts-quick-tasks">
3
+ <QuickTaskTabBar
4
+ v-model="currentTab"
5
+ :failure-count="failureTasks.length"
6
+ :loading
7
+ :pending-count="pendingTasks.length"
8
+ :success-count="successTasks.length"
9
+ />
10
+ <QuickTaskList :loading :tasks="currentTasks" />
11
+ </div>
12
+ </template>
13
+
14
+ <script lang="ts" setup>
15
+ import QuickTaskList from '@core/components/task/QuickTaskList.vue'
16
+ import QuickTaskTabBar from '@core/components/task/QuickTaskTabBar.vue'
17
+ import { useUiStore } from '@core/stores/ui.store'
18
+ import type { Task, TaskTab } from '@core/types/task.type'
19
+ import { computed, ref } from 'vue'
20
+
21
+ const props = defineProps<{
22
+ tasks: Task[]
23
+ loading?: boolean
24
+ }>()
25
+
26
+ const { isMobile } = useUiStore()
27
+
28
+ const currentTab = ref<TaskTab>('pending')
29
+
30
+ const pendingTasks = computed(() => props.tasks.filter(task => task.status === 'pending'))
31
+ const successTasks = computed(() => props.tasks.filter(task => task.status === 'success'))
32
+ const failureTasks = computed(() => props.tasks.filter(task => task.status === 'failure'))
33
+
34
+ const currentTasks = computed(() => {
35
+ switch (currentTab.value) {
36
+ case 'pending':
37
+ return pendingTasks.value
38
+ case 'success':
39
+ return successTasks.value
40
+ case 'failure':
41
+ return failureTasks.value
42
+ case 'all':
43
+ return props.tasks
44
+ default:
45
+ return []
46
+ }
47
+ })
48
+ </script>
49
+
50
+ <style lang="postcss" scoped>
51
+ .vts-quick-tasks {
52
+ width: fit-content;
53
+ min-width: 65rem;
54
+ border-radius: 0.8rem;
55
+ overflow: hidden;
56
+ border: 0.1rem solid var(--color-grey-500);
57
+ z-index: 1001;
58
+
59
+ &.mobile {
60
+ width: 100%;
61
+ min-width: 0;
62
+ border-radius: 0;
63
+ }
64
+ }
65
+ </style>
@@ -0,0 +1,46 @@
1
+ <template>
2
+ <TabList :disabled="loading">
3
+ <TabItem v-bind="tabs.pending.bindings">
4
+ {{ $t('tasks.quick-view.in-progress') }}
5
+ <UiCounter v-if="pendingCount !== undefined" :value="pendingCount" color="info" />
6
+ </TabItem>
7
+ <TabItem v-bind="tabs.success.bindings">
8
+ {{ $t('tasks.quick-view.done') }}
9
+ <UiCounter v-if="successCount !== undefined" :value="successCount" color="success" />
10
+ </TabItem>
11
+ <TabItem v-bind="tabs.failure.bindings">
12
+ {{ $t('tasks.quick-view.failed') }}
13
+ <UiCounter v-if="failureCount !== undefined" :value="failureCount" color="danger" />
14
+ </TabItem>
15
+ <Divider type="tab" />
16
+ <TabItem v-bind="tabs.all.bindings">
17
+ {{ $t('tasks.quick-view.all') }}
18
+ </TabItem>
19
+ <!--
20
+ TODO
21
+ <UiButton :right-icon="faAngleRight" class="see-all" level="tertiary" size="extra-small">
22
+ {{ $t('see-all') }}
23
+ </UiButton>
24
+ -->
25
+ </TabList>
26
+ </template>
27
+
28
+ <script lang="ts" setup>
29
+ import Divider from '@core/components/divider/Divider.vue'
30
+ import TabItem from '@core/components/tab/TabItem.vue'
31
+ import TabList from '@core/components/tab/TabList.vue'
32
+ import UiCounter from '@core/components/UiCounter.vue'
33
+ import { useTabList } from '@core/composables/tab-list.composable'
34
+ import type { TaskTab } from '@core/types/task.type'
35
+
36
+ defineProps<{
37
+ loading?: boolean
38
+ pendingCount?: number
39
+ successCount?: number
40
+ failureCount?: number
41
+ }>()
42
+
43
+ const currentTab = defineModel<TaskTab>({ required: true })
44
+
45
+ const { tabs } = useTabList<TaskTab>(['pending', 'success', 'failure', 'all'], currentTab)
46
+ </script>
@@ -2,22 +2,23 @@
2
2
  <template>
3
3
  <li class="tree-item">
4
4
  <slot />
5
- <slot v-if="isExpanded" name="sublist" />
5
+ <slot v-if="expanded" name="sublist" />
6
6
  </li>
7
7
  </template>
8
8
 
9
9
  <script lang="ts" setup>
10
- import { IK_TREE_ITEM_EXPANDED, IK_TREE_ITEM_HAS_CHILDREN, IK_TREE_ITEM_TOGGLE } from '@core/utils/injection-keys.util'
11
- import { useToggle } from '@vueuse/core'
12
- import { onBeforeMount, onBeforeUpdate, provide, ref, useSlots } from 'vue'
10
+ import { IK_TREE_ITEM_EXPANDED, IK_TREE_ITEM_HAS_CHILDREN } from '@core/utils/injection-keys.util'
11
+ import { onBeforeMount, onBeforeUpdate, provide, ref, toRef, useSlots } from 'vue'
12
+
13
+ const props = defineProps<{
14
+ expanded?: boolean
15
+ }>()
13
16
 
14
17
  defineSlots<{
15
18
  default: () => void
16
19
  sublist: () => void
17
20
  }>()
18
21
 
19
- const [isExpanded, toggle] = useToggle(true)
20
-
21
22
  const hasChildren = ref(false)
22
23
 
23
24
  const updateHasChildren = () => {
@@ -29,6 +30,5 @@ onBeforeMount(() => updateHasChildren())
29
30
  onBeforeUpdate(() => updateHasChildren())
30
31
 
31
32
  provide(IK_TREE_ITEM_HAS_CHILDREN, hasChildren)
32
- provide(IK_TREE_ITEM_TOGGLE, toggle)
33
- provide(IK_TREE_ITEM_EXPANDED, isExpanded)
33
+ provide(IK_TREE_ITEM_EXPANDED, toRef(props, 'expanded'))
34
34
  </script>
@@ -1,8 +1,8 @@
1
1
  <!-- v1.1 -->
2
2
  <template>
3
- <RouterLink v-slot="{ isExactActive, href, navigate }" :to="route" custom>
3
+ <RouterLink v-slot="{ isExactActive, isActive, href, navigate }" :to="route" custom>
4
4
  <div
5
- :class="isExactActive ? 'exact-active' : active ? 'active' : undefined"
5
+ :class="isExactActive ? 'exact-active' : active || isActive ? 'active' : undefined"
6
6
  class="tree-item-label"
7
7
  v-bind="$attrs"
8
8
  >
@@ -17,16 +17,17 @@
17
17
  <ButtonIcon
18
18
  v-if="hasToggle"
19
19
  v-tooltip="isExpanded ? $t('core.close') : $t('core.open')"
20
+ class="toggle"
20
21
  :icon="isExpanded ? faAngleDown : faAngleRight"
21
22
  size="small"
22
- @click="toggle()"
23
+ @click="emit('toggle')"
23
24
  />
24
- <TreeLine v-else-if="!noIndent" />
25
+ <div v-else class="h-line" />
25
26
  <a v-tooltip="{ selector: '.text' }" :href class="link typo p2-medium" @click="navigate">
26
27
  <slot name="icon">
27
28
  <UiIcon :icon class="icon" />
28
29
  </slot>
29
- <div class="text">
30
+ <div class="text text-ellipsis">
30
31
  <slot />
31
32
  </div>
32
33
  </a>
@@ -40,12 +41,7 @@ import ButtonIcon from '@core/components/button/ButtonIcon.vue'
40
41
  import UiIcon from '@core/components/icon/UiIcon.vue'
41
42
  import TreeLine from '@core/components/tree/TreeLine.vue'
42
43
  import { vTooltip } from '@core/directives/tooltip.directive'
43
- import {
44
- IK_TREE_ITEM_EXPANDED,
45
- IK_TREE_ITEM_HAS_CHILDREN,
46
- IK_TREE_ITEM_TOGGLE,
47
- IK_TREE_LIST_DEPTH,
48
- } from '@core/utils/injection-keys.util'
44
+ import { IK_TREE_ITEM_EXPANDED, IK_TREE_ITEM_HAS_CHILDREN, IK_TREE_LIST_DEPTH } from '@core/utils/injection-keys.util'
49
45
  import type { IconDefinition } from '@fortawesome/fontawesome-common-types'
50
46
  import { faAngleDown, faAngleRight } from '@fortawesome/free-solid-svg-icons'
51
47
  import { inject, ref } from 'vue'
@@ -59,12 +55,14 @@ defineProps<{
59
55
  icon?: IconDefinition
60
56
  route: RouteLocationRaw
61
57
  active?: boolean
62
- noIndent?: boolean
58
+ }>()
59
+
60
+ const emit = defineEmits<{
61
+ toggle: []
63
62
  }>()
64
63
 
65
64
  const hasToggle = inject(IK_TREE_ITEM_HAS_CHILDREN, ref(false))
66
65
 
67
- const toggle = inject(IK_TREE_ITEM_TOGGLE, () => undefined)
68
66
  const isExpanded = inject(IK_TREE_ITEM_EXPANDED, ref(true))
69
67
 
70
68
  const depth = inject(IK_TREE_LIST_DEPTH, 0)
@@ -120,13 +118,27 @@ const depth = inject(IK_TREE_LIST_DEPTH, 0)
120
118
  }
121
119
 
122
120
  .text {
123
- overflow: hidden;
124
- white-space: nowrap;
125
- text-overflow: ellipsis;
126
121
  padding-inline-end: 0.4rem;
127
122
  }
128
123
 
129
124
  .icon {
130
125
  font-size: 1.6rem;
131
126
  }
127
+
128
+ .h-line {
129
+ width: 2rem;
130
+ border-bottom: 0.1rem solid var(--color-purple-base);
131
+ margin-left: -0.4rem;
132
+ }
133
+
134
+ /*
135
+ * Increase the size of the clickable area,
136
+ * without changing the padding of the ButtonIcon component
137
+ */
138
+ .toggle::after {
139
+ content: '';
140
+ position: absolute;
141
+ inset: 0;
142
+ transform: scale(1.5, 2);
143
+ }
132
144
  </style>
@@ -0,0 +1,33 @@
1
+ import type { Tab, TabList } from '@core/types/tab.type'
2
+ import { computed, type MaybeRefOrGetter, type Ref, toRef } from 'vue'
3
+
4
+ export function useTabList<TName extends string>(names: TName[], initialTab?: MaybeRefOrGetter<TName>) {
5
+ const currentTab = toRef(initialTab) as Ref<TName | undefined>
6
+
7
+ const activate = (name: TName | undefined) => {
8
+ currentTab.value = name
9
+ }
10
+
11
+ const isActive = (name: TName) => currentTab.value === name
12
+
13
+ const tabs = computed(() => {
14
+ return Object.fromEntries(
15
+ names.map(name => [
16
+ name,
17
+ {
18
+ isActive: isActive(name),
19
+ activate: () => activate(name),
20
+ bindings: {
21
+ onClick: (event: MouseEvent) => {
22
+ event.preventDefault()
23
+ activate(name)
24
+ },
25
+ active: isActive(name),
26
+ },
27
+ },
28
+ ])
29
+ ) as Record<TName, Tab>
30
+ })
31
+
32
+ return { currentTab, activate, isActive, tabs } as TabList<TName>
33
+ }
@@ -40,7 +40,11 @@ export class Branch<
40
40
  }
41
41
 
42
42
  get failsFilterDownwards(): boolean {
43
- return this.passesFilter !== true && this.rawChildren.every(child => child.failsFilterDownwards)
43
+ if (this.passesFilter !== undefined) {
44
+ return !this.passesFilter
45
+ }
46
+
47
+ return this.rawChildren.length > 0 && this.rawChildren.every(child => child.failsFilterDownwards)
44
48
  }
45
49
 
46
50
  get isExcluded() {
@@ -48,10 +52,6 @@ export class Branch<
48
52
  return true
49
53
  }
50
54
 
51
- if (!this.hasChildren) {
52
- return true
53
- }
54
-
55
55
  if (this.passesFilterUpwards || this.passesFilterDownwards) {
56
56
  return false
57
57
  }
package/lib/i18n.ts CHANGED
@@ -21,6 +21,10 @@ export const locales: Locales = {
21
21
  code: 'de',
22
22
  name: 'Deutsch',
23
23
  },
24
+ fa: {
25
+ code: 'fa',
26
+ name: 'Persian',
27
+ },
24
28
  }
25
29
 
26
30
  export default createI18n({
@@ -163,6 +167,48 @@ export default createI18n({
163
167
  minute: '2-digit',
164
168
  },
165
169
  },
170
+ fa: {
171
+ date_short: {
172
+ year: 'numeric',
173
+ month: 'numeric',
174
+ day: 'numeric',
175
+ },
176
+ date_medium: {
177
+ year: 'numeric',
178
+ month: 'short',
179
+ day: 'numeric',
180
+ },
181
+ date_long: {
182
+ year: 'numeric',
183
+ month: 'long',
184
+ day: 'numeric',
185
+ },
186
+ datetime_short: {
187
+ year: 'numeric',
188
+ month: 'numeric',
189
+ day: 'numeric',
190
+ hour: '2-digit',
191
+ minute: '2-digit',
192
+ },
193
+ datetime_medium: {
194
+ year: 'numeric',
195
+ month: 'short',
196
+ day: 'numeric',
197
+ hour: '2-digit',
198
+ minute: '2-digit',
199
+ },
200
+ datetime_long: {
201
+ year: 'numeric',
202
+ month: 'long',
203
+ day: 'numeric',
204
+ hour: '2-digit',
205
+ minute: '2-digit',
206
+ },
207
+ time: {
208
+ hour: '2-digit',
209
+ minute: '2-digit',
210
+ },
211
+ },
166
212
  },
167
213
  numberFormats: {
168
214
  en: {
@@ -186,5 +232,12 @@ export default createI18n({
186
232
  maximumFractionDigits: 2,
187
233
  },
188
234
  },
235
+ fa: {
236
+ percent: {
237
+ style: 'percent',
238
+ minimumFractionDigits: 0,
239
+ maximumFractionDigits: 2,
240
+ },
241
+ },
189
242
  },
190
243
  })
@@ -14,11 +14,7 @@
14
14
  <slot name="app-header" />
15
15
  </header>
16
16
  <div class="container">
17
- <div
18
- v-if="sidebarStore.isExpanded && !sidebarStore.isLocked"
19
- class="sidebar-close-backdrop"
20
- @click="sidebarStore.toggleExpand(false)"
21
- />
17
+ <Backdrop v-if="sidebarStore.isExpanded && !sidebarStore.isLocked" @click="sidebarStore.toggleExpand(false)" />
22
18
  <LayoutSidebar class="sidebar">
23
19
  <template #header>
24
20
  <slot name="sidebar-header" />
@@ -38,6 +34,7 @@
38
34
  </template>
39
35
 
40
36
  <script lang="ts" setup>
37
+ import Backdrop from '@core/components/backdrop/Backdrop.vue'
41
38
  import UiButtonIcon from '@core/components/button/ButtonIcon.vue'
42
39
  import LayoutSidebar from '@core/components/layout/LayoutSidebar.vue'
43
40
  import { vTooltip } from '@core/directives/tooltip.directive'
@@ -48,12 +45,6 @@ const sidebarStore = useSidebarStore()
48
45
  </script>
49
46
 
50
47
  <style lang="postcss" scoped>
51
- .sidebar-close-backdrop {
52
- position: fixed;
53
- inset: 0;
54
- z-index: 1000;
55
- }
56
-
57
48
  .core-layout {
58
49
  display: flex;
59
50
  height: 100dvh;
@@ -19,9 +19,11 @@
19
19
 
20
20
  "dashboard": "Dashboard",
21
21
  "documentation-name": "{name} Dokumentation",
22
+ "hosts": "Hosts",
22
23
  "loading-in-progress": "Ladevorgang läuft…",
23
24
  "log-out": "Abmelden",
24
25
  "master": "Primärer Host",
26
+ "n-vms": "1 VM | {n} VMs",
25
27
  "network": "Netzwerk",
26
28
  "object-not-found": "Objekt {id} wurde nicht gefunden…",
27
29
  "power-on-for-console": "Konsole ist nach Start der VM verfügbar",
@@ -29,5 +31,9 @@
29
31
  "storage": "Speicher",
30
32
  "support-name": "{name} pro support",
31
33
  "system": "System",
32
- "tasks": "Aufgaben"
34
+
35
+ "tasks": "Aufgaben",
36
+ "tasks.quick-view": "Schnellansicht der Aufgaben",
37
+
38
+ "vms": "VMs"
33
39
  }
@@ -8,6 +8,8 @@
8
8
  "coming-soon": "Coming soon!",
9
9
  "console": "Console",
10
10
 
11
+ "core.copied": "Copied",
12
+ "core.copy-id": "Copy ID",
11
13
  "core.close": "Close",
12
14
  "core.current": "Current",
13
15
  "core.filter": "Filter",
@@ -16,6 +18,12 @@
16
18
  "core.open": "Open",
17
19
  "core.quick-actions": "Quick actions",
18
20
 
21
+ "core.search": "Search",
22
+
23
+ "core.search-bar.label": "Search Engine",
24
+ "core.search-bar.placeholder": "Write your query…",
25
+ "core.search-bar.use-query-builder": "Use query builder",
26
+
19
27
  "core.select.all": "Select all",
20
28
  "core.select.none": "Select none",
21
29
 
@@ -33,15 +41,28 @@
33
41
 
34
42
  "dashboard": "Dashboard",
35
43
  "documentation-name": "{name} documentation",
44
+ "hosts": "Hosts",
36
45
  "loading-in-progress": "Loading in progress…",
37
46
  "log-out": "Log out",
38
47
  "master": "Primary host",
48
+ "n-vms": "1 VM | {n} VMs",
39
49
  "network": "Network",
40
50
  "object-not-found": "Object {id} can't be found…",
41
51
  "power-on-for-console": "Power on your VM to access its console",
52
+ "see-all": "See all",
42
53
  "stats": "Stats",
43
54
  "storage": "Storage",
44
55
  "support-name": "{name} pro support",
45
56
  "system": "System",
46
- "tasks": "Tasks"
57
+
58
+ "tasks": "Tasks",
59
+ "tasks.n-subtasks": "{n} subtask | {n} subtasks",
60
+ "tasks.no-tasks": "No tasks",
61
+ "tasks.quick-view": "Tasks' quick view",
62
+ "tasks.quick-view.all": "All",
63
+ "tasks.quick-view.done": "Done",
64
+ "tasks.quick-view.failed": "Failed",
65
+ "tasks.quick-view.in-progress": "In progress",
66
+
67
+ "vms": "VMs"
47
68
  }