From 012cfc1806129ea0255b880b171a16eced9c6a09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivar=20Conradi=20=C3=98sthus?= Date: Tue, 12 Oct 2021 13:21:45 +0200 Subject: [PATCH] fix: hide project CRUD actions for oss (#416) --- .../src/component/project/access-component.js | 27 ++- .../project/form-project-component.jsx | 200 ----------------- .../project/form-project-component.tsx | 208 ++++++++++++++++++ .../api/getters/useUiConfig/useUiConfig.ts | 2 + 4 files changed, 230 insertions(+), 207 deletions(-) delete mode 100644 frontend/src/component/project/form-project-component.jsx create mode 100644 frontend/src/component/project/form-project-component.tsx diff --git a/frontend/src/component/project/access-component.js b/frontend/src/component/project/access-component.js index 8c3dc176ec..b169c6b88e 100644 --- a/frontend/src/component/project/access-component.js +++ b/frontend/src/component/project/access-component.js @@ -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

....

; + if (isOss()) { + return ( + + + Controlling access to projects requires a paid version of Unleash. + Check out getunleash.io to find out more. + + ); } const handleRoleChange = (userId, currRoleId) => async evt => { diff --git a/frontend/src/component/project/form-project-component.jsx b/frontend/src/component/project/form-project-component.jsx deleted file mode 100644 index 64988c961a..0000000000 --- a/frontend/src/component/project/form-project-component.jsx +++ /dev/null @@ -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 ( - - } - > - - Projects allows you to group feature toggles together in the - management UI. - -
- this.validateId(v.target.value)} - onChange={v => - this.setValue('id', trim(v.target.value)) - } - /> -
- this.setValue('name', v.target.value)} - /> - - this.setValue('description', v.target.value) - } - /> - - - - - } - /> - -
- ); - } -} - -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; diff --git a/frontend/src/component/project/form-project-component.tsx b/frontend/src/component/project/form-project-component.tsx new file mode 100644 index 0000000000..e84d012725 --- /dev/null +++ b/frontend/src/component/project/form-project-component.tsx @@ -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; + history: any; + submit: (project: any) => Promise; +} + +const ProjectFormComponent = (props: ProjectFormComponentProps) => { + const { editMode } = props; + + const { hasAccess } = useContext(AccessContext); + const [project, setProject ] = useState(props.project || {}); + const [errors, setErrors ] = useState({}); + 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) => { + 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 ( +
+ + } + > + + + Creating and updating projects requires a paid version of Unleash. + Check out getunleash.io + to find out more. + + } elseShow={ + <> + + Projects allows you to group feature toggles together in the + management UI. + +
+ validateId(v.target.value)} + onChange={v => + setValue('id', trim(v.target.value)) + } + /> +
+ setValue('name', v.target.value)} + /> + + setValue('description', v.target.value) + } + /> + + + +
+ } + /> + + + } /> + + + ); +} + +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; diff --git a/frontend/src/hooks/api/getters/useUiConfig/useUiConfig.ts b/frontend/src/hooks/api/getters/useUiConfig/useUiConfig.ts index 44c28578c1..2f50605943 100644 --- a/frontend/src/hooks/api/getters/useUiConfig/useUiConfig.ts +++ b/frontend/src/hooks/api/getters/useUiConfig/useUiConfig.ts @@ -26,6 +26,8 @@ const useUiConfig = () => { const isOss = () => { if (data?.versionInfo?.current?.enterprise) { return false; + } else if (!data || !data.versionInfo) { + return false; } return true; };