1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-08-13 13:48:59 +02:00

fix: instant refresh project features list on import

This commit is contained in:
kwasniew 2024-05-20 11:05:33 +02:00
parent dfc0c3c63f
commit 801cb4577a
No known key found for this signature in database
GPG Key ID: 43A7CBC24C119560
6 changed files with 80 additions and 22 deletions

View File

@ -42,9 +42,21 @@ test('Import happy path', async () => {
const setOpen = (open: boolean) => { const setOpen = (open: boolean) => {
closed = !open; closed = !open;
}; };
render(<ImportModal open={true} setOpen={setOpen} project='default' />, { let imported = false;
permissions: [{ permission: CREATE_FEATURE }], const onImport = () => {
}); imported = true;
};
render(
<ImportModal
open={true}
setOpen={setOpen}
project='default'
onImport={onImport}
/>,
{
permissions: [{ permission: CREATE_FEATURE }],
},
);
// configure stage // configure stage
screen.getByText('Import options'); screen.getByText('Import options');
@ -76,6 +88,8 @@ test('Import happy path', async () => {
await screen.findByText('Importing...'); await screen.findByText('Importing...');
await screen.findByText('Import completed'); await screen.findByText('Import completed');
expect(imported).toBe(true);
expect(closed).toBe(false); expect(closed).toBe(false);
const closeButton = screen.getByText('Close'); const closeButton = screen.getByText('Close');
closeButton.click(); closeButton.click();
@ -85,9 +99,18 @@ test('Import happy path', async () => {
test('Block when importing non json content', async () => { test('Block when importing non json content', async () => {
setupApi(); setupApi();
const setOpen = () => {}; const setOpen = () => {};
render(<ImportModal open={true} setOpen={setOpen} project='default' />, { const onImport = () => {};
permissions: [{ permission: CREATE_FEATURE }], render(
}); <ImportModal
open={true}
setOpen={setOpen}
project='default'
onImport={onImport}
/>,
{
permissions: [{ permission: CREATE_FEATURE }],
},
);
const codeEditorLabel = screen.getByText('Code editor'); const codeEditorLabel = screen.getByText('Code editor');
codeEditorLabel.click(); codeEditorLabel.click();
@ -123,9 +146,18 @@ test('Show validation errors', async () => {
'post', 'post',
); );
const setOpen = () => {}; const setOpen = () => {};
render(<ImportModal open={true} setOpen={setOpen} project='default' />, { const onImport = () => {};
permissions: [{ permission: CREATE_FEATURE }], render(
}); <ImportModal
open={true}
setOpen={setOpen}
project='default'
onImport={onImport}
/>,
{
permissions: [{ permission: CREATE_FEATURE }],
},
);
await importFile('{}'); await importFile('{}');
await waitFor(() => { await waitFor(() => {

View File

@ -47,9 +47,15 @@ interface IImportModalProps {
open: boolean; open: boolean;
setOpen: (value: boolean) => void; setOpen: (value: boolean) => void;
project: string; project: string;
onImport: () => void;
} }
export const ImportModal = ({ open, setOpen, project }: IImportModalProps) => { export const ImportModal = ({
open,
setOpen,
project,
onImport,
}: IImportModalProps) => {
const [importStage, setImportStage] = useState<StageName>('configure'); const [importStage, setImportStage] = useState<StageName>('configure');
const [environment, setEnvironment] = useState(''); const [environment, setEnvironment] = useState('');
const [importPayload, setImportPayload] = useState(''); const [importPayload, setImportPayload] = useState('');
@ -135,6 +141,7 @@ export const ImportModal = ({ open, setOpen, project }: IImportModalProps) => {
environment={environment} environment={environment}
payload={importPayload} payload={importPayload}
onClose={close} onClose={close}
onImport={onImport}
/> />
} }
/> />

View File

@ -12,8 +12,6 @@ import { PulsingAvatar } from '../PulsingAvatar';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { Box } from '@mui/system'; import { Box } from '@mui/system';
import { useChangeRequestsEnabled } from 'hooks/useChangeRequestsEnabled'; import { useChangeRequestsEnabled } from 'hooks/useChangeRequestsEnabled';
import useProject from 'hooks/api/getters/useProject/useProject';
import { usePendingChangeRequests } from 'hooks/api/getters/usePendingChangeRequests/usePendingChangeRequests';
export const ImportStatusArea = styled(Box)(({ theme }) => ({ export const ImportStatusArea = styled(Box)(({ theme }) => ({
padding: theme.spacing(4, 2, 2, 2), padding: theme.spacing(4, 2, 2, 2),
@ -63,19 +61,16 @@ export const ImportStage: FC<{
project: string; project: string;
payload: string; payload: string;
onClose: () => void; onClose: () => void;
}> = ({ environment, project, payload, onClose }) => { onImport: () => void;
}> = ({ environment, project, payload, onClose, onImport }) => {
const { createImport, loading, errors } = useImportApi(); const { createImport, loading, errors } = useImportApi();
const { refetch: refreshProject } = useProject(project);
const { refetch: refreshChangeRequests } =
usePendingChangeRequests(project);
const { setToastData } = useToast(); const { setToastData } = useToast();
const { isChangeRequestConfigured } = useChangeRequestsEnabled(project); const { isChangeRequestConfigured } = useChangeRequestsEnabled(project);
useEffect(() => { useEffect(() => {
createImport({ environment, project, data: JSON.parse(payload) }) createImport({ environment, project, data: JSON.parse(payload) })
.then(() => { .then(() => {
refreshProject(); onImport();
refreshChangeRequests();
}) })
.catch((error) => { .catch((error) => {
setToastData({ setToastData({

View File

@ -0,0 +1,16 @@
import { usePendingChangeRequests } from 'hooks/api/getters/usePendingChangeRequests/usePendingChangeRequests';
import { useState } from 'react';
export const useRefreshOnImport = (projectId: string) => {
const { refetch: refreshChangeRequests } =
usePendingChangeRequests(projectId);
const [projectKey, setProjectKey] = useState(projectId);
const refreshProjectOverviewKey = () => {
setProjectKey(projectId + Date.now());
};
const refreshOnImport = () => {
refreshChangeRequests();
refreshProjectOverviewKey();
};
return { refreshOnImport, projectKey };
};

View File

@ -14,7 +14,7 @@ import {
StyledTabContainer, StyledTabContainer,
StyledTopRow, StyledTopRow,
} from './Project.styles'; } from './Project.styles';
import { Box, Paper, Tabs, Typography, styled } from '@mui/material'; import { Box, Paper, styled, Tabs, Typography } from '@mui/material';
import FileUpload from '@mui/icons-material/FileUpload'; import FileUpload from '@mui/icons-material/FileUpload';
import useToast from 'hooks/useToast'; import useToast from 'hooks/useToast';
import useQueryParams from 'hooks/useQueryParams'; import useQueryParams from 'hooks/useQueryParams';
@ -43,6 +43,7 @@ import { HiddenProjectIconWithTooltip } from './HiddenProjectIconWithTooltip/Hid
import { ChangeRequestPlausibleProvider } from 'component/changeRequest/ChangeRequestContext'; import { ChangeRequestPlausibleProvider } from 'component/changeRequest/ChangeRequestContext';
import { ProjectApplications } from '../ProjectApplications/ProjectApplications'; import { ProjectApplications } from '../ProjectApplications/ProjectApplications';
import { ProjectInsights } from './ProjectInsights/ProjectInsights'; import { ProjectInsights } from './ProjectInsights/ProjectInsights';
import { useRefreshOnImport } from './Import/useRefreshOnImport';
const StyledBadge = styled(Badge)(({ theme }) => ({ const StyledBadge = styled(Badge)(({ theme }) => ({
position: 'absolute', position: 'absolute',
@ -190,6 +191,8 @@ export const Project = () => {
</Box> </Box>
); );
const { refreshOnImport, projectKey } = useRefreshOnImport(projectId);
return ( return (
<div ref={ref}> <div ref={ref}>
<StyledHeader> <StyledHeader>
@ -324,12 +327,16 @@ export const Project = () => {
/> />
<Route path='settings/*' element={<ProjectSettings />} /> <Route path='settings/*' element={<ProjectSettings />} />
<Route path='applications' element={<ProjectApplications />} /> <Route path='applications' element={<ProjectApplications />} />
<Route path='*' element={<ProjectOverview />} /> <Route
path='*'
element={<ProjectOverview key={projectKey} />}
/>
</Routes> </Routes>
<ImportModal <ImportModal
open={modalOpen} open={modalOpen}
setOpen={setModalOpen} setOpen={setModalOpen}
project={projectId} project={projectId}
onImport={refreshOnImport}
/> />
</div> </div>
); );

View File

@ -34,7 +34,8 @@ const StyledContentContainer = styled(Box)(({ theme }) => ({
const ProjectOverview: FC<{ const ProjectOverview: FC<{
storageKey?: string; storageKey?: string;
}> = ({ storageKey = 'project-overview-v2' }) => { key: string;
}> = ({ key, storageKey = 'project-overview-v2' }) => {
const projectId = useRequiredPathParam('projectId'); const projectId = useRequiredPathParam('projectId');
const projectName = useProjectOverviewNameOrId(projectId); const projectName = useProjectOverviewNameOrId(projectId);
@ -49,7 +50,7 @@ const ProjectOverview: FC<{
}, [projectId, setLastViewed]); }, [projectId, setLastViewed]);
return ( return (
<StyledContainer key={projectId}> <StyledContainer key={key}>
<StyledContentContainer> <StyledContentContainer>
<ProjectOverviewChangeRequests project={projectId} /> <ProjectOverviewChangeRequests project={projectId} />