@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.
Files changed (111) hide show
  1. package/lib/assets/css/base.pcss +5 -0
  2. package/lib/components/card-object-title/VtsCardObjectTitle.vue +36 -0
  3. package/lib/components/code-snippet/VtsCodeSnippet.vue +11 -5
  4. package/lib/components/drawer/VtsDrawer.vue +5 -1
  5. package/lib/components/drawer/VtsDrawerButton.vue +4 -3
  6. package/lib/components/drawer/VtsDrawerConfirmButton.vue +4 -2
  7. package/lib/components/icon/VtsIcon.vue +3 -1
  8. package/lib/components/input-wrapper/VtsInputWrapper.vue +2 -2
  9. package/lib/components/layout/VtsContentSidePanel.vue +41 -0
  10. package/lib/components/layout/VtsLayoutSidebar.vue +116 -43
  11. package/lib/components/menu/MenuItem.vue +9 -1
  12. package/lib/components/menu/MenuList.vue +4 -2
  13. package/lib/components/menu/VtsActionsMenu.vue +48 -14
  14. package/lib/components/modal/VtsActionModal.vue +44 -9
  15. package/lib/components/modal/VtsBlockedModal.vue +1 -1
  16. package/lib/components/modal/VtsDeleteModal.vue +1 -1
  17. package/lib/components/operation-card/VtsOperationCard.vue +2 -1
  18. package/lib/components/overlay/VtsOverlayButton.vue +35 -0
  19. package/lib/components/overlay/VtsOverlayCancelButton.vue +16 -0
  20. package/lib/components/overlay/VtsOverlayConfirmButton.vue +25 -0
  21. package/lib/components/overlay/VtsOverlayList.vue +82 -0
  22. package/lib/components/panel/VtsPanel.vue +80 -0
  23. package/lib/components/panel/VtsSidePanel.vue +140 -0
  24. package/lib/components/progress-bar/VtsProgressBar.vue +5 -3
  25. package/lib/components/select/VtsSelect.vue +1 -3
  26. package/lib/components/space-card/VtsSpaceCard.vue +1 -1
  27. package/lib/components/state-hero/VtsStateHero.vue +9 -17
  28. package/lib/components/table/VtsTable.vue +2 -1
  29. package/lib/components/table/cells/VtsActionCell.vue +7 -0
  30. package/lib/components/table/cells/VtsLinkCell.vue +3 -1
  31. package/lib/components/table/cells/VtsProgressBarCell.vue +1 -1
  32. package/lib/components/table/cells/VtsUserNameCell.vue +29 -0
  33. package/lib/components/task/VtsQuickTaskButton.vue +1 -1
  34. package/lib/components/task/VtsQuickTaskList.vue +1 -1
  35. package/lib/components/tree/VtsTreeItem.vue +13 -7
  36. package/lib/components/tree/VtsTreeList.vue +6 -3
  37. package/lib/components/tree/VtsTreeLoadingItem.vue +3 -3
  38. package/lib/components/ui/head-bar/UiHeadBar.vue +2 -2
  39. package/lib/components/ui/input/UiInput.vue +56 -10
  40. package/lib/components/ui/link/UiLink.vue +3 -1
  41. package/lib/components/ui/panel/UiPanel.vue +7 -24
  42. package/lib/components/ui/query-search-bar/UiQuerySearchBar.vue +1 -15
  43. package/lib/components/ui/quick-task-item/UiQuickTaskItem.vue +1 -1
  44. package/lib/components/ui/quick-task-panel/UiQuickTaskPanel.vue +1 -1
  45. package/lib/components/ui/task-item/UiTaskItem.vue +14 -6
  46. package/lib/components/ui/task-list/UiTaskList.vue +1 -1
  47. package/lib/components/ui/text-area/UiTextarea.vue +12 -14
  48. package/lib/components/ui/tree-item-label/UiTreeItemLabel.vue +1 -1
  49. package/lib/components/vif-connection-toggle-modal/VtsVifConnectionToggleModal.vue +43 -0
  50. package/lib/composables/table/multi-select.composable.md +33 -0
  51. package/lib/composables/table-state.composable.ts +1 -1
  52. package/lib/icons/action-icons.ts +14 -0
  53. package/lib/layouts/CoreLayout.vue +74 -62
  54. package/lib/locales/cs.json +56 -1
  55. package/lib/locales/de.json +3 -2
  56. package/lib/locales/en.json +85 -4
  57. package/lib/locales/es.json +11 -1
  58. package/lib/locales/fa.json +0 -1
  59. package/lib/locales/fr.json +85 -4
  60. package/lib/locales/it.json +0 -1
  61. package/lib/locales/ko.json +2 -0
  62. package/lib/locales/nl.json +2 -1
  63. package/lib/locales/pt-BR.json +0 -1
  64. package/lib/locales/pt.json +0 -1
  65. package/lib/locales/ru.json +0 -1
  66. package/lib/locales/sk.json +56 -1
  67. package/lib/locales/sv.json +3 -2
  68. package/lib/locales/uk.json +0 -1
  69. package/lib/locales/zh-Hans.json +79 -4
  70. package/lib/packages/form-validation/custom-rules/ip-addresses.rule.ts +15 -0
  71. package/lib/packages/form-validation/custom-rules/ip.regex.ts +26 -0
  72. package/lib/packages/form-validation/custom-rules/ipv4-or-cidr.rule.ts +2 -3
  73. package/lib/packages/form-validation/index.ts +2 -0
  74. package/lib/packages/hide-permanently/README.md +60 -0
  75. package/lib/packages/hide-permanently/types.ts +3 -0
  76. package/lib/packages/hide-permanently/use-hide-permanently.ts +15 -0
  77. package/lib/packages/overlay/OverlayComponent.vue +18 -0
  78. package/lib/packages/overlay/README.md +285 -0
  79. package/lib/packages/overlay/create-event-handler.ts +80 -0
  80. package/lib/packages/overlay/injection-keys.ts +3 -0
  81. package/lib/packages/overlay/is-thenable.ts +3 -0
  82. package/lib/packages/overlay/symbols.ts +5 -0
  83. package/lib/packages/overlay/types.ts +94 -0
  84. package/lib/packages/overlay/use-overlay-escape.ts +34 -0
  85. package/lib/packages/overlay/use-overlay-store.ts +33 -0
  86. package/lib/packages/overlay/use-overlay-trigger.ts +33 -0
  87. package/lib/packages/overlay/use-overlay.ts +99 -0
  88. package/lib/packages/progress/use-progress.ts +12 -2
  89. package/lib/packages/remote-resource/define-remote-resource.ts +64 -29
  90. package/lib/packages/sidebar/index.ts +2 -0
  91. package/lib/packages/sidebar/sidebar.store.ts +55 -0
  92. package/lib/packages/sidebar/types.ts +21 -0
  93. package/lib/packages/sidebar/use-sidebar-resize.ts +47 -0
  94. package/lib/packages/sidebar/use-sidebar-responsive-expand.ts +19 -0
  95. package/lib/packages/tree/types.ts +6 -0
  96. package/lib/packages/tree/use-tree.ts +38 -37
  97. package/lib/stores/panel.store.ts +56 -5
  98. package/lib/tables/column-definitions/action-column.ts +21 -9
  99. package/lib/tables/column-definitions/user-name-column.ts +10 -0
  100. package/lib/tables/column-sets/server-columns.ts +2 -2
  101. package/lib/tables/column-sets/user-columns.ts +16 -0
  102. package/lib/tables/column-sets/vm-columns.ts +2 -3
  103. package/lib/types/object.type.ts +9 -1
  104. package/lib/types/state-hero.type.ts +19 -0
  105. package/lib/types/task.type.ts +5 -12
  106. package/lib/types/vue-virtual-scroller.d.ts +8 -2
  107. package/lib/utils/injection-keys.util.ts +4 -2
  108. package/lib/utils/ip-address.utils.ts +7 -0
  109. package/lib/utils/sr.utils.ts +4 -0
  110. package/package.json +2 -1
  111. package/lib/stores/sidebar.store.ts +0 -79
@@ -12,9 +12,10 @@
12
12
  </template>
13
13
 
14
14
  <script lang="ts" setup>
15
- import VtsStateHero, { type StateHeroType } from '@core/components/state-hero/VtsStateHero.vue'
15
+ import VtsStateHero from '@core/components/state-hero/VtsStateHero.vue'
16
16
  import UiCard from '@core/components/ui/card/UiCard.vue'
17
17
  import { useUiStore } from '@core/stores/ui.store.ts'
18
+ import type { StateHeroType } from '@core/types/state-hero.type.ts'
18
19
 
19
20
  defineProps<{
20
21
  title: string
@@ -0,0 +1,35 @@
1
+ <template>
2
+ <UiButton :accent="buttonAccent" :busy="isBusy" :disabled="isDisabled" :variant size="medium" @click="trigger">
3
+ <slot />
4
+ </UiButton>
5
+ </template>
6
+
7
+ <script lang="ts" setup>
8
+ import UiButton, { type ButtonVariant } from '@core/components/ui/button/UiButton.vue'
9
+ import { useMapper } from '@core/packages/mapper'
10
+ import { useOverlayTrigger } from '@core/packages/overlay/use-overlay-trigger.ts'
11
+ import { IK_OVERLAY_ACCENT } from '@core/utils/injection-keys.util.ts'
12
+ import { inject } from 'vue'
13
+
14
+ defineProps<{
15
+ variant: ButtonVariant
16
+ }>()
17
+
18
+ defineSlots<{
19
+ default(): any
20
+ }>()
21
+
22
+ const { isBusy, isDisabled, trigger } = useOverlayTrigger()
23
+
24
+ const overlayAccent = inject(IK_OVERLAY_ACCENT, undefined)
25
+
26
+ const buttonAccent = useMapper(
27
+ () => overlayAccent?.value,
28
+ {
29
+ info: 'brand',
30
+ warning: 'warning',
31
+ danger: 'danger',
32
+ },
33
+ 'info'
34
+ )
35
+ </script>
@@ -0,0 +1,16 @@
1
+ <template>
2
+ <VtsOverlayButton variant="secondary">
3
+ <slot>{{ t('cancel') }}</slot>
4
+ </VtsOverlayButton>
5
+ </template>
6
+
7
+ <script lang="ts" setup>
8
+ import VtsOverlayButton from '@core/components/overlay/VtsOverlayButton.vue'
9
+ import { useI18n } from 'vue-i18n'
10
+
11
+ defineSlots<{
12
+ default?(): any
13
+ }>()
14
+
15
+ const { t } = useI18n()
16
+ </script>
@@ -0,0 +1,25 @@
1
+ <template>
2
+ <VtsOverlayButton
3
+ variant="primary"
4
+ :type="onClick ? 'button' : 'submit'"
5
+ v-on="onClick ? { click: () => emit('click') } : {}"
6
+ >
7
+ <slot />
8
+ </VtsOverlayButton>
9
+ </template>
10
+
11
+ <script lang="ts" setup>
12
+ import VtsOverlayButton from '@core/components/overlay/VtsOverlayButton.vue'
13
+
14
+ const { onClick } = defineProps<{
15
+ onClick?: () => void
16
+ }>()
17
+
18
+ const emit = defineEmits<{
19
+ click: []
20
+ }>()
21
+
22
+ defineSlots<{
23
+ default(): any
24
+ }>()
25
+ </script>
@@ -0,0 +1,82 @@
1
+ <template>
2
+ <div class="vts-overlay-list">
3
+ <Transition name="fade">
4
+ <div v-if="overlayStore.overlays.length > 0" class="backdrop" />
5
+ </Transition>
6
+
7
+ <TransitionGroup tag="div" name="overlay" class="overlays">
8
+ <OverlayComponent
9
+ v-for="overlay of overlayStore.overlays"
10
+ :key="overlay.key"
11
+ class="overlay"
12
+ :overlay
13
+ :class="{ dimmed: !overlayStore.isCurrent(overlay.key) }"
14
+ />
15
+ </TransitionGroup>
16
+ </div>
17
+ </template>
18
+
19
+ <script lang="ts" setup>
20
+ import OverlayComponent from '@core/packages/overlay/OverlayComponent.vue'
21
+ import { useOverlayStore } from '@core/packages/overlay/use-overlay-store.ts'
22
+
23
+ const overlayStore = useOverlayStore()
24
+ </script>
25
+
26
+ <style lang="postcss" scoped>
27
+ .vts-overlay-list {
28
+ .backdrop {
29
+ position: fixed;
30
+ inset: 0;
31
+ z-index: 1011;
32
+ background-color: var(--color-opacity-primary);
33
+ pointer-events: none;
34
+
35
+ &.fade-enter-active,
36
+ &.fade-leave-active {
37
+ transition: opacity 0.3s ease;
38
+ }
39
+
40
+ &.fade-enter-from,
41
+ &.fade-leave-to {
42
+ opacity: 0;
43
+ }
44
+ }
45
+
46
+ .overlays {
47
+ position: fixed;
48
+ inset: 0;
49
+ z-index: 1012;
50
+
51
+ /* The container only positions the stacked modals; each modal catches its own
52
+ clicks, so an empty container must let clicks through. */
53
+ pointer-events: none;
54
+
55
+ .overlay {
56
+ pointer-events: auto;
57
+ transition:
58
+ opacity 0.3s ease,
59
+ transform 0.3s ease,
60
+ filter 0.3s ease;
61
+
62
+ &.dimmed {
63
+ filter: brightness(0.8);
64
+ }
65
+
66
+ &.overlay-enter-from.ui-modal,
67
+ &.overlay-leave-to.ui-modal {
68
+ opacity: 0;
69
+ }
70
+
71
+ &.overlay-enter-from.ui-drawer,
72
+ &.overlay-leave-to.ui-drawer {
73
+ transform: translateX(100%);
74
+
75
+ &:dir(rtl) {
76
+ transform: translateX(-100%);
77
+ }
78
+ }
79
+ }
80
+ }
81
+ }
82
+ </style>
@@ -0,0 +1,80 @@
1
+ <!-- v5 -->
2
+ <template>
3
+ <UiPanel :error>
4
+ <template v-if="needsHeader" #header>
5
+ <slot v-if="slots.header" name="header" />
6
+ <div v-if="slots.actions || slots['more-actions']" class="action-buttons">
7
+ <template v-if="slots.actions">
8
+ <slot name="actions" />
9
+ </template>
10
+ <MenuList v-if="slots['more-actions']" placement="bottom-end">
11
+ <template #trigger="{ open }">
12
+ <UiButtonIcon icon="action:more-actions" accent="brand" size="medium" @click="open($event)" />
13
+ </template>
14
+ <slot name="more-actions" />
15
+ </MenuList>
16
+ </div>
17
+ <div v-if="slots['corner-actions'] || closable" class="corner-actions">
18
+ <slot v-if="slots['corner-actions']" name="corner-actions" />
19
+ <UiButtonIcon
20
+ v-if="closable"
21
+ v-tooltip="t('action:close')"
22
+ size="small"
23
+ variant="tertiary"
24
+ accent="brand"
25
+ :icon="closeIcon"
26
+ @click="emit('close')"
27
+ />
28
+ </div>
29
+ </template>
30
+ <slot />
31
+ </UiPanel>
32
+ </template>
33
+
34
+ <script setup lang="ts">
35
+ import MenuList from '@core/components/menu/MenuList.vue'
36
+ import UiButtonIcon from '@core/components/ui/button-icon/UiButtonIcon.vue'
37
+ import UiPanel from '@core/components/ui/panel/UiPanel.vue'
38
+ import { vTooltip } from '@core/directives/tooltip.directive'
39
+ import type { IconName } from '@core/icons'
40
+ import { computed } from 'vue'
41
+ import { useI18n } from 'vue-i18n'
42
+
43
+ const { closable, closeIcon = 'action:close-cancel-clear' } = defineProps<{
44
+ error?: boolean
45
+ closable?: boolean
46
+ closeIcon?: IconName
47
+ }>()
48
+
49
+ const emit = defineEmits<{
50
+ close: []
51
+ }>()
52
+
53
+ const slots = defineSlots<{
54
+ default(): any
55
+ header?(): any
56
+ actions?(): any
57
+ 'more-actions'?(): any
58
+ 'corner-actions'?(): any
59
+ }>()
60
+
61
+ const { t } = useI18n()
62
+
63
+ const needsHeader = computed(
64
+ () => slots.header || slots.actions || slots['more-actions'] || slots['corner-actions'] || closable
65
+ )
66
+ </script>
67
+
68
+ <style scoped lang="postcss">
69
+ .action-buttons {
70
+ display: flex;
71
+ align-items: center;
72
+ gap: 1.6rem;
73
+ }
74
+ .corner-actions {
75
+ display: flex;
76
+ align-items: center;
77
+ margin-inline-start: auto;
78
+ gap: 0.8rem;
79
+ }
80
+ </style>
@@ -0,0 +1,140 @@
1
+ <!-- v5 -->
2
+ <template>
3
+ <div class="vts-side-panel-sticky" :class="{ mobile: uiStore.isSmall }">
4
+ <VtsPanel
5
+ :closable="hasSelection"
6
+ :close-icon="uiStore.isSmall ? 'fa:angle-left' : 'action:close-cancel-clear'"
7
+ class="vts-side-panel"
8
+ :class="{
9
+ locked: panelStore.isLocked && !uiStore.isSmall,
10
+ mobile: uiStore.isSmall,
11
+ }"
12
+ @close="handleClose"
13
+ >
14
+ <template v-if="slots.actions" #actions>
15
+ <slot name="actions" />
16
+ </template>
17
+
18
+ <template v-if="slots['more-actions']" #more-actions>
19
+ <slot name="more-actions" />
20
+ </template>
21
+
22
+ <template v-if="slots['corner-actions'] || !uiStore.isSmall" #corner-actions>
23
+ <slot v-if="slots['corner-actions']" name="corner-actions" />
24
+ <UiButtonIcon
25
+ v-if="!uiStore.isSmall"
26
+ v-tooltip="{
27
+ content: panelStore.isLocked ? t('action:sidebar-unlock') : t('action:sidebar-lock'),
28
+ placement: 'left',
29
+ }"
30
+ accent="brand"
31
+ size="small"
32
+ :icon="panelStore.isLocked ? 'action:pin-panel-hide' : 'action:pin-panel'"
33
+ @click="panelStore.toggleLock()"
34
+ />
35
+ </template>
36
+
37
+ <VtsStateHero v-if="!hasSelection" format="panel" type="no-selection" size="medium" />
38
+ <slot v-else />
39
+ </VtsPanel>
40
+ </div>
41
+ </template>
42
+
43
+ <script setup lang="ts">
44
+ import VtsPanel from '@core/components/panel/VtsPanel.vue'
45
+ import VtsStateHero from '@core/components/state-hero/VtsStateHero.vue'
46
+ import UiButtonIcon from '@core/components/ui/button-icon/UiButtonIcon.vue'
47
+ import { vTooltip } from '@core/directives/tooltip.directive'
48
+ import { usePanelStore } from '@core/stores/panel.store'
49
+ import { useUiStore } from '@core/stores/ui.store'
50
+ import { watch } from 'vue'
51
+ import { useI18n } from 'vue-i18n'
52
+
53
+ const { hasSelection } = defineProps<{
54
+ hasSelection?: boolean
55
+ }>()
56
+
57
+ const emit = defineEmits<{
58
+ close: []
59
+ }>()
60
+
61
+ const slots = defineSlots<{
62
+ default(): any
63
+ actions?(): any
64
+ 'more-actions'?(): any
65
+ 'corner-actions'?(): any
66
+ }>()
67
+
68
+ const panelStore = usePanelStore()
69
+ const uiStore = useUiStore()
70
+
71
+ const { t } = useI18n()
72
+
73
+ watch(
74
+ [() => hasSelection, () => panelStore.isLocked, () => uiStore.isSmall],
75
+ ([hasSelection]) => {
76
+ if (hasSelection === undefined) {
77
+ return
78
+ }
79
+
80
+ panelStore.syncWithSelection(hasSelection)
81
+ },
82
+ { immediate: true }
83
+ )
84
+
85
+ function handleClose() {
86
+ if (panelStore.syncsOpenStateWithSelection) {
87
+ panelStore.collapse()
88
+ }
89
+
90
+ emit('close')
91
+ }
92
+ </script>
93
+
94
+ <style scoped lang="postcss">
95
+ .vts-side-panel-sticky:not(.mobile) {
96
+ position: sticky;
97
+ top: 0;
98
+ align-self: start;
99
+ }
100
+
101
+ .vts-side-panel {
102
+ width: var(--side-panel-width, 40rem);
103
+ transition: transform 0.25s;
104
+
105
+ &:not(.mobile) {
106
+ --panel-viewport-height: calc(100dvh - 5.6rem);
107
+ --panel-min-height: calc(100dvh - 16.6rem);
108
+
109
+ min-height: var(--panel-min-height);
110
+ max-height: var(--panel-viewport-height);
111
+ overflow: hidden;
112
+ transform: translateX(v-bind('panelStore.cssHorizontalOffset'));
113
+
114
+ :deep(> .content) {
115
+ flex: 1 1 auto;
116
+ min-height: 0;
117
+ overflow-y: auto;
118
+ }
119
+ }
120
+
121
+ &.mobile {
122
+ z-index: 1010;
123
+ position: fixed;
124
+ width: 100dvw;
125
+ height: 100dvh;
126
+ inset: 0;
127
+ transform: translateX(v-bind('panelStore.cssHorizontalOffset'));
128
+
129
+ :deep(.corner-actions) {
130
+ margin-inline-start: 0;
131
+ margin-inline-end: auto;
132
+ order: -1;
133
+ }
134
+
135
+ :deep(> .content) {
136
+ overflow: auto;
137
+ }
138
+ }
139
+ }
140
+ </style>
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <div class="vts-progress-bar">
3
- <UiDataRuler v-if="!noruler" :max="percentageCap" :warning="threshold.payload" />
3
+ <UiDataRuler v-if="!noRuler" :max="percentageCap" :warning="threshold.payload" />
4
4
  <UiProgressBar :accent="threshold.payload.accent ?? 'info'" :fill-width :legend />
5
5
  </div>
6
6
  </template>
@@ -25,18 +25,20 @@ const {
25
25
  label,
26
26
  thresholds = defaultProgressThresholds(),
27
27
  legendType,
28
+ noRuler,
28
29
  } = defineProps<{
29
30
  current: number
30
31
  total: number
31
32
  label?: string
32
33
  legendType?: ProgressBarLegendType
33
34
  thresholds?: ProgressBarThresholdConfig
34
- noruler?: boolean
35
+ noRuler?: boolean
35
36
  }>()
36
37
 
37
38
  const progress = useProgress(
38
39
  () => current,
39
- () => total
40
+ () => total,
41
+ () => noRuler
40
42
  )
41
43
 
42
44
  const { percentageCap, percentage, fillWidth } = progress
@@ -4,7 +4,6 @@
4
4
  ref="triggerRef"
5
5
  :accent
6
6
  :disabled="isDisabled"
7
- :icon
8
7
  :model-value="selectedLabel"
9
8
  :placeholder
10
9
  :required="isRequired"
@@ -24,6 +23,7 @@
24
23
  :placeholder="searchPlaceholder"
25
24
  right-icon="fa:magnifying-glass"
26
25
  accent="brand"
26
+ detached
27
27
  />
28
28
  </div>
29
29
  </template>
@@ -46,7 +46,6 @@ import VtsOption from '@core/components/select/VtsOption.vue'
46
46
  import UiDropdown from '@core/components/ui/dropdown/UiDropdown.vue'
47
47
  import UiDropdownList from '@core/components/ui/dropdown/UiDropdownList.vue'
48
48
  import UiInput from '@core/components/ui/input/UiInput.vue'
49
- import type { IconName } from '@core/icons'
50
49
  import {
51
50
  type FormSelect,
52
51
  type FormSelectId,
@@ -61,7 +60,6 @@ import { useI18n } from 'vue-i18n'
61
60
  const { accent, id } = defineProps<{
62
61
  accent: 'brand' | 'warning' | 'danger'
63
62
  id: TSelectId
64
- icon?: IconName
65
63
  }>()
66
64
 
67
65
  defineSlots<{
@@ -5,7 +5,7 @@
5
5
  </UiCardTitle>
6
6
 
7
7
  <div class="content">
8
- <VtsProgressBar noruler :current="used" :total :label legend-type="percent" class="progress" />
8
+ <VtsProgressBar no-ruler :current="used" :total :label legend-type="percent" class="progress" />
9
9
 
10
10
  <VtsCardRowKeyValue>
11
11
  <template #key>{{ t('used-space') }}</template>
@@ -9,32 +9,24 @@
9
9
  <div v-if="success">{{ t('all-good!') }}</div>
10
10
  <slot />
11
11
  </div>
12
+ <div v-else-if="type === 'no-selection'" :class="typoClass" class="content">
13
+ <I18nT keypath="select-to-see-details" scope="global" tag="p">
14
+ <template #icon>
15
+ <VtsIcon name="fa:eye" size="current" />
16
+ </template>
17
+ </I18nT>
18
+ </div>
12
19
  </div>
13
20
  </template>
14
21
 
15
22
  <script lang="ts" setup>
16
23
  import UiLoader from '@core/components/ui/loader/UiLoader.vue'
17
24
  import { useUiStore } from '@core/stores/ui.store'
25
+ import type { StateHeroFormat, StateHeroSize, StateHeroType } from '@core/types/state-hero.type.ts'
18
26
  import { toVariants } from '@core/utils/to-variants.util.ts'
19
27
  import { computed } from 'vue'
20
28
  import { useI18n } from 'vue-i18n'
21
-
22
- export type StateHeroFormat = 'page' | 'card' | 'panel' | 'table'
23
-
24
- export type StateHeroSize = 'extra-small' | 'small' | 'medium' | 'large'
25
-
26
- export type StateHeroType =
27
- | 'busy'
28
- | 'no-result'
29
- | 'under-construction'
30
- | 'no-data'
31
- | 'no-selection'
32
- | 'error'
33
- | 'not-found'
34
- | 'offline'
35
- | 'all-good'
36
- | 'all-done'
37
- | 'creating'
29
+ import VtsIcon from '../icon/VtsIcon.vue'
38
30
 
39
31
  const { format, type, size, horizontal } = defineProps<{
40
32
  format: StateHeroFormat
@@ -16,9 +16,10 @@
16
16
  </template>
17
17
 
18
18
  <script lang="ts" setup>
19
- import VtsStateHero, { type StateHeroSize, type StateHeroType } from '@core/components/state-hero/VtsStateHero.vue'
19
+ import VtsStateHero from '@core/components/state-hero/VtsStateHero.vue'
20
20
  import UiTablePagination from '@core/components/ui/table-pagination/UiTablePagination.vue'
21
21
  import type { PaginationBindings } from '@core/composables/pagination.composable'
22
+ import type { StateHeroType, StateHeroSize } from '@core/types/state-hero.type.ts'
22
23
  import { hasEllipsis } from '@core/utils/has-ellipsis.util'
23
24
  import { toVariants } from '@core/utils/to-variants.util'
24
25
  import { useResizeObserver, useScroll } from '@vueuse/core'
@@ -9,6 +9,9 @@
9
9
  @click="emit('click')"
10
10
  />
11
11
  <VtsActionsMenu v-if="actions.length" :actions />
12
+ <VtsActionsMenu v-else>
13
+ <slot />
14
+ </VtsActionsMenu>
12
15
  </div>
13
16
  </UiTableCell>
14
17
  </template>
@@ -34,6 +37,10 @@ const {
34
37
  const emit = defineEmits<{
35
38
  click: []
36
39
  }>()
40
+
41
+ defineSlots<{
42
+ default(): any
43
+ }>()
37
44
  </script>
38
45
 
39
46
  <style scoped lang="postcss">
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <UiTableCell>
3
3
  <div class="vts-link-cell">
4
- <UiLink size="medium" :icon :to :href :target class="link">
4
+ <UiLink size="medium" :icon :busy :busy-tooltip :to :href :target class="link">
5
5
  <slot />
6
6
  <VtsIcon v-if="rightIcon" v-tooltip="rightIcon.tooltip ?? false" :name="rightIcon.icon" size="medium" />
7
7
  </UiLink>
@@ -21,6 +21,8 @@ import type { IconName } from '@core/icons'
21
21
 
22
22
  export type VtsLinkCellProps = LinkOptions & {
23
23
  icon?: IconName
24
+ busy?: boolean
25
+ busyTooltip?: string
24
26
  rightIcon?: {
25
27
  icon: IconName
26
28
  tooltip?: string
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <UiTableCell>
3
3
  <div class="container">
4
- <VtsProgressBar :current :total noruler class="progress" />
4
+ <VtsProgressBar :current :total no-ruler class="progress" />
5
5
  <span>{{ n(percentage / 100, { maximumFractionDigits: 0, style: 'percent' }) }}</span>
6
6
  </div>
7
7
  </UiTableCell>
@@ -0,0 +1,29 @@
1
+ <template>
2
+ <UiTableCell>
3
+ <div class="user-name">
4
+ <UiUserLogo size="small" />
5
+ <UiLink :href size="medium">
6
+ {{ content }}
7
+ </UiLink>
8
+ </div>
9
+ </UiTableCell>
10
+ </template>
11
+
12
+ <script setup lang="ts">
13
+ import UiLink from '@core/components/ui/link/UiLink.vue'
14
+ import UiTableCell from '@core/components/ui/table-cell/UiTableCell.vue'
15
+ import UiUserLogo from '@core/components/ui/user-logo/UiUserLogo.vue'
16
+
17
+ defineProps<{
18
+ content: string
19
+ href?: string
20
+ }>()
21
+ </script>
22
+
23
+ <style scoped lang="postcss">
24
+ .user-name {
25
+ display: flex;
26
+ align-items: center;
27
+ gap: 0.8rem;
28
+ }
29
+ </style>
@@ -19,8 +19,8 @@
19
19
  import VtsBackdrop from '@core/components/backdrop/VtsBackdrop.vue'
20
20
  import UiButtonIcon from '@core/components/ui/button-icon/UiButtonIcon.vue'
21
21
  import UiQuickTaskPanel from '@core/components/ui/quick-task-panel/UiQuickTaskPanel.vue'
22
+ import type { Task } from '@core/components/ui/task-item/UiTaskItem.vue'
22
23
  import { vTooltip } from '@core/directives/tooltip.directive'
23
- import type { Task } from '@core/types/task.type.ts'
24
24
  import { unrefElement, watchArray, whenever } from '@vueuse/core'
25
25
  import placementJs from 'placement.js'
26
26
  import { computed, nextTick, ref } from 'vue'
@@ -27,7 +27,7 @@
27
27
  <script lang="ts" setup>
28
28
  import UiLoader from '@core/components/ui/loader/UiLoader.vue'
29
29
  import UiQuickTaskItem from '@core/components/ui/quick-task-item/UiQuickTaskItem.vue'
30
- import type { Task } from '@core/types/task.type.ts'
30
+ import type { Task } from '@core/components/ui/task-item/UiTaskItem.vue'
31
31
  import { useI18n } from 'vue-i18n'
32
32
  import { DynamicScroller, DynamicScrollerItem } from 'vue-virtual-scroller'
33
33
 
@@ -6,15 +6,16 @@
6
6
  </template>
7
7
 
8
8
  <script lang="ts" setup>
9
+ import { useLeftSidebarStore } from '@core/packages/sidebar'
9
10
  import type { TreeNodeId } from '@core/packages/tree/types.ts'
10
- import { useSidebarStore } from '@core/stores/sidebar.store'
11
- import { useUiStore } from '@core/stores/ui.store'
12
- import { IK_TREE_ITEM_EXPANDED, IK_TREE_ITEM_HAS_CHILDREN } from '@core/utils/injection-keys.util'
11
+ import { useUiStore } from '@core/stores/ui.store.ts'
12
+ import { IK_TREE_ITEM_EXPANDED, IK_TREE_ITEM_HAS_CHILDREN } from '@core/utils/injection-keys.util.ts'
13
13
  import { onBeforeMount, onBeforeUpdate, provide, ref, toRef, useSlots } from 'vue'
14
14
 
15
15
  const props = defineProps<{
16
16
  nodeId?: TreeNodeId
17
17
  expanded?: boolean
18
+ hasChildren?: boolean
18
19
  }>()
19
20
 
20
21
  defineSlots<{
@@ -22,13 +23,18 @@ defineSlots<{
22
23
  sublist?(): any
23
24
  }>()
24
25
 
25
- const sidebar = useSidebarStore()
26
+ const sidebar = useLeftSidebarStore()
26
27
  const uiStore = useUiStore()
27
- const hasChildren = ref(false)
28
+ const hasChildrenState = ref(false)
28
29
 
29
30
  const updateHasChildren = () => {
31
+ if (props.hasChildren !== undefined) {
32
+ hasChildrenState.value = props.hasChildren
33
+ return
34
+ }
35
+
30
36
  const { sublist } = useSlots()
31
- hasChildren.value = sublist !== undefined
37
+ hasChildrenState.value = sublist !== undefined
32
38
  }
33
39
 
34
40
  const handleClick = () => {
@@ -40,6 +46,6 @@ const handleClick = () => {
40
46
  onBeforeMount(() => updateHasChildren())
41
47
  onBeforeUpdate(() => updateHasChildren())
42
48
 
43
- provide(IK_TREE_ITEM_HAS_CHILDREN, hasChildren)
49
+ provide(IK_TREE_ITEM_HAS_CHILDREN, hasChildrenState)
44
50
  provide(IK_TREE_ITEM_EXPANDED, toRef(props, 'expanded'))
45
51
  </script>