1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-05-17 01:17:29 +02:00

refactor: port some things to TS (#843)

* refactor: port useSort to TS

* refactor: port loadingFeatures to TS

* refactor: port admin index to TS

* refactor: port TagTypeList to TS

* refactor: merge route interfaces

* refactor: port common utils to TS

* refactor: fix snapshot date typo

* refactor: port Reporting utils to TS

* refactor: improve PermissionIconButton prop types
This commit is contained in:
olav 2022-04-06 12:22:24 +02:00 committed by GitHub
parent 73652b66e9
commit a088866124
24 changed files with 172 additions and 128 deletions

View File

@ -9,15 +9,17 @@ import {
sortFeaturesByExpiredAtDescending, sortFeaturesByExpiredAtDescending,
sortFeaturesByStatusAscending, sortFeaturesByStatusAscending,
sortFeaturesByStatusDescending, sortFeaturesByStatusDescending,
} from './utils'; } from 'component/Reporting/utils';
import { IFeatureToggleListItem } from 'interfaces/featureToggle';
const getTestData = () => [ const getTestData = (): IFeatureToggleListItem[] => [
{ {
name: 'abe', name: 'abe',
createdAt: '2021-02-14T02:42:34.515Z', createdAt: '2021-02-14T02:42:34.515Z',
lastSeenAt: '2021-02-21T19:34:21.830Z', lastSeenAt: '2021-02-21T19:34:21.830Z',
type: 'release', type: 'release',
stale: false, stale: false,
environments: [],
}, },
{ {
name: 'bet', name: 'bet',
@ -25,6 +27,7 @@ const getTestData = () => [
lastSeenAt: '2021-02-19T19:34:21.830Z', lastSeenAt: '2021-02-19T19:34:21.830Z',
type: 'release', type: 'release',
stale: false, stale: false,
environments: [],
}, },
{ {
name: 'cat', name: 'cat',
@ -32,6 +35,7 @@ const getTestData = () => [
lastSeenAt: '2021-02-18T19:34:21.830Z', lastSeenAt: '2021-02-18T19:34:21.830Z',
type: 'experiment', type: 'experiment',
stale: true, stale: true,
environments: [],
}, },
]; ];

View File

@ -4,38 +4,54 @@ import differenceInDays from 'date-fns/differenceInDays';
import { EXPERIMENT, OPERATIONAL, RELEASE } from 'constants/featureToggleTypes'; import { EXPERIMENT, OPERATIONAL, RELEASE } from 'constants/featureToggleTypes';
import { FOURTYDAYS, SEVENDAYS } from './constants'; import { FOURTYDAYS, SEVENDAYS } from './constants';
import { IFeatureToggleListItem } from 'interfaces/featureToggle';
export const toggleExpiryByTypeMap = { export const toggleExpiryByTypeMap: Record<string, number> = {
[EXPERIMENT]: FOURTYDAYS, [EXPERIMENT]: FOURTYDAYS,
[RELEASE]: FOURTYDAYS, [RELEASE]: FOURTYDAYS,
[OPERATIONAL]: SEVENDAYS, [OPERATIONAL]: SEVENDAYS,
}; };
export const applyCheckedToFeatures = (features, checkedState) => export interface IFeatureToggleListItemCheck extends IFeatureToggleListItem {
features.map(feature => ({ ...feature, checked: checkedState })); checked: boolean;
}
export const getCheckedState = (name, features) => { export const applyCheckedToFeatures = (
features: IFeatureToggleListItem[],
checkedState: boolean
): IFeatureToggleListItemCheck[] => {
return features.map(feature => ({
...feature,
checked: checkedState,
}));
};
export const getCheckedState = (
name: string,
features: IFeatureToggleListItemCheck[]
) => {
const feature = features.find(feature => feature.name === name); const feature = features.find(feature => feature.name === name);
if (feature) { if (feature) {
return feature.checked ? feature.checked : false; return feature.checked;
} }
return false; return false;
}; };
export const getDiffInDays = (date, now) => export const getDiffInDays = (date: Date, now: Date) =>
Math.abs(differenceInDays(date, now)); Math.abs(differenceInDays(date, now));
export const formatProjectOptions = projects => export const expired = (diff: number, type: string) => {
projects.map(project => ({ key: project.id, label: project.name }));
export const expired = (diff, type) => {
if (diff >= toggleExpiryByTypeMap[type]) return true; if (diff >= toggleExpiryByTypeMap[type]) return true;
return false; return false;
}; };
export const getObjectProperties = (target, ...keys) => { export const getObjectProperties = <T extends object>(
const newObject = {}; target: T,
...keys: (keyof T)[]
): Partial<T> => {
const newObject: Partial<T> = {};
keys.forEach(key => { keys.forEach(key => {
if (target[key] !== undefined) { if (target[key] !== undefined) {
@ -46,7 +62,9 @@ export const getObjectProperties = (target, ...keys) => {
return newObject; return newObject;
}; };
export const sortFeaturesByNameAscending = features => { export const sortFeaturesByNameAscending = (
features: IFeatureToggleListItem[]
): IFeatureToggleListItem[] => {
const sorted = [...features]; const sorted = [...features];
sorted.sort((a, b) => { sorted.sort((a, b) => {
if (a.name < b.name) { if (a.name < b.name) {
@ -60,10 +78,14 @@ export const sortFeaturesByNameAscending = features => {
return sorted; return sorted;
}; };
export const sortFeaturesByNameDescending = features => export const sortFeaturesByNameDescending = (
features: IFeatureToggleListItem[]
): IFeatureToggleListItem[] =>
sortFeaturesByNameAscending([...features]).reverse(); sortFeaturesByNameAscending([...features]).reverse();
export const sortFeaturesByLastSeenAscending = features => { export const sortFeaturesByLastSeenAscending = (
features: IFeatureToggleListItem[]
): IFeatureToggleListItem[] => {
const sorted = [...features]; const sorted = [...features];
sorted.sort((a, b) => { sorted.sort((a, b) => {
if (!a.lastSeenAt) return -1; if (!a.lastSeenAt) return -1;
@ -77,10 +99,14 @@ export const sortFeaturesByLastSeenAscending = features => {
return sorted; return sorted;
}; };
export const sortFeaturesByLastSeenDescending = features => export const sortFeaturesByLastSeenDescending = (
features: IFeatureToggleListItem[]
): IFeatureToggleListItem[] =>
sortFeaturesByLastSeenAscending([...features]).reverse(); sortFeaturesByLastSeenAscending([...features]).reverse();
export const sortFeaturesByCreatedAtAscending = features => { export const sortFeaturesByCreatedAtAscending = (
features: IFeatureToggleListItem[]
): IFeatureToggleListItem[] => {
const sorted = [...features]; const sorted = [...features];
sorted.sort((a, b) => { sorted.sort((a, b) => {
const dateA = parseISO(a.createdAt); const dateA = parseISO(a.createdAt);
@ -91,10 +117,14 @@ export const sortFeaturesByCreatedAtAscending = features => {
return sorted; return sorted;
}; };
export const sortFeaturesByCreatedAtDescending = features => export const sortFeaturesByCreatedAtDescending = (
features: IFeatureToggleListItem[]
): IFeatureToggleListItem[] =>
sortFeaturesByCreatedAtAscending([...features]).reverse(); sortFeaturesByCreatedAtAscending([...features]).reverse();
export const sortFeaturesByExpiredAtAscending = features => { export const sortFeaturesByExpiredAtAscending = (
features: IFeatureToggleListItem[]
): IFeatureToggleListItem[] => {
const sorted = [...features]; const sorted = [...features];
sorted.sort((a, b) => { sorted.sort((a, b) => {
const now = new Date(); const now = new Date();
@ -120,7 +150,9 @@ export const sortFeaturesByExpiredAtAscending = features => {
return sorted; return sorted;
}; };
export const sortFeaturesByExpiredAtDescending = features => { export const sortFeaturesByExpiredAtDescending = (
features: IFeatureToggleListItem[]
): IFeatureToggleListItem[] => {
const sorted = [...features]; const sorted = [...features];
const now = new Date(); const now = new Date();
sorted.sort((a, b) => { sorted.sort((a, b) => {
@ -146,7 +178,9 @@ export const sortFeaturesByExpiredAtDescending = features => {
return sorted; return sorted;
}; };
export const sortFeaturesByStatusAscending = features => { export const sortFeaturesByStatusAscending = (
features: IFeatureToggleListItem[]
): IFeatureToggleListItem[] => {
const sorted = [...features]; const sorted = [...features];
sorted.sort((a, b) => { sorted.sort((a, b) => {
if (a.stale) return 1; if (a.stale) return 1;
@ -156,15 +190,17 @@ export const sortFeaturesByStatusAscending = features => {
return sorted; return sorted;
}; };
export const sortFeaturesByStatusDescending = features => export const sortFeaturesByStatusDescending = (
features: IFeatureToggleListItem[]
): IFeatureToggleListItem[] =>
sortFeaturesByStatusAscending([...features]).reverse(); sortFeaturesByStatusAscending([...features]).reverse();
export const pluralize = (items, word) => { export const pluralize = (items: number, word: string): string => {
if (items === 1) return `${items} ${word}`; if (items === 1) return `${items} ${word}`;
return `${items} ${word}s`; return `${items} ${word}s`;
}; };
export const getDates = dateString => { export const getDates = (dateString: string): [Date, Date] => {
const date = parseISO(dateString); const date = parseISO(dateString);
const now = new Date(); const now = new Date();

View File

@ -69,7 +69,7 @@ const Constraint = ({
show={ show={
<div className={styles.btnContainer}> <div className={styles.btnContainer}>
<PermissionIconButton <PermissionIconButton
onClick={editCallback} onClick={editCallback!}
permission={UPDATE_FEATURE} permission={UPDATE_FEATURE}
projectId={projectId} projectId={projectId}
disabled={disabledEdit} disabled={disabledEdit}
@ -78,7 +78,7 @@ const Constraint = ({
</PermissionIconButton> </PermissionIconButton>
<PermissionIconButton <PermissionIconButton
onClick={deleteCallback} onClick={deleteCallback!}
permission={UPDATE_FEATURE} permission={UPDATE_FEATURE}
projectId={projectId} projectId={projectId}
> >

View File

@ -100,7 +100,7 @@ export const ConstraintAccordionViewHeader = ({
condition={Boolean(onEditClick)} condition={Boolean(onEditClick)}
show={ show={
<PermissionIconButton <PermissionIconButton
onClick={onEditClick} onClick={onEditClick!}
permission={UPDATE_FEATURE_STRATEGY} permission={UPDATE_FEATURE_STRATEGY}
projectId={projectId} projectId={projectId}
environmentId={environmentId} environmentId={environmentId}
@ -114,7 +114,7 @@ export const ConstraintAccordionViewHeader = ({
condition={Boolean(onDeleteClick)} condition={Boolean(onDeleteClick)}
show={ show={
<PermissionIconButton <PermissionIconButton
onClick={onDeleteClick} onClick={onDeleteClick!}
permission={UPDATE_FEATURE_STRATEGY} permission={UPDATE_FEATURE_STRATEGY}
projectId={projectId} projectId={projectId}
environmentId={environmentId} environmentId={environmentId}

View File

@ -1,26 +1,37 @@
import { IconButton, Tooltip, IconButtonProps } from '@material-ui/core'; import { IconButton, Tooltip, IconButtonProps } from '@material-ui/core';
import React, { useContext } from 'react'; import React, { useContext, ReactNode } from 'react';
import AccessContext from 'contexts/AccessContext'; import AccessContext from 'contexts/AccessContext';
import { Link } from 'react-router-dom';
interface IPermissionIconButtonProps extends IconButtonProps { interface IPermissionIconButtonProps {
permission: string; permission: string;
Icon?: React.ElementType;
onClick?: (e: any) => void;
projectId?: string; projectId?: string;
environmentId?: string; environmentId?: string;
className?: string; className?: string;
title?: string; title?: string;
children?: ReactNode;
disabled?: boolean;
hidden?: boolean;
type?: 'button';
edge?: IconButtonProps['edge'];
} }
const PermissionIconButton: React.FC<IPermissionIconButtonProps> = ({ interface IButtonProps extends IPermissionIconButtonProps {
onClick: (event: React.SyntheticEvent) => void;
}
interface ILinkProps extends IPermissionIconButtonProps {
component: typeof Link;
to: string;
}
const PermissionIconButton = ({
permission, permission,
Icon,
onClick,
projectId, projectId,
children, children,
environmentId, environmentId,
...rest ...rest
}) => { }: IButtonProps | ILinkProps) => {
const { hasAccess } = useContext(AccessContext); const { hasAccess } = useContext(AccessContext);
let access; let access;
@ -39,7 +50,7 @@ const PermissionIconButton: React.FC<IPermissionIconButtonProps> = ({
return ( return (
<Tooltip title={tooltipText} arrow> <Tooltip title={tooltipText} arrow>
<span> <span>
<IconButton onClick={onClick} disabled={!access} {...rest}> <IconButton disabled={!access} {...rest}>
{children} {children}
</IconButton> </IconButton>
</span> </span>

View File

@ -1,17 +1,21 @@
import { weightTypes } from '../feature/FeatureView/FeatureVariants/FeatureVariantsList/AddFeatureVariant/enums'; import { weightTypes } from '../feature/FeatureView/FeatureVariants/FeatureVariantsList/AddFeatureVariant/enums';
import { IFlags } from 'interfaces/uiConfig';
import { IRoute } from 'interfaces/route';
import { IFeatureVariant } from 'interfaces/featureToggle';
export const filterByFlags = flags => r => { export const filterByFlags = (flags: IFlags) => (r: IRoute) => {
if (r.flag && !flags[r.flag]) { if (!r.flag) {
return false; return true;
} }
return true;
return (flags as unknown as Record<string, boolean>)[r.flag];
}; };
export const scrollToTop = () => { export const scrollToTop = () => {
window.scrollTo(0, 0); window.scrollTo(0, 0);
}; };
export const trim = value => { export const trim = (value: string): string => {
if (value && value.trim) { if (value && value.trim) {
return value.trim(); return value.trim();
} else { } else {
@ -19,7 +23,7 @@ export const trim = value => {
} }
}; };
export function updateWeight(variants, totalWeight) { export function updateWeight(variants: IFeatureVariant[], totalWeight: number) {
if (variants.length === 0) { if (variants.length === 0) {
return []; return [];
} }
@ -48,7 +52,9 @@ export function updateWeight(variants, totalWeight) {
throw new Error('There must be at least one variable variant'); throw new Error('There must be at least one variable variant');
} }
const percentage = parseInt(remainingPercentage / variableVariantCount); const percentage = parseInt(
String(remainingPercentage / variableVariantCount)
);
return variants.map(variant => { return variants.map(variant => {
if (variant.weightType !== weightTypes.FIX) { if (variant.weightType !== weightTypes.FIX) {

View File

@ -1,4 +1,6 @@
const loadingFeatures = [ import { IFeatureToggle } from 'interfaces/featureToggle';
const loadingFeatures: Partial<IFeatureToggle>[] = [
{ {
createdAt: '2021-03-19T09:16:21.329Z', createdAt: '2021-03-19T09:16:21.329Z',
description: '', description: '',
@ -6,7 +8,6 @@ const loadingFeatures = [
lastSeenAt: '2021-03-24T10:46:38.036Z', lastSeenAt: '2021-03-24T10:46:38.036Z',
name: 'one', name: 'one',
project: 'default', project: 'default',
reviveName: 'cool-thing',
stale: true, stale: true,
strategies: [], strategies: [],
variants: [], variants: [],
@ -19,7 +20,6 @@ const loadingFeatures = [
lastSeenAt: '2021-03-24T10:46:38.036Z', lastSeenAt: '2021-03-24T10:46:38.036Z',
name: 'two', name: 'two',
project: 'default', project: 'default',
reviveName: 'cool-thing',
stale: true, stale: true,
strategies: [], strategies: [],
variants: [], variants: [],
@ -32,7 +32,6 @@ const loadingFeatures = [
lastSeenAt: '2021-03-24T10:46:38.036Z', lastSeenAt: '2021-03-24T10:46:38.036Z',
name: 'three', name: 'three',
project: 'default', project: 'default',
reviveName: 'cool-thing',
stale: true, stale: true,
strategies: [], strategies: [],
variants: [], variants: [],
@ -45,7 +44,6 @@ const loadingFeatures = [
lastSeenAt: '2021-03-24T10:46:38.036Z', lastSeenAt: '2021-03-24T10:46:38.036Z',
name: 'four', name: 'four',
project: 'default', project: 'default',
reviveName: 'cool-thing',
stale: true, stale: true,
strategies: [], strategies: [],
variants: [], variants: [],
@ -58,7 +56,6 @@ const loadingFeatures = [
lastSeenAt: '2021-03-24T10:46:38.036Z', lastSeenAt: '2021-03-24T10:46:38.036Z',
name: 'five', name: 'five',
project: 'default', project: 'default',
reviveName: 'cool-thing',
stale: true, stale: true,
strategies: [], strategies: [],
variants: [], variants: [],
@ -71,7 +68,6 @@ const loadingFeatures = [
lastSeenAt: '2021-03-24T10:46:38.036Z', lastSeenAt: '2021-03-24T10:46:38.036Z',
name: 'six', name: 'six',
project: 'default', project: 'default',
reviveName: 'cool-thing',
stale: true, stale: true,
strategies: [], strategies: [],
variants: [], variants: [],
@ -84,7 +80,6 @@ const loadingFeatures = [
lastSeenAt: '2021-03-24T10:46:38.036Z', lastSeenAt: '2021-03-24T10:46:38.036Z',
name: 'seven', name: 'seven',
project: 'default', project: 'default',
reviveName: 'cool-thing',
stale: true, stale: true,
strategies: [], strategies: [],
variants: [], variants: [],
@ -97,7 +92,6 @@ const loadingFeatures = [
lastSeenAt: '2021-03-24T10:46:38.036Z', lastSeenAt: '2021-03-24T10:46:38.036Z',
name: 'eight', name: 'eight',
project: 'default', project: 'default',
reviveName: 'cool-thing',
stale: true, stale: true,
strategies: [], strategies: [],
variants: [], variants: [],
@ -110,7 +104,6 @@ const loadingFeatures = [
lastSeenAt: '2021-03-24T10:46:38.036Z', lastSeenAt: '2021-03-24T10:46:38.036Z',
name: 'nine', name: 'nine',
project: 'default', project: 'default',
reviveName: 'cool-thing',
stale: true, stale: true,
strategies: [], strategies: [],
variants: [], variants: [],
@ -123,7 +116,6 @@ const loadingFeatures = [
lastSeenAt: '2021-03-24T10:46:38.036Z', lastSeenAt: '2021-03-24T10:46:38.036Z',
name: 'ten', name: 'ten',
project: 'default', project: 'default',
reviveName: 'cool-thing',
stale: true, stale: true,
strategies: [], strategies: [],
variants: [], variants: [],

View File

@ -1,11 +1,13 @@
const loadingFeatures = [ import { IFeatureToggleListItem } from 'interfaces/featureToggle';
const loadingFeatures: IFeatureToggleListItem[] = [
{ {
type: 'release', type: 'release',
name: 'loading1', name: 'loading1',
createdAt: '2006-01-02T15:04:05Z',
environments: [ environments: [
{ {
name: ':global:', name: ':global:',
displayName: 'Across all environments',
enabled: true, enabled: true,
}, },
], ],
@ -13,10 +15,10 @@ const loadingFeatures = [
{ {
type: 'release', type: 'release',
name: 'loadg2', name: 'loadg2',
createdAt: '2006-01-02T15:04:05Z',
environments: [ environments: [
{ {
name: ':global:', name: ':global:',
displayName: 'Across all environments',
enabled: true, enabled: true,
}, },
], ],
@ -24,10 +26,10 @@ const loadingFeatures = [
{ {
type: 'release', type: 'release',
name: 'loading3', name: 'loading3',
createdAt: '2006-01-02T15:04:05Z',
environments: [ environments: [
{ {
name: ':global:', name: ':global:',
displayName: 'Across all environments',
enabled: true, enabled: true,
}, },
], ],
@ -35,10 +37,10 @@ const loadingFeatures = [
{ {
type: 'release', type: 'release',
name: 'loadi4', name: 'loadi4',
createdAt: '2006-01-02T15:04:05Z',
environments: [ environments: [
{ {
name: ':global:', name: ':global:',
displayName: 'Across all environments',
enabled: true, enabled: true,
}, },
], ],
@ -46,10 +48,10 @@ const loadingFeatures = [
{ {
type: 'release', type: 'release',
name: 'loadi5', name: 'loadi5',
createdAt: '2006-01-02T15:04:05Z',
environments: [ environments: [
{ {
name: ':global:', name: ':global:',
displayName: 'Across all environments',
enabled: true, enabled: true,
}, },
], ],
@ -57,10 +59,10 @@ const loadingFeatures = [
{ {
type: 'release', type: 'release',
name: 'loadg6', name: 'loadg6',
createdAt: '2006-01-02T15:04:05Z',
environments: [ environments: [
{ {
name: ':global:', name: ':global:',
displayName: 'Across all environments',
enabled: true, enabled: true,
}, },
], ],
@ -68,10 +70,10 @@ const loadingFeatures = [
{ {
type: 'release', type: 'release',
name: 'loading7', name: 'loading7',
createdAt: '2006-01-02T15:04:05Z',
environments: [ environments: [
{ {
name: ':global:', name: ':global:',
displayName: 'Across all environments',
enabled: true, enabled: true,
}, },
], ],
@ -79,10 +81,10 @@ const loadingFeatures = [
{ {
type: 'release', type: 'release',
name: 'ln8', name: 'ln8',
createdAt: '2006-01-02T15:04:05Z',
environments: [ environments: [
{ {
name: ':global:', name: ':global:',
displayName: 'Across all environments',
enabled: true, enabled: true,
}, },
], ],
@ -90,10 +92,10 @@ const loadingFeatures = [
{ {
type: 'release', type: 'release',
name: 'load9', name: 'load9',
createdAt: '2006-01-02T15:04:05Z',
environments: [ environments: [
{ {
name: ':global:', name: ':global:',
displayName: 'Across all environments',
enabled: true, enabled: true,
}, },
], ],

View File

@ -51,7 +51,6 @@ const FeatureOverviewEnvironmentStrategy = ({
permission={UPDATE_FEATURE_STRATEGY} permission={UPDATE_FEATURE_STRATEGY}
environmentId={environmentId} environmentId={environmentId}
projectId={projectId} projectId={projectId}
// @ts-expect-error
component={Link} component={Link}
to={editStrategyPath} to={editStrategyPath}
> >

View File

@ -49,7 +49,6 @@ const FeatureOverviewMetaData = () => {
<PermissionIconButton <PermissionIconButton
projectId={projectId} projectId={projectId}
permission={UPDATE_FEATURE} permission={UPDATE_FEATURE}
// @ts-expect-error
component={Link} component={Link}
to={`/projects/${projectId}/features/${featureId}/settings`} to={`/projects/${projectId}/features/${featureId}/settings`}
> >
@ -65,7 +64,6 @@ const FeatureOverviewMetaData = () => {
<PermissionIconButton <PermissionIconButton
projectId={projectId} projectId={projectId}
permission={UPDATE_FEATURE} permission={UPDATE_FEATURE}
// @ts-expect-error
component={Link} component={Link}
to={`/projects/${projectId}/features/${featureId}/settings`} to={`/projects/${projectId}/features/${featureId}/settings`}
> >

View File

@ -141,7 +141,6 @@ export const FeatureView = () => {
permission={CREATE_FEATURE} permission={CREATE_FEATURE}
projectId={projectId} projectId={projectId}
data-loading data-loading
// @ts-expect-error
component={Link} component={Link}
to={`/projects/${projectId}/features/${featureId}/strategies/copy`} to={`/projects/${projectId}/features/${featureId}/strategies/copy`}
> >

View File

@ -50,26 +50,9 @@ import { CreateUnleashContextPage } from 'component/context/CreateUnleashContext
import { CreateSegment } from 'component/segments/CreateSegment/CreateSegment'; import { CreateSegment } from 'component/segments/CreateSegment/CreateSegment';
import { EditSegment } from 'component/segments/EditSegment/EditSegment'; import { EditSegment } from 'component/segments/EditSegment/EditSegment';
import { SegmentsList } from 'component/segments/SegmentList/SegmentList'; import { SegmentsList } from 'component/segments/SegmentList/SegmentList';
import { FunctionComponent } from 'react'; import { IRoute } from 'interfaces/route';
interface Route { export const routes: IRoute[] = [
path: string;
title: string;
type: string;
layout?: string;
parent?: string;
flag?: string;
hidden?: Boolean;
component: FunctionComponent;
menu: {
mobile?: boolean;
advanced?: boolean;
adminSettings?: boolean;
};
}
export const routes: Route[] = [
// Splash // Splash
{ {
path: '/splash/:splashId', path: '/splash/:splashId',

View File

@ -52,7 +52,6 @@ const ProjectInfo = ({
<PermissionIconButton <PermissionIconButton
permission={UPDATE_PROJECT} permission={UPDATE_PROJECT}
projectId={id} projectId={id}
// @ts-expect-error
component={Link} component={Link}
className={permissionButtonClass} className={permissionButtonClass}
data-loading data-loading

View File

@ -27,10 +27,14 @@ import useTagTypes from 'hooks/api/getters/useTagTypes/useTagTypes';
import useToast from 'hooks/useToast'; import useToast from 'hooks/useToast';
import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton'; import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton';
import { formatUnknownError } from 'utils/formatUnknownError'; import { formatUnknownError } from 'utils/formatUnknownError';
import { ITagType } from 'interfaces/tags';
export const TagTypeList = () => { export const TagTypeList = () => {
const { hasAccess } = useContext(AccessContext); const { hasAccess } = useContext(AccessContext);
const [deletion, setDeletion] = useState({ open: false }); const [deletion, setDeletion] = useState<{
open: boolean;
name?: string;
}>({ open: false });
const history = useHistory(); const history = useHistory();
const smallScreen = useMediaQuery('(max-width:700px)'); const smallScreen = useMediaQuery('(max-width:700px)');
const { deleteTagType } = useTagTypesApi(); const { deleteTagType } = useTagTypesApi();
@ -39,14 +43,16 @@ export const TagTypeList = () => {
const deleteTag = async () => { const deleteTag = async () => {
try { try {
await deleteTagType(deletion.name); if (deletion.name) {
refetch(); await deleteTagType(deletion.name);
setDeletion({ open: false }); refetch();
setToastData({ setDeletion({ open: false });
type: 'success', setToastData({
show: true, type: 'success',
text: 'Successfully deleted tag type.', show: true,
}); title: 'Successfully deleted tag type.',
});
}
} catch (error) { } catch (error) {
setToastApiError(formatUnknownError(error)); setToastApiError(formatUnknownError(error));
} }
@ -91,7 +97,7 @@ export const TagTypeList = () => {
/> />
); );
const renderTagType = tagType => { const renderTagType = (tagType: ITagType) => {
let link = ( let link = (
<Link to={`/tag-types/edit/${tagType.name}`}> <Link to={`/tag-types/edit/${tagType.name}`}>
<strong>{tagType.name}</strong> <strong>{tagType.name}</strong>
@ -126,7 +132,7 @@ export const TagTypeList = () => {
component={Link} component={Link}
to={`/tag-types/edit/${tagType.name}`} to={`/tag-types/edit/${tagType.name}`}
> >
<Edit className={styles.icon} /> <Edit className={styles.icon} titleAccess="Edit tag type" />
</PermissionIconButton> </PermissionIconButton>
<ConditionallyRender <ConditionallyRender
condition={hasAccess(DELETE_TAG_TYPE)} condition={hasAccess(DELETE_TAG_TYPE)}

View File

@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import { TagTypeList } from '../TagTypeList'; import { TagTypeList } from 'component/tags/TagTypeList/TagTypeList';
import renderer from 'react-test-renderer'; import renderer from 'react-test-renderer';
import { MemoryRouter } from 'react-router-dom'; import { MemoryRouter } from 'react-router-dom';
import { ThemeProvider } from '@material-ui/styles'; import { ThemeProvider } from '@material-ui/styles';

View File

@ -9,7 +9,7 @@ Object {
"filtered": Array [ "filtered": Array [
Object { Object {
"archived": false, "archived": false,
"createdAt": "22006-01-02T15:04:05Z", "createdAt": "2006-01-02T15:04:05Z",
"description": "1", "description": "1",
"enabled": false, "enabled": false,
"environments": Array [], "environments": Array [],
@ -81,7 +81,7 @@ Object {
"filtered": Array [ "filtered": Array [
Object { Object {
"archived": false, "archived": false,
"createdAt": "22006-01-02T15:04:05Z", "createdAt": "2006-01-02T15:04:05Z",
"description": "1", "description": "1",
"enabled": false, "enabled": false,
"environments": Array [], "environments": Array [],
@ -96,7 +96,7 @@ Object {
}, },
Object { Object {
"archived": false, "archived": false,
"createdAt": "22006-01-02T15:04:05Z", "createdAt": "2006-01-02T15:04:05Z",
"description": "1", "description": "1",
"enabled": false, "enabled": false,
"environments": Array [], "environments": Array [],
@ -111,7 +111,7 @@ Object {
}, },
Object { Object {
"archived": false, "archived": false,
"createdAt": "22006-01-02T15:04:05Z", "createdAt": "2006-01-02T15:04:05Z",
"description": "1", "description": "1",
"enabled": false, "enabled": false,
"environments": Array [], "environments": Array [],
@ -137,7 +137,7 @@ Object {
"filtered": Array [ "filtered": Array [
Object { Object {
"archived": false, "archived": false,
"createdAt": "22006-01-02T15:04:05Z", "createdAt": "2006-01-02T15:04:05Z",
"description": "1", "description": "1",
"enabled": false, "enabled": false,
"environments": Array [], "environments": Array [],
@ -152,7 +152,7 @@ Object {
}, },
Object { Object {
"archived": false, "archived": false,
"createdAt": "22006-01-02T15:04:05Z", "createdAt": "2006-01-02T15:04:05Z",
"description": "1", "description": "1",
"enabled": false, "enabled": false,
"environments": Array [], "environments": Array [],
@ -179,7 +179,7 @@ Object {
"filtered": Array [ "filtered": Array [
Object { Object {
"archived": false, "archived": false,
"createdAt": "22006-01-02T15:04:05Z", "createdAt": "2006-01-02T15:04:05Z",
"description": "1", "description": "1",
"enabled": false, "enabled": false,
"environments": Array [], "environments": Array [],
@ -194,7 +194,7 @@ Object {
}, },
Object { Object {
"archived": false, "archived": false,
"createdAt": "22006-01-02T15:04:05Z", "createdAt": "2006-01-02T15:04:05Z",
"description": "1", "description": "1",
"enabled": false, "enabled": false,
"environments": Array [], "environments": Array [],

View File

@ -102,7 +102,7 @@ const mockFeatureToggle = (
strategies: [], strategies: [],
variants: [], variants: [],
environments: [], environments: [],
createdAt: '22006-01-02T15:04:05Z', createdAt: '2006-01-02T15:04:05Z',
lastSeenAt: '2006-01-02T15:04:05Z', lastSeenAt: '2006-01-02T15:04:05Z',
...overrides, ...overrides,
}; };

View File

@ -10,7 +10,7 @@ import {
sortFeaturesByExpiredAtDescending, sortFeaturesByExpiredAtDescending,
sortFeaturesByStatusAscending, sortFeaturesByStatusAscending,
sortFeaturesByStatusDescending, sortFeaturesByStatusDescending,
} from '../component/Reporting/utils'; } from 'component/Reporting/utils';
import { import {
LAST_SEEN, LAST_SEEN,
@ -19,7 +19,8 @@ import {
EXPIRED, EXPIRED,
STATUS, STATUS,
REPORT, REPORT,
} from '../component/Reporting/constants'; } from 'component/Reporting/constants';
import { IFeatureToggleListItem } from 'interfaces/featureToggle';
const useSort = () => { const useSort = () => {
const [sortData, setSortData] = useState({ const [sortData, setSortData] = useState({
@ -27,7 +28,7 @@ const useSort = () => {
ascending: true, ascending: true,
}); });
const handleSortName = features => { const handleSortName = (features: IFeatureToggleListItem[]) => {
if (sortData.ascending) { if (sortData.ascending) {
return sortFeaturesByNameAscending(features); return sortFeaturesByNameAscending(features);
} }
@ -35,35 +36,35 @@ const useSort = () => {
return sortFeaturesByNameDescending(features); return sortFeaturesByNameDescending(features);
}; };
const handleSortLastSeen = features => { const handleSortLastSeen = (features: IFeatureToggleListItem[]) => {
if (sortData.ascending) { if (sortData.ascending) {
return sortFeaturesByLastSeenAscending(features); return sortFeaturesByLastSeenAscending(features);
} }
return sortFeaturesByLastSeenDescending(features); return sortFeaturesByLastSeenDescending(features);
}; };
const handleSortCreatedAt = features => { const handleSortCreatedAt = (features: IFeatureToggleListItem[]) => {
if (sortData.ascending) { if (sortData.ascending) {
return sortFeaturesByCreatedAtAscending(features); return sortFeaturesByCreatedAtAscending(features);
} }
return sortFeaturesByCreatedAtDescending(features); return sortFeaturesByCreatedAtDescending(features);
}; };
const handleSortExpiredAt = features => { const handleSortExpiredAt = (features: IFeatureToggleListItem[]) => {
if (sortData.ascending) { if (sortData.ascending) {
return sortFeaturesByExpiredAtAscending(features); return sortFeaturesByExpiredAtAscending(features);
} }
return sortFeaturesByExpiredAtDescending(features); return sortFeaturesByExpiredAtDescending(features);
}; };
const handleSortStatus = features => { const handleSortStatus = (features: IFeatureToggleListItem[]) => {
if (sortData.ascending) { if (sortData.ascending) {
return sortFeaturesByStatusAscending(features); return sortFeaturesByStatusAscending(features);
} }
return sortFeaturesByStatusDescending(features); return sortFeaturesByStatusDescending(features);
}; };
const sort = features => { const sort = (features: IFeatureToggleListItem[]) => {
switch (sortData.sortKey) { switch (sortData.sortKey) {
case NAME: case NAME:
return handleSortName(features); return handleSortName(features);

View File

@ -3,6 +3,9 @@ import { IFeatureStrategy } from './strategy';
export interface IFeatureToggleListItem { export interface IFeatureToggleListItem {
type: string; type: string;
name: string; name: string;
stale?: boolean;
lastSeenAt?: string;
createdAt: string;
environments: IEnvironments[]; environments: IEnvironments[];
} }

View File

@ -1,14 +1,19 @@
import React from 'react'; import { FunctionComponent } from 'react';
interface IRoute { export interface IRoute {
path: string; path: string;
icon?: string; title: string;
title?: string;
component: React.ComponentType;
type: string; type: string;
hidden?: boolean; layout?: string;
flag?: string;
parent?: string; parent?: string;
flag?: string;
hidden?: boolean;
component: FunctionComponent;
menu: IRouteMenu;
} }
export default IRoute; interface IRouteMenu {
mobile?: boolean;
advanced?: boolean;
adminSettings?: boolean;
}