refactor / new structure for repositoryRoles

This commit is contained in:
Eduard Heimbuch
2019-05-15 13:13:48 +02:00
parent dfbc2e2cfd
commit 8fd034d599
10 changed files with 260 additions and 28 deletions

View File

@@ -0,0 +1,28 @@
//@flow
import React from "react";
import type { User } from "@scm-manager/ui-types";
import { NavLink } from "@scm-manager/ui-components";
import { translate } from "react-i18next";
type Props = {
user: User,
editUrl: String,
t: string => string
};
class EditRepositoryRoleNavLink extends React.Component<Props> {
isEditable = () => {
return this.props.user._links.update;
};
render() {
const { t, editUrl } = this.props;
if (!this.isEditable()) {
return null;
}
return <NavLink to={editUrl} label={t("singleUser.menu.generalNavLink")} />;
}
}
export default translate("users")(EditRepositoryRoleNavLink);

View File

@@ -0,0 +1,27 @@
import React from "react";
import { shallow } from "enzyme";
import "../../../tests/enzyme";
import "../../../tests/i18n";
import EditUserNavLink from "./EditRepositoryRoleNavLink";
it("should render nothing, if the edit link is missing", () => {
const user = {
_links: {}
};
const navLink = shallow(<EditUserNavLink user={user} editUrl='/user/edit'/>);
expect(navLink.text()).toBe("");
});
it("should render the navLink", () => {
const user = {
_links: {
update: {
href: "/users"
}
}
};
const navLink = shallow(<EditUserNavLink user={user} editUrl='/user/edit'/>);
expect(navLink.text()).not.toBe("");
});

View File

@@ -0,0 +1,28 @@
//@flow
import React from "react";
import { translate } from "react-i18next";
import type { User } from "@scm-manager/ui-types";
import { NavLink } from "@scm-manager/ui-components";
type Props = {
t: string => string,
user: User,
permissionsUrl: String
};
class ChangePermissionNavLink extends React.Component<Props> {
render() {
const { t, permissionsUrl } = this.props;
// if (!this.hasPermissionToSetPermission()) {
// return null;
// }
return <NavLink to={permissionsUrl} label={t("singleUser.menu.setPermissionsNavLink")} />;
}
// hasPermissionToSetPermission = () => {
// return this.props.user._links.permissions;
// };
}
export default translate("users")(ChangePermissionNavLink);

View File

@@ -0,0 +1,31 @@
import React from "react";
import { shallow } from "enzyme";
import "../../../tests/enzyme";
import "../../../tests/i18n";
import SetPermissionsNavLink from "./RepositoryRoleDetailNavLink";
it("should render nothing, if the permissions link is missing", () => {
const user = {
_links: {}
};
const navLink = shallow(
<SetPermissionsNavLink user={user} permissionsUrl="/user/permissions" />
);
expect(navLink.text()).toBe("");
});
it("should render the navLink", () => {
const user = {
_links: {
permissions: {
href: "/permissions"
}
}
};
const navLink = shallow(
<SetPermissionsNavLink user={user} permissionsUrl="/user/permissions" />
);
expect(navLink.text()).not.toBe("");
});

View File

@@ -0,0 +1,2 @@
export { default as EditRepositoryRoleNavLink } from "./EditRepositoryRoleNavLink";
export { default as RepositoryRoleDetailNavLink } from "./RepositoryRoleDetailNavLink";

View File

@@ -15,7 +15,8 @@ class PermissionRoleRow extends React.Component<Props> {
render() { render() {
const { baseUrl, role } = this.props; const { baseUrl, role } = this.props;
const to = `${baseUrl}/${encodeURIComponent(role.name)}/edit`; const singleRoleUrl = baseUrl.substring(0, baseUrl.length - 1);
const to = `${singleRoleUrl}/${encodeURIComponent(role.name)}`;
return ( return (
<tr> <tr>
<td>{this.renderLink(to, role.name)}</td> <td>{this.renderLink(to, role.name)}</td>

View File

@@ -10,8 +10,9 @@ import type { Links } from "@scm-manager/ui-types";
import { Page, Navigation, NavLink, Section } from "@scm-manager/ui-components"; import { Page, Navigation, NavLink, Section } from "@scm-manager/ui-components";
import { getLinks } from "../../modules/indexResource"; import { getLinks } from "../../modules/indexResource";
import GlobalConfig from "./GlobalConfig"; import GlobalConfig from "./GlobalConfig";
import GlobalPermissionRoles from "./GlobalPermissionRoles"; import RepositoryRoles from "./RepositoryRoles";
import GlobalPermissionRoleForm from "./GlobalPermissionRoleForm"; import RepositoryRoleForm from "./RepositoryRoleForm"
import SingleRepositoryRole from "./SingleRepositoryRole";
type Props = { type Props = {
links: Links, links: Links,
@@ -57,13 +58,9 @@ class Config extends React.Component<Props> {
<Route <Route
path={`${url}/roles`} path={`${url}/roles`}
exact exact
render={() => ( render={() => <RepositoryRoles baseUrl={`${url}/roles`} />}
<GlobalPermissionRoles
baseUrl={`${url}/role`}
/> />
)} <Route path={`${url}/role`} component={SingleRepositoryRole} />
/>
<Route path={`${url}/role`} component={GlobalPermissionRoleForm} />
<ExtensionPoint <ExtensionPoint
name="config.route" name="config.route"
props={extensionProps} props={extensionProps}

View File

@@ -6,12 +6,13 @@ import type { Role } from "@scm-manager/ui-types";
import { InputField, SubmitButton } from "@scm-manager/ui-components"; import { InputField, SubmitButton } from "@scm-manager/ui-components";
import PermissionCheckbox from "../../repos/permissions/components/PermissionCheckbox"; import PermissionCheckbox from "../../repos/permissions/components/PermissionCheckbox";
import { import {
createRole,
fetchAvailableVerbs, fetchAvailableVerbs,
getFetchVerbsFailure, getFetchVerbsFailure,
getVerbsFromState, getVerbsFromState,
isFetchVerbsPending isFetchVerbsPending
} from "../modules/roles"; } from "../modules/roles";
import { getRepositoryVerbsLink } from "../../modules/indexResource"; import {getRepositoryRolesLink, getRepositoryVerbsLink} from "../../modules/indexResource";
type Props = { type Props = {
role?: Role, role?: Role,
@@ -24,14 +25,15 @@ type Props = {
t: string => string, t: string => string,
// dispatch functions // dispatch functions
fetchAvailableVerbs: (link: string) => void fetchAvailableVerbs: (link: string) => void,
addRole: (link: string, role: Role) => void
}; };
type State = { type State = {
role: Role role: Role
}; };
class GlobalPermissionRoleForm extends React.Component<Props, State> { class RepositoryRoleForm extends React.Component<Props, State> {
constructor(props: Props) { constructor(props: Props) {
super(props); super(props);
@@ -46,17 +48,8 @@ class GlobalPermissionRoleForm extends React.Component<Props, State> {
} }
componentDidMount() { componentDidMount() {
const { fetchAvailableVerbs, verbsLink, role } = this.props; const { fetchAvailableVerbs, verbsLink} = this.props;
fetchAvailableVerbs(verbsLink); fetchAvailableVerbs(verbsLink);
if (role) {
this.setState({
role: {
...role,
role: { verbs: role.verbs }
}
});
}
} }
isFalsy(value) { isFalsy(value) {
@@ -100,8 +93,7 @@ class GlobalPermissionRoleForm extends React.Component<Props, State> {
submit = (event: Event) => { submit = (event: Event) => {
event.preventDefault(); event.preventDefault();
if (this.isValid()) { if (this.isValid()) {
// this.props.submitForm(this.state.role); this.props.addRole(this.props.repositoryRolesLink, this.state.role)
//TODO ADD createRole here
} }
}; };
@@ -155,12 +147,14 @@ const mapStateToProps = (state, ownProps) => {
const error = getFetchVerbsFailure(state); const error = getFetchVerbsFailure(state);
const verbsLink = getRepositoryVerbsLink(state); const verbsLink = getRepositoryVerbsLink(state);
const availableVerbs = getVerbsFromState(state); const availableVerbs = getVerbsFromState(state);
const repositoryRolesLink = getRepositoryRolesLink(state);
return { return {
loading, loading,
error, error,
verbsLink, verbsLink,
availableVerbs availableVerbs,
repositoryRolesLink
}; };
}; };
@@ -168,6 +162,9 @@ const mapDispatchToProps = dispatch => {
return { return {
fetchAvailableVerbs: (link: string) => { fetchAvailableVerbs: (link: string) => {
dispatch(fetchAvailableVerbs(link)); dispatch(fetchAvailableVerbs(link));
},
addRole: (link: string, role: Role) => {
createRole(link, role)
} }
}; };
}; };
@@ -175,4 +172,4 @@ const mapDispatchToProps = dispatch => {
export default connect( export default connect(
mapStateToProps, mapStateToProps,
mapDispatchToProps mapDispatchToProps
)(translate("roles")(GlobalPermissionRoleForm)); )(translate("roles")(RepositoryRoleForm));

View File

@@ -41,7 +41,7 @@ type Props = {
fetchRolesByPage: (link: string, page: number) => void fetchRolesByPage: (link: string, page: number) => void
}; };
class GlobalPermissionRoles extends React.Component<Props> { class RepositoryRoles extends React.Component<Props> {
componentDidMount() { componentDidMount() {
const { fetchRolesByPage, rolesLink, page } = this.props; const { fetchRolesByPage, rolesLink, page } = this.props;
fetchRolesByPage(rolesLink, page); fetchRolesByPage(rolesLink, page);
@@ -119,4 +119,4 @@ const mapDispatchToProps = dispatch => {
export default withRouter(connect( export default withRouter(connect(
mapStateToProps, mapStateToProps,
mapDispatchToProps mapDispatchToProps
)(translate("config")(GlobalPermissionRoles))); )(translate("config")(RepositoryRoles)));

View File

@@ -0,0 +1,121 @@
//@flow
import React from "react";
import { connect } from "react-redux";
import {
Page,
Loading,
ErrorPage
} from "@scm-manager/ui-components";
import { Route } from "react-router";
import type { History } from "history";
import { EditRepositoryRoleNavLink, RepositoryRoleDetailNavLink } from "./../components/navLinks";
import { translate } from "react-i18next";
import type { Role } from "@scm-manager/ui-types";
import {getRepositoryRolesLink} from "../../modules/indexResource";
import {ExtensionPoint} from "@scm-manager/ui-extensions";
import {fetchRoleByName, getFetchRoleFailure, getRoleByName, isFetchRolePending} from "../modules/roles";
type Props = {
name: string,
role: Role,
loading: boolean,
error: Error,
repositoryRolesLink: string,
// dispatcher function
fetchRoleByName: (string, string) => void,
// context objects
t: string => string,
match: any,
history: History
};
class SingleRepositoryRole extends React.Component<Props> {
componentDidMount() {
this.props.fetchRoleByName(this.props.repositoryRolesLink, this.props.name);
}
stripEndingSlash = (url: string) => {
if (url.endsWith("/")) {
return url.substring(0, url.length - 2);
}
return url;
};
matchedUrl = () => {
return this.stripEndingSlash(this.props.match.url);
};
render() {
const { t, loading, error, role } = this.props;
if (error) {
return (
<ErrorPage
title={t("singleUser.errorTitle")}
subtitle={t("singleUser.errorSubtitle")}
error={error}
/>
);
}
if (!role || loading) {
return <Loading />;
}
const url = this.matchedUrl();
const extensionProps = {
role,
url
};
return (
<Page title={role.displayName}>
<div className="columns">
<div className="column is-three-quarters">
<Route path={url} exact component={() => <RepositoryRoleDetailNavLink role={role} />} />
<Route
path={`${url}/settings/general`}
component={() => <EditRepositoryRoleNavLink role={role} />}
/>
<ExtensionPoint
name="user.route"
props={extensionProps}
renderAll={true}
/>
</div>
</div>
</Page>
);
}
}
const mapStateToProps = (state, ownProps) => {
const name = ownProps.match.params.name;
const role = getRoleByName(state, name);
const loading = isFetchRolePending(state, name);
const error = getFetchRoleFailure(state, name);
const repositoryRolesLink = getRepositoryRolesLink(state);
return {
repositoryRolesLink,
name,
role,
loading,
error
};
};
const mapDispatchToProps = dispatch => {
return {
fetchRoleByName: (link: string, name: string) => {
dispatch(fetchRoleByName(link, name));
}
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(translate("users")(SingleRepositoryRole));