Skip to content

Commit

Permalink
refactor(admin-ui): Co-locate ui extension code
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelbromley committed Sep 6, 2023
1 parent 97ba022 commit 5f26a1e
Show file tree
Hide file tree
Showing 27 changed files with 318 additions and 281 deletions.
2 changes: 1 addition & 1 deletion packages/admin-ui/src/lib/core/src/core.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { InjectableTranslateMessageFormatCompiler } from './providers/i18n/custo
import { I18nService } from './providers/i18n/i18n.service';
import { LocalStorageService } from './providers/local-storage/local-storage.service';
import { NotificationService } from './providers/notification/notification.service';
import { registerDefaultFormInputs } from './shared/dynamic-form-inputs/register-dynamic-input-components';
import { registerDefaultFormInputs } from './shared/dynamic-form-inputs/default-form-inputs';
import { SharedModule } from './shared/shared.module';

@NgModule({
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { APP_INITIALIZER, Provider } from '@angular/core';
import { ActionBarItem } from '../providers/nav-builder/nav-builder-types';
import { NavBuilderService } from '../providers/nav-builder/nav-builder.service';

/**
* @description
* Adds a button to the ActionBar at the top right of each list or detail view. The locationId can
* be determined by inspecting the DOM and finding the <vdr-action-bar> element and its
* `data-location-id` attribute.
*
* This should be used in the NgModule `providers` array of your ui extension module.
*
* @example
* ```TypeScript
* \@NgModule({
* imports: [SharedModule],
* providers: [
* addActionBarItem({
* id: 'print-invoice'
* label: 'Print Invoice',
* locationId: 'order-detail',
* routerLink: ['/extensions/invoicing'],
* }),
* ],
* })
* export class MyUiExtensionModule {}
* ```
* @docsCategory action-bar
*/
export function addActionBarItem(config: ActionBarItem): Provider {
return {
provide: APP_INITIALIZER,
multi: true,
useFactory: (navBuilderService: NavBuilderService) => () => {
navBuilderService.addActionBarItem(config);
},
deps: [NavBuilderService],
};
}
81 changes: 81 additions & 0 deletions packages/admin-ui/src/lib/core/src/extension/add-nav-menu-item.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { APP_INITIALIZER, Provider } from '@angular/core';
import { NavMenuItem, NavMenuSection } from '../providers/nav-builder/nav-builder-types';
import { NavBuilderService } from '../providers/nav-builder/nav-builder.service';

/**
* @description
* Add a section to the main nav menu. Providing the `before` argument will
* move the section before any existing section with the specified id. If
* omitted (or if the id is not found) the section will be appended to the
* existing set of sections.
* This should be used in the NgModule `providers` array of your ui extension module.
*
* @example
* ```TypeScript
* \@NgModule({
* imports: [SharedModule],
* providers: [
* addNavMenuSection({
* id: 'reports',
* label: 'Reports',
* items: [{
* // ...
* }],
* },
* 'settings'),
* ],
* })
* export class MyUiExtensionModule {}
* ```
* @docsCategory nav-menu
*/
export function addNavMenuSection(config: NavMenuSection, before?: string): Provider {
return {
provide: APP_INITIALIZER,
multi: true,
useFactory: (navBuilderService: NavBuilderService) => () => {
navBuilderService.addNavMenuSection(config, before);
},
deps: [NavBuilderService],
};
}

/**
* @description
* Add a menu item to an existing section specified by `sectionId`. The id of the section
* can be found by inspecting the DOM and finding the `data-section-id` attribute.
* Providing the `before` argument will move the item before any existing item with the specified id.
* If omitted (or if the name is not found) the item will be appended to the
* end of the section.
*
* This should be used in the NgModule `providers` array of your ui extension module.
*
* @example
* ```TypeScript
* \@NgModule({
* imports: [SharedModule],
* providers: [
* addNavMenuItem({
* id: 'reviews',
* label: 'Product Reviews',
* routerLink: ['/extensions/reviews'],
* icon: 'star',
* },
* 'marketing'),
* ],
* })
* export class MyUiExtensionModule {}
* ``
*
* @docsCategory nav-menu
*/
export function addNavMenuItem(config: NavMenuItem, sectionId: string, before?: string): Provider {
return {
provide: APP_INITIALIZER,
multi: true,
useFactory: (navBuilderService: NavBuilderService) => () => {
navBuilderService.addNavMenuItem(config, sectionId, before);
},
deps: [NavBuilderService],
};
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { APP_INITIALIZER, FactoryProvider } from '@angular/core';

import { BulkActionRegistryService } from './bulk-action-registry.service';
import { BulkAction } from './bulk-action-types';
import { BulkActionRegistryService } from '../providers/bulk-action-registry/bulk-action-registry.service';
import { BulkAction } from '../providers/bulk-action-registry/bulk-action-types';

/**
* @description
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { APP_INITIALIZER, Provider } from '@angular/core';
import { CustomDetailComponentConfig } from '../providers/custom-detail-component/custom-detail-component-types';
import { CustomDetailComponentService } from '../providers/custom-detail-component/custom-detail-component.service';

/**
* @description
* Registers a {@link CustomDetailComponent} to be placed in a given location. This allows you
* to embed any type of custom Angular component in the entity detail pages of the Admin UI.
*
* @docsCategory custom-detail-components
*/
export function registerCustomDetailComponent(config: CustomDetailComponentConfig): Provider {
return {
provide: APP_INITIALIZER,
multi: true,
useFactory: (customDetailComponentService: CustomDetailComponentService) => () => {
customDetailComponentService.registerCustomDetailComponent(config);
},
deps: [CustomDetailComponentService],
};
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import { APP_INITIALIZER, FactoryProvider } from '@angular/core';

import { DashboardWidgetConfig, WidgetLayoutDefinition } from './dashboard-widget-types';
import { DashboardWidgetService } from './dashboard-widget.service';
import {
DashboardWidgetConfig,
WidgetLayoutDefinition,
} from '../providers/dashboard-widget/dashboard-widget-types';
import { DashboardWidgetService } from '../providers/dashboard-widget/dashboard-widget.service';

/**
* @description
* Registers a dashboard widget. Once registered, the widget can be set as part of the default
* (using {@link setDashboardWidgetLayout}).
*
* @docsCategory dashboard-widgets
*/
export function registerDashboardWidget(id: string, config: DashboardWidgetConfig): FactoryProvider {
return {
Expand All @@ -22,6 +27,8 @@ export function registerDashboardWidget(id: string, config: DashboardWidgetConfi
/**
* @description
* Sets the default widget layout for the Admin UI dashboard.
*
* @docsCategory dashboard-widgets
*/
export function setDashboardWidgetLayout(layoutDef: WidgetLayoutDefinition): FactoryProvider {
return {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { APP_INITIALIZER, FactoryProvider, Type } from '@angular/core';
import { FormInputComponent } from '../common/component-registry-types';
import { ComponentRegistryService } from '../providers/component-registry/component-registry.service';

/**
* @description
* Registers a custom FormInputComponent which can be used to control the argument inputs
* of a {@link ConfigurableOperationDef} (e.g. CollectionFilter, ShippingMethod etc) or for
* a custom field.
*
* @example
* ```TypeScript
* \@NgModule({
* imports: [SharedModule],
* declarations: [MyCustomFieldControl],
* providers: [
* registerFormInputComponent('my-custom-input', MyCustomFieldControl),
* ],
* })
* export class MyUiExtensionModule {}
* ```
*
* This input component can then be used in a custom field:
*
* @example
* ```TypeScript
* const config = {
* // ...
* customFields: {
* ProductVariant: [
* {
* name: 'rrp',
* type: 'int',
* ui: { component: 'my-custom-input' },
* },
* ]
* }
* }
* ```
*
* or with an argument of a {@link ConfigurableOperationDef}:
*
* @example
* ```TypeScript
* args: {
* rrp: { type: 'int', ui: { component: 'my-custom-input' } },
* }
* ```
*
* @docsCategory custom-input-components
*/
export function registerFormInputComponent(id: string, component: Type<FormInputComponent>): FactoryProvider {
return {
provide: APP_INITIALIZER,
multi: true,
useFactory: (registry: ComponentRegistryService) => () => {
registry.registerInputComponent(id, component);
},
deps: [ComponentRegistryService],
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { APP_INITIALIZER, Provider } from '@angular/core';
import { HistoryEntryConfig } from '../providers/custom-history-entry-component/history-entry-component-types';
import { HistoryEntryComponentService } from '../providers/custom-history-entry-component/history-entry-component.service';

/**
* @description
* Registers a {@link HistoryEntryComponent} for displaying history entries in the Order/Customer
* history timeline.
*
* @since 1.9.0
* @docsCategory custom-history-entry-components
*/
export function registerHistoryEntryComponent(config: HistoryEntryConfig): Provider {
return {
provide: APP_INITIALIZER,
multi: true,
useFactory: (customHistoryEntryComponentService: HistoryEntryComponentService) => () => {
customHistoryEntryComponentService.registerComponent(config);
},
deps: [HistoryEntryComponentService],
};
}
Original file line number Diff line number Diff line change
@@ -1,25 +1,7 @@
import { APP_INITIALIZER, Injectable, Provider } from '@angular/core';
import { Injectable } from '@angular/core';

import { CustomDetailComponentConfig } from './custom-detail-component-types';

/**
* @description
* Registers a {@link CustomDetailComponent} to be placed in a given location. This allows you
* to embed any type of custom Angular component in the entity detail pages of the Admin UI.
*
* @docsCategory custom-detail-components
*/
export function registerCustomDetailComponent(config: CustomDetailComponentConfig): Provider {
return {
provide: APP_INITIALIZER,
multi: true,
useFactory: (customDetailComponentService: CustomDetailComponentService) => () => {
customDetailComponentService.registerCustomDetailComponent(config);
},
deps: [CustomDetailComponentService],
};
}

@Injectable({
providedIn: 'root',
})
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,7 @@
import { APP_INITIALIZER, Injectable, Provider, Type } from '@angular/core';
import { Injectable, Type } from '@angular/core';

import { HistoryEntryComponent, HistoryEntryConfig } from './history-entry-component-types';

/**
* @description
* Registers a {@link HistoryEntryComponent} for displaying history entries in the Order/Customer
* history timeline.
*
* @since 1.9.0
* @docsCategory custom-history-entry-components
*/
export function registerHistoryEntryComponent(config: HistoryEntryConfig): Provider {
return {
provide: APP_INITIALIZER,
multi: true,
useFactory: (customHistoryEntryComponentService: HistoryEntryComponentService) => () => {
customHistoryEntryComponentService.registerComponent(config);
},
deps: [HistoryEntryComponentService],
};
}

@Injectable({
providedIn: 'root',
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,18 @@ import { Type } from '@angular/core';

export type DashboardWidgetWidth = 3 | 4 | 6 | 8 | 12;

/**
* @description
* A configuration object for a dashboard widget.
*
* @docsCategory dashboard-widgets
*/
export interface DashboardWidgetConfig {
/**
* @description
* Used to specify the widget component. Supports both eager- and lazy-loading.
* @example
* ```TypeScript
* ```ts
* // eager-loading
* loadComponent: () => MyWidgetComponent,
*
Expand All @@ -16,22 +23,31 @@ export interface DashboardWidgetConfig {
*/
loadComponent: () => Promise<Type<any>> | Type<any>;
/**
* @description
* The title of the widget. Can be a translation token as it will get passed
* through the `translate` pipe.
*/
title?: string;
/**
* @description
* The supported widths of the widget, in terms of a Bootstrap-style 12-column grid.
* If omitted, then it is assumed the widget supports all widths.
*/
supportedWidths?: DashboardWidgetWidth[];
/**
* @description
* If set, the widget will only be displayed if the current user has all the
* specified permissions.
*/
requiresPermissions?: string[];
}

/**
* @description
* A configuration object for the default dashboard widget layout.
*
* @docsCategory dashboard-widgets
*/
export type WidgetLayoutDefinition = Array<{ id: string; width: DashboardWidgetWidth }>;
export type WidgetLayout = Array<
Array<{ id: string; config: DashboardWidgetConfig; width: DashboardWidgetWidth }>
Expand Down
Loading

0 comments on commit 5f26a1e

Please sign in to comment.