1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-07-26 13:48:33 +02:00

fix: hide project CRUD actions for oss (#416)

This commit is contained in:
Ivar Conradi Østhus 2021-10-12 13:21:45 +02:00 committed by GitHub
parent 2990fc180a
commit 012cfc1806
4 changed files with 230 additions and 207 deletions

View File

@ -1,3 +1,4 @@
/* eslint-disable react/jsx-no-target-blank */
import { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import {
@ -20,16 +21,27 @@ import {
FormControl,
} from '@material-ui/core';
import { Delete } from '@material-ui/icons';
import { Alert } from '@material-ui/lab';
import AddUserComponent from './access-add-user';
import projectApi from '../../store/project/api';
import PageContent from '../common/PageContent';
import useUiConfig from '../../hooks/api/getters/useUiConfig/useUiConfig';
function AccessComponent({ projectId, project }) {
const [roles, setRoles] = useState([]);
const [users, setUsers] = useState([]);
const [error, setError] = useState();
const { isOss } = useUiConfig();
useEffect(() => {
fetchAccess();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [projectId]);
const fetchAccess = async () => {
try {
@ -43,13 +55,14 @@ function AccessComponent({ projectId, project }) {
}
};
useEffect(() => {
fetchAccess();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [projectId]);
if (!project) {
return <p>....</p>;
if (isOss()) {
return (
<PageContent>
<Alert severity="error">
Controlling access to projects requires a paid version of Unleash.
Check out <a href="https://www.getunleash.io" target="_blank">getunleash.io</a> to find out more.
</Alert>
</PageContent>);
}
const handleRoleChange = (userId, currRoleId) => async evt => {

View File

@ -1,200 +0,0 @@
import { Component } from 'react';
import PropTypes from 'prop-types';
import { TextField, Typography } from '@material-ui/core';
import styles from './Project.module.scss';
import classnames from 'classnames';
import { FormButtons, styles as commonStyles } from '../common';
import { trim } from '../common/util';
import PageContent from '../common/PageContent/PageContent';
import AccessContext from '../../contexts/AccessContext';
import ConditionallyRender from '../common/ConditionallyRender';
import { CREATE_PROJECT } from '../AccessProvider/permissions';
import HeaderTitle from '../common/HeaderTitle';
class ProjectFormComponent extends Component {
static contextType = AccessContext;
constructor(props) {
super(props);
this.state = {
project: props.project,
errors: {},
currentLegalValue: '',
dirty: false,
};
}
static getDerivedStateFromProps(props, state) {
if (!state.project.id && props.project.id) {
return { project: props.project };
} else {
return null;
}
}
setValue = (field, value) => {
const { project } = this.state;
project[field] = value;
this.setState({ project, dirty: true });
};
validateId = async id => {
const { errors } = this.state;
const { validateId, editMode } = this.props;
if (editMode) return true;
try {
await validateId(id);
errors.id = undefined;
} catch (err) {
errors.id = err.message;
}
this.setState({ errors });
if (errors.id) return false;
return true;
};
validateName = () => {
const { project } = this.state;
if (project.name.length === 0) {
this.setState(prev => ({
errors: { ...prev.errors, name: 'Name can not be empty.' },
}));
return false;
}
return true;
};
validate = async id => {
const validId = await this.validateId(id);
const validName = this.validateName();
return validId && validName;
};
onCancel = evt => {
const { project } = this.state;
evt.preventDefault();
const { editMode } = this.props;
if (editMode) {
this.props.history.push(`/projects/${project.id}`);
return;
}
this.props.history.goBack();
};
onSubmit = async evt => {
evt.preventDefault();
const { project } = this.state;
const valid = await this.validate(project.id);
if (valid) {
const { editMode } = this.props;
const query = editMode ? 'edited=true' : 'created=true';
await this.props.submit(project);
this.props.history.push(`/projects/${project.id}?${query}`);
}
};
render() {
const { project, errors } = this.state;
const { hasAccess } = this.context;
const { editMode } = this.props;
const submitText = editMode ? 'Update' : 'Create';
return (
<PageContent
headerContent={
<HeaderTitle
title={`${submitText} Project`}
/>
}
>
<Typography
variant="subtitle1"
style={{ marginBottom: '0.5rem' }}
>
Projects allows you to group feature toggles together in the
management UI.
</Typography>
<form
onSubmit={this.onSubmit}
className={classnames(
commonStyles.contentSpacing,
styles.formContainer
)}
>
<TextField
label="Project Id"
name="id"
placeholder="A-unique-key"
value={project.id}
error={!!errors.id}
helperText={errors.id}
disabled={editMode}
variant="outlined"
size="small"
onBlur={v => this.validateId(v.target.value)}
onChange={v =>
this.setValue('id', trim(v.target.value))
}
/>
<br />
<TextField
label="Name"
name="name"
placeholder="Project name"
value={project.name}
error={!!errors.name}
variant="outlined"
size="small"
helperText={errors.name}
onChange={v => this.setValue('name', v.target.value)}
/>
<TextField
className={commonStyles.fullwidth}
placeholder="A short description"
rowsMax={2}
label="Description"
error={!!errors.description}
helperText={errors.description}
variant="outlined"
size="small"
multiline
value={project.description}
onChange={v =>
this.setValue('description', v.target.value)
}
/>
<ConditionallyRender
condition={hasAccess(CREATE_PROJECT)}
show={
<div className={styles.formButtons}>
<FormButtons
submitText={submitText}
onCancel={this.onCancel}
/>
</div>
}
/>
</form>
</PageContent>
);
}
}
ProjectFormComponent.propTypes = {
project: PropTypes.object.isRequired,
validateId: PropTypes.func.isRequired,
submit: PropTypes.func.isRequired,
history: PropTypes.object.isRequired,
editMode: PropTypes.bool.isRequired,
};
export default ProjectFormComponent;

View File

@ -0,0 +1,208 @@
import { useContext, useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { TextField, Typography } from '@material-ui/core';
import styles from './Project.module.scss';
import classnames from 'classnames';
import { FormButtons, styles as commonStyles } from '../common';
import { trim } from '../common/util';
import PageContent from '../common/PageContent/PageContent';
import AccessContext from '../../contexts/AccessContext';
import ConditionallyRender from '../common/ConditionallyRender';
import { CREATE_PROJECT } from '../AccessProvider/permissions';
import HeaderTitle from '../common/HeaderTitle';
import useUiConfig from '../../hooks/api/getters/useUiConfig/useUiConfig';
import { Alert } from '@material-ui/lab';
import { FormEvent } from 'react-router/node_modules/@types/react';
import useLoading from '../../hooks/useLoading';
interface ProjectFormComponentProps {
editMode: boolean;
project: any;
validateId: (id: string) => Promise<void>;
history: any;
submit: (project: any) => Promise<void>;
}
const ProjectFormComponent = (props: ProjectFormComponentProps) => {
const { editMode } = props;
const { hasAccess } = useContext(AccessContext);
const [project, setProject ] = useState(props.project || {});
const [errors, setErrors ] = useState<any>({});
const { isOss, loading } = useUiConfig();
const ref = useLoading(loading);
useEffect(() => {
if(!project.id && props.project.id) {
setProject(props.project);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [props.project]);
const setValue = (field: string, value: string) => {
const p = {...project}
p[field] = value;
setProject(p)
};
const validateId = async (id: string) => {
if (editMode) return true;
const e = {...errors};
try {
await props.validateId(id);
e.id = undefined;
} catch (err: any) {
e.id = err.message;
}
setErrors(e)
if (e.id) return false;
return true;
};
const validateName = () => {
if (project.name.length === 0) {
setErrors({...errors, name: 'Name can not be empty.' })
return false;
}
return true;
};
const validate = async (id: string) => {
const validId = await validateId(id);
const validName = validateName();
return validId && validName;
};
const onCancel = (evt: Event) => {
evt.preventDefault();
if (editMode) {
props.history.push(`/projects/${project.id}`);
return;
}
props.history.push(`/projects/`);
};
const onSubmit = async (evt: FormEvent<HTMLFormElement>) => {
evt.preventDefault();
const valid = await validate(project.id);
if (valid) {
const query = editMode ? 'edited=true' : 'created=true';
await props.submit(project);
props.history.push(`/projects/${project.id}?${query}`);
}
};
const submitText = editMode ? 'Update' : 'Create';
return (
<div ref={ref}>
<PageContent
headerContent={
<HeaderTitle
title={`${submitText} Project`}
/>
}
>
<ConditionallyRender condition={isOss()} show={
<Alert data-loading severity="error">
Creating and updating projects requires a paid version of Unleash.
Check out <a href="https://www.getunleash.io" target="_blank" rel="noreferrer">getunleash.io</a>
to find out more.
</Alert>
} elseShow={
<>
<Typography
variant="subtitle1"
style={{ marginBottom: '0.5rem' }}
>
Projects allows you to group feature toggles together in the
management UI.
</Typography>
<form
data-loading
onSubmit={onSubmit}
className={classnames(
commonStyles.contentSpacing,
styles.formContainer
)}
>
<TextField
label="Project Id"
name="id"
placeholder="A-unique-key"
value={project.id}
error={!!errors.id}
helperText={errors.id}
disabled={editMode}
variant="outlined"
size="small"
onBlur={v => validateId(v.target.value)}
onChange={v =>
setValue('id', trim(v.target.value))
}
/>
<br />
<TextField
label="Name"
name="name"
placeholder="Project name"
value={project.name}
error={!!errors.name}
variant="outlined"
size="small"
helperText={errors.name}
onChange={v => setValue('name', v.target.value)}
/>
<TextField
className={commonStyles.fullwidth}
placeholder="A short description"
maxRows={2}
label="Description"
error={!!errors.description}
helperText={errors.description}
variant="outlined"
size="small"
multiline
value={project.description}
onChange={v =>
setValue('description', v.target.value)
}
/>
<ConditionallyRender
condition={hasAccess(CREATE_PROJECT)}
show={
<div className={styles.formButtons}>
<FormButtons
submitText={submitText}
onCancel={onCancel}
/>
</div>
}
/>
</form>
</>
} />
</PageContent>
</div>
);
}
ProjectFormComponent.propTypes = {
project: PropTypes.object.isRequired,
validateId: PropTypes.func.isRequired,
submit: PropTypes.func.isRequired,
history: PropTypes.object.isRequired,
editMode: PropTypes.bool.isRequired,
};
export default ProjectFormComponent;

View File

@ -26,6 +26,8 @@ const useUiConfig = () => {
const isOss = () => {
if (data?.versionInfo?.current?.enterprise) {
return false;
} else if (!data || !data.versionInfo) {
return false;
}
return true;
};