From db3bce33a054f0aff6703e4fb9968d7c3779ce0f Mon Sep 17 00:00:00 2001 From: Michael Bromley Date: Mon, 23 Mar 2020 13:05:18 +0100 Subject: [PATCH] feat(admin-ui-plugin): Allow ui languages to be set in the AdminUiPlugin Relates to #264 --- packages/admin-ui-plugin/src/plugin.ts | 91 +++++++++++++++++--------- packages/common/src/shared-types.ts | 58 +++++++++++++++- 2 files changed, 116 insertions(+), 33 deletions(-) diff --git a/packages/admin-ui-plugin/src/plugin.ts b/packages/admin-ui-plugin/src/plugin.ts index 4fdd4aa249..cbbd3f0ae5 100644 --- a/packages/admin-ui-plugin/src/plugin.ts +++ b/packages/admin-ui-plugin/src/plugin.ts @@ -6,9 +6,9 @@ import { Type, } from '@vendure/common/lib/shared-types'; import { - AuthOptions, ConfigService, createProxyHandler, + LanguageCode, Logger, OnVendureBootstrap, OnVendureClose, @@ -29,7 +29,7 @@ import { DEFAULT_APP_PATH, loggerCtx } from './constants'; * * @docsCategory AdminUiPlugin */ -export interface AdminUiOptions { +export interface AdminUiPluginOptions { /** * @description * The port on which the server will listen. If not @@ -55,6 +55,7 @@ export interface AdminUiOptions { * to. If set to "auto", the admin ui app will determine the hostname from the * current location (i.e. `window.location.hostname`). * + * @deprecated Use the adminUiConfig property instead * @default 'auto' */ apiHost?: string | 'auto'; @@ -64,9 +65,16 @@ export interface AdminUiOptions { * to. If set to "auto", the admin ui app will determine the port from the * current location (i.e. `window.location.port`). * + * @deprecated Use the adminUiConfig property instead * @default 'auto' */ apiPort?: number | 'auto'; + /** + * @description + * Allows the contents of the `vendure-ui-config.json` file to be set, e.g. + * for specifying the Vendure GraphQL API host, available UI languages, etc. + */ + adminUiConfig?: Partial; } /** @@ -104,7 +112,7 @@ export interface AdminUiOptions { configuration: config => AdminUiPlugin.configure(config), }) export class AdminUiPlugin implements OnVendureBootstrap, OnVendureClose { - private static options: AdminUiOptions; + private static options: AdminUiPluginOptions; private server: Server; constructor(private configService: ConfigService) {} @@ -113,7 +121,7 @@ export class AdminUiPlugin implements OnVendureBootstrap, OnVendureClose { * @description * Set the plugin options */ - static init(options: AdminUiOptions): Type { + static init(options: AdminUiPluginOptions): Type { this.options = options; return AdminUiPlugin; } @@ -156,20 +164,27 @@ export class AdminUiPlugin implements OnVendureBootstrap, OnVendureClose { /** @internal */ async onVendureBootstrap() { - const { adminApiPath, authOptions } = this.configService; - const { apiHost, apiPort, port, app } = AdminUiPlugin.options; + const { apiHost, apiPort, port, app, adminUiConfig } = AdminUiPlugin.options; + // TODO: Remove in next minor version (0.11.0) + if (apiHost || apiPort) { + Logger.warn( + `The "apiHost" and "apiPort" options are deprecated and will be removed in a future version.`, + loggerCtx, + ); + Logger.warn( + `Use the "adminUiConfig.apiHost", "adminUiConfig.apiPort" properties instead.`, + loggerCtx, + ); + } const adminUiAppPath = AdminUiPlugin.isDevModeApp(app) ? path.join(app.sourcePath, 'src') : (app && app.path) || DEFAULT_APP_PATH; const adminUiConfigPath = path.join(adminUiAppPath, 'vendure-ui-config.json'); - const overwriteConfig = () => - this.overwriteAdminUiConfig({ - host: apiHost || 'auto', - port: apiPort || 'auto', - adminApiPath, - authOptions, - adminUiConfigPath, - }); + + const overwriteConfig = () => { + const uiConfig = this.getAdminUiConfig(adminUiConfig); + return this.overwriteAdminUiConfig(adminUiConfigPath, uiConfig); + }; if (!AdminUiPlugin.isDevModeApp(app)) { // If not in dev mode, start a static server for the compiled app @@ -215,19 +230,38 @@ export class AdminUiPlugin implements OnVendureBootstrap, OnVendureClose { } } + /** + * Takes an optional AdminUiConfig provided in the plugin options, and returns a complete + * config object for writing to disk. + */ + private getAdminUiConfig(partialConfig?: Partial): AdminUiConfig { + const { authOptions } = this.configService; + + const propOrDefault = ( + prop: Prop, + defaultVal: AdminUiConfig[Prop], + ): AdminUiConfig[Prop] => { + return partialConfig ? (partialConfig as AdminUiConfig)[prop] || defaultVal : defaultVal; + }; + return { + adminApiPath: propOrDefault('adminApiPath', this.configService.adminApiPath), + apiHost: propOrDefault('apiHost', AdminUiPlugin.options.apiHost || 'http://localhost'), + apiPort: propOrDefault('apiPort', AdminUiPlugin.options.apiPort || this.configService.port), + tokenMethod: propOrDefault('tokenMethod', authOptions.tokenMethod || 'cookie'), + authTokenHeaderKey: propOrDefault( + 'authTokenHeaderKey', + authOptions.authTokenHeaderKey || DEFAULT_AUTH_TOKEN_HEADER_KEY, + ), + defaultLanguage: propOrDefault('defaultLanguage', LanguageCode.en), + availableLanguages: propOrDefault('availableLanguages', [LanguageCode.en, LanguageCode.es]), + }; + } + /** * Overwrites the parts of the admin-ui app's `vendure-ui-config.json` file relating to connecting to * the server admin API. */ - private async overwriteAdminUiConfig(options: { - host: string | 'auto'; - port: number | 'auto'; - adminApiPath: string; - authOptions: AuthOptions; - adminUiConfigPath: string; - }) { - const { host, port, adminApiPath, authOptions, adminUiConfigPath } = options; - + private async overwriteAdminUiConfig(adminUiConfigPath: string, config: AdminUiConfig) { /** * It might be that the ui-devkit compiler has not yet copied the config * file to the expected location (perticularly when running in watch mode), @@ -258,18 +292,11 @@ export class AdminUiPlugin implements OnVendureBootstrap, OnVendureClose { } const content = await pollForConfigFile(); - let config: AdminUiConfig; try { - config = JSON.parse(content); + await fs.writeFile(adminUiConfigPath, JSON.stringify(config, null, 2)); } catch (e) { - throw new Error('[AdminUiPlugin] Could not parse vendure-ui-config.json file:\n' + e.message); + throw new Error('[AdminUiPlugin] Could not write vendure-ui-config.json file:\n' + e.message); } - config.apiHost = host || 'http://localhost'; - config.apiPort = port; - config.adminApiPath = adminApiPath; - config.tokenMethod = authOptions.tokenMethod || 'cookie'; - config.authTokenHeaderKey = authOptions.authTokenHeaderKey || DEFAULT_AUTH_TOKEN_HEADER_KEY; - await fs.writeFile(adminUiConfigPath, JSON.stringify(config, null, 2)); Logger.verbose(`Applied configuration to vendure-ui-config.json file`, loggerCtx); } diff --git a/packages/common/src/shared-types.ts b/packages/common/src/shared-types.ts index 33a9f529bb..5c9656ada3 100644 --- a/packages/common/src/shared-types.ts +++ b/packages/common/src/shared-types.ts @@ -97,15 +97,71 @@ export type ConfigArgSubset = T; export type CustomFieldsObject = { [key: string]: any }; /** - * This interface describes the shape of the JSON config file used by the Admin UI. + * @description + * This interface describes JSON config file (vendure-ui-config.json) used by the Admin UI. + * The values are loaded at run-time by the Admin UI app, and allow core configuration to be + * managed without the need to re-build the application. + * + * @docsCategory AdminUiPlugin */ export interface AdminUiConfig { + /** + * @description + * The hostname of the Vendure server which the admin ui will be making API calls + * to. If set to "auto", the Admin UI app will determine the hostname from the + * current location (i.e. `window.location.hostname`). + * + * @default 'http://localhost' + */ apiHost: string | 'auto'; + /** + * @description + * The port of the Vendure server which the admin ui will be making API calls + * to. If set to "auto", the Admin UI app will determine the port from the + * current location (i.e. `window.location.port`). + * + * @default 3000 + */ apiPort: number | 'auto'; + /** + * @description + * The path to the GraphQL Admin API. + * + * @default 'admin-api' + */ adminApiPath: string; + /** + * @description + * Whether to use cookies or bearer tokens to track sessions. + * Should match the setting of in the server's `tokenMethod` config + * option. + * + * @default 'cookie' + */ tokenMethod: 'cookie' | 'bearer'; + /** + * @description + * The header used when using the 'bearer' auth method. Should match the + * setting of the server's `authOptions.authTokenHeaderKey` config + * option. + * + * @default 'vendure-auth-token' + */ authTokenHeaderKey: string; + /** + * @description + * The default language for the Admin UI. Must be one of the + * items specified in the `availableLanguages` property. + * + * @default LanguageCode.en + */ defaultLanguage: LanguageCode; + /** + * @description + * An array of languages for which translations exist for the Admin UI. + * + * @default [LanguageCode.en, LanguageCode.es] + */ availableLanguages: LanguageCode[]; }