Skip to content

Commit e490802

Browse files
committed
docs: update menu configuration documentation to include plugin contributions and dynamic menu items
1 parent 10d3f4f commit e490802

1 file changed

Lines changed: 126 additions & 125 deletions

File tree

adminforth/documentation/docs/tutorial/03-Customization/10-menuConfiguration.md

Lines changed: 126 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -57,131 +57,6 @@ E.g. create group "Blog" with Items who link to resource "posts" and "categories
5757

5858
If it is rare Group you can make it `open: false` so it would not take extra space in menu, but admin users will be able to open it by clicking on the group name.
5959

60-
## Adding menu items from plugins
61-
62-
Plugins can add top-level menu items without mutating the user-defined `config.menu`. This keeps the application menu owned by the app configuration, while plugins can contribute their own entries.
63-
64-
Use `registerMenuContribution` from a plugin's `modifyResourceConfig`:
65-
66-
```ts title='./plugins/adminforth-dashboard/index.ts'
67-
async modifyResourceConfig(adminforth, resourceConfig) {
68-
super.modifyResourceConfig(adminforth, resourceConfig);
69-
70-
adminforth.registerMenuContribution({
71-
item: {
72-
itemId: 'dashboard',
73-
type: 'page',
74-
label: 'Dashboard',
75-
icon: 'flowbite:chart-pie-solid',
76-
path: '/dashboard',
77-
component: this.componentPath('Dashboard.vue'),
78-
},
79-
placement: { before: { resourceId: 'adminuser' } },
80-
});
81-
}
82-
```
83-
84-
Supported placements:
85-
86-
```ts
87-
adminforth.registerMenuContribution({
88-
item: {
89-
itemId: 'dashboard',
90-
type: 'page',
91-
label: 'Dashboard',
92-
path: '/dashboard',
93-
component: this.componentPath('Dashboard.vue'),
94-
},
95-
placement: { position: 'first' },
96-
});
97-
98-
adminforth.registerMenuContribution({
99-
item: {
100-
itemId: 'reports',
101-
type: 'page',
102-
label: 'Reports',
103-
path: '/reports',
104-
component: this.componentPath('Reports.vue'),
105-
},
106-
placement: { after: { resourceId: 'orders' } },
107-
});
108-
```
109-
110-
`placement` can be:
111-
112-
- `{ position: 'first' }`
113-
- `{ position: 'last' }`
114-
- `{ before: 'usersMenuItemId' }`
115-
- `{ after: 'usersMenuItemId' }`
116-
- `{ before: { itemId: 'usersMenuItemId' } }`
117-
- `{ after: { resourceId: 'adminuser' } }`
118-
- `{ before: { path: '/reports' } }`
119-
120-
If placement is omitted, or if the target item is not found, AdminForth appends the contributed item to the end of the top-level menu.
121-
122-
Plugin menu contributions are additive only:
123-
124-
- user-defined `config.menu` is not changed
125-
- plugins cannot remove or edit existing menu items through this API
126-
- contributed `itemId` must not duplicate an existing top-level menu item
127-
- this first version inserts only top-level menu items
128-
129-
### Dynamic menu items from plugin state
130-
131-
If a plugin needs to add menu items at runtime, for example after a user clicks a button and creates a new dashboard, register a menu contribution provider. AdminForth calls providers every time it fetches the menu.
132-
133-
```ts title='./plugins/adminforth-dashboard/index.ts'
134-
async modifyResourceConfig(adminforth, resourceConfig) {
135-
super.modifyResourceConfig(adminforth, resourceConfig);
136-
137-
adminforth.registerMenuContributionProvider(async ({ adminUser, adminforth }) => {
138-
const dashboards = await adminforth.resource('dashboards').list();
139-
140-
return [
141-
{
142-
item: {
143-
itemId: 'dashboardsMenu',
144-
type: 'group',
145-
label: 'Dashboards',
146-
icon: 'flowbite:chart-pie-solid',
147-
children: dashboards.map((dashboard) => ({
148-
itemId: `dashboard-${dashboard.id}`,
149-
type: 'page',
150-
label: dashboard.name,
151-
path: `/dashboards/${dashboard.id}`,
152-
})),
153-
},
154-
placement: { position: 'first' },
155-
},
156-
];
157-
});
158-
}
159-
```
160-
161-
After the plugin changes the state used by the provider, call `refreshMenu` on the backend:
162-
163-
```ts
164-
await adminforth.resource('dashboards').create({
165-
name: 'Sales',
166-
});
167-
168-
await adminforth.refreshMenu(adminUser);
169-
```
170-
171-
AdminForth sends a websocket event to the current user, and the frontend refetches the menu without a page reload.
172-
173-
Frontend components can also refresh the menu directly:
174-
175-
```ts
176-
import { useAdminforth } from '@/adminforth';
177-
178-
const { menu } = useAdminforth();
179-
180-
await menu.refresh();
181-
```
182-
183-
Dynamic menu items should point to routes that are already available in the SPA. If a provider returns a brand-new custom `component` path that was not known during AdminForth build, the menu item can appear, but the route will not be registered until the app is rebuilt.
184-
18560
## Visibility of menu items
18661

18762
You might want to hide some menu items from the menu for some users.
@@ -429,3 +304,129 @@ menu: [
429304

430305
```
431306
> 👆 Please note start internal URLs with a leading / to ensure correct routing.
307+
308+
309+
## Adding menu items from plugins
310+
311+
Plugins can add top-level menu items without mutating the user-defined `config.menu`. This keeps the application menu owned by the app configuration, while plugins can contribute their own entries.
312+
313+
Use `registerMenuContribution` from a plugin's `modifyResourceConfig`:
314+
315+
```ts title='./plugins/adminforth-dashboard/index.ts'
316+
async modifyResourceConfig(adminforth, resourceConfig) {
317+
super.modifyResourceConfig(adminforth, resourceConfig);
318+
319+
adminforth.registerMenuContribution({
320+
item: {
321+
itemId: 'dashboard',
322+
type: 'page',
323+
label: 'Dashboard',
324+
icon: 'flowbite:chart-pie-solid',
325+
path: '/dashboard',
326+
component: this.componentPath('Dashboard.vue'),
327+
},
328+
placement: { before: { resourceId: 'adminuser' } },
329+
});
330+
}
331+
```
332+
333+
Supported placements:
334+
335+
```ts
336+
adminforth.registerMenuContribution({
337+
item: {
338+
itemId: 'dashboard',
339+
type: 'page',
340+
label: 'Dashboard',
341+
path: '/dashboard',
342+
component: this.componentPath('Dashboard.vue'),
343+
},
344+
placement: { position: 'first' },
345+
});
346+
347+
adminforth.registerMenuContribution({
348+
item: {
349+
itemId: 'reports',
350+
type: 'page',
351+
label: 'Reports',
352+
path: '/reports',
353+
component: this.componentPath('Reports.vue'),
354+
},
355+
placement: { after: { resourceId: 'orders' } },
356+
});
357+
```
358+
359+
`placement` can be:
360+
361+
- `{ position: 'first' }`
362+
- `{ position: 'last' }`
363+
- `{ before: 'usersMenuItemId' }`
364+
- `{ after: 'usersMenuItemId' }`
365+
- `{ before: { itemId: 'usersMenuItemId' } }`
366+
- `{ after: { resourceId: 'adminuser' } }`
367+
- `{ before: { path: '/reports' } }`
368+
369+
If placement is omitted, or if the target item is not found, AdminForth appends the contributed item to the end of the top-level menu.
370+
371+
Plugin menu contributions are additive only:
372+
373+
- user-defined `config.menu` is not changed
374+
- plugins cannot remove or edit existing menu items through this API
375+
- contributed `itemId` must not duplicate an existing top-level menu item
376+
- this first version inserts only top-level menu items
377+
378+
### Dynamic menu items from plugin state
379+
380+
If a plugin needs to add menu items at runtime, for example after a user clicks a button and creates a new dashboard, register a menu contribution provider. AdminForth calls providers every time it fetches the menu.
381+
382+
```ts title='./plugins/adminforth-dashboard/index.ts'
383+
async modifyResourceConfig(adminforth, resourceConfig) {
384+
super.modifyResourceConfig(adminforth, resourceConfig);
385+
386+
adminforth.registerMenuContributionProvider(async ({ adminUser, adminforth }) => {
387+
const dashboards = await adminforth.resource('dashboards').list();
388+
389+
return [
390+
{
391+
item: {
392+
itemId: 'dashboardsMenu',
393+
type: 'group',
394+
label: 'Dashboards',
395+
icon: 'flowbite:chart-pie-solid',
396+
children: dashboards.map((dashboard) => ({
397+
itemId: `dashboard-${dashboard.id}`,
398+
type: 'page',
399+
label: dashboard.name,
400+
path: `/dashboards/${dashboard.id}`,
401+
})),
402+
},
403+
placement: { position: 'first' },
404+
},
405+
];
406+
});
407+
}
408+
```
409+
410+
After the plugin changes the state used by the provider, call `refreshMenu` on the backend:
411+
412+
```ts
413+
await adminforth.resource('dashboards').create({
414+
name: 'Sales',
415+
});
416+
417+
await adminforth.refreshMenu(adminUser);
418+
```
419+
420+
AdminForth sends a websocket event to the current user, and the frontend refetches the menu without a page reload.
421+
422+
Frontend components can also refresh the menu directly:
423+
424+
```ts
425+
import { useAdminforth } from '@/adminforth';
426+
427+
const { menu } = useAdminforth();
428+
429+
await menu.refresh();
430+
```
431+
432+
Dynamic menu items should point to routes that are already available in the SPA. If a provider returns a brand-new custom `component` path that was not known during AdminForth build, the menu item can appear, but the route will not be registered until the app is rebuilt.

0 commit comments

Comments
 (0)