@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.
- package/lib/components/console/VtsRemoteConsole.vue +1 -1
- package/lib/components/copy-button/VtsCopyButton.vue +1 -1
- package/lib/components/layout/VtsLayoutSidebar.vue +1 -1
- package/lib/components/quick-info-card/VtsQuickInfoCard.vue +1 -1
- package/lib/components/relative-time/VtsRelativeTime.vue +2 -3
- package/lib/components/select/VtsSelect.vue +1 -1
- package/lib/components/state-hero/VtsStateHero.vue +20 -10
- package/lib/components/table/VtsRow.vue +26 -0
- package/lib/components/table/VtsTable.vue +99 -42
- package/lib/components/table/cells/VtsCollapsedListCell.vue +59 -0
- package/lib/components/table/cells/VtsHeaderCell.vue +31 -0
- package/lib/components/table/cells/VtsLinkCell.vue +33 -0
- package/lib/components/table/cells/VtsNumberCell.vue +21 -0
- package/lib/components/{size-progress-cell/VtsSizeProgressCell.vue → table/cells/VtsProgressBarCell.vue} +8 -5
- package/lib/components/table/cells/VtsStatusCell.vue +69 -0
- package/lib/components/table/cells/VtsTagCell.vue +24 -0
- package/lib/components/table/cells/VtsTextCell.vue +32 -0
- package/lib/components/table/cells/VtsTruncatedTextCell.vue +64 -0
- package/lib/components/task/VtsQuickTaskButton.vue +1 -1
- package/lib/components/tree/VtsTreeLine.vue +1 -1
- package/lib/components/ui/alert/UiAlert.vue +1 -1
- package/lib/components/ui/button/UiButton.vue +4 -2
- package/lib/components/ui/button-icon/UiButtonIcon.vue +12 -11
- package/lib/components/ui/column-header/UiColumnHeader.vue +22 -0
- package/lib/components/ui/info/UiInfo.vue +5 -1
- package/lib/components/ui/input/UiInput.vue +3 -2
- package/lib/components/ui/link/UiLink.vue +5 -0
- package/lib/components/ui/log-entry-viewer/UiLogEntryViewer.vue +1 -1
- package/lib/components/ui/query-search-bar/UiQuerySearchBar.vue +2 -2
- package/lib/components/ui/table-cell/UiTableCell.vue +41 -0
- package/lib/components/ui/table-pagination/PaginationButton.vue +1 -1
- package/lib/components/ui/toaster/UiToaster.vue +1 -1
- package/lib/components/ui/top-bottom-table/UiTopBottomTable.vue +6 -2
- package/lib/composables/pagination.composable.ts +16 -1
- package/lib/composables/relative-time.composable.ts +8 -61
- package/lib/composables/table-state.composable.ts +56 -0
- package/lib/composables/tree-filter.composable.ts +2 -2
- package/lib/icons/fa-icons.ts +2 -0
- package/lib/icons/object-icons.ts +1 -1
- package/lib/locales/en.json +23 -0
- package/lib/locales/fr.json +23 -0
- package/lib/packages/form-select/use-form-select-controller.ts +1 -0
- package/lib/packages/table/README.md +53 -308
- package/lib/packages/table/define-column.ts +7 -0
- package/lib/packages/table/define-columns.ts +104 -50
- package/lib/packages/table/index.ts +3 -11
- package/lib/packages/table/types.ts +10 -0
- package/lib/{composables/tree.composable.md → packages/tree/README.md} +28 -23
- package/lib/{composables → packages}/tree/branch-definition.ts +9 -4
- package/lib/{composables → packages}/tree/branch.ts +15 -20
- package/lib/{composables → packages}/tree/build-nodes.ts +5 -5
- package/lib/{composables → packages}/tree/define-branch.ts +8 -4
- package/lib/{composables → packages}/tree/define-leaf.ts +8 -3
- package/lib/{composables → packages}/tree/define-tree.ts +10 -5
- package/lib/{composables → packages}/tree/leaf-definition.ts +1 -1
- package/lib/{composables → packages}/tree/leaf.ts +3 -3
- package/lib/{composables → packages}/tree/tree-node-base.ts +18 -3
- package/lib/{composables → packages}/tree/tree-node-definition-base.ts +4 -2
- package/lib/{composables → packages}/tree/types.ts +11 -9
- package/lib/{composables/tree.composable.ts → packages/tree/use-tree.ts} +24 -11
- package/lib/tables/column-definitions/address-column.ts +4 -0
- package/lib/tables/column-definitions/button-column.ts +35 -0
- package/lib/tables/column-definitions/button-icon-column.ts +30 -0
- package/lib/tables/column-definitions/collapsed-list-column.ts +12 -0
- package/lib/tables/column-definitions/date-column.ts +34 -0
- package/lib/tables/column-definitions/info-column.ts +12 -0
- package/lib/tables/column-definitions/input-column.ts +32 -0
- package/lib/tables/column-definitions/link-column.ts +14 -0
- package/lib/tables/column-definitions/literal-column.ts +9 -0
- package/lib/tables/column-definitions/number-column.ts +10 -0
- package/lib/tables/column-definitions/percent-column.ts +15 -0
- package/lib/tables/column-definitions/progress-bar-column.ts +10 -0
- package/lib/tables/column-definitions/select-column.ts +12 -0
- package/lib/tables/column-definitions/select-item-column.ts +8 -0
- package/lib/tables/column-definitions/status-column.ts +16 -0
- package/lib/tables/column-definitions/tag-column.ts +11 -0
- package/lib/tables/column-definitions/text-column.ts +11 -0
- package/lib/tables/column-definitions/truncated-text-column.ts +10 -0
- package/lib/tables/column-sets/backup-issue-columns.ts +15 -0
- package/lib/tables/column-sets/backup-job-columns.ts +23 -0
- package/lib/tables/column-sets/backup-job-schedule-columns.ts +21 -0
- package/lib/tables/column-sets/backup-log-columns.ts +19 -0
- package/lib/tables/column-sets/host-columns.ts +19 -0
- package/lib/tables/column-sets/network-columns.ts +22 -0
- package/lib/tables/column-sets/new-vm-network-columns.ts +24 -0
- package/lib/tables/column-sets/new-vm-sr-columns.ts +33 -0
- package/lib/tables/column-sets/patch-columns.ts +13 -0
- package/lib/tables/column-sets/pif-columns.ts +23 -0
- package/lib/tables/column-sets/server-columns.ts +18 -0
- package/lib/tables/column-sets/sr-columns.ts +20 -0
- package/lib/tables/column-sets/vdi-columns.ts +21 -0
- package/lib/tables/column-sets/vif-columns.ts +23 -0
- package/lib/tables/column-sets/vm-columns.ts +21 -0
- package/lib/tables/helpers/render-body-cell.ts +4 -0
- package/lib/tables/helpers/render-head-cell.ts +6 -0
- package/lib/tables/helpers/render-loading-cell.ts +5 -0
- package/lib/tables/types.ts +7 -0
- package/lib/utils/size.util.ts +5 -9
- package/package.json +1 -1
- package/lib/components/data-table/VtsDataTable.vue +0 -70
- package/lib/components/table/ColumnTitle.vue +0 -152
- package/lib/packages/table/apply-extensions.ts +0 -26
- package/lib/packages/table/define-renderer/define-table-cell-renderer.ts +0 -27
- package/lib/packages/table/define-renderer/define-table-renderer.ts +0 -47
- package/lib/packages/table/define-renderer/define-table-row-renderer.ts +0 -29
- package/lib/packages/table/define-renderer/define-table-section-renderer.ts +0 -29
- package/lib/packages/table/define-table/define-multi-source-table.ts +0 -39
- package/lib/packages/table/define-table/define-table.ts +0 -13
- package/lib/packages/table/define-table/define-typed-table.ts +0 -18
- package/lib/packages/table/transform-sources.ts +0 -13
- package/lib/packages/table/types/extensions.ts +0 -16
- package/lib/packages/table/types/index.ts +0 -47
- package/lib/packages/table/types/table-cell.ts +0 -18
- package/lib/packages/table/types/table-row.ts +0 -20
- package/lib/packages/table/types/table-section.ts +0 -19
- package/lib/packages/table/types/table.ts +0 -28
- 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,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))
|
package/lib/utils/size.util.ts
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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,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
|
-
}
|