ソースを参照

feat(admin-ui): Add support for tabs on custom UI routes

21_Reinite 1 年間 前
コミット
26b4ea5e17

+ 1 - 0
docs/docs/guides/extending-the-admin-ui/defining-routes/index.md

@@ -482,6 +482,7 @@ export default [
     registerRouteComponent({
         component: TestComponent,
         title: 'Test',
+        locationId: 'my-location-id'
         // highlight-next-line
         breadcrumb: 'Test',
     }),

+ 16 - 0
docs/docs/guides/extending-the-admin-ui/page-tabs/index.md

@@ -23,6 +23,22 @@ export default [
 
 ![./ui-extensions-tabs.webp](./ui-extensions-tabs.webp)
 
+If you want to add page tabs to a custom admin page, specify the `locationId` property:
+
+```ts title="src/plugins/my-plugin/ui/routes.ts"
+import { registerRouteComponent } from '@vendure/admin-ui/core';
+import { TestComponent } from './components/test/test.component';
+
+export default [
+    registerRouteComponent({
+        component: TestComponent,
+        title: 'Test',
+        // highlight-next-line
+        locationId: 'my-location-id'
+    }),
+];
+```
+
 :::note
 Currently it is only possible to define new tabs using Angular components.
 :::

+ 1 - 1
docs/docs/reference/admin-ui-api/routes/register-route-component.md

@@ -11,7 +11,7 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 ## registerRouteComponent
 
-<GenerationInfo sourceFile="packages/admin-ui/src/lib/core/src/extension/register-route-component.ts" sourceLine="77" packageName="@vendure/admin-ui" />
+<GenerationInfo sourceFile="packages/admin-ui/src/lib/core/src/extension/register-route-component.ts" sourceLine="79" packageName="@vendure/admin-ui" />
 
 Registers an Angular standalone component to be rendered in a route.
 

+ 22 - 2
packages/admin-ui/src/lib/core/src/extension/components/route.component.ts

@@ -1,4 +1,4 @@
-import { Component, inject, InjectionToken } from '@angular/core';
+import { Component, inject, InjectionToken, Input } from '@angular/core';
 import { ActivatedRoute } from '@angular/router';
 import { notNullOrUndefined } from '@vendure/common/lib/shared-utils';
 import { combineLatest, Observable, of, switchMap } from 'rxjs';
@@ -7,6 +7,9 @@ import { BreadcrumbValue } from '../../providers/breadcrumb/breadcrumb.service';
 import { SharedModule } from '../../shared/shared.module';
 import { PageMetadataService } from '../providers/page-metadata.service';
 import { AngularRouteComponentOptions } from '../types';
+import { HeaderTab } from '../../shared/components/page-header-tabs/page-header-tabs.component';
+import { PageService } from '../../providers/page/page.service';
+import { PageLocationId } from '../../common/component-registry-types';
 
 export const ROUTE_COMPONENT_OPTIONS = new InjectionToken<AngularRouteComponentOptions>(
     'ROUTE_COMPONENT_OPTIONS',
@@ -17,6 +20,8 @@ export const ROUTE_COMPONENT_OPTIONS = new InjectionToken<AngularRouteComponentO
     template: `
         <vdr-page-header>
             <vdr-page-title *ngIf="title$ | async as title" [title]="title"></vdr-page-title>
+            <vdr-page-header-description *ngIf="description">{{ description }}</vdr-page-header-description>
+            <vdr-page-header-tabs *ngIf="headerTabs.length > 1" [tabs]="headerTabs"></vdr-page-header-tabs>
         </vdr-page-header>
         <vdr-page-body><ng-content /></vdr-page-body>
     `,
@@ -26,8 +31,14 @@ export const ROUTE_COMPONENT_OPTIONS = new InjectionToken<AngularRouteComponentO
 })
 export class RouteComponent {
     protected title$: Observable<string | undefined>;
+    @Input() protected locationId: PageLocationId;
+    @Input() protected description: string;
+    headerTabs: HeaderTab[] = [];
 
-    constructor(private route: ActivatedRoute) {
+    constructor(
+        private route: ActivatedRoute,
+        private pageService: PageService,
+    ) {
         const breadcrumbLabel$ = this.route.data.pipe(
             switchMap(data => {
                 if (data.breadcrumb instanceof Observable) {
@@ -53,5 +64,14 @@ export class RouteComponent {
         this.title$ = combineLatest([inject(ROUTE_COMPONENT_OPTIONS).title$, breadcrumbLabel$]).pipe(
             map(([title, breadcrumbLabel]) => title ?? breadcrumbLabel),
         );
+
+        this.locationId = this.route.snapshot.data.locationId;
+        this.description = this.route.snapshot.data.description;
+        this.headerTabs = this.pageService.getPageTabs(this.locationId).map(tab => ({
+            id: tab.tab,
+            label: tab.tab,
+            icon: tab.tabIcon,
+            route: tab.route ? [tab.route] : ['./'],
+        }));
     }
 }

+ 5 - 1
packages/admin-ui/src/lib/core/src/extension/register-route-component.ts

@@ -25,6 +25,8 @@ export type RegisterRouteComponentOptions<
 > = {
     component: Type<Component> | Component;
     title?: string;
+    locationId?: string;
+    description?: string;
     breadcrumb?: BreadcrumbValue;
     path?: string;
     query?: T;
@@ -81,7 +83,7 @@ export function registerRouteComponent<
     Field extends keyof ResultOf<T>,
     R extends Field,
 >(options: RegisterRouteComponentOptions<Component, Entity, T, Field, R>) {
-    const { query, entityKey, variables, getBreadcrumbs } = options;
+    const { query, entityKey, variables, getBreadcrumbs, locationId, description } = options;
 
     const breadcrumbSubject$ = new BehaviorSubject<BreadcrumbValue>(options.breadcrumb ?? '');
     const titleSubject$ = new BehaviorSubject<string | undefined>(options.title);
@@ -129,6 +131,8 @@ export function registerRouteComponent<
         ...(options.routeConfig ?? {}),
         resolve: { ...(resolveFn ? { detail: resolveFn } : {}), ...(options.routeConfig?.resolve ?? {}) },
         data: {
+            locationId,
+            description,
             breadcrumb: breadcrumbSubject$,
             ...(options.routeConfig?.data ?? {}),
             ...(getBreadcrumbs && query && entityKey

+ 31 - 1
packages/dev-server/example-plugins/ui-extensions-library/ui/providers.ts

@@ -1,4 +1,5 @@
-import { addNavMenuSection } from '@vendure/admin-ui/core';
+import { PageLocationId, addNavMenuSection, registerPageTab } from '@vendure/admin-ui/core';
+import { AngularUiComponent } from './angular-components/angular-ui/angular-ui.component';
 
 export default [
     addNavMenuSection({
@@ -17,4 +18,33 @@ export default [
             },
         ],
     }),
+    //Testing page tabs on custom angular components
+    registerPageTab({
+        location: 'angular-ui' as PageLocationId,
+        tab: 'Example Tab 1',
+        route: '/extensions/ui-library/angular-ui',
+        tabIcon: 'star',
+        component: AngularUiComponent,
+    }),
+    registerPageTab({
+        location: 'angular-ui' as PageLocationId,
+        tab: 'Example Tab 2',
+        route: '/extensions/ui-library/angular-ui2',
+        tabIcon: 'star',
+        component: AngularUiComponent,
+    }),
+    registerPageTab({
+        location: 'react-ui' as PageLocationId,
+        tab: 'Example Tab 1',
+        route: '/extensions/ui-library/angular-ui',
+        tabIcon: 'star',
+        component: AngularUiComponent,
+    }),
+    registerPageTab({
+        location: 'react-ui' as PageLocationId,
+        tab: 'Example Tab 2',
+        route: '/extensions/ui-library/angular-ui2',
+        tabIcon: 'star',
+        component: AngularUiComponent,
+    }),
 ];

+ 13 - 1
packages/dev-server/example-plugins/ui-extensions-library/ui/routes.ts

@@ -9,10 +9,22 @@ export default [
         path: 'react-ui',
         component: ReactUi,
         title: 'React UI',
+        description: "Test description",
+        locationId: "react-ui"
     }),
     registerRouteComponent({
         path: 'angular-ui',
         component: AngularUiComponent,
         title: 'Angular UI',
+        locationId: "angular-ui",
+        description: "Test description 2"
     }),
-];
+    //Test page tabs on angular components
+    registerRouteComponent({
+        path: 'angular-ui2',
+        component: AngularUiComponent,
+        title: 'Angular UI 2',
+        locationId: "angular-ui",
+        description: "Test description 2"
+    })
+]