Skip to content

Commit 8489d1a

Browse files
Docs: Tree example (#19624)
* add basic collection example * add card view example * update example readme * Add workspace view example with collection * wip tree example * clean up * Update README.md * Update README.md
1 parent e0a00bf commit 8489d1a

File tree

21 files changed

+296
-0
lines changed

21 files changed

+296
-0
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Tree Example
2+
3+
This example demonstrates how to register a tree
4+
5+
The example includes:
6+
7+
- Tree + Tree Item Registration
8+
- Tree Repository + Store Registration
9+
- A Dashboard to show how to render a tree anywhere in the backoffice
10+
- How to use the tree in the sidebar menu
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { EXAMPLE_TREE_ALIAS } from '../tree/constants.js';
2+
import { html, customElement, LitElement, css } from '@umbraco-cms/backoffice/external/lit';
3+
import { UmbElementMixin } from '@umbraco-cms/backoffice/element-api';
4+
5+
@customElement('example-dashboard-with-tree')
6+
export class ExampleDashboardWithTree extends UmbElementMixin(LitElement) {
7+
override render() {
8+
return html`<uui-box><umb-tree alias=${EXAMPLE_TREE_ALIAS}></umb-tree></uui-box>`;
9+
}
10+
11+
static override styles = [
12+
css`
13+
:host {
14+
display: block;
15+
padding: var(--uui-size-layout-1);
16+
}
17+
`,
18+
];
19+
}
20+
21+
export { ExampleDashboardWithTree as element };
22+
23+
declare global {
24+
interface HTMLElementTagNameMap {
25+
'example-dashboard-with-tree': ExampleDashboardWithTree;
26+
}
27+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
export const manifests: Array<UmbExtensionManifest> = [
2+
{
3+
type: 'dashboard',
4+
kind: 'default',
5+
name: 'Example Dashboard With Tree',
6+
alias: 'Example.Dashboard.WithTree',
7+
element: () => import('./dashboard-with-tree.element.js'),
8+
weight: 3000,
9+
meta: {
10+
label: 'Tree Example',
11+
pathname: 'tree-example',
12+
},
13+
},
14+
];
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export const EXAMPLE_ENTITY_TYPE = 'example';
2+
export const EXAMPLE_ROOT_ENTITY_TYPE = 'example-root';
3+
4+
export type ExampleEntityType = typeof EXAMPLE_ENTITY_TYPE;
5+
export type ExampleRootEntityType = typeof EXAMPLE_ROOT_ENTITY_TYPE;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { manifests as dashboardManifests } from './dashboard-with-tree/manifests.js';
2+
import { manifests as menuItemManifests } from './menu-item-with-tree/manifests.js';
3+
import { manifests as treeManifests } from './tree/manifests.js';
4+
5+
export const manifests: Array<UmbExtensionManifest> = [...dashboardManifests, ...menuItemManifests, ...treeManifests];
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { EXAMPLE_TREE_ALIAS } from '../tree/constants.js';
2+
import { UMB_CONTENT_MENU_ALIAS } from '@umbraco-cms/backoffice/document';
3+
4+
export const manifests: Array<UmbExtensionManifest> = [
5+
{
6+
type: 'menuItem',
7+
kind: 'tree',
8+
alias: 'Example.MenuItem.Tree',
9+
name: 'Example Tree Menu Item',
10+
weight: 1000,
11+
meta: {
12+
label: 'Example Tree',
13+
menus: [UMB_CONTENT_MENU_ALIAS],
14+
treeAlias: EXAMPLE_TREE_ALIAS,
15+
},
16+
},
17+
];
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const EXAMPLE_TREE_ALIAS = 'Example.Tree';
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './repository/constants.js';
2+
export * from './store/constants.js';
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './tree.local.data-source.js';
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import type { ExampleTreeItemModel } from '../../types.js';
2+
import { EXAMPLE_ENTITY_TYPE, EXAMPLE_ROOT_ENTITY_TYPE } from '../../../entity.js';
3+
import type {
4+
UmbTreeAncestorsOfRequestArgs,
5+
UmbTreeChildrenOfRequestArgs,
6+
UmbTreeDataSource,
7+
UmbTreeRootItemsRequestArgs,
8+
} from '@umbraco-cms/backoffice/tree';
9+
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
10+
11+
const EXAMPLE_TREE_DATA: Array<ExampleTreeItemModel> = [
12+
{
13+
entityType: EXAMPLE_ENTITY_TYPE,
14+
hasChildren: false,
15+
isFolder: false,
16+
name: 'Item 1',
17+
parent: { unique: null, entityType: EXAMPLE_ROOT_ENTITY_TYPE },
18+
unique: 'ab7b6e03-5f4d-4a6b-9f4c-21292d462e08',
19+
icon: 'icon-newspaper',
20+
},
21+
{
22+
entityType: EXAMPLE_ENTITY_TYPE,
23+
hasChildren: true,
24+
isFolder: false,
25+
name: 'Item 2',
26+
parent: { unique: null, entityType: EXAMPLE_ROOT_ENTITY_TYPE },
27+
unique: '74a5b2d9-3564-45b8-a3ee-98fc7ec0c1fb',
28+
icon: 'icon-newspaper',
29+
},
30+
{
31+
entityType: EXAMPLE_ENTITY_TYPE,
32+
hasChildren: false,
33+
isFolder: false,
34+
name: 'Item 3',
35+
parent: { unique: null, entityType: EXAMPLE_ROOT_ENTITY_TYPE },
36+
unique: '1b8ed2ac-b4bb-4384-972e-2cf18f40586a',
37+
icon: 'icon-newspaper',
38+
},
39+
{
40+
entityType: EXAMPLE_ENTITY_TYPE,
41+
hasChildren: false,
42+
isFolder: false,
43+
name: 'Item 2.1',
44+
parent: { unique: '74a5b2d9-3564-45b8-a3ee-98fc7ec0c1fb', entityType: EXAMPLE_ENTITY_TYPE },
45+
unique: '62dbd672-b198-4fc8-8b42-5d21dfbd3788',
46+
icon: 'icon-newspaper',
47+
},
48+
{
49+
entityType: EXAMPLE_ENTITY_TYPE,
50+
hasChildren: true,
51+
isFolder: false,
52+
name: 'Item 2.2',
53+
parent: { unique: '74a5b2d9-3564-45b8-a3ee-98fc7ec0c1fb', entityType: EXAMPLE_ENTITY_TYPE },
54+
unique: 'deaa3f8c-e40b-4eb7-8268-34014504152e',
55+
icon: 'icon-newspaper',
56+
},
57+
{
58+
entityType: EXAMPLE_ENTITY_TYPE,
59+
hasChildren: false,
60+
isFolder: false,
61+
name: 'Item 2.2.1',
62+
parent: { unique: 'deaa3f8c-e40b-4eb7-8268-34014504152e', entityType: EXAMPLE_ENTITY_TYPE },
63+
unique: 'd4cf5fd2-1f84-4f3b-b63b-5f29a38e72d1',
64+
icon: 'icon-newspaper',
65+
},
66+
];
67+
68+
export class ExampleTreeLocalDataSource extends UmbControllerBase implements UmbTreeDataSource<ExampleTreeItemModel> {
69+
async getRootItems(args: UmbTreeRootItemsRequestArgs) {
70+
// TODO: handle skip, take, foldersOnly.
71+
console.log(args);
72+
const rootItems: Array<ExampleTreeItemModel> = EXAMPLE_TREE_DATA.filter((item) => item.parent.unique === null);
73+
return { data: { items: rootItems, total: rootItems.length } };
74+
}
75+
76+
async getChildrenOf(args: UmbTreeChildrenOfRequestArgs) {
77+
// TODO: handle skip, take, foldersOnly.
78+
const children = EXAMPLE_TREE_DATA.filter(
79+
(item) => item.parent.unique === args.parent.unique && item.parent.entityType === args.parent.entityType,
80+
);
81+
82+
return { data: { items: children, total: children.length } };
83+
}
84+
85+
async getAncestorsOf(args: UmbTreeAncestorsOfRequestArgs) {
86+
const ancestors = findAncestors(args.treeItem.unique, args.treeItem.entityType);
87+
return { data: ancestors };
88+
}
89+
}
90+
91+
// Helper function to find ancestors recursively
92+
const findAncestors = (unique: string, entityType: string): Array<ExampleTreeItemModel> => {
93+
const item = EXAMPLE_TREE_DATA.find((i) => i.unique === unique && i.entityType === entityType);
94+
95+
if (!item || !item.parent || item.parent.unique === null) {
96+
return [];
97+
}
98+
99+
const parent = EXAMPLE_TREE_DATA.find(
100+
(i) => i.unique === item.parent.unique && i.entityType === item.parent.entityType,
101+
);
102+
103+
if (!parent) {
104+
return [];
105+
}
106+
107+
return [parent, ...findAncestors(parent.unique, parent.entityType)];
108+
};

0 commit comments

Comments
 (0)