Skip to content

Commit 4d3bbfc

Browse files
Merge branch 'develop' into feat/DEVSU-2213-CD8T-score-editable
2 parents a2c54de + a4d2681 commit 4d3bbfc

File tree

26 files changed

+498
-177
lines changed

26 files changed

+498
-177
lines changed

.eslintrc.js

+37-31
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,45 @@
11
module.exports = {
2-
"extends": [
3-
"airbnb",
4-
"airbnb-typescript",
5-
"airbnb/hooks",
6-
"plugin:@typescript-eslint/recommended"
2+
extends: [
3+
'airbnb',
4+
'airbnb-typescript',
5+
'airbnb/hooks',
6+
'plugin:@typescript-eslint/recommended',
77
],
8-
"env": {
9-
"browser": true,
10-
"es6": true,
11-
"node": true
8+
env: {
9+
browser: true,
10+
es6: true,
11+
node: true,
1212
},
13-
"parser": "@typescript-eslint/parser",
14-
"parserOptions": {
15-
"project": "./tsconfig.json"
13+
parser: '@typescript-eslint/parser',
14+
parserOptions: {
15+
project: './tsconfig.json',
1616
},
17-
"rules": {
18-
"react/function-component-definition": "off",
19-
"import/extensions": "off",
20-
"react/jsx-props-no-spreading": "off",
21-
"react/require-default-props": "off",
22-
"import/prefer-default-export": "warn",
23-
"max-len": "off",
24-
"no-param-reassign": "warn",
25-
"no-underscore-dangle": ["warn", { "allow": ["_env_"] }],
26-
"no-restricted-syntax": [
27-
"error",
28-
"ForInStatement",
29-
"LabeledStatement",
30-
"WithStatement"
17+
rules: {
18+
'react/function-component-definition': 'off',
19+
'import/extensions': 'off',
20+
'react/jsx-props-no-spreading': 'off',
21+
'react/require-default-props': 'off',
22+
'import/prefer-default-export': 'warn',
23+
'max-len': 'off',
24+
'no-param-reassign': 'warn',
25+
'no-underscore-dangle': ['warn', { allow: ['_env_'] }],
26+
'no-restricted-syntax': [
27+
'error',
28+
'ForInStatement',
29+
'LabeledStatement',
30+
'WithStatement',
3131
],
32-
"prefer-destructuring": ["error", { "object": true, "array": true }],
32+
'prefer-destructuring': ['error', { object: true, array: true }],
3333
},
34-
"settings": {
35-
"import/resolver": {
36-
typescript: {}
34+
settings: {
35+
'import/resolver': {
36+
typescript: {},
3737
},
3838
},
39-
}
39+
overrides: [
40+
{
41+
extends: ['plugin:@typescript-eslint/disable-type-checked'],
42+
files: ['./*.js'],
43+
},
44+
],
45+
};
+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
name: Create JIRA ticket on release PR creation
2+
3+
on:
4+
pull_request:
5+
types: [opened]
6+
branches:
7+
- master
8+
9+
jobs:
10+
create_ticket:
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- name: Check out code
15+
uses: actions/checkout@v4
16+
17+
- name: Set up Node.js
18+
uses: actions/setup-node@v3
19+
with:
20+
node-version: 20
21+
22+
- name: Run script
23+
run: node ./create-jira-ticket.js
24+
env:
25+
JIRA_PROJECT_NAME: ${{ vars.JIRA_PROJECT_NAME }}
26+
JIRA_ISSUE_TYPE: ${{ vars.JIRA_ISSUE_TYPE }}
27+
JIRA_BASE_URL: ${{ vars.JIRA_BASE_URL }}
28+
JIRA_PORT: ${{ vars.JIRA_PORT }}
29+
JIRA_API_TOKEN: ${{ secrets.JACLI_JIRA_TOKEN }}
30+
PR_TITLE: ${{ github.event.pull_request.title }}
31+
PR_DESCRIPTION: ${{ github.event.pull_request.body }}

app/components/AuthenticatedRoute/index.jsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
/* eslint-disable react/display-name */
22
import { PropTypes } from 'prop-types';
3-
import React, { useContext, useMemo } from 'react';
3+
import React, { useMemo } from 'react';
44
import {
55
Redirect,
66
Route,
77
} from 'react-router-dom';
88

9-
import SecurityContext from '@/context/SecurityContext';
9+
import useSecurity from '@/hooks/useSecurity';
1010
import useResource from '@/hooks/useResource';
1111
import { isAuthorized } from '@/services/management/auth';
1212

@@ -16,7 +16,7 @@ import { isAuthorized } from '@/services/management/auth';
1616
const AuthenticatedRoute = ({
1717
component: Component, adminRequired, showNav, onToggleNav, ...rest
1818
}) => {
19-
const { authorizationToken } = useContext(SecurityContext);
19+
const { authorizationToken } = useSecurity();
2020
const { adminAccess } = useResource();
2121
const authOk = isAuthorized(authorizationToken);
2222

app/components/IPRWYSIWYGEditor/index.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ const IPRWYSIWYGEditor = ({
186186

187187
const handleOnSave = useCallback(() => {
188188
if (editor) {
189-
onClose(editor.getHTML());
189+
onClose(editor.isEmpty ? '' : editor.getHTML());
190190
}
191191
}, [editor, onClose]);
192192

app/components/NavBar/index.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ import MenuIcon from '@mui/icons-material/Menu';
1212
import PersonIcon from '@mui/icons-material/Person';
1313

1414
import { logout } from '@/services/management/auth';
15-
import SecurityContext from '@/context/SecurityContext';
15+
import useSecurity from '@/hooks/useSecurity';
1616
import SidebarContext from '@/context/SidebarContext';
1717
import FeedbackDialog from './components/FeedbackDialog';
1818

1919
import './index.scss';
2020

2121
const NavBar = (): JSX.Element => {
22-
const { userDetails } = useContext(SecurityContext);
22+
const { userDetails } = useSecurity();
2323
const { sidebarMaximized, setSidebarMaximized } = useContext(SidebarContext);
2424

2525
const [anchorEl, setAnchorEl] = useState<HTMLElement | null>();

app/components/TumourSummaryEdit/index.tsx

+13-12
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,6 @@ const TumourSummaryEdit = ({
162162

163163
if (reportDirty && newReportData) {
164164
apiCalls.push(api.put(`/reports/${report.ident}`, newReportData, {}));
165-
} else {
166-
apiCalls.push({ request: () => null });
167165
}
168166

169167
if (tCellCd8Dirty && newTCellCd8Data) {
@@ -180,17 +178,20 @@ const TumourSummaryEdit = ({
180178
if (mutationBurden?.ident) {
181179
apiCalls.push(api.put(`/reports/${report.ident}/mutation-burden/${mutationBurden.ident}`, newMutationBurdenData, {}));
182180
} else {
183-
// Default role of new mutation burden data for reports with no existing analysis per ClinInfo team
184-
apiCalls.push(api.post(`/reports/${report.ident}/mutation-burden`, { ...newMutationBurdenData, role: 'primary' }, {}));
181+
apiCalls.push(api.post(
182+
`/reports/${report.ident}/mutation-burden`,
183+
{ ...newMutationBurdenData, role: 'primary' },
184+
{},
185+
));
185186
}
186-
} else {
187-
apiCalls.push({ request: () => null });
188187
}
189188

190-
if (tmburMutDirty && newTmburMutData && tmburMutBur?.ident) {
191-
apiCalls.push(api.put(`/reports/${report.ident}/tmbur-mutation-burden`, newTmburMutData, {}));
192-
} else {
193-
apiCalls.push({ request: () => null });
189+
if (tmburMutDirty && newTmburMutData) {
190+
if (tmburMutBur?.ident) {
191+
apiCalls.push(api.put(`/reports/${report.ident}/tmbur-mutation-burden`, newTmburMutData, {}));
192+
} else {
193+
apiCalls.push(api.post(`/reports/${report.ident}/tmbur-mutation-burden`, newTmburMutData, {}));
194+
}
194195
}
195196

196197
callSet = new ApiCallSet(apiCalls);
@@ -462,8 +463,8 @@ const TumourSummaryEdit = ({
462463
fullWidth
463464
type="number"
464465
/>
465-
</>
466-
), [newTmburMutData, handleTmburChange]);
466+
</>;
467+
), [newTmburMutData?.genomeSnvTmb, newTmburMutData?.genomeIndelTmb, handleTmburChange]);
467468

468469
return (
469470
<Dialog open={isOpen}>

app/context/ReportContext/types.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ type ReportType = {
5555
kbDiseaseMatch: string;
5656
m1m2Score: number;
5757
captiv8Score: number;
58+
appendix?: string;
5859
} & RecordDefaults;
5960

6061
type ReportContextType = {

app/context/ResourceContext/index.tsx

+38-20
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import React, {
2-
createContext, ReactChild, useContext, useState, useEffect, useMemo,
2+
createContext, ReactChild, useState, useEffect, useMemo, useContext,
33
} from 'react';
4-
import SecurityContext from '@/context/SecurityContext';
5-
64
import { checkAccess, ALL_ROLES } from '@/utils/checkAccess';
5+
import useSecurity from '@/hooks/useSecurity';
76
import ResourceContextType from './types';
7+
import ReportContext from '../ReportContext';
88

99
const GERMLINE_ACCESS = ['admin', 'analyst', 'bioinformatician', 'projects', 'manager'];
1010
const GERMLINE_BLOCK = ALL_ROLES;
@@ -13,42 +13,57 @@ const REPORTS_BLOCK = [];
1313
const ADMIN_ACCESS = ['admin'];
1414
const ADMIN_BLOCK = ALL_ROLES;
1515

16-
type UseResourcesReturnType = {
17-
germlineAccess: boolean;
18-
reportsAccess: boolean;
19-
adminAccess: boolean;
20-
reportSettingAccess: boolean;
21-
};
22-
23-
const useResources = (): UseResourcesReturnType => {
24-
const { userDetails } = useContext(SecurityContext);
16+
const useResources = (): ResourceContextType => {
17+
const { userDetails: { groups, ident: userIdent } } = useSecurity();
18+
const { report } = useContext(ReportContext);
2519

2620
const [germlineAccess, setGermlineAccess] = useState(false);
2721
const [reportsAccess, setReportsAccess] = useState(false);
22+
const [reportEditAccess, setReportEditAccess] = useState(false);
2823
const [adminAccess, setAdminAccess] = useState(false);
2924
const [reportSettingAccess, setReportSettingAccess] = useState(false);
3025

26+
// Check user group first to see which resources they can access
3127
useEffect(() => {
32-
if (userDetails?.groups) {
33-
if (checkAccess(userDetails.groups, GERMLINE_ACCESS, GERMLINE_BLOCK)) {
28+
if (groups) {
29+
if (checkAccess(groups, GERMLINE_ACCESS, GERMLINE_BLOCK)) {
3430
setGermlineAccess(true);
3531
}
3632

37-
if (checkAccess(userDetails.groups, REPORTS_ACCESS, REPORTS_BLOCK)) {
33+
if (checkAccess(groups, REPORTS_ACCESS, REPORTS_BLOCK)) {
3834
setReportsAccess(true);
3935
}
4036

41-
if (checkAccess(userDetails.groups, ADMIN_ACCESS, ADMIN_BLOCK)) {
37+
if (checkAccess(groups, ADMIN_ACCESS, ADMIN_BLOCK)) {
4238
setAdminAccess(true);
4339
}
44-
if (checkAccess(userDetails.groups, [...ADMIN_ACCESS, 'manager'], ADMIN_BLOCK)) {
40+
41+
if (checkAccess(groups, [...ADMIN_ACCESS, 'manager'], ADMIN_BLOCK)) {
4542
setReportSettingAccess(true);
43+
setReportEditAccess(true);
44+
}
45+
}
46+
}, [groups]);
47+
48+
/**
49+
* Check report specific permissions if user isn't admin
50+
*/
51+
useEffect(() => {
52+
if (!adminAccess) {
53+
if (report && report.users.some(({ ident: i }) => i === userIdent)) {
54+
setReportEditAccess(true);
55+
} else {
56+
setReportEditAccess(false);
4657
}
4758
}
48-
}, [userDetails?.groups]);
59+
}, [report, userIdent, adminAccess]);
4960

5061
return {
51-
germlineAccess, reportsAccess, adminAccess, reportSettingAccess,
62+
germlineAccess,
63+
reportsAccess,
64+
adminAccess,
65+
reportSettingAccess,
66+
reportEditAccess,
5267
};
5368
};
5469

@@ -57,6 +72,7 @@ const ResourceContext = createContext<ResourceContextType>({
5772
reportsAccess: false,
5873
adminAccess: false,
5974
reportSettingAccess: false,
75+
reportEditAccess: false,
6076
});
6177

6278
type ResourceContextProviderProps = {
@@ -65,19 +81,21 @@ type ResourceContextProviderProps = {
6581

6682
const ResourceContextProvider = ({ children }: ResourceContextProviderProps): JSX.Element => {
6783
const {
68-
germlineAccess, reportsAccess, adminAccess, reportSettingAccess,
84+
germlineAccess, reportsAccess, adminAccess, reportSettingAccess, reportEditAccess,
6985
} = useResources();
7086

7187
const providerValue = useMemo(() => ({
7288
germlineAccess,
7389
reportsAccess,
7490
adminAccess,
7591
reportSettingAccess,
92+
reportEditAccess,
7693
}), [
7794
germlineAccess,
7895
reportsAccess,
7996
adminAccess,
8097
reportSettingAccess,
98+
reportEditAccess,
8199
]);
82100

83101
return (

app/context/ResourceContext/types.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ type ResourceContextType = {
33
reportsAccess: boolean;
44
adminAccess: boolean;
55
reportSettingAccess: boolean;
6+
reportEditAccess: boolean;
67
};
78

89
export default ResourceContextType;

app/context/SecurityContext/index.js

-10
This file was deleted.

app/context/SecurityContext/index.tsx

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { UserType } from '@/common';
2+
import React from 'react';
3+
4+
type SecurityContextType = {
5+
authorizationToken: string;
6+
setAuthorizationToken: (token: string) => void;
7+
userDetails: Partial<UserType>;
8+
setUserDetails: (userDetails: UserType) => void;
9+
};
10+
11+
const SecurityContext = React.createContext<SecurityContextType>({
12+
authorizationToken: '',
13+
setAuthorizationToken: () => {},
14+
userDetails: {},
15+
setUserDetails: () => {},
16+
});
17+
18+
export default SecurityContext;
19+
20+
export {
21+
SecurityContextType,
22+
SecurityContext,
23+
};

app/context/UserContext/index.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React, {
22
createContext, ReactChild, useMemo, useContext,
33
} from 'react';
4-
import SecurityContext from '@/context/SecurityContext';
4+
import useSecurity from '@/hooks/useSecurity';
55
import { checkAccess } from '@/utils/checkAccess';
66
import UserContextInterface from './interfaces';
77

@@ -18,7 +18,7 @@ type UserContextProviderProps = {
1818
};
1919

2020
const UserContextProvider = ({ children }: UserContextProviderProps): JSX.Element => {
21-
const { userDetails } = useContext(SecurityContext);
21+
const { userDetails } = useSecurity();
2222

2323
const canEdit = useMemo(() => {
2424
if (userDetails && checkAccess(userDetails.groups, EDIT_ACCESS, EDIT_BLOCK)) {

0 commit comments

Comments
 (0)