@xen-orchestra/web-core 0.35.1 → 0.36.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 (117) 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/toaster/UiToaster.vue +1 -1
  33. package/lib/components/ui/top-bottom-table/UiTopBottomTable.vue +6 -2
  34. package/lib/composables/pagination.composable.ts +16 -1
  35. package/lib/composables/relative-time.composable.ts +8 -61
  36. package/lib/composables/table-state.composable.ts +56 -0
  37. package/lib/composables/tree-filter.composable.ts +2 -2
  38. package/lib/icons/fa-icons.ts +2 -0
  39. package/lib/icons/object-icons.ts +1 -1
  40. package/lib/locales/en.json +23 -0
  41. package/lib/locales/fr.json +23 -0
  42. package/lib/packages/form-select/use-form-select-controller.ts +1 -0
  43. package/lib/packages/table/README.md +53 -308
  44. package/lib/packages/table/define-column.ts +7 -0
  45. package/lib/packages/table/define-columns.ts +104 -50
  46. package/lib/packages/table/index.ts +3 -11
  47. package/lib/packages/table/types.ts +10 -0
  48. package/lib/{composables/tree.composable.md → packages/tree/README.md} +28 -23
  49. package/lib/{composables → packages}/tree/branch-definition.ts +9 -4
  50. package/lib/{composables → packages}/tree/branch.ts +15 -20
  51. package/lib/{composables → packages}/tree/build-nodes.ts +5 -5
  52. package/lib/{composables → packages}/tree/define-branch.ts +8 -4
  53. package/lib/{composables → packages}/tree/define-leaf.ts +8 -3
  54. package/lib/{composables → packages}/tree/define-tree.ts +10 -5
  55. package/lib/{composables → packages}/tree/leaf-definition.ts +1 -1
  56. package/lib/{composables → packages}/tree/leaf.ts +3 -3
  57. package/lib/{composables → packages}/tree/tree-node-base.ts +18 -3
  58. package/lib/{composables → packages}/tree/tree-node-definition-base.ts +4 -2
  59. package/lib/{composables → packages}/tree/types.ts +11 -9
  60. package/lib/{composables/tree.composable.ts → packages/tree/use-tree.ts} +24 -11
  61. package/lib/tables/column-definitions/address-column.ts +4 -0
  62. package/lib/tables/column-definitions/button-column.ts +35 -0
  63. package/lib/tables/column-definitions/button-icon-column.ts +30 -0
  64. package/lib/tables/column-definitions/collapsed-list-column.ts +12 -0
  65. package/lib/tables/column-definitions/date-column.ts +34 -0
  66. package/lib/tables/column-definitions/info-column.ts +12 -0
  67. package/lib/tables/column-definitions/input-column.ts +32 -0
  68. package/lib/tables/column-definitions/link-column.ts +14 -0
  69. package/lib/tables/column-definitions/literal-column.ts +9 -0
  70. package/lib/tables/column-definitions/number-column.ts +10 -0
  71. package/lib/tables/column-definitions/percent-column.ts +15 -0
  72. package/lib/tables/column-definitions/progress-bar-column.ts +10 -0
  73. package/lib/tables/column-definitions/select-column.ts +12 -0
  74. package/lib/tables/column-definitions/select-item-column.ts +8 -0
  75. package/lib/tables/column-definitions/status-column.ts +16 -0
  76. package/lib/tables/column-definitions/tag-column.ts +11 -0
  77. package/lib/tables/column-definitions/text-column.ts +11 -0
  78. package/lib/tables/column-definitions/truncated-text-column.ts +10 -0
  79. package/lib/tables/column-sets/backup-issue-columns.ts +15 -0
  80. package/lib/tables/column-sets/backup-job-columns.ts +23 -0
  81. package/lib/tables/column-sets/backup-job-schedule-columns.ts +21 -0
  82. package/lib/tables/column-sets/backup-log-columns.ts +19 -0
  83. package/lib/tables/column-sets/host-columns.ts +19 -0
  84. package/lib/tables/column-sets/network-columns.ts +22 -0
  85. package/lib/tables/column-sets/new-vm-network-columns.ts +24 -0
  86. package/lib/tables/column-sets/new-vm-sr-columns.ts +33 -0
  87. package/lib/tables/column-sets/patch-columns.ts +13 -0
  88. package/lib/tables/column-sets/pif-columns.ts +23 -0
  89. package/lib/tables/column-sets/server-columns.ts +18 -0
  90. package/lib/tables/column-sets/sr-columns.ts +20 -0
  91. package/lib/tables/column-sets/vdi-columns.ts +21 -0
  92. package/lib/tables/column-sets/vif-columns.ts +23 -0
  93. package/lib/tables/column-sets/vm-columns.ts +21 -0
  94. package/lib/tables/helpers/render-body-cell.ts +4 -0
  95. package/lib/tables/helpers/render-head-cell.ts +6 -0
  96. package/lib/tables/helpers/render-loading-cell.ts +5 -0
  97. package/lib/tables/types.ts +7 -0
  98. package/lib/utils/size.util.ts +5 -9
  99. package/package.json +1 -1
  100. package/lib/components/data-table/VtsDataTable.vue +0 -70
  101. package/lib/components/table/ColumnTitle.vue +0 -152
  102. package/lib/packages/table/apply-extensions.ts +0 -26
  103. package/lib/packages/table/define-renderer/define-table-cell-renderer.ts +0 -27
  104. package/lib/packages/table/define-renderer/define-table-renderer.ts +0 -47
  105. package/lib/packages/table/define-renderer/define-table-row-renderer.ts +0 -29
  106. package/lib/packages/table/define-renderer/define-table-section-renderer.ts +0 -29
  107. package/lib/packages/table/define-table/define-multi-source-table.ts +0 -39
  108. package/lib/packages/table/define-table/define-table.ts +0 -13
  109. package/lib/packages/table/define-table/define-typed-table.ts +0 -18
  110. package/lib/packages/table/transform-sources.ts +0 -13
  111. package/lib/packages/table/types/extensions.ts +0 -16
  112. package/lib/packages/table/types/index.ts +0 -47
  113. package/lib/packages/table/types/table-cell.ts +0 -18
  114. package/lib/packages/table/types/table-row.ts +0 -20
  115. package/lib/packages/table/types/table-section.ts +0 -19
  116. package/lib/packages/table/types/table.ts +0 -28
  117. package/lib/types/button.type.ts +0 -3
@@ -0,0 +1,24 @@
1
+ import { defineColumns } from '@core/packages/table/define-columns.ts'
2
+ import { useButtonIconColumn } from '@core/tables/column-definitions/button-icon-column.ts'
3
+ import { useInputColumn } from '@core/tables/column-definitions/input-column.ts'
4
+ import { useSelectColumn } from '@core/tables/column-definitions/select-column.ts'
5
+ import { useI18n } from 'vue-i18n'
6
+
7
+ export const useNewVmNetworkColumns = defineColumns(() => {
8
+ const { t } = useI18n()
9
+
10
+ return {
11
+ interface: useSelectColumn({
12
+ headerLabel: () => t('interfaces'),
13
+ headerIcon: 'fa:network-wired',
14
+ }),
15
+
16
+ mac: useInputColumn({
17
+ headerLabel: () => t('mac-addresses'),
18
+ headerIcon: 'fa:at',
19
+ placeholder: () => t('auto-generated'),
20
+ }),
21
+
22
+ remove: useButtonIconColumn({ buttonIcon: 'fa:trash' }),
23
+ }
24
+ })
@@ -0,0 +1,33 @@
1
+ import { defineColumns } from '@core/packages/table/define-columns.ts'
2
+ import { useButtonIconColumn } from '@core/tables/column-definitions/button-icon-column.ts'
3
+ import { useInputColumn } from '@core/tables/column-definitions/input-column.ts'
4
+ import { useSelectColumn } from '@core/tables/column-definitions/select-column.ts'
5
+ import { useI18n } from 'vue-i18n'
6
+
7
+ export const useNewVmSrColumns = defineColumns(() => {
8
+ const { t } = useI18n()
9
+
10
+ return {
11
+ sr: useSelectColumn({
12
+ headerLabel: () => t('storage-repositories'),
13
+ headerIcon: 'fa:database',
14
+ }),
15
+
16
+ diskName: useInputColumn({
17
+ headerLabel: () => t('disk-name'),
18
+ placeholder: () => t('disk-name'),
19
+ }),
20
+
21
+ size: useInputColumn({
22
+ type: 'number',
23
+ headerLabel: () => `${t('size')} (GB)`,
24
+ }),
25
+
26
+ description: useInputColumn({
27
+ headerLabel: () => t('description'),
28
+ placeholder: () => t('description'),
29
+ }),
30
+
31
+ remove: useButtonIconColumn({ buttonIcon: 'fa:trash' }),
32
+ }
33
+ })
@@ -0,0 +1,13 @@
1
+ import { defineColumns } from '@core/packages/table/define-columns.ts'
2
+ import { useNumberColumn } from '@core/tables/column-definitions/number-column.ts'
3
+ import { useTextColumn } from '@core/tables/column-definitions/text-column.ts'
4
+ import { useI18n } from 'vue-i18n'
5
+
6
+ export const usePatchColumns = defineColumns(() => {
7
+ const { t } = useI18n()
8
+
9
+ return {
10
+ name: useTextColumn({ headerLabel: () => t('patch-name') }),
11
+ version: useNumberColumn({ headerLabel: () => t('version') }),
12
+ }
13
+ })
@@ -0,0 +1,23 @@
1
+ import { defineColumns } from '@core/packages/table/define-columns.ts'
2
+ import { useAddressColumn } from '@core/tables/column-definitions/address-column.ts'
3
+ import { useLinkColumn } from '@core/tables/column-definitions/link-column'
4
+ import { useNumberColumn } from '@core/tables/column-definitions/number-column.ts'
5
+ import { useSelectItemColumn } from '@core/tables/column-definitions/select-item-column'
6
+ import { useStatusColumn } from '@core/tables/column-definitions/status-column.ts'
7
+ import { useTextColumn } from '@core/tables/column-definitions/text-column.ts'
8
+ import { useI18n } from 'vue-i18n'
9
+
10
+ export const usePifColumns = defineColumns(() => {
11
+ const { t } = useI18n()
12
+
13
+ return {
14
+ network: useLinkColumn({ headerLabel: () => t('network') }),
15
+ device: useTextColumn({ headerLabel: () => t('device') }),
16
+ status: useStatusColumn({ headerLabel: () => t('status') }),
17
+ vlan: useNumberColumn({ headerLabel: () => t('vlan') }),
18
+ ip: useAddressColumn({ headerLabel: () => t('ip-address') }),
19
+ mac: useAddressColumn({ headerLabel: () => t('mac-address') }),
20
+ mode: useTextColumn({ headerLabel: () => t('mode') }),
21
+ selectItem: useSelectItemColumn(),
22
+ }
23
+ })
@@ -0,0 +1,18 @@
1
+ import { defineColumns } from '@core/packages/table/define-columns.ts'
2
+ import { useAddressColumn } from '@core/tables/column-definitions/address-column.ts'
3
+ import { useLinkColumn } from '@core/tables/column-definitions/link-column'
4
+ import { useSelectItemColumn } from '@core/tables/column-definitions/select-item-column'
5
+ import { useStatusColumn } from '@core/tables/column-definitions/status-column.ts'
6
+ import { useI18n } from 'vue-i18n'
7
+
8
+ export const useServerColumns = defineColumns(() => {
9
+ const { t } = useI18n()
10
+
11
+ return {
12
+ pool: useLinkColumn({ headerLabel: () => t('pool') }),
13
+ hostIp: useAddressColumn({ headerLabel: () => t('ip-address') }),
14
+ status: useStatusColumn({ headerLabel: () => t('status') }),
15
+ primaryHost: useLinkColumn({ headerLabel: () => t('master'), headerIcon: 'fa:server' }),
16
+ selectItem: useSelectItemColumn(),
17
+ }
18
+ })
@@ -0,0 +1,20 @@
1
+ import { defineColumns } from '@core/packages/table/define-columns.ts'
2
+ import { useLinkColumn } from '@core/tables/column-definitions/link-column'
3
+ import { useLiteralColumn } from '@core/tables/column-definitions/literal-column.ts'
4
+ import { useProgressBarColumn } from '@core/tables/column-definitions/progress-bar-column.ts'
5
+ import { useSelectItemColumn } from '@core/tables/column-definitions/select-item-column'
6
+ import { useTruncatedTextColumn } from '@core/tables/column-definitions/truncated-text-column'
7
+ import { useI18n } from 'vue-i18n'
8
+
9
+ export const useSrColumns = defineColumns(() => {
10
+ const { t } = useI18n()
11
+
12
+ return {
13
+ storageRepository: useLinkColumn({ headerLabel: () => t('storage-repository') }),
14
+ description: useTruncatedTextColumn({ headerLabel: () => t('description') }),
15
+ storageFormat: useLiteralColumn({ headerLabel: () => t('storage-format') }),
16
+ accessMode: useLiteralColumn({ headerLabel: () => t('access-mode') }),
17
+ usedSpace: useProgressBarColumn({ headerLabel: () => t('used-space') }),
18
+ selectItem: useSelectItemColumn(),
19
+ }
20
+ })
@@ -0,0 +1,21 @@
1
+ import { defineColumns } from '@core/packages/table/define-columns.ts'
2
+ import { useLinkColumn } from '@core/tables/column-definitions/link-column.ts'
3
+ import { useLiteralColumn } from '@core/tables/column-definitions/literal-column.ts'
4
+ import { useNumberColumn } from '@core/tables/column-definitions/number-column.ts'
5
+ import { useProgressBarColumn } from '@core/tables/column-definitions/progress-bar-column.ts'
6
+ import { useSelectItemColumn } from '@core/tables/column-definitions/select-item-column.ts'
7
+ import { useTruncatedTextColumn } from '@core/tables/column-definitions/truncated-text-column.ts'
8
+ import { useI18n } from 'vue-i18n'
9
+
10
+ export const useVdiColumns = defineColumns(() => {
11
+ const { t } = useI18n()
12
+
13
+ return {
14
+ vdi: useLinkColumn({ headerLabel: () => t('vdis') }),
15
+ description: useTruncatedTextColumn({ headerLabel: () => t('description') }),
16
+ usedSpace: useProgressBarColumn({ headerLabel: () => t('used-space') }),
17
+ size: useNumberColumn({ headerLabel: () => t('size') }),
18
+ format: useLiteralColumn({ headerLabel: () => t('format') }),
19
+ selectItem: useSelectItemColumn(),
20
+ }
21
+ })
@@ -0,0 +1,23 @@
1
+ import { defineColumns } from '@core/packages/table/define-columns.ts'
2
+ import { useAddressColumn } from '@core/tables/column-definitions/address-column.ts'
3
+ import { useLinkColumn } from '@core/tables/column-definitions/link-column'
4
+ import { useNumberColumn } from '@core/tables/column-definitions/number-column.ts'
5
+ import { useSelectItemColumn } from '@core/tables/column-definitions/select-item-column'
6
+ import { useStatusColumn } from '@core/tables/column-definitions/status-column.ts'
7
+ import { useTextColumn } from '@core/tables/column-definitions/text-column.ts'
8
+ import { useI18n } from 'vue-i18n'
9
+
10
+ export const useVifColumns = defineColumns(() => {
11
+ const { t } = useI18n()
12
+
13
+ return {
14
+ network: useLinkColumn({ headerLabel: () => t('network') }),
15
+ device: useTextColumn({ headerLabel: () => t('device') }),
16
+ status: useStatusColumn({ headerLabel: () => t('status') }),
17
+ ipsAddresses: useAddressColumn({ headerLabel: () => t('ip-addresses') }),
18
+ macAddresses: useAddressColumn({ headerLabel: () => t('mac-addresses') }),
19
+ mtu: useNumberColumn({ headerLabel: () => t('mtu') }),
20
+ lockingMode: useTextColumn({ headerLabel: () => t('locking-mode') }),
21
+ selectItem: useSelectItemColumn(),
22
+ }
23
+ })
@@ -0,0 +1,21 @@
1
+ import { defineColumns } from '@core/packages/table/define-columns.ts'
2
+ import { useAddressColumn } from '@core/tables/column-definitions/address-column.ts'
3
+ import { useLinkColumn } from '@core/tables/column-definitions/link-column'
4
+ import { useNumberColumn } from '@core/tables/column-definitions/number-column.ts'
5
+ import { useSelectItemColumn } from '@core/tables/column-definitions/select-item-column'
6
+ import { useTagColumn } from '@core/tables/column-definitions/tag-column.ts'
7
+ import { useI18n } from 'vue-i18n'
8
+
9
+ export const useVmColumns = defineColumns(() => {
10
+ const { t } = useI18n()
11
+
12
+ return {
13
+ vm: useLinkColumn({ headerLabel: () => t('vm') }),
14
+ ipAddresses: useAddressColumn({ headerLabel: () => t('ip-addresses') }),
15
+ vcpus: useNumberColumn({ headerLabel: () => t('vcpus') }),
16
+ ram: useNumberColumn({ headerLabel: () => t('ram') }),
17
+ diskSpace: useNumberColumn({ headerLabel: () => t('disk-space') }),
18
+ tags: useTagColumn({ headerLabel: () => t('tags') }),
19
+ selectItem: useSelectItemColumn(),
20
+ }
21
+ })
@@ -0,0 +1,4 @@
1
+ import UiTableCell, { type TableCellAlign } from '@core/components/ui/table-cell/UiTableCell.vue'
2
+ import { h } from 'vue'
3
+
4
+ export const renderBodyCell = (content?: () => any, align?: TableCellAlign) => h(UiTableCell, { align }, content)
@@ -0,0 +1,6 @@
1
+ import VtsHeaderCell from '@core/components/table/cells/VtsHeaderCell.vue'
2
+ import type { IconName } from '@core/icons/index.ts'
3
+ import { h, toValue, type MaybeRefOrGetter } from 'vue'
4
+
5
+ export const renderHeadCell = (icon?: MaybeRefOrGetter<IconName>, label?: MaybeRefOrGetter<string | undefined>) =>
6
+ h(VtsHeaderCell, { icon: toValue(icon) }, () => toValue(label))
@@ -0,0 +1,5 @@
1
+ import UiLoader from '@core/components/ui/loader/UiLoader.vue'
2
+ import UiTableCell from '@core/components/ui/table-cell/UiTableCell.vue'
3
+ import { h } from 'vue'
4
+
5
+ export const renderLoadingCell = () => h(UiTableCell, { align: 'center' }, () => h(UiLoader))
@@ -0,0 +1,7 @@
1
+ import type { IconName } from '@core/icons/index.ts'
2
+ import type { MaybeRefOrGetter } from 'vue'
3
+
4
+ export type HeaderConfig = {
5
+ headerLabel?: MaybeRefOrGetter<string | undefined>
6
+ headerIcon?: MaybeRefOrGetter<IconName>
7
+ }
@@ -2,16 +2,12 @@ import { parse, raw, Scale, type Info } from 'human-format'
2
2
 
3
3
  const scale = Scale.create(['', 'KiB', 'MiB', 'GiB', 'TiB'], 1024)
4
4
 
5
- export function formatSizeRaw(bytes: number, decimals: number): Info<Scale<'B' | 'KiB' | 'MiB' | 'GiB' | 'TiB'>>
5
+ export type SizeInfo = Info<Scale<'B' | 'KiB' | 'MiB' | 'GiB' | 'TiB'>>
6
+
7
+ export function formatSizeRaw(bytes: number, decimals: number): SizeInfo
6
8
  export function formatSizeRaw(bytes: undefined, decimals: number): undefined
7
- export function formatSizeRaw(
8
- bytes: undefined | number,
9
- decimals: number
10
- ): undefined | Info<Scale<'B' | 'KiB' | 'MiB' | 'GiB' | 'TiB'>>
11
- export function formatSizeRaw(
12
- bytes: number | undefined,
13
- decimals: number
14
- ): Info<Scale<'B' | 'KiB' | 'MiB' | 'GiB' | 'TiB'>> | undefined {
9
+ export function formatSizeRaw(bytes: number | undefined, decimals: number): SizeInfo | undefined
10
+ export function formatSizeRaw(bytes: number | undefined, decimals: number): SizeInfo | undefined {
15
11
  if (bytes === undefined) {
16
12
  return undefined
17
13
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@xen-orchestra/web-core",
3
3
  "type": "module",
4
- "version": "0.35.1",
4
+ "version": "0.36.0",
5
5
  "private": false,
6
6
  "exports": {
7
7
  "./*": {
@@ -1,70 +0,0 @@
1
- <template>
2
- <div class="table-container">
3
- <VtsStateHero v-if="!isReady" format="table" busy size="medium" />
4
- <VtsStateHero v-else-if="hasError" format="table" type="error" size="small" no-background>
5
- {{ t('error-no-data') }}
6
- </VtsStateHero>
7
- <VtsStateHero v-else-if="noDataMessage" format="table" type="no-data" size="small">
8
- {{ noDataMessage ? noDataMessage : t('no-data') }}
9
- </VtsStateHero>
10
- <VtsTable v-else vertical-border>
11
- <thead>
12
- <slot name="thead" />
13
- </thead>
14
- <tbody>
15
- <slot name="tbody" />
16
- </tbody>
17
- </VtsTable>
18
- </div>
19
- </template>
20
-
21
- <script lang="ts" setup>
22
- import VtsStateHero from '@core/components/state-hero/VtsStateHero.vue'
23
- import VtsTable from '@core/components/table/VtsTable.vue'
24
- import { useI18n } from 'vue-i18n'
25
-
26
- defineProps<{
27
- isReady?: boolean
28
- hasError?: boolean
29
- noDataMessage?: string
30
- }>()
31
-
32
- defineSlots<{
33
- thead(): any
34
- tbody(): any
35
- }>()
36
-
37
- const { t } = useI18n()
38
- </script>
39
-
40
- <style lang="postcss" scoped>
41
- .table-container {
42
- display: flex;
43
- flex-direction: column;
44
- gap: 0.8rem;
45
- overflow-x: auto;
46
-
47
- :deep(tbody) tr {
48
- &:hover {
49
- cursor: pointer;
50
- background-color: var(--color-brand-background-hover);
51
- }
52
-
53
- &:active {
54
- background-color: var(--color-brand-background-active);
55
- }
56
-
57
- &.selected {
58
- background-color: var(--color-brand-background-selected);
59
- }
60
-
61
- &:last-child {
62
- border-bottom: 0.1rem solid var(--color-neutral-border);
63
- }
64
- }
65
-
66
- :deep(th) {
67
- width: 10rem;
68
- }
69
- }
70
- </style>
@@ -1,152 +0,0 @@
1
- <!-- v1.0 -->
2
- <template>
3
- <MenuList :disabled placement="bottom-start">
4
- <template #trigger="{ open, isOpen }">
5
- <th
6
- :class="{ interactive, disabled, focus: isOpen }"
7
- class="column-header"
8
- @click="ev => (interactive ? open(ev) : noop())"
9
- >
10
- <div class="content">
11
- <span class="label">
12
- <VtsIcon :name="icon" size="medium" />
13
- <slot />
14
- </span>
15
- <VtsIcon :name="currentInteraction?.icon" size="medium" />
16
- </div>
17
- </th>
18
- </template>
19
- <MenuItem
20
- v-for="interaction in interactions"
21
- :key="interaction.id"
22
- v-tooltip="t('coming-soon')"
23
- :disabled="interaction.disabled"
24
- :on-click="() => updateInteraction(interaction)"
25
- >
26
- <VtsIcon :name="interaction.icon" size="medium" />
27
- {{ interaction.label }}
28
- <i v-if="currentInteraction?.id === interaction.id" class="current-interaction typo-body-regular-small">
29
- {{ t('core.current').toLowerCase() }}
30
- </i>
31
- </MenuItem>
32
- </MenuList>
33
- </template>
34
-
35
- <script lang="ts" setup>
36
- import VtsIcon from '@core/components/icon/VtsIcon.vue'
37
- import MenuItem from '@core/components/menu/MenuItem.vue'
38
- import MenuList from '@core/components/menu/MenuList.vue'
39
- import { vTooltip } from '@core/directives/tooltip.directive'
40
- import type { IconName } from '@core/icons'
41
- import { noop } from '@vueuse/core'
42
- import { computed, inject } from 'vue'
43
- import { useI18n } from 'vue-i18n'
44
- import { useRouter } from 'vue-router'
45
-
46
- type InteractionId = 'sort-asc' | 'sort-desc' | 'group' | 'filter' | 'hide'
47
- type Interaction = {
48
- disabled?: boolean
49
- id: InteractionId
50
- icon: IconName
51
- label: string
52
- }
53
-
54
- const props = withDefaults(
55
- defineProps<{
56
- id?: string
57
- icon?: IconName
58
- interactive?: boolean
59
- disabled?: boolean
60
- }>(),
61
- {
62
- disabled: false,
63
- interactive: true,
64
- }
65
- )
66
- const { t } = useI18n()
67
- const router = useRouter()
68
-
69
- const interactions = computed<Interaction[]>(() => [
70
- { id: 'sort-asc', icon: 'fa:arrow-down', label: t('core.sort.ascending'), disabled: true },
71
- { id: 'sort-desc', icon: 'fa:arrow-up', label: t('core.sort.descending'), disabled: true },
72
- { id: 'group', icon: 'fa:layer-group', label: t('core.group'), disabled: true },
73
- { id: 'filter', icon: 'fa:filter', label: t('core.filter'), disabled: true },
74
- { id: 'hide', icon: 'fa:eye-slash', label: t('core.hide'), disabled: true },
75
- ])
76
-
77
- const tableName = inject<string>('tableName')
78
-
79
- const columnName = `${tableName}__${props.id}`
80
-
81
- const currentInteraction = computed(() =>
82
- interactions.value.find(interaction => router.currentRoute.value.query[columnName] === interaction.id)
83
- )
84
-
85
- const updateInteraction = (interaction: Interaction) => {
86
- router.replace({
87
- query: {
88
- [columnName]: interaction.id,
89
- },
90
- })
91
- }
92
- </script>
93
-
94
- <style lang="postcss" scoped>
95
- /* COLOR VARIANTS */
96
- .column-header.interactive {
97
- --color: var(--color-brand-txt-base);
98
- --background-color: var(--color-neutral-background-primary);
99
-
100
- &.focus {
101
- --color: var(--color-brand-txt-base);
102
- --background-color: var(--color-brand-background-selected);
103
- }
104
-
105
- &:hover {
106
- --color: var(--color-brand-txt-hover);
107
- --background-color: var(--color-brand-background-hover);
108
- }
109
-
110
- &:active {
111
- --color: var(--color-brand-txt-active);
112
- --background-color: var(--color-brand-background-active);
113
- }
114
-
115
- &.disabled {
116
- --color: var(--color-neutral-txt-secondary);
117
- --background-color: var(--color-neutral-background-disabled);
118
- }
119
- }
120
-
121
- /* IMPLEMENTATION */
122
- .column-header.interactive {
123
- cursor: pointer;
124
- color: var(--color);
125
- background-color: var(--background-color);
126
-
127
- &.disabled {
128
- cursor: not-allowed;
129
- }
130
- }
131
-
132
- .current-interaction {
133
- color: var(--color-neutral-txt-secondary);
134
- }
135
-
136
- .content {
137
- display: flex;
138
- align-items: center;
139
- justify-content: space-between;
140
- gap: 1rem;
141
- }
142
-
143
- .label {
144
- display: flex;
145
- align-items: center;
146
- gap: 1rem;
147
- }
148
-
149
- .filter-icon {
150
- cursor: pointer;
151
- }
152
- </style>
@@ -1,26 +0,0 @@
1
- import type { Extensions } from '.'
2
- import { mergeProps } from 'vue'
3
-
4
- export function applyExtensions(
5
- config: {
6
- props?: (config: any) => Record<string, any>
7
- extensions?: Extensions<any>
8
- },
9
- renderConfig: {
10
- props?: Record<string, any>
11
- extensions?: Record<string, any>
12
- }
13
- ): { props: Record<string, any> } {
14
- const baseProps = mergeProps(config.props?.(renderConfig) ?? {}, renderConfig.props ?? {})
15
-
16
- if (!renderConfig.extensions) {
17
- return { props: baseProps }
18
- }
19
-
20
- const props = Object.entries(renderConfig.extensions).reduce(
21
- (props, [extName, extData]) => mergeProps(props, config.extensions?.[extName!](extData).props ?? {}),
22
- baseProps
23
- )
24
-
25
- return { props }
26
- }
@@ -1,27 +0,0 @@
1
- import { type VNode, defineAsyncComponent, h } from 'vue'
2
- import {
3
- type TableCellRenderer,
4
- type TableCellVNode,
5
- type Extensions,
6
- applyExtensions,
7
- type ComponentLoader,
8
- type PropsOverride,
9
- } from '..'
10
-
11
- export function defineTableCellRenderer<
12
- TComponentProps extends Record<string, any>,
13
- TExtensions extends Extensions<TComponentProps>,
14
- TPropsConfig extends Record<string, any>,
15
- >(config: {
16
- component: ComponentLoader<TComponentProps>
17
- props?: (config: TPropsConfig) => PropsOverride<TComponentProps>
18
- extensions?: TExtensions
19
- }): TableCellRenderer<TComponentProps, TExtensions, TPropsConfig> {
20
- const component = defineAsyncComponent(config.component)
21
-
22
- return function RenderCell(renderConfig) {
23
- const extension = applyExtensions(config, renderConfig)
24
-
25
- return h(component, extension.props) satisfies VNode as TableCellVNode
26
- }
27
- }
@@ -1,47 +0,0 @@
1
- import { type VNode, defineAsyncComponent, h } from 'vue'
2
- import {
3
- applyExtensions,
4
- type ComponentLoader,
5
- type PropsOverride,
6
- type Extensions,
7
- type TableRenderer,
8
- type TableVNode,
9
- } from '..'
10
-
11
- export function defineTableRenderer<
12
- TComponentProps extends Record<string, any>,
13
- TExtensions extends Extensions<TComponentProps>,
14
- TPropsConfig extends Record<string, any>,
15
- >(config: {
16
- component: ComponentLoader<TComponentProps>
17
- props?: (config: TPropsConfig) => PropsOverride<TComponentProps>
18
- extensions?: TExtensions
19
- }): TableRenderer<TComponentProps, TExtensions, TPropsConfig> {
20
- const component = defineAsyncComponent(config.component)
21
-
22
- return function RenderTable(renderConfig) {
23
- const { thead, tbody } = renderConfig
24
-
25
- const renderThead =
26
- typeof thead === 'function'
27
- ? thead
28
- : 'cells' in thead && thead.cells
29
- ? () => h('thead', {}, h('tr', {}, { default: () => thead.cells() }))
30
- : 'rows' in thead && thead.rows
31
- ? () => h('thead', {}, { default: () => thead.rows() })
32
- : () => undefined
33
-
34
- const renderTbody =
35
- typeof tbody === 'function'
36
- ? tbody
37
- : 'rows' in tbody && tbody.rows
38
- ? () => h('tbody', {}, { default: () => tbody.rows() })
39
- : () => undefined
40
-
41
- const extension = applyExtensions(config, renderConfig)
42
-
43
- return h(component, extension.props, () => {
44
- return [renderThead(), renderTbody()]
45
- }) satisfies VNode as TableVNode
46
- }
47
- }
@@ -1,29 +0,0 @@
1
- import { type VNode, defineAsyncComponent, h } from 'vue'
2
- import {
3
- applyExtensions,
4
- type TableRowRenderer,
5
- type TableRowVNode,
6
- type Extensions,
7
- type ComponentLoader,
8
- type PropsOverride,
9
- } from '..'
10
-
11
- export function defineRowRenderer<
12
- TComponentProps extends Record<string, any>,
13
- TExtensions extends Extensions<TComponentProps>,
14
- TPropsConfig extends Record<string, any>,
15
- >(config: {
16
- component: ComponentLoader<TComponentProps>
17
- props?: (config: TPropsConfig) => PropsOverride<TComponentProps>
18
- extensions?: TExtensions
19
- }): TableRowRenderer<TComponentProps, TExtensions, TPropsConfig> {
20
- const component = defineAsyncComponent(config.component)
21
-
22
- return function RenderRow(renderConfig): TableRowVNode {
23
- const extension = applyExtensions(config, renderConfig)
24
-
25
- return h(component, extension.props, {
26
- default: () => renderConfig.cells(),
27
- }) satisfies VNode as TableRowVNode
28
- }
29
- }
@@ -1,29 +0,0 @@
1
- import { type VNode, defineAsyncComponent, h } from 'vue'
2
- import {
3
- applyExtensions,
4
- type TableSectionRenderer,
5
- type TableSectionVNode,
6
- type Extensions,
7
- type ComponentLoader,
8
- type PropsOverride,
9
- } from '..'
10
-
11
- export function defineSectionRenderer<
12
- TComponentProps extends Record<string, any>,
13
- TExtensions extends Extensions<TComponentProps>,
14
- TPropsConfig extends Record<string, any>,
15
- >(config: {
16
- component: ComponentLoader<TComponentProps>
17
- props?: (config: TPropsConfig) => PropsOverride<TComponentProps>
18
- extensions?: TExtensions
19
- }): TableSectionRenderer<TComponentProps, TExtensions, TPropsConfig> {
20
- const component = defineAsyncComponent(config.component)
21
-
22
- return function RenderSection(renderConfig): TableSectionVNode {
23
- const extension = applyExtensions(config, renderConfig)
24
-
25
- return h(component, extension.props, {
26
- default: () => renderConfig.rows(),
27
- }) satisfies VNode as TableSectionVNode
28
- }
29
- }