Browse Source

feat(admin-ui): Allow shared & lazy UI plugins to be specified

Relates to #55
Michael Bromley 6 years ago
parent
commit
5daf756d56

+ 2 - 0
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],

+ 1 - 1
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`,
             },
         ],
     },

+ 3 - 2
packages/admin-ui/src/app/extensions/extensions.module.ts → 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 {}

+ 13 - 0
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 {}

+ 41 - 39
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,

+ 31 - 28
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<AdminUiExtension>): strin
     return path.join(EXTENSIONS_DIR, EXTENSIONS_MODULES_DIR, extension.id);
 }
 
-export function createExtensionsModule(extensions: Array<Required<AdminUiExtension>>) {
+export function createExtensionsModules(extensions: Array<Required<AdminUiExtension>>) {
     const removeTsExtension = (filename: string): string => filename.replace(/\.ts$/, '');
     const importPath = (e: Required<AdminUiExtension>): 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 {}
 `;
 }

+ 2 - 2
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<Required
         restoreOriginalExtensionsModule();
         deleteExistingExtensionModules();
         copyExtensionModules(extensions);
-        createExtensionsModule(extensions);
+        createExtensionsModules(extensions);
 
         const config = isInVendureMonorepo() ? 'plugin-dev' : 'plugin';
         const buildProcess = spawn(

+ 4 - 4
packages/admin-ui/src/devkit/watch.ts

@@ -6,11 +6,11 @@ import * as path from 'path';
 
 import {
     copyExtensionModules,
-    createExtensionsModule,
+    createExtensionsModules,
     deleteExistingExtensionModules,
     getModuleOutputDir,
     isInVendureMonorepo,
-    restoreExtensionsModule,
+    restoreExtensionsModules,
     restoreOriginalExtensionsModule,
 } from './common';
 
@@ -25,10 +25,10 @@ export type Watcher = {
  */
 export function watchAdminUiApp(extensions: Array<Required<AdminUiExtension>>, 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}`], {

+ 2 - 0
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';

+ 2 - 1
packages/common/src/shared-types.ts

@@ -22,7 +22,7 @@ export type DeepRequired<T, U extends object | undefined = undefined> = T extend
     ? {
           [P in keyof T]-?: NonNullable<T[P]> extends NonNullable<U | Function | Type<any>>
               ? NonNullable<T[P]>
-              : DeepRequired<NonNullable<T[P]>, U>
+              : DeepRequired<NonNullable<T[P]>, 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;