mirror of
https://github.com/dbeaver/cloudbeaver.git
synced 2026-10-16 06:40:05 +08:00
feat(plugin-administration): CB-340 server configuration page
This commit is contained in:
+3
-3
@@ -115,9 +115,9 @@ export class AdministrationScreenService {
|
||||
}
|
||||
|
||||
getItemState<T>(name: string): T | undefined
|
||||
getItemState<T>(name: string, defaultState: () => T): T
|
||||
getItemState<T>(name: string, defaultState?: () => T): T | undefined {
|
||||
if (!this.itemState.has(name) && defaultState) {
|
||||
getItemState<T>(name: string, defaultState: () => T, update?: boolean): T
|
||||
getItemState<T>(name: string, defaultState?: () => T, update?: boolean): T | undefined {
|
||||
if ((!this.itemState.has(name) || update) && defaultState) {
|
||||
this.itemState.set(name, defaultState());
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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',
|
||||
|
||||
+2
-1
@@ -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,
|
||||
});
|
||||
|
||||
+58
-42
@@ -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<boolean>;
|
||||
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<HTMLFormElement>({ 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))(
|
||||
<SubmittingForm ref={focusedRef} name='server_config' onSubmit={onSave}>
|
||||
<SubmittingForm ref={focusedRef} name='server_config' onSubmit={onSubmit}>
|
||||
<box as="div">
|
||||
<box-element as='div'>
|
||||
<group as="div">
|
||||
@@ -88,31 +98,37 @@ export const ServerConfigurationForm = observer(function ServerConfigurationForm
|
||||
{translate('administration_configuration_wizard_configuration_server_name')}
|
||||
</InputField>
|
||||
</group>
|
||||
<group as="div">
|
||||
<InputGroup long>{translate('administration_configuration_wizard_configuration_admin')}</InputGroup>
|
||||
</group>
|
||||
<InputField
|
||||
type="text"
|
||||
name="adminName"
|
||||
state={serverConfig}
|
||||
mod='surface'
|
||||
minLength={6}
|
||||
required
|
||||
long
|
||||
>
|
||||
{translate('administration_configuration_wizard_configuration_admin_name')}
|
||||
</InputField>
|
||||
<InputField
|
||||
type="password"
|
||||
name="adminPassword"
|
||||
state={serverConfig}
|
||||
autoComplete='new-password'
|
||||
mod='surface'
|
||||
required
|
||||
long
|
||||
>
|
||||
{translate('administration_configuration_wizard_configuration_admin_password')}
|
||||
</InputField>
|
||||
{editing
|
||||
? <group as="div"><Button mod={['raised']}>Save</Button></group>
|
||||
: (
|
||||
<>
|
||||
<group as="div">
|
||||
<InputGroup long>{translate('administration_configuration_wizard_configuration_admin')}</InputGroup>
|
||||
</group>
|
||||
<InputField
|
||||
type="text"
|
||||
name="adminName"
|
||||
state={serverConfig}
|
||||
mod='surface'
|
||||
minLength={6}
|
||||
required
|
||||
long
|
||||
>
|
||||
{translate('administration_configuration_wizard_configuration_admin_name')}
|
||||
</InputField>
|
||||
<InputField
|
||||
type="password"
|
||||
name="adminPassword"
|
||||
state={serverConfig}
|
||||
autoComplete='new-password'
|
||||
mod='surface'
|
||||
required
|
||||
long
|
||||
>
|
||||
{translate('administration_configuration_wizard_configuration_admin_password')}
|
||||
</InputField>
|
||||
</>
|
||||
)}
|
||||
</box-element>
|
||||
<box-element as='div'>
|
||||
<group as="div">
|
||||
|
||||
+12
-4
@@ -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))(
|
||||
<layout-grid as="div">
|
||||
<layout-grid-inner as="div">
|
||||
<layout-grid-cell as='div' {...use({ span: 12 })}>
|
||||
<h3>{translate('administration_configuration_wizard_configuration_title')}</h3>
|
||||
<p>{translate('administration_configuration_wizard_configuration_message')}</p>
|
||||
{!controller.editing && (
|
||||
<>
|
||||
<h3>{translate('administration_configuration_wizard_configuration_title')}</h3>
|
||||
<p>{translate('administration_configuration_wizard_configuration_message')}</p>
|
||||
</>
|
||||
)}
|
||||
<ServerConfigurationForm
|
||||
serverConfig={controller.state.serverConfig}
|
||||
validationTask={service.validationTask}
|
||||
editing={controller.editing}
|
||||
onChange={controller.onChange}
|
||||
onSave={controller.finish}
|
||||
onSubmit={controller.finish}
|
||||
/>
|
||||
</layout-grid-cell>
|
||||
</layout-grid-inner>
|
||||
|
||||
+15
-2
@@ -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<void> => await this.configurationWizardService.next();
|
||||
finish = async (): Promise<void> => {
|
||||
if (this.administrationScreenService.isConfigurationMode) {
|
||||
await this.configurationWizardService.next();
|
||||
} else {
|
||||
if (this.serverConfigurationService.validate()) {
|
||||
await this.serverConfigurationService.apply();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
+85
-34
@@ -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<boolean>;
|
||||
|
||||
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<IServerConfigurationPageState>('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<void> {
|
||||
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,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ export class UsersAdministrationService extends Bootstrap {
|
||||
register() {
|
||||
this.administrationItemService.create({
|
||||
name: UsersAdministrationNavigationService.ItemName,
|
||||
order: 1,
|
||||
order: 2,
|
||||
sub: [
|
||||
{
|
||||
name: UsersAdministrationNavigationService.AddItemName,
|
||||
|
||||
Reference in New Issue
Block a user