@xen-orchestra/web-core 0.35.1 → 0.37.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 (120) hide show
  1. package/lib/components/console/VtsRemoteConsole.vue +1 -1
  2. package/lib/components/copy-button/VtsCopyButton.vue +1 -1
  3. package/lib/components/layout/VtsLayoutSidebar.vue +1 -1
  4. package/lib/components/quick-info-card/VtsQuickInfoCard.vue +1 -1
  5. package/lib/components/relative-time/VtsRelativeTime.vue +2 -3
  6. package/lib/components/select/VtsSelect.vue +1 -1
  7. package/lib/components/state-hero/VtsStateHero.vue +20 -10
  8. package/lib/components/table/VtsRow.vue +26 -0
  9. package/lib/components/table/VtsTable.vue +99 -42
  10. package/lib/components/table/cells/VtsCollapsedListCell.vue +59 -0
  11. package/lib/components/table/cells/VtsHeaderCell.vue +31 -0
  12. package/lib/components/table/cells/VtsLinkCell.vue +33 -0
  13. package/lib/components/table/cells/VtsNumberCell.vue +21 -0
  14. package/lib/components/{size-progress-cell/VtsSizeProgressCell.vue → table/cells/VtsProgressBarCell.vue} +8 -5
  15. package/lib/components/table/cells/VtsStatusCell.vue +69 -0
  16. package/lib/components/table/cells/VtsTagCell.vue +24 -0
  17. package/lib/components/table/cells/VtsTextCell.vue +32 -0
  18. package/lib/components/table/cells/VtsTruncatedTextCell.vue +64 -0
  19. package/lib/components/task/VtsQuickTaskButton.vue +1 -1
  20. package/lib/components/tree/VtsTreeLine.vue +1 -1
  21. package/lib/components/ui/alert/UiAlert.vue +1 -1
  22. package/lib/components/ui/button/UiButton.vue +4 -2
  23. package/lib/components/ui/button-icon/UiButtonIcon.vue +12 -11
  24. package/lib/components/ui/column-header/UiColumnHeader.vue +22 -0
  25. package/lib/components/ui/info/UiInfo.vue +5 -1
  26. package/lib/components/ui/input/UiInput.vue +3 -2
  27. package/lib/components/ui/link/UiLink.vue +5 -0
  28. package/lib/components/ui/log-entry-viewer/UiLogEntryViewer.vue +1 -1
  29. package/lib/components/ui/query-search-bar/UiQuerySearchBar.vue +2 -2
  30. package/lib/components/ui/table-cell/UiTableCell.vue +41 -0
  31. package/lib/components/ui/table-pagination/PaginationButton.vue +1 -1
  32. package/lib/components/ui/task-item/UiTaskItem.vue +229 -0
  33. package/lib/components/ui/task-list/UiTaskList.vue +31 -0
  34. package/lib/components/ui/toaster/UiToaster.vue +1 -1
  35. package/lib/components/ui/top-bottom-table/UiTopBottomTable.vue +6 -2
  36. package/lib/components/ui/tree-item-label/UiTreeItemLabel.vue +1 -7
  37. package/lib/composables/pagination.composable.ts +16 -1
  38. package/lib/composables/relative-time.composable.ts +8 -61
  39. package/lib/composables/table-state.composable.ts +56 -0
  40. package/lib/composables/tree-filter.composable.ts +2 -2
  41. package/lib/icons/fa-icons.ts +2 -0
  42. package/lib/icons/object-icons.ts +1 -1
  43. package/lib/locales/en.json +26 -1
  44. package/lib/locales/fr.json +26 -1
  45. package/lib/packages/form-select/use-form-select-controller.ts +1 -0
  46. package/lib/packages/table/README.md +53 -308
  47. package/lib/packages/table/define-column.ts +7 -0
  48. package/lib/packages/table/define-columns.ts +104 -50
  49. package/lib/packages/table/index.ts +3 -11
  50. package/lib/packages/table/types.ts +10 -0
  51. package/lib/{composables/tree.composable.md → packages/tree/README.md} +28 -23
  52. package/lib/{composables → packages}/tree/branch-definition.ts +9 -4
  53. package/lib/{composables → packages}/tree/branch.ts +15 -20
  54. package/lib/{composables → packages}/tree/build-nodes.ts +5 -5
  55. package/lib/{composables → packages}/tree/define-branch.ts +8 -4
  56. package/lib/{composables → packages}/tree/define-leaf.ts +8 -3
  57. package/lib/{composables → packages}/tree/define-tree.ts +10 -5
  58. package/lib/{composables → packages}/tree/leaf-definition.ts +1 -1
  59. package/lib/{composables → packages}/tree/leaf.ts +3 -3
  60. package/lib/{composables → packages}/tree/tree-node-base.ts +18 -3
  61. package/lib/{composables → packages}/tree/tree-node-definition-base.ts +4 -2
  62. package/lib/{composables → packages}/tree/types.ts +11 -9
  63. package/lib/{composables/tree.composable.ts → packages/tree/use-tree.ts} +24 -11
  64. package/lib/tables/column-definitions/address-column.ts +4 -0
  65. package/lib/tables/column-definitions/button-column.ts +35 -0
  66. package/lib/tables/column-definitions/button-icon-column.ts +30 -0
  67. package/lib/tables/column-definitions/collapsed-list-column.ts +12 -0
  68. package/lib/tables/column-definitions/date-column.ts +34 -0
  69. package/lib/tables/column-definitions/info-column.ts +12 -0
  70. package/lib/tables/column-definitions/input-column.ts +32 -0
  71. package/lib/tables/column-definitions/link-column.ts +14 -0
  72. package/lib/tables/column-definitions/literal-column.ts +9 -0
  73. package/lib/tables/column-definitions/number-column.ts +10 -0
  74. package/lib/tables/column-definitions/percent-column.ts +15 -0
  75. package/lib/tables/column-definitions/progress-bar-column.ts +10 -0
  76. package/lib/tables/column-definitions/select-column.ts +12 -0
  77. package/lib/tables/column-definitions/select-item-column.ts +8 -0
  78. package/lib/tables/column-definitions/status-column.ts +16 -0
  79. package/lib/tables/column-definitions/tag-column.ts +11 -0
  80. package/lib/tables/column-definitions/text-column.ts +11 -0
  81. package/lib/tables/column-definitions/truncated-text-column.ts +10 -0
  82. package/lib/tables/column-sets/backup-issue-columns.ts +15 -0
  83. package/lib/tables/column-sets/backup-job-columns.ts +23 -0
  84. package/lib/tables/column-sets/backup-job-schedule-columns.ts +21 -0
  85. package/lib/tables/column-sets/backup-log-columns.ts +19 -0
  86. package/lib/tables/column-sets/host-columns.ts +19 -0
  87. package/lib/tables/column-sets/network-columns.ts +22 -0
  88. package/lib/tables/column-sets/new-vm-network-columns.ts +24 -0
  89. package/lib/tables/column-sets/new-vm-sr-columns.ts +33 -0
  90. package/lib/tables/column-sets/patch-columns.ts +13 -0
  91. package/lib/tables/column-sets/pif-columns.ts +23 -0
  92. package/lib/tables/column-sets/server-columns.ts +18 -0
  93. package/lib/tables/column-sets/sr-columns.ts +20 -0
  94. package/lib/tables/column-sets/vdi-columns.ts +21 -0
  95. package/lib/tables/column-sets/vif-columns.ts +23 -0
  96. package/lib/tables/column-sets/vm-columns.ts +21 -0
  97. package/lib/tables/helpers/render-body-cell.ts +4 -0
  98. package/lib/tables/helpers/render-head-cell.ts +6 -0
  99. package/lib/tables/helpers/render-loading-cell.ts +5 -0
  100. package/lib/tables/types.ts +7 -0
  101. package/lib/utils/size.util.ts +5 -9
  102. package/package.json +1 -1
  103. package/lib/components/data-table/VtsDataTable.vue +0 -70
  104. package/lib/components/table/ColumnTitle.vue +0 -152
  105. package/lib/packages/table/apply-extensions.ts +0 -26
  106. package/lib/packages/table/define-renderer/define-table-cell-renderer.ts +0 -27
  107. package/lib/packages/table/define-renderer/define-table-renderer.ts +0 -47
  108. package/lib/packages/table/define-renderer/define-table-row-renderer.ts +0 -29
  109. package/lib/packages/table/define-renderer/define-table-section-renderer.ts +0 -29
  110. package/lib/packages/table/define-table/define-multi-source-table.ts +0 -39
  111. package/lib/packages/table/define-table/define-table.ts +0 -13
  112. package/lib/packages/table/define-table/define-typed-table.ts +0 -18
  113. package/lib/packages/table/transform-sources.ts +0 -13
  114. package/lib/packages/table/types/extensions.ts +0 -16
  115. package/lib/packages/table/types/index.ts +0 -47
  116. package/lib/packages/table/types/table-cell.ts +0 -18
  117. package/lib/packages/table/types/table-row.ts +0 -20
  118. package/lib/packages/table/types/table-section.ts +0 -19
  119. package/lib/packages/table/types/table.ts +0 -28
  120. package/lib/types/button.type.ts +0 -3
@@ -0,0 +1,64 @@
1
+ <template>
2
+ <UiTableCell>
3
+ <div class="content">
4
+ <span class="text">
5
+ {{ truncatedContent }}
6
+ </span>
7
+
8
+ <UiButton
9
+ v-if="shouldTruncate"
10
+ accent="brand"
11
+ size="small"
12
+ variant="tertiary"
13
+ class="typo-body-regular-small button"
14
+ @click="toggleExpanded()"
15
+ >
16
+ {{ isExpanded ? t('show-less') : t('show-more') }}
17
+ </UiButton>
18
+ </div>
19
+ </UiTableCell>
20
+ </template>
21
+
22
+ <script setup lang="ts">
23
+ import UiButton from '@core/components/ui/button/UiButton.vue'
24
+ import UiTableCell from '@core/components/ui/table-cell/UiTableCell.vue'
25
+ import { useToggle } from '@vueuse/shared'
26
+ import { computed } from 'vue'
27
+ import { useI18n } from 'vue-i18n'
28
+
29
+ const { content, limit } = defineProps<{
30
+ content: string
31
+ limit?: number
32
+ }>()
33
+
34
+ const DEFAULT_TRUNCATE_LIMIT = 90
35
+
36
+ const TRUNCATE_TOLERANCE = 20
37
+
38
+ const { t } = useI18n()
39
+
40
+ const truncateLimit = computed(() => limit ?? DEFAULT_TRUNCATE_LIMIT)
41
+
42
+ const shouldTruncate = computed(() => content.length > truncateLimit.value + TRUNCATE_TOLERANCE)
43
+
44
+ const [isExpanded, toggleExpanded] = useToggle(false)
45
+
46
+ const truncatedContent = computed(() => {
47
+ if (!shouldTruncate.value || isExpanded.value) {
48
+ return content
49
+ }
50
+
51
+ return `${content.slice(0, truncateLimit.value)}…`
52
+ })
53
+ </script>
54
+
55
+ <style lang="postcss" scoped>
56
+ .text {
57
+ overflow-wrap: anywhere;
58
+ }
59
+
60
+ .button {
61
+ float: right;
62
+ margin-top: -0.25rem;
63
+ }
64
+ </style>
@@ -5,7 +5,7 @@
5
5
  accent="brand"
6
6
  :dot="hasNewTask"
7
7
  icon="fa:bars-progress"
8
- size="large"
8
+ size="medium"
9
9
  @click="isPanelOpen = true"
10
10
  />
11
11
  <Teleport v-if="isPanelOpen" to="body">
@@ -14,7 +14,7 @@ defineProps<{
14
14
 
15
15
  <style lang="postcss" scoped>
16
16
  .vts-tree-line {
17
- flex: 0 1 1em;
17
+ flex: 0 1 1.5em;
18
18
  align-self: stretch;
19
19
  display: flex;
20
20
  align-items: center;
@@ -16,7 +16,7 @@
16
16
  class="close-button"
17
17
  icon="fa:xmark"
18
18
  accent="brand"
19
- size="medium"
19
+ size="small"
20
20
  @click="emit('close')"
21
21
  />
22
22
  </div>
@@ -18,7 +18,7 @@ export type ButtonVariant = 'primary' | 'secondary' | 'tertiary'
18
18
  export type ButtonAccent = 'brand' | 'warning' | 'danger'
19
19
  export type ButtonSize = 'small' | 'medium'
20
20
 
21
- const { accent, variant, size, disabled, busy, lockIcon } = defineProps<{
21
+ export type ButtonProps = {
22
22
  variant: ButtonVariant
23
23
  accent: ButtonAccent
24
24
  size: ButtonSize
@@ -26,7 +26,9 @@ const { accent, variant, size, disabled, busy, lockIcon } = defineProps<{
26
26
  disabled?: boolean
27
27
  lockIcon?: boolean
28
28
  leftIcon?: IconName
29
- }>()
29
+ }
30
+
31
+ const { accent, variant, size, disabled, busy, lockIcon } = defineProps<ButtonProps>()
30
32
 
31
33
  defineSlots<{
32
34
  default(): any
@@ -2,7 +2,7 @@
2
2
  <!-- TODO: Add complex icon -->
3
3
  <template>
4
4
  <button :class="classNames" :disabled class="ui-button-icon" type="button">
5
- <VtsIcon :name="icon" size="medium" />
5
+ <VtsIcon :name="icon" size="current" />
6
6
  <span v-if="dot" class="dot" />
7
7
  </button>
8
8
  </template>
@@ -13,8 +13,9 @@ import type { IconName } from '@core/icons'
13
13
  import { toVariants } from '@core/utils/to-variants.util'
14
14
  import { computed } from 'vue'
15
15
 
16
- type ButtonIconAccent = 'brand' | 'warning' | 'danger'
17
- type ButtonSize = 'small' | 'medium' | 'large'
16
+ export type ButtonIconAccent = 'brand' | 'warning' | 'danger'
17
+
18
+ export type ButtonIconSize = 'small' | 'medium' | 'large'
18
19
 
19
20
  const {
20
21
  accent,
@@ -24,7 +25,7 @@ const {
24
25
  targetScale = 1,
25
26
  } = defineProps<{
26
27
  icon: IconName
27
- size: ButtonSize
28
+ size: ButtonIconSize
28
29
  accent: ButtonIconAccent
29
30
  disabled?: boolean
30
31
  selected?: boolean
@@ -191,9 +192,9 @@ const classNames = computed(() => {
191
192
 
192
193
  &.size--small {
193
194
  & {
194
- width: 1.6rem;
195
- height: 1.6rem;
196
- font-size: 1.2rem;
195
+ width: 2.4rem;
196
+ height: 2.4rem;
197
+ font-size: 1.6rem;
197
198
  }
198
199
 
199
200
  .dot {
@@ -206,9 +207,9 @@ const classNames = computed(() => {
206
207
 
207
208
  &.size--medium {
208
209
  & {
209
- width: 2.4rem;
210
- height: 2.4rem;
211
- font-size: 1.6rem;
210
+ width: 3.2rem;
211
+ height: 3.2rem;
212
+ font-size: 2rem;
212
213
  }
213
214
 
214
215
  .dot {
@@ -223,7 +224,7 @@ const classNames = computed(() => {
223
224
  & {
224
225
  width: 4rem;
225
226
  height: 4rem;
226
- font-size: 2.4rem;
227
+ font-size: 3.2rem;
227
228
  }
228
229
 
229
230
  .dot {
@@ -0,0 +1,22 @@
1
+ <!-- WIP -->
2
+ <template>
3
+ <th class="ui-column-header typo-caption" scope="col">
4
+ <slot />
5
+ </th>
6
+ </template>
7
+
8
+ <style lang="postcss" scoped>
9
+ .ui-column-header {
10
+ max-width: 30rem;
11
+ padding: 0.8rem 1.2rem;
12
+ border-block-start: 0.1rem solid var(--color-neutral-border);
13
+ border-inline-end: 0.1rem solid var(--color-neutral-border);
14
+ text-align: start;
15
+ color: var(--color-brand-txt-base);
16
+ background-color: var(--color-neutral-background-primary);
17
+
18
+ &:last-child {
19
+ border-inline-end: none;
20
+ }
21
+ }
22
+ </style>
@@ -2,7 +2,7 @@
2
2
  <template>
3
3
  <div class="ui-info">
4
4
  <VtsIcon class="icon" :name="icon" size="medium" />
5
- <p v-tooltip="!wrap" class="typo-body-regular-small" :class="{ 'text-ellipsis': !wrap }">
5
+ <p v-tooltip="!wrap" class="typo-body-regular-small label" :class="{ 'text-ellipsis': !wrap }">
6
6
  <slot />
7
7
  </p>
8
8
  </div>
@@ -47,5 +47,9 @@ const icon = useMapper<InfoAccent, IconName>(
47
47
  .icon {
48
48
  font-size: 1.6rem;
49
49
  }
50
+
51
+ .label:empty {
52
+ display: none;
53
+ }
50
54
  }
51
55
  </style>
@@ -35,8 +35,9 @@ import { IK_INPUT_WRAPPER_CONTROLLER } from '@core/utils/injection-keys.util'
35
35
  import { toVariants } from '@core/utils/to-variants.util'
36
36
  import { inject, ref, useAttrs, watchEffect } from 'vue'
37
37
 
38
- type InputAccent = 'brand' | 'warning' | 'danger'
39
- type InputType = 'text' | 'number' | 'password' | 'search'
38
+ export type InputAccent = 'brand' | 'warning' | 'danger'
39
+
40
+ export type InputType = 'text' | 'number' | 'password' | 'search'
40
41
 
41
42
  defineOptions({
42
43
  inheritAttrs: false,
@@ -62,6 +62,11 @@ const classes = computed(() => [typoClasses[props.size], { disabled: isDisabled.
62
62
  cursor: not-allowed;
63
63
  }
64
64
 
65
+ &:not([href]) {
66
+ text-decoration: none;
67
+ cursor: default;
68
+ }
69
+
65
70
  .external-icon {
66
71
  font-size: 0.75em;
67
72
  }
@@ -9,7 +9,7 @@
9
9
  <VtsCopyButton :value="content" />
10
10
  <UiButtonIcon
11
11
  icon="fa:arrow-up-right-from-square"
12
- size="medium"
12
+ size="small"
13
13
  accent="brand"
14
14
  @click="openRawValueInNewTab()"
15
15
  />
@@ -32,8 +32,8 @@
32
32
 
33
33
  <!-- Mobile icons: search + filter -->
34
34
  <template v-else>
35
- <UiButtonIcon accent="brand" size="medium" type="submit" icon="fa:magnifying-glass" class="action-button" />
36
- <UiButtonIcon accent="brand" size="medium" disabled icon="fa:filter" class="action-button" />
35
+ <UiButtonIcon accent="brand" size="small" type="submit" icon="fa:magnifying-glass" class="action-button" />
36
+ <UiButtonIcon accent="brand" size="small" disabled icon="fa:filter" class="action-button" />
37
37
  </template>
38
38
  </form>
39
39
  </template>
@@ -0,0 +1,41 @@
1
+ <!-- WIP -->
2
+ <template>
3
+ <td class="ui-table-cell typo-body-regular" :class="align">
4
+ <slot />
5
+ </td>
6
+ </template>
7
+
8
+ <script lang="ts" setup>
9
+ export type TableCellAlign = 'start' | 'center' | 'end'
10
+
11
+ const { align = 'start' } = defineProps<{
12
+ align?: TableCellAlign
13
+ }>()
14
+ </script>
15
+
16
+ <style lang="postcss" scoped>
17
+ .ui-table-cell {
18
+ padding: 1.2rem;
19
+ border: 0.1rem solid var(--color-neutral-border);
20
+ border-inline-start: none;
21
+ color: var(--color-neutral-txt-primary);
22
+ background-color: var(--ui-table-cell-background-color, var(--color-neutral-background-primary));
23
+ max-width: 50rem;
24
+
25
+ &:last-child {
26
+ border-inline-end: none;
27
+ }
28
+
29
+ &.start {
30
+ text-align: start;
31
+ }
32
+
33
+ &.center {
34
+ text-align: center;
35
+ }
36
+
37
+ &.end {
38
+ text-align: end;
39
+ }
40
+ }
41
+ </style>
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <UiButtonIcon :disabled accent="brand" class="pagination-button" size="medium" :icon />
2
+ <UiButtonIcon :disabled accent="brand" class="pagination-button" size="small" :icon />
3
3
  </template>
4
4
 
5
5
  <script setup lang="ts">
@@ -0,0 +1,229 @@
1
+ <!-- v10 -->
2
+ <template>
3
+ <li class="ui-task-item" :data-depth="depth">
4
+ <div class="container">
5
+ <div class="tree-section">
6
+ <div class="tree-lines">
7
+ <div v-for="index in depth - 1" :key="index" class="tree-line">
8
+ <div class="tree-line-vertical" />
9
+ </div>
10
+ </div>
11
+ <UiButtonIcon
12
+ v-if="hasSubTasks"
13
+ v-tooltip="expanded ? t('core.close') : t('core.open')"
14
+ accent="brand"
15
+ :icon="expanded ? 'fa:angle-down' : 'fa:angle-right'"
16
+ size="small"
17
+ :target-scale="{ x: 1.5, y: 2 }"
18
+ @click="emit('expand')"
19
+ />
20
+ <div v-else class="h-space" />
21
+ </div>
22
+
23
+ <div class="main-content">
24
+ <div v-if="task.name" class="content-left">
25
+ <UiLink size="medium">
26
+ {{ task.name }}
27
+ </UiLink>
28
+ <div v-if="shouldShowInfos || hasSubTasks" class="infos">
29
+ <UiCounter v-if="hasSubTasks" :value="subTasksCount" accent="brand" variant="secondary" size="small" />
30
+ <UiInfo v-if="hasInfos" accent="info" />
31
+ <UiInfo v-if="hasWarnings" accent="warning" />
32
+ <UiInfo v-if="isError" accent="danger" />
33
+ </div>
34
+ </div>
35
+
36
+ <div class="content-right typo-body-regular-small">
37
+ <span v-if="task.end">
38
+ {{ `${t('task.ended')} ${end}` }}
39
+ </span>
40
+ <div class="progress">
41
+ <UiCircleProgressBar
42
+ v-if="task.progress !== undefined"
43
+ :accent="progressAccent"
44
+ size="small"
45
+ :value="task.progress"
46
+ />
47
+ </div>
48
+ <div class="actions">
49
+ <UiButtonIcon icon="fa:eye" size="medium" accent="brand" @click="emit('select')" />
50
+ </div>
51
+ </div>
52
+ </div>
53
+ </div>
54
+ <template v-if="hasSubTasks && expanded">
55
+ <UiTaskList :tasks="subTasks" :depth />
56
+ </template>
57
+ </li>
58
+ </template>
59
+
60
+ <script lang="ts" setup>
61
+ import UiButtonIcon from '@core/components/ui/button-icon/UiButtonIcon.vue'
62
+ import UiCircleProgressBar from '@core/components/ui/circle-progress-bar/UiCircleProgressBar.vue'
63
+ import UiCounter from '@core/components/ui/counter/UiCounter.vue'
64
+ import UiInfo from '@core/components/ui/info/UiInfo.vue'
65
+ import UiLink from '@core/components/ui/link/UiLink.vue'
66
+ import UiTaskList from '@core/components/ui/task-list/UiTaskList.vue'
67
+ import { useTimeAgo } from '@core/composables/locale-time-ago.composable.ts'
68
+ import { vTooltip } from '@core/directives/tooltip.directive'
69
+ import { logicOr } from '@vueuse/math'
70
+ import { computed } from 'vue'
71
+ import { useI18n } from 'vue-i18n'
72
+
73
+ export type Task = {
74
+ id: string
75
+ infos?: { data: unknown; message: string }[]
76
+ name?: string
77
+ progress?: number
78
+ end?: number
79
+ status: 'failure' | 'interrupted' | 'pending' | 'success'
80
+ tasks?: Task[]
81
+ warning?: { data: unknown; message: string }[]
82
+ }
83
+
84
+ const { task } = defineProps<{
85
+ task: Task
86
+ depth: number
87
+ expanded?: boolean
88
+ }>()
89
+
90
+ const emit = defineEmits<{
91
+ expand: []
92
+ select: []
93
+ }>()
94
+
95
+ const { t } = useI18n()
96
+
97
+ const subTasks = computed(() => task.tasks ?? [])
98
+
99
+ const subTasksCount = computed(() => subTasks.value.length)
100
+
101
+ const hasSubTasks = computed(() => subTasksCount.value > 0)
102
+
103
+ const isError = computed(() => task.status === 'failure' || task.status === 'interrupted')
104
+
105
+ const end = useTimeAgo(() => task.end ?? 0)
106
+
107
+ const hasWarnings = computed(() => task.warning && task.warning.length > 0)
108
+
109
+ const hasInfos = computed(() => task.infos && task.infos.length > 0)
110
+
111
+ const shouldShowInfos = logicOr(isError, hasWarnings, hasInfos)
112
+
113
+ const progressAccent = computed(() => (isError.value ? 'danger' : 'info'))
114
+ </script>
115
+
116
+ <style lang="postcss" scoped>
117
+ .ui-task-item {
118
+ &[data-depth='1']:last-child {
119
+ border-bottom: 0.1rem solid var(--color-neutral-border);
120
+ }
121
+
122
+ .container {
123
+ display: flex;
124
+ min-height: 4.8rem;
125
+ position: relative;
126
+
127
+ &::after {
128
+ content: '';
129
+ width: 100%;
130
+ position: absolute;
131
+ clip-path: inset(0 0 0 calc(4rem * v-bind(depth - 1)));
132
+ height: 0.1rem;
133
+ background: var(--color-neutral-border);
134
+ }
135
+
136
+ .tree-section {
137
+ display: flex;
138
+ align-items: center;
139
+ padding-left: 1.6rem;
140
+ gap: 0.4rem;
141
+
142
+ .tree-lines {
143
+ display: flex;
144
+ align-self: stretch;
145
+ }
146
+
147
+ .tree-line {
148
+ flex: 0 0 2.8rem;
149
+ display: flex;
150
+ align-items: center;
151
+ justify-content: center;
152
+
153
+ .tree-line-vertical {
154
+ width: 0.1rem;
155
+ background: var(--color-brand-txt-base);
156
+ height: 100%;
157
+ }
158
+ }
159
+
160
+ .h-space {
161
+ width: 2.4rem;
162
+ }
163
+ }
164
+
165
+ .main-content {
166
+ display: flex;
167
+ flex-direction: row;
168
+ flex: 1;
169
+ min-width: 0;
170
+ gap: 1.6rem;
171
+ padding: 0.4rem 1.6rem;
172
+ justify-content: space-between;
173
+ align-items: center;
174
+ }
175
+
176
+ .content-left {
177
+ display: flex;
178
+ gap: 1.6rem;
179
+ align-items: center;
180
+ flex-wrap: wrap;
181
+ color: var(--color-neutral-txt-secondary);
182
+ word-break: break-word;
183
+
184
+ .infos {
185
+ display: flex;
186
+ align-items: center;
187
+ gap: 0.8rem;
188
+ }
189
+ }
190
+
191
+ .content-right {
192
+ display: flex;
193
+ align-items: center;
194
+ gap: 1.6rem;
195
+ color: var(--color-neutral-txt-secondary);
196
+ flex-shrink: 0;
197
+
198
+ .progress {
199
+ display: flex;
200
+ width: 4rem;
201
+ }
202
+
203
+ .actions {
204
+ display: flex;
205
+ gap: 1.6rem;
206
+ }
207
+ }
208
+ }
209
+
210
+ @media (max-width: 768px) {
211
+ .container {
212
+ .main-content {
213
+ flex-direction: column;
214
+ align-items: flex-start;
215
+ gap: 0.8rem;
216
+ padding: 0.8rem;
217
+ }
218
+
219
+ .content-right {
220
+ gap: 0.8rem;
221
+
222
+ .actions {
223
+ gap: 0.8rem;
224
+ }
225
+ }
226
+ }
227
+ }
228
+ }
229
+ </style>
@@ -0,0 +1,31 @@
1
+ <template>
2
+ <ul>
3
+ <UiTaskItem
4
+ v-for="task of tasksItems"
5
+ :key="task.id"
6
+ :task="task.source"
7
+ :expanded="task.flags.expanded"
8
+ :depth="depth + 1"
9
+ @select="emit('select', task.id)"
10
+ @expand="task.toggleFlag('expanded')"
11
+ />
12
+ </ul>
13
+ </template>
14
+
15
+ <script lang="ts" setup>
16
+ import UiTaskItem, { type Task } from '@core/components/ui/task-item/UiTaskItem.vue'
17
+ import { useCollection } from '@core/packages/collection'
18
+
19
+ const { tasks, depth = 0 } = defineProps<{
20
+ tasks: Task[]
21
+ depth?: number
22
+ }>()
23
+
24
+ const emit = defineEmits<{
25
+ select: [id: string]
26
+ }>()
27
+
28
+ const { items: tasksItems } = useCollection(() => tasks, {
29
+ flags: ['expanded'],
30
+ })
31
+ </script>
@@ -11,7 +11,7 @@
11
11
  <slot name="description" />
12
12
  </div>
13
13
  </div>
14
- <UiButtonIcon class="close-icon" icon="fa:xmark" accent="brand" size="medium" @click="emit('close')" />
14
+ <UiButtonIcon class="close-icon" icon="fa:xmark" accent="brand" size="small" @click="emit('close')" />
15
15
  </div>
16
16
  <div v-if="slots.actions" class="actions">
17
17
  <slot name="actions" />
@@ -1,7 +1,7 @@
1
1
  <!-- v2 -->
2
2
  <template>
3
- <div class="ui-top-bottom-table">
4
- <div class="content">
3
+ <div class="ui-top-bottom-table" :class="{ 'no-content': totalItems === 0 }">
4
+ <div v-if="totalItems > 0" class="content">
5
5
  <span class="typo-body-regular-small label">
6
6
  {{ t('core.select.n-selected-of', { count: selectedItems, total: totalItems }) }}
7
7
  </span>
@@ -63,5 +63,9 @@ const { t } = useI18n()
63
63
  .label {
64
64
  color: var(--color-neutral-txt-secondary);
65
65
  }
66
+
67
+ &.no-content {
68
+ justify-content: flex-end;
69
+ }
66
70
  }
67
71
  </style>
@@ -7,12 +7,7 @@
7
7
  v-bind="attrs"
8
8
  >
9
9
  <template v-if="depth > 1">
10
- <VtsTreeLine
11
- v-for="i in depth - 1"
12
- :key="i"
13
- :half-height="(!hasToggle && i === depth - 1) || !isExpanded"
14
- :right="i === depth - 1"
15
- />
10
+ <VtsTreeLine v-for="i in depth - 1" :key="i" />
16
11
  </template>
17
12
  <UiButtonIcon
18
13
  v-if="hasToggle"
@@ -116,7 +111,6 @@ const depth = inject(IK_TREE_LIST_DEPTH, 0)
116
111
 
117
112
  .h-line {
118
113
  width: 2rem;
119
- border-bottom: 0.1rem solid var(--color-brand-txt-base);
120
114
  margin-left: -0.4rem;
121
115
  }
122
116
 
@@ -5,6 +5,21 @@ import { toComputed } from '@core/utils/to-computed.util'
5
5
  import { clamp, useLocalStorage } from '@vueuse/core'
6
6
  import { computed, type MaybeRefOrGetter } from 'vue'
7
7
 
8
+ export type PaginationBindings = {
9
+ size: TablePaginationSize
10
+ showBy: number
11
+ 'onUpdate:showBy': (value: number) => void
12
+ from: number
13
+ to: number
14
+ total: number
15
+ isFirstPage: boolean
16
+ isLastPage: boolean
17
+ onFirst: () => void
18
+ onLast: () => void
19
+ onNext: () => void
20
+ onPrevious: () => void
21
+ }
22
+
8
23
  export function usePagination<T>(id: string, _records: MaybeRefOrGetter<T[]>) {
9
24
  const records = toComputed(_records)
10
25
 
@@ -65,7 +80,7 @@ export function usePagination<T>(id: string, _records: MaybeRefOrGetter<T[]>) {
65
80
 
66
81
  const uiStore = useUiStore()
67
82
 
68
- const paginationBindings = computed(() => ({
83
+ const paginationBindings = computed<PaginationBindings>(() => ({
69
84
  size: (uiStore.isMobile ? 'small' : 'medium') as TablePaginationSize,
70
85
  showBy: showBy.value,
71
86
  'onUpdate:showBy': (value: number) => (showBy.value = value),