Skip to content

Commit a4f691d

Browse files
hextrazaSebastian Benjamin
andauthored
Misc fixes (#325)
* en localization for pagination, for commas * React-select for autocomplete on VariantSearch * Add share button to VariantTable * in set -> equals one of * Fix tests for new autocomplete input --------- Co-authored-by: Sebastian Benjamin <sebastiancbenjamin@gmail.com>
1 parent 16fc136 commit a4f691d

File tree

7 files changed

+173
-97
lines changed

7 files changed

+173
-97
lines changed

jbrowse/src/client/JBrowse/VariantSearch/components/FilterForm.tsx

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import React, { useState } from 'react';
22
import TextField from '@mui/material/TextField';
33
import Button from '@mui/material/Button';
44
import Select from '@mui/material/Select';
5+
import ReactSelect from 'react-select';
56
import AsyncSelect from 'react-select/async';
67
import MenuItem from '@mui/material/MenuItem';
78
import FormControl from '@mui/material/FormControl';
@@ -109,7 +110,7 @@ const FilterForm = (props: FilterFormProps ) => {
109110
updatedFilter.value = '';
110111
}
111112

112-
if (value === "in set" || filter.operator === "in set") {
113+
if (value === "equals one of" || filter.operator === "equals one of") {
113114
updatedFilter.value = '';
114115
}
115116
}
@@ -211,25 +212,33 @@ const FilterForm = (props: FilterFormProps ) => {
211212
<FormScroll>
212213
{filters.map((filter, index) => (
213214
<FilterRow key={index} >
214-
<FormControlMinWidth sx={ highlightedInputs[index]?.field ? highlightedSx : null }>
215-
<InputLabel id="field-label">Field</InputLabel>
216-
<Select
217-
labelId="field-label"
218-
label = 'Field'
219-
value={filter.field}
220-
onChange={(event) =>
221-
handleFilterChange(index, "field", event.target.value)
215+
<FormControlMinWidth sx={highlightedInputs[index]?.field ? highlightedSx : null}>
216+
<ReactSelect
217+
inputId={`field-select-${index}`}
218+
aria-labelledby={`field-label`}
219+
placeholder="Select field..."
220+
menuPortalTarget={document.body}
221+
menuPosition="fixed"
222+
styles={{
223+
menuPortal: (base) => ({ ...base, zIndex: 9999 }),
224+
}}
225+
options={fieldTypeInfo.map(field => ({
226+
value: field.name,
227+
label: field.label ?? field.name,
228+
}))}
229+
onChange={(selected) =>
230+
handleFilterChange(index, 'field', selected?.value ?? '')
222231
}
223-
>
224-
<MenuItem value="" style={{ display: 'none' }}>
225-
<em>None</em>
226-
</MenuItem>
227-
{fieldTypeInfo.map((field) => (
228-
<MenuItem key={field.name} value={field.name}>
229-
{field.label ?? field.name}
230-
</MenuItem>
231-
))}
232-
</Select>
232+
value={
233+
filter.field
234+
? {
235+
value: filter.field,
236+
label: fieldTypeInfo.find(f => f.name === filter.field)?.label ?? filter.field
237+
}
238+
: null
239+
}
240+
isClearable
241+
/>
233242
</FormControlMinWidth>
234243

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

262-
{filter.operator === "in set" ? (
271+
{filter.operator === "equals one of" ? (
263272
<FormControlMinWidth sx={ highlightedInputs[index]?.value ? highlightedSx : null } >
264273
<InputLabel id="value-select-label">Value</InputLabel>
265274
<Select
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import React from 'react';
2+
import { Button } from '@mui/material';
3+
import LinkIcon from '@mui/icons-material/Link';
4+
5+
export const ShareButton = () => {
6+
return (
7+
<Button
8+
startIcon={<LinkIcon />}
9+
size="small"
10+
color="primary"
11+
onClick={() => {
12+
navigator.clipboard.writeText(window.location.href)
13+
.then(() => {
14+
alert('URL copied to clipboard.');
15+
})
16+
.catch(err => {
17+
console.error('Failed to copy the URL: ', err);
18+
alert('Failed to copy the URL.');
19+
});
20+
}}
21+
>
22+
Share
23+
</Button>
24+
);
25+
};

jbrowse/src/client/JBrowse/VariantSearch/components/VariantTableWidget.tsx

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import {
1313
GridToolbarExport
1414
} from '@mui/x-data-grid';
1515
import SearchIcon from '@mui/icons-material/Search';
16-
import LinkIcon from '@mui/icons-material/Link';
1716
import React, { useEffect, useState } from 'react';
1817
import { getConf } from '@jbrowse/core/configuration';
1918
import { AppBar, Box, Button, Dialog, Paper, Popover, Toolbar, Tooltip, Typography } from '@mui/material';
@@ -37,8 +36,10 @@ import '../../jbrowse.css';
3736
import LoadingIndicator from './LoadingIndicator';
3837
import { BaseFeatureDataAdapter } from '@jbrowse/core/data_adapters/BaseAdapter';
3938
import { lastValueFrom } from 'rxjs';
39+
import { ShareButton } from './ShareButton';
4040

4141
const VariantTableWidget = observer(props => {
42+
const numberFormatter = new Intl.NumberFormat('en-US');
4243
const { assembly, trackId, parsedLocString, sessionId, session, pluginManager } = props;
4344
const { assemblyNames = [], assemblyManager } = session ?? {};
4445
const { view } = session ?? {};
@@ -200,25 +201,7 @@ const VariantTableWidget = observer(props => {
200201
delimiter: ';',
201202
}} />
202203

203-
<Button
204-
startIcon={<LinkIcon />}
205-
size="small"
206-
color="primary"
207-
onClick={() => {
208-
navigator.clipboard.writeText(window.location.href)
209-
.then(() => {
210-
// Popup message for successful copy
211-
alert('URL copied to clipboard.');
212-
})
213-
.catch(err => {
214-
// Error handling
215-
console.error('Failed to copy the URL: ', err);
216-
alert('Failed to copy the URL.');
217-
});
218-
}}
219-
>
220-
Share
221-
</Button>
204+
<ShareButton />
222205
</GridToolbarContainer>
223206
);
224207
}
@@ -469,6 +452,14 @@ const VariantTableWidget = observer(props => {
469452
setSortModel(newModel)
470453
handleQuery(filters, true, { page: 0, pageSize: pageSizeModel.pageSize }, newModel);
471454
}}
455+
localeText={{
456+
MuiTablePagination: {
457+
labelDisplayedRows: ({ from, to, count }) =>
458+
`${numberFormatter.format(from)}${numberFormatter.format(to)} of ${
459+
count !== -1 ? numberFormatter.format(count) : 'more than ' + numberFormatter.format(to)
460+
}`,
461+
},
462+
}}
472463
/>
473464
)
474465

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import React from 'react';
2+
import { Button } from '@mui/material';
3+
import LinkIcon from '@mui/icons-material/Link';
4+
5+
export const ShareButton = () => {
6+
return (
7+
<Button
8+
startIcon={<LinkIcon />}
9+
size="small"
10+
color="primary"
11+
onClick={() => {
12+
navigator.clipboard.writeText(window.location.href)
13+
.then(() => {
14+
alert('URL copied to clipboard.');
15+
})
16+
.catch(err => {
17+
console.error('Failed to copy the URL: ', err);
18+
alert('Failed to copy the URL.');
19+
});
20+
}}
21+
>
22+
Share
23+
</Button>
24+
);
25+
};

jbrowse/src/client/JBrowse/VariantTable/components/VariantTableWidget.tsx

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,29 @@ import React, { useEffect, useState } from 'react';
33
import { getConf } from '@jbrowse/core/configuration';
44
import { ParsedLocString, parseLocString } from '@jbrowse/core/util';
55
import { getAdapter } from '@jbrowse/core/data_adapters/dataAdapterCache';
6-
import { AppBar, Box, Button, Dialog, Grid, MenuItem, Paper, Toolbar, Typography } from '@mui/material';
6+
import {
7+
AppBar,
8+
Box,
9+
Button,
10+
Dialog,
11+
Grid,
12+
MenuItem,
13+
Paper,
14+
Toolbar,
15+
Typography,
16+
} from '@mui/material';
717
import ScopedCssBaseline from '@mui/material/ScopedCssBaseline';
818
import {
919
DataGrid,
1020
GridColDef,
1121
GridColumnVisibilityModel, GridFilterPanel,
1222
GridPaginationModel,
1323
GridRenderCellParams,
14-
GridToolbar
24+
GridToolbar,
25+
GridToolbarColumnsButton,
26+
GridToolbarFilterButton,
27+
GridToolbarDensitySelector,
28+
GridToolbarExport
1529
} from '@mui/x-data-grid';
1630
import MenuButton from './MenuButton';
1731
import '../../jbrowse.css';
@@ -27,6 +41,7 @@ import {
2741
passesSampleFilters
2842
} from '../../utils';
2943
import LoadingIndicator from './LoadingIndicator';
44+
import { ShareButton } from './ShareButton';
3045
import { NoAssemblyRegion } from '@jbrowse/core/util/types';
3146
import StandaloneSearchComponent from '../../Search/components/StandaloneSearchComponent';
3247
import { VcfFeature } from '@jbrowse/plugin-variants';
@@ -352,12 +367,24 @@ const VariantTableWidget = observer(props => {
352367
}
353368
}
354369

370+
const CustomToolbar = () => (
371+
<Box sx={{ display: 'flex', justifyContent: 'space-between', p: 1 }}>
372+
<Box>
373+
<GridToolbarColumnsButton />
374+
<GridToolbarFilterButton />
375+
<GridToolbarDensitySelector />
376+
<GridToolbarExport />
377+
<ShareButton />
378+
</Box>
379+
</Box>
380+
);
381+
355382
const gridElement = (
356383
// 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
357384
<DataGrid
358385
columns={[...gridColumns, actionsCol]}
359386
rows={features.map((rawFeature, id) => rawFeatureToRow(rawFeature, id, gridColumns, trackId))}
360-
slots={{ toolbar: GridToolbar, filterPanel: GridFilterPanel }}
387+
slots={{ toolbar: CustomToolbar, filterPanel: GridFilterPanel }}
361388
slotProps={{
362389
filterPanel: {
363390
filterFormProps: {
@@ -444,7 +471,7 @@ const VariantTableWidget = observer(props => {
444471
</Grid>
445472

446473
{supportsLuceneIndex ? <Grid key='luceneViewButton' item xs="auto">
447-
<Button hidden={!supportsLuceneIndex} style={{ marginTop:"8px"}} color="primary" variant="contained" onClick={() => handleMenu("luceneRedirect")}>Switch to Free-text Search</Button>
474+
<Button hidden={!supportsLuceneIndex} style={{ marginTop:"8px"}} color="primary" variant="contained" onClick={() => handleMenu("luceneRedirect")}>Switch to Full-text Search</Button>
448475
</Grid> : null}
449476
</Grid>
450477
</div>

jbrowse/src/client/JBrowse/utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ export function serializeLocationToLuceneQuery(contig, start, end) {
330330
function generateLuceneString(field, operator, value) {
331331
let luceneQueryString = '';
332332

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

657657
export function getOperatorsForField(fieldObj: FieldModel): string[] {
658658
const stringOperators = ["equals", "does not equal", "contains", "does not contain", "starts with", "ends with", "is empty", "is not empty"];
659-
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"];
659+
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"];
660660
const numericOperators = ["=", "!=", ">", ">=", "<", "<="];
661661
const noneOperators = [];
662662

0 commit comments

Comments
 (0)