diff --git a/frontend/src/component/Reporting/ReportToggleList/ReportToggleListItem/ReportToggleListItem.jsx b/frontend/src/component/Reporting/ReportToggleList/ReportToggleListItem/ReportToggleListItem.jsx
index 8d3d561eb6..cb5ca47a82 100644
--- a/frontend/src/component/Reporting/ReportToggleList/ReportToggleListItem/ReportToggleListItem.jsx
+++ b/frontend/src/component/Reporting/ReportToggleList/ReportToggleListItem/ReportToggleListItem.jsx
@@ -8,12 +8,27 @@ import CheckIcon from '@material-ui/icons/Check';
import ReportProblemOutlinedIcon from '@material-ui/icons/ReportProblemOutlined';
import ConditionallyRender from '../../../common/ConditionallyRender/ConditionallyRender';
-import { pluralize, getDates, expired, toggleExpiryByTypeMap, getDiffInDays } from '../../utils';
+import {
+ pluralize,
+ getDates,
+ expired,
+ toggleExpiryByTypeMap,
+ getDiffInDays,
+} from '../../utils';
import { KILLSWITCH, PERMISSION } from '../../constants';
import styles from '../ReportToggleList.module.scss';
-const ReportToggleListItem = ({ name, stale, lastSeenAt, createdAt, type, checked, bulkActionsOn, setFeatures }) => {
+const ReportToggleListItem = ({
+ name,
+ stale,
+ lastSeenAt,
+ createdAt,
+ type,
+ checked,
+ bulkActionsOn,
+ setFeatures,
+}) => {
const nameMatches = feature => feature.name === name;
const history = useHistory();
@@ -80,17 +95,26 @@ const ReportToggleListItem = ({ name, stale, lastSeenAt, createdAt, type, checke
const formatReportStatus = () => {
if (type === KILLSWITCH || type === PERMISSION) {
- return renderStatus(
, 'Active');
+ return renderStatus(
+
,
+ 'Healthy'
+ );
}
const [date, now] = getDates(createdAt);
const diff = getDiffInDays(date, now);
if (expired(diff, type)) {
- return renderStatus(
, 'Potentially stale');
+ return renderStatus(
+
,
+ 'Potentially stale'
+ );
}
- return renderStatus(
, 'Active');
+ return renderStatus(
+
,
+ 'Healthy'
+ );
};
const navigateToFeature = () => {
@@ -102,7 +126,12 @@ const ReportToggleListItem = ({ name, stale, lastSeenAt, createdAt, type, checke
});
return (
-
+
({
+ emptyStateListItem: {
+ border: `2px dashed ${theme.palette.borders.main}`,
+ padding: '0.8rem',
+ textAlign: 'center',
+ display: 'flex',
+ justifyContent: 'space-between',
+ alignItems: 'center',
+ },
+}));
diff --git a/frontend/src/component/common/ListPlaceholder/ListPlaceholder.tsx b/frontend/src/component/common/ListPlaceholder/ListPlaceholder.tsx
new file mode 100644
index 0000000000..77e7fa1660
--- /dev/null
+++ b/frontend/src/component/common/ListPlaceholder/ListPlaceholder.tsx
@@ -0,0 +1,26 @@
+import { ListItem } from '@material-ui/core';
+import { Link } from 'react-router-dom';
+import ConditionallyRender from '../ConditionallyRender';
+import { useStyles } from './ListPlaceholder.styles';
+
+interface IListPlaceholderProps {
+ text: string;
+ link?: string;
+ linkText?: string;
+}
+
+const ListPlaceholder = ({ text, link, linkText }: IListPlaceholderProps) => {
+ const styles = useStyles();
+
+ return (
+
+ {text}
+ Add your first toggle}
+ />
+
+ );
+};
+
+export default ListPlaceholder;
diff --git a/frontend/src/component/common/common.module.scss b/frontend/src/component/common/common.module.scss
index b35152d53a..9cb2fa3b00 100644
--- a/frontend/src/component/common/common.module.scss
+++ b/frontend/src/component/common/common.module.scss
@@ -78,7 +78,6 @@
}
.dropdownButton {
- text-transform: none;
font-weight: normal;
}
diff --git a/frontend/src/component/common/index.js b/frontend/src/component/common/index.js
index 68f4b6da43..d653c3d12e 100644
--- a/frontend/src/component/common/index.js
+++ b/frontend/src/component/common/index.js
@@ -84,7 +84,6 @@ export const FormButtons = ({
type="submit"
color="primary"
variant="contained"
- startIcon={add }
>
{submitText}
diff --git a/frontend/src/component/context/ContextList/ContextList.jsx b/frontend/src/component/context/ContextList/ContextList.jsx
index 0ba5874cd8..e7cae50cc7 100644
--- a/frontend/src/component/context/ContextList/ContextList.jsx
+++ b/frontend/src/component/context/ContextList/ContextList.jsx
@@ -14,6 +14,8 @@ import {
ListItemIcon,
ListItemText,
Tooltip,
+ useMediaQuery,
+ Button,
} from '@material-ui/core';
import { useContext, useState } from 'react';
import { Link } from 'react-router-dom';
@@ -24,6 +26,7 @@ import AccessContext from '../../../contexts/AccessContext';
const ContextList = ({ removeContextField, history, contextFields }) => {
const { hasAccess } = useContext(AccessContext);
const [showDelDialogue, setShowDelDialogue] = useState(false);
+ const smallScreen = useMediaQuery('(max-width:700px)');
const [name, setName] = useState();
const styles = useStyles();
@@ -63,11 +66,27 @@ const ContextList = ({ removeContextField, history, contextFields }) => {
- history.push('/context/create')}>
- add
-
-
+
+ history.push('/context/create')}
+ >
+ add
+
+
+ }
+ elseShow={
+ history.push('/context/create')}
+ color="primary"
+ variant="contained"
+ >
+ Add new context field
+
+ }
+ />
}
/>
);
diff --git a/frontend/src/component/feature/FeatureToggleList/FeatureToggleList.jsx b/frontend/src/component/feature/FeatureToggleList/FeatureToggleList.jsx
index ed2f4c118a..599376b006 100644
--- a/frontend/src/component/feature/FeatureToggleList/FeatureToggleList.jsx
+++ b/frontend/src/component/feature/FeatureToggleList/FeatureToggleList.jsx
@@ -26,6 +26,7 @@ import { CREATE_FEATURE } from '../../AccessProvider/permissions';
import AccessContext from '../../../contexts/AccessContext';
import { useStyles } from './styles';
+import ListPlaceholder from '../../common/ListPlaceholder/ListPlaceholder';
const FeatureToggleList = ({
fetcher,
@@ -41,7 +42,7 @@ const FeatureToggleList = ({
}) => {
const { hasAccess } = useContext(AccessContext);
const styles = useStyles();
- const smallScreen = useMediaQuery('(max-width:700px)');
+ const smallScreen = useMediaQuery('(max-width:800px)');
useLayoutEffect(() => {
fetcher();
@@ -102,13 +103,12 @@ const FeatureToggleList = ({
}
elseShow={
-
- No features available. Get started by adding a
- new feature toggle.
-
- Add your first toggle
-
-
+
}
/>
}
diff --git a/frontend/src/component/feature/FeatureToggleList/FeatureToggleListActions/FeatureToggleListActions.jsx b/frontend/src/component/feature/FeatureToggleList/FeatureToggleListActions/FeatureToggleListActions.jsx
index 16aa50eda0..dde36ca6a1 100644
--- a/frontend/src/component/feature/FeatureToggleList/FeatureToggleListActions/FeatureToggleListActions.jsx
+++ b/frontend/src/component/feature/FeatureToggleList/FeatureToggleListActions/FeatureToggleListActions.jsx
@@ -1,7 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
-import { MenuItem } from '@material-ui/core';
+import { MenuItem, Typography } from '@material-ui/core';
import { MenuItemWithIcon } from '../../../common';
import DropdownMenu from '../../../common/DropdownMenu/DropdownMenu';
import ProjectSelect from '../../../common/ProjectSelect';
@@ -66,6 +66,9 @@ const FeatureToggleListActions = ({
return (
diff --git a/frontend/src/component/feature/FeatureToggleList/FeatureToggleListActions/styles.js b/frontend/src/component/feature/FeatureToggleList/FeatureToggleListActions/styles.js
index a9c119e368..8800e17d1c 100644
--- a/frontend/src/component/feature/FeatureToggleList/FeatureToggleListActions/styles.js
+++ b/frontend/src/component/feature/FeatureToggleList/FeatureToggleListActions/styles.js
@@ -6,5 +6,7 @@ export const useStyles = makeStyles({
margin: '0 0.25rem',
},
marginRight: '0.25rem',
+ display: 'flex',
+ alignItems: 'center',
},
});
diff --git a/frontend/src/component/feature/FeatureToggleList/__tests__/__snapshots__/list-component-test.jsx.snap b/frontend/src/component/feature/FeatureToggleList/__tests__/__snapshots__/list-component-test.jsx.snap
index f17034d80b..4787dadf0c 100644
--- a/frontend/src/component/feature/FeatureToggleList/__tests__/__snapshots__/list-component-test.jsx.snap
+++ b/frontend/src/component/feature/FeatureToggleList/__tests__/__snapshots__/list-component-test.jsx.snap
@@ -66,6 +66,12 @@ exports[`renders correctly with one feature 1`] = `
+
+ Sorted by:
+
+
+ Sorted by:
+
-
Clone
+
setDelDialog(false)}
/>
);
diff --git a/frontend/src/component/feature/strategy/EditStrategyModal/FlexibleStrategy.jsx b/frontend/src/component/feature/strategy/EditStrategyModal/FlexibleStrategy.jsx
index fb6d269889..f809e2d08b 100644
--- a/frontend/src/component/feature/strategy/EditStrategyModal/FlexibleStrategy.jsx
+++ b/frontend/src/component/feature/strategy/EditStrategyModal/FlexibleStrategy.jsx
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import InputPercentage from './input-percentage';
import Select from '../../../common/select';
-import { TextField, Typography } from '@material-ui/core';
+import { Icon, TextField, Tooltip, Typography } from '@material-ui/core';
const builtInStickinessOptions = [
{ key: 'default', label: 'default' },
@@ -21,7 +21,9 @@ const FlexibleStrategy = ({ updateParameter, parameters, context }) => {
builtInStickinessOptions.concat(
context
.filter(c => c.stickiness)
- .filter(c => !builtInStickinessOptions.find(s => s.key === c.name))
+ .filter(
+ c => !builtInStickinessOptions.find(s => s.key === c.name)
+ )
.map(c => ({ key: c.name, label: c.name }))
);
@@ -33,13 +35,37 @@ const FlexibleStrategy = ({ updateParameter, parameters, context }) => {
return (
-
+
-
- Stickiness
-
-
+
+
+ Stickiness
+
+ info
+
+
+
{
onChange={e => onUpdate('stickiness')(e, e.target.value)}
/>
+
+
+
+
+ GroupId
+
+ info
+
+
+
{
+const StrategyConstraintInput = ({
+ constraints,
+ updateConstraints,
+ contextNames,
+ contextFields,
+ enabled,
+}) => {
const commonStyles = useCommonStyles();
const addConstraint = evt => {
evt.preventDefault();
const updatedConstraints = [...constraints];
- updatedConstraints.push({ contextName: contextNames[0], operator: 'IN', values: [] });
+ updatedConstraints.push({
+ contextName: contextNames[0],
+ operator: 'IN',
+ values: [],
+ });
updateConstraints(updatedConstraints);
};
@@ -35,12 +45,22 @@ const StrategyConstraintInput = ({ constraints, updateConstraints, contextNames,
return (
-
- {'Constraints '}
- Use context fields to constrain the activation strategy.}>
- info
-
-
+
+ Use context fields to constrain the activation strategy.
+
+ }
+ >
+
+ {'Constraints '}
+
+
+ info
+
+
+
{constraints.map((c, index) => (
@@ -56,7 +76,11 @@ const StrategyConstraintInput = ({ constraints, updateConstraints, contextNames,
-
+
Add constraint
diff --git a/frontend/src/component/feature/view/__tests__/__snapshots__/view-component-test.jsx.snap b/frontend/src/component/feature/view/__tests__/__snapshots__/view-component-test.jsx.snap
index 3a3c10c57e..e51bd7b382 100644
--- a/frontend/src/component/feature/view/__tests__/__snapshots__/view-component-test.jsx.snap
+++ b/frontend/src/component/feature/view/__tests__/__snapshots__/view-component-test.jsx.snap
@@ -216,6 +216,32 @@ exports[`renders correctly with one feature 1`] = `
+
+
+ Clone
+
+
-
-
- Clone
-
-
{
const { hasAccess } = useContext(AccessContext);
+ const smallScreen = useMediaQuery('(max-width:700px)');
const [showDelDialogue, setShowDelDialogue] = useState(false);
const [project, setProject] = useState(undefined);
const styles = useStyles();
@@ -35,14 +38,27 @@ const ProjectList = ({ projects, fetchProjects, removeProject, history }) => {
- history.push('/projects/create')}
- >
- add
-
-
+
+ history.push('/projects/create')}
+ >
+ add
+
+
+ }
+ elseShow={
+ history.push('/projects/create')}
+ color="primary"
+ variant="contained"
+ >
+ Add new project
+
+ }
+ />
}
/>
);
diff --git a/frontend/src/component/project/ViewProject/ViewProject.js b/frontend/src/component/project/ProjectView/ProjectView.js
similarity index 80%
rename from frontend/src/component/project/ViewProject/ViewProject.js
rename to frontend/src/component/project/ProjectView/ProjectView.js
index 161192c7fa..bc7e6c7859 100644
--- a/frontend/src/component/project/ViewProject/ViewProject.js
+++ b/frontend/src/component/project/ProjectView/ProjectView.js
@@ -1,5 +1,5 @@
import { useContext, useEffect } from 'react';
-import { Typography, Button, List } from '@material-ui/core';
+import { Typography, Button, List, ListItem } from '@material-ui/core';
import { Link } from 'react-router-dom';
import AccessContext from '../../../contexts/AccessContext';
import HeaderTitle from '../../common/HeaderTitle';
@@ -7,8 +7,9 @@ import PageContent from '../../common/PageContent';
import FeatureToggleListItem from '../../feature/FeatureToggleList/FeatureToggleListItem';
import ConditionallyRender from '../../common/ConditionallyRender';
+import ListPlaceholder from '../../common/ListPlaceholder/ListPlaceholder';
-const ViewProject = ({
+const ProjectView = ({
project,
features,
settings,
@@ -81,10 +82,21 @@ const ViewProject = ({
Feature toggles in this project
- {renderProjectFeatures()}
+
+ 0}
+ show={renderProjectFeatures()}
+ elseShow={
+
+ }
+ />
+
);
};
-export default ViewProject;
+export default ProjectView;
diff --git a/frontend/src/component/project/ViewProject/index.js b/frontend/src/component/project/ProjectView/index.js
similarity index 95%
rename from frontend/src/component/project/ViewProject/index.js
rename to frontend/src/component/project/ProjectView/index.js
index 382b74a998..cc645ecbfc 100644
--- a/frontend/src/component/project/ViewProject/index.js
+++ b/frontend/src/component/project/ProjectView/index.js
@@ -3,7 +3,7 @@ import {
fetchFeatureToggles,
toggleFeature,
} from '../../../store/feature-toggle/actions';
-import ViewProject from './ViewProject';
+import ViewProject from './ProjectView';
const mapStateToProps = (state, props) => {
const projectBase = { id: '', name: '', description: '' };
diff --git a/frontend/src/component/project/access-add-user.js b/frontend/src/component/project/access-add-user.js
index deec0fa062..43375f5569 100644
--- a/frontend/src/component/project/access-add-user.js
+++ b/frontend/src/component/project/access-add-user.js
@@ -68,7 +68,7 @@ function AddUserComponent({ roles, addUserToRole }) {
};
return (
-
+
-
-
+
+
Role
{
const access = await projectApi.fetchAccess(projectId);
setRoles(access.roles);
- setUsers(access.users.map(u => ({ ...u, name: u.name || '(No name)' })));
+ setUsers(
+ access.users.map(u => ({ ...u, name: u.name || '(No name)' }))
+ );
};
useEffect(() => {
@@ -85,8 +91,23 @@ function AccessComponent({ projectId, project }) {
};
return (
-
-
+ history.goBack()}
+ >
+ Back
+
+ }
+ />
+ }
+ >
{'Error'}
- {error}
+
+ {error}
+
-
+
Close
+
{users.map(user => {
const labelId = `checkbox-list-secondary-label-${user.id}`;
@@ -112,25 +148,50 @@ function AccessComponent({ projectId, project }) {
-
-
-
-
- Choose role
-
- {roles.map(role => (
-
- {role.name}
+
+
+
+
+ Role
+
+
+
+ Choose role
- ))}
-
+ {roles.map(role => (
+
+ {role.name}
+
+ ))}
+
+
-
+
);
}
diff --git a/frontend/src/component/project/form-project-component.jsx b/frontend/src/component/project/form-project-component.jsx
index 25c293f0f6..3518fb7856 100644
--- a/frontend/src/component/project/form-project-component.jsx
+++ b/frontend/src/component/project/form-project-component.jsx
@@ -75,8 +75,15 @@ class ProjectFormComponent extends Component {
};
onCancel = evt => {
+ const { editMode } = this.props;
+ const { project } = this.state;
+
evt.preventDefault();
- this.props.history.push('/projects');
+ if (editMode) {
+ this.props.history.push(`/projects/view/${project.id}`);
+ } else {
+ this.props.history.push('/projects');
+ }
};
onSubmit = async evt => {
@@ -87,7 +94,7 @@ class ProjectFormComponent extends Component {
if (valid) {
await this.props.submit(project);
- this.props.history.push('/projects');
+ this.props.history.push(`/projects/view/${project.id}`);
}
};
@@ -98,21 +105,24 @@ class ProjectFormComponent extends Component {
const submitText = editMode ? 'Update' : 'Create';
return (
-
- {submitText} Project
-
- Manage access
-
- }
- />
- }>
+
+ {submitText} Project
+
+ Manage access
+
+ }
+ />
+
+ }
+ >
-
-
{
evt.preventDefault();
- const {
- createStrategy,
- updateStrategy,
- history,
- editMode,
- } = this.props;
+ const { createStrategy, updateStrategy, history, editMode } =
+ this.props;
const { strategy } = this.state;
const parameters = (strategy.parameters || [])
diff --git a/frontend/src/component/tag-types/__tests__/__snapshots__/tag-type-create-component-test.js.snap b/frontend/src/component/tag-types/__tests__/__snapshots__/tag-type-create-component-test.js.snap
index 3a7a5768f2..7eb1a64021 100644
--- a/frontend/src/component/tag-types/__tests__/__snapshots__/tag-type-create-component-test.js.snap
+++ b/frontend/src/component/tag-types/__tests__/__snapshots__/tag-type-create-component-test.js.snap
@@ -60,16 +60,6 @@ exports[`it supports editMode 1`] = `
-
-
- add
-
-
Update
@@ -166,16 +156,6 @@ exports[`renders correctly for creating 1`] = `
-
-
- add
-
-
Create
diff --git a/frontend/src/component/user/HostedAuth/HostedAuth.jsx b/frontend/src/component/user/HostedAuth/HostedAuth.jsx
index 662a2c66c1..5fac62f9f9 100644
--- a/frontend/src/component/user/HostedAuth/HostedAuth.jsx
+++ b/frontend/src/component/user/HostedAuth/HostedAuth.jsx
@@ -2,13 +2,12 @@ import React, { useState } from 'react';
import classnames from 'classnames';
import PropTypes from 'prop-types';
import { Button, Grid, TextField, Typography } from '@material-ui/core';
-import LockRounded from '@material-ui/icons/LockRounded';
import { useHistory } from 'react-router';
import { useCommonStyles } from '../../../common.styles';
import { useStyles } from './HostedAuth.styles';
import { Link } from 'react-router-dom';
-import { GoogleSvg } from './Icons';
import useQueryParams from '../../../hooks/useQueryParams';
+import AuthOptions from '../common/AuthOptions/AuthOptions';
const PasswordAuth = ({ authDetails, passwordLogin }) => {
const commonStyles = useCommonStyles();
@@ -64,7 +63,6 @@ const PasswordAuth = ({ authDetails, passwordLogin }) => {
}
};
-
const { usernameError, passwordError, apiError } = errors;
const { options = [] } = authDetails;
@@ -72,19 +70,7 @@ const PasswordAuth = ({ authDetails, passwordLogin }) => {
- {options.map(o => (
-
- : }>
- {o.message}
-
-
- ))}
+
or
diff --git a/frontend/src/component/user/NewUser/NewUser.styles.ts b/frontend/src/component/user/NewUser/NewUser.styles.ts
index 67c4152ed2..5b91dbfad0 100644
--- a/frontend/src/component/user/NewUser/NewUser.styles.ts
+++ b/frontend/src/component/user/NewUser/NewUser.styles.ts
@@ -23,6 +23,9 @@ export const useStyles = makeStyles(theme => ({
marginBottom: '0.5rem',
fontSize: '1.1rem',
},
+ passwordHeader: {
+ marginTop: '2rem',
+ },
emailField: {
minWidth: '300px',
[theme.breakpoints.down('xs')]: {
diff --git a/frontend/src/component/user/NewUser/NewUser.tsx b/frontend/src/component/user/NewUser/NewUser.tsx
index 8b2596c340..ed1fea3ab1 100644
--- a/frontend/src/component/user/NewUser/NewUser.tsx
+++ b/frontend/src/component/user/NewUser/NewUser.tsx
@@ -10,15 +10,16 @@ import useResetPassword from '../../../hooks/useResetPassword';
import StandaloneLayout from '../common/StandaloneLayout/StandaloneLayout';
import ConditionallyRender from '../../common/ConditionallyRender';
import InvalidToken from '../common/InvalidToken/InvalidToken';
+import { IAuthStatus } from '../../../interfaces/user';
+import AuthOptions from '../common/AuthOptions/AuthOptions';
-const NewUser = () => {
- const {
- token,
- data,
- loading,
- setLoading,
- invalidToken,
- } = useResetPassword();
+interface INewUserProps {
+ user: IAuthStatus;
+}
+
+const NewUser = ({ user }: INewUserProps) => {
+ const { token, data, loading, setLoading, invalidToken } =
+ useResetPassword();
const ref = useLoading(loading);
const commonStyles = useCommonStyles();
const styles = useStyles();
@@ -57,7 +58,7 @@ const NewUser = () => {
{
className={commonStyles.largeDivider}
data-loading
/>
-
- Set a password for your account.
-
+ 0
+ }
+ show={
+ <>
+
+ Login with 3rd party providers
+
+
+
+
+ OR set a new password for your
+ account
+
+ >
+ }
+ elseShow={
+
+ Set a password for your account.
+
+ }
+ />
}
diff --git a/frontend/src/component/user/NewUser/index.js b/frontend/src/component/user/NewUser/index.js
new file mode 100644
index 0000000000..d2d6eb8f8e
--- /dev/null
+++ b/frontend/src/component/user/NewUser/index.js
@@ -0,0 +1,8 @@
+import { connect } from 'react-redux';
+import NewUser from './NewUser';
+
+const mapStateToProps = (state: any) => ({
+ user: state.user.toJS(),
+});
+
+export default connect(mapStateToProps)(NewUser);
diff --git a/frontend/src/component/user/StandaloneBanner/StandaloneBanner.styles.ts b/frontend/src/component/user/StandaloneBanner/StandaloneBanner.styles.ts
index 2bfd4cc876..4460fe2670 100644
--- a/frontend/src/component/user/StandaloneBanner/StandaloneBanner.styles.ts
+++ b/frontend/src/component/user/StandaloneBanner/StandaloneBanner.styles.ts
@@ -19,7 +19,7 @@ export const useStyles = makeStyles(theme => ({
},
},
switchesContainer: {
- position: 'fixed',
+ position: 'absolute',
bottom: '40px',
display: 'flex',
flexDirection: 'column',
diff --git a/frontend/src/component/user/common/AuthOptions/AuthOptions.tsx b/frontend/src/component/user/common/AuthOptions/AuthOptions.tsx
new file mode 100644
index 0000000000..42a85211c3
--- /dev/null
+++ b/frontend/src/component/user/common/AuthOptions/AuthOptions.tsx
@@ -0,0 +1,47 @@
+import { Button } from '@material-ui/core';
+import classnames from 'classnames';
+import { useCommonStyles } from '../../../../common.styles';
+import { IAuthOptions } from '../../../../interfaces/user';
+import { ReactComponent as GoogleSvg } from '../../../../assets/icons/google.svg';
+import LockRounded from '@material-ui/icons/LockRounded';
+
+interface IAuthOptionProps {
+ options?: IAuthOptions[];
+}
+
+const AuthOptions = ({ options }: IAuthOptionProps) => {
+ const commonStyles = useCommonStyles();
+ return (
+ <>
+ {options?.map(o => (
+
+
+ ) : (
+
+ )
+ }
+ >
+ {o.message}
+
+
+ ))}
+ >
+ );
+};
+
+export default AuthOptions;
diff --git a/frontend/src/component/user/common/ResetPasswordForm/ResetPasswordForm.tsx b/frontend/src/component/user/common/ResetPasswordForm/ResetPasswordForm.tsx
index ea8d660667..25acdae8af 100644
--- a/frontend/src/component/user/common/ResetPasswordForm/ResetPasswordForm.tsx
+++ b/frontend/src/component/user/common/ResetPasswordForm/ResetPasswordForm.tsx
@@ -111,17 +111,19 @@ const ResetPasswordForm = ({ token, setLoading }: IResetPasswordProps) => {
size="small"
type="password"
placeholder="Password"
- value={password}
+ value={password || ''}
onChange={e => setPassword(e.target.value)}
+ autoComplete="password"
data-loading
/>
setConfirmPassword(e.target.value)}
+ autoComplete="confirm-password"
data-loading
/>
-
-
- supervised_user_circle
+
+
Users
-
+
}
- >
-
-
- apps
- API Access
-
- }>
-
-
- lock
- Authentication
-
- }>
-
+ >
+
+ API Access
+
+ }
+ >
+
+ Authentication
+
+ }
+ >
);
diff --git a/frontend/src/page/admin/api/api-key-create.jsx b/frontend/src/page/admin/api/api-key-create.jsx
index 1e66f83fce..266445ec09 100644
--- a/frontend/src/page/admin/api/api-key-create.jsx
+++ b/frontend/src/page/admin/api/api-key-create.jsx
@@ -13,10 +13,9 @@ import classnames from 'classnames';
import { styles as commonStyles } from '../../../component/common';
import { useStyles } from './styles';
-function CreateApiKey({ addKey }) {
+function CreateApiKey({ addKey, show, setShow }) {
const styles = useStyles();
const [type, setType] = useState('CLIENT');
- const [show, setShow] = useState(false);
const [username, setUsername] = useState();
const [error, setError] = useState();
@@ -107,6 +106,9 @@ function CreateApiKey({ addKey }) {
CreateApiKey.propTypes = {
addKey: PropTypes.func.isRequired,
+ setShow: PropTypes.func.isRequired,
+ show: PropTypes.bool.isRequired,
+ toggle: PropTypes.func.isRequired,
};
export default CreateApiKey;
diff --git a/frontend/src/page/admin/api/api-key-list.jsx b/frontend/src/page/admin/api/api-key-list.jsx
index cfdddcb831..a560e00d6d 100644
--- a/frontend/src/page/admin/api/api-key-list.jsx
+++ b/frontend/src/page/admin/api/api-key-list.jsx
@@ -21,6 +21,8 @@ import {
DELETE_API_TOKEN,
CREATE_API_TOKEN,
} from '../../../component/AccessProvider/permissions';
+import PageContent from '../../../component/common/PageContent';
+import HeaderTitle from '../../../component/common/HeaderTitle';
function ApiKeyList({
location,
@@ -30,6 +32,8 @@ function ApiKeyList({
keys,
unleashUrl,
}) {
+ const [show, setShow] = useState(false);
+
const { hasAccess } = useContext(AccessContext);
const [showDelete, setShowDelete] = useState(false);
const [delKey, setDelKey] = useState(undefined);
@@ -45,93 +49,111 @@ function ApiKeyList({
}, []);
return (
-
-
-
- Read the{' '}
-
- Getting started guide
- {' '}
- to learn how to connect to the Unleash API from your
- application or programmatically. Please note it can take up
- to 1 minute before a new API key is activated.
-
+
+ }
+ />
+ }
+ />
+ }
+ >
+
+
+
+ Read the{' '}
+
+ Getting started guide
+ {' '}
+ to learn how to connect to the Unleash API from your
+ application or programmatically. Please note it can take
+ up to 1 minute before a new API key is activated.
+
+
+ API URL: {' '}
+ {unleashUrl}/api/
+
+
+
-
API URL: {' '}
-
{unleashUrl}/api/
-
-
-
-
-
-
-
-
- Created
- Username
- Access Type
- Secret
- Action
-
-
-
- {keys.map(item => (
-
-
- {formatFullDateTimeWithLocale(
- item.createdAt,
- location.locale
- )}
-
-
- {item.username}
-
-
- {item.type}
-
-
-
-
-
- {
- setDelKey(item.secret);
- setShowDelete(true);
- }}
- >
- delete
-
-
- }
- />
+
+
+
+
+ Created
+ Username
+ Access Type
+ Secret
+ Action
- ))}
-
-
- {
- setShowDelete(false);
- setDelKey(undefined);
- }}
- title="Really delete API key?"
- >
- Are you sure you want to delete?
-
- }
- />
-
+
+
+ {keys.map(item => (
+
+
+ {formatFullDateTimeWithLocale(
+ item.createdAt,
+ location.locale
+ )}
+
+
+ {item.username}
+
+
+ {item.type}
+
+
+
+
+
+ {
+ setDelKey(item.secret);
+ setShowDelete(true);
+ }}
+ >
+ delete
+
+
+ }
+ />
+
+ ))}
+
+
+
{
+ setShowDelete(false);
+ setDelKey(undefined);
+ }}
+ title="Really delete API key?"
+ >
+ Are you sure you want to delete?
+
+
+
);
}
diff --git a/frontend/src/page/admin/api/index.js b/frontend/src/page/admin/api/index.js
index 4d6ada91cc..7a69775d4d 100644
--- a/frontend/src/page/admin/api/index.js
+++ b/frontend/src/page/admin/api/index.js
@@ -1,18 +1,16 @@
-import React from 'react';
import PropTypes from 'prop-types';
import ApiKeyList from './api-key-list-container';
import AdminMenu from '../admin-menu';
-import PageContent from '../../../component/common/PageContent/PageContent';
-const render = ({history}) => (
-
-
-
+const render = ({ history }) => {
+ return (
+
-);
+
+ );
+};
render.propTypes = {
match: PropTypes.object.isRequired,
diff --git a/frontend/src/page/admin/users/ConfirmUserAdded/ConfirmUserLink/ConfirmUserLink.tsx b/frontend/src/page/admin/users/ConfirmUserAdded/ConfirmUserLink/ConfirmUserLink.tsx
index 2a63419217..c799c919e2 100644
--- a/frontend/src/page/admin/users/ConfirmUserAdded/ConfirmUserLink/ConfirmUserLink.tsx
+++ b/frontend/src/page/admin/users/ConfirmUserAdded/ConfirmUserLink/ConfirmUserLink.tsx
@@ -40,7 +40,7 @@ const ConfirmUserLink = ({
Want to avoid this step in the future?{' '}
{/* TODO - ADD LINK HERE ONCE IT EXISTS*/}
diff --git a/frontend/src/page/admin/users/UsersList/UsersList.jsx b/frontend/src/page/admin/users/UsersList/UsersList.jsx
index 5f341382b5..08123c3a5f 100644
--- a/frontend/src/page/admin/users/UsersList/UsersList.jsx
+++ b/frontend/src/page/admin/users/UsersList/UsersList.jsx
@@ -2,7 +2,6 @@
import { useContext, useState } from 'react';
import PropTypes from 'prop-types';
import {
- Button,
Table,
TableBody,
TableCell,
@@ -23,7 +22,7 @@ import UserListItem from './UserListItem/UserListItem';
import loadingData from './loadingData';
import useLoading from '../../../../hooks/useLoading';
-function UsersList({ location }) {
+function UsersList({ location, closeDialog, showDialog }) {
const { users, roles, refetch, loading } = useUsers();
const {
addUser,
@@ -35,7 +34,6 @@ function UsersList({ location }) {
userApiErrors,
} = useAdminUsersApi();
const { hasAccess } = useContext(AccessContext);
- const [showDialog, setDialog] = useState(false);
const [pwDialog, setPwDialog] = useState({ open: false });
const [delDialog, setDelDialog] = useState(false);
const [showConfirm, setShowConfirm] = useState(false);
@@ -45,15 +43,6 @@ function UsersList({ location }) {
const [updateDialog, setUpdateDialog] = useState({ open: false });
const ref = useLoading(loading);
- const openDialog = e => {
- e.preventDefault();
- setDialog(true);
- };
-
- const closeDialog = () => {
- setDialog(false);
- };
-
const closeDelDialog = () => {
setDelDialog(false);
setDelUser(undefined);
@@ -177,19 +166,6 @@ function UsersList({ location }) {
{renderUsers()}
-
- Add new user
-
- }
- elseShow={PS! Only admins can add/remove users. }
- />
({
- location: state.settings.toJS().location || {},
-});
+const mapStateToProps = state => {
+ return {
+ location: state.settings.toJS().location || {},
+ };
+};
const Container = connect(mapStateToProps)(UsersList);
diff --git a/frontend/src/page/admin/users/del-user-component.jsx b/frontend/src/page/admin/users/del-user-component.jsx
index b2ee4ac289..bde257c8eb 100644
--- a/frontend/src/page/admin/users/del-user-component.jsx
+++ b/frontend/src/page/admin/users/del-user-component.jsx
@@ -78,7 +78,7 @@ const DelUserComponent = ({
DelUserComponent.propTypes = {
showDialog: propTypes.bool.isRequired,
closeDialog: propTypes.func.isRequired,
- user: propTypes.object.isRequired,
+ user: propTypes.object,
removeUser: propTypes.func.isRequired,
};
diff --git a/frontend/src/page/admin/users/index.js b/frontend/src/page/admin/users/index.js
index 4d779c7cea..d0762bfa43 100644
--- a/frontend/src/page/admin/users/index.js
+++ b/frontend/src/page/admin/users/index.js
@@ -1,4 +1,4 @@
-import { useContext } from 'react';
+import { useContext, useState } from 'react';
import PropTypes from 'prop-types';
import UsersList from './UsersList';
import AdminMenu from '../admin-menu';
@@ -7,17 +7,60 @@ import AccessContext from '../../../contexts/AccessContext';
import ConditionallyRender from '../../../component/common/ConditionallyRender';
import { ADMIN } from '../../../component/AccessProvider/permissions';
import { Alert } from '@material-ui/lab';
+import HeaderTitle from '../../../component/common/HeaderTitle';
+import { Button } from '@material-ui/core';
const UsersAdmin = ({ history }) => {
const { hasAccess } = useContext(AccessContext);
+ const [showDialog, setDialog] = useState(false);
+
+ const openDialog = e => {
+ e.preventDefault();
+ setDialog(true);
+ };
+
+ const closeDialog = () => {
+ setDialog(false);
+ };
return (
-
+
+ Add new user
+
+ }
+ elseShow={
+
+ PS! Only admins can add/remove users.
+
+ }
+ />
+ }
+ />
+ }
+ >
}
+ show={
+
+ }
elseShow={
You need instance admin to access this section.
diff --git a/frontend/src/page/project/view.js b/frontend/src/page/project/view.js
index 46c8b83739..a9565d331d 100644
--- a/frontend/src/page/project/view.js
+++ b/frontend/src/page/project/view.js
@@ -1,5 +1,5 @@
import React from 'react';
-import ViewProject from '../../component/project/ViewProject';
+import ViewProject from '../../component/project/ProjectView';
import PropTypes from 'prop-types';
const render = ({ match: { params }, history }) => (