mirror of
https://github.com/Unleash/unleash.git
synced 2025-04-24 01:18:01 +02:00
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 <fredrik.no@gmail.com>
This commit is contained in:
parent
4aa1a34fef
commit
0dba973881
3
frontend/src/assets/icons/merge.svg
Normal file
3
frontend/src/assets/icons/merge.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="18" height="14" viewBox="0 0 18 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0.59 2.00016L2 0.590157L5.41 4.00016L4 5.41016L0.59 2.00016ZM13 11.5002L13 8.00016L7.41 8.00016L2 13.4102L0.59 12.0002L6.59 6.00016L13 6.00016L13 2.50016L17.5 7.00016L13 11.5002Z" fill="currentColor"/>
|
||||
</svg>
|
After Width: | Height: | Size: 319 B |
@ -43,6 +43,7 @@ export const StyledTrueChip = styled(StyledChip)(({ theme }) => ({
|
||||
},
|
||||
['& .MuiChip-icon']: {
|
||||
color: theme.palette.success.main,
|
||||
marginRight: 0,
|
||||
},
|
||||
}));
|
||||
|
||||
|
@ -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 = () => {
|
||||
<Route path="environments" element={<ProjectEnvironment />} />
|
||||
<Route path="archive" element={<ProjectFeaturesArchive />} />
|
||||
<Route path="logs" element={<ProjectLog />} />
|
||||
<Route
|
||||
path="suggest-changes/:id"
|
||||
element={
|
||||
<ConditionallyRender
|
||||
condition={Boolean(uiConfig?.flags?.suggestChanges)}
|
||||
show={<SuggestedChangeOverview />}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<Route path="*" element={<ProjectOverview />} />
|
||||
</Routes>
|
||||
</MainLayout>
|
||||
|
@ -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<IDraftBannerProps> = ({ environment }) => {
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
<SuggestedChanges
|
||||
open={reviewChangesOpen}
|
||||
setOpen={setReviewChangesOpen}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
@ -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 (
|
||||
<Paper
|
||||
elevation={0}
|
||||
sx={theme => ({
|
||||
p: theme.spacing(2, 4),
|
||||
borderRadius: theme => `${theme.shape.borderRadiusLarge}px`,
|
||||
})}
|
||||
>
|
||||
<Box
|
||||
sx={theme => ({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: 2,
|
||||
marginBottom: theme.spacing(2),
|
||||
})}
|
||||
>
|
||||
<Typography
|
||||
sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
variant="h1"
|
||||
>
|
||||
Suggestion
|
||||
<Typography variant="h1" component="p">
|
||||
#{suggestedChange.id}
|
||||
</Typography>
|
||||
</Typography>
|
||||
<StyledTrueChip
|
||||
icon={<ChangesAppliedIcon strokeWidth="0.25" />}
|
||||
label="Changes applied"
|
||||
/>
|
||||
</Box>
|
||||
<Box sx={{ display: 'flex', verticalAlign: 'center', gap: 2 }}>
|
||||
<Typography sx={{ margin: 'auto 0' }}>
|
||||
Created{' '}
|
||||
<TimeAgo date={new Date(suggestedChange.createdAt)} /> by
|
||||
</Typography>
|
||||
<Avatar src={suggestedChange?.createdBy?.avatar} />
|
||||
<Card
|
||||
variant="outlined"
|
||||
sx={theme => ({
|
||||
padding: 1,
|
||||
backgroundColor: theme.palette.tertiary.light,
|
||||
})}
|
||||
>
|
||||
Environment:{' '}
|
||||
<Typography display="inline" fontWeight="bold">
|
||||
{suggestedChange?.environment}
|
||||
</Typography>{' '}
|
||||
| Updates:{' '}
|
||||
<Typography display="inline" fontWeight="bold">
|
||||
{suggestedChange?.changes.length} feature toggles
|
||||
</Typography>
|
||||
</Card>
|
||||
</Box>
|
||||
</Paper>
|
||||
);
|
||||
};
|
@ -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 (
|
||||
<>
|
||||
<SuggestedChangeHeader suggestedChange={suggestedChange} />
|
||||
<Box sx={{ display: 'flex' }}>
|
||||
<Box
|
||||
sx={{
|
||||
width: '30%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
}}
|
||||
>
|
||||
<SuggestedChangeTimeline />
|
||||
<SuggestedChangeReviewers />
|
||||
</Box>
|
||||
|
||||
<SuggestedChangeSet suggestedChange={suggestedChange} />
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
};
|
@ -0,0 +1,16 @@
|
||||
import { Box, Paper } from '@mui/material';
|
||||
|
||||
export const SuggestedChangeReviewers = () => {
|
||||
return (
|
||||
<Paper
|
||||
elevation={0}
|
||||
sx={theme => ({
|
||||
marginTop: theme.spacing(2),
|
||||
padding: 2,
|
||||
borderRadius: theme => `${theme.shape.borderRadiusLarge}px`,
|
||||
})}
|
||||
>
|
||||
<Box sx={theme => ({ padding: theme.spacing(2) })}>Reviewers</Box>
|
||||
</Paper>
|
||||
);
|
||||
};
|
@ -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 (
|
||||
<Paper
|
||||
elevation={0}
|
||||
sx={theme => ({
|
||||
marginTop: theme.spacing(2),
|
||||
marginLeft: theme.spacing(2),
|
||||
width: '70%',
|
||||
padding: 2,
|
||||
borderRadius: theme => `${theme.shape.borderRadiusLarge}px`,
|
||||
})}
|
||||
>
|
||||
<Box
|
||||
sx={theme => ({
|
||||
padding: theme.spacing(2),
|
||||
})}
|
||||
>
|
||||
Changes
|
||||
{suggestedChange.changes?.map((featureToggleChange: any) => (
|
||||
<SuggestedFeatureToggleChange
|
||||
key={featureToggleChange.feature}
|
||||
featureToggleName={featureToggleChange.feature}
|
||||
>
|
||||
{featureToggleChange.changeSet.map((change: any) => (
|
||||
<Box key={objectId(change)}>
|
||||
<ConditionallyRender
|
||||
condition={
|
||||
change.action === 'updateEnabled'
|
||||
}
|
||||
show={
|
||||
<ToggleStatusChange
|
||||
enabled={
|
||||
change?.payload?.data?.data
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<ConditionallyRender
|
||||
condition={change.action === 'addStrategy'}
|
||||
show={
|
||||
<StrategyAddedChange>
|
||||
<GetFeatureStrategyIcon
|
||||
strategyName={
|
||||
change.payload.name
|
||||
}
|
||||
/>
|
||||
{formatStrategyName(
|
||||
change.payload.name
|
||||
)}
|
||||
</StrategyAddedChange>
|
||||
}
|
||||
/>
|
||||
<ConditionallyRender
|
||||
condition={
|
||||
change.action === 'deleteStrategy'
|
||||
}
|
||||
show={<StrategyDeletedChange />}
|
||||
/>
|
||||
<ConditionallyRender
|
||||
condition={
|
||||
change.action === 'updateStrategy'
|
||||
}
|
||||
show={<StrategyEditedChange />}
|
||||
/>
|
||||
</Box>
|
||||
))}
|
||||
</SuggestedFeatureToggleChange>
|
||||
))}
|
||||
</Box>
|
||||
</Paper>
|
||||
);
|
||||
};
|
@ -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 (
|
||||
<Paper
|
||||
elevation={0}
|
||||
sx={theme => ({
|
||||
marginTop: theme.spacing(2),
|
||||
borderRadius: theme => `${theme.shape.borderRadiusLarge}px`,
|
||||
})}
|
||||
>
|
||||
<Box sx={theme => ({ padding: theme.spacing(2) })}>
|
||||
<Timeline
|
||||
sx={{
|
||||
[`& .${timelineItemClasses.root}:before`]: {
|
||||
flex: 0,
|
||||
padding: 0,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<TimelineItem>
|
||||
<TimelineSeparator>
|
||||
<TimelineDot color="success" />
|
||||
<TimelineConnector color="success" />
|
||||
</TimelineSeparator>
|
||||
<TimelineContent>Draft</TimelineContent>
|
||||
</TimelineItem>
|
||||
<TimelineItem>
|
||||
<TimelineSeparator>
|
||||
<TimelineDot color="success" />
|
||||
<TimelineConnector />
|
||||
</TimelineSeparator>
|
||||
<TimelineContent>Approved</TimelineContent>
|
||||
</TimelineItem>
|
||||
<TimelineItem>
|
||||
<TimelineSeparator>
|
||||
<TimelineDot />
|
||||
</TimelineSeparator>
|
||||
<TimelineContent>Applied</TimelineContent>
|
||||
</TimelineItem>
|
||||
</Timeline>
|
||||
</Box>
|
||||
</Paper>
|
||||
);
|
||||
};
|
@ -0,0 +1,27 @@
|
||||
import { Box, Typography } from '@mui/material';
|
||||
import { FC } from 'react';
|
||||
|
||||
export const StrategyAddedChange: FC = ({ children }) => {
|
||||
return (
|
||||
<Box sx={{ p: 1, display: 'flex', gap: 1 }}>
|
||||
<Typography sx={theme => ({ color: theme.palette.success.main })}>
|
||||
+ Strategy Added:
|
||||
</Typography>
|
||||
{children}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export const StrategyEditedChange: FC = () => {
|
||||
return <Box sx={{ p: 1 }}>Strategy Edited</Box>;
|
||||
};
|
||||
|
||||
export const StrategyDeletedChange: FC = () => {
|
||||
return (
|
||||
<Box sx={{ p: 1 }}>
|
||||
<Typography sx={theme => ({ color: theme.palette.error.main })}>
|
||||
- Strategy Deleted
|
||||
</Typography>
|
||||
</Box>
|
||||
);
|
||||
};
|
@ -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 (
|
||||
<Card
|
||||
elevation={0}
|
||||
sx={theme => ({
|
||||
marginTop: theme.spacing(2),
|
||||
borderRadius: theme => `${theme.shape.borderRadiusLarge}px`,
|
||||
overflow: 'hidden',
|
||||
border: '1px solid',
|
||||
borderColor: theme => theme.palette.dividerAlternative,
|
||||
})}
|
||||
>
|
||||
<Box
|
||||
sx={theme => ({
|
||||
backgroundColor: theme.palette.tableHeaderBackground,
|
||||
p: 2,
|
||||
})}
|
||||
>
|
||||
<Box sx={{ display: 'flex', gap: 1 }}>
|
||||
<ToggleOnIcon color="disabled" />
|
||||
<Typography color="primary">{featureToggleName}</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box sx={{ p: 2 }}>{children}</Box>
|
||||
</Card>
|
||||
);
|
||||
};
|
@ -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 (
|
||||
<Box sx={{ p: 1 }}>
|
||||
New status:{' '}
|
||||
<PlaygroundResultChip
|
||||
showIcon={false}
|
||||
label={enabled ? ' Enabled' : 'Disabled'}
|
||||
enabled={enabled}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
};
|
@ -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<React.SetStateAction<boolean>>;
|
||||
}
|
||||
|
||||
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<ISuggestedChangesProps> = ({
|
||||
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 (
|
||||
<SidebarModal
|
||||
open={open}
|
||||
onClose={() => {
|
||||
setOpen(false);
|
||||
}}
|
||||
label="Review changes"
|
||||
>
|
||||
<StyledPageContent
|
||||
header={
|
||||
<PageHeader
|
||||
secondary
|
||||
titleElement={
|
||||
<>
|
||||
Review your changes
|
||||
<Tooltip
|
||||
title="You can review your changes from this page.
|
||||
Needs a text to explain the process."
|
||||
arrow
|
||||
>
|
||||
<StyledHelpOutline />
|
||||
</Tooltip>
|
||||
<StyledHeaderHint>
|
||||
Make sure you are sending the right changes
|
||||
suggestions to be reviewed
|
||||
</StyledHeaderHint>
|
||||
</>
|
||||
}
|
||||
></PageHeader>
|
||||
}
|
||||
>
|
||||
{/* TODO: multiple environments (changesets) */}
|
||||
<Typography>{changeRequest?.state}</Typography>
|
||||
<br />
|
||||
<ChangesetDiff
|
||||
changes={changeRequest?.changes}
|
||||
state={changeRequest?.state}
|
||||
/>
|
||||
<Box sx={{ display: 'flex' }}>
|
||||
<ConditionallyRender
|
||||
condition={changeRequest?.state === 'APPROVED'}
|
||||
show={<Typography>Applied</Typography>}
|
||||
/>
|
||||
<ConditionallyRender
|
||||
condition={changeRequest?.state === 'CLOSED'}
|
||||
show={<Typography>Applied</Typography>}
|
||||
/>
|
||||
<ConditionallyRender
|
||||
condition={changeRequest?.state === 'APPROVED'}
|
||||
show={
|
||||
<>
|
||||
<Button
|
||||
sx={{ mt: 2 }}
|
||||
variant="contained"
|
||||
onClick={onApply}
|
||||
>
|
||||
Apply changes
|
||||
</Button>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
<ConditionallyRender
|
||||
condition={changeRequest?.state === 'CREATED'}
|
||||
show={
|
||||
<>
|
||||
<Button
|
||||
sx={{ mt: 2, ml: 'auto' }}
|
||||
variant="contained"
|
||||
onClick={onReview}
|
||||
>
|
||||
Request changes
|
||||
</Button>
|
||||
<Button
|
||||
sx={{ mt: 2, ml: 2 }}
|
||||
variant="outlined"
|
||||
onClick={onDiscard}
|
||||
>
|
||||
Discard changes
|
||||
</Button>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
</Box>
|
||||
</StyledPageContent>
|
||||
</SidebarModal>
|
||||
);
|
||||
};
|
@ -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());
|
||||
};
|
@ -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());
|
||||
};
|
@ -36,6 +36,13 @@ export const getFeatureStrategyIcon = (strategyName: string): ElementType => {
|
||||
}
|
||||
};
|
||||
|
||||
export const GetFeatureStrategyIcon: FC<{ strategyName: string }> = ({
|
||||
strategyName,
|
||||
}) => {
|
||||
const Icon = getFeatureStrategyIcon(strategyName);
|
||||
return <Icon />;
|
||||
};
|
||||
|
||||
export const formattedStrategyNames: Record<string, string> = {
|
||||
applicationHostname: 'Hosts',
|
||||
default: 'Standard',
|
||||
|
Loading…
Reference in New Issue
Block a user