Skip to content

Commit

Permalink
#2605: Add types to react table v8 (#2606)
Browse files Browse the repository at this point in the history
  • Loading branch information
samrichca authored Apr 13, 2023
1 parent 00bd4ed commit 6d23b73
Show file tree
Hide file tree
Showing 20 changed files with 358 additions and 251 deletions.
56 changes: 45 additions & 11 deletions components/pages/donor-entity/ClinicalTimeline/Samples.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
*/

import {
CellContext,
ColumnDef,
css,
Table,
TableColumnConfig,
Expand All @@ -29,36 +31,68 @@ import { createRef } from 'react';
import { SampleNode } from '../types';
import { formatTableHeader, formatTableDisplayNames, formatTableData } from './util';
import { getConfig } from 'global/config';
import { usePageQuery } from 'global/hooks/usePageContext';
import NextLink from 'next/link';
import { Link } from '@icgc-argo/uikit';
import urlJoin from 'url-join';
import { FILE_REPOSITORY_PATH } from 'global/constants/pages';
import sqonBuilder from 'sqon-builder';

const { FEATURE_REACT_TABLE_V8_ENABLED } = getConfig();

const Samples = ({ samples }: { samples: SampleNode[] }) => {
export type SamplesTableRecord = SampleNode['node'];

const getAvailableFilesLink = (props: CellContext<SamplesTableRecord, JSX.Element>) => {
const { getValue, row } = props;
const { donorId } = usePageQuery<{ donorId: string }>();
const sampleFilter = sqonBuilder
.has('donor_id', donorId)
.has('submitter_sample_id', row.original.submitter_sample_id)
.build();

const sampleFilterUrl = urlJoin(
FILE_REPOSITORY_PATH,
`?filters=${encodeURIComponent(JSON.stringify(sampleFilter))}`,
);

return (
<NextLink href={sampleFilterUrl} passHref>
<Link variant="INLINE">{getValue()}</Link>
</NextLink>
);
};

const Samples = ({ samples }: { samples: SamplesTableRecord[] }) => {
// react table v6
const tableData_legacy: TableDataBase = formatTableDisplayNames(samples);
const tableColumns_legacy: TableColumnConfig<TableDataBase>[] = Object.keys(tableData_legacy).map(
const tableDataTableV6: TableDataBase = formatTableDisplayNames(samples);
const tableColumnsTableV6: TableColumnConfig<TableDataBase>[] = Object.keys(tableDataTableV6).map(
(key) => ({
Header: key,
Cell: tableData_legacy[key],
Cell: tableDataTableV6[key],
}),
);
const containerRef = createRef<HTMLDivElement>();

// react table v8
const tableColumns = !!samples.length
? Object.keys(samples[0]).map((sampleKey) => ({
const tableColumns: ColumnDef<SamplesTableRecord>[] = samples.length
? Object.keys(samples[0]).map((sampleKey: keyof SamplesTableRecord) => ({
accessorKey: sampleKey,
header: () => formatTableHeader(sampleKey),
id: sampleKey,
...(sampleKey === 'available_files'
? {
cell: getAvailableFilesLink,
}
: {}),
}))
: [];

const tableData = samples.map((sample) =>
Object.entries(sample).reduce(
const tableData: SamplesTableRecord[] = samples.map((sample) =>
Object.entries(sample).reduce<SamplesTableRecord>(
(acc, [key, value]) => ({
...acc,
...formatTableData(key, value),
}),
{},
{} as SamplesTableRecord,
),
);

Expand Down Expand Up @@ -91,7 +125,7 @@ const Samples = ({ samples }: { samples: SampleNode[] }) => {
) : (
<Table
parentRef={containerRef}
columns={tableColumns_legacy}
columns={tableColumnsTableV6}
data={samples}
withOutsideBorder
stripped
Expand Down
33 changes: 20 additions & 13 deletions components/pages/donor-entity/ClinicalTimeline/Treatment.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,34 @@
import { css, Table, TableV8, Typography } from '@icgc-argo/uikit';
import { ColumnDef, css, Table, TableV8, Typography } from '@icgc-argo/uikit';
import { createRef } from 'react';
import { TreatmentNode } from '../types';
import { getConfig } from 'global/config';
import { TreatmentData } from '../types';

const { FEATURE_REACT_TABLE_V8_ENABLED } = getConfig();

const Treatment = ({ treatment }: { key: string; treatment: TreatmentNode }) => {
const {
node: { treatment_type: title, data: tableData },
} = treatment;
// NOTE types based on dummy data
export type TreatmentTableColumns = TreatmentData;

type TreatmentTableInput = {
treatment_type: string;
data: TreatmentTableColumns[];
};

const Treatment = ({ treatment }: { treatment: TreatmentTableInput }) => {
const { treatment_type, data: tableData } = treatment;

// react table v6
const tableColumns_legacy = Object.keys(tableData[0]).map((k) => ({
const tableColumnsTableV6 = Object.keys(tableData[0]).map((k) => ({
Header: k,
accessor: k,
}));
const containerRef = createRef<HTMLDivElement>();

// react table v8
const tableColumns = Object.keys(tableData[0]).map((k) => ({
header: () => k,
accessorKey: k,
}));
const tableColumns: ColumnDef<TreatmentTableColumns>[] = Object.keys(tableData[0]).map(
(treatmentKey: keyof TreatmentTableColumns) => ({
accessorKey: treatmentKey,
}),
);

return (
<div
Expand All @@ -36,7 +43,7 @@ const Treatment = ({ treatment }: { key: string; treatment: TreatmentNode }) =>
margin-bottom: 4px;
`}
>
{title}
{treatment_type}
</Typography>
<div ref={containerRef}>
{FEATURE_REACT_TABLE_V8_ENABLED ? (
Expand All @@ -51,7 +58,7 @@ const Treatment = ({ treatment }: { key: string; treatment: TreatmentNode }) =>
) : (
<Table
parentRef={containerRef}
columns={tableColumns_legacy}
columns={tableColumnsTableV6}
data={tableData}
withOutsideBorder
stripped
Expand Down
10 changes: 8 additions & 2 deletions components/pages/donor-entity/ClinicalTimeline/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ import { DonorCentricRecord, Entity, EntityType, SampleNode, TreatmentNode } fro
import Header from './Header';
import Samples from './Samples';
import Timeline from './Timeline';
import Treatment from './Treatment';
import Treatment, { TreatmentTableColumns } from './Treatment';
import { formatTableDisplayNames, formatTimelineEntityData, splitIntoColumns } from './util';

export const ENTITY_DISPLAY = Object.freeze({
Expand Down Expand Up @@ -258,7 +258,13 @@ const ClinicalTimeline = ({ data }: { data: DonorCentricRecord }) => {
`}
>
{selectedTreatments.map((treatment, i) => (
<Treatment key={`treatment-${i}`} treatment={treatment} />
<Treatment
key={treatment.node.treatment_type}
treatment={{
treatment_type: treatment.node.treatment_type,
data: treatment.node.data,
}}
/>
))}
</div>
)}
Expand Down
49 changes: 14 additions & 35 deletions components/pages/donor-entity/ClinicalTimeline/util.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,16 @@
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

import { Link, UikitTheme } from '@icgc-argo/uikit';
import { FILE_REPOSITORY_PATH } from 'global/constants/pages';
import { usePageQuery } from 'global/hooks/usePageContext';
import { UikitTheme } from '@icgc-argo/uikit';
import { chunk, isEmpty } from 'lodash';
import sqonBuilder from 'sqon-builder';
import urlJoin from 'url-join';
import { DiagnosisNode, EntityType, SpecimenNode } from '../types';

type TableDataValue = string | number | React.ReactNode;
import {
AliasedDisplayData,
DiagnosisNode,
EntityType,
SpecimenNode,
Specimens,
TableDataValue,
} from '../types';

export const getTimelineStyles = (theme: UikitTheme) => {
const colors = theme.colors;
Expand Down Expand Up @@ -86,7 +87,7 @@ export const splitIntoColumns = (
}
};

const donorCentricDisplayNames = {
export const donorCentricDisplayNames = {
age_at_diagnosis: 'Age at Diagnosis',
age_at_menarche: 'Age at Menarche',
available_files: 'Available Files',
Expand Down Expand Up @@ -167,10 +168,6 @@ const donorCentricDisplayNames = {
workflow_names: 'Workflow Names',
};

type AliasedDisplayData = {
[K in keyof typeof donorCentricDisplayNames]?: any;
};

// format for display
// react table v6
export const formatTableDisplayNames = (data: any[]) =>
Expand Down Expand Up @@ -262,7 +259,7 @@ export const formatTimelineEntityData = (donorData) => {
},
)[0];

const specimens = donorData.specimens?.hits.edges.map(({ node }: SpecimenNode) => {
const specimens: Specimens = donorData.specimens?.hits.edges.map(({ node }: SpecimenNode) => {
const { pathological_t_category, pathological_n_category, pathological_m_category } = node;

const aliasedKeys = [
Expand All @@ -277,25 +274,7 @@ export const formatTimelineEntityData = (donorData) => {
if (pathological_t_category && pathological_n_category && pathological_m_category)
data.pathological_tnm_category = `${pathological_t_category}${pathological_n_category}${pathological_m_category}`;

const samples = node.samples.hits.edges.map((sample) => {
const { donorId } = usePageQuery<{ donorId: string }>();
const sampleFilter = sqonBuilder
.has('donor_id', donorId)
.has('submitter_sample_id', sample.node['submitter_sample_id'])
.build();

const sampleFilterUrl = urlJoin(
FILE_REPOSITORY_PATH,
`?filters=${encodeURIComponent(JSON.stringify(sampleFilter))}`,
);

const available_files = (
<Link variant="INLINE" href={sampleFilterUrl}>
{sample.node['available_files']}
</Link>
);
return { ...sample.node, available_files };
});
const samples = node.samples.hits.edges.map((sample) => sample.node);

return {
id: `SPECIMEN ${node.submitter_specimen_id}`,
Expand All @@ -318,8 +297,8 @@ export const formatTimelineEntityData = (donorData) => {
export const formatTableHeader = (columnKey: string) =>
donorCentricDisplayNames[columnKey] || columnKey;

export const formatTableData = (key: string, value: TableDataValue) => {
let displayValue: TableDataValue;
export const formatTableData = (key: string, value: React.ReactNode) => {
let displayValue: React.ReactNode;
switch (key) {
case 'age_at_diagnosis':
displayValue = `${value} years`;
Expand Down
21 changes: 12 additions & 9 deletions components/pages/donor-entity/DonorFileCard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import {
Button,
ColumnDef,
Container,
css,
Icon,
Expand All @@ -28,7 +29,7 @@ import {
Typography,
useTheme,
} from '@icgc-argo/uikit';
import { ComponentType } from 'react';
import { ComponentType, ReactElement } from 'react';
import { Col, Row } from 'react-grid-system';
import { getConfig } from 'global/config';

Expand Down Expand Up @@ -116,6 +117,15 @@ const DataRow: ComponentType<{ name: string; link: string; fileCount: number }>
const FileTable: ComponentType<{ header: string; data: Array<any> }> = ({ header, data }) => {
const theme = useTheme();

const tableColumns: ColumnDef<{ id: ReactElement }>[] = [
{
accessorKey: 'id',
id: 'id',
header,
cell: ({ renderValue }) => renderValue(),
},
];

return (
<Col xs={12}>
{FEATURE_REACT_TABLE_V8_ENABLED ? (
Expand All @@ -130,14 +140,7 @@ const FileTable: ComponentType<{ header: string; data: Array<any> }> = ({ header
}
`}
data={data}
columns={[
{
accessorKey: 'id',
id: 'id',
header,
cell: ({ renderValue }) => renderValue(),
},
]}
columns={tableColumns}
withHeaders
withRowBorder
/>
Expand Down
25 changes: 24 additions & 1 deletion components/pages/donor-entity/types.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
*/

import { Associations, FileRecord } from '../file-entity/types';
import { SamplesTableRecord } from './ClinicalTimeline/Samples';
import { donorCentricDisplayNames } from './ClinicalTimeline/util';

export interface DonorCentricRecord {
donor_id: string;
Expand Down Expand Up @@ -219,10 +221,18 @@ export type SpecimenNode = {
};
};

// NOTE: types based on dummy data
export type TreatmentData = {
drug_rxnormcui: string;
drug_name: string;
cumulative_drug_dose: string;
chemotherapy_dosage_units: string;
};

export type TreatmentNode = {
node: {
treatment_type: string;
data: Array<{}>;
data: Array<TreatmentData>;
program_id?: string;
submitter_donor_id?: string;
submitter_treatment_id?: string;
Expand Down Expand Up @@ -267,3 +277,16 @@ export type Entity = {
};

export interface DonorEntityData extends Entity {}

export type AliasedDisplayData = {
[K in keyof typeof donorCentricDisplayNames]?: any;
};

export type Specimens = {
id: string;
description: string;
type: string;
interval: string;
data: AliasedDisplayData;
samples: SamplesTableRecord;
};
Loading

0 comments on commit 6d23b73

Please sign in to comment.