mirror of
https://github.com/Unleash/unleash.git
synced 2025-02-23 00:22:19 +01:00
Merge branch 'master' into fix/breadcrumb-createToggle2
This commit is contained in:
commit
90af5a40d6
34
frontend/.github/workflows/release_to_cdn.yml
vendored
Normal file
34
frontend/.github/workflows/release_to_cdn.yml
vendored
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
name: 'Release static assets to CDN'
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v*'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
node-version: [14.x]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v1
|
||||||
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
|
uses: actions/setup-node@v2
|
||||||
|
with:
|
||||||
|
node-version: ${{ matrix.node-version }}
|
||||||
|
- run: yarn
|
||||||
|
- uses: aws-actions/configure-aws-credentials@v1
|
||||||
|
with:
|
||||||
|
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||||
|
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||||
|
aws-region: ${{ secrets.AWS_DEFAULT_REGION }}
|
||||||
|
- name: Get the version
|
||||||
|
id: get_version
|
||||||
|
run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\//}
|
||||||
|
- name: Deploy static assets to S3
|
||||||
|
run: |
|
||||||
|
aws s3 cp build/ s3://getunleash-static/unleash/${{ steps.get_version.outputs.VERSION }} --recursive
|
||||||
|
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "unleash-frontend",
|
"name": "unleash-frontend",
|
||||||
"description": "unleash your features",
|
"description": "unleash your features",
|
||||||
"version": "4.4.0",
|
"version": "4.4.1",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"unleash",
|
"unleash",
|
||||||
"feature toggle",
|
"feature toggle",
|
||||||
@ -45,11 +45,11 @@
|
|||||||
"@testing-library/user-event": "13.5.0",
|
"@testing-library/user-event": "13.5.0",
|
||||||
"@types/debounce": "1.2.1",
|
"@types/debounce": "1.2.1",
|
||||||
"@types/deep-diff": "1.0.1",
|
"@types/deep-diff": "1.0.1",
|
||||||
"@types/enzyme": "3.10.10",
|
"@types/enzyme": "3.10.11",
|
||||||
"@types/enzyme-adapter-react-16": "1.0.6",
|
"@types/enzyme-adapter-react-16": "1.0.6",
|
||||||
"@types/jest": "27.0.3",
|
"@types/jest": "27.4.0",
|
||||||
"@types/node": "14.18.1",
|
"@types/node": "14.18.5",
|
||||||
"@types/react": "17.0.37",
|
"@types/react": "17.0.38",
|
||||||
"@types/react-dom": "17.0.11",
|
"@types/react-dom": "17.0.11",
|
||||||
"@types/react-router-dom": "5.3.2",
|
"@types/react-router-dom": "5.3.2",
|
||||||
"@types/react-timeago": "4.1.3",
|
"@types/react-timeago": "4.1.3",
|
||||||
@ -60,7 +60,7 @@
|
|||||||
"craco": "0.0.3",
|
"craco": "0.0.3",
|
||||||
"css-loader": "6.5.1",
|
"css-loader": "6.5.1",
|
||||||
"cypress": "8.7.0",
|
"cypress": "8.7.0",
|
||||||
"date-fns": "2.27.0",
|
"date-fns": "2.28.0",
|
||||||
"debounce": "1.2.1",
|
"debounce": "1.2.1",
|
||||||
"deep-diff": "1.0.2",
|
"deep-diff": "1.0.2",
|
||||||
"enzyme": "3.11.0",
|
"enzyme": "3.11.0",
|
||||||
@ -75,8 +75,8 @@
|
|||||||
"node-fetch": "2.6.6",
|
"node-fetch": "2.6.6",
|
||||||
"prettier": "2.5.1",
|
"prettier": "2.5.1",
|
||||||
"react": "17.0.2",
|
"react": "17.0.2",
|
||||||
"react-dnd": "14.0.4",
|
"react-dnd": "14.0.5",
|
||||||
"react-dnd-html5-backend": "14.0.2",
|
"react-dnd-html5-backend": "14.1.0",
|
||||||
"react-dom": "17.0.2",
|
"react-dom": "17.0.2",
|
||||||
"react-outside-click-handler": "1.3.0",
|
"react-outside-click-handler": "1.3.0",
|
||||||
"react-redux": "7.2.6",
|
"react-redux": "7.2.6",
|
||||||
@ -87,7 +87,7 @@
|
|||||||
"redux-devtools-extension": "2.13.9",
|
"redux-devtools-extension": "2.13.9",
|
||||||
"redux-mock-store": "1.5.4",
|
"redux-mock-store": "1.5.4",
|
||||||
"redux-thunk": "2.4.1",
|
"redux-thunk": "2.4.1",
|
||||||
"sass": "1.44.0",
|
"sass": "1.46.0",
|
||||||
"swr": "1.0.1",
|
"swr": "1.0.1",
|
||||||
"typescript": "4.5.4",
|
"typescript": "4.5.4",
|
||||||
"web-vitals": "2.1.2"
|
"web-vitals": "2.1.2"
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
<meta name="baseUriPath" content="::baseUriPath::" />
|
<meta name="baseUriPath" content="::baseUriPath::" />
|
||||||
|
<meta name="cdnPrefix" content="::cdnPrefix::" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<meta name="description" content="unleash" />
|
<meta name="description" content="unleash" />
|
||||||
<title>Unleash - Enterprise ready feature toggles</title>
|
<title>Unleash - Enterprise ready feature toggles</title>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import { TextField, Typography, Avatar } from '@material-ui/core';
|
import { Typography, Avatar } from '@material-ui/core';
|
||||||
import { trim } from '../../common/util';
|
import { trim } from '../../common/util';
|
||||||
import { modalStyles } from './util';
|
import { modalStyles } from './util';
|
||||||
import Dialogue from '../../common/Dialogue/Dialogue';
|
import Dialogue from '../../common/Dialogue/Dialogue';
|
||||||
@ -10,6 +10,7 @@ import { useCommonStyles } from '../../../common.styles';
|
|||||||
import PasswordMatcher from '../../user/common/ResetPasswordForm/PasswordMatcher/PasswordMatcher';
|
import PasswordMatcher from '../../user/common/ResetPasswordForm/PasswordMatcher/PasswordMatcher';
|
||||||
import ConditionallyRender from '../../common/ConditionallyRender';
|
import ConditionallyRender from '../../common/ConditionallyRender';
|
||||||
import { Alert } from '@material-ui/lab';
|
import { Alert } from '@material-ui/lab';
|
||||||
|
import PasswordField from '../../common/PasswordField/PasswordField';
|
||||||
|
|
||||||
function ChangePassword({
|
function ChangePassword({
|
||||||
showDialog,
|
showDialog,
|
||||||
@ -109,26 +110,20 @@ function ChangePassword({
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<p style={{ color: 'red' }}>{error.general}</p>
|
<p style={{ color: 'red' }}>{error.general}</p>
|
||||||
<TextField
|
<PasswordField
|
||||||
label="New password"
|
label="New password"
|
||||||
name="password"
|
name="password"
|
||||||
type="password"
|
|
||||||
value={data.password}
|
value={data.password}
|
||||||
helperText={error.password}
|
helperText={error.password}
|
||||||
onChange={updateField}
|
onChange={updateField}
|
||||||
variant="outlined"
|
|
||||||
size="small"
|
|
||||||
/>
|
/>
|
||||||
<TextField
|
<PasswordField
|
||||||
label="Confirm password"
|
label="Confirm password"
|
||||||
name="confirm"
|
name="confirm"
|
||||||
type="password"
|
|
||||||
value={data.confirm}
|
value={data.confirm}
|
||||||
error={error.confirm !== undefined}
|
error={error.confirm !== undefined}
|
||||||
helperText={error.confirm}
|
helperText={error.confirm}
|
||||||
onChange={updateField}
|
onChange={updateField}
|
||||||
variant="outlined"
|
|
||||||
size="small"
|
|
||||||
/>
|
/>
|
||||||
<PasswordMatcher
|
<PasswordMatcher
|
||||||
started={data.password && data.confirm}
|
started={data.password && data.confirm}
|
||||||
|
@ -0,0 +1,44 @@
|
|||||||
|
import { IconButton, InputAdornment, TextField } from '@material-ui/core';
|
||||||
|
import { Visibility, VisibilityOff } from '@material-ui/icons';
|
||||||
|
import { useState } from 'react';
|
||||||
|
|
||||||
|
const PasswordField = ({ ...rest }) => {
|
||||||
|
const [showPassword, setShowPassword] = useState(false);
|
||||||
|
|
||||||
|
const handleClickShowPassword = () => {
|
||||||
|
setShowPassword(!showPassword);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMouseDownPassword = (
|
||||||
|
e: React.MouseEvent<HTMLButtonElement>
|
||||||
|
) => {
|
||||||
|
e.preventDefault();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TextField
|
||||||
|
variant="outlined"
|
||||||
|
size="small"
|
||||||
|
type={showPassword ? 'text' : 'password'}
|
||||||
|
InputProps={{
|
||||||
|
style: {
|
||||||
|
paddingRight: '0px !important',
|
||||||
|
},
|
||||||
|
endAdornment: (
|
||||||
|
<InputAdornment position="end">
|
||||||
|
<IconButton
|
||||||
|
aria-label="toggle password visibility"
|
||||||
|
onClick={handleClickShowPassword}
|
||||||
|
onMouseDown={handleMouseDownPassword}
|
||||||
|
>
|
||||||
|
{showPassword ? <Visibility /> : <VisibilityOff />}
|
||||||
|
</IconButton>
|
||||||
|
</InputAdornment>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
{...rest}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PasswordField;
|
@ -7,6 +7,7 @@ export const useStyles = makeStyles(theme => ({
|
|||||||
position: 'relative',
|
position: 'relative',
|
||||||
width: '50px',
|
width: '50px',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
|
padding: '15px 0px',
|
||||||
},
|
},
|
||||||
vertical: {
|
vertical: {
|
||||||
borderRadius: '1px',
|
borderRadius: '1px',
|
||||||
|
@ -3,7 +3,6 @@ import { makeStyles } from '@material-ui/core/styles';
|
|||||||
export const useStyles = makeStyles(theme => ({
|
export const useStyles = makeStyles(theme => ({
|
||||||
splashMainContainer: {
|
splashMainContainer: {
|
||||||
backgroundColor: theme.palette.primary.light,
|
backgroundColor: theme.palette.primary.light,
|
||||||
height: '100%',
|
|
||||||
width: '100%',
|
width: '100%',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
|
@ -19,6 +19,13 @@ export const useStyles = makeStyles(theme => ({
|
|||||||
position: 'relative',
|
position: 'relative',
|
||||||
paddingBottom: '1rem',
|
paddingBottom: '1rem',
|
||||||
},
|
},
|
||||||
|
header: {
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
flexDirection: 'column',
|
||||||
|
|
||||||
|
paddingTop: '1.5rem',
|
||||||
|
},
|
||||||
headerTitle: {
|
headerTitle: {
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
@ -70,8 +77,8 @@ export const useStyles = makeStyles(theme => ({
|
|||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
},
|
},
|
||||||
percentageContainer: {
|
percentageContainer: {
|
||||||
width: '50px',
|
width: '90px',
|
||||||
height: '50px',
|
height: '90px',
|
||||||
border: `2px solid ${theme.palette.primary.light}`,
|
border: `2px solid ${theme.palette.primary.light}`,
|
||||||
borderRadius: '50%',
|
borderRadius: '50%',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@ -95,6 +102,7 @@ export const useStyles = makeStyles(theme => ({
|
|||||||
requestText: {
|
requestText: {
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
marginTop: '1rem',
|
marginTop: '1rem',
|
||||||
|
fontSize: theme.fontSizes.smallBody,
|
||||||
},
|
},
|
||||||
linkContainer: {
|
linkContainer: {
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@ -114,6 +122,29 @@ export const useStyles = makeStyles(theme => ({
|
|||||||
fill: theme.palette.grey[400],
|
fill: theme.palette.grey[400],
|
||||||
marginBottom: '1rem',
|
marginBottom: '1rem',
|
||||||
},
|
},
|
||||||
|
strategiesText: {
|
||||||
|
fontSize: '14px',
|
||||||
|
color: theme.palette.grey[700],
|
||||||
|
},
|
||||||
|
stratigiesInfoContainer: {
|
||||||
|
display: 'flex',
|
||||||
|
},
|
||||||
|
noStratigiesInfoContainer: {
|
||||||
|
top: '1px',
|
||||||
|
position: 'relative',
|
||||||
|
},
|
||||||
|
stratigiesIconsContainer: {
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
transform: 'scale(0.8)',
|
||||||
|
top: '3px',
|
||||||
|
left: '-10px',
|
||||||
|
position: 'relative',
|
||||||
|
[theme.breakpoints.down(560)]: {
|
||||||
|
marginLeft: '0px',
|
||||||
|
top: '5px',
|
||||||
|
},
|
||||||
|
},
|
||||||
[theme.breakpoints.down(750)]: {
|
[theme.breakpoints.down(750)]: {
|
||||||
accordionBodyFooter: {
|
accordionBodyFooter: {
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
@ -124,7 +155,7 @@ export const useStyles = makeStyles(theme => ({
|
|||||||
},
|
},
|
||||||
[theme.breakpoints.down(560)]: {
|
[theme.breakpoints.down(560)]: {
|
||||||
disabledIndicatorPos: {
|
disabledIndicatorPos: {
|
||||||
top: '-8px',
|
top: '13px',
|
||||||
},
|
},
|
||||||
headerTitle: {
|
headerTitle: {
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
@ -135,6 +166,9 @@ export const useStyles = makeStyles(theme => ({
|
|||||||
truncator: {
|
truncator: {
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
},
|
},
|
||||||
|
resultContainer: {
|
||||||
|
flexWrap: 'wrap',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
[theme.breakpoints.down(400)]: {
|
[theme.breakpoints.down(400)]: {
|
||||||
accordionHeader: {
|
accordionHeader: {
|
||||||
@ -145,4 +179,60 @@ export const useStyles = makeStyles(theme => ({
|
|||||||
padding: '0.5rem',
|
padding: '0.5rem',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
strategyIconContainer: {
|
||||||
|
marginRight: '5px',
|
||||||
|
},
|
||||||
|
strategyIcon: {
|
||||||
|
fill: theme.palette.grey[600],
|
||||||
|
},
|
||||||
|
container: {
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
marginLeft: '1.3rem',
|
||||||
|
[theme.breakpoints.down(560)]: {
|
||||||
|
flexDirection: 'column',
|
||||||
|
marginLeft: '0',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
addStrategyButton: {
|
||||||
|
background: 'none',
|
||||||
|
textDecoration: 'none',
|
||||||
|
boxShadow: 'none',
|
||||||
|
color: theme.palette.primary.main,
|
||||||
|
fontWeight: 'normal',
|
||||||
|
'&:hover': {
|
||||||
|
background: 'none',
|
||||||
|
textDecoration: 'none',
|
||||||
|
boxShadow: 'none',
|
||||||
|
color: theme.palette.primary.main,
|
||||||
|
fontWeight: 'normal',
|
||||||
|
},
|
||||||
|
'&:disabled': {
|
||||||
|
margin: '0px 16px',
|
||||||
|
height: '35px'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
separtor: {
|
||||||
|
marginLeft: '-10px',
|
||||||
|
marginRight: '9px',
|
||||||
|
[theme.breakpoints.down(560)]: {
|
||||||
|
display: 'none',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
resultContainer: {
|
||||||
|
display: 'flex',
|
||||||
|
width: '100%',
|
||||||
|
justifyContent: 'space-around',
|
||||||
|
},
|
||||||
|
dataContainer: {
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
padding: '0px 15px',
|
||||||
|
},
|
||||||
|
resultTitle: {
|
||||||
|
color: theme.palette.primary.main,
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
|
@ -2,24 +2,38 @@ import {
|
|||||||
Accordion,
|
Accordion,
|
||||||
AccordionDetails,
|
AccordionDetails,
|
||||||
AccordionSummary,
|
AccordionSummary,
|
||||||
|
Tooltip,
|
||||||
} from '@material-ui/core';
|
} from '@material-ui/core';
|
||||||
import { ExpandMore } from '@material-ui/icons';
|
import { ExpandMore } from '@material-ui/icons';
|
||||||
|
import React from 'react';
|
||||||
import { useParams } from 'react-router';
|
import { useParams } from 'react-router';
|
||||||
|
import { useHistory } from 'react-router-dom';
|
||||||
import useFeature from '../../../../../../hooks/api/getters/useFeature/useFeature';
|
import useFeature from '../../../../../../hooks/api/getters/useFeature/useFeature';
|
||||||
import useFeatureMetrics from '../../../../../../hooks/api/getters/useFeatureMetrics/useFeatureMetrics';
|
import useFeatureMetrics from '../../../../../../hooks/api/getters/useFeatureMetrics/useFeatureMetrics';
|
||||||
import { IFeatureEnvironment } from '../../../../../../interfaces/featureToggle';
|
import { IFeatureEnvironment } from '../../../../../../interfaces/featureToggle';
|
||||||
import { IFeatureViewParams } from '../../../../../../interfaces/params';
|
import { IFeatureViewParams } from '../../../../../../interfaces/params';
|
||||||
import { getFeatureMetrics } from '../../../../../../utils/get-feature-metrics';
|
import { getFeatureMetrics } from '../../../../../../utils/get-feature-metrics';
|
||||||
|
import {
|
||||||
|
getFeatureStrategyIcon,
|
||||||
|
getHumanReadableStrategyName,
|
||||||
|
} from '../../../../../../utils/strategy-names';
|
||||||
import ConditionallyRender from '../../../../../common/ConditionallyRender';
|
import ConditionallyRender from '../../../../../common/ConditionallyRender';
|
||||||
import DisabledIndicator from '../../../../../common/DisabledIndicator/DisabledIndicator';
|
import DisabledIndicator from '../../../../../common/DisabledIndicator/DisabledIndicator';
|
||||||
import EnvironmentIcon from '../../../../../common/EnvironmentIcon/EnvironmentIcon';
|
import EnvironmentIcon from '../../../../../common/EnvironmentIcon/EnvironmentIcon';
|
||||||
|
import PermissionButton from '../../../../../common/PermissionButton/PermissionButton';
|
||||||
import StringTruncator from '../../../../../common/StringTruncator/StringTruncator';
|
import StringTruncator from '../../../../../common/StringTruncator/StringTruncator';
|
||||||
|
import { UPDATE_FEATURE } from '../../../../../providers/AccessProvider/permissions';
|
||||||
|
|
||||||
import { useStyles } from './FeatureOverviewEnvironment.styles';
|
import { useStyles } from './FeatureOverviewEnvironment.styles';
|
||||||
import FeatureOverviewEnvironmentBody from './FeatureOverviewEnvironmentBody/FeatureOverviewEnvironmentBody';
|
import FeatureOverviewEnvironmentBody from './FeatureOverviewEnvironmentBody/FeatureOverviewEnvironmentBody';
|
||||||
import FeatureOverviewEnvironmentFooter from './FeatureOverviewEnvironmentFooter/FeatureOverviewEnvironmentFooter';
|
import FeatureOverviewEnvironmentFooter from './FeatureOverviewEnvironmentFooter/FeatureOverviewEnvironmentFooter';
|
||||||
import FeatureOverviewEnvironmentMetrics from './FeatureOverviewEnvironmentMetrics/FeatureOverviewEnvironmentMetrics';
|
import FeatureOverviewEnvironmentMetrics from './FeatureOverviewEnvironmentMetrics/FeatureOverviewEnvironmentMetrics';
|
||||||
|
|
||||||
|
interface IStrategyIconObject {
|
||||||
|
count: number;
|
||||||
|
Icon: React.ReactElement;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
interface IFeatureOverviewEnvironmentProps {
|
interface IFeatureOverviewEnvironmentProps {
|
||||||
env: IFeatureEnvironment;
|
env: IFeatureEnvironment;
|
||||||
}
|
}
|
||||||
@ -31,6 +45,7 @@ const FeatureOverviewEnvironment = ({
|
|||||||
const { projectId, featureId } = useParams<IFeatureViewParams>();
|
const { projectId, featureId } = useParams<IFeatureViewParams>();
|
||||||
const { metrics } = useFeatureMetrics(projectId, featureId);
|
const { metrics } = useFeatureMetrics(projectId, featureId);
|
||||||
const { feature } = useFeature(projectId, featureId);
|
const { feature } = useFeature(projectId, featureId);
|
||||||
|
const history = useHistory();
|
||||||
|
|
||||||
const featureMetrics = getFeatureMetrics(feature?.environments, metrics);
|
const featureMetrics = getFeatureMetrics(feature?.environments, metrics);
|
||||||
const environmentMetric = featureMetrics.find(
|
const environmentMetric = featureMetrics.find(
|
||||||
@ -48,6 +63,29 @@ const FeatureOverviewEnvironment = ({
|
|||||||
return `This environment is disabled, which means that none of your strategies are executing`;
|
return `This environment is disabled, which means that none of your strategies are executing`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const strategiesLink = `/projects/${projectId}/features2/${featureId}/strategies?environment=${featureEnvironment?.name}&addStrategy=true`;
|
||||||
|
|
||||||
|
const getStrategyIcons = () => {
|
||||||
|
const strategyObjects = featureEnvironment?.strategies.reduce(
|
||||||
|
(acc, current) => {
|
||||||
|
if (acc[current.name]) {
|
||||||
|
acc[current.name].count = acc[current.name].count + 1;
|
||||||
|
} else {
|
||||||
|
acc[current.name] = {
|
||||||
|
count: 1,
|
||||||
|
Icon: getFeatureStrategyIcon(current.name),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
{} as { [key: string]: IStrategyIconObject }
|
||||||
|
);
|
||||||
|
|
||||||
|
return Object.keys(strategyObjects).map(strategyName => {
|
||||||
|
return { ...strategyObjects[strategyName], name: strategyName };
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.featureOverviewEnvironment}>
|
<div className={styles.featureOverviewEnvironment}>
|
||||||
<Accordion style={{ boxShadow: 'none' }}>
|
<Accordion style={{ boxShadow: 'none' }}>
|
||||||
@ -55,17 +93,76 @@ const FeatureOverviewEnvironment = ({
|
|||||||
className={styles.accordionHeader}
|
className={styles.accordionHeader}
|
||||||
expandIcon={<ExpandMore />}
|
expandIcon={<ExpandMore />}
|
||||||
>
|
>
|
||||||
<div className={styles.headerTitle} data-loading>
|
<div className={styles.header} data-loading>
|
||||||
<EnvironmentIcon
|
<div className={styles.headerTitle}>
|
||||||
enabled={env.enabled}
|
<EnvironmentIcon
|
||||||
className={styles.headerIcon}
|
enabled={env.enabled}
|
||||||
/>
|
className={styles.headerIcon}
|
||||||
Feature toggle execution for
|
/>
|
||||||
<StringTruncator
|
Feature toggle execution for
|
||||||
text={env.name}
|
<StringTruncator
|
||||||
className={styles.truncator}
|
text={env.name}
|
||||||
maxWidth="100"
|
className={styles.truncator}
|
||||||
/>
|
maxWidth="100"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className={styles.container}>
|
||||||
|
<PermissionButton
|
||||||
|
permission={UPDATE_FEATURE}
|
||||||
|
onClick={() => history.push(strategiesLink)}
|
||||||
|
className={styles.addStrategyButton}
|
||||||
|
>
|
||||||
|
Add strategy
|
||||||
|
</PermissionButton>
|
||||||
|
<span className={styles.separtor}>|</span>
|
||||||
|
<ConditionallyRender
|
||||||
|
condition={
|
||||||
|
featureEnvironment?.strategies.length !== 0
|
||||||
|
}
|
||||||
|
show={
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
styles.stratigiesIconsContainer
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{getStrategyIcons()?.map(
|
||||||
|
({ name, Icon }) => (
|
||||||
|
<Tooltip
|
||||||
|
title={getHumanReadableStrategyName(
|
||||||
|
name
|
||||||
|
)}
|
||||||
|
arrow
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
styles.strategyIconContainer
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
className={
|
||||||
|
styles.strategyIcon
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
elseShow={
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
styles.noStratigiesInfoContainer
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<p className={styles.strategiesText}>
|
||||||
|
No strategies defined on this toggle
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={!env.enabled}
|
condition={!env.enabled}
|
||||||
show={
|
show={
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Link, useParams, useHistory } from 'react-router-dom';
|
import { useParams, useHistory } from 'react-router-dom';
|
||||||
import { IFeatureViewParams } from '../../../../../../../interfaces/params';
|
import { IFeatureViewParams } from '../../../../../../../interfaces/params';
|
||||||
import ConditionallyRender from '../../../../../../common/ConditionallyRender';
|
import ConditionallyRender from '../../../../../../common/ConditionallyRender';
|
||||||
import NoItemsStrategies from '../../../../../../common/NoItems/NoItemsStrategies/NoItemsStrategies';
|
import NoItemsStrategies from '../../../../../../common/NoItems/NoItemsStrategies/NoItemsStrategies';
|
||||||
@ -6,6 +6,9 @@ import FeatureOverviewEnvironmentStrategies from '../FeatureOverviewEnvironmentS
|
|||||||
|
|
||||||
import { useStyles } from '../FeatureOverviewEnvironment.styles';
|
import { useStyles } from '../FeatureOverviewEnvironment.styles';
|
||||||
import { IFeatureEnvironment } from '../../../../../../../interfaces/featureToggle';
|
import { IFeatureEnvironment } from '../../../../../../../interfaces/featureToggle';
|
||||||
|
import { UPDATE_FEATURE } from '../../../../../../providers/AccessProvider/permissions';
|
||||||
|
import ResponsiveButton from '../../../../../../common/ResponsiveButton/ResponsiveButton';
|
||||||
|
import { Add } from '@material-ui/icons';
|
||||||
|
|
||||||
interface IFeatureOverviewEnvironmentBodyProps {
|
interface IFeatureOverviewEnvironmentBodyProps {
|
||||||
getOverviewText: () => string;
|
getOverviewText: () => string;
|
||||||
@ -39,7 +42,14 @@ const FeatureOverviewEnvironmentBody = ({
|
|||||||
show={
|
show={
|
||||||
<>
|
<>
|
||||||
<div className={styles.linkContainer}>
|
<div className={styles.linkContainer}>
|
||||||
<Link to={strategiesLink}>Edit strategies</Link>
|
<ResponsiveButton
|
||||||
|
Icon={Add}
|
||||||
|
onClick={() => history.push(strategiesLink)}
|
||||||
|
maxWidth="700px"
|
||||||
|
permission={UPDATE_FEATURE}
|
||||||
|
>
|
||||||
|
Add strategy
|
||||||
|
</ResponsiveButton>
|
||||||
</div>
|
</div>
|
||||||
<FeatureOverviewEnvironmentStrategies
|
<FeatureOverviewEnvironmentStrategies
|
||||||
strategies={featureEnvironment?.strategies}
|
strategies={featureEnvironment?.strategies}
|
||||||
|
@ -1,12 +1,8 @@
|
|||||||
import { Warning } from '@material-ui/icons';
|
|
||||||
import {
|
import {
|
||||||
IFeatureEnvironment,
|
IFeatureEnvironment,
|
||||||
IFeatureEnvironmentMetrics,
|
IFeatureEnvironmentMetrics,
|
||||||
} from '../../../../../../../interfaces/featureToggle';
|
} from '../../../../../../../interfaces/featureToggle';
|
||||||
import { calculatePercentage } from '../../../../../../../utils/calculate-percentage';
|
import { calculatePercentage } from '../../../../../../../utils/calculate-percentage';
|
||||||
import ConditionallyRender from '../../../../../../common/ConditionallyRender';
|
|
||||||
import FeatureEnvironmentMetrics from '../../../FeatureEnvironmentMetrics/FeatureEnvironmentMetrics';
|
|
||||||
|
|
||||||
import { useStyles } from '../FeatureOverviewEnvironment.styles';
|
import { useStyles } from '../FeatureOverviewEnvironment.styles';
|
||||||
|
|
||||||
interface IFeatureOverviewEnvironmentFooterProps {
|
interface IFeatureOverviewEnvironmentFooterProps {
|
||||||
@ -32,37 +28,41 @@ const FeatureOverviewEnvironmentFooter = ({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles.accordionBodyFooter}>
|
<div className={styles.accordionBodyFooter}>
|
||||||
<ConditionallyRender
|
<div className={styles.resultContainer}>
|
||||||
condition={env.enabled}
|
<div className={styles.dataContainer}>
|
||||||
show={
|
<h3 className={styles.resultTitle}>Exposure</h3>
|
||||||
<FeatureEnvironmentMetrics metric={environmentMetric} />
|
<div className={styles.percentageContainer}>
|
||||||
}
|
{environmentMetric?.yes}
|
||||||
elseShow={
|
|
||||||
<div className={styles.disabledInfo}>
|
|
||||||
<Warning className={styles.disabledIcon} />
|
|
||||||
<p>
|
|
||||||
As long as the environment is disabled, all
|
|
||||||
requests made for this feature toggle will
|
|
||||||
return false. Add a strategy and turn on the
|
|
||||||
environment to enable it for your users.
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
}
|
<p className={styles.requestText}>
|
||||||
/>
|
Total exposure of the feature in the environment in
|
||||||
|
the last hour
|
||||||
<div className={styles.requestContainer}>
|
</p>
|
||||||
Total requests {totalTraffic}
|
</div>
|
||||||
<div className={styles.percentageContainer}>
|
<div className={styles.dataContainer}>
|
||||||
{calculatePercentage(
|
<h3 className={styles.resultTitle}>% exposure</h3>
|
||||||
totalTraffic,
|
<div className={styles.percentageContainer}>
|
||||||
environmentMetric?.yes
|
{calculatePercentage(
|
||||||
)}
|
totalTraffic,
|
||||||
%
|
environmentMetric?.yes
|
||||||
|
)}
|
||||||
|
%
|
||||||
|
</div>
|
||||||
|
<p className={styles.requestText}>
|
||||||
|
Total exposure of the feature in the environment in
|
||||||
|
the last hour
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className={styles.dataContainer}>
|
||||||
|
<h3 className={styles.resultTitle}>Total requests</h3>
|
||||||
|
<div className={styles.percentageContainer}>
|
||||||
|
{environmentMetric?.yes + environmentMetric?.no}
|
||||||
|
</div>
|
||||||
|
<p className={styles.requestText}>
|
||||||
|
The total request of the feature in the environment
|
||||||
|
in the last hour
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<p className={styles.requestText}>
|
|
||||||
Received enabled for this feature in this environment in
|
|
||||||
the last hour.
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
@ -17,15 +17,18 @@ export const useStyles = makeStyles(theme => ({
|
|||||||
width: '75px',
|
width: '75px',
|
||||||
},
|
},
|
||||||
infoParagraph: {
|
infoParagraph: {
|
||||||
maxWidth: '150px',
|
maxWidth: '215px',
|
||||||
marginTop: '0.25rem',
|
marginTop: '0.25rem',
|
||||||
fontSize: theme.fontSizes.smallBody,
|
fontSize: theme.fontSizes.smallBody,
|
||||||
},
|
},
|
||||||
percentage: {
|
percentage: {
|
||||||
color: theme.palette.primary.light,
|
color: theme.palette.primary.light,
|
||||||
textAlign: 'center',
|
textAlign: 'right',
|
||||||
fontSize: theme.fontSizes.subHeader,
|
fontSize: theme.fontSizes.subHeader,
|
||||||
},
|
},
|
||||||
|
percentageCircle: {
|
||||||
|
transform: 'scale(0.85)',
|
||||||
|
},
|
||||||
[theme.breakpoints.down(700)]: {
|
[theme.breakpoints.down(700)]: {
|
||||||
infoParagraph: {
|
infoParagraph: {
|
||||||
display: 'none',
|
display: 'none',
|
||||||
@ -35,8 +38,6 @@ export const useStyles = makeStyles(theme => ({
|
|||||||
icon: {
|
icon: {
|
||||||
display: 'none',
|
display: 'none',
|
||||||
},
|
},
|
||||||
},
|
|
||||||
[theme.breakpoints.down(400)]: {
|
|
||||||
percentageCircle: {
|
percentageCircle: {
|
||||||
display: 'none',
|
display: 'none',
|
||||||
},
|
},
|
||||||
|
@ -27,7 +27,8 @@ const FeatureOverviewEnvironmentMetrics = ({
|
|||||||
{percentage}%
|
{percentage}%
|
||||||
</p>
|
</p>
|
||||||
<p className={styles.infoParagraph} data-loading>
|
<p className={styles.infoParagraph} data-loading>
|
||||||
No one has received this feature in the last hour.
|
The feature has been requested <b>0 times</b> and
|
||||||
|
exposed<b> 0 times</b> in the last hour
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<FiberManualRecord
|
<FiberManualRecord
|
||||||
@ -44,8 +45,10 @@ const FeatureOverviewEnvironmentMetrics = ({
|
|||||||
<div className={styles.info}>
|
<div className={styles.info}>
|
||||||
<p className={styles.percentage}>{percentage}%</p>
|
<p className={styles.percentage}>{percentage}%</p>
|
||||||
<p className={styles.infoParagraph}>
|
<p className={styles.infoParagraph}>
|
||||||
{environmentMetric.yes} users have received the feature in
|
The feature has been requested{' '}
|
||||||
the last hour.
|
<b>{environmentMetric.yes + environmentMetric.no} times</b>{' '}
|
||||||
|
and exposed <b>{environmentMetric.yes} times</b> in the last
|
||||||
|
hour
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<PercentageCircle
|
<PercentageCircle
|
||||||
|
@ -63,7 +63,7 @@ const FeatureStrategyExecution = ({
|
|||||||
return (
|
return (
|
||||||
<Fragment key={key}>
|
<Fragment key={key}>
|
||||||
<p className={styles.text}>
|
<p className={styles.text}>
|
||||||
{parameters[key]}% of your user base{' '}
|
{parameters[key]}% of your base{' '}
|
||||||
{constraints.length > 0
|
{constraints.length > 0
|
||||||
? 'who match constraints'
|
? 'who match constraints'
|
||||||
: ''}{' '}
|
: ''}{' '}
|
||||||
@ -146,8 +146,7 @@ const FeatureStrategyExecution = ({
|
|||||||
return (
|
return (
|
||||||
<Fragment key={param?.name}>
|
<Fragment key={param?.name}>
|
||||||
<p className={styles.text}>
|
<p className={styles.text}>
|
||||||
{strategy?.parameters[param.name]}% of your user
|
{strategy?.parameters[param.name]}% of your base{' '}
|
||||||
base{' '}
|
|
||||||
{constraints?.length > 0
|
{constraints?.length > 0
|
||||||
? 'who match constraints'
|
? 'who match constraints'
|
||||||
: ''}{' '}
|
: ''}{' '}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Button, Grid, TextField, Typography } from '@material-ui/core';
|
import { Button, Grid, TextField, Typography } from '@material-ui/core';
|
||||||
@ -10,6 +10,7 @@ import AuthOptions from '../common/AuthOptions/AuthOptions';
|
|||||||
import DividerText from '../../common/DividerText/DividerText';
|
import DividerText from '../../common/DividerText/DividerText';
|
||||||
import ConditionallyRender from '../../common/ConditionallyRender';
|
import ConditionallyRender from '../../common/ConditionallyRender';
|
||||||
import useUser from '../../../hooks/api/getters/useUser/useUser';
|
import useUser from '../../../hooks/api/getters/useUser/useUser';
|
||||||
|
import PasswordField from '../../common/PasswordField/PasswordField';
|
||||||
|
|
||||||
const HostedAuth = ({ authDetails, passwordLogin }) => {
|
const HostedAuth = ({ authDetails, passwordLogin }) => {
|
||||||
const commonStyles = useCommonStyles();
|
const commonStyles = useCommonStyles();
|
||||||
@ -109,16 +110,13 @@ const HostedAuth = ({ authDetails, passwordLogin }) => {
|
|||||||
variant="outlined"
|
variant="outlined"
|
||||||
size="small"
|
size="small"
|
||||||
/>
|
/>
|
||||||
<TextField
|
<PasswordField
|
||||||
label="Password"
|
label="Password"
|
||||||
onChange={evt => setPassword(evt.target.value)}
|
onChange={evt => setPassword(evt.target.value)}
|
||||||
name="password"
|
name="password"
|
||||||
type="password"
|
|
||||||
value={password}
|
value={password}
|
||||||
error={!!passwordError}
|
error={!!passwordError}
|
||||||
helperText={passwordError}
|
helperText={passwordError}
|
||||||
variant="outlined"
|
|
||||||
size="small"
|
|
||||||
/>
|
/>
|
||||||
<Grid container>
|
<Grid container>
|
||||||
<Button
|
<Button
|
||||||
|
@ -16,6 +16,7 @@ import {
|
|||||||
LOGIN_EMAIL_ID,
|
LOGIN_EMAIL_ID,
|
||||||
} from '../../../testIds';
|
} from '../../../testIds';
|
||||||
import useUser from '../../../hooks/api/getters/useUser/useUser';
|
import useUser from '../../../hooks/api/getters/useUser/useUser';
|
||||||
|
import PasswordField from '../../common/PasswordField/PasswordField';
|
||||||
|
|
||||||
const PasswordAuth = ({ authDetails, passwordLogin }) => {
|
const PasswordAuth = ({ authDetails, passwordLogin }) => {
|
||||||
const commonStyles = useCommonStyles();
|
const commonStyles = useCommonStyles();
|
||||||
@ -111,22 +112,17 @@ const PasswordAuth = ({ authDetails, passwordLogin }) => {
|
|||||||
value={username}
|
value={username}
|
||||||
error={!!usernameError}
|
error={!!usernameError}
|
||||||
helperText={usernameError}
|
helperText={usernameError}
|
||||||
variant="outlined"
|
|
||||||
autoComplete="true"
|
autoComplete="true"
|
||||||
size="small"
|
|
||||||
data-test={LOGIN_EMAIL_ID}
|
data-test={LOGIN_EMAIL_ID}
|
||||||
/>
|
/>
|
||||||
<TextField
|
<PasswordField
|
||||||
label="Password"
|
label="Password"
|
||||||
onChange={evt => setPassword(evt.target.value)}
|
onChange={evt => setPassword(evt.target.value)}
|
||||||
name="password"
|
name="password"
|
||||||
type="password"
|
|
||||||
value={password}
|
value={password}
|
||||||
error={!!passwordError}
|
error={!!passwordError}
|
||||||
helperText={passwordError}
|
helperText={passwordError}
|
||||||
variant="outlined"
|
|
||||||
autoComplete="true"
|
autoComplete="true"
|
||||||
size="small"
|
|
||||||
data-test={LOGIN_PASSWORD_ID}
|
data-test={LOGIN_PASSWORD_ID}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { SyntheticEvent, useState } from 'react';
|
import { SyntheticEvent, useState } from 'react';
|
||||||
import { Button, TextField, Typography } from '@material-ui/core';
|
import { Button, Typography } from '@material-ui/core';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import { useStyles } from './EditProfile.styles';
|
import { useStyles } from './EditProfile.styles';
|
||||||
import { useCommonStyles } from '../../../../common.styles';
|
import { useCommonStyles } from '../../../../common.styles';
|
||||||
@ -16,6 +16,7 @@ import {
|
|||||||
UNAUTHORIZED,
|
UNAUTHORIZED,
|
||||||
} from '../../../../constants/statusCodes';
|
} from '../../../../constants/statusCodes';
|
||||||
import { formatApiPath } from '../../../../utils/format-path';
|
import { formatApiPath } from '../../../../utils/format-path';
|
||||||
|
import PasswordField from '../../../common/PasswordField/PasswordField';
|
||||||
|
|
||||||
interface IEditProfileProps {
|
interface IEditProfileProps {
|
||||||
setEditingProfile: React.Dispatch<React.SetStateAction<boolean>>;
|
setEditingProfile: React.Dispatch<React.SetStateAction<boolean>>;
|
||||||
@ -54,7 +55,7 @@ const EditProfile = ({
|
|||||||
credentials: 'include',
|
credentials: 'include',
|
||||||
});
|
});
|
||||||
handleResponse(res);
|
handleResponse(res);
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
setError(e);
|
setError(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -112,27 +113,25 @@ const EditProfile = ({
|
|||||||
callback={setValidPassword}
|
callback={setValidPassword}
|
||||||
data-loading
|
data-loading
|
||||||
/>
|
/>
|
||||||
<TextField
|
<PasswordField
|
||||||
data-loading
|
data-loading
|
||||||
variant="outlined"
|
|
||||||
size="small"
|
|
||||||
label="Password"
|
label="Password"
|
||||||
type="password"
|
|
||||||
name="password"
|
name="password"
|
||||||
value={password}
|
value={password}
|
||||||
autoComplete="on"
|
autoComplete="on"
|
||||||
onChange={e => setPassword(e.target.value)}
|
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
||||||
|
setPassword(e.target.value)
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<TextField
|
<PasswordField
|
||||||
data-loading
|
data-loading
|
||||||
variant="outlined"
|
|
||||||
size="small"
|
|
||||||
label="Confirm password"
|
label="Confirm password"
|
||||||
type="password"
|
|
||||||
name="confirmPassword"
|
name="confirmPassword"
|
||||||
value={confirmPassword}
|
value={confirmPassword}
|
||||||
autoComplete="on"
|
autoComplete="on"
|
||||||
onChange={e => setConfirmPassword(e.target.value)}
|
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
||||||
|
setConfirmPassword(e.target.value)
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<PasswordMatcher
|
<PasswordMatcher
|
||||||
data-loading
|
data-loading
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Button, TextField } from '@material-ui/core';
|
import { Button } from '@material-ui/core';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import {
|
import {
|
||||||
SyntheticEvent,
|
SyntheticEvent,
|
||||||
@ -17,6 +17,7 @@ import PasswordMatcher from './PasswordMatcher/PasswordMatcher';
|
|||||||
import { useStyles } from './ResetPasswordForm.styles';
|
import { useStyles } from './ResetPasswordForm.styles';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { formatApiPath } from '../../../../utils/format-path';
|
import { formatApiPath } from '../../../../utils/format-path';
|
||||||
|
import PasswordField from '../../../common/PasswordField/PasswordField';
|
||||||
|
|
||||||
interface IResetPasswordProps {
|
interface IResetPasswordProps {
|
||||||
token: string;
|
token: string;
|
||||||
@ -107,24 +108,22 @@ const ResetPasswordForm = ({ token, setLoading }: IResetPasswordProps) => {
|
|||||||
styles.container
|
styles.container
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<TextField
|
<PasswordField
|
||||||
variant="outlined"
|
|
||||||
size="small"
|
|
||||||
type="password"
|
|
||||||
placeholder="Password"
|
placeholder="Password"
|
||||||
value={password || ''}
|
value={password || ''}
|
||||||
onChange={e => setPassword(e.target.value)}
|
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
||||||
|
setPassword(e.target.value)
|
||||||
|
}
|
||||||
onFocus={() => setShowPasswordChecker(true)}
|
onFocus={() => setShowPasswordChecker(true)}
|
||||||
autoComplete="password"
|
autoComplete="password"
|
||||||
data-loading
|
data-loading
|
||||||
/>
|
/>
|
||||||
<TextField
|
<PasswordField
|
||||||
variant="outlined"
|
|
||||||
size="small"
|
|
||||||
type="password"
|
|
||||||
value={confirmPassword || ''}
|
value={confirmPassword || ''}
|
||||||
placeholder="Confirm password"
|
placeholder="Confirm password"
|
||||||
onChange={e => setConfirmPassword(e.target.value)}
|
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
||||||
|
setConfirmPassword(e.target.value)
|
||||||
|
}
|
||||||
autoComplete="confirm-password"
|
autoComplete="confirm-password"
|
||||||
data-loading
|
data-loading
|
||||||
/>
|
/>
|
||||||
|
@ -1991,10 +1991,10 @@
|
|||||||
"@types/cheerio" "*"
|
"@types/cheerio" "*"
|
||||||
"@types/react" "*"
|
"@types/react" "*"
|
||||||
|
|
||||||
"@types/enzyme@3.10.10":
|
"@types/enzyme@3.10.11":
|
||||||
version "3.10.10"
|
version "3.10.11"
|
||||||
resolved "https://registry.npmjs.org/@types/enzyme/-/enzyme-3.10.10.tgz"
|
resolved "https://registry.yarnpkg.com/@types/enzyme/-/enzyme-3.10.11.tgz#8924bd92cc63ac1843e215225dfa8f71555fe814"
|
||||||
integrity sha512-/D4wFhiEjUDfPu+j5FVK0g/jf7rqeEIpNfAI+kyxzLpw5CKO0drnW3W5NC38alIjsWgnyQ8pbuPF5+UD+vhVyg==
|
integrity sha512-LEtC7zXsQlbGXWGcnnmOI7rTyP+i1QzQv4Va91RKXDEukLDaNyxu0rXlfMiGEhJwfgTPCTb0R+Pnlj//oM9e/w==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/cheerio" "*"
|
"@types/cheerio" "*"
|
||||||
"@types/react" "*"
|
"@types/react" "*"
|
||||||
@ -2084,10 +2084,10 @@
|
|||||||
jest-diff "^26.0.0"
|
jest-diff "^26.0.0"
|
||||||
pretty-format "^26.0.0"
|
pretty-format "^26.0.0"
|
||||||
|
|
||||||
"@types/jest@27.0.3":
|
"@types/jest@27.4.0":
|
||||||
version "27.0.3"
|
version "27.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/@types/jest/-/jest-27.0.3.tgz#0cf9dfe9009e467f70a342f0f94ead19842a783a"
|
resolved "https://registry.yarnpkg.com/@types/jest/-/jest-27.4.0.tgz#037ab8b872067cae842a320841693080f9cb84ed"
|
||||||
integrity sha512-cmmwv9t7gBYt7hNKH5Spu7Kuu/DotGa+Ff+JGRKZ4db5eh8PnKS4LuebJ3YLUoyOyIHraTGyULn23YtEAm0VSg==
|
integrity sha512-gHl8XuC1RZ8H2j5sHv/JqsaxXkDDM9iDOgu0Wp8sjs4u/snb2PVehyWXJPr+ORA0RPpgw231mnutWI1+0hgjIQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
jest-diff "^27.0.0"
|
jest-diff "^27.0.0"
|
||||||
pretty-format "^27.0.0"
|
pretty-format "^27.0.0"
|
||||||
@ -2112,10 +2112,10 @@
|
|||||||
resolved "https://registry.npmjs.org/@types/node/-/node-14.14.37.tgz"
|
resolved "https://registry.npmjs.org/@types/node/-/node-14.14.37.tgz"
|
||||||
integrity sha512-XYmBiy+ohOR4Lh5jE379fV2IU+6Jn4g5qASinhitfyO71b/sCo6MKsMLF5tc7Zf2CE8hViVQyYSobJNke8OvUw==
|
integrity sha512-XYmBiy+ohOR4Lh5jE379fV2IU+6Jn4g5qASinhitfyO71b/sCo6MKsMLF5tc7Zf2CE8hViVQyYSobJNke8OvUw==
|
||||||
|
|
||||||
"@types/node@14.18.1":
|
"@types/node@14.18.5":
|
||||||
version "14.18.1"
|
version "14.18.5"
|
||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.1.tgz#459886b51f52aa923dc06b9ea81cb8b1d733e9d3"
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.5.tgz#0dd636fe7b2c6055cbed0d4ca3b7fb540f130a96"
|
||||||
integrity sha512-fTFWOFrgAkj737w1o0HLTIgisgYHnsZfeiqhG1Ltrf/iJjudEbUwetQAsfrtVE49JGwvpEzQR+EbMkIqG4227g==
|
integrity sha512-LMy+vDDcQR48EZdEx5wRX1q/sEl6NdGuHXPnfeL8ixkwCOSZ2qnIyIZmcCbdX0MeRqHhAcHmX+haCbrS8Run+A==
|
||||||
|
|
||||||
"@types/node@^14.14.31":
|
"@types/node@^14.14.31":
|
||||||
version "14.17.19"
|
version "14.17.19"
|
||||||
@ -2204,10 +2204,10 @@
|
|||||||
"@types/scheduler" "*"
|
"@types/scheduler" "*"
|
||||||
csstype "^3.0.2"
|
csstype "^3.0.2"
|
||||||
|
|
||||||
"@types/react@17.0.37":
|
"@types/react@17.0.38":
|
||||||
version "17.0.37"
|
version "17.0.38"
|
||||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.37.tgz#6884d0aa402605935c397ae689deed115caad959"
|
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.38.tgz#f24249fefd89357d5fa71f739a686b8d7c7202bd"
|
||||||
integrity sha512-2FS1oTqBGcH/s0E+CjrCCR9+JMpsu9b69RTFO+40ua43ZqP5MmQ4iUde/dMjWR909KxZwmOQIFq6AV6NjEG5xg==
|
integrity sha512-SI92X1IA+FMnP3qM5m4QReluXzhcmovhZnLNm3pyeQlooi02qI7sLiepEYqT678uNiyc25XfCqxREFpy3W7YhQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/prop-types" "*"
|
"@types/prop-types" "*"
|
||||||
"@types/scheduler" "*"
|
"@types/scheduler" "*"
|
||||||
@ -4655,10 +4655,10 @@ data-urls@^2.0.0:
|
|||||||
whatwg-mimetype "^2.3.0"
|
whatwg-mimetype "^2.3.0"
|
||||||
whatwg-url "^8.0.0"
|
whatwg-url "^8.0.0"
|
||||||
|
|
||||||
date-fns@2.27.0:
|
date-fns@2.28.0:
|
||||||
version "2.27.0"
|
version "2.28.0"
|
||||||
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.27.0.tgz#e1ff3c3ddbbab8a2eaadbb6106be2929a5a2d92b"
|
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.28.0.tgz#9570d656f5fc13143e50c975a3b6bbeb46cd08b2"
|
||||||
integrity sha512-sj+J0Mo2p2X1e306MHq282WS4/A8Pz/95GIFcsPNMPMZVI3EUrAdSv90al1k+p74WGLCruMXk23bfEDZa71X9Q==
|
integrity sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw==
|
||||||
|
|
||||||
dayjs@^1.10.4:
|
dayjs@^1.10.4:
|
||||||
version "1.10.7"
|
version "1.10.7"
|
||||||
@ -10479,17 +10479,17 @@ react-dev-utils@^11.0.3:
|
|||||||
strip-ansi "6.0.0"
|
strip-ansi "6.0.0"
|
||||||
text-table "0.2.0"
|
text-table "0.2.0"
|
||||||
|
|
||||||
react-dnd-html5-backend@14.0.2:
|
react-dnd-html5-backend@14.1.0:
|
||||||
version "14.0.2"
|
version "14.1.0"
|
||||||
resolved "https://registry.npmjs.org/react-dnd-html5-backend/-/react-dnd-html5-backend-14.0.2.tgz"
|
resolved "https://registry.yarnpkg.com/react-dnd-html5-backend/-/react-dnd-html5-backend-14.1.0.tgz#b35a3a0c16dd3a2bfb5eb7ec62cf0c2cace8b62f"
|
||||||
integrity sha512-QgN6rYrOm4UUj6tIvN8ovImu6uP48xBXF2rzVsp6tvj6d5XQ7OjHI4SJ/ZgGobOneRAU3WCX4f8DGCYx0tuhlw==
|
integrity sha512-6ONeqEC3XKVf4eVmMTe0oPds+c5B9Foyj8p/ZKLb7kL2qh9COYxiBHv3szd6gztqi/efkmriywLUVlPotqoJyw==
|
||||||
dependencies:
|
dependencies:
|
||||||
dnd-core "14.0.1"
|
dnd-core "14.0.1"
|
||||||
|
|
||||||
react-dnd@14.0.4:
|
react-dnd@14.0.5:
|
||||||
version "14.0.4"
|
version "14.0.5"
|
||||||
resolved "https://registry.npmjs.org/react-dnd/-/react-dnd-14.0.4.tgz"
|
resolved "https://registry.yarnpkg.com/react-dnd/-/react-dnd-14.0.5.tgz#ecf264e220ae62e35634d9b941502f3fca0185ed"
|
||||||
integrity sha512-AFJJXzUIWp5WAhgvI85ESkDCawM0lhoVvfo/lrseLXwFdH3kEO3v8I2C81QPqBW2UEyJBIPStOhPMGYGFtq/bg==
|
integrity sha512-9i1jSgbyVw0ELlEVt/NkCUkxy1hmhJOkePoCH713u75vzHGyXhPDm28oLfc2NMSBjZRM1Y+wRjHXJT3sPrTy+A==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@react-dnd/invariant" "^2.0.0"
|
"@react-dnd/invariant" "^2.0.0"
|
||||||
"@react-dnd/shallowequal" "^2.0.0"
|
"@react-dnd/shallowequal" "^2.0.0"
|
||||||
@ -11265,13 +11265,14 @@ sass-loader@^10.0.5:
|
|||||||
schema-utils "^3.0.0"
|
schema-utils "^3.0.0"
|
||||||
semver "^7.3.2"
|
semver "^7.3.2"
|
||||||
|
|
||||||
sass@1.44.0:
|
sass@1.46.0:
|
||||||
version "1.44.0"
|
version "1.46.0"
|
||||||
resolved "https://registry.yarnpkg.com/sass/-/sass-1.44.0.tgz#619aa0a2275c097f9af5e6b8fe8a95e3056430fb"
|
resolved "https://registry.yarnpkg.com/sass/-/sass-1.46.0.tgz#923117049525236026a7ede69715580eb0fac751"
|
||||||
integrity sha512-0hLREbHFXGQqls/K8X+koeP+ogFRPF4ZqetVB19b7Cst9Er8cOR0rc6RU7MaI4W1JmUShd1BPgPoeqmmgMMYFw==
|
integrity sha512-Z4BYTgioAOlMmo4LU3Ky2txR8KR0GRPLXxO38kklaYxgo7qMTgy+mpNN4eKsrXDTFlwS5vdruvazG4cihxHRVQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
chokidar ">=3.0.0 <4.0.0"
|
chokidar ">=3.0.0 <4.0.0"
|
||||||
immutable "^4.0.0"
|
immutable "^4.0.0"
|
||||||
|
source-map-js ">=0.6.2 <2.0.0"
|
||||||
|
|
||||||
sax@~1.2.4:
|
sax@~1.2.4:
|
||||||
version "1.2.4"
|
version "1.2.4"
|
||||||
@ -11607,6 +11608,11 @@ source-list-map@^2.0.0:
|
|||||||
resolved "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz"
|
resolved "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz"
|
||||||
integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==
|
integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==
|
||||||
|
|
||||||
|
"source-map-js@>=0.6.2 <2.0.0":
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.1.tgz#a1741c131e3c77d048252adfa24e23b908670caf"
|
||||||
|
integrity sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA==
|
||||||
|
|
||||||
source-map-js@^0.6.2:
|
source-map-js@^0.6.2:
|
||||||
version "0.6.2"
|
version "0.6.2"
|
||||||
resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-0.6.2.tgz"
|
resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-0.6.2.tgz"
|
||||||
|
Loading…
Reference in New Issue
Block a user