1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-07-21 13:47:39 +02:00

refactor: format files (#719)

* refactor: fix deprecated prettier config name

* refactor: add fmt scripts

* refactor: check fmt during CI

* refactor: format files
This commit is contained in:
olav 2022-02-18 09:51:10 +01:00 committed by GitHub
parent 46bf92124d
commit 016633dae9
65 changed files with 282 additions and 247 deletions

View File

@ -25,6 +25,4 @@ jobs:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
- run: yarn - run: yarn
- run: yarn run test - run: yarn run test
- run: yarn run fmt:check

View File

@ -1,7 +1,7 @@
{ {
"singleQuote": true, "singleQuote": true,
"bracketSpacing": true, "bracketSpacing": true,
"jsxBracketSameLine": false, "bracketSameLine": false,
"arrowParens": "avoid", "arrowParens": "avoid",
"printWidth": 80 "printWidth": 80
} }

View File

@ -32,6 +32,8 @@
"start:demo": "UNLEASH_API=http://unleash.herokuapp.com yarn run start", "start:demo": "UNLEASH_API=http://unleash.herokuapp.com yarn run start",
"test": "react-scripts test", "test": "react-scripts test",
"prepare": "yarn run build", "prepare": "yarn run build",
"fmt": "prettier src --write --loglevel warn",
"fmt:check": "prettier src --check",
"e2e": "yarn run cypress open --config baseUrl='http://localhost:3000' --env PASSWORD_AUTH=true,AUTH_TOKEN=$AUTH_TOKEN", "e2e": "yarn run cypress open --config baseUrl='http://localhost:3000' --env PASSWORD_AUTH=true,AUTH_TOKEN=$AUTH_TOKEN",
"e2e:heroku": "yarn run cypress open --config baseUrl='http://localhost:3000' --env PASSWORD_AUTH=false,AUTH_TOKEN=$AUTH_TOKEN", "e2e:heroku": "yarn run cypress open --config baseUrl='http://localhost:3000' --env PASSWORD_AUTH=false,AUTH_TOKEN=$AUTH_TOKEN",
"e2e:enterprise": "yarn run cypress open --config baseUrl='http://localhost:3000' --env PASSWORD_AUTH=true,ENTERPRISE=true,AUTH_TOKEN=$AUTH_TOKEN" "e2e:enterprise": "yarn run cypress open --config baseUrl='http://localhost:3000' --env PASSWORD_AUTH=true,ENTERPRISE=true,AUTH_TOKEN=$AUTH_TOKEN"

View File

@ -1,2 +1,2 @@
export default 'SvgrURL' export default 'SvgrURL';
export const ReactComponent = 'div' export const ReactComponent = 'div';

View File

@ -5,10 +5,10 @@ import ReportProblemOutlinedIcon from '@material-ui/icons/ReportProblemOutlined'
import ConditionallyRender from '../../common/ConditionallyRender/ConditionallyRender'; import ConditionallyRender from '../../common/ConditionallyRender/ConditionallyRender';
import styles from './ReportCard.module.scss'; import styles from './ReportCard.module.scss';
import ReactTimeAgo from 'react-timeago'; import ReactTimeAgo from 'react-timeago';
import { IProjectHealthReport } from "../../../interfaces/project"; import { IProjectHealthReport } from '../../../interfaces/project';
interface IReportCardProps { interface IReportCardProps {
healthReport: IProjectHealthReport healthReport: IProjectHealthReport;
} }
export const ReportCard = ({ healthReport }: IReportCardProps) => { export const ReportCard = ({ healthReport }: IReportCardProps) => {
@ -37,7 +37,9 @@ export const ReportCard = ({ healthReport }: IReportCardProps) => {
const renderPotentiallyStaleToggles = () => ( const renderPotentiallyStaleToggles = () => (
<> <>
<ReportProblemOutlinedIcon className={styles.danger} /> <ReportProblemOutlinedIcon className={styles.danger} />
<span>{healthReport.potentiallyStaleCount} potentially stale toggles</span> <span>
{healthReport.potentiallyStaleCount} potentially stale toggles
</span>
</> </>
); );
@ -51,7 +53,9 @@ export const ReportCard = ({ healthReport }: IReportCardProps) => {
condition={healthReport.health > -1} condition={healthReport.health > -1}
show={ show={
<div> <div>
<p className={healthClasses}>{healthReport.health}%</p> <p className={healthClasses}>
{healthReport.health}%
</p>
<p className={styles.lastUpdate}> <p className={styles.lastUpdate}>
Last updated:{' '} Last updated:{' '}
<ReactTimeAgo <ReactTimeAgo
@ -97,13 +101,17 @@ export const ReportCard = ({ healthReport }: IReportCardProps) => {
<ul className={styles.reportCardList}> <ul className={styles.reportCardList}>
<li> <li>
<ConditionallyRender <ConditionallyRender
condition={Boolean(healthReport.potentiallyStaleCount)} condition={Boolean(
healthReport.potentiallyStaleCount
)}
show={renderPotentiallyStaleToggles} show={renderPotentiallyStaleToggles}
/> />
</li> </li>
</ul> </ul>
<ConditionallyRender <ConditionallyRender
condition={Boolean(healthReport.potentiallyStaleCount)} condition={Boolean(
healthReport.potentiallyStaleCount
)}
show={ show={
<p className={styles.reportCardActionText}> <p className={styles.reportCardActionText}>
Review your feature toggles and delete Review your feature toggles and delete

View File

@ -18,35 +18,35 @@ export const useStyles = makeStyles(theme => ({
marginBottom: '1rem', marginBottom: '1rem',
}, },
center: { center: {
textAlign: 'center' textAlign: 'center',
}, },
actionsContainer: { actionsContainer: {
textAlign: 'center', textAlign: 'center',
display: 'flex-inline', display: 'flex-inline',
flexWrap: 'nowrap' flexWrap: 'nowrap',
}, },
infoBoxContainer:{ infoBoxContainer: {
marginBottom:40 marginBottom: 40,
}, },
hideSM:{ hideSM: {
[theme.breakpoints.down('sm')]: { [theme.breakpoints.down('sm')]: {
display: 'none' display: 'none',
} },
}, },
hideMD:{ hideMD: {
[theme.breakpoints.down('md')]: { [theme.breakpoints.down('md')]: {
display: 'none' display: 'none',
} },
}, },
hideXS:{ hideXS: {
[theme.breakpoints.down('xs')]: { [theme.breakpoints.down('xs')]: {
display: 'none' display: 'none',
} },
}, },
token:{ token: {
textAlign: 'left', textAlign: 'left',
[theme.breakpoints.up('sm')]: { [theme.breakpoints.up('sm')]: {
display: 'none' display: 'none',
} },
} },
})); }));

View File

@ -1,9 +1,10 @@
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
function Secret({ value }) { function Secret({ value }) {
return ( return (
<div> <div>
<span style={{ width: '250px', display: 'inline-block' }}>************************************</span> <span style={{ width: '250px', display: 'inline-block' }}>
************************************
</span>
</div> </div>
); );
} }

View File

@ -20,7 +20,7 @@ const useApiToken = (
setType(initialtype); setType(initialtype);
if (type === 'ADMIN') { if (type === 'ADMIN') {
setProject('*'); setProject('*');
setEnvironment('*') setEnvironment('*');
} }
//eslint-disable-next-line react-hooks/exhaustive-deps //eslint-disable-next-line react-hooks/exhaustive-deps
}, [initialtype]); }, [initialtype]);
@ -35,11 +35,11 @@ const useApiToken = (
const setTokenType = (value: string) => { const setTokenType = (value: string) => {
if (value === 'ADMIN') { if (value === 'ADMIN') {
setType(value) setType(value);
setProject('*'); setProject('*');
setEnvironment('*'); setEnvironment('*');
} else { } else {
setType(value) setType(value);
setEnvironment(initialEnvironment); setEnvironment(initialEnvironment);
} }
}; };

View File

@ -9,10 +9,7 @@ const ApiPage = () => {
return ( return (
<div> <div>
<ConditionallyRender <ConditionallyRender condition={isAdmin} show={<AdminMenu />} />
condition={isAdmin}
show={<AdminMenu />}
/>
<ApiTokenList /> <ApiTokenList />
</div> </div>
); );

View File

@ -7,4 +7,3 @@ export const useStyles = makeStyles(theme => ({
position: 'relative', position: 'relative',
}, },
})); }));

View File

@ -97,10 +97,7 @@ const CreateUser = () => {
setRootRole={setRootRole} setRootRole={setRootRole}
clearErrors={clearErrors} clearErrors={clearErrors}
> >
<PermissionButton <PermissionButton permission={ADMIN} type="submit">
permission={ADMIN}
type="submit"
>
Create user Create user
</PermissionButton> </PermissionButton>
</UserForm> </UserForm>

View File

@ -35,11 +35,7 @@ const EditUser = () => {
validateName, validateName,
errors, errors,
clearErrors, clearErrors,
} = useAddUserForm( } = useAddUserForm(user?.name, user?.email, user?.rootRole);
user?.name,
user?.email,
user?.rootRole
);
const formatApiCode = () => { const formatApiCode = () => {
return `curl --location --request PUT '${ return `curl --location --request PUT '${
@ -98,10 +94,7 @@ const EditUser = () => {
clearErrors={clearErrors} clearErrors={clearErrors}
mode={EDIT} mode={EDIT}
> >
<PermissionButton <PermissionButton permission={ADMIN} type="submit">
permission={ADMIN}
type="submit"
>
Edit user Edit user
</PermissionButton> </PermissionButton>
</UserForm> </UserForm>

View File

@ -6,7 +6,7 @@ export const useStyles = makeStyles(theme => ({
backgroundColor: theme.palette.grey[200], backgroundColor: theme.palette.grey[200],
}, },
}, },
leftTableCell:{ leftTableCell: {
textAlign: 'left' textAlign: 'left',
} },
})); }));

View File

@ -14,7 +14,7 @@ import AccessContext from '../../../../../contexts/AccessContext';
import { IUser } from '../../../../../interfaces/user'; import { IUser } from '../../../../../interfaces/user';
import { useStyles } from './UserListItem.styles'; import { useStyles } from './UserListItem.styles';
import { useHistory } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
import { ILocationSettings } from "../../../../../hooks/useLocationSettings"; import { ILocationSettings } from '../../../../../hooks/useLocationSettings';
interface IUserListItemProps { interface IUserListItemProps {
user: IUser; user: IUser;
@ -34,7 +34,7 @@ const UserListItem = ({
locationSettings, locationSettings,
}: IUserListItemProps) => { }: IUserListItemProps) => {
const { hasAccess } = useContext(AccessContext); const { hasAccess } = useContext(AccessContext);
const history = useHistory() const history = useHistory();
const styles = useStyles(); const styles = useStyles();
return ( return (
@ -51,7 +51,10 @@ const UserListItem = ({
</TableCell> </TableCell>
<TableCell> <TableCell>
<span data-loading> <span data-loading>
{formatDateWithLocale(user.createdAt, locationSettings.locale)} {formatDateWithLocale(
user.createdAt,
locationSettings.locale
)}
</span> </span>
</TableCell> </TableCell>
<TableCell className={styles.leftTableCell}> <TableCell className={styles.leftTableCell}>
@ -77,7 +80,9 @@ const UserListItem = ({
data-loading data-loading
aria-label="Edit" aria-label="Edit"
title="Edit" title="Edit"
onClick={()=> history.push(`/admin/users/${user.id}/edit`)} onClick={() =>
history.push(`/admin/users/${user.id}/edit`)
}
> >
<Edit /> <Edit />
</IconButton> </IconButton>

View File

@ -23,7 +23,7 @@ import PaginateUI from '../../../common/PaginateUI/PaginateUI';
import { IUser } from '../../../../interfaces/user'; import { IUser } from '../../../../interfaces/user';
import IRole from '../../../../interfaces/role'; import IRole from '../../../../interfaces/role';
import useToast from '../../../../hooks/useToast'; import useToast from '../../../../hooks/useToast';
import { useLocationSettings } from "../../../../hooks/useLocationSettings"; import { useLocationSettings } from '../../../../hooks/useLocationSettings';
const UsersList = () => { const UsersList = () => {
const { users, roles, refetch, loading } = useUsers(); const { users, roles, refetch, loading } = useUsers();
@ -36,7 +36,7 @@ const UsersList = () => {
userApiErrors, userApiErrors,
} = useAdminUsersApi(); } = useAdminUsersApi();
const { hasAccess } = useContext(AccessContext); const { hasAccess } = useContext(AccessContext);
const { locationSettings } = useLocationSettings() const { locationSettings } = useLocationSettings();
const [pwDialog, setPwDialog] = useState<{ open: boolean; user?: IUser }>({ const [pwDialog, setPwDialog] = useState<{ open: boolean; user?: IUser }>({
open: false, open: false,
}); });

View File

@ -26,9 +26,8 @@ const BreadcrumbNav = () => {
item !== 'strategies' && item !== 'strategies' &&
item !== 'features' && item !== 'features' &&
item !== 'features2' && item !== 'features2' &&
item !== 'create-toggle'&& item !== 'create-toggle' &&
item !== 'settings' item !== 'settings'
); );
return ( return (
@ -52,7 +51,10 @@ const BreadcrumbNav = () => {
styles.breadcrumbNavParagraph styles.breadcrumbNavParagraph
} }
> >
<StringTruncator text={path} maxWidth="200" /> <StringTruncator
text={path}
maxWidth="200"
/>
</p> </p>
); );
} }
@ -73,7 +75,10 @@ const BreadcrumbNav = () => {
className={styles.breadcrumbLink} className={styles.breadcrumbLink}
to={link} to={link}
> >
<StringTruncator text={path} maxWidth="200" /> <StringTruncator
text={path}
maxWidth="200"
/>
</Link> </Link>
); );
})} })}

View File

@ -71,9 +71,7 @@ const FormTemplate: React.FC<ICreateProps> = ({
<> <>
<h3 className={styles.subtitle}> <h3 className={styles.subtitle}>
API Command{' '} API Command{' '}
<IconButton <IconButton onClick={copyCommand}>
onClick={copyCommand}
>
<FileCopy className={styles.icon} /> <FileCopy className={styles.icon} />
</IconButton> </IconButton>
</h3> </h3>

View File

@ -11,6 +11,6 @@ export const useStyles = makeStyles(theme => ({
envName: { envName: {
position: 'relative', position: 'relative',
top: '6px', top: '6px',
fontWeight: 'bold' fontWeight: 'bold',
}, },
})); }));

View File

@ -1,17 +1,35 @@
import { formatFullDateTimeWithLocale } from '../util'; import { formatFullDateTimeWithLocale } from '../util';
test.skip('formats dates correctly', () => { test.skip('formats dates correctly', () => {
expect(formatFullDateTimeWithLocale(1487861809466, 'nb-NO', 'UTC')).toEqual('2017-02-23 14:56:49'); expect(formatFullDateTimeWithLocale(1487861809466, 'nb-NO', 'UTC')).toEqual(
expect(formatFullDateTimeWithLocale(1487861809466, 'nb-NO', 'Europe/Paris')).toEqual('2017-02-23 15:56:49'); '2017-02-23 14:56:49'
expect(formatFullDateTimeWithLocale(1487861809466, 'nb-NO', 'Europe/Oslo')).toEqual('2017-02-23 15:56:49'); );
expect(formatFullDateTimeWithLocale(1487861809466, 'nb-NO', 'Europe/London')).toEqual('2017-02-23 14:56:49'); expect(
expect(formatFullDateTimeWithLocale(1487861809466, 'en-GB', 'Europe/Paris')).toEqual('02/23/2017, 3:56:49 PM'); formatFullDateTimeWithLocale(1487861809466, 'nb-NO', 'Europe/Paris')
expect(formatFullDateTimeWithLocale(1487861809466, 'en-GB', 'Europe/Oslo')).toEqual('02/23/2017, 3:56:49 PM'); ).toEqual('2017-02-23 15:56:49');
expect(formatFullDateTimeWithLocale(1487861809466, 'en-GB', 'Europe/London')).toEqual('02/23/2017, 2:56:49 PM'); expect(
formatFullDateTimeWithLocale(1487861809466, 'nb-NO', 'Europe/Oslo')
).toEqual('2017-02-23 15:56:49');
expect(
formatFullDateTimeWithLocale(1487861809466, 'nb-NO', 'Europe/London')
).toEqual('2017-02-23 14:56:49');
expect(
formatFullDateTimeWithLocale(1487861809466, 'en-GB', 'Europe/Paris')
).toEqual('02/23/2017, 3:56:49 PM');
expect(
formatFullDateTimeWithLocale(1487861809466, 'en-GB', 'Europe/Oslo')
).toEqual('02/23/2017, 3:56:49 PM');
expect(
formatFullDateTimeWithLocale(1487861809466, 'en-GB', 'Europe/London')
).toEqual('02/23/2017, 2:56:49 PM');
expect(formatFullDateTimeWithLocale(1487861809466, 'nb-NO')).toEqual( expect(formatFullDateTimeWithLocale(1487861809466, 'nb-NO')).toEqual(
expect.stringMatching(/(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})/) expect.stringMatching(/(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})/)
); );
expect(formatFullDateTimeWithLocale(1487861809466, 'en-GB')).toEqual(expect.stringContaining('02/23/2017')); expect(formatFullDateTimeWithLocale(1487861809466, 'en-GB')).toEqual(
expect(formatFullDateTimeWithLocale(1487861809466, 'en-US')).toEqual(expect.stringContaining('02/23/2017')); expect.stringContaining('02/23/2017')
);
expect(formatFullDateTimeWithLocale(1487861809466, 'en-US')).toEqual(
expect.stringContaining('02/23/2017')
);
}); });

View File

@ -46,7 +46,6 @@
} }
} }
.dataTableHeader { .dataTableHeader {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;

View File

@ -110,7 +110,7 @@ export const modalStyles = {
}, },
}; };
export const showPnpsFeedback = (feedbackList) => { export const showPnpsFeedback = feedbackList => {
if (!feedbackList) return; if (!feedbackList) return;
if (feedbackList.length > 0) { if (feedbackList.length > 0) {
const feedback = feedbackList.find( const feedback = feedbackList.find(
@ -135,4 +135,4 @@ export const showPnpsFeedback = (feedbackList) => {
return true; return true;
}; };
export const PNPS_FEEDBACK_ID = 'pnps' export const PNPS_FEEDBACK_ID = 'pnps';

View File

@ -10,8 +10,8 @@ export const useStyles = makeStyles(theme => ({
height: '100%', height: '100%',
}, },
input: { width: '100%', marginBottom: '1rem' }, input: { width: '100%', marginBottom: '1rem' },
inputHeader:{ inputHeader: {
marginBottom: '0.3rem' marginBottom: '0.3rem',
}, },
label: { label: {
minWidth: '300px', minWidth: '300px',
@ -22,7 +22,7 @@ export const useStyles = makeStyles(theme => ({
tagContainer: { tagContainer: {
display: 'flex', display: 'flex',
alignItems: 'flex-start', alignItems: 'flex-start',
marginBottom: '1rem' marginBottom: '1rem',
}, },
tagInput: { tagInput: {
width: '75%', width: '75%',
@ -30,7 +30,7 @@ export const useStyles = makeStyles(theme => ({
}, },
tagValue: { tagValue: {
marginRight: '3px', marginRight: '3px',
marginBottom: '1rem' marginBottom: '1rem',
}, },
buttonContainer: { buttonContainer: {
marginTop: 'auto', marginTop: 'auto',
@ -62,6 +62,6 @@ export const useStyles = makeStyles(theme => ({
switchContainer: { switchContainer: {
display: 'flex', display: 'flex',
alignItems: 'center', alignItems: 'center',
marginLeft: '-9px' marginLeft: '-9px',
}, },
})); }));

View File

@ -112,7 +112,7 @@ const ContextForm: React.FC<IContextForm> = ({
autoFocus autoFocus
/> />
<p className={styles.inputDescription}> <p className={styles.inputDescription}>
What is this context for? What is this context for?
</p> </p>
<TextField <TextField
className={styles.input} className={styles.input}

View File

@ -100,10 +100,7 @@ const CreateEnvironment = () => {
mode="Create" mode="Create"
clearErrors={clearErrors} clearErrors={clearErrors}
> >
<PermissionButton <PermissionButton permission={ADMIN} type="submit">
permission={ADMIN}
type="submit"
>
Create environment Create environment
</PermissionButton> </PermissionButton>
</EnvironmentForm> </EnvironmentForm>

View File

@ -85,10 +85,7 @@ const EditEnvironment = () => {
errors={errors} errors={errors}
clearErrors={clearErrors} clearErrors={clearErrors}
> >
<PermissionButton <PermissionButton permission={ADMIN} type="submit">
permission={ADMIN}
type="submit"
>
Edit environment Edit environment
</PermissionButton> </PermissionButton>
</EnvironmentForm> </EnvironmentForm>

View File

@ -1,10 +1,7 @@
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import useEnvironmentApi from '../../../hooks/api/actions/useEnvironmentApi/useEnvironmentApi'; import useEnvironmentApi from '../../../hooks/api/actions/useEnvironmentApi/useEnvironmentApi';
const useEnvironmentForm = ( const useEnvironmentForm = (initialName = '', initialType = 'development') => {
initialName = '',
initialType = 'development'
) => {
const NAME_EXISTS_ERROR = 'Error: Environment'; const NAME_EXISTS_ERROR = 'Error: Environment';
const [name, setName] = useState(initialName); const [name, setName] = useState(initialName);
const [type, setType] = useState(initialType); const [type, setType] = useState(initialType);

View File

@ -9,7 +9,6 @@
.content { .content {
padding: var(--card-padding); padding: var(--card-padding);
} }
.content form { .content form {
@ -25,4 +24,4 @@
.text { .text {
max-width: 400px; max-width: 400px;
} }

View File

@ -1,21 +1,27 @@
import { Tooltip } from '@material-ui/core'; import { Tooltip } from '@material-ui/core';
import { formatDateWithLocale, formatFullDateTimeWithLocale } from '../../../common/util'; import {
import { useLocationSettings } from "../../../../hooks/useLocationSettings"; formatDateWithLocale,
formatFullDateTimeWithLocale,
} from '../../../common/util';
import { useLocationSettings } from '../../../../hooks/useLocationSettings';
interface CreatedAtProps { interface CreatedAtProps {
time: Date; time: Date;
} }
const CreatedAt = ({time}: CreatedAtProps) => { const CreatedAt = ({ time }: CreatedAtProps) => {
const { locationSettings } = useLocationSettings(); const { locationSettings } = useLocationSettings();
return ( return (
<Tooltip title={`Created at ${formatFullDateTimeWithLocale(time, locationSettings.locale)}`}> <Tooltip
<span> title={`Created at ${formatFullDateTimeWithLocale(
{formatDateWithLocale(time, locationSettings.locale)} time,
</span> locationSettings.locale
)}`}
>
<span>{formatDateWithLocale(time, locationSettings.locale)}</span>
</Tooltip> </Tooltip>
); );
} };
export default CreatedAt; export default CreatedAt;

View File

@ -10,7 +10,7 @@ const FeatureLog = () => {
const { feature } = useFeature(projectId, featureId); const { feature } = useFeature(projectId, featureId);
if (!feature.name) { if (!feature.name) {
return null return null;
} }
return ( return (

View File

@ -1,7 +1,7 @@
import classNames from 'classnames'; import classNames from 'classnames';
import PercentageCircle from '../../../../common/PercentageCircle/PercentageCircle'; import PercentageCircle from '../../../../common/PercentageCircle/PercentageCircle';
import { useStyles } from './FeatureEnvironmentMetrics.styles'; import { useStyles } from './FeatureEnvironmentMetrics.styles';
import {FiberManualRecord} from '@material-ui/icons'; import { FiberManualRecord } from '@material-ui/icons';
import { useMediaQuery } from '@material-ui/core'; import { useMediaQuery } from '@material-ui/core';
import { IFeatureEnvironmentMetrics } from '../../../../../interfaces/featureToggle'; import { IFeatureEnvironmentMetrics } from '../../../../../interfaces/featureToggle';
import { parseISO } from 'date-fns'; import { parseISO } from 'date-fns';

View File

@ -11,5 +11,5 @@ export const useStyles = makeStyles(theme => ({
whiteSpace: 'nowrap', whiteSpace: 'nowrap',
overflow: 'hidden', overflow: 'hidden',
textOverflow: 'ellipsis', textOverflow: 'ellipsis',
} },
})); }));

View File

@ -12,24 +12,24 @@ const FeatureSeenApplications: React.FC = () => {
const styles = useStyles(); const styles = useStyles();
const seenApplications = (seenApps: string[]) => { const seenApplications = (seenApps: string[]) => {
return seenApps.map(appName => { return seenApps.map(appName => {
return (<Grid item md={4} xs={6} xl={3}> return (
<Link <Grid item md={4} xs={6} xl={3}>
to={`/applications/${appName}`} <Link
className={[ to={`/applications/${appName}`}
styles.listLink, className={[styles.listLink, styles.truncate].join(' ')}
styles.truncate >
].join(' ')} {appName}
> </Link>
{appName} </Grid>
</Link> );
</Grid>);
}); });
}; };
const noApplications = (<Grid item xs={12}> const noApplications = (
<div>{'Not seen in any applications'}</div> <Grid item xs={12}>
</Grid>); <div>{'Not seen in any applications'}</div>
</Grid>
);
return ( return (
<Grid container spacing={1}> <Grid container spacing={1}>
@ -37,7 +37,8 @@ const FeatureSeenApplications: React.FC = () => {
<ConditionallyRender <ConditionallyRender
condition={metrics?.seenApplications?.length > 0} condition={metrics?.seenApplications?.length > 0}
show={seenApplications(metrics.seenApplications)} show={seenApplications(metrics.seenApplications)}
elseShow={noApplications} /> elseShow={noApplications}
/>
</Grid> </Grid>
); );
}; };

View File

@ -21,12 +21,11 @@ const FeatureSettingsProject = () => {
const [dirty, setDirty] = useState(false); const [dirty, setDirty] = useState(false);
const [showConfirmDialog, setShowConfirmDialog] = useState(false); const [showConfirmDialog, setShowConfirmDialog] = useState(false);
const editable = hasAccess(MOVE_FEATURE_TOGGLE, projectId); const editable = hasAccess(MOVE_FEATURE_TOGGLE, projectId);
const { permissions = [] } = useAuthPermissions() const { permissions = [] } = useAuthPermissions();
const { changeFeatureProject } = useFeatureApi(); const { changeFeatureProject } = useFeatureApi();
const { setToastData, setToastApiError } = useToast(); const { setToastData, setToastApiError } = useToast();
const history = useHistory(); const history = useHistory();
useEffect(() => { useEffect(() => {
if (project !== feature.project) { if (project !== feature.project) {
setDirty(true); setDirty(true);

View File

@ -148,16 +148,9 @@ const FeatureStrategyAccordionBody: React.FC<
const { parameters } = strategy; const { parameters } = strategy;
const ON = uiConfig.flags[C]; const ON = uiConfig.flags[C];
const editable = hasAccess( const editable =
UPDATE_FEATURE_STRATEGY, hasAccess(UPDATE_FEATURE_STRATEGY, projectId, activeEnvironment.name) ||
projectId, hasAccess(CREATE_FEATURE_STRATEGY, projectId, activeEnvironment.name);
activeEnvironment.name
) ||
hasAccess(
CREATE_FEATURE_STRATEGY,
projectId,
activeEnvironment.name
);
return ( return (
<div className={styles.accordionContainer}> <div className={styles.accordionContainer}>

View File

@ -29,7 +29,7 @@ const FlexibleStrategy = ({
updateParameter, updateParameter,
parameters, parameters,
context, context,
editable=true editable = true,
}: IFlexibleStrategyProps) => { }: IFlexibleStrategyProps) => {
const onUpdate = const onUpdate =
(field: string) => (field: string) =>

View File

@ -3,14 +3,13 @@ import { Tooltip } from '@material-ui/core';
import { getFeatureTypeIcons } from '../../../../utils/get-feature-type-icons'; import { getFeatureTypeIcons } from '../../../../utils/get-feature-type-icons';
import useFeatureTypes from '../../../../hooks/api/getters/useFeatureTypes/useFeatureTypes'; import useFeatureTypes from '../../../../hooks/api/getters/useFeatureTypes/useFeatureTypes';
interface FeatureTypeProps { interface FeatureTypeProps {
type: string; type: string;
} }
const FeatureStatus = ({ type }: FeatureTypeProps) => { const FeatureStatus = ({ type }: FeatureTypeProps) => {
const styles = useStyles(); const styles = useStyles();
const { featureTypes } = useFeatureTypes() const { featureTypes } = useFeatureTypes();
const IconComponent = getFeatureTypeIcons(type); const IconComponent = getFeatureTypeIcons(type);
const typeName = featureTypes.filter(t => t.id === type).map(t => t.name); const typeName = featureTypes.filter(t => t.id === type).map(t => t.name);
@ -19,10 +18,7 @@ const FeatureStatus = ({ type }: FeatureTypeProps) => {
return ( return (
<Tooltip arrow placement="right" title={title}> <Tooltip arrow placement="right" title={title}>
<IconComponent <IconComponent data-loading className={styles.icon} />
data-loading
className={styles.icon}
/>
</Tooltip> </Tooltip>
); );
}; };

View File

@ -8,10 +8,10 @@ interface IUseDeleteVariantMarkupProps {
} }
const useDeleteVariantMarkup = ({ const useDeleteVariantMarkup = ({
show, show,
onClick, onClick,
onClose, onClose,
}: IUseDeleteVariantMarkupProps) => { }: IUseDeleteVariantMarkupProps) => {
return ( return (
<Dialogue <Dialogue
title="Are you sure you want to delete this variant?" title="Are you sure you want to delete this variant?"

View File

@ -45,6 +45,6 @@ export const useStyles = makeStyles(theme => ({
}, },
}, },
featureId: { featureId: {
wordBreak: 'break-all' wordBreak: 'break-all',
} },
})); }));

View File

@ -17,26 +17,34 @@ const EventCard = ({ entry, timeFormatted }) => {
<dd>{entry.type}</dd> <dd>{entry.type}</dd>
<dt className={styles.eventLogHeader}>Changed by: </dt> <dt className={styles.eventLogHeader}>Changed by: </dt>
<dd title={entry.createdBy}>{entry.createdBy}</dd> <dd title={entry.createdBy}>{entry.createdBy}</dd>
<ConditionallyRender condition={entry.project} show={ <ConditionallyRender
<> condition={entry.project}
<dt className={styles.eventLogHeader}>Project: </dt> show={
<dd>{entry.project}</dd> <>
</> <dt className={styles.eventLogHeader}>Project: </dt>
} /> <dd>{entry.project}</dd>
<ConditionallyRender condition={entry.featureName} show={ </>
<> }
<dt className={styles.eventLogHeader}>Feature: </dt> />
<dd>{entry.featureName}</dd> <ConditionallyRender
</> condition={entry.featureName}
} /> show={
<>
<dt className={styles.eventLogHeader}>Feature: </dt>
<dd>{entry.featureName}</dd>
</>
}
/>
</dl> </dl>
<ConditionallyRender condition={entry.data || entry.preData} show={ <ConditionallyRender
condition={entry.data || entry.preData}
show={
<> <>
<strong>Change</strong> <strong>Change</strong>
<EventDiff entry={entry} /> <EventDiff entry={entry} />
</> </>
} /> }
/>
</div> </div>
); );
}; };

View File

@ -20,7 +20,10 @@ const EventDiff = ({ entry }) => {
N: styles.positive, // added N: styles.positive, // added
}; };
const diffs = entry.data && entry.preData ? diff(entry.preData, entry.data) : undefined; const diffs =
entry.data && entry.preData
? diff(entry.preData, entry.data)
: undefined;
const buildItemDiff = (diff, key) => { const buildItemDiff = (diff, key) => {
let change; let change;

View File

@ -1,6 +1,6 @@
import EventLog from './EventLog'; import EventLog from './EventLog';
import { useEventSettings } from "../../../hooks/useEventSettings"; import { useEventSettings } from '../../../hooks/useEventSettings';
import { useLocationSettings } from "../../../hooks/useLocationSettings"; import { useLocationSettings } from '../../../hooks/useLocationSettings';
interface IEventLogContainerProps { interface IEventLogContainerProps {
title: string; title: string;

View File

@ -11,7 +11,12 @@ export const Footer = () => {
return ( return (
<footer className={styles.footer}> <footer className={styles.footer}>
<Grid container justifyContent="center" spacing={10} style={{marginBottom: 0}}> <Grid
container
justifyContent="center"
spacing={10}
style={{ marginBottom: 0 }}
>
<Grid item md={4} xs={12}> <Grid item md={4} xs={12}>
<ApiDetails uiConfig={uiConfig} /> <ApiDetails uiConfig={uiConfig} />
</Grid> </Grid>

View File

@ -27,7 +27,7 @@ export const useStyles = makeStyles(theme => ({
display: '-webkit-box', display: '-webkit-box',
boxOrient: 'vertical', boxOrient: 'vertical',
textOverflow: 'ellipsis', textOverflow: 'ellipsis',
overflow: 'hidden' overflow: 'hidden',
}, },
projectIcon: { projectIcon: {

View File

@ -9,7 +9,7 @@ export const useStyles = makeStyles(theme => ({
}, },
'&:hover': { '&:hover': {
backgroundColor: theme.palette.grey[200], backgroundColor: theme.palette.grey[200],
} },
}, },
deprecated: { deprecated: {
'& a': { '& a': {

View File

@ -74,10 +74,7 @@ const EditTagType = () => {
mode="Edit" mode="Edit"
clearErrors={clearErrors} clearErrors={clearErrors}
> >
<PermissionButton <PermissionButton permission={UPDATE_TAG_TYPE} type="submit">
permission={UPDATE_TAG_TYPE}
type="submit"
>
Edit type Edit type
</PermissionButton> </PermissionButton>
</TagForm> </TagForm>

View File

@ -41,7 +41,7 @@ const useTagTypeForm = (initialTagName = '', initialTagDesc = '') => {
} catch (err: unknown) { } catch (err: unknown) {
setErrors(prev => ({ setErrors(prev => ({
...prev, ...prev,
name: formatUnknownError(err) name: formatUnknownError(err),
})); }));
return false; return false;
} }

View File

@ -7,13 +7,15 @@ import KeyboardArrowDownIcon from '@material-ui/icons/KeyboardArrowDown';
import { useStyles } from './UserProfile.styles'; import { useStyles } from './UserProfile.styles';
import { useCommonStyles } from '../../../common.styles'; import { useCommonStyles } from '../../../common.styles';
import UserProfileContent from './UserProfileContent/UserProfileContent'; import UserProfileContent from './UserProfileContent/UserProfileContent';
import { IUser } from "../../../interfaces/user"; import { IUser } from '../../../interfaces/user';
import { ILocationSettings } from "../../../hooks/useLocationSettings"; import { ILocationSettings } from '../../../hooks/useLocationSettings';
interface IUserProfileProps { interface IUserProfileProps {
profile: IUser profile: IUser;
locationSettings: ILocationSettings locationSettings: ILocationSettings;
setLocationSettings: React.Dispatch<React.SetStateAction<ILocationSettings>> setLocationSettings: React.Dispatch<
React.SetStateAction<ILocationSettings>
>;
} }
const UserProfile = ({ const UserProfile = ({

View File

@ -98,14 +98,19 @@ const UserProfileContent = ({
condition={!editingProfile} condition={!editingProfile}
show={ show={
<> <>
<ConditionallyRender condition={!uiConfig.disablePasswordAuth} show={ <ConditionallyRender
<Button condition={!uiConfig.disablePasswordAuth}
variant="contained" show={
onClick={() => setEditingProfile(true)} <Button
> variant="contained"
Update password onClick={() =>
</Button> setEditingProfile(true)
} /> }
>
Update password
</Button>
}
/>
<div className={commonStyles.divider} /> <div className={commonStyles.divider} />
<div className={legacyStyles.showUserSettings}> <div className={legacyStyles.showUserSettings}>
<FormControl <FormControl

View File

@ -1 +1,2 @@
export const ENVIRONMENT_STRATEGY_ERROR = 'You can not enable the environment before it has strategies'; export const ENVIRONMENT_STRATEGY_ERROR =
'You can not enable the environment before it has strategies';

View File

@ -27,7 +27,10 @@ const useApiTokensApi = () => {
const createToken = async (newToken: IApiTokenCreate) => { const createToken = async (newToken: IApiTokenCreate) => {
const path = `api/admin/api-tokens`; const path = `api/admin/api-tokens`;
const req = createRequest(path, { method: 'POST', body: JSON.stringify(newToken) }); const req = createRequest(path, {
method: 'POST',
body: JSON.stringify(newToken),
});
try { try {
const res = await makeRequest(req.caller, req.id); const res = await makeRequest(req.caller, req.id);

View File

@ -7,12 +7,12 @@ export interface ISimpleAuthSettings {
export const handleBadRequest = async ( export const handleBadRequest = async (
setErrors?: Dispatch<SetStateAction<{}>>, setErrors?: Dispatch<SetStateAction<{}>>,
res?: Response, res?: Response
) => { ) => {
if (!setErrors) return; if (!setErrors) return;
if (res) { if (res) {
const data = await res.json(); const data = await res.json();
setErrors({message: data.message}); setErrors({ message: data.message });
throw new Error(data.message); throw new Error(data.message);
} }

View File

@ -74,7 +74,7 @@ const useContextsApi = () => {
updateContext, updateContext,
removeContext, removeContext,
errors, errors,
loading loading,
}; };
}; };

View File

@ -68,8 +68,8 @@ const useTagTypesApi = () => {
updateTagType, updateTagType,
deleteTagType, deleteTagType,
errors, errors,
loading loading,
}; };
}; };
export default useTagTypesApi; export default useTagTypesApi;

View File

@ -30,7 +30,12 @@ const useContext = (name: string, options: SWRConfiguration = {}) => {
}, [data, error]); }, [data, error]);
return { return {
context: data || { name: '', description: '', legalValues: [], stickiness: false }, context: data || {
name: '',
description: '',
legalValues: [],
stickiness: false,
},
error, error,
loading, loading,
refetch, refetch,
@ -38,4 +43,4 @@ const useContext = (name: string, options: SWRConfiguration = {}) => {
}; };
}; };
export default useContext; export default useContext;

View File

@ -6,5 +6,5 @@ export const defaultEnvironment: IEnvironment = {
createdAt: '', createdAt: '',
sortOrder: 0, sortOrder: 0,
enabled: false, enabled: false,
protected: false protected: false,
}; };

View File

@ -6,14 +6,9 @@ import { IEnvironment } from '../../../../interfaces/environments';
import handleErrorResponses from '../httpErrorResponseHandler'; import handleErrorResponses from '../httpErrorResponseHandler';
import { defaultEnvironment } from './defaultEnvironment'; import { defaultEnvironment } from './defaultEnvironment';
const useEnvironment = ( const useEnvironment = (id: string, options: SWRConfiguration = {}) => {
id: string,
options: SWRConfiguration = {}
) => {
const fetcher = async () => { const fetcher = async () => {
const path = formatApiPath( const path = formatApiPath(`api/admin/environments/${id}`);
`api/admin/environments/${id}`
);
return fetch(path, { return fetch(path, {
method: 'GET', method: 'GET',
}) })

View File

@ -6,7 +6,9 @@ export const getProjectFetcher = (id: string) => {
const path = formatApiPath(`api/admin/projects/${id}`); const path = formatApiPath(`api/admin/projects/${id}`);
return fetch(path, { return fetch(path, {
method: 'GET', method: 'GET',
}).then(handleErrorResponses('Project overview')).then(res => res.json()); })
.then(handleErrorResponses('Project overview'))
.then(res => res.json());
}; };
const KEY = `api/admin/projects/${id}`; const KEY = `api/admin/projects/${id}`;

View File

@ -38,4 +38,4 @@ const useTagType = (name: string, options: SWRConfiguration = {}) => {
}; };
}; };
export default useTagType; export default useTagType;

View File

@ -12,8 +12,12 @@ const useUserInfo = (id: string, options: SWRConfiguration = {}) => {
.then(handleErrorResponses('Users')) .then(handleErrorResponses('Users'))
.then(res => res.json()); .then(res => res.json());
}; };
const { data, error } = useSWR(`api/admin/user-admin/${id}`, fetcher, options); const { data, error } = useSWR(
`api/admin/user-admin/${id}`,
fetcher,
options
);
const [loading, setLoading] = useState(!error && !data); const [loading, setLoading] = useState(!error && !data);
const refetch = () => { const refetch = () => {

View File

@ -11,7 +11,7 @@ export interface IFeaturesFilter {
export interface IFeaturesSortOutput { export interface IFeaturesSortOutput {
filtered: IFeatureToggle[]; filtered: IFeatureToggle[];
filter: IFeaturesFilter; filter: IFeaturesFilter;
setFilter: React.Dispatch<React.SetStateAction<IFeaturesFilter>> setFilter: React.Dispatch<React.SetStateAction<IFeaturesFilter>>;
} }
// Store the features filter state globally, and in localStorage. // Store the features filter state globally, and in localStorage.

View File

@ -19,7 +19,7 @@ interface IFeaturesSort {
export interface IFeaturesSortOutput { export interface IFeaturesSortOutput {
sort: IFeaturesSort; sort: IFeaturesSort;
sorted: IFeatureToggle[]; sorted: IFeatureToggle[];
setSort: React.Dispatch<React.SetStateAction<IFeaturesSort>> setSort: React.Dispatch<React.SetStateAction<IFeaturesSort>>;
} }
export interface IFeaturesFilterSortOption { export interface IFeaturesFilterSortOption {

View File

@ -71,6 +71,6 @@ export interface IFeatureEnvironmentMetrics {
export interface IFeatureMetrics { export interface IFeatureMetrics {
version: number; version: number;
maturity: string; maturity: string;
lastHourUsage: IFeatureEnvironmentMetrics[], lastHourUsage: IFeatureEnvironmentMetrics[];
seenApplications: string[] seenApplications: string[];
} }

View File

@ -9,7 +9,7 @@ export interface IUiConfig {
versionInfo: IVersionInfo; versionInfo: IVersionInfo;
links: ILinks[]; links: ILinks[];
disablePasswordAuth?: boolean; disablePasswordAuth?: boolean;
toast?: IProclamationToast toast?: IProclamationToast;
} }
export interface IProclamationToast { export interface IProclamationToast {

View File

@ -2,26 +2,26 @@ const { createProxyMiddleware } = require('http-proxy-middleware');
const API_URL = process.env.UNLEASH_API || 'http://localhost:4242'; const API_URL = process.env.UNLEASH_API || 'http://localhost:4242';
module.exports = function(app) { module.exports = function (app) {
app.use( app.use(
'/api', '/api',
createProxyMiddleware({ createProxyMiddleware({
target: API_URL, target: API_URL,
changeOrigin: true, changeOrigin: true,
}), })
); );
app.use( app.use(
'/auth', '/auth',
createProxyMiddleware({ createProxyMiddleware({
target: API_URL, target: API_URL,
changeOrigin: true, changeOrigin: true,
}), })
); );
app.use( app.use(
'/logout', '/logout',
createProxyMiddleware({ createProxyMiddleware({
target: API_URL, target: API_URL,
changeOrigin: true, changeOrigin: true,
}), })
); );
}; };

View File

@ -1,3 +1,3 @@
import '@testing-library/jest-dom' import '@testing-library/jest-dom';
process.env.TZ = 'UTC'; process.env.TZ = 'UTC';