mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-15 09:46:16 +01:00
update users module to use new pending and error state
This commit is contained in:
@@ -35,7 +35,10 @@ class Page extends React.Component<Props> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderContent() {
|
renderContent() {
|
||||||
const { loading, children } = this.props;
|
const { loading, children, error } = this.props;
|
||||||
|
if (error) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return <Loading />;
|
return <Loading />;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,11 @@ export default function reducer(state: Object = {}, action: Action): Object {
|
|||||||
} else {
|
} else {
|
||||||
const matches = RESET_PATTERN.exec(type);
|
const matches = RESET_PATTERN.exec(type);
|
||||||
if (matches) {
|
if (matches) {
|
||||||
return removeFromState(state, matches[1]);
|
let identifier = matches[1];
|
||||||
|
if (action.itemId) {
|
||||||
|
identifier += "/" + action.itemId;
|
||||||
|
}
|
||||||
|
return removeFromState(state, identifier);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return state;
|
return state;
|
||||||
|
|||||||
@@ -69,6 +69,16 @@ describe("pending reducer", () => {
|
|||||||
expect(newState["FETCH_USER/21"]).toBe(true);
|
expect(newState["FETCH_USER/21"]).toBe(true);
|
||||||
expect(newState["FETCH_USER/42"]).toBe(false);
|
expect(newState["FETCH_USER/42"]).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should reset pending for a single item", () => {
|
||||||
|
const newState = reducer(
|
||||||
|
{
|
||||||
|
"FETCH_USER/42": true
|
||||||
|
},
|
||||||
|
{ type: "FETCH_USER_SUCCESS", itemId: 42 }
|
||||||
|
);
|
||||||
|
expect(newState["FETCH_USER/42"]).toBeFalsy();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("pending selectors", () => {
|
describe("pending selectors", () => {
|
||||||
|
|||||||
4
scm-ui/src/modules/types.js
Normal file
4
scm-ui/src/modules/types.js
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export const PENDING_SUFFIX = "PENDING";
|
||||||
|
export const SUCCESS_SUFFIX = "SUCCESS";
|
||||||
|
export const FAILURE_SUFFIX = "FAILURE";
|
||||||
|
export const RESET_SUFFIX = "RESET";
|
||||||
@@ -10,9 +10,3 @@ export type PagedCollection = Collection & {
|
|||||||
page: number,
|
page: number,
|
||||||
pageTotal: number
|
pageTotal: number
|
||||||
};
|
};
|
||||||
|
|
||||||
export type PageCollectionStateSlice = {
|
|
||||||
entry?: PagedCollection,
|
|
||||||
error?: Error,
|
|
||||||
loading?: boolean
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
//@flow
|
//@flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { translate } from "react-i18next";
|
import { translate } from "react-i18next";
|
||||||
import type { UserEntry } from "../../types/UserEntry";
|
import type { User } from "../../types/User";
|
||||||
import { NavLink } from "../../../components/navigation";
|
import { NavLink } from "../../../components/navigation";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
t: string => string,
|
t: string => string,
|
||||||
user: UserEntry,
|
user: User,
|
||||||
editUrl: String
|
editUrl: String
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -2,16 +2,16 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { translate } from "react-i18next";
|
import { translate } from "react-i18next";
|
||||||
import UserRow from "./UserRow";
|
import UserRow from "./UserRow";
|
||||||
import type { UserEntry } from "../../types/UserEntry";
|
import type { User } from "../../types/User";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
t: string => string,
|
t: string => string,
|
||||||
entries: Array<UserEntry>
|
users: User[]
|
||||||
};
|
};
|
||||||
|
|
||||||
class UserTable extends React.Component<Props> {
|
class UserTable extends React.Component<Props> {
|
||||||
render() {
|
render() {
|
||||||
const { entries, t } = this.props;
|
const { users, t } = this.props;
|
||||||
return (
|
return (
|
||||||
<table className="table is-hoverable is-fullwidth">
|
<table className="table is-hoverable is-fullwidth">
|
||||||
<thead>
|
<thead>
|
||||||
@@ -23,8 +23,8 @@ class UserTable extends React.Component<Props> {
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{entries.map((entry, index) => {
|
{users.map((user, index) => {
|
||||||
return <UserRow key={index} user={entry.entry} />;
|
return <UserRow key={index} user={user} />;
|
||||||
})}
|
})}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@@ -4,17 +4,26 @@ import { connect } from "react-redux";
|
|||||||
import UserForm from "./../components/UserForm";
|
import UserForm from "./../components/UserForm";
|
||||||
import type { User } from "../types/User";
|
import type { User } from "../types/User";
|
||||||
import type { History } from "history";
|
import type { History } from "history";
|
||||||
import { createUser, createUserReset } from "../modules/users";
|
import {
|
||||||
|
createUser,
|
||||||
|
createUserReset,
|
||||||
|
isCreateUserPending,
|
||||||
|
getCreateUserFailure
|
||||||
|
} from "../modules/users";
|
||||||
import { Page } from "../../components/layout";
|
import { Page } from "../../components/layout";
|
||||||
import { translate } from "react-i18next";
|
import { translate } from "react-i18next";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
t: string => string,
|
|
||||||
addUser: (user: User, callback?: () => void) => void,
|
|
||||||
loading?: boolean,
|
loading?: boolean,
|
||||||
error?: Error,
|
error?: Error,
|
||||||
history: History,
|
|
||||||
resetForm: () => void
|
// dispatcher functions
|
||||||
|
addUser: (user: User, callback?: () => void) => void,
|
||||||
|
resetForm: () => void,
|
||||||
|
|
||||||
|
// context objects
|
||||||
|
t: string => string,
|
||||||
|
history: History
|
||||||
};
|
};
|
||||||
|
|
||||||
class AddUser extends React.Component<Props> {
|
class AddUser extends React.Component<Props> {
|
||||||
@@ -61,10 +70,12 @@ const mapDispatchToProps = dispatch => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = (state, ownProps) => {
|
const mapStateToProps = (state, ownProps) => {
|
||||||
if (state.users && state.users.create) {
|
const loading = isCreateUserPending(state);
|
||||||
return state.users.create;
|
const error = getCreateUserFailure(state);
|
||||||
}
|
return {
|
||||||
return {};
|
loading,
|
||||||
|
error
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
|
|||||||
@@ -1,16 +1,26 @@
|
|||||||
//@flow
|
//@flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {connect} from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import {withRouter} from "react-router-dom";
|
import { withRouter } from "react-router-dom";
|
||||||
import UserForm from "./../components/UserForm";
|
import UserForm from "./../components/UserForm";
|
||||||
import type {User} from "../types/User";
|
import type { User } from "../types/User";
|
||||||
import {modifyUser} from "../modules/users";
|
import {
|
||||||
import type {History} from "history";
|
modifyUser,
|
||||||
|
isModifyUserPending,
|
||||||
|
getModifyUserFailure
|
||||||
|
} from "../modules/users";
|
||||||
|
import type { History } from "history";
|
||||||
|
import ErrorNotification from "../../components/ErrorNotification";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
user: User,
|
|
||||||
modifyUser: (user: User, callback?: () => void) => void,
|
|
||||||
loading: boolean,
|
loading: boolean,
|
||||||
|
error: Error,
|
||||||
|
|
||||||
|
// dispatch functions
|
||||||
|
modifyUser: (user: User, callback?: () => void) => void,
|
||||||
|
|
||||||
|
// context objects
|
||||||
|
user: User,
|
||||||
history: History
|
history: History
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -24,8 +34,17 @@ class EditUser extends React.Component<Props> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { user } = this.props;
|
const { user, loading, error } = this.props;
|
||||||
return <UserForm submitForm={user => this.modifyUser(user)} user={user} />;
|
return (
|
||||||
|
<div>
|
||||||
|
<ErrorNotification error={error} />
|
||||||
|
<UserForm
|
||||||
|
submitForm={user => this.modifyUser(user)}
|
||||||
|
user={user}
|
||||||
|
loading={loading}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,7 +57,12 @@ const mapDispatchToProps = dispatch => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = (state, ownProps) => {
|
const mapStateToProps = (state, ownProps) => {
|
||||||
return {};
|
const loading = isModifyUserPending(state, ownProps.user.name);
|
||||||
|
const error = getModifyUserFailure(state, ownProps.user.name);
|
||||||
|
return {
|
||||||
|
loading,
|
||||||
|
error
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
|
|||||||
@@ -6,9 +6,16 @@ import { Route } from "react-router";
|
|||||||
import { Details } from "./../components/table";
|
import { Details } from "./../components/table";
|
||||||
import EditUser from "./EditUser";
|
import EditUser from "./EditUser";
|
||||||
import type { User } from "../types/User";
|
import type { User } from "../types/User";
|
||||||
import type { UserEntry } from "../types/UserEntry";
|
|
||||||
import type { History } from "history";
|
import type { History } from "history";
|
||||||
import { fetchUser, deleteUser } from "../modules/users";
|
import {
|
||||||
|
fetchUser,
|
||||||
|
deleteUser,
|
||||||
|
getUserByName,
|
||||||
|
isFetchUserPending,
|
||||||
|
getFetchUserFailure,
|
||||||
|
isDeleteUserPending,
|
||||||
|
getDeleteUserFailure
|
||||||
|
} from "../modules/users";
|
||||||
import Loading from "../../components/Loading";
|
import Loading from "../../components/Loading";
|
||||||
|
|
||||||
import { Navigation, Section, NavLink } from "../../components/navigation";
|
import { Navigation, Section, NavLink } from "../../components/navigation";
|
||||||
@@ -16,14 +23,19 @@ import { DeleteUserNavLink, EditUserNavLink } from "./../components/navLinks";
|
|||||||
import ErrorPage from "../../components/ErrorPage";
|
import ErrorPage from "../../components/ErrorPage";
|
||||||
import { translate } from "react-i18next";
|
import { translate } from "react-i18next";
|
||||||
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
t: string => string,
|
|
||||||
name: string,
|
name: string,
|
||||||
userEntry?: UserEntry,
|
user: User,
|
||||||
match: any,
|
loading: boolean,
|
||||||
|
error: Error,
|
||||||
|
|
||||||
|
// dispatcher functions
|
||||||
deleteUser: (user: User, callback?: () => void) => void,
|
deleteUser: (user: User, callback?: () => void) => void,
|
||||||
fetchUser: string => void,
|
fetchUser: string => void,
|
||||||
|
|
||||||
|
// context objects
|
||||||
|
t: string => string,
|
||||||
|
match: any,
|
||||||
history: History
|
history: History
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -52,23 +64,22 @@ class SingleUser extends React.Component<Props> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { t, userEntry } = this.props;
|
const { t, loading, error, user } = this.props;
|
||||||
|
|
||||||
if (!userEntry || userEntry.loading) {
|
if (error) {
|
||||||
return <Loading />;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (userEntry.error) {
|
|
||||||
return (
|
return (
|
||||||
<ErrorPage
|
<ErrorPage
|
||||||
title={t("single-user.error-title")}
|
title={t("single-user.error-title")}
|
||||||
subtitle={t("single-user.error-subtitle")}
|
subtitle={t("single-user.error-subtitle")}
|
||||||
error={userEntry.error}
|
error={error}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const user = userEntry.entry;
|
if (!user || loading) {
|
||||||
|
return <Loading />;
|
||||||
|
}
|
||||||
|
|
||||||
const url = this.matchedUrl();
|
const url = this.matchedUrl();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -84,7 +95,10 @@ class SingleUser extends React.Component<Props> {
|
|||||||
<div className="column">
|
<div className="column">
|
||||||
<Navigation>
|
<Navigation>
|
||||||
<Section label={t("single-user.navigation-label")}>
|
<Section label={t("single-user.navigation-label")}>
|
||||||
<NavLink to={`${url}`} label={t("single-user.information-label")} />
|
<NavLink
|
||||||
|
to={`${url}`}
|
||||||
|
label={t("single-user.information-label")}
|
||||||
|
/>
|
||||||
<EditUserNavLink user={user} editUrl={`${url}/edit`} />
|
<EditUserNavLink user={user} editUrl={`${url}/edit`} />
|
||||||
</Section>
|
</Section>
|
||||||
<Section label={t("single-user.actions-label")}>
|
<Section label={t("single-user.actions-label")}>
|
||||||
@@ -101,14 +115,17 @@ class SingleUser extends React.Component<Props> {
|
|||||||
|
|
||||||
const mapStateToProps = (state, ownProps) => {
|
const mapStateToProps = (state, ownProps) => {
|
||||||
const name = ownProps.match.params.name;
|
const name = ownProps.match.params.name;
|
||||||
let userEntry;
|
const user = getUserByName(state, name);
|
||||||
if (state.users && state.users.byNames) {
|
const loading =
|
||||||
userEntry = state.users.byNames[name];
|
isFetchUserPending(state, name) || isDeleteUserPending(state, name);
|
||||||
}
|
const error =
|
||||||
|
getFetchUserFailure(state, name) || getDeleteUserFailure(state, name);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name,
|
name,
|
||||||
userEntry
|
user,
|
||||||
|
loading,
|
||||||
|
error
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -9,20 +9,24 @@ import {
|
|||||||
fetchUsersByLink,
|
fetchUsersByLink,
|
||||||
getUsersFromState,
|
getUsersFromState,
|
||||||
selectListAsCollection,
|
selectListAsCollection,
|
||||||
isPermittedToCreateUsers
|
isPermittedToCreateUsers,
|
||||||
|
isFetchUsersPending,
|
||||||
|
getFetchUsersFailure
|
||||||
} from "../modules/users";
|
} from "../modules/users";
|
||||||
|
|
||||||
import { Page } from "../../components/layout";
|
import { Page } from "../../components/layout";
|
||||||
import { UserTable } from "./../components/table";
|
import { UserTable } from "./../components/table";
|
||||||
import type { UserEntry } from "../types/UserEntry";
|
import type { User } from "../types/User";
|
||||||
import type { PageCollectionStateSlice } from "../../types/Collection";
|
import type { PagedCollection } from "../../types/Collection";
|
||||||
import Paginator from "../../components/Paginator";
|
import Paginator from "../../components/Paginator";
|
||||||
import CreateUserButton from "../components/buttons/CreateUserButton";
|
import CreateUserButton from "../components/buttons/CreateUserButton";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
userEntries: UserEntry[],
|
users: User[],
|
||||||
|
loading: boolean,
|
||||||
|
error: Error,
|
||||||
canAddUsers: boolean,
|
canAddUsers: boolean,
|
||||||
list: PageCollectionStateSlice,
|
list: PagedCollection,
|
||||||
page: number,
|
page: number,
|
||||||
|
|
||||||
// context objects
|
// context objects
|
||||||
@@ -48,9 +52,9 @@ class Users extends React.Component<Props> {
|
|||||||
*/
|
*/
|
||||||
componentDidUpdate = (prevProps: Props) => {
|
componentDidUpdate = (prevProps: Props) => {
|
||||||
const { page, list } = this.props;
|
const { page, list } = this.props;
|
||||||
if (list.entry) {
|
if (list.page) {
|
||||||
// backend starts paging by 0
|
// backend starts paging by 0
|
||||||
const statePage: number = list.entry.page + 1;
|
const statePage: number = list.page + 1;
|
||||||
if (page !== statePage) {
|
if (page !== statePage) {
|
||||||
this.props.history.push(`/users/${statePage}`);
|
this.props.history.push(`/users/${statePage}`);
|
||||||
}
|
}
|
||||||
@@ -58,15 +62,15 @@ class Users extends React.Component<Props> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { userEntries, list, t } = this.props;
|
const { users, loading, error, t } = this.props;
|
||||||
return (
|
return (
|
||||||
<Page
|
<Page
|
||||||
title={t("users.title")}
|
title={t("users.title")}
|
||||||
subtitle={t("users.subtitle")}
|
subtitle={t("users.subtitle")}
|
||||||
loading={list.loading || !userEntries}
|
loading={loading || !users}
|
||||||
error={list.error}
|
error={error}
|
||||||
>
|
>
|
||||||
<UserTable entries={userEntries} />
|
<UserTable users={users} />
|
||||||
{this.renderPaginator()}
|
{this.renderPaginator()}
|
||||||
{this.renderCreateButton()}
|
{this.renderCreateButton()}
|
||||||
</Page>
|
</Page>
|
||||||
@@ -75,10 +79,8 @@ class Users extends React.Component<Props> {
|
|||||||
|
|
||||||
renderPaginator() {
|
renderPaginator() {
|
||||||
const { list } = this.props;
|
const { list } = this.props;
|
||||||
if (list.entry) {
|
if (list) {
|
||||||
return (
|
return <Paginator collection={list} onPageChange={this.onPageChange} />;
|
||||||
<Paginator collection={list.entry} onPageChange={this.onPageChange} />
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -103,12 +105,18 @@ const getPageFromProps = props => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = (state, ownProps) => {
|
const mapStateToProps = (state, ownProps) => {
|
||||||
|
const users = getUsersFromState(state);
|
||||||
|
const loading = isFetchUsersPending(state);
|
||||||
|
const error = getFetchUsersFailure(state);
|
||||||
|
|
||||||
const page = getPageFromProps(ownProps);
|
const page = getPageFromProps(ownProps);
|
||||||
const userEntries = getUsersFromState(state);
|
|
||||||
const canAddUsers = isPermittedToCreateUsers(state);
|
const canAddUsers = isPermittedToCreateUsers(state);
|
||||||
const list = selectListAsCollection(state);
|
const list = selectListAsCollection(state);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
userEntries,
|
users,
|
||||||
|
loading,
|
||||||
|
error,
|
||||||
canAddUsers,
|
canAddUsers,
|
||||||
list,
|
list,
|
||||||
page
|
page
|
||||||
|
|||||||
@@ -1,39 +1,46 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import { apiClient } from "../../apiclient";
|
import { apiClient } from "../../apiclient";
|
||||||
|
import { isPending } from "../../modules/pending";
|
||||||
|
import { getFailure } from "../../modules/failure";
|
||||||
|
import * as types from "../../modules/types";
|
||||||
import type { User } from "../types/User";
|
import type { User } from "../types/User";
|
||||||
import type { UserEntry } from "../types/UserEntry";
|
|
||||||
import { combineReducers, Dispatch } from "redux";
|
import { combineReducers, Dispatch } from "redux";
|
||||||
import type { Action } from "../../types/Action";
|
import type { Action } from "../../types/Action";
|
||||||
import type { PageCollectionStateSlice } from "../../types/Collection";
|
import type { PagedCollection } from "../../types/Collection";
|
||||||
|
|
||||||
export const FETCH_USERS_PENDING = "scm/users/FETCH_USERS_PENDING";
|
export const FETCH_USERS = "scm/users/FETCH_USERS";
|
||||||
export const FETCH_USERS_SUCCESS = "scm/users/FETCH_USERS_SUCCESS";
|
export const FETCH_USERS_PENDING = `${FETCH_USERS}_${types.PENDING_SUFFIX}`;
|
||||||
export const FETCH_USERS_FAILURE = "scm/users/FETCH_USERS_FAILURE";
|
export const FETCH_USERS_SUCCESS = `${FETCH_USERS}_${types.SUCCESS_SUFFIX}`;
|
||||||
|
export const FETCH_USERS_FAILURE = `${FETCH_USERS}_${types.FAILURE_SUFFIX}`;
|
||||||
|
|
||||||
export const FETCH_USER_PENDING = "scm/users/FETCH_USER_PENDING";
|
export const FETCH_USER = "scm/users/FETCH_USER";
|
||||||
export const FETCH_USER_SUCCESS = "scm/users/FETCH_USER_SUCCESS";
|
export const FETCH_USER_PENDING = `${FETCH_USER}_${types.PENDING_SUFFIX}`;
|
||||||
export const FETCH_USER_FAILURE = "scm/users/FETCH_USER_FAILURE";
|
export const FETCH_USER_SUCCESS = `${FETCH_USER}_${types.SUCCESS_SUFFIX}`;
|
||||||
|
export const FETCH_USER_FAILURE = `${FETCH_USER}_${types.FAILURE_SUFFIX}`;
|
||||||
|
|
||||||
export const CREATE_USER_PENDING = "scm/users/CREATE_USER_PENDING";
|
export const CREATE_USER = "scm/users/CREATE_USER";
|
||||||
export const CREATE_USER_SUCCESS = "scm/users/CREATE_USER_SUCCESS";
|
export const CREATE_USER_PENDING = `${CREATE_USER}_${types.PENDING_SUFFIX}`;
|
||||||
export const CREATE_USER_FAILURE = "scm/users/CREATE_USER_FAILURE";
|
export const CREATE_USER_SUCCESS = `${CREATE_USER}_${types.SUCCESS_SUFFIX}`;
|
||||||
export const CREATE_USER_RESET = "scm/users/CREATE_USER_RESET";
|
export const CREATE_USER_FAILURE = `${CREATE_USER}_${types.FAILURE_SUFFIX}`;
|
||||||
|
export const CREATE_USER_RESET = `${CREATE_USER}_${types.RESET_SUFFIX}`;
|
||||||
|
|
||||||
export const MODIFY_USER_PENDING = "scm/users/MODIFY_USER_PENDING";
|
export const MODIFY_USER = "scm/users/MODIFY_USER";
|
||||||
export const MODIFY_USER_SUCCESS = "scm/users/MODIFY_USER_SUCCESS";
|
export const MODIFY_USER_PENDING = `${MODIFY_USER}_${types.PENDING_SUFFIX}`;
|
||||||
export const MODIFY_USER_FAILURE = "scm/users/MODIFY_USER_FAILURE";
|
export const MODIFY_USER_SUCCESS = `${MODIFY_USER}_${types.SUCCESS_SUFFIX}`;
|
||||||
|
export const MODIFY_USER_FAILURE = `${MODIFY_USER}_${types.FAILURE_SUFFIX}`;
|
||||||
|
|
||||||
export const DELETE_USER_PENDING = "scm/users/DELETE_PENDING";
|
export const DELETE_USER = "scm/users/DELETE";
|
||||||
export const DELETE_USER_SUCCESS = "scm/users/DELETE_SUCCESS";
|
export const DELETE_USER_PENDING = `${DELETE_USER}_${types.PENDING_SUFFIX}`;
|
||||||
export const DELETE_USER_FAILURE = "scm/users/DELETE_FAILURE";
|
export const DELETE_USER_SUCCESS = `${DELETE_USER}_${types.SUCCESS_SUFFIX}`;
|
||||||
|
export const DELETE_USER_FAILURE = `${DELETE_USER}_${types.FAILURE_SUFFIX}`;
|
||||||
|
|
||||||
const USERS_URL = "users";
|
const USERS_URL = "users";
|
||||||
|
|
||||||
const CONTENT_TYPE_USER = "application/vnd.scmm-user+json;v=2";
|
const CONTENT_TYPE_USER = "application/vnd.scmm-user+json;v=2";
|
||||||
|
|
||||||
//TODO i18n
|
// TODO i18n for error messages
|
||||||
|
|
||||||
//fetch users
|
// fetch users
|
||||||
|
|
||||||
export function fetchUsers() {
|
export function fetchUsers() {
|
||||||
return fetchUsersByLink(USERS_URL);
|
return fetchUsersByLink(USERS_URL);
|
||||||
@@ -111,14 +118,16 @@ export function fetchUser(name: string) {
|
|||||||
export function fetchUserPending(name: string): Action {
|
export function fetchUserPending(name: string): Action {
|
||||||
return {
|
return {
|
||||||
type: FETCH_USER_PENDING,
|
type: FETCH_USER_PENDING,
|
||||||
payload: name
|
payload: name,
|
||||||
|
itemId: name
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fetchUserSuccess(user: any): Action {
|
export function fetchUserSuccess(user: any): Action {
|
||||||
return {
|
return {
|
||||||
type: FETCH_USER_SUCCESS,
|
type: FETCH_USER_SUCCESS,
|
||||||
payload: user
|
payload: user,
|
||||||
|
itemId: user.name
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,7 +137,8 @@ export function fetchUserFailure(name: string, error: Error): Action {
|
|||||||
payload: {
|
payload: {
|
||||||
name,
|
name,
|
||||||
error
|
error
|
||||||
}
|
},
|
||||||
|
itemId: name
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,14 +213,16 @@ export function modifyUser(user: User, callback?: () => void) {
|
|||||||
export function modifyUserPending(user: User): Action {
|
export function modifyUserPending(user: User): Action {
|
||||||
return {
|
return {
|
||||||
type: MODIFY_USER_PENDING,
|
type: MODIFY_USER_PENDING,
|
||||||
payload: user
|
payload: user,
|
||||||
|
itemId: user.name
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function modifyUserSuccess(user: User): Action {
|
export function modifyUserSuccess(user: User): Action {
|
||||||
return {
|
return {
|
||||||
type: MODIFY_USER_SUCCESS,
|
type: MODIFY_USER_SUCCESS,
|
||||||
payload: user
|
payload: user,
|
||||||
|
itemId: user.name
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,7 +232,8 @@ export function modifyUserFailure(user: User, error: Error): Action {
|
|||||||
payload: {
|
payload: {
|
||||||
error,
|
error,
|
||||||
user
|
user
|
||||||
}
|
},
|
||||||
|
itemId: user.name
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,14 +262,16 @@ export function deleteUser(user: User, callback?: () => void) {
|
|||||||
export function deleteUserPending(user: User): Action {
|
export function deleteUserPending(user: User): Action {
|
||||||
return {
|
return {
|
||||||
type: DELETE_USER_PENDING,
|
type: DELETE_USER_PENDING,
|
||||||
payload: user
|
payload: user,
|
||||||
|
itemId: user.name
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function deleteUserSuccess(user: User): Action {
|
export function deleteUserSuccess(user: User): Action {
|
||||||
return {
|
return {
|
||||||
type: DELETE_USER_SUCCESS,
|
type: DELETE_USER_SUCCESS,
|
||||||
payload: user
|
payload: user,
|
||||||
|
itemId: user.name
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -266,40 +281,20 @@ export function deleteUserFailure(user: User, error: Error): Action {
|
|||||||
payload: {
|
payload: {
|
||||||
error,
|
error,
|
||||||
user
|
user
|
||||||
}
|
},
|
||||||
|
itemId: user.name
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
//helper functions
|
|
||||||
|
|
||||||
export function getUsersFromState(state: any) {
|
|
||||||
if (!state.users.list) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const userNames = state.users.list.entries;
|
|
||||||
if (!userNames) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const userEntries: Array<UserEntry> = [];
|
|
||||||
|
|
||||||
for (let userName of userNames) {
|
|
||||||
userEntries.push(state.users.byNames[userName]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return userEntries;
|
|
||||||
}
|
|
||||||
|
|
||||||
function extractUsersByNames(
|
function extractUsersByNames(
|
||||||
users: Array<User>,
|
users: User[],
|
||||||
userNames: Array<string>,
|
userNames: string[],
|
||||||
oldUsersByNames: {}
|
oldUsersByNames: Object
|
||||||
) {
|
) {
|
||||||
const usersByNames = {};
|
const usersByNames = {};
|
||||||
|
|
||||||
for (let user of users) {
|
for (let user of users) {
|
||||||
usersByNames[user.name] = {
|
usersByNames[user.name] = user;
|
||||||
entry: user
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let userName in oldUsersByNames) {
|
for (let userName in oldUsersByNames) {
|
||||||
@@ -335,20 +330,12 @@ const reducerByName = (state: any, username: string, newUserState: any) => {
|
|||||||
|
|
||||||
function listReducer(state: any = {}, action: any = {}) {
|
function listReducer(state: any = {}, action: any = {}) {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
// Fetch all users actions
|
|
||||||
case FETCH_USERS_PENDING:
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
loading: true
|
|
||||||
};
|
|
||||||
case FETCH_USERS_SUCCESS:
|
case FETCH_USERS_SUCCESS:
|
||||||
const users = action.payload._embedded.users;
|
const users = action.payload._embedded.users;
|
||||||
const userNames = users.map(user => user.name);
|
const userNames = users.map(user => user.name);
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
error: null,
|
|
||||||
entries: userNames,
|
entries: userNames,
|
||||||
loading: false,
|
|
||||||
entry: {
|
entry: {
|
||||||
userCreatePermission: action.payload._links.create ? true : false,
|
userCreatePermission: action.payload._links.create ? true : false,
|
||||||
page: action.payload.page,
|
page: action.payload.page,
|
||||||
@@ -356,12 +343,7 @@ function listReducer(state: any = {}, action: any = {}) {
|
|||||||
_links: action.payload._links
|
_links: action.payload._links
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
case FETCH_USERS_FAILURE:
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
loading: false,
|
|
||||||
error: action.payload.error
|
|
||||||
};
|
|
||||||
// Delete single user actions
|
// Delete single user actions
|
||||||
case DELETE_USER_SUCCESS:
|
case DELETE_USER_SUCCESS:
|
||||||
const newUserEntries = deleteUserInEntries(
|
const newUserEntries = deleteUserInEntries(
|
||||||
@@ -389,44 +371,12 @@ function byNamesReducer(state: any = {}, action: any = {}) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Fetch single user actions
|
// Fetch single user actions
|
||||||
case FETCH_USER_PENDING:
|
|
||||||
return reducerByName(state, action.payload, {
|
|
||||||
loading: true,
|
|
||||||
error: null
|
|
||||||
});
|
|
||||||
case FETCH_USER_SUCCESS:
|
case FETCH_USER_SUCCESS:
|
||||||
return reducerByName(state, action.payload.name, {
|
return reducerByName(state, action.payload.name, action.payload);
|
||||||
loading: false,
|
|
||||||
error: null,
|
|
||||||
entry: action.payload
|
|
||||||
});
|
|
||||||
case FETCH_USER_FAILURE:
|
|
||||||
return reducerByName(state, action.payload.name, {
|
|
||||||
loading: false,
|
|
||||||
error: action.payload.error
|
|
||||||
});
|
|
||||||
|
|
||||||
// Update single user actions
|
|
||||||
case MODIFY_USER_PENDING:
|
|
||||||
return reducerByName(state, action.payload.name, {
|
|
||||||
loading: true
|
|
||||||
});
|
|
||||||
case MODIFY_USER_SUCCESS:
|
case MODIFY_USER_SUCCESS:
|
||||||
return reducerByName(state, action.payload.name, {
|
return reducerByName(state, action.payload.name, action.payload);
|
||||||
entry: action.payload
|
|
||||||
});
|
|
||||||
case MODIFY_USER_FAILURE:
|
|
||||||
return reducerByName(state, action.payload.user.name, {
|
|
||||||
error: action.payload.error
|
|
||||||
});
|
|
||||||
|
|
||||||
// Delete single user actions
|
|
||||||
case DELETE_USER_PENDING:
|
|
||||||
return reducerByName(state, action.payload.name, {
|
|
||||||
loading: true,
|
|
||||||
error: null,
|
|
||||||
entry: action.payload
|
|
||||||
});
|
|
||||||
case DELETE_USER_SUCCESS:
|
case DELETE_USER_SUCCESS:
|
||||||
const newUserByNames = deleteUserInUsersByNames(
|
const newUserByNames = deleteUserInUsersByNames(
|
||||||
state,
|
state,
|
||||||
@@ -434,17 +384,16 @@ function byNamesReducer(state: any = {}, action: any = {}) {
|
|||||||
);
|
);
|
||||||
return newUserByNames;
|
return newUserByNames;
|
||||||
|
|
||||||
case DELETE_USER_FAILURE:
|
|
||||||
return reducerByName(state, action.payload.user.name, {
|
|
||||||
loading: false,
|
|
||||||
error: action.payload.error,
|
|
||||||
entry: action.payload.user
|
|
||||||
});
|
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default combineReducers({
|
||||||
|
list: listReducer,
|
||||||
|
byNames: byNamesReducer
|
||||||
|
});
|
||||||
|
|
||||||
// selectors
|
// selectors
|
||||||
|
|
||||||
const selectList = (state: Object) => {
|
const selectList = (state: Object) => {
|
||||||
@@ -454,7 +403,7 @@ const selectList = (state: Object) => {
|
|||||||
return {};
|
return {};
|
||||||
};
|
};
|
||||||
|
|
||||||
const selectListEntry = (state: Object) => {
|
const selectListEntry = (state: Object): Object => {
|
||||||
const list = selectList(state);
|
const list = selectList(state);
|
||||||
if (list.entry) {
|
if (list.entry) {
|
||||||
return list.entry;
|
return list.entry;
|
||||||
@@ -462,10 +411,8 @@ const selectListEntry = (state: Object) => {
|
|||||||
return {};
|
return {};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const selectListAsCollection = (
|
export const selectListAsCollection = (state: Object): PagedCollection => {
|
||||||
state: Object
|
return selectListEntry(state);
|
||||||
): PageCollectionStateSlice => {
|
|
||||||
return selectList(state);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isPermittedToCreateUsers = (state: Object): boolean => {
|
export const isPermittedToCreateUsers = (state: Object): boolean => {
|
||||||
@@ -475,29 +422,63 @@ export const isPermittedToCreateUsers = (state: Object): boolean => {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
function createReducer(state: any = {}, action: any = {}) {
|
|
||||||
switch (action.type) {
|
export function getUsersFromState(state: Object) {
|
||||||
case CREATE_USER_PENDING:
|
const userNames = selectList(state).entries;
|
||||||
return {
|
if (!userNames) {
|
||||||
loading: true
|
return null;
|
||||||
};
|
}
|
||||||
case CREATE_USER_SUCCESS:
|
const userEntries: User[] = [];
|
||||||
case CREATE_USER_RESET:
|
|
||||||
return {
|
for (let userName of userNames) {
|
||||||
loading: false
|
userEntries.push(state.users.byNames[userName]);
|
||||||
};
|
}
|
||||||
case CREATE_USER_FAILURE:
|
|
||||||
return {
|
return userEntries;
|
||||||
loading: false,
|
}
|
||||||
error: action.payload
|
|
||||||
};
|
export function isFetchUsersPending(state: Object) {
|
||||||
default:
|
return isPending(state, FETCH_USERS);
|
||||||
return state;
|
}
|
||||||
|
|
||||||
|
export function getFetchUsersFailure(state: Object) {
|
||||||
|
return getFailure(state, FETCH_USERS);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isCreateUserPending(state: Object) {
|
||||||
|
return isPending(state, CREATE_USER);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getCreateUserFailure(state: Object) {
|
||||||
|
return getFailure(state, CREATE_USER);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getUserByName(state: Object, name: string) {
|
||||||
|
if (state.users && state.users.byNames) {
|
||||||
|
return state.users.byNames[name];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default combineReducers({
|
export function isFetchUserPending(state: Object, name: string) {
|
||||||
list: listReducer,
|
return isPending(state, FETCH_USER, name);
|
||||||
byNames: byNamesReducer,
|
}
|
||||||
create: createReducer
|
|
||||||
});
|
export function getFetchUserFailure(state: Object, name: string) {
|
||||||
|
return getFailure(state, FETCH_USER, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isModifyUserPending(state: Object, name: string) {
|
||||||
|
return isPending(state, MODIFY_USER, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getModifyUserFailure(state: Object, name: string) {
|
||||||
|
return getFailure(state, MODIFY_USER, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isDeleteUserPending(state: Object, name: string) {
|
||||||
|
return isPending(state, DELETE_USER, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getDeleteUserFailure(state: Object, name: string) {
|
||||||
|
return getFailure(state, DELETE_USER, name);
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,16 +8,10 @@ import reducer, {
|
|||||||
CREATE_USER_PENDING,
|
CREATE_USER_PENDING,
|
||||||
CREATE_USER_SUCCESS,
|
CREATE_USER_SUCCESS,
|
||||||
createUser,
|
createUser,
|
||||||
createUserFailure,
|
|
||||||
createUserPending,
|
|
||||||
createUserSuccess,
|
|
||||||
createUserReset,
|
|
||||||
DELETE_USER_FAILURE,
|
DELETE_USER_FAILURE,
|
||||||
DELETE_USER_PENDING,
|
DELETE_USER_PENDING,
|
||||||
DELETE_USER_SUCCESS,
|
DELETE_USER_SUCCESS,
|
||||||
deleteUser,
|
deleteUser,
|
||||||
deleteUserFailure,
|
|
||||||
deleteUserPending,
|
|
||||||
deleteUserSuccess,
|
deleteUserSuccess,
|
||||||
FETCH_USER_FAILURE,
|
FETCH_USER_FAILURE,
|
||||||
FETCH_USER_PENDING,
|
FETCH_USER_PENDING,
|
||||||
@@ -26,21 +20,15 @@ import reducer, {
|
|||||||
FETCH_USERS_PENDING,
|
FETCH_USERS_PENDING,
|
||||||
FETCH_USERS_SUCCESS,
|
FETCH_USERS_SUCCESS,
|
||||||
fetchUser,
|
fetchUser,
|
||||||
fetchUserFailure,
|
|
||||||
fetchUserPending,
|
|
||||||
fetchUsers,
|
|
||||||
fetchUsersFailure,
|
|
||||||
fetchUsersPending,
|
|
||||||
fetchUsersSuccess,
|
|
||||||
fetchUserSuccess,
|
fetchUserSuccess,
|
||||||
|
fetchUsers,
|
||||||
|
fetchUsersSuccess,
|
||||||
selectListAsCollection,
|
selectListAsCollection,
|
||||||
isPermittedToCreateUsers,
|
isPermittedToCreateUsers,
|
||||||
MODIFY_USER_FAILURE,
|
MODIFY_USER_FAILURE,
|
||||||
MODIFY_USER_PENDING,
|
MODIFY_USER_PENDING,
|
||||||
MODIFY_USER_SUCCESS,
|
MODIFY_USER_SUCCESS,
|
||||||
modifyUser,
|
modifyUser,
|
||||||
modifyUserFailure,
|
|
||||||
modifyUserPending,
|
|
||||||
modifyUserSuccess
|
modifyUserSuccess
|
||||||
} from "./users";
|
} from "./users";
|
||||||
|
|
||||||
@@ -325,19 +313,11 @@ describe("users fetch()", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("users reducer", () => {
|
describe("users reducer", () => {
|
||||||
it("should update state correctly according to FETCH_USERS_PENDING action", () => {
|
|
||||||
const newState = reducer({}, fetchUsersPending());
|
|
||||||
expect(newState.list.loading).toBeTruthy();
|
|
||||||
expect(newState.list.error).toBeFalsy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should update state correctly according to FETCH_USERS_SUCCESS action", () => {
|
it("should update state correctly according to FETCH_USERS_SUCCESS action", () => {
|
||||||
const newState = reducer({}, fetchUsersSuccess(responseBody));
|
const newState = reducer({}, fetchUsersSuccess(responseBody));
|
||||||
|
|
||||||
expect(newState.list).toEqual({
|
expect(newState.list).toEqual({
|
||||||
entries: ["zaphod", "ford"],
|
entries: ["zaphod", "ford"],
|
||||||
error: null,
|
|
||||||
loading: false,
|
|
||||||
entry: {
|
entry: {
|
||||||
userCreatePermission: true,
|
userCreatePermission: true,
|
||||||
page: 0,
|
page: 0,
|
||||||
@@ -347,31 +327,13 @@ describe("users reducer", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
expect(newState.byNames).toEqual({
|
expect(newState.byNames).toEqual({
|
||||||
zaphod: {
|
zaphod: userZaphod,
|
||||||
entry: userZaphod
|
ford: userFord
|
||||||
},
|
|
||||||
ford: {
|
|
||||||
entry: userFord
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(newState.list.entry.userCreatePermission).toBeTruthy();
|
expect(newState.list.entry.userCreatePermission).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should set error when fetching users failed", () => {
|
|
||||||
const oldState = {
|
|
||||||
list: {
|
|
||||||
loading: true
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const error = new Error("kaputt");
|
|
||||||
|
|
||||||
const newState = reducer(oldState, fetchUsersFailure("url.com", error));
|
|
||||||
expect(newState.list.loading).toBeFalsy();
|
|
||||||
expect(newState.list.error).toEqual(error);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should set userCreatePermission to true if update link is present", () => {
|
it("should set userCreatePermission to true if update link is present", () => {
|
||||||
const newState = reducer({}, fetchUsersSuccess(responseBody));
|
const newState = reducer({}, fetchUsersSuccess(responseBody));
|
||||||
|
|
||||||
@@ -381,9 +343,7 @@ describe("users reducer", () => {
|
|||||||
it("should not replace whole byNames map when fetching users", () => {
|
it("should not replace whole byNames map when fetching users", () => {
|
||||||
const oldState = {
|
const oldState = {
|
||||||
byNames: {
|
byNames: {
|
||||||
ford: {
|
ford: userFord
|
||||||
entry: userFord
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -392,95 +352,14 @@ describe("users reducer", () => {
|
|||||||
expect(newState.byNames["ford"]).toBeDefined();
|
expect(newState.byNames["ford"]).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should update state correctly according to DELETE_USER_PENDING action", () => {
|
|
||||||
const state = {
|
|
||||||
byNames: {
|
|
||||||
zaphod: {
|
|
||||||
loading: false,
|
|
||||||
error: null,
|
|
||||||
entry: userZaphod
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const newState = reducer(state, deleteUserPending(userZaphod));
|
|
||||||
const zaphod = newState.byNames["zaphod"];
|
|
||||||
expect(zaphod.loading).toBeTruthy();
|
|
||||||
expect(zaphod.entry).toBe(userZaphod);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not effect other users if one user will be deleted", () => {
|
|
||||||
const state = {
|
|
||||||
byNames: {
|
|
||||||
zaphod: {
|
|
||||||
loading: false,
|
|
||||||
error: null,
|
|
||||||
entry: userZaphod
|
|
||||||
},
|
|
||||||
ford: {
|
|
||||||
loading: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const newState = reducer(state, deleteUserPending(userZaphod));
|
|
||||||
const ford = newState.byNames["ford"];
|
|
||||||
expect(ford.loading).toBeFalsy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should set the error of user which could not be deleted", () => {
|
|
||||||
const state = {
|
|
||||||
byNames: {
|
|
||||||
zaphod: {
|
|
||||||
loading: true,
|
|
||||||
entry: userZaphod
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const error = new Error("error");
|
|
||||||
const newState = reducer(state, deleteUserFailure(userZaphod, error));
|
|
||||||
const zaphod = newState.byNames["zaphod"];
|
|
||||||
expect(zaphod.loading).toBeFalsy();
|
|
||||||
expect(zaphod.error).toBe(error);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not effect other users if one user could not be deleted", () => {
|
|
||||||
const state = {
|
|
||||||
byNames: {
|
|
||||||
zaphod: {
|
|
||||||
loading: false,
|
|
||||||
error: null,
|
|
||||||
entry: userZaphod
|
|
||||||
},
|
|
||||||
ford: {
|
|
||||||
loading: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const error = new Error("error");
|
|
||||||
const newState = reducer(state, deleteUserFailure(userZaphod, error));
|
|
||||||
const ford = newState.byNames["ford"];
|
|
||||||
expect(ford.loading).toBeFalsy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should remove user from state when delete succeeds", () => {
|
it("should remove user from state when delete succeeds", () => {
|
||||||
const state = {
|
const state = {
|
||||||
list: {
|
list: {
|
||||||
entries: ["ford", "zaphod"]
|
entries: ["ford", "zaphod"]
|
||||||
},
|
},
|
||||||
byNames: {
|
byNames: {
|
||||||
zaphod: {
|
zaphod: userZaphod,
|
||||||
loading: true,
|
ford: userFord
|
||||||
error: null,
|
|
||||||
entry: userZaphod
|
|
||||||
},
|
|
||||||
ford: {
|
|
||||||
loading: true,
|
|
||||||
error: null,
|
|
||||||
entry: userFord
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -499,68 +378,9 @@ describe("users reducer", () => {
|
|||||||
expect(newState.byNames["zaphod"]).toBeTruthy();
|
expect(newState.byNames["zaphod"]).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should update state correctly according to CREATE_USER_PENDING action", () => {
|
|
||||||
const newState = reducer({}, createUserPending(userZaphod));
|
|
||||||
expect(newState.create.loading).toBeTruthy();
|
|
||||||
expect(newState.create.error).toBeFalsy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should update state correctly according to CREATE_USER_SUCCESS action", () => {
|
|
||||||
const newState = reducer(
|
|
||||||
{ create: { loading: true } },
|
|
||||||
createUserSuccess()
|
|
||||||
);
|
|
||||||
expect(newState.create.loading).toBeFalsy();
|
|
||||||
expect(newState.create.error).toBeFalsy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should set the loading to false and the error if user could not be created", () => {
|
|
||||||
const newState = reducer(
|
|
||||||
{ create: { loading: true, error: null } },
|
|
||||||
createUserFailure(new Error("kaputt kaputt"))
|
|
||||||
);
|
|
||||||
expect(newState.create.loading).toBeFalsy();
|
|
||||||
expect(newState.create.error).toEqual(new Error("kaputt kaputt"));
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should reset the user create form", () => {
|
|
||||||
const newState = reducer(
|
|
||||||
{ create: { loading: true, error: new Error("kaputt kaputt") } },
|
|
||||||
createUserReset()
|
|
||||||
);
|
|
||||||
expect(newState.create.loading).toBeFalsy();
|
|
||||||
expect(newState.create.error).toBeFalsy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should update state according to FETCH_USER_PENDING action", () => {
|
|
||||||
const newState = reducer({}, fetchUserPending("zaphod"));
|
|
||||||
expect(newState.byNames["zaphod"].loading).toBeTruthy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not affect list state", () => {
|
|
||||||
const newState = reducer(
|
|
||||||
{
|
|
||||||
list: {
|
|
||||||
entries: ["ford"]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
fetchUserPending("zaphod")
|
|
||||||
);
|
|
||||||
expect(newState.byNames["zaphod"].loading).toBeTruthy();
|
|
||||||
expect(newState.list.entries).toEqual(["ford"]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should update state according to FETCH_USER_FAILURE action", () => {
|
|
||||||
const error = new Error("kaputt!");
|
|
||||||
const newState = reducer({}, fetchUserFailure(userFord.name, error));
|
|
||||||
expect(newState.byNames["ford"].error).toBe(error);
|
|
||||||
expect(newState.byNames["ford"].loading).toBeFalsy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should update state according to FETCH_USER_SUCCESS action", () => {
|
it("should update state according to FETCH_USER_SUCCESS action", () => {
|
||||||
const newState = reducer({}, fetchUserSuccess(userFord));
|
const newState = reducer({}, fetchUserSuccess(userFord));
|
||||||
expect(newState.byNames["ford"].loading).toBeFalsy();
|
expect(newState.byNames["ford"]).toBe(userFord);
|
||||||
expect(newState.byNames["ford"].entry).toBe(userFord);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should affect users state nor the state of other users", () => {
|
it("should affect users state nor the state of other users", () => {
|
||||||
@@ -572,62 +392,22 @@ describe("users reducer", () => {
|
|||||||
},
|
},
|
||||||
fetchUserSuccess(userFord)
|
fetchUserSuccess(userFord)
|
||||||
);
|
);
|
||||||
expect(newState.byNames["ford"].loading).toBeFalsy();
|
expect(newState.byNames["ford"]).toBe(userFord);
|
||||||
expect(newState.byNames["ford"].entry).toBe(userFord);
|
|
||||||
expect(newState.list.entries).toEqual(["zaphod"]);
|
expect(newState.list.entries).toEqual(["zaphod"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should update state according to MODIFY_USER_PENDING action", () => {
|
|
||||||
const newState = reducer(
|
|
||||||
{
|
|
||||||
byNames: {
|
|
||||||
ford: {
|
|
||||||
error: new Error("something"),
|
|
||||||
entry: {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
modifyUserPending(userFord)
|
|
||||||
);
|
|
||||||
expect(newState.byNames["ford"].loading).toBeTruthy();
|
|
||||||
expect(newState.byNames["ford"].error).toBeFalsy();
|
|
||||||
expect(newState.byNames["ford"].entry).toBeFalsy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should update state according to MODIFY_USER_SUCCESS action", () => {
|
it("should update state according to MODIFY_USER_SUCCESS action", () => {
|
||||||
const newState = reducer(
|
const newState = reducer(
|
||||||
{
|
{
|
||||||
byNames: {
|
byNames: {
|
||||||
ford: {
|
ford: {
|
||||||
loading: true,
|
name: "ford"
|
||||||
error: new Error("something"),
|
|
||||||
entry: {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
modifyUserSuccess(userFord)
|
modifyUserSuccess(userFord)
|
||||||
);
|
);
|
||||||
expect(newState.byNames["ford"].loading).toBeFalsy();
|
expect(newState.byNames["ford"]).toBe(userFord);
|
||||||
expect(newState.byNames["ford"].error).toBeFalsy();
|
|
||||||
expect(newState.byNames["ford"].entry).toBe(userFord);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should update state according to MODIFY_USER_SUCCESS action", () => {
|
|
||||||
const error = new Error("something went wrong");
|
|
||||||
const newState = reducer(
|
|
||||||
{
|
|
||||||
byNames: {
|
|
||||||
ford: {
|
|
||||||
loading: true,
|
|
||||||
entry: {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
modifyUserFailure(userFord, error)
|
|
||||||
);
|
|
||||||
expect(newState.byNames["ford"].loading).toBeFalsy();
|
|
||||||
expect(newState.byNames["ford"].error).toBe(error);
|
|
||||||
expect(newState.byNames["ford"].entry).toBeFalsy();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
export type UserEntry = {
|
|
||||||
loading: boolean,
|
|
||||||
error: Error,
|
|
||||||
entry: User
|
|
||||||
};
|
|
||||||
Reference in New Issue
Block a user