@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
@@ -50,12 +50,13 @@ This option allows you to customize the label of the selected nodes.
50
50
  ## `LeafDefinition`
51
51
 
52
52
  ```ts
53
- new LeafDefinition(data)
54
- new LeafDefinition(data, options)
53
+ new LeafDefinition(treeId, data)
54
+ new LeafDefinition(treeId, data, options)
55
55
  ```
56
56
 
57
57
  | | Required | Type | Default | |
58
58
  | ----------------------- | :------------------: | ---------------------------------------------------- | --------------------------------------- | -------------------------------------------------------------------------------------- |
59
+ | `treeId` | ✓ | `string` | | identifier for tree this node belongs to |
59
60
  | `data` | ✓ | `TData` | | data to be stored in the node |
60
61
  | `options.discriminator` | | `string` | `undefined` | discriminator for the node when you mix different data types (see Discriminator below) |
61
62
  | `options.predicate` | | `(node: TreeNode) => boolean \| undefined` | `undefined` | filter function (see Filtering below) |
@@ -66,7 +67,7 @@ new LeafDefinition(data, options)
66
67
  ### Example
67
68
 
68
69
  ```ts
69
- const definition = new LeafDefinition({ id: 1, label: 'John Doe', age: 30 })
70
+ const definition = new LeafDefinition('users', { id: 1, label: 'John Doe', age: 30 })
70
71
  ```
71
72
 
72
73
  ## `BranchDefinition`
@@ -74,8 +75,8 @@ const definition = new LeafDefinition({ id: 1, label: 'John Doe', age: 30 })
74
75
  A `BranchDefinition` is very similar to a `LeafDefinition`, but it contains a collection of children definitions.
75
76
 
76
77
  ```ts
77
- new BranchDefinition(data, children)
78
- new BranchDefinition(data, options, children)
78
+ new BranchDefinition(treeId, data, children)
79
+ new BranchDefinition(treeId, data, options, children)
79
80
  ```
80
81
 
81
82
  | | | Type | Default | |
@@ -86,9 +87,9 @@ new BranchDefinition(data, options, children)
86
87
  ### Example
87
88
 
88
89
  ```ts
89
- const definition = new BranchDefinition({ id: 'smithes', name: 'The Smithes' }, [
90
- new LeafDefinition({ id: 'jd-1', name: 'John Smith', age: 30 }),
91
- new LeafDefinition({ id: 'jd-2', name: 'Jane Smith', age: 28 }),
90
+ const definition = new BranchDefinition('users', { id: 'smithes', name: 'The Smithes' }, [
91
+ new LeafDefinition('users', { id: 'jd-1', name: 'John Smith', age: 30 }),
92
+ new LeafDefinition('users', { id: 'jd-2', name: 'Jane Smith', age: 28 }),
92
93
  ])
93
94
  ```
94
95
 
@@ -101,8 +102,8 @@ mix different types of nodes at the same collection depth.
101
102
 
102
103
  ```ts
103
104
  const definitions = [
104
- new LeafDefinition({ id: 'jd-1', label: 'John Doe', age: 30 }),
105
- new LeafDefinition({ id: 'rx-1', label: 'Rex', breed: 'Golden Retriever' }),
105
+ new LeafDefinition('family', { id: 'jd-1', label: 'John Doe', age: 30 }),
106
+ new LeafDefinition('family', { id: 'rx-1', label: 'Rex', breed: 'Golden Retriever' }),
106
107
  ]
107
108
 
108
109
  const { nodes } = useTree(definitions)
@@ -116,8 +117,8 @@ nodes.value.forEach(node => {
116
117
 
117
118
  ```ts
118
119
  const definitions = [
119
- new LeafDefinition({ id: 'jd-1', label: 'John Doe', age: 30 }, { discriminator: 'person' }),
120
- new LeafDefinition({ id: 'rx-1', label: 'Rex', breed: 'Golden Retriever' }, { discriminator: 'animal' }),
120
+ new LeafDefinition('family', { id: 'jd-1', label: 'John Doe', age: 30 }, { discriminator: 'person' }),
121
+ new LeafDefinition('family', { id: 'rx-1', label: 'Rex', breed: 'Golden Retriever' }, { discriminator: 'animal' }),
121
122
  ]
122
123
 
123
124
  const { nodes } = useTree(definitions)
@@ -138,8 +139,8 @@ the `isBranch` property will serve the same purpose.
138
139
 
139
140
  ```ts
140
141
  const definitions = [
141
- new LeafDefinition({ id: 'jd-1', label: 'John Doe', age: 30 }),
142
- new BranchDefinition({ id: 'dogs', label: 'Dogs', legs: 4 }, [
142
+ new LeafDefinition('family', { id: 'jd-1', label: 'John Doe', age: 30 }),
143
+ new BranchDefinition('family', { id: 'dogs', label: 'Dogs', legs: 4 }, [
143
144
  /* ... */
144
145
  ]),
145
146
  ]
@@ -254,7 +255,9 @@ const families = [
254
255
  You can use the `defineTree` helper this way:
255
256
 
256
257
  ```ts
257
- const definitions = defineTree(families, family => defineTree(family.members, member => defineTree(member.animals)))
258
+ const definitions = defineTree('family', families, family =>
259
+ defineTree('member', family.members, member => defineTree('animal', member.animals))
260
+ )
258
261
  ```
259
262
 
260
263
  This is the equivalent of the following code:
@@ -263,12 +266,14 @@ This is the equivalent of the following code:
263
266
  const definitions = families.map(
264
267
  family =>
265
268
  new BranchDefinition(
269
+ 'family',
266
270
  family,
267
271
  family.members.map(
268
272
  member =>
269
273
  new BranchDefinition(
274
+ 'member',
270
275
  member,
271
- member.animals.map(animal => new LeafDefinition(animal))
276
+ member.animals.map('animal', animal => new LeafDefinition(animal))
272
277
  )
273
278
  )
274
279
  )
@@ -287,12 +292,12 @@ const entries = [
287
292
  { uuid: 'jd-2', name: 'Jane Doe' },
288
293
  ]
289
294
 
290
- const definitionsA = defineTree(entries, {
295
+ const definitionsA = defineTree('user', entries, {
291
296
  getId: 'uuid',
292
297
  getLabel: 'name',
293
298
  })
294
299
 
295
- const definitionsB = defineTree(entries, {
300
+ const definitionsB = defineTree('user', entries, {
296
301
  getId: entry => entry.uuid,
297
302
  getLabel: entry => entry.name,
298
303
  })
@@ -394,8 +399,8 @@ Here are the rules to determine whether a node is visible or not.
394
399
  </template>
395
400
 
396
401
  <script lang="ts" setup>
397
- const familyDefinitions = defineTree(families, ({ members }) =>
398
- defineTree(members, ({ animals }) => defineTree(animals))
402
+ const familyDefinitions = defineTree('family', families, ({ members }) =>
403
+ defineTree('member', members, ({ animals }) => defineTree('animal', animals))
399
404
  )
400
405
 
401
406
  const { nodes } = useTree(familyDefinitions)
@@ -448,7 +453,7 @@ Here are the rules to determine whether a node is visible or not.
448
453
  </template>
449
454
 
450
455
  <script lang="ts" setup>
451
- const definitions = defineTree(families, ({ members }) => defineTree(members))
456
+ const definitions = defineTree('family', families, ({ members }) => defineTree('member', members))
452
457
 
453
458
  const { nodes } = useTree(definitions, { allowMultiSelect: true })
454
459
  </script>
@@ -517,8 +522,8 @@ Here are the rules to determine whether a node is visible or not.
517
522
  return !filterValue ? undefined : label.toLocaleLowerCase().includes(filterValue)
518
523
  }
519
524
 
520
- const definitions = defineTree(families, { predicate }, ({ members }) =>
521
- defineTree(members, { predicate }, ({ animals }) => defineTree(animals, { predicate }))
525
+ const definitions = defineTree('family', families, { predicate }, ({ members }) =>
526
+ defineTree('member', members, { predicate }, ({ animals }) => defineTree('animal', animals, { predicate }))
522
527
  )
523
528
 
524
529
  const { nodes } = useTree(definitions, { expand: false })
@@ -1,5 +1,5 @@
1
- import { TreeNodeDefinitionBase } from '@core/composables/tree/tree-node-definition-base'
2
- import type { TreeNodeDefinition, TreeNodeOptions } from '@core/composables/tree/types'
1
+ import { TreeNodeDefinitionBase } from '@core/packages/tree/tree-node-definition-base'
2
+ import type { TreeNodeDefinition, TreeNodeOptions } from '@core/packages/tree/types'
3
3
 
4
4
  export class BranchDefinition<
5
5
  TData extends object = any,
@@ -9,8 +9,13 @@ export class BranchDefinition<
9
9
  readonly isBranch = true
10
10
  children: TChildDefinition[]
11
11
 
12
- constructor(data: TData, options: TreeNodeOptions<TData, TDiscriminator>, children: TChildDefinition[]) {
13
- super(data, options)
12
+ constructor(
13
+ treeId: string,
14
+ data: TData,
15
+ options: TreeNodeOptions<TData, TDiscriminator>,
16
+ children: TChildDefinition[]
17
+ ) {
18
+ super(treeId, data, options)
14
19
 
15
20
  this.children = children
16
21
  }
@@ -1,11 +1,5 @@
1
- import { TreeNodeBase } from '@core/composables/tree/tree-node-base'
2
- import type {
3
- BranchStatuses,
4
- ChildTreeGetter,
5
- TreeContext,
6
- TreeNode,
7
- TreeNodeOptions,
8
- } from '@core/composables/tree/types'
1
+ import { TreeNodeBase } from '@core/packages/tree/tree-node-base'
2
+ import type { BranchStatuses, ChildTreeGetter, TreeContext, TreeNode, TreeNodeOptions } from '@core/packages/tree/types'
9
3
 
10
4
  export class Branch<
11
5
  TData extends object = any,
@@ -16,6 +10,7 @@ export class Branch<
16
10
  readonly rawChildren: TChildNode[]
17
11
 
18
12
  constructor(
13
+ treeId: string,
19
14
  data: TData,
20
15
  parent: Branch | undefined,
21
16
  context: TreeContext,
@@ -23,7 +18,7 @@ export class Branch<
23
18
  options: TreeNodeOptions<TData, TDiscriminator> | undefined,
24
19
  getChildTree: ChildTreeGetter<TData, TChildNode, TDiscriminator>
25
20
  ) {
26
- super(data, parent, context, depth, options)
21
+ super(treeId, data, parent, context, depth, options)
27
22
  this.rawChildren = getChildTree(this)
28
23
  }
29
24
 
@@ -48,7 +43,7 @@ export class Branch<
48
43
  }
49
44
 
50
45
  get isExcluded() {
51
- if (this.parent?.isExpanded === false) {
46
+ if (this.parent?.isCollapsed === true) {
52
47
  return true
53
48
  }
54
49
 
@@ -59,8 +54,8 @@ export class Branch<
59
54
  return this.failsFilterDownwards
60
55
  }
61
56
 
62
- get isExpanded() {
63
- return this.context.expandedIds.has(this.id) || this.passesFilterDownwards || this.passesFilterUpwards
57
+ get isCollapsed() {
58
+ return this.context.collapsedIds.has(this.id)
64
59
  }
65
60
 
66
61
  get areChildrenFullySelected(): boolean {
@@ -92,7 +87,7 @@ export class Branch<
92
87
  matches: this.passesFilter === true,
93
88
  'selected-partial': this.context.allowMultiSelect && this.areChildrenPartiallySelected,
94
89
  'selected-full': this.context.allowMultiSelect && this.areChildrenFullySelected,
95
- expanded: this.isExpanded,
90
+ collapsed: this.isCollapsed,
96
91
  }
97
92
  }
98
93
 
@@ -101,21 +96,21 @@ export class Branch<
101
96
  return this.areChildrenFullySelected ? 'all' : this.areChildrenPartiallySelected ? 'some' : 'none'
102
97
  }
103
98
 
104
- toggleExpand(forcedValue?: boolean, recursive?: boolean) {
105
- const nextExpanded = forcedValue ?? !this.isExpanded
99
+ toggleCollapse(forcedValue?: boolean, recursive?: boolean) {
100
+ const nextCollapsed = forcedValue ?? !this.isCollapsed
106
101
 
107
- if (nextExpanded) {
108
- this.context.expandedIds.add(this.id)
102
+ if (nextCollapsed) {
103
+ this.context.collapsedIds.add(this.id)
109
104
  } else {
110
- this.context.expandedIds.delete(this.id)
105
+ this.context.collapsedIds.delete(this.id)
111
106
  }
112
107
 
113
- const shouldPropagate = recursive ?? !nextExpanded
108
+ const shouldPropagate = recursive ?? nextCollapsed
114
109
 
115
110
  if (shouldPropagate) {
116
111
  this.rawChildren.forEach(child => {
117
112
  if (child.isBranch) {
118
- child.toggleExpand(nextExpanded, recursive)
113
+ child.toggleCollapse(nextCollapsed, recursive)
119
114
  }
120
115
  })
121
116
  }
@@ -1,6 +1,6 @@
1
- import { Branch } from '@core/composables/tree/branch'
2
- import { Leaf } from '@core/composables/tree/leaf'
3
- import type { DefinitionToTreeNode, TreeContext, TreeNode, TreeNodeDefinition } from '@core/composables/tree/types'
1
+ import { Branch } from '@core/packages/tree/branch'
2
+ import { Leaf } from '@core/packages/tree/leaf'
3
+ import type { DefinitionToTreeNode, TreeContext, TreeNode, TreeNodeDefinition } from '@core/packages/tree/types'
4
4
 
5
5
  export function buildNodes<TDefinition extends TreeNodeDefinition, TTreeNode extends DefinitionToTreeNode<TDefinition>>(
6
6
  definitions: TDefinition[],
@@ -9,10 +9,10 @@ export function buildNodes<TDefinition extends TreeNodeDefinition, TTreeNode ext
9
9
  function create(definitions: TreeNodeDefinition[], parent: Branch | undefined, depth: number): TreeNode[] {
10
10
  return definitions.map(definition =>
11
11
  definition.isBranch
12
- ? new Branch(definition.data, parent, context, depth, definition.options, thisBranch =>
12
+ ? new Branch(definition.treeId, definition.data, parent, context, depth, definition.options, thisBranch =>
13
13
  create(definition.children, thisBranch, depth + 1)
14
14
  )
15
- : new Leaf(definition.data, parent, context, depth, definition.options)
15
+ : new Leaf(definition.treeId, definition.data, parent, context, depth, definition.options)
16
16
  )
17
17
  }
18
18
 
@@ -1,17 +1,21 @@
1
- import { BranchDefinition } from '@core/composables/tree/branch-definition'
2
- import type { Identifiable, Labeled, TreeNodeDefinition, TreeNodeOptions } from '@core/composables/tree/types'
1
+ import { BranchDefinition } from '@core/packages/tree/branch-definition'
2
+ import type { Identifiable, Labeled, TreeNodeDefinition, TreeNodeOptions } from '@core/packages/tree/types'
3
3
 
4
4
  export function defineBranch<
5
5
  TData extends Identifiable & Labeled,
6
6
  TChildDefinition extends TreeNodeDefinition,
7
7
  const TDiscriminator,
8
- >(data: TData, children: TChildDefinition[]): BranchDefinition<TData, TChildDefinition, TDiscriminator>
8
+ >(treeId: string, data: TData, children: TChildDefinition[]): BranchDefinition<TData, TChildDefinition, TDiscriminator>
9
+
9
10
  export function defineBranch<TData extends object, TChildDefinition extends TreeNodeDefinition, const TDiscriminator>(
11
+ treeId: string,
10
12
  data: TData,
11
13
  options: TreeNodeOptions<TData, TDiscriminator>,
12
14
  children: TChildDefinition[]
13
15
  ): BranchDefinition<TData, TChildDefinition, TDiscriminator>
16
+
14
17
  export function defineBranch<TData extends object, TChildDefinition extends TreeNodeDefinition, const TDiscriminator>(
18
+ treeId: string,
15
19
  data: TData,
16
20
  optionsOrChildren: TreeNodeOptions<TData, TDiscriminator> | TChildDefinition[],
17
21
  childrenOrNone?: TChildDefinition[]
@@ -19,5 +23,5 @@ export function defineBranch<TData extends object, TChildDefinition extends Tree
19
23
  const options = Array.isArray(optionsOrChildren) ? ({} as TreeNodeOptions<TData, TDiscriminator>) : optionsOrChildren
20
24
  const children = Array.isArray(optionsOrChildren) ? optionsOrChildren : childrenOrNone!
21
25
 
22
- return new BranchDefinition(data, options, children)
26
+ return new BranchDefinition(treeId, data, options, children)
23
27
  }
@@ -1,16 +1,21 @@
1
- import { LeafDefinition } from '@core/composables/tree/leaf-definition'
2
- import type { Identifiable, Labeled, TreeNodeOptions } from '@core/composables/tree/types'
1
+ import { LeafDefinition } from '@core/packages/tree/leaf-definition'
2
+ import type { Identifiable, Labeled, TreeNodeOptions } from '@core/packages/tree/types'
3
3
 
4
4
  export function defineLeaf<TData extends Identifiable & Labeled, const TDiscriminator>(
5
+ treeId: string,
5
6
  data: TData
6
7
  ): LeafDefinition<TData, TDiscriminator>
8
+
7
9
  export function defineLeaf<TData extends object, const TDiscriminator>(
10
+ treeId: string,
8
11
  data: TData,
9
12
  options: TreeNodeOptions<TData, TDiscriminator>
10
13
  ): LeafDefinition<TData, TDiscriminator>
14
+
11
15
  export function defineLeaf<TData extends object, const TDiscriminator>(
16
+ treeId: string,
12
17
  data: TData,
13
18
  options?: TreeNodeOptions<TData, TDiscriminator>
14
19
  ): LeafDefinition<TData, TDiscriminator> {
15
- return new LeafDefinition(data, options ?? ({} as TreeNodeOptions<TData, TDiscriminator>))
20
+ return new LeafDefinition(treeId, data, options ?? ({} as TreeNodeOptions<TData, TDiscriminator>))
16
21
  }
@@ -1,20 +1,22 @@
1
- import { BranchDefinition } from '@core/composables/tree/branch-definition'
2
- import { LeafDefinition } from '@core/composables/tree/leaf-definition'
1
+ import { BranchDefinition } from '@core/packages/tree/branch-definition'
2
+ import { LeafDefinition } from '@core/packages/tree/leaf-definition'
3
3
  import type {
4
4
  ChildTreeDefinitionGetter,
5
5
  Identifiable,
6
6
  Labeled,
7
7
  TreeNodeDefinition,
8
8
  TreeNodeOptions,
9
- } from '@core/composables/tree/types'
9
+ } from '@core/packages/tree/types'
10
10
 
11
11
  // Overload 1: Leaf with no options
12
12
  export function defineTree<TData extends Identifiable & Labeled, const TDiscriminator = any>(
13
+ treeId: string,
13
14
  entries: TData[]
14
15
  ): LeafDefinition<TData, TDiscriminator>[]
15
16
 
16
17
  // Overload 2: Leaf with options
17
18
  export function defineTree<TData extends object, const TDiscriminator = any>(
19
+ treeId: string,
18
20
  entries: TData[],
19
21
  options: TreeNodeOptions<TData, TDiscriminator>
20
22
  ): LeafDefinition<TData, TDiscriminator>[]
@@ -25,6 +27,7 @@ export function defineTree<
25
27
  TChildDefinition extends TreeNodeDefinition,
26
28
  const TDiscriminator = any,
27
29
  >(
30
+ treeId: string,
28
31
  entries: TData[],
29
32
  getChildTree: ChildTreeDefinitionGetter<TData, TChildDefinition>
30
33
  ): BranchDefinition<TData, TChildDefinition, TDiscriminator>[]
@@ -35,6 +38,7 @@ export function defineTree<
35
38
  TChildDefinition extends TreeNodeDefinition = TreeNodeDefinition,
36
39
  const TDiscriminator = any,
37
40
  >(
41
+ treeId: string,
38
42
  entries: TData[],
39
43
  options: TreeNodeOptions<TData, TDiscriminator>,
40
44
  getChildTree: ChildTreeDefinitionGetter<TData, TChildDefinition>
@@ -46,6 +50,7 @@ export function defineTree<
46
50
  TChildDefinition extends TreeNodeDefinition = TreeNodeDefinition,
47
51
  const TDiscriminator = any,
48
52
  >(
53
+ treeId: string,
49
54
  entries: TData[],
50
55
  optionsOrGetChildTree?: TreeNodeOptions<TData, TDiscriminator> | ChildTreeDefinitionGetter<TData, TChildDefinition>,
51
56
  getChildTreeOrNone?: ChildTreeDefinitionGetter<TData, TChildDefinition>
@@ -58,8 +63,8 @@ export function defineTree<
58
63
  const getChildTree = typeof optionsOrGetChildTree === 'function' ? optionsOrGetChildTree : getChildTreeOrNone
59
64
 
60
65
  if (getChildTree !== undefined) {
61
- return entries.map(data => new BranchDefinition(data, options, getChildTree(data)))
66
+ return entries.map(data => new BranchDefinition(treeId, data, options, getChildTree(data)))
62
67
  }
63
68
 
64
- return entries.map(data => new LeafDefinition(data, options))
69
+ return entries.map(data => new LeafDefinition(treeId, data, options))
65
70
  }
@@ -1,4 +1,4 @@
1
- import { TreeNodeDefinitionBase } from '@core/composables/tree/tree-node-definition-base'
1
+ import { TreeNodeDefinitionBase } from '@core/packages/tree/tree-node-definition-base'
2
2
 
3
3
  export class LeafDefinition<TData extends object = any, const TDiscriminator = any> extends TreeNodeDefinitionBase<
4
4
  TData,
@@ -1,5 +1,5 @@
1
- import { TreeNodeBase } from '@core/composables/tree/tree-node-base'
2
- import type { LeafStatuses } from '@core/composables/tree/types'
1
+ import { TreeNodeBase } from '@core/packages/tree/tree-node-base'
2
+ import type { LeafStatuses } from '@core/packages/tree/types'
3
3
 
4
4
  export class Leaf<TData extends object = any, const TDiscriminator = any> extends TreeNodeBase<TData, TDiscriminator> {
5
5
  readonly isBranch = false
@@ -13,7 +13,7 @@ export class Leaf<TData extends object = any, const TDiscriminator = any> extend
13
13
  }
14
14
 
15
15
  get isExcluded() {
16
- if (this.parent?.isExpanded === false) {
16
+ if (this.parent?.isCollapsed === true) {
17
17
  return true
18
18
  }
19
19
 
@@ -1,5 +1,5 @@
1
- import type { Branch } from '@core/composables/tree/branch'
2
- import type { Identifiable, Labeled, TreeContext, TreeNodeId, TreeNodeOptions } from '@core/composables/tree/types'
1
+ import type { Branch } from '@core/packages/tree/branch'
2
+ import type { Identifiable, Labeled, TreeContext, TreeNodeId, TreeNodeOptions } from '@core/packages/tree/types'
3
3
 
4
4
  export abstract class TreeNodeBase<TData extends object = any, TDiscriminator = any> {
5
5
  abstract readonly isBranch: boolean
@@ -7,6 +7,7 @@ export abstract class TreeNodeBase<TData extends object = any, TDiscriminator =
7
7
  abstract isExcluded: boolean
8
8
  abstract statuses: Record<string, boolean>
9
9
 
10
+ readonly treeId: string
10
11
  readonly data: TData
11
12
  readonly depth: number
12
13
  readonly parent: Branch | undefined
@@ -14,12 +15,14 @@ export abstract class TreeNodeBase<TData extends object = any, TDiscriminator =
14
15
  readonly options: TreeNodeOptions<TData, TDiscriminator>
15
16
 
16
17
  constructor(
18
+ treeId: string,
17
19
  data: TData,
18
20
  parent: Branch | undefined,
19
21
  context: TreeContext,
20
22
  depth: number,
21
23
  options?: TreeNodeOptions<TData, TDiscriminator>
22
24
  ) {
25
+ this.treeId = treeId
23
26
  this.data = data
24
27
  this.parent = parent
25
28
  this.context = context
@@ -27,7 +30,7 @@ export abstract class TreeNodeBase<TData extends object = any, TDiscriminator =
27
30
  this.options = options ?? ({} as TreeNodeOptions<TData, TDiscriminator>)
28
31
  }
29
32
 
30
- get id(): TreeNodeId {
33
+ get dataId(): TreeNodeId {
31
34
  if (this.options.getId === undefined) {
32
35
  return (this.data as Identifiable).id
33
36
  }
@@ -39,6 +42,18 @@ export abstract class TreeNodeBase<TData extends object = any, TDiscriminator =
39
42
  return this.data[this.options.getId as keyof TData] as TreeNodeId
40
43
  }
41
44
 
45
+ get id(): TreeNodeId {
46
+ const parts = [this.dataId, this.treeId]
47
+ let currentParent = this.parent
48
+
49
+ while (currentParent) {
50
+ parts.push(currentParent.treeId)
51
+ currentParent = currentParent.parent
52
+ }
53
+
54
+ return parts.reverse().join('.')
55
+ }
56
+
42
57
  get label() {
43
58
  if (this.options.getLabel === undefined) {
44
59
  return (this.data as Labeled).label
@@ -1,11 +1,13 @@
1
- import type { TreeNodeOptions } from '@core/composables/tree/types'
1
+ import type { TreeNodeOptions } from '@core/packages/tree/types'
2
2
 
3
3
  export abstract class TreeNodeDefinitionBase<TData extends object, TDiscriminator> {
4
4
  abstract readonly isBranch: boolean
5
+ readonly treeId: string
5
6
  data: TData
6
7
  options: TreeNodeOptions<TData, TDiscriminator>
7
8
 
8
- constructor(data: TData, options: TreeNodeOptions<TData, TDiscriminator>) {
9
+ constructor(treeId: string, data: TData, options: TreeNodeOptions<TData, TDiscriminator>) {
10
+ this.treeId = treeId
9
11
  this.data = data
10
12
  this.options = options
11
13
  }
@@ -1,9 +1,10 @@
1
- import type { Branch } from '@core/composables/tree/branch'
2
- import type { BranchDefinition } from '@core/composables/tree/branch-definition'
3
- import type { Leaf } from '@core/composables/tree/leaf'
4
- import type { LeafDefinition } from '@core/composables/tree/leaf-definition'
5
- import type { TreeNodeBase } from '@core/composables/tree/tree-node-base'
6
- import { useTree } from '@core/composables/tree.composable'
1
+ import type { Branch } from '@core/packages/tree/branch'
2
+ import type { BranchDefinition } from '@core/packages/tree/branch-definition'
3
+ import type { Leaf } from '@core/packages/tree/leaf'
4
+ import type { LeafDefinition } from '@core/packages/tree/leaf-definition'
5
+ import type { TreeNodeBase } from '@core/packages/tree/tree-node-base'
6
+ import { useTree } from '@core/packages/tree/use-tree'
7
+ import type { Ref } from 'vue'
7
8
 
8
9
  export type TreeNodeId = string | number
9
10
 
@@ -62,13 +63,14 @@ export type ChildTreeDefinitionGetter<TData extends object, TChildDefinition ext
62
63
  export type TreeContext = {
63
64
  allowMultiSelect: boolean
64
65
  selectedIds: Set<TreeNodeId>
65
- expandedIds: Set<TreeNodeId>
66
+ collapsedIds: Set<TreeNodeId>
66
67
  activeId: TreeNodeId | undefined
67
68
  }
68
69
 
69
70
  export type UseTreeOptions = {
70
71
  allowMultiSelect?: boolean
71
- expand?: boolean
72
+ collapse?: boolean
73
+ collapsedIds?: Ref<Set<TreeNodeId>>
72
74
  selectedLabel?:
73
75
  | ((nodes: TreeNode[]) => string)
74
76
  | {
@@ -88,5 +90,5 @@ export type LeafStatuses = {
88
90
  export type BranchStatuses = LeafStatuses & {
89
91
  'selected-partial': boolean
90
92
  'selected-full': boolean
91
- expanded: boolean
93
+ collapsed: boolean
92
94
  }
@@ -1,4 +1,4 @@
1
- import { buildNodes } from '@core/composables/tree/build-nodes'
1
+ import { buildNodes } from '@core/packages/tree/build-nodes'
2
2
  import type {
3
3
  DefinitionToTreeNode,
4
4
  TreeContext,
@@ -6,7 +6,7 @@ import type {
6
6
  TreeNodeDefinition,
7
7
  TreeNodeId,
8
8
  UseTreeOptions,
9
- } from '@core/composables/tree/types'
9
+ } from '@core/packages/tree/types'
10
10
  import { computed, type MaybeRefOrGetter, reactive, ref, toValue } from 'vue'
11
11
 
12
12
  export function useTree<
@@ -14,21 +14,21 @@ export function useTree<
14
14
  TTreeNode extends DefinitionToTreeNode<TDefinition> = DefinitionToTreeNode<TDefinition>,
15
15
  >(definitions: MaybeRefOrGetter<TDefinition[]>, options: UseTreeOptions = {}) {
16
16
  const selectedIds = ref(new Set<TreeNodeId>())
17
- const expandedIds = ref(new Set<TreeNodeId>())
17
+ const collapsedIds = options.collapsedIds ?? ref(new Set<TreeNodeId>())
18
18
  const activeId = ref<TreeNodeId>()
19
19
 
20
20
  const context = reactive({
21
21
  allowMultiSelect: options.allowMultiSelect ?? false,
22
22
  selectedIds,
23
- expandedIds,
23
+ collapsedIds,
24
24
  activeId,
25
- }) as TreeContext
25
+ }) satisfies TreeContext
26
26
 
27
27
  const nodes = computed(() => {
28
28
  const nodes = buildNodes<TDefinition, TTreeNode>(toValue(definitions), context)
29
29
 
30
- if (options.expand !== false) {
31
- nodes.forEach(node => node.isBranch && node.toggleExpand(true, true))
30
+ if (options.collapse) {
31
+ nodes.forEach(node => node.isBranch && node.toggleCollapse(true, true))
32
32
  }
33
33
 
34
34
  return nodes
@@ -52,11 +52,24 @@ export function useTree<
52
52
 
53
53
  const visibleNodes = computed(() => nodes.value.filter(node => !node.isExcluded))
54
54
 
55
- const getNode = (id: TreeNodeId | undefined) => (id !== undefined ? nodesMap.value.get(id) : undefined)
56
- const getNodes = (ids: TreeNodeId[]) => ids.map(getNode).filter(node => node !== undefined) as TreeNode[]
55
+ function getNode(id: TreeNodeId | undefined): TreeNode | undefined {
56
+ if (id === undefined) {
57
+ return undefined
58
+ }
59
+
60
+ return nodesMap.value.get(id)
61
+ }
62
+
63
+ const selectedNodes = computed(() =>
64
+ Array.from(selectedIds.value.values())
65
+ .map(id => getNode(id))
66
+ .filter(node => node !== undefined)
67
+ )
68
+
69
+ const expandedIds = computed(() => Array.from(nodesMap.value.keys()).filter(id => !collapsedIds.value.has(id)))
70
+
71
+ const expandedNodes = computed(() => expandedIds.value.map(id => getNode(id)).filter(node => node !== undefined))
57
72
 
58
- const selectedNodes = computed(() => getNodes(Array.from(selectedIds.value.values())))
59
- const expandedNodes = computed(() => getNodes(Array.from(expandedIds.value.values())))
60
73
  const activeNode = computed(() => getNode(activeId.value))
61
74
 
62
75
  const selectedLabel = computed(() => {
@@ -0,0 +1,4 @@
1
+ import { useCollapsedListColumn } from '@core/tables/column-definitions/collapsed-list-column.ts'
2
+ import type { HeaderConfig } from '@core/tables/types.ts'
3
+
4
+ export const useAddressColumn = (config?: HeaderConfig) => useCollapsedListColumn({ headerIcon: 'fa:at', ...config })
@@ -0,0 +1,35 @@
1
+ import UiButton, {
2
+ type ButtonAccent,
3
+ type ButtonProps,
4
+ type ButtonVariant,
5
+ type ButtonSize,
6
+ } from '@core/components/ui/button/UiButton.vue'
7
+ import { defineColumn } from '@core/packages/table/define-column'
8
+ import { renderBodyCell } from '@core/tables/helpers/render-body-cell'
9
+ import { renderHeadCell } from '@core/tables/helpers/render-head-cell'
10
+ import type { HeaderConfig } from '@core/tables/types.ts'
11
+ import { h, toValue, type MaybeRefOrGetter } from 'vue'
12
+
13
+ type ButtonConfig = {
14
+ buttonAccent?: MaybeRefOrGetter<ButtonAccent>
15
+ buttonVariant?: MaybeRefOrGetter<ButtonVariant>
16
+ buttonSize?: MaybeRefOrGetter<ButtonSize>
17
+ }
18
+
19
+ export const useButtonColumn = defineColumn((config?: HeaderConfig & ButtonConfig) => ({
20
+ renderHead: () => renderHeadCell(config?.headerIcon, config?.headerLabel),
21
+ renderBody: (label: string, onClick: () => void, props?: Partial<ButtonProps>) =>
22
+ renderBodyCell(() =>
23
+ h(
24
+ UiButton,
25
+ {
26
+ accent: toValue(config?.buttonAccent) ?? 'brand',
27
+ variant: toValue(config?.buttonVariant) ?? 'primary',
28
+ size: toValue(config?.buttonSize) ?? 'medium',
29
+ ...props,
30
+ onClick,
31
+ },
32
+ () => label
33
+ )
34
+ ),
35
+ }))