mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-14 01:15:44 +01:00
Merge with custom roles branch
This commit is contained in:
@@ -12,6 +12,8 @@ export type ButtonProps = {
|
||||
fullWidth?: boolean,
|
||||
className?: string,
|
||||
children?: React.Node,
|
||||
|
||||
// context props
|
||||
classes: any
|
||||
};
|
||||
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
//@flow
|
||||
import type {Links} from "./hal";
|
||||
|
||||
export type PermissionCreateEntry = {
|
||||
name: string,
|
||||
role?: string,
|
||||
verbs?: string[],
|
||||
groupPermission: boolean
|
||||
}
|
||||
|
||||
export type Permission = PermissionCreateEntry & {
|
||||
_links: Links
|
||||
};
|
||||
|
||||
export type PermissionCreateEntry = {
|
||||
name: string,
|
||||
verbs: string[],
|
||||
groupPermission: boolean
|
||||
}
|
||||
|
||||
export type PermissionCollection = Permission[];
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
// @flow
|
||||
|
||||
import type {Links} from "./hal";
|
||||
|
||||
export type RepositoryRole = {
|
||||
name: string,
|
||||
verbs: string[],
|
||||
type?: string,
|
||||
creationDate?: string,
|
||||
lastModified?: string,
|
||||
_links: Links
|
||||
};
|
||||
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
//@flow
|
||||
|
||||
import type { Links } from "./hal";
|
||||
|
||||
export type Role = {
|
||||
name: string,
|
||||
verbs: string[],
|
||||
creationDate?: number,
|
||||
lastModified?: number,
|
||||
system: boolean,
|
||||
_links: Links
|
||||
};
|
||||
@@ -16,7 +16,6 @@ export type { Changeset } from "./Changesets";
|
||||
export type { Tag } from "./Tags";
|
||||
|
||||
export type { Config } from "./Config";
|
||||
export type { Role } from "./Role";
|
||||
|
||||
export type { IndexResources } from "./IndexResources";
|
||||
|
||||
|
||||
@@ -6,12 +6,22 @@
|
||||
"errorTitle": "Fehler",
|
||||
"errorSubtitle": "Unbekannter Einstellungen Fehler"
|
||||
},
|
||||
"roles": {
|
||||
"repositoryRole": {
|
||||
"navLink": "Berechtigungsrollen",
|
||||
"title": "Berechtigungsrollen",
|
||||
"noPermissionRoles": "Keine Berechtigungsrollen gefunden.",
|
||||
"system": "System",
|
||||
"createButton": "Berechtigungsrolle erstellen",
|
||||
"name": "Name",
|
||||
"type": "Typ",
|
||||
"verbs": "Verben",
|
||||
"button": {
|
||||
"edit": "Bearbeiten"
|
||||
},
|
||||
"create": {
|
||||
"name": "Name"
|
||||
},
|
||||
"edit": "Berechtigungsrolle bearbeiten",
|
||||
"form": {
|
||||
"subtitle": "Berechtigungsrolle bearbeiten",
|
||||
"name": "Name",
|
||||
@@ -19,6 +29,10 @@
|
||||
"submit": "Speichern"
|
||||
}
|
||||
},
|
||||
"role": {
|
||||
"name": "Name",
|
||||
"system": "System"
|
||||
},
|
||||
"config-form": {
|
||||
"submit": "Speichern",
|
||||
"submit-success-notification": "Einstellungen wurden erfolgreich geändert!",
|
||||
|
||||
@@ -119,6 +119,7 @@
|
||||
"error-subtitle": "Unbekannter Fehler bei Berechtigung",
|
||||
"name": "Benutzer oder Gruppe",
|
||||
"role": "Rolle",
|
||||
"custom": "CUSTOM",
|
||||
"permissions": "Berechtigung",
|
||||
"group-permission": "Gruppenberechtigung",
|
||||
"user-permission": "Benutzerberechtigung",
|
||||
|
||||
@@ -6,11 +6,22 @@
|
||||
"errorTitle": "Error",
|
||||
"errorSubtitle": "Unknown Config Error"
|
||||
},
|
||||
"roles": {
|
||||
"repositoryRole": {
|
||||
"navLink": "Permission Roles",
|
||||
"title": "Permission Roles",
|
||||
"noPermissionRoles": "No permission roles found.",
|
||||
"system": "System",
|
||||
"createButton": "Create Permission Role",
|
||||
"name": "Name",
|
||||
"type": "Type",
|
||||
"verbs": "Verbs",
|
||||
"edit": "Edit Permission Role",
|
||||
"button": {
|
||||
"edit": "Edit"
|
||||
},
|
||||
"create": {
|
||||
"name": "Name"
|
||||
},
|
||||
"form": {
|
||||
"subtitle": "Edit Permission Role",
|
||||
"name": "Name",
|
||||
|
||||
@@ -122,6 +122,7 @@
|
||||
"error-subtitle": "Unknown permissions error",
|
||||
"name": "User or group",
|
||||
"role": "Role",
|
||||
"custom": "CUSTOM",
|
||||
"permissions": "Permissions",
|
||||
"group-permission": "Group Permission",
|
||||
"user-permission": "User Permission",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// @flow
|
||||
import React from "react";
|
||||
import { translate } from "react-i18next";
|
||||
import { Route } from "react-router";
|
||||
import { Route, Switch } from "react-router-dom";
|
||||
import { ExtensionPoint } from "@scm-manager/ui-extensions";
|
||||
import type { History } from "history";
|
||||
import { connect } from "react-redux";
|
||||
@@ -10,9 +10,9 @@ import type { Links } from "@scm-manager/ui-types";
|
||||
import { Page, Navigation, NavLink, Section } from "@scm-manager/ui-components";
|
||||
import { getLinks } from "../../modules/indexResource";
|
||||
import GlobalConfig from "./GlobalConfig";
|
||||
import PermissionRolesOverview from "../roles/containers/PermissionRolesOverview";
|
||||
import PermissionRoleRoot from "../roles/containers/PermissionRoleRoot";
|
||||
import CreatePermissionRole from "../roles/containers/CreatePermissionRole";
|
||||
import RepositoryRoles from "../roles/containers/RepositoryRoles";
|
||||
import SingleRepositoryRole from "../roles/containers/SingleRepositoryRole";
|
||||
import CreateRepositoryRole from "../roles/containers/CreateRepositoryRole";
|
||||
|
||||
type Props = {
|
||||
links: Links,
|
||||
@@ -37,7 +37,7 @@ class Config extends React.Component<Props> {
|
||||
|
||||
matchesRoles = (route: any) => {
|
||||
const url = this.matchedUrl();
|
||||
const regex = new RegExp(`${url}/role/.+/info`);
|
||||
const regex = new RegExp(`${url}/role/`);
|
||||
return route.location.pathname.match(regex);
|
||||
};
|
||||
|
||||
@@ -54,25 +54,44 @@ class Config extends React.Component<Props> {
|
||||
<Page>
|
||||
<div className="columns">
|
||||
<div className="column is-three-quarters">
|
||||
<Switch>
|
||||
<Route path={url} exact component={GlobalConfig} />
|
||||
<Route
|
||||
path={`${url}/role/:role`}
|
||||
component={() => <PermissionRoleRoot baseUrl={`${url}/roles`} />}
|
||||
render={() => (
|
||||
<SingleRepositoryRole
|
||||
baseUrl={`${url}/roles`}
|
||||
history={this.props.history}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<Route
|
||||
path={`${url}/roles`}
|
||||
exact
|
||||
render={() => <PermissionRolesOverview baseUrl={`${url}/role`} />}
|
||||
render={() => <RepositoryRoles baseUrl={`${url}/roles`} />}
|
||||
/>
|
||||
<Route
|
||||
path={`${url}/roles/create`}
|
||||
render={() => <CreatePermissionRole />}
|
||||
render={() => (
|
||||
<CreateRepositoryRole
|
||||
disabled={false}
|
||||
history={this.props.history}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<Route
|
||||
path={`${url}/roles/:page`}
|
||||
exact
|
||||
render={() => (
|
||||
<RepositoryRoles baseUrl={`${url}/roles`} />
|
||||
)}
|
||||
/>
|
||||
<ExtensionPoint
|
||||
name="config.route"
|
||||
props={extensionProps}
|
||||
renderAll={true}
|
||||
/>
|
||||
</Switch>
|
||||
</div>
|
||||
<div className="column is-one-quarter">
|
||||
<Navigation>
|
||||
@@ -83,9 +102,8 @@ class Config extends React.Component<Props> {
|
||||
/>
|
||||
<NavLink
|
||||
to={`${url}/roles/`}
|
||||
label={t("roles.navLink")}
|
||||
label={t("repositoryRole.navLink")}
|
||||
activeWhenMatch={this.matchesRoles}
|
||||
activeOnlyWhenExact={false}
|
||||
/>
|
||||
<ExtensionPoint
|
||||
name="config.navigation"
|
||||
|
||||
47
scm-ui/src/config/roles/components/AvailableVerbs.js
Normal file
47
scm-ui/src/config/roles/components/AvailableVerbs.js
Normal file
@@ -0,0 +1,47 @@
|
||||
//@flow
|
||||
import React from "react";
|
||||
import type { RepositoryRole } from "@scm-manager/ui-types";
|
||||
import { translate } from "react-i18next";
|
||||
import { compose } from "redux";
|
||||
import injectSheet from "react-jss";
|
||||
|
||||
type Props = {
|
||||
role: RepositoryRole,
|
||||
// context props
|
||||
t: string => string
|
||||
};
|
||||
|
||||
const styles = {
|
||||
spacing: {
|
||||
padding: "0 !important"
|
||||
}
|
||||
};
|
||||
|
||||
class AvailableVerbs extends React.Component<Props> {
|
||||
render() {
|
||||
const { role, t, classes } = this.props;
|
||||
|
||||
let verbs = null;
|
||||
if (role.verbs.length > 0) {
|
||||
verbs = (
|
||||
<tr>
|
||||
<td className={classes.spacing}>
|
||||
<ul>
|
||||
{role.verbs.map(verb => {
|
||||
return (
|
||||
<li>{t("verbs.repository." + verb + ".displayName")}</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
return verbs;
|
||||
}
|
||||
}
|
||||
|
||||
export default compose(
|
||||
injectSheet(styles),
|
||||
translate("plugins")
|
||||
)(AvailableVerbs);
|
||||
@@ -1,29 +0,0 @@
|
||||
//@flow
|
||||
import React from "react";
|
||||
import { translate } from "react-i18next";
|
||||
import type { Role } from "@scm-manager/ui-types";
|
||||
import SystemRoleTag from "./SystemRoleTag";
|
||||
|
||||
type Props = {
|
||||
role: Role,
|
||||
|
||||
// context props
|
||||
t: string => string,
|
||||
};
|
||||
|
||||
class PermissionRoleDetail extends React.Component<Props> {
|
||||
render() {
|
||||
const { role, t } = this.props;
|
||||
|
||||
return (
|
||||
<div className="media">
|
||||
<div className="media-content subtitle">
|
||||
<strong>{t("role.name")}:</strong> {role.name}{" "}
|
||||
<SystemRoleTag system={!role._links.update} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default translate("config")(PermissionRoleDetail);
|
||||
52
scm-ui/src/config/roles/components/PermissionRoleDetails.js
Normal file
52
scm-ui/src/config/roles/components/PermissionRoleDetails.js
Normal file
@@ -0,0 +1,52 @@
|
||||
//@flow
|
||||
import React from "react";
|
||||
import { translate } from "react-i18next";
|
||||
import type { RepositoryRole } from "@scm-manager/ui-types";
|
||||
import ExtensionPoint from "@scm-manager/ui-extensions/lib/ExtensionPoint";
|
||||
import PermissionRoleDetailsTable from "./PermissionRoleDetailsTable";
|
||||
import { Button, Subtitle } from "@scm-manager/ui-components";
|
||||
|
||||
type Props = {
|
||||
role: RepositoryRole,
|
||||
url: string,
|
||||
|
||||
// context props
|
||||
t: string => string
|
||||
};
|
||||
|
||||
class PermissionRoleDetails extends React.Component<Props> {
|
||||
renderEditButton() {
|
||||
const { t, url } = this.props;
|
||||
if (!!this.props.role._links.update) {
|
||||
return (
|
||||
<Button
|
||||
label={t("repositoryRole.button.edit")}
|
||||
link={`${url}/edit`}
|
||||
color="primary"
|
||||
/>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { role } = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<PermissionRoleDetailsTable role={role} />
|
||||
<hr />
|
||||
{this.renderEditButton()}
|
||||
<div className="content">
|
||||
<ExtensionPoint
|
||||
name="repositoryRole.role-details.information"
|
||||
renderAll={true}
|
||||
props={{ role }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default translate("config")(PermissionRoleDetails);
|
||||
@@ -0,0 +1,37 @@
|
||||
//@flow
|
||||
import React from "react";
|
||||
import type { RepositoryRole } from "@scm-manager/ui-types";
|
||||
import { translate } from "react-i18next";
|
||||
import AvailableVerbs from "./AvailableVerbs";
|
||||
|
||||
type Props = {
|
||||
role: RepositoryRole,
|
||||
// context props
|
||||
t: string => string
|
||||
};
|
||||
|
||||
class PermissionRoleDetailsTable extends React.Component<Props> {
|
||||
render() {
|
||||
const { role, t } = this.props;
|
||||
return (
|
||||
<table className="table content">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>{t("repositoryRole.name")}</th>
|
||||
<td>{role.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{t("repositoryRole.type")}</th>
|
||||
<td>{role.type}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{t("repositoryRole.verbs")}</th>
|
||||
<AvailableVerbs role={role} />
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default translate("config")(PermissionRoleDetailsTable);
|
||||
@@ -1,12 +1,12 @@
|
||||
// @flow
|
||||
import React from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import type { Role } from "@scm-manager/ui-types";
|
||||
import type { RepositoryRole } from "@scm-manager/ui-types";
|
||||
import SystemRoleTag from "./SystemRoleTag";
|
||||
|
||||
type Props = {
|
||||
baseUrl: string,
|
||||
role: Role
|
||||
role: RepositoryRole
|
||||
};
|
||||
|
||||
class PermissionRoleRow extends React.Component<Props> {
|
||||
@@ -20,7 +20,8 @@ class PermissionRoleRow extends React.Component<Props> {
|
||||
|
||||
render() {
|
||||
const { baseUrl, role } = this.props;
|
||||
const to = `${baseUrl}/${encodeURIComponent(role.name)}/info`;
|
||||
const singleRepoRoleUrl = baseUrl.substring(0, baseUrl.length - 1);
|
||||
const to = `${singleRepoRoleUrl}/${encodeURIComponent(role.name)}/info`;
|
||||
return (
|
||||
<tr>
|
||||
<td>{this.renderLink(to, role.name, !role._links.update)}</td>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
// @flow
|
||||
import React from "react";
|
||||
import { translate } from "react-i18next";
|
||||
import type { Role } from "@scm-manager/ui-types";
|
||||
import type { RepositoryRole } from "@scm-manager/ui-types";
|
||||
import PermissionRoleRow from "./PermissionRoleRow";
|
||||
|
||||
type Props = {
|
||||
baseUrl: string,
|
||||
roles: Role[],
|
||||
roles: RepositoryRole[],
|
||||
|
||||
t: string => string
|
||||
};
|
||||
@@ -18,7 +18,7 @@ class PermissionRoleTable extends React.Component<Props> {
|
||||
<table className="card-table table is-hoverable is-fullwidth">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{t("roles.form.name")}</th>
|
||||
<th>{t("repositoryRole.form.name")}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
// @flow
|
||||
import React from "react";
|
||||
|
||||
type Props = {};
|
||||
|
||||
class CreatePermissionRole extends React.Component<Props> {
|
||||
render() {
|
||||
return <>yep</>;
|
||||
}
|
||||
}
|
||||
|
||||
export default CreatePermissionRole;
|
||||
87
scm-ui/src/config/roles/containers/CreateRepositoryRole.js
Normal file
87
scm-ui/src/config/roles/containers/CreateRepositoryRole.js
Normal file
@@ -0,0 +1,87 @@
|
||||
// @flow
|
||||
import React from "react";
|
||||
import RepositoryRoleForm from "./RepositoryRoleForm";
|
||||
import { connect } from "react-redux";
|
||||
import { translate } from "react-i18next";
|
||||
import { ErrorNotification, Title } from "@scm-manager/ui-components";
|
||||
import {
|
||||
createRole,
|
||||
getCreateRoleFailure,
|
||||
getFetchVerbsFailure,
|
||||
isFetchVerbsPending
|
||||
} from "../modules/roles";
|
||||
import type { RepositoryRole } from "@scm-manager/ui-types";
|
||||
import {
|
||||
getRepositoryRolesLink,
|
||||
getRepositoryVerbsLink
|
||||
} from "../../../modules/indexResource";
|
||||
|
||||
type Props = {
|
||||
disabled: boolean,
|
||||
repositoryRolesLink: string,
|
||||
error?: Error,
|
||||
|
||||
//dispatch function
|
||||
addRole: (link: string, role: RepositoryRole, callback?: () => void) => void,
|
||||
|
||||
// context objects
|
||||
t: string => string
|
||||
};
|
||||
|
||||
class CreateRepositoryRole extends React.Component<Props> {
|
||||
repositoryRoleCreated = (role: RepositoryRole) => {
|
||||
const { history } = this.props;
|
||||
history.push("/config/role/" + role.name + "/info");
|
||||
};
|
||||
|
||||
createRepositoryRole = (role: RepositoryRole) => {
|
||||
this.props.addRole(this.props.repositoryRolesLink, role, () =>
|
||||
this.repositoryRoleCreated(role)
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { t, error } = this.props;
|
||||
|
||||
if (error) {
|
||||
return <ErrorNotification error={error} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Title title={t("repositoryRole.title")} />
|
||||
<RepositoryRoleForm
|
||||
disabled={this.props.disabled}
|
||||
submitForm={role => this.createRepositoryRole(role)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
const loading = isFetchVerbsPending(state);
|
||||
const error = getFetchVerbsFailure(state) || getCreateRoleFailure(state);
|
||||
const verbsLink = getRepositoryVerbsLink(state);
|
||||
const repositoryRolesLink = getRepositoryRolesLink(state);
|
||||
|
||||
return {
|
||||
loading,
|
||||
error,
|
||||
verbsLink,
|
||||
repositoryRolesLink
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
addRole: (link: string, role: RepositoryRole, callback?: () => void) => {
|
||||
dispatch(createRole(link, role, callback));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(translate("config")(CreateRepositoryRole));
|
||||
78
scm-ui/src/config/roles/containers/EditRepositoryRole.js
Normal file
78
scm-ui/src/config/roles/containers/EditRepositoryRole.js
Normal file
@@ -0,0 +1,78 @@
|
||||
// @flow
|
||||
import React from "react";
|
||||
import RepositoryRoleForm from "./RepositoryRoleForm";
|
||||
import { connect } from "react-redux";
|
||||
import { translate } from "react-i18next";
|
||||
import {
|
||||
getModifyRoleFailure,
|
||||
isModifyRolePending,
|
||||
modifyRole
|
||||
} from "../modules/roles";
|
||||
import { ErrorNotification } from "@scm-manager/ui-components";
|
||||
import type { RepositoryRole } from "@scm-manager/ui-types";
|
||||
|
||||
type Props = {
|
||||
disabled: boolean,
|
||||
role: RepositoryRole,
|
||||
repositoryRolesLink: string,
|
||||
error?: Error,
|
||||
|
||||
//dispatch function
|
||||
updateRole: (
|
||||
link: string,
|
||||
role: RepositoryRole,
|
||||
callback?: () => void
|
||||
) => void
|
||||
};
|
||||
|
||||
class EditRepositoryRole extends React.Component<Props> {
|
||||
repositoryRoleUpdated = (role: RepositoryRole) => {
|
||||
const { history } = this.props;
|
||||
history.push("/config/roles/");
|
||||
};
|
||||
|
||||
updateRepositoryRole = (role: RepositoryRole) => {
|
||||
this.props.updateRole(role, () => this.repositoryRoleUpdated(role));
|
||||
};
|
||||
|
||||
render() {
|
||||
const { error } = this.props;
|
||||
|
||||
if (error) {
|
||||
return <ErrorNotification error={error} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<RepositoryRoleForm
|
||||
nameDisabled={true}
|
||||
role={this.props.role}
|
||||
submitForm={role => this.updateRepositoryRole(role)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
const loading = isModifyRolePending(state);
|
||||
const error = getModifyRoleFailure(state, ownProps.role.name);
|
||||
|
||||
return {
|
||||
loading,
|
||||
error
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
updateRole: (role: RepositoryRole, callback?: () => void) => {
|
||||
dispatch(modifyRole(role, callback));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(translate("config")(EditRepositoryRole));
|
||||
@@ -1,103 +0,0 @@
|
||||
//@flow
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { Redirect, Route, Switch, withRouter } from "react-router-dom";
|
||||
import type {Role} from "@scm-manager/ui-types";
|
||||
import {ErrorNotification, Loading} from "@scm-manager/ui-components";
|
||||
import { getRolesLink } from "../../../modules/indexResource";
|
||||
import {
|
||||
fetchRoleByName,
|
||||
getRoleByName,
|
||||
isFetchRolePending,
|
||||
getFetchRoleFailure
|
||||
} from "../modules/roles";
|
||||
import PermissionRoleDetail from "../components/PermissionRoleDetail";
|
||||
|
||||
type Props = {
|
||||
roleLink: string,
|
||||
roleName: string,
|
||||
role: Role,
|
||||
loading: boolean,
|
||||
error: Error,
|
||||
|
||||
// context props
|
||||
match: any,
|
||||
t: string => string,
|
||||
|
||||
// dispatch functions
|
||||
fetchRoleByName: (roleLink: string, roleName: string) => void
|
||||
};
|
||||
|
||||
class PermissionRoleRoot extends React.Component<Props> {
|
||||
componentDidMount() {
|
||||
const { fetchRoleByName, roleLink, roleName } = this.props;
|
||||
fetchRoleByName(roleLink, roleName);
|
||||
}
|
||||
|
||||
stripEndingSlash = (url: string) => {
|
||||
if (url.endsWith("/")) {
|
||||
return url.substring(0, url.length - 1);
|
||||
}
|
||||
return url;
|
||||
};
|
||||
|
||||
matchedUrl = () => {
|
||||
return this.stripEndingSlash(this.props.match.url);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { loading, error, role} = this.props;
|
||||
|
||||
const url = this.matchedUrl();
|
||||
|
||||
if (error) {
|
||||
return <ErrorNotification error={error} />;
|
||||
}
|
||||
|
||||
if (loading || !role) {
|
||||
return <Loading />;
|
||||
}
|
||||
|
||||
return (
|
||||
<Switch>
|
||||
<Redirect exact from={url} to={`${url}/info`} />
|
||||
<Route
|
||||
path={`${url}/info`}
|
||||
component={() => (
|
||||
<PermissionRoleDetail role={role} />
|
||||
)}
|
||||
/>
|
||||
</Switch>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
const roleName = decodeURIComponent(ownProps.match.params.role);
|
||||
const role = getRoleByName(state, roleName);
|
||||
const loading = isFetchRolePending(state, roleName);
|
||||
const error = getFetchRoleFailure(state, roleName);
|
||||
const roleLink = getRolesLink(state);
|
||||
return {
|
||||
roleName,
|
||||
role,
|
||||
loading,
|
||||
error,
|
||||
roleLink
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
fetchRoleByName: (roleLink: string, roleName: string) => {
|
||||
dispatch(fetchRoleByName(roleLink, roleName));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export default withRouter(
|
||||
connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(PermissionRoleRoot)
|
||||
);
|
||||
@@ -2,7 +2,7 @@
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { translate } from "react-i18next";
|
||||
import type { Role } from "@scm-manager/ui-types";
|
||||
import type { RepositoryRole } from "@scm-manager/ui-types";
|
||||
import { InputField, SubmitButton } from "@scm-manager/ui-components";
|
||||
import PermissionCheckbox from "../../../repos/permissions/components/PermissionCheckbox";
|
||||
import {
|
||||
@@ -11,14 +11,18 @@ import {
|
||||
getVerbsFromState,
|
||||
isFetchVerbsPending
|
||||
} from "../modules/roles";
|
||||
import { getRepositoryVerbsLink } from "../../../modules/indexResource";
|
||||
import {
|
||||
getRepositoryRolesLink,
|
||||
getRepositoryVerbsLink
|
||||
} from "../../../modules/indexResource";
|
||||
|
||||
type Props = {
|
||||
role?: Role,
|
||||
role?: RepositoryRole,
|
||||
loading?: boolean,
|
||||
disabled: boolean,
|
||||
nameDisabled: boolean,
|
||||
availableVerbs: string[],
|
||||
verbsLink: string,
|
||||
submitForm: RepositoryRole => void,
|
||||
|
||||
// context objects
|
||||
t: string => string,
|
||||
@@ -28,10 +32,10 @@ type Props = {
|
||||
};
|
||||
|
||||
type State = {
|
||||
role: Role
|
||||
role: RepositoryRole
|
||||
};
|
||||
|
||||
class GlobalPermissionRoleForm extends React.Component<Props, State> {
|
||||
class RepositoryRoleForm extends React.Component<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
@@ -46,16 +50,10 @@ class GlobalPermissionRoleForm extends React.Component<Props, State> {
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { fetchAvailableVerbs, verbsLink, role } = this.props;
|
||||
const { fetchAvailableVerbs, verbsLink } = this.props;
|
||||
fetchAvailableVerbs(verbsLink);
|
||||
|
||||
if (role) {
|
||||
this.setState({
|
||||
role: {
|
||||
...role,
|
||||
role: { verbs: role.verbs }
|
||||
}
|
||||
});
|
||||
if (this.props.role) {
|
||||
this.setState({ role: this.props.role });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +66,7 @@ class GlobalPermissionRoleForm extends React.Component<Props, State> {
|
||||
return !(
|
||||
this.isFalsy(role) ||
|
||||
this.isFalsy(role.name) ||
|
||||
this.isFalsy(role.verbs)
|
||||
this.isFalsy(role.verbs.length > 0)
|
||||
);
|
||||
};
|
||||
|
||||
@@ -100,13 +98,12 @@ class GlobalPermissionRoleForm extends React.Component<Props, State> {
|
||||
submit = (event: Event) => {
|
||||
event.preventDefault();
|
||||
if (this.isValid()) {
|
||||
// this.props.submitForm(this.state.role);
|
||||
//TODO ADD createRole here
|
||||
this.props.submitForm(this.state.role);
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { loading, availableVerbs, disabled, t } = this.props;
|
||||
const { loading, availableVerbs, nameDisabled, t } = this.props;
|
||||
const { role } = this.state;
|
||||
|
||||
const verbSelectBoxes = !availableVerbs
|
||||
@@ -114,7 +111,6 @@ class GlobalPermissionRoleForm extends React.Component<Props, State> {
|
||||
: availableVerbs.map(verb => (
|
||||
<PermissionCheckbox
|
||||
key={verb}
|
||||
// disabled={readOnly}
|
||||
name={verb}
|
||||
checked={role.verbs.includes(verb)}
|
||||
onChange={this.handleVerbChange}
|
||||
@@ -127,22 +123,21 @@ class GlobalPermissionRoleForm extends React.Component<Props, State> {
|
||||
<div className="column">
|
||||
<InputField
|
||||
name="name"
|
||||
label={t("roles.form.name")}
|
||||
label={t("repositoryRole.create.name")}
|
||||
onChange={this.handleNameChange}
|
||||
value={role.name ? role.name : ""}
|
||||
disabled={!!role.name || disabled}
|
||||
disabled={nameDisabled}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{verbSelectBoxes}
|
||||
<>{verbSelectBoxes}</>
|
||||
<hr />
|
||||
<div className="columns">
|
||||
<div className="column">
|
||||
<SubmitButton
|
||||
loading={loading}
|
||||
label={t("roles.form.submit")}
|
||||
disabled={disabled || !this.isValid()}
|
||||
label={t("repositoryRole.form.submit")}
|
||||
disabled={!this.isValid()}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -156,12 +151,14 @@ const mapStateToProps = (state, ownProps) => {
|
||||
const error = getFetchVerbsFailure(state);
|
||||
const verbsLink = getRepositoryVerbsLink(state);
|
||||
const availableVerbs = getVerbsFromState(state);
|
||||
const repositoryRolesLink = getRepositoryRolesLink(state);
|
||||
|
||||
return {
|
||||
loading,
|
||||
error,
|
||||
verbsLink,
|
||||
availableVerbs
|
||||
availableVerbs,
|
||||
repositoryRolesLink
|
||||
};
|
||||
};
|
||||
|
||||
@@ -176,4 +173,4 @@ const mapDispatchToProps = dispatch => {
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(translate("config")(GlobalPermissionRoleForm));
|
||||
)(translate("config")(RepositoryRoleForm));
|
||||
@@ -1,10 +1,10 @@
|
||||
// @flow
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import {withRouter} from "react-router-dom";
|
||||
import { withRouter } from "react-router-dom";
|
||||
import { translate } from "react-i18next";
|
||||
import type { History } from "history";
|
||||
import type { Role, PagedCollection } from "@scm-manager/ui-types";
|
||||
import type { RepositoryRole, PagedCollection } from "@scm-manager/ui-types";
|
||||
import {
|
||||
Title,
|
||||
Loading,
|
||||
@@ -23,10 +23,9 @@ import {
|
||||
} from "../modules/roles";
|
||||
import PermissionRoleTable from "../components/PermissionRoleTable";
|
||||
import { getRolesLink } from "../../../modules/indexResource";
|
||||
|
||||
type Props = {
|
||||
baseUrl: string,
|
||||
roles: Role[],
|
||||
roles: RepositoryRole[],
|
||||
loading: boolean,
|
||||
error: Error,
|
||||
canAddRoles: boolean,
|
||||
@@ -42,12 +41,33 @@ type Props = {
|
||||
fetchRolesByPage: (link: string, page: number) => void
|
||||
};
|
||||
|
||||
class PermissionRolesOverview extends React.Component<Props> {
|
||||
class RepositoryRoles extends React.Component<Props> {
|
||||
componentDidMount() {
|
||||
const { fetchRolesByPage, rolesLink, page } = this.props;
|
||||
fetchRolesByPage(rolesLink, page);
|
||||
}
|
||||
|
||||
componentDidUpdate = (prevProps: Props) => {
|
||||
const {
|
||||
loading,
|
||||
list,
|
||||
page,
|
||||
rolesLink,
|
||||
location,
|
||||
fetchRolesByPage
|
||||
} = this.props;
|
||||
if (list && page && !loading) {
|
||||
const statePage: number = list.page + 1;
|
||||
if (page !== statePage || prevProps.location.search !== location.search) {
|
||||
fetchRolesByPage(
|
||||
rolesLink,
|
||||
page,
|
||||
urls.getQueryStringFromLocation(location)
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { t, loading } = this.props;
|
||||
|
||||
@@ -57,7 +77,7 @@ class PermissionRolesOverview extends React.Component<Props> {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Title title={t("roles.title")} />
|
||||
<Title title={t("repositoryRole.title")} />
|
||||
{this.renderPermissionsTable()}
|
||||
{this.renderCreateButton()}
|
||||
</div>
|
||||
@@ -75,14 +95,21 @@ class PermissionRolesOverview extends React.Component<Props> {
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Notification type="info">{t("roles.noPermissionRoles")}</Notification>
|
||||
<Notification type="info">
|
||||
{t("repositoryRole.noPermissionRoles")}
|
||||
</Notification>
|
||||
);
|
||||
}
|
||||
|
||||
renderCreateButton() {
|
||||
const { canAddRoles, baseUrl, t } = this.props;
|
||||
if (canAddRoles) {
|
||||
return <CreateButton label={t("roles.createButton")} link={`${baseUrl}/create`} />;
|
||||
return (
|
||||
<CreateButton
|
||||
label={t("repositoryRole.createButton")}
|
||||
link={`${baseUrl}/create`}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -117,7 +144,9 @@ const mapDispatchToProps = dispatch => {
|
||||
};
|
||||
};
|
||||
|
||||
export default withRouter(connect(
|
||||
export default withRouter(
|
||||
connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(translate("config")(PermissionRolesOverview)));
|
||||
)(translate("config")(RepositoryRoles))
|
||||
);
|
||||
137
scm-ui/src/config/roles/containers/SingleRepositoryRole.js
Normal file
137
scm-ui/src/config/roles/containers/SingleRepositoryRole.js
Normal file
@@ -0,0 +1,137 @@
|
||||
//@flow
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { Loading, ErrorPage, Title } from "@scm-manager/ui-components";
|
||||
import { Route } from "react-router";
|
||||
import type { History } from "history";
|
||||
import { translate } from "react-i18next";
|
||||
import type { RepositoryRole } 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";
|
||||
import { withRouter } from "react-router-dom";
|
||||
import PermissionRoleDetail from "../components/PermissionRoleDetails";
|
||||
import EditRepositoryRole from "./EditRepositoryRole";
|
||||
|
||||
type Props = {
|
||||
roleName: string,
|
||||
role: RepositoryRole,
|
||||
loading: boolean,
|
||||
error: Error,
|
||||
repositoryRolesLink: string,
|
||||
disabled: boolean,
|
||||
|
||||
// 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.roleName
|
||||
);
|
||||
}
|
||||
|
||||
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("repositoryRole.errorTitle")}
|
||||
subtitle={t("repositoryRole.errorSubtitle")}
|
||||
error={error}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (!role || loading) {
|
||||
return <Loading />;
|
||||
}
|
||||
|
||||
const url = this.matchedUrl();
|
||||
|
||||
const extensionProps = {
|
||||
role,
|
||||
url
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Title title={t("repositoryRole.title")} />
|
||||
<div className="columns">
|
||||
<div className="column is-three-quarters">
|
||||
<Route
|
||||
path={`${url}/info`}
|
||||
component={() => <PermissionRoleDetail role={role} url={url} />}
|
||||
/>
|
||||
<Route
|
||||
path={`${url}/edit`}
|
||||
exact
|
||||
component={() => (
|
||||
<EditRepositoryRole role={role} history={this.props.history} />
|
||||
)}
|
||||
/>
|
||||
<ExtensionPoint
|
||||
name="roles.route"
|
||||
props={extensionProps}
|
||||
renderAll={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
const roleName = ownProps.match.params.role;
|
||||
const role = getRoleByName(state, roleName);
|
||||
const loading = isFetchRolePending(state, roleName);
|
||||
const error = getFetchRoleFailure(state, roleName);
|
||||
const repositoryRolesLink = getRepositoryRolesLink(state);
|
||||
return {
|
||||
repositoryRolesLink,
|
||||
roleName,
|
||||
role,
|
||||
loading,
|
||||
error
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
fetchRoleByName: (link: string, name: string) => {
|
||||
dispatch(fetchRoleByName(link, name));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export default withRouter(
|
||||
connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(translate("config")(SingleRepositoryRole))
|
||||
);
|
||||
@@ -4,7 +4,11 @@ import { isPending } from "../../../modules/pending";
|
||||
import { getFailure } from "../../../modules/failure";
|
||||
import * as types from "../../../modules/types";
|
||||
import { combineReducers, Dispatch } from "redux";
|
||||
import type {Action, PagedCollection, Repository, Role} from "@scm-manager/ui-types";
|
||||
import type {
|
||||
Action,
|
||||
PagedCollection,
|
||||
RepositoryRole
|
||||
} from "@scm-manager/ui-types";
|
||||
|
||||
export const FETCH_ROLES = "scm/roles/FETCH_ROLES";
|
||||
export const FETCH_ROLES_PENDING = `${FETCH_ROLES}_${types.PENDING_SUFFIX}`;
|
||||
@@ -138,12 +142,12 @@ export function fetchRoleByName(link: string, name: string) {
|
||||
return fetchRole(roleUrl, name);
|
||||
}
|
||||
|
||||
export function fetchRoleByLink(role: Role) {
|
||||
export function fetchRoleByLink(role: RepositoryRole) {
|
||||
return fetchRole(role._links.self.href, role.name);
|
||||
}
|
||||
|
||||
// create role
|
||||
export function createRolePending(role: Role): Action {
|
||||
export function createRolePending(role: RepositoryRole): Action {
|
||||
return {
|
||||
type: CREATE_ROLE_PENDING,
|
||||
role
|
||||
@@ -169,7 +173,11 @@ export function createRoleReset() {
|
||||
};
|
||||
}
|
||||
|
||||
export function createRole(link: string, role: Role, callback?: () => void) {
|
||||
export function createRole(
|
||||
link: string,
|
||||
role: RepositoryRole,
|
||||
callback?: () => void
|
||||
) {
|
||||
return function(dispatch: Dispatch) {
|
||||
dispatch(createRolePending(role));
|
||||
return apiClient
|
||||
@@ -233,7 +241,7 @@ function verbReducer(state: any = {}, action: any = {}) {
|
||||
}
|
||||
|
||||
// modify role
|
||||
export function modifyRolePending(role: Role): Action {
|
||||
export function modifyRolePending(role: RepositoryRole): Action {
|
||||
return {
|
||||
type: MODIFY_ROLE_PENDING,
|
||||
payload: role,
|
||||
@@ -241,7 +249,7 @@ export function modifyRolePending(role: Role): Action {
|
||||
};
|
||||
}
|
||||
|
||||
export function modifyRoleSuccess(role: Role): Action {
|
||||
export function modifyRoleSuccess(role: RepositoryRole): Action {
|
||||
return {
|
||||
type: MODIFY_ROLE_SUCCESS,
|
||||
payload: role,
|
||||
@@ -249,7 +257,7 @@ export function modifyRoleSuccess(role: Role): Action {
|
||||
};
|
||||
}
|
||||
|
||||
export function modifyRoleFailure(role: Role, error: Error): Action {
|
||||
export function modifyRoleFailure(role: RepositoryRole, error: Error): Action {
|
||||
return {
|
||||
type: MODIFY_ROLE_FAILURE,
|
||||
payload: {
|
||||
@@ -260,14 +268,14 @@ export function modifyRoleFailure(role: Role, error: Error): Action {
|
||||
};
|
||||
}
|
||||
|
||||
export function modifyRoleReset(role: Role): Action {
|
||||
export function modifyRoleReset(role: RepositoryRole): Action {
|
||||
return {
|
||||
type: MODIFY_ROLE_RESET,
|
||||
itemId: role.name
|
||||
};
|
||||
}
|
||||
|
||||
export function modifyRole(role: Role, callback?: () => void) {
|
||||
export function modifyRole(role: RepositoryRole, callback?: () => void) {
|
||||
return function(dispatch: Dispatch) {
|
||||
dispatch(modifyRolePending(role));
|
||||
return apiClient
|
||||
@@ -288,7 +296,7 @@ export function modifyRole(role: Role, callback?: () => void) {
|
||||
}
|
||||
|
||||
// delete role
|
||||
export function deleteRolePending(role: Role): Action {
|
||||
export function deleteRolePending(role: RepositoryRole): Action {
|
||||
return {
|
||||
type: DELETE_ROLE_PENDING,
|
||||
payload: role,
|
||||
@@ -296,7 +304,7 @@ export function deleteRolePending(role: Role): Action {
|
||||
};
|
||||
}
|
||||
|
||||
export function deleteRoleSuccess(role: Role): Action {
|
||||
export function deleteRoleSuccess(role: RepositoryRole): Action {
|
||||
return {
|
||||
type: DELETE_ROLE_SUCCESS,
|
||||
payload: role,
|
||||
@@ -304,7 +312,7 @@ export function deleteRoleSuccess(role: Role): Action {
|
||||
};
|
||||
}
|
||||
|
||||
export function deleteRoleFailure(role: Role, error: Error): Action {
|
||||
export function deleteRoleFailure(role: RepositoryRole, error: Error): Action {
|
||||
return {
|
||||
type: DELETE_ROLE_FAILURE,
|
||||
payload: {
|
||||
@@ -315,7 +323,7 @@ export function deleteRoleFailure(role: Role, error: Error): Action {
|
||||
};
|
||||
}
|
||||
|
||||
export function deleteRole(role: Role, callback?: () => void) {
|
||||
export function deleteRole(role: RepositoryRole, callback?: () => void) {
|
||||
return function(dispatch: any) {
|
||||
dispatch(deleteRolePending(role));
|
||||
return apiClient
|
||||
@@ -333,7 +341,7 @@ export function deleteRole(role: Role, callback?: () => void) {
|
||||
}
|
||||
|
||||
function extractRolesByNames(
|
||||
roles: Role[],
|
||||
roles: RepositoryRole[],
|
||||
roleNames: string[],
|
||||
oldRolesByNames: Object
|
||||
) {
|
||||
@@ -460,7 +468,7 @@ export function getRolesFromState(state: Object) {
|
||||
if (!roleNames) {
|
||||
return null;
|
||||
}
|
||||
const roleEntries: Role[] = [];
|
||||
const roleEntries: RepositoryRole[] = [];
|
||||
|
||||
for (let roleName of roleNames) {
|
||||
roleEntries.push(state.roles.byNames[roleName]);
|
||||
@@ -470,12 +478,7 @@ export function getRolesFromState(state: Object) {
|
||||
}
|
||||
|
||||
export function getRoleCreateLink(state: Object) {
|
||||
if (
|
||||
state &&
|
||||
state.list &&
|
||||
state.list._links &&
|
||||
state.list._links.create
|
||||
) {
|
||||
if (state && state.list && state.list._links && state.list._links.create) {
|
||||
return state.list._links.create.href;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -307,10 +307,9 @@ const reduceByBranchesSuccess = (state, payload) => {
|
||||
const byName = repoState.byName || {};
|
||||
repoState.byName = byName;
|
||||
|
||||
if(response._embedded) {
|
||||
if (response._embedded) {
|
||||
const branches = response._embedded.branches;
|
||||
const names = branches.map(b => b.name);
|
||||
response._embedded.branches = names;
|
||||
response._embedded.branches = branches.map(b => b.name);
|
||||
for (let branch of branches) {
|
||||
byName[branch.name] = branch;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,19 @@
|
||||
// @flow
|
||||
|
||||
import {FAILURE_SUFFIX, PENDING_SUFFIX, SUCCESS_SUFFIX} from "../../modules/types";
|
||||
import {apiClient, urls} from "@scm-manager/ui-components";
|
||||
import {isPending} from "../../modules/pending";
|
||||
import {getFailure} from "../../modules/failure";
|
||||
import type {Action, Branch, PagedCollection, Repository} from "@scm-manager/ui-types";
|
||||
import {
|
||||
FAILURE_SUFFIX,
|
||||
PENDING_SUFFIX,
|
||||
SUCCESS_SUFFIX
|
||||
} from "../../modules/types";
|
||||
import { apiClient, urls } from "@scm-manager/ui-components";
|
||||
import { isPending } from "../../modules/pending";
|
||||
import { getFailure } from "../../modules/failure";
|
||||
import type {
|
||||
Action,
|
||||
Branch,
|
||||
PagedCollection,
|
||||
Repository
|
||||
} from "@scm-manager/ui-types";
|
||||
|
||||
export const FETCH_CHANGESETS = "scm/repos/FETCH_CHANGESETS";
|
||||
export const FETCH_CHANGESETS_PENDING = `${FETCH_CHANGESETS}_${PENDING_SUFFIX}`;
|
||||
|
||||
@@ -353,15 +353,13 @@ function normalizeByNamespaceAndName(
|
||||
|
||||
const reducerByNames = (state: Object, repository: Repository) => {
|
||||
const identifier = createIdentifier(repository);
|
||||
const newState = {
|
||||
return {
|
||||
...state,
|
||||
byNames: {
|
||||
...state.byNames,
|
||||
[identifier]: repository
|
||||
}
|
||||
};
|
||||
|
||||
return newState;
|
||||
};
|
||||
|
||||
export default function reducer(
|
||||
|
||||
@@ -49,10 +49,7 @@ export function shouldFetchRepositoryTypes(state: Object) {
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
if (state.repositoryTypes && state.repositoryTypes.length > 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return !(state.repositoryTypes && state.repositoryTypes.length > 0);
|
||||
}
|
||||
|
||||
export function fetchRepositoryTypesPending(): Action {
|
||||
|
||||
@@ -26,9 +26,11 @@ class AdvancedPermissionsDialog extends React.Component<Props, State> {
|
||||
|
||||
const verbs = {};
|
||||
props.availableVerbs.forEach(
|
||||
verb => (verbs[verb] = props.selectedVerbs.includes(verb))
|
||||
verb =>
|
||||
(verbs[verb] = props.selectedVerbs
|
||||
? props.selectedVerbs.includes(verb)
|
||||
: false)
|
||||
);
|
||||
|
||||
this.state = { verbs };
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
// @flow
|
||||
import React from "react";
|
||||
import { translate } from "react-i18next";
|
||||
import type {
|
||||
RepositoryRole,
|
||||
PermissionCollection,
|
||||
PermissionCreateEntry,
|
||||
SelectValue
|
||||
} from "@scm-manager/ui-types";
|
||||
import {
|
||||
Subtitle,
|
||||
Autocomplete,
|
||||
@@ -9,31 +15,28 @@ import {
|
||||
LabelWithHelpIcon,
|
||||
Radio
|
||||
} from "@scm-manager/ui-components";
|
||||
import RoleSelector from "../components/RoleSelector";
|
||||
import type {
|
||||
RepositoryRole,
|
||||
PermissionCollection,
|
||||
PermissionCreateEntry,
|
||||
SelectValue
|
||||
} from "@scm-manager/ui-types";
|
||||
import * as validator from "../components/permissionValidation";
|
||||
import { findMatchingRoleName } from "../modules/permissions";
|
||||
import RoleSelector from "../components/RoleSelector";
|
||||
import AdvancedPermissionsDialog from "./AdvancedPermissionsDialog";
|
||||
import { findVerbsForRole } from "../modules/permissions";
|
||||
|
||||
type Props = {
|
||||
t: string => string,
|
||||
availableRoles: RepositoryRole[],
|
||||
availableVerbs: string[],
|
||||
createPermission: (permission: PermissionCreateEntry) => void,
|
||||
loading: boolean,
|
||||
currentPermissions: PermissionCollection,
|
||||
groupAutoCompleteLink: string,
|
||||
userAutoCompleteLink: string
|
||||
userAutoCompleteLink: string,
|
||||
|
||||
// Context props
|
||||
t: string => string
|
||||
};
|
||||
|
||||
type State = {
|
||||
name: string,
|
||||
verbs: string[],
|
||||
role?: string,
|
||||
verbs?: string[],
|
||||
groupPermission: boolean,
|
||||
valid: boolean,
|
||||
value?: SelectValue,
|
||||
@@ -46,7 +49,8 @@ class CreatePermissionForm extends React.Component<Props, State> {
|
||||
|
||||
this.state = {
|
||||
name: "",
|
||||
verbs: props.availableRoles[0].verbs,
|
||||
role: props.availableRoles[0].name,
|
||||
verbs: undefined,
|
||||
groupPermission: false,
|
||||
valid: true,
|
||||
value: undefined,
|
||||
@@ -91,6 +95,7 @@ class CreatePermissionForm extends React.Component<Props, State> {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
renderAutocompletionField = () => {
|
||||
const { t } = this.props;
|
||||
if (this.state.groupPermission) {
|
||||
@@ -135,18 +140,16 @@ class CreatePermissionForm extends React.Component<Props, State> {
|
||||
|
||||
render() {
|
||||
const { t, availableRoles, availableVerbs, loading } = this.props;
|
||||
const { role, verbs, showAdvancedDialog } = this.state;
|
||||
|
||||
const { verbs, showAdvancedDialog } = this.state;
|
||||
const availableRoleNames = availableRoles.map(r => r.name);
|
||||
|
||||
const availableRoleNames = availableRoles.map(
|
||||
r => r.name
|
||||
);
|
||||
const matchingRole = findMatchingRoleName(availableRoles, verbs);
|
||||
const selectedVerbs = role ? findVerbsForRole(availableRoles, role) : verbs;
|
||||
|
||||
const advancedDialog = showAdvancedDialog ? (
|
||||
<AdvancedPermissionsDialog
|
||||
availableVerbs={availableVerbs}
|
||||
selectedVerbs={verbs}
|
||||
selectedVerbs={selectedVerbs}
|
||||
onClose={this.closeAdvancedPermissionsDialog}
|
||||
onSubmit={this.submitAdvancedPermissionsDialog}
|
||||
/>
|
||||
@@ -188,7 +191,7 @@ class CreatePermissionForm extends React.Component<Props, State> {
|
||||
label={t("permission.role")}
|
||||
helpText={t("permission.help.roleHelpText")}
|
||||
handleRoleChange={this.handleRoleChange}
|
||||
role={matchingRole}
|
||||
role={role}
|
||||
/>
|
||||
</div>
|
||||
<div className="column">
|
||||
@@ -229,6 +232,7 @@ class CreatePermissionForm extends React.Component<Props, State> {
|
||||
submitAdvancedPermissionsDialog = (newVerbs: string[]) => {
|
||||
this.setState({
|
||||
showAdvancedDialog: false,
|
||||
role: undefined,
|
||||
verbs: newVerbs
|
||||
});
|
||||
};
|
||||
@@ -236,6 +240,7 @@ class CreatePermissionForm extends React.Component<Props, State> {
|
||||
submit = e => {
|
||||
this.props.createPermission({
|
||||
name: this.state.name,
|
||||
role: this.state.role,
|
||||
verbs: this.state.verbs,
|
||||
groupPermission: this.state.groupPermission
|
||||
});
|
||||
@@ -246,7 +251,8 @@ class CreatePermissionForm extends React.Component<Props, State> {
|
||||
removeState = () => {
|
||||
this.setState({
|
||||
name: "",
|
||||
verbs: this.props.availableRoles[0].verbs,
|
||||
role: this.props.availableRoles[0].name,
|
||||
verbs: undefined,
|
||||
valid: true,
|
||||
value: undefined
|
||||
});
|
||||
@@ -258,14 +264,13 @@ class CreatePermissionForm extends React.Component<Props, State> {
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
verbs: selectedRole.verbs
|
||||
role: selectedRole.name,
|
||||
verbs: []
|
||||
});
|
||||
};
|
||||
|
||||
findAvailableRole = (roleName: string) => {
|
||||
return this.props.availableRoles.find(
|
||||
role => role.name === roleName
|
||||
);
|
||||
return this.props.availableRoles.find(role => role.name === roleName);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,9 @@ import {
|
||||
getDeletePermissionsFailure,
|
||||
getModifyPermissionsFailure,
|
||||
modifyPermissionReset,
|
||||
deletePermissionReset, getAvailableRepositoryRoles, getAvailableRepositoryVerbs
|
||||
deletePermissionReset,
|
||||
getAvailableRepositoryRoles,
|
||||
getAvailableRepositoryVerbs
|
||||
} from "../modules/permissions";
|
||||
import {
|
||||
Loading,
|
||||
@@ -38,11 +40,14 @@ import CreatePermissionForm from "./CreatePermissionForm";
|
||||
import type { History } from "history";
|
||||
import { getPermissionsLink } from "../../modules/repos";
|
||||
import {
|
||||
getGroupAutoCompleteLink, getRepositoryRolesLink, getRepositoryVerbsLink,
|
||||
getGroupAutoCompleteLink,
|
||||
getRepositoryRolesLink,
|
||||
getRepositoryVerbsLink,
|
||||
getUserAutoCompleteLink
|
||||
} from "../../../modules/indexResource";
|
||||
|
||||
type Props = {
|
||||
availablePermissions: boolean,
|
||||
availableRepositoryRoles: RepositoryRole[],
|
||||
availableVerbs: string[],
|
||||
namespace: string,
|
||||
@@ -59,7 +64,10 @@ type Props = {
|
||||
userAutoCompleteLink: string,
|
||||
|
||||
//dispatch functions
|
||||
fetchAvailablePermissionsIfNeeded: () => void,
|
||||
fetchAvailablePermissionsIfNeeded: (
|
||||
repositoryRolesLink: string,
|
||||
repositoryVerbsLink: string
|
||||
) => void,
|
||||
fetchPermissions: (link: string, namespace: string, repoName: string) => void,
|
||||
createPermission: (
|
||||
link: string,
|
||||
@@ -77,7 +85,6 @@ type Props = {
|
||||
history: History
|
||||
};
|
||||
|
||||
|
||||
class Permissions extends React.Component<Props> {
|
||||
componentDidMount() {
|
||||
const {
|
||||
@@ -251,8 +258,16 @@ const mapDispatchToProps = dispatch => {
|
||||
fetchPermissions: (link: string, namespace: string, repoName: string) => {
|
||||
dispatch(fetchPermissions(link, namespace, repoName));
|
||||
},
|
||||
fetchAvailablePermissionsIfNeeded: (repositoryRolesLink: string, repositoryVerbsLink: string) => {
|
||||
dispatch(fetchAvailablePermissionsIfNeeded(repositoryRolesLink, repositoryVerbsLink));
|
||||
fetchAvailablePermissionsIfNeeded: (
|
||||
repositoryRolesLink: string,
|
||||
repositoryVerbsLink: string
|
||||
) => {
|
||||
dispatch(
|
||||
fetchAvailablePermissionsIfNeeded(
|
||||
repositoryRolesLink,
|
||||
repositoryVerbsLink
|
||||
)
|
||||
);
|
||||
},
|
||||
createPermission: (
|
||||
link: string,
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
// @flow
|
||||
import React from "react";
|
||||
import type {
|
||||
RepositoryRole,
|
||||
Permission
|
||||
} from "@scm-manager/ui-types";
|
||||
import type { RepositoryRole, Permission } from "@scm-manager/ui-types";
|
||||
import { translate } from "react-i18next";
|
||||
import {
|
||||
modifyPermission,
|
||||
isModifyPermissionPending,
|
||||
deletePermission,
|
||||
isDeletePermissionPending,
|
||||
findMatchingRoleName
|
||||
findVerbsForRole
|
||||
} from "../modules/permissions";
|
||||
import { connect } from "react-redux";
|
||||
import type { History } from "history";
|
||||
@@ -47,7 +44,6 @@ type Props = {
|
||||
};
|
||||
|
||||
type State = {
|
||||
role: string,
|
||||
permission: Permission,
|
||||
showAdvancedDialog: boolean
|
||||
};
|
||||
@@ -69,39 +65,34 @@ class SinglePermission extends React.Component<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
const defaultPermission = props.availableRoles
|
||||
? props.availableRoles[0]
|
||||
const defaultPermission = props.availableRepositoryRoles
|
||||
? props.availableRepositoryRoles[0]
|
||||
: {};
|
||||
|
||||
this.state = {
|
||||
permission: {
|
||||
name: "",
|
||||
role: undefined,
|
||||
verbs: defaultPermission.verbs,
|
||||
groupPermission: false,
|
||||
_links: {}
|
||||
},
|
||||
role: defaultPermission.name,
|
||||
showAdvancedDialog: false
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { availableRepositoryRoles, permission } = this.props;
|
||||
|
||||
const matchingRole = findMatchingRoleName(
|
||||
availableRepositoryRoles,
|
||||
permission.verbs
|
||||
);
|
||||
const { permission } = this.props;
|
||||
|
||||
if (permission) {
|
||||
this.setState({
|
||||
permission: {
|
||||
name: permission.name,
|
||||
role: permission.role,
|
||||
verbs: permission.verbs,
|
||||
groupPermission: permission.groupPermission,
|
||||
_links: permission._links
|
||||
},
|
||||
role: matchingRole
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -115,7 +106,7 @@ class SinglePermission extends React.Component<Props, State> {
|
||||
};
|
||||
|
||||
render() {
|
||||
const { role, permission, showAdvancedDialog } = this.state;
|
||||
const { permission, showAdvancedDialog } = this.state;
|
||||
const {
|
||||
t,
|
||||
availableRepositoryRoles,
|
||||
@@ -125,28 +116,31 @@ class SinglePermission extends React.Component<Props, State> {
|
||||
repoName,
|
||||
classes
|
||||
} = this.props;
|
||||
const availableRoleNames = !!availableRepositoryRoles && availableRepositoryRoles.map(
|
||||
r => r.name
|
||||
);
|
||||
const availableRoleNames =
|
||||
!!availableRepositoryRoles && availableRepositoryRoles.map(r => r.name);
|
||||
const readOnly = !this.mayChangePermissions();
|
||||
const roleSelector = readOnly ? (
|
||||
<td>{role}</td>
|
||||
<td>{permission.role ? permission.role : t("permission.custom")}</td>
|
||||
) : (
|
||||
<td>
|
||||
<RoleSelector
|
||||
handleRoleChange={this.handleRoleChange}
|
||||
availableRoles={availableRoleNames}
|
||||
role={role}
|
||||
role={permission.role}
|
||||
loading={loading}
|
||||
/>
|
||||
</td>
|
||||
);
|
||||
|
||||
const advancedDialg = showAdvancedDialog ? (
|
||||
const selectedVerbs = permission.role
|
||||
? findVerbsForRole(availableRepositoryRoles, permission.role)
|
||||
: permission.verbs;
|
||||
|
||||
const advancedDialog = showAdvancedDialog ? (
|
||||
<AdvancedPermissionsDialog
|
||||
readOnly={readOnly}
|
||||
availableVerbs={availableRepositoryVerbs}
|
||||
selectedVerbs={permission.verbs}
|
||||
selectedVerbs={selectedVerbs}
|
||||
onClose={this.closeAdvancedPermissionsDialog}
|
||||
onSubmit={this.submitAdvancedPermissionsDialog}
|
||||
/>
|
||||
@@ -154,9 +148,15 @@ class SinglePermission extends React.Component<Props, State> {
|
||||
|
||||
const iconType =
|
||||
permission && permission.groupPermission ? (
|
||||
<i title={t("permission.group")} className={classNames("fas fa-user-friends", classes.iconColor)} />
|
||||
<i
|
||||
title={t("permission.group")}
|
||||
className={classNames("fas fa-user-friends", classes.iconColor)}
|
||||
/>
|
||||
) : (
|
||||
<i title={t("permission.user")} className={classNames("fas fa-user", classes.iconColor)} />
|
||||
<i
|
||||
title={t("permission.user")}
|
||||
className={classNames("fas fa-user", classes.iconColor)}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
@@ -179,7 +179,7 @@ class SinglePermission extends React.Component<Props, State> {
|
||||
deletePermission={this.deletePermission}
|
||||
loading={this.props.deleteLoading}
|
||||
/>
|
||||
{advancedDialg}
|
||||
{advancedDialog}
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
@@ -199,42 +199,41 @@ class SinglePermission extends React.Component<Props, State> {
|
||||
|
||||
submitAdvancedPermissionsDialog = (newVerbs: string[]) => {
|
||||
const { permission } = this.state;
|
||||
const newRole = findMatchingRoleName(
|
||||
this.props.availableRoles,
|
||||
newVerbs
|
||||
);
|
||||
this.setState(
|
||||
{
|
||||
showAdvancedDialog: false,
|
||||
permission: { ...permission, verbs: newVerbs },
|
||||
role: newRole
|
||||
permission: { ...permission, role: undefined, verbs: newVerbs }
|
||||
},
|
||||
() => this.modifyPermission(newVerbs)
|
||||
() => this.modifyPermissionVerbs(newVerbs)
|
||||
);
|
||||
};
|
||||
|
||||
handleRoleChange = (role: string) => {
|
||||
const selectedRole = this.findAvailableRole(role);
|
||||
const { permission } = this.state;
|
||||
this.setState(
|
||||
{
|
||||
permission: {
|
||||
...this.state.permission,
|
||||
verbs: selectedRole.verbs
|
||||
permission: { ...permission, role: role, verbs: undefined }
|
||||
},
|
||||
role: role
|
||||
},
|
||||
() => this.modifyPermission(selectedRole.verbs)
|
||||
() => this.modifyPermissionRole(role)
|
||||
);
|
||||
};
|
||||
|
||||
findAvailableRole = (roleName: string) => {
|
||||
const { availableRepositoryRoles } = this.props;
|
||||
return availableRepositoryRoles.find(
|
||||
role => role.name === roleName
|
||||
return availableRepositoryRoles.find(role => role.name === roleName);
|
||||
};
|
||||
|
||||
modifyPermissionRole = (role: string) => {
|
||||
let permission = this.state.permission;
|
||||
permission.role = role;
|
||||
this.props.modifyPermission(
|
||||
permission,
|
||||
this.props.namespace,
|
||||
this.props.repoName
|
||||
);
|
||||
};
|
||||
|
||||
modifyPermission = (verbs: string[]) => {
|
||||
modifyPermissionVerbs = (verbs: string[]) => {
|
||||
let permission = this.state.permission;
|
||||
permission.verbs = verbs;
|
||||
this.props.modifyPermission(
|
||||
|
||||
@@ -77,10 +77,18 @@ const CONTENT_TYPE = "application/vnd.scmm-repositoryPermission+json";
|
||||
|
||||
// fetch available permissions
|
||||
|
||||
export function fetchAvailablePermissionsIfNeeded(repositoryRolesLink: string, repositoryVerbsLink: string) {
|
||||
export function fetchAvailablePermissionsIfNeeded(
|
||||
repositoryRolesLink: string,
|
||||
repositoryVerbsLink: string
|
||||
) {
|
||||
return function(dispatch: any, getState: () => Object) {
|
||||
if (shouldFetchAvailablePermissions(getState())) {
|
||||
return fetchAvailablePermissions(dispatch, getState, repositoryRolesLink, repositoryVerbsLink);
|
||||
return fetchAvailablePermissions(
|
||||
dispatch,
|
||||
getState,
|
||||
repositoryRolesLink,
|
||||
repositoryVerbsLink
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -97,7 +105,8 @@ export function fetchAvailablePermissions(
|
||||
.then(repositoryRoles => repositoryRoles.json())
|
||||
.then(repositoryRoles => repositoryRoles._embedded.repositoryRoles)
|
||||
.then(repositoryRoles => {
|
||||
return apiClient.get(repositoryVerbsLink)
|
||||
return apiClient
|
||||
.get(repositoryVerbsLink)
|
||||
.then(repositoryVerbs => repositoryVerbs.json())
|
||||
.then(repositoryVerbs => repositoryVerbs.verbs)
|
||||
.then(repositoryVerbs => {
|
||||
@@ -577,8 +586,7 @@ export function getPermissionsOfRepo(
|
||||
repoName: string
|
||||
) {
|
||||
if (state.permissions && state.permissions[namespace + "/" + repoName]) {
|
||||
const permissions = state.permissions[namespace + "/" + repoName].entries;
|
||||
return permissions;
|
||||
return state.permissions[namespace + "/" + repoName].entries;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -732,32 +740,16 @@ export function getModifyPermissionsFailure(
|
||||
return null;
|
||||
}
|
||||
|
||||
export function findMatchingRoleName(
|
||||
availableRoles: RepositoryRole[],
|
||||
verbs: string[]
|
||||
export function findVerbsForRole(
|
||||
availableRepositoryRoles: RepositoryRole[],
|
||||
roleName: string
|
||||
) {
|
||||
if (!verbs) {
|
||||
return "";
|
||||
}
|
||||
const matchingRole = !! availableRoles && availableRoles.find(role => {
|
||||
return equalVerbs(role.verbs, verbs);
|
||||
});
|
||||
|
||||
const matchingRole = availableRepositoryRoles.find(
|
||||
role => roleName === role.name
|
||||
);
|
||||
if (matchingRole) {
|
||||
return matchingRole.name;
|
||||
return matchingRole.verbs;
|
||||
} else {
|
||||
return "";
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
function equalVerbs(verbs1: string[], verbs2: string[]) {
|
||||
if (!verbs1 || !verbs2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (verbs1.length !== verbs2.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return verbs1.every(verb => verbs2.includes(verb));
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ public class RepositoryCollectionResource {
|
||||
|
||||
private Repository createModelObjectFromDto(@Valid RepositoryDto repositoryDto) {
|
||||
Repository repository = dtoToRepositoryMapper.map(repositoryDto, null);
|
||||
repository.setPermissions(singletonList(new RepositoryPermission(currentUser(), singletonList("*"), false)));
|
||||
repository.setPermissions(singletonList(new RepositoryPermission(currentUser(), "OWNER", false)));
|
||||
return repository;
|
||||
}
|
||||
|
||||
|
||||
@@ -332,7 +332,7 @@ public class RepositoryRootResourceTest extends RepositoryTestBase {
|
||||
.hasSize(1)
|
||||
.allSatisfy(p -> {
|
||||
assertThat(p.getName()).isEqualTo("trillian");
|
||||
assertThat(p.getVerbs()).containsExactly("*");
|
||||
assertThat(p.getRole()).isEqualTo("OWNER");
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user