[ARVADOS-WORKBENCH2] updated: 1.1.4-293-g0603536
Git user
git at public.curoverse.com
Tue Jul 17 03:59:43 EDT 2018
Summary of changes:
src/common/api/common-resource-service.ts | 41 ++++++++++++++--------
src/store/project/project-action.ts | 2 +-
src/store/project/project-reducer.ts | 7 ++--
src/utils/dialog-validator.tsx | 25 ++++++-------
.../create-project-dialog.tsx | 1 +
.../dialog-create/dialog-project-create.tsx | 35 ++++++++++++------
6 files changed, 68 insertions(+), 43 deletions(-)
via 060353602bb2cb48639f040a3ff986b8dcbe84da (commit)
from 109103ee47da299c04ffdcabebc38bcd665555d9 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
commit 060353602bb2cb48639f040a3ff986b8dcbe84da
Author: Pawel Kowalczyk <pawel.kowalczyk at contractors.roche.com>
Date: Tue Jul 17 09:59:32 2018 +0200
validation from BE
Feature #13781
Arvados-DCO-1.1-Signed-off-by: Pawel Kowalczyk <pawel.kowalczyk at contractors.roche.com>
diff --git a/src/common/api/common-resource-service.ts b/src/common/api/common-resource-service.ts
index 4c05392..39825c0 100644
--- a/src/common/api/common-resource-service.ts
+++ b/src/common/api/common-resource-service.ts
@@ -5,7 +5,7 @@
import * as _ from "lodash";
import FilterBuilder from "./filter-builder";
import OrderBuilder from "./order-builder";
-import { AxiosInstance } from "axios";
+import { AxiosInstance, AxiosPromise } from "axios";
import { Resource } from "../../models/resource";
export interface ListArguments {
@@ -26,6 +26,11 @@ export interface ListResults<T> {
itemsAvailable: number;
}
+export interface Errors {
+ errors: string[];
+ errorToken: string;
+}
+
export default class CommonResourceService<T extends Resource> {
static mapResponseKeys = (response: any): Promise<any> =>
@@ -49,6 +54,12 @@ export default class CommonResourceService<T extends Resource> {
}
}
+ static defaultResponse<R>(promise: AxiosPromise<R>): Promise<R> {
+ return promise
+ .then(CommonResourceService.mapResponseKeys)
+ .catch(({ response }) => Promise.reject<Errors>(CommonResourceService.mapResponseKeys(response)));
+ }
+
protected serverApi: AxiosInstance;
protected resourceType: string;
@@ -58,21 +69,21 @@ export default class CommonResourceService<T extends Resource> {
}
create(data: Partial<T>) {
- return this.serverApi
- .post<T>(this.resourceType, CommonResourceService.mapKeys(_.snakeCase)(data))
- .then(CommonResourceService.mapResponseKeys);
+ return CommonResourceService.defaultResponse(
+ this.serverApi
+ .post<T>(this.resourceType, CommonResourceService.mapKeys(_.snakeCase)(data)));
}
delete(uuid: string): Promise<T> {
- return this.serverApi
- .delete(this.resourceType + uuid)
- .then(CommonResourceService.mapResponseKeys);
+ return CommonResourceService.defaultResponse(
+ this.serverApi
+ .delete(this.resourceType + uuid));
}
get(uuid: string) {
- return this.serverApi
- .get<T>(this.resourceType + uuid)
- .then(CommonResourceService.mapResponseKeys);
+ return CommonResourceService.defaultResponse(
+ this.serverApi
+ .get<T>(this.resourceType + uuid));
}
list(args: ListArguments = {}): Promise<ListResults<T>> {
@@ -82,11 +93,11 @@ export default class CommonResourceService<T extends Resource> {
filters: filters ? filters.serialize() : undefined,
order: order ? order.getOrder() : undefined
};
- return this.serverApi
- .get(this.resourceType, {
- params: CommonResourceService.mapKeys(_.snakeCase)(params)
- })
- .then(CommonResourceService.mapResponseKeys);
+ return CommonResourceService.defaultResponse(
+ this.serverApi
+ .get(this.resourceType, {
+ params: CommonResourceService.mapKeys(_.snakeCase)(params)
+ }));
}
update(uuid: string) {
diff --git a/src/store/project/project-action.ts b/src/store/project/project-action.ts
index 2d59a48..b141736 100644
--- a/src/store/project/project-action.ts
+++ b/src/store/project/project-action.ts
@@ -46,7 +46,7 @@ export const createProject = (project: Partial<ProjectResource>) =>
return projectService
.create(projectData)
.then(project => dispatch(actions.CREATE_PROJECT_SUCCESS(project)))
- .catch((response) => dispatch(actions.CREATE_PROJECT_ERROR(response.response.data.errors)));
+ .catch(errors => dispatch(actions.CREATE_PROJECT_ERROR(errors.errors.join(''))));
};
export type ProjectAction = UnionOf<typeof actions>;
diff --git a/src/store/project/project-reducer.ts b/src/store/project/project-reducer.ts
index 10d272c..6df428c 100644
--- a/src/store/project/project-reducer.ts
+++ b/src/store/project/project-reducer.ts
@@ -18,6 +18,7 @@ interface ProjectCreator {
opened: boolean;
pending: boolean;
ownerUuid: string;
+ error?: string;
}
export function findTreeItem<T>(tree: Array<TreeItem<T>>, itemId: string): TreeItem<T> | undefined {
@@ -113,11 +114,11 @@ const initialState: ProjectState = {
const projectsReducer = (state: ProjectState = initialState, action: ProjectAction) => {
return actions.match(action, {
- OPEN_PROJECT_CREATOR: ({ ownerUuid }) => updateCreator(state, { ownerUuid, opened: true, pending: false }),
+ OPEN_PROJECT_CREATOR: ({ ownerUuid }) => updateCreator(state, { ownerUuid, opened: true }),
CLOSE_PROJECT_CREATOR: () => updateCreator(state, { opened: false }),
- CREATE_PROJECT: () => updateCreator(state, { pending: true }),
+ CREATE_PROJECT: () => updateCreator(state, { pending: true, error: undefined }),
CREATE_PROJECT_SUCCESS: () => updateCreator(state, { opened: false, ownerUuid: "", pending: false }),
- CREATE_PROJECT_ERROR: () => updateCreator(state, { ownerUuid: "", pending: false }),
+ CREATE_PROJECT_ERROR: error => updateCreator(state, { pending: false, error }),
REMOVE_PROJECT: () => state,
PROJECTS_REQUEST: itemId => {
const items = _.cloneDeep(state.items);
diff --git a/src/utils/dialog-validator.tsx b/src/utils/dialog-validator.tsx
index 1d1a921..848acec 100644
--- a/src/utils/dialog-validator.tsx
+++ b/src/utils/dialog-validator.tsx
@@ -10,19 +10,15 @@ type ValidatorProps = {
onChange: (isValid: boolean | string) => void;
render: (hasError: boolean) => React.ReactElement<any>;
isRequired: boolean;
+ duplicatedName?: string;
};
interface ValidatorState {
- isPatternValid: boolean;
isLengthValid: boolean;
}
-const nameRegEx = /^[a-zA-Z0-9-_ ]+$/;
-const maxInputLength = 60;
-
class Validator extends React.Component<ValidatorProps & WithStyles<CssRules>> {
state: ValidatorState = {
- isPatternValid: true,
isLengthValid: true
};
@@ -31,34 +27,35 @@ class Validator extends React.Component<ValidatorProps & WithStyles<CssRules>> {
if (this.props.value !== value) {
this.setState({
- isPatternValid: value.match(nameRegEx),
- isLengthValid: value.length < maxInputLength
+ isLengthValid: value.length < MAX_INPUT_LENGTH
}, () => this.onChange());
}
}
onChange() {
const { value, onChange, isRequired } = this.props;
- const { isPatternValid, isLengthValid } = this.state;
- const isValid = value && isPatternValid && isLengthValid && (isRequired || (!isRequired && value.length > 0));
+ const { isLengthValid } = this.state;
+ const isValid = value && isLengthValid && (isRequired || (!isRequired && value.length > 0));
onChange(isValid);
}
render() {
- const { classes, isRequired, value } = this.props;
- const { isPatternValid, isLengthValid } = this.state;
+ const { classes, isRequired, value, duplicatedName } = this.props;
+ const { isLengthValid } = this.state;
return (
<span>
- {this.props.render(!(isPatternValid && isLengthValid) && (isRequired || (!isRequired && value.length > 0)))}
- {!isPatternValid && (isRequired || (!isRequired && value.length > 0)) ? <span className={classes.formInputError}>This field allow only alphanumeric characters, dashes, spaces and underscores.<br /></span> : null}
- {!isLengthValid ? <span className={classes.formInputError}>This field should have max 60 characters.</span> : null}
+ {this.props.render(!isLengthValid && (isRequired || (!isRequired && value.length > 0)))}
+ {!isLengthValid ? <span className={classes.formInputError}>This field should have max 255 characters.</span> : null}
+ {duplicatedName ? <span className={classes.formInputError}>Project with this name already exists</span> : null}
</span>
);
}
}
+const MAX_INPUT_LENGTH = 255;
+
type CssRules = "formInputError";
const styles: StyleRulesCallback<CssRules> = theme => ({
diff --git a/src/views-components/create-project-dialog/create-project-dialog.tsx b/src/views-components/create-project-dialog/create-project-dialog.tsx
index eb69837..2cdd479 100644
--- a/src/views-components/create-project-dialog/create-project-dialog.tsx
+++ b/src/views-components/create-project-dialog/create-project-dialog.tsx
@@ -13,6 +13,7 @@ import { PROJECT_PANEL_ID } from "../../views/project-panel/project-panel";
const mapStateToProps = (state: RootState) => ({
open: state.projects.creator.opened,
pending: state.projects.creator.pending,
+ error: state.projects.creator.error
});
const submit = (data: { name: string, description: string }) =>
diff --git a/src/views-components/dialog-create/dialog-project-create.tsx b/src/views-components/dialog-create/dialog-project-create.tsx
index 48b8911..9f4768a 100644
--- a/src/views-components/dialog-create/dialog-project-create.tsx
+++ b/src/views-components/dialog-create/dialog-project-create.tsx
@@ -8,13 +8,14 @@ import Dialog from '@material-ui/core/Dialog';
import DialogActions from '@material-ui/core/DialogActions';
import DialogContent from '@material-ui/core/DialogContent';
import DialogTitle from '@material-ui/core/DialogTitle';
-import { Button, StyleRulesCallback, WithStyles, withStyles, CircularProgress } from '@material-ui/core';
+import { Button, StyleRulesCallback, WithStyles, withStyles, CircularProgress, Typography } from '@material-ui/core';
import Validator from '../../utils/dialog-validator';
interface ProjectCreateProps {
open: boolean;
pending: boolean;
+ error: string;
handleClose: () => void;
onSubmit: (data: { name: string, description: string }) => void;
}
@@ -24,6 +25,7 @@ interface DialogState {
description: string;
isNameValid: boolean;
isDescriptionValid: boolean;
+ duplicatedName: string;
}
class DialogProjectCreate extends React.Component<ProjectCreateProps & WithStyles<CssRules>> {
@@ -31,11 +33,22 @@ class DialogProjectCreate extends React.Component<ProjectCreateProps & WithStyle
name: '',
description: '',
isNameValid: false,
- isDescriptionValid: true
+ isDescriptionValid: true,
+ duplicatedName: ''
};
+ componentWillReceiveProps(nextProps: ProjectCreateProps) {
+ const { error } = nextProps;
+
+ if (this.props.error !== error) {
+ this.setState({
+ duplicatedName: error
+ });
+ }
+ }
+
render() {
- const { name, description, isNameValid, isDescriptionValid } = this.state;
+ const { name, description, isNameValid, isDescriptionValid, duplicatedName } = this.state;
const { classes, open, handleClose, pending } = this.props;
return (
@@ -49,6 +62,7 @@ class DialogProjectCreate extends React.Component<ProjectCreateProps & WithStyle
value={name}
onChange={e => this.isNameValid(e)}
isRequired={true}
+ duplicatedName={duplicatedName}
render={hasError =>
<TextField
margin="dense"
@@ -56,7 +70,7 @@ class DialogProjectCreate extends React.Component<ProjectCreateProps & WithStyle
id="name"
onChange={e => this.handleProjectName(e)}
label="Project name"
- error={hasError}
+ error={hasError || !!duplicatedName}
fullWidth />} />
<Validator
value={description}
@@ -74,14 +88,14 @@ class DialogProjectCreate extends React.Component<ProjectCreateProps & WithStyle
</DialogContent>
<DialogActions>
<Button onClick={handleClose} className={classes.button} color="primary" disabled={pending}>CANCEL</Button>
- <Button onClick={this.handleSubmit}
- className={classes.lastButton}
- color="primary"
- disabled={!isNameValid || (!isDescriptionValid && description.length > 0) || pending}
+ <Button onClick={this.handleSubmit}
+ className={classes.lastButton}
+ color="primary"
+ disabled={!isNameValid || (!isDescriptionValid && description.length > 0) || pending}
variant="contained">
CREATE A PROJECT
- </Button>
- {pending && <CircularProgress size={20} className={classes.createProgress} />}
+ </Button>
+ {pending && <CircularProgress size={20} className={classes.createProgress} />}
</DialogActions>
</div>
</Dialog>
@@ -98,6 +112,7 @@ class DialogProjectCreate extends React.Component<ProjectCreateProps & WithStyle
handleProjectName(e: any) {
this.setState({
name: e.target.value,
+ duplicatedName: ''
});
}
-----------------------------------------------------------------------
hooks/post-receive
--
More information about the arvados-commits
mailing list