diff --git a/package.json b/package.json index c659bfd56f2..fb29a8e15e1 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "@emotion/react": "^11.9.0", "@emotion/styled": "^11.8.1", "@mui/material": "^5.10.17", - "@mui/x-data-grid": "^5.0.0", + "@mui/x-data-grid": "^6.0.1", "@oclif/dev-cli": "^1.26.9", "@oclif/test": "^1.2.7", "@storybook/addon-essentials": "^7.0.0-beta.35", diff --git a/packages/core/BaseFeatureWidget/BaseFeatureDetail.tsx b/packages/core/BaseFeatureWidget/BaseFeatureDetail.tsx index d66374fd2ef..03efc7ee2ae 100644 --- a/packages/core/BaseFeatureWidget/BaseFeatureDetail.tsx +++ b/packages/core/BaseFeatureWidget/BaseFeatureDetail.tsx @@ -396,7 +396,7 @@ function DataGridDetails({ }} > - + setInfo({ @@ -207,7 +208,7 @@ export default observer(function FacetedSelector({ width: widthsDebounced[e] || 100, // can be undefined before useEffect update renderCell: (params: GridCellParams) => { const { value } = params - return value ? : '' + return value ? : '' }, })), ...filteredMetadataKeys.map(e => ({ @@ -215,7 +216,7 @@ export default observer(function FacetedSelector({ width: widthsDebounced[e] || 100, // can be undefined before useEffect update renderCell: (params: GridCellParams) => { const { value } = params - return value ? : '' + return value ? : '' }, })), ] @@ -286,11 +287,11 @@ export default observer(function FacetedSelector({ )} columnVisibilityModel={visible} onColumnVisibilityModelChange={newModel => setVisible(newModel)} - headerHeight={35} + columnHeaderHeight={35} checkboxSelection - disableSelectionOnClick + disableRowSelectionOnClick keepNonExistentRowsSelected - onSelectionModelChange={userSelectedIds => { + onRowSelectionModelChange={userSelectedIds => { if (!useShoppingCart) { const a1 = shownTrackIds const a2 = userSelectedIds as string[] @@ -309,7 +310,7 @@ export default observer(function FacetedSelector({ model.setSelection(tracks) } }} - selectionModel={ + rowSelectionModel={ useShoppingCart ? selection.map(s => s.trackId) : shownTrackIds } columns={columns} diff --git a/plugins/dotplot-view/package.json b/plugins/dotplot-view/package.json index 1492f283741..b942c43012a 100644 --- a/plugins/dotplot-view/package.json +++ b/plugins/dotplot-view/package.json @@ -38,7 +38,7 @@ }, "dependencies": { "@mui/icons-material": "^5.0.1", - "@mui/x-data-grid": "^5.0.1", + "@mui/x-data-grid": "^6.0.1", "@types/file-saver": "^2.0.1", "@types/normalize-wheel": "^1.0.0", "clone": "^2.1.2", diff --git a/plugins/dotplot-view/src/DotplotView/components/WarningDialog.tsx b/plugins/dotplot-view/src/DotplotView/components/WarningDialog.tsx index 9a95b69fafd..dcbfc45ef96 100644 --- a/plugins/dotplot-view/src/DotplotView/components/WarningDialog.tsx +++ b/plugins/dotplot-view/src/DotplotView/components/WarningDialog.tsx @@ -63,7 +63,7 @@ export default observer(function WarningDialog({ diff --git a/plugins/grid-bookmark/package.json b/plugins/grid-bookmark/package.json index bee2fd3d498..b9225d6b77c 100644 --- a/plugins/grid-bookmark/package.json +++ b/plugins/grid-bookmark/package.json @@ -46,7 +46,7 @@ "@jbrowse/plugin-config": "^2.0.0", "@jbrowse/plugin-linear-genome-view": "^2.0.0", "@mui/material": "^5.0.0", - "@mui/x-data-grid": "^5.0.1", + "@mui/x-data-grid": "^6.0.1", "mobx": "^6.0.0", "mobx-react": "^7.0.0", "mobx-state-tree": "^5.0.0", diff --git a/plugins/grid-bookmark/src/GridBookmarkWidget/components/GridBookmarkWidget.tsx b/plugins/grid-bookmark/src/GridBookmarkWidget/components/GridBookmarkWidget.tsx index 4f4763d6b50..581bf014ed1 100644 --- a/plugins/grid-bookmark/src/GridBookmarkWidget/components/GridBookmarkWidget.tsx +++ b/plugins/grid-bookmark/src/GridBookmarkWidget/components/GridBookmarkWidget.tsx @@ -3,7 +3,13 @@ import { observer } from 'mobx-react' import { Link, IconButton, Typography } from '@mui/material' import { makeStyles } from 'tss-react/mui' import { DataGrid, GridCellParams } from '@mui/x-data-grid' -import { getSession, assembleLocString, measureText } from '@jbrowse/core/util' +import { + getSession, + assembleLocString, + measureGridWidth, +} from '@jbrowse/core/util' + +// icons import DeleteIcon from '@mui/icons-material/Delete' // locals @@ -20,13 +26,6 @@ const useStyles = makeStyles()(() => ({ cursor: 'pointer', }, })) - -// creates a coarse measurement of column width, similar to code in -// BaseFeatureDetails -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const measure = (row: any, col: string) => - Math.min(Math.max(measureText(String(row[col]), 14) + 20, 80), 1000) - const BookmarkGrid = observer(({ model }: { model: GridBookmarkModel }) => { const { classes } = useStyles() const [dialogRowNumber, setDialogRowNumber] = useState() @@ -49,68 +48,62 @@ const BookmarkGrid = observer(({ model }: { model: GridBookmarkModel }) => { } }) - const columns = [ - { - field: 'locString', - headerName: 'bookmark link', - width: Math.max(...bookmarkRows.map(row => measure(row, 'locString'))), - renderCell: (params: GridCellParams) => { - const { value } = params - return ( - { - event.preventDefault() - // has own error handling - await navToBookmark(value as string, views, model) - }} - > - {value} - - ) - }, - }, - { - field: 'label', - width: Math.max( - 100, - Math.max(...bookmarkRows.map(row => measure(row, 'label'))), - ), - editable: true, - }, - { - field: 'delete', - width: 30, - renderCell: (params: GridCellParams) => { - const { value } = params - return ( - { - if (value !== null && value !== undefined) { - setDialogRowNumber(+value) - } - }} - > - - - ) - }, - }, - ] - return ( <> { - const { value, id } = args - model.updateBookmarkLabel(id as number, value as string) - }} - disableSelectionOnClick + columns={[ + { + field: 'locString', + headerName: 'bookmark link', + width: measureGridWidth(bookmarkRows.map(row => row.locString)), + renderCell: params => { + const { value } = params + return ( + { + event.preventDefault() + await navToBookmark(value as string, views, model) + }} + > + {value} + + ) + }, + }, + { + field: 'label', + width: measureGridWidth(bookmarkRows.map(row => row.label)), + editable: true, + }, + { + field: 'delete', + width: 30, + renderCell: (params: GridCellParams) => { + const { value } = params + return ( + { + if (value != null) { + setDialogRowNumber(+value) + } + }} + > + + + ) + }, + }, + ]} + onCellEditStop={({ id, value }) => + model.updateBookmarkLabel(id as number, value) + } + disableRowSelectionOnClick /> @@ -135,9 +135,9 @@ export default function VariantSamples(props: { diff --git a/plugins/wiggle/package.json b/plugins/wiggle/package.json index f231cfa8155..cf63620259e 100644 --- a/plugins/wiggle/package.json +++ b/plugins/wiggle/package.json @@ -55,7 +55,7 @@ "@jbrowse/plugin-data-management": "^2.0.0", "@jbrowse/plugin-linear-genome-view": "^2.0.0", "@mui/material": "^5.0.0", - "@mui/x-data-grid": "^5.0.1", + "@mui/x-data-grid": "^6.0.1", "mobx": "^6.0.0", "mobx-react": "^7.0.0", "mobx-state-tree": "^5.0.0", diff --git a/plugins/wiggle/src/MultiLinearWiggleDisplay/components/SetColorDialog.tsx b/plugins/wiggle/src/MultiLinearWiggleDisplay/components/SetColorDialog.tsx index 9d109b2c58f..cec936e42d7 100644 --- a/plugins/wiggle/src/MultiLinearWiggleDisplay/components/SetColorDialog.tsx +++ b/plugins/wiggle/src/MultiLinearWiggleDisplay/components/SetColorDialog.tsx @@ -129,6 +129,11 @@ export default function SetColorDialog({ ) } +interface SortField { + idx: number + field: string | null +} + function SourcesGrid({ rows, onChange, @@ -143,53 +148,11 @@ function SourcesGrid({ // @ts-expect-error const { name: _name, color: _color, baseUri: _baseUri, ...rest } = rows[0] - - // similar to BaseFeatureDetail data-grid for auto-measuring columns - const columns = [ - { - field: 'color', - headerName: 'Color', - renderCell: (params: GridCellParams) => { - const { value, id } = params - return ( - { - const elt = rows.find(f => f.name === id) - if (elt) { - elt.color = c - } - onChange([...rows]) - }} - /> - ) - }, - }, - { - field: 'name', - sortingOrder: [null], - headerName: 'Name', - width: measureGridWidth(rows.map(r => r.name)), - }, - ...Object.keys(rest).map(val => ({ - field: val, - sortingOrder: [null], - renderCell: (params: GridCellParams) => { - const { value } = params - return isUriLocation(value) ? : getStr(value) - }, - // @ts-expect-error - width: measureGridWidth(rows.map(r => r[val])), - })), - ] - - // this helps keep track of the selection, even though it is not used - // anywhere except inside the picker const [widgetColor, setWidgetColor] = useState('blue') - const [currSort, setCurrSort] = useState<{ - idx: number - field: string | null - }>({ idx: 0, field: null }) + const [currSort, setCurrSort] = useState({ + idx: 0, + field: null, + }) return (
@@ -247,12 +210,52 @@ function SourcesGrid({ row.name} checkboxSelection - disableSelectionOnClick - onSelectionModelChange={arg => setSelected(arg as string[])} + disableRowSelectionOnClick + onRowSelectionModelChange={arg => setSelected(arg as string[])} rows={rows} rowHeight={25} - headerHeight={33} - columns={columns} + columnHeaderHeight={33} + columns={[ + { + field: 'color', + headerName: 'Color', + renderCell: params => { + const { value, id } = params + return ( + { + const elt = rows.find(f => f.name === id) + if (elt) { + elt.color = c + } + onChange([...rows]) + }} + /> + ) + }, + }, + { + field: 'name', + sortingOrder: [null], + headerName: 'Name', + width: measureGridWidth(rows.map(r => r.name)), + }, + ...Object.keys(rest).map(val => ({ + field: val, + sortingOrder: [null], + renderCell: (params: GridCellParams) => { + const { value } = params + return isUriLocation(value) ? ( + + ) : ( + getStr(value) + ) + }, + // @ts-ignore + width: measureGridWidth(rows.map(r => r[val])), + })), + ]} sortModel={ [ /* we control the sort as a controlled component using onSortModelChange */ diff --git a/products/jbrowse-desktop/package.json b/products/jbrowse-desktop/package.json index bbe3e4be7ec..d842d2c2192 100644 --- a/products/jbrowse-desktop/package.json +++ b/products/jbrowse-desktop/package.json @@ -77,7 +77,7 @@ "@jbrowse/text-indexing": "^2.4.2", "@mui/icons-material": "^5.0.0", "@mui/material": "^5.10.17", - "@mui/x-data-grid": "^5.0.1", + "@mui/x-data-grid": "^6.0.1", "deepmerge": "^4.2.2", "electron-debug": "^3.0.1", "electron-is-dev": "^2.0.0", diff --git a/products/jbrowse-desktop/src/StartScreen/RecentSessionList.tsx b/products/jbrowse-desktop/src/StartScreen/RecentSessionList.tsx index faf3ea230aa..8b9d9c4a561 100644 --- a/products/jbrowse-desktop/src/StartScreen/RecentSessionList.tsx +++ b/products/jbrowse-desktop/src/StartScreen/RecentSessionList.tsx @@ -1,7 +1,7 @@ import React from 'react' import { IconButton, Link, Tooltip } from '@mui/material' import { makeStyles } from 'tss-react/mui' -import { DataGrid, GridCellParams } from '@mui/x-data-grid' +import { DataGrid } from '@mui/x-data-grid' import PluginManager from '@jbrowse/core/PluginManager' import { format } from 'timeago.js' @@ -17,6 +17,19 @@ const useStyles = makeStyles()({ }, }) +function DateSinceLastUsed({ value }: { value: string }) { + const lastModified = new Date(value) + const now = Date.now() + const oneDayLength = 24 * 60 * 60 * 1000 + return now - lastModified.getTime() < oneDayLength ? ( + +
{format(lastModified)}
+
+ ) : ( + <>{lastModified.toLocaleString('en-US')} + ) +} + export default function RecentSessionsList({ setError, sessions, @@ -31,93 +44,15 @@ export default function RecentSessionsList({ sessions: RecentSessionData[] }) { const { classes } = useStyles() - const columns = [ - { - field: 'rename', - minWidth: 40, - width: 40, - sortable: false, - filterable: false, - headerName: ' ', - renderCell: (params: GridCellParams) => { - return ( - setSessionToRename(params.row as RecentSessionData)} - > - - - - - ) - }, - }, - { - field: 'name', - headerName: 'Session name', - flex: 0.7, - renderCell: (params: GridCellParams) => { - const { value } = params - return ( - { - try { - setPluginManager(await loadPluginManager(params.row.path)) - } catch (e) { - console.error(e) - setError(e) - } - }} - > - {value} - - ) - }, - }, - { - field: 'path', - headerName: 'Session path', - flex: 0.7, - renderCell: (params: GridCellParams) => { - const { value } = params - return ( - -
{value}
-
- ) - }, - }, - { - field: 'lastModified', - headerName: 'Last modified', - renderCell: ({ value }: GridCellParams) => { - if (!value) { - return null - } - const lastModified = new Date(value as string) - const now = Date.now() - const oneDayLength = 24 * 60 * 60 * 1000 - if (now - lastModified.getTime() < oneDayLength) { - return ( - -
{format(lastModified)}
-
- ) - } - return lastModified.toLocaleString('en-US') - }, - width: 150, - }, - ] return (
{ + disableRowSelectionOnClick + onRowSelectionModelChange={args => setSelectedSessions(sessions.filter(s => args.includes(s.path))) - }} + } rows={sessions.map(session => ({ id: session.path, name: session.name, @@ -127,8 +62,77 @@ export default function RecentSessionsList({ path: session.path, }))} rowHeight={25} - headerHeight={33} - columns={columns} + columnHeaderHeight={33} + columns={[ + { + field: 'rename', + minWidth: 40, + width: 40, + sortable: false, + filterable: false, + headerName: ' ', + renderCell: params => { + return ( + { + const { lastModified: updated, ...rest } = params.row + setSessionToRename({ + ...rest, + updated, + }) + }} + > + + + + + ) + }, + }, + { + field: 'name', + headerName: 'Session name', + flex: 0.7, + renderCell: params => { + const { value } = params + return ( + { + try { + setPluginManager(await loadPluginManager(params.row.path)) + } catch (e) { + console.error(e) + setError(e) + } + }} + > + {value as string} + + ) + }, + }, + { + field: 'path', + headerName: 'Session path', + flex: 0.7, + renderCell: params => { + const { value } = params + return ( + +
{value as string}
+
+ ) + }, + }, + { + field: 'lastModified', + headerName: 'Last modified', + renderCell: ({ value }) => + !value ? null : , + width: 150, + }, + ]} />
) diff --git a/products/jbrowse-web/package.json b/products/jbrowse-web/package.json index 44744f7dd86..13427deb353 100644 --- a/products/jbrowse-web/package.json +++ b/products/jbrowse-web/package.json @@ -49,7 +49,7 @@ "@jbrowse/plugin-wiggle": "^2.4.2", "@mui/icons-material": "^5.0.0", "@mui/material": "^5.10.17", - "@mui/x-data-grid": "^5.0.1", + "@mui/x-data-grid": "^6.0.1", "base64-js": "^1.3.0", "clone": "^2.1.2", "copy-to-clipboard": "^3.3.1", diff --git a/yarn.lock b/yarn.lock index 177959f1fc7..2afecb49cec 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1101,7 +1101,7 @@ resolved "https://registry.yarnpkg.com/@babel/regjsgen/-/regjsgen-0.8.0.tgz#f0ba69b075e1f05fb2825b7fad991e7adbb18310" integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA== -"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.0", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.16.3", "@babel/runtime@^7.17.8", "@babel/runtime@^7.17.9", "@babel/runtime@^7.18.3", "@babel/runtime@^7.18.9", "@babel/runtime@^7.20.6", "@babel/runtime@^7.20.7", "@babel/runtime@^7.21.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.0", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.16.3", "@babel/runtime@^7.17.8", "@babel/runtime@^7.17.9", "@babel/runtime@^7.18.3", "@babel/runtime@^7.20.6", "@babel/runtime@^7.20.7", "@babel/runtime@^7.21.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": version "7.21.0" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.21.0.tgz#5b55c9d394e5fcf304909a8b00c07dc217b56673" integrity sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw== @@ -3087,7 +3087,7 @@ resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.2.3.tgz#06faae1c0e2f3a31c86af6f28b3a4a42143670b9" integrity sha512-tZ+CQggbe9Ol7e/Fs5RcKwg/woU+o8DCtOnccX6KmbBc7YrfqMYEYuaIcXHuhpT880QwNkZZ3wQwvtlDFA2yOw== -"@mui/utils@^5.10.3", "@mui/utils@^5.11.13": +"@mui/utils@^5.11.13": version "5.11.13" resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.11.13.tgz#8d7317f221e8973200764820fa7f2a622dbc7150" integrity sha512-5ltA58MM9euOuUcnvwFJqpLdEugc9XFsRR8Gt4zZNb31XzMfSKJPR4eumulyhsOTK1rWf7K4D63NKFPfX0AxqA== @@ -3098,16 +3098,16 @@ prop-types "^15.8.1" react-is "^18.2.0" -"@mui/x-data-grid@^5.0.0", "@mui/x-data-grid@^5.0.1": - version "5.17.26" - resolved "https://registry.yarnpkg.com/@mui/x-data-grid/-/x-data-grid-5.17.26.tgz#1f7fa73dd3986cf052e2fd2cb56eb4678a7bd913" - integrity sha512-eGJq9J0g9cDGLFfMmugOadZx0mJeOd/yQpHwEa5gUXyONS6qF0OhXSWyDOhDdA3l2TOoQzotMN5dY/T4Wl1KYA== +"@mui/x-data-grid@^6.0.1": + version "6.0.4" + resolved "https://registry.yarnpkg.com/@mui/x-data-grid/-/x-data-grid-6.0.4.tgz#e69617ed50ed5497a9f23886eac15c4d3d34ad49" + integrity sha512-SPkxmPhVU0hJEun/Ju5do5CPVzJj4NHT5XEPpfvDyVhHR4p4ax/EiXbtmLBl5d+D/tA8uaLEK0PUQWBLC8JNQA== dependencies: - "@babel/runtime" "^7.18.9" - "@mui/utils" "^5.10.3" + "@babel/runtime" "^7.21.0" + "@mui/utils" "^5.11.13" clsx "^1.2.1" prop-types "^15.8.1" - reselect "^4.1.6" + reselect "^4.1.7" "@ndelangen/get-tarball@^3.0.7": version "3.0.7" @@ -16619,7 +16619,7 @@ requires-port@^1.0.0: resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== -reselect@^4.1.6: +reselect@^4.1.7: version "4.1.7" resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.7.tgz#56480d9ff3d3188970ee2b76527bd94a95567a42" integrity sha512-Zu1xbUt3/OPwsXL46hvOOoQrap2azE7ZQbokq61BQfiXvhewsKDwhMeZjTX9sX0nvw1t/U5Audyn1I9P/m9z0A==