Skip to content

Commit

Permalink
📛 #2683 User Role Authorization (#2692)
Browse files Browse the repository at this point in the history
* Unused Imports

* First testing + setup

* Updated Clinical Error Types

* RDPC + Program auth codes

* Add Feature Flag

* Show/Hide Links behind Flag

* Add Service Codes

* Remove Original Code

* Remove Unused Variables

* Remove Regions

* Refactor Submission State

* Use isProgramAdmin
  • Loading branch information
demariadaniel authored Jul 28, 2023
1 parent 71a54c6 commit 7b6c231
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 111 deletions.
214 changes: 109 additions & 105 deletions components/pages/submission-system/SideMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import { css, DnaLoader, Icon, Input, MenuItem, styled, SubMenu } from '@icgc-ar
import { getConfig } from 'global/config';
import useAuthContext from 'global/hooks/useAuthContext';
import usePersistentState from 'global/hooks/usePersistentContext';
import { canWriteProgram, isCollaborator, isDccMember, isRdpcMember } from 'global/utils/egoJwt';
import { isCollaborator, isDccMember, isProgramAdmin, isRdpcMember } from 'global/utils/egoJwt';
import SIDE_MENU_CLINICAL_SUBMISSION_STATE_QUERY from './gql/SIDE_MENU_CLINICAL_SUBMISSION_STATE_QUERY';
import SIDE_MENU_PROGRAM_LIST_QUERY from './gql/SIDE_MENU_PROGRAM_LIST_QUERY';
import SIDE_MENU_SAMPLE_REGISTRATION_STATE_QUERY from './gql/SIDE_MENU_SAMPLE_REGISTRATION_STATE_QUERY';
Expand All @@ -50,7 +50,7 @@ import {
} from './program-submitted-data/common';
import SUBMITTED_DATA_SIDE_MENU_QUERY from './program-submitted-data/gql/SUBMITTED_DATA_SIDE_MENU_QUERY';
import { useSubmissionSystemDisabled } from './SubmissionSystemLockedNotification';
import { useState, useMemo, ReactNode } from 'react';
import { useState, useMemo } from 'react';

type SideMenuProgram = {
shortName: string;
Expand Down Expand Up @@ -113,7 +113,12 @@ type SampleRegistrationQueryResponse = {
const LinksToProgram = (props: { program: SideMenuProgram; isCurrentlyViewed: boolean }) => {
const pageContext = usePageContext();
const { egoJwt, permissions } = useAuthContext();
const { FEATURE_SUBMITTED_DATA_ENABLED, FEATURE_SUBMIT_CLINICAL_ENABLED } = getConfig();
const {
FEATURE_SUBMITTED_DATA_ENABLED,
FEATURE_SUBMIT_CLINICAL_ENABLED,
FEATURE_FEDERATED_RDPC,
} = getConfig();

const { data } = useQuery<ClinicalSubmissionQueryResponse>(
SIDE_MENU_CLINICAL_SUBMISSION_STATE_QUERY,
{
Expand Down Expand Up @@ -164,143 +169,144 @@ const LinksToProgram = (props: { program: SideMenuProgram; isCurrentlyViewed: bo
})
);
}, [egoJwt]);
const canWriteToProgram = useMemo(() => {

const canManageProgram = useMemo(() => {
return (
egoJwt &&
canWriteProgram({
isProgramAdmin({
permissions,
programId: props.program.shortName,
})
);
}, [egoJwt]);

const SubmissionState = {
OPEN: clinicalSubmissionHasSchemaErrors ? (
<Icon name="exclamation" fill="error" width="15px" />
) : (
<Icon name="ellipses" fill="warning" width="15px" />
),
VALID: <Icon name="ellipses" fill="warning" width="15px" />,
INVALID: <Icon name="exclamation" fill="error" width="15px" />,
INVALID_BY_MIGRATION: <Icon name="exclamation" fill="error" width="15px" />,
PENDING_APPROVAL: <Icon name="lock" fill="accent3_dark" width="15px" />,
// submission state remains as null and rejects creating open state with initial invalid upload
// if errors exist, error icon should still show up despite the null state
[null as any]: clinicalSubmissionHasSchemaErrors ? (
<Icon name="exclamation" fill="error" width="15px" />
) : null,
}[data ? data.clinicalSubmissions.state : null];

return (
<div>
<NextLink
as={PROGRAM_DASHBOARD_PATH.replace(PROGRAM_SHORT_NAME_PATH, props.program.shortName)}
href={PROGRAM_DASHBOARD_PATH}
>
<MenuItem
level={3}
content="Dashboard"
selected={PROGRAM_DASHBOARD_PATH === pageContext.pathname && props.isCurrentlyViewed}
/>
</NextLink>
{canSeeCollaboratorView && (
{!FEATURE_FEDERATED_RDPC && (
<>
<NextLink
as={PROGRAM_SAMPLE_REGISTRATION_PATH.replace(
PROGRAM_SHORT_NAME_PATH,
props.program.shortName,
)}
href={PROGRAM_SAMPLE_REGISTRATION_PATH}
as={PROGRAM_DASHBOARD_PATH.replace(PROGRAM_SHORT_NAME_PATH, props.program.shortName)}
href={PROGRAM_DASHBOARD_PATH}
>
<MenuItem
level={3}
content={
<StatusMenuItem>
Register Samples
{isSubmissionSystemDisabled ? (
<Icon name="lock" fill="accent3_dark" width="15px" />
) : clinicalRegistrationHasError ? (
<Icon name="exclamation" fill="error" width="15px" />
) : clinicalRegistrationInProgress ? (
<Icon name="ellipses" fill="warning" width="15px" />
) : null}
</StatusMenuItem>
}
selected={
PROGRAM_SAMPLE_REGISTRATION_PATH === pageContext.pathname && props.isCurrentlyViewed
}
content="Dashboard"
selected={PROGRAM_DASHBOARD_PATH === pageContext.pathname && props.isCurrentlyViewed}
/>
</NextLink>
{FEATURE_SUBMIT_CLINICAL_ENABLED ? (
{canSeeCollaboratorView && (
<NextLink
as={PROGRAM_SUBMIT_CLINICAL_PATH.replace(
as={PROGRAM_SAMPLE_REGISTRATION_PATH.replace(
PROGRAM_SHORT_NAME_PATH,
props.program.shortName,
)}
href={PROGRAM_SUBMIT_CLINICAL_PATH}
>
<MenuItem
level={3}
content={<StatusMenuItem>Submit Clinical Data</StatusMenuItem>}
selected={
PROGRAM_SUBMIT_CLINICAL_PATH === pageContext.pathname && props.isCurrentlyViewed
}
/>
</NextLink>
) : (
<NextLink
as={PROGRAM_CLINICAL_SUBMISSION_PATH.replace(
PROGRAM_SHORT_NAME_PATH,
props.program.shortName,
)}
href={PROGRAM_CLINICAL_SUBMISSION_PATH}
href={PROGRAM_SAMPLE_REGISTRATION_PATH}
>
<MenuItem
level={3}
content={
<StatusMenuItem>
Submit Clinical Data
Register Samples
{isSubmissionSystemDisabled ? (
<Icon name="lock" fill="accent3_dark" width="15px" />
) : (
(
{
OPEN: clinicalSubmissionHasSchemaErrors ? (
<Icon name="exclamation" fill="error" width="15px" />
) : (
<Icon name="ellipses" fill="warning" width="15px" />
),
VALID: <Icon name="ellipses" fill="warning" width="15px" />,
INVALID: <Icon name="exclamation" fill="error" width="15px" />,
INVALID_BY_MIGRATION: (
<Icon name="exclamation" fill="error" width="15px" />
),
PENDING_APPROVAL: <Icon name="lock" fill="accent3_dark" width="15px" />,
// submission state remains as null and rejects creating open state with initial invalid upload
// if errors exist, error icon should still show up despite the null state
[null as any]: clinicalSubmissionHasSchemaErrors ? (
<Icon name="exclamation" fill="error" width="15px" />
) : null,
} as { [k in typeof data.clinicalSubmissions.state]: ReactNode }
)[data ? data.clinicalSubmissions.state : null]
)}
) : clinicalRegistrationHasError ? (
<Icon name="exclamation" fill="error" width="15px" />
) : clinicalRegistrationInProgress ? (
<Icon name="ellipses" fill="warning" width="15px" />
) : null}
</StatusMenuItem>
}
selected={
PROGRAM_CLINICAL_SUBMISSION_PATH === pageContext.pathname &&
PROGRAM_SAMPLE_REGISTRATION_PATH === pageContext.pathname &&
props.isCurrentlyViewed
}
/>
</NextLink>
)}
{FEATURE_SUBMITTED_DATA_ENABLED && (
<NextLink
as={`${PROGRAM_CLINICAL_DATA_PATH.replace(
PROGRAM_SHORT_NAME_PATH,
props.program.shortName,
)}?tab=donor`}
href={PROGRAM_CLINICAL_DATA_PATH}
>
<MenuItem
level={3}
content={
<StatusMenuItem>
Submitted Data{' '}
{clinicalDataHasErrors && <Icon name="exclamation" fill="error" width="15px" />}
</StatusMenuItem>
}
selected={
PROGRAM_CLINICAL_DATA_PATH === pageContext.pathname && props.isCurrentlyViewed
}
/>
</NextLink>
)}
</>
)}
{canWriteToProgram && (
{FEATURE_SUBMIT_CLINICAL_ENABLED ? (
<NextLink
as={PROGRAM_SUBMIT_CLINICAL_PATH.replace(
PROGRAM_SHORT_NAME_PATH,
props.program.shortName,
)}
href={PROGRAM_SUBMIT_CLINICAL_PATH}
>
<MenuItem
level={3}
content={<StatusMenuItem>Submit Clinical Data</StatusMenuItem>}
selected={
PROGRAM_SUBMIT_CLINICAL_PATH === pageContext.pathname && props.isCurrentlyViewed
}
/>
</NextLink>
) : (
<NextLink
as={PROGRAM_CLINICAL_SUBMISSION_PATH.replace(
PROGRAM_SHORT_NAME_PATH,
props.program.shortName,
)}
href={PROGRAM_CLINICAL_SUBMISSION_PATH}
>
<MenuItem
level={3}
content={
<StatusMenuItem>
Submit Clinical Data
{isSubmissionSystemDisabled ? (
<Icon name="lock" fill="accent3_dark" width="15px" />
) : (
SubmissionState
)}
</StatusMenuItem>
}
selected={
PROGRAM_CLINICAL_SUBMISSION_PATH === pageContext.pathname && props.isCurrentlyViewed
}
/>
</NextLink>
)}
{!FEATURE_FEDERATED_RDPC && FEATURE_SUBMITTED_DATA_ENABLED && (
<NextLink
as={`${PROGRAM_CLINICAL_DATA_PATH.replace(
PROGRAM_SHORT_NAME_PATH,
props.program.shortName,
)}?tab=donor`}
href={PROGRAM_CLINICAL_DATA_PATH}
>
<MenuItem
level={3}
content={
<StatusMenuItem>
Submitted Data{' '}
{clinicalDataHasErrors && <Icon name="exclamation" fill="error" width="15px" />}
</StatusMenuItem>
}
selected={
PROGRAM_CLINICAL_DATA_PATH === pageContext.pathname && props.isCurrentlyViewed
}
/>
</NextLink>
)}
{canManageProgram && (
<NextLink
as={PROGRAM_MANAGE_PATH.replace(PROGRAM_SHORT_NAME_PATH, props.program.shortName)}
href={PROGRAM_MANAGE_PATH}
Expand Down Expand Up @@ -390,12 +396,10 @@ export default function SideMenu() {
);

const { data: egoTokenData, egoJwt, permissions } = useAuthContext();

const isDcc = useMemo(() => (egoJwt ? isDccMember(permissions) : false), [egoJwt]);
const isRdpc = useMemo(() => (egoJwt ? isRdpcMember(permissions) : false), [egoJwt]);

const canOnlyAccessOneProgram = programs && programs.length === 1 && !isDcc;
const canSeeDcc = isDcc;

return (
<SubMenu>
Expand All @@ -417,7 +421,7 @@ export default function SideMenu() {
)
) : (
<>
{canSeeDcc && (
{isDcc && (
<NextLink href={DCC_DASHBOARD_PATH}>
<MenuItem icon={<Icon name="dashboard" />} content={'DCC Dashboard'} />
</NextLink>
Expand Down
4 changes: 2 additions & 2 deletions generated/gql_types.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1087,7 +1087,7 @@ export type Query = {
/** Retrieve all stored Clinical Entity and Donor Completion data for a program */
clinicalData: ClinicalData;
/** Retrieve all stored Clinical Migration Errors for a program */
clinicalErrors: ClinicalData;
clinicalErrors: Array<ClinicalErrors>;
/** Retrieve current stored Clinical Registration data for a program */
clinicalRegistration: ClinicalRegistrationData;
/** Retrieve DonorIds + Submitter Donor Ids for given Clinical Entity and Program */
Expand Down Expand Up @@ -1132,7 +1132,7 @@ export type QueryClinicalDataArgs = {


export type QueryClinicalErrorsArgs = {
filters: ClinicalInput;
donorIds?: InputMaybe<Array<InputMaybe<Scalars['Int']>>>;
programShortName: Scalars['String'];
};

Expand Down
2 changes: 2 additions & 0 deletions global/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export const getConfig = () => {
publicConfig.FEATURE_PROGRAM_DASHBOARD_RNA_ENABLED === 'true',
FEATURE_REACT_TABLE_V8_ENABLED: publicConfig.FEATURE_REACT_TABLE_V8_ENABLED === 'true',
FEATURE_SUBMIT_CLINICAL_ENABLED: publicConfig.FEATURE_SUBMIT_CLINICAL_ENABLED === 'true',
FEATURE_FEDERATED_RDPC: publicConfig.FEATURE_FEDERATED_RDPC === 'true',
} as {
GATEWAY_API_ROOT: string;
EGO_API_ROOT: string;
Expand All @@ -73,5 +74,6 @@ export const getConfig = () => {
FEATURE_PROGRAM_DASHBOARD_RNA_ENABLED: boolean;
FEATURE_REACT_TABLE_V8_ENABLED: boolean;
FEATURE_SUBMIT_CLINICAL_ENABLED: boolean;
FEATURE_FEDERATED_RDPC: boolean;
};
};
4 changes: 0 additions & 4 deletions global/utils/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,13 @@

import orderBy from 'lodash/orderBy';
import {
LOGIN_PAGE_PATH,
PROGRAMS_LIST_PATH,
USER_PAGE_PATH,
PROGRAM_MANAGE_PATH,
PROGRAM_SHORT_NAME_PATH,
RDPC_PATH,
PROGRAM_DASHBOARD_PATH,
} from 'global/constants/pages';
import {
isDccMember,
isRdpcMember,
canReadSomeProgram,
getReadableProgramShortNames,
getAuthorizedProgramScopes,
Expand Down
1 change: 1 addition & 0 deletions next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ const nextConfig = withPlugins([withImages, withTM], {
FEATURE_PROGRAM_DASHBOARD_RNA_ENABLED: process.env.FEATURE_PROGRAM_DASHBOARD_RNA_ENABLED,
FEATURE_REACT_TABLE_V8_ENABLED: process.env.FEATURE_REACT_TABLE_V8_ENABLED,
FEATURE_SUBMIT_CLINICAL_ENABLED: process.env.FEATURE_SUBMIT_CLINICAL_ENABLED,
FEATURE_FEDERATED_RDPC: process.env.FEATURE_FEDERATED_RDPC,
},
});

Expand Down

0 comments on commit 7b6c231

Please sign in to comment.