feat(core-administration): configuration forms validation handling

This commit is contained in:
Wroud
2020-09-01 23:29:44 +03:00
parent 553269c0a1
commit 08ef22b15c
6 changed files with 54 additions and 19 deletions
@@ -20,6 +20,7 @@
"@cloudbeaver/core-root": "^0.1.0",
"@cloudbeaver/core-routing": "^0.1.0",
"@cloudbeaver/core-theming": "^0.1.0",
"@cloudbeaver/core-executor": "^0.1.0",
"react": "^16.x.x",
"mobx": "^5.x.x",
"mobx-react": "^6.x.x",
@@ -54,7 +54,7 @@ export interface IAdministrationItemSubItem {
export interface IConfigurationWizardItemOptions {
description: string;
onValidate?: () => boolean;
onValidate?: () => Promise<boolean> | boolean;
isDisabled?: () => boolean;
isHidden?: () => boolean;
isDone?: () => boolean;
@@ -55,15 +55,6 @@ export class ConfigurationWizardService {
});
}
@computed get canNext() {
if (this.currentStep?.configurationWizardOptions?.isDone
&& !this.currentStep?.configurationWizardOptions?.isDone()) {
return false;
}
return true;
}
@computed get nextStep() {
return this.steps.find((item, index) => {
if (index <= this.currentStepIndex) {
@@ -112,27 +103,37 @@ export class ConfigurationWizardService {
const step = this.getStep(name);
if (!step) {
return;
return false;
}
if (step.configurationWizardOptions?.onValidate) {
const isValid = await step.configurationWizardOptions.onValidate();
if (!isValid) {
return false;
}
}
if (step.configurationWizardOptions?.onFinish) {
await step.configurationWizardOptions.onFinish();
}
return true;
}
next() {
if (!this.currentStep || !this.canNext) {
async next() {
if (!this.currentStep) {
return;
}
this.finishStep(this.currentStep.name);
if (!await this.finishStep(this.currentStep.name)) {
return;
}
if (this.currentStepIndex + 1 < this.steps.length) {
if (this.nextStep) {
this.administrationScreenService.navigateToItem(this.nextStep.name);
}
} else {
this.finish();
await this.finish();
}
}
@@ -7,15 +7,19 @@
*/
import { observer } from 'mobx-react';
import { useEffect } from 'react';
import styled, { css } from 'reshadow';
import {
SubmittingForm, InputGroup, InputField, useFocus, Switch
} from '@cloudbeaver/core-blocks';
import { useService } from '@cloudbeaver/core-di';
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;
@@ -51,9 +55,20 @@ export const ServerConfigurationForm = observer(function ServerConfigurationForm
onChange,
onSave,
}: 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);
return () => service.validationTask.removeHandler(validate);
}, [service]);
return styled(useStyles(formStyles, boxStyles))(
<SubmittingForm onSubmit={onSave} name='server_config' ref={focusedRef}>
<box as="div">
@@ -8,6 +8,7 @@
import { injectable } from '@cloudbeaver/core-di';
import { NotificationService } from '@cloudbeaver/core-events';
import { IExecutor, Executor, IContextProvider } from '@cloudbeaver/core-executor';
import { GraphQLService } from '@cloudbeaver/core-sdk';
import { AdministrationScreenService } from '../../../AdministrationScreenService';
@@ -17,6 +18,7 @@ import { IServerConfigurationPageState } from './IServerConfigurationPageState';
export class ServerConfigurationService {
readonly state: IServerConfigurationPageState;
readonly validationTask: IExecutor<boolean>;
constructor(
private administrationScreenService: AdministrationScreenService,
@@ -42,18 +44,35 @@ export class ServerConfigurationService {
showUtilityObjects: false,
},
}));
this.validationTask = new Executor();
}
isDone() {
return this.isFormFilled();
}
validate() {
return this.isFormFilled();
async validate() {
const context = await this.validationTask.execute(true);
const state = await context.getContext(this.validationStatusContext);
return state.getState();
}
validationStatusContext = (context: IContextProvider<boolean>) => {
let state = this.isFormFilled();
const invalidate = () => {
state = false;
};
const getState = () => state;
return {
getState,
invalidate,
};
}
private isFormFilled() {
return !!(
this.state?.serverConfig.serverName
&& this.state.serverConfig.adminName
@@ -79,7 +79,6 @@ export const WizardStepper = observer(function WizardStepper() {
type="button"
mod={['unelevated']}
onClick={() => service.next()}
disabled={!service.canNext}
>
{translate(service.currentStepIndex === service.steps.length - 1 ? 'ui_stepper_finish' : 'ui_stepper_next')}
</Button>