From 5daf756d563aa9437ecc423a6e224b69f2a9221e Mon Sep 17 00:00:00 2001 From: Michael Bromley Date: Tue, 24 Sep 2019 16:14:04 +0200 Subject: [PATCH] feat(admin-ui): Allow shared & lazy UI plugins to be specified Relates to #55 --- packages/admin-ui/src/app/app.module.ts | 2 + packages/admin-ui/src/app/app.routes.ts | 2 +- ...ns.module.ts => lazy-extensions.module.ts} | 5 +- .../extensions/shared-extensions.module.ts | 13 +++ .../admin-ui/src/app/shared/shared.module.ts | 80 ++++++++++--------- packages/admin-ui/src/devkit/common.ts | 59 +++++++------- packages/admin-ui/src/devkit/compile.ts | 4 +- packages/admin-ui/src/devkit/watch.ts | 8 +- packages/admin-ui/src/index.ts | 2 + packages/common/src/shared-types.ts | 3 +- 10 files changed, 101 insertions(+), 77 deletions(-) rename packages/admin-ui/src/app/extensions/{extensions.module.ts => lazy-extensions.module.ts} (56%) create mode 100644 packages/admin-ui/src/app/extensions/shared-extensions.module.ts diff --git a/packages/admin-ui/src/app/app.module.ts b/packages/admin-ui/src/app/app.module.ts index 41d4b5e1b5..7a87ac7543 100644 --- a/packages/admin-ui/src/app/app.module.ts +++ b/packages/admin-ui/src/app/app.module.ts @@ -13,6 +13,7 @@ import { CoreModule } from './core/core.module'; import { CustomHttpTranslationLoader } from './core/providers/i18n/custom-http-loader'; import { I18nService } from './core/providers/i18n/i18n.service'; import { DataService } from './data/providers/data.service'; +import { SharedExtensionsModule } from './extensions/shared-extensions.module'; @Injectable() export class BaseHrefHolder { @@ -39,6 +40,7 @@ export function HttpLoaderFactory(http: HttpClient, location: PlatformLocation) compiler: { provide: TranslateCompiler, useClass: TranslateMessageFormatCompiler }, }), CoreModule, + SharedExtensionsModule, ], providers: [BaseHrefHolder], bootstrap: [AppComponent], diff --git a/packages/admin-ui/src/app/app.routes.ts b/packages/admin-ui/src/app/app.routes.ts index 5c0add96e8..8a348b14af 100644 --- a/packages/admin-ui/src/app/app.routes.ts +++ b/packages/admin-ui/src/app/app.routes.ts @@ -41,7 +41,7 @@ export const routes: Route[] = [ }, { path: 'extensions', - loadChildren: `./extensions/extensions.module#ExtensionsModule`, + loadChildren: `./extensions/lazy-extensions.module#LazyExtensionsModule`, }, ], }, diff --git a/packages/admin-ui/src/app/extensions/extensions.module.ts b/packages/admin-ui/src/app/extensions/lazy-extensions.module.ts similarity index 56% rename from packages/admin-ui/src/app/extensions/extensions.module.ts rename to packages/admin-ui/src/app/extensions/lazy-extensions.module.ts index d1c13c43c0..85d69d8838 100644 --- a/packages/admin-ui/src/app/extensions/extensions.module.ts +++ b/packages/admin-ui/src/app/extensions/lazy-extensions.module.ts @@ -1,12 +1,13 @@ +/** This file is generated by the createExtensionsModules() function in devkit/common.ts. Do not edit. */ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; /** * This is a placeholder module for UI extensions provided by the AdminUiPlugin `extensions` option. - * When the {@link compileUiExtensions} function is executed, this module gets temporarily replaced + * When the {@link createExtensionsModules} function is executed, this module gets temporarily replaced * by a generated module which includes all of the configured extension modules. */ @NgModule({ imports: [CommonModule], }) -export class ExtensionsModule {} +export class LazyExtensionsModule {} diff --git a/packages/admin-ui/src/app/extensions/shared-extensions.module.ts b/packages/admin-ui/src/app/extensions/shared-extensions.module.ts new file mode 100644 index 0000000000..09b86fa37c --- /dev/null +++ b/packages/admin-ui/src/app/extensions/shared-extensions.module.ts @@ -0,0 +1,13 @@ +/** This file is generated by the createExtensionsModules() function in devkit/common.ts. Do not edit. */ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; + +/** + * This is a placeholder module for UI extensions provided by the AdminUiPlugin `extensions` option. + * When the {@link createExtensionsModules} function is executed, this module gets temporarily replaced + * by a generated module which includes all of the configured extension modules. + */ +@NgModule({ + imports: [CommonModule], +}) +export class SharedExtensionsModule {} diff --git a/packages/admin-ui/src/app/shared/shared.module.ts b/packages/admin-ui/src/app/shared/shared.module.ts index 763e22d5df..cd93a0c35c 100644 --- a/packages/admin-ui/src/app/shared/shared.module.ts +++ b/packages/admin-ui/src/app/shared/shared.module.ts @@ -19,45 +19,47 @@ import { IfPermissionsDirective } from './directives/if-permissions.directive'; import { HasPermissionPipe } from './pipes/has-permission.pipe'; import { ModalService } from './providers/modal/modal.service'; import { CanDeactivateDetailGuard } from './providers/routing/can-deactivate-detail-guard'; -import { ChipComponent } from './shared-declarations'; -import { ConfigurableInputComponent } from './shared-declarations'; -import { CurrencyInputComponent } from './shared-declarations'; -import { CustomFieldControlComponent } from './shared-declarations'; -import { CustomerLabelComponent } from './shared-declarations'; -import { DataTableColumnComponent } from './shared-declarations'; -import { DataTableComponent } from './shared-declarations'; -import { DropdownItemDirective } from './shared-declarations'; -import { DropdownMenuComponent } from './shared-declarations'; -import { DropdownTriggerDirective } from './shared-declarations'; -import { DropdownComponent } from './shared-declarations'; -import { FacetValueChipComponent } from './shared-declarations'; -import { FacetValueSelectorComponent } from './shared-declarations'; -import { FormFieldControlDirective } from './shared-declarations'; -import { FormFieldComponent } from './shared-declarations'; -import { FormItemComponent } from './shared-declarations'; -import { AffixedInputComponent } from './shared-declarations'; -import { PercentageSuffixInputComponent } from './shared-declarations'; -import { LabeledDataComponent } from './shared-declarations'; -import { LanguageSelectorComponent } from './shared-declarations'; -import { DialogButtonsDirective } from './shared-declarations'; -import { DialogComponentOutletComponent } from './shared-declarations'; -import { DialogTitleDirective } from './shared-declarations'; -import { ModalDialogComponent } from './shared-declarations'; -import { ObjectTreeComponent } from './shared-declarations'; -import { OrderStateLabelComponent } from './shared-declarations'; -import { PaginationControlsComponent } from './shared-declarations'; -import { RichTextEditorComponent } from './shared-declarations'; -import { SelectToggleComponent } from './shared-declarations'; -import { SimpleDialogComponent } from './shared-declarations'; -import { TableRowActionComponent } from './shared-declarations'; -import { TitleInputComponent } from './shared-declarations'; -import { CurrencyNamePipe } from './shared-declarations'; -import { FileSizePipe } from './shared-declarations'; -import { SentenceCasePipe } from './shared-declarations'; -import { SortPipe } from './shared-declarations'; -import { StringToColorPipe } from './shared-declarations'; -import { FormattedAddressComponent } from './shared-declarations'; -import { ItemsPerPageControlsComponent } from './shared-declarations'; +import { + AffixedInputComponent, + ChipComponent, + ConfigurableInputComponent, + CurrencyInputComponent, + CurrencyNamePipe, + CustomerLabelComponent, + CustomFieldControlComponent, + DataTableColumnComponent, + DataTableComponent, + DialogButtonsDirective, + DialogComponentOutletComponent, + DialogTitleDirective, + DropdownComponent, + DropdownItemDirective, + DropdownMenuComponent, + DropdownTriggerDirective, + FacetValueChipComponent, + FacetValueSelectorComponent, + FileSizePipe, + FormattedAddressComponent, + FormFieldComponent, + FormFieldControlDirective, + FormItemComponent, + ItemsPerPageControlsComponent, + LabeledDataComponent, + LanguageSelectorComponent, + ModalDialogComponent, + ObjectTreeComponent, + OrderStateLabelComponent, + PaginationControlsComponent, + PercentageSuffixInputComponent, + RichTextEditorComponent, + SelectToggleComponent, + SentenceCasePipe, + SimpleDialogComponent, + SortPipe, + StringToColorPipe, + TableRowActionComponent, + TitleInputComponent, +} from './shared-declarations'; const IMPORTS = [ ClarityModule, diff --git a/packages/admin-ui/src/devkit/common.ts b/packages/admin-ui/src/devkit/common.ts index 3b7c91f5ad..c5c4b9ed15 100644 --- a/packages/admin-ui/src/devkit/common.ts +++ b/packages/admin-ui/src/devkit/common.ts @@ -4,8 +4,8 @@ import * as path from 'path'; const EXTENSIONS_DIR = path.join(__dirname, '../src/app/extensions'); const EXTENSIONS_MODULES_DIR = 'modules'; -const originalExtensionsModuleFile = path.join(EXTENSIONS_DIR, 'extensions.module.ts'); -const tempExtensionsModuleFile = path.join(EXTENSIONS_DIR, 'extensions.module.ts.temp'); +const lazyExtensionsModuleFile = path.join(EXTENSIONS_DIR, 'lazy-extensions.module.ts'); +const sharedExtensionsModuleFile = path.join(EXTENSIONS_DIR, 'shared-extensions.module.ts'); /** * Returns true if currently being executed from inside the Vendure monorepo. @@ -38,56 +38,59 @@ export function getModuleOutputDir(extension: Required): strin return path.join(EXTENSIONS_DIR, EXTENSIONS_MODULES_DIR, extension.id); } -export function createExtensionsModule(extensions: Array>) { +export function createExtensionsModules(extensions: Array>) { const removeTsExtension = (filename: string): string => filename.replace(/\.ts$/, ''); const importPath = (e: Required): string => `./${EXTENSIONS_MODULES_DIR}/${e.id}/${removeTsExtension(e.ngModuleFileName)}`; - fs.renameSync(originalExtensionsModuleFile, tempExtensionsModuleFile); - const source = generateExtensionModuleTsSource( - extensions.map(e => ({ className: e.ngModuleName, path: importPath(e) })), - ); - fs.writeFileSync(path.join(EXTENSIONS_DIR, 'extensions.module.ts'), source, 'utf-8'); + for (const type of ['lazy', 'shared'] as const) { + const source = generateExtensionModuleTsSource( + type, + extensions + .filter(e => e.type === type) + .map(e => ({ className: e.ngModuleName, path: importPath(e) })), + ); + const filePath = type === 'lazy' ? lazyExtensionsModuleFile : sharedExtensionsModuleFile; + fs.writeFileSync(filePath, source, 'utf-8'); + } } export function restoreOriginalExtensionsModule() { - fs.renameSync(originalExtensionsModuleFile, path.join(EXTENSIONS_DIR, 'extensions.module.ts.generated')); - restoreExtensionsModule(); + restoreExtensionsModules(); } /** * Restores the placeholder ExtensionsModule file from a template. */ -export function restoreExtensionsModule() { - const source = `import { CommonModule } from '@angular/common'; -import { NgModule } from '@angular/core'; - -/** - * This is a placeholder module for UI extensions provided by the AdminUiPlugin \`extensions\` option. - * When the {@link compileUiExtensions} function is executed, this module gets temporarily replaced - * by a generated module which includes all of the configured extension modules. - */ -@NgModule({ - imports: [CommonModule], -}) -export class ExtensionsModule {} -`; - fs.writeFileSync(originalExtensionsModuleFile, source, 'utf-8'); +export function restoreExtensionsModules() { + for (const type of ['lazy', 'shared'] as const) { + const source = generateExtensionModuleTsSource(type, []); + const filePath = type === 'lazy' ? lazyExtensionsModuleFile : sharedExtensionsModuleFile; + fs.writeFileSync(filePath, source, 'utf-8'); + } } -function generateExtensionModuleTsSource(modules: Array<{ className: string; path: string }>): string { - return `/** This file is generated by the build() function. Do not edit. */ +function generateExtensionModuleTsSource( + type: 'shared' | 'lazy', + modules: Array<{ className: string; path: string }>, +): string { + return `/** This file is generated by the createExtensionsModules() function in devkit/common.ts. Do not edit. */ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; ${modules.map(e => `import { ${e.className} } from '${e.path}';`).join('\n')} +/** + * This is a placeholder module for UI extensions provided by the AdminUiPlugin \`extensions\` option. + * When the {@link createExtensionsModules} function is executed, this module gets temporarily replaced + * by a generated module which includes all of the configured extension modules. + */ @NgModule({ imports: [ CommonModule, ${modules.map(e => e.className + ',').join('\n')} ], }) -export class ExtensionsModule {} +export class ${type === 'lazy' ? 'Lazy' : 'Shared'}ExtensionsModule {} `; } diff --git a/packages/admin-ui/src/devkit/compile.ts b/packages/admin-ui/src/devkit/compile.ts index ffa2bebc3d..a3f7fa4437 100644 --- a/packages/admin-ui/src/devkit/compile.ts +++ b/packages/admin-ui/src/devkit/compile.ts @@ -4,7 +4,7 @@ import * as path from 'path'; import { copyExtensionModules, - createExtensionsModule, + createExtensionsModules, deleteExistingExtensionModules, isInVendureMonorepo, restoreOriginalExtensionsModule, @@ -20,7 +20,7 @@ export function compileAdminUiApp(outputPath: string, extensions: Array>, port: number): Watcher { const cwd = path.join(__dirname, '..'); - restoreExtensionsModule(); + restoreExtensionsModules(); deleteExistingExtensionModules(); copyExtensionModules(extensions); - createExtensionsModule(extensions); + createExtensionsModules(extensions); const config = isInVendureMonorepo() ? 'plugin-dev' : 'plugin'; const buildProcess = spawn('yarn', ['ng', 'serve', `-c=${config}`, `--port=${port}`], { diff --git a/packages/admin-ui/src/index.ts b/packages/admin-ui/src/index.ts index 5beb0093ae..916f19d2f7 100644 --- a/packages/admin-ui/src/index.ts +++ b/packages/admin-ui/src/index.ts @@ -9,4 +9,6 @@ export { DataService } from './app/data/providers/data.service'; export { ServerConfigService } from './app/data/server-config'; export { ModalService } from './app/shared/providers/modal/modal.service'; export { SharedModule } from './app/shared/shared.module'; +export { NavBuilderService } from './app/core/providers/nav-builder/nav-builder.service'; +export * from './app/core/providers/nav-builder/nav-builder-types'; export * from './app/shared/shared-declarations'; diff --git a/packages/common/src/shared-types.ts b/packages/common/src/shared-types.ts index 7294336de0..4b82159205 100644 --- a/packages/common/src/shared-types.ts +++ b/packages/common/src/shared-types.ts @@ -22,7 +22,7 @@ export type DeepRequired = T extend ? { [P in keyof T]-?: NonNullable extends NonNullable> ? NonNullable - : DeepRequired, U> + : DeepRequired, U>; } : T; // tslint:enable:ban-types @@ -92,6 +92,7 @@ export interface AdminUiConfig { export interface AdminUiExtension { id?: string; + type: 'shared' | 'lazy'; ngModulePath: string; ngModuleFileName: string; ngModuleName: string;