Skip to content

Commit 963da38

Browse files
committed
Apply review feedback
1 parent 2fb5578 commit 963da38

12 files changed

+125
-201
lines changed

api/routes/web.py

-3
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,6 @@ async def get_project_participants_grid_with_limit(
9696
wlayer.count_participants(pfilter),
9797
)
9898

99-
# then have to get all nested objects
100-
10199
return ProjectParticipantGridResponse.from_params(
102100
participants=participants,
103101
total_results=pcount,
@@ -258,7 +256,6 @@ async def search_by_keyword(keyword: str, connection=get_projectless_db_connecti
258256
This searches the keyword, in families, participants + samples in the projects
259257
that you are a part of (automatically).
260258
"""
261-
# raise ValueError('Test')
262259
pt = ProjectPermissionsTable(connection)
263260
projects = await pt.get_projects_accessible_by_user(
264261
connection.author, readonly=True

models/models/__init__.py

+1-6
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,4 @@
6464
SequencingGroupUpsert,
6565
SequencingGroupUpsertInternal,
6666
)
67-
from models.models.web import (
68-
PagingLinks,
69-
ProjectSummary,
70-
ProjectSummaryInternal,
71-
WebProject,
72-
)
67+
from models.models.web import ProjectSummary, ProjectSummaryInternal, WebProject

models/models/web.py

-8
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,6 @@ class WebProject(SMBase):
1818
meta: dict
1919

2020

21-
class PagingLinks(SMBase):
22-
"""Model for PAGING"""
23-
24-
current: str
25-
next: str | None
26-
token: str | None
27-
28-
2921
@dataclasses.dataclass
3022
class ProjectSummaryInternal:
3123
"""Return class for the project summary endpoint"""

web/src/index.css

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
--color-text-red: #ff0000;
1616

1717
--color-border-color: #c8c9ca;
18-
--color-border-default: #d0d7de;
18+
--color-border-default: #e1e6ec;
1919
--color-border-red: #f04848;
2020

2121
--color-divider: rgba(0, 0, 0, 0.3);

web/src/pages/project/DictEditor.tsx

+15-27
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,22 @@ import * as React from 'react'
44
import { Button } from 'semantic-ui-react'
55
import { ThemeContext } from '../../shared/components/ThemeProvider'
66

7+
type InputValue = null | string | number | boolean | InputValue[] | { [key: string]: InputValue }
8+
type Input = { [key: string]: InputValue } | string
9+
710
interface DictEditorProps {
8-
jsonStr?: string
9-
yamlStr?: string
10-
obj?: any
11+
input: Input
1112
onChange: (json: object) => void
1213
}
1314

14-
const getStringFromValues = (obj?: any, jsonStr?: string, yamlString?: string) => {
15-
if (obj) {
16-
return yaml.dump(obj, { indent: 2 })
15+
const getStringFromValue = (input: Input) => {
16+
// if it's a string, return it
17+
if (typeof input === 'string') {
18+
return input
1719
}
18-
return jsonStr || yamlString || '\n'
20+
21+
// otherwise try to convert it to a string
22+
return yaml.dump(input)
1923
}
2024

2125
const parseString = (str: string) => {
@@ -34,22 +38,15 @@ const parseString = (str: string) => {
3438
}
3539
}
3640

37-
export const DictEditor: React.FunctionComponent<DictEditorProps> = ({
38-
jsonStr,
39-
yamlStr,
40-
obj,
41-
onChange,
42-
}) => {
43-
const [textValue, setInnerTextValue] = React.useState<string>(
44-
getStringFromValues(obj, jsonStr, yamlStr)
45-
)
41+
export const DictEditor: React.FunctionComponent<DictEditorProps> = ({ input, onChange }) => {
42+
const [textValue, setInnerTextValue] = React.useState<string>(getStringFromValue(input))
4643
const theme = React.useContext(ThemeContext)
4744

4845
const [error, setError] = React.useState<string | undefined>(undefined)
4946

5047
React.useEffect(() => {
51-
setInnerTextValue(getStringFromValues(obj, jsonStr, yamlStr))
52-
}, [obj, jsonStr, yamlStr])
48+
setInnerTextValue(getStringFromValue(input))
49+
}, [input])
5350

5451
const handleChange = (value: string) => {
5552
setInnerTextValue(value)
@@ -86,15 +83,6 @@ export const DictEditor: React.FunctionComponent<DictEditorProps> = ({
8683
minimap: { enabled: false },
8784
automaticLayout: true,
8885
}}
89-
90-
// style={{
91-
// width: '100%',
92-
// height: '400px',
93-
// border: !!error ? '3px solid var(--color-border-red)' : '1px solid #ccc',
94-
// padding: '10px',
95-
// fontFamily:
96-
// 'Consolas,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New, monospace',
97-
// }}
9886
/>
9987
{error && (
10088
<p>

web/src/pages/project/ExportProjectButton.tsx

+4-2
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ export const ProjectExportButton: React.FunctionComponent<{
3232
const [exportType, setExportType] = React.useState<ExportType>(ExportType.Csv)
3333
const [isDownloading, setIsDownloading] = React.useState(false)
3434
const [downloadError, setDownloadError] = React.useState<string | undefined>(undefined)
35-
// const keys = Object.keys(headerGroups).reduce((prev, k) => ({...prev, k}), {})
3635

3736
const download = (_exportType: ExportType) => {
3837
if (!_exportType) return
@@ -61,7 +60,10 @@ export const ProjectExportButton: React.FunctionComponent<{
6160
document.body.appendChild(link)
6261
link.click()
6362
})
64-
.catch((er) => setDownloadError(er.message))
63+
.catch((er) => {
64+
setIsDownloading(false)
65+
setDownloadError(er.message)
66+
})
6567
}
6668

6769
// onClick={() => download(ExportType.Csv)

web/src/pages/project/ParticipantGridRow.tsx

+42-70
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,26 @@
11
import * as React from 'react'
22

3-
import _ from 'lodash'
4-
3+
import { TableCell, TableRow } from 'semantic-ui-react'
54
import FamilyLink from '../../shared/components/links/FamilyLink'
65
import SampleLink from '../../shared/components/links/SampleLink'
76
import SequencingGroupLink from '../../shared/components/links/SequencingGroupLink'
87
import sanitiseValue from '../../shared/utilities/sanitiseValue'
9-
import { Assay, NestedParticipant, NestedSample, NestedSequencingGroup } from '../../sm-api/api'
8+
import {
9+
Assay,
10+
FamilySimple,
11+
NestedParticipant,
12+
NestedSample,
13+
NestedSequencingGroup,
14+
ProjectParticipantGridField,
15+
} from '../../sm-api/api'
16+
import { firstColBorder, otherColBorder } from './ProjectGridHeaderGroup'
17+
18+
const getBorderStyles = (idx: number) => {
19+
return {
20+
borderBottom: otherColBorder,
21+
borderLeft: idx === 0 ? firstColBorder : otherColBorder,
22+
}
23+
}
1024

1125
interface IProjectGridParticipantRowProps {
1226
projectName: string
@@ -44,8 +58,6 @@ const prepareExternalIds = (ids: Record<string, string>) => {
4458
.join(', ')
4559
}
4660

47-
const border = '1px solid #dee2e6'
48-
4961
const FamilyCells: React.FC<{
5062
fields: ProjectParticipantGridField[]
5163
participant: NestedParticipant
@@ -55,15 +67,11 @@ const FamilyCells: React.FC<{
5567
}> = ({ fields, participant, backgroundColor, projectName, participantRowSpan }) => (
5668
<>
5769
{fields.map((field) => (
58-
<td
70+
<TableCell
5971
key={`${participant.id}family.${field.key}`}
6072
style={{
61-
// display: field.is_visible ? 'table-cell' : 'none',
6273
backgroundColor,
63-
borderRight: border,
64-
borderBottom: border,
65-
borderTop: border,
66-
borderLeft: '2px solid var(--color-border-color)',
74+
...getBorderStyles(0),
6775
}}
6876
rowSpan={participantRowSpan}
6977
>
@@ -76,10 +84,10 @@ const FamilyCells: React.FC<{
7684
</FamilyLink>
7785
) : (
7886
participant.families
79-
.map((fam) => sanitiseValue(_.get(fam, field.key)))
87+
.map((fam) => sanitiseValue(fam[field.key as keyof FamilySimple]))
8088
.join(', ')
8189
)}
82-
</td>
90+
</TableCell>
8391
))}
8492
</>
8593
)
@@ -93,25 +101,18 @@ const ParticipantCells: React.FC<{
93101
}> = ({ fields, participant, backgroundColor, projectName, participantRowSpan }) => (
94102
<>
95103
{fields.map((field, i) => (
96-
<td
104+
<TableCell
97105
style={{
98-
// display: field.is_visible ? 'table-cell' : 'none',
99106
backgroundColor,
100-
borderRight: border,
101-
borderBottom: border,
102-
borderTop: border,
103-
borderLeft:
104-
i === 0
105-
? '2px solid var(--color-border-color)'
106-
: '1px solid var(--color-border-default)',
107+
...getBorderStyles(i),
107108
}}
108109
key={`${participant.id}participant.${field.key}`}
109110
rowSpan={participantRowSpan}
110111
>
111112
{field.key == 'external_ids'
112113
? prepareExternalIds(participant.external_ids || {})
113-
: sanitiseValue(_.get(participant, field.key))}
114-
</td>
114+
: sanitiseValue(participant[field.key as keyof NestedParticipant])}
115+
</TableCell>
115116
))}
116117
</>
117118
)
@@ -130,8 +131,6 @@ export const ProjectGridParticipantRows: React.FC<IProjectGridParticipantRowProp
130131
const lengthOfParticipant = nRowsForParticipant(participant)
131132
// debugger
132133
const rows = participant.samples.flatMap((s, sidx) => {
133-
// const border = '1px solid #dee2e6'
134-
135134
const lengthOfSample = nRowsForSample(s)
136135

137136
const participantRowSpan = lengthOfParticipant > 0 ? lengthOfParticipant : undefined
@@ -150,7 +149,7 @@ export const ProjectGridParticipantRows: React.FC<IProjectGridParticipantRowProp
150149
return assays.map((assay, assayidx) => {
151150
const isFirstOfGroup = sidx === 0 && sgidx === 0 && assayidx === 0
152151
return (
153-
<tr key={`${participant.id}-${s.id}-${sg.id}-${assay.id}`} {...props}>
152+
<TableRow key={`${participant.id}-${s.id}-${sg.id}-${assay.id}`} {...props}>
154153
{isFirstOfGroup && (
155154
<>
156155
<FamilyCells
@@ -172,18 +171,10 @@ export const ProjectGridParticipantRows: React.FC<IProjectGridParticipantRowProp
172171
{sgidx === 0 &&
173172
assayidx === 0 &&
174173
sampleFields.map((field, i) => (
175-
<td
174+
<TableCell
176175
style={{
177-
display: field.is_visible ? 'table-cell' : 'none',
178176
backgroundColor,
179-
borderRight: border,
180-
borderBottom: border,
181-
borderTop: border,
182-
borderLeft:
183-
i === 0
184-
? '2px solid var(--color-border-color)'
185-
: '1px solid var(--color-border-default)',
186-
// border,
177+
...getBorderStyles(i),
187178
}}
188179
key={`${s.id}sample.${field.key}`}
189180
rowSpan={samplesRowSpan}
@@ -195,64 +186,45 @@ export const ProjectGridParticipantRows: React.FC<IProjectGridParticipantRowProp
195186
: s.id}
196187
</SampleLink>
197188
) : (
198-
sanitiseValue(_.get(s, field.key))
189+
sanitiseValue(s[field.key as keyof NestedSample])
199190
)}
200-
</td>
191+
</TableCell>
201192
))}
202193
{assayidx === 0 &&
203194
sequencingGroupFields.map((field, i) => (
204-
<td
195+
<TableCell
205196
style={{
206-
// display: field.is_visible ? 'table-cell' : 'none',
207-
borderRight: border,
208-
borderBottom: border,
209-
borderTop: border,
210-
borderLeft:
211-
i === 0
212-
? '2px solid var(--color-border-color)'
213-
: '1px solid var(--color-border-default)',
197+
...getBorderStyles(i),
214198
backgroundColor,
215199
}}
216200
key={`${s.id}sequencing_group.${field.key}`}
217-
rowSpan={
218-
(sg.assays ?? []).length > 0
219-
? (sg.assays ?? []).length
220-
: undefined
221-
}
201+
rowSpan={sg.assays?.length || undefined}
222202
>
223203
{field.key === 'id' ? (
224204
<SequencingGroupLink
225205
projectName={projectName}
226206
id={s.id}
227-
sg_id={_.get(sg, 'id')?.toString()}
207+
sg_id={sg.id?.toString()}
228208
>
229-
{sanitiseValue(_.get(sg, field.key))}
209+
{sanitiseValue(sg.id)}
230210
</SequencingGroupLink>
231211
) : (
232-
sanitiseValue(_.get(sg, field.key))
212+
sanitiseValue(sg[field.key as keyof NestedSequencingGroup])
233213
)}
234-
</td>
214+
</TableCell>
235215
))}
236216
{assayFields.map((field, i) => (
237-
<td
217+
<TableCell
238218
style={{
239-
// display: field.is_visible ? 'table-cell' : 'none',
240219
backgroundColor,
241-
borderRight: border,
242-
borderBottom: border,
243-
borderTop: border,
244-
borderLeft:
245-
i === 0
246-
? '2px solid var(--color-border-color)'
247-
: '1px solid var(--color-border-default)',
248-
// border,
220+
...getBorderStyles(i),
249221
}}
250222
key={`${s.id}-assay.${field.key || field.label}`}
251223
>
252-
{sanitiseValue(_.get(assay, field.key))}
253-
</td>
224+
{sanitiseValue(assay[field.key as keyof Assay])}
225+
</TableCell>
254226
))}
255-
</tr>
227+
</TableRow>
256228
)
257229
})
258230
})

web/src/pages/project/ProjectColumnOptions.tsx

+2-4
Original file line numberDiff line numberDiff line change
@@ -74,14 +74,14 @@ export const ProjectColumnOptions: React.FC<ProjectColumnOptionsProps> = ({
7474
<Message warning>
7575
There are a high number of participants ({participantCount}), showing /
7676
hiding columns may take a few seconds to process, and the UI might
77-
appear to freeze
77+
appear to freeze.
7878
</Message>
7979
)}
8080
<Message info>
8181
To filter the data, you can use the <FilterAltIcon /> button at the top of
8282
each column.
8383
</Message>
84-
<DictEditor obj={filterValues} onChange={updateFilters} />
84+
<DictEditor input={filterValues} onChange={updateFilters} />
8585
<br />
8686
<Grid container divided>
8787
{headerGroupOrder.map((headerGroup) => {
@@ -138,11 +138,9 @@ const CategoryColumnOptions: React.FC<{
138138
}
139139

140140
const start = (e: React.DragEvent<HTMLTableRowElement>) => {
141-
console.log('start', e.target)
142141
setDraggedRowIndex(e.currentTarget.rowIndex)
143142
}
144143
const dragEnd = (e: React.DragEvent<HTMLTableRowElement>) => {
145-
console.log('end', e.target)
146144
setDraggedRowIndex(null)
147145
if (tempFields === null) return
148146
updateFields(tempFields)

0 commit comments

Comments
 (0)