Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EES-5419 import new data set version #5152

Merged
merged 4 commits into from
Aug 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useConfig } from '@admin/contexts/ConfigContext';
import ApiDataSetVersionSummaryList from '@admin/pages/release/data/components/ApiDataSetVersionSummaryList';
import DeleteDraftVersionButton from '@admin/pages/release/data/components/DeleteDraftVersionButton';
import ApiDataSetCreateModal from '@admin/pages/release/data/components/ApiDataSetCreateModal';
import ApiDataSetFinaliseBanner from '@admin/pages/release/data/components/ApiDataSetFinaliseBanner';
import { useReleaseContext } from '@admin/pages/release/contexts/ReleaseContext';
import apiDataSetQueries from '@admin/queries/apiDataSetQueries';
import {
Expand All @@ -25,9 +26,11 @@ import Tag, { TagProps } from '@common/components/Tag';
import TaskList from '@common/components/TaskList';
import TaskListItem from '@common/components/TaskListItem';
import { useQuery } from '@tanstack/react-query';
import React from 'react';
import React, { useEffect, useState } from 'react';
import { generatePath, useHistory, useParams } from 'react-router-dom';

export type DataSetFinalisingStatus = 'finalising' | 'finalised' | undefined;

// TODO: EES-4367
const showChangelog = false;
// TODO: EES-4382
Expand All @@ -40,14 +43,20 @@ export default function ReleaseApiDataSetDetailsPage() {
const { publicAppUrl } = useConfig();
const { release } = useReleaseContext();

const [finalisingStatus, setFinalisingStatus] =
useState<DataSetFinalisingStatus>(undefined);

const {
data: dataSet,
isLoading,
refetch,
} = useQuery({
...apiDataSetQueries.get(dataSetId),
refetchInterval: data => {
return data?.draftVersion?.status === 'Processing' ? 3000 : false;
return data?.draftVersion?.status === 'Processing' ||
finalisingStatus === 'finalising'
? 3000
: false;
},
});

Expand All @@ -58,6 +67,24 @@ export default function ReleaseApiDataSetDetailsPage() {
? 'govuk-grid-column-one-half-from-desktop'
: 'govuk-grid-column-two-thirds-from-desktop';

const handleFinalise = async () => {
if (dataSet?.draftVersion) {
setFinalisingStatus('finalising');
await apiDataSetVersionService.completeVersion({
dataSetVersionId: dataSet?.draftVersion?.id,
});
}
};

useEffect(() => {
if (
finalisingStatus === 'finalising' &&
dataSet?.draftVersion?.status !== 'Mapping'
) {
setFinalisingStatus('finalised');
}
}, [finalisingStatus, dataSet?.draftVersion?.status, setFinalisingStatus]);

const draftVersionSummary = dataSet?.draftVersion ? (
<ApiDataSetVersionSummaryList
dataSetVersion={dataSet?.draftVersion}
Expand Down Expand Up @@ -156,16 +183,15 @@ export default function ReleaseApiDataSetDetailsPage() {
/>
) : null;

function getDataSetStatusColour(status: DataSetStatus): TagProps['colour'] {
switch (status) {
case 'Deprecated':
return 'purple';
case 'Withdrawn':
return 'red';
default:
return 'blue';
}
}
const mappingComplete =
dataSet?.draftVersion?.mappingStatus &&
dataSet.draftVersion.mappingStatus.filtersComplete &&
dataSet.draftVersion.mappingStatus.locationsComplete;

const showDraftVersionTasks =
finalisingStatus !== 'finalising' &&
(dataSet?.draftVersion?.status === 'Draft' ||
dataSet?.draftVersion?.status === 'Mapping');

return (
<>
Expand All @@ -186,6 +212,14 @@ export default function ReleaseApiDataSetDetailsPage() {
<span className="govuk-caption-l">API data set details</span>
<h2>{dataSet.title}</h2>

{mappingComplete && (
<ApiDataSetFinaliseBanner
draftVersionStatus={dataSet.draftVersion?.status}
finalisingStatus={finalisingStatus}
onFinalise={handleFinalise}
/>
)}

<SummaryList
className="govuk-!-margin-bottom-8"
testId="data-set-summary"
Expand All @@ -200,7 +234,7 @@ export default function ReleaseApiDataSetDetailsPage() {
</SummaryListItem>
</SummaryList>

{dataSet.draftVersion?.status === 'Mapping' && (
{showDraftVersionTasks && dataSet.draftVersion && (
<div className="govuk-grid-row">
<div className={columnSizeClassName}>
<h3>Draft version tasks</h3>
Expand Down Expand Up @@ -343,3 +377,14 @@ export default function ReleaseApiDataSetDetailsPage() {
</>
);
}

function getDataSetStatusColour(status: DataSetStatus): TagProps['colour'] {
switch (status) {
case 'Deprecated':
return 'purple';
case 'Withdrawn':
return 'red';
default:
return 'blue';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,18 @@ import _apiDataSetService, {
ApiDataSetDraftVersion,
ApiDataSetLiveVersion,
} from '@admin/services/apiDataSetService';
import _apiDataSetVersionService from '@admin/services/apiDataSetVersionService';
import { Release } from '@admin/services/releaseService';
import render from '@common-test/render';
import { screen, within } from '@testing-library/react';
import { screen, waitFor, within } from '@testing-library/react';
import React from 'react';
import { generatePath, MemoryRouter, Route } from 'react-router-dom';

jest.mock('@admin/services/apiDataSetService');
jest.mock('@admin/services/apiDataSetVersionService');

const apiDataSetService = jest.mocked(_apiDataSetService);
const apiDataSetVersionService = jest.mocked(_apiDataSetVersionService);

describe('ReleaseApiDataSetDetailsPage', () => {
const testDataSet: ApiDataSet = {
Expand Down Expand Up @@ -396,10 +399,213 @@ describe('ReleaseApiDataSetDetailsPage', () => {
).not.toBeInTheDocument();
});

describe('finalising', () => {
beforeEach(() => {
jest.useFakeTimers({ advanceTimers: true });
});
afterEach(() => {
jest.useRealTimers();
});

test('shows the finalise banner when mapping is complete', async () => {
apiDataSetService.getDataSet.mockResolvedValue({
...testDataSet,
draftVersion: {
...testDraftVersion,
status: 'Mapping',
mappingStatus: {
filtersComplete: true,
locationsComplete: true,
},
},
latestLiveVersion: testLiveVersion,
});

renderPage();

expect(
await screen.findByText('Draft version details'),
).toBeInTheDocument();

const banner = within(screen.getByTestId('notificationBanner'));
expect(
banner.getByRole('heading', { name: 'Action required' }),
).toBeInTheDocument();
expect(
banner.getByText('Draft API data set version is ready to be finalised'),
).toBeInTheDocument();
expect(
banner.getByRole('button', { name: 'Finalise this data set version' }),
).toBeInTheDocument();
});

test('successfully finalised', async () => {
apiDataSetService.getDataSet.mockResolvedValueOnce({
...testDataSet,
draftVersion: {
...testDraftVersion,
status: 'Mapping',
mappingStatus: {
filtersComplete: true,
locationsComplete: true,
},
},
latestLiveVersion: testLiveVersion,
});
apiDataSetService.getDataSet.mockResolvedValueOnce({
...testDataSet,
draftVersion: {
...testDraftVersion,
status: 'Draft',
mappingStatus: {
filtersComplete: true,
locationsComplete: true,
},
},
latestLiveVersion: testLiveVersion,
});

const { user } = renderPage();

expect(
await screen.findByText('Draft version details'),
).toBeInTheDocument();

expect(apiDataSetVersionService.completeVersion).not.toHaveBeenCalled();

const banner = within(screen.getByTestId('notificationBanner'));
expect(
banner.getByRole('heading', { name: 'Action required' }),
).toBeInTheDocument();

await user.click(
banner.getByRole('button', { name: 'Finalise this data set version' }),
);

await waitFor(() => {
expect(apiDataSetVersionService.completeVersion).toHaveBeenCalledTimes(
1,
);
expect(apiDataSetVersionService.completeVersion).toHaveBeenCalledWith({
dataSetVersionId: 'draft-version-id',
});
});

expect(
banner.getByRole('heading', { name: 'Finalising' }),
).toBeInTheDocument();
expect(
banner.getByText('Finalising draft API data set version'),
).toBeInTheDocument();
expect(
banner.queryByRole('button', {
name: 'Finalise this data set version',
}),
).not.toBeInTheDocument();

jest.runOnlyPendingTimers();

await waitFor(() => {
expect(
banner.getByText(
'Draft API data set version is ready to be published',
),
).toBeInTheDocument();
});

expect(
banner.getByRole('heading', {
name: 'Mappings finalised',
}),
).toBeInTheDocument();

expect(
banner.queryByRole('button', {
name: 'Finalise this data set version',
}),
).not.toBeInTheDocument();
});

test('finalising failed', async () => {
apiDataSetService.getDataSet.mockResolvedValueOnce({
...testDataSet,
draftVersion: {
...testDraftVersion,
status: 'Mapping',
mappingStatus: {
filtersComplete: true,
locationsComplete: true,
},
},
latestLiveVersion: testLiveVersion,
});
apiDataSetService.getDataSet.mockResolvedValueOnce({
...testDataSet,
draftVersion: {
...testDraftVersion,
status: 'Failed',
mappingStatus: {
filtersComplete: true,
locationsComplete: true,
},
},
latestLiveVersion: testLiveVersion,
});

const { user } = renderPage();

expect(
await screen.findByText('Draft version details'),
).toBeInTheDocument();

expect(apiDataSetVersionService.completeVersion).not.toHaveBeenCalled();

const banner = within(screen.getByTestId('notificationBanner'));
expect(
banner.getByRole('heading', { name: 'Action required' }),
).toBeInTheDocument();

await user.click(
banner.getByRole('button', { name: 'Finalise this data set version' }),
);

await waitFor(() => {
expect(apiDataSetVersionService.completeVersion).toHaveBeenCalledTimes(
1,
);
expect(apiDataSetVersionService.completeVersion).toHaveBeenCalledWith({
dataSetVersionId: 'draft-version-id',
});
});

expect(
banner.getByRole('heading', { name: 'Finalising' }),
).toBeInTheDocument();
expect(
banner.getByText('Finalising draft API data set version'),
).toBeInTheDocument();
expect(
banner.queryByRole('button', {
name: 'Finalise this data set version',
}),
).not.toBeInTheDocument();

jest.runOnlyPendingTimers();

await waitFor(() => {
expect(banner.getByText('There is a problem')).toBeInTheDocument();
});

expect(
banner.getByText('Data set version finalisation failed'),
).toBeInTheDocument();
});
});

function renderPage(options?: { release?: Release; dataSetId?: string }) {
const { release = testRelease, dataSetId = 'data-set-id' } = options ?? {};

render(
return render(
<TestConfigContextProvider>
<ReleaseContextProvider release={release}>
<MemoryRouter
Expand Down
Loading