mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2026-10-31 08:34:01 -05:00
Supersedes dependabot #9843 and #9888, which must land together because date-pickers v9 requires @mui/material v9 as a peer. @mui/material skipped v8 on npm (7.x -> 9.x), so only v9's breaking changes apply. ## Manifest changes - @mui/material ^7.3.10 -> ^9.0.0 (resolved 9.0.1) - @mui/icons-material ^7.3.10 -> ^9.0.0 (resolved 9.0.1) - @mui/x-date-pickers ^8.28.3 -> ^9.0.2 (resolved 9.2.0) ## Source changes (98 files, mostly mechanical) 1. Two legacy icon imports renamed (v9 removed these in favor of the *Outlined variants): -import ErrorOutlineIcon from '@mui/icons-material/ErrorOutline'; +import ErrorOutlineIcon from '@mui/icons-material/ErrorOutlined'; -import CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline'; +import CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutlined'; Both in web/pgadmin/static/js/Explain/AIInsights.jsx. 2. `styled(Box)` -> `styled('div')` across 50 files. v9's `Box` stopped filtering CSS-property-named keys (flexDirection, marginLeft, etc.) out of the props it forwarded to the DOM, so any `styled(Box)(({theme}) => ({ flexDirection: 'column', ... }))` leaked those CSS keys to the underlying `<div>` as React props. Using `styled('div')` keeps the CSS-in-JS layer working as expected and removes the now-redundant Box layer (every affected styled wrapper was a pure styling container, not using Box's sx-passthrough or component-swap behavior). 3. Box / Stack / Typography / Link / Grid / DialogContentText / TimelineContent / TimelineOppositeContent system props moved to `sx`. v9 removed individual system-prop syntax from these components; `<Box flexGrow={1}>` is now `<Box sx={{flexGrow: 1}}>`. Applied via the official codemod: npx @mui/codemod@latest v9.0.0/system-props pgadmin 65 files transformed, 6 Jinja-templated `.js` files skipped (parse errors, not real JS; no MUI usage in them). 4. One test updated for v9's class-name split. Button's variant+color combo class (`MuiButton-containedPrimary`) is now emitted as two separate classes (`MuiButton-contained` + `MuiButton-colorPrimary`). web/regression/javascript/components/Buttons.spec.js ## Test plan - [x] `yarn install` resolved cleanly - [x] `yarn run test:js-once` -> 140/0/0 suites, 824/0/0 tests - [x] `yarn run linter` -> clean (silent) - [ ] CI matrix (Linux/Mac/Windows) passes - [ ] Visual sweep of main UI surfaces in `yarn start`: login screen, browser tree, query tool, ERD, schema dialogs (table/function/trigger/index), theme switcher (light/dark/high-contrast), file manager, debugger panel, backup/restore dialogs. ## Notes for reviewers The major risk surface for this PR is not API breakage (all caught by jest) but **visual regression**. v9's "sx prop performance" and "deprecated API cleanup" work shifts a few pixels in places — most notably ListItemIcon spacing (which v9 changed from hardcoded `minWidth` to theme spacing). Worth a careful look at menus and toolbars. The other Box-related changes (system props -> sx) preserve behavior 1:1 — they're a pure syntactic migration. `@mui/x-date-pickers`'s legacy `LocalizationProvider` API was removed, but we already use the modern `dateAdapter={AdapterDateFns}` form in `Theme/index.jsx`, so no change needed there.
110 lines
4.2 KiB
React
110 lines
4.2 KiB
React
/////////////////////////////////////////////////////////////
|
|
//
|
|
// pgAdmin 4 - PostgreSQL Tools
|
|
//
|
|
// Copyright (C) 2013 - 2026, The pgAdmin Development Team
|
|
// This software is released under the PostgreSQL Licence
|
|
//
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
import { useEffect, useState } from 'react';
|
|
import { usePgAdmin } from '../../PgAdminProvider';
|
|
import { Badge, Box } from '@mui/material';
|
|
import { QueryToolIcon, RowFilterIcon, ViewDataIcon } from '../../components/ExternalIcon';
|
|
import TerminalRoundedIcon from '@mui/icons-material/TerminalRounded';
|
|
import SearchOutlinedIcon from '@mui/icons-material/SearchOutlined';
|
|
import FilterAltRoundedIcon from '@mui/icons-material/FilterAltRounded';
|
|
import { PgButtonGroup, PgIconButton } from '../../components/Buttons';
|
|
import _ from 'lodash';
|
|
import PropTypes from 'prop-types';
|
|
import CustomPropTypes from '../../custom_prop_types';
|
|
import usePreferences from '../../../../preferences/static/js/store';
|
|
import gettext from 'sources/gettext';
|
|
|
|
function ToolbarButton({menuItem, ...props}) {
|
|
return (
|
|
<PgIconButton title={menuItem?.label??''} {...props} size="xs"
|
|
disabled={menuItem?.isDisabled??true} onClick={()=>menuItem?.callback()} />
|
|
);
|
|
}
|
|
ToolbarButton.propTypes = {
|
|
menuItem: PropTypes.object,
|
|
icon: CustomPropTypes.children,
|
|
};
|
|
|
|
export default function ObjectExplorerToolbar() {
|
|
const [menus, setMenus] = useState({
|
|
'query_tool': undefined,
|
|
'view_all_rows_context': undefined,
|
|
'view_filtered_rows_context': undefined,
|
|
'search_objects': undefined,
|
|
'psql': undefined,
|
|
});
|
|
const browserPref = usePreferences().getPreferencesForModule('browser');
|
|
const [hasFilters, setHasFilters] = useState(false);
|
|
const pgAdmin = usePgAdmin();
|
|
|
|
const checkMenuState = ()=>{
|
|
const viewMenus = pgAdmin.Browser.MainMenus.
|
|
find((m)=>(m.name=='object'))?.
|
|
menuItems?.
|
|
find((m)=>(m.name=='view_data'))?.
|
|
menu_items;
|
|
|
|
const toolsMenus = pgAdmin.Browser.MainMenus.
|
|
find((m)=>(m.name=='tools'))?.
|
|
menuItems;
|
|
|
|
setMenus({
|
|
'query_tool': toolsMenus?.find((m)=>(m.name=='query_tool')),
|
|
'view_all_rows_context': viewMenus?.find((m)=>(m.name=='view_all_rows_context_' + m.node)),
|
|
'view_filtered_rows_context': viewMenus?.find((m)=>(m.name=='view_filtered_rows_context_' + m.node)),
|
|
'search_objects': toolsMenus?.find((m)=>(m.name=='search_objects')),
|
|
'psql': toolsMenus?.find((m)=>(m.name=='psql'))
|
|
});
|
|
};
|
|
|
|
useEffect(()=>{
|
|
const deregister = pgAdmin.Browser.Events.on('pgadmin:enable-disable-menu-items', _.debounce(checkMenuState, 100));
|
|
|
|
const deregisterFilter = pgAdmin.Browser.Events.on('pgadmin:object-explorer:filter:apply', (hasFilters)=>{
|
|
setHasFilters(hasFilters);
|
|
});
|
|
checkMenuState();
|
|
return ()=>{
|
|
deregister();
|
|
deregisterFilter();
|
|
};
|
|
}, []);
|
|
|
|
return (
|
|
<Box
|
|
sx={{
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
gap: '2px'
|
|
}}>
|
|
<PgButtonGroup size="small">
|
|
<ToolbarButton icon={
|
|
<Badge badgeContent=" " overlap="circular" variant='dot' color="success" invisible={!hasFilters}>
|
|
<FilterAltRoundedIcon />
|
|
</Badge>
|
|
} menuItem={{
|
|
label: gettext('Filter Objects'),
|
|
isDisabled: false,
|
|
callback: () => {
|
|
pgAdmin.Browser.Events.trigger('pgadmin:object-explorer:filter:show');
|
|
}
|
|
}} id="filter-objects" isDropdown />
|
|
<ToolbarButton icon={<QueryToolIcon />} menuItem={menus['query_tool']} shortcut={browserPref?.sub_menu_query_tool} />
|
|
<ToolbarButton icon={<ViewDataIcon />} menuItem={menus['view_all_rows_context'] ??
|
|
{label :gettext('All Rows')}}
|
|
shortcut={browserPref?.sub_menu_view_data} />
|
|
<ToolbarButton icon={<RowFilterIcon />} menuItem={menus['view_filtered_rows_context'] ?? { label : gettext('Filtered Rows...')}} />
|
|
<ToolbarButton icon={<SearchOutlinedIcon style={{height: '1.4rem'}} />} menuItem={menus['search_objects']} shortcut={browserPref?.sub_menu_search_objects} />
|
|
{!_.isUndefined(menus['psql']) && <ToolbarButton icon={<TerminalRoundedIcon style={{height: '1.4rem'}}/>} menuItem={menus['psql']} />}
|
|
</PgButtonGroup>
|
|
</Box>
|
|
);
|
|
}
|