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) => {
|
||||
closed = !open;
|
||||
};
|
||||
render(<ImportModal open={true} setOpen={setOpen} project='default' />, {
|
||||
permissions: [{ permission: CREATE_FEATURE }],
|
||||
});
|
||||
let imported = false;
|
||||
const onImport = () => {
|
||||
imported = true;
|
||||
};
|
||||
render(
|
||||
<ImportModal
|
||||
open={true}
|
||||
setOpen={setOpen}
|
||||
project='default'
|
||||
onImport={onImport}
|
||||
/>,
|
||||
{
|
||||
permissions: [{ permission: CREATE_FEATURE }],
|
||||
},
|
||||
);
|
||||
|
||||
// configure stage
|
||||
screen.getByText('Import options');
|
||||
@ -76,6 +88,8 @@ test('Import happy path', async () => {
|
||||
await screen.findByText('Importing...');
|
||||
await screen.findByText('Import completed');
|
||||
|
||||
expect(imported).toBe(true);
|
||||
|
||||
expect(closed).toBe(false);
|
||||
const closeButton = screen.getByText('Close');
|
||||
closeButton.click();
|
||||
@ -85,9 +99,18 @@ test('Import happy path', async () => {
|
||||
test('Block when importing non json content', async () => {
|
||||
setupApi();
|
||||
const setOpen = () => {};
|
||||
render(<ImportModal open={true} setOpen={setOpen} project='default' />, {
|
||||
permissions: [{ permission: CREATE_FEATURE }],
|
||||
});
|
||||
const onImport = () => {};
|
||||
render(
|
||||
<ImportModal
|
||||
open={true}
|
||||
setOpen={setOpen}
|
||||
project='default'
|
||||
onImport={onImport}
|
||||
/>,
|
||||
{
|
||||
permissions: [{ permission: CREATE_FEATURE }],
|
||||
},
|
||||
);
|
||||
|
||||
const codeEditorLabel = screen.getByText('Code editor');
|
||||
codeEditorLabel.click();
|
||||
@ -123,9 +146,18 @@ test('Show validation errors', async () => {
|
||||
'post',
|
||||
);
|
||||
const setOpen = () => {};
|
||||
render(<ImportModal open={true} setOpen={setOpen} project='default' />, {
|
||||
permissions: [{ permission: CREATE_FEATURE }],
|
||||
});
|
||||
const onImport = () => {};
|
||||
render(
|
||||
<ImportModal
|
||||
open={true}
|
||||
setOpen={setOpen}
|
||||
project='default'
|
||||
onImport={onImport}
|
||||
/>,
|
||||
{
|
||||
permissions: [{ permission: CREATE_FEATURE }],
|
||||
},
|
||||
);
|
||||
|
||||
await importFile('{}');
|
||||
await waitFor(() => {
|
||||
|
@ -47,9 +47,15 @@ interface IImportModalProps {
|
||||
open: boolean;
|
||||
setOpen: (value: boolean) => void;
|
||||
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 [environment, setEnvironment] = useState('');
|
||||
const [importPayload, setImportPayload] = useState('');
|
||||
@ -135,6 +141,7 @@ export const ImportModal = ({ open, setOpen, project }: IImportModalProps) => {
|
||||
environment={environment}
|
||||
payload={importPayload}
|
||||
onClose={close}
|
||||
onImport={onImport}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
@ -12,8 +12,6 @@ import { PulsingAvatar } from '../PulsingAvatar';
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
import { Box } from '@mui/system';
|
||||
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 }) => ({
|
||||
padding: theme.spacing(4, 2, 2, 2),
|
||||
@ -63,19 +61,16 @@ export const ImportStage: FC<{
|
||||
project: string;
|
||||
payload: string;
|
||||
onClose: () => void;
|
||||
}> = ({ environment, project, payload, onClose }) => {
|
||||
onImport: () => void;
|
||||
}> = ({ environment, project, payload, onClose, onImport }) => {
|
||||
const { createImport, loading, errors } = useImportApi();
|
||||
const { refetch: refreshProject } = useProject(project);
|
||||
const { refetch: refreshChangeRequests } =
|
||||
usePendingChangeRequests(project);
|
||||
const { setToastData } = useToast();
|
||||
const { isChangeRequestConfigured } = useChangeRequestsEnabled(project);
|
||||
|
||||
useEffect(() => {
|
||||
createImport({ environment, project, data: JSON.parse(payload) })
|
||||
.then(() => {
|
||||
refreshProject();
|
||||
refreshChangeRequests();
|
||||
onImport();
|
||||
})
|
||||
.catch((error) => {
|
||||
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,
|
||||
StyledTopRow,
|
||||
} 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 useToast from 'hooks/useToast';
|
||||
import useQueryParams from 'hooks/useQueryParams';
|
||||
@ -43,6 +43,7 @@ import { HiddenProjectIconWithTooltip } from './HiddenProjectIconWithTooltip/Hid
|
||||
import { ChangeRequestPlausibleProvider } from 'component/changeRequest/ChangeRequestContext';
|
||||
import { ProjectApplications } from '../ProjectApplications/ProjectApplications';
|
||||
import { ProjectInsights } from './ProjectInsights/ProjectInsights';
|
||||
import { useRefreshOnImport } from './Import/useRefreshOnImport';
|
||||
|
||||
const StyledBadge = styled(Badge)(({ theme }) => ({
|
||||
position: 'absolute',
|
||||
@ -190,6 +191,8 @@ export const Project = () => {
|
||||
</Box>
|
||||
);
|
||||
|
||||
const { refreshOnImport, projectKey } = useRefreshOnImport(projectId);
|
||||
|
||||
return (
|
||||
<div ref={ref}>
|
||||
<StyledHeader>
|
||||
@ -324,12 +327,16 @@ export const Project = () => {
|
||||
/>
|
||||
<Route path='settings/*' element={<ProjectSettings />} />
|
||||
<Route path='applications' element={<ProjectApplications />} />
|
||||
<Route path='*' element={<ProjectOverview />} />
|
||||
<Route
|
||||
path='*'
|
||||
element={<ProjectOverview key={projectKey} />}
|
||||
/>
|
||||
</Routes>
|
||||
<ImportModal
|
||||
open={modalOpen}
|
||||
setOpen={setModalOpen}
|
||||
project={projectId}
|
||||
onImport={refreshOnImport}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
@ -34,7 +34,8 @@ const StyledContentContainer = styled(Box)(({ theme }) => ({
|
||||
|
||||
const ProjectOverview: FC<{
|
||||
storageKey?: string;
|
||||
}> = ({ storageKey = 'project-overview-v2' }) => {
|
||||
key: string;
|
||||
}> = ({ key, storageKey = 'project-overview-v2' }) => {
|
||||
const projectId = useRequiredPathParam('projectId');
|
||||
const projectName = useProjectOverviewNameOrId(projectId);
|
||||
|
||||
@ -49,7 +50,7 @@ const ProjectOverview: FC<{
|
||||
}, [projectId, setLastViewed]);
|
||||
|
||||
return (
|
||||
<StyledContainer key={projectId}>
|
||||
<StyledContainer key={key}>
|
||||
<StyledContentContainer>
|
||||
<ProjectOverviewChangeRequests project={projectId} />
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user