Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 29 additions & 20 deletions jbrowse/src/client/JBrowse/VariantSearch/components/FilterForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { useState } from 'react';
import TextField from '@mui/material/TextField';
import Button from '@mui/material/Button';
import Select from '@mui/material/Select';
import ReactSelect from 'react-select';
import AsyncSelect from 'react-select/async';
import MenuItem from '@mui/material/MenuItem';
import FormControl from '@mui/material/FormControl';
Expand Down Expand Up @@ -109,7 +110,7 @@ const FilterForm = (props: FilterFormProps ) => {
updatedFilter.value = '';
}

if (value === "in set" || filter.operator === "in set") {
if (value === "equals one of" || filter.operator === "equals one of") {
updatedFilter.value = '';
}
}
Expand Down Expand Up @@ -211,25 +212,33 @@ const FilterForm = (props: FilterFormProps ) => {
<FormScroll>
{filters.map((filter, index) => (
<FilterRow key={index} >
<FormControlMinWidth sx={ highlightedInputs[index]?.field ? highlightedSx : null }>
<InputLabel id="field-label">Field</InputLabel>
<Select
labelId="field-label"
label = 'Field'
value={filter.field}
onChange={(event) =>
handleFilterChange(index, "field", event.target.value)
<FormControlMinWidth sx={highlightedInputs[index]?.field ? highlightedSx : null}>
<ReactSelect
inputId={`field-select-${index}`}
aria-labelledby={`field-label`}
placeholder="Select field..."
menuPortalTarget={document.body}
menuPosition="fixed"
styles={{
menuPortal: (base) => ({ ...base, zIndex: 9999 }),
}}
options={fieldTypeInfo.map(field => ({
value: field.name,
label: field.label ?? field.name,
}))}
onChange={(selected) =>
handleFilterChange(index, 'field', selected?.value ?? '')
}
>
<MenuItem value="" style={{ display: 'none' }}>
<em>None</em>
</MenuItem>
{fieldTypeInfo.map((field) => (
<MenuItem key={field.name} value={field.name}>
{field.label ?? field.name}
</MenuItem>
))}
</Select>
value={
filter.field
? {
value: filter.field,
label: fieldTypeInfo.find(f => f.name === filter.field)?.label ?? filter.field
}
: null
}
isClearable
/>
</FormControlMinWidth>

<FormControlMinWidth sx={ highlightedInputs[index]?.operator ? highlightedSx : null } >
Expand Down Expand Up @@ -259,7 +268,7 @@ const FilterForm = (props: FilterFormProps ) => {
</Select>
</FormControlMinWidth>

{filter.operator === "in set" ? (
{filter.operator === "equals one of" ? (
<FormControlMinWidth sx={ highlightedInputs[index]?.value ? highlightedSx : null } >
<InputLabel id="value-select-label">Value</InputLabel>
<Select
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from 'react';
import { Button } from '@mui/material';
import LinkIcon from '@mui/icons-material/Link';

export const ShareButton = () => {
return (
<Button
startIcon={<LinkIcon />}
size="small"
color="primary"
onClick={() => {
navigator.clipboard.writeText(window.location.href)
.then(() => {
alert('URL copied to clipboard.');
})
.catch(err => {
console.error('Failed to copy the URL: ', err);
alert('Failed to copy the URL.');
});
}}
>
Share
</Button>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import {
GridToolbarExport
} from '@mui/x-data-grid';
import SearchIcon from '@mui/icons-material/Search';
import LinkIcon from '@mui/icons-material/Link';
import React, { useEffect, useState } from 'react';
import { getConf } from '@jbrowse/core/configuration';
import { AppBar, Box, Button, Dialog, Paper, Popover, Toolbar, Tooltip, Typography } from '@mui/material';
Expand All @@ -37,8 +36,10 @@ import '../../jbrowse.css';
import LoadingIndicator from './LoadingIndicator';
import { BaseFeatureDataAdapter } from '@jbrowse/core/data_adapters/BaseAdapter';
import { lastValueFrom } from 'rxjs';
import { ShareButton } from './ShareButton';

const VariantTableWidget = observer(props => {
const numberFormatter = new Intl.NumberFormat('en-US');
const { assembly, trackId, parsedLocString, sessionId, session, pluginManager } = props;
const { assemblyNames = [], assemblyManager } = session ?? {};
const { view } = session ?? {};
Expand Down Expand Up @@ -200,25 +201,7 @@ const VariantTableWidget = observer(props => {
delimiter: ';',
}} />

<Button
startIcon={<LinkIcon />}
size="small"
color="primary"
onClick={() => {
navigator.clipboard.writeText(window.location.href)
.then(() => {
// Popup message for successful copy
alert('URL copied to clipboard.');
})
.catch(err => {
// Error handling
console.error('Failed to copy the URL: ', err);
alert('Failed to copy the URL.');
});
}}
>
Share
</Button>
<ShareButton />
</GridToolbarContainer>
);
}
Expand Down Expand Up @@ -469,6 +452,14 @@ const VariantTableWidget = observer(props => {
setSortModel(newModel)
handleQuery(filters, true, { page: 0, pageSize: pageSizeModel.pageSize }, newModel);
}}
localeText={{
MuiTablePagination: {
labelDisplayedRows: ({ from, to, count }) =>
`${numberFormatter.format(from)}–${numberFormatter.format(to)} of ${
count !== -1 ? numberFormatter.format(count) : 'more than ' + numberFormatter.format(to)
}`,
},
}}
/>
)

Expand Down
25 changes: 25 additions & 0 deletions jbrowse/src/client/JBrowse/VariantTable/components/ShareButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from 'react';
import { Button } from '@mui/material';
import LinkIcon from '@mui/icons-material/Link';

export const ShareButton = () => {
return (
<Button
startIcon={<LinkIcon />}
size="small"
color="primary"
onClick={() => {
navigator.clipboard.writeText(window.location.href)
.then(() => {
alert('URL copied to clipboard.');
})
.catch(err => {
console.error('Failed to copy the URL: ', err);
alert('Failed to copy the URL.');
});
}}
>
Share
</Button>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,29 @@ import React, { useEffect, useState } from 'react';
import { getConf } from '@jbrowse/core/configuration';
import { ParsedLocString, parseLocString } from '@jbrowse/core/util';
import { getAdapter } from '@jbrowse/core/data_adapters/dataAdapterCache';
import { AppBar, Box, Button, Dialog, Grid, MenuItem, Paper, Toolbar, Typography } from '@mui/material';
import {
AppBar,
Box,
Button,
Dialog,
Grid,
MenuItem,
Paper,
Toolbar,
Typography,
} from '@mui/material';
import ScopedCssBaseline from '@mui/material/ScopedCssBaseline';
import {
DataGrid,
GridColDef,
GridColumnVisibilityModel, GridFilterPanel,
GridPaginationModel,
GridRenderCellParams,
GridToolbar
GridToolbar,
GridToolbarColumnsButton,
GridToolbarFilterButton,
GridToolbarDensitySelector,
GridToolbarExport
} from '@mui/x-data-grid';
import MenuButton from './MenuButton';
import '../../jbrowse.css';
Expand All @@ -27,6 +41,7 @@ import {
passesSampleFilters
} from '../../utils';
import LoadingIndicator from './LoadingIndicator';
import { ShareButton } from './ShareButton';
import { NoAssemblyRegion } from '@jbrowse/core/util/types';
import StandaloneSearchComponent from '../../Search/components/StandaloneSearchComponent';
import { VcfFeature } from '@jbrowse/plugin-variants';
Expand Down Expand Up @@ -352,12 +367,24 @@ const VariantTableWidget = observer(props => {
}
}

const CustomToolbar = () => (
<Box sx={{ display: 'flex', justifyContent: 'space-between', p: 1 }}>
<Box>
<GridToolbarColumnsButton />
<GridToolbarFilterButton />
<GridToolbarDensitySelector />
<GridToolbarExport />
<ShareButton />
</Box>
</Box>
);

const gridElement = (
// NOTE: the filterPanel/sx override is added to fix an issue where the grid column filter value input doesn't align with the field and operator inputs
<DataGrid
columns={[...gridColumns, actionsCol]}
rows={features.map((rawFeature, id) => rawFeatureToRow(rawFeature, id, gridColumns, trackId))}
slots={{ toolbar: GridToolbar, filterPanel: GridFilterPanel }}
slots={{ toolbar: CustomToolbar, filterPanel: GridFilterPanel }}
slotProps={{
filterPanel: {
filterFormProps: {
Expand Down Expand Up @@ -444,7 +471,7 @@ const VariantTableWidget = observer(props => {
</Grid>

{supportsLuceneIndex ? <Grid key='luceneViewButton' item xs="auto">
<Button hidden={!supportsLuceneIndex} style={{ marginTop:"8px"}} color="primary" variant="contained" onClick={() => handleMenu("luceneRedirect")}>Switch to Free-text Search</Button>
<Button hidden={!supportsLuceneIndex} style={{ marginTop:"8px"}} color="primary" variant="contained" onClick={() => handleMenu("luceneRedirect")}>Switch to Full-text Search</Button>
</Grid> : null}
</Grid>
</div>
Expand Down
4 changes: 2 additions & 2 deletions jbrowse/src/client/JBrowse/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ export function serializeLocationToLuceneQuery(contig, start, end) {
function generateLuceneString(field, operator, value) {
let luceneQueryString = '';

if (field === 'variableSamples' && operator == "in set") {
if (field === 'variableSamples' && operator == "equals one of") {
return `variableSamples:~${value}~`;
}
let intValue = parseInt(value);
Expand Down Expand Up @@ -656,7 +656,7 @@ export function searchStringToInitialFilters(knownFieldNames: string[]) : Filter

export function getOperatorsForField(fieldObj: FieldModel): string[] {
const stringOperators = ["equals", "does not equal", "contains", "does not contain", "starts with", "ends with", "is empty", "is not empty"];
const variableSamplesType = ["in set", "variable in", "not variable in", "variable in all of", "variable in any of", "not variable in any of", "not variable in one of", "is empty", "is not empty"];
const variableSamplesType = ["equals one of", "variable in", "not variable in", "variable in all of", "variable in any of", "not variable in any of", "not variable in one of", "is empty", "is not empty"];
const numericOperators = ["=", "!=", ">", ">=", "<", "<="];
const noneOperators = [];

Expand Down
Loading