Skip to content

Commit

Permalink
Display error msg on invalid fields (debezium#294)
Browse files Browse the repository at this point in the history
  • Loading branch information
indraraj authored Jan 27, 2021
1 parent 368f895 commit bc66822
Show file tree
Hide file tree
Showing 9 changed files with 145 additions and 63 deletions.
23 changes: 23 additions & 0 deletions ui/packages/ui/src/app/components/ConnectionPropertiesError.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { PropertyValidationResult } from '@debezium/ui-models/dist/js/ui.model';
import React from 'react';

export interface IConnectionPropertiesErrorProps{
connectionPropsMsg: PropertyValidationResult[];
validationErrorMsg: string;
}

export const ConnectionPropertiesError : React.FunctionComponent<IConnectionPropertiesErrorProps> = (props)=>{
if (props.connectionPropsMsg.length !== 0) {
return (
<ul>
{props.connectionPropsMsg.map((item, index) => (
<li key={index}>
{item.property === 'Generic' ? `${item.displayName}: ${item.message}` : props.validationErrorMsg}
</li>
))}
</ul>
);
} else {
return <div>{props.validationErrorMsg}</div>;
}
}
120 changes: 89 additions & 31 deletions ui/packages/ui/src/app/components/formHelpers/FormComponent.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,55 @@
import { ConnectorProperty } from '@debezium/ui-models';
import * as React from 'react';
import { useTranslation } from 'react-i18next';
import { FormCheckboxComponent } from './FormCheckboxComponent';
import { FormDurationComponent } from './FormDurationComponent';
import { FormInputComponent } from './FormInputComponent';
import { FormMaskHashSaltComponent } from './FormMaskHashSaltComponent';
import { FormMaskOrTruncateComponent } from './FormMaskOrTruncateComponent';
import { FormSelectComponent } from './FormSelectComponent';
import { FormSwitchComponent } from './FormSwitchComponent';
import {
ConnectorProperty,
PropertyValidationResult,
} from "@debezium/ui-models";
import * as React from "react";
import { useTranslation } from "react-i18next";
import { FormCheckboxComponent } from "./FormCheckboxComponent";
import { FormDurationComponent } from "./FormDurationComponent";
import { FormInputComponent } from "./FormInputComponent";
import { FormMaskHashSaltComponent } from "./FormMaskHashSaltComponent";
import { FormMaskOrTruncateComponent } from "./FormMaskOrTruncateComponent";
import { FormSelectComponent } from "./FormSelectComponent";
import { FormSwitchComponent } from "./FormSwitchComponent";

export interface IFormComponentProps {
propertyDefinition: ConnectorProperty;
helperTextInvalid?: any;
validated?: "default" | "success" | "warning" | "error" | undefined
invalidMsg: PropertyValidationResult[];
validated?: "default" | "success" | "warning" | "error" | undefined;
propertyChange: (name: string, selection: any) => void;
setFieldValue: (field: string, value: any, shouldValidate?: boolean | undefined) => void;
setFieldValue: (
field: string,
value: any,
shouldValidate?: boolean | undefined
) => void;
}

const getInvalidFilterMsg = (
filter: string,
errorMsg: PropertyValidationResult[]
) => {
let returnVal = "";
errorMsg?.forEach((val) => {
if (val.property === filter.replace(/_/g, ".")) {
returnVal = val.message;
}
});
return returnVal;
};

export const FormComponent: React.FunctionComponent<IFormComponentProps> = (
props
) => {
const { t } = useTranslation(['app']);
const { t } = useTranslation(["app"]);

const getValidate = () => {
return props.validated === "default"
? getInvalidFilterMsg(props.propertyDefinition.name, props.invalidMsg)
? "error"
: "default"
: "error";
};

// Has allowed values - Select component
if (props.propertyDefinition.allowedValues) {
Expand All @@ -41,7 +70,10 @@ export const FormComponent: React.FunctionComponent<IFormComponentProps> = (
} else if (props.propertyDefinition.type === "BOOLEAN") {
return (
<FormCheckboxComponent
isChecked={typeof props.propertyDefinition.defaultValue !== 'undefined' && props.propertyDefinition.defaultValue === true}
isChecked={
typeof props.propertyDefinition.defaultValue !== "undefined" &&
props.propertyDefinition.defaultValue === true
}
label={props.propertyDefinition.displayName}
name={props.propertyDefinition.name}
description={props.propertyDefinition.description}
Expand All @@ -53,7 +85,10 @@ export const FormComponent: React.FunctionComponent<IFormComponentProps> = (
} else if (props.propertyDefinition.type === "BOOLEAN-SWITCH") {
return (
<FormSwitchComponent
isChecked={typeof props.propertyDefinition.defaultValue !== 'undefined' && props.propertyDefinition.defaultValue === true}
isChecked={
typeof props.propertyDefinition.defaultValue !== "undefined" &&
props.propertyDefinition.defaultValue === true
}
label={props.propertyDefinition.displayName}
name={props.propertyDefinition.name}
description={props.propertyDefinition.description}
Expand All @@ -68,63 +103,86 @@ export const FormComponent: React.FunctionComponent<IFormComponentProps> = (
description={props.propertyDefinition.description}
isRequired={props.propertyDefinition.isMandatory}
fieldId={props.propertyDefinition.name}
helperTextInvalid={props.helperTextInvalid}
helperTextInvalid={
getInvalidFilterMsg(
props.propertyDefinition.name,
props.invalidMsg
) || props.helperTextInvalid
}
label={props.propertyDefinition.displayName}
name={props.propertyDefinition.name}
propertyChange={props.propertyChange}
setFieldValue={props.setFieldValue}
validated={getValidate()}
/>
);
// Column Mask or Column Truncate
// Column Mask or Column Truncate
} else if (props.propertyDefinition.type === "COL_MASK_OR_TRUNCATE") {
return (
<FormMaskOrTruncateComponent
description={props.propertyDefinition.description}
isRequired={props.propertyDefinition.isMandatory}
fieldId={props.propertyDefinition.name}
helperTextInvalid={props.helperTextInvalid}
helperTextInvalid={
getInvalidFilterMsg(
props.propertyDefinition.name,
props.invalidMsg
) || props.helperTextInvalid
}
label={props.propertyDefinition.displayName}
name={props.propertyDefinition.name}
i18nAddDefinitionText={t('addDefinition')}
i18nAddDefinitionTooltip={t('addDefinitionTooltip')}
i18nRemoveDefinitionTooltip={t('removeDefinitionTooltip')}
i18nAddDefinitionText={t("addDefinition")}
i18nAddDefinitionTooltip={t("addDefinitionTooltip")}
i18nRemoveDefinitionTooltip={t("removeDefinitionTooltip")}
propertyChange={props.propertyChange}
setFieldValue={props.setFieldValue}
validated={getValidate()}
/>
);
// Column Mask Hash and Salt
// Column Mask Hash and Salt
} else if (props.propertyDefinition.type === "COL_MASK_HASH_SALT") {
return (
<FormMaskHashSaltComponent
description={props.propertyDefinition.description}
isRequired={props.propertyDefinition.isMandatory}
fieldId={props.propertyDefinition.name}
helperTextInvalid={props.helperTextInvalid}
helperTextInvalid={
getInvalidFilterMsg(
props.propertyDefinition.name,
props.invalidMsg
) || props.helperTextInvalid
}
label={props.propertyDefinition.displayName}
name={props.propertyDefinition.name}
i18nAddDefinitionText={t('addDefinition')}
i18nAddDefinitionTooltip={t('addDefinitionTooltip')}
i18nRemoveDefinitionTooltip={t('removeDefinitionTooltip')}
i18nAddDefinitionText={t("addDefinition")}
i18nAddDefinitionTooltip={t("addDefinitionTooltip")}
i18nRemoveDefinitionTooltip={t("removeDefinitionTooltip")}
propertyChange={props.propertyChange}
setFieldValue={props.setFieldValue}
validated={getValidate()}
/>
);
// Any other - Text input
} else {

// Any other - Text input
} else {
return (
<FormInputComponent
isRequired={props.propertyDefinition.isMandatory}
label={props.propertyDefinition.displayName}
fieldId={props.propertyDefinition.name}
name={props.propertyDefinition.name}
type={props.propertyDefinition.type}
helperTextInvalid={props.helperTextInvalid}
helperTextInvalid={
getInvalidFilterMsg(
props.propertyDefinition.name,
props.invalidMsg
) || props.helperTextInvalid
}
infoTitle={
props.propertyDefinition.displayName || props.propertyDefinition.name
}
infoText={props.propertyDefinition.description}
validated={props.validated}
validated={getValidate()}
/>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export interface IFormDurationComponentProps {
fieldId: string;
helperTextInvalid?: any;
isRequired: boolean;
validated?: "default" | "success" | "warning" | "error" | undefined;
validated: "default" | "success" | "warning" | "error";
propertyChange: (name: string, selection: any) => void;
setFieldValue: (
field: string,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export interface IFormMaskHashSaltComponentProps {
fieldId: string;
helperTextInvalid?: any;
isRequired: boolean;
validated?: "default" | "success" | "warning" | "error" | undefined;
validated: "default" | "success" | "warning" | "error";
i18nAddDefinitionText: string;
i18nAddDefinitionTooltip: string;
i18nRemoveDefinitionTooltip: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export interface IFormMaskOrTruncateComponentProps {
fieldId: string;
helperTextInvalid?: any;
isRequired: boolean;
validated?: "default" | "success" | "warning" | "error" | undefined;
validated: "default" | "success" | "warning" | "error";
i18nAddDefinitionText: string;
i18nAddDefinitionTooltip: string;
i18nRemoveDefinitionTooltip: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import React, { Dispatch, ReactNode, SetStateAction } from "react";
import { useTranslation } from "react-i18next";
import { Prompt } from "react-router-dom";
import { ToastAlertComponent } from "src/app/components";
import { ConnectionPropertiesError } from "src/app/components/ConnectionPropertiesError";
import {
ConfirmationButtonStyle,
ConfirmationDialog,
Expand Down Expand Up @@ -87,7 +88,6 @@ export const CreateConnectorComponent: React.FunctionComponent<ICreateConnectorC
) => {
const { t } = useTranslation(["app"]);

const validationErrorMsg = t("resolvePropertyErrorsMsg");
const validationSuccessNextMsg = t("resolvePropertySucessMsg");
const createConnectorUnknownErrorMsg = t("unknownError");
const CONNECTOR_TYPE_STEP = (
Expand Down Expand Up @@ -475,6 +475,7 @@ export const CreateConnectorComponent: React.FunctionComponent<ICreateConnectorC
}
} else {
setConnectionPropsValid(true);
setConnectionPropsValidMsg([]);
}
setValidateInProgress(false);
})
Expand Down Expand Up @@ -536,6 +537,7 @@ export const CreateConnectorComponent: React.FunctionComponent<ICreateConnectorC
}
setConnectionPropsValidMsg(result.propertyValidationResults);
} else {
setConnectionPropsValidMsg([]);
if (isDataOptions(propertyCategory)) {
setDataOptionsValid(true);
} else if (isRuntimeOptions(propertyCategory)) {
Expand Down Expand Up @@ -598,22 +600,6 @@ export const CreateConnectorComponent: React.FunctionComponent<ICreateConnectorC
initPropertyValues();
}, [connectorTypes]);

const ConnectionPropertiesError = ({ connectionPropsMsg }) => {
if (connectionPropsMsg.length !== 0) {
return (
<ul>
{connectionPropsMsg.map((item, index) => (
<li key={index}>
{item.displayName}: {item.message}
</li>
))}
</ul>
);
} else {
return <div>{validationErrorMsg}</div>;
}
};

const connectorTypeStep = {
id: 1,
name: CONNECTOR_TYPE_STEP,
Expand Down Expand Up @@ -653,6 +639,7 @@ export const CreateConnectorComponent: React.FunctionComponent<ICreateConnectorC
ref={connectionPropsRef}
setConnectionPropsValid={setConnectionPropsValid}
setConnectionStepsValid={setConnectionStepsValid}
invalidMsg={connectionPropsValidMsg}
/>
{validateInProgress ? (
<Spinner size="lg" />
Expand All @@ -666,6 +653,7 @@ export const CreateConnectorComponent: React.FunctionComponent<ICreateConnectorC
title={
<ConnectionPropertiesError
connectionPropsMsg={connectionPropsValidMsg}
validationErrorMsg={t("resolvePropertyErrorsMsg")}
/>
}
/>
Expand Down Expand Up @@ -758,6 +746,7 @@ export const CreateConnectorComponent: React.FunctionComponent<ICreateConnectorC
ref={dataOptionRef}
setDataOptionsValid={setDataOptionsValid}
setDataStepsValid={setDataStepsValid}
invalidMsg={connectionPropsValidMsg}
/>
{validateInProgress ? (
<Spinner size="lg" />
Expand All @@ -771,6 +760,7 @@ export const CreateConnectorComponent: React.FunctionComponent<ICreateConnectorC
title={
<ConnectionPropertiesError
connectionPropsMsg={connectionPropsValidMsg}
validationErrorMsg={t("resolvePropertyErrorsMsg")}
/>
}
/>
Expand All @@ -797,6 +787,7 @@ export const CreateConnectorComponent: React.FunctionComponent<ICreateConnectorC
ref={runtimeOptionRef}
setRuntimeOptionsValid={setRuntimeOptionsValid}
setRuntimeStepsValid={setRuntimeStepsValid}
invalidMsg={connectionPropsValidMsg}
/>
{validateInProgress ? (
<Spinner size="lg" />
Expand All @@ -811,6 +802,7 @@ export const CreateConnectorComponent: React.FunctionComponent<ICreateConnectorC
title={
<ConnectionPropertiesError
connectionPropsMsg={connectionPropsValidMsg}
validationErrorMsg={t("resolvePropertyErrorsMsg")}
/>
}
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ConnectorProperty } from "@debezium/ui-models";
import { ConnectorProperty, PropertyValidationResult } from "@debezium/ui-models";
import {
ExpandableSection,
Grid,
Expand All @@ -15,6 +15,7 @@ import "./DataOptionsComponent.css";
export interface IDataOptionsComponentProps {
propertyDefinitions: ConnectorProperty[];
propertyValues: Map<string, string>;
invalidMsg: PropertyValidationResult[];
i18nAdvancedMappingPropertiesText: string;
i18nMappingPropertiesText: string;
i18nSnapshotPropertiesText: string;
Expand Down Expand Up @@ -166,6 +167,7 @@ export const DataOptionsComponent: React.FC<any> = React.forwardRef(
helperTextInvalid={
errors[propertyDefinition.name]
}
invalidMsg={props.invalidMsg}
validated={
errors[propertyDefinition.name] &&
touched[propertyDefinition.name]
Expand Down Expand Up @@ -206,6 +208,7 @@ export const DataOptionsComponent: React.FC<any> = React.forwardRef(
helperTextInvalid={
errors[propertyDefinition.name]
}
invalidMsg={props.invalidMsg}
validated={
errors[propertyDefinition.name] &&
touched[propertyDefinition.name]
Expand Down Expand Up @@ -243,6 +246,7 @@ export const DataOptionsComponent: React.FC<any> = React.forwardRef(
helperTextInvalid={
errors[propertyDefinition.name]
}
invalidMsg={props.invalidMsg}
validated={
errors[propertyDefinition.name] &&
touched[propertyDefinition.name]
Expand Down
Loading

0 comments on commit bc66822

Please sign in to comment.