mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	feat: integrate with API for suggest changes (#2286)
* feat: integrate with API for suggest changes * fix: suggestions table tabs state (#2287) * fix: suggestions table tabs state * fix suggestion header padding * fix: update snapshots * fix: pr comments * fix: revert store change * fix: revert store fix Co-authored-by: Tymoteusz Czech <2625371+Tymek@users.noreply.github.com>
This commit is contained in:
		
							parent
							
								
									95779754fb
								
							
						
					
					
						commit
						15c22d7630
					
				@ -6,7 +6,6 @@ export const useStyles = makeStyles()(theme => ({
 | 
				
			|||||||
        boxShadow: 'none',
 | 
					        boxShadow: 'none',
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    headerContainer: {
 | 
					    headerContainer: {
 | 
				
			||||||
        padding: theme.spacing(2, 4),
 | 
					 | 
				
			||||||
        borderBottomStyle: 'solid',
 | 
					        borderBottomStyle: 'solid',
 | 
				
			||||||
        borderBottomWidth: 1,
 | 
					        borderBottomWidth: 1,
 | 
				
			||||||
        borderBottomColor: theme.palette.divider,
 | 
					        borderBottomColor: theme.palette.divider,
 | 
				
			||||||
@ -14,6 +13,9 @@ export const useStyles = makeStyles()(theme => ({
 | 
				
			|||||||
            padding: '1.5rem 1rem',
 | 
					            padding: '1.5rem 1rem',
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    headerPadding: {
 | 
				
			||||||
 | 
					        padding: theme.spacing(2, 4),
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    bodyContainer: {
 | 
					    bodyContainer: {
 | 
				
			||||||
        padding: theme.spacing(4),
 | 
					        padding: theme.spacing(4),
 | 
				
			||||||
        [theme.breakpoints.down('md')]: {
 | 
					        [theme.breakpoints.down('md')]: {
 | 
				
			||||||
 | 
				
			|||||||
@ -19,6 +19,7 @@ interface IPageContentProps extends PaperProps {
 | 
				
			|||||||
    disableBorder?: boolean;
 | 
					    disableBorder?: boolean;
 | 
				
			||||||
    disableLoading?: boolean;
 | 
					    disableLoading?: boolean;
 | 
				
			||||||
    bodyClass?: string;
 | 
					    bodyClass?: string;
 | 
				
			||||||
 | 
					    headerClass?: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const PageContentLoading: FC<{ isLoading: boolean }> = ({
 | 
					const PageContentLoading: FC<{ isLoading: boolean }> = ({
 | 
				
			||||||
@ -40,6 +41,7 @@ export const PageContent: FC<IPageContentProps> = ({
 | 
				
			|||||||
    disablePadding = false,
 | 
					    disablePadding = false,
 | 
				
			||||||
    disableBorder = false,
 | 
					    disableBorder = false,
 | 
				
			||||||
    bodyClass = '',
 | 
					    bodyClass = '',
 | 
				
			||||||
 | 
					    headerClass = '',
 | 
				
			||||||
    isLoading = false,
 | 
					    isLoading = false,
 | 
				
			||||||
    disableLoading = false,
 | 
					    disableLoading = false,
 | 
				
			||||||
    className,
 | 
					    className,
 | 
				
			||||||
@ -47,10 +49,15 @@ export const PageContent: FC<IPageContentProps> = ({
 | 
				
			|||||||
}) => {
 | 
					}) => {
 | 
				
			||||||
    const { classes: styles } = useStyles();
 | 
					    const { classes: styles } = useStyles();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const headerClasses = classnames('header', styles.headerContainer, {
 | 
					    const headerClasses = classnames(
 | 
				
			||||||
        [styles.paddingDisabled]: disablePadding,
 | 
					        'header',
 | 
				
			||||||
        [styles.borderDisabled]: disableBorder,
 | 
					        styles.headerContainer,
 | 
				
			||||||
    });
 | 
					        headerClass || styles.headerPadding,
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            [styles.paddingDisabled]: disablePadding,
 | 
				
			||||||
 | 
					            [styles.borderDisabled]: disableBorder,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const bodyClasses = classnames(
 | 
					    const bodyClasses = classnames(
 | 
				
			||||||
        'body',
 | 
					        'body',
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
 | 
					import { VFC } from 'react';
 | 
				
			||||||
import { Chip, styled } from '@mui/material';
 | 
					import { Chip, styled } from '@mui/material';
 | 
				
			||||||
import { colors } from '../../../../../themes/colors';
 | 
					import { colors } from 'themes/colors';
 | 
				
			||||||
import { TextCell } from '../../../../common/Table/cells/TextCell/TextCell';
 | 
					import { TextCell } from 'component/common/Table/cells/TextCell/TextCell';
 | 
				
			||||||
import { Check, CircleOutlined, Close } from '@mui/icons-material';
 | 
					import { Check, CircleOutlined, Close } from '@mui/icons-material';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface IChangesetStatusCellProps {
 | 
					interface IChangesetStatusCellProps {
 | 
				
			||||||
@ -60,7 +61,10 @@ export const StyledReviewChip = styled(StyledChip)(({ theme }) => ({
 | 
				
			|||||||
        color: theme.palette.primary.main,
 | 
					        color: theme.palette.primary.main,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
}));
 | 
					}));
 | 
				
			||||||
export const ChangesetStatusCell = ({ value }: IChangesetStatusCellProps) => {
 | 
					
 | 
				
			||||||
 | 
					export const ChangesetStatusCell: VFC<IChangesetStatusCellProps> = ({
 | 
				
			||||||
 | 
					    value,
 | 
				
			||||||
 | 
					}) => {
 | 
				
			||||||
    const renderState = (state: string) => {
 | 
					    const renderState = (state: string) => {
 | 
				
			||||||
        switch (state) {
 | 
					        switch (state) {
 | 
				
			||||||
            case SuggestChangesetState.IN_REVIEW:
 | 
					            case SuggestChangesetState.IN_REVIEW:
 | 
				
			||||||
 | 
				
			|||||||
@ -2,6 +2,7 @@ import { TextCell } from '../../../../common/Table/cells/TextCell/TextCell';
 | 
				
			|||||||
import { Link, styled, Typography } from '@mui/material';
 | 
					import { Link, styled, Typography } from '@mui/material';
 | 
				
			||||||
import { Link as RouterLink } from 'react-router-dom';
 | 
					import { Link as RouterLink } from 'react-router-dom';
 | 
				
			||||||
import { useTheme } from '@mui/system';
 | 
					import { useTheme } from '@mui/system';
 | 
				
			||||||
 | 
					import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface IChangesetTitleCellProps {
 | 
					interface IChangesetTitleCellProps {
 | 
				
			||||||
    value?: any;
 | 
					    value?: any;
 | 
				
			||||||
@ -18,9 +19,10 @@ export const ChangesetTitleCell = ({
 | 
				
			|||||||
    value,
 | 
					    value,
 | 
				
			||||||
    row: { original },
 | 
					    row: { original },
 | 
				
			||||||
}: IChangesetTitleCellProps) => {
 | 
					}: IChangesetTitleCellProps) => {
 | 
				
			||||||
    const { id, features: changes, project } = original;
 | 
					    const projectId = useRequiredPathParam('projectId');
 | 
				
			||||||
 | 
					    const { id, features: changes } = original;
 | 
				
			||||||
    const theme = useTheme();
 | 
					    const theme = useTheme();
 | 
				
			||||||
    const path = `projects/${project}/suggest-changes/${id}`;
 | 
					    const path = `/projects/${projectId}/suggest-changes/${id}`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!value) {
 | 
					    if (!value) {
 | 
				
			||||||
        return <TextCell />;
 | 
					        return <TextCell />;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,8 +1,12 @@
 | 
				
			|||||||
import { makeStyles } from 'tss-react/mui';
 | 
					import { makeStyles } from 'tss-react/mui';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const useStyles = makeStyles()(theme => ({
 | 
					export const useStyles = makeStyles()(theme => ({
 | 
				
			||||||
 | 
					    header: {
 | 
				
			||||||
 | 
					        padding: theme.spacing(0, 4),
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    tabContainer: {
 | 
					    tabContainer: {
 | 
				
			||||||
        paddingLeft: 0,
 | 
					        paddingLeft: 0,
 | 
				
			||||||
 | 
					        paddingBottom: 0,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    tabButton: {
 | 
					    tabButton: {
 | 
				
			||||||
        textTransform: 'none',
 | 
					        textTransform: 'none',
 | 
				
			||||||
 | 
				
			|||||||
@ -77,7 +77,7 @@ export const SuggestionsTabs = ({
 | 
				
			|||||||
        },
 | 
					        },
 | 
				
			||||||
    ];
 | 
					    ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const [activeTab, setActiveTab] = useState(tabs[0]);
 | 
					    const [activeTab, setActiveTab] = useState(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const columns = useMemo(
 | 
					    const columns = useMemo(
 | 
				
			||||||
        () => [
 | 
					        () => [
 | 
				
			||||||
@ -137,7 +137,7 @@ export const SuggestionsTabs = ({
 | 
				
			|||||||
        data: searchedData,
 | 
					        data: searchedData,
 | 
				
			||||||
        getSearchText,
 | 
					        getSearchText,
 | 
				
			||||||
        getSearchContext,
 | 
					        getSearchContext,
 | 
				
			||||||
    } = useSearch(columns, searchValue, activeTab.data);
 | 
					    } = useSearch(columns, searchValue, tabs[activeTab]?.data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const data = useMemo(
 | 
					    const data = useMemo(
 | 
				
			||||||
        () => (loading ? featuresPlaceholder : searchedData),
 | 
					        () => (loading ? featuresPlaceholder : searchedData),
 | 
				
			||||||
@ -206,34 +206,31 @@ export const SuggestionsTabs = ({
 | 
				
			|||||||
        setStoredParams({ id: sortBy[0].id, desc: sortBy[0].desc || false });
 | 
					        setStoredParams({ id: sortBy[0].id, desc: sortBy[0].desc || false });
 | 
				
			||||||
    }, [loading, sortBy, searchValue]); // eslint-disable-line react-hooks/exhaustive-deps
 | 
					    }, [loading, sortBy, searchValue]); // eslint-disable-line react-hooks/exhaustive-deps
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const renderTabs = () => {
 | 
					 | 
				
			||||||
        return (
 | 
					 | 
				
			||||||
            <div className={classes.tabContainer}>
 | 
					 | 
				
			||||||
                <Tabs
 | 
					 | 
				
			||||||
                    value={activeTab?.title}
 | 
					 | 
				
			||||||
                    indicatorColor="primary"
 | 
					 | 
				
			||||||
                    textColor="primary"
 | 
					 | 
				
			||||||
                >
 | 
					 | 
				
			||||||
                    {tabs.map(tab => (
 | 
					 | 
				
			||||||
                        <Tab
 | 
					 | 
				
			||||||
                            key={tab.title}
 | 
					 | 
				
			||||||
                            label={`${tab.title} (${tab.data.length})`}
 | 
					 | 
				
			||||||
                            value={tab.title}
 | 
					 | 
				
			||||||
                            onClick={() => setActiveTab(tab)}
 | 
					 | 
				
			||||||
                            className={classes.tabButton}
 | 
					 | 
				
			||||||
                        />
 | 
					 | 
				
			||||||
                    ))}
 | 
					 | 
				
			||||||
                </Tabs>
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <PageContent
 | 
					        <PageContent
 | 
				
			||||||
            isLoading={loading}
 | 
					            isLoading={loading}
 | 
				
			||||||
 | 
					            headerClass={classes.header}
 | 
				
			||||||
            header={
 | 
					            header={
 | 
				
			||||||
                <PageHeader
 | 
					                <PageHeader
 | 
				
			||||||
                    titleElement={renderTabs()}
 | 
					                    titleElement={
 | 
				
			||||||
 | 
					                        <div className={classes.tabContainer}>
 | 
				
			||||||
 | 
					                            <Tabs
 | 
				
			||||||
 | 
					                                value={tabs[activeTab]?.title}
 | 
				
			||||||
 | 
					                                indicatorColor="primary"
 | 
				
			||||||
 | 
					                                textColor="primary"
 | 
				
			||||||
 | 
					                            >
 | 
				
			||||||
 | 
					                                {tabs.map((tab, index) => (
 | 
				
			||||||
 | 
					                                    <Tab
 | 
				
			||||||
 | 
					                                        key={tab.title}
 | 
				
			||||||
 | 
					                                        label={`${tab.title} (${tab.data.length})`}
 | 
				
			||||||
 | 
					                                        value={tab.title}
 | 
				
			||||||
 | 
					                                        onClick={() => setActiveTab(index)}
 | 
				
			||||||
 | 
					                                        className={classes.tabButton}
 | 
				
			||||||
 | 
					                                    />
 | 
				
			||||||
 | 
					                                ))}
 | 
				
			||||||
 | 
					                            </Tabs>
 | 
				
			||||||
 | 
					                        </div>
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
                    actions={
 | 
					                    actions={
 | 
				
			||||||
                        <Search
 | 
					                        <Search
 | 
				
			||||||
                            initialValue={searchValue}
 | 
					                            initialValue={searchValue}
 | 
				
			||||||
 | 
				
			|||||||
@ -16,7 +16,7 @@ export const DraftBanner: VFC<IDraftBannerProps> = ({ project }) => {
 | 
				
			|||||||
    const { draft, loading } = useSuggestedChangesDraft(project);
 | 
					    const { draft, loading } = useSuggestedChangesDraft(project);
 | 
				
			||||||
    const environment = '';
 | 
					    const environment = '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!loading && !draft) {
 | 
					    if (!loading && draft?.length === 0) {
 | 
				
			||||||
        return null;
 | 
					        return null;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -37,8 +37,8 @@ export const SuggestedChangeHeader: FC<{ suggestedChange: any }> = ({
 | 
				
			|||||||
                </Typography>
 | 
					                </Typography>
 | 
				
			||||||
                <PlaygroundResultChip
 | 
					                <PlaygroundResultChip
 | 
				
			||||||
                    // icon={<ChangesAppliedIcon strokeWidth="0.25" />}
 | 
					                    // icon={<ChangesAppliedIcon strokeWidth="0.25" />}
 | 
				
			||||||
                    label="Changes applied"
 | 
					                    label="Changes approved"
 | 
				
			||||||
                    enabled="unknown"
 | 
					                    enabled
 | 
				
			||||||
                />
 | 
					                />
 | 
				
			||||||
            </Box>
 | 
					            </Box>
 | 
				
			||||||
            <Box sx={{ display: 'flex', verticalAlign: 'center', gap: 2 }}>
 | 
					            <Box sx={{ display: 'flex', verticalAlign: 'center', gap: 2 }}>
 | 
				
			||||||
@ -60,7 +60,7 @@ export const SuggestedChangeHeader: FC<{ suggestedChange: any }> = ({
 | 
				
			|||||||
                    </Typography>{' '}
 | 
					                    </Typography>{' '}
 | 
				
			||||||
                    | Updates:{' '}
 | 
					                    | Updates:{' '}
 | 
				
			||||||
                    <Typography display="inline" fontWeight="bold">
 | 
					                    <Typography display="inline" fontWeight="bold">
 | 
				
			||||||
                        {suggestedChange?.changes.length} feature toggles
 | 
					                        {suggestedChange?.features.length} feature toggles
 | 
				
			||||||
                    </Typography>
 | 
					                    </Typography>
 | 
				
			||||||
                </Card>
 | 
					                </Card>
 | 
				
			||||||
            </Box>
 | 
					            </Box>
 | 
				
			||||||
 | 
				
			|||||||
@ -1,13 +1,38 @@
 | 
				
			|||||||
import { FC } from 'react';
 | 
					import { FC } from 'react';
 | 
				
			||||||
import { Box, Paper } from '@mui/material';
 | 
					import { Box, Button, Paper } from '@mui/material';
 | 
				
			||||||
import { useSuggestedChange } from 'hooks/api/getters/useSuggestChange/useSuggestedChange';
 | 
					import { useSuggestedChange } from 'hooks/api/getters/useSuggestChange/useSuggestedChange';
 | 
				
			||||||
import { SuggestedChangeHeader } from './SuggestedChangeHeader/SuggestedChangeHeader';
 | 
					import { SuggestedChangeHeader } from './SuggestedChangeHeader/SuggestedChangeHeader';
 | 
				
			||||||
import { SuggestedChangeTimeline } from './SuggestedChangeTimeline/SuggestedChangeTimeline';
 | 
					import { SuggestedChangeTimeline } from './SuggestedChangeTimeline/SuggestedChangeTimeline';
 | 
				
			||||||
import { SuggestedChangeReviewers } from './SuggestedChangeReviewers/SuggestedChangeReviewers';
 | 
					import { SuggestedChangeReviewers } from './SuggestedChangeReviewers/SuggestedChangeReviewers';
 | 
				
			||||||
import { SuggestedChangeset } from '../SuggestedChangeset/SuggestedChangeset';
 | 
					import { SuggestedChangeset } from '../SuggestedChangeset/SuggestedChangeset';
 | 
				
			||||||
 | 
					import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
 | 
				
			||||||
 | 
					import { useSuggestChangeApi } from 'hooks/api/actions/useSuggestChangeApi/useSuggestChangeApi';
 | 
				
			||||||
 | 
					import useToast from 'hooks/useToast';
 | 
				
			||||||
 | 
					import { formatUnknownError } from 'utils/formatUnknownError';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const SuggestedChangeOverview: FC = () => {
 | 
					export const SuggestedChangeOverview: FC = () => {
 | 
				
			||||||
    const { data: suggestedChange } = useSuggestedChange();
 | 
					    const projectId = useRequiredPathParam('projectId');
 | 
				
			||||||
 | 
					    const id = useRequiredPathParam('id');
 | 
				
			||||||
 | 
					    const { data: suggestedChange } = useSuggestedChange(projectId, id);
 | 
				
			||||||
 | 
					    const { applyChanges } = useSuggestChangeApi();
 | 
				
			||||||
 | 
					    const { setToastData, setToastApiError } = useToast();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!suggestedChange) {
 | 
				
			||||||
 | 
					        return null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const onApplyChanges = async () => {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            await applyChanges(projectId, id);
 | 
				
			||||||
 | 
					            setToastData({
 | 
				
			||||||
 | 
					                type: 'success',
 | 
				
			||||||
 | 
					                title: 'Success',
 | 
				
			||||||
 | 
					                text: 'Changes appplied',
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        } catch (error: unknown) {
 | 
				
			||||||
 | 
					            setToastApiError(formatUnknownError(error));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <>
 | 
					        <>
 | 
				
			||||||
@ -40,6 +65,13 @@ export const SuggestedChangeOverview: FC = () => {
 | 
				
			|||||||
                        })}
 | 
					                        })}
 | 
				
			||||||
                    >
 | 
					                    >
 | 
				
			||||||
                        <SuggestedChangeset suggestedChange={suggestedChange} />
 | 
					                        <SuggestedChangeset suggestedChange={suggestedChange} />
 | 
				
			||||||
 | 
					                        <Button
 | 
				
			||||||
 | 
					                            variant="contained"
 | 
				
			||||||
 | 
					                            sx={{ marginTop: 2 }}
 | 
				
			||||||
 | 
					                            onClick={onApplyChanges}
 | 
				
			||||||
 | 
					                        >
 | 
				
			||||||
 | 
					                            Apply changes
 | 
				
			||||||
 | 
					                        </Button>
 | 
				
			||||||
                    </Box>
 | 
					                    </Box>
 | 
				
			||||||
                </Paper>
 | 
					                </Paper>
 | 
				
			||||||
            </Box>
 | 
					            </Box>
 | 
				
			||||||
 | 
				
			|||||||
@ -7,6 +7,7 @@ import { PageHeader } from 'component/common/PageHeader/PageHeader';
 | 
				
			|||||||
import { HelpOutline } from '@mui/icons-material';
 | 
					import { HelpOutline } from '@mui/icons-material';
 | 
				
			||||||
import { SuggestedChangeset } from '../SuggestedChangeset/SuggestedChangeset';
 | 
					import { SuggestedChangeset } from '../SuggestedChangeset/SuggestedChangeset';
 | 
				
			||||||
import { useSuggestedChangesDraft } from 'hooks/api/getters/useSuggestedChangesDraft/useSuggestedChangesDraft';
 | 
					import { useSuggestedChangesDraft } from 'hooks/api/getters/useSuggestedChangesDraft/useSuggestedChangesDraft';
 | 
				
			||||||
 | 
					import { useSuggestChangeApi } from 'hooks/api/actions/useSuggestChangeApi/useSuggestChangeApi';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface ISuggestedChangesSidebarProps {
 | 
					interface ISuggestedChangesSidebarProps {
 | 
				
			||||||
    open: boolean;
 | 
					    open: boolean;
 | 
				
			||||||
@ -45,10 +46,20 @@ export const SuggestedChangesSidebar: VFC<ISuggestedChangesSidebarProps> = ({
 | 
				
			|||||||
    project,
 | 
					    project,
 | 
				
			||||||
    onClose,
 | 
					    onClose,
 | 
				
			||||||
}) => {
 | 
					}) => {
 | 
				
			||||||
    const { draft, loading } = useSuggestedChangesDraft(project);
 | 
					    const {
 | 
				
			||||||
 | 
					        draft,
 | 
				
			||||||
 | 
					        loading,
 | 
				
			||||||
 | 
					        refetch: refetchSuggestedChanges,
 | 
				
			||||||
 | 
					    } = useSuggestedChangesDraft(project);
 | 
				
			||||||
 | 
					    const { changeState } = useSuggestChangeApi();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const onReview = async () => {
 | 
					    const onReview = async (draftId: number) => {
 | 
				
			||||||
        alert('approve');
 | 
					        try {
 | 
				
			||||||
 | 
					            await changeState(project, draftId, { state: 'In review' });
 | 
				
			||||||
 | 
					            refetchSuggestedChanges();
 | 
				
			||||||
 | 
					        } catch (e) {
 | 
				
			||||||
 | 
					            console.log('something went wrong');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    const onDiscard = async () => {
 | 
					    const onDiscard = async () => {
 | 
				
			||||||
        alert('discard');
 | 
					        alert('discard');
 | 
				
			||||||
@ -163,7 +174,11 @@ export const SuggestedChangesSidebar: VFC<ISuggestedChangesSidebarProps> = ({
 | 
				
			|||||||
                                        <Button
 | 
					                                        <Button
 | 
				
			||||||
                                            sx={{ mt: 2, ml: 'auto' }}
 | 
					                                            sx={{ mt: 2, ml: 'auto' }}
 | 
				
			||||||
                                            variant="contained"
 | 
					                                            variant="contained"
 | 
				
			||||||
                                            onClick={onReview}
 | 
					                                            onClick={() =>
 | 
				
			||||||
 | 
					                                                onReview(
 | 
				
			||||||
 | 
					                                                    environmentChangeset.id
 | 
				
			||||||
 | 
					                                                )
 | 
				
			||||||
 | 
					                                            }
 | 
				
			||||||
                                        >
 | 
					                                        >
 | 
				
			||||||
                                            Request changes
 | 
					                                            Request changes
 | 
				
			||||||
                                        </Button>
 | 
					                                        </Button>
 | 
				
			||||||
 | 
				
			|||||||
@ -10,7 +10,7 @@ exports[`renders an empty list correctly 1`] = `
 | 
				
			|||||||
      className="MuiPaper-root MuiPaper-elevation MuiPaper-rounded MuiPaper-elevation1 css-p9j8ie-MuiPaper-root-container"
 | 
					      className="MuiPaper-root MuiPaper-elevation MuiPaper-rounded MuiPaper-elevation1 css-p9j8ie-MuiPaper-root-container"
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
      <div
 | 
					      <div
 | 
				
			||||||
        className="header css-1ywhhai-headerContainer"
 | 
					        className="header css-zq4ve2-headerContainer css-70tvrt-headerPadding"
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        <div
 | 
					        <div
 | 
				
			||||||
          className="css-1ylehva-headerContainer"
 | 
					          className="css-1ylehva-headerContainer"
 | 
				
			||||||
 | 
				
			|||||||
@ -10,12 +10,13 @@ interface ISuggestChangeSchema {
 | 
				
			|||||||
    payload: string | boolean | object | number;
 | 
					    payload: string | boolean | object | number;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const useSuggestChangeApi = (project: string) => {
 | 
					export const useSuggestChangeApi = () => {
 | 
				
			||||||
    const { makeRequest, createRequest, errors, loading } = useAPI({
 | 
					    const { makeRequest, createRequest, errors, loading } = useAPI({
 | 
				
			||||||
        propagateErrors: true,
 | 
					        propagateErrors: true,
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const addSuggestion = async (
 | 
					    const addSuggestion = async (
 | 
				
			||||||
 | 
					        project: string,
 | 
				
			||||||
        environment: string,
 | 
					        environment: string,
 | 
				
			||||||
        payload: ISuggestChangeSchema
 | 
					        payload: ISuggestChangeSchema
 | 
				
			||||||
    ) => {
 | 
					    ) => {
 | 
				
			||||||
@ -26,7 +27,38 @@ export const useSuggestChangeApi = (project: string) => {
 | 
				
			|||||||
        });
 | 
					        });
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            const response = await makeRequest(req.caller, req.id);
 | 
					            const response = await makeRequest(req.caller, req.id);
 | 
				
			||||||
            return await response.json();
 | 
					            return response.json();
 | 
				
			||||||
 | 
					        } catch (e) {
 | 
				
			||||||
 | 
					            throw e;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const changeState = async (
 | 
				
			||||||
 | 
					        project: string,
 | 
				
			||||||
 | 
					        suggestChangeId: number,
 | 
				
			||||||
 | 
					        payload: any
 | 
				
			||||||
 | 
					    ) => {
 | 
				
			||||||
 | 
					        const path = `api/admin/projects/${project}/suggest-changes/${suggestChangeId}/state`;
 | 
				
			||||||
 | 
					        const req = createRequest(path, {
 | 
				
			||||||
 | 
					            method: 'PUT',
 | 
				
			||||||
 | 
					            body: JSON.stringify(payload),
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            const response = await makeRequest(req.caller, req.id);
 | 
				
			||||||
 | 
					            return response.json();
 | 
				
			||||||
 | 
					        } catch (e) {
 | 
				
			||||||
 | 
					            throw e;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const applyChanges = async (project: string, suggestChangeId: string) => {
 | 
				
			||||||
 | 
					        const path = `api/admin/projects/${project}/suggest-changes/${suggestChangeId}/apply`;
 | 
				
			||||||
 | 
					        const req = createRequest(path, {
 | 
				
			||||||
 | 
					            method: 'PUT',
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            const response = await makeRequest(req.caller, req.id);
 | 
				
			||||||
 | 
					            return response;
 | 
				
			||||||
        } catch (e) {
 | 
					        } catch (e) {
 | 
				
			||||||
            throw e;
 | 
					            throw e;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -34,6 +66,8 @@ export const useSuggestChangeApi = (project: string) => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
        addSuggestion,
 | 
					        addSuggestion,
 | 
				
			||||||
 | 
					        applyChanges,
 | 
				
			||||||
 | 
					        changeState,
 | 
				
			||||||
        errors,
 | 
					        errors,
 | 
				
			||||||
        loading,
 | 
					        loading,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
				
			|||||||
@ -1,99 +1,18 @@
 | 
				
			|||||||
// import useSWR from 'swr';
 | 
					import useSWR from 'swr';
 | 
				
			||||||
// import { formatApiPath } from 'utils/formatPath';
 | 
					import { formatApiPath } from 'utils/formatPath';
 | 
				
			||||||
import { ISuggestChangeset } from 'interfaces/suggestChangeset';
 | 
					 | 
				
			||||||
import handleErrorResponses from '../httpErrorResponseHandler';
 | 
					import handleErrorResponses from '../httpErrorResponseHandler';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// FIXME: mock
 | 
					export const useSuggestedChange = (projectId: string, id: string) => {
 | 
				
			||||||
const data: any = {
 | 
					    const { data, error, mutate } = useSWR(
 | 
				
			||||||
    id: '12',
 | 
					        formatApiPath(`api/admin/projects/${projectId}/suggest-changes/${id}`),
 | 
				
			||||||
    environment: 'production',
 | 
					        fetcher
 | 
				
			||||||
    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: {},
 | 
					 | 
				
			||||||
                    },
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
            ],
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
    ],
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * @deprecated for draft: useSuggestedChangesDraft
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
export const useSuggestedChange = () => {
 | 
					 | 
				
			||||||
    // const { data, error, mutate } = useSWR(
 | 
					 | 
				
			||||||
    //     formatApiPath(`api/admin/suggest-changes/${id}`),
 | 
					 | 
				
			||||||
    //     fetcher
 | 
					 | 
				
			||||||
    // );
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
        data,
 | 
					        data,
 | 
				
			||||||
        // loading: !error && !data,
 | 
					        loading: !error && !data,
 | 
				
			||||||
        // refetchChangeRequest: () => mutate(),
 | 
					        refetchSuggestedChange: () => mutate(),
 | 
				
			||||||
        // error,
 | 
					        error,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -2,10 +2,14 @@ import { useCallback, useState } from 'react';
 | 
				
			|||||||
import useToast from 'hooks/useToast';
 | 
					import useToast from 'hooks/useToast';
 | 
				
			||||||
import { formatUnknownError } from 'utils/formatUnknownError';
 | 
					import { formatUnknownError } from 'utils/formatUnknownError';
 | 
				
			||||||
import { useSuggestChangeApi } from './api/actions/useSuggestChangeApi/useSuggestChangeApi';
 | 
					import { useSuggestChangeApi } from './api/actions/useSuggestChangeApi/useSuggestChangeApi';
 | 
				
			||||||
 | 
					import { useSuggestedChangesDraft } from './api/getters/useSuggestedChangesDraft/useSuggestedChangesDraft';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const useSuggestToggle = (project: string) => {
 | 
					export const useSuggestToggle = (project: string) => {
 | 
				
			||||||
    const { setToastData, setToastApiError } = useToast();
 | 
					    const { setToastData, setToastApiError } = useToast();
 | 
				
			||||||
    const { addSuggestion } = useSuggestChangeApi(project);
 | 
					    const { addSuggestion } = useSuggestChangeApi();
 | 
				
			||||||
 | 
					    const { refetch: refetchSuggestedChange } =
 | 
				
			||||||
 | 
					        useSuggestedChangesDraft(project);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const [suggestChangesDialogDetails, setSuggestChangesDialogDetails] =
 | 
					    const [suggestChangesDialogDetails, setSuggestChangesDialogDetails] =
 | 
				
			||||||
        useState<{
 | 
					        useState<{
 | 
				
			||||||
            enabled?: boolean;
 | 
					            enabled?: boolean;
 | 
				
			||||||
@ -32,13 +36,18 @@ export const useSuggestToggle = (project: string) => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    const onSuggestToggleConfirm = useCallback(async () => {
 | 
					    const onSuggestToggleConfirm = useCallback(async () => {
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            await addSuggestion(suggestChangesDialogDetails.environment!, {
 | 
					            await addSuggestion(
 | 
				
			||||||
                feature: suggestChangesDialogDetails.featureName!,
 | 
					                project,
 | 
				
			||||||
                action: 'updateEnabled',
 | 
					                suggestChangesDialogDetails.environment!,
 | 
				
			||||||
                payload: {
 | 
					                {
 | 
				
			||||||
                    enabled: Boolean(suggestChangesDialogDetails.enabled),
 | 
					                    feature: suggestChangesDialogDetails.featureName!,
 | 
				
			||||||
                },
 | 
					                    action: 'updateEnabled',
 | 
				
			||||||
            });
 | 
					                    payload: {
 | 
				
			||||||
 | 
					                        enabled: Boolean(suggestChangesDialogDetails.enabled),
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					            refetchSuggestedChange();
 | 
				
			||||||
            setSuggestChangesDialogDetails({ isOpen: false });
 | 
					            setSuggestChangesDialogDetails({ isOpen: false });
 | 
				
			||||||
            setToastData({
 | 
					            setToastData({
 | 
				
			||||||
                type: 'success',
 | 
					                type: 'success',
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user