From f272d282b1952122f39334286b11642617e3de71 Mon Sep 17 00:00:00 2001 From: Yoganandan Pandiyan Date: Fri, 31 Jan 2025 16:48:16 +0100 Subject: [PATCH] WIP --- ...nameSampleReviewerToExperimentReviewer.sql | 15 +++ .../backend/src/auth/ProposalAuthorization.ts | 2 +- apps/backend/src/auth/SampleAuthorization.ts | 2 +- apps/backend/src/auth/UserAuthorization.ts | 4 +- .../src/config/eli/configureELIEnvironment.ts | 2 +- .../src/config/ess/configureESSEnvironment.ts | 2 +- .../src/datasources/mockups/UserDataSource.ts | 4 +- apps/backend/src/models/Feature.ts | 2 +- apps/backend/src/models/Role.ts | 2 +- apps/backend/src/models/Settings.ts | 2 +- apps/backend/src/models/User.ts | 4 +- apps/backend/src/mutations/ReviewMutations.ts | 2 +- .../src/mutations/SampleMutations.spec.ts | 4 +- apps/backend/src/queries/SampleQueries.ts | 2 +- apps/backend/src/queries/ShipmentQueries.ts | 2 +- .../types/ProposalStatusActionConfig.ts | 6 +- .../statusActionEngine/emailActionHandler.ts | 34 ++--- apps/e2e/cypress/e2e/samples.cy.ts | 82 ++++++++---- apps/e2e/cypress/support/initialDBData.ts | 2 +- apps/frontend/src/components/AppRoutes.tsx | 44 ++++--- .../ExperimentSafetyReviewPage.tsx} | 14 +- .../SampleDetails.tsx | 0 .../SamplesTable.tsx | 8 +- .../src/components/menu/MenuItems.tsx | 29 +++-- .../SamplesAnswerRenderer.tsx | 2 +- .../components/sampleEsi/SampleEsiReview.tsx | 2 +- .../xpress/ProposalScientistComment.tsx | 3 +- .../docs/user-guide/user-officer/page.md | 63 +++++---- .../docs/user-guide/user-officer/roles.md | 20 +-- .../user-officer/settings/features.md | 123 +++++++++--------- 30 files changed, 275 insertions(+), 208 deletions(-) create mode 100644 apps/backend/db_patches/0169_RenameSampleReviewerToExperimentReviewer.sql rename apps/frontend/src/components/{sample/SampleSafetyPage.tsx => experimentSafetyReview/ExperimentSafetyReviewPage.tsx} (93%) rename apps/frontend/src/components/{sample => experimentSafetyReview}/SampleDetails.tsx (100%) rename apps/frontend/src/components/{sample => experimentSafetyReview}/SamplesTable.tsx (90%) diff --git a/apps/backend/db_patches/0169_RenameSampleReviewerToExperimentReviewer.sql b/apps/backend/db_patches/0169_RenameSampleReviewerToExperimentReviewer.sql new file mode 100644 index 0000000000..99cfae1f05 --- /dev/null +++ b/apps/backend/db_patches/0169_RenameSampleReviewerToExperimentReviewer.sql @@ -0,0 +1,15 @@ +DO +$$ +BEGIN + IF register_patch('0169_RenameSampleReviewerToExperimentReviewer.sql', 'Yoganandan Pandiyan', 'Rename the Roles Sample Safety Reviewer to Experiment Safety Reviewer', '2024-01-31') THEN + BEGIN + UPDATE roles SET title = 'Experiment safety reviewer', short_code = 'experiment_safety_reviewer' WHERE short_code = 'sample_safety_reviewer'; + + UPDATE settings SET settings_id = 'EXPERIMENT_SAFETY_REVIEW_EMAIL', description = 'Email address for the experiment safety review team.' WHERE settings_id = 'SAMPLE_SAFETY_EMAIL'; + + UPDATE features SET feature_id = 'EXPERIMENT_SAFETY_REVIEW', description = 'Experiment safety review functionality' WHERE feature_id = 'SAMPLE_SAFETY'; + END; + END IF; +END; +$$ +LANGUAGE plpgsql; \ No newline at end of file diff --git a/apps/backend/src/auth/ProposalAuthorization.ts b/apps/backend/src/auth/ProposalAuthorization.ts index cba0f0898e..402a518a01 100644 --- a/apps/backend/src/auth/ProposalAuthorization.ts +++ b/apps/backend/src/auth/ProposalAuthorization.ts @@ -240,7 +240,7 @@ export class ProposalAuthorization { case Roles.USER_OFFICER: hasAccess = true; break; - case Roles.SAMPLE_SAFETY_REVIEWER: + case Roles.EXPERIMENT_SAFETY_REVIEWER: hasAccess = true; break; default: diff --git a/apps/backend/src/auth/SampleAuthorization.ts b/apps/backend/src/auth/SampleAuthorization.ts index 7c7be4e989..e01d85e53e 100644 --- a/apps/backend/src/auth/SampleAuthorization.ts +++ b/apps/backend/src/auth/SampleAuthorization.ts @@ -85,7 +85,7 @@ export class SampleAuthorization { return ( canEditProposal || (isMemberOfProposal && isPostProposalSubmission) || - this.userAuth.isSampleSafetyReviewer(agent) + this.userAuth.isExperimentSafetyReviewer(agent) ); } } diff --git a/apps/backend/src/auth/UserAuthorization.ts b/apps/backend/src/auth/UserAuthorization.ts index 96dddef6d9..ec21d820c5 100644 --- a/apps/backend/src/auth/UserAuthorization.ts +++ b/apps/backend/src/auth/UserAuthorization.ts @@ -36,8 +36,8 @@ export abstract class UserAuthorization { return agent?.currentRole?.shortCode === Roles.USER_OFFICER; } - isSampleSafetyReviewer(agent: UserWithRole | null) { - return agent?.currentRole?.shortCode === Roles.SAMPLE_SAFETY_REVIEWER; + isExperimentSafetyReviewer(agent: UserWithRole | null) { + return agent?.currentRole?.shortCode === Roles.EXPERIMENT_SAFETY_REVIEWER; } async isInternalUser( diff --git a/apps/backend/src/config/eli/configureELIEnvironment.ts b/apps/backend/src/config/eli/configureELIEnvironment.ts index b90bba9b2e..bde82f33e1 100644 --- a/apps/backend/src/config/eli/configureELIEnvironment.ts +++ b/apps/backend/src/config/eli/configureELIEnvironment.ts @@ -89,7 +89,7 @@ async function enableDefaultELIFeatures() { FeatureId.FAP_REVIEW, FeatureId.USER_MANAGEMENT, FeatureId.VISIT_MANAGEMENT, - FeatureId.SAMPLE_SAFETY, + FeatureId.EXPERIMENT_SAFETY_REVIEW, FeatureId.OAUTH, ], true diff --git a/apps/backend/src/config/ess/configureESSEnvironment.ts b/apps/backend/src/config/ess/configureESSEnvironment.ts index 71378f5fc7..ded982422b 100644 --- a/apps/backend/src/config/ess/configureESSEnvironment.ts +++ b/apps/backend/src/config/ess/configureESSEnvironment.ts @@ -80,7 +80,7 @@ async function enableDefaultEssFeatures() { FeatureId.FAP_REVIEW, FeatureId.USER_MANAGEMENT, FeatureId.VISIT_MANAGEMENT, - FeatureId.SAMPLE_SAFETY, + FeatureId.EXPERIMENT_SAFETY_REVIEW, FeatureId.OAUTH, FeatureId.CONFLICT_OF_INTEREST_WARNING, ], diff --git a/apps/backend/src/datasources/mockups/UserDataSource.ts b/apps/backend/src/datasources/mockups/UserDataSource.ts index 8b8caa978e..343d2a46e9 100644 --- a/apps/backend/src/datasources/mockups/UserDataSource.ts +++ b/apps/backend/src/datasources/mockups/UserDataSource.ts @@ -128,8 +128,8 @@ export const dummySampleReviewer: UserWithRole = { ...dummyUser, currentRole: { id: 9, - title: 'Sample Reviewer', - shortCode: 'sample_safety_reviewer', + title: 'Experiment Safety Reviewer', + shortCode: 'experiment_safety_reviewer', }, }; diff --git a/apps/backend/src/models/Feature.ts b/apps/backend/src/models/Feature.ts index 36db903def..20108f63f3 100644 --- a/apps/backend/src/models/Feature.ts +++ b/apps/backend/src/models/Feature.ts @@ -17,7 +17,7 @@ export enum FeatureId { FAP_REVIEW = 'FAP_REVIEW', USER_MANAGEMENT = 'USER_MANAGEMENT', VISIT_MANAGEMENT = 'VISIT_MANAGEMENT', - SAMPLE_SAFETY = 'SAMPLE_SAFETY', + EXPERIMENT_SAFETY_REVIEW = 'EXPERIMENT_SAFETY_REVIEW', OAUTH = 'OAUTH', STFC_IDLE_TIMER = 'STFC_IDLE_TIMER', USER_SEARCH_FILTER = 'USER_SEARCH_FILTER', diff --git a/apps/backend/src/models/Role.ts b/apps/backend/src/models/Role.ts index a0bf07888d..86f723be70 100644 --- a/apps/backend/src/models/Role.ts +++ b/apps/backend/src/models/Role.ts @@ -13,6 +13,6 @@ export enum Roles { FAP_SECRETARY = 'fap_secretary', FAP_REVIEWER = 'fap_reviewer', INSTRUMENT_SCIENTIST = 'instrument_scientist', - SAMPLE_SAFETY_REVIEWER = 'sample_safety_reviewer', + EXPERIMENT_SAFETY_REVIEWER = 'experiment_safety_reviewer', INTERNAL_REVIEWER = 'internal_reviewer', } diff --git a/apps/backend/src/models/Settings.ts b/apps/backend/src/models/Settings.ts index 19d0d3163a..71562882db 100644 --- a/apps/backend/src/models/Settings.ts +++ b/apps/backend/src/models/Settings.ts @@ -41,5 +41,5 @@ export enum SettingsId { FAP_SECS_EDIT_TECH_REVIEWS = 'FAP_SECS_EDIT_TECH_REVIEWS', DISPLAY_FAQ_LINK = 'DISPLAY_FAQ_LINK', DISPLAY_PRIVACY_STATEMENT_LINK = 'DISPLAY_PRIVACY_STATEMENT_LINK', - SAMPLE_SAFETY_EMAIL = 'SAMPLE_SAFETY_EMAIL', + EXPERIMENT_SAFETY_REVIEW_EMAIL = 'EXPERIMENT_SAFETY_REVIEW_EMAIL', } diff --git a/apps/backend/src/models/User.ts b/apps/backend/src/models/User.ts index f52f603c3a..cf19ce80ab 100644 --- a/apps/backend/src/models/User.ts +++ b/apps/backend/src/models/User.ts @@ -66,7 +66,7 @@ export enum UserRole { FAP_SECRETARY, FAP_REVIEWER, INSTRUMENT_SCIENTIST, - SAMPLE_SAFETY_REVIEWER, + EXPERIMENT_SAFETY_REVIEWER, INTERNAL_REVIEWER, } @@ -77,7 +77,7 @@ export const UserRoleShortCodeMap = { [UserRole.FAP_SECRETARY]: Roles.FAP_SECRETARY, [UserRole.FAP_REVIEWER]: Roles.FAP_REVIEWER, [UserRole.INSTRUMENT_SCIENTIST]: Roles.INSTRUMENT_SCIENTIST, - [UserRole.SAMPLE_SAFETY_REVIEWER]: Roles.SAMPLE_SAFETY_REVIEWER, + [UserRole.EXPERIMENT_SAFETY_REVIEWER]: Roles.EXPERIMENT_SAFETY_REVIEWER, [UserRole.INTERNAL_REVIEWER]: Roles.INTERNAL_REVIEWER, } as const; diff --git a/apps/backend/src/mutations/ReviewMutations.ts b/apps/backend/src/mutations/ReviewMutations.ts index 827edbdb1f..589256b33c 100644 --- a/apps/backend/src/mutations/ReviewMutations.ts +++ b/apps/backend/src/mutations/ReviewMutations.ts @@ -208,7 +208,7 @@ export default class ReviewMutations { } @EventBus(Event.PROPOSAL_SAMPLE_REVIEW_SUBMITTED) - @Authorized([Roles.USER_OFFICER, Roles.SAMPLE_SAFETY_REVIEWER]) + @Authorized([Roles.USER_OFFICER, Roles.EXPERIMENT_SAFETY_REVIEWER]) async submitSampleReview( agent: UserWithRole | null, args: SubmitSampleReviewArg diff --git a/apps/backend/src/mutations/SampleMutations.spec.ts b/apps/backend/src/mutations/SampleMutations.spec.ts index 44d67c4b3d..34959f17c0 100644 --- a/apps/backend/src/mutations/SampleMutations.spec.ts +++ b/apps/backend/src/mutations/SampleMutations.spec.ts @@ -50,7 +50,7 @@ test('User should be able to update title of the sample', () => { ).resolves.toHaveProperty('title', newTitle); }); -test('User should not be able to update the sample safety status and comment', async () => { +test('User should not be able to update the experiment safety status and comment', async () => { const newComment = 'Updated comment'; return expect( @@ -62,7 +62,7 @@ test('User should not be able to update the sample safety status and comment', a ).resolves.not.toHaveProperty('safetyStatus', SampleStatus.HIGH_RISK); }); -test('Sample safety reviewer should be able to update the sample safety status and comment', async () => { +test('Experiment safety reviewer should be able to update the experiment safety status and comment', async () => { const newComment = 'Updated comment'; return expect( diff --git a/apps/backend/src/queries/SampleQueries.ts b/apps/backend/src/queries/SampleQueries.ts index df5c3bbcfd..13aac348c8 100644 --- a/apps/backend/src/queries/SampleQueries.ts +++ b/apps/backend/src/queries/SampleQueries.ts @@ -43,7 +43,7 @@ export default class SampleQueries { return samples; } - @Authorized([Roles.USER_OFFICER, Roles.SAMPLE_SAFETY_REVIEWER]) + @Authorized([Roles.USER_OFFICER, Roles.EXPERIMENT_SAFETY_REVIEWER]) async getSamplesByCallId(user: UserWithRole | null, callId: number) { return await this.dataSource.getSamplesByCallId(callId); } diff --git a/apps/backend/src/queries/ShipmentQueries.ts b/apps/backend/src/queries/ShipmentQueries.ts index 194d29722e..6db5fc9f7a 100644 --- a/apps/backend/src/queries/ShipmentQueries.ts +++ b/apps/backend/src/queries/ShipmentQueries.ts @@ -41,7 +41,7 @@ export default class ShipmentQueries { return shipments; } - @Authorized([Roles.USER_OFFICER, Roles.SAMPLE_SAFETY_REVIEWER]) + @Authorized([Roles.USER_OFFICER, Roles.EXPERIMENT_SAFETY_REVIEWER]) async getShipmentsByCallId(user: UserWithRole | null, callId: number) { return await this.dataSource.getShipmentsByCallId(callId); } diff --git a/apps/backend/src/resolvers/types/ProposalStatusActionConfig.ts b/apps/backend/src/resolvers/types/ProposalStatusActionConfig.ts index 98502d3ac3..e83b463c4d 100644 --- a/apps/backend/src/resolvers/types/ProposalStatusActionConfig.ts +++ b/apps/backend/src/resolvers/types/ProposalStatusActionConfig.ts @@ -8,7 +8,7 @@ export enum EmailStatusActionRecipients { FAP_CHAIR_AND_SECRETARY = 'FAP_CHAIR_AND_SECRETARY', USER_OFFICE = 'USER_OFFICE', TECHNIQUE_SCIENTISTS = 'TECHNIQUE_SCIENTISTS', - SAMPLE_SAFETY = 'SAMPLE_SAFETY', + EXPERIMENT_SAFETY_REVIEWERS = 'EXPERIMENT_SAFETY_REVIEWERS', OTHER = 'OTHER', } @@ -36,8 +36,8 @@ export const EmailStatusActionRecipientsWithDescription = new Map< 'The Technique Scentists email address', ], [ - EmailStatusActionRecipients.SAMPLE_SAFETY, - 'The Sample Safety email address', + EmailStatusActionRecipients.EXPERIMENT_SAFETY_REVIEWERS, + 'The Experiment Safety email address', ], [ EmailStatusActionRecipients.OTHER, diff --git a/apps/backend/src/statusActionEngine/emailActionHandler.ts b/apps/backend/src/statusActionEngine/emailActionHandler.ts index 675690bf16..ad99d8f410 100644 --- a/apps/backend/src/statusActionEngine/emailActionHandler.ts +++ b/apps/backend/src/statusActionEngine/emailActionHandler.ts @@ -309,50 +309,54 @@ export const emailStatusActionRecipient = async ( break; } - case EmailStatusActionRecipients.SAMPLE_SAFETY: { + case EmailStatusActionRecipients.EXPERIMENT_SAFETY_REVIEWERS: { const adminDataSource = container.resolve( Tokens.AdminDataSource ); - const sampleSafetyEmail = ( - await adminDataSource.getSetting(SettingsId.SAMPLE_SAFETY_EMAIL) + const experimentSafetyEmail = ( + await adminDataSource.getSetting( + SettingsId.EXPERIMENT_SAFETY_REVIEW_EMAIL + ) )?.settingsValue; - if (!sampleSafetyEmail) { + if (!experimentSafetyEmail) { logger.logError( - 'Could not send email(s) to the Sample Safety team as the setting (SAMPLE_SAFETY_EMAIL) is not set.', + 'Could not send email(s) to the Experiment Safety team as the setting (EXPERIMENT_SAFETY_REVIEW_EMAIL) is not set.', { proposalEmailsSkipped: proposals } ); break; } - let sampleSafetyRecipients: EmailReadyType[]; + let experimentSafetyRecipients: EmailReadyType[]; if (recipientWithTemplate.combineEmails) { - sampleSafetyRecipients = [ + experimentSafetyRecipients = [ { id: recipientWithTemplate.recipient.name, - email: sampleSafetyEmail, + email: experimentSafetyEmail, proposals: proposals, template: recipientWithTemplate.emailTemplate.id, }, ]; } else { - sampleSafetyRecipients = await getOtherAndFormatOutputForEmailSending( - proposals, - recipientWithTemplate, - sampleSafetyEmail - ); + experimentSafetyRecipients = + await getOtherAndFormatOutputForEmailSending( + proposals, + recipientWithTemplate, + experimentSafetyEmail + ); } await sendMail( - sampleSafetyRecipients, + experimentSafetyRecipients, statusActionLogger({ connectionId: proposalStatusAction.connectionId, actionId: proposalStatusAction.actionId, statusActionsLogId, - emailStatusActionRecipient: EmailStatusActionRecipients.SAMPLE_SAFETY, + emailStatusActionRecipient: + EmailStatusActionRecipients.EXPERIMENT_SAFETY_REVIEWERS, proposalPks, }), successfulMessage, diff --git a/apps/e2e/cypress/e2e/samples.cy.ts b/apps/e2e/cypress/e2e/samples.cy.ts index 28ccc507f3..fde4b38da0 100644 --- a/apps/e2e/cypress/e2e/samples.cy.ts +++ b/apps/e2e/cypress/e2e/samples.cy.ts @@ -563,7 +563,11 @@ context('Samples tests', () => { }); it('Officer should be able to evaluate sample', function () { - if (!featureFlags.getEnabledFeatures().get(FeatureId.SAMPLE_SAFETY)) { + if ( + !featureFlags + .getEnabledFeatures() + .get(FeatureId.EXPERIMENT_SAFETY_REVIEW) + ) { this.skip(); } cy.createSample({ @@ -575,24 +579,31 @@ context('Samples tests', () => { cy.submitProposal({ proposalPk: createdProposalPk }); cy.visit('/'); - cy.contains('Sample safety').click(); + cy.contains('Experiment Safety').click(); - cy.get('[data-cy=samples-table]').contains(createdProposalId); + cy.get('[data-cy=experiment-safety-forms-table]').contains( + createdProposalId + ); cy.get('[placeholder=Search]').click().clear().type(createdProposalId); - cy.get('[data-cy=samples-table]').contains(createdProposalId); + cy.get('[data-cy=experiment-safety-forms-table]').contains( + createdProposalId + ); - cy.get('[data-cy=samples-table]').should('not.contain', '999999'); + cy.get('[data-cy=experiment-safety-forms-table]').should( + 'not.contain', + '999999' + ); cy.get('[placeholder=Search]').click().clear(); - cy.get('[data-cy=samples-table]').contains('999999'); + cy.get('[data-cy=experiment-safety-forms-table]').contains('999999'); cy.contains(createdProposalId) .last() .parent() - .find('[aria-label="Review sample"]') + .find('[aria-label="Experiment Safety Review"]') .click(); cy.get('[data-cy="safety-status"]').click(); @@ -610,7 +621,7 @@ context('Samples tests', () => { cy.contains(createdProposalId) .last() .parent() - .find('[aria-label="Review sample"]') + .find('[aria-label="Experiment Safety Review"]') .last() .click(); @@ -625,8 +636,12 @@ context('Samples tests', () => { cy.contains('HIGH_RISK'); // test if status has changed }); - it('Sample Safety Reviewer should be able to evaluate sample', function () { - if (!featureFlags.getEnabledFeatures().get(FeatureId.SAMPLE_SAFETY)) { + it('Experiment Safety Reviewer should be able to evaluate sample', function () { + if ( + !featureFlags + .getEnabledFeatures() + .get(FeatureId.EXPERIMENT_SAFETY_REVIEW) + ) { this.skip(); } cy.createSample({ @@ -637,36 +652,43 @@ context('Samples tests', () => { }); cy.submitProposal({ proposalPk: createdProposalPk }); - const sampleSafetyReviewer = initialDBData.users.user1; + const experimentSafetyReviewer = initialDBData.users.user1; cy.updateUserRoles({ - id: sampleSafetyReviewer.id, + id: experimentSafetyReviewer.id, - roles: [initialDBData.roles.sampleSafetyReviewer], + roles: [initialDBData.roles.experimentSafetyReviewer], }); - cy.login(sampleSafetyReviewer); + cy.login(experimentSafetyReviewer); cy.visit('/'); - cy.contains('Sample safety').click(); + cy.contains('Experiment Safety').click(); - cy.get('[data-cy=samples-table]').contains(createdProposalId); + cy.get('[data-cy=experiment-safety-forms-table]').contains( + createdProposalId + ); cy.get('[placeholder=Search]').click().clear().type(createdProposalId); - cy.get('[data-cy=samples-table]').contains(createdProposalId); + cy.get('[data-cy=experiment-safety-forms-table]').contains( + createdProposalId + ); - cy.get('[data-cy=samples-table]').should('not.contain', '999999'); + cy.get('[data-cy=experiment-safety-forms-table]').should( + 'not.contain', + '999999' + ); cy.get('[placeholder=Search]').click().clear(); - cy.get('[data-cy=samples-table]').contains('999999'); + cy.get('[data-cy=experiment-safety-forms-table]').contains('999999'); cy.contains(createdProposalId) .last() .parent() - .find('[aria-label="Review sample"]') + .find('[aria-label="Experiment Safety Review"]') .click(); cy.get('[data-cy="safety-status"]').click(); @@ -684,7 +706,7 @@ context('Samples tests', () => { cy.contains(createdProposalId) .last() .parent() - .find('[aria-label="Review sample"]') + .find('[aria-label="Experiment Safety Review"]') .last() .click(); @@ -700,7 +722,11 @@ context('Samples tests', () => { }); it('Download samples is working with dialog window showing up', function () { - if (!featureFlags.getEnabledFeatures().get(FeatureId.SAMPLE_SAFETY)) { + if ( + !featureFlags + .getEnabledFeatures() + .get(FeatureId.EXPERIMENT_SAFETY_REVIEW) + ) { this.skip(); } cy.createSample({ @@ -711,9 +737,9 @@ context('Samples tests', () => { }); cy.visit('/'); - cy.contains('Sample safety').click(); + cy.contains('Experiment Safety').click(); - cy.get('[data-cy=samples-table]') + cy.get('[data-cy=experiment-safety-forms-table]') .contains(sampleTitle) .first() .closest('tr') @@ -727,7 +753,11 @@ context('Samples tests', () => { }); it('Should be able to download sample pdf', function () { - if (!featureFlags.getEnabledFeatures().get(FeatureId.SAMPLE_SAFETY)) { + if ( + !featureFlags + .getEnabledFeatures() + .get(FeatureId.EXPERIMENT_SAFETY_REVIEW) + ) { this.skip(); } cy.createSample({ @@ -738,7 +768,7 @@ context('Samples tests', () => { }); cy.visit('/'); - cy.contains('Sample safety').click(); + cy.contains('Experiment Safety').click(); const token = window.localStorage.getItem('token'); diff --git a/apps/e2e/cypress/support/initialDBData.ts b/apps/e2e/cypress/support/initialDBData.ts index c3223061fe..ff09a1b61b 100644 --- a/apps/e2e/cypress/support/initialDBData.ts +++ b/apps/e2e/cypress/support/initialDBData.ts @@ -231,7 +231,7 @@ export default { fapSecretary: 5, fapReviewer: 6, instrumentScientist: 7, - sampleSafetyReviewer: 8, + experimentSafetyReviewer: 8, internalReviewer: 9, }, users: { diff --git a/apps/frontend/src/components/AppRoutes.tsx b/apps/frontend/src/components/AppRoutes.tsx index e3fb06d3d1..010049d345 100644 --- a/apps/frontend/src/components/AppRoutes.tsx +++ b/apps/frontend/src/components/AppRoutes.tsx @@ -46,7 +46,9 @@ const CreateProposalEsiPage = lazy( const UpdateProposalEsiPage = lazy( () => import('./proposalEsi/UpdateProposalEsiPage') ); -const SampleSafetyPage = lazy(() => import('./sample/SampleSafetyPage')); +const ExperimentSafetyReviewPage = lazy( + () => import('./experimentSafetyReview/ExperimentSafetyReviewPage') +); const ApiAccessTokensPage = lazy( () => import('./settings/apiAccessTokens/ApiAccessTokensPage') ); @@ -126,8 +128,8 @@ const AppRoutes = () => { const { t } = useTranslation(); const isUserOfficer = useCheckAccess([UserRole.USER_OFFICER]); const isUser = useCheckAccess([UserRole.USER]); - const isSampleSafetyReviewer = useCheckAccess([ - UserRole.SAMPLE_SAFETY_REVIEWER, + const isExperimentSafetyReviewer = useCheckAccess([ + UserRole.EXPERIMENT_SAFETY_REVIEWER, ]); const isInstrumentScientist = useCheckAccess([UserRole.INSTRUMENT_SCIENTIST]); @@ -147,8 +149,8 @@ const AppRoutes = () => { const isVisitManagementEnabled = featureContext.featuresMap.get( FeatureId.VISIT_MANAGEMENT )?.isEnabled; - const isSampleSafetyEnabled = featureContext.featuresMap.get( - FeatureId.SAMPLE_SAFETY + const isExperimentSafetyReviewEnabled = featureContext.featuresMap.get( + FeatureId.EXPERIMENT_SAFETY_REVIEW )?.isEnabled; const isXpressRouteEnabled = useXpressAccess([ UserRole.USER_OFFICER, @@ -452,17 +454,20 @@ const AppRoutes = () => { } /> )} - {isSampleSafetyEnabled && (isSampleSafetyReviewer || isUserOfficer) && ( - } - /> - } - /> - )} + {isExperimentSafetyReviewEnabled && + (isExperimentSafetyReviewer || + isUserOfficer || + isInstrumentScientist) && ( + } + /> + } + /> + )} {isUserOfficer && ( { /> } /> + ) : isExperimentSafetyReviewer ? ( + } /> + } + /> ) : ( ) => void; }) { @@ -44,7 +44,7 @@ function SampleEvaluationDialog(props: { onClose={() => onClose(null)} fullWidth={true} maxWidth="lg" - title="Review sample" + title="Experiment Safety Review" > @@ -63,7 +63,7 @@ function SampleEvaluationDialog(props: { safetyComment, safetyStatus, }); - onClose({ ...values, ...updatedSample } || null); + onClose({ ...values, ...updatedSample }); }} > {({ isSubmitting, dirty }) => ( @@ -174,7 +174,7 @@ const columns = [ { title: 'Created', field: 'created' }, ]; -function SampleSafetyPage() { +function ExperimentSafetyReviewPage() { const { api, isExecutingCall } = useDataApiWithFeedback(); const { calls, loadingCalls } = useCallsData({ isActive: true }); const [searchParam] = useSearchParams(); @@ -210,7 +210,7 @@ function SampleSafetyPage() { const downloadPDFSample = useDownloadPDFSample(); const RowActionButtons = (rowData: SampleWithProposalData) => ( <> - + setSelectedSample(rowData)}> @@ -234,7 +234,7 @@ function SampleSafetyPage() { return ( <> {selectedSample && ( - { if (newSample) { @@ -291,4 +291,4 @@ function SampleSafetyPage() { ); } -export default SampleSafetyPage; +export default ExperimentSafetyReviewPage; diff --git a/apps/frontend/src/components/sample/SampleDetails.tsx b/apps/frontend/src/components/experimentSafetyReview/SampleDetails.tsx similarity index 100% rename from apps/frontend/src/components/sample/SampleDetails.tsx rename to apps/frontend/src/components/experimentSafetyReview/SampleDetails.tsx diff --git a/apps/frontend/src/components/sample/SamplesTable.tsx b/apps/frontend/src/components/experimentSafetyReview/SamplesTable.tsx similarity index 90% rename from apps/frontend/src/components/sample/SamplesTable.tsx rename to apps/frontend/src/components/experimentSafetyReview/SamplesTable.tsx index 1d49a4fc57..28181d2b41 100644 --- a/apps/frontend/src/components/sample/SamplesTable.tsx +++ b/apps/frontend/src/components/experimentSafetyReview/SamplesTable.tsx @@ -15,7 +15,7 @@ const defaultColumns: Column[] = [ { title: 'Created', field: 'created' }, ]; -const SamplesTable = ( +const ExperimentSafetyFormsTable = ( props: Omit, 'columns'> & { columns?: Column[]; } @@ -24,13 +24,13 @@ const SamplesTable = ( const search = searchParam.get('search'); return ( -
+
- Samples + Experiment Safety Forms } onSearchChange={(searchText) => { @@ -51,7 +51,7 @@ const SamplesTable = ( }; export default React.memo( - SamplesTable, + ExperimentSafetyFormsTable, (prevProps, nextProps) => prevProps.isLoading === nextProps.isLoading && prevProps.data === nextProps.data diff --git a/apps/frontend/src/components/menu/MenuItems.tsx b/apps/frontend/src/components/menu/MenuItems.tsx index 6575f3596b..6c22a13653 100644 --- a/apps/frontend/src/components/menu/MenuItems.tsx +++ b/apps/frontend/src/components/menu/MenuItems.tsx @@ -39,14 +39,14 @@ type MenuItemsProps = { currentRole: UserRole | null; }; -const SamplesMenuListItem = () => { +const ExperimentSafetyReviewMenuListItem = () => { return ( - - + + - + ); @@ -82,8 +82,8 @@ const MenuItems = ({ currentRole }: MenuItemsProps) => { const isUserManagementEnabled = context.featuresMap.get( FeatureId.USER_MANAGEMENT )?.isEnabled; - const isSampleSafetyEnabled = context.featuresMap.get( - FeatureId.SAMPLE_SAFETY + const isExperimentSafetyReviewEnabled = context.featuresMap.get( + FeatureId.EXPERIMENT_SAFETY_REVIEW )?.isEnabled; const isXpressRouteEnabled = useXpressAccess([ @@ -252,7 +252,9 @@ const MenuItems = ({ currentRole }: MenuItemsProps) => { - {isSampleSafetyEnabled && } + {isExperimentSafetyReviewEnabled && ( + + )}
); @@ -308,12 +310,17 @@ const MenuItems = ({ currentRole }: MenuItemsProps) => { )} + {isExperimentSafetyReviewEnabled && ( + + )}
); - const sampleSafetyReviewer = ( + const ExperimentSafetyReviewPageReviewer = (
- + {isExperimentSafetyReviewEnabled && ( + + )}
); @@ -334,8 +341,8 @@ const MenuItems = ({ currentRole }: MenuItemsProps) => { case UserRole.FAP_SECRETARY: case UserRole.FAP_REVIEWER: return FapRoles; - case UserRole.SAMPLE_SAFETY_REVIEWER: - return sampleSafetyReviewer; + case UserRole.EXPERIMENT_SAFETY_REVIEWER: + return ExperimentSafetyReviewPageReviewer; case UserRole.INTERNAL_REVIEWER: return internalReviewer; default: diff --git a/apps/frontend/src/components/questionary/questionaryComponents/SampleDeclaration/SamplesAnswerRenderer.tsx b/apps/frontend/src/components/questionary/questionaryComponents/SampleDeclaration/SamplesAnswerRenderer.tsx index c65d00e718..3b40034ce2 100644 --- a/apps/frontend/src/components/questionary/questionaryComponents/SampleDeclaration/SamplesAnswerRenderer.tsx +++ b/apps/frontend/src/components/questionary/questionaryComponents/SampleDeclaration/SamplesAnswerRenderer.tsx @@ -6,7 +6,7 @@ import ListItem from '@mui/material/ListItem'; import React, { useState } from 'react'; import StyledDialog from 'components/common/StyledDialog'; -import SampleDetails from 'components/sample/SampleDetails'; +import SampleDetails from 'components/experimentSafetyReview/SampleDetails'; import { Answer } from 'generated/sdk'; import { useSamplesWithQuestionaryStatus } from 'hooks/sample/useSamplesWithQuestionaryStatus'; import { SampleCore } from 'models/questionary/sample/SampleCore'; diff --git a/apps/frontend/src/components/sampleEsi/SampleEsiReview.tsx b/apps/frontend/src/components/sampleEsi/SampleEsiReview.tsx index 73187f9d49..63fb10a081 100644 --- a/apps/frontend/src/components/sampleEsi/SampleEsiReview.tsx +++ b/apps/frontend/src/components/sampleEsi/SampleEsiReview.tsx @@ -30,7 +30,7 @@ function SampleEsiReview() { <> diff --git a/apps/frontend/src/components/xpress/ProposalScientistComment.tsx b/apps/frontend/src/components/xpress/ProposalScientistComment.tsx index 066e3daf74..85d4046596 100755 --- a/apps/frontend/src/components/xpress/ProposalScientistComment.tsx +++ b/apps/frontend/src/components/xpress/ProposalScientistComment.tsx @@ -56,7 +56,8 @@ const ProposalScientistComment = (props: ProposalScientistCommentProps) => {

Tips:

1. Comments are managed by only instrument scientists.

- 2. Comments are not be accessible to users or sample safety. + 2. Comments are not be accessible to users or experiment + safety reviewers.

3. Comments will be available for editing in all proposal diff --git a/documentation/docs/user-guide/user-officer/page.md b/documentation/docs/user-guide/user-officer/page.md index 041c0e5a3c..6a0f36afc3 100644 --- a/documentation/docs/user-guide/user-officer/page.md +++ b/documentation/docs/user-guide/user-officer/page.md @@ -1,62 +1,61 @@ # Pages :material-cog-box: -_________________________________________________________________________________________________________ +--- ## What are pages? -Pages are highly customizable sections of information within User Office. Pages can be utilized to display key dates, advice and links to users and reviewers. +Pages are highly customizable sections of information within User Office. Pages can be utilized to display key dates, advice and links to users and reviewers. -_________________________________________________________________________________________________________ +--- ## How do I edit pages? ### Step 1: Navigate to the Page editor -* To edit a page, select `PAGES` :material-cog-box: from the main menu -* From the Page Editor, choose the page you wish to edit +- To edit a page, select `PAGES` :material-cog-box: from the main menu +- From the Page Editor, choose the page you wish to edit ### Step 2: Edit the page -* To create a new page click on `FILE` > `NEW DOCUMENT`, or edit the preexisting message. -* The editor contains many useful features to aid in creating the page such as `EDITING` and `FORMATTING` tools. -* The `INSERT` button can also be used to insert images and links into the page. +- To create a new page click on `FILE` > `NEW DOCUMENT`, or edit the preexisting message. +- The editor contains many useful features to aid in creating the page such as `EDITING` and `FORMATTING` tools. +- The `INSERT` button can also be used to insert images and links into the page. > **_NOTE:_** It is good practice to carefully check the preview before updating the page to ensure that it is well formatted. You can do this in `VIEW` > `PREVIEW` #### User page !!! note "" - This sets the users' homepage; this is the information that users will see on their dashboard. - This may include the following key information: - +This sets the users' homepage; this is the information that users will see on their dashboard. + This may include the following key information: + * A welcome message to users * Key dates - * Information on the proposal process + * Information on the proposal process * Important links (e.g., to publication guidelines) _____________________________________________________________________________________________________________ -

+
![User](../../assets/images/user_homepage.png)
User homepage (dashboard)
- #### Reviewer page !!! note "" - This sets the reviewers' homepage; this is the information that reviewers will see on their dashboard (This is displayed to the following roles: [Sample Safety Reviewer](roles.md), [Internal Reviewer](roles.md), [FAP chairs](roles.md), [FAP secretaries](roles.md) and [FAP reviewers](roles.md)). +This sets the reviewers' homepage; this is the information that reviewers will see on their dashboard (This is displayed to the following roles: [Experiment Safety Reviewer](roles.md), [Internal Reviewer](roles.md), [FAP chairs](roles.md), [FAP secretaries](roles.md) and [FAP reviewers](roles.md)). - The reviewer page may include the following key information: + The reviewer page may include the following key information: - * A welcome message to reviewers + * A welcome message to reviewers * Key dates - * Information on the review process - * Important links + * Information on the review process + * Important links _____________________________________________________________________________________________________________ -
+
![Reviewer Homepage](../../assets/images/reviewer_page.png)
Reviewer homepage (dashboard)
@@ -64,10 +63,10 @@ ________________________________________________________________________________ #### Help page !!! note "" - This sets the help page; this is the information that is displayed to users on the 'help' page, and at the FAQ button at the bottom of the page for all users. See the 'FAQs for help page section for a list of example questions that may be useful to include in the help page. - +This sets the help page; this is the information that is displayed to users on the 'help' page, and at the FAQ button at the bottom of the page for all users. See the 'FAQs for help page section for a list of example questions that may be useful to include in the help page. + ??? info "FAQs for help page" - Frequently asked questions: + Frequently asked questions: * **Can I view all the questions before I start completing my proposal?** @@ -99,12 +98,12 @@ ________________________________________________________________________________ _____________________________________________________________________________________________________________ -
+
![Help page](../../assets/images/faq_page.png)
User help page (FAQ)
-
+
![Help notice](../../assets/images/faq_notice.png)
Help notice (FAQ)
@@ -112,9 +111,9 @@ ________________________________________________________________________________ #### Privacy Agreement page !!! note "" - This sets the privacy agreement page; this is the information that is displayed when clicking on the `PRIVACY STATEMENT` button at the bottom of all pages. +This sets the privacy agreement page; this is the information that is displayed when clicking on the `PRIVACY STATEMENT` button at the bottom of all pages. -
+
![Privacy page](../../assets/images/privacy_page.png)
Privacy Agreement Page
@@ -122,20 +121,20 @@ ________________________________________________________________________________ #### Footer !!! note "" - This sets the footer. The page must be refreshed in order to view the updated footer. +This sets the footer. The page must be refreshed in order to view the updated footer. #### Login !!! note "" - This sets the login. +This sets the login. #### Grade guide !!! note "" - This sets the grade guide. Note: this is different from the grade guide in the FAP page +This sets the grade guide. Note: this is different from the grade guide in the FAP page ### Step 3: Update your changes -* Once you are satisfied with the changes and ensured that the page is well-formatted with the `PREVIEW` function you can update the page by clicking on the `UPDATE` button. +- Once you are satisfied with the changes and ensured that the page is well-formatted with the `PREVIEW` function you can update the page by clicking on the `UPDATE` button. -_________________________________________________________________________________________________________ +--- diff --git a/documentation/docs/user-guide/user-officer/roles.md b/documentation/docs/user-guide/user-officer/roles.md index 9de382ceac..7067e625af 100644 --- a/documentation/docs/user-guide/user-officer/roles.md +++ b/documentation/docs/user-guide/user-officer/roles.md @@ -1,13 +1,13 @@ # Roles :material-account-supervisor-circle: -_________________________________________________________________________________________________________ +--- -There are many roles within User Office: +There are many roles within User Office: ??? info "User" - + The **Users** are the visiting scientists who are applying for beamtime through proposals. - + **Main uses of User Office:** * Submitting Proposals @@ -21,7 +21,7 @@ There are many roles within User Office: * Creating calls * Managing proposals * Coordinating review and selection - * Impersonating other users + * Impersonating other users ??? info "Instrument Scientist" @@ -34,14 +34,14 @@ There are many roles within User Office: * Ensuring instrument readiness and maintenance * Reviewing and approving experiment proposals -??? info "Sample Safety Reviewer" +??? info "Experiment Safety Reviewer" - The **Sample Safety Reviewer** is responsible for evaluating the safety aspects of the samples proposed for experiments. They ensure that all safety protocols are followed and that the samples do not pose any risk. + The **Experiment Safety Reviewer** is responsible for evaluating the safety aspects of the samples proposed for experiments. They ensure that all safety protocols are followed and that the samples do not pose any risk. **Main uses of User Office:** - * Reviewing sample safety information - * Approving or rejecting sample safety status + * Reviewing Experiment safety information + * Approving or rejecting Experiment safety status * Providing safety-related comments and feedback * Ensuring compliance with safety regulations @@ -86,4 +86,4 @@ There are many roles within User Office: * Providing detailed feedback and evaluations * Submitting review grades and comments -_________________________________________________________________________________________________________ +--- diff --git a/documentation/docs/user-guide/user-officer/settings/features.md b/documentation/docs/user-guide/user-officer/settings/features.md index 51aff2ff54..cd35149247 100644 --- a/documentation/docs/user-guide/user-officer/settings/features.md +++ b/documentation/docs/user-guide/user-officer/settings/features.md @@ -1,92 +1,91 @@ # Features -_________________________________________________________________________________________________________ +--- ## What are features? -* **`EMAIL SEARCH:`** Search by Email functionality  +- **`EMAIL SEARCH:`** Search by Email functionality -* **`STFC IDLE TIMER:`** STFC idle warning popup +- **`STFC IDLE TIMER:`** STFC idle warning popup -* **`USER SEARCH FILTER:`** Flag for users list filter functionality +- **`USER SEARCH FILTER:`** Flag for users list filter functionality -* **`USER MANAGEMENT:`** User management functionality +- **`USER MANAGEMENT:`** User management functionality -* **`FAP REVIEW:`** FAP (facility access panels) functionality +- **`FAP REVIEW:`** FAP (facility access panels) functionality -* **`SHIPPING:`** Shipping feature +- **`SHIPPING:`** Shipping feature -* **`SCHEDULER:`** Scheduler feature +- **`SCHEDULER:`** Scheduler feature -* **`RISK ASSESSMENT:`** Risk assessment functionality +- **`RISK ASSESSMENT:`** Risk assessment functionality -* **`INSTRUMENT MANAGEMENT:`** Instrument management functionality +- **`INSTRUMENT MANAGEMENT:`** Instrument management functionality -* **`TECHNICAL REVIEW:`** Technical review functionality  +- **`TECHNICAL REVIEW:`** Technical review functionality -* **`VISIT MANAGEMENT:`** Visit management functionality +- **`VISIT MANAGEMENT:`** Visit management functionality -* **`SAMPLE SAFETY:`** Sample safety functionality +- **`EXPERIMENT SAFETY:`** Experiment safety functionality -* **`OAUTH:`** Is OAuth enabled +- **`OAUTH:`** Is OAuth enabled -* **`EMAIL INVITE:`** Email invitation functionality     +- **`EMAIL INVITE:`** Email invitation functionality -_________________________________________________________________________________________________________ +--- ## What are the icons for the different features? Icon functions -* Proposals - :material-folder-outline: -* Experiments - :material-calendar: -* Calls - :material-calendar-blank: -* People - :fontawesome-solid-user-group: -* Instruments - :material-microscope: -* Techniques - -* FAPs - :material-google-circles-communities: -* Pages - :material-cog-box: -* Institutions - :material-bank: -* Templates - :material-text-box-multiple: -* PDF - :material-file-pdf-box: -* Proposal templates - :material-note-text: -* Sample declaration - :material-inbox: -* Sub template - :material-collapse-all-outline: -* Shipment declaration - :material-truck: -* Visit registration - :material-airplane-takeoff: -* ESI - -* Proposal ESI - :material-note-text: -* Sample ESI - :material-inbox: -* Feedback - :material-message-alert: -* Questions - :material-comment-question: -* Sample safety - -* Settings - :material-cog: -* Units - :material-sigma: -* Proposal statuses - :material-folder-cog-outline: -* Proposal workflows - :material-sitemap: -* API access tokens - :material-key: -* Features - -* App settings - - -* check :material-check-all: +- Proposals - :material-folder-outline: +- Experiments - :material-calendar: +- Calls - :material-calendar-blank: +- People - :fontawesome-solid-user-group: +- Instruments - :material-microscope: +- Techniques - +- FAPs - :material-google-circles-communities: +- Pages - :material-cog-box: +- Institutions - :material-bank: +- Templates - :material-text-box-multiple: +- PDF - :material-file-pdf-box: +- Proposal templates - :material-note-text: +- Sample declaration - :material-inbox: +- Sub template - :material-collapse-all-outline: +- Shipment declaration - :material-truck: +- Visit registration - :material-airplane-takeoff: +- ESI - +- Proposal ESI - :material-note-text: +- Sample ESI - :material-inbox: +- Feedback - :material-message-alert: +- Questions - :material-comment-question: +- Experiment safety - +- Settings - :material-cog: +- Units - :material-sigma: +- Proposal statuses - :material-folder-cog-outline: +- Proposal workflows - :material-sitemap: +- API access tokens - :material-key: +- Features - +- App settings - + +- check :material-check-all: Profile -* Profile - -* Roles - :material-account-supervisor-circle: - +- Profile - +- Roles - :material-account-supervisor-circle: Tools -* Search - :material-magnify: -* Delete - :material-delete: -* Edit - :material-pencil: -* Clone - :material-file-multiple: -* Import - -* Export - :material-share-variant: -* Select - :fontawesome-regular-square: -* Show columns - :material-view-column: -* Mark as active - -* Rename - :material-rename-box: - -_________________________________________________________________________________________________________ +- Search - :material-magnify: +- Delete - :material-delete: +- Edit - :material-pencil: +- Clone - :material-file-multiple: +- Import - +- Export - :material-share-variant: +- Select - :fontawesome-regular-square: +- Show columns - :material-view-column: +- Mark as active - +- Rename - :material-rename-box: + +---