Skip to content

Commit 6db5eda

Browse files
[PRMP-1079] merge main, resolve conflicts
2 parents 5fcaf29 + 52819f8 commit 6db5eda

File tree

44 files changed

+728
-235
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+728
-235
lines changed

.devcontainer/Dockerfile

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,28 @@ RUN apt-get update && apt-get upgrade -y && apt-get install -y \
1010
strip-nondeterminism \
1111
uuid-runtime \
1212
parallel \
13-
bc
13+
bc \
14+
curl \
15+
ca-certificates \
16+
gnupg
17+
18+
# Prepare github-cli install
19+
RUN mkdir -p /etc/apt/keyrings \
20+
&& curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \
21+
| gpg --dearmor \
22+
| tee /etc/apt/keyrings/githubcli-archive-keyring.gpg > /dev/null \
23+
&& chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg \
24+
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] \
25+
https://cli.github.com/packages stable main" \
26+
| tee /etc/apt/sources.list.d/github-cli.list > /dev/null
1427

1528
# Install CLI tools.
1629
RUN apt-get update && apt-get install -y \
1730
vim \
1831
ranger \
1932
tmux \
20-
fzf
33+
fzf \
34+
gh
2135

2236
# Install base neovim
2337
RUN set -eux; \

.devcontainer/devcontainer.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@
4848
"source=${localEnv:HOME}/.ssh,target=/home/vscode/.ssh,type=bind,consistency=cached",
4949
"source=${localEnv:HOME}/.gnupg,target=/home/vscode/.gnupg,type=bind,consistency=cached",
5050
"source=${localWorkspaceFolder}/.devcontainer/config/nvim,target=/home/vscode/.config/nvim,type=bind",
51-
"source=${env:HOME}/.gitconfig,target=/home/vscode/.gitconfig,type=bind,consistency=cached"
51+
"source=${env:HOME}/.gitconfig,target=/home/vscode/.gitconfig,type=bind,consistency=cached",
52+
"source=${localEnv:HOME}/.config/gh,target=/home/vscode/.config/gh,type=bind",
53+
"source=${localEnv:NDRI_LOCATION},target=/workspaces/national-document-repository-infrastructure,type=bind,consistency=cached"
5254
],
5355
"postCreateCommand": "HOST_PWD=${localWorkspaceFolder} bash -c '.devcontainer/src/create.sh' ",
5456
"runArgs": [

Makefile

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ ZIP_BASE_PATH = ./$(LAMBDAS_BUILD_PATH)/$(lambda_name)/tmp
1818
ZIP_COMMON_FILES = lambdas/utils lambdas/models lambdas/services lambdas/repositories lambdas/enums lambdas/scripts
1919
CONTAINER ?= false
2020

21-
.PHONY: install clean help format list requirements ruff
21+
.PHONY: install clean help format list requirements ruff build-and-deploy-sandbox
2222

2323
default: help
2424

@@ -68,6 +68,17 @@ check-packages:
6868
./lambdas/venv/bin/pip-audit -r $(REPORTS_REQUIREMENTS)
6969
./lambdas/venv/bin/pip-audit -r $(ALERTING_REQUIREMENTS)
7070

71+
build-and-deploy-sandbox: ## Build a sandbox and deploy code. If no SANDBOX_NAME is provided it will use your current branch as the name. It will default to building and deploying using 'main', You can skip building infrastructure by BUILD_INFRA=false. Usage: make build-and-deploy-sandbox SANDBOX_NAME=<sandbox_name> NDRI_WORKFLOW_BRANCH=<branch> NDRI_BRANCH=<branch> NDR_WORKFLOW_BRANCH=<branch> NDR_BRANCH=<branch> BUILD_INFRA=<true|false> NDRI_DIR_LOC_OVERRIDE=<dir_location>
72+
@./scripts/build_and_deploy_sandbox.sh \
73+
$(if $(NDRI_WORKFLOW_BRANCH),--ndri_workflow_branch=$(NDRI_WORKFLOW_BRANCH)) \
74+
$(if $(NDRI_BRANCH),--ndri_branch=$(NDRI_BRANCH)) \
75+
$(if $(NDR_WORKFLOW_BRANCH),--ndr_workflow_branch=$(NDR_WORKFLOW_BRANCH)) \
76+
$(if $(NDR_BRANCH),--ndr_branch=$(NDR_BRANCH)) \
77+
$(if $(SANDBOX_NAME),--sandbox_name=$(SANDBOX_NAME)) \
78+
$(if $(BUILD_INFRA),--build_infra=$(BUILD_INFRA)) \
79+
$(if $(FULL_DEPLOY),--full_deploy=$(FULL_DEPLOY)) \
80+
$(if $(NDRI_DIR_LOC_OVERRIDE),--ndri_dir_loc_override=$(NDRI_DIR_LOC_OVERRIDE))
81+
7182
download-api-certs: ## Downloads mTLS certificates (use with dev envs only). Usage: make download-api-certs WORKSPACE=<workspace>
7283
rm -rf ./lambdas/mtls_env_certs/$(WORKSPACE)
7384
./scripts/aws/download-api-certs.sh $(WORKSPACE)

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,15 @@ The following tools are required for all options:
3131
- [Git](https://git-scm.com/)
3232
- Docker (e.g. via [Brew](https://formulae.brew.sh/formula/docker))
3333
34+
Setup an environment variable on your local system. The environment variable points to your national-document-repository-infrastructure directory on your local system.
35+
For Linux/MacOS users add the following to your ~/.zshrc or ~/.bashrc file
36+
37+
```bash
38+
export NDRI_LOCATION=<national-document-repository-infrastructure FOLDER location>
39+
```
40+
41+
For Windows users, please follow Microsoft's recommendations for creating persistent environment variables
42+
3443
### Method 1 - Dev container within VS Code (recommended)
3544

3645
> [!IMPORTANT]
@@ -70,6 +79,18 @@ lazygit
7079
- [Node@24](https://formulae.brew.sh/formula/node@24)
7180
- [[email protected]](https://formulae.brew.sh/formula/[email protected])
7281

82+
### Initial Setup of the container
83+
84+
1. Configure Github-CLI with
85+
86+
```bash
87+
gh auth login
88+
```
89+
90+
## Deploying a sandbox
91+
92+
In order to fully test your development it may be necessary to build and deploy your own temporary sandbox on the dev environment. In order to build a sandbox please [follow the steps outlined in confluence](https://nhsd-confluence.digital.nhs.uk/spaces/NDR/pages/1145307545/How+To+Deploy+Custom+Sandbox)
93+
7394
## Monitoring
7495

7596
We have configured AWS CloudWatch to provide alarm notifications whenever one of a number of metrics exceeds its normal
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
import { pdsPatients } from '../../../support/patients';
2+
import { Roles } from '../../../support/roles';
3+
4+
const workspace = Cypress.env('WORKSPACE');
5+
6+
const baseUrl = Cypress.config('baseUrl');
7+
8+
const uploadedFilePathNames = [
9+
'cypress/fixtures/lg-files/zenia_lees/1of3_Lloyd_George_Record_[Zenia Ellisa LEES]_[9730153930]_[20-03-1929].pdf',
10+
'cypress/fixtures/lg-files/zenia_lees/2of3_Lloyd_George_Record_[Zenia Ellisa LEES]_[9730153930]_[20-03-1929].pdf',
11+
'cypress/fixtures/lg-files/zenia_lees/3of3_Lloyd_George_Record_[Zenia Ellisa LEES]_[9730153930]_[20-03-1929].pdf',
12+
];
13+
const uploadedFileNames = [
14+
'1of3_Lloyd_George_Record_[Zenia Ellisa LEES]_[9730153930]_[20-03-1929].pdf',
15+
'2of3_Lloyd_George_Record_[Zenia Ellisa LEES]_[9730153930]_[20-03-1929].pdf',
16+
'3of3_Lloyd_George_Record_[Zenia Ellisa LEES]_[9730153930]_[20-03-1929].pdf',
17+
];
18+
19+
const bucketName = `${workspace}-lloyd-george-store`;
20+
const referenceTableName = `${workspace}_LloydGeorgeReferenceMetadata`;
21+
const stitchTableName = `${workspace}_LloydGeorgeStitchJobMetadata`;
22+
23+
const patientVerifyUrl = '/patient/verify';
24+
const lloydGeorgeRecordUrl = '/patient/lloyd-george-record';
25+
const selectOrderUrl = '/patient/document-upload/select-order';
26+
const confirmationUrl = '/patient/document-upload/confirmation';
27+
28+
const activePatient = pdsPatients.activeNoUpload;
29+
30+
describe('GP Workflow: Upload Lloyd George record', () => {
31+
context('Upload a Lloyd George document', () => {
32+
beforeEach(() => {
33+
//delete any records present for the active patient
34+
cy.deleteItemsBySecondaryKeyFromDynamoDb(
35+
referenceTableName,
36+
'NhsNumberIndex',
37+
'NhsNumber',
38+
activePatient.toString(),
39+
);
40+
cy.deleteItemsBySecondaryKeyFromDynamoDb(
41+
stitchTableName,
42+
'NhsNumberIndex',
43+
'NhsNumber',
44+
activePatient.toString()
45+
);
46+
uploadedFileNames.forEach((file) => {
47+
cy.deleteFileFromS3(bucketName, file);
48+
});
49+
});
50+
51+
afterEach(() => {
52+
//clean up any records present for the active patient
53+
cy.deleteItemsBySecondaryKeyFromDynamoDb(
54+
referenceTableName,
55+
'NhsNumberIndex',
56+
'NhsNumber',
57+
activePatient.toString(),
58+
);
59+
cy.deleteItemsBySecondaryKeyFromDynamoDb(
60+
stitchTableName,
61+
'NhsNumberIndex',
62+
'NhsNumber',
63+
activePatient.toString()
64+
);
65+
uploadedFileNames.forEach((file) => {
66+
cy.deleteFileFromS3(bucketName, file);
67+
});
68+
});
69+
70+
it(
71+
'[Smoke] GP Clinical can upload multiple files and then view a Lloyd George record for an active patient with no record',
72+
{ tags: 'smoke', defaultCommandTimeout: 20000 },
73+
() => {
74+
cy.smokeLogin(Roles.SMOKE_GP_CLINICAL);
75+
76+
cy.navigateToPatientSearchPage();
77+
78+
cy.get('#nhs-number-input').should('exist');
79+
cy.get('#nhs-number-input').click();
80+
cy.get('#nhs-number-input').type(activePatient);
81+
cy.getByTestId('search-submit-btn').should('exist');
82+
cy.getByTestId('search-submit-btn').click();
83+
84+
cy.url({ timeout: 15000 }).should('contain', patientVerifyUrl);
85+
86+
cy.get('#verify-submit').should('exist');
87+
cy.get('#verify-submit').click();
88+
89+
cy.url().should('contain', lloydGeorgeRecordUrl);
90+
cy.getByTestId('no-records-title').should(
91+
'include.text',
92+
'This patient does not have a Lloyd George record',
93+
);
94+
cy.getByTestId('upload-patient-record-button').should('exist');
95+
cy.getByTestId('upload-patient-record-button').click();
96+
uploadedFilePathNames.forEach((file) => {
97+
cy.getByTestId('button-input').selectFile(file, { force: true });
98+
var index = uploadedFilePathNames.indexOf(file);
99+
cy.get('#selected-documents-table').should('contain', uploadedFileNames[index]);
100+
});
101+
cy.get('#continue-button').click();
102+
103+
cy.url().should('contain', selectOrderUrl);
104+
cy.get('#selected-documents-table').should('exist');
105+
uploadedFileNames.forEach((name) => {
106+
cy.get('#selected-documents-table').should('contain', name);
107+
});
108+
cy.getByTestId('form-submit-button').click();
109+
110+
cy.url().should('contain', confirmationUrl);
111+
uploadedFileNames.forEach((name) => {
112+
cy.get('#selected-documents-table').should('contain', name);
113+
});
114+
cy.getByTestId('confirm-button').click();
115+
116+
cy.getByTestId('upload-complete-page', { timeout: 25000 }).should('exist');
117+
118+
cy.getByTestId('upload-complete-card').should('be.visible');
119+
120+
cy.getByTestId('home-btn').eq(1).click();
121+
122+
cy.navigateToPatientSearchPage();
123+
124+
cy.get('#nhs-number-input').type(activePatient);
125+
cy.get('#search-submit').click();
126+
cy.wait(5000)
127+
128+
cy.get('.patient-results-form').submit();
129+
130+
cy.get("#pdf-viewer", { timeout: 20000 }).should('exist');
131+
});
132+
});
133+
});

app/src/components/blocks/_delete/deleteResultStage/DeleteResultStage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ const DeleteResultStage = ({ docType, setDownloadStage }: Props): React.JSX.Elem
3535
const recordLabel = docType ? getDocumentTypeLabel(docType) : '';
3636

3737
const isGP = role === REPOSITORY_ROLE.GP_ADMIN || role === REPOSITORY_ROLE.GP_CLINICAL;
38-
const pageHeader = `You have permanently removed the ${recordLabel ? recordLabel : 'records'} of:`;
38+
const pageHeader = `You have permanently removed the ${recordLabel || 'records'} of:`;
3939
useTitle({ pageTitle: pageHeader });
4040

4141
return (

app/src/components/blocks/_delete/deleteSubmitStage/DeleteSubmitStage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ const DeleteSubmitStageIndexView = ({
116116
}
117117
};
118118

119-
const pageTitle = `You are removing the ${getDocumentTypeLabel(docType) ?? 'records'} of`;
119+
const pageTitle = `You are removing the ${getDocumentTypeLabel(docType) || 'records'} of`;
120120
useTitle({ pageTitle });
121121

122122
return (

app/src/pages/startPage/StartPage.test.tsx

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,12 @@ describe('StartPage', () => {
5151
);
5252
expect(downloadOdsReport).toHaveLength(2);
5353

54-
const contact = screen.getAllByText(/Contact the/i);
55-
expect(contact.length).toBe(2);
56-
const contactLinks = screen.getAllByRole('link', {
57-
name: /NHS National Service Desk/i,
58-
});
59-
expect(contactLinks.length).toBe(2);
54+
expect(screen.getByText(/Contact the/i)).toBeInTheDocument();
55+
expect(
56+
screen.getByRole('link', {
57+
name: /NHS National Service Desk/i,
58+
}),
59+
).toBeInTheDocument();
6060
expect(
6161
screen.getByText(/if there is an issue with this service or call 0300 303 5035\./i),
6262
).toBeInTheDocument();
@@ -65,20 +65,19 @@ describe('StartPage', () => {
6565
it('renders a service link that takes you to service help-desk in a new tab', () => {
6666
render(<StartPage />);
6767

68-
const contactTexts = screen.getAllByText(/Contact the/i);
69-
expect(contactTexts.length).toBe(2);
70-
const nationalServiceDeskLink = screen.getAllByRole('link', {
68+
expect(screen.getByText(/Contact the/i)).toBeInTheDocument();
69+
const nationalServiceDeskLink = screen.getByRole('link', {
7170
name: /NHS National Service Desk/i,
7271
});
7372
expect(
7473
screen.getByText(/if there is an issue with this service or call 0300 303 5035/i),
7574
).toBeInTheDocument();
7675

77-
expect(nationalServiceDeskLink[1]).toHaveAttribute(
76+
expect(nationalServiceDeskLink).toHaveAttribute(
7877
'href',
7978
'https://digital.nhs.uk/about-nhs-digital/contact-us#nhs-digital-service-desks',
8079
);
81-
expect(nationalServiceDeskLink[1]).toHaveAttribute('target', '_blank');
80+
expect(nationalServiceDeskLink).toHaveAttribute('target', '_blank');
8281
});
8382

8483
it('pass accessibility checks', async () => {

app/src/pages/startPage/StartPage.tsx

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import useBaseAPIUrl from '../../helpers/hooks/useBaseAPIUrl';
1010
import TestPanel from '../../components/blocks/testPanel/TestPanel';
1111
import ServiceDeskLink from '../../components/generic/serviceDeskLink/ServiceDeskLink';
1212
import useTitle from '../../helpers/hooks/useTitle';
13-
import NotificationBanner from '../../components/layout/notificationBanner/NotificationBanner';
1413

1514
const StartPage = (): React.JSX.Element => {
1615
const navigate = useNavigate();
@@ -27,36 +26,11 @@ const StartPage = (): React.JSX.Element => {
2726
}
2827
};
2928

30-
const nhsServiceDeskLink = <ServiceDeskLink />;
31-
const nationalServiceDeskEmail = (
32-
33-
);
34-
3529
const pageHeader = 'Access and store digital patient documents';
3630
useTitle({ pageTitle: pageHeader });
3731

3832
return !isLoading ? (
3933
<>
40-
<NotificationBanner
41-
title="Important"
42-
className="start_page_notification_banner"
43-
dataTestId="start_page_notification_banner"
44-
scrollToRef={null}
45-
>
46-
<span>
47-
<p>
48-
<b>
49-
There will be reduced support for this service between 24 December 2025
50-
and 2 January 2026
51-
</b>
52-
</p>
53-
<p>
54-
If there is a problem with this service between these dates, contact the{' '}
55-
{nhsServiceDeskLink} on 0300 303 5035, or email {nationalServiceDeskEmail}.
56-
</p>
57-
</span>
58-
</NotificationBanner>
59-
6034
<h1>{pageHeader}</h1>
6135
<p>
6236
This service gives you access to Lloyd George digital health records. You may have

app/src/styles/App.scss

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1161,11 +1161,6 @@ $hunit: '%';
11611161
border-color: black;
11621162
}
11631163

1164-
.start_page_notification_banner {
1165-
background-color: #005eb8;
1166-
border-color: #005eb8;
1167-
}
1168-
11691164
.download-failed-banner {
11701165
max-width: fit-content;
11711166
}

0 commit comments

Comments
 (0)