diff --git a/docs/en_US/erd_tool.rst b/docs/en_US/erd_tool.rst index ea1a8c81583..409ce669058 100644 --- a/docs/en_US/erd_tool.rst +++ b/docs/en_US/erd_tool.rst @@ -86,6 +86,9 @@ Editing Options +----------------------+---------------------------------------------------------------------------------------------------+----------------+ | Icon | Behavior | Shortcut | +======================+===================================================================================================+================+ + | *Search table* | Click to search for a table in the diagram. Selecting a table from the search results will bring | Option/Alt + | + | | it into view and highlight it. | Ctrl + F | + +----------------------+---------------------------------------------------------------------------------------------------+----------------+ | *Add table* | Click this button to add a new table to the diagram. On clicking, this will open a table dialog | Option/Alt + | | | where you can put the table details. | Ctrl + A | +----------------------+---------------------------------------------------------------------------------------------------+----------------+ @@ -109,11 +112,14 @@ Table Relationship Options +----------------------+---------------------------------------------------------------------------------------------------+----------------+ | Icon | Behavior | Shortcut | +======================+===================================================================================================+================+ - | *1M* | Click this button to open a one-to-many relationship dialog to add a relationship between the | Option/Alt + | + | *1-1* | Click this button to open a one-to-one relationship dialog to add a relationship between the | Option/Alt + | + | | two tables. The selected table becomes the referencing table. | Ctrl + B | + +----------------------+---------------------------------------------------------------------------------------------------+----------------+ + | *1-M* | Click this button to open a one-to-many relationship dialog to add a relationship between the | Option/Alt + | | | two tables. The selected table becomes the referencing table and will have the *many* endpoint of | Ctrl + O | | | the link. | | +----------------------+---------------------------------------------------------------------------------------------------+----------------+ - | *MM* | Click this button to open a many-to-many relationship dialog to add a relationship between the | Option/Alt + | + | *M-M* | Click this button to open a many-to-many relationship dialog to add a relationship between the | Option/Alt + | | | two tables. This option will create a new table based on the selected columns for the two relating| Ctrl + M | | | tables and link them. | | +----------------------+---------------------------------------------------------------------------------------------------+----------------+ diff --git a/docs/en_US/images/erd_tool.png b/docs/en_US/images/erd_tool.png index 6665bfa9607..1b9dc966e55 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 8d6dcf282cf..9e4a12b536c 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/docs/en_US/release_notes_9_10.rst b/docs/en_US/release_notes_9_10.rst index c2b6198161d..e6f36e9ebd6 100644 --- a/docs/en_US/release_notes_9_10.rst +++ b/docs/en_US/release_notes_9_10.rst @@ -20,6 +20,7 @@ Bundled PostgreSQL Utilities New features ************ + | `Issue #4306 `_ - Added the ability to search for tables and automatically bring them into view in the ERD tool. | `Issue #6698 `_ - Add support for setting image download resolution in the ERD tool. | `Issue #7885 `_ - Add support for displaying detailed Citus query plans instead of 'Custom Scan' placeholder. | `Issue #8912 `_ - Add support for formatting .pgerd ERD project file. @@ -34,4 +35,6 @@ Bug fixes | `Issue #8504 `_ - Fixed an issue where data output column resize is not sticking in Safari. | `Issue #9117 `_ - Fixed an issue where Schema Diff does not ignore Tablespace for indexes. + | `Issue #9132 `_ - Fixed an issue where the 2FA window redirected to the login page after session expiration. + | `Issue #9240 `_ - Fixed an issue where the Debian build process failed with a "Sphinx module not found" error when using a Python virtual environment. | `Issue #9304 `_ - Fixed an issue that prevented assigning multiple users to an RLS policy. \ No newline at end of file diff --git a/web/pgadmin/static/js/helpers/ModalProvider.jsx b/web/pgadmin/static/js/helpers/ModalProvider.jsx index b4ef9ffb086..3d686018851 100644 --- a/web/pgadmin/static/js/helpers/ModalProvider.jsx +++ b/web/pgadmin/static/js/helpers/ModalProvider.jsx @@ -295,7 +295,7 @@ const StyleDialog = styled(Dialog)(({theme}) => ({ }, })); -function ModalContainer({ id, title, content, dialogHeight, dialogWidth, onClose, fullScreen = false, isFullWidth = false, showFullScreen = false, isResizeable = false, minHeight = MIN_HEIGHT, minWidth = MIN_WIDTH, showTitle=true }) { +function ModalContainer({ id, title, content, dialogHeight, dialogWidth, onClose, fullScreen = false, isFullWidth = false, showFullScreen = false, isResizeable = false, minHeight = MIN_HEIGHT, minWidth = MIN_WIDTH, showTitle=true, ...props }) { let useModalRef = useModal(); let closeModal = (_e, reason) => { if(reason == 'backdropClick' && showTitle) { @@ -321,6 +321,7 @@ function ModalContainer({ id, title, content, dialogHeight, dialogWidth, onClose fullScreen={isFullScreen} fullWidth={isFullWidth} disablePortal + {...props} > { showTitle && diff --git a/web/pgadmin/tools/erd/__init__.py b/web/pgadmin/tools/erd/__init__.py index 126028b6875..f8d8d2a40a2 100644 --- a/web/pgadmin/tools/erd/__init__.py +++ b/web/pgadmin/tools/erd/__init__.py @@ -158,6 +158,24 @@ def register_preferences(self): fields=shortcut_fields ) + self.preference.register( + 'keyboard_shortcuts', + 'search_table', + gettext('Search table'), + 'keyboardshortcut', + { + 'alt': True, + 'shift': False, + 'control': True, + 'key': { + 'key_code': 70, + 'char': 'f' + } + }, + category_label=PREF_LABEL_KEYBOARD_SHORTCUTS, + fields=shortcut_fields + ) + self.preference.register( 'keyboard_shortcuts', 'add_table', diff --git a/web/pgadmin/tools/erd/static/js/erd_tool/ERDConstants.js b/web/pgadmin/tools/erd/static/js/erd_tool/ERDConstants.js index e9b7af1f951..e8954436626 100644 --- a/web/pgadmin/tools/erd/static/js/erd_tool/ERDConstants.js +++ b/web/pgadmin/tools/erd/static/js/erd_tool/ERDConstants.js @@ -4,10 +4,13 @@ export const ERD_EVENTS = { TRIGGER_SHOW_SQL: 'TRIGGER_SHOW_SQL', SHOW_SQL: 'SHOW_SQL', DOWNLOAD_IMAGE: 'DOWNLOAD_IMAGE', + + SEARCH_NODE: 'SEARCH_NODE', ADD_NODE: 'ADD_NODE', EDIT_NODE: 'EDIT_NODE', CLONE_NODE: 'CLONE_NODE', DELETE_NODE: 'DELETE_NODE', + SHOW_NOTE: 'SHOW_NOTE', ONE_TO_ONE: 'ONE_TO_ONE', ONE_TO_MANY: 'ONE_TO_MANY', 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 28651f70008..f2e201ff93e 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 @@ -42,6 +42,7 @@ import { useApplicationState } from '../../../../../../settings/static/Applicati import { connectServerModal, connectServer } from '../../../../../sqleditor/static/js/components/connectServer'; import { useEffect } from 'react'; import { FileManagerUtils } from '../../../../../../misc/file_manager/static/js/components/FileManager'; +import SearchNode from './SearchNode'; /* Custom react-diagram action for keyboard events */ export class KeyboardShortcutAction extends Action { @@ -178,9 +179,9 @@ export default class ERDTool extends React.Component { this.eventBus = new EventBus(); _.bindAll(this, ['onLoadDiagram', 'onSaveDiagram', 'onSQLClick', - 'onImageClick', 'onAddNewNode', 'onEditTable', 'onCloneNode', 'onDeleteNode', 'onNoteClick', + 'onImageClick', 'onSearchNode', 'onAddNewNode', 'onEditTable', 'onCloneNode', 'onDeleteNode', 'onNoteClick', 'onNoteClose', 'onOneToOneClick', 'onOneToManyClick', 'onManyToManyClick', 'onAutoDistribute', 'onDetailsToggle', - 'onChangeColors', 'onDropNode', 'onNotationChange', 'closePanel' + 'onChangeColors', 'onDropNode', 'onNotationChange', 'closePanel', 'scrollToNode' ]); this.diagram.zoomToFit = this.diagram.zoomToFit.bind(this.diagram); @@ -249,6 +250,7 @@ export default class ERDTool extends React.Component { this.eventBus.registerListener(ERD_EVENTS.SAVE_DIAGRAM, this.onSaveDiagram); this.eventBus.registerListener(ERD_EVENTS.SHOW_SQL, this.onSQLClick); this.eventBus.registerListener(ERD_EVENTS.DOWNLOAD_IMAGE, this.onImageClick); + this.eventBus.registerListener(ERD_EVENTS.SEARCH_NODE, this.onSearchNode); this.eventBus.registerListener(ERD_EVENTS.ADD_NODE, this.onAddNewNode); this.eventBus.registerListener(ERD_EVENTS.EDIT_NODE, this.onEditTable); this.eventBus.registerListener(ERD_EVENTS.CLONE_NODE, this.onCloneNode); @@ -285,6 +287,9 @@ export default class ERDTool extends React.Component { [this.state.preferences.download_image, ()=>{ this.eventBus.fireEvent(ERD_EVENTS.DOWNLOAD_IMAGE); }], + [this.state.preferences.search_table, ()=>{ + this.eventBus.fireEvent(ERD_EVENTS.SEARCH_NODE); + }], [this.state.preferences.add_table, ()=>{ this.eventBus.fireEvent(ERD_EVENTS.ADD_NODE); }], @@ -488,12 +493,69 @@ export default class ERDTool extends React.Component { } } + scrollToNode(node) { + const engine = this.diagram.getEngine(); + const model = engine.getModel(); + const container = this.canvasEle; + if (!node || !container) return; + + const { x, y } = node.getPosition(); + const zoom = model.getZoomLevel() / 100; + const offsetX = model.getOffsetX(); + const offsetY = model.getOffsetY(); + + const viewportWidth = container.clientWidth; + const viewportHeight = container.clientHeight; + + const nodeWidth = node.width; // Approximate width of a table node + const nodeHeight = node.height; // Approximate height of a table node + + // Node screen bounds + const nodeLeft = x * zoom + offsetX; + const nodeRight = nodeLeft + nodeWidth * zoom; + const nodeTop = y * zoom + offsetY; + const nodeBottom = nodeTop + nodeHeight * zoom; + + let newOffsetX = offsetX; + let newOffsetY = offsetY; + + // Check horizontal visibility + if (nodeLeft < 0) { + newOffsetX += -nodeLeft + 20; // 20px padding + } else if (nodeRight > viewportWidth) { + newOffsetX -= nodeRight - viewportWidth + 20; + } + + // Check vertical visibility + if (nodeHeight * zoom >= viewportHeight) { + // Node taller than viewport: snap top of node to top of viewport + newOffsetY = offsetY + viewportHeight / 2 - (nodeHeight * zoom) / 2; + newOffsetY = offsetY - (nodeTop - 20); // aligns top + } else { + // Node fits in viewport: ensure fully visible + if (nodeTop < 0) { + newOffsetY += -nodeTop + 20; + } else if (nodeBottom > viewportHeight) { + newOffsetY -= nodeBottom - viewportHeight + 20; + } + } + + // Update offset only if needed + if (newOffsetX !== offsetX || newOffsetY !== offsetY) { + model.setOffset(newOffsetX, newOffsetY); + } + + this.diagram.repaint(); + node.setSelected(true); + node.fireEvent({}, 'highlightFlash'); + }; + + addEditTable(node) { let dialog = this.getDialog('table_dialog'); if(node) { - let [schema, table] = node.getSchemaTableName(); let oldData = node.getData(); - dialog(gettext('Table: %s (%s)', _.escape(table),_.escape(schema)), oldData, false, (newData)=>{ + dialog(gettext('Table: %s', node.getDisplayName()), oldData, false, (newData)=>{ if(this.diagram.anyDuplicateNodeName(newData, oldData)) { return gettext('Table name already exists'); } @@ -560,6 +622,12 @@ export default class ERDTool extends React.Component { } } + onSearchNode() { + this.context.showModal(gettext('Search'), (closeModal)=>( + + ), {id: 'id-erd-search-node', showTitle: false, disableRestoreFocus: true}); + } + onAddNewNode() { this.addEditTable(); } diff --git a/web/pgadmin/tools/erd/static/js/erd_tool/components/FloatingNote.jsx b/web/pgadmin/tools/erd/static/js/erd_tool/components/FloatingNote.jsx index 8ec8b9864b8..5e5bcdad8ed 100644 --- a/web/pgadmin/tools/erd/static/js/erd_tool/components/FloatingNote.jsx +++ b/web/pgadmin/tools/erd/static/js/erd_tool/components/FloatingNote.jsx @@ -62,8 +62,7 @@ export default function FloatingNote({open, onClose, anchorEl, rows, noteNode}) const header = useMemo(()=>{ if(noteNode) { - let [schema, name] = noteNode.getSchemaTableName(); - return `${name} (${schema})`; + return noteNode.getDisplayName(); } return ''; }, [open]); 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 ede60fa3669..72ea6d7f962 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 @@ -28,6 +28,7 @@ import ImageRoundedIcon from '@mui/icons-material/ImageRounded'; import FormatColorFillRoundedIcon from '@mui/icons-material/FormatColorFillRounded'; import FormatColorTextRoundedIcon from '@mui/icons-material/FormatColorTextRounded'; import AccountTreeOutlinedIcon from '@mui/icons-material/AccountTreeOutlined'; +import SearchOutlinedIcon from '@mui/icons-material/SearchOutlined'; import { PgMenu, PgMenuItem, usePgMenuGroup } from '../../../../../../static/js/components/Menu'; import gettext from 'sources/gettext'; @@ -201,6 +202,11 @@ export function MainToolBar({preferences, eventBus, fillColor, textColor, notati }} /> + } + shortcut={preferences.search_table} + onClick={()=>{ + eventBus.fireEvent(ERD_EVENTS.SEARCH_NODE); + }} /> } shortcut={preferences.add_table} onClick={()=>{ diff --git a/web/pgadmin/tools/erd/static/js/erd_tool/components/SearchNode.jsx b/web/pgadmin/tools/erd/static/js/erd_tool/components/SearchNode.jsx new file mode 100644 index 00000000000..b1dd6a9149c --- /dev/null +++ b/web/pgadmin/tools/erd/static/js/erd_tool/components/SearchNode.jsx @@ -0,0 +1,40 @@ +///////////////////////////////////////////////////////////// +// +// pgAdmin 4 - PostgreSQL Tools +// +// Copyright (C) 2013 - 2025, The pgAdmin Development Team +// This software is released under the PostgreSQL Licence +// +////////////////////////////////////////////////////////////// + +import PropTypes from 'prop-types'; +import { InputSelect } from '../../../../../../static/js/components/FormComponents'; + + +export default function SearchNode({tableNodes, onClose, scrollToNode}) { + const onSelectChange = (val) => { + let node = tableNodes[val]; + if(node) { + scrollToNode(node); + } + onClose(); + }; + + return ( + ({ + value: node.getID(), + label: node.getDisplayName(), + }))} + onChange={onSelectChange} + autoFocus + placeholder="Select a table" + openMenuOnFocus + /> + ); +} + +SearchNode.propTypes = { + tableNodes: PropTypes.object.isRequired, + onClose: PropTypes.func.isRequired, +}; diff --git a/web/pgadmin/tools/erd/static/js/erd_tool/dialogs/ManyToManyDialog.js b/web/pgadmin/tools/erd/static/js/erd_tool/dialogs/ManyToManyDialog.js index fce67bd3ad7..c3294b73511 100644 --- a/web/pgadmin/tools/erd/static/js/erd_tool/dialogs/ManyToManyDialog.js +++ b/web/pgadmin/tools/erd/static/js/erd_tool/dialogs/ManyToManyDialog.js @@ -50,8 +50,7 @@ class ManyToManySchema extends BaseUISchema { export function getManyToManyDialogSchema(attributes, tableNodesDict) { let tablesData = []; _.forEach(tableNodesDict, (node, uid)=>{ - let [schema, name] = node.getSchemaTableName(); - tablesData.push({value: uid, label: `(${schema}) ${name}`, image: 'icon-table'}); + tablesData.push({value: uid, label: node.getDisplayName(), image: 'icon-table'}); }); return new ManyToManySchema({ diff --git a/web/pgadmin/tools/erd/static/js/erd_tool/dialogs/OneToManyDialog.js b/web/pgadmin/tools/erd/static/js/erd_tool/dialogs/OneToManyDialog.js index 2084f4dd1ea..89cc8b3740f 100644 --- a/web/pgadmin/tools/erd/static/js/erd_tool/dialogs/OneToManyDialog.js +++ b/web/pgadmin/tools/erd/static/js/erd_tool/dialogs/OneToManyDialog.js @@ -50,8 +50,7 @@ class OneToManySchema extends BaseUISchema { export function getOneToManyDialogSchema(attributes, tableNodesDict) { let tablesData = []; _.forEach(tableNodesDict, (node, uid)=>{ - let [schema, name] = node.getSchemaTableName(); - tablesData.push({value: uid, label: `(${schema}) ${name}`, image: 'icon-table'}); + tablesData.push({value: uid, label: node.getDisplayName(), image: 'icon-table'}); }); return new OneToManySchema({ diff --git a/web/pgadmin/tools/erd/static/js/erd_tool/dialogs/OneToOneDialog.js b/web/pgadmin/tools/erd/static/js/erd_tool/dialogs/OneToOneDialog.js index a66a7d2511d..a9bc725c4cd 100644 --- a/web/pgadmin/tools/erd/static/js/erd_tool/dialogs/OneToOneDialog.js +++ b/web/pgadmin/tools/erd/static/js/erd_tool/dialogs/OneToOneDialog.js @@ -83,8 +83,7 @@ class OneToOneSchema extends BaseUISchema { export function getOneToOneDialogSchema(attributes, tableNodesDict) { let tablesData = []; _.forEach(tableNodesDict, (node, uid)=>{ - let [schema, name] = node.getSchemaTableName(); - tablesData.push({value: uid, label: `(${schema}) ${name}`, image: 'icon-table'}); + tablesData.push({value: uid, label: node.getDisplayName(), image: 'icon-table'}); }); return new OneToOneSchema({ diff --git a/web/pgadmin/tools/erd/static/js/erd_tool/dialogs/TableDialog.js b/web/pgadmin/tools/erd/static/js/erd_tool/dialogs/TableDialog.js index 5896d2e431e..4f71037c885 100644 --- a/web/pgadmin/tools/erd/static/js/erd_tool/dialogs/TableDialog.js +++ b/web/pgadmin/tools/erd/static/js/erd_tool/dialogs/TableDialog.js @@ -61,8 +61,7 @@ export function getTableDialogSchema(attributes, isNew, tableNodesDict, colTypes references: ()=>{ let retOpts = []; _.forEach(tableNodesDict, (node, uid)=>{ - let [schema, name] = node.getSchemaTableName(); - retOpts.push({value: uid, label: `(${schema}) ${name}`}); + retOpts.push({value: uid, label: node.getDisplayName()}); }); return retOpts; } 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 ce95701e516..eaac4205836 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 @@ -147,6 +147,10 @@ export class TableNodeModel extends DefaultNodeModel { return [this._data.schema, this._data.name]; } + getDisplayName() { + return `(${this._data.schema}) ${this._data.name}`; + } + remove() { Object.values(this.getPorts()).forEach((port)=>{ port.removeAllLinks(); @@ -218,6 +222,19 @@ const StyledDiv = styled('div')(({theme})=>({ position: 'relative', width: `${TABLE_WIDTH}px`, fontSize: '0.8em', + borderRadius: theme.shape.borderRadius, + + '&.flash': { + animation: 'flash 2s ease-in-out', + }, + '@keyframes flash': { + '0%': { + boxShadow: `0 0 10px 5px ${theme.palette.primary.main}`, + }, + '100%': { + boxShadow: 'none', + }, + }, '& .TableNode-tableContent': { backgroundColor: theme.palette.background.default, @@ -263,10 +280,21 @@ const StyledDiv = styled('div')(({theme})=>({ padding: '0.125rem 0.25rem', wordBreak: 'break-all', }, + + '&:last-child': { + borderBottom: 'none', + }, }, }, '&.TableNode-tableNodeSelected': { - borderColor: theme.palette.primary.main, + '& .TableNode-tableToolbar': { + borderColor: theme.palette.primary.main, + }, + '& .TableNode-tableContent': { + borderLeftColor: theme.palette.primary.main, + borderRightColor: theme.palette.primary.main, + borderBottomColor: theme.palette.primary.main, + }, }, })); @@ -276,6 +304,7 @@ export class TableNodeWidget extends React.Component { this.state = { show_details: true, + flash: false, }; this.tableNodeEventListener = this.props.node.registerListener({ @@ -291,6 +320,12 @@ export class TableNodeWidget extends React.Component { dataAvaiable: ()=>{ /* Just re-render */ this.setState({}); + }, + highlightFlash: ()=>{ + this.setState({flash: true}); + setTimeout(()=>{ + this.setState({flash: false}); + }, 2000); } }); } @@ -368,13 +403,21 @@ export class TableNodeWidget extends React.Component { (tableData.unique_constraint||[]).forEach((uk)=>{ localUkCols.push(...uk.columns.map((c)=>c.column)); }); - const styles = { + const contentStyles = { backgroundColor: tableMetaData.fillColor, color: tableMetaData.textColor, }; + + let classList = ['TableNode-tableNode']; + if(this.props.node.isSelected()) { + classList.push('TableNode-tableNodeSelected'); + } + if(this.state.flash) { + classList.push('flash'); + } return ( - {this.props.node.fireEvent({}, 'editTable');}} style={styles}> + {this.props.node.fireEvent({}, 'editTable');}}>
: } onClick={this.toggleShowDetails} onDoubleClick={(e)=>{e.stopPropagation();}} /> @@ -386,7 +429,7 @@ export class TableNodeWidget extends React.Component { }} />}
-
+
{tableMetaData.is_promise &&
{!tableMetaData.data_failed &&
{gettext('Fetching...')}
} diff --git a/web/regression/javascript/SchemaView/SchemaDialogView.spec.js b/web/regression/javascript/SchemaView/SchemaDialogView.spec.js index 80cde1e8173..4e6ee1f3a87 100644 --- a/web/regression/javascript/SchemaView/SchemaDialogView.spec.js +++ b/web/regression/javascript/SchemaView/SchemaDialogView.spec.js @@ -65,18 +65,25 @@ describe('SchemaView', ()=>{ }); }, simulateValidData = async ()=>{ - + // Wait for focus + await act(async ()=>{ + await new Promise(resolve => setTimeout(resolve, 500)); + }); await user.type(ctrl.container.querySelector('[name="field1"]'), 'val1'); await user.type(ctrl.container.querySelector('[name="field2"]'), '2'); await user.type(ctrl.container.querySelector('[name="field5"]'), 'val5'); /* Add a row */ await user.click(ctrl.container.querySelector('button[data-test="add-row"]')); await user.click(ctrl.container.querySelector('button[data-test="add-row"]')); + // Wait for focus + await act(async ()=>{ + await new Promise(resolve => setTimeout(resolve, 500)); + }); await user.type(ctrl.container.querySelectorAll('[name="field5"]')[0], 'rval51'); await user.type(ctrl.container.querySelectorAll('[name="field5"]')[1], 'rval52'); // Wait for validations to run await act(async ()=>{ - await new Promise(resolve => setTimeout(resolve)); + await new Promise(resolve => setTimeout(resolve, 500)); }); }; diff --git a/web/regression/javascript/erd/fake_item.js b/web/regression/javascript/erd/fake_item.js index 9332ca73b65..d92831342a3 100644 --- a/web/regression/javascript/erd/fake_item.js +++ b/web/regression/javascript/erd/fake_item.js @@ -20,6 +20,7 @@ export class FakeNode { getColumnAt(pos) {return _.find(this.getColumns()||[], (c)=>c.attnum==pos);} remove() {/*This is intentional (SonarQube)*/} getSchemaTableName() {return [this.data.schema, this.data.name];} + getDisplayName() {return `(${this.data.schema}) ${this.data.name}`;} cloneData(tabName) { let retVal = {...this.data}; retVal.name = tabName; diff --git a/web/regression/javascript/erd/ui_components/FloatingNote.spec.js b/web/regression/javascript/erd/ui_components/FloatingNote.spec.js index b2f4865f70f..3193a1f310f 100644 --- a/web/regression/javascript/erd/ui_components/FloatingNote.spec.js +++ b/web/regression/javascript/erd/ui_components/FloatingNote.spec.js @@ -26,6 +26,9 @@ describe('ERD FloatingNote', ()=>{ getSchemaTableName: function() { return ['schema1', 'table1']; }, + getDisplayName: function() { + return '(schema1) table1'; + } }; const user = userEvent.setup();