Skip to content

Commit 2f234b7

Browse files
authored
Release/v6.8.0
IPR Client v6.8.0 Release Notes Bugfixes [DEVSU-1701] - Notification of erasing signature pops up in unsigned reports [DEVSU-1717] - Update storybook to use webpack 5 New Features [DEVSU-1650] - export single germline report [DEVSU-1675] - use backend storage of appendix text instead of storing it in client Improvements [DEVSU-1699] - Update babelrc with updated settings [DEVSU-1714] - Update client columns in germline_small_mutations [DEVSU-1702] - Update to work with new expDensity images
2 parents 8fadc8a + 8656c83 commit 2f234b7

File tree

24 files changed

+30328
-57411
lines changed

24 files changed

+30328
-57411
lines changed

.babelrc

Lines changed: 12 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,14 @@
11
{
2-
"presets": [["@babel/preset-env", {
3-
"useBuiltIns": "usage",
4-
"modules": "auto",
5-
"corejs": 3
6-
}],
7-
"@babel/preset-react",
8-
"@babel/preset-typescript"],
9-
"plugins": [
10-
"@babel/plugin-proposal-optional-chaining",
11-
"@babel/plugin-syntax-dynamic-import"
12-
],
13-
"env": {
14-
"test": {
15-
"plugins": ["@babel/plugin-transform-modules-commonjs"]
16-
},
17-
"production": {
18-
"plugins": [
19-
["transform-imports", {
20-
"@material-ui/core": {
21-
"transform": "@material-ui/core/esm/${member}",
22-
"preventFullImport": true
23-
},
24-
"@material-ui/icons": {
25-
"transform": "@material-ui/icons/esm/${member}",
26-
"preventFullImport": true
27-
}
28-
}]
29-
]
30-
},
31-
"staging": {
32-
"plugins": [
33-
["transform-imports", {
34-
"@material-ui/core": {
35-
"transform": "@material-ui/core/esm/${member}",
36-
"preventFullImport": true
37-
},
38-
"@material-ui/icons": {
39-
"transform": "@material-ui/icons/esm/${member}",
40-
"preventFullImport": true
41-
}
42-
}]
43-
]
44-
},
45-
"development": {
46-
"plugins": [
47-
["transform-imports", {
48-
"@material-ui/core": {
49-
"transform": "@material-ui/core/esm/${member}",
50-
"preventFullImport": true
51-
},
52-
"@material-ui/icons": {
53-
"transform": "@material-ui/icons/esm/${member}",
54-
"preventFullImport": true
55-
}
56-
}]
57-
]
58-
},
59-
"local": {
60-
"plugins": [
61-
["transform-imports", {
62-
"@material-ui/core": {
63-
"transform": "@material-ui/core/esm/${member}",
64-
"preventFullImport": true
65-
},
66-
"@material-ui/icons": {
67-
"transform": "@material-ui/icons/esm/${member}",
68-
"preventFullImport": true
69-
}
70-
}]
71-
]
72-
}
73-
}
2+
"presets": [
3+
[
4+
"@babel/preset-env",
5+
{
6+
"useBuiltIns": "usage",
7+
"modules": "auto",
8+
"corejs": 3
9+
}
10+
],
11+
"@babel/preset-react",
12+
"@babel/preset-typescript"
13+
]
7414
}

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ builds/*
66
dist/*
77
coverage/*
88
app/ipr-env-config.js
9+
storybook-static/*

.storybook/main.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
const custom = require('../config/webpack/webpack.config');
22

33
module.exports = {
4+
core: {
5+
builder: "webpack5",
6+
},
47
stories: [
58
"../app/**/*.stories.@(js|jsx|ts|tsx)",
69
],

.storybook/preview-head.html

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<script>
2+
var _env_ = {
3+
KEYCLOAK_CLIENT_ID: "IPR",
4+
KEYCLOAK_REALM: "GSC",
5+
KEYCLOAK_URL: "https://keycloakdev.bcgsc.ca/auth",
6+
GRAPHKB_URL: "https://graphkbstaging.bcgsc.ca",
7+
API_BASE_URL: "https://iprdev-api.bcgsc.ca/api",
8+
CONTACT_EMAIL: "ipr@bcgsc.ca",
9+
CONTACT_TICKET_URL: "https://www.bcgsc.ca/jira/projects/IPR",
10+
IS_DEMO: false,
11+
PUBLIC_PATH: "/",
12+
}
13+
</script>

app/common.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ declare global {
2222
CONTACT_EMAIL: string;
2323
CONTACT_TICKET_URL: string;
2424
IS_DEMO: boolean;
25+
PUBLIC_PATH: string;
2526
};
2627
}
2728
}

app/views/GermlineView/components/Report/columnDefs.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,16 @@ const columnDefs = [
5656
hide: false,
5757
},
5858
{
59-
headerName: 'dbSNP',
60-
field: 'dbSnp',
59+
field: 'dbSnpIds',
60+
hide: false,
61+
},
62+
{
63+
field: 'clinvarIds',
64+
minWidth: 80,
65+
hide: false,
66+
},
67+
{
68+
field: 'cosmicIds',
6169
hide: false,
6270
},
6371
{

app/views/GermlineView/components/Report/index.tsx

Lines changed: 54 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
1-
import React, { useEffect, useState, useCallback } from 'react';
1+
import React, { useEffect, useState, useCallback, useRef } from 'react';
22
import { useParams, useHistory } from 'react-router-dom';
33
import {
4-
Button,
54
Checkbox,
65
FormControlLabel,
76
Typography,
7+
IconButton,
8+
Menu,
9+
MenuItem,
10+
DialogProps,
811
} from '@mui/material';
912
import { AgGridReact } from '@ag-grid-community/react';
10-
13+
import MoreHorizIcon from '@mui/icons-material/MoreHoriz';
1114
import useGrid from '@/hooks/useGrid';
1215
import api from '@/services/api';
1316
import GermlineReportContext from '@/context/GermlineReportContext';
@@ -20,7 +23,7 @@ import StrikethroughCell from './components/StrikethroughCell';
2023
import EditDialog from './components/EditDialog';
2124
import Reviews from './components/Reviews';
2225
import columnDefs from './columnDefs';
23-
26+
import { getDate } from '@/utils/date';
2427
import './index.scss';
2528

2629
type GermlineReportProps = WithLoadingInjectedProps;
@@ -29,8 +32,8 @@ const GermlineReport = ({
2932
isLoading,
3033
setIsLoading,
3134
}: GermlineReportProps): JSX.Element => {
32-
const { ident } = useParams();
33-
const { colApi, onGridReady } = useGrid();
35+
const { ident } = useParams<{ ident: string }>();
36+
const { gridApi, colApi, onGridReady } = useGrid();
3437
const history = useHistory();
3538
const [report, setReport] = useState<GermlineReportType>();
3639

@@ -39,6 +42,8 @@ const GermlineReport = ({
3942
const [showAlertDialog, setShowAlertDialog] = useState(false);
4043
const [editData, setEditData] = useState();
4144

45+
const [menuAnchor, setMenuAnchor] = useState<HTMLElement>();
46+
4247
useEffect(() => {
4348
if (ident) {
4449
const getData = async () => {
@@ -98,8 +103,9 @@ const GermlineReport = ({
98103
/>
99104
), [onEdit]);
100105

101-
const handleConfirmDelete = useCallback(async (confirm) => {
106+
const handleDeleteAlertClose = useCallback(async (confirm) => {
102107
setShowAlertDialog(false);
108+
setMenuAnchor(null);
103109
if (confirm) {
104110
try {
105111
await api.del(`/germline-small-mutation-reports/${report.ident}`, {}).request();
@@ -111,6 +117,20 @@ const GermlineReport = ({
111117
}
112118
}, [report, history]);
113119

120+
const handleTSVExport = useCallback(() => {
121+
setMenuAnchor(null);
122+
const date = getDate();
123+
gridApi.exportDataAsCsv({
124+
suppressQuotes: true,
125+
columnSeparator: '\t',
126+
columnKeys: colApi.getAllDisplayedColumns()
127+
.filter((col) => col.colDef.headerName !== 'Actions' && col.colDef.headerName)
128+
.map((col) => col.colId),
129+
fileName: `ipr_${report.patientId}_${report.ident}_germline_${date}.tsv`,
130+
processCellCallback: (({ value }) => (typeof value === 'string' ? value?.replace(/,/g, '') : value)),
131+
});
132+
}, [colApi, gridApi, report]);
133+
114134
return (
115135
<GermlineReportContext.Provider value={{ report, setReport }}>
116136
<div className="germline-report">
@@ -122,17 +142,33 @@ const GermlineReport = ({
122142
<Typography display="inline" variant="h5">
123143
{`${report.patientId} - ${report.normalLibrary}`}
124144
</Typography>
125-
<Button
126-
color="secondary"
127-
onClick={() => setShowAlertDialog(true)}
128-
variant="outlined"
129-
>
130-
Remove report
131-
</Button>
145+
<>
146+
<span className="data-table__action">
147+
<IconButton
148+
onClick={(event) => setMenuAnchor(event.currentTarget)}
149+
className="data-table__icon-button"
150+
size="large"
151+
>
152+
<MoreHorizIcon />
153+
</IconButton>
154+
<Menu
155+
anchorEl={menuAnchor}
156+
open={Boolean(menuAnchor)}
157+
onClose={() => setMenuAnchor(null)}
158+
>
159+
<MenuItem onClick={() => setShowAlertDialog(true)}>
160+
Remove report
161+
</MenuItem>
162+
<MenuItem onClick={() => handleTSVExport()}>
163+
Export to TSV
164+
</MenuItem>
165+
</Menu>
166+
</span>
167+
</>
132168
</div>
133169
<AlertDialog
134170
isOpen={showAlertDialog}
135-
onClose={handleConfirmDelete}
171+
onClose={handleDeleteAlertClose}
136172
title="Confirm"
137173
text="Are you sure you want to delete this report?"
138174
confirmText="Confirm"
@@ -169,6 +205,9 @@ const GermlineReport = ({
169205
}}
170206
gridOptions={{
171207
rowClass: 'center-text',
208+
defaultColDef: {
209+
resizable: true,
210+
},
172211
}}
173212
frameworkComponents={{
174213
'strikethroughCell': StrikethroughCell,

app/views/ReportView/components/AnalystComments/components/TextEditor/index.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ const modules = {
4040

4141
['link'],
4242
],
43+
clipboard: {
44+
// https://github.com/zenoamaro/react-quill/issues/281
45+
// https://stackoverflow.com/questions/63678128/how-to-prevent-react-quill-to-insert-a-new-line-before-list-when-re-loading-cont
46+
matchVisual: false,
47+
}
4348
};
4449

4550
const TextEditor = ({
@@ -54,7 +59,7 @@ const TextEditor = ({
5459
}, [analystComments]);
5560

5661
return (
57-
<Dialog maxWidth="lg" open={isOpen} onClose={onClose}>
62+
<Dialog fullWidth maxWidth="lg" open={isOpen} onClose={onClose}>
5863
<DialogTitle>Edit Comments</DialogTitle>
5964
<DialogContent>
6065
<ReactQuill

app/views/ReportView/components/AnalystComments/index.tsx

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,13 @@ import './index.scss';
2222

2323
type AnalystCommentsProps = {
2424
isPrint?: boolean;
25+
isSigned?: boolean;
2526
} & WithLoadingInjectedProps;
2627

2728
const AnalystComments = ({
2829
isPrint = false,
2930
isLoading,
31+
isSigned,
3032
setIsLoading,
3133
}: AnalystCommentsProps): JSX.Element => {
3234
const { report } = useContext(ReportContext);
@@ -98,15 +100,19 @@ const AnalystComments = ({
98100
const commentsResp = await api.put(
99101
`/reports/${report.ident}/summary/analyst-comments`,
100102
{ comments: editedComments },
101-
).request(true);
102-
setComments(sanitizeHtml(commentsResp?.comments, {
103-
allowedSchemes: [],
104-
allowedAttributes: {
105-
'*': ['style'],
106-
},
107-
}));
103+
).request(isSigned);
104+
105+
// If signed, the dialog that opens up will refesh the page instead
106+
if (!isSigned) {
107+
setComments(sanitizeHtml(commentsResp?.comments, {
108+
allowedSchemes: [],
109+
allowedAttributes: {
110+
'*': ['style'],
111+
},
112+
}));
113+
}
108114
}
109-
}, [report]);
115+
}, [report, isSigned]);
110116

111117
return (
112118
<div className="analyst-comments">
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import React from 'react';
2+
import { Story } from '@storybook/react/types-6-0';
3+
import AppendixEditor, { AppendixEditorProps } from '.';
4+
5+
export default {
6+
title: 'components/AppendixEditor',
7+
component: AppendixEditor,
8+
};
9+
10+
const Template = (args) => <AppendixEditor {...args} />;
11+
12+
export const Empty: Story<AppendixEditorProps> = Template.bind({});
13+
Empty.args = {
14+
isOpen: true,
15+
text: null,
16+
};
17+
18+
export const WithDefaultText: Story<AppendixEditorProps> = Template.bind({});
19+
WithDefaultText.args = {
20+
isOpen: true,
21+
text: 'Default loaded text',
22+
};
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
.AppendixEditor {
2+
&__container {
3+
.ql-container {
4+
font-size: 1rem;
5+
font-family: inherit;
6+
}
7+
.ql-editor {
8+
min-height: 10rem;
9+
}
10+
}
11+
}

0 commit comments

Comments
 (0)