Skip to content

Commit

Permalink
Merged in bugfix/SHIBUI-2177 (pull request #556)
Browse files Browse the repository at this point in the history
Added validation messages to copying source form

Approved-by: Bill Smith
Approved-by: Jonathan Johnson
  • Loading branch information
rmathis committed Nov 1, 2021
2 parents a0655a6 + 49e0e98 commit 0b16613
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 92 deletions.
67 changes: 37 additions & 30 deletions ui/src/app/metadata/copy/CopySource.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import React from 'react';
import { useForm } from 'react-hook-form';
import Check from 'react-bootstrap/FormCheck';
import Button from 'react-bootstrap/Button';
import Form from 'react-bootstrap/Form';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faArrowCircleRight, faAsterisk, faCheck, faTimes } from '@fortawesome/free-solid-svg-icons';

import { Translate } from '../../i18n/components/translate';
import { EntityTypeahead } from './EntityTypeahead';
import kebabCase from 'lodash/kebabCase';
import { useMetadataSources } from '../hooks/api';

const sections = [
{ i18nKey: 'organizationInformation', property: 'organization' },
Expand All @@ -23,6 +24,8 @@ const sections = [

export function CopySource({ copy, onNext }) {

const { data = [] } = useMetadataSources({ cachePolicy: 'no-cache' }, []);

const [selected, setSelected] = React.useState(copy.properties);
const onSelect = (item, checked) => {
let s = [...selected];
Expand Down Expand Up @@ -59,9 +62,11 @@ export function CopySource({ copy, onNext }) {
setValue('properties', selected);
}, [selected, setValue]);

const sourceIds = data.map(p => p.entityId);

React.useEffect(() => {
console.log(errors, formState);
}, [errors, formState]);
console.log(errors, isValid);
}, [errors]);

return (
<>
Expand Down Expand Up @@ -98,50 +103,52 @@ export function CopySource({ copy, onNext }) {
<div className="col col-xs-12 col-xl-6">
<form onSubmit={handleSubmit(onNext)}>
<fieldset className="bg-light border rounded p-4">
<div className={`form-group ${errors?.target ? 'is-invalid' : ''}`}>
<label htmlFor="target">
<Form.Group className={`${errors.target ? 'is-invalid text-danger' : ''}`}>
<Form.Label htmlFor="target">
<Translate value="label.select-entity-id-to-copy">Select the Entity ID to copy</Translate>
<FontAwesomeIcon icon={faAsterisk} className="text-danger" />
</label>
<EntityTypeahead name="target" control={control} />
<small id="target-help"
className={`form-text text-danger ${errors?.target?.type === 'required' ? '' : 'sr-only'}`}>
</Form.Label>
<EntityTypeahead id="target" name="target" control={control} />
<Form.Text id="target-help"
className={`text-danger ${errors?.target?.type === 'required' ? '' : 'sr-only'}`}>
<Translate value="message.target-required">Entity ID to copy is Required</Translate>
</small>
</div>
<div className="form-group">
<label htmlFor="serviceProviderName">
</Form.Text>
</Form.Group>
<Form.Group className={`${errors.serviceProviderName ? 'text-danger is-invalid' : ''}`}>
<Form.Label htmlFor="serviceProviderName">
<Translate value="label.metadata-source-name-dashboard-display-only">Metadata Source Name (Dashboard Display Only)</Translate>
<FontAwesomeIcon icon={faAsterisk} className="text-danger" />
</label>
<input id="serviceProviderName" type="text" className="form-control"
</Form.Label>
<Form.Control id="serviceProviderName" type="text" className="form-control"
{...register('serviceProviderName', {required: true})}
aria-describedby="serviceProviderName-help" />
<small className={`form-text text-danger ${errors?.serviceProviderName?.type === 'required' ? '' : 'sr-only'}`}
<Form.Text className={`form-text text-danger ${errors?.serviceProviderName?.type === 'required' ? '' : 'sr-only'}`}
id="serviceProviderName-help">
<Translate value="message.service-resolver-name-required">Service Resolver Name is required</Translate>
</small>
</div>
<div className="form-group">
<label htmlFor="entityId">
</Form.Text>
</Form.Group>
<Form.Group className={`${errors.entityId ? 'is-invalid text-danger' : ''}`}>
<Form.Label htmlFor="entityId">
<Translate value="label.service-resolver-entity-id">New Entity ID</Translate>
<FontAwesomeIcon icon={faAsterisk} className="text-danger" />
</label>
<input id="entityId" type="text"
className="form-control"
placeholder=""
</Form.Label>
<Form.Control id="entityId" type="text"
isInvalid={errors.entityId}
aria-describedby="entityId-help"
{...register('entityId', { required: true })} />
<small className={`form-text text-danger ${errors?.entityId ? '' : 'sr-only'}`}
id="entityId-help">
{...register('entityId', {
required: true, validate: {
unique: v => !(sourceIds.indexOf(v) > -1)
}
})} />
<Form.Text className={errors?.entityId ? 'text-danger' : 'sr-only'} id="entityId-help">
{errors?.entityId?.type === 'required' &&
<Translate value="message.entity-id-required">Entity ID is required</Translate>
}
{errors?.entityId?.type === 'unique' &&
<Translate value="message.entity-id-must-be-unique">Entity ID must be unique</Translate>
}
</small>
</div>
</Form.Text>
</Form.Group>
</fieldset>
</form>
</div>
Expand All @@ -158,7 +165,7 @@ export function CopySource({ copy, onNext }) {
<tr key={i}>
<td><span className="mb-0" id={`property-checkbox-${i}`}><Translate value={`label.${kebabCase(item.i18nKey)}`} /></span></td>
<td>
<Check
<Form.Check
custom
type={'checkbox'}
id={`property-checkbox-${i}-check`}
Expand Down
9 changes: 6 additions & 3 deletions ui/src/app/metadata/copy/EntityTypeahead.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Typeahead } from 'react-bootstrap-typeahead';
import { useController } from 'react-hook-form';
import { useMetadataSources } from '../hooks/api';

export function EntityTypeahead ({control, name}) {
export function EntityTypeahead ({id, control, name}) {
const { data = [] } = useMetadataSources({}, []);
const entities = React.useMemo(() => data.map(d => d.entityId), [data]);

Expand All @@ -12,7 +12,9 @@ export function EntityTypeahead ({control, name}) {
} = useController({
name,
control,
rules: { required: true },
rules: {
required: true
},
defaultValue: "",
});

Expand All @@ -22,7 +24,8 @@ export function EntityTypeahead ({control, name}) {
onChange={(selected) => onChange(selected ? data.find(e => e.entityId === selected[0]) : '')}
defaultInputValue={value ? value.entityId : ''}
options={entities}
id="copySourceTypeahead"
required={true}
id={id}
/>
)
}
95 changes: 36 additions & 59 deletions ui/src/app/metadata/copy/SaveCopy.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React from 'react';
import Check from 'react-bootstrap/FormCheck';
import Button from 'react-bootstrap/Button';
import { faArrowCircleLeft, faCheck, faSave, faSpinner } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
Expand All @@ -12,9 +11,6 @@ import { removeNull } from '../../core/utility/remove_null';
import { MetadataConfiguration } from '../component/MetadataConfiguration';
import Translate from '../../i18n/components/translate';

import { InfoIcon } from '../../form/component/InfoIcon';


export function useCopiedModel (copy) {
const { properties, target, serviceProviderName, entityId } = copy;
const copied = removeNull(properties.reduce((c, section) => ({ ...c, ...{ [section]: target[section] } }), {}));
Expand All @@ -37,7 +33,7 @@ export function SaveCopy ({ copy, saving, onSave, onBack }) {
const model = useCopiedModel(copy);
const configuration = useCopiedConfiguration(model, schema, definition);

const { register, handleSubmit } = useForm({
const { handleSubmit } = useForm({
mode: 'onChange',
reValidateMode: 'onBlur',
defaultValues: {
Expand All @@ -59,61 +55,42 @@ export function SaveCopy ({ copy, saving, onSave, onBack }) {

return (
<>
<div className="row">
<div className="col col-xs-12">
<ul className="nav nav-wizard m-3">
<li className="nav-item">
<Button type="button" className="nav-link previous btn d-flex justify-content-between align-items-start" onClick={onBack}>
<span className="direction d-flex flex-column align-items-center">
<FontAwesomeIcon icon={faArrowCircleLeft} size="2x" />
<Translate value="action.back">Back</Translate>
</span>
<span className="label">
<Translate value="label.name-and-entityid">
Name and Entity ID.
</Translate>
</span>
</Button>
</li>
<li className="nav-item">
<h3 className="tag tag-primary">
<span className="index">
<FontAwesomeIcon icon={faCheck} />
</span>
<Translate value="label.finish-summary-validation">Finished!</Translate>
</h3>
</li>
<li className="nav-item">
<Button className="nav-link save btn d-flex justify-content-between align-items-start" aria-label="Save" onClick={() => handleSubmit(onFinish)()} type="button">
<span className="label"><Translate value="action.save">Save</Translate></span>
<span className="direction d-flex flex-column align-items-center">
<FontAwesomeIcon icon={saving ? faSpinner : faSave} pulse={saving} size="2x" />
<Translate value="action.save">Save</Translate>
</span>
</Button>
</li>
</ul>
</div>
<div className="row">
<div className="col col-xs-12">
<ul className="nav nav-wizard m-3">
<li className="nav-item">
<Button type="button" className="nav-link previous btn d-flex justify-content-between align-items-start" onClick={onBack}>
<span className="direction d-flex flex-column align-items-center">
<FontAwesomeIcon icon={faArrowCircleLeft} size="2x" />
<Translate value="action.back">Back</Translate>
</span>
<span className="label">
<Translate value="label.name-and-entityid">
Name and Entity ID.
</Translate>
</span>
</Button>
</li>
<li className="nav-item">
<h3 className="tag tag-primary">
<span className="index">
<FontAwesomeIcon icon={faCheck} />
</span>
<Translate value="label.finish-summary-validation">Finished!</Translate>
</h3>
</li>
<li className="nav-item">
<Button className="nav-link save btn d-flex justify-content-between align-items-start" aria-label="Save" onClick={() => handleSubmit(onFinish)()} type="button">
<span className="label"><Translate value="action.save">Save</Translate></span>
<span className="direction d-flex flex-column align-items-center">
<FontAwesomeIcon icon={saving ? faSpinner : faSave} pulse={saving} size="2x" />
<Translate value="action.save">Save</Translate>
</span>
</Button>
</li>
</ul>
</div>
<form onSubmit={ handleSubmit(onFinish) }>
<div className="row">
<fieldset className="col-xl-6 form-section">
<section className="entity-section">
<div className="form-group d-flex">
<label htmlFor="serviceEnabled" className="mr-2"><Translate value="label.enable-this-service" /></label>
<Check custom
id="serviceEnabled"
className="mr-2"
type={'checkbox'}
{...register('serviceEnabled')}
/>
<InfoIcon value={`tooltip.enable-this-service-upon-saving`} placement="right" />
</div>
</section>
</fieldset>
</div>
</form>

</div>
<MetadataConfiguration configuration={configuration} />
</>
);
Expand Down
9 changes: 9 additions & 0 deletions ui/src/app/metadata/view/MetadataCopy.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@ import { CopySource } from '../copy/CopySource';
import { SaveCopy } from '../copy/SaveCopy';
import { useMetadataEntity } from '../hooks/api';
import { useHistory } from 'react-router';
import { createNotificationAction, NotificationTypes, useNotificationDispatcher } from '../../notifications/hoc/Notifications';

export function MetadataCopy ({ onShowNav }) {

const { post, response, loading } = useMetadataEntity('source');
const history = useHistory();

const dispatch = useNotificationDispatcher();

const [copy, setCopy] = React.useState({
target: null,
serviceProviderName: null,
Expand All @@ -34,6 +37,12 @@ export function MetadataCopy ({ onShowNav }) {
await post('', data);
if (response.ok) {
history.push('/');
} else {
const { errorCode, errorMessage, cause } = response.data;
dispatch(createNotificationAction(
`${errorCode}: ${errorMessage} ${cause ? `-${cause}` : ''}`,
NotificationTypes.ERROR
));
}
}

Expand Down

0 comments on commit 0b16613

Please sign in to comment.