From 0dba973881b92a1bcca75507782931f8932d4530 Mon Sep 17 00:00:00 2001 From: Mateusz Kwasniewski Date: Wed, 26 Oct 2022 09:45:24 +0200 Subject: [PATCH] Feat/apply changes (#2258) * feat: add suggested change component * fix: build * feat: suggestion header * ui sketching different toggle changes * feat: strategy change sets UI tweaks * refactor: extract nested components Co-authored-by: Fredrik Oseberg --- frontend/src/assets/icons/merge.svg | 3 + .../PlaygroundResultChip.tsx | 1 + .../src/component/project/Project/Project.tsx | 12 +- .../DraftBanner/DraftBanner.tsx | 6 - .../SuggestedChangeHeader.tsx | 68 ++++++++ .../SuggestedChangeOverview.tsx | 31 ++++ .../SuggestedChangeReviewers.tsx | 16 ++ .../SuggestedChangeSet/SuggestedChangeSet.tsx | 90 ++++++++++ .../SuggestedChangeTimeline.tsx | 52 ++++++ .../StrategyChange.tsx | 27 +++ .../SuggestedFeatureToggleChange.tsx | 37 ++++ .../ToggleStatusChange.tsx | 16 ++ .../SuggestedChanges/SuggestedChanges.tsx | 163 ------------------ .../useChangeRequest/useChangeRequest.ts | 50 ------ .../useSuggestChange/useSuggestedChange.ts | 101 +++++++++++ frontend/src/utils/strategyNames.tsx | 7 + 16 files changed, 460 insertions(+), 220 deletions(-) create mode 100644 frontend/src/assets/icons/merge.svg create mode 100644 frontend/src/component/project/Project/SuggestedChanges/SuggestedChangeOverview/SuggestedChangeHeader/SuggestedChangeHeader.tsx create mode 100644 frontend/src/component/project/Project/SuggestedChanges/SuggestedChangeOverview/SuggestedChangeOverview.tsx create mode 100644 frontend/src/component/project/Project/SuggestedChanges/SuggestedChangeOverview/SuggestedChangeReviewers/SuggestedChangeReviewers.tsx create mode 100644 frontend/src/component/project/Project/SuggestedChanges/SuggestedChangeOverview/SuggestedChangeSet/SuggestedChangeSet.tsx create mode 100644 frontend/src/component/project/Project/SuggestedChanges/SuggestedChangeOverview/SuggestedChangeTimeline/SuggestedChangeTimeline.tsx create mode 100644 frontend/src/component/project/Project/SuggestedChanges/SuggestedChangeOverview/SuggestedFeatureToggleChange/StrategyChange.tsx create mode 100644 frontend/src/component/project/Project/SuggestedChanges/SuggestedChangeOverview/SuggestedFeatureToggleChange/SuggestedFeatureToggleChange.tsx create mode 100644 frontend/src/component/project/Project/SuggestedChanges/SuggestedChangeOverview/SuggestedFeatureToggleChange/ToggleStatusChange.tsx delete mode 100644 frontend/src/component/project/Project/SuggestedChanges/SuggestedChanges.tsx delete mode 100644 frontend/src/hooks/api/getters/useChangeRequest/useChangeRequest.ts create mode 100644 frontend/src/hooks/api/getters/useSuggestChange/useSuggestedChange.ts diff --git a/frontend/src/assets/icons/merge.svg b/frontend/src/assets/icons/merge.svg new file mode 100644 index 0000000000..b7a15a8864 --- /dev/null +++ b/frontend/src/assets/icons/merge.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/component/playground/Playground/PlaygroundResultsTable/PlaygroundResultChip/PlaygroundResultChip.tsx b/frontend/src/component/playground/Playground/PlaygroundResultsTable/PlaygroundResultChip/PlaygroundResultChip.tsx index e6618ac7ea..6c02cd3320 100644 --- a/frontend/src/component/playground/Playground/PlaygroundResultsTable/PlaygroundResultChip/PlaygroundResultChip.tsx +++ b/frontend/src/component/playground/Playground/PlaygroundResultsTable/PlaygroundResultChip/PlaygroundResultChip.tsx @@ -43,6 +43,7 @@ export const StyledTrueChip = styled(StyledChip)(({ theme }) => ({ }, ['& .MuiChip-icon']: { color: theme.palette.success.main, + marginRight: 0, }, })); diff --git a/frontend/src/component/project/Project/Project.tsx b/frontend/src/component/project/Project/Project.tsx index 1c5073f0e1..f2555a6eb2 100644 --- a/frontend/src/component/project/Project/Project.tsx +++ b/frontend/src/component/project/Project/Project.tsx @@ -24,7 +24,7 @@ import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; import { Routes, Route, useLocation } from 'react-router-dom'; import { DeleteProjectDialogue } from './DeleteProject/DeleteProjectDialogue'; import { ProjectLog } from './ProjectLog/ProjectLog'; -import { SuggestedChanges } from './SuggestedChanges/SuggestedChanges'; +import { SuggestedChangeOverview } from './SuggestedChanges/SuggestedChangeOverview/SuggestedChangeOverview'; import { DraftBanner } from './SuggestedChanges/DraftBanner/DraftBanner'; import { MainLayout } from 'component/layout/MainLayout/MainLayout'; @@ -224,6 +224,16 @@ const Project = () => { } /> } /> } /> + } + /> + } + /> + } /> diff --git a/frontend/src/component/project/Project/SuggestedChanges/DraftBanner/DraftBanner.tsx b/frontend/src/component/project/Project/SuggestedChanges/DraftBanner/DraftBanner.tsx index 01d1e9ce7c..c5f98de4d8 100644 --- a/frontend/src/component/project/Project/SuggestedChanges/DraftBanner/DraftBanner.tsx +++ b/frontend/src/component/project/Project/SuggestedChanges/DraftBanner/DraftBanner.tsx @@ -3,8 +3,6 @@ import { Box, Button, Typography } from '@mui/material'; import { useStyles as useAppStyles } from 'component/App.styles'; import WarningAmberIcon from '@mui/icons-material/WarningAmber'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; -import { EditGroupUsers } from '../../../../admin/groups/Group/EditGroupUsers/EditGroupUsers'; -import { SuggestedChanges } from '../SuggestedChanges'; interface IDraftBannerProps { environment?: string; @@ -61,10 +59,6 @@ export const DraftBanner: VFC = ({ environment }) => { - ); }; diff --git a/frontend/src/component/project/Project/SuggestedChanges/SuggestedChangeOverview/SuggestedChangeHeader/SuggestedChangeHeader.tsx b/frontend/src/component/project/Project/SuggestedChanges/SuggestedChangeOverview/SuggestedChangeHeader/SuggestedChangeHeader.tsx new file mode 100644 index 0000000000..558851ba32 --- /dev/null +++ b/frontend/src/component/project/Project/SuggestedChanges/SuggestedChangeOverview/SuggestedChangeHeader/SuggestedChangeHeader.tsx @@ -0,0 +1,68 @@ +import { FC } from 'react'; +import { Avatar, Box, Card, Paper, Typography } from '@mui/material'; +import { StyledTrueChip } from '../../../../../playground/Playground/PlaygroundResultsTable/PlaygroundResultChip/PlaygroundResultChip'; +import { ReactComponent as ChangesAppliedIcon } from '../../../../../../assets/icons/merge.svg'; +import TimeAgo from 'react-timeago'; + +export const SuggestedChangeHeader: FC<{ suggestedChange: any }> = ({ + suggestedChange, +}) => { + return ( + ({ + p: theme.spacing(2, 4), + borderRadius: theme => `${theme.shape.borderRadiusLarge}px`, + })} + > + ({ + display: 'flex', + alignItems: 'center', + gap: 2, + marginBottom: theme.spacing(2), + })} + > + + Suggestion + + #{suggestedChange.id} + + + } + label="Changes applied" + /> + + + + Created{' '} + by + + + ({ + padding: 1, + backgroundColor: theme.palette.tertiary.light, + })} + > + Environment:{' '} + + {suggestedChange?.environment} + {' '} + | Updates:{' '} + + {suggestedChange?.changes.length} feature toggles + + + + + ); +}; diff --git a/frontend/src/component/project/Project/SuggestedChanges/SuggestedChangeOverview/SuggestedChangeOverview.tsx b/frontend/src/component/project/Project/SuggestedChanges/SuggestedChangeOverview/SuggestedChangeOverview.tsx new file mode 100644 index 0000000000..cc90a3fac3 --- /dev/null +++ b/frontend/src/component/project/Project/SuggestedChanges/SuggestedChangeOverview/SuggestedChangeOverview.tsx @@ -0,0 +1,31 @@ +import { FC } from 'react'; +import { Box } from '@mui/material'; +import { useSuggestedChange } from 'hooks/api/getters/useSuggestChange/useSuggestedChange'; +import { SuggestedChangeHeader } from './SuggestedChangeHeader/SuggestedChangeHeader'; +import { SuggestedChangeTimeline } from './SuggestedChangeTimeline/SuggestedChangeTimeline'; +import { SuggestedChangeReviewers } from './SuggestedChangeReviewers/SuggestedChangeReviewers'; +import { SuggestedChangeSet } from './SuggestedChangeSet/SuggestedChangeSet'; + +export const SuggestedChangeOverview: FC = () => { + const { data: suggestedChange } = useSuggestedChange(); + + return ( + <> + + + + + + + + + + + ); +}; diff --git a/frontend/src/component/project/Project/SuggestedChanges/SuggestedChangeOverview/SuggestedChangeReviewers/SuggestedChangeReviewers.tsx b/frontend/src/component/project/Project/SuggestedChanges/SuggestedChangeOverview/SuggestedChangeReviewers/SuggestedChangeReviewers.tsx new file mode 100644 index 0000000000..d4a0a31f05 --- /dev/null +++ b/frontend/src/component/project/Project/SuggestedChanges/SuggestedChangeOverview/SuggestedChangeReviewers/SuggestedChangeReviewers.tsx @@ -0,0 +1,16 @@ +import { Box, Paper } from '@mui/material'; + +export const SuggestedChangeReviewers = () => { + return ( + ({ + marginTop: theme.spacing(2), + padding: 2, + borderRadius: theme => `${theme.shape.borderRadiusLarge}px`, + })} + > + ({ padding: theme.spacing(2) })}>Reviewers + + ); +}; diff --git a/frontend/src/component/project/Project/SuggestedChanges/SuggestedChangeOverview/SuggestedChangeSet/SuggestedChangeSet.tsx b/frontend/src/component/project/Project/SuggestedChanges/SuggestedChangeOverview/SuggestedChangeSet/SuggestedChangeSet.tsx new file mode 100644 index 0000000000..d79f178b79 --- /dev/null +++ b/frontend/src/component/project/Project/SuggestedChanges/SuggestedChangeOverview/SuggestedChangeSet/SuggestedChangeSet.tsx @@ -0,0 +1,90 @@ +import { FC } from 'react'; +import { Box, Paper } from '@mui/material'; +import { SuggestedFeatureToggleChange } from '../SuggestedFeatureToggleChange/SuggestedFeatureToggleChange'; +import { objectId } from '../../../../../../utils/objectId'; +import { ConditionallyRender } from '../../../../../common/ConditionallyRender/ConditionallyRender'; +import { ToggleStatusChange } from '../SuggestedFeatureToggleChange/ToggleStatusChange'; +import { + StrategyAddedChange, + StrategyDeletedChange, + StrategyEditedChange, +} from '../SuggestedFeatureToggleChange/StrategyChange'; +import { + formatStrategyName, + GetFeatureStrategyIcon, +} from '../../../../../../utils/strategyNames'; + +export const SuggestedChangeSet: FC<{ suggestedChange: any }> = ({ + suggestedChange, +}) => { + return ( + ({ + marginTop: theme.spacing(2), + marginLeft: theme.spacing(2), + width: '70%', + padding: 2, + borderRadius: theme => `${theme.shape.borderRadiusLarge}px`, + })} + > + ({ + padding: theme.spacing(2), + })} + > + Changes + {suggestedChange.changes?.map((featureToggleChange: any) => ( + + {featureToggleChange.changeSet.map((change: any) => ( + + + } + /> + + + {formatStrategyName( + change.payload.name + )} + + } + /> + } + /> + } + /> + + ))} + + ))} + + + ); +}; diff --git a/frontend/src/component/project/Project/SuggestedChanges/SuggestedChangeOverview/SuggestedChangeTimeline/SuggestedChangeTimeline.tsx b/frontend/src/component/project/Project/SuggestedChanges/SuggestedChangeOverview/SuggestedChangeTimeline/SuggestedChangeTimeline.tsx new file mode 100644 index 0000000000..80b04bc997 --- /dev/null +++ b/frontend/src/component/project/Project/SuggestedChanges/SuggestedChangeOverview/SuggestedChangeTimeline/SuggestedChangeTimeline.tsx @@ -0,0 +1,52 @@ +import { FC } from 'react'; +import { Box, Paper } from '@mui/material'; +import Timeline from '@mui/lab/Timeline'; +import TimelineItem, { timelineItemClasses } from '@mui/lab/TimelineItem'; +import TimelineSeparator from '@mui/lab/TimelineSeparator'; +import TimelineDot from '@mui/lab/TimelineDot'; +import TimelineConnector from '@mui/lab/TimelineConnector'; +import TimelineContent from '@mui/lab/TimelineContent'; + +export const SuggestedChangeTimeline: FC = () => { + return ( + ({ + marginTop: theme.spacing(2), + borderRadius: theme => `${theme.shape.borderRadiusLarge}px`, + })} + > + ({ padding: theme.spacing(2) })}> + + + + + + + Draft + + + + + + + Approved + + + + + + Applied + + + + + ); +}; diff --git a/frontend/src/component/project/Project/SuggestedChanges/SuggestedChangeOverview/SuggestedFeatureToggleChange/StrategyChange.tsx b/frontend/src/component/project/Project/SuggestedChanges/SuggestedChangeOverview/SuggestedFeatureToggleChange/StrategyChange.tsx new file mode 100644 index 0000000000..32728cca0e --- /dev/null +++ b/frontend/src/component/project/Project/SuggestedChanges/SuggestedChangeOverview/SuggestedFeatureToggleChange/StrategyChange.tsx @@ -0,0 +1,27 @@ +import { Box, Typography } from '@mui/material'; +import { FC } from 'react'; + +export const StrategyAddedChange: FC = ({ children }) => { + return ( + + ({ color: theme.palette.success.main })}> + + Strategy Added: + + {children} + + ); +}; + +export const StrategyEditedChange: FC = () => { + return Strategy Edited; +}; + +export const StrategyDeletedChange: FC = () => { + return ( + + ({ color: theme.palette.error.main })}> + - Strategy Deleted + + + ); +}; diff --git a/frontend/src/component/project/Project/SuggestedChanges/SuggestedChangeOverview/SuggestedFeatureToggleChange/SuggestedFeatureToggleChange.tsx b/frontend/src/component/project/Project/SuggestedChanges/SuggestedChangeOverview/SuggestedFeatureToggleChange/SuggestedFeatureToggleChange.tsx new file mode 100644 index 0000000000..a134ffe46f --- /dev/null +++ b/frontend/src/component/project/Project/SuggestedChanges/SuggestedChangeOverview/SuggestedFeatureToggleChange/SuggestedFeatureToggleChange.tsx @@ -0,0 +1,37 @@ +import { FC } from 'react'; +import { Box, Card, Typography } from '@mui/material'; +import ToggleOnIcon from '@mui/icons-material/ToggleOn'; + +interface ISuggestedFeatureToggleChange { + featureToggleName: string; +} + +export const SuggestedFeatureToggleChange: FC< + ISuggestedFeatureToggleChange +> = ({ featureToggleName, children }) => { + return ( + ({ + marginTop: theme.spacing(2), + borderRadius: theme => `${theme.shape.borderRadiusLarge}px`, + overflow: 'hidden', + border: '1px solid', + borderColor: theme => theme.palette.dividerAlternative, + })} + > + ({ + backgroundColor: theme.palette.tableHeaderBackground, + p: 2, + })} + > + + + {featureToggleName} + + + {children} + + ); +}; diff --git a/frontend/src/component/project/Project/SuggestedChanges/SuggestedChangeOverview/SuggestedFeatureToggleChange/ToggleStatusChange.tsx b/frontend/src/component/project/Project/SuggestedChanges/SuggestedChangeOverview/SuggestedFeatureToggleChange/ToggleStatusChange.tsx new file mode 100644 index 0000000000..fa68484a50 --- /dev/null +++ b/frontend/src/component/project/Project/SuggestedChanges/SuggestedChangeOverview/SuggestedFeatureToggleChange/ToggleStatusChange.tsx @@ -0,0 +1,16 @@ +import { Box } from '@mui/material'; +import { FC } from 'react'; +import { PlaygroundResultChip } from '../../../../../playground/Playground/PlaygroundResultsTable/PlaygroundResultChip/PlaygroundResultChip'; + +export const ToggleStatusChange: FC<{ enabled: boolean }> = ({ enabled }) => { + return ( + + New status:{' '} + + + ); +}; diff --git a/frontend/src/component/project/Project/SuggestedChanges/SuggestedChanges.tsx b/frontend/src/component/project/Project/SuggestedChanges/SuggestedChanges.tsx deleted file mode 100644 index 7388ee096d..0000000000 --- a/frontend/src/component/project/Project/SuggestedChanges/SuggestedChanges.tsx +++ /dev/null @@ -1,163 +0,0 @@ -import React, { useState, VFC } from 'react'; -import { - Box, - Paper, - Button, - Typography, - Popover, - Radio, - FormControl, - FormControlLabel, - RadioGroup, - styled, - Tooltip, -} from '@mui/material'; -import { useChangeRequest } from 'hooks/api/getters/useChangeRequest/useChangeRequest'; -import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; -import { ChangesetDiff } from './ChangesetDiff/ChangesetDiff'; -import { SidebarModal } from 'component/common/SidebarModal/SidebarModal'; -import { PageContent } from '../../../common/PageContent/PageContent'; -import { PageHeader } from '../../../common/PageHeader/PageHeader'; -import { HelpOutline } from '@mui/icons-material'; -interface ISuggestedChangesProps { - open: boolean; - setOpen: React.Dispatch>; -} - -const StyledPageContent = styled(PageContent)(({ theme }) => ({ - height: '100vh', - overflow: 'auto', - padding: theme.spacing(7.5, 6), - [theme.breakpoints.down('md')]: { - padding: theme.spacing(4, 2), - }, - '& .header': { - padding: theme.spacing(0, 0, 2, 0), - }, - '& .body': { - padding: theme.spacing(3, 0, 0, 0), - }, - borderRadius: `${theme.spacing(1.5, 0, 0, 1.5)} !important`, -})); - -const StyledHelpOutline = styled(HelpOutline)(({ theme }) => ({ - fontSize: theme.fontSizes.mainHeader, - marginLeft: '0.3rem', - color: theme.palette.grey[700], -})); - -const StyledHeaderHint = styled('div')(({ theme }) => ({ - color: theme.palette.text.secondary, - fontSize: theme.fontSizes.smallBody, -})); - -export const SuggestedChanges: VFC = ({ - open, - setOpen, -}) => { - const [selectedValue, setSelectedValue] = useState(''); - const { data: changeRequest } = useChangeRequest(); - - const onReview = async () => { - console.log('approve'); - }; - - const onDiscard = async () => { - console.log('discard'); - }; - - const onApply = async () => { - try { - console.log('apply'); - } catch (e) { - console.log(e); - } - }; - - return ( - { - setOpen(false); - }} - label="Review changes" - > - - Review your changes - - - - - Make sure you are sending the right changes - suggestions to be reviewed - - - } - > - } - > - {/* TODO: multiple environments (changesets) */} - {changeRequest?.state} -
- - - Applied} - /> - Applied} - /> - - - - } - /> - - - - - } - /> - -
-
- ); -}; diff --git a/frontend/src/hooks/api/getters/useChangeRequest/useChangeRequest.ts b/frontend/src/hooks/api/getters/useChangeRequest/useChangeRequest.ts deleted file mode 100644 index 6d4ac42873..0000000000 --- a/frontend/src/hooks/api/getters/useChangeRequest/useChangeRequest.ts +++ /dev/null @@ -1,50 +0,0 @@ -// import useSWR from 'swr'; -// import { formatApiPath } from 'utils/formatPath'; -import { ISuggestChangeset } from 'interfaces/suggestChangeset'; -import handleErrorResponses from '../httpErrorResponseHandler'; - -// FIXME: mock -const data: ISuggestChangeset = { - id: 123, - environment: 'production', - state: 'CREATED', - createdAt: new Date('2021-03-01T12:00:00.000Z'), - project: 'default', - createdBy: '123412341', - changes: [ - { - id: 1, - feature: 'feature1', - action: 'updateEnabled', - payload: true, - createdAt: new Date('2021-03-01T12:00:00.000Z'), - }, - { - id: 2, - feature: 'feature2', - action: 'updateEnabled', - payload: false, - createdAt: new Date('2022-09-30T16:34:00.000Z'), - }, - ], -}; - -export const useChangeRequest = () => { - // const { data, error, mutate } = useSWR( - // formatApiPath(`api/admin/suggest-changes/${id}`), - // fetcher - // ); - - return { - data, - // loading: !error && !data, - // refetchChangeRequest: () => mutate(), - // error, - }; -}; - -const fetcher = (path: string) => { - return fetch(path) - .then(handleErrorResponses('Request changes')) - .then(res => res.json()); -}; diff --git a/frontend/src/hooks/api/getters/useSuggestChange/useSuggestedChange.ts b/frontend/src/hooks/api/getters/useSuggestChange/useSuggestedChange.ts new file mode 100644 index 0000000000..e0e4623f47 --- /dev/null +++ b/frontend/src/hooks/api/getters/useSuggestChange/useSuggestedChange.ts @@ -0,0 +1,101 @@ +// import useSWR from 'swr'; +// import { formatApiPath } from 'utils/formatPath'; +import { ISuggestChangeset } from 'interfaces/suggestChangeset'; +import handleErrorResponses from '../httpErrorResponseHandler'; + +// FIXME: mock +const data: any = { + id: '12', + environment: 'production', + state: 'DRAFT', + project: 'default', + createdBy: { + email: 'mateusz@getunleash.ai', + avatar: 'https://gravatar-uri.com/1321', + }, + createdAt: '2020-10-20T12:00:00.000Z', + changes: [ + { + feature: 'my-feature-toggle', + changeSet: [ + { + id: 'f79d399f-cb38-4982-b9b6-4141sdsdaad', + action: 'updateEnabled', + payload: { data: { data: true } }, + }, + { + id: 'f79d399f-cb38-4982-b9b6-4141sdsdaad', + action: 'addStrategy', + payload: { + name: 'flexibleRollout', + constraints: [], + parameters: { + rollout: '50', + stickiness: 'default', + groupId: 'suggest-changes', + }, + }, + }, + { + id: 'f79d399f-cb38-4982-b9b6-4141sdsdaad', + action: 'updateStrategy', + payload: { + data: {}, + }, + }, + { + id: 'f79d399f-cb38-4982-b9b6-4141sdsdaad', + action: 'deleteStrategy', + payload: { + data: {}, + }, + }, + ], + }, + { + feature: 'new-feature-toggle', + changeSet: [ + { + id: 'f79d399f-cb38-4982-b9b6-4141sdsdaad', + action: 'updateEnabled', + payload: { + data: { data: false }, + strategyId: '123-14', + }, + }, + ], + }, + { + feature: 'add-strategy-feature-toggle', + changeSet: [ + { + id: 'f79d399f-cb38-4982-b9b6-4141sdsdaad', + action: 'addStrategy', + payload: { + data: {}, + }, + }, + ], + }, + ], +}; + +export const useSuggestedChange = () => { + // const { data, error, mutate } = useSWR( + // formatApiPath(`api/admin/suggest-changes/${id}`), + // fetcher + // ); + + return { + data, + // loading: !error && !data, + // refetchChangeRequest: () => mutate(), + // error, + }; +}; + +const fetcher = (path: string) => { + return fetch(path) + .then(handleErrorResponses('Request changes')) + .then(res => res.json()); +}; diff --git a/frontend/src/utils/strategyNames.tsx b/frontend/src/utils/strategyNames.tsx index cea5275588..315453c4ac 100644 --- a/frontend/src/utils/strategyNames.tsx +++ b/frontend/src/utils/strategyNames.tsx @@ -36,6 +36,13 @@ export const getFeatureStrategyIcon = (strategyName: string): ElementType => { } }; +export const GetFeatureStrategyIcon: FC<{ strategyName: string }> = ({ + strategyName, +}) => { + const Icon = getFeatureStrategyIcon(strategyName); + return ; +}; + export const formattedStrategyNames: Record = { applicationHostname: 'Hosts', default: 'Standard',