Skip to content

feat: add export to excel functionality in reviewers and assignments tab in fap page - #1839

Open
Bhaswati1148 wants to merge 30 commits into
developfrom
1574-export-fap-reviewers-review
Open

Bhaswati1148 wants to merge 30 commits into
developfrom
1574-export-fap-reviewers-review

Conversation

@Bhaswati1148

Copy link
Copy Markdown
Contributor

Description

This PR adds the export to excel functionality in reviewers and assignments tab in fap page. The export creates multiple sheets if multiple users(reviewers) are selected.
The exported excel will have the columns : Proposal ID, Proposal title, Instrument, Date assigned, Rank, Grade, Comment, Status

Motivation and Context

This functionality has been added to allow the FAP Secretary in STFC to export reviewer reviews to Excel.

How Has This Been Tested

An E2E test has been added to verify the export functionality when the download button is clicked and to validate the contents of the exported Excel file.

Fixes

Closes UserOfficeProject/issue-tracker#1574

Changes

Depends on

Tests included/Docs Updated?

  • I have added tests to cover my changes.
  • All relevant doc has been updated

@Bhaswati1148
Bhaswati1148 requested a review from a team as a code owner September 28, 2026 14:21
@Bhaswati1148
Bhaswati1148 requested review from mutambaraf and removed request for a team September 28, 2026 14:21
@Bhaswati1148 Bhaswati1148 changed the title feat: add export to excel functionality in reviewers and assignments page feat: add export to excel functionality in reviewers and assignments tab in fap page Sep 28, 2026
.andWhere('call_id', callId);
.where('fap_id', fapId);

if (callId != 0) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a legitimate case where callId is 0?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The callId is set to 0 when no calls are selected in the frontend.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could add a commment?

Comment thread apps/e2e/cypress/e2e/FAPs.cy.ts Outdated

cy.get('[data-cy="submit"]').click();

cy.notification({

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the motivation behind removing this?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed the notification assertion because the success notification appears and disappears very quickly, and I couldn't find a reliable way for Cypress to get hold of it before it disappeared. This was making the test unreliable. The assignment itself is still verified by checking that the proposal appears in the FAP assignments table, so the test continues to validate the operation successfully.

return;
}
const reviewerProposalMap = new Map<number, number[]>();
// const reviewerIds = rowData.map((reviewer) => reviewer.user.userId);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can these commented out lines please be removed?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed them

});
const reviewerProposals = Object.fromEntries(reviewerProposalMap);
reviewerProposalMap.forEach((key, value) => {
console.log('reviewerid ' + key + `proposals ` + value);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This logging can be removed now, I reckon.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed them

@mutambaraf mutambaraf left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM apart form just a few comments

Comment on lines +144 to +146
const userWithRole = {
...res.locals.agent,
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may need to validate we are getting all the information we need from this object.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Id is the information we need from userWithRole object which will be used further in the process. The middleware effectively validates the user’s id, it reads req.user.user.id, looks up that user with getAgent(id), and returns an unauthorized response if no user is found. It then puts the resulting user data into res.locals.agent. So I believe a second id check in the XLSX handler would usually be redundant.

const reviewerProposalsParam = req.query.reviewerProposals;

if (typeof reviewerProposalsParam !== 'string') {
throw new Error('reviewerProposals is required');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can say Proposals reviewer is required

@mutambaraf mutambaraf left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM apart from the failing tests

dateAssigned: formatDate(assignment.dateAssigned),
rank: assignment.rank ?? null,
grade: assignment.grade,
comment: stripHtml(assignment.comment ?? '-'),

@zacharyjhankin zacharyjhankin Oct 12, 2026 •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could be more clear about what comment this is. There are loads of different types of comments on proposals, which one?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could be more clear about what comment this is. There are loads of different types of comments on proposals, which one?

The Excel export feature is being added to the Review and Assignments tab on the FAP page. This tab displays reviewers and their reviews of proposals assigned to them, as well as reviews submitted by other reviewers. Therefore, the comments included in the Excel export refer specifically to the FAP reviewers’ comments on those proposals.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thus "FAP review comment" column heading?

@zacharyjhankin

Copy link
Copy Markdown
Collaborator

Are we planning to support importing this in the future?

@Bhaswati1148

Copy link
Copy Markdown
Contributor Author

Are we planning to support importing this in the future?

There are no plans to support importing this at the moment.

Comment thread apps/e2e/package.json Outdated
"luxon": "^3.4.4",
"pdf-parse": "^1.1.1",
"typescript": "~5.3.3",
"typescript": "^5.3.3",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From memory typescript doesn't actually follow semantic versioning. So when you put this ^ it allows the minor version to get automatically bumped. Which could potentially break UOS when someone releases to production. It seems like we shouldn't update any dependencies, maybe an accident while developing?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also isn't typescript in dev dependencies now? Maybe this is a git branch conflict?

comment,
status,
}: ReviewRowInput): Array<string | number> => [
proposalId ?? '-',

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The convention in the rest of the export xlsx is to use instead of - for this purpose. It would be good to be consistent.


const rows = rankedRows
.sort((a, b) => {
if (a.rank === null || b.rank === null) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If instead of using === you used == to check vs null then your code would also work for undefined

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because currently your code puts null at the bottom, but undefined at the top which probably isn't desired

return a.grade === null ? 1 : -1;
}
} else if (a.grade !== b.grade) {
return b.grade - a.grade;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be worth adding a comment that we are sorting from rank smallest to biggest, and grade biggest to smallest. Just to avoid confustion


break;
}
case Event.PROPOSAL_DATA_ACCESS_INVITE_ACCEPTED: {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you deleting this event?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that something went wrong while updating my branch with develop. I will revert back the changes that are not related to my changes.

break;
default: {
let changedObjectId: number;
if (typeof (event as any)[event.key]?.primaryKey === 'number') {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you changing this?

const userRole = req.user.currentRole;

callFactoryService(
DownloadType.XLSX,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just want to add that:

  DownloadType.XLSX,
  XLSXType.MANAGEMENT_DECISION,

seems to work perfectly fine.
The factory doesn't seem to need us to add a bespoke one for each download type.

@zacharyjhankin

zacharyjhankin commented Oct 20, 2026 •

Copy link
Copy Markdown
Collaborator

There is certainly a bug here. The fap_reviews table in the database does not contain the instrument that it is relevant to. So why do we have the instrument in the excel document/UI of "reviewers and assignments"?

image

My DB

fap_reviews:

review_id	user_id	proposal_pk	"comment"	grade	status	created_at	updated_at	fap_id	notification_email_sent	fap_proposal_id	questionary_id	date_assigned	reassigned	date_reassigned	email_sent	"rank"
3	2	1	<p>f</p>	7	1	2026-10-20 10:58:16.035 +0100	2026-10-20 10:58:16.035 +0100	1	false	3	9	2026-10-20 10:58:16.035 +0100	false		false	

fap_proposals

proposal_pk	fap_id	date_assigned	call_id	fap_time_allocation	instrument_id	fap_meeting_instrument_submitted	fap_proposal_id	instrument_has_proposals_id
1	1	2026-10-20 10:54:41.934 +0100	1		1	false	3	1
1	1	2026-10-20 10:54:41.934 +0100	1		2	false	4	2
image image

This is one proposal that as two instruments reviewed by the same FAP panel

@zacharyjhankin
zacharyjhankin self-requested a review October 20, 2026 10:21

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FAP sec to export one reviewers reviews

4 participants