-
-
-
+ admin,
+ routes,
+}) => {
+ const renderLinks = () => {
+ return links.map(link => {
+ let icon = null;
+ if (link.value === 'GitHub') {
+ icon = ;
+ } else if (link.value === 'Documentation') {
+ icon = ;
+ }
- {title}
-
+ return (
+
+ {icon}
+ {link.value}
+
+ );
+ });
+ };
+
+ return (
+
toggleDrawer()}
+ >
+
+
+
+
+
+ {title}
+
+
+
+
+ {routes.mainNavRoutes.map(item => (
+ toggleDrawer()}
+ path={item.path}
+ text={item.title}
+ key={item.path}
+ />
+ ))}
+
+
+
+
+
+ {routes.adminRoutes.map(item => (
+ toggleDrawer()}
+ path={item.path}
+ text={item.title}
+ key={item.path}
+ />
+ ))}
+
+ >
+ }
+ />
+
+ {renderLinks()}
-
-
- {routes.filter(filterByFlags(flags)).map(item => (
- toggleDrawer()}
- key={item.path}
- to={item.path}
- className={classnames(styles.navigationLink)}
- activeClassName={classnames(
- styles.navigationLinkActive
- )}
- >
- {getIcon(item.icon)}
- {item.title}
-
- ))}
-
-
-
- {links.map(l => renderLink(l, toggleDrawer))}
-
-
-
-);
+
+ );
+};
DrawerMenu.propTypes = {
links: PropTypes.array,
diff --git a/frontend/src/component/menu/drawer.module.scss b/frontend/src/component/menu/drawer.module.scss
index 33c52efd4a..730d8c3497 100644
--- a/frontend/src/component/menu/drawer.module.scss
+++ b/frontend/src/component/menu/drawer.module.scss
@@ -22,10 +22,19 @@
margin-left: 0.25rem;
}
-.drawerList {
+.drawerList,
+.iconLinkList {
display: flex;
flex-direction: column;
align-items: centre;
+ padding: 0.5rem;
+}
+
+.iconLink {
+ display: flex;
+ padding: 0.8rem;
+ text-decoration: none;
+ color: inherit;
}
.navigationLink {
@@ -44,6 +53,7 @@
.navigationIcon {
margin-right: 16px;
+ fill: #635dc5;
}
.iconGitHub {
diff --git a/frontend/src/component/menu/routes.js b/frontend/src/component/menu/routes.js
index e7c23af929..d9b8d09fac 100644
--- a/frontend/src/component/menu/routes.js
+++ b/frontend/src/component/menu/routes.js
@@ -15,7 +15,6 @@ import ContextFields from '../../page/context';
import CreateContextField from '../../page/context/create';
import EditContextField from '../../page/context/edit';
import LogoutFeatures from '../../page/user/logout';
-import ListProjects from '../../page/project';
import CreateProject from '../../page/project/create';
import EditProject from '../../page/project/edit';
import ViewProject from '../../page/project/view';
@@ -39,25 +38,9 @@ import { P, C } from '../common/flags';
import NewUser from '../user/NewUser';
import ResetPassword from '../user/ResetPassword/ResetPassword';
import ForgottenPassword from '../user/ForgottenPassword/ForgottenPassword';
-import ProjectListNew from '../project/ProjectListNew/ProjectListNew';
+import ProjectListNew from '../project/ProjectList/ProjectList';
import Project from '../project/Project/Project';
-import {
- List,
- Extension,
- History,
- Archive as ArchiveIcon,
- Apps,
- Label,
- DeviceHub,
- Album,
- ExitToApp,
- FolderOpen,
- Report,
- Money,
- Person,
-} from '@material-ui/icons';
-
export const routes = [
// Features
{
@@ -87,7 +70,6 @@ export const routes = [
{
path: '/features',
title: 'Feature Toggles',
- icon: List,
component: Features,
type: 'protected',
layout: 'main',
@@ -113,7 +95,6 @@ export const routes = [
{
path: '/strategies',
title: 'Strategies',
- icon: Extension,
component: Strategies,
type: 'protected',
layout: 'main',
@@ -131,7 +112,6 @@ export const routes = [
{
path: '/history',
title: 'Event History',
- icon: History,
component: HistoryPage,
type: 'protected',
layout: 'main',
@@ -149,7 +129,6 @@ export const routes = [
{
path: '/archive',
title: 'Archived Toggles',
- icon: ArchiveIcon,
component: Archive,
type: 'protected',
layout: 'main',
@@ -167,7 +146,6 @@ export const routes = [
{
path: '/applications',
title: 'Applications',
- icon: Apps,
component: Applications,
type: 'protected',
layout: 'main',
@@ -193,7 +171,6 @@ export const routes = [
{
path: '/context',
title: 'Context Fields',
- icon: Album,
component: ContextFields,
type: 'protected',
flag: C,
@@ -245,20 +222,9 @@ export const routes = [
{
path: '/projects',
title: 'Projects',
- icon: FolderOpen,
- component: ListProjects,
- flag: P,
- type: 'protected',
- layout: 'main',
- },
- {
- path: '/projects-new',
- title: 'Projects new',
- icon: 'folder_open',
component: ProjectListNew,
flag: P,
type: 'protected',
- hidden: true,
layout: 'main',
},
@@ -281,7 +247,6 @@ export const routes = [
{
path: '/tag-types',
title: 'Tag types',
- icon: Label,
component: ListTagTypes,
type: 'protected',
layout: 'main',
@@ -298,7 +263,6 @@ export const routes = [
{
path: '/tags',
title: 'Tags',
- icon: Label,
component: ListTags,
hidden: true,
type: 'protected',
@@ -325,7 +289,6 @@ export const routes = [
{
path: '/addons',
title: 'Addons',
- icon: DeviceHub,
component: Addons,
hidden: false,
type: 'protected',
@@ -334,7 +297,6 @@ export const routes = [
{
path: '/reporting',
title: 'Reporting',
- icon: Report,
component: Reporting,
type: 'protected',
layout: 'main',
@@ -367,7 +329,6 @@ export const routes = [
{
path: '/admin-invoices',
title: 'Invoices',
- icon: Money,
component: AdminInvoice,
hidden: true,
type: 'protected',
@@ -376,7 +337,6 @@ export const routes = [
{
path: '/admin',
title: 'Admin',
- icon: Album,
component: Admin,
hidden: false,
type: 'protected',
@@ -385,7 +345,6 @@ export const routes = [
{
path: '/logout',
title: 'Sign out',
- icon: ExitToApp,
component: LogoutFeatures,
type: 'unprotected',
layout: 'main',
@@ -393,7 +352,6 @@ export const routes = [
{
path: '/login',
title: 'Log in',
- icon: Person,
component: Login,
type: 'unprotected',
hidden: true,
@@ -430,3 +388,28 @@ export const getRoute = path => routes.find(route => route.path === path);
export const baseRoutes = routes
.filter(route => !route.hidden)
.filter(route => !route.parent);
+
+const computeRoutes = () => {
+ const computedRoutes = {
+ mainNavRoutes:
+ baseRoutes.filter(
+ route =>
+ route.path !== '/admin' &&
+ route.path !== '/logout' &&
+ route.path !== '/history'
+ ) || [],
+ adminRoutes:
+ routes.filter(
+ route =>
+ (route.path.startsWith('/admin') &&
+ route.path !== '/admin-invoices' &&
+ route.path !== '/admin') ||
+ route.path === '/history'
+ ) || [],
+ };
+ return () => {
+ return computedRoutes;
+ };
+};
+
+export const getRoutes = computeRoutes();
diff --git a/frontend/src/component/project/Project/Project.styles.ts b/frontend/src/component/project/Project/Project.styles.ts
new file mode 100644
index 0000000000..cdc33a7f16
--- /dev/null
+++ b/frontend/src/component/project/Project/Project.styles.ts
@@ -0,0 +1,11 @@
+import { makeStyles } from '@material-ui/core/styles';
+
+export const useStyles = makeStyles(theme => ({
+ containerStyles: {
+ marginTop: '1.5rem',
+ display: 'flex',
+ [theme.breakpoints.down('sm')]: {
+ flexDirection: 'column',
+ },
+ },
+}));
diff --git a/frontend/src/component/project/Project/Project.tsx b/frontend/src/component/project/Project/Project.tsx
index 3aeed3a95f..23f196d5c2 100644
--- a/frontend/src/component/project/Project/Project.tsx
+++ b/frontend/src/component/project/Project/Project.tsx
@@ -6,20 +6,46 @@ import ApiError from '../../common/ApiError/ApiError';
import ConditionallyRender from '../../common/ConditionallyRender';
import ProjectFeatureToggles from './ProjectFeatureToggles/ProjectFeatureToggles';
import ProjectInfo from './ProjectInfo/ProjectInfo';
+import { useStyles } from './Project.styles';
+import { IconButton } from '@material-ui/core';
+import { Edit } from '@material-ui/icons';
+import { Link } from 'react-router-dom';
+import useToast from '../../../hooks/useToast';
+import useQueryParams from '../../../hooks/useQueryParams';
+import { useEffect } from 'react';
const Project = () => {
const { id } = useParams<{ id: string }>();
+ const params = useQueryParams();
const { project, error, loading, refetch } = useProject(id);
const ref = useLoading(loading);
+ const { toast, setToastData } = useToast();
const { members, features, health } = project;
const commonStyles = useCommonStyles();
+ const styles = useStyles();
- const containerStyles = { marginTop: '1.5rem', display: 'flex' };
+ useEffect(() => {
+ const created = params.get('created');
+ const edited = params.get('edited');
+
+ if (created || edited) {
+ const text = created ? 'Project created' : 'Project updated';
+ setToastData({
+ show: true,
+ type: 'success',
+ text,
+ });
+ }
+ /* eslint-disable-next-line */
+ }, []);
return (
- {project?.name}
+ {project?.name}{' '}
+
+
+
{
/>
}
/>
-
);
};
diff --git a/frontend/src/component/project/Project/ProjectFeatureToggles/ProjectFeatureToggles.styles.ts b/frontend/src/component/project/Project/ProjectFeatureToggles/ProjectFeatureToggles.styles.ts
index 37a5bce823..4a7839d6bd 100644
--- a/frontend/src/component/project/Project/ProjectFeatureToggles/ProjectFeatureToggles.styles.ts
+++ b/frontend/src/component/project/Project/ProjectFeatureToggles/ProjectFeatureToggles.styles.ts
@@ -6,6 +6,10 @@ export const useStyles = makeStyles(theme => ({
marginLeft: '2rem',
width: '100%',
position: 'relative',
+ [theme.breakpoints.down('sm')]: {
+ marginLeft: '0',
+ paddingBottom: '4rem',
+ },
},
header: {
padding: '1rem',
@@ -22,4 +26,10 @@ export const useStyles = makeStyles(theme => ({
height: '30px',
width: '30px',
},
+ noTogglesFound: {
+ marginBottom: '0.5rem',
+ },
+ link: {
+ textDecoration: 'none',
+ },
}));
diff --git a/frontend/src/component/project/Project/ProjectFeatureToggles/ProjectFeatureToggles.tsx b/frontend/src/component/project/Project/ProjectFeatureToggles/ProjectFeatureToggles.tsx
index a9ca984c9f..d479d8542e 100644
--- a/frontend/src/component/project/Project/ProjectFeatureToggles/ProjectFeatureToggles.tsx
+++ b/frontend/src/component/project/Project/ProjectFeatureToggles/ProjectFeatureToggles.tsx
@@ -1,12 +1,14 @@
-import { Button, IconButton } from '@material-ui/core';
+import { IconButton } from '@material-ui/core';
+import { Add } from '@material-ui/icons';
import FilterListIcon from '@material-ui/icons/FilterList';
import { useParams } from 'react-router';
-import { Link } from 'react-router-dom';
+import { Link, useHistory } from 'react-router-dom';
import { IFeatureToggleListItem } from '../../../../interfaces/featureToggle';
import ConditionallyRender from '../../../common/ConditionallyRender';
import { PROJECTFILTERING } from '../../../common/flags';
import HeaderTitle from '../../../common/HeaderTitle';
import PageContent from '../../../common/PageContent';
+import ResponsiveButton from '../../../common/ResponsiveButton/ResponsiveButton';
import FeatureToggleListNew from '../../../feature/FeatureToggleListNew/FeatureToggleListNew';
import { useStyles } from './ProjectFeatureToggles.styles';
@@ -21,6 +23,7 @@ const ProjectFeatureToggles = ({
}: IProjectFeatureToggles) => {
const styles = useStyles();
const { id } = useParams();
+ const history = useHistory();
return (
}
/>
-
+
>
}
/>
}
>
- 0}
+ show={
+
+ }
+ elseShow={
+ <>
+
+ No feature toggles added yet.
+
+
+ Add your first toggle
+
+ >
+ }
/>
);
diff --git a/frontend/src/component/project/Project/ProjectInfo/ProjectInfo.styles.ts b/frontend/src/component/project/Project/ProjectInfo/ProjectInfo.styles.ts
index fdfde78e46..4090f7bb73 100644
--- a/frontend/src/component/project/Project/ProjectInfo/ProjectInfo.styles.ts
+++ b/frontend/src/component/project/Project/ProjectInfo/ProjectInfo.styles.ts
@@ -3,11 +3,23 @@ import { makeStyles } from '@material-ui/core/styles';
export const useStyles = makeStyles(theme => ({
projectInfo: {
width: '275px',
- padding: '1rem',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
boxShadow: 'none',
+ [theme.breakpoints.down('sm')]: {
+ flexDirection: 'row',
+ alignItems: 'stretch',
+ width: '100%',
+ marginBottom: '1rem',
+ },
+ },
+ projectIcon: {
+ margin: '2rem 0',
+ [theme.breakpoints.down('sm')]: {
+ margin: '0 0 0.25rem 0',
+ width: '53px',
+ },
},
subtitle: {
marginBottom: '1.25rem',
@@ -15,10 +27,35 @@ export const useStyles = makeStyles(theme => ({
emphazisedText: {
fontSize: '1.5rem',
marginBottom: '1rem',
+ [theme.breakpoints.down('sm')]: {
+ fontSize: '1rem',
+ marginBottom: '2rem',
+ },
},
infoSection: {
- margin: '1.8rem 0',
+ margin: '0',
textAlign: 'center',
+ marginBottom: '1.5rem',
+ backgroundColor: '#fff',
+ borderRadius: '10px',
+ width: '100%',
+ padding: '1.5rem 1rem 1.5rem 1rem',
+ [theme.breakpoints.down('sm')]: {
+ margin: '0 0.25rem',
+ display: 'flex',
+ flexDirection: 'column',
+ alignItems: 'center',
+ justifyContent: 'center',
+ fontSize: '0.8rem',
+ position: 'relative',
+ padding: '0.8rem',
+ ['&:first-child']: {
+ marginLeft: '0',
+ },
+ ['&:last-child']: {
+ marginRight: '0',
+ },
+ },
},
arrowIcon: {
color: '#635dc5',
@@ -27,5 +64,14 @@ export const useStyles = makeStyles(theme => ({
infoLink: {
textDecoration: 'none',
color: '#635dc5',
+ [theme.breakpoints.down('sm')]: {
+ position: 'absolute',
+ bottom: '5px',
+ },
+ },
+ linkText: {
+ [theme.breakpoints.down('sm')]: {
+ display: 'none',
+ },
},
}));
diff --git a/frontend/src/component/project/Project/ProjectInfo/ProjectInfo.tsx b/frontend/src/component/project/Project/ProjectInfo/ProjectInfo.tsx
index d4924f095d..dc0fa4e04e 100644
--- a/frontend/src/component/project/Project/ProjectInfo/ProjectInfo.tsx
+++ b/frontend/src/component/project/Project/ProjectInfo/ProjectInfo.tsx
@@ -1,4 +1,3 @@
-import { Paper } from '@material-ui/core';
import { useStyles } from './ProjectInfo.styles';
import { Link } from 'react-router-dom';
import ArrowForwardIcon from '@material-ui/icons/ArrowForward';
@@ -33,15 +32,19 @@ const ProjectInfo = ({
return (
);
diff --git a/frontend/src/component/project/ProjectList/index.jsx b/frontend/src/component/project/ProjectList/index.jsx
deleted file mode 100644
index 73dacbfef7..0000000000
--- a/frontend/src/component/project/ProjectList/index.jsx
+++ /dev/null
@@ -1,22 +0,0 @@
-import { connect } from 'react-redux';
-import { fetchProjects, removeProject } from '../../../store/project/actions';
-import ProjectList from './ProjectList';
-
-const mapStateToProps = state => {
- const projects = state.projects.toJS();
-
- return {
- projects,
- };
-};
-
-const mapDispatchToProps = dispatch => ({
- removeProject: project => {
- removeProject(project)(dispatch);
- },
- fetchProjects: () => fetchProjects()(dispatch),
-});
-
-const ProjectListContainer = connect(mapStateToProps, mapDispatchToProps)(ProjectList);
-
-export default ProjectListContainer;
diff --git a/frontend/src/component/project/ProjectList/loadingData.ts b/frontend/src/component/project/ProjectList/loadingData.ts
new file mode 100644
index 0000000000..04de3f2973
--- /dev/null
+++ b/frontend/src/component/project/ProjectList/loadingData.ts
@@ -0,0 +1,40 @@
+const loadingData = [
+ {
+ id: 'loading1',
+ name: 'loading1',
+ memberCount: 1,
+ health: 95,
+ featureCount: 4,
+ createdAt: '',
+ description: '',
+ },
+ {
+ id: 'loading2',
+ name: 'loading2',
+ memberCount: 1,
+ health: 95,
+ featureCount: 4,
+ createdAt: '',
+ description: '',
+ },
+ {
+ id: 'loading3',
+ name: 'loading3',
+ memberCount: 1,
+ health: 95,
+ featureCount: 4,
+ createdAt: '',
+ description: '',
+ },
+ {
+ id: 'loading4',
+ name: 'loading4',
+ memberCount: 1,
+ health: 95,
+ featureCount: 4,
+ createdAt: '',
+ description: '',
+ },
+];
+
+export default loadingData;
diff --git a/frontend/src/component/project/ProjectList/styles.js b/frontend/src/component/project/ProjectList/styles.js
deleted file mode 100644
index fb054b3439..0000000000
--- a/frontend/src/component/project/ProjectList/styles.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import { makeStyles } from '@material-ui/styles';
-
-export const useStyles = makeStyles({
- listItem: {
- padding: 0,
- ['& a']: {
- textDecoration: 'none',
- color: 'inherit',
- },
- },
-});
diff --git a/frontend/src/component/project/ProjectListNew/ProjectListNew.styles.ts b/frontend/src/component/project/ProjectListNew/ProjectListNew.styles.ts
deleted file mode 100644
index 958b81cb0a..0000000000
--- a/frontend/src/component/project/ProjectListNew/ProjectListNew.styles.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { makeStyles } from '@material-ui/core/styles';
-
-export const useStyles = makeStyles(theme => ({
- container: {
- display: 'flex',
- flexWrap: 'wrap',
- },
- apiError: {
- maxWidth: '400px',
- marginBottom: '1rem',
- },
- cardLink: { color: 'inherit', textDecoration: 'none' },
-}));
diff --git a/frontend/src/component/project/ProjectListNew/loadingData.ts b/frontend/src/component/project/ProjectListNew/loadingData.ts
deleted file mode 100644
index 2747f907b3..0000000000
--- a/frontend/src/component/project/ProjectListNew/loadingData.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-const loadingData = [
- {
- id: 'loading1',
- name: 'loading1',
- members: 1,
- health: 95,
- toggles: 4,
- },
- {
- id: 'loading2',
- name: 'loading2',
- members: 1,
- health: 95,
- toggles: 4,
- },
- {
- id: 'loading3',
- name: 'loading3',
- members: 1,
- health: 95,
- toggles: 4,
- },
- {
- id: 'loading4',
- name: 'loading4',
- members: 1,
- health: 95,
- toggles: 4,
- },
-];
-
-export default loadingData;
diff --git a/frontend/src/component/project/form-project-component.jsx b/frontend/src/component/project/form-project-component.jsx
index 3518fb7856..5f8349bc54 100644
--- a/frontend/src/component/project/form-project-component.jsx
+++ b/frontend/src/component/project/form-project-component.jsx
@@ -1,6 +1,6 @@
-import React, { Component } from 'react';
+import { Component } from 'react';
import PropTypes from 'prop-types';
-import { TextField, Typography } from '@material-ui/core';
+import { TextField, Typography, Button } from '@material-ui/core';
import styles from './Project.module.scss';
import classnames from 'classnames';
@@ -10,7 +10,7 @@ import PageContent from '../common/PageContent/PageContent';
import AccessContext from '../../contexts/AccessContext';
import ConditionallyRender from '../common/ConditionallyRender';
import { CREATE_PROJECT } from '../AccessProvider/permissions';
-import { Link } from 'react-router-dom';
+import HeaderTitle from '../common/HeaderTitle';
class ProjectFormComponent extends Component {
static contextType = AccessContext;
@@ -75,15 +75,10 @@ class ProjectFormComponent extends Component {
};
onCancel = evt => {
- const { editMode } = this.props;
const { project } = this.state;
-
evt.preventDefault();
- if (editMode) {
- this.props.history.push(`/projects/view/${project.id}`);
- } else {
- this.props.history.push('/projects');
- }
+
+ this.props.history.push(`/projects/${project.id}`);
};
onSubmit = async evt => {
@@ -93,8 +88,10 @@ class ProjectFormComponent extends Component {
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/view/${project.id}`);
+ this.props.history.push(`/projects/${project.id}?${query}`);
}
};
@@ -107,20 +104,28 @@ class ProjectFormComponent extends Component {
return (
- {submitText} Project
-
- Manage access
-
- }
- />
-
+