From 20e1bc48b36b8da14cc7d99b7645130a03e33e37 Mon Sep 17 00:00:00 2001 From: Wroud Date: Fri, 9 Oct 2020 03:22:47 +0300 Subject: [PATCH] feat(plugin-administration): CB-340 server configuration page --- .../AdministrationScreenService.ts | 6 +- .../ConnectionsAdministrationService.ts | 2 +- ...onfigurationWizardPagesBootstrapService.ts | 3 +- .../ServerConfigurationForm.tsx | 100 ++++++++------- .../ServerConfigurationPage.tsx | 16 ++- .../ServerConfigurationPageController.ts | 17 ++- .../ServerConfigurationService.ts | 119 +++++++++++++----- .../Users/UsersAdministrationService.ts | 2 +- 8 files changed, 177 insertions(+), 88 deletions(-) diff --git a/webapp/packages/core-administration/src/AdministrationScreen/AdministrationScreenService.ts b/webapp/packages/core-administration/src/AdministrationScreen/AdministrationScreenService.ts index 8d9de1b794..72d194fa9c 100644 --- a/webapp/packages/core-administration/src/AdministrationScreen/AdministrationScreenService.ts +++ b/webapp/packages/core-administration/src/AdministrationScreen/AdministrationScreenService.ts @@ -115,9 +115,9 @@ export class AdministrationScreenService { } getItemState(name: string): T | undefined - getItemState(name: string, defaultState: () => T): T - getItemState(name: string, defaultState?: () => T): T | undefined { - if (!this.itemState.has(name) && defaultState) { + getItemState(name: string, defaultState: () => T, update?: boolean): T + getItemState(name: string, defaultState?: () => T, update?: boolean): T | undefined { + if ((!this.itemState.has(name) || update) && defaultState) { this.itemState.set(name, defaultState()); } diff --git a/webapp/packages/core-connections/src/Administration/Connections/ConnectionsAdministrationService.ts b/webapp/packages/core-connections/src/Administration/Connections/ConnectionsAdministrationService.ts index 1f379929a1..f6e7305e59 100644 --- a/webapp/packages/core-connections/src/Administration/Connections/ConnectionsAdministrationService.ts +++ b/webapp/packages/core-connections/src/Administration/Connections/ConnectionsAdministrationService.ts @@ -31,7 +31,7 @@ export class ConnectionsAdministrationService extends Bootstrap { this.administrationItemService.create({ name: 'connections', type: AdministrationItemType.Default, - order: 2, + order: 3, configurationWizardOptions: { defaultRoute: { sub: 'create', param: 'search-database' }, description: 'connections_administration_configuration_wizard_step_description', diff --git a/webapp/packages/plugin-administration/src/ConfigurationWizard/ConfigurationWizardPagesBootstrapService.ts b/webapp/packages/plugin-administration/src/ConfigurationWizard/ConfigurationWizardPagesBootstrapService.ts index fe498e1a19..48d35503f6 100644 --- a/webapp/packages/plugin-administration/src/ConfigurationWizard/ConfigurationWizardPagesBootstrapService.ts +++ b/webapp/packages/plugin-administration/src/ConfigurationWizard/ConfigurationWizardPagesBootstrapService.ts @@ -40,7 +40,7 @@ export class ConfigurationWizardPagesBootstrapService extends Bootstrap { }); this.administrationItemService.create({ name: 'configuration', - type: AdministrationItemType.ConfigurationWizard, + type: AdministrationItemType.Default, configurationWizardOptions: { description: 'administration_configuration_wizard_configuration_step_description', isDone: this.serverConfigurationService.isDone.bind(this.serverConfigurationService), @@ -48,6 +48,7 @@ export class ConfigurationWizardPagesBootstrapService extends Bootstrap { onConfigurationFinish: this.serverConfigurationService.apply.bind(this.serverConfigurationService), }, order: 1.1, + onActivate: this.serverConfigurationService.loadConfig.bind(this.serverConfigurationService), getContentComponent: () => ServerConfigurationPage, getDrawerComponent: () => ServerConfigurationDrawerItem, }); diff --git a/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/ServerConfigurationForm.tsx b/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/ServerConfigurationForm.tsx index 0ffa919718..315c601a63 100644 --- a/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/ServerConfigurationForm.tsx +++ b/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/ServerConfigurationForm.tsx @@ -7,19 +7,17 @@ */ import { observer } from 'mobx-react'; -import { useEffect } from 'react'; +import { useCallback, useEffect } from 'react'; import styled, { css } from 'reshadow'; import { - SubmittingForm, InputGroup, InputField, useFocus, Switch + SubmittingForm, InputGroup, InputField, useFocus, Switch, Button } from '@cloudbeaver/core-blocks'; -import { useService } from '@cloudbeaver/core-di'; +import { IExecutor } from '@cloudbeaver/core-executor'; import { useTranslate } from '@cloudbeaver/core-localization'; import { ServerConfigInput } from '@cloudbeaver/core-sdk'; import { useStyles } from '@cloudbeaver/core-theming'; -import { ServerConfigurationService } from './ServerConfigurationService'; - export const formStyles = css` SubmittingForm { flex: 1; @@ -31,6 +29,11 @@ export const formStyles = css` box-sizing: border-box; display: flex; } + Button { + margin: 12px; + margin-left: 24px; + float: right; + } `; const boxStyles = css` @@ -46,31 +49,38 @@ const boxStyles = css` interface Props { serverConfig: ServerConfigInput; + validationTask?: IExecutor; + editing?: boolean; onChange: () => void; - onSave: () => void; + onSubmit: () => void; } export const ServerConfigurationForm = observer(function ServerConfigurationForm({ serverConfig, + validationTask, + editing, onChange, - onSave, + onSubmit, }: Props) { - const service = useService(ServerConfigurationService); const translate = useTranslate(); const [focusedRef] = useFocus({ focusFirstChild: true }); - useEffect(() => { - const validate = () => { - focusedRef.current?.checkValidity(); - focusedRef.current?.reportValidity(); - }; - service.validationTask.addHandler(validate); + const validate = useCallback(() => { + focusedRef.current?.checkValidity(); + focusedRef.current?.reportValidity(); + }, []); - return () => service.validationTask.removeHandler(validate); - }, [service]); + useEffect(() => { + if (!validationTask) { + return; + } + validationTask.addHandler(validate); + + return () => validationTask.removeHandler(validate); + }, [validationTask]); return styled(useStyles(formStyles, boxStyles))( - + @@ -88,31 +98,37 @@ export const ServerConfigurationForm = observer(function ServerConfigurationForm {translate('administration_configuration_wizard_configuration_server_name')} - - {translate('administration_configuration_wizard_configuration_admin')} - - - {translate('administration_configuration_wizard_configuration_admin_name')} - - - {translate('administration_configuration_wizard_configuration_admin_password')} - + {editing + ? + : ( + <> + + {translate('administration_configuration_wizard_configuration_admin')} + + + {translate('administration_configuration_wizard_configuration_admin_name')} + + + {translate('administration_configuration_wizard_configuration_admin_password')} + + + )} diff --git a/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/ServerConfigurationPage.tsx b/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/ServerConfigurationPage.tsx index f30cb4c8ac..697f099fd6 100644 --- a/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/ServerConfigurationPage.tsx +++ b/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/ServerConfigurationPage.tsx @@ -9,12 +9,13 @@ import { observer } from 'mobx-react'; import styled, { use, css } from 'reshadow'; -import { useController } from '@cloudbeaver/core-di'; +import { useController, useService } from '@cloudbeaver/core-di'; import { useTranslate } from '@cloudbeaver/core-localization'; import { useStyles, composes } from '@cloudbeaver/core-theming'; import { ServerConfigurationForm } from './ServerConfigurationForm'; import { ServerConfigurationPageController } from './ServerConfigurationPageController'; +import { ServerConfigurationService } from './ServerConfigurationService'; const styles = composes( css` @@ -50,18 +51,25 @@ const styles = composes( export const ServerConfigurationPage = observer(function ServerConfigurationPage() { const translate = useTranslate(); + const service = useService(ServerConfigurationService); const controller = useController(ServerConfigurationPageController); return styled(useStyles(styles))( -

{translate('administration_configuration_wizard_configuration_title')}

-

{translate('administration_configuration_wizard_configuration_message')}

+ {!controller.editing && ( + <> +

{translate('administration_configuration_wizard_configuration_title')}

+

{translate('administration_configuration_wizard_configuration_message')}

+ + )}
diff --git a/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/ServerConfigurationPageController.ts b/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/ServerConfigurationPageController.ts index f2a9acbda8..1f4866a96d 100644 --- a/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/ServerConfigurationPageController.ts +++ b/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/ServerConfigurationPageController.ts @@ -6,7 +6,7 @@ * you may not use this file except in compliance with the License. */ -import { ConfigurationWizardService } from '@cloudbeaver/core-administration'; +import { AdministrationScreenService, ConfigurationWizardService } from '@cloudbeaver/core-administration'; import { injectable } from '@cloudbeaver/core-di'; import { IServerConfigurationPageState } from './IServerConfigurationPageState'; @@ -18,9 +18,14 @@ export class ServerConfigurationPageController { return this.serverConfigurationService.state; } + get editing(): boolean { + return !this.administrationScreenService.isConfigurationMode; + } + constructor( private readonly configurationWizardService: ConfigurationWizardService, private readonly serverConfigurationService: ServerConfigurationService, + private readonly administrationScreenService: AdministrationScreenService, ) { } @@ -30,5 +35,13 @@ export class ServerConfigurationPageController { } }; - finish = async (): Promise => await this.configurationWizardService.next(); + finish = async (): Promise => { + if (this.administrationScreenService.isConfigurationMode) { + await this.configurationWizardService.next(); + } else { + if (this.serverConfigurationService.validate()) { + await this.serverConfigurationService.apply(); + } + } + }; } diff --git a/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/ServerConfigurationService.ts b/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/ServerConfigurationService.ts index b2254bb318..2ee2617602 100644 --- a/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/ServerConfigurationService.ts +++ b/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/ServerConfigurationService.ts @@ -11,7 +11,8 @@ import { UsersResource } from '@cloudbeaver/core-authentication'; import { injectable } from '@cloudbeaver/core-di'; import { NotificationService } from '@cloudbeaver/core-events'; import { IExecutor, Executor } from '@cloudbeaver/core-executor'; -import { GraphQLService } from '@cloudbeaver/core-sdk'; +import { ServerConfigResource } from '@cloudbeaver/core-root'; +import { GraphQLService, ServerConfig } from '@cloudbeaver/core-sdk'; import { IServerConfigurationPageState } from './IServerConfigurationPageState'; @@ -23,37 +24,35 @@ export interface IValidationStatusContext { @injectable() export class ServerConfigurationService { - readonly state: IServerConfigurationPageState; + state: IServerConfigurationPageState; readonly validationTask: IExecutor; constructor( - private administrationScreenService: AdministrationScreenService, - private graphQLService: GraphQLService, - private notificationService: NotificationService, - private usersResource: UsersResource + private readonly administrationScreenService: AdministrationScreenService, + private readonly serverConfigResource: ServerConfigResource, + private readonly graphQLService: GraphQLService, + private readonly notificationService: NotificationService, + private readonly usersResource: UsersResource ) { - this.state = this.administrationScreenService.getItemState('welcome', () => ({ - serverConfig: { - serverName: 'CloudBeaver', - adminName: 'cbadmin', - adminPassword: '', - anonymousAccessEnabled: true, - authenticationEnabled: false, - customConnectionsEnabled: false, - }, - navigatorConfig: { - hideFolders: false, - hideSchemas: false, - hideVirtualModel: false, - mergeEntities: false, - showOnlyEntities: false, - showSystemObjects: false, - showUtilityObjects: false, - }, - })); + this.state = this.administrationScreenService + .getItemState( + 'server-configuration', + () => this.getConfig(), + ); this.validationTask = new Executor(); } + async loadConfig() { + const config = await this.serverConfigResource.load(null); + + this.state = this.administrationScreenService + .getItemState( + 'server-configuration', + () => this.getConfig(config), + !config?.configurationMode + ); + } + isDone(): boolean { return this.isFormFilled(); } @@ -79,15 +78,6 @@ export class ServerConfigurationService { }; }; - private isFormFilled() { - return !!( - this.state?.serverConfig.serverName - && this.state.serverConfig.adminName - && this.state.serverConfig.adminName.length > 5 - && this.state.serverConfig.adminPassword - ); - } - async apply(): Promise { if (!this.state) { throw new Error('No state available'); @@ -96,6 +86,10 @@ export class ServerConfigurationService { try { await this.graphQLService.sdk.setDefaultNavigatorSettings({ settings: this.state.navigatorConfig }); await this.graphQLService.sdk.configureServer({ configuration: this.state.serverConfig }); + + if (!this.serverConfigResource.data?.configurationMode) { + await this.serverConfigResource.refresh(null); + } this.usersResource.refreshAllLazy(); } catch (exception) { this.notificationService.logException(exception, 'Can\'t save server configuration'); @@ -104,4 +98,61 @@ export class ServerConfigurationService { } } + private isFormFilled() { + if (!this.state?.serverConfig.serverName) { + return false; + } + if (this.administrationScreenService.isConfigurationMode) { + if (!this.state.serverConfig.adminName + || this.state.serverConfig.adminName.length < 6 + || !this.state.serverConfig.adminPassword + ) { + return false; + } + } + return true; + } + + private getConfig(config?: ServerConfig | null): IServerConfigurationPageState { + if (!config || config?.configurationMode) { + return { + serverConfig: { + serverName: 'CloudBeaver', + adminName: 'cbadmin', + adminPassword: '', + anonymousAccessEnabled: true, + authenticationEnabled: false, + customConnectionsEnabled: false, + }, + navigatorConfig: { + hideFolders: false, + hideSchemas: false, + hideVirtualModel: false, + mergeEntities: false, + showOnlyEntities: false, + showSystemObjects: false, + showUtilityObjects: false, + }, + }; + } + + return { + serverConfig: { + serverName: config.name, + anonymousAccessEnabled: config.anonymousAccessEnabled, + authenticationEnabled: config.authenticationEnabled, + customConnectionsEnabled: config.supportsCustomConnections, + }, + navigatorConfig: { + hideFolders: false, + hideSchemas: false, + hideVirtualModel: false, + mergeEntities: false, + showOnlyEntities: false, + showSystemObjects: false, + showUtilityObjects: false, + }, + }; + } + } diff --git a/webapp/packages/plugin-authentication/src/Administration/Users/UsersAdministrationService.ts b/webapp/packages/plugin-authentication/src/Administration/Users/UsersAdministrationService.ts index 33fe5b0840..31b4d3f453 100644 --- a/webapp/packages/plugin-authentication/src/Administration/Users/UsersAdministrationService.ts +++ b/webapp/packages/plugin-authentication/src/Administration/Users/UsersAdministrationService.ts @@ -28,7 +28,7 @@ export class UsersAdministrationService extends Bootstrap { register() { this.administrationItemService.create({ name: UsersAdministrationNavigationService.ItemName, - order: 1, + order: 2, sub: [ { name: UsersAdministrationNavigationService.AddItemName,