diff --git a/webapp/packages/plugin-administration/src/ConfigurationWizard/ConfigurationWizardPagesBootstrapService.ts b/webapp/packages/plugin-administration/src/ConfigurationWizard/ConfigurationWizardPagesBootstrapService.ts index cd0ef5c754..6bf0f8c170 100644 --- a/webapp/packages/plugin-administration/src/ConfigurationWizard/ConfigurationWizardPagesBootstrapService.ts +++ b/webapp/packages/plugin-administration/src/ConfigurationWizard/ConfigurationWizardPagesBootstrapService.ts @@ -43,7 +43,7 @@ export class ConfigurationWizardPagesBootstrapService extends Bootstrap { type: AdministrationItemType.Default, configurationWizardOptions: { description: 'administration_configuration_wizard_configuration_step_description', - order: 1.1, + order: 1.5, isDone: this.serverConfigurationService.isDone.bind(this.serverConfigurationService), onFinish: this.serverConfigurationService.validate.bind(this.serverConfigurationService), onConfigurationFinish: this.serverConfigurationService.handleConfigurationFinish.bind( diff --git a/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/ServerConfigurationService.ts b/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/ServerConfigurationService.ts index 8daf42b0f4..441dafeff1 100644 --- a/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/ServerConfigurationService.ts +++ b/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/ServerConfigurationService.ts @@ -83,13 +83,13 @@ export class ServerConfigurationService { }; }; - async save(): Promise { + async save(): Promise { if (!this.state) { throw new Error('No state available'); } if (!(await this.validate())) { - return false; + return; } try { @@ -102,8 +102,6 @@ export class ServerConfigurationService { }); await this.serverConfigResource.update(); this.usersResource.refreshAllLazy(); - - return true; } catch (exception) { this.notificationService.logException(exception, 'Can\'t save server configuration'); diff --git a/webapp/packages/plugin-administration/src/Pages/License/AdministrationLicensePageBootstrapService.ts b/webapp/packages/plugin-administration/src/Pages/License/AdministrationLicensePageBootstrapService.ts new file mode 100644 index 0000000000..f23ae455a0 --- /dev/null +++ b/webapp/packages/plugin-administration/src/Pages/License/AdministrationLicensePageBootstrapService.ts @@ -0,0 +1,43 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2021 DBeaver Corp and others + * + * Licensed under the Apache License, Version 2.0. + * you may not use this file except in compliance with the License. + */ + +import { AdministrationItemService, AdministrationItemType } from '@cloudbeaver/core-administration'; +import { Bootstrap, injectable } from '@cloudbeaver/core-di'; + +import { AdministrationLicensePageService } from './AdministrationLicensePageService'; +import { LicenseDrawerItem } from './LicenseDrawerItem'; +import { LicensePage } from './LicensePage'; + +@injectable() +export class AdministrationLicensePageBootstrapService extends Bootstrap { + constructor( + private readonly administrationItemService: AdministrationItemService, + private readonly administrationLicensePageService: AdministrationLicensePageService + ) { + super(); + } + + register(): void { + this.administrationItemService.create({ + name: 'license', + type: AdministrationItemType.Default, + configurationWizardOptions: { + description: 'administration_configuration_wizard_license_step_description', + order: 1.2, + isDone: this.administrationLicensePageService.isDone.bind(this.administrationLicensePageService), + onFinish: this.administrationLicensePageService.save.bind(this.administrationLicensePageService), + }, + order: 5, + onActivate: this.administrationLicensePageService.loadConfig.bind(this.administrationLicensePageService), + getContentComponent: () => LicensePage, + getDrawerComponent: () => LicenseDrawerItem, + }); + } + + load(): void { } +} diff --git a/webapp/packages/plugin-administration/src/Pages/License/AdministrationLicensePageService.ts b/webapp/packages/plugin-administration/src/Pages/License/AdministrationLicensePageService.ts new file mode 100644 index 0000000000..c8a732409d --- /dev/null +++ b/webapp/packages/plugin-administration/src/Pages/License/AdministrationLicensePageService.ts @@ -0,0 +1,118 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2021 DBeaver Corp and others + * + * Licensed under the Apache License, Version 2.0. + * you may not use this file except in compliance with the License. + */ + +import { makeObservable, observable } from 'mobx'; + +import { AdministrationScreenService } from '@cloudbeaver/core-administration'; +import { injectable } from '@cloudbeaver/core-di'; +import { NotificationService } from '@cloudbeaver/core-events'; +import { Executor, IExecutor } from '@cloudbeaver/core-executor'; +import { ServerConfigResource } from '@cloudbeaver/core-root'; + +import type { ILicensePageState } from './ILicensePageState'; + +export interface IValidationStatusContext { + getState: () => boolean; + invalidate: () => void; +} + +@injectable() +export class AdministrationLicensePageService { + state: ILicensePageState; + loading: boolean; + readonly validationTask: IExecutor; + + constructor( + private readonly administrationScreenService: AdministrationScreenService, + private readonly serverConfigResource: ServerConfigResource, + private readonly notificationService: NotificationService, + ) { + makeObservable(this, { + state: observable, + loading: observable, + }); + + this.loading = true; + this.state = this.getConfig(); + this.validationTask = new Executor(); + } + + isDone(): boolean { + return this.isFormFilled(); + } + + validationStatusContext = (): IValidationStatusContext => { + let state = this.isFormFilled(); + + const invalidate = () => { + state = false; + }; + const getState = () => state; + + return { + getState, + invalidate, + }; + }; + + async save(): Promise { + if (!this.state) { + throw new Error('No state available'); + } + + if (!(await this.validate())) { + return false; + } + + return true; + } + + async validate(): Promise { + const context = await this.validationTask.execute(true); + const state = await context.getContext(this.validationStatusContext); + + return state.getState(); + } + + private isFormFilled() { + if ((this.state?.license.length || 0) < 6) { + return false; + } + return true; + } + + async loadConfig(): Promise { + this.loading = true; + try { + const config = await this.serverConfigResource.load(); + + this.state = this.administrationScreenService + .getItemState( + 'license', + this.getConfig.bind(this), + !config?.configurationMode, + value => { + if (typeof value === 'object' && typeof value.license === 'string') { + return true; + } + return false; + } + ); + } catch (exception) { + this.notificationService.logException(exception, 'Can\'t load server configuration'); + } finally { + this.loading = false; + } + } + + private getConfig(): ILicensePageState { + return { + license: '', + }; + } +} diff --git a/webapp/packages/plugin-administration/src/Pages/License/ILicensePageState.ts b/webapp/packages/plugin-administration/src/Pages/License/ILicensePageState.ts new file mode 100644 index 0000000000..5fda0133f6 --- /dev/null +++ b/webapp/packages/plugin-administration/src/Pages/License/ILicensePageState.ts @@ -0,0 +1,11 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2021 DBeaver Corp and others + * + * Licensed under the Apache License, Version 2.0. + * you may not use this file except in compliance with the License. + */ + +export interface ILicensePageState { + license: string; +} diff --git a/webapp/packages/plugin-administration/src/Pages/License/LicenseDrawerItem.tsx b/webapp/packages/plugin-administration/src/Pages/License/LicenseDrawerItem.tsx new file mode 100644 index 0000000000..467bc1b493 --- /dev/null +++ b/webapp/packages/plugin-administration/src/Pages/License/LicenseDrawerItem.tsx @@ -0,0 +1,25 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2021 DBeaver Corp and others + * + * Licensed under the Apache License, Version 2.0. + * you may not use this file except in compliance with the License. + */ + +import styled from 'reshadow'; + +import type { AdministrationItemDrawerProps } from '@cloudbeaver/core-administration'; +import { Tab, TabTitle, TabIcon } from '@cloudbeaver/core-blocks'; +import { Translate } from '@cloudbeaver/core-localization'; +import { useStyles } from '@cloudbeaver/core-theming'; + +export const LicenseDrawerItem: React.FC = function LicenseDrawerItem({ + item, onSelect, style, disabled, +}) { + return styled(useStyles(...style))( + onSelect(item.name)}> + + + + ); +}; diff --git a/webapp/packages/plugin-administration/src/Pages/License/LicensePage.tsx b/webapp/packages/plugin-administration/src/Pages/License/LicensePage.tsx new file mode 100644 index 0000000000..56641f2951 --- /dev/null +++ b/webapp/packages/plugin-administration/src/Pages/License/LicensePage.tsx @@ -0,0 +1,133 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2021 DBeaver Corp and others + * + * Licensed under the Apache License, Version 2.0. + * you may not use this file except in compliance with the License. + */ + +import { observer } from 'mobx-react-lite'; +import { useCallback } from 'react'; +import styled, { use, css } from 'reshadow'; + +import { AdministrationItemContentComponent, ConfigurationWizardService } from '@cloudbeaver/core-administration'; +import { FormBox, FormBoxElement, FormGroup, InputField, Loader, SubmittingForm, useFocus } from '@cloudbeaver/core-blocks'; +import { useService } from '@cloudbeaver/core-di'; +import { useFormValidator } from '@cloudbeaver/core-executor'; +import { Translate, useTranslate } from '@cloudbeaver/core-localization'; +import { useStyles, composes } from '@cloudbeaver/core-theming'; + +import { AdministrationLicensePageService } from './AdministrationLicensePageService'; + +const styles = composes( + css` + layout-grid-cell { + composes: theme-background-surface theme-text-on-surface from global; + } + + layout-grid-cell, message-box { + composes: theme-border-color-background from global; + } + `, + css` + layout-grid { + width: 100%; + flex: 1; + } + + layout-grid-inner { + min-height: 100%; + } + + layout-grid-cell { + position: relative; + border: solid 1px; + padding: 16px 24px + } + + message-box { + border-bottom: solid 1px; + } + + message-box, SubmittingForm { + padding: 16px 24px; + } + + SubmittingForm { + flex: 1; + display: flex; + overflow: auto; + flex-direction: column; + } + + FormBox { + flex: 0; + } + + p { + line-height: 2; + } + ` +); + +export const LicensePage: AdministrationItemContentComponent = observer(function LicensePage({ + configurationWizard, +}) { + const translate = useTranslate(); + const [focusedRef] = useFocus({ focusFirstChild: true }); + const licensePageService = useService(AdministrationLicensePageService); + const configurationWizardService = useService(ConfigurationWizardService); + + const handleSave = useCallback(async () => { + if (configurationWizard) { + await configurationWizardService.next(); + } else { + await licensePageService.save(); + } + }, []); + + useFormValidator(licensePageService.validationTask, focusedRef); + + return styled(useStyles(styles))( + + + + +

+

+
+ + {configurationWizard && ( + + {licensePageService.loading ? ( + + ) : ( + <> + + + + + {translate('administration_configuration_wizard_license_key')} + + + + + + + + )} + + )} +
+
+
+ ); +}); diff --git a/webapp/packages/plugin-administration/src/index.ts b/webapp/packages/plugin-administration/src/index.ts index 7128d5d867..7fa117f692 100644 --- a/webapp/packages/plugin-administration/src/index.ts +++ b/webapp/packages/plugin-administration/src/index.ts @@ -7,3 +7,4 @@ export * from './ConfigurationWizard/ServerConfiguration/Form/ServerConfiguratio export * from './ConfigurationWizard/ServerConfiguration/Form/ServerConfigurationInfoForm'; export * from './ConfigurationWizard/ServerConfiguration/Form/ServerConfigurationNavigatorViewForm'; export * from './ConfigurationWizard/ServerConfiguration/Form/ServerConfigurationSecurityForm'; +export * from './Pages/License/AdministrationLicensePageService'; diff --git a/webapp/packages/plugin-administration/src/locales/en.ts b/webapp/packages/plugin-administration/src/locales/en.ts index 05401d53bf..35b792871c 100644 --- a/webapp/packages/plugin-administration/src/locales/en.ts +++ b/webapp/packages/plugin-administration/src/locales/en.ts @@ -6,6 +6,10 @@ export default [ ['administration_configuration_wizard_welcome_title', 'Welcome to CloudBeaver, cloud database management system!'], ['administration_configuration_wizard_welcome_message', 'The easy configuration wizard will guide you through several simple steps to set up the CloudBeaver server. You will need to set server information and administrator credentials. You can also add first database connections here.'], ['administration_configuration_wizard_welcome_note', 'Note: you will be able to change these configuration parameters later on the administration panel.'], + ['administration_configuration_wizard_license', 'License'], + ['administration_configuration_wizard_license_step_description', 'License setup'], + ['administration_configuration_wizard_license_title', 'Please enter you License Key..'], + ['administration_configuration_wizard_license_key', 'License Key'], ['administration_configuration_wizard_configuration', 'Server configuration'], ['administration_configuration_wizard_configuration_step_description', 'Main server configuration'], ['administration_configuration_wizard_configuration_title', 'You can configure the main server parameters here.'], diff --git a/webapp/packages/plugin-administration/src/locales/ru.ts b/webapp/packages/plugin-administration/src/locales/ru.ts index db2831ea6e..0775dd0fe2 100644 --- a/webapp/packages/plugin-administration/src/locales/ru.ts +++ b/webapp/packages/plugin-administration/src/locales/ru.ts @@ -1,4 +1,8 @@ export default [ + ['administration_configuration_wizard_license', 'Лицензия'], + ['administration_configuration_wizard_license_step_description', 'Настройка лицензии'], + ['administration_configuration_wizard_license_title', 'Пожалуйста укажите лицензию...'], + ['administration_configuration_wizard_license_key', 'Ключ'], ['administration_configuration_wizard_configuration', 'Настройки сервера'], ['administration_configuration_wizard_configuration_server_session_lifetime', 'Время сессии'], ['administration_configuration_wizard_configuration_custom_connections', 'Разрешить пользовательские подключения'], diff --git a/webapp/packages/plugin-administration/src/manifest.ts b/webapp/packages/plugin-administration/src/manifest.ts index 38f06b5de9..80dbe8cfee 100644 --- a/webapp/packages/plugin-administration/src/manifest.ts +++ b/webapp/packages/plugin-administration/src/manifest.ts @@ -11,6 +11,8 @@ import type { PluginManifest } from '@cloudbeaver/core-di'; import { ConfigurationWizardPagesBootstrapService } from './ConfigurationWizard/ConfigurationWizardPagesBootstrapService'; import { ServerConfigurationService } from './ConfigurationWizard/ServerConfiguration/ServerConfigurationService'; import { LocaleService } from './LocaleService'; +import { AdministrationLicensePageBootstrapService } from './Pages/License/AdministrationLicensePageBootstrapService'; +import { AdministrationLicensePageService } from './Pages/License/AdministrationLicensePageService'; export const manifest: PluginManifest = { info: { @@ -20,6 +22,8 @@ export const manifest: PluginManifest = { providers: [ ServerConfigurationService, ConfigurationWizardPagesBootstrapService, + AdministrationLicensePageBootstrapService, + AdministrationLicensePageService, LocaleService, ], };