mirror of
https://github.com/Unleash/unleash.git
synced 2025-04-06 01:15:28 +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:
parent
46bf92124d
commit
016633dae9
4
frontend/.github/workflows/node.js.yml
vendored
4
frontend/.github/workflows/node.js.yml
vendored
@ -25,6 +25,4 @@ jobs:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- run: yarn
|
||||
- run: yarn run test
|
||||
|
||||
|
||||
|
||||
- run: yarn run fmt:check
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"singleQuote": true,
|
||||
"bracketSpacing": true,
|
||||
"jsxBracketSameLine": false,
|
||||
"bracketSameLine": false,
|
||||
"arrowParens": "avoid",
|
||||
"printWidth": 80
|
||||
}
|
||||
|
@ -32,6 +32,8 @@
|
||||
"start:demo": "UNLEASH_API=http://unleash.herokuapp.com yarn run start",
|
||||
"test": "react-scripts test",
|
||||
"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: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"
|
||||
|
@ -1,2 +1,2 @@
|
||||
export default 'SvgrURL'
|
||||
export const ReactComponent = 'div'
|
||||
export default 'SvgrURL';
|
||||
export const ReactComponent = 'div';
|
||||
|
@ -5,10 +5,10 @@ import ReportProblemOutlinedIcon from '@material-ui/icons/ReportProblemOutlined'
|
||||
import ConditionallyRender from '../../common/ConditionallyRender/ConditionallyRender';
|
||||
import styles from './ReportCard.module.scss';
|
||||
import ReactTimeAgo from 'react-timeago';
|
||||
import { IProjectHealthReport } from "../../../interfaces/project";
|
||||
import { IProjectHealthReport } from '../../../interfaces/project';
|
||||
|
||||
interface IReportCardProps {
|
||||
healthReport: IProjectHealthReport
|
||||
healthReport: IProjectHealthReport;
|
||||
}
|
||||
|
||||
export const ReportCard = ({ healthReport }: IReportCardProps) => {
|
||||
@ -37,7 +37,9 @@ export const ReportCard = ({ healthReport }: IReportCardProps) => {
|
||||
const renderPotentiallyStaleToggles = () => (
|
||||
<>
|
||||
<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}
|
||||
show={
|
||||
<div>
|
||||
<p className={healthClasses}>{healthReport.health}%</p>
|
||||
<p className={healthClasses}>
|
||||
{healthReport.health}%
|
||||
</p>
|
||||
<p className={styles.lastUpdate}>
|
||||
Last updated:{' '}
|
||||
<ReactTimeAgo
|
||||
@ -97,13 +101,17 @@ export const ReportCard = ({ healthReport }: IReportCardProps) => {
|
||||
<ul className={styles.reportCardList}>
|
||||
<li>
|
||||
<ConditionallyRender
|
||||
condition={Boolean(healthReport.potentiallyStaleCount)}
|
||||
condition={Boolean(
|
||||
healthReport.potentiallyStaleCount
|
||||
)}
|
||||
show={renderPotentiallyStaleToggles}
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
<ConditionallyRender
|
||||
condition={Boolean(healthReport.potentiallyStaleCount)}
|
||||
condition={Boolean(
|
||||
healthReport.potentiallyStaleCount
|
||||
)}
|
||||
show={
|
||||
<p className={styles.reportCardActionText}>
|
||||
Review your feature toggles and delete
|
||||
|
@ -18,35 +18,35 @@ export const useStyles = makeStyles(theme => ({
|
||||
marginBottom: '1rem',
|
||||
},
|
||||
center: {
|
||||
textAlign: 'center'
|
||||
textAlign: 'center',
|
||||
},
|
||||
actionsContainer: {
|
||||
textAlign: 'center',
|
||||
display: 'flex-inline',
|
||||
flexWrap: 'nowrap'
|
||||
flexWrap: 'nowrap',
|
||||
},
|
||||
infoBoxContainer:{
|
||||
marginBottom:40
|
||||
infoBoxContainer: {
|
||||
marginBottom: 40,
|
||||
},
|
||||
hideSM:{
|
||||
[theme.breakpoints.down('sm')]: {
|
||||
display: 'none'
|
||||
}
|
||||
hideSM: {
|
||||
[theme.breakpoints.down('sm')]: {
|
||||
display: 'none',
|
||||
},
|
||||
},
|
||||
hideMD:{
|
||||
[theme.breakpoints.down('md')]: {
|
||||
display: 'none'
|
||||
}
|
||||
hideMD: {
|
||||
[theme.breakpoints.down('md')]: {
|
||||
display: 'none',
|
||||
},
|
||||
},
|
||||
hideXS:{
|
||||
[theme.breakpoints.down('xs')]: {
|
||||
display: 'none'
|
||||
}
|
||||
hideXS: {
|
||||
[theme.breakpoints.down('xs')]: {
|
||||
display: 'none',
|
||||
},
|
||||
},
|
||||
token:{
|
||||
token: {
|
||||
textAlign: 'left',
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
display: 'none'
|
||||
}
|
||||
}
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
display: 'none',
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
@ -1,9 +1,10 @@
|
||||
import PropTypes from 'prop-types';
|
||||
function Secret({ value }) {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<span style={{ width: '250px', display: 'inline-block' }}>************************************</span>
|
||||
<span style={{ width: '250px', display: 'inline-block' }}>
|
||||
************************************
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ const useApiToken = (
|
||||
setType(initialtype);
|
||||
if (type === 'ADMIN') {
|
||||
setProject('*');
|
||||
setEnvironment('*')
|
||||
setEnvironment('*');
|
||||
}
|
||||
//eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [initialtype]);
|
||||
@ -35,11 +35,11 @@ const useApiToken = (
|
||||
|
||||
const setTokenType = (value: string) => {
|
||||
if (value === 'ADMIN') {
|
||||
setType(value)
|
||||
setType(value);
|
||||
setProject('*');
|
||||
setEnvironment('*');
|
||||
} else {
|
||||
setType(value)
|
||||
setType(value);
|
||||
setEnvironment(initialEnvironment);
|
||||
}
|
||||
};
|
||||
|
@ -9,10 +9,7 @@ const ApiPage = () => {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ConditionallyRender
|
||||
condition={isAdmin}
|
||||
show={<AdminMenu />}
|
||||
/>
|
||||
<ConditionallyRender condition={isAdmin} show={<AdminMenu />} />
|
||||
<ApiTokenList />
|
||||
</div>
|
||||
);
|
||||
|
@ -7,4 +7,3 @@ export const useStyles = makeStyles(theme => ({
|
||||
position: 'relative',
|
||||
},
|
||||
}));
|
||||
|
||||
|
@ -97,10 +97,7 @@ const CreateUser = () => {
|
||||
setRootRole={setRootRole}
|
||||
clearErrors={clearErrors}
|
||||
>
|
||||
<PermissionButton
|
||||
permission={ADMIN}
|
||||
type="submit"
|
||||
>
|
||||
<PermissionButton permission={ADMIN} type="submit">
|
||||
Create user
|
||||
</PermissionButton>
|
||||
</UserForm>
|
||||
|
@ -35,11 +35,7 @@ const EditUser = () => {
|
||||
validateName,
|
||||
errors,
|
||||
clearErrors,
|
||||
} = useAddUserForm(
|
||||
user?.name,
|
||||
user?.email,
|
||||
user?.rootRole
|
||||
);
|
||||
} = useAddUserForm(user?.name, user?.email, user?.rootRole);
|
||||
|
||||
const formatApiCode = () => {
|
||||
return `curl --location --request PUT '${
|
||||
@ -98,10 +94,7 @@ const EditUser = () => {
|
||||
clearErrors={clearErrors}
|
||||
mode={EDIT}
|
||||
>
|
||||
<PermissionButton
|
||||
permission={ADMIN}
|
||||
type="submit"
|
||||
>
|
||||
<PermissionButton permission={ADMIN} type="submit">
|
||||
Edit user
|
||||
</PermissionButton>
|
||||
</UserForm>
|
||||
|
@ -6,7 +6,7 @@ export const useStyles = makeStyles(theme => ({
|
||||
backgroundColor: theme.palette.grey[200],
|
||||
},
|
||||
},
|
||||
leftTableCell:{
|
||||
textAlign: 'left'
|
||||
}
|
||||
leftTableCell: {
|
||||
textAlign: 'left',
|
||||
},
|
||||
}));
|
||||
|
@ -14,7 +14,7 @@ import AccessContext from '../../../../../contexts/AccessContext';
|
||||
import { IUser } from '../../../../../interfaces/user';
|
||||
import { useStyles } from './UserListItem.styles';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { ILocationSettings } from "../../../../../hooks/useLocationSettings";
|
||||
import { ILocationSettings } from '../../../../../hooks/useLocationSettings';
|
||||
|
||||
interface IUserListItemProps {
|
||||
user: IUser;
|
||||
@ -34,7 +34,7 @@ const UserListItem = ({
|
||||
locationSettings,
|
||||
}: IUserListItemProps) => {
|
||||
const { hasAccess } = useContext(AccessContext);
|
||||
const history = useHistory()
|
||||
const history = useHistory();
|
||||
const styles = useStyles();
|
||||
|
||||
return (
|
||||
@ -51,7 +51,10 @@ const UserListItem = ({
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<span data-loading>
|
||||
{formatDateWithLocale(user.createdAt, locationSettings.locale)}
|
||||
{formatDateWithLocale(
|
||||
user.createdAt,
|
||||
locationSettings.locale
|
||||
)}
|
||||
</span>
|
||||
</TableCell>
|
||||
<TableCell className={styles.leftTableCell}>
|
||||
@ -77,7 +80,9 @@ const UserListItem = ({
|
||||
data-loading
|
||||
aria-label="Edit"
|
||||
title="Edit"
|
||||
onClick={()=> history.push(`/admin/users/${user.id}/edit`)}
|
||||
onClick={() =>
|
||||
history.push(`/admin/users/${user.id}/edit`)
|
||||
}
|
||||
>
|
||||
<Edit />
|
||||
</IconButton>
|
||||
|
@ -23,7 +23,7 @@ import PaginateUI from '../../../common/PaginateUI/PaginateUI';
|
||||
import { IUser } from '../../../../interfaces/user';
|
||||
import IRole from '../../../../interfaces/role';
|
||||
import useToast from '../../../../hooks/useToast';
|
||||
import { useLocationSettings } from "../../../../hooks/useLocationSettings";
|
||||
import { useLocationSettings } from '../../../../hooks/useLocationSettings';
|
||||
|
||||
const UsersList = () => {
|
||||
const { users, roles, refetch, loading } = useUsers();
|
||||
@ -36,7 +36,7 @@ const UsersList = () => {
|
||||
userApiErrors,
|
||||
} = useAdminUsersApi();
|
||||
const { hasAccess } = useContext(AccessContext);
|
||||
const { locationSettings } = useLocationSettings()
|
||||
const { locationSettings } = useLocationSettings();
|
||||
const [pwDialog, setPwDialog] = useState<{ open: boolean; user?: IUser }>({
|
||||
open: false,
|
||||
});
|
||||
|
@ -26,9 +26,8 @@ const BreadcrumbNav = () => {
|
||||
item !== 'strategies' &&
|
||||
item !== 'features' &&
|
||||
item !== 'features2' &&
|
||||
item !== 'create-toggle'&&
|
||||
item !== 'create-toggle' &&
|
||||
item !== 'settings'
|
||||
|
||||
);
|
||||
|
||||
return (
|
||||
@ -52,7 +51,10 @@ const BreadcrumbNav = () => {
|
||||
styles.breadcrumbNavParagraph
|
||||
}
|
||||
>
|
||||
<StringTruncator text={path} maxWidth="200" />
|
||||
<StringTruncator
|
||||
text={path}
|
||||
maxWidth="200"
|
||||
/>
|
||||
</p>
|
||||
);
|
||||
}
|
||||
@ -73,7 +75,10 @@ const BreadcrumbNav = () => {
|
||||
className={styles.breadcrumbLink}
|
||||
to={link}
|
||||
>
|
||||
<StringTruncator text={path} maxWidth="200" />
|
||||
<StringTruncator
|
||||
text={path}
|
||||
maxWidth="200"
|
||||
/>
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
|
@ -71,9 +71,7 @@ const FormTemplate: React.FC<ICreateProps> = ({
|
||||
<>
|
||||
<h3 className={styles.subtitle}>
|
||||
API Command{' '}
|
||||
<IconButton
|
||||
onClick={copyCommand}
|
||||
>
|
||||
<IconButton onClick={copyCommand}>
|
||||
<FileCopy className={styles.icon} />
|
||||
</IconButton>
|
||||
</h3>
|
||||
|
@ -11,6 +11,6 @@ export const useStyles = makeStyles(theme => ({
|
||||
envName: {
|
||||
position: 'relative',
|
||||
top: '6px',
|
||||
fontWeight: 'bold'
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
}));
|
||||
|
@ -1,17 +1,35 @@
|
||||
import { formatFullDateTimeWithLocale } from '../util';
|
||||
|
||||
test.skip('formats dates correctly', () => {
|
||||
expect(formatFullDateTimeWithLocale(1487861809466, 'nb-NO', 'UTC')).toEqual('2017-02-23 14:56:49');
|
||||
expect(formatFullDateTimeWithLocale(1487861809466, 'nb-NO', 'Europe/Paris')).toEqual('2017-02-23 15: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(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', 'UTC')).toEqual(
|
||||
'2017-02-23 14:56:49'
|
||||
);
|
||||
expect(
|
||||
formatFullDateTimeWithLocale(1487861809466, 'nb-NO', 'Europe/Paris')
|
||||
).toEqual('2017-02-23 15: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(
|
||||
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.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-US')).toEqual(expect.stringContaining('02/23/2017'));
|
||||
expect(formatFullDateTimeWithLocale(1487861809466, 'en-GB')).toEqual(
|
||||
expect.stringContaining('02/23/2017')
|
||||
);
|
||||
expect(formatFullDateTimeWithLocale(1487861809466, 'en-US')).toEqual(
|
||||
expect.stringContaining('02/23/2017')
|
||||
);
|
||||
});
|
||||
|
@ -46,7 +46,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.dataTableHeader {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
@ -110,7 +110,7 @@ export const modalStyles = {
|
||||
},
|
||||
};
|
||||
|
||||
export const showPnpsFeedback = (feedbackList) => {
|
||||
export const showPnpsFeedback = feedbackList => {
|
||||
if (!feedbackList) return;
|
||||
if (feedbackList.length > 0) {
|
||||
const feedback = feedbackList.find(
|
||||
@ -135,4 +135,4 @@ export const showPnpsFeedback = (feedbackList) => {
|
||||
return true;
|
||||
};
|
||||
|
||||
export const PNPS_FEEDBACK_ID = 'pnps'
|
||||
export const PNPS_FEEDBACK_ID = 'pnps';
|
||||
|
@ -10,8 +10,8 @@ export const useStyles = makeStyles(theme => ({
|
||||
height: '100%',
|
||||
},
|
||||
input: { width: '100%', marginBottom: '1rem' },
|
||||
inputHeader:{
|
||||
marginBottom: '0.3rem'
|
||||
inputHeader: {
|
||||
marginBottom: '0.3rem',
|
||||
},
|
||||
label: {
|
||||
minWidth: '300px',
|
||||
@ -22,7 +22,7 @@ export const useStyles = makeStyles(theme => ({
|
||||
tagContainer: {
|
||||
display: 'flex',
|
||||
alignItems: 'flex-start',
|
||||
marginBottom: '1rem'
|
||||
marginBottom: '1rem',
|
||||
},
|
||||
tagInput: {
|
||||
width: '75%',
|
||||
@ -30,7 +30,7 @@ export const useStyles = makeStyles(theme => ({
|
||||
},
|
||||
tagValue: {
|
||||
marginRight: '3px',
|
||||
marginBottom: '1rem'
|
||||
marginBottom: '1rem',
|
||||
},
|
||||
buttonContainer: {
|
||||
marginTop: 'auto',
|
||||
@ -62,6 +62,6 @@ export const useStyles = makeStyles(theme => ({
|
||||
switchContainer: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
marginLeft: '-9px'
|
||||
marginLeft: '-9px',
|
||||
},
|
||||
}));
|
||||
|
@ -112,7 +112,7 @@ const ContextForm: React.FC<IContextForm> = ({
|
||||
autoFocus
|
||||
/>
|
||||
<p className={styles.inputDescription}>
|
||||
What is this context for?
|
||||
What is this context for?
|
||||
</p>
|
||||
<TextField
|
||||
className={styles.input}
|
||||
|
@ -100,10 +100,7 @@ const CreateEnvironment = () => {
|
||||
mode="Create"
|
||||
clearErrors={clearErrors}
|
||||
>
|
||||
<PermissionButton
|
||||
permission={ADMIN}
|
||||
type="submit"
|
||||
>
|
||||
<PermissionButton permission={ADMIN} type="submit">
|
||||
Create environment
|
||||
</PermissionButton>
|
||||
</EnvironmentForm>
|
||||
|
@ -85,10 +85,7 @@ const EditEnvironment = () => {
|
||||
errors={errors}
|
||||
clearErrors={clearErrors}
|
||||
>
|
||||
<PermissionButton
|
||||
permission={ADMIN}
|
||||
type="submit"
|
||||
>
|
||||
<PermissionButton permission={ADMIN} type="submit">
|
||||
Edit environment
|
||||
</PermissionButton>
|
||||
</EnvironmentForm>
|
||||
|
@ -1,10 +1,7 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import useEnvironmentApi from '../../../hooks/api/actions/useEnvironmentApi/useEnvironmentApi';
|
||||
|
||||
const useEnvironmentForm = (
|
||||
initialName = '',
|
||||
initialType = 'development'
|
||||
) => {
|
||||
const useEnvironmentForm = (initialName = '', initialType = 'development') => {
|
||||
const NAME_EXISTS_ERROR = 'Error: Environment';
|
||||
const [name, setName] = useState(initialName);
|
||||
const [type, setType] = useState(initialType);
|
||||
|
@ -9,7 +9,6 @@
|
||||
|
||||
.content {
|
||||
padding: var(--card-padding);
|
||||
|
||||
}
|
||||
|
||||
.content form {
|
||||
@ -25,4 +24,4 @@
|
||||
|
||||
.text {
|
||||
max-width: 400px;
|
||||
}
|
||||
}
|
||||
|
@ -1,21 +1,27 @@
|
||||
import { Tooltip } from '@material-ui/core';
|
||||
import { formatDateWithLocale, formatFullDateTimeWithLocale } from '../../../common/util';
|
||||
import { useLocationSettings } from "../../../../hooks/useLocationSettings";
|
||||
import {
|
||||
formatDateWithLocale,
|
||||
formatFullDateTimeWithLocale,
|
||||
} from '../../../common/util';
|
||||
import { useLocationSettings } from '../../../../hooks/useLocationSettings';
|
||||
|
||||
interface CreatedAtProps {
|
||||
time: Date;
|
||||
}
|
||||
|
||||
const CreatedAt = ({time}: CreatedAtProps) => {
|
||||
const CreatedAt = ({ time }: CreatedAtProps) => {
|
||||
const { locationSettings } = useLocationSettings();
|
||||
|
||||
return (
|
||||
<Tooltip title={`Created at ${formatFullDateTimeWithLocale(time, locationSettings.locale)}`}>
|
||||
<span>
|
||||
{formatDateWithLocale(time, locationSettings.locale)}
|
||||
</span>
|
||||
<Tooltip
|
||||
title={`Created at ${formatFullDateTimeWithLocale(
|
||||
time,
|
||||
locationSettings.locale
|
||||
)}`}
|
||||
>
|
||||
<span>{formatDateWithLocale(time, locationSettings.locale)}</span>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default CreatedAt;
|
||||
|
@ -10,7 +10,7 @@ const FeatureLog = () => {
|
||||
const { feature } = useFeature(projectId, featureId);
|
||||
|
||||
if (!feature.name) {
|
||||
return null
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -1,7 +1,7 @@
|
||||
import classNames from 'classnames';
|
||||
import PercentageCircle from '../../../../common/PercentageCircle/PercentageCircle';
|
||||
import { useStyles } from './FeatureEnvironmentMetrics.styles';
|
||||
import {FiberManualRecord} from '@material-ui/icons';
|
||||
import { FiberManualRecord } from '@material-ui/icons';
|
||||
import { useMediaQuery } from '@material-ui/core';
|
||||
import { IFeatureEnvironmentMetrics } from '../../../../../interfaces/featureToggle';
|
||||
import { parseISO } from 'date-fns';
|
||||
|
@ -11,5 +11,5 @@ export const useStyles = makeStyles(theme => ({
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
}
|
||||
},
|
||||
}));
|
||||
|
@ -12,24 +12,24 @@ const FeatureSeenApplications: React.FC = () => {
|
||||
const styles = useStyles();
|
||||
const seenApplications = (seenApps: string[]) => {
|
||||
return seenApps.map(appName => {
|
||||
return (<Grid item md={4} xs={6} xl={3}>
|
||||
<Link
|
||||
to={`/applications/${appName}`}
|
||||
className={[
|
||||
styles.listLink,
|
||||
styles.truncate
|
||||
].join(' ')}
|
||||
>
|
||||
{appName}
|
||||
</Link>
|
||||
</Grid>);
|
||||
return (
|
||||
<Grid item md={4} xs={6} xl={3}>
|
||||
<Link
|
||||
to={`/applications/${appName}`}
|
||||
className={[styles.listLink, styles.truncate].join(' ')}
|
||||
>
|
||||
{appName}
|
||||
</Link>
|
||||
</Grid>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
const noApplications = (<Grid item xs={12}>
|
||||
<div>{'Not seen in any applications'}</div>
|
||||
</Grid>);
|
||||
|
||||
const noApplications = (
|
||||
<Grid item xs={12}>
|
||||
<div>{'Not seen in any applications'}</div>
|
||||
</Grid>
|
||||
);
|
||||
|
||||
return (
|
||||
<Grid container spacing={1}>
|
||||
@ -37,7 +37,8 @@ const FeatureSeenApplications: React.FC = () => {
|
||||
<ConditionallyRender
|
||||
condition={metrics?.seenApplications?.length > 0}
|
||||
show={seenApplications(metrics.seenApplications)}
|
||||
elseShow={noApplications} />
|
||||
elseShow={noApplications}
|
||||
/>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
@ -21,12 +21,11 @@ const FeatureSettingsProject = () => {
|
||||
const [dirty, setDirty] = useState(false);
|
||||
const [showConfirmDialog, setShowConfirmDialog] = useState(false);
|
||||
const editable = hasAccess(MOVE_FEATURE_TOGGLE, projectId);
|
||||
const { permissions = [] } = useAuthPermissions()
|
||||
const { permissions = [] } = useAuthPermissions();
|
||||
const { changeFeatureProject } = useFeatureApi();
|
||||
const { setToastData, setToastApiError } = useToast();
|
||||
const history = useHistory();
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (project !== feature.project) {
|
||||
setDirty(true);
|
||||
|
@ -148,16 +148,9 @@ const FeatureStrategyAccordionBody: React.FC<
|
||||
const { parameters } = strategy;
|
||||
const ON = uiConfig.flags[C];
|
||||
|
||||
const editable = hasAccess(
|
||||
UPDATE_FEATURE_STRATEGY,
|
||||
projectId,
|
||||
activeEnvironment.name
|
||||
) ||
|
||||
hasAccess(
|
||||
CREATE_FEATURE_STRATEGY,
|
||||
projectId,
|
||||
activeEnvironment.name
|
||||
);
|
||||
const editable =
|
||||
hasAccess(UPDATE_FEATURE_STRATEGY, projectId, activeEnvironment.name) ||
|
||||
hasAccess(CREATE_FEATURE_STRATEGY, projectId, activeEnvironment.name);
|
||||
|
||||
return (
|
||||
<div className={styles.accordionContainer}>
|
||||
|
@ -29,7 +29,7 @@ const FlexibleStrategy = ({
|
||||
updateParameter,
|
||||
parameters,
|
||||
context,
|
||||
editable=true
|
||||
editable = true,
|
||||
}: IFlexibleStrategyProps) => {
|
||||
const onUpdate =
|
||||
(field: string) =>
|
||||
|
@ -3,14 +3,13 @@ import { Tooltip } from '@material-ui/core';
|
||||
import { getFeatureTypeIcons } from '../../../../utils/get-feature-type-icons';
|
||||
import useFeatureTypes from '../../../../hooks/api/getters/useFeatureTypes/useFeatureTypes';
|
||||
|
||||
|
||||
interface FeatureTypeProps {
|
||||
type: string;
|
||||
}
|
||||
|
||||
const FeatureStatus = ({ type }: FeatureTypeProps) => {
|
||||
const styles = useStyles();
|
||||
const { featureTypes } = useFeatureTypes()
|
||||
const { featureTypes } = useFeatureTypes();
|
||||
const IconComponent = getFeatureTypeIcons(type);
|
||||
|
||||
const typeName = featureTypes.filter(t => t.id === type).map(t => t.name);
|
||||
@ -19,10 +18,7 @@ const FeatureStatus = ({ type }: FeatureTypeProps) => {
|
||||
|
||||
return (
|
||||
<Tooltip arrow placement="right" title={title}>
|
||||
<IconComponent
|
||||
data-loading
|
||||
className={styles.icon}
|
||||
/>
|
||||
<IconComponent data-loading className={styles.icon} />
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
@ -8,10 +8,10 @@ interface IUseDeleteVariantMarkupProps {
|
||||
}
|
||||
|
||||
const useDeleteVariantMarkup = ({
|
||||
show,
|
||||
onClick,
|
||||
onClose,
|
||||
}: IUseDeleteVariantMarkupProps) => {
|
||||
show,
|
||||
onClick,
|
||||
onClose,
|
||||
}: IUseDeleteVariantMarkupProps) => {
|
||||
return (
|
||||
<Dialogue
|
||||
title="Are you sure you want to delete this variant?"
|
||||
|
@ -45,6 +45,6 @@ export const useStyles = makeStyles(theme => ({
|
||||
},
|
||||
},
|
||||
featureId: {
|
||||
wordBreak: 'break-all'
|
||||
}
|
||||
wordBreak: 'break-all',
|
||||
},
|
||||
}));
|
||||
|
@ -17,26 +17,34 @@ const EventCard = ({ entry, timeFormatted }) => {
|
||||
<dd>{entry.type}</dd>
|
||||
<dt className={styles.eventLogHeader}>Changed by: </dt>
|
||||
<dd title={entry.createdBy}>{entry.createdBy}</dd>
|
||||
<ConditionallyRender condition={entry.project} show={
|
||||
<>
|
||||
<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.project}
|
||||
show={
|
||||
<>
|
||||
<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>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
</dl>
|
||||
<ConditionallyRender condition={entry.data || entry.preData} show={
|
||||
<ConditionallyRender
|
||||
condition={entry.data || entry.preData}
|
||||
show={
|
||||
<>
|
||||
<strong>Change</strong>
|
||||
<EventDiff entry={entry} />
|
||||
</>
|
||||
} />
|
||||
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -20,7 +20,10 @@ const EventDiff = ({ entry }) => {
|
||||
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) => {
|
||||
let change;
|
||||
|
@ -1,6 +1,6 @@
|
||||
import EventLog from './EventLog';
|
||||
import { useEventSettings } from "../../../hooks/useEventSettings";
|
||||
import { useLocationSettings } from "../../../hooks/useLocationSettings";
|
||||
import { useEventSettings } from '../../../hooks/useEventSettings';
|
||||
import { useLocationSettings } from '../../../hooks/useLocationSettings';
|
||||
|
||||
interface IEventLogContainerProps {
|
||||
title: string;
|
||||
|
@ -11,7 +11,12 @@ export const Footer = () => {
|
||||
|
||||
return (
|
||||
<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}>
|
||||
<ApiDetails uiConfig={uiConfig} />
|
||||
</Grid>
|
||||
|
@ -27,7 +27,7 @@ export const useStyles = makeStyles(theme => ({
|
||||
display: '-webkit-box',
|
||||
boxOrient: 'vertical',
|
||||
textOverflow: 'ellipsis',
|
||||
overflow: 'hidden'
|
||||
overflow: 'hidden',
|
||||
},
|
||||
|
||||
projectIcon: {
|
||||
|
@ -9,7 +9,7 @@ export const useStyles = makeStyles(theme => ({
|
||||
},
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.grey[200],
|
||||
}
|
||||
},
|
||||
},
|
||||
deprecated: {
|
||||
'& a': {
|
||||
|
@ -74,10 +74,7 @@ const EditTagType = () => {
|
||||
mode="Edit"
|
||||
clearErrors={clearErrors}
|
||||
>
|
||||
<PermissionButton
|
||||
permission={UPDATE_TAG_TYPE}
|
||||
type="submit"
|
||||
>
|
||||
<PermissionButton permission={UPDATE_TAG_TYPE} type="submit">
|
||||
Edit type
|
||||
</PermissionButton>
|
||||
</TagForm>
|
||||
|
@ -41,7 +41,7 @@ const useTagTypeForm = (initialTagName = '', initialTagDesc = '') => {
|
||||
} catch (err: unknown) {
|
||||
setErrors(prev => ({
|
||||
...prev,
|
||||
name: formatUnknownError(err)
|
||||
name: formatUnknownError(err),
|
||||
}));
|
||||
return false;
|
||||
}
|
||||
|
@ -7,13 +7,15 @@ import KeyboardArrowDownIcon from '@material-ui/icons/KeyboardArrowDown';
|
||||
import { useStyles } from './UserProfile.styles';
|
||||
import { useCommonStyles } from '../../../common.styles';
|
||||
import UserProfileContent from './UserProfileContent/UserProfileContent';
|
||||
import { IUser } from "../../../interfaces/user";
|
||||
import { ILocationSettings } from "../../../hooks/useLocationSettings";
|
||||
import { IUser } from '../../../interfaces/user';
|
||||
import { ILocationSettings } from '../../../hooks/useLocationSettings';
|
||||
|
||||
interface IUserProfileProps {
|
||||
profile: IUser
|
||||
locationSettings: ILocationSettings
|
||||
setLocationSettings: React.Dispatch<React.SetStateAction<ILocationSettings>>
|
||||
profile: IUser;
|
||||
locationSettings: ILocationSettings;
|
||||
setLocationSettings: React.Dispatch<
|
||||
React.SetStateAction<ILocationSettings>
|
||||
>;
|
||||
}
|
||||
|
||||
const UserProfile = ({
|
||||
|
@ -98,14 +98,19 @@ const UserProfileContent = ({
|
||||
condition={!editingProfile}
|
||||
show={
|
||||
<>
|
||||
<ConditionallyRender condition={!uiConfig.disablePasswordAuth} show={
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={() => setEditingProfile(true)}
|
||||
>
|
||||
Update password
|
||||
</Button>
|
||||
} />
|
||||
<ConditionallyRender
|
||||
condition={!uiConfig.disablePasswordAuth}
|
||||
show={
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={() =>
|
||||
setEditingProfile(true)
|
||||
}
|
||||
>
|
||||
Update password
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
<div className={commonStyles.divider} />
|
||||
<div className={legacyStyles.showUserSettings}>
|
||||
<FormControl
|
||||
|
@ -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';
|
||||
|
@ -27,7 +27,10 @@ const useApiTokensApi = () => {
|
||||
|
||||
const createToken = async (newToken: IApiTokenCreate) => {
|
||||
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 {
|
||||
const res = await makeRequest(req.caller, req.id);
|
||||
|
@ -7,12 +7,12 @@ export interface ISimpleAuthSettings {
|
||||
|
||||
export const handleBadRequest = async (
|
||||
setErrors?: Dispatch<SetStateAction<{}>>,
|
||||
res?: Response,
|
||||
res?: Response
|
||||
) => {
|
||||
if (!setErrors) return;
|
||||
if (res) {
|
||||
const data = await res.json();
|
||||
setErrors({message: data.message});
|
||||
setErrors({ message: data.message });
|
||||
throw new Error(data.message);
|
||||
}
|
||||
|
||||
|
@ -74,7 +74,7 @@ const useContextsApi = () => {
|
||||
updateContext,
|
||||
removeContext,
|
||||
errors,
|
||||
loading
|
||||
loading,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -68,8 +68,8 @@ const useTagTypesApi = () => {
|
||||
updateTagType,
|
||||
deleteTagType,
|
||||
errors,
|
||||
loading
|
||||
loading,
|
||||
};
|
||||
};
|
||||
|
||||
export default useTagTypesApi;
|
||||
export default useTagTypesApi;
|
||||
|
@ -30,7 +30,12 @@ const useContext = (name: string, options: SWRConfiguration = {}) => {
|
||||
}, [data, error]);
|
||||
|
||||
return {
|
||||
context: data || { name: '', description: '', legalValues: [], stickiness: false },
|
||||
context: data || {
|
||||
name: '',
|
||||
description: '',
|
||||
legalValues: [],
|
||||
stickiness: false,
|
||||
},
|
||||
error,
|
||||
loading,
|
||||
refetch,
|
||||
@ -38,4 +43,4 @@ const useContext = (name: string, options: SWRConfiguration = {}) => {
|
||||
};
|
||||
};
|
||||
|
||||
export default useContext;
|
||||
export default useContext;
|
||||
|
@ -6,5 +6,5 @@ export const defaultEnvironment: IEnvironment = {
|
||||
createdAt: '',
|
||||
sortOrder: 0,
|
||||
enabled: false,
|
||||
protected: false
|
||||
};
|
||||
protected: false,
|
||||
};
|
||||
|
@ -6,14 +6,9 @@ import { IEnvironment } from '../../../../interfaces/environments';
|
||||
import handleErrorResponses from '../httpErrorResponseHandler';
|
||||
import { defaultEnvironment } from './defaultEnvironment';
|
||||
|
||||
const useEnvironment = (
|
||||
id: string,
|
||||
options: SWRConfiguration = {}
|
||||
) => {
|
||||
const useEnvironment = (id: string, options: SWRConfiguration = {}) => {
|
||||
const fetcher = async () => {
|
||||
const path = formatApiPath(
|
||||
`api/admin/environments/${id}`
|
||||
);
|
||||
const path = formatApiPath(`api/admin/environments/${id}`);
|
||||
return fetch(path, {
|
||||
method: 'GET',
|
||||
})
|
||||
|
@ -6,7 +6,9 @@ export const getProjectFetcher = (id: string) => {
|
||||
const path = formatApiPath(`api/admin/projects/${id}`);
|
||||
return fetch(path, {
|
||||
method: 'GET',
|
||||
}).then(handleErrorResponses('Project overview')).then(res => res.json());
|
||||
})
|
||||
.then(handleErrorResponses('Project overview'))
|
||||
.then(res => res.json());
|
||||
};
|
||||
|
||||
const KEY = `api/admin/projects/${id}`;
|
||||
|
@ -38,4 +38,4 @@ const useTagType = (name: string, options: SWRConfiguration = {}) => {
|
||||
};
|
||||
};
|
||||
|
||||
export default useTagType;
|
||||
export default useTagType;
|
||||
|
@ -12,8 +12,12 @@ const useUserInfo = (id: string, options: SWRConfiguration = {}) => {
|
||||
.then(handleErrorResponses('Users'))
|
||||
.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 refetch = () => {
|
||||
|
@ -11,7 +11,7 @@ export interface IFeaturesFilter {
|
||||
export interface IFeaturesSortOutput {
|
||||
filtered: IFeatureToggle[];
|
||||
filter: IFeaturesFilter;
|
||||
setFilter: React.Dispatch<React.SetStateAction<IFeaturesFilter>>
|
||||
setFilter: React.Dispatch<React.SetStateAction<IFeaturesFilter>>;
|
||||
}
|
||||
|
||||
// Store the features filter state globally, and in localStorage.
|
||||
|
@ -19,7 +19,7 @@ interface IFeaturesSort {
|
||||
export interface IFeaturesSortOutput {
|
||||
sort: IFeaturesSort;
|
||||
sorted: IFeatureToggle[];
|
||||
setSort: React.Dispatch<React.SetStateAction<IFeaturesSort>>
|
||||
setSort: React.Dispatch<React.SetStateAction<IFeaturesSort>>;
|
||||
}
|
||||
|
||||
export interface IFeaturesFilterSortOption {
|
||||
|
@ -71,6 +71,6 @@ export interface IFeatureEnvironmentMetrics {
|
||||
export interface IFeatureMetrics {
|
||||
version: number;
|
||||
maturity: string;
|
||||
lastHourUsage: IFeatureEnvironmentMetrics[],
|
||||
seenApplications: string[]
|
||||
lastHourUsage: IFeatureEnvironmentMetrics[];
|
||||
seenApplications: string[];
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ export interface IUiConfig {
|
||||
versionInfo: IVersionInfo;
|
||||
links: ILinks[];
|
||||
disablePasswordAuth?: boolean;
|
||||
toast?: IProclamationToast
|
||||
toast?: IProclamationToast;
|
||||
}
|
||||
|
||||
export interface IProclamationToast {
|
||||
|
@ -2,26 +2,26 @@ const { createProxyMiddleware } = require('http-proxy-middleware');
|
||||
|
||||
const API_URL = process.env.UNLEASH_API || 'http://localhost:4242';
|
||||
|
||||
module.exports = function(app) {
|
||||
app.use(
|
||||
'/api',
|
||||
createProxyMiddleware({
|
||||
target: API_URL,
|
||||
changeOrigin: true,
|
||||
}),
|
||||
);
|
||||
app.use(
|
||||
'/auth',
|
||||
createProxyMiddleware({
|
||||
target: API_URL,
|
||||
changeOrigin: true,
|
||||
}),
|
||||
);
|
||||
app.use(
|
||||
'/logout',
|
||||
createProxyMiddleware({
|
||||
target: API_URL,
|
||||
changeOrigin: true,
|
||||
}),
|
||||
);
|
||||
};
|
||||
module.exports = function (app) {
|
||||
app.use(
|
||||
'/api',
|
||||
createProxyMiddleware({
|
||||
target: API_URL,
|
||||
changeOrigin: true,
|
||||
})
|
||||
);
|
||||
app.use(
|
||||
'/auth',
|
||||
createProxyMiddleware({
|
||||
target: API_URL,
|
||||
changeOrigin: true,
|
||||
})
|
||||
);
|
||||
app.use(
|
||||
'/logout',
|
||||
createProxyMiddleware({
|
||||
target: API_URL,
|
||||
changeOrigin: true,
|
||||
})
|
||||
);
|
||||
};
|
||||
|
@ -1,3 +1,3 @@
|
||||
import '@testing-library/jest-dom'
|
||||
import '@testing-library/jest-dom';
|
||||
|
||||
process.env.TZ = 'UTC';
|
||||
|
Loading…
Reference in New Issue
Block a user