Add support for setting image download resolution in the ERD tool. #6698
							parent
							
								
									c7a6056ee3
								
							
						
					
					
						commit
						abdcd983f6
					
				| 
						 | 
				
			
			@ -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',
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)=>{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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>
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue