mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-11 07:55:47 +01:00
scm-ui: new repository layout
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
// @flow
|
||||
import React from "react";
|
||||
import { translate } from "react-i18next";
|
||||
import { Checkbox } from "@scm-manager/ui-components";
|
||||
|
||||
type Props = {
|
||||
t: string => string,
|
||||
disabled: boolean,
|
||||
name: string,
|
||||
checked: boolean,
|
||||
onChange?: (value: boolean, name?: string) => void
|
||||
};
|
||||
|
||||
class PermissionCheckbox extends React.Component<Props> {
|
||||
render() {
|
||||
const { t } = this.props;
|
||||
return (
|
||||
<Checkbox
|
||||
key={this.props.name}
|
||||
name={this.props.name}
|
||||
helpText={t("verbs.repository." + this.props.name + ".description")}
|
||||
label={t("verbs.repository." + this.props.name + ".displayName")}
|
||||
checked={this.props.checked}
|
||||
onChange={this.props.onChange}
|
||||
disabled={this.props.disabled}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default translate("plugins")(PermissionCheckbox);
|
||||
@@ -0,0 +1,55 @@
|
||||
// @flow
|
||||
import React from "react";
|
||||
import { translate } from "react-i18next";
|
||||
import { Select } from "@scm-manager/ui-components";
|
||||
|
||||
type Props = {
|
||||
t: string => string,
|
||||
availableRoles: string[],
|
||||
handleRoleChange: string => void,
|
||||
role: string,
|
||||
label?: string,
|
||||
helpText?: string,
|
||||
loading?: boolean
|
||||
};
|
||||
|
||||
class RoleSelector extends React.Component<Props> {
|
||||
render() {
|
||||
const {
|
||||
availableRoles,
|
||||
role,
|
||||
handleRoleChange,
|
||||
loading,
|
||||
label,
|
||||
helpText
|
||||
} = this.props;
|
||||
|
||||
if (!availableRoles) return null;
|
||||
|
||||
const options = role
|
||||
? this.createSelectOptions(availableRoles)
|
||||
: ["", ...this.createSelectOptions(availableRoles)];
|
||||
|
||||
return (
|
||||
<Select
|
||||
onChange={handleRoleChange}
|
||||
value={role ? role : ""}
|
||||
options={options}
|
||||
loading={loading}
|
||||
label={label}
|
||||
helpText={helpText}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
createSelectOptions(roles: string[]) {
|
||||
return roles.map(role => {
|
||||
return {
|
||||
label: role,
|
||||
value: role
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default translate("repos")(RoleSelector);
|
||||
@@ -0,0 +1,73 @@
|
||||
// @flow
|
||||
import React from "react";
|
||||
import { translate } from "react-i18next";
|
||||
import type { Permission } from "@scm-manager/ui-types";
|
||||
import { confirmAlert } from "@scm-manager/ui-components";
|
||||
|
||||
type Props = {
|
||||
permission: Permission,
|
||||
namespace: string,
|
||||
repoName: string,
|
||||
confirmDialog?: boolean,
|
||||
t: string => string,
|
||||
deletePermission: (
|
||||
permission: Permission,
|
||||
namespace: string,
|
||||
repoName: string
|
||||
) => void,
|
||||
loading: boolean
|
||||
};
|
||||
|
||||
class DeletePermissionButton extends React.Component<Props> {
|
||||
static defaultProps = {
|
||||
confirmDialog: true
|
||||
};
|
||||
|
||||
deletePermission = () => {
|
||||
this.props.deletePermission(
|
||||
this.props.permission,
|
||||
this.props.namespace,
|
||||
this.props.repoName
|
||||
);
|
||||
};
|
||||
|
||||
confirmDelete = () => {
|
||||
const { t } = this.props;
|
||||
confirmAlert({
|
||||
title: t("permission.delete-permission-button.confirm-alert.title"),
|
||||
message: t("permission.delete-permission-button.confirm-alert.message"),
|
||||
buttons: [
|
||||
{
|
||||
label: t("permission.delete-permission-button.confirm-alert.submit"),
|
||||
onClick: () => this.deletePermission()
|
||||
},
|
||||
{
|
||||
label: t("permission.delete-permission-button.confirm-alert.cancel"),
|
||||
onClick: () => null
|
||||
}
|
||||
]
|
||||
});
|
||||
};
|
||||
|
||||
isDeletable = () => {
|
||||
return this.props.permission._links.delete;
|
||||
};
|
||||
|
||||
render() {
|
||||
const { confirmDialog } = this.props;
|
||||
const action = confirmDialog ? this.confirmDelete : this.deletePermission;
|
||||
|
||||
if (!this.isDeletable()) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<a className="level-item" onClick={action}>
|
||||
<span className="icon is-small">
|
||||
<i className="fas fa-trash" />
|
||||
</span>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default translate("repos")(DeletePermissionButton);
|
||||
@@ -0,0 +1,98 @@
|
||||
import React from "react";
|
||||
import { mount, shallow } from "enzyme";
|
||||
import "../../../../tests/enzyme";
|
||||
import "../../../../tests/i18n";
|
||||
import DeletePermissionButton from "./DeletePermissionButton";
|
||||
|
||||
import { confirmAlert } from "@scm-manager/ui-components";
|
||||
import ReactRouterEnzymeContext from "react-router-enzyme-context";
|
||||
jest.mock("@scm-manager/ui-components", () => ({
|
||||
confirmAlert: jest.fn(),
|
||||
DeleteButton: require.requireActual("@scm-manager/ui-components").DeleteButton
|
||||
}));
|
||||
|
||||
describe("DeletePermissionButton", () => {
|
||||
const options = new ReactRouterEnzymeContext();
|
||||
|
||||
it("should render nothing, if the delete link is missing", () => {
|
||||
const permission = {
|
||||
_links: {}
|
||||
};
|
||||
|
||||
const navLink = shallow(
|
||||
<DeletePermissionButton
|
||||
permission={permission}
|
||||
deletePermission={() => {}}
|
||||
/>,
|
||||
options.get()
|
||||
);
|
||||
expect(navLink.text()).toBe("");
|
||||
});
|
||||
|
||||
it("should render the delete icon", () => {
|
||||
const permission = {
|
||||
_links: {
|
||||
delete: {
|
||||
href: "/permission"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const deleteIcon = mount(
|
||||
<DeletePermissionButton
|
||||
permission={permission}
|
||||
deletePermission={() => {}}
|
||||
/>,
|
||||
options.get()
|
||||
);
|
||||
expect(deleteIcon.html()).not.toBe("");
|
||||
});
|
||||
|
||||
it("should open the confirm dialog on button click", () => {
|
||||
const permission = {
|
||||
_links: {
|
||||
delete: {
|
||||
href: "/permission"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const button = mount(
|
||||
<DeletePermissionButton
|
||||
permission={permission}
|
||||
deletePermission={() => {}}
|
||||
/>,
|
||||
options.get()
|
||||
);
|
||||
button.find(".fa-trash").simulate("click");
|
||||
|
||||
expect(confirmAlert.mock.calls.length).toBe(1);
|
||||
});
|
||||
|
||||
it("should call the delete permission function with delete url", () => {
|
||||
const permission = {
|
||||
_links: {
|
||||
delete: {
|
||||
href: "/permission"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let calledUrl = null;
|
||||
function capture(permission) {
|
||||
calledUrl = permission._links.delete.href;
|
||||
}
|
||||
|
||||
const button = mount(
|
||||
<DeletePermissionButton
|
||||
permission={permission}
|
||||
confirmDialog={false}
|
||||
deletePermission={capture}
|
||||
/>,
|
||||
options.get()
|
||||
);
|
||||
button.find(".fa-trash").simulate("click");
|
||||
|
||||
expect(calledUrl).toBe("/permission");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,33 @@
|
||||
// @flow
|
||||
import {validation} from "@scm-manager/ui-components";
|
||||
import type {PermissionCollection} from "@scm-manager/ui-types";
|
||||
|
||||
const isNameValid = validation.isNameValid;
|
||||
|
||||
export { isNameValid };
|
||||
|
||||
export const isPermissionValid = (
|
||||
name: string,
|
||||
groupPermission: boolean,
|
||||
permissions: PermissionCollection
|
||||
) => {
|
||||
return (
|
||||
isNameValid(name) &&
|
||||
!currentPermissionIncludeName(name, groupPermission, permissions)
|
||||
);
|
||||
};
|
||||
|
||||
const currentPermissionIncludeName = (
|
||||
name: string,
|
||||
groupPermission: boolean,
|
||||
permissions: PermissionCollection
|
||||
) => {
|
||||
for (let i = 0; i < permissions.length; i++) {
|
||||
if (
|
||||
permissions[i].name === name &&
|
||||
permissions[i].groupPermission === groupPermission
|
||||
)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
@@ -0,0 +1,70 @@
|
||||
//@flow
|
||||
import * as validator from "./permissionValidation";
|
||||
|
||||
describe("permission validation", () => {
|
||||
it("should return true if permission is valid and does not exist", () => {
|
||||
const permissions = [];
|
||||
const name = "PermissionName";
|
||||
const groupPermission = false;
|
||||
|
||||
expect(
|
||||
validator.isPermissionValid(name, groupPermission, permissions)
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("should return true if permission is valid and does not exists with same group permission", () => {
|
||||
const permissions = [
|
||||
{
|
||||
name: "PermissionName",
|
||||
groupPermission: true,
|
||||
type: "READ",
|
||||
_links: {},
|
||||
verbs: []
|
||||
}
|
||||
];
|
||||
const name = "PermissionName";
|
||||
const groupPermission = false;
|
||||
|
||||
expect(
|
||||
validator.isPermissionValid(name, groupPermission, permissions)
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("should return false if permission is valid but exists", () => {
|
||||
const permissions = [
|
||||
{
|
||||
name: "PermissionName",
|
||||
groupPermission: false,
|
||||
type: "READ",
|
||||
_links: {},
|
||||
verbs: []
|
||||
}
|
||||
];
|
||||
const name = "PermissionName";
|
||||
const groupPermission = false;
|
||||
|
||||
expect(
|
||||
validator.isPermissionValid(name, groupPermission, permissions)
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it("should return false if permission does not exist but is invalid", () => {
|
||||
const permissions = [];
|
||||
const name = "@PermissionName";
|
||||
const groupPermission = false;
|
||||
|
||||
expect(
|
||||
validator.isPermissionValid(name, groupPermission, permissions)
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it("should return false if permission is not valid and does not exist", () => {
|
||||
const permissions = [];
|
||||
const name = "@PermissionName";
|
||||
const groupPermission = false;
|
||||
|
||||
expect(
|
||||
validator.isPermissionValid(name, groupPermission, permissions)
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,99 @@
|
||||
// @flow
|
||||
import React from "react";
|
||||
import {
|
||||
ButtonGroup,
|
||||
Button,
|
||||
SubmitButton,
|
||||
Modal
|
||||
} from "@scm-manager/ui-components";
|
||||
import { translate } from "react-i18next";
|
||||
import PermissionCheckbox from "../components/PermissionCheckbox";
|
||||
|
||||
type Props = {
|
||||
readOnly: boolean,
|
||||
availableVerbs: string[],
|
||||
selectedVerbs: string[],
|
||||
onSubmit: (string[]) => void,
|
||||
onClose: () => void,
|
||||
|
||||
// context props
|
||||
t: string => string
|
||||
};
|
||||
|
||||
type State = {
|
||||
verbs: any
|
||||
};
|
||||
|
||||
class AdvancedPermissionsDialog extends React.Component<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
const verbs = {};
|
||||
props.availableVerbs.forEach(
|
||||
verb =>
|
||||
(verbs[verb] = props.selectedVerbs
|
||||
? props.selectedVerbs.includes(verb)
|
||||
: false)
|
||||
);
|
||||
this.state = { verbs };
|
||||
}
|
||||
|
||||
render() {
|
||||
const { t, onClose, readOnly } = this.props;
|
||||
const { verbs } = this.state;
|
||||
|
||||
const verbSelectBoxes = Object.entries(verbs).map(e => (
|
||||
<PermissionCheckbox
|
||||
key={e[0]}
|
||||
disabled={readOnly}
|
||||
name={e[0]}
|
||||
checked={e[1]}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
));
|
||||
|
||||
const submitButton = !readOnly ? (
|
||||
<SubmitButton label={t("permission.advanced.dialog.submit")} />
|
||||
) : null;
|
||||
|
||||
const body = <>{verbSelectBoxes}</>;
|
||||
|
||||
const footer = (
|
||||
<form onSubmit={this.onSubmit}>
|
||||
<ButtonGroup>
|
||||
{submitButton}
|
||||
<Button
|
||||
label={t("permission.advanced.dialog.abort")}
|
||||
action={onClose}
|
||||
/>
|
||||
</ButtonGroup>
|
||||
</form>
|
||||
);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title={t("permission.advanced.dialog.title")}
|
||||
closeFunction={() => onClose()}
|
||||
body={body}
|
||||
footer={footer}
|
||||
active={true}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
handleChange = (value: boolean, name: string) => {
|
||||
const { verbs } = this.state;
|
||||
const newVerbs = { ...verbs, [name]: value };
|
||||
this.setState({ verbs: newVerbs });
|
||||
};
|
||||
|
||||
onSubmit = () => {
|
||||
this.props.onSubmit(
|
||||
Object.entries(this.state.verbs)
|
||||
.filter(e => e[1])
|
||||
.map(e => e[0])
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
export default translate("repos")(AdvancedPermissionsDialog);
|
||||
@@ -0,0 +1,235 @@
|
||||
// @flow
|
||||
import React from "react";
|
||||
import {translate} from "react-i18next";
|
||||
import type {PermissionCollection, PermissionCreateEntry, RepositoryRole, SelectValue} from "@scm-manager/ui-types";
|
||||
import {
|
||||
Button,
|
||||
GroupAutocomplete,
|
||||
LabelWithHelpIcon,
|
||||
Radio,
|
||||
SubmitButton,
|
||||
Subtitle,
|
||||
UserAutocomplete
|
||||
} from "@scm-manager/ui-components";
|
||||
import * as validator from "../components/permissionValidation";
|
||||
import RoleSelector from "../components/RoleSelector";
|
||||
import AdvancedPermissionsDialog from "./AdvancedPermissionsDialog";
|
||||
import {findVerbsForRole} from "../modules/permissions";
|
||||
|
||||
type Props = {
|
||||
availableRoles: RepositoryRole[],
|
||||
availableVerbs: string[],
|
||||
createPermission: (permission: PermissionCreateEntry) => void,
|
||||
loading: boolean,
|
||||
currentPermissions: PermissionCollection,
|
||||
groupAutocompleteLink: string,
|
||||
userAutocompleteLink: string,
|
||||
|
||||
// Context props
|
||||
t: string => string
|
||||
};
|
||||
|
||||
type State = {
|
||||
name: string,
|
||||
role?: string,
|
||||
verbs?: string[],
|
||||
groupPermission: boolean,
|
||||
valid: boolean,
|
||||
value?: SelectValue,
|
||||
showAdvancedDialog: boolean
|
||||
};
|
||||
|
||||
class CreatePermissionForm extends React.Component<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
name: "",
|
||||
role: props.availableRoles[0].name,
|
||||
verbs: undefined,
|
||||
groupPermission: false,
|
||||
valid: true,
|
||||
value: undefined,
|
||||
showAdvancedDialog: false
|
||||
};
|
||||
}
|
||||
|
||||
permissionScopeChanged = event => {
|
||||
const groupPermission = event.target.value === "GROUP_PERMISSION";
|
||||
this.setState({
|
||||
value: undefined,
|
||||
name: "",
|
||||
groupPermission: groupPermission,
|
||||
valid: false
|
||||
});
|
||||
};
|
||||
|
||||
renderAutocompletionField = () => {
|
||||
const group = this.state.groupPermission;
|
||||
if (group) {
|
||||
return (
|
||||
<GroupAutocomplete
|
||||
autocompleteLink={this.props.groupAutocompleteLink}
|
||||
valueSelected={this.selectName}
|
||||
value={this.state.value ? this.state.value : ""}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<UserAutocomplete
|
||||
autocompleteLink={this.props.userAutocompleteLink}
|
||||
valueSelected={this.selectName}
|
||||
value={this.state.value ? this.state.value : ""}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
selectName = (value: SelectValue) => {
|
||||
this.setState({
|
||||
value,
|
||||
name: value.value.id,
|
||||
valid: validator.isPermissionValid(
|
||||
value.value.id,
|
||||
this.state.groupPermission,
|
||||
this.props.currentPermissions
|
||||
)
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { t, availableRoles, availableVerbs, loading } = this.props;
|
||||
const { role, verbs, showAdvancedDialog } = this.state;
|
||||
|
||||
const availableRoleNames = availableRoles.map(r => r.name);
|
||||
|
||||
const selectedVerbs = role ? findVerbsForRole(availableRoles, role) : verbs;
|
||||
|
||||
const advancedDialog = showAdvancedDialog ? (
|
||||
<AdvancedPermissionsDialog
|
||||
availableVerbs={availableVerbs}
|
||||
selectedVerbs={selectedVerbs}
|
||||
onClose={this.toggleAdvancedPermissionsDialog}
|
||||
onSubmit={this.submitAdvancedPermissionsDialog}
|
||||
/>
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<>
|
||||
<hr />
|
||||
<Subtitle
|
||||
subtitle={t("permission.add-permission.add-permission-heading")}
|
||||
/>
|
||||
{advancedDialog}
|
||||
<form onSubmit={this.submit}>
|
||||
<div className="field is-grouped">
|
||||
<div className="control">
|
||||
<Radio
|
||||
name="permission_scope"
|
||||
value="USER_PERMISSION"
|
||||
checked={!this.state.groupPermission}
|
||||
label={t("permission.user-permission")}
|
||||
onChange={this.permissionScopeChanged}
|
||||
/>
|
||||
<Radio
|
||||
name="permission_scope"
|
||||
value="GROUP_PERMISSION"
|
||||
checked={this.state.groupPermission}
|
||||
label={t("permission.group-permission")}
|
||||
onChange={this.permissionScopeChanged}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="columns">
|
||||
<div className="column is-three-fifths">
|
||||
{this.renderAutocompletionField()}
|
||||
</div>
|
||||
<div className="column is-two-fifths">
|
||||
<div className="columns">
|
||||
<div className="column is-narrow">
|
||||
<RoleSelector
|
||||
availableRoles={availableRoleNames}
|
||||
label={t("permission.role")}
|
||||
helpText={t("permission.help.roleHelpText")}
|
||||
handleRoleChange={this.handleRoleChange}
|
||||
role={role}
|
||||
/>
|
||||
</div>
|
||||
<div className="column">
|
||||
<LabelWithHelpIcon
|
||||
label={t("permission.permissions")}
|
||||
helpText={t("permission.help.permissionsHelpText")}
|
||||
/>
|
||||
<Button
|
||||
label={t("permission.advanced-button.label")}
|
||||
action={this.toggleAdvancedPermissionsDialog}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="columns">
|
||||
<div className="column">
|
||||
<SubmitButton
|
||||
label={t("permission.add-permission.submit-button")}
|
||||
loading={loading}
|
||||
disabled={!this.state.valid || this.state.name === ""}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
toggleAdvancedPermissionsDialog = () => {
|
||||
this.setState(prevState => ({
|
||||
showAdvancedDialog: !prevState.showAdvancedDialog
|
||||
}));
|
||||
};
|
||||
|
||||
submitAdvancedPermissionsDialog = (newVerbs: string[]) => {
|
||||
this.setState({
|
||||
showAdvancedDialog: false,
|
||||
role: undefined,
|
||||
verbs: newVerbs
|
||||
});
|
||||
};
|
||||
|
||||
submit = e => {
|
||||
this.props.createPermission({
|
||||
name: this.state.name,
|
||||
role: this.state.role,
|
||||
verbs: this.state.verbs,
|
||||
groupPermission: this.state.groupPermission
|
||||
});
|
||||
this.removeState();
|
||||
e.preventDefault();
|
||||
};
|
||||
|
||||
removeState = () => {
|
||||
this.setState({
|
||||
name: "",
|
||||
role: this.props.availableRoles[0].name,
|
||||
verbs: undefined,
|
||||
valid: true,
|
||||
value: undefined
|
||||
});
|
||||
};
|
||||
|
||||
handleRoleChange = (role: string) => {
|
||||
const selectedRole = this.findAvailableRole(role);
|
||||
if (!selectedRole) {
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
role: selectedRole.name,
|
||||
verbs: []
|
||||
});
|
||||
};
|
||||
|
||||
findAvailableRole = (roleName: string) => {
|
||||
return this.props.availableRoles.find(role => role.name === roleName);
|
||||
};
|
||||
}
|
||||
|
||||
export default translate("repos")(CreatePermissionForm);
|
||||
288
scm-ui/ui-webapp/src/repos/permissions/containers/Permissions.js
Normal file
288
scm-ui/ui-webapp/src/repos/permissions/containers/Permissions.js
Normal file
@@ -0,0 +1,288 @@
|
||||
//@flow
|
||||
import React from "react";
|
||||
import {connect} from "react-redux";
|
||||
import {translate} from "react-i18next";
|
||||
import {
|
||||
createPermission,
|
||||
createPermissionReset,
|
||||
deletePermissionReset,
|
||||
fetchAvailablePermissionsIfNeeded,
|
||||
fetchPermissions,
|
||||
getAvailablePermissions,
|
||||
getAvailableRepositoryRoles,
|
||||
getAvailableRepositoryVerbs,
|
||||
getCreatePermissionFailure,
|
||||
getDeletePermissionsFailure,
|
||||
getFetchAvailablePermissionsFailure,
|
||||
getFetchPermissionsFailure,
|
||||
getModifyPermissionsFailure,
|
||||
getPermissionsOfRepo,
|
||||
hasCreatePermission,
|
||||
isCreatePermissionPending,
|
||||
isFetchAvailablePermissionsPending,
|
||||
isFetchPermissionsPending,
|
||||
modifyPermissionReset
|
||||
} from "../modules/permissions";
|
||||
import {ErrorPage, LabelWithHelpIcon, Loading, Subtitle} from "@scm-manager/ui-components";
|
||||
import type {Permission, PermissionCollection, PermissionCreateEntry, RepositoryRole} from "@scm-manager/ui-types";
|
||||
import SinglePermission from "./SinglePermission";
|
||||
import CreatePermissionForm from "./CreatePermissionForm";
|
||||
import type {History} from "history";
|
||||
import {getPermissionsLink} from "../../modules/repos";
|
||||
import {
|
||||
getGroupAutoCompleteLink,
|
||||
getRepositoryRolesLink,
|
||||
getRepositoryVerbsLink,
|
||||
getUserAutoCompleteLink
|
||||
} from "../../../modules/indexResource";
|
||||
|
||||
type Props = {
|
||||
availablePermissions: boolean,
|
||||
availableRepositoryRoles: RepositoryRole[],
|
||||
availableVerbs: string[],
|
||||
namespace: string,
|
||||
repoName: string,
|
||||
loading: boolean,
|
||||
error: Error,
|
||||
permissions: PermissionCollection,
|
||||
hasPermissionToCreate: boolean,
|
||||
loadingCreatePermission: boolean,
|
||||
repositoryRolesLink: string,
|
||||
repositoryVerbsLink: string,
|
||||
permissionsLink: string,
|
||||
groupAutocompleteLink: string,
|
||||
userAutocompleteLink: string,
|
||||
|
||||
//dispatch functions
|
||||
fetchAvailablePermissionsIfNeeded: (
|
||||
repositoryRolesLink: string,
|
||||
repositoryVerbsLink: string
|
||||
) => void,
|
||||
fetchPermissions: (link: string, namespace: string, repoName: string) => void,
|
||||
createPermission: (
|
||||
link: string,
|
||||
permission: PermissionCreateEntry,
|
||||
namespace: string,
|
||||
repoName: string,
|
||||
callback?: () => void
|
||||
) => void,
|
||||
createPermissionReset: (string, string) => void,
|
||||
modifyPermissionReset: (string, string) => void,
|
||||
deletePermissionReset: (string, string) => void,
|
||||
// context props
|
||||
t: string => string,
|
||||
match: any,
|
||||
history: History
|
||||
};
|
||||
|
||||
class Permissions extends React.Component<Props> {
|
||||
componentDidMount() {
|
||||
const {
|
||||
fetchAvailablePermissionsIfNeeded,
|
||||
fetchPermissions,
|
||||
namespace,
|
||||
repoName,
|
||||
modifyPermissionReset,
|
||||
createPermissionReset,
|
||||
deletePermissionReset,
|
||||
permissionsLink,
|
||||
repositoryRolesLink,
|
||||
repositoryVerbsLink
|
||||
} = this.props;
|
||||
|
||||
createPermissionReset(namespace, repoName);
|
||||
modifyPermissionReset(namespace, repoName);
|
||||
deletePermissionReset(namespace, repoName);
|
||||
fetchAvailablePermissionsIfNeeded(repositoryRolesLink, repositoryVerbsLink);
|
||||
fetchPermissions(permissionsLink, namespace, repoName);
|
||||
}
|
||||
|
||||
createPermission = (permission: Permission) => {
|
||||
this.props.createPermission(
|
||||
this.props.permissionsLink,
|
||||
permission,
|
||||
this.props.namespace,
|
||||
this.props.repoName
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
availablePermissions,
|
||||
availableRepositoryRoles,
|
||||
availableVerbs,
|
||||
loading,
|
||||
error,
|
||||
permissions,
|
||||
t,
|
||||
namespace,
|
||||
repoName,
|
||||
loadingCreatePermission,
|
||||
hasPermissionToCreate,
|
||||
userAutocompleteLink,
|
||||
groupAutocompleteLink
|
||||
} = this.props;
|
||||
if (error) {
|
||||
return (
|
||||
<ErrorPage
|
||||
title={t("permission.error-title")}
|
||||
subtitle={t("permission.error-subtitle")}
|
||||
error={error}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (loading || !permissions || !availablePermissions) {
|
||||
return <Loading />;
|
||||
}
|
||||
|
||||
const createPermissionForm = hasPermissionToCreate ? (
|
||||
<CreatePermissionForm
|
||||
availableRoles={availableRepositoryRoles}
|
||||
availableVerbs={availableVerbs}
|
||||
createPermission={permission => this.createPermission(permission)}
|
||||
loading={loadingCreatePermission}
|
||||
currentPermissions={permissions}
|
||||
userAutocompleteLink={userAutocompleteLink}
|
||||
groupAutocompleteLink={groupAutocompleteLink}
|
||||
/>
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Subtitle subtitle={t("permission.title")} />
|
||||
<table className="card-table table is-hoverable is-fullwidth">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<LabelWithHelpIcon
|
||||
label={t("permission.name")}
|
||||
helpText={t("permission.help.nameHelpText")}
|
||||
/>
|
||||
</th>
|
||||
<th>
|
||||
<LabelWithHelpIcon
|
||||
label={t("permission.role")}
|
||||
helpText={t("permission.help.roleHelpText")}
|
||||
/>
|
||||
</th>
|
||||
<th>
|
||||
<LabelWithHelpIcon
|
||||
label={t("permission.permissions")}
|
||||
helpText={t("permission.help.permissionsHelpText")}
|
||||
/>
|
||||
</th>
|
||||
<th />
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{permissions.map(permission => {
|
||||
return (
|
||||
<SinglePermission
|
||||
availableRepositoryRoles={availableRepositoryRoles}
|
||||
availableRepositoryVerbs={availableVerbs}
|
||||
key={permission.name + permission.groupPermission.toString()}
|
||||
namespace={namespace}
|
||||
repoName={repoName}
|
||||
permission={permission}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
{createPermissionForm}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
const namespace = ownProps.namespace;
|
||||
const repoName = ownProps.repoName;
|
||||
const error =
|
||||
getFetchPermissionsFailure(state, namespace, repoName) ||
|
||||
getCreatePermissionFailure(state, namespace, repoName) ||
|
||||
getDeletePermissionsFailure(state, namespace, repoName) ||
|
||||
getModifyPermissionsFailure(state, namespace, repoName) ||
|
||||
getFetchAvailablePermissionsFailure(state);
|
||||
const loading =
|
||||
isFetchPermissionsPending(state, namespace, repoName) ||
|
||||
isFetchAvailablePermissionsPending(state);
|
||||
const permissions = getPermissionsOfRepo(state, namespace, repoName);
|
||||
const loadingCreatePermission = isCreatePermissionPending(
|
||||
state,
|
||||
namespace,
|
||||
repoName
|
||||
);
|
||||
const hasPermissionToCreate = hasCreatePermission(state, namespace, repoName);
|
||||
const repositoryRolesLink = getRepositoryRolesLink(state);
|
||||
const repositoryVerbsLink = getRepositoryVerbsLink(state);
|
||||
const permissionsLink = getPermissionsLink(state, namespace, repoName);
|
||||
const groupAutocompleteLink = getGroupAutoCompleteLink(state);
|
||||
const userAutocompleteLink = getUserAutoCompleteLink(state);
|
||||
const availablePermissions = getAvailablePermissions(state);
|
||||
const availableRepositoryRoles = getAvailableRepositoryRoles(state);
|
||||
const availableVerbs = getAvailableRepositoryVerbs(state);
|
||||
|
||||
return {
|
||||
availablePermissions,
|
||||
availableRepositoryRoles,
|
||||
availableVerbs,
|
||||
namespace,
|
||||
repoName,
|
||||
repositoryRolesLink,
|
||||
repositoryVerbsLink,
|
||||
error,
|
||||
loading,
|
||||
permissions,
|
||||
hasPermissionToCreate,
|
||||
loadingCreatePermission,
|
||||
permissionsLink,
|
||||
groupAutocompleteLink,
|
||||
userAutocompleteLink
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
fetchPermissions: (link: string, namespace: string, repoName: string) => {
|
||||
dispatch(fetchPermissions(link, namespace, repoName));
|
||||
},
|
||||
fetchAvailablePermissionsIfNeeded: (
|
||||
repositoryRolesLink: string,
|
||||
repositoryVerbsLink: string
|
||||
) => {
|
||||
dispatch(
|
||||
fetchAvailablePermissionsIfNeeded(
|
||||
repositoryRolesLink,
|
||||
repositoryVerbsLink
|
||||
)
|
||||
);
|
||||
},
|
||||
createPermission: (
|
||||
link: string,
|
||||
permission: PermissionCreateEntry,
|
||||
namespace: string,
|
||||
repoName: string,
|
||||
callback?: () => void
|
||||
) => {
|
||||
dispatch(
|
||||
createPermission(link, permission, namespace, repoName, callback)
|
||||
);
|
||||
},
|
||||
createPermissionReset: (namespace: string, repoName: string) => {
|
||||
dispatch(createPermissionReset(namespace, repoName));
|
||||
},
|
||||
modifyPermissionReset: (namespace: string, repoName: string) => {
|
||||
dispatch(modifyPermissionReset(namespace, repoName));
|
||||
},
|
||||
deletePermissionReset: (namespace: string, repoName: string) => {
|
||||
dispatch(deletePermissionReset(namespace, repoName));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(translate("repos")(Permissions));
|
||||
@@ -0,0 +1,277 @@
|
||||
// @flow
|
||||
import React from "react";
|
||||
import type { RepositoryRole, Permission } from "@scm-manager/ui-types";
|
||||
import { translate } from "react-i18next";
|
||||
import {
|
||||
modifyPermission,
|
||||
isModifyPermissionPending,
|
||||
deletePermission,
|
||||
isDeletePermissionPending,
|
||||
findVerbsForRole
|
||||
} from "../modules/permissions";
|
||||
import { connect } from "react-redux";
|
||||
import type { History } from "history";
|
||||
import { Button, Icon } from "@scm-manager/ui-components";
|
||||
import DeletePermissionButton from "../components/buttons/DeletePermissionButton";
|
||||
import RoleSelector from "../components/RoleSelector";
|
||||
import AdvancedPermissionsDialog from "./AdvancedPermissionsDialog";
|
||||
import classNames from "classnames";
|
||||
import injectSheet from "react-jss";
|
||||
|
||||
type Props = {
|
||||
availableRepositoryRoles: RepositoryRole[],
|
||||
availableRepositoryVerbs: string[],
|
||||
submitForm: Permission => void,
|
||||
modifyPermission: (
|
||||
permission: Permission,
|
||||
namespace: string,
|
||||
name: string
|
||||
) => void,
|
||||
permission: Permission,
|
||||
t: string => string,
|
||||
namespace: string,
|
||||
repoName: string,
|
||||
match: any,
|
||||
history: History,
|
||||
loading: boolean,
|
||||
deletePermission: (
|
||||
permission: Permission,
|
||||
namespace: string,
|
||||
name: string
|
||||
) => void,
|
||||
deleteLoading: boolean,
|
||||
classes: any
|
||||
};
|
||||
|
||||
type State = {
|
||||
permission: Permission,
|
||||
showAdvancedDialog: boolean
|
||||
};
|
||||
|
||||
const styles = {
|
||||
centerMiddle: {
|
||||
display: "table-cell",
|
||||
verticalAlign: "middle !important"
|
||||
},
|
||||
columnWidth: {
|
||||
width: "100%"
|
||||
}
|
||||
};
|
||||
|
||||
class SinglePermission extends React.Component<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
const defaultPermission = props.availableRepositoryRoles
|
||||
? props.availableRepositoryRoles[0]
|
||||
: {};
|
||||
|
||||
this.state = {
|
||||
permission: {
|
||||
name: "",
|
||||
role: undefined,
|
||||
verbs: defaultPermission.verbs,
|
||||
groupPermission: false,
|
||||
_links: {}
|
||||
},
|
||||
showAdvancedDialog: false
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { permission } = this.props;
|
||||
|
||||
if (permission) {
|
||||
this.setState({
|
||||
permission: {
|
||||
name: permission.name,
|
||||
role: permission.role,
|
||||
verbs: permission.verbs,
|
||||
groupPermission: permission.groupPermission,
|
||||
_links: permission._links
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
deletePermission = () => {
|
||||
this.props.deletePermission(
|
||||
this.props.permission,
|
||||
this.props.namespace,
|
||||
this.props.repoName
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { permission, showAdvancedDialog } = this.state;
|
||||
const {
|
||||
t,
|
||||
availableRepositoryRoles,
|
||||
availableRepositoryVerbs,
|
||||
loading,
|
||||
namespace,
|
||||
repoName,
|
||||
classes
|
||||
} = this.props;
|
||||
const availableRoleNames =
|
||||
!!availableRepositoryRoles && availableRepositoryRoles.map(r => r.name);
|
||||
const readOnly = !this.mayChangePermissions();
|
||||
const roleSelector = readOnly ? (
|
||||
<td>{permission.role ? permission.role : t("permission.custom")}</td>
|
||||
) : (
|
||||
<td>
|
||||
<RoleSelector
|
||||
handleRoleChange={this.handleRoleChange}
|
||||
availableRoles={availableRoleNames}
|
||||
role={permission.role}
|
||||
loading={loading}
|
||||
/>
|
||||
</td>
|
||||
);
|
||||
|
||||
const selectedVerbs = permission.role
|
||||
? findVerbsForRole(availableRepositoryRoles, permission.role)
|
||||
: permission.verbs;
|
||||
|
||||
const advancedDialog = showAdvancedDialog ? (
|
||||
<AdvancedPermissionsDialog
|
||||
readOnly={readOnly}
|
||||
availableVerbs={availableRepositoryVerbs}
|
||||
selectedVerbs={selectedVerbs}
|
||||
onClose={this.closeAdvancedPermissionsDialog}
|
||||
onSubmit={this.submitAdvancedPermissionsDialog}
|
||||
/>
|
||||
) : null;
|
||||
|
||||
const iconType =
|
||||
permission && permission.groupPermission ? (
|
||||
<Icon title={t("permission.group")} name="user-friends" />
|
||||
) : (
|
||||
<Icon title={t("permission.user")} name="user" />
|
||||
);
|
||||
|
||||
return (
|
||||
<tr className={classes.columnWidth}>
|
||||
<td className={classes.centerMiddle}>
|
||||
{iconType} {permission.name}
|
||||
</td>
|
||||
{roleSelector}
|
||||
<td className={classes.centerMiddle}>
|
||||
<Button
|
||||
label={t("permission.advanced-button.label")}
|
||||
action={this.handleDetailedPermissionsPressed}
|
||||
/>
|
||||
</td>
|
||||
<td className={classNames("is-darker", classes.centerMiddle)}>
|
||||
<DeletePermissionButton
|
||||
permission={permission}
|
||||
namespace={namespace}
|
||||
repoName={repoName}
|
||||
deletePermission={this.deletePermission}
|
||||
loading={this.props.deleteLoading}
|
||||
/>
|
||||
{advancedDialog}
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
mayChangePermissions = () => {
|
||||
return this.props.permission._links && this.props.permission._links.update;
|
||||
};
|
||||
|
||||
handleDetailedPermissionsPressed = () => {
|
||||
this.setState({ showAdvancedDialog: true });
|
||||
};
|
||||
|
||||
closeAdvancedPermissionsDialog = () => {
|
||||
this.setState({ showAdvancedDialog: false });
|
||||
};
|
||||
|
||||
submitAdvancedPermissionsDialog = (newVerbs: string[]) => {
|
||||
const { permission } = this.state;
|
||||
this.setState(
|
||||
{
|
||||
showAdvancedDialog: false,
|
||||
permission: { ...permission, role: undefined, verbs: newVerbs }
|
||||
},
|
||||
() => this.modifyPermissionVerbs(newVerbs)
|
||||
);
|
||||
};
|
||||
|
||||
handleRoleChange = (role: string) => {
|
||||
const { permission } = this.state;
|
||||
this.setState(
|
||||
{
|
||||
permission: { ...permission, role: role, verbs: undefined }
|
||||
},
|
||||
() => this.modifyPermissionRole(role)
|
||||
);
|
||||
};
|
||||
|
||||
findAvailableRole = (roleName: string) => {
|
||||
const { availableRepositoryRoles } = this.props;
|
||||
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
|
||||
);
|
||||
};
|
||||
|
||||
modifyPermissionVerbs = (verbs: string[]) => {
|
||||
let permission = this.state.permission;
|
||||
permission.verbs = verbs;
|
||||
this.props.modifyPermission(
|
||||
permission,
|
||||
this.props.namespace,
|
||||
this.props.repoName
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
const permission = ownProps.permission;
|
||||
const loading = isModifyPermissionPending(
|
||||
state,
|
||||
ownProps.namespace,
|
||||
ownProps.repoName,
|
||||
permission
|
||||
);
|
||||
const deleteLoading = isDeletePermissionPending(
|
||||
state,
|
||||
ownProps.namespace,
|
||||
ownProps.repoName,
|
||||
permission
|
||||
);
|
||||
|
||||
return { loading, deleteLoading };
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
modifyPermission: (
|
||||
permission: Permission,
|
||||
namespace: string,
|
||||
repoName: string
|
||||
) => {
|
||||
dispatch(modifyPermission(permission, namespace, repoName));
|
||||
},
|
||||
deletePermission: (
|
||||
permission: Permission,
|
||||
namespace: string,
|
||||
repoName: string
|
||||
) => {
|
||||
dispatch(deletePermission(permission, namespace, repoName));
|
||||
}
|
||||
};
|
||||
};
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(translate("repos")(injectSheet(styles)(SinglePermission)));
|
||||
755
scm-ui/ui-webapp/src/repos/permissions/modules/permissions.js
Normal file
755
scm-ui/ui-webapp/src/repos/permissions/modules/permissions.js
Normal file
@@ -0,0 +1,755 @@
|
||||
// @flow
|
||||
|
||||
import type { Action } from "@scm-manager/ui-components";
|
||||
import { apiClient } from "@scm-manager/ui-components";
|
||||
import * as types from "../../../modules/types";
|
||||
import type {
|
||||
RepositoryRole,
|
||||
Permission,
|
||||
PermissionCollection,
|
||||
PermissionCreateEntry
|
||||
} from "@scm-manager/ui-types";
|
||||
import { isPending } from "../../../modules/pending";
|
||||
import { getFailure } from "../../../modules/failure";
|
||||
import { Dispatch } from "redux";
|
||||
|
||||
export const FETCH_AVAILABLE = "scm/permissions/FETCH_AVAILABLE";
|
||||
export const FETCH_AVAILABLE_PENDING = `${FETCH_AVAILABLE}_${
|
||||
types.PENDING_SUFFIX
|
||||
}`;
|
||||
export const FETCH_AVAILABLE_SUCCESS = `${FETCH_AVAILABLE}_${
|
||||
types.SUCCESS_SUFFIX
|
||||
}`;
|
||||
export const FETCH_AVAILABLE_FAILURE = `${FETCH_AVAILABLE}_${
|
||||
types.FAILURE_SUFFIX
|
||||
}`;
|
||||
export const FETCH_PERMISSIONS = "scm/permissions/FETCH_PERMISSIONS";
|
||||
export const FETCH_PERMISSIONS_PENDING = `${FETCH_PERMISSIONS}_${
|
||||
types.PENDING_SUFFIX
|
||||
}`;
|
||||
export const FETCH_PERMISSIONS_SUCCESS = `${FETCH_PERMISSIONS}_${
|
||||
types.SUCCESS_SUFFIX
|
||||
}`;
|
||||
export const FETCH_PERMISSIONS_FAILURE = `${FETCH_PERMISSIONS}_${
|
||||
types.FAILURE_SUFFIX
|
||||
}`;
|
||||
export const MODIFY_PERMISSION = "scm/permissions/MODFIY_PERMISSION";
|
||||
export const MODIFY_PERMISSION_PENDING = `${MODIFY_PERMISSION}_${
|
||||
types.PENDING_SUFFIX
|
||||
}`;
|
||||
export const MODIFY_PERMISSION_SUCCESS = `${MODIFY_PERMISSION}_${
|
||||
types.SUCCESS_SUFFIX
|
||||
}`;
|
||||
export const MODIFY_PERMISSION_FAILURE = `${MODIFY_PERMISSION}_${
|
||||
types.FAILURE_SUFFIX
|
||||
}`;
|
||||
export const MODIFY_PERMISSION_RESET = `${MODIFY_PERMISSION}_${
|
||||
types.RESET_SUFFIX
|
||||
}`;
|
||||
export const CREATE_PERMISSION = "scm/permissions/CREATE_PERMISSION";
|
||||
export const CREATE_PERMISSION_PENDING = `${CREATE_PERMISSION}_${
|
||||
types.PENDING_SUFFIX
|
||||
}`;
|
||||
export const CREATE_PERMISSION_SUCCESS = `${CREATE_PERMISSION}_${
|
||||
types.SUCCESS_SUFFIX
|
||||
}`;
|
||||
export const CREATE_PERMISSION_FAILURE = `${CREATE_PERMISSION}_${
|
||||
types.FAILURE_SUFFIX
|
||||
}`;
|
||||
export const CREATE_PERMISSION_RESET = `${CREATE_PERMISSION}_${
|
||||
types.RESET_SUFFIX
|
||||
}`;
|
||||
export const DELETE_PERMISSION = "scm/permissions/DELETE_PERMISSION";
|
||||
export const DELETE_PERMISSION_PENDING = `${DELETE_PERMISSION}_${
|
||||
types.PENDING_SUFFIX
|
||||
}`;
|
||||
export const DELETE_PERMISSION_SUCCESS = `${DELETE_PERMISSION}_${
|
||||
types.SUCCESS_SUFFIX
|
||||
}`;
|
||||
export const DELETE_PERMISSION_FAILURE = `${DELETE_PERMISSION}_${
|
||||
types.FAILURE_SUFFIX
|
||||
}`;
|
||||
export const DELETE_PERMISSION_RESET = `${DELETE_PERMISSION}_${
|
||||
types.RESET_SUFFIX
|
||||
}`;
|
||||
|
||||
const CONTENT_TYPE = "application/vnd.scmm-repositoryPermission+json";
|
||||
|
||||
// fetch available permissions
|
||||
|
||||
export function fetchAvailablePermissionsIfNeeded(
|
||||
repositoryRolesLink: string,
|
||||
repositoryVerbsLink: string
|
||||
) {
|
||||
return function(dispatch: any, getState: () => Object) {
|
||||
if (shouldFetchAvailablePermissions(getState())) {
|
||||
return fetchAvailablePermissions(
|
||||
dispatch,
|
||||
getState,
|
||||
repositoryRolesLink,
|
||||
repositoryVerbsLink
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchAvailablePermissions(
|
||||
dispatch: any,
|
||||
getState: () => Object,
|
||||
repositoryRolesLink: string,
|
||||
repositoryVerbsLink: string
|
||||
) {
|
||||
dispatch(fetchAvailablePending());
|
||||
return apiClient
|
||||
.get(repositoryRolesLink)
|
||||
.then(repositoryRoles => repositoryRoles.json())
|
||||
.then(repositoryRoles => repositoryRoles._embedded.repositoryRoles)
|
||||
.then(repositoryRoles => {
|
||||
return apiClient
|
||||
.get(repositoryVerbsLink)
|
||||
.then(repositoryVerbs => repositoryVerbs.json())
|
||||
.then(repositoryVerbs => repositoryVerbs.verbs)
|
||||
.then(repositoryVerbs => {
|
||||
return {
|
||||
repositoryVerbs,
|
||||
repositoryRoles
|
||||
};
|
||||
});
|
||||
})
|
||||
.then(available => {
|
||||
dispatch(fetchAvailableSuccess(available));
|
||||
})
|
||||
.catch(err => {
|
||||
dispatch(fetchAvailableFailure(err));
|
||||
});
|
||||
}
|
||||
|
||||
export function shouldFetchAvailablePermissions(state: Object) {
|
||||
if (
|
||||
isFetchAvailablePermissionsPending(state) ||
|
||||
getFetchAvailablePermissionsFailure(state)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return !state.available;
|
||||
}
|
||||
|
||||
export function fetchAvailablePending(): Action {
|
||||
return {
|
||||
type: FETCH_AVAILABLE_PENDING,
|
||||
payload: {},
|
||||
itemId: "available"
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchAvailableSuccess(
|
||||
available: [RepositoryRole[], string[]]
|
||||
): Action {
|
||||
return {
|
||||
type: FETCH_AVAILABLE_SUCCESS,
|
||||
payload: available,
|
||||
itemId: "available"
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchAvailableFailure(error: Error): Action {
|
||||
return {
|
||||
type: FETCH_AVAILABLE_FAILURE,
|
||||
payload: {
|
||||
error
|
||||
},
|
||||
itemId: "available"
|
||||
};
|
||||
}
|
||||
|
||||
// fetch permissions
|
||||
|
||||
export function fetchPermissions(
|
||||
link: string,
|
||||
namespace: string,
|
||||
repoName: string
|
||||
) {
|
||||
return function(dispatch: any) {
|
||||
dispatch(fetchPermissionsPending(namespace, repoName));
|
||||
return apiClient
|
||||
.get(link)
|
||||
.then(response => response.json())
|
||||
.then(permissions => {
|
||||
dispatch(fetchPermissionsSuccess(permissions, namespace, repoName));
|
||||
})
|
||||
.catch(err => {
|
||||
dispatch(fetchPermissionsFailure(namespace, repoName, err));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchPermissionsPending(
|
||||
namespace: string,
|
||||
repoName: string
|
||||
): Action {
|
||||
return {
|
||||
type: FETCH_PERMISSIONS_PENDING,
|
||||
payload: {
|
||||
namespace,
|
||||
repoName
|
||||
},
|
||||
itemId: namespace + "/" + repoName
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchPermissionsSuccess(
|
||||
permissions: any,
|
||||
namespace: string,
|
||||
repoName: string
|
||||
): Action {
|
||||
return {
|
||||
type: FETCH_PERMISSIONS_SUCCESS,
|
||||
payload: permissions,
|
||||
itemId: namespace + "/" + repoName
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchPermissionsFailure(
|
||||
namespace: string,
|
||||
repoName: string,
|
||||
error: Error
|
||||
): Action {
|
||||
return {
|
||||
type: FETCH_PERMISSIONS_FAILURE,
|
||||
payload: {
|
||||
namespace,
|
||||
repoName,
|
||||
error
|
||||
},
|
||||
itemId: namespace + "/" + repoName
|
||||
};
|
||||
}
|
||||
|
||||
// modify permission
|
||||
|
||||
export function modifyPermission(
|
||||
permission: Permission,
|
||||
namespace: string,
|
||||
repoName: string,
|
||||
callback?: () => void
|
||||
) {
|
||||
return function(dispatch: any) {
|
||||
dispatch(modifyPermissionPending(permission, namespace, repoName));
|
||||
return apiClient
|
||||
.put(permission._links.update.href, permission, CONTENT_TYPE)
|
||||
.then(() => {
|
||||
dispatch(modifyPermissionSuccess(permission, namespace, repoName));
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
dispatch(modifyPermissionFailure(permission, err, namespace, repoName));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function modifyPermissionPending(
|
||||
permission: Permission,
|
||||
namespace: string,
|
||||
repoName: string
|
||||
): Action {
|
||||
return {
|
||||
type: MODIFY_PERMISSION_PENDING,
|
||||
payload: permission,
|
||||
itemId: createItemId(permission, namespace, repoName)
|
||||
};
|
||||
}
|
||||
|
||||
export function modifyPermissionSuccess(
|
||||
permission: Permission,
|
||||
namespace: string,
|
||||
repoName: string
|
||||
): Action {
|
||||
return {
|
||||
type: MODIFY_PERMISSION_SUCCESS,
|
||||
payload: {
|
||||
permission,
|
||||
position: namespace + "/" + repoName
|
||||
},
|
||||
itemId: createItemId(permission, namespace, repoName)
|
||||
};
|
||||
}
|
||||
|
||||
export function modifyPermissionFailure(
|
||||
permission: Permission,
|
||||
error: Error,
|
||||
namespace: string,
|
||||
repoName: string
|
||||
): Action {
|
||||
return {
|
||||
type: MODIFY_PERMISSION_FAILURE,
|
||||
payload: { error, permission },
|
||||
itemId: createItemId(permission, namespace, repoName)
|
||||
};
|
||||
}
|
||||
|
||||
function newPermissions(
|
||||
oldPermissions: PermissionCollection,
|
||||
newPermission: Permission
|
||||
) {
|
||||
for (let i = 0; i < oldPermissions.length; i++) {
|
||||
if (oldPermissions[i].name === newPermission.name) {
|
||||
oldPermissions.splice(i, 1, newPermission);
|
||||
return oldPermissions;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function modifyPermissionReset(namespace: string, repoName: string) {
|
||||
return {
|
||||
type: MODIFY_PERMISSION_RESET,
|
||||
payload: {
|
||||
namespace,
|
||||
repoName
|
||||
},
|
||||
itemId: namespace + "/" + repoName
|
||||
};
|
||||
}
|
||||
|
||||
// create permission
|
||||
export function createPermission(
|
||||
link: string,
|
||||
permission: PermissionCreateEntry,
|
||||
namespace: string,
|
||||
repoName: string,
|
||||
callback?: () => void
|
||||
) {
|
||||
return function(dispatch: Dispatch) {
|
||||
dispatch(createPermissionPending(permission, namespace, repoName));
|
||||
return apiClient
|
||||
.post(link, permission, CONTENT_TYPE)
|
||||
.then(response => {
|
||||
const location = response.headers.get("Location");
|
||||
return apiClient.get(location);
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(createdPermission => {
|
||||
dispatch(
|
||||
createPermissionSuccess(createdPermission, namespace, repoName)
|
||||
);
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
})
|
||||
.catch(err =>
|
||||
dispatch(createPermissionFailure(err, namespace, repoName))
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
export function createPermissionPending(
|
||||
permission: PermissionCreateEntry,
|
||||
namespace: string,
|
||||
repoName: string
|
||||
): Action {
|
||||
return {
|
||||
type: CREATE_PERMISSION_PENDING,
|
||||
payload: permission,
|
||||
itemId: namespace + "/" + repoName
|
||||
};
|
||||
}
|
||||
|
||||
export function createPermissionSuccess(
|
||||
permission: PermissionCreateEntry,
|
||||
namespace: string,
|
||||
repoName: string
|
||||
): Action {
|
||||
return {
|
||||
type: CREATE_PERMISSION_SUCCESS,
|
||||
payload: {
|
||||
permission,
|
||||
position: namespace + "/" + repoName
|
||||
},
|
||||
itemId: namespace + "/" + repoName
|
||||
};
|
||||
}
|
||||
|
||||
export function createPermissionFailure(
|
||||
error: Error,
|
||||
namespace: string,
|
||||
repoName: string
|
||||
): Action {
|
||||
return {
|
||||
type: CREATE_PERMISSION_FAILURE,
|
||||
payload: error,
|
||||
itemId: namespace + "/" + repoName
|
||||
};
|
||||
}
|
||||
|
||||
export function createPermissionReset(namespace: string, repoName: string) {
|
||||
return {
|
||||
type: CREATE_PERMISSION_RESET,
|
||||
itemId: namespace + "/" + repoName
|
||||
};
|
||||
}
|
||||
|
||||
// delete permission
|
||||
|
||||
export function deletePermission(
|
||||
permission: Permission,
|
||||
namespace: string,
|
||||
repoName: string,
|
||||
callback?: () => void
|
||||
) {
|
||||
return function(dispatch: any) {
|
||||
dispatch(deletePermissionPending(permission, namespace, repoName));
|
||||
return apiClient
|
||||
.delete(permission._links.delete.href)
|
||||
.then(() => {
|
||||
dispatch(deletePermissionSuccess(permission, namespace, repoName));
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
dispatch(deletePermissionFailure(permission, namespace, repoName, err));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function deletePermissionPending(
|
||||
permission: Permission,
|
||||
namespace: string,
|
||||
repoName: string
|
||||
): Action {
|
||||
return {
|
||||
type: DELETE_PERMISSION_PENDING,
|
||||
payload: permission,
|
||||
itemId: createItemId(permission, namespace, repoName)
|
||||
};
|
||||
}
|
||||
|
||||
export function deletePermissionSuccess(
|
||||
permission: Permission,
|
||||
namespace: string,
|
||||
repoName: string
|
||||
): Action {
|
||||
return {
|
||||
type: DELETE_PERMISSION_SUCCESS,
|
||||
payload: {
|
||||
permission,
|
||||
position: namespace + "/" + repoName
|
||||
},
|
||||
itemId: createItemId(permission, namespace, repoName)
|
||||
};
|
||||
}
|
||||
|
||||
export function deletePermissionFailure(
|
||||
permission: Permission,
|
||||
namespace: string,
|
||||
repoName: string,
|
||||
error: Error
|
||||
): Action {
|
||||
return {
|
||||
type: DELETE_PERMISSION_FAILURE,
|
||||
payload: {
|
||||
error,
|
||||
permission
|
||||
},
|
||||
itemId: createItemId(permission, namespace, repoName)
|
||||
};
|
||||
}
|
||||
|
||||
export function deletePermissionReset(namespace: string, repoName: string) {
|
||||
return {
|
||||
type: DELETE_PERMISSION_RESET,
|
||||
payload: {
|
||||
namespace,
|
||||
repoName
|
||||
},
|
||||
itemId: namespace + "/" + repoName
|
||||
};
|
||||
}
|
||||
|
||||
function deletePermissionFromState(
|
||||
oldPermissions: PermissionCollection,
|
||||
permission: Permission
|
||||
) {
|
||||
let newPermission = [];
|
||||
for (let i = 0; i < oldPermissions.length; i++) {
|
||||
if (
|
||||
oldPermissions[i].name !== permission.name ||
|
||||
oldPermissions[i].groupPermission !== permission.groupPermission
|
||||
) {
|
||||
newPermission.push(oldPermissions[i]);
|
||||
}
|
||||
}
|
||||
return newPermission;
|
||||
}
|
||||
|
||||
function createItemId(
|
||||
permission: Permission,
|
||||
namespace: string,
|
||||
repoName: string
|
||||
) {
|
||||
let groupPermission = permission.groupPermission ? "@" : "";
|
||||
return namespace + "/" + repoName + "/" + groupPermission + permission.name;
|
||||
}
|
||||
|
||||
// reducer
|
||||
export default function reducer(
|
||||
state: Object = {},
|
||||
action: Action = { type: "UNKNOWN" }
|
||||
): Object {
|
||||
if (!action.payload) {
|
||||
return state;
|
||||
}
|
||||
switch (action.type) {
|
||||
case FETCH_AVAILABLE_SUCCESS:
|
||||
return {
|
||||
...state,
|
||||
available: action.payload
|
||||
};
|
||||
case FETCH_PERMISSIONS_SUCCESS:
|
||||
return {
|
||||
...state,
|
||||
[action.itemId]: {
|
||||
entries: action.payload._embedded.permissions,
|
||||
createPermission: !!action.payload._links.create
|
||||
}
|
||||
};
|
||||
case MODIFY_PERMISSION_SUCCESS:
|
||||
const positionOfPermission = action.payload.position;
|
||||
const newPermission = newPermissions(
|
||||
state[action.payload.position].entries,
|
||||
action.payload.permission
|
||||
);
|
||||
return {
|
||||
...state,
|
||||
[positionOfPermission]: {
|
||||
...state[positionOfPermission],
|
||||
entries: newPermission
|
||||
}
|
||||
};
|
||||
case CREATE_PERMISSION_SUCCESS:
|
||||
// return state;
|
||||
const position = action.payload.position;
|
||||
const permissions = state[action.payload.position].entries;
|
||||
permissions.push(action.payload.permission);
|
||||
return {
|
||||
...state,
|
||||
[position]: {
|
||||
...state[position],
|
||||
entries: permissions
|
||||
}
|
||||
};
|
||||
case DELETE_PERMISSION_SUCCESS:
|
||||
const permissionPosition = action.payload.position;
|
||||
const new_Permissions = deletePermissionFromState(
|
||||
state[action.payload.position].entries,
|
||||
action.payload.permission
|
||||
);
|
||||
return {
|
||||
...state,
|
||||
[permissionPosition]: {
|
||||
...state[permissionPosition],
|
||||
entries: new_Permissions
|
||||
}
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
// selectors
|
||||
|
||||
export function getAvailablePermissions(state: Object) {
|
||||
if (state.permissions) {
|
||||
return state.permissions.available;
|
||||
}
|
||||
}
|
||||
|
||||
export function getAvailableRepositoryRoles(state: Object) {
|
||||
return available(state).repositoryRoles;
|
||||
}
|
||||
|
||||
export function getAvailableRepositoryVerbs(state: Object) {
|
||||
return available(state).repositoryVerbs;
|
||||
}
|
||||
|
||||
function available(state: Object) {
|
||||
if (state.permissions && state.permissions.available) {
|
||||
return state.permissions.available;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
export function getPermissionsOfRepo(
|
||||
state: Object,
|
||||
namespace: string,
|
||||
repoName: string
|
||||
) {
|
||||
if (state.permissions && state.permissions[namespace + "/" + repoName]) {
|
||||
return state.permissions[namespace + "/" + repoName].entries;
|
||||
}
|
||||
}
|
||||
|
||||
export function isFetchAvailablePermissionsPending(state: Object) {
|
||||
return isPending(state, FETCH_AVAILABLE, "available");
|
||||
}
|
||||
|
||||
export function isFetchPermissionsPending(
|
||||
state: Object,
|
||||
namespace: string,
|
||||
repoName: string
|
||||
) {
|
||||
return isPending(state, FETCH_PERMISSIONS, namespace + "/" + repoName);
|
||||
}
|
||||
|
||||
export function getFetchAvailablePermissionsFailure(state: Object) {
|
||||
return getFailure(state, FETCH_AVAILABLE, "available");
|
||||
}
|
||||
|
||||
export function getFetchPermissionsFailure(
|
||||
state: Object,
|
||||
namespace: string,
|
||||
repoName: string
|
||||
) {
|
||||
return getFailure(state, FETCH_PERMISSIONS, namespace + "/" + repoName);
|
||||
}
|
||||
|
||||
export function isModifyPermissionPending(
|
||||
state: Object,
|
||||
namespace: string,
|
||||
repoName: string,
|
||||
permission: Permission
|
||||
) {
|
||||
return isPending(
|
||||
state,
|
||||
MODIFY_PERMISSION,
|
||||
createItemId(permission, namespace, repoName)
|
||||
);
|
||||
}
|
||||
|
||||
export function getModifyPermissionFailure(
|
||||
state: Object,
|
||||
namespace: string,
|
||||
repoName: string,
|
||||
permission: Permission
|
||||
) {
|
||||
return getFailure(
|
||||
state,
|
||||
MODIFY_PERMISSION,
|
||||
createItemId(permission, namespace, repoName)
|
||||
);
|
||||
}
|
||||
|
||||
export function hasCreatePermission(
|
||||
state: Object,
|
||||
namespace: string,
|
||||
repoName: string
|
||||
) {
|
||||
if (state.permissions && state.permissions[namespace + "/" + repoName])
|
||||
return state.permissions[namespace + "/" + repoName].createPermission;
|
||||
else return null;
|
||||
}
|
||||
|
||||
export function isCreatePermissionPending(
|
||||
state: Object,
|
||||
namespace: string,
|
||||
repoName: string
|
||||
) {
|
||||
return isPending(state, CREATE_PERMISSION, namespace + "/" + repoName);
|
||||
}
|
||||
|
||||
export function getCreatePermissionFailure(
|
||||
state: Object,
|
||||
namespace: string,
|
||||
repoName: string
|
||||
) {
|
||||
return getFailure(state, CREATE_PERMISSION, namespace + "/" + repoName);
|
||||
}
|
||||
|
||||
export function isDeletePermissionPending(
|
||||
state: Object,
|
||||
namespace: string,
|
||||
repoName: string,
|
||||
permission: Permission
|
||||
) {
|
||||
return isPending(
|
||||
state,
|
||||
DELETE_PERMISSION,
|
||||
createItemId(permission, namespace, repoName)
|
||||
);
|
||||
}
|
||||
|
||||
export function getDeletePermissionFailure(
|
||||
state: Object,
|
||||
namespace: string,
|
||||
repoName: string,
|
||||
permission: Permission
|
||||
) {
|
||||
return getFailure(
|
||||
state,
|
||||
DELETE_PERMISSION,
|
||||
createItemId(permission, namespace, repoName)
|
||||
);
|
||||
}
|
||||
|
||||
export function getDeletePermissionsFailure(
|
||||
state: Object,
|
||||
namespace: string,
|
||||
repoName: string
|
||||
) {
|
||||
const permissions =
|
||||
state.permissions && state.permissions[namespace + "/" + repoName]
|
||||
? state.permissions[namespace + "/" + repoName].entries
|
||||
: null;
|
||||
if (permissions == null) return undefined;
|
||||
for (let i = 0; i < permissions.length; i++) {
|
||||
if (
|
||||
getDeletePermissionFailure(state, namespace, repoName, permissions[i])
|
||||
) {
|
||||
return getFailure(
|
||||
state,
|
||||
DELETE_PERMISSION,
|
||||
createItemId(permissions[i], namespace, repoName)
|
||||
);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function getModifyPermissionsFailure(
|
||||
state: Object,
|
||||
namespace: string,
|
||||
repoName: string
|
||||
) {
|
||||
const permissions =
|
||||
state.permissions && state.permissions[namespace + "/" + repoName]
|
||||
? state.permissions[namespace + "/" + repoName].entries
|
||||
: null;
|
||||
if (permissions == null) return undefined;
|
||||
for (let i = 0; i < permissions.length; i++) {
|
||||
if (
|
||||
getModifyPermissionFailure(state, namespace, repoName, permissions[i])
|
||||
) {
|
||||
return getFailure(
|
||||
state,
|
||||
MODIFY_PERMISSION,
|
||||
createItemId(permissions[i], namespace, repoName)
|
||||
);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function findVerbsForRole(
|
||||
availableRepositoryRoles: RepositoryRole[],
|
||||
roleName: string
|
||||
) {
|
||||
const matchingRole = availableRepositoryRoles.find(
|
||||
role => roleName === role.name
|
||||
);
|
||||
if (matchingRole) {
|
||||
return matchingRole.verbs;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,783 @@
|
||||
// @flow
|
||||
import configureMockStore from "redux-mock-store";
|
||||
import thunk from "redux-thunk";
|
||||
import fetchMock from "fetch-mock";
|
||||
import reducer, {
|
||||
CREATE_PERMISSION,
|
||||
CREATE_PERMISSION_FAILURE,
|
||||
CREATE_PERMISSION_PENDING,
|
||||
CREATE_PERMISSION_SUCCESS,
|
||||
createPermission,
|
||||
createPermissionSuccess,
|
||||
DELETE_PERMISSION,
|
||||
DELETE_PERMISSION_FAILURE,
|
||||
DELETE_PERMISSION_PENDING,
|
||||
DELETE_PERMISSION_SUCCESS,
|
||||
deletePermission,
|
||||
deletePermissionSuccess,
|
||||
FETCH_PERMISSIONS,
|
||||
FETCH_PERMISSIONS_FAILURE,
|
||||
FETCH_PERMISSIONS_PENDING,
|
||||
FETCH_PERMISSIONS_SUCCESS,
|
||||
fetchPermissions,
|
||||
fetchPermissionsSuccess,
|
||||
getCreatePermissionFailure,
|
||||
getDeletePermissionFailure,
|
||||
getDeletePermissionsFailure,
|
||||
getFetchPermissionsFailure,
|
||||
getModifyPermissionFailure,
|
||||
getModifyPermissionsFailure,
|
||||
getPermissionsOfRepo,
|
||||
hasCreatePermission,
|
||||
isCreatePermissionPending,
|
||||
isDeletePermissionPending,
|
||||
isFetchPermissionsPending,
|
||||
isModifyPermissionPending,
|
||||
MODIFY_PERMISSION,
|
||||
MODIFY_PERMISSION_FAILURE,
|
||||
MODIFY_PERMISSION_PENDING,
|
||||
MODIFY_PERMISSION_SUCCESS,
|
||||
modifyPermission,
|
||||
modifyPermissionSuccess
|
||||
} from "./permissions";
|
||||
import type {Permission, PermissionCollection} from "@scm-manager/ui-types";
|
||||
|
||||
const hitchhiker_puzzle42Permission_user_eins: Permission = {
|
||||
name: "user_eins",
|
||||
type: "READ",
|
||||
groupPermission: false,
|
||||
_links: {
|
||||
self: {
|
||||
href:
|
||||
"http://localhost:8081/scm/api/rest/v2/repositories/hitchhiker/puzzle42/permissions/user_eins"
|
||||
},
|
||||
delete: {
|
||||
href:
|
||||
"http://localhost:8081/scm/api/rest/v2/repositories/hitchhiker/puzzle42/permissions/user_eins"
|
||||
},
|
||||
update: {
|
||||
href:
|
||||
"http://localhost:8081/scm/api/rest/v2/repositories/hitchhiker/puzzle42/permissions/user_eins"
|
||||
}
|
||||
},
|
||||
verbs: []
|
||||
};
|
||||
|
||||
const hitchhiker_puzzle42Permission_user_zwei: Permission = {
|
||||
name: "user_zwei",
|
||||
type: "WRITE",
|
||||
groupPermission: true,
|
||||
_links: {
|
||||
self: {
|
||||
href:
|
||||
"http://localhost:8081/scm/api/rest/v2/repositories/hitchhiker/puzzle42/permissions/user_zwei"
|
||||
},
|
||||
delete: {
|
||||
href:
|
||||
"http://localhost:8081/scm/api/rest/v2/repositories/hitchhiker/puzzle42/permissions/user_zwei"
|
||||
},
|
||||
update: {
|
||||
href:
|
||||
"http://localhost:8081/scm/api/rest/v2/repositories/hitchhiker/puzzle42/permissions/user_zwei"
|
||||
}
|
||||
},
|
||||
verbs: []
|
||||
};
|
||||
|
||||
const hitchhiker_puzzle42Permissions: PermissionCollection = [
|
||||
hitchhiker_puzzle42Permission_user_eins,
|
||||
hitchhiker_puzzle42Permission_user_zwei
|
||||
];
|
||||
|
||||
const hitchhiker_puzzle42RepoPermissions = {
|
||||
_embedded: {
|
||||
permissions: hitchhiker_puzzle42Permissions
|
||||
},
|
||||
_links: {
|
||||
create: {
|
||||
href:
|
||||
"http://localhost:8081/scm/api/rest/v2/repositories/hitchhiker/puzzle42/permissions"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
describe("permission fetch", () => {
|
||||
const REPOS_URL = "/api/v2/repositories";
|
||||
const URL = "repositories";
|
||||
const mockStore = configureMockStore([thunk]);
|
||||
|
||||
afterEach(() => {
|
||||
fetchMock.reset();
|
||||
fetchMock.restore();
|
||||
});
|
||||
|
||||
it("should successfully fetch permissions to repo hitchhiker/puzzle42", () => {
|
||||
fetchMock.getOnce(
|
||||
REPOS_URL + "/hitchhiker/puzzle42/permissions",
|
||||
hitchhiker_puzzle42RepoPermissions
|
||||
);
|
||||
|
||||
const expectedActions = [
|
||||
{
|
||||
type: FETCH_PERMISSIONS_PENDING,
|
||||
payload: {
|
||||
namespace: "hitchhiker",
|
||||
repoName: "puzzle42"
|
||||
},
|
||||
itemId: "hitchhiker/puzzle42"
|
||||
},
|
||||
{
|
||||
type: FETCH_PERMISSIONS_SUCCESS,
|
||||
payload: hitchhiker_puzzle42RepoPermissions,
|
||||
itemId: "hitchhiker/puzzle42"
|
||||
}
|
||||
];
|
||||
|
||||
const store = mockStore({});
|
||||
return store
|
||||
.dispatch(
|
||||
fetchPermissions(
|
||||
URL + "/hitchhiker/puzzle42/permissions",
|
||||
"hitchhiker",
|
||||
"puzzle42"
|
||||
)
|
||||
)
|
||||
.then(() => {
|
||||
expect(store.getActions()).toEqual(expectedActions);
|
||||
});
|
||||
});
|
||||
|
||||
it("should dispatch FETCH_PERMISSIONS_FAILURE, it the request fails", () => {
|
||||
fetchMock.getOnce(REPOS_URL + "/hitchhiker/puzzle42/permissions", {
|
||||
status: 500
|
||||
});
|
||||
|
||||
const store = mockStore({});
|
||||
return store
|
||||
.dispatch(
|
||||
fetchPermissions(
|
||||
URL + "/hitchhiker/puzzle42/permissions",
|
||||
"hitchhiker",
|
||||
"puzzle42"
|
||||
)
|
||||
)
|
||||
.then(() => {
|
||||
const actions = store.getActions();
|
||||
expect(actions[0].type).toEqual(FETCH_PERMISSIONS_PENDING);
|
||||
expect(actions[1].type).toEqual(FETCH_PERMISSIONS_FAILURE);
|
||||
expect(actions[1].payload).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
it("should successfully modify user_eins permission", () => {
|
||||
fetchMock.putOnce(
|
||||
hitchhiker_puzzle42Permission_user_eins._links.update.href,
|
||||
{
|
||||
status: 204
|
||||
}
|
||||
);
|
||||
|
||||
let editedPermission = { ...hitchhiker_puzzle42Permission_user_eins, type: "OWNER" };
|
||||
|
||||
const store = mockStore({});
|
||||
|
||||
return store
|
||||
.dispatch(modifyPermission(editedPermission, "hitchhiker", "puzzle42"))
|
||||
.then(() => {
|
||||
const actions = store.getActions();
|
||||
expect(actions[0].type).toEqual(MODIFY_PERMISSION_PENDING);
|
||||
expect(actions[1].type).toEqual(MODIFY_PERMISSION_SUCCESS);
|
||||
});
|
||||
});
|
||||
|
||||
it("should successfully modify user_eins permission and call the callback", () => {
|
||||
fetchMock.putOnce(
|
||||
hitchhiker_puzzle42Permission_user_eins._links.update.href,
|
||||
{
|
||||
status: 204
|
||||
}
|
||||
);
|
||||
|
||||
let editedPermission = { ...hitchhiker_puzzle42Permission_user_eins, type: "OWNER" };
|
||||
|
||||
const store = mockStore({});
|
||||
|
||||
let called = false;
|
||||
const callback = () => {
|
||||
called = true;
|
||||
};
|
||||
|
||||
return store
|
||||
.dispatch(
|
||||
modifyPermission(editedPermission, "hitchhiker", "puzzle42", callback)
|
||||
)
|
||||
.then(() => {
|
||||
const actions = store.getActions();
|
||||
expect(actions[0].type).toEqual(MODIFY_PERMISSION_PENDING);
|
||||
expect(actions[1].type).toEqual(MODIFY_PERMISSION_SUCCESS);
|
||||
expect(called).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
it("should fail modifying on HTTP 500", () => {
|
||||
fetchMock.putOnce(
|
||||
hitchhiker_puzzle42Permission_user_eins._links.update.href,
|
||||
{
|
||||
status: 500
|
||||
}
|
||||
);
|
||||
|
||||
let editedPermission = { ...hitchhiker_puzzle42Permission_user_eins, type: "OWNER" };
|
||||
|
||||
const store = mockStore({});
|
||||
|
||||
return store
|
||||
.dispatch(modifyPermission(editedPermission, "hitchhiker", "puzzle42"))
|
||||
.then(() => {
|
||||
const actions = store.getActions();
|
||||
expect(actions[0].type).toEqual(MODIFY_PERMISSION_PENDING);
|
||||
expect(actions[1].type).toEqual(MODIFY_PERMISSION_FAILURE);
|
||||
expect(actions[1].payload).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
it("should add a permission successfully", () => {
|
||||
// unmatched
|
||||
fetchMock.postOnce(REPOS_URL + "/hitchhiker/puzzle42/permissions", {
|
||||
status: 204,
|
||||
headers: {
|
||||
location: "repositories/hitchhiker/puzzle42/permissions/user_eins"
|
||||
}
|
||||
});
|
||||
|
||||
fetchMock.getOnce(
|
||||
REPOS_URL + "/hitchhiker/puzzle42/permissions/user_eins",
|
||||
hitchhiker_puzzle42Permission_user_eins
|
||||
);
|
||||
|
||||
const store = mockStore({});
|
||||
return store
|
||||
.dispatch(
|
||||
createPermission(
|
||||
URL + "/hitchhiker/puzzle42/permissions",
|
||||
hitchhiker_puzzle42Permission_user_eins,
|
||||
"hitchhiker",
|
||||
"puzzle42"
|
||||
)
|
||||
)
|
||||
.then(() => {
|
||||
const actions = store.getActions();
|
||||
expect(actions[0].type).toEqual(CREATE_PERMISSION_PENDING);
|
||||
expect(actions[1].type).toEqual(CREATE_PERMISSION_SUCCESS);
|
||||
});
|
||||
});
|
||||
|
||||
it("should fail adding a permission on HTTP 500", () => {
|
||||
fetchMock.postOnce(REPOS_URL + "/hitchhiker/puzzle42/permissions", {
|
||||
status: 500
|
||||
});
|
||||
|
||||
const store = mockStore({});
|
||||
return store
|
||||
.dispatch(
|
||||
createPermission(
|
||||
URL + "/hitchhiker/puzzle42/permissions",
|
||||
hitchhiker_puzzle42Permission_user_eins,
|
||||
"hitchhiker",
|
||||
"puzzle42"
|
||||
)
|
||||
)
|
||||
.then(() => {
|
||||
const actions = store.getActions();
|
||||
expect(actions[0].type).toEqual(CREATE_PERMISSION_PENDING);
|
||||
expect(actions[1].type).toEqual(CREATE_PERMISSION_FAILURE);
|
||||
expect(actions[1].payload).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
it("should call the callback after permission successfully created", () => {
|
||||
// unmatched
|
||||
fetchMock.postOnce(REPOS_URL + "/hitchhiker/puzzle42/permissions", {
|
||||
status: 204,
|
||||
headers: {
|
||||
location: "repositories/hitchhiker/puzzle42/permissions/user_eins"
|
||||
}
|
||||
});
|
||||
|
||||
fetchMock.getOnce(
|
||||
REPOS_URL + "/hitchhiker/puzzle42/permissions/user_eins",
|
||||
hitchhiker_puzzle42Permission_user_eins
|
||||
);
|
||||
let callMe = "not yet";
|
||||
|
||||
const callback = () => {
|
||||
callMe = "yeah";
|
||||
};
|
||||
|
||||
const store = mockStore({});
|
||||
return store
|
||||
.dispatch(
|
||||
createPermission(
|
||||
URL + "/hitchhiker/puzzle42/permissions",
|
||||
hitchhiker_puzzle42Permission_user_eins,
|
||||
"hitchhiker",
|
||||
"puzzle42",
|
||||
callback
|
||||
)
|
||||
)
|
||||
.then(() => {
|
||||
expect(callMe).toBe("yeah");
|
||||
});
|
||||
});
|
||||
it("should delete successfully permission user_eins", () => {
|
||||
fetchMock.deleteOnce(
|
||||
hitchhiker_puzzle42Permission_user_eins._links.delete.href,
|
||||
{
|
||||
status: 204
|
||||
}
|
||||
);
|
||||
|
||||
const store = mockStore({});
|
||||
return store
|
||||
.dispatch(
|
||||
deletePermission(
|
||||
hitchhiker_puzzle42Permission_user_eins,
|
||||
"hitchhiker",
|
||||
"puzzle42"
|
||||
)
|
||||
)
|
||||
.then(() => {
|
||||
const actions = store.getActions();
|
||||
expect(actions.length).toBe(2);
|
||||
expect(actions[0].type).toEqual(DELETE_PERMISSION_PENDING);
|
||||
expect(actions[0].payload).toBe(
|
||||
hitchhiker_puzzle42Permission_user_eins
|
||||
);
|
||||
expect(actions[1].type).toEqual(DELETE_PERMISSION_SUCCESS);
|
||||
});
|
||||
});
|
||||
|
||||
it("should call the callback, after successful delete", () => {
|
||||
fetchMock.deleteOnce(
|
||||
hitchhiker_puzzle42Permission_user_eins._links.delete.href,
|
||||
{
|
||||
status: 204
|
||||
}
|
||||
);
|
||||
|
||||
let called = false;
|
||||
const callMe = () => {
|
||||
called = true;
|
||||
};
|
||||
|
||||
const store = mockStore({});
|
||||
return store
|
||||
.dispatch(
|
||||
deletePermission(
|
||||
hitchhiker_puzzle42Permission_user_eins,
|
||||
"hitchhiker",
|
||||
"puzzle42",
|
||||
callMe
|
||||
)
|
||||
)
|
||||
.then(() => {
|
||||
expect(called).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
it("should fail to delete permission", () => {
|
||||
fetchMock.deleteOnce(
|
||||
hitchhiker_puzzle42Permission_user_eins._links.delete.href,
|
||||
{
|
||||
status: 500
|
||||
}
|
||||
);
|
||||
|
||||
const store = mockStore({});
|
||||
return store
|
||||
.dispatch(
|
||||
deletePermission(
|
||||
hitchhiker_puzzle42Permission_user_eins,
|
||||
"hitchhiker",
|
||||
"puzzle42"
|
||||
)
|
||||
)
|
||||
.then(() => {
|
||||
const actions = store.getActions();
|
||||
expect(actions[0].type).toEqual(DELETE_PERMISSION_PENDING);
|
||||
expect(actions[0].payload).toBe(
|
||||
hitchhiker_puzzle42Permission_user_eins
|
||||
);
|
||||
expect(actions[1].type).toEqual(DELETE_PERMISSION_FAILURE);
|
||||
expect(actions[1].payload).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("permissions reducer", () => {
|
||||
it("should return empty object, if state and action is undefined", () => {
|
||||
expect(reducer()).toEqual({});
|
||||
});
|
||||
|
||||
it("should return the same state, if the action is undefined", () => {
|
||||
const state = { x: true };
|
||||
expect(reducer(state)).toBe(state);
|
||||
});
|
||||
|
||||
it("should return the same state, if the action is unknown to the reducer", () => {
|
||||
const state = { x: true };
|
||||
expect(reducer(state, { type: "EL_SPECIALE" })).toBe(state);
|
||||
});
|
||||
|
||||
it("should store the permissions on FETCH_PERMISSION_SUCCESS", () => {
|
||||
const newState = reducer(
|
||||
{},
|
||||
fetchPermissionsSuccess(
|
||||
hitchhiker_puzzle42RepoPermissions,
|
||||
"hitchhiker",
|
||||
"puzzle42"
|
||||
)
|
||||
);
|
||||
|
||||
expect(newState["hitchhiker/puzzle42"].entries).toBe(
|
||||
hitchhiker_puzzle42Permissions
|
||||
);
|
||||
});
|
||||
|
||||
it("should update permission", () => {
|
||||
const oldState = {
|
||||
"hitchhiker/puzzle42": {
|
||||
entries: [hitchhiker_puzzle42Permission_user_eins]
|
||||
}
|
||||
};
|
||||
let permissionEdited = { ...hitchhiker_puzzle42Permission_user_eins, type: "OWNER" };
|
||||
let expectedState = {
|
||||
"hitchhiker/puzzle42": {
|
||||
entries: [permissionEdited]
|
||||
}
|
||||
};
|
||||
const newState = reducer(
|
||||
oldState,
|
||||
modifyPermissionSuccess(permissionEdited, "hitchhiker", "puzzle42")
|
||||
);
|
||||
expect(newState["hitchhiker/puzzle42"]).toEqual(
|
||||
expectedState["hitchhiker/puzzle42"]
|
||||
);
|
||||
});
|
||||
|
||||
it("should remove permission from state when delete succeeds", () => {
|
||||
const state = {
|
||||
"hitchhiker/puzzle42": {
|
||||
entries: [
|
||||
hitchhiker_puzzle42Permission_user_eins,
|
||||
hitchhiker_puzzle42Permission_user_zwei
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
const expectedState = {
|
||||
"hitchhiker/puzzle42": {
|
||||
entries: [hitchhiker_puzzle42Permission_user_zwei]
|
||||
}
|
||||
};
|
||||
|
||||
const newState = reducer(
|
||||
state,
|
||||
deletePermissionSuccess(
|
||||
hitchhiker_puzzle42Permission_user_eins,
|
||||
"hitchhiker",
|
||||
"puzzle42"
|
||||
)
|
||||
);
|
||||
expect(newState["hitchhiker/puzzle42"]).toEqual(
|
||||
expectedState["hitchhiker/puzzle42"]
|
||||
);
|
||||
});
|
||||
|
||||
it("should add permission", () => {
|
||||
//changing state had to be removed because of errors
|
||||
const oldState = {
|
||||
"hitchhiker/puzzle42": {
|
||||
entries: [hitchhiker_puzzle42Permission_user_eins]
|
||||
}
|
||||
};
|
||||
let expectedState = {
|
||||
"hitchhiker/puzzle42": {
|
||||
entries: [
|
||||
hitchhiker_puzzle42Permission_user_eins,
|
||||
hitchhiker_puzzle42Permission_user_zwei
|
||||
]
|
||||
}
|
||||
};
|
||||
const newState = reducer(
|
||||
oldState,
|
||||
createPermissionSuccess(
|
||||
hitchhiker_puzzle42Permission_user_zwei,
|
||||
"hitchhiker",
|
||||
"puzzle42"
|
||||
)
|
||||
);
|
||||
expect(newState["hitchhiker/puzzle42"]).toEqual(
|
||||
expectedState["hitchhiker/puzzle42"]
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("permissions selectors", () => {
|
||||
const error = new Error("something goes wrong");
|
||||
|
||||
it("should return the permissions of one repository", () => {
|
||||
const state = {
|
||||
permissions: {
|
||||
"hitchhiker/puzzle42": {
|
||||
entries: hitchhiker_puzzle42Permissions
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const repoPermissions = getPermissionsOfRepo(
|
||||
state,
|
||||
"hitchhiker",
|
||||
"puzzle42"
|
||||
);
|
||||
expect(repoPermissions).toEqual(hitchhiker_puzzle42Permissions);
|
||||
});
|
||||
|
||||
it("should return true, when fetch permissions is pending", () => {
|
||||
const state = {
|
||||
pending: {
|
||||
[FETCH_PERMISSIONS + "/hitchhiker/puzzle42"]: true
|
||||
}
|
||||
};
|
||||
expect(isFetchPermissionsPending(state, "hitchhiker", "puzzle42")).toEqual(
|
||||
true
|
||||
);
|
||||
});
|
||||
|
||||
it("should return false, when fetch permissions is not pending", () => {
|
||||
expect(isFetchPermissionsPending({}, "hitchiker", "puzzle42")).toEqual(
|
||||
false
|
||||
);
|
||||
});
|
||||
|
||||
it("should return error when fetch permissions did fail", () => {
|
||||
const state = {
|
||||
failure: {
|
||||
[FETCH_PERMISSIONS + "/hitchhiker/puzzle42"]: error
|
||||
}
|
||||
};
|
||||
expect(getFetchPermissionsFailure(state, "hitchhiker", "puzzle42")).toEqual(
|
||||
error
|
||||
);
|
||||
});
|
||||
|
||||
it("should return undefined when fetch permissions did not fail", () => {
|
||||
expect(getFetchPermissionsFailure({}, "hitchhiker", "puzzle42")).toBe(
|
||||
undefined
|
||||
);
|
||||
});
|
||||
|
||||
it("should return true, when modify permission is pending", () => {
|
||||
const state = {
|
||||
pending: {
|
||||
[MODIFY_PERMISSION + "/hitchhiker/puzzle42/user_eins"]: true
|
||||
}
|
||||
};
|
||||
expect(
|
||||
isModifyPermissionPending(
|
||||
state,
|
||||
"hitchhiker",
|
||||
"puzzle42",
|
||||
hitchhiker_puzzle42Permission_user_eins
|
||||
)
|
||||
).toEqual(true);
|
||||
});
|
||||
|
||||
it("should return false, when modify permission is not pending", () => {
|
||||
expect(
|
||||
isModifyPermissionPending(
|
||||
{},
|
||||
"hitchiker",
|
||||
"puzzle42",
|
||||
hitchhiker_puzzle42Permission_user_eins
|
||||
)
|
||||
).toEqual(false);
|
||||
});
|
||||
|
||||
it("should return error when modify permission did fail", () => {
|
||||
const state = {
|
||||
failure: {
|
||||
[MODIFY_PERMISSION + "/hitchhiker/puzzle42/user_eins"]: error
|
||||
}
|
||||
};
|
||||
expect(
|
||||
getModifyPermissionFailure(
|
||||
state,
|
||||
"hitchhiker",
|
||||
"puzzle42",
|
||||
hitchhiker_puzzle42Permission_user_eins
|
||||
)
|
||||
).toEqual(error);
|
||||
});
|
||||
|
||||
it("should return undefined when modify permission did not fail", () => {
|
||||
expect(
|
||||
getModifyPermissionFailure(
|
||||
{},
|
||||
"hitchhiker",
|
||||
"puzzle42",
|
||||
hitchhiker_puzzle42Permission_user_eins
|
||||
)
|
||||
).toBe(undefined);
|
||||
});
|
||||
|
||||
it("should return error when one of the modify permissions did fail", () => {
|
||||
const state = {
|
||||
permissions: {
|
||||
"hitchhiker/puzzle42": { entries: hitchhiker_puzzle42Permissions }
|
||||
},
|
||||
failure: {
|
||||
[MODIFY_PERMISSION + "/hitchhiker/puzzle42/user_eins"]: error
|
||||
}
|
||||
};
|
||||
expect(
|
||||
getModifyPermissionsFailure(state, "hitchhiker", "puzzle42")
|
||||
).toEqual(error);
|
||||
});
|
||||
|
||||
it("should return undefined when no modify permissions did not fail", () => {
|
||||
expect(getModifyPermissionsFailure({}, "hitchhiker", "puzzle42")).toBe(
|
||||
undefined
|
||||
);
|
||||
});
|
||||
|
||||
it("should return true, when createPermission is true", () => {
|
||||
const state = {
|
||||
permissions: {
|
||||
"hitchhiker/puzzle42": {
|
||||
createPermission: true
|
||||
}
|
||||
}
|
||||
};
|
||||
expect(hasCreatePermission(state, "hitchhiker", "puzzle42")).toBe(true);
|
||||
});
|
||||
|
||||
it("should return false, when createPermission is false", () => {
|
||||
const state = {
|
||||
permissions: {
|
||||
"hitchhiker/puzzle42": {
|
||||
createPermission: false
|
||||
}
|
||||
}
|
||||
};
|
||||
expect(hasCreatePermission(state, "hitchhiker", "puzzle42")).toEqual(false);
|
||||
});
|
||||
|
||||
it("should return true, when delete permission is pending", () => {
|
||||
const state = {
|
||||
pending: {
|
||||
[DELETE_PERMISSION + "/hitchhiker/puzzle42/user_eins"]: true
|
||||
}
|
||||
};
|
||||
expect(
|
||||
isDeletePermissionPending(
|
||||
state,
|
||||
"hitchhiker",
|
||||
"puzzle42",
|
||||
hitchhiker_puzzle42Permission_user_eins
|
||||
)
|
||||
).toEqual(true);
|
||||
});
|
||||
|
||||
it("should return false, when delete permission is not pending", () => {
|
||||
expect(
|
||||
isDeletePermissionPending(
|
||||
{},
|
||||
"hitchiker",
|
||||
"puzzle42",
|
||||
hitchhiker_puzzle42Permission_user_eins
|
||||
)
|
||||
).toEqual(false);
|
||||
});
|
||||
|
||||
it("should return error when delete permission did fail", () => {
|
||||
const state = {
|
||||
failure: {
|
||||
[DELETE_PERMISSION + "/hitchhiker/puzzle42/user_eins"]: error
|
||||
}
|
||||
};
|
||||
expect(
|
||||
getDeletePermissionFailure(
|
||||
state,
|
||||
"hitchhiker",
|
||||
"puzzle42",
|
||||
hitchhiker_puzzle42Permission_user_eins
|
||||
)
|
||||
).toEqual(error);
|
||||
});
|
||||
|
||||
it("should return undefined when delete permission did not fail", () => {
|
||||
expect(
|
||||
getDeletePermissionFailure(
|
||||
{},
|
||||
"hitchhiker",
|
||||
"puzzle42",
|
||||
hitchhiker_puzzle42Permission_user_eins
|
||||
)
|
||||
).toBe(undefined);
|
||||
});
|
||||
|
||||
it("should return error when one of the delete permissions did fail", () => {
|
||||
const state = {
|
||||
permissions: {
|
||||
"hitchhiker/puzzle42": { entries: hitchhiker_puzzle42Permissions }
|
||||
},
|
||||
failure: {
|
||||
[DELETE_PERMISSION + "/hitchhiker/puzzle42/user_eins"]: error
|
||||
}
|
||||
};
|
||||
expect(
|
||||
getDeletePermissionsFailure(state, "hitchhiker", "puzzle42")
|
||||
).toEqual(error);
|
||||
});
|
||||
|
||||
it("should return undefined when no delete permissions did not fail", () => {
|
||||
expect(getDeletePermissionsFailure({}, "hitchhiker", "puzzle42")).toBe(
|
||||
undefined
|
||||
);
|
||||
});
|
||||
|
||||
it("should return true, when create permission is pending", () => {
|
||||
const state = {
|
||||
pending: {
|
||||
[CREATE_PERMISSION + "/hitchhiker/puzzle42"]: true
|
||||
}
|
||||
};
|
||||
expect(isCreatePermissionPending(state, "hitchhiker", "puzzle42")).toEqual(
|
||||
true
|
||||
);
|
||||
});
|
||||
|
||||
it("should return false, when create permissions is not pending", () => {
|
||||
expect(isCreatePermissionPending({}, "hitchiker", "puzzle42")).toEqual(
|
||||
false
|
||||
);
|
||||
});
|
||||
|
||||
it("should return error when create permissions did fail", () => {
|
||||
const state = {
|
||||
failure: {
|
||||
[CREATE_PERMISSION + "/hitchhiker/puzzle42"]: error
|
||||
}
|
||||
};
|
||||
expect(getCreatePermissionFailure(state, "hitchhiker", "puzzle42")).toEqual(
|
||||
error
|
||||
);
|
||||
});
|
||||
|
||||
it("should return undefined when create permissions did not fail", () => {
|
||||
expect(getCreatePermissionFailure({}, "hitchhiker", "puzzle42")).toBe(
|
||||
undefined
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user