@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
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <div :class="uiStore.isMobile ? 'mobile' : undefined" class="vts-remote-console">
3
- <VtsStateHero v-if="!isReady" format="page" busy size="medium">{{ t('loading') }}</VtsStateHero>
3
+ <VtsStateHero v-if="!isReady" format="page" type="busy" size="medium">{{ t('loading') }}</VtsStateHero>
4
4
  <div ref="console-container" class="console" />
5
5
  </div>
6
6
  </template>
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <UiButtonIcon v-tooltip="copied && t('core.copied')" :icon size="medium" accent="brand" @click="copy()" />
2
+ <UiButtonIcon v-tooltip="copied && t('core.copied')" :icon size="small" accent="brand" @click="copy()" />
3
3
  </template>
4
4
 
5
5
  <script setup lang="ts">
@@ -10,7 +10,7 @@
10
10
  placement: 'right',
11
11
  }"
12
12
  accent="brand"
13
- size="medium"
13
+ size="small"
14
14
  :icon="sidebar.isLocked ? 'fa:thumb-tack-slash' : 'fa:thumb-tack'"
15
15
  @click="sidebar.toggleLock()"
16
16
  />
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <UiCard class="vts-quick-info-card">
3
3
  <UiCardTitle>{{ t('quick-info') }}</UiCardTitle>
4
- <VtsStateHero v-if="loading" format="card" busy size="medium" />
4
+ <VtsStateHero v-if="loading" format="card" type="busy" size="medium" />
5
5
  <div v-else class="info-container">
6
6
  <slot />
7
7
  </div>
@@ -5,7 +5,6 @@
5
5
  <script lang="ts" setup>
6
6
  import useRelativeTime from '@core/composables/relative-time.composable'
7
7
  import { parseDateTime } from '@core/utils/time.util'
8
- import { useNow } from '@vueuse/core'
9
8
  import { computed } from 'vue'
10
9
 
11
10
  const props = defineProps<{
@@ -13,6 +12,6 @@ const props = defineProps<{
13
12
  }>()
14
13
 
15
14
  const date = computed(() => new Date(parseDateTime(props.date)))
16
- const now = useNow({ interval: 1000 })
17
- const relativeTime = useRelativeTime(date, now)
15
+
16
+ const relativeTime = useRelativeTime(date)
18
17
  </script>
@@ -65,7 +65,7 @@ const { accent, id } = defineProps<{
65
65
  }>()
66
66
 
67
67
  defineSlots<{
68
- default(props: { option: FormSelectIdToOption<TSelectId> }): any
68
+ default?(props: { option: FormSelectIdToOption<TSelectId> }): any
69
69
  }>()
70
70
 
71
71
  const { t } = useI18n()
@@ -1,8 +1,9 @@
1
1
  <template>
2
2
  <div :class="[className, { horizontal, error, success, 'no-background': noBackground }]" class="vts-state-hero">
3
- <UiLoader v-if="busy" class="loader" />
3
+ <UiLoader v-if="type === 'busy'" class="loader" />
4
4
  <img v-else-if="imageSrc" :src="imageSrc" :alt="type" class="image" />
5
- <div v-if="slots.default" :class="typoClass" class="content">
5
+ <div v-if="slots.default || success" :class="typoClass" class="content">
6
+ <div v-if="success">{{ t('all-good') }}</div>
6
7
  <slot />
7
8
  </div>
8
9
  </div>
@@ -12,10 +13,14 @@
12
13
  import UiLoader from '@core/components/ui/loader/UiLoader.vue'
13
14
  import { toVariants } from '@core/utils/to-variants.util.ts'
14
15
  import { computed } from 'vue'
16
+ import { useI18n } from 'vue-i18n'
15
17
 
16
18
  export type StateHeroFormat = 'page' | 'card' | 'panel' | 'table'
17
19
 
18
- type StateHeroType =
20
+ export type StateHeroSize = 'extra-small' | 'small' | 'medium' | 'large'
21
+
22
+ export type StateHeroType =
23
+ | 'busy'
19
24
  | 'no-result'
20
25
  | 'under-construction'
21
26
  | 'no-data'
@@ -26,12 +31,11 @@ type StateHeroType =
26
31
  | 'all-good'
27
32
  | 'all-done'
28
33
 
29
- const { format, type, size, busy } = defineProps<{
34
+ const { format, type, size } = defineProps<{
30
35
  format: StateHeroFormat
31
- type?: StateHeroType
32
- size: 'extra-small' | 'small' | 'medium' | 'large'
36
+ type: StateHeroType
37
+ size: StateHeroSize
33
38
  horizontal?: boolean
34
- busy?: boolean
35
39
  noBackground?: boolean
36
40
  }>()
37
41
 
@@ -39,16 +43,18 @@ const slots = defineSlots<{
39
43
  default?(): any
40
44
  }>()
41
45
 
46
+ const { t } = useI18n()
47
+
42
48
  const typoClass = computed(() => (format === 'page' ? 'typo-h2' : 'typo-h4'))
43
49
 
44
50
  const className = computed(() => toVariants({ size, format }))
45
51
 
46
- const error = computed(() => !busy && type === 'error')
52
+ const error = computed(() => type === 'error')
47
53
 
48
- const success = computed(() => !busy && (type === 'all-good' || type === 'all-done'))
54
+ const success = computed(() => type === 'all-good' || type === 'all-done')
49
55
 
50
56
  const imageSrc = computed(() => {
51
- if (!type) {
57
+ if (type === 'busy') {
52
58
  return undefined
53
59
  }
54
60
 
@@ -80,6 +86,10 @@ const imageSrc = computed(() => {
80
86
  display: flex;
81
87
  flex-direction: column;
82
88
  gap: 1.6rem;
89
+
90
+ &:empty {
91
+ display: none;
92
+ }
83
93
  }
84
94
 
85
95
  .loader,
@@ -0,0 +1,26 @@
1
+ <template>
2
+ <tr class="vts-row" :class="{ selected }">
3
+ <slot />
4
+ </tr>
5
+ </template>
6
+
7
+ <script lang="ts" setup>
8
+ defineProps<{
9
+ selected?: boolean
10
+ }>()
11
+ </script>
12
+
13
+ <style lang="postcss" scoped>
14
+ .vts-row {
15
+ &.selected {
16
+ --ui-table-cell-background-color: var(--color-brand-background-selected);
17
+ }
18
+
19
+ &:not(:last-child) {
20
+ :deep(th),
21
+ :deep(td) {
22
+ border-bottom: none;
23
+ }
24
+ }
25
+ }
26
+ </style>
@@ -1,66 +1,123 @@
1
1
  <template>
2
- <table :class="{ 'vertical-border': verticalBorder }" class="vts-table typo-body-regular-small">
3
- <slot />
4
- </table>
2
+ <div class="vts-table" :class="className">
3
+ <VtsStateHero v-if="state" format="table" :type="state.type" :size="state.size ?? 'medium'">
4
+ {{ state.message }}
5
+ </VtsStateHero>
6
+ <div v-else class="table-container">
7
+ <UiTablePagination v-if="paginationBindings" v-bind="paginationBindings" class="pagination" />
8
+ <div ref="wrapper" class="wrapper">
9
+ <table class="table" vertical-border>
10
+ <slot />
11
+ </table>
12
+ </div>
13
+ <UiTablePagination v-if="paginationBindings" v-bind="paginationBindings" class="pagination" />
14
+ </div>
15
+ </div>
5
16
  </template>
6
17
 
7
18
  <script lang="ts" setup>
8
- import { provide } from 'vue'
19
+ import VtsStateHero, { type StateHeroSize, type StateHeroType } from '@core/components/state-hero/VtsStateHero.vue'
20
+ import UiTablePagination from '@core/components/ui/table-pagination/UiTablePagination.vue'
21
+ import type { PaginationBindings } from '@core/composables/pagination.composable'
22
+ import { hasEllipsis } from '@core/utils/has-ellipsis.util'
23
+ import { toVariants } from '@core/utils/to-variants.util'
24
+ import { useResizeObserver, useScroll } from '@vueuse/core'
25
+ import { computed, ref, useTemplateRef } from 'vue'
9
26
 
10
- const props = defineProps<{
11
- name?: string
12
- verticalBorder?: boolean
13
- }>()
27
+ export type TableStickySide = 'left' | 'right' | 'both'
28
+
29
+ export type TableState = {
30
+ type: StateHeroType
31
+ message?: string
32
+ size?: StateHeroSize
33
+ }
14
34
 
15
- defineSlots<{
16
- default(): any
35
+ const { state, sticky } = defineProps<{
36
+ state?: TableState
37
+ sticky?: TableStickySide
38
+ paginationBindings?: PaginationBindings
17
39
  }>()
18
40
 
19
- provide('tableName', props.name)
41
+ const wrapper = useTemplateRef('wrapper')
42
+
43
+ const { arrivedState } = useScroll(wrapper)
44
+
45
+ const canScroll = ref(false)
46
+
47
+ useResizeObserver(wrapper, ([entry]) => {
48
+ canScroll.value = hasEllipsis(entry.target)
49
+ })
50
+
51
+ const className = computed(() =>
52
+ canScroll.value
53
+ ? toVariants({
54
+ sticky,
55
+ stuck: arrivedState.left ? (arrivedState.right ? 'both' : 'left') : arrivedState.right ? 'right' : false,
56
+ })
57
+ : {}
58
+ )
20
59
  </script>
21
60
 
22
61
  <style lang="postcss" scoped>
23
62
  .vts-table {
24
- width: 100%;
25
- border-spacing: 0;
26
- background-color: var(--color-neutral-background-primary);
27
- line-height: 2.4rem;
28
- color: var(--color-neutral-txt-secondary);
29
- border-collapse: collapse;
30
- table-layout: fixed;
31
-
32
- :deep(th),
33
- :deep(td) {
34
- padding: 1rem;
35
- border-top: 0.1rem solid var(--color-neutral-border);
36
- text-align: left;
63
+ display: flex;
64
+ flex-direction: column;
65
+ gap: 0.8rem;
66
+
67
+ .table-container {
68
+ display: flex;
69
+ flex-direction: column;
70
+ gap: 0.8rem;
37
71
  }
38
72
 
39
- :deep(th) {
40
- font-weight: 700;
73
+ .pagination {
74
+ margin-left: auto;
41
75
  }
42
76
 
43
- :deep(thead) {
44
- th,
45
- td {
46
- color: var(--color-brand-txt-base);
47
- font-size: 1.4rem;
48
- font-weight: 400;
49
- text-transform: uppercase;
50
- }
77
+ .wrapper {
78
+ max-width: 100%;
79
+ overflow: auto;
80
+ }
81
+
82
+ .table {
83
+ min-width: 100%;
84
+ width: max-content;
85
+ border-spacing: 0;
51
86
  }
52
87
 
53
- &.vertical-border {
54
- :deep(th),
55
- :deep(td) {
56
- border-right: 0.1rem solid var(--color-neutral-border);
88
+ &.sticky--left,
89
+ &.sticky--both {
90
+ :deep(th:first-child),
91
+ :deep(td:first-child) {
92
+ position: sticky;
93
+ left: 0;
94
+ border-right: 0.3rem solid var(--color-brand-item-base);
95
+ transition: border-right 0.1s ease-out;
96
+ z-index: 1;
97
+ }
57
98
 
58
- &:first-child {
59
- border-left: none;
99
+ &.stuck--left {
100
+ :deep(th:first-child),
101
+ :deep(td:first-child) {
102
+ border-right-color: var(--color-neutral-border);
60
103
  }
104
+ }
105
+ }
106
+
107
+ &.sticky--right,
108
+ &.sticky--both {
109
+ :deep(th:last-child),
110
+ :deep(td:last-child) {
111
+ position: sticky;
112
+ right: 0;
113
+ border-left: 0.3rem solid var(--color-brand-item-base);
114
+ transition: border-left 0.1s ease-out;
115
+ }
61
116
 
62
- &:last-child {
63
- border-right: none;
117
+ &.stuck--right {
118
+ :deep(th:last-child),
119
+ :deep(td:last-child) {
120
+ border-left-color: var(--color-neutral-border);
64
121
  }
65
122
  }
66
123
  }
@@ -0,0 +1,59 @@
1
+ <template>
2
+ <UiTableCell>
3
+ <div v-if="items.length > 1 && !isExpanded" class="content">
4
+ {{ items[0] }}
5
+ <UiButton
6
+ accent="brand"
7
+ size="small"
8
+ variant="tertiary"
9
+ class="typo-body-regular-small more"
10
+ @click="toggleExpand(true)"
11
+ >
12
+ {{ `+${items.length - 1}` }}
13
+ </UiButton>
14
+ </div>
15
+ <ul v-else>
16
+ <li v-for="(item, index) of items" :key="index">
17
+ <div class="content">
18
+ {{ item }}
19
+ <UiButton
20
+ v-if="isExpanded && index === 0"
21
+ accent="brand"
22
+ size="small"
23
+ variant="tertiary"
24
+ class="typo-body-regular-small more"
25
+ @click="toggleExpand(false)"
26
+ >
27
+ <VtsIcon size="small" name="fa:minus" />
28
+ </UiButton>
29
+ </div>
30
+ </li>
31
+ </ul>
32
+ </UiTableCell>
33
+ </template>
34
+
35
+ <script setup lang="ts">
36
+ import VtsIcon from '@core/components/icon/VtsIcon.vue'
37
+ import UiButton from '@core/components/ui/button/UiButton.vue'
38
+ import UiTableCell from '@core/components/ui/table-cell/UiTableCell.vue'
39
+ import type { MaybeArray } from '@core/types/utility.type'
40
+ import { useToggle } from '@vueuse/shared'
41
+
42
+ defineProps<{
43
+ items: MaybeArray<string>
44
+ }>()
45
+
46
+ const [isExpanded, toggleExpand] = useToggle()
47
+ </script>
48
+
49
+ <style lang="postcss" scoped>
50
+ .content {
51
+ display: flex;
52
+ justify-content: space-between;
53
+ align-items: center;
54
+
55
+ .more {
56
+ color: var(--color-neutral-txt-secondary);
57
+ }
58
+ }
59
+ </style>
@@ -0,0 +1,31 @@
1
+ <template>
2
+ <UiColumnHeader class="vts-header-cell">
3
+ <div class="cell-content">
4
+ <VtsIcon v-if="icon" :name="icon" size="medium" />
5
+ <slot />
6
+ </div>
7
+ </UiColumnHeader>
8
+ </template>
9
+
10
+ <script lang="ts" setup>
11
+ import VtsIcon from '@core/components/icon/VtsIcon.vue'
12
+ import UiColumnHeader from '@core/components/ui/column-header/UiColumnHeader.vue'
13
+ import type { IconName } from '@core/icons'
14
+
15
+ defineProps<{
16
+ icon?: IconName
17
+ }>()
18
+ </script>
19
+
20
+ <style lang="postcss" scoped>
21
+ .vts-header-cell {
22
+ max-width: 30rem;
23
+
24
+ .cell-content {
25
+ display: flex;
26
+ align-items: center;
27
+ gap: 0.8rem;
28
+ white-space: nowrap;
29
+ }
30
+ }
31
+ </style>
@@ -0,0 +1,33 @@
1
+ <template>
2
+ <UiTableCell>
3
+ <UiLink size="medium" :icon :to :href :target class="link">
4
+ <slot />
5
+ <VtsIcon v-if="rightIcon" v-tooltip="rightIcon.tooltip ?? false" :name="rightIcon.icon" size="medium" />
6
+ </UiLink>
7
+ </UiTableCell>
8
+ </template>
9
+
10
+ <script setup lang="ts">
11
+ import VtsIcon from '@core/components/icon/VtsIcon.vue'
12
+ import UiLink from '@core/components/ui/link/UiLink.vue'
13
+ import UiTableCell from '@core/components/ui/table-cell/UiTableCell.vue'
14
+ import type { LinkOptions } from '@core/composables/link-component.composable'
15
+ import { vTooltip } from '@core/directives/tooltip.directive'
16
+ import type { IconName } from '@core/icons'
17
+
18
+ export type VtsLinkCellProps = LinkOptions & {
19
+ icon?: IconName
20
+ rightIcon?: {
21
+ icon: IconName
22
+ tooltip?: string
23
+ }
24
+ }
25
+
26
+ defineProps<VtsLinkCellProps>()
27
+ </script>
28
+
29
+ <style lang="postcss" scoped>
30
+ .link {
31
+ line-height: 1.5;
32
+ }
33
+ </style>
@@ -0,0 +1,21 @@
1
+ <template>
2
+ <UiTableCell align="end">
3
+ <slot />
4
+ <span v-if="unit" class="unit">{{ unit }}</span>
5
+ </UiTableCell>
6
+ </template>
7
+
8
+ <script setup lang="ts">
9
+ import UiTableCell from '@core/components/ui/table-cell/UiTableCell.vue'
10
+
11
+ defineProps<{
12
+ unit?: string
13
+ }>()
14
+ </script>
15
+
16
+ <style lang="postcss" scoped>
17
+ .unit {
18
+ color: var(--color-neutral-txt-secondary);
19
+ margin-inline-start: 0.4rem;
20
+ }
21
+ </style>
@@ -1,12 +1,15 @@
1
1
  <template>
2
- <div class="progress-cell">
3
- <VtsProgressBar :current :total noruler class="progress" />
4
- <span>{{ n(percentage / 100, { maximumFractionDigits: 0, style: 'percent' }) }}</span>
5
- </div>
2
+ <UiTableCell>
3
+ <div class="container">
4
+ <VtsProgressBar :current :total noruler class="progress" />
5
+ <span>{{ n(percentage / 100, { maximumFractionDigits: 0, style: 'percent' }) }}</span>
6
+ </div>
7
+ </UiTableCell>
6
8
  </template>
7
9
 
8
10
  <script setup lang="ts">
9
11
  import VtsProgressBar from '@core/components/progress-bar/VtsProgressBar.vue'
12
+ import UiTableCell from '@core/components/ui/table-cell/UiTableCell.vue'
10
13
  import { useProgress } from '@core/packages/progress/use-progress.ts'
11
14
  import { useI18n } from 'vue-i18n'
12
15
 
@@ -24,7 +27,7 @@ const { percentage } = useProgress(
24
27
  </script>
25
28
 
26
29
  <style lang="postcss" scoped>
27
- .progress-cell {
30
+ .container {
28
31
  display: flex;
29
32
  align-items: center;
30
33
  gap: 0.8rem;
@@ -0,0 +1,69 @@
1
+ <template>
2
+ <UiTableCell>
3
+ <div class="statuses" :class="{ 'has-label': !iconOnly, progressive: progressiveSize }">
4
+ <VtsStatus
5
+ v-for="(statusItem, index) of statuses"
6
+ :key="index"
7
+ v-tooltip="statusItem.tooltip ?? false"
8
+ :icon-only
9
+ class="status"
10
+ :status="statusItem.status"
11
+ />
12
+ </div>
13
+ </UiTableCell>
14
+ </template>
15
+
16
+ <script setup lang="ts">
17
+ import VtsStatus, { type Status } from '@core/components/status/VtsStatus.vue'
18
+ import UiTableCell from '@core/components/ui/table-cell/UiTableCell.vue'
19
+ import { vTooltip } from '@core/directives/tooltip.directive'
20
+ import type { MaybeArray } from '@core/types/utility.type'
21
+ import { toArray } from '@core/utils/to-array.utils'
22
+ import { computed } from 'vue'
23
+
24
+ export type StatusCellProps = {
25
+ status: MaybeArray<Status | { status: Status; tooltip?: string }>
26
+ progressiveSize?: boolean
27
+ iconOnly?: boolean
28
+ }
29
+
30
+ const { status } = defineProps<StatusCellProps>()
31
+
32
+ const statuses = computed(() => toArray(status).map(status => (typeof status === 'object' ? status : { status })))
33
+ </script>
34
+
35
+ <style lang="postcss" scoped>
36
+ .statuses {
37
+ display: flex;
38
+ align-items: center;
39
+
40
+ &.has-label {
41
+ gap: 1.2rem;
42
+ }
43
+
44
+ &.progressive .status {
45
+ position: relative;
46
+
47
+ &:first-child {
48
+ scale: 1.2;
49
+ }
50
+
51
+ &:nth-child(2) {
52
+ margin-inline-start: 0.7rem;
53
+ }
54
+
55
+ /* From 3rd status onward, all are scaled down to 0.8 */
56
+ &:nth-child(n + 3) {
57
+ scale: 0.8;
58
+ margin-inline-start: 0.4rem;
59
+
60
+ &::after {
61
+ content: '';
62
+ position: absolute;
63
+ inset: 0;
64
+ transform: scale(1.7);
65
+ }
66
+ }
67
+ }
68
+ }
69
+ </style>
@@ -0,0 +1,24 @@
1
+ <template>
2
+ <UiTableCell>
3
+ <UiTagsList>
4
+ <UiTag v-for="tagItem of tags" :key="tagItem" accent="info" variant="secondary">
5
+ {{ tagItem }}
6
+ </UiTag>
7
+ </UiTagsList>
8
+ </UiTableCell>
9
+ </template>
10
+
11
+ <script setup lang="ts">
12
+ import UiTableCell from '@core/components/ui/table-cell/UiTableCell.vue'
13
+ import UiTag from '@core/components/ui/tag/UiTag.vue'
14
+ import UiTagsList from '@core/components/ui/tag/UiTagsList.vue'
15
+ import type { MaybeArray } from '@core/types/utility.type'
16
+ import { toArray } from '@core/utils/to-array.utils'
17
+ import { computed } from 'vue'
18
+
19
+ const { tag } = defineProps<{
20
+ tag: MaybeArray<string>
21
+ }>()
22
+
23
+ const tags = computed(() => toArray(tag).filter(tagItem => tagItem.trim() !== ''))
24
+ </script>
@@ -0,0 +1,32 @@
1
+ <template>
2
+ <UiTableCell>
3
+ <div class="content">
4
+ <span><slot /></span>
5
+ <VtsIcon v-if="rightIcon" v-tooltip="rightIcon.tooltip ?? false" :name="rightIcon.icon" size="medium" />
6
+ </div>
7
+ </UiTableCell>
8
+ </template>
9
+
10
+ <script setup lang="ts">
11
+ import VtsIcon from '@core/components/icon/VtsIcon.vue'
12
+ import UiTableCell from '@core/components/ui/table-cell/UiTableCell.vue'
13
+ import { vTooltip } from '@core/directives/tooltip.directive'
14
+ import type { IconName } from '@core/icons'
15
+
16
+ export type TextCellProps = {
17
+ rightIcon?: {
18
+ icon: IconName
19
+ tooltip?: string
20
+ }
21
+ }
22
+
23
+ defineProps<TextCellProps>()
24
+ </script>
25
+
26
+ <style lang="postcss" scoped>
27
+ .content {
28
+ display: inline-flex;
29
+ align-items: center;
30
+ gap: 0.8rem;
31
+ }
32
+ </style>