diff --git a/docs/en_US/erd_tool.rst b/docs/en_US/erd_tool.rst index 39c7f1f26..bc35dcc1b 100644 --- a/docs/en_US/erd_tool.rst +++ b/docs/en_US/erd_tool.rst @@ -135,18 +135,21 @@ Utility Options :class: longtable :widths: 1 4 1 - +----------------------+---------------------------------------------------------------------------------------------------+----------------+ - | Icon | Behavior | Shortcut | - +======================+===================================================================================================+================+ - | *Add/Edit note* | Click this button to make notes on tables nodes while designing the database. | Option/Alt + | - | | | Ctrl + N | - +----------------------+---------------------------------------------------------------------------------------------------+----------------+ - | *Auto align* | Click this button to auto align all tables and links to make it look more cleaner. | Option/Alt + | - | | | Ctrl + L | - +----------------------+---------------------------------------------------------------------------------------------------+----------------+ - | *Show details* | Click this button to toggle the column details visibility. It allows you to show few or more | Option/Alt + | - | | column details. | Shift + D | - +----------------------+---------------------------------------------------------------------------------------------------+----------------+ + +-------------------------+------------------------------------------------------------------------------------------------+----------------+ + | Icon | Behavior | Shortcut | + +=========================+================================================================================================+================+ + | *Add/Edit note* | Click this button to make notes on tables nodes while designing the database. | Option/Alt + | + | | | Ctrl + N | + +-------------------------+------------------------------------------------------------------------------------------------+----------------+ + | *Auto align* | Click this button to auto align all tables and links to make it look more cleaner. | Option/Alt + | + | | | Ctrl + L | + +-------------------------+------------------------------------------------------------------------------------------------+----------------+ + | *Show details* | Click this button to toggle the column details visibility. It allows you to show few or more | Option/Alt + | + | | column details. | Shift + D | + +-------------------------+------------------------------------------------------------------------------------------------+----------------+ + | *Cardinality Notation* | Change the cardinality notation format used to present relationship links. Options available | | + | | are - Crow's Foot Notation and Chen Notation. | | + +-------------------------+------------------------------------------------------------------------------------------------+----------------+ Zoom Options ************ diff --git a/docs/en_US/images/erd_tool.png b/docs/en_US/images/erd_tool.png index c641d121d..6665bfa96 100644 Binary files a/docs/en_US/images/erd_tool.png and b/docs/en_US/images/erd_tool.png differ diff --git a/docs/en_US/images/erd_tool_toolbar.png b/docs/en_US/images/erd_tool_toolbar.png index ecef47933..8d6dcf282 100644 Binary files a/docs/en_US/images/erd_tool_toolbar.png and b/docs/en_US/images/erd_tool_toolbar.png differ diff --git a/web/pgadmin/tools/erd/__init__.py b/web/pgadmin/tools/erd/__init__.py index a003d0b5c..2a1ed13d5 100644 --- a/web/pgadmin/tools/erd/__init__.py +++ b/web/pgadmin/tools/erd/__init__.py @@ -400,6 +400,31 @@ class ERDModule(PgAdminModule): ) ) + self.preference.register( + 'options', 'cardinality_notation', + gettext('Cardinality Notation'), 'radioModern', 'crows', + category_label=PREF_LABEL_OPTIONS, options=[ + {'label': gettext('Crow\'s foot'), 'value': 'crows'}, + {'label': gettext('Chen'), 'value': 'chen'}, + ], + help_str=gettext( + 'Notation to be used to present cardinality.' + ) + ) + + self.preference.register( + 'options', + 'sql_with_drop', + gettext('SQL With DROP Table'), + 'boolean', + False, + category_label=PREF_LABEL_OPTIONS, + help_str=gettext( + 'If enabled, the SQL generated by the ERD Tool will add ' + 'DROP table DDL before each CREATE table DDL.' + ) + ) + blueprint = ERDModule(MODULE_NAME, __name__, static_url_path='/static') diff --git a/web/pgadmin/tools/erd/static/js/erd_tool/components/ERDTool.jsx b/web/pgadmin/tools/erd/static/js/erd_tool/components/ERDTool.jsx index 89448cd57..47fa231b9 100644 --- a/web/pgadmin/tools/erd/static/js/erd_tool/components/ERDTool.jsx +++ b/web/pgadmin/tools/erd/static/js/erd_tool/components/ERDTool.jsx @@ -141,7 +141,7 @@ class ERDTool extends React.Component { _.bindAll(this, ['onLoadDiagram', 'onSaveDiagram', 'onSaveAsDiagram', 'onSQLClick', 'onImageClick', 'onAddNewNode', 'onEditTable', 'onCloneNode', 'onDeleteNode', 'onNoteClick', 'onNoteClose', 'onOneToManyClick', 'onManyToManyClick', 'onAutoDistribute', 'onDetailsToggle', - 'onDetailsToggle', 'onChangeColors', 'onHelpClick', 'onDropNode', 'onBeforeUnload', + 'onChangeColors', 'onHelpClick', 'onDropNode', 'onBeforeUnload', 'onNotationChange', ]); this.diagram.zoomToFit = this.diagram.zoomToFit.bind(this.diagram); @@ -293,11 +293,13 @@ class ERDTool extends React.Component { this.setLoading(gettext('Preparing...')); this.registerEvents(); + const erdPref = this.props.pgWindow.pgAdmin.Browser.get_preferences_for_module('erd'); this.setState({ - preferences: this.props.pgWindow.pgAdmin.Browser.get_preferences_for_module('erd'), + preferences: erdPref, is_new_tab: (this.props.pgWindow.pgAdmin.Browser.get_preferences_for_module('browser').new_browser_tab_open || '') .includes('erd_tool'), is_close_tab_warning: this.props.pgWindow.pgAdmin.Browser.get_preferences_for_module('browser').confirm_on_refresh_close, + cardinality_notation: erdPref.cardinality_notation, }, ()=>{ this.registerKeyboardShortcuts(); this.setTitle(this.state.current_file); @@ -559,6 +561,10 @@ class ERDTool extends React.Component { }); } + onNotationChange(e) { + this.setState({cardinality_notation: e.value}); + } + onHelpClick() { let url = url_for('help.static', {'filename': 'erd_tool.html'}); if (this.props.pgWindow) { @@ -948,12 +954,17 @@ class ERDTool extends React.Component { fgcolor={this.props.params.fgcolor} title={this.props.params.title}/>
{e.preventDefault();}}> - {this.canvasEle = ele?.ref?.current;}} engine={this.diagram.getEngine()} /> + + {this.canvasEle = ele?.ref?.current;}} engine={this.diagram.getEngine()} /> +
); @@ -981,3 +992,5 @@ ERDTool.propTypes = { panel: PropTypes.object, classes: PropTypes.object, }; + +export const ERDCanvasSettings = React.createContext({}); diff --git a/web/pgadmin/tools/erd/static/js/erd_tool/components/MainToolBar.jsx b/web/pgadmin/tools/erd/static/js/erd_tool/components/MainToolBar.jsx index 2c95a9622..beb09465d 100644 --- a/web/pgadmin/tools/erd/static/js/erd_tool/components/MainToolBar.jsx +++ b/web/pgadmin/tools/erd/static/js/erd_tool/components/MainToolBar.jsx @@ -27,6 +27,7 @@ import VisibilityOffRoundedIcon from '@material-ui/icons/VisibilityOffRounded'; import ImageRoundedIcon from '@material-ui/icons/ImageRounded'; import FormatColorFillRoundedIcon from '@material-ui/icons/FormatColorFillRounded'; import FormatColorTextRoundedIcon from '@material-ui/icons/FormatColorTextRounded'; +import AccountTreeOutlinedIcon from '@material-ui/icons/AccountTreeOutlined'; import { PgMenu, PgMenuItem, usePgMenuGroup } from '../../../../../../static/js/components/Menu'; import gettext from 'sources/gettext'; @@ -69,7 +70,7 @@ const useStyles = makeStyles((theme)=>({ }), })); -export function MainToolBar({preferences, eventBus, fillColor, textColor}) { +export function MainToolBar({preferences, eventBus, fillColor, textColor, notation, onNotationChange}) { const classes = useStyles({fillColor,textColor}); const theme = useTheme(); const [buttonsDisabled, setButtonsDisabled] = useState({ @@ -86,6 +87,7 @@ export function MainToolBar({preferences, eventBus, fillColor, textColor}) { const {openMenuName, toggleMenu, onMenuClose} = usePgMenuGroup(); const saveAsMenuRef = React.useRef(null); const sqlMenuRef = React.useRef(null); + const notationMenuRef = React.useRef(null); const isDirtyRef = React.useRef(null); const [checkedMenuItems, setCheckedMenuItems] = React.useState({}); const modal = useModal(); @@ -283,6 +285,9 @@ export function MainToolBar({preferences, eventBus, fillColor, textColor}) { eventBus.fireEvent(ERD_EVENTS.TOGGLE_DETAILS); setShowDetails((prev)=>!prev); }} /> + } + name="menu-notation" ref={notationMenuRef} onClick={toggleMenu} /> } @@ -323,6 +328,16 @@ export function MainToolBar({preferences, eventBus, fillColor, textColor}) { > {gettext('With DROP Table')} + + {gettext('Crow\'s Foot Notation')} + {gettext('Chen Notation')} + ); } @@ -332,6 +347,8 @@ MainToolBar.propTypes = { eventBus: PropTypes.object, fillColor: PropTypes.string, textColor: PropTypes.string, + notation: PropTypes.string, + onNotationChange: PropTypes.func, }; const ColorButton = withColorPicker(PgIconButton); diff --git a/web/pgadmin/tools/erd/static/js/erd_tool/links/OneToManyLink.jsx b/web/pgadmin/tools/erd/static/js/erd_tool/links/OneToManyLink.jsx index 50c1bfea0..bb9e307e8 100644 --- a/web/pgadmin/tools/erd/static/js/erd_tool/links/OneToManyLink.jsx +++ b/web/pgadmin/tools/erd/static/js/erd_tool/links/OneToManyLink.jsx @@ -7,7 +7,7 @@ // ////////////////////////////////////////////////////////////// -import React, { forwardRef } from 'react'; +import React, { forwardRef, useContext } from 'react'; import { RightAngleLinkModel, RightAngleLinkWidget, @@ -21,6 +21,7 @@ import _ from 'lodash'; import PropTypes from 'prop-types'; import { makeStyles } from '@material-ui/core'; import clsx from 'clsx'; +import { ERDCanvasSettings } from '../components/ERDTool'; export const POINTER_SIZE = 30; @@ -81,6 +82,7 @@ export class OneToManyLinkModel extends RightAngleLinkModel { const useStyles = makeStyles((theme)=>({ svgLink: { stroke: theme.palette.text.primary, + fontSize: '0.8em', }, '@keyframes svgLinkSelected': { 'from': { strokeDashoffset: 24}, @@ -99,15 +101,37 @@ const useStyles = makeStyles((theme)=>({ } })); -const CustomLinkEndWidget = props => { +function ChenNotation({rotation, type}) { + const classes = useStyles(); + const textX = Math.sign(rotation) > 0 ? -14 : 8; + const textY = -5; + return ( + <> + + {type == 'one' ? '1' : 'N'} + + + + ); +} +ChenNotation.propTypes = { + rotation: PropTypes.number, + type: PropTypes.string, +}; + +function CustomLinkEndWidget(props) { const { point, rotation, tx, ty, type } = props; const classes = useStyles(); + const settings = useContext(ERDCanvasSettings); const svgForType = (itype) => { + if(settings.cardinality_notation == 'chen') { + return ; + } if(itype == 'many') { return ( <> - + ); @@ -127,7 +151,7 @@ const CustomLinkEndWidget = props => { ); -}; +} CustomLinkEndWidget.propTypes = { point: PropTypes.instanceOf(PointModel).isRequired, diff --git a/web/pgadmin/tools/erd/static/js/erd_tool/nodes/TableNode.jsx b/web/pgadmin/tools/erd/static/js/erd_tool/nodes/TableNode.jsx index cc7751240..3e37393d7 100644 --- a/web/pgadmin/tools/erd/static/js/erd_tool/nodes/TableNode.jsx +++ b/web/pgadmin/tools/erd/static/js/erd_tool/nodes/TableNode.jsx @@ -202,6 +202,17 @@ const styles = (theme)=>({ padding: '0.125rem 0.25rem', display: 'flex', }, + columnSection: { + display:'flex', + width: '100%' , + ...theme.mixins.panelBorder.bottom, + }, + columnName: { + display:'flex', + width: '100%' , + padding: '0.125rem 0.25rem', + wordBreak: 'break-all', + }, tableToolbar: { background: theme.otherVars.editorToolbarBg, borderTopLeftRadius: 'inherit', @@ -269,11 +280,11 @@ class TableNodeWidgetRaw extends React.Component { const {classes} = this.props; return ( -
+ {this.generatePort(leftPort)} - + {col.name}  @@ -284,7 +295,7 @@ class TableNodeWidgetRaw extends React.Component { {this.generatePort(rightPort)} -
+ ); } diff --git a/web/regression/javascript/erd/erd_core_spec.js b/web/regression/javascript/erd/erd_core_spec.js index 7a0d6f2ab..faed0e85e 100644 --- a/web/regression/javascript/erd/erd_core_spec.js +++ b/web/regression/javascript/erd/erd_core_spec.js @@ -291,13 +291,6 @@ describe('ERDCore', ()=>{ ])); }); - it('dagreDistributeNodes', ()=>{ - spyOn(erdCoreObj.dagre_engine, 'redistribute'); - erdCoreObj.dagreDistributeNodes(); - expect(erdEngine.getLinkFactories().getFactory().calculateRoutingMatrix).toHaveBeenCalled(); - expect(erdCoreObj.dagre_engine.redistribute).toHaveBeenCalledWith(erdEngine.getModel()); - }); - it('zoomIn', ()=>{ spyOn(erdEngine.getModel(), 'getZoomLevel').and.returnValue(100); spyOn(erdCoreObj, 'repaint');