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