mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-08 14:35:45 +01:00
Bootstrapped validation for groups
This commit is contained in:
@@ -5,14 +5,17 @@ import InputField from "../../components/forms/InputField";
|
||||
import { SubmitButton } from "../../components/buttons";
|
||||
import { translate } from "react-i18next";
|
||||
import type { Group } from "../types/Group";
|
||||
import * as validator from "./groupValidation"
|
||||
|
||||
export interface Props {
|
||||
t: string => string;
|
||||
submitForm: Group => void;
|
||||
type Props = {
|
||||
t: string => string,
|
||||
submitForm: Group => void
|
||||
}
|
||||
|
||||
export interface State {
|
||||
group: Group;
|
||||
type State = {
|
||||
group: Group,
|
||||
nameValidationError: boolean,
|
||||
descriptionValidationError: boolean
|
||||
}
|
||||
|
||||
class GroupForm extends React.Component<Props, State> {
|
||||
@@ -28,21 +31,27 @@ class GroupForm extends React.Component<Props, State> {
|
||||
_links: {},
|
||||
members: [],
|
||||
type: "",
|
||||
}
|
||||
},
|
||||
nameValidationError: false,
|
||||
descriptionValidationError: false
|
||||
};
|
||||
}
|
||||
|
||||
onSubmit = (event: Event) => {
|
||||
event.preventDefault();
|
||||
this.props.submitForm(this.state.group);
|
||||
};
|
||||
|
||||
isValid = () => {
|
||||
return true;
|
||||
const group = this.state.group;
|
||||
return !(this.state.nameValidationError || this.state.descriptionValidationError || group.name);
|
||||
}
|
||||
|
||||
submit = (event: Event) => {
|
||||
event.preventDefault();
|
||||
this.props.submitForm(this.state.group)
|
||||
if (this.isValid) {
|
||||
this.props.submitForm(this.state.group)
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
@@ -51,15 +60,15 @@ class GroupForm extends React.Component<Props, State> {
|
||||
<form onSubmit={this.onSubmit}>
|
||||
<InputField
|
||||
label={t("group.name")}
|
||||
errorMessage=""
|
||||
errorMessage="group name invalid"
|
||||
onChange={this.handleGroupNameChange}
|
||||
validationError={false}
|
||||
validationError={this.state.nameValidationError}
|
||||
/>
|
||||
<InputField
|
||||
label={t("group.description")}
|
||||
errorMessage=""
|
||||
onChange={this.handleDescriptionChange}
|
||||
validationError={false}
|
||||
validationError={this.state.descriptionValidationError}
|
||||
/>
|
||||
<SubmitButton label={t("group-form.submit")} />
|
||||
</form>
|
||||
@@ -68,19 +77,14 @@ class GroupForm extends React.Component<Props, State> {
|
||||
|
||||
handleGroupNameChange = (name: string) => {
|
||||
this.setState({
|
||||
group: {
|
||||
...this.state.group,
|
||||
name
|
||||
}
|
||||
nameValidationError: !validator.isNameValid(name),
|
||||
group: {...this.state.group, name}
|
||||
});
|
||||
};
|
||||
|
||||
handleDescriptionChange = (description: string) => {
|
||||
this.setState({
|
||||
group: {
|
||||
...this.state.group,
|
||||
description
|
||||
}
|
||||
group: {...this.state.group, description }
|
||||
});
|
||||
};
|
||||
}
|
||||
10
scm-ui/src/groups/components/groupValidation.js
Normal file
10
scm-ui/src/groups/components/groupValidation.js
Normal file
@@ -0,0 +1,10 @@
|
||||
// @flow
|
||||
|
||||
//TODO: How should a group be validated
|
||||
//TODO: Tests!
|
||||
|
||||
const nameRegex = /^([A-z0-9.\-_@]|[^ ]([A-z0-9.\-_@ ]*[A-z0-9.\-_@]|[^\s])?)$/;
|
||||
|
||||
export const isNameValid = (name: string) => {
|
||||
return nameRegex.test(name);
|
||||
};
|
||||
@@ -3,17 +3,19 @@ import React from "react";
|
||||
|
||||
import Page from "../../components/layout/Page";
|
||||
import { translate } from "react-i18next";
|
||||
import GroupForm from "./GroupForm";
|
||||
import GroupForm from "../components/GroupForm";
|
||||
import { connect } from "react-redux";
|
||||
import { createGroup } from "../modules/groups";
|
||||
import type { Group } from "../types/Group";
|
||||
import type { History } from "history";
|
||||
|
||||
export interface Props {
|
||||
t: string => string;
|
||||
createGroup: Group => void;
|
||||
type Props = {
|
||||
t: string => string,
|
||||
createGroup: (group: Group, callback?: () => void) => void,
|
||||
history: History
|
||||
}
|
||||
|
||||
export interface State {}
|
||||
type State = {}
|
||||
|
||||
class AddGroup extends React.Component<Props, State> {
|
||||
render() {
|
||||
@@ -27,14 +29,18 @@ class AddGroup extends React.Component<Props, State> {
|
||||
);
|
||||
}
|
||||
|
||||
groupCreated = () => {
|
||||
console.log("pushing history")
|
||||
this.props.history.push("/groups")
|
||||
}
|
||||
createGroup = (group: Group) => {
|
||||
this.props.createGroup(group);
|
||||
this.props.createGroup(group, this.groupCreated)
|
||||
};
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
createGroup: (group: Group) => dispatch(createGroup(group))
|
||||
createGroup: (group: Group, callback?: () => void) => dispatch(createGroup(group, callback))
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -133,12 +133,16 @@ export function fetchGroupFailure(name: string, error: Error): Action {
|
||||
}
|
||||
|
||||
//create group
|
||||
export function createGroup(group: Group) {
|
||||
export function createGroup(group: Group, callback?: () => void) {
|
||||
return function(dispatch: Dispatch) {
|
||||
dispatch(createGroupPending());
|
||||
return apiClient
|
||||
.postWithContentType(GROUPS_URL, group, CONTENT_TYPE_GROUP)
|
||||
.then(() => dispatch(createGroupSuccess()))
|
||||
.then(() => {
|
||||
dispatch(createGroupSuccess())
|
||||
if (callback) {
|
||||
callback();
|
||||
}})
|
||||
.catch(error => {
|
||||
dispatch(
|
||||
createGroupFailure(
|
||||
@@ -168,6 +172,11 @@ export function createGroupFailure(error: Error) {
|
||||
};
|
||||
}
|
||||
|
||||
export function createGroupReset() {
|
||||
return {
|
||||
type: CREATE_GROUP_RESET
|
||||
}
|
||||
}
|
||||
//delete group
|
||||
|
||||
export function deleteGroup(group: Group, callback?: () => void) {
|
||||
|
||||
@@ -205,6 +205,25 @@ describe("groups fetch()", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("should call the callback after creating group", () => {
|
||||
fetchMock.postOnce(GROUPS_URL, {
|
||||
status: 201
|
||||
});
|
||||
let called = false;
|
||||
|
||||
const callMe = () => {
|
||||
called = true;
|
||||
}
|
||||
const store = mockStore({});
|
||||
return store.dispatch(createGroup(humanGroup, callMe)).then(() => {
|
||||
const actions = store.getActions();
|
||||
expect(actions[0].type).toEqual(CREATE_GROUP_PENDING);
|
||||
expect(actions[1].type).toEqual(CREATE_GROUP_SUCCESS);
|
||||
expect(called).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it("should fail creating group on HTTP 500", () => {
|
||||
fetchMock.postOnce(GROUPS_URL, {
|
||||
status: 500
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//@flow
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import UserForm from "./../components/UserForm";
|
||||
import UserForm from "../components/UserForm";
|
||||
import type { User } from "../types/User";
|
||||
import type { History } from "history";
|
||||
import {
|
||||
|
||||
Reference in New Issue
Block a user