Skip to content

Commit

Permalink
Merge pull request #20 from WorldHealthOrganization/feature/find721-s…
Browse files Browse the repository at this point in the history
…ample-search-base-implementation

FIND-721 INSDC Samples Search: Baseline page implementation.
  • Loading branch information
TraMZzz authored Jan 30, 2025
2 parents 0e18e8b + 70a852e commit afa9252
Show file tree
Hide file tree
Showing 21 changed files with 345 additions and 23 deletions.
5 changes: 5 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"rules": {
"max-len": ["error", { "code": 120 }]
}
}
3 changes: 3 additions & 0 deletions src/app/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { submissionApi } from '../services/submissionApi/submissionApi';
import { overviewApi } from '../services/overviewApi/overviewApi';
import drugsApi from '../services/drugsApi';
import genesApi from '../services/genesApi';
import genotypeResistanceApi from '../services/genotypeResistanceApi';

import drawerReducer from '../features/drawer/drawerSlice';
import { s3Api } from '../services/s3Api/s3Api';
Expand All @@ -18,6 +19,7 @@ export const reducer = {
[dictionariesApi.reducerPath]: dictionariesApi.reducer,
[drugsApi.reducerPath]: drugsApi.reducer,
[genesApi.reducerPath]: genesApi.reducer,
[genotypeResistanceApi.reducerPath]: genotypeResistanceApi.reducer,
[submissionApi.reducerPath]: submissionApi.reducer,
[s3Api.reducerPath]: s3Api.reducer,
[feederApi.reducerPath]: feederApi.reducer,
Expand All @@ -36,6 +38,7 @@ export const store = configureStore({
dictionariesApi.middleware,
drugsApi.middleware,
genesApi.middleware,
genotypeResistanceApi.middleware,
submissionApi.middleware,
overviewApi.middleware,
feederApi.middleware,
Expand Down
1 change: 1 addition & 0 deletions src/components/AppBar/tabsConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export const dropdownConfig = [

export const tabsConfig = [
{ ...appRoutes.mutations, label: 'Mutation' },
{ ...appRoutes.genotypeResistance, label: 'Genotype Resistance' },
{ ...appRoutes.dataSubmission, label: 'Data submission' },
{ ...appRoutes.download, label: 'Download' },
];
Expand Down
6 changes: 6 additions & 0 deletions src/components/DataGrid/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,9 @@ export interface DrugTableColumns extends BaseColumns {
export interface GeneTableColumns extends BaseColumns {
drug: number;
}

export interface GenotypeResistance extends DrugTableColumns {
variant: string;
sampleAliasesName: string;
resistanceFlag: string;
}
2 changes: 2 additions & 0 deletions src/components/ExportButton/ExportButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { styles } from './styles';
import H3 from '../typography/H3';
import { AppButton } from '../AppButton/AppButton';
import { useExportTable } from '../../hooks/useExportTable';
import { useGetExportTableLazyQuery } from '../../services/drugsApi/drugsApi';
import { IDrug } from '../../services/drugsApi/models';
import { IGene } from '../../services/genesApi/models';
import { IColumnFilter, ISortState } from '../DataGrid/models';
Expand All @@ -33,6 +34,7 @@ export const ExportButton = ({
response,
fetchData,
} = useExportTable(
useGetExportTableLazyQuery,
{
drugID: 'drugId' in selectedDropdownItem ? selectedDropdownItem.drugId : undefined,
geneDbCrossrefId: 'geneDbCrossrefId' in selectedDropdownItem
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
/** @jsxImportSource @emotion/react */
import React, {
useEffect, useState, SyntheticEvent, useRef,
} from 'react';
import { CSVLink } from 'react-csv';

import { useGetDrugsDataQuery } from '../../../../services/drugsApi/drugsApi';
import { useGetTableDataQuery, useGetExportTableLazyQuery } from '../../../../services/genotypeResistanceApi/genotypeResistanceApi';
import { DEFAULT_PAGE_SIZE, useTableData } from '../../hooks/useTableData';
import { useDebounce } from '../../../../hooks/useDebounce';
import { useExportTable } from '../../../../hooks/useExportTable';

import H1 from '../../../../components/typography/H1';
import AppPaper from '../../../../components/AppPaper/AppPaper';
import H3 from '../../../../components/typography/H3';

import AutocompleteInputSearch from '../../../../components/AutocompleteInputSearch/AutocompleteInputSearch';
import LoadingWrapper from '../../../../components/LoadingWrapper/LoadingWrapper';
import AppButton from '../../../../components/AppButton/AppButton';

import DataGrid from '../../../../components/DataGrid';
import { pagination } from '../../../../components/DataGrid/styles';
import Pagination from '../../../drugsView/componets/Pagination/Pagination';
import {
GenotypeResistance, GridType, IColumn,
} from '../../../../components/DataGrid/models';

import {
header,
wrapper,
paperWrapper,
paper,
dataGrid,
viewStyles,
buttonUploadWrapper,
addStyle,
} from './styles';

export const columns: IColumn<GenotypeResistance>[] = [
{ name: 'drugName', header: 'Drug' },
{ name: 'variant', header: 'Variant' },
{ name: 'sampleAliasesName', header: 'Sample Alias Name' },
{ name: 'resistanceFlag', header: 'Genotype Resistance' },
];

const GenotypeResistanceView = () => {
// react-scv lib doesn't have types for ref
const csvRef = useRef<any>(null);

const [inputSampleValue, setInputSampleValue] = useState<boolean | string>(false);
const debouncedSampleValue = useDebounce<boolean | string>(inputSampleValue, 500);

const {
data: drugsData = [],
} = useGetDrugsDataQuery({ isAssociated: 1 });

const getDrugIds = () => {
let drugsIds = '';
drugsData.forEach((drugItem) => {
drugsIds += `,${drugItem.drugId}`;
});
return drugsIds.substring(1);
};

const {
rowsCount,
tableData = [],
isTableDataLoading,
sortState,
filters,
page,
updateSort,
updateFilters,
updatePaging,
} = useTableData({
drugID: getDrugIds(),
useGetDataQuery: useGetTableDataQuery,
});

const {
response,
fetchData,
} = useExportTable(useGetExportTableLazyQuery, { filters });

const handleSampleChange = (e: SyntheticEvent, value: string) => {
setInputSampleValue(value);
};

useEffect(() => {
if (csvRef?.current && response.data?.length && response.status === 'fulfilled') {
csvRef.current.link.click();
}
}, [response]);

useEffect(() => {
if (typeof debouncedSampleValue === 'boolean') {
// eslint-disable-line
} else {
updateFilters([{ id: 'sampleAliasesName', value: debouncedSampleValue }]);
}
// eslint-disable-line
}, [debouncedSampleValue]);

if (!tableData.length && isTableDataLoading) {
return (
<div css={wrapper}>
<H1 style={header}>Sample Alias Search</H1>
<LoadingWrapper centered isLoading>
<span />
</LoadingWrapper>
</div>
);
}

return (
<div css={wrapper}>
<H1 style={header}>Sample Alias Search</H1>
<div css={dataGrid}>
<DataGrid<GenotypeResistance>
isLoading={isTableDataLoading}
columns={columns}
dataSource={tableData}
filterValues={filters}
onFilterChange={updateFilters}
onSortingChange={updateSort}
selectedDropdownItem={{}}
sortState={sortState}
type={GridType.Drug}
addStyle={addStyle}
>
<div css={paperWrapper}>
<AppPaper style={paper}>
<div css={viewStyles.autoCompleteContainer}>
<H3
style={viewStyles.autoCompleteInputLabel}
>
Sample Alias
</H3>
<AutocompleteInputSearch
isLoading={isTableDataLoading}
onSelectionChanged={(e, value) => { console.log(e, value); }}
selectedValue={null}
onChange={handleSampleChange}
value={`${debouncedSampleValue}`}
options={[]}
style={viewStyles.sxAutoComplete}
placeholder="Search by Sample Alias Name"
/>
</div>
<div css={buttonUploadWrapper}>
<H3 style={viewStyles.autoCompleteInputLabel}>Export CSV Data</H3>
<AppButton
onClick={fetchData}
variant="outlined"
size="medium"
startIconName="file_download"
>
{response.isLoading ? 'Loading...' : 'Download'}
</AppButton>
<CSVLink
ref={csvRef}
data={response.data || []}
filename="GenotypeResistanceSearch"
/>
</div>
</AppPaper>
</div>
</DataGrid>
<div css={pagination.wrapper}>
<Pagination
page={page}
pageCount={Math.ceil(rowsCount / DEFAULT_PAGE_SIZE)}
onPageClick={updatePaging}
/>
</div>
</div>
</div>
);
};

export default GenotypeResistanceView;
23 changes: 23 additions & 0 deletions src/features/TableView/components/GenotypeResistanceView/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import {
wrapper,
header,
dataGrid,
paperWrapper,
paper,
iconStyles,
viewStyles,
buttonUploadWrapper,
addStyle,
} from '../../styles';

export {
wrapper,
header,
dataGrid,
paperWrapper,
paper,
iconStyles,
viewStyles,
buttonUploadWrapper,
addStyle,
};
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { CSVLink } from 'react-csv';
// import { InputAdornment, TextField } from '@mui/material';
// import SearchIcon from '@mui/icons-material/Search';

import { useGetDrugsDataQuery, useGetTableDataQuery } from '../../../../services/drugsApi/drugsApi';
import { useGetDrugsDataQuery, useGetTableDataQuery, useGetExportTableLazyQuery } from '../../../../services/drugsApi/drugsApi';
import { IDrug } from '../../../../services/drugsApi/models';
import { IGene } from '../../../../services/genesApi/models';
import { DEFAULT_PAGE_SIZE, useTableData } from '../../hooks/useTableData';
Expand Down Expand Up @@ -37,9 +37,8 @@ import {
wrapper,
paperWrapper,
paper,
genesViewStyles,
viewStyles,
dataGrid,
// iconStyles,
buttonUploadWrapper,
addStyle,
} from './styles';
Expand Down Expand Up @@ -146,9 +145,7 @@ const MutationView = () => {
const {
response,
fetchData,
} = useExportTable(
{ filters },
);
} = useExportTable(useGetExportTableLazyQuery, { filters });

useEffect(() => {
// eslint-disable-line
Expand Down Expand Up @@ -250,9 +247,9 @@ const MutationView = () => {
>
<div css={paperWrapper}>
<AppPaper style={paper}>
<div css={genesViewStyles.autoCompleteContainer}>
<div css={viewStyles.autoCompleteContainer}>
<H3
style={genesViewStyles.autoCompleteInputLabel}
style={viewStyles.autoCompleteInputLabel}
>
Gene
</H3>
Expand All @@ -268,18 +265,18 @@ const MutationView = () => {
onChange={handleGeneChange}
value={`${debouncedGeneValue}`}
options={optionsGene}
style={genesViewStyles.sxAutoComplete}
style={viewStyles.sxAutoComplete}
placeholder="Search by Gene"
/>
</div>
{/* <div css={genesViewStyles.autoCompleteContainer}>
{/* <div css={viewStyles.autoCompleteContainer}>
<H3
style={genesViewStyles.autoCompleteInputLabel}
style={viewStyles.autoCompleteInputLabel}
>
Position
</H3>
<TextField
sx={genesViewStyles.sxAutoComplete}
sx={viewStyles.sxAutoComplete}
placeholder="Search by Position"
type="text"
disabled={isTableDataLoading}
Expand All @@ -298,7 +295,7 @@ const MutationView = () => {
/>
</div> */}
<div css={buttonUploadWrapper}>
<H3 style={genesViewStyles.autoCompleteInputLabel}>Export CSV Data</H3>
<H3 style={viewStyles.autoCompleteInputLabel}>Export CSV Data</H3>
<AppButton
onClick={fetchData}
variant="outlined"
Expand Down
23 changes: 23 additions & 0 deletions src/features/TableView/components/MutationView/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import {
wrapper,
header,
dataGrid,
paperWrapper,
paper,
iconStyles,
viewStyles,
buttonUploadWrapper,
addStyle,
} from '../../styles';

export {
wrapper,
header,
dataGrid,
paperWrapper,
paper,
iconStyles,
viewStyles,
buttonUploadWrapper,
addStyle,
};
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { css } from '@emotion/react';
import appColors from '../../../../styles/colors';
import appColors from '../../styles/colors';

const wrapper = css({
padding: '64px 54px',
Expand Down Expand Up @@ -45,7 +45,7 @@ const paper = css({
padding: 0,
});

const genesViewStyles = {
const viewStyles = {
tablesWrapper: css({
display: 'flex',
marginTop: '16px',
Expand Down Expand Up @@ -122,7 +122,7 @@ export {
paperWrapper,
paper,
iconStyles,
genesViewStyles,
viewStyles,
buttonUploadWrapper,
addStyle,
};
Loading

0 comments on commit afa9252

Please sign in to comment.