Add support for setting image download resolution in the ERD tool. #6698

pull/9299/head
Aditya Toshniwal 2025-10-29 14:57:20 +05:30 committed by GitHub
parent c7a6056ee3
commit abdcd983f6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 74 additions and 37 deletions

View File

@ -431,6 +431,19 @@ class ERDModule(PgAdminModule):
)
)
self.preference.register(
'options', 'image_pixel_ratio',
gettext('Image Download Resolution'), 'radioModern', '1',
category_label=PREF_LABEL_OPTIONS, options=[
{'label': gettext('Good'), 'value': '1'},
{'label': gettext('High'), 'value': '3'},
{'label': gettext('Very High'), 'value': '5'},
],
help_str=gettext(
'Higher values will use higher memory and slower rendering.'
),
)
self.preference.register(
'options',
'sql_with_drop',

View File

@ -103,6 +103,16 @@ const StyledBox = styled(Box)(({theme})=>({
'& .ERDTool-html2canvasReset': {
backgroundImage: 'none !important',
overflow: 'auto !important',
textRendering: 'geometricPrecision',
'& .TableNode-tableToolbar': {
visibility: 'hidden',
},
'& .TableNode-tableContent': {
borderTopLeftRadius: theme.shape.borderRadius,
borderTopRightRadius: theme.shape.borderRadius,
},
}
}));
@ -163,7 +173,6 @@ export default class ERDTool extends React.Component {
this.keyboardActionObj = null;
this.erdDialogs = new ERDDialogs(this.context);
this.apiObj = getApiInstance();
this.preferencesStore = usePreferences.getState();
this.fmUtilsObj = new FileManagerUtils(this.apiObj, {modal: this.context});
this.restore = props.params.restore == 'true';
this.eventBus = new EventBus();
@ -328,17 +337,25 @@ export default class ERDTool extends React.Component {
this.setLoading(gettext('Preparing...'));
this.registerEvents();
this.diagramContainerRef.current?.focus();
const erdPref = this.preferencesStore.getPreferencesForModule('erd');
const erdPref = usePreferences.getState().getPreferencesForModule('erd');
this.setState({
preferences: erdPref,
is_new_tab: (this.preferencesStore.getPreferencesForModule('browser').new_browser_tab_open || '')
is_new_tab: (usePreferences.getState().getPreferencesForModule('browser').new_browser_tab_open || '')
.includes('erd_tool'),
is_close_tab_warning: this.preferencesStore.getPreferencesForModule('browser').confirm_on_refresh_close,
is_close_tab_warning: usePreferences.getState().getPreferencesForModule('browser').confirm_on_refresh_close,
cardinality_notation: erdPref.cardinality_notation,
}, ()=>{
this.registerKeyboardShortcuts();
if(this.state.current_file)this.setTitle(this.state.current_file);
});
usePreferences.subscribe((state)=>{
this.setState({
preferences: state.getPreferencesForModule('erd'),
is_close_tab_warning: state.getPreferencesForModule('browser').confirm_on_refresh_close,
});
});
this.registerModelEvents();
this.realignGrid({
backgroundSize: '45px 45px',
@ -808,7 +825,7 @@ export default class ERDTool extends React.Component {
height = 32766;
isCut = true;
}
toPng(this.canvasEle, {width, height})
toPng(this.canvasEle, {width, height, pixelRatio: this.state.preferences.image_pixel_ratio || 1})
.then((dataUrl)=>{
DownloadUtils.downloadBase64UrlData(dataUrl, `${this.getCurrentProjectName()}.png`);
}).catch((err)=>{

View File

@ -27,7 +27,7 @@ import { Box } from '@mui/material';
import { styled } from '@mui/material/styles';
const TYPE = 'table';
const TABLE_WIDTH = 175;
const TABLE_WIDTH = 180;
export class TableNodeModel extends DefaultNodeModel {
constructor({otherInfo, ...options}) {
@ -214,16 +214,31 @@ RowIcon.propTypes = {
const StyledDiv = styled('div')(({theme})=>({
'&.TableNode-tableNode': {
backgroundColor: theme.palette.background.default,
color: theme.palette.text.primary,
...theme.mixins.panelBorder.all,
borderRadius: theme.shape.borderRadius,
position: 'relative',
width: `${TABLE_WIDTH}px`,
fontSize: '0.8em',
'& div:last-child': {
borderBottomLeftRadius: 'inherit',
borderBottomRightRadius: 'inherit',
'& .TableNode-tableContent': {
backgroundColor: theme.palette.background.default,
...theme.mixins.panelBorder.all,
borderBottomLeftRadius: theme.shape.borderRadius,
borderBottomRightRadius: theme.shape.borderRadius,
},
'& .TableNode-tableToolbar': {
background: theme.otherVars.editorToolbarBg,
...theme.mixins.panelBorder.all,
borderBottom: 'none',
borderTopLeftRadius: theme.shape.borderRadius,
borderTopRightRadius: theme.shape.borderRadius,
padding: '0.125rem 0.25rem',
display: 'flex',
'& .TableNode-noteBtn': {
marginLeft: 'auto',
backgroundColor: theme.palette.warning.main,
color: theme.palette.warning.contrastText,
},
},
'& .TableNode-tableSection': {
...theme.mixins.panelBorder.bottom,
@ -237,16 +252,6 @@ const StyledDiv = styled('div')(({theme})=>({
color: theme.palette.error.main,
},
},
'&.TableNode-tableToolbar': {
background: theme.otherVars.editorToolbarBg,
borderTopLeftRadius: 'inherit',
borderTopRightRadius: 'inherit',
},
'& .TableNode-noteBtn': {
marginLeft: 'auto',
backgroundColor: theme.palette.warning.main,
color: theme.palette.warning.contrastText,
},
},
'& .TableNode-columnSection': {
display:'flex',
@ -370,7 +375,7 @@ export class TableNodeWidget extends React.Component {
return (
<StyledDiv className={['TableNode-tableNode', (this.props.node.isSelected() ? 'TableNode-tableNodeSelected': '')].join(' ')}
onDoubleClick={()=>{this.props.node.fireEvent({}, 'editTable');}} style={styles}>
<div className={'TableNode-tableSection TableNode-tableToolbar'}>
<div className={'TableNode-tableToolbar'}>
<PgIconButton size="xs" title={gettext('Show Details')} icon={this.state.show_details ? <VisibilityRoundedIcon /> : <VisibilityOffRoundedIcon />}
onClick={this.toggleShowDetails} onDoubleClick={(e)=>{e.stopPropagation();}} />
{this.props.node.getNote() &&
@ -381,24 +386,26 @@ export class TableNodeWidget extends React.Component {
}}
/>}
</div>
{tableMetaData.is_promise &&
<div className='TableNode-tableContent'>
{tableMetaData.is_promise &&
<div className='TableNode-tableSection'>
{!tableMetaData.data_failed && <div className='TableNode-tableNameText'>{gettext('Fetching...')}</div>}
{tableMetaData.data_failed && <div className={'TableNode-tableNameText TableNode-error'}>{gettext('Failed to get data. Please delete this table.')}</div>}
</div>}
{!tableMetaData.is_promise && <>
<div className='TableNode-tableSection'>
<RowIcon icon={SchemaIcon}/>
<div className='TableNode-tableNameText' data-test="schema-name">{tableData.schema}</div>
</div>
<div className='TableNode-tableSection'>
<RowIcon icon={TableIcon} />
<div className='TableNode-tableNameText' data-test="table-name">{tableData.name}</div>
</div>
{tableData.columns.length > 0 && <div>
{_.map(tableData.columns, (col)=>this.generateColumn(col, localFkCols, localUkCols))}
</div>}
</>}
{!tableMetaData.is_promise && <>
<div className='TableNode-tableSection'>
<RowIcon icon={SchemaIcon}/>
<div className='TableNode-tableNameText' data-test="schema-name">{tableData.schema}</div>
</div>
<div className='TableNode-tableSection'>
<RowIcon icon={TableIcon} />
<div className='TableNode-tableNameText' data-test="table-name">{tableData.name}</div>
</div>
{tableData.columns.length > 0 && <div>
{_.map(tableData.columns, (col)=>this.generateColumn(col, localFkCols, localUkCols))}
</div>}
</>}
</div>
</StyledDiv>
);
}