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:
parent
dfc0c3c63f
commit
801cb4577a
@ -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(() => {
|
||||||
|
@ -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}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
@ -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({
|
||||||
|
@ -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 };
|
||||||
|
};
|
@ -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>
|
||||||
);
|
);
|
||||||
|
@ -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} />
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user