1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-11-10 01:19:53 +01:00

refactor: fix misc TS errors (#729)

* refactor: update test deps

* refactor: remove unused ts-expect-error annotations

* refactor: add missing arg and return types

* refactor: the loading prop is optional

* refactor: add missing arg and return types

* reafactor: fix value arg type

* refactor: fix missing array type

* refactor: the parameters field is an array

* refactor: use undefined instead of null in state

* refactor: add missing params type

* refactor: add missing children prop

* refactor: add missing array type

* refactor: add missing React imports

* refactor: use correct IProjectEnvironment type

* refactor: type errors as unknown

* refactor: the index prop is required

* refactor: fix date prop type

* refactor: fix tooltip placement prop type

* refactor: fix environments state type

* refactor: add missing arg types

* refactor: add guard for undefined field

* refactor: fix ChangePassword prop types

* refactor: fix MUI import paths

* refactor: add missing arg type

* refactor: fix showDialog prop type

* refactor: remove unused openUpdateDialog prop

* refactor: add missing non-null assertion

* refactor: remove unused types prop

* refactor: stricten API error handler types

* refactor: add missing undefined check

* refactor: add missing IProject id field

* refactor: fix ConditionallyRender condition prop types

* refactor: remove unused args

* refactor: add AddVariant prop types

* refactor: add types to UIContext

* refactor: fix event arg type

* refactor: add missing default impressionData field

* refactor: fix handleDeleteEnvironment prop args

* refactor: fix IFeatureMetrics field requirements

* refactor: add missing element types to ConditionallyRender

* refactor: remove unused ProjectAccess projectId prop

* refactor: add missing undefined check

* refactor: fix getCreateTogglePath arg type

* refactor: add missing IStrategyPayload import

* refactor: remove unused user arg

* refactor: add missing event arg type

* refactor: add missing style object types

* refactor: improve userApiErrors prop type

* refactor: the Dialogue onClose prop is optional

* refactor: fix the AddonEvents setEventValue prop type
This commit is contained in:
olav 2022-02-25 10:55:39 +01:00 committed by GitHub
parent a4dab966a3
commit 3959e846e8
118 changed files with 595 additions and 466 deletions

View File

@ -42,6 +42,7 @@
"@material-ui/core": "4.12.3", "@material-ui/core": "4.12.3",
"@material-ui/icons": "4.11.2", "@material-ui/icons": "4.11.2",
"@material-ui/lab": "4.0.0-alpha.60", "@material-ui/lab": "4.0.0-alpha.60",
"@testing-library/dom": "^8.11.3",
"@testing-library/jest-dom": "5.16.2", "@testing-library/jest-dom": "5.16.2",
"@testing-library/react": "12.1.3", "@testing-library/react": "12.1.3",
"@testing-library/user-event": "13.5.0", "@testing-library/user-event": "13.5.0",
@ -49,7 +50,7 @@
"@types/deep-diff": "1.0.1", "@types/deep-diff": "1.0.1",
"@types/jest": "27.4.1", "@types/jest": "27.4.1",
"@types/lodash.clonedeep": "4.5.6", "@types/lodash.clonedeep": "4.5.6",
"@types/node": "14.18.12", "@types/node": "17.0.18",
"@types/react": "17.0.39", "@types/react": "17.0.39",
"@types/react-dom": "17.0.11", "@types/react-dom": "17.0.11",
"@types/react-outside-click-handler": "1.3.1", "@types/react-outside-click-handler": "1.3.1",
@ -63,7 +64,7 @@
"copy-to-clipboard": "3.3.1", "copy-to-clipboard": "3.3.1",
"craco": "0.0.3", "craco": "0.0.3",
"css-loader": "6.6.0", "css-loader": "6.6.0",
"cypress": "8.7.0", "cypress": "9.5.0",
"date-fns": "2.28.0", "date-fns": "2.28.0",
"debounce": "1.2.1", "debounce": "1.2.1",
"deep-diff": "1.0.2", "deep-diff": "1.0.2",
@ -82,7 +83,7 @@
"react-outside-click-handler": "1.3.0", "react-outside-click-handler": "1.3.0",
"react-router-dom": "5.3.0", "react-router-dom": "5.3.0",
"react-scripts": "4.0.3", "react-scripts": "4.0.3",
"react-test-renderer": "16.14.0", "react-test-renderer": "17.0.2",
"react-timeago": "6.2.1", "react-timeago": "6.2.1",
"sass": "1.49.8", "sass": "1.49.8",
"swr": "1.2.2", "swr": "1.2.2",

View File

@ -7,7 +7,9 @@ import { IAddonProvider } from '../../../../interfaces/addons';
interface IAddonProps { interface IAddonProps {
provider: IAddonProvider; provider: IAddonProvider;
checkedEvents: string[]; checkedEvents: string[];
setEventValue: (name: string) => void; setEventValue: (
name: string
) => (event: React.ChangeEvent<HTMLInputElement>) => void;
error: Record<string, string>; error: Record<string, string>;
} }

View File

@ -1,4 +1,4 @@
import { ReactElement } from 'react'; import React, { ReactElement } from 'react';
import { ConfiguredAddons } from './ConfiguredAddons/ConfiguredAddons'; import { ConfiguredAddons } from './ConfiguredAddons/ConfiguredAddons';
import { AvailableAddons } from './AvailableAddons/AvailableAddons'; import { AvailableAddons } from './AvailableAddons/AvailableAddons';
import { Avatar } from '@material-ui/core'; import { Avatar } from '@material-ui/core';
@ -12,7 +12,7 @@ import dataDogIcon from '../../../assets/icons/datadog.svg';
import { formatAssetPath } from '../../../utils/format-path'; import { formatAssetPath } from '../../../utils/format-path';
import useAddons from '../../../hooks/api/getters/useAddons/useAddons'; import useAddons from '../../../hooks/api/getters/useAddons/useAddons';
const style = { const style: React.CSSProperties = {
width: '40px', width: '40px',
height: '40px', height: '40px',
marginRight: '16px', marginRight: '16px',

View File

@ -21,6 +21,7 @@ import AccessContext from '../../../../contexts/AccessContext';
import { IAddon } from '../../../../interfaces/addons'; import { IAddon } from '../../../../interfaces/addons';
import PermissionIconButton from '../../../common/PermissionIconButton/PermissionIconButton'; import PermissionIconButton from '../../../common/PermissionIconButton/PermissionIconButton';
import Dialogue from '../../../common/Dialogue'; import Dialogue from '../../../common/Dialogue';
import { formatUnknownError } from '../../../../utils/format-unknown-error';
interface IConfigureAddonsProps { interface IConfigureAddonsProps {
getAddonIcon: (name: string) => ReactElement; getAddonIcon: (name: string) => ReactElement;
@ -59,8 +60,8 @@ export const ConfiguredAddons = ({ getAddonIcon }: IConfigureAddonsProps) => {
title: 'Success', title: 'Success',
text: 'Addon state switched successfully', text: 'Addon state switched successfully',
}); });
} catch (e: any) { } catch (error: unknown) {
setToastApiError(e.toString()); setToastApiError(formatUnknownError(error));
} }
}; };

View File

@ -10,6 +10,7 @@ import { ADMIN } from '../../../providers/AccessProvider/permissions';
import { ConfirmToken } from '../ConfirmToken/ConfirmToken'; import { ConfirmToken } from '../ConfirmToken/ConfirmToken';
import { useState } from 'react'; import { useState } from 'react';
import { scrollToTop } from '../../../common/util'; import { scrollToTop } from '../../../common/util';
import { formatUnknownError } from '../../../../utils/format-unknown-error';
export const CreateApiToken = () => { export const CreateApiToken = () => {
const { setToastApiError } = useToast(); const { setToastApiError } = useToast();
@ -49,8 +50,8 @@ export const CreateApiToken = () => {
setToken(api.secret); setToken(api.secret);
setShowConfirm(true); setShowConfirm(true);
}); });
} catch (e: any) { } catch (error: unknown) {
setToastApiError(e.toString()); setToastApiError(formatUnknownError(error));
} }
}; };

View File

@ -68,8 +68,8 @@ export const GoogleAuth = () => {
title: 'Settings stored', title: 'Settings stored',
type: 'success', type: 'success',
}); });
} catch (err) { } catch (error: unknown) {
setToastApiError(formatUnknownError(err)); setToastApiError(formatUnknownError(error));
} }
}; };

View File

@ -79,8 +79,8 @@ export const OidcAuth = () => {
title: 'Settings stored', title: 'Settings stored',
type: 'success', type: 'success',
}); });
} catch (err) { } catch (error: unknown) {
setToastApiError(formatUnknownError(err)); setToastApiError(formatUnknownError(error));
} }
}; };

View File

@ -51,8 +51,8 @@ export const PasswordAuth = () => {
type: 'success', type: 'success',
show: true, show: true,
}); });
} catch (err) { } catch (error: unknown) {
setToastApiError(formatUnknownError(err)); setToastApiError(formatUnknownError(error));
setDisablePasswordAuth(config.disabled); setDisablePasswordAuth(config.disabled);
} }
}; };

View File

@ -75,8 +75,8 @@ export const SamlAuth = () => {
title: 'Settings stored', title: 'Settings stored',
type: 'success', type: 'success',
}); });
} catch (err) { } catch (error: unknown) {
setToastApiError(formatUnknownError(err)); setToastApiError(formatUnknownError(error));
} }
}; };

View File

@ -7,6 +7,7 @@ import useUiConfig from '../../../../hooks/api/getters/useUiConfig/useUiConfig';
import useToast from '../../../../hooks/useToast'; import useToast from '../../../../hooks/useToast';
import PermissionButton from '../../../common/PermissionButton/PermissionButton'; import PermissionButton from '../../../common/PermissionButton/PermissionButton';
import { ADMIN } from '../../../providers/AccessProvider/permissions'; import { ADMIN } from '../../../providers/AccessProvider/permissions';
import { formatUnknownError } from '../../../../utils/format-unknown-error';
const CreateProjectRole = () => { const CreateProjectRole = () => {
const { setToastData, setToastApiError } = useToast(); const { setToastData, setToastApiError } = useToast();
@ -49,8 +50,8 @@ const CreateProjectRole = () => {
confetti: true, confetti: true,
type: 'success', type: 'success',
}); });
} catch (e: any) { } catch (error: unknown) {
setToastApiError(e.toString()); setToastApiError(formatUnknownError(error));
} }
} }
}; };

View File

@ -13,6 +13,7 @@ import useUiConfig from '../../../../hooks/api/getters/useUiConfig/useUiConfig';
import useToast from '../../../../hooks/useToast'; import useToast from '../../../../hooks/useToast';
import PermissionButton from '../../../common/PermissionButton/PermissionButton'; import PermissionButton from '../../../common/PermissionButton/PermissionButton';
import { ADMIN } from '../../../providers/AccessProvider/permissions'; import { ADMIN } from '../../../providers/AccessProvider/permissions';
import { formatUnknownError } from '../../../../utils/format-unknown-error';
const EditProjectRole = () => { const EditProjectRole = () => {
const { uiConfig } = useUiConfig(); const { uiConfig } = useUiConfig();
@ -88,8 +89,8 @@ const EditProjectRole = () => {
text: 'Your role changes will automatically be applied to the users with this role.', text: 'Your role changes will automatically be applied to the users with this role.',
confetti: true, confetti: true,
}); });
} catch (e: any) { } catch (error: unknown) {
setToastApiError(e.toString()); setToastApiError(formatUnknownError(error));
} }
} }
}; };

View File

@ -1,16 +1,16 @@
import Input from '../../../common/Input/Input'; import Input from '../../../common/Input/Input';
import EnvironmentPermissionAccordion from './EnvironmentPermissionAccordion/EnvironmentPermissionAccordion'; import EnvironmentPermissionAccordion from './EnvironmentPermissionAccordion/EnvironmentPermissionAccordion';
import { import {
Button,
Checkbox, Checkbox,
FormControlLabel, FormControlLabel,
TextField, TextField,
Button,
} from '@material-ui/core'; } from '@material-ui/core';
import useProjectRolePermissions from '../../../../hooks/api/getters/useProjectRolePermissions/useProjectRolePermissions'; import useProjectRolePermissions from '../../../../hooks/api/getters/useProjectRolePermissions/useProjectRolePermissions';
import { useStyles } from './ProjectRoleForm.styles'; import { useStyles } from './ProjectRoleForm.styles';
import ConditionallyRender from '../../../common/ConditionallyRender'; import ConditionallyRender from '../../../common/ConditionallyRender';
import React from 'react'; import React, { ReactNode } from 'react';
import { IPermission } from '../../../../interfaces/project'; import { IPermission } from '../../../../interfaces/project';
import { import {
ICheckedPermission, ICheckedPermission,
@ -33,6 +33,7 @@ interface IProjectRoleForm {
clearErrors: () => void; clearErrors: () => void;
validateNameUniqueness?: () => void; validateNameUniqueness?: () => void;
getRoleKey: (permission: { id: number; environment?: string }) => string; getRoleKey: (permission: { id: number; environment?: string }) => string;
children: ReactNode;
} }
const ProjectRoleForm: React.FC<IProjectRoleForm> = ({ const ProjectRoleForm: React.FC<IProjectRoleForm> = ({

View File

@ -1,4 +1,4 @@
import { makeStyles } from '@material-ui/styles'; import { makeStyles } from '@material-ui/core/styles';
export const useStyles = makeStyles(theme => ({ export const useStyles = makeStyles(theme => ({
deleteParagraph: { deleteParagraph: {

View File

@ -16,6 +16,7 @@ import IRole, { IProjectRole } from '../../../../../interfaces/role';
import useProjectRolesApi from '../../../../../hooks/api/actions/useProjectRolesApi/useProjectRolesApi'; import useProjectRolesApi from '../../../../../hooks/api/actions/useProjectRolesApi/useProjectRolesApi';
import useToast from '../../../../../hooks/useToast'; import useToast from '../../../../../hooks/useToast';
import ProjectRoleDeleteConfirm from '../ProjectRoleDeleteConfirm/ProjectRoleDeleteConfirm'; import ProjectRoleDeleteConfirm from '../ProjectRoleDeleteConfirm/ProjectRoleDeleteConfirm';
import { formatUnknownError } from '../../../../../utils/format-unknown-error';
const ROOTROLE = 'root'; const ROOTROLE = 'root';
@ -44,8 +45,8 @@ const ProjectRoleList = () => {
title: 'Successfully deleted role', title: 'Successfully deleted role',
text: 'Your role is now deleted', text: 'Your role is now deleted',
}); });
} catch (e) { } catch (error: unknown) {
setToastApiError(e.toString()); setToastApiError(formatUnknownError(error));
} }
setDelDialog(false); setDelDialog(false);
setConfirmName(''); setConfirmName('');

View File

@ -1,11 +1,12 @@
import { useStyles } from './ProjectRoleListItem.styles'; import { useStyles } from './ProjectRoleListItem.styles';
import { TableRow, TableCell, Typography } from '@material-ui/core'; import { TableCell, TableRow, Typography } from '@material-ui/core';
import { Edit, Delete } from '@material-ui/icons'; import { Delete, Edit } from '@material-ui/icons';
import { ADMIN } from '../../../../../providers/AccessProvider/permissions'; import { ADMIN } from '../../../../../providers/AccessProvider/permissions';
import SupervisedUserCircleIcon from '@material-ui/icons/SupervisedUserCircle'; import SupervisedUserCircleIcon from '@material-ui/icons/SupervisedUserCircle';
import PermissionIconButton from '../../../../../common/PermissionIconButton/PermissionIconButton'; import PermissionIconButton from '../../../../../common/PermissionIconButton/PermissionIconButton';
import { IProjectRole } from '../../../../../../interfaces/role'; import { IProjectRole } from '../../../../../../interfaces/role';
import { useHistory } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
import React from 'react';
interface IRoleListItemProps { interface IRoleListItemProps {
id: number; id: number;

View File

@ -1,4 +1,4 @@
import { makeStyles } from '@material-ui/styles'; import { makeStyles } from '@material-ui/core/styles';
export const useStyles = makeStyles(theme => ({ export const useStyles = makeStyles(theme => ({
rolesListBody: { rolesListBody: {

View File

@ -1,4 +1,4 @@
import { makeStyles } from '@material-ui/styles'; import { makeStyles } from '@material-ui/core/styles';
export const useStyles = makeStyles({ export const useStyles = makeStyles({
iconContainer: { iconContainer: {

View File

@ -10,6 +10,7 @@ import { useState } from 'react';
import { scrollToTop } from '../../../common/util'; import { scrollToTop } from '../../../common/util';
import PermissionButton from '../../../common/PermissionButton/PermissionButton'; import PermissionButton from '../../../common/PermissionButton/PermissionButton';
import { ADMIN } from '../../../providers/AccessProvider/permissions'; import { ADMIN } from '../../../providers/AccessProvider/permissions';
import { formatUnknownError } from '../../../../utils/format-unknown-error';
const CreateUser = () => { const CreateUser = () => {
const { setToastApiError } = useToast(); const { setToastApiError } = useToast();
@ -51,8 +52,8 @@ const CreateUser = () => {
setInviteLink(user.inviteLink); setInviteLink(user.inviteLink);
setShowConfirm(true); setShowConfirm(true);
}); });
} catch (e: any) { } catch (error: unknown) {
setToastApiError(e.toString()); setToastApiError(formatUnknownError(error));
} }
} }
}; };

View File

@ -11,6 +11,7 @@ import { useEffect } from 'react';
import PermissionButton from '../../../common/PermissionButton/PermissionButton'; import PermissionButton from '../../../common/PermissionButton/PermissionButton';
import { ADMIN } from '../../../providers/AccessProvider/permissions'; import { ADMIN } from '../../../providers/AccessProvider/permissions';
import { EDIT } from '../../../../constants/misc'; import { EDIT } from '../../../../constants/misc';
import { formatUnknownError } from '../../../../utils/format-unknown-error';
const EditUser = () => { const EditUser = () => {
useEffect(() => { useEffect(() => {
@ -60,8 +61,8 @@ const EditUser = () => {
title: 'User information updated', title: 'User information updated',
type: 'success', type: 'success',
}); });
} catch (e: any) { } catch (error: unknown) {
setToastApiError(e.toString()); setToastApiError(formatUnknownError(error));
} }
} }
}; };

View File

@ -1,4 +1,4 @@
import { makeStyles } from '@material-ui/styles'; import { makeStyles } from '@material-ui/core/styles';
export const useStyles = makeStyles(theme => ({ export const useStyles = makeStyles(theme => ({
userListBody: { userListBody: {

View File

@ -1,6 +1,6 @@
import { useState } from 'react'; import { useState } from 'react';
import classnames from 'classnames'; import classnames from 'classnames';
import { TextField, Typography, Avatar } from '@material-ui/core'; import { Avatar, TextField, Typography } 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';
@ -12,10 +12,10 @@ import { Alert } from '@material-ui/lab';
import { IUser } from '../../../../../interfaces/user'; import { IUser } from '../../../../../interfaces/user';
interface IChangePasswordProps { interface IChangePasswordProps {
showDialog: () => void; showDialog: boolean;
closeDialog: () => void; closeDialog: () => void;
changePassword: () => void; changePassword: (user: IUser, password: string) => Promise<Response>;
user: IUser; user: Partial<IUser>;
} }
const ChangePassword = ({ const ChangePassword = ({
@ -25,7 +25,7 @@ const ChangePassword = ({
user = {}, user = {},
}: IChangePasswordProps) => { }: IChangePasswordProps) => {
const [data, setData] = useState({}); const [data, setData] = useState({});
const [error, setError] = useState({}); const [error, setError] = useState<Record<string, string>>({});
const [validPassword, setValidPassword] = useState(false); const [validPassword, setValidPassword] = useState(false);
const commonStyles = useCommonStyles(); const commonStyles = useCommonStyles();
@ -88,7 +88,7 @@ const ChangePassword = ({
)} )}
> >
<ConditionallyRender <ConditionallyRender
condition={error.general} condition={Boolean(error.general)}
show={<Alert severity="error">{error.general}</Alert>} show={<Alert severity="error">{error.general}</Alert>}
/> />
<Typography variant="subtitle1"> <Typography variant="subtitle1">

View File

@ -9,12 +9,12 @@ import { useCommonStyles } from '../../../../../common.styles';
import { IUser } from '../../../../../interfaces/user'; import { IUser } from '../../../../../interfaces/user';
interface IDeleteUserProps { interface IDeleteUserProps {
showDialog: () => void; showDialog: boolean;
closeDialog: () => void; closeDialog: () => void;
user: IUser; user: IUser;
userLoading: boolean; userLoading: boolean;
removeUser: () => void; removeUser: () => void;
userApiErrors: Object; userApiErrors: Record<string, string>;
} }
const DeleteUser = ({ const DeleteUser = ({
@ -33,13 +33,13 @@ const DeleteUser = ({
open={showDialog} open={showDialog}
title="Really delete user?" title="Really delete user?"
onClose={closeDialog} onClose={closeDialog}
onClick={() => removeUser(user)} onClick={removeUser}
primaryButtonText="Delete user" primaryButtonText="Delete user"
secondaryButtonText="Cancel" secondaryButtonText="Cancel"
> >
<div ref={ref}> <div ref={ref}>
<ConditionallyRender <ConditionallyRender
condition={userApiErrors[REMOVE_USER_ERROR]} condition={Boolean(userApiErrors[REMOVE_USER_ERROR])}
show={ show={
<Alert <Alert
data-loading data-loading

View File

@ -19,7 +19,6 @@ import { formatDateYMD } from '../../../../../utils/format-date';
interface IUserListItemProps { interface IUserListItemProps {
user: IUser; user: IUser;
renderRole: (roleId: number) => string; renderRole: (roleId: number) => string;
openUpdateDialog: (user: IUser) => (e: SyntheticEvent) => void;
openPwDialog: (user: IUser) => (e: SyntheticEvent) => void; openPwDialog: (user: IUser) => (e: SyntheticEvent) => void;
openDelDialog: (user: IUser) => (e: SyntheticEvent) => void; openDelDialog: (user: IUser) => (e: SyntheticEvent) => void;
locationSettings: ILocationSettings; locationSettings: ILocationSettings;
@ -30,7 +29,6 @@ const UserListItem = ({
renderRole, renderRole,
openDelDialog, openDelDialog,
openPwDialog, openPwDialog,
openUpdateDialog,
locationSettings, locationSettings,
}: IUserListItemProps) => { }: IUserListItemProps) => {
const { hasAccess } = useContext(AccessContext); const { hasAccess } = useContext(AccessContext);

View File

@ -24,6 +24,7 @@ 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';
import { formatUnknownError } from '../../../../utils/format-unknown-error';
const UsersList = () => { const UsersList = () => {
const { users, roles, refetch, loading } = useUsers(); const { users, roles, refetch, loading } = useUsers();
@ -79,8 +80,8 @@ const UsersList = () => {
}); });
refetch(); refetch();
closeDelDialog(); closeDelDialog();
} catch (e: any) { } catch (error: unknown) {
setToastApiError(e.toString()); setToastApiError(formatUnknownError(error));
} }
}; };
@ -172,7 +173,7 @@ const UsersList = () => {
<DeleteUser <DeleteUser
showDialog={delDialog} showDialog={delDialog}
closeDialog={closeDelDialog} closeDialog={closeDelDialog}
user={delUser} user={delUser!}
removeUser={onDeleteUser} removeUser={onDeleteUser}
userLoading={userLoading} userLoading={userLoading}
userApiErrors={userApiErrors} userApiErrors={userApiErrors}

View File

@ -1,11 +1,11 @@
/* eslint react/no-multi-comp:off */ /* eslint react/no-multi-comp:off */
import { useContext, useState } from 'react'; import React, { useContext, useState } from 'react';
import { import {
Avatar, Avatar,
Link,
Icon, Icon,
IconButton, IconButton,
LinearProgress, LinearProgress,
Link,
Typography, Typography,
} from '@material-ui/core'; } from '@material-ui/core';
import { Link as LinkIcon } from '@material-ui/icons'; import { Link as LinkIcon } from '@material-ui/icons';
@ -25,6 +25,7 @@ import { useLocationSettings } from '../../../hooks/useLocationSettings';
import useToast from '../../../hooks/useToast'; import useToast from '../../../hooks/useToast';
import PermissionButton from '../../common/PermissionButton/PermissionButton'; import PermissionButton from '../../common/PermissionButton/PermissionButton';
import { formatDateYMD } from '../../../utils/format-date'; import { formatDateYMD } from '../../../utils/format-date';
import { formatUnknownError } from '../../../utils/format-unknown-error';
export const ApplicationEdit = () => { export const ApplicationEdit = () => {
const history = useHistory(); const history = useHistory();
@ -44,7 +45,7 @@ export const ApplicationEdit = () => {
const formatDate = (v: string) => formatDateYMD(v, locationSettings.locale); const formatDate = (v: string) => formatDateYMD(v, locationSettings.locale);
const onDeleteApplication = async (evt: Event) => { const onDeleteApplication = async (evt: React.SyntheticEvent) => {
evt.preventDefault(); evt.preventDefault();
try { try {
await deleteApplication(appName); await deleteApplication(appName);
@ -54,8 +55,8 @@ export const ApplicationEdit = () => {
type: 'success', type: 'success',
}); });
history.push('/applications'); history.push('/applications');
} catch (e: any) { } catch (error: unknown) {
setToastApiError(e.toString()); setToastApiError(formatUnknownError(error));
} }
}; };

View File

@ -1,5 +1,5 @@
import { ChangeEvent, useState } from 'react'; import { ChangeEvent, useState } from 'react';
import { TextField, Grid } from '@material-ui/core'; import { Grid, TextField } from '@material-ui/core';
import { useCommonStyles } from '../../../common.styles'; import { useCommonStyles } from '../../../common.styles';
import icons from '../icon-names'; import icons from '../icon-names';
import GeneralSelect from '../../common/GeneralSelect/GeneralSelect'; import GeneralSelect from '../../common/GeneralSelect/GeneralSelect';
@ -7,6 +7,7 @@ import useApplicationsApi from '../../../hooks/api/actions/useApplicationsApi/us
import useToast from '../../../hooks/useToast'; import useToast from '../../../hooks/useToast';
import { IApplication } from '../../../interfaces/application'; import { IApplication } from '../../../interfaces/application';
import useApplication from '../../../hooks/api/getters/useApplication/useApplication'; import useApplication from '../../../hooks/api/getters/useApplication/useApplication';
import { formatUnknownError } from '../../../utils/format-unknown-error';
interface IApplicationUpdateProps { interface IApplicationUpdateProps {
application: IApplication; application: IApplication;
@ -35,8 +36,8 @@ export const ApplicationUpdate = ({ application }: IApplicationUpdateProps) => {
title: 'Updated Successfully', title: 'Updated Successfully',
text: `${field} successfully updated`, text: `${field} successfully updated`,
}); });
} catch (e: any) { } catch (error: unknown) {
setToastApiError(e.toString()); setToastApiError(formatUnknownError(error));
} }
}; };

View File

@ -4,16 +4,16 @@ import {
Grid, Grid,
List, List,
ListItem, ListItem,
ListItemText,
ListItemAvatar, ListItemAvatar,
ListItemText,
Typography, Typography,
} from '@material-ui/core'; } from '@material-ui/core';
import { import {
Report,
Extension, Extension,
Timeline,
FlagRounded, FlagRounded,
Report,
SvgIconComponent, SvgIconComponent,
Timeline,
} from '@material-ui/icons'; } from '@material-ui/icons';
import { import {
CREATE_FEATURE, CREATE_FEATURE,
@ -117,10 +117,9 @@ export const ApplicationView = () => {
createUrl: `/projects/default/create-toggle?name=${name}`, createUrl: `/projects/default/create-toggle?name=${name}`,
name, name,
permission: CREATE_FEATURE, permission: CREATE_FEATURE,
i,
})} })}
elseShow={foundListItem({ elseShow={foundListItem({
viewUrl: getTogglePath(project, name, true), viewUrl: getTogglePath(project, name),
name, name,
description, description,
Icon: FlagRounded, Icon: FlagRounded,

View File

@ -1,4 +1,4 @@
import { useEffect, useState, useRef, FC } from 'react'; import React, { useEffect, useState, useRef, FC } from 'react';
import ConditionallyRender from '../ConditionallyRender'; import ConditionallyRender from '../ConditionallyRender';
interface IAnimateOnMountProps { interface IAnimateOnMountProps {
@ -7,7 +7,7 @@ interface IAnimateOnMountProps {
start: string; start: string;
leave: string; leave: string;
container?: string; container?: string;
style?: Object; style?: React.CSSProperties;
} }
const AnimateOnMount: FC<IAnimateOnMountProps> = ({ const AnimateOnMount: FC<IAnimateOnMountProps> = ({

View File

@ -1,5 +1,6 @@
import { Button } from '@material-ui/core'; import { Button } from '@material-ui/core';
import { Alert } from '@material-ui/lab'; import { Alert } from '@material-ui/lab';
import React from 'react';
interface IApiErrorProps { interface IApiErrorProps {
className?: string; className?: string;

View File

@ -1,9 +1,10 @@
interface IConditionallyRenderProps { interface IConditionallyRenderProps {
condition: boolean; condition: boolean;
show: JSX.Element | RenderFunc; show: TargetElement;
elseShow?: JSX.Element | RenderFunc; elseShow?: TargetElement;
} }
type TargetElement = JSX.Element | JSX.Element[] | RenderFunc | null;
type RenderFunc = () => JSX.Element; type RenderFunc = () => JSX.Element;
const ConditionallyRender = ({ const ConditionallyRender = ({
@ -23,8 +24,9 @@ const ConditionallyRender = ({
return result; return result;
}; };
const isFunc = (param: JSX.Element | RenderFunc) => const isFunc = (param: TargetElement): boolean => {
typeof param === 'function'; return typeof param === 'function';
};
if (condition) { if (condition) {
if (isFunc(show)) { if (isFunc(show)) {

View File

@ -1,10 +1,10 @@
import React from 'react'; import React from 'react';
import { import {
Button,
Dialog, Dialog,
DialogTitle,
DialogActions, DialogActions,
DialogContent, DialogContent,
Button, DialogTitle,
} from '@material-ui/core'; } from '@material-ui/core';
import ConditionallyRender from '../ConditionallyRender/ConditionallyRender'; import ConditionallyRender from '../ConditionallyRender/ConditionallyRender';
@ -15,15 +15,15 @@ interface IDialogue {
primaryButtonText?: string; primaryButtonText?: string;
secondaryButtonText?: string; secondaryButtonText?: string;
open: boolean; open: boolean;
onClick: (e: any) => void; onClick: (e: React.SyntheticEvent) => void;
onClose: () => void; onClose?: (e: React.SyntheticEvent) => void;
style?: object; style?: object;
title: string; title: string;
fullWidth?: boolean; fullWidth?: boolean;
maxWidth?: 'lg' | 'sm' | 'xs' | 'md' | 'xl'; maxWidth?: 'lg' | 'sm' | 'xs' | 'md' | 'xl';
disabledPrimaryButton?: boolean; disabledPrimaryButton?: boolean;
formId?: string; formId?: string;
permissionButton?: React.ReactNode; permissionButton?: JSX.Element;
} }
const Dialogue: React.FC<IDialogue> = ({ const Dialogue: React.FC<IDialogue> = ({
@ -69,7 +69,7 @@ const Dialogue: React.FC<IDialogue> = ({
<DialogActions> <DialogActions>
<ConditionallyRender <ConditionallyRender
condition={Boolean(permissionButton)} condition={Boolean(permissionButton)}
show={permissionButton} show={permissionButton!}
elseShow={ elseShow={
<ConditionallyRender <ConditionallyRender
condition={Boolean(onClick)} condition={Boolean(onClick)}

View File

@ -1,3 +1,5 @@
import React from 'react';
interface EnvironmentSplashPageProps { interface EnvironmentSplashPageProps {
title: React.ReactNode; title: React.ReactNode;
topDescription: React.ReactNode; topDescription: React.ReactNode;

View File

@ -7,6 +7,7 @@ import ConditionallyRender from '../ConditionallyRender';
import Loader from '../Loader/Loader'; import Loader from '../Loader/Loader';
import copy from 'copy-to-clipboard'; import copy from 'copy-to-clipboard';
import useToast from '../../../hooks/useToast'; import useToast from '../../../hooks/useToast';
import React from 'react';
interface ICreateProps { interface ICreateProps {
title: string; title: string;

View File

@ -1,3 +1,5 @@
import React from 'react';
interface IGradientProps { interface IGradientProps {
from: string; from: string;
to: string; to: string;

View File

@ -1,6 +1,7 @@
import { TextField } from '@material-ui/core'; import { TextField } from '@material-ui/core';
import { INPUT_ERROR_TEXT } from '../../../testIds'; import { INPUT_ERROR_TEXT } from '../../../testIds';
import { useStyles } from './Input.styles.ts'; import { useStyles } from './Input.styles';
import React from 'react';
interface IInputProps extends React.InputHTMLAttributes<HTMLInputElement> { interface IInputProps extends React.InputHTMLAttributes<HTMLInputElement> {
label: string; label: string;

View File

@ -1,5 +1,6 @@
import { ReactComponent as NoItemsIcon } from '../../../assets/icons/addfiles.svg'; import { ReactComponent as NoItemsIcon } from '../../../assets/icons/addfiles.svg';
import { useStyles } from './NoItems.styles'; import { useStyles } from './NoItems.styles';
import React from 'react';
const NoItems: React.FC = ({ children }) => { const NoItems: React.FC = ({ children }) => {
const styles = useStyles(); const styles = useStyles();

View File

@ -1,4 +1,4 @@
import { useState, useEffect } from 'react'; import React, { useEffect, useState } from 'react';
import ConditionallyRender from '../ConditionallyRender'; import ConditionallyRender from '../ConditionallyRender';
import classnames from 'classnames'; import classnames from 'classnames';
import { useStyles } from './PaginationUI.styles'; import { useStyles } from './PaginationUI.styles';

View File

@ -1,6 +1,6 @@
import { IconButton, InputAdornment, TextField } from '@material-ui/core'; import { IconButton, InputAdornment, TextField } from '@material-ui/core';
import { Visibility, VisibilityOff } from '@material-ui/icons'; import { Visibility, VisibilityOff } from '@material-ui/icons';
import { useState } from 'react'; import React, { useState } from 'react';
const PasswordField = ({ ...rest }) => { const PasswordField = ({ ...rest }) => {
const [showPassword, setShowPassword] = useState(false); const [showPassword, setShowPassword] = useState(false);

View File

@ -1,6 +1,6 @@
import { Button, Tooltip } from '@material-ui/core'; import { Button, Tooltip } from '@material-ui/core';
import { Lock } from '@material-ui/icons'; import { Lock } from '@material-ui/icons';
import { useContext } from 'react'; import React, { useContext } from 'react';
import AccessContext from '../../../contexts/AccessContext'; import AccessContext from '../../../contexts/AccessContext';
import ConditionallyRender from '../ConditionallyRender'; import ConditionallyRender from '../ConditionallyRender';

View File

@ -1,5 +1,5 @@
import { IconButton, Tooltip } from '@material-ui/core'; import { IconButton, Tooltip } from '@material-ui/core';
import { useContext } from 'react'; import React, { useContext } from 'react';
import AccessContext from '../../../contexts/AccessContext'; import AccessContext from '../../../contexts/AccessContext';
interface IPermissionIconButtonProps interface IPermissionIconButtonProps

View File

@ -2,6 +2,7 @@ import { useMediaQuery } from '@material-ui/core';
import ConditionallyRender from '../ConditionallyRender'; import ConditionallyRender from '../ConditionallyRender';
import PermissionButton from '../PermissionButton/PermissionButton'; import PermissionButton from '../PermissionButton/PermissionButton';
import PermissionIconButton from '../PermissionIconButton/PermissionIconButton'; import PermissionIconButton from '../PermissionIconButton/PermissionIconButton';
import React from 'react';
interface IResponsiveButtonProps { interface IResponsiveButtonProps {
Icon: React.ElementType; Icon: React.ElementType;

View File

@ -1,12 +1,11 @@
import { Fragment } from 'react'; import React, { Fragment, useState } from 'react';
import { Button, IconButton } from '@material-ui/core'; import { Button, IconButton } from '@material-ui/core';
import { useStyles } from './Splash.styles'; import { useStyles } from './Splash.styles';
import { import {
CloseOutlined,
FiberManualRecord, FiberManualRecord,
FiberManualRecordOutlined, FiberManualRecordOutlined,
CloseOutlined,
} from '@material-ui/icons'; } from '@material-ui/icons';
import { useState } from 'react';
import ConditionallyRender from '../ConditionallyRender'; import ConditionallyRender from '../ConditionallyRender';
import { CLOSE_SPLASH } from '../../../testIds'; import { CLOSE_SPLASH } from '../../../testIds';

View File

@ -7,7 +7,7 @@ interface ITagSelect extends React.SelectHTMLAttributes<HTMLSelectElement> {
onChange: (val: any) => void; onChange: (val: any) => void;
} }
const TagSelect = ({ value, types, onChange, ...rest }: ITagSelect) => { const TagSelect = ({ value, onChange, ...rest }: ITagSelect) => {
const { tagTypes } = useTagTypes(); const { tagTypes } = useTagTypes();
const options = tagTypes.map(tagType => ({ const options = tagTypes.map(tagType => ({

View File

@ -3,12 +3,12 @@ import classnames from 'classnames';
import { useContext } from 'react'; import { useContext } from 'react';
import { IconButton } from '@material-ui/core'; import { IconButton } from '@material-ui/core';
import CheckMarkBadge from '../../CheckmarkBadge/CheckMarkBadge'; import CheckMarkBadge from '../../CheckmarkBadge/CheckMarkBadge';
import UIContext, { IToastData } from '../../../../contexts/UIContext'; import UIContext from '../../../../contexts/UIContext';
import ConditionallyRender from '../../ConditionallyRender'; import ConditionallyRender from '../../ConditionallyRender';
import Close from '@material-ui/icons/Close'; import Close from '@material-ui/icons/Close';
import { IToast } from '../../../../interfaces/toast';
const Toast = ({ title, text, type, confetti }: IToastData) => { const Toast = ({ title, text, type, confetti }: IToast) => {
// @ts-expect-error
const { setToast } = useContext(UIContext); const { setToast } = useContext(UIContext);
const styles = useStyles(); const styles = useStyles();
@ -51,7 +51,7 @@ const Toast = ({ title, text, type, confetti }: IToastData) => {
}; };
const hide = () => { const hide = () => {
setToast((prev: IToastData) => ({ ...prev, show: false })); setToast((prev: IToast) => ({ ...prev, show: false }));
}; };
return ( return (

View File

@ -1,19 +1,19 @@
import { Portal } from '@material-ui/core'; import { Portal } from '@material-ui/core';
import { useContext, useEffect } from 'react'; import { useContext, useEffect } from 'react';
import { useCommonStyles } from '../../../common.styles'; import { useCommonStyles } from '../../../common.styles';
import UIContext, { IToastData } from '../../../contexts/UIContext'; import UIContext from '../../../contexts/UIContext';
import { useStyles } from './ToastRenderer.styles'; import { useStyles } from './ToastRenderer.styles';
import AnimateOnMount from '../AnimateOnMount/AnimateOnMount'; import AnimateOnMount from '../AnimateOnMount/AnimateOnMount';
import Toast from './Toast/Toast'; import Toast from './Toast/Toast';
import { IToast } from '../../../interfaces/toast';
const ToastRenderer = () => { const ToastRenderer = () => {
// @ts-expect-error
const { toastData, setToast } = useContext(UIContext); const { toastData, setToast } = useContext(UIContext);
const commonStyles = useCommonStyles(); const commonStyles = useCommonStyles();
const styles = useStyles(); const styles = useStyles();
const hide = () => { const hide = () => {
setToast((prev: IToastData) => ({ ...prev, show: false })); setToast((prev: IToast) => ({ ...prev, show: false }));
}; };
useEffect(() => { useEffect(() => {
@ -31,7 +31,7 @@ const ToastRenderer = () => {
return ( return (
<Portal> <Portal>
<AnimateOnMount <AnimateOnMount
mounted={toastData?.show} mounted={Boolean(toastData?.show)}
start={commonStyles.fadeInBottomStartWithoutFixed} start={commonStyles.fadeInBottomStartWithoutFixed}
enter={commonStyles.fadeInBottomEnter} enter={commonStyles.fadeInBottomEnter}
leave={commonStyles.fadeInBottomLeave} leave={commonStyles.fadeInBottomLeave}

View File

@ -7,6 +7,7 @@ import {
UPDATE_CONTEXT_FIELD, UPDATE_CONTEXT_FIELD,
} from '../../providers/AccessProvider/permissions'; } from '../../providers/AccessProvider/permissions';
import { import {
Button,
IconButton, IconButton,
List, List,
ListItem, ListItem,
@ -14,7 +15,6 @@ import {
ListItemText, ListItemText,
Tooltip, Tooltip,
useMediaQuery, useMediaQuery,
Button,
} from '@material-ui/core'; } from '@material-ui/core';
import { Add, Album, Delete, Edit } from '@material-ui/icons'; import { Add, Album, Delete, Edit } from '@material-ui/icons';
import { useContext, useState } from 'react'; import { useContext, useState } from 'react';
@ -25,6 +25,7 @@ import AccessContext from '../../../contexts/AccessContext';
import useUnleashContext from '../../../hooks/api/getters/useUnleashContext/useUnleashContext'; import useUnleashContext from '../../../hooks/api/getters/useUnleashContext/useUnleashContext';
import useContextsApi from '../../../hooks/api/actions/useContextsApi/useContextsApi'; import useContextsApi from '../../../hooks/api/actions/useContextsApi/useContextsApi';
import useToast from '../../../hooks/useToast'; import useToast from '../../../hooks/useToast';
import { formatUnknownError } from '../../../utils/format-unknown-error';
const ContextList = () => { const ContextList = () => {
const { hasAccess } = useContext(AccessContext); const { hasAccess } = useContext(AccessContext);
@ -46,8 +47,8 @@ const ContextList = () => {
title: 'Successfully deleted context', title: 'Successfully deleted context',
text: 'Your context is now deleted', text: 'Your context is now deleted',
}); });
} catch (e) { } catch (error) {
setToastApiError(e.toString()); setToastApiError(formatUnknownError(error));
} }
setName(undefined); setName(undefined);
setShowDelDialogue(false); setShowDelDialogue(false);

View File

@ -8,6 +8,7 @@ import PermissionButton from '../../common/PermissionButton/PermissionButton';
import { CREATE_CONTEXT_FIELD } from '../../providers/AccessProvider/permissions'; import { CREATE_CONTEXT_FIELD } from '../../providers/AccessProvider/permissions';
import useContextsApi from '../../../hooks/api/actions/useContextsApi/useContextsApi'; import useContextsApi from '../../../hooks/api/actions/useContextsApi/useContextsApi';
import useUnleashContext from '../../../hooks/api/getters/useUnleashContext/useUnleashContext'; import useUnleashContext from '../../../hooks/api/getters/useUnleashContext/useUnleashContext';
import { formatUnknownError } from '../../../utils/format-unknown-error';
const CreateContext = () => { const CreateContext = () => {
const { setToastData, setToastApiError } = useToast(); const { setToastData, setToastApiError } = useToast();
@ -46,8 +47,8 @@ const CreateContext = () => {
confetti: true, confetti: true,
type: 'success', type: 'success',
}); });
} catch (e: any) { } catch (error: unknown) {
setToastApiError(e.toString()); setToastApiError(formatUnknownError(error));
} }
} }
}; };
@ -69,7 +70,7 @@ const CreateContext = () => {
<FormTemplate <FormTemplate
loading={loading} loading={loading}
title="Create context" title="Create context"
description="Context fields are a basic building block used in Unleash to control roll-out. description="Context fields are a basic building block used in Unleash to control roll-out.
They can be used together with strategy constraints as part of the activation strategy evaluation." They can be used together with strategy constraints as part of the activation strategy evaluation."
documentationLink="https://docs.getunleash.io/how-to/how-to-define-custom-context-fields" documentationLink="https://docs.getunleash.io/how-to/how-to-define-custom-context-fields"
formatApiCode={formatApiCode} formatApiCode={formatApiCode}

View File

@ -10,6 +10,7 @@ import { scrollToTop } from '../../common/util';
import { UPDATE_CONTEXT_FIELD } from '../../providers/AccessProvider/permissions'; import { UPDATE_CONTEXT_FIELD } from '../../providers/AccessProvider/permissions';
import ContextForm from '../ContextForm/ContextForm'; import ContextForm from '../ContextForm/ContextForm';
import useContextForm from '../hooks/useContextForm'; import useContextForm from '../hooks/useContextForm';
import { formatUnknownError } from '../../../utils/format-unknown-error';
const EditContext = () => { const EditContext = () => {
useEffect(() => { useEffect(() => {
@ -67,8 +68,8 @@ const EditContext = () => {
title: 'Context information updated', title: 'Context information updated',
type: 'success', type: 'success',
}); });
} catch (e: any) { } catch (error: unknown) {
setToastApiError(e.toString()); setToastApiError(formatUnknownError(error));
} }
} }
}; };
@ -81,7 +82,7 @@ const EditContext = () => {
<FormTemplate <FormTemplate
loading={loading} loading={loading}
title="Edit context" title="Edit context"
description="Context fields are a basic building block used in Unleash to control roll-out. description="Context fields are a basic building block used in Unleash to control roll-out.
They can be used together with strategy constraints as part of the activation strategy evaluation." They can be used together with strategy constraints as part of the activation strategy evaluation."
documentationLink="https://docs.getunleash.io/how-to/how-to-define-custom-context-fields" documentationLink="https://docs.getunleash.io/how-to/how-to-define-custom-context-fields"
formatApiCode={formatApiCode} formatApiCode={formatApiCode}

View File

@ -14,6 +14,7 @@ import HeaderTitle from '../../common/HeaderTitle';
import PermissionButton from '../../common/PermissionButton/PermissionButton'; import PermissionButton from '../../common/PermissionButton/PermissionButton';
import { ADMIN } from '../../providers/AccessProvider/permissions'; import { ADMIN } from '../../providers/AccessProvider/permissions';
import useProjectRolePermissions from '../../../hooks/api/getters/useProjectRolePermissions/useProjectRolePermissions'; import useProjectRolePermissions from '../../../hooks/api/getters/useProjectRolePermissions/useProjectRolePermissions';
import { formatUnknownError } from '../../../utils/format-unknown-error';
const CreateEnvironment = () => { const CreateEnvironment = () => {
const { setToastApiError, setToastData } = useToast(); const { setToastApiError, setToastData } = useToast();
@ -49,8 +50,8 @@ const CreateEnvironment = () => {
confetti: true, confetti: true,
}); });
history.push('/environments'); history.push('/environments');
} catch (e: any) { } catch (error: unknown) {
setToastApiError(e.toString()); setToastApiError(formatUnknownError(error));
} }
} }
}; };

View File

@ -9,6 +9,7 @@ import PermissionButton from '../../common/PermissionButton/PermissionButton';
import { ADMIN } from '../../providers/AccessProvider/permissions'; import { ADMIN } from '../../providers/AccessProvider/permissions';
import EnvironmentForm from '../EnvironmentForm/EnvironmentForm'; import EnvironmentForm from '../EnvironmentForm/EnvironmentForm';
import useEnvironmentForm from '../hooks/useEnvironmentForm'; import useEnvironmentForm from '../hooks/useEnvironmentForm';
import { formatUnknownError } from '../../../utils/format-unknown-error';
const EditEnvironment = () => { const EditEnvironment = () => {
const { uiConfig } = useUiConfig(); const { uiConfig } = useUiConfig();
@ -49,8 +50,8 @@ const EditEnvironment = () => {
type: 'success', type: 'success',
title: 'Successfully updated environment.', title: 'Successfully updated environment.',
}); });
} catch (e: any) { } catch (error: unknown) {
setToastApiError(e.toString()); setToastApiError(formatUnknownError(error));
} }
}; };
@ -61,7 +62,7 @@ const EditEnvironment = () => {
return ( return (
<FormTemplate <FormTemplate
title="Edit environment" title="Edit environment"
description="Environments allow you to manage your description="Environments allow you to manage your
product lifecycle from local development product lifecycle from local development
through production. Your projects and through production. Your projects and
feature toggles are accessible in all your feature toggles are accessible in all your

View File

@ -1,10 +1,11 @@
import { import {
FormControl, FormControl,
FormControlLabel, FormControlLabel,
RadioGroup,
Radio, Radio,
RadioGroup,
} from '@material-ui/core'; } from '@material-ui/core';
import { useStyles } from './EnvironmentTypeSelector.styles'; import { useStyles } from './EnvironmentTypeSelector.styles';
import React from 'react';
interface IEnvironmentTypeSelectorProps { interface IEnvironmentTypeSelectorProps {
onChange: (event: React.FormEvent<HTMLInputElement>) => void; onChange: (event: React.FormEvent<HTMLInputElement>) => void;

View File

@ -11,7 +11,7 @@ interface IEnviromentDeleteConfirmProps {
open: boolean; open: boolean;
setSelectedEnv: React.Dispatch<React.SetStateAction<IEnvironment>>; setSelectedEnv: React.Dispatch<React.SetStateAction<IEnvironment>>;
setDeldialogue: React.Dispatch<React.SetStateAction<boolean>>; setDeldialogue: React.Dispatch<React.SetStateAction<boolean>>;
handleDeleteEnvironment: (name: string) => Promise<void>; handleDeleteEnvironment: () => Promise<void>;
confirmName: string; confirmName: string;
setConfirmName: React.Dispatch<React.SetStateAction<string>>; setConfirmName: React.Dispatch<React.SetStateAction<string>>;
} }

View File

@ -21,6 +21,7 @@ import EnvironmentToggleConfirm from './EnvironmentToggleConfirm/EnvironmentTogg
import useProjectRolePermissions from '../../../hooks/api/getters/useProjectRolePermissions/useProjectRolePermissions'; import useProjectRolePermissions from '../../../hooks/api/getters/useProjectRolePermissions/useProjectRolePermissions';
import { ADMIN } from 'component/providers/AccessProvider/permissions'; import { ADMIN } from 'component/providers/AccessProvider/permissions';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { formatUnknownError } from '../../../utils/format-unknown-error';
const EnvironmentList = () => { const EnvironmentList = () => {
const defaultEnv = { const defaultEnv = {
@ -75,16 +76,16 @@ const EnvironmentList = () => {
try { try {
await sortOrderAPICall(sortOrder); await sortOrderAPICall(sortOrder);
refetch(); refetch();
} catch (e) { } catch (error: unknown) {
setToastApiError(e.toString()); setToastApiError(formatUnknownError(error));
} }
}; };
const sortOrderAPICall = async (sortOrder: ISortOrderPayload) => { const sortOrderAPICall = async (sortOrder: ISortOrderPayload) => {
try { try {
await changeSortOrder(sortOrder); await changeSortOrder(sortOrder);
} catch (e) { } catch (error: unknown) {
setToastApiError(e.toString()); setToastApiError(formatUnknownError(error));
} }
}; };
@ -97,8 +98,8 @@ const EnvironmentList = () => {
title: 'Project environment deleted', title: 'Project environment deleted',
text: 'You have successfully deleted the project environment.', text: 'You have successfully deleted the project environment.',
}); });
} catch (e) { } catch (error: unknown) {
setToastApiError(e.toString()); setToastApiError(formatUnknownError(error));
} finally { } finally {
setDeldialogue(false); setDeldialogue(false);
setSelectedEnv(defaultEnv); setSelectedEnv(defaultEnv);
@ -124,8 +125,8 @@ const EnvironmentList = () => {
title: 'Project environment enabled', title: 'Project environment enabled',
text: 'Your environment is enabled', text: 'Your environment is enabled',
}); });
} catch (e) { } catch (error: unknown) {
setToastApiError(e.toString()); setToastApiError(formatUnknownError(error));
} finally { } finally {
refetch(); refetch();
} }
@ -140,8 +141,8 @@ const EnvironmentList = () => {
title: 'Project environment disabled', title: 'Project environment disabled',
text: 'Your environment is disabled.', text: 'Your environment is disabled.',
}); });
} catch (e) { } catch (error: unknown) {
setToastApiError(e.toString()); setToastApiError(formatUnknownError(error));
} finally { } finally {
refetch(); refetch();
} }

View File

@ -10,6 +10,7 @@ import PermissionButton from '../../common/PermissionButton/PermissionButton';
import { CF_CREATE_BTN_ID } from '../../../testIds'; import { CF_CREATE_BTN_ID } from '../../../testIds';
import { useContext } from 'react'; import { useContext } from 'react';
import UIContext from '../../../contexts/UIContext'; import UIContext from '../../../contexts/UIContext';
import { formatUnknownError } from '../../../utils/format-unknown-error';
const CreateFeature = () => { const CreateFeature = () => {
const { setToastData, setToastApiError } = useToast(); const { setToastData, setToastApiError } = useToast();
@ -53,8 +54,8 @@ const CreateFeature = () => {
type: 'success', type: 'success',
}); });
setShowFeedback(true); setShowFeedback(true);
} catch (e: any) { } catch (error: unknown) {
setToastApiError(e.toString()); setToastApiError(formatUnknownError(error));
} }
} }
}; };

View File

@ -10,6 +10,7 @@ import { IFeatureViewParams } from '../../../interfaces/params';
import * as jsonpatch from 'fast-json-patch'; import * as jsonpatch from 'fast-json-patch';
import PermissionButton from '../../common/PermissionButton/PermissionButton'; import PermissionButton from '../../common/PermissionButton/PermissionButton';
import { UPDATE_FEATURE } from '../../providers/AccessProvider/permissions'; import { UPDATE_FEATURE } from '../../providers/AccessProvider/permissions';
import { formatUnknownError } from '../../../utils/format-unknown-error';
const EditFeature = () => { const EditFeature = () => {
const { setToastData, setToastApiError } = useToast(); const { setToastData, setToastApiError } = useToast();
@ -57,8 +58,8 @@ const EditFeature = () => {
title: 'Toggle updated successfully', title: 'Toggle updated successfully',
type: 'success', type: 'success',
}); });
} catch (e: any) { } catch (error: unknown) {
setToastApiError(e.toString()); setToastApiError(formatUnknownError(error));
} }
}; };

View File

@ -1,10 +1,12 @@
import { useRef, useState } from 'react'; import { useRef, useState } from 'react';
import { TableCell, TableRow } from '@material-ui/core'; import { TableCell, TableRow } from '@material-ui/core';
import { useHistory } from 'react-router'; import { useHistory } from 'react-router';
import { useStyles } from '../FeatureToggleListNew.styles'; import { useStyles } from '../FeatureToggleListNew.styles';
import useToggleFeatureByEnv from '../../../../hooks/api/actions/useToggleFeatureByEnv/useToggleFeatureByEnv'; import useToggleFeatureByEnv from '../../../../hooks/api/actions/useToggleFeatureByEnv/useToggleFeatureByEnv';
import { IEnvironments } from '../../../../interfaces/featureToggle'; import {
IEnvironments,
IFeatureEnvironment,
} from '../../../../interfaces/featureToggle';
import useToast from '../../../../hooks/useToast'; import useToast from '../../../../hooks/useToast';
import { getTogglePath } from '../../../../utils/route-path-helpers'; import { getTogglePath } from '../../../../utils/route-path-helpers';
import { SyntheticEvent } from 'react-router/node_modules/@types/react'; import { SyntheticEvent } from 'react-router/node_modules/@types/react';
@ -25,8 +27,8 @@ interface IFeatureToggleListNewItemProps {
type: string; type: string;
environments: IFeatureEnvironment[]; environments: IFeatureEnvironment[];
projectId: string; projectId: string;
lastSeenAt?: Date; lastSeenAt?: string;
createdAt: Date; createdAt: string;
} }
const FeatureToggleListNewItem = ({ const FeatureToggleListNewItem = ({

View File

@ -1,6 +1,6 @@
import { DialogContentText } from '@material-ui/core'; import { DialogContentText } from '@material-ui/core';
import { useParams } from 'react-router'; import { useParams } from 'react-router';
import { useState } from 'react'; import React, { useState } from 'react';
import { IFeatureViewParams } from '../../../../../interfaces/params'; import { IFeatureViewParams } from '../../../../../interfaces/params';
import Dialogue from '../../../../common/Dialogue'; import Dialogue from '../../../../common/Dialogue';
import Input from '../../../../common/Input/Input'; import Input from '../../../../common/Input/Input';
@ -11,6 +11,7 @@ import TagSelect from '../../../../common/TagSelect/TagSelect';
import useFeatureApi from '../../../../../hooks/api/actions/useFeatureApi/useFeatureApi'; import useFeatureApi from '../../../../../hooks/api/actions/useFeatureApi/useFeatureApi';
import useTags from '../../../../../hooks/api/getters/useTags/useTags'; import useTags from '../../../../../hooks/api/getters/useTags/useTags';
import useToast from '../../../../../hooks/useToast'; import useToast from '../../../../../hooks/useToast';
import { formatUnknownError } from '../../../../../utils/format-unknown-error';
interface IAddTagDialogProps { interface IAddTagDialogProps {
open: boolean; open: boolean;
@ -20,6 +21,7 @@ interface IAddTagDialogProps {
interface IDefaultTag { interface IDefaultTag {
type: string; type: string;
value: string; value: string;
[index: string]: string; [index: string]: string;
} }
@ -62,9 +64,10 @@ const AddTagDialog = ({ open, setOpen }: IAddTagDialogProps) => {
text: 'We successfully added a tag to your toggle', text: 'We successfully added a tag to your toggle',
confetti: true, confetti: true,
}); });
} catch (e) { } catch (error: unknown) {
setToastApiError(e.message); const message = formatUnknownError(error);
setErrors({ tagError: e.message }); setToastApiError(message);
setErrors({ tagError: message });
} }
}; };

View File

@ -8,6 +8,8 @@ import { IFeatureViewParams } from '../../../../../../interfaces/params';
import PermissionSwitch from '../../../../../common/PermissionSwitch/PermissionSwitch'; import PermissionSwitch from '../../../../../common/PermissionSwitch/PermissionSwitch';
import StringTruncator from '../../../../../common/StringTruncator/StringTruncator'; import StringTruncator from '../../../../../common/StringTruncator/StringTruncator';
import { UPDATE_FEATURE_ENVIRONMENT } from '../../../../../providers/AccessProvider/permissions'; import { UPDATE_FEATURE_ENVIRONMENT } from '../../../../../providers/AccessProvider/permissions';
import React from 'react';
import { formatUnknownError } from '../../../../../../utils/format-unknown-error';
interface IFeatureOverviewEnvSwitchProps { interface IFeatureOverviewEnvSwitchProps {
env: IFeatureEnvironment; env: IFeatureEnvironment;
@ -40,7 +42,7 @@ const FeatureOverviewEnvSwitch = ({
if (callback) { if (callback) {
callback(); callback();
} }
} catch (e: any) { } catch (e) {
if (e.message === ENVIRONMENT_STRATEGY_ERROR) { if (e.message === ENVIRONMENT_STRATEGY_ERROR) {
showInfoBox(true); showInfoBox(true);
} else { } else {
@ -61,8 +63,8 @@ const FeatureOverviewEnvSwitch = ({
if (callback) { if (callback) {
callback(); callback();
} }
} catch (e: any) { } catch (error: unknown) {
setToastApiError(e.message); setToastApiError(formatUnknownError(error));
} }
}; };

View File

@ -1,5 +1,5 @@
import { Settings } from '@material-ui/icons'; import { Settings } from '@material-ui/icons';
import { useTheme } from '@material-ui/styles'; import { useTheme } from '@material-ui/core/styles';
import { Link, useParams } from 'react-router-dom'; import { Link, useParams } from 'react-router-dom';
import { IFeatureViewParams } from '../../../../../../../../interfaces/params'; import { IFeatureViewParams } from '../../../../../../../../interfaces/params';
import { IFeatureStrategy } from '../../../../../../../../interfaces/strategy'; import { IFeatureStrategy } from '../../../../../../../../interfaces/strategy';

View File

@ -1,6 +1,6 @@
import { useState, useContext } from 'react'; import React, { useContext, useState } from 'react';
import { Chip } from '@material-ui/core'; import { Chip } from '@material-ui/core';
import { Label, Close } from '@material-ui/icons'; import { Close, Label } from '@material-ui/icons';
import { useParams } from 'react-router-dom'; import { useParams } from 'react-router-dom';
import useTags from '../../../../../../hooks/api/getters/useTags/useTags'; import useTags from '../../../../../../hooks/api/getters/useTags/useTags';
import { IFeatureViewParams } from '../../../../../../interfaces/params'; import { IFeatureViewParams } from '../../../../../../interfaces/params';
@ -17,6 +17,7 @@ import useToast from '../../../../../../hooks/useToast';
import { UPDATE_FEATURE } from '../../../../../providers/AccessProvider/permissions'; import { UPDATE_FEATURE } from '../../../../../providers/AccessProvider/permissions';
import ConditionallyRender from '../../../../../common/ConditionallyRender'; import ConditionallyRender from '../../../../../common/ConditionallyRender';
import AccessContext from '../../../../../../contexts/AccessContext'; import AccessContext from '../../../../../../contexts/AccessContext';
import { formatUnknownError } from '../../../../../../utils/format-unknown-error';
interface IFeatureOverviewTagsProps extends React.HTMLProps<HTMLButtonElement> { interface IFeatureOverviewTagsProps extends React.HTMLProps<HTMLButtonElement> {
projectId: string; projectId: string;
@ -53,8 +54,8 @@ const FeatureOverviewTags: React.FC<IFeatureOverviewTagsProps> = ({
title: 'Tag deleted', title: 'Tag deleted',
text: 'Successfully deleted tag', text: 'Successfully deleted tag',
}); });
} catch (e) { } catch (error: unknown) {
setToastApiError(e.message); setToastApiError(formatUnknownError(error));
} }
}; };

View File

@ -1,4 +1,4 @@
import { useState, useEffect, useContext } from 'react'; import { useContext, useEffect, useState } from 'react';
import * as jsonpatch from 'fast-json-patch'; import * as jsonpatch from 'fast-json-patch';
import { TextField } from '@material-ui/core'; import { TextField } from '@material-ui/core';
import PermissionButton from '../../../../common/PermissionButton/PermissionButton'; import PermissionButton from '../../../../common/PermissionButton/PermissionButton';
@ -11,6 +11,7 @@ import { IFeatureViewParams } from '../../../../../interfaces/params';
import useToast from '../../../../../hooks/useToast'; import useToast from '../../../../../hooks/useToast';
import useFeatureApi from '../../../../../hooks/api/actions/useFeatureApi/useFeatureApi'; import useFeatureApi from '../../../../../hooks/api/actions/useFeatureApi/useFeatureApi';
import ConditionallyRender from '../../../../common/ConditionallyRender'; import ConditionallyRender from '../../../../common/ConditionallyRender';
import { formatUnknownError } from '../../../../../utils/format-unknown-error';
const FeatureSettingsMetadata = () => { const FeatureSettingsMetadata = () => {
const { hasAccess } = useContext(AccessContext); const { hasAccess } = useContext(AccessContext);
@ -54,8 +55,8 @@ const FeatureSettingsMetadata = () => {
}); });
setDirty(false); setDirty(false);
refetch(); refetch();
} catch (e) { } catch (error: unknown) {
setToastApiError(e.toString()); setToastApiError(formatUnknownError(error));
} }
}; };

View File

@ -1,4 +1,4 @@
import { useState, useEffect, useContext } from 'react'; import { useContext, useEffect, useState } from 'react';
import { useHistory, useParams } from 'react-router'; import { useHistory, useParams } from 'react-router';
import AccessContext from '../../../../../contexts/AccessContext'; import AccessContext from '../../../../../contexts/AccessContext';
import useFeatureApi from '../../../../../hooks/api/actions/useFeatureApi/useFeatureApi'; import useFeatureApi from '../../../../../hooks/api/actions/useFeatureApi/useFeatureApi';
@ -12,6 +12,7 @@ import FeatureProjectSelect from './FeatureProjectSelect/FeatureProjectSelect';
import FeatureSettingsProjectConfirm from './FeatureSettingsProjectConfirm/FeatureSettingsProjectConfirm'; import FeatureSettingsProjectConfirm from './FeatureSettingsProjectConfirm/FeatureSettingsProjectConfirm';
import { IPermission } from '../../../../../interfaces/user'; import { IPermission } from '../../../../../interfaces/user';
import { useAuthPermissions } from '../../../../../hooks/api/getters/useAuth/useAuthPermissions'; import { useAuthPermissions } from '../../../../../hooks/api/getters/useAuth/useAuthPermissions';
import { formatUnknownError } from '../../../../../utils/format-unknown-error';
const FeatureSettingsProject = () => { const FeatureSettingsProject = () => {
const { hasAccess } = useContext(AccessContext); const { hasAccess } = useContext(AccessContext);
@ -61,16 +62,16 @@ const FeatureSettingsProject = () => {
history.replace( history.replace(
`/projects/${newProject}/features/${featureId}/settings` `/projects/${newProject}/features/${featureId}/settings`
); );
} catch (e) { } catch (error: unknown) {
setToastApiError(e.message); setToastApiError(formatUnknownError(error));
} }
}; };
const createMoveTargets = () => { const createMoveTargets = () => {
return permissions.reduce( return permissions.reduce(
(acc: { [key: string]: boolean }, permission: IPermission) => { (acc: { [key: string]: boolean }, p: IPermission) => {
if (permission.permission === MOVE_FEATURE_TOGGLE) { if (p.project && p.permission === MOVE_FEATURE_TOGGLE) {
acc[permission.project] = true; acc[p.project] = true;
} }
return acc; return acc;
}, },

View File

@ -1,7 +1,8 @@
import { useStyles } from './FeatureStatus.styles'; import { useStyles } from './FeatureStatus.styles';
import TimeAgo from 'react-timeago'; import TimeAgo from 'react-timeago';
import ConditionallyRender from '../../../common/ConditionallyRender'; import ConditionallyRender from '../../../common/ConditionallyRender';
import { Tooltip } from '@material-ui/core'; import { Tooltip, TooltipProps } from '@material-ui/core';
import React from 'react';
function generateUnit(unit?: string): string { function generateUnit(unit?: string): string {
switch (unit) { switch (unit) {
@ -46,8 +47,8 @@ function getColor(unit?: string): string {
} }
interface FeatureStatusProps { interface FeatureStatusProps {
lastSeenAt?: Date; lastSeenAt?: string;
tooltipPlacement?: string; tooltipPlacement?: TooltipProps['placement'];
} }
const FeatureStatus = ({ const FeatureStatus = ({
@ -76,7 +77,7 @@ const FeatureStatus = ({
condition={!!lastSeenAt} condition={!!lastSeenAt}
show={ show={
<TimeAgo <TimeAgo
date={lastSeenAt} date={lastSeenAt!}
title="" title=""
live={false} live={false}
formatter={( formatter={(

View File

@ -19,6 +19,7 @@ import { ADD_NEW_STRATEGY_SAVE_ID } from '../../../../../../testIds';
import useFeature from '../../../../../../hooks/api/getters/useFeature/useFeature'; import useFeature from '../../../../../../hooks/api/getters/useFeature/useFeature';
import { scrollToTop } from '../../../../../common/util'; import { scrollToTop } from '../../../../../common/util';
import useToast from '../../../../../../hooks/useToast'; import useToast from '../../../../../../hooks/useToast';
import { formatUnknownError } from '../../../../../../utils/format-unknown-error';
const FeatureStrategiesConfigure = () => { const FeatureStrategiesConfigure = () => {
const history = useHistory(); const history = useHistory();
@ -99,8 +100,8 @@ const FeatureStrategiesConfigure = () => {
history.replace(history.location.pathname); history.replace(history.location.pathname);
refetch(); refetch();
scrollToTop(); scrollToTop();
} catch (e) { } catch (error: unknown) {
setToastApiError(e.message); setToastApiError(formatUnknownError(error));
} }
}; };

View File

@ -39,7 +39,6 @@ const FeatureStrategiesEnvironmentList = ({
const { const {
activeEnvironmentsRef, activeEnvironmentsRef,
setToastData,
deleteStrategy, deleteStrategy,
updateStrategy, updateStrategy,
delDialog, delDialog,
@ -162,7 +161,6 @@ const FeatureStrategiesEnvironmentList = ({
: 'Toggle is disabled and no strategies are executing' : 'Toggle is disabled and no strategies are executing'
} }
env={activeEnvironment} env={activeEnvironment}
setToastData={setToastData}
callback={updateFeatureEnvironmentCache} callback={updateFeatureEnvironmentCache}
/> />
</div> </div>

View File

@ -4,9 +4,13 @@ import FeatureStrategiesUIContext from '../../../../../../contexts/FeatureStrate
import useFeatureStrategyApi from '../../../../../../hooks/api/actions/useFeatureStrategyApi/useFeatureStrategyApi'; import useFeatureStrategyApi from '../../../../../../hooks/api/actions/useFeatureStrategyApi/useFeatureStrategyApi';
import useToast from '../../../../../../hooks/useToast'; import useToast from '../../../../../../hooks/useToast';
import { IFeatureViewParams } from '../../../../../../interfaces/params'; import { IFeatureViewParams } from '../../../../../../interfaces/params';
import { IFeatureStrategy } from '../../../../../../interfaces/strategy'; import {
IFeatureStrategy,
IStrategyPayload,
} from '../../../../../../interfaces/strategy';
import cloneDeep from 'lodash.clonedeep'; import cloneDeep from 'lodash.clonedeep';
import { IFeatureEnvironment } from '../../../../../../interfaces/featureToggle'; import { IFeatureEnvironment } from '../../../../../../interfaces/featureToggle';
import { formatUnknownError } from '../../../../../../utils/format-unknown-error';
const useFeatureStrategiesEnvironmentList = () => { const useFeatureStrategiesEnvironmentList = () => {
const { projectId, featureId } = useParams<IFeatureViewParams>(); const { projectId, featureId } = useParams<IFeatureViewParams>();
@ -85,8 +89,8 @@ const useFeatureStrategiesEnvironmentList = () => {
strategy.constraints = updateStrategyPayload.constraints; strategy.constraints = updateStrategyPayload.constraints;
history.replace(history.location.pathname); history.replace(history.location.pathname);
setFeatureCache(feature); setFeatureCache(feature);
} catch (e) { } catch (error: unknown) {
setToastApiError(e.message); setToastApiError(formatUnknownError(error));
} }
}; };
@ -118,14 +122,13 @@ const useFeatureStrategiesEnvironmentList = () => {
text: `Successfully deleted strategy from ${featureId}`, text: `Successfully deleted strategy from ${featureId}`,
}); });
history.replace(history.location.pathname); history.replace(history.location.pathname);
} catch (e) { } catch (error: unknown) {
setToastApiError(e.message); setToastApiError(formatUnknownError(error));
} }
}; };
return { return {
activeEnvironmentsRef, activeEnvironmentsRef,
setToastData,
deleteStrategy, deleteStrategy,
updateStrategy, updateStrategy,
delDialog, delDialog,

View File

@ -11,7 +11,7 @@ interface IFeatureStrategiesProductionGuard {
onClick: () => void; onClick: () => void;
onClose: () => void; onClose: () => void;
primaryButtonText: string; primaryButtonText: string;
loading: boolean; loading?: boolean;
} }
const FeatureStrategiesProductionGuard = ({ const FeatureStrategiesProductionGuard = ({

View File

@ -1,4 +1,4 @@
import { useContext, useEffect, useState } from 'react'; import React, { useContext, useEffect, useState } from 'react';
import { useParams } from 'react-router-dom'; import { useParams } from 'react-router-dom';
import { mutate } from 'swr'; import { mutate } from 'swr';
import FeatureStrategiesUIContext from '../../../../../../contexts/FeatureStrategiesUIContext'; import FeatureStrategiesUIContext from '../../../../../../contexts/FeatureStrategiesUIContext';
@ -6,8 +6,8 @@ import useFeatureStrategy from '../../../../../../hooks/api/getters/useFeatureSt
import { IFeatureViewParams } from '../../../../../../interfaces/params'; import { IFeatureViewParams } from '../../../../../../interfaces/params';
import { import {
IConstraint, IConstraint,
IParameter,
IFeatureStrategy, IFeatureStrategy,
IParameter,
} from '../../../../../../interfaces/strategy'; } from '../../../../../../interfaces/strategy';
import FeatureStrategyAccordion from '../../FeatureStrategyAccordion/FeatureStrategyAccordion'; import FeatureStrategyAccordion from '../../FeatureStrategyAccordion/FeatureStrategyAccordion';
import cloneDeep from 'lodash.clonedeep'; import cloneDeep from 'lodash.clonedeep';

View File

@ -23,7 +23,7 @@ interface IFeatureStrategyCardProps {
name: string; name: string;
description: string; description: string;
configureNewStrategy: boolean; configureNewStrategy: boolean;
index?: number; index: number;
} }
export const FEATURE_STRATEGIES_DRAG_TYPE = 'FEATURE_STRATEGIES_DRAG_TYPE'; export const FEATURE_STRATEGIES_DRAG_TYPE = 'FEATURE_STRATEGIES_DRAG_TYPE';

View File

@ -8,7 +8,7 @@ import useStrategies from '../../../../../../hooks/api/getters/useStrategies/use
import GeneralStrategy from '../../common/GeneralStrategy/GeneralStrategy'; import GeneralStrategy from '../../common/GeneralStrategy/GeneralStrategy';
import UserWithIdStrategy from '../../common/UserWithIdStrategy/UserWithId'; import UserWithIdStrategy from '../../common/UserWithIdStrategy/UserWithId';
import StrategyConstraints from '../../common/StrategyConstraints/StrategyConstraints'; import StrategyConstraints from '../../common/StrategyConstraints/StrategyConstraints';
import { useContext, useState } from 'react'; import React, { useContext, useState } from 'react';
import ConditionallyRender from '../../../../../common/ConditionallyRender'; import ConditionallyRender from '../../../../../common/ConditionallyRender';
import useUiConfig from '../../../../../../hooks/api/getters/useUiConfig/useUiConfig'; import useUiConfig from '../../../../../../hooks/api/getters/useUiConfig/useUiConfig';
import { C } from '../../../../../common/flags'; import { C } from '../../../../../common/flags';

View File

@ -1,16 +1,16 @@
import React from 'react'; import React from 'react';
import { import {
Switch,
FormControlLabel, FormControlLabel,
Tooltip, Switch,
TextField, TextField,
Tooltip,
} from '@material-ui/core'; } from '@material-ui/core';
import StrategyInputList from '../StrategyInputList/StrategyInputList'; import StrategyInputList from '../StrategyInputList/StrategyInputList';
import RolloutSlider from '../RolloutSlider/RolloutSlider'; import RolloutSlider from '../RolloutSlider/RolloutSlider';
import { import {
IParameter,
IFeatureStrategy, IFeatureStrategy,
IParameter,
} from '../../../../../../interfaces/strategy'; } from '../../../../../../interfaces/strategy';
import { useStyles } from './GeneralStrategy.styles'; import { useStyles } from './GeneralStrategy.styles';
@ -77,7 +77,7 @@ const GeneralStrategy = ({
</div> </div>
); );
} else if (type === 'list') { } else if (type === 'list') {
let list = []; let list: string[] = [];
if (typeof value === 'string') { if (typeof value === 'string') {
list = value.trim().split(',').filter(Boolean); list = value.trim().split(',').filter(Boolean);
} }

View File

@ -1,6 +1,7 @@
import { makeStyles, withStyles } from '@material-ui/core/styles'; import { makeStyles, withStyles } from '@material-ui/core/styles';
import { Slider, Typography } from '@material-ui/core'; import { Slider, Typography } from '@material-ui/core';
import { ROLLOUT_SLIDER_ID } from '../../../../../../testIds'; import { ROLLOUT_SLIDER_ID } from '../../../../../../testIds';
import React from 'react';
const StyledSlider = withStyles({ const StyledSlider = withStyles({
root: { root: {

View File

@ -7,7 +7,7 @@ import useUiConfig from '../../../../../../hooks/api/getters/useUiConfig/useUiCo
import { C } from '../../../../../common/flags'; import { C } from '../../../../../common/flags';
import useUnleashContext from '../../../../../../hooks/api/getters/useUnleashContext/useUnleashContext'; import useUnleashContext from '../../../../../../hooks/api/getters/useUnleashContext/useUnleashContext';
import StrategyConstraintInputField from './StrategyConstraintInputField'; import StrategyConstraintInputField from './StrategyConstraintInputField';
import { useEffect } from 'react'; import React, { useEffect } from 'react';
interface IStrategyConstraintProps { interface IStrategyConstraintProps {
constraints: IConstraint[]; constraints: IConstraint[];
@ -38,7 +38,7 @@ const StrategyConstraints: React.FC<IStrategyConstraintProps> = ({
const enabled = uiConfig.flags[C]; const enabled = uiConfig.flags[C];
const contextNames = contextFields.map(context => context.name); const contextNames = contextFields.map(context => context.name);
const onClick = evt => { const onClick = (evt: React.SyntheticEvent) => {
evt.preventDefault(); evt.preventDefault();
addConstraint(); addConstraint();
}; };
@ -57,15 +57,15 @@ const StrategyConstraints: React.FC<IStrategyConstraintProps> = ({
}; };
}; };
const removeConstraint = index => evt => { const removeConstraint = (index: number) => (event: Event) => {
evt.preventDefault(); event.preventDefault();
const updatedConstraints = [...constraints]; const updatedConstraints = [...constraints];
updatedConstraints.splice(index, 1); updatedConstraints.splice(index, 1);
updateConstraints(updatedConstraints); updateConstraints(updatedConstraints);
}; };
const updateConstraint = index => (value, field) => { const updateConstraint = (index: number) => (value, field) => {
const updatedConstraints = [...constraints]; const updatedConstraints = [...constraints];
const constraint = updatedConstraints[index]; const constraint = updatedConstraints[index];
constraint[field] = value; constraint[field] = value;

View File

@ -10,7 +10,7 @@ import {
interface IStrategyInputList { interface IStrategyInputList {
name: string; name: string;
list: string[]; list: string[];
setConfig: () => void; setConfig: (field: string, value: string) => void;
disabled: boolean; disabled: boolean;
} }

View File

@ -3,7 +3,7 @@ import StrategyInputList from '../StrategyInputList/StrategyInputList';
interface IUserWithIdStrategyProps { interface IUserWithIdStrategyProps {
parameters: IParameter; parameters: IParameter;
updateParameter: (field: string, value: any) => void; updateParameter: (field: string, value: string) => void;
editable: boolean; editable: boolean;
} }

View File

@ -1,12 +1,11 @@
import { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { import {
Button,
FormControl, FormControl,
FormControlLabel, FormControlLabel,
Grid, Grid,
TextField,
InputAdornment, InputAdornment,
Button, TextField,
Tooltip, Tooltip,
} from '@material-ui/core'; } from '@material-ui/core';
import { Info } from '@material-ui/icons'; import { Info } from '@material-ui/icons';
@ -18,13 +17,16 @@ import ConditionallyRender from '../../../../../common/ConditionallyRender';
import GeneralSelect from '../../../../../common/GeneralSelect/GeneralSelect'; import GeneralSelect from '../../../../../common/GeneralSelect/GeneralSelect';
import { useCommonStyles } from '../../../../../../common.styles'; import { useCommonStyles } from '../../../../../../common.styles';
import Dialogue from '../../../../../common/Dialogue'; import Dialogue from '../../../../../common/Dialogue';
import { trim, modalStyles } from '../../../../../common/util'; import { modalStyles, trim } from '../../../../../common/util';
import PermissionSwitch from '../../../../../common/PermissionSwitch/PermissionSwitch'; import PermissionSwitch from '../../../../../common/PermissionSwitch/PermissionSwitch';
import { UPDATE_FEATURE_VARIANTS } from '../../../../../providers/AccessProvider/permissions'; import { UPDATE_FEATURE_VARIANTS } from '../../../../../providers/AccessProvider/permissions';
import useFeature from '../../../../../../hooks/api/getters/useFeature/useFeature'; import useFeature from '../../../../../../hooks/api/getters/useFeature/useFeature';
import { useParams } from 'react-router-dom'; import { useParams } from 'react-router-dom';
import { IFeatureViewParams } from '../../../../../../interfaces/params'; import { IFeatureViewParams } from '../../../../../../interfaces/params';
import { IFeatureVariant } from '../../../../../../interfaces/featureToggle'; import {
IFeatureVariant,
IOverride,
} from '../../../../../../interfaces/featureToggle';
import cloneDeep from 'lodash.clonedeep'; import cloneDeep from 'lodash.clonedeep';
const payloadOptions = [ const payloadOptions = [
@ -35,6 +37,17 @@ const payloadOptions = [
const EMPTY_PAYLOAD = { type: 'string', value: '' }; const EMPTY_PAYLOAD = { type: 'string', value: '' };
interface IAddVariantProps {
showDialog: boolean;
closeDialog: () => void;
save: (variantToSave: IFeatureVariant) => Promise<void>;
editVariant: IFeatureVariant;
validateName: (value: string) => Record<string, string> | undefined;
validateWeight: (value: string) => Record<string, string> | undefined;
title: string;
editing: boolean;
}
const AddVariant = ({ const AddVariant = ({
showDialog, showDialog,
closeDialog, closeDialog,
@ -44,11 +57,11 @@ const AddVariant = ({
validateWeight, validateWeight,
title, title,
editing, editing,
}) => { }: IAddVariantProps) => {
const [data, setData] = useState({}); const [data, setData] = useState({});
const [payload, setPayload] = useState(EMPTY_PAYLOAD); const [payload, setPayload] = useState(EMPTY_PAYLOAD);
const [overrides, setOverrides] = useState([]); const [overrides, setOverrides] = useState<IOverride[]>([]);
const [error, setError] = useState({}); const [error, setError] = useState<Record<string, string>>({});
const commonStyles = useCommonStyles(); const commonStyles = useCommonStyles();
const { projectId, featureId } = useParams<IFeatureViewParams>(); const { projectId, featureId } = useParams<IFeatureViewParams>();
const { feature } = useFeature(projectId, featureId); const { feature } = useFeature(projectId, featureId);
@ -80,7 +93,7 @@ const AddVariant = ({
setError({}); setError({});
}; };
const setClonedVariants = clonedVariants => const setClonedVariants = (clonedVariants: IFeatureVariant[]) =>
setVariants(cloneDeep(clonedVariants)); setVariants(cloneDeep(clonedVariants));
useEffect(() => { useEffect(() => {
@ -159,7 +172,7 @@ const AddVariant = ({
} }
}; };
const onPayload = e => { const onPayload = (e: React.SyntheticEvent) => {
e.preventDefault(); e.preventDefault();
setPayload({ setPayload({
...payload, ...payload,
@ -167,13 +180,13 @@ const AddVariant = ({
}); });
}; };
const onCancel = e => { const onCancel = (e: React.SyntheticEvent) => {
e.preventDefault(); e.preventDefault();
clear(); clear();
closeDialog(); closeDialog();
}; };
const updateOverrideType = index => e => { const updateOverrideType = (index: number) => (e: React.SyntheticEvent) => {
e.preventDefault(); e.preventDefault();
setOverrides( setOverrides(
overrides.map((o, i) => { overrides.map((o, i) => {
@ -186,7 +199,7 @@ const AddVariant = ({
); );
}; };
const updateOverrideValues = (index, values) => { const updateOverrideValues = (index: number, values: string[]) => {
setOverrides( setOverrides(
overrides.map((o, i) => { overrides.map((o, i) => {
if (i === index) { if (i === index) {
@ -197,12 +210,12 @@ const AddVariant = ({
); );
}; };
const removeOverride = index => e => { const removeOverride = (index: number) => (e: React.SyntheticEvent) => {
e.preventDefault(); e.preventDefault();
setOverrides(overrides.filter((o, i) => i !== index)); setOverrides(overrides.filter((o, i) => i !== index));
}; };
const onAddOverride = e => { const onAddOverride = (e: React.SyntheticEvent) => {
e.preventDefault(); e.preventDefault();
setOverrides([ setOverrides([
...overrides, ...overrides,
@ -388,7 +401,6 @@ const AddVariant = ({
removeOverride={removeOverride} removeOverride={removeOverride}
updateOverrideType={updateOverrideType} updateOverrideType={updateOverrideType}
updateOverrideValues={updateOverrideValues} updateOverrideValues={updateOverrideValues}
updateValues={updateOverrideValues}
/> />
<Button <Button
onClick={onAddOverride} onClick={onAddOverride}
@ -402,15 +414,4 @@ const AddVariant = ({
); );
}; };
AddVariant.propTypes = {
showDialog: PropTypes.bool.isRequired,
closeDialog: PropTypes.func.isRequired,
save: PropTypes.func.isRequired,
validateName: PropTypes.func.isRequired,
validateWeight: PropTypes.func.isRequired,
editVariant: PropTypes.object,
title: PropTypes.string,
uiConfig: PropTypes.object,
};
export default AddVariant; export default AddVariant;

View File

@ -30,6 +30,7 @@ import cloneDeep from 'lodash.clonedeep';
import useDeleteVariantMarkup from './FeatureVariantsListItem/useDeleteVariantMarkup'; import useDeleteVariantMarkup from './FeatureVariantsListItem/useDeleteVariantMarkup';
import PermissionButton from '../../../../common/PermissionButton/PermissionButton'; import PermissionButton from '../../../../common/PermissionButton/PermissionButton';
import { mutate } from 'swr'; import { mutate } from 'swr';
import { formatUnknownError } from '../../../../../utils/format-unknown-error';
const FeatureOverviewVariants = () => { const FeatureOverviewVariants = () => {
const { hasAccess } = useContext(AccessContext); const { hasAccess } = useContext(AccessContext);
@ -155,8 +156,8 @@ const FeatureOverviewVariants = () => {
type: 'success', type: 'success',
text: 'Successfully updated variant stickiness', text: 'Successfully updated variant stickiness',
}); });
} catch (e) { } catch (error: unknown) {
setToastApiError(e.message); setToastApiError(formatUnknownError(error));
} }
}; };
@ -167,8 +168,8 @@ const FeatureOverviewVariants = () => {
updatedVariants, updatedVariants,
'Successfully removed variant' 'Successfully removed variant'
); );
} catch (e) { } catch (error: unknown) {
setToastApiError(e.message); setToastApiError(formatUnknownError(error));
} }
}; };
const updateVariant = async (variant: IFeatureVariant) => { const updateVariant = async (variant: IFeatureVariant) => {
@ -210,8 +211,8 @@ const FeatureOverviewVariants = () => {
type: 'success', type: 'success',
text: successText, text: successText,
}); });
} catch (e) { } catch (error: unknown) {
setToastApiError(e.message); setToastApiError(formatUnknownError(error));
} }
}; };
@ -221,7 +222,7 @@ const FeatureOverviewVariants = () => {
} }
}; };
const validateWeight = (weight: number) => { const validateWeight = (weight: string) => {
const weightValue = parseInt(weight); const weightValue = parseInt(weight);
if (weightValue > 100 || weightValue < 0) { if (weightValue > 100 || weightValue < 0) {
return { weight: 'weight must be between 0 and 100' }; return { weight: 'weight must be between 0 and 100' };
@ -230,7 +231,7 @@ const FeatureOverviewVariants = () => {
const delDialogueMarkup = useDeleteVariantMarkup({ const delDialogueMarkup = useDeleteVariantMarkup({
show: delDialog.show, show: delDialog.show,
onClick: e => { onClick: () => {
removeVariant(delDialog.name); removeVariant(delDialog.name);
setDelDialog({ name: '', show: false }); setDelDialog({ name: '', show: false });
setToastData({ setToastData({

View File

@ -1,5 +1,5 @@
import { IconButton, Chip, TableCell, TableRow } from '@material-ui/core'; import { Chip, IconButton, TableCell, TableRow } from '@material-ui/core';
import { Edit, Delete } from '@material-ui/icons'; import { Delete, Edit } from '@material-ui/icons';
import styles from '../variants.module.scss'; import styles from '../variants.module.scss';
import { IFeatureVariant } from '../../../../../../interfaces/featureToggle'; import { IFeatureVariant } from '../../../../../../interfaces/featureToggle';
@ -26,7 +26,7 @@ const FeatureVariantListItem = ({
<TableCell data-test={'VARIANT_NAME'}>{variant.name}</TableCell> <TableCell data-test={'VARIANT_NAME'}>{variant.name}</TableCell>
<TableCell className={styles.chipContainer}> <TableCell className={styles.chipContainer}>
<ConditionallyRender <ConditionallyRender
condition={variant.payload} condition={Boolean(variant.payload)}
show={<Chip label="Payload" />} show={<Chip label="Payload" />}
/> />
<ConditionallyRender <ConditionallyRender

View File

@ -61,7 +61,7 @@ const FeatureView = () => {
setShowDelDialog(false); setShowDelDialog(false);
projectRefetch(); projectRefetch();
history.push(`/projects/${projectId}`); history.push(`/projects/${projectId}`);
} catch (error) { } catch (error: unknown) {
setToastApiError(formatUnknownError(error)); setToastApiError(formatUnknownError(error));
setShowDelDialog(false); setShowDelDialog(false);
} }

View File

@ -11,9 +11,7 @@ interface IRedirectParams {
const RedirectFeatureView = () => { const RedirectFeatureView = () => {
const { name } = useParams<IRedirectParams>(); const { name } = useParams<IRedirectParams>();
const { features } = useFeatures(); const { features } = useFeatures();
const [featureToggle, setFeatureToggle] = useState<IFeatureToggle | null>( const [featureToggle, setFeatureToggle] = useState<IFeatureToggle>();
null
);
useEffect(() => { useEffect(() => {
const toggle = features.find( const toggle = features.find(
@ -23,7 +21,9 @@ const RedirectFeatureView = () => {
setFeatureToggle(toggle); setFeatureToggle(toggle);
}, [features, name]); }, [features, name]);
if (!featureToggle) return null; if (!featureToggle) {
return null;
}
return ( return (
<Redirect <Redirect

View File

@ -8,6 +8,7 @@ import useToast from '../../../../hooks/useToast';
import PermissionButton from '../../../common/PermissionButton/PermissionButton'; import PermissionButton from '../../../common/PermissionButton/PermissionButton';
import { CREATE_PROJECT } from '../../../providers/AccessProvider/permissions'; import { CREATE_PROJECT } from '../../../providers/AccessProvider/permissions';
import { useAuthUser } from '../../../../hooks/api/getters/useAuth/useAuthUser'; import { useAuthUser } from '../../../../hooks/api/getters/useAuth/useAuthUser';
import { formatUnknownError } from '../../../../utils/format-unknown-error';
const CreateProject = () => { const CreateProject = () => {
const { setToastData, setToastApiError } = useToast(); const { setToastData, setToastApiError } = useToast();
@ -48,8 +49,8 @@ const CreateProject = () => {
confetti: true, confetti: true,
type: 'success', type: 'success',
}); });
} catch (e: any) { } catch (error: unknown) {
setToastApiError(e.toString()); setToastApiError(formatUnknownError(error));
} }
} }
}; };

View File

@ -8,6 +8,7 @@ import useUiConfig from '../../../../hooks/api/getters/useUiConfig/useUiConfig';
import useToast from '../../../../hooks/useToast'; import useToast from '../../../../hooks/useToast';
import PermissionButton from '../../../common/PermissionButton/PermissionButton'; import PermissionButton from '../../../common/PermissionButton/PermissionButton';
import { UPDATE_PROJECT } from '../../../providers/AccessProvider/permissions'; import { UPDATE_PROJECT } from '../../../providers/AccessProvider/permissions';
import { formatUnknownError } from '../../../../utils/format-unknown-error';
const EditProject = () => { const EditProject = () => {
const { uiConfig } = useUiConfig(); const { uiConfig } = useUiConfig();
@ -58,8 +59,8 @@ const EditProject = () => {
title: 'Project information updated', title: 'Project information updated',
type: 'success', type: 'success',
}); });
} catch (e: any) { } catch (error: unknown) {
setToastApiError(e.toString()); setToastApiError(formatUnknownError(error));
} }
} }
}; };

View File

@ -45,7 +45,7 @@ const Project = () => {
}, },
{ {
title: 'Access', title: 'Access',
component: <ProjectAccess projectId={id} />, component: <ProjectAccess />,
path: `${basePath}/access`, path: `${basePath}/access`,
name: 'access', name: 'access',
}, },

View File

@ -27,7 +27,7 @@ const ProjectFeatureToggles = ({
loading, loading,
}: IProjectFeatureToggles) => { }: IProjectFeatureToggles) => {
const styles = useStyles(); const styles = useStyles();
const { id } = useParams(); const { id } = useParams<{ id: string }>();
const history = useHistory(); const history = useHistory();
const { hasAccess } = useContext(AccessContext); const { hasAccess } = useContext(AccessContext);
const { uiConfig } = useUiConfig(); const { uiConfig } = useUiConfig();

View File

@ -38,7 +38,6 @@ export const useStyles = makeStyles(theme => ({
position: 'relative', position: 'relative',
}, },
errorMessage: { errorMessage: {
// @ts-expect-error
fontSize: theme.fontSizes.smallBody, fontSize: theme.fontSizes.smallBody,
color: theme.palette.error.main, color: theme.palette.error.main,
position: 'absolute', position: 'absolute',

View File

@ -4,6 +4,7 @@ import {
IProjectAccessUser, IProjectAccessUser,
} from '../../../../hooks/api/getters/useProjectAccess/useProjectAccess'; } from '../../../../hooks/api/getters/useProjectAccess/useProjectAccess';
import { ProjectAccessListItem } from './ProjectAccessListItem/ProjectAccessListItem'; import { ProjectAccessListItem } from './ProjectAccessListItem/ProjectAccessListItem';
import React from 'react';
interface IProjectAccesListProps { interface IProjectAccesListProps {
page: IProjectAccessUser[]; page: IProjectAccessUser[];
@ -28,8 +29,8 @@ export const ProjectAccessList: React.FC<IProjectAccesListProps> = ({
children, children,
}) => { }) => {
const sortUsers = (users: IProjectAccessUser[]): IProjectAccessUser[] => { const sortUsers = (users: IProjectAccessUser[]): IProjectAccessUser[] => {
/* This should be done on the API side in the future, /* This should be done on the API side in the future,
we should expect the list of users to come in the we should expect the list of users to come in the
same order each time and not jump around on the screen*/ same order each time and not jump around on the screen*/
return users.sort( return users.sort(

View File

@ -1,22 +1,23 @@
import { import {
Avatar,
ListItem, ListItem,
ListItemAvatar, ListItemAvatar,
Avatar,
ListItemText,
ListItemSecondaryAction, ListItemSecondaryAction,
ListItemText,
MenuItem, MenuItem,
} from '@material-ui/core'; } from '@material-ui/core';
import { Delete } from '@material-ui/icons'; import { Delete } from '@material-ui/icons';
import { useParams } from 'react-router-dom'; import { useParams } from 'react-router-dom';
import { import {
IProjectAccessUser,
IProjectAccessOutput, IProjectAccessOutput,
IProjectAccessUser,
} from '../../../../../hooks/api/getters/useProjectAccess/useProjectAccess'; } from '../../../../../hooks/api/getters/useProjectAccess/useProjectAccess';
import { IProjectViewParams } from '../../../../../interfaces/params'; import { IProjectViewParams } from '../../../../../interfaces/params';
import PermissionIconButton from '../../../../common/PermissionIconButton/PermissionIconButton'; import PermissionIconButton from '../../../../common/PermissionIconButton/PermissionIconButton';
import { UPDATE_PROJECT } from '../../../../providers/AccessProvider/permissions'; import { UPDATE_PROJECT } from '../../../../providers/AccessProvider/permissions';
import { ProjectRoleSelect } from '../../ProjectRoleSelect/ProjectRoleSelect'; import { ProjectRoleSelect } from '../../ProjectRoleSelect/ProjectRoleSelect';
import { useStyles } from '../ProjectAccessListItem/ProjectAccessListItem.styles'; import { useStyles } from '../ProjectAccessListItem/ProjectAccessListItem.styles';
import React from 'react';
interface IProjectAccessListItemProps { interface IProjectAccessListItemProps {
user: IProjectAccessUser; user: IProjectAccessUser;

View File

@ -2,11 +2,11 @@ import { Alert } from '@material-ui/lab';
import React from 'react'; import React from 'react';
import Dialogue from '../../../common/Dialogue'; import Dialogue from '../../../common/Dialogue';
import Input from '../../../common/Input/Input'; import Input from '../../../common/Input/Input';
import { ProjectEnvironment } from '../ProjectEnvironment';
import { useStyles } from './EnvironmentDisableConfirm.styles'; import { useStyles } from './EnvironmentDisableConfirm.styles';
import { IProjectEnvironment } from '../../../../interfaces/environments';
interface IEnvironmentDisableConfirmProps { interface IEnvironmentDisableConfirmProps {
env?: ProjectEnvironment; env?: IProjectEnvironment;
open: boolean; open: boolean;
handleDisableEnvironment: () => Promise<void>; handleDisableEnvironment: () => Promise<void>;
handleCancelDisableEnvironment: () => void; handleCancelDisableEnvironment: () => void;

View File

@ -1,4 +1,4 @@
import { useState, useEffect } from 'react'; import { useEffect, useState } from 'react';
import ConditionallyRender from '../../common/ConditionallyRender'; import ConditionallyRender from '../../common/ConditionallyRender';
import { useStyles } from './ProjectEnvironment.styles'; import { useStyles } from './ProjectEnvironment.styles';
@ -27,7 +27,7 @@ interface ProjectEnvironmentListProps {
const ProjectEnvironmentList = ({ projectId }: ProjectEnvironmentListProps) => { const ProjectEnvironmentList = ({ projectId }: ProjectEnvironmentListProps) => {
// api state // api state
const [envs, setEnvs] = useState<IProjectEnvironment>([]); const [envs, setEnvs] = useState<IProjectEnvironment[]>([]);
const { setToastData, setToastApiError } = useToast(); const { setToastData, setToastApiError } = useToast();
const { uiConfig } = useUiConfig(); const { uiConfig } = useUiConfig();
const { const {
@ -76,7 +76,7 @@ const ProjectEnvironmentList = ({ projectId }: ProjectEnvironmentListProps) => {
} the environment.`; } the environment.`;
}; };
const toggleEnv = async (env: ProjectEnvironment) => { const toggleEnv = async (env: IProjectEnvironment) => {
if (env.enabled) { if (env.enabled) {
const enabledEnvs = getEnabledEnvs(envs); const enabledEnvs = getEnabledEnvs(envs);
@ -128,7 +128,7 @@ const ProjectEnvironmentList = ({ projectId }: ProjectEnvironmentListProps) => {
setConfirmName(''); setConfirmName('');
}; };
const genLabel = (env: ProjectEnvironment) => ( const genLabel = (env: IProjectEnvironment) => (
<> <>
<code>{env.name}</code> environment is{' '} <code>{env.name}</code> environment is{' '}
<strong>{env.enabled ? 'enabled' : 'disabled'}</strong> <strong>{env.enabled ? 'enabled' : 'disabled'}</strong>

View File

@ -1,17 +1,10 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import UIContext, { createEmptyToast } from '../../../contexts/UIContext';
import UIContext, { IToastData } from '../../../contexts/UIContext'; import { IToast } from '../../../interfaces/toast';
const UIProvider: React.FC = ({ children }) => { const UIProvider: React.FC = ({ children }) => {
const [toastData, setToast] = useState<IToastData>({ const [toastData, setToast] = useState<IToast>(createEmptyToast());
title: '', const [showFeedback, setShowFeedback] = useState(false);
text: '',
components: [],
show: false,
persist: false,
type: '',
});
const [showFeedback, setShowFeedback] = useState();
const context = React.useMemo( const context = React.useMemo(
() => ({ () => ({

View File

@ -1,4 +1,4 @@
import { makeStyles } from '@material-ui/styles'; import { makeStyles } from '@material-ui/core/styles';
export const useStyles = makeStyles(theme => ({ export const useStyles = makeStyles(theme => ({
listItem: { listItem: {

View File

@ -36,6 +36,7 @@ import useStrategies from '../../../hooks/api/getters/useStrategies/useStrategie
import useStrategiesApi from '../../../hooks/api/actions/useStrategiesApi/useStrategiesApi'; import useStrategiesApi from '../../../hooks/api/actions/useStrategiesApi/useStrategiesApi';
import useToast from '../../../hooks/useToast'; import useToast from '../../../hooks/useToast';
import { IStrategy } from '../../../interfaces/strategy'; import { IStrategy } from '../../../interfaces/strategy';
import { formatUnknownError } from '../../../utils/format-unknown-error';
interface IDialogueMetaData { interface IDialogueMetaData {
show: boolean; show: boolean;
@ -49,7 +50,11 @@ export const StrategiesList = () => {
const smallScreen = useMediaQuery('(max-width:700px)'); const smallScreen = useMediaQuery('(max-width:700px)');
const { hasAccess } = useContext(AccessContext); const { hasAccess } = useContext(AccessContext);
const [dialogueMetaData, setDialogueMetaData] = useState<IDialogueMetaData>( const [dialogueMetaData, setDialogueMetaData] = useState<IDialogueMetaData>(
{ show: false, title: '', onConfirm: () => {} } {
show: false,
title: '',
onConfirm: () => {},
}
); );
const { strategies, refetchStrategies } = useStrategies(); const { strategies, refetchStrategies } = useStrategies();
const { removeStrategy, deprecateStrategy, reactivateStrategy } = const { removeStrategy, deprecateStrategy, reactivateStrategy } =
@ -88,7 +93,7 @@ export const StrategiesList = () => {
/> />
); );
const strategyLink = ({ name, deprecated }) => ( const strategyLink = ({ name, deprecated }: IStrategy) => (
<Link to={`/strategies/view/${name}`}> <Link to={`/strategies/view/${name}`}>
<strong>{getHumanReadableStrategyName(name)}</strong> <strong>{getHumanReadableStrategyName(name)}</strong>
<ConditionallyRender <ConditionallyRender
@ -111,8 +116,8 @@ export const StrategiesList = () => {
title: 'Success', title: 'Success',
text: 'Strategy reactivated successfully', text: 'Strategy reactivated successfully',
}); });
} catch (e: any) { } catch (error: unknown) {
setToastApiError(e.toString()); setToastApiError(formatUnknownError(error));
} }
}, },
}); });
@ -131,8 +136,8 @@ export const StrategiesList = () => {
title: 'Success', title: 'Success',
text: 'Strategy deprecated successfully', text: 'Strategy deprecated successfully',
}); });
} catch (e: any) { } catch (error: unknown) {
setToastApiError(e.toString()); setToastApiError(formatUnknownError(error));
} }
}, },
}); });
@ -151,8 +156,8 @@ export const StrategiesList = () => {
title: 'Success', title: 'Success',
text: 'Strategy deleted successfully', text: 'Strategy deleted successfully',
}); });
} catch (e: any) { } catch (error: unknown) {
setToastApiError(e.toString()); setToastApiError(formatUnknownError(error));
} }
}, },
}); });

View File

@ -20,7 +20,7 @@ export const StrategyView = () => {
const { applications } = useApplications(); const { applications } = useApplications();
const toggles = features.filter(toggle => { const toggles = features.filter(toggle => {
return toggle?.strategies.findIndex(s => s.name === strategyName) > -1; return toggle?.strategies?.find(s => s.name === strategyName);
}); });
const strategy = strategies.find(n => n.name === strategyName); const strategy = strategies.find(n => n.name === strategyName);

View File

@ -5,13 +5,14 @@ import {
ListItemText, ListItemText,
Tooltip, Tooltip,
} from '@material-ui/core'; } from '@material-ui/core';
import { PlayArrow, Pause } from '@material-ui/icons'; import { Pause, PlayArrow } from '@material-ui/icons';
import styles from '../../common/common.module.scss'; import styles from '../../common/common.module.scss';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import ConditionallyRender from '../../common/ConditionallyRender'; import ConditionallyRender from '../../common/ConditionallyRender';
import { IFeatureToggle } from '../../../interfaces/featureToggle';
interface ITogglesLinkListProps { interface ITogglesLinkListProps {
toggles: []; toggles: IFeatureToggle[];
} }
export const TogglesLinkList = ({ toggles }: ITogglesLinkListProps) => ( export const TogglesLinkList = ({ toggles }: ITogglesLinkListProps) => (

View File

@ -7,6 +7,7 @@ import PermissionButton from '../../common/PermissionButton/PermissionButton';
import { UPDATE_TAG_TYPE } from '../../providers/AccessProvider/permissions'; import { UPDATE_TAG_TYPE } from '../../providers/AccessProvider/permissions';
import useTagTypeForm from '../TagTypeForm/useTagTypeForm'; import useTagTypeForm from '../TagTypeForm/useTagTypeForm';
import TagTypeForm from '../TagTypeForm/TagTypeForm'; import TagTypeForm from '../TagTypeForm/TagTypeForm';
import { formatUnknownError } from '../../../utils/format-unknown-error';
const CreateTagType = () => { const CreateTagType = () => {
const { setToastData, setToastApiError } = useToast(); const { setToastData, setToastApiError } = useToast();
@ -38,8 +39,8 @@ const CreateTagType = () => {
confetti: true, confetti: true,
type: 'success', type: 'success',
}); });
} catch (e: any) { } catch (error: unknown) {
setToastApiError(e.toString()); setToastApiError(formatUnknownError(error));
} }
} }
}; };

View File

@ -8,6 +8,7 @@ import PermissionButton from '../../common/PermissionButton/PermissionButton';
import { UPDATE_TAG_TYPE } from '../../providers/AccessProvider/permissions'; import { UPDATE_TAG_TYPE } from '../../providers/AccessProvider/permissions';
import useTagTypeForm from '../TagTypeForm/useTagTypeForm'; import useTagTypeForm from '../TagTypeForm/useTagTypeForm';
import TagForm from '../TagTypeForm/TagTypeForm'; import TagForm from '../TagTypeForm/TagTypeForm';
import { formatUnknownError } from '../../../utils/format-unknown-error';
const EditTagType = () => { const EditTagType = () => {
const { setToastData, setToastApiError } = useToast(); const { setToastData, setToastApiError } = useToast();
@ -37,8 +38,8 @@ const EditTagType = () => {
title: 'Tag type updated', title: 'Tag type updated',
type: 'success', type: 'success',
}); });
} catch (e: any) { } catch (error: unknown) {
setToastApiError(e.toString()); setToastApiError(formatUnknownError(error));
} }
}; };

View File

@ -26,6 +26,7 @@ import useTagTypesApi from '../../../hooks/api/actions/useTagTypesApi/useTagType
import useTagTypes from '../../../hooks/api/getters/useTagTypes/useTagTypes'; import useTagTypes from '../../../hooks/api/getters/useTagTypes/useTagTypes';
import useToast from '../../../hooks/useToast'; import useToast from '../../../hooks/useToast';
import PermissionIconButton from '../../common/PermissionIconButton/PermissionIconButton'; import PermissionIconButton from '../../common/PermissionIconButton/PermissionIconButton';
import { formatUnknownError } from '../../../utils/format-unknown-error';
export const TagTypeList = () => { export const TagTypeList = () => {
const { hasAccess } = useContext(AccessContext); const { hasAccess } = useContext(AccessContext);
@ -46,8 +47,8 @@ export const TagTypeList = () => {
show: true, show: true,
text: 'Successfully deleted tag type.', text: 'Successfully deleted tag type.',
}); });
} catch (e) { } catch (error) {
setToastApiError(e.toString()); setToastApiError(formatUnknownError(error));
} }
}; };

View File

@ -8,6 +8,7 @@ import { useHistory } from 'react-router-dom';
import { useAuthApi } from '../../../hooks/api/actions/useAuthApi/useAuthApi'; import { useAuthApi } from '../../../hooks/api/actions/useAuthApi/useAuthApi';
import { useAuthUser } from '../../../hooks/api/getters/useAuth/useAuthUser'; import { useAuthUser } from '../../../hooks/api/getters/useAuth/useAuthUser';
import useToast from '../../../hooks/useToast'; import useToast from '../../../hooks/useToast';
import { formatUnknownError } from '../../../utils/format-unknown-error';
const DemoAuth = ({ authDetails }) => { const DemoAuth = ({ authDetails }) => {
const [email, setEmail] = useState(''); const [email, setEmail] = useState('');
@ -23,8 +24,8 @@ const DemoAuth = ({ authDetails }) => {
await emailAuth(authDetails.path, email); await emailAuth(authDetails.path, email);
refetchUser(); refetchUser();
history.push(`/`); history.push(`/`);
} catch (e) { } catch (error) {
setToastApiError(e.toString()); setToastApiError(formatUnknownError(error));
} }
}; };

View File

@ -7,6 +7,7 @@ import { useAuthApi } from '../../../hooks/api/actions/useAuthApi/useAuthApi';
import { useAuthUser } from '../../../hooks/api/getters/useAuth/useAuthUser'; import { useAuthUser } from '../../../hooks/api/getters/useAuth/useAuthUser';
import { LOGIN_BUTTON, LOGIN_EMAIL_ID } from '../../../testIds'; import { LOGIN_BUTTON, LOGIN_EMAIL_ID } from '../../../testIds';
import useToast from '../../../hooks/useToast'; import useToast from '../../../hooks/useToast';
import { formatUnknownError } from '../../../utils/format-unknown-error';
const SimpleAuth = ({ authDetails }) => { const SimpleAuth = ({ authDetails }) => {
const [email, setEmail] = useState(''); const [email, setEmail] = useState('');
@ -22,8 +23,8 @@ const SimpleAuth = ({ authDetails }) => {
await emailAuth(authDetails.path, email); await emailAuth(authDetails.path, email);
refetchUser(); refetchUser();
history.push(`/`); history.push(`/`);
} catch (e) { } catch (error) {
setToastApiError(e.toString()); setToastApiError(formatUnknownError(error));
} }
}; };

View File

@ -1,4 +1,4 @@
import { SyntheticEvent, useState } from 'react'; import React, { SyntheticEvent, useState } from 'react';
import { Button, 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';

Some files were not shown because too many files have changed in this diff Show More