diff --git a/docs/en_US/images/erd_1m_dialog.png b/docs/en_US/images/erd_1m_dialog.png index df6629a7b..87ae94acd 100644 Binary files a/docs/en_US/images/erd_1m_dialog.png and b/docs/en_US/images/erd_1m_dialog.png differ diff --git a/docs/en_US/images/erd_mm_dialog.png b/docs/en_US/images/erd_mm_dialog.png index 25621bde7..abb414b24 100644 Binary files a/docs/en_US/images/erd_mm_dialog.png and b/docs/en_US/images/erd_mm_dialog.png differ diff --git a/docs/en_US/images/erd_table_dialog.png b/docs/en_US/images/erd_table_dialog.png index 8eec7f07c..01577c8bf 100644 Binary files a/docs/en_US/images/erd_table_dialog.png and b/docs/en_US/images/erd_table_dialog.png differ diff --git a/docs/en_US/images/erd_table_link.png b/docs/en_US/images/erd_table_link.png index 3b334bd3e..10698e47d 100644 Binary files a/docs/en_US/images/erd_table_link.png and b/docs/en_US/images/erd_table_link.png differ diff --git a/docs/en_US/images/erd_table_node.png b/docs/en_US/images/erd_table_node.png index fafca52c6..78e4ddfac 100644 Binary files a/docs/en_US/images/erd_table_node.png and b/docs/en_US/images/erd_table_node.png differ diff --git a/docs/en_US/images/erd_table_note.png b/docs/en_US/images/erd_table_note.png index c9c2d914a..c29fdf56e 100644 Binary files a/docs/en_US/images/erd_table_note.png and b/docs/en_US/images/erd_table_note.png differ diff --git a/docs/en_US/images/erd_tool.png b/docs/en_US/images/erd_tool.png index 64591dc7f..c4e51391b 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 1491dc78b..62ad7aca3 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_6_14.rst b/docs/en_US/release_notes_6_14.rst index 3950f495b..6e3f3c041 100644 --- a/docs/en_US/release_notes_6_14.rst +++ b/docs/en_US/release_notes_6_14.rst @@ -19,6 +19,7 @@ New features Housekeeping ************ + | `Issue #7343 `_ - Port the remaining components of the ERD Tool to React. | `Issue #7622 `_ - Port search object dialog to React. Bug fixes diff --git a/web/package.json b/web/package.json index b0c24b834..fe8baf944 100644 --- a/web/package.json +++ b/web/package.json @@ -88,7 +88,6 @@ "@projectstorm/react-diagrams": "^6.6.1", "@simonwep/pickr": "^1.5.1", "@szhsin/react-menu": "^2.2.0", - "@tippyjs/react": "^4.2.0", "@types/classnames": "^2.2.6", "@types/react": "^16.7.18", "@types/react-dom": "^16.0.11", diff --git a/web/pgadmin/browser/server_groups/servers/databases/static/js/database.js b/web/pgadmin/browser/server_groups/servers/databases/static/js/database.js index 0cb80fe18..4fccec388 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/static/js/database.js +++ b/web/pgadmin/browser/server_groups/servers/databases/static/js/database.js @@ -279,7 +279,7 @@ define('pgadmin.node.database', [ t = pgBrowser.tree, i = input.item || t.selected(), d = i ? t.itemData(i) : undefined; - pgBrowser.erd.showErdTool(d, i, true); + pgAdmin.Tools.ERD.showErdTool(d, i, true); }, /* Connect the database (if not connected), before opening this node */ diff --git a/web/pgadmin/static/img/magic.svg b/web/pgadmin/static/img/magic.svg new file mode 100644 index 000000000..58753b7e8 --- /dev/null +++ b/web/pgadmin/static/img/magic.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/pgadmin/static/img/sql_file.svg b/web/pgadmin/static/img/sql_file.svg new file mode 100644 index 000000000..3d6df27c8 --- /dev/null +++ b/web/pgadmin/static/img/sql_file.svg @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web/pgadmin/tools/sqleditor/static/js/components/dialogs/ConfirmSaveContent.jsx b/web/pgadmin/static/js/Dialogs/ConfirmSaveContent.jsx similarity index 89% rename from web/pgadmin/tools/sqleditor/static/js/components/dialogs/ConfirmSaveContent.jsx rename to web/pgadmin/static/js/Dialogs/ConfirmSaveContent.jsx index ef48b8c30..2838c6bec 100644 --- a/web/pgadmin/tools/sqleditor/static/js/components/dialogs/ConfirmSaveContent.jsx +++ b/web/pgadmin/static/js/Dialogs/ConfirmSaveContent.jsx @@ -1,8 +1,8 @@ import React from 'react'; -import { useModalStyles } from '../../../../../../static/js/helpers/ModalProvider'; +import { useModalStyles } from '../helpers/ModalProvider'; import gettext from 'sources/gettext'; import { Box } from '@material-ui/core'; -import { DefaultButton, PrimaryButton } from '../../../../../../static/js/components/Buttons'; +import { DefaultButton, PrimaryButton } from '../components/Buttons'; import CloseIcon from '@material-ui/icons/CloseRounded'; import CheckRoundedIcon from '@material-ui/icons/CheckRounded'; import DeleteRoundedIcon from '@material-ui/icons/DeleteRounded'; diff --git a/web/pgadmin/static/js/SchemaView/DataGridView.jsx b/web/pgadmin/static/js/SchemaView/DataGridView.jsx index 8d13115fe..b377544c9 100644 --- a/web/pgadmin/static/js/SchemaView/DataGridView.jsx +++ b/web/pgadmin/static/js/SchemaView/DataGridView.jsx @@ -508,7 +508,7 @@ export default function DataGridView({ setGlobalFilter(value || undefined); }} />} -
+
({style: {minWidth: 'unset'}}))} className={classes.table}>
{rows.map((row, i) => { diff --git a/web/pgadmin/static/js/Theme/dark.js b/web/pgadmin/static/js/Theme/dark.js index 506434ad6..e36072a6e 100644 --- a/web/pgadmin/static/js/Theme/dark.js +++ b/web/pgadmin/static/js/Theme/dark.js @@ -100,7 +100,9 @@ export default function(basicSettings) { cardHeaderBg: '#424242', colorFg: '#FFFFFF', emptySpaceBg: '#212121', - textMuted: '#8A8A8A' + textMuted: '#8A8A8A', + erdCanvasBg: '#303030', + erdGridColor: '#444952', } }); } diff --git a/web/pgadmin/static/js/Theme/high_contrast.js b/web/pgadmin/static/js/Theme/high_contrast.js index 4fbd6c0ca..9c8757370 100644 --- a/web/pgadmin/static/js/Theme/high_contrast.js +++ b/web/pgadmin/static/js/Theme/high_contrast.js @@ -98,7 +98,9 @@ export default function(basicSettings) { cardHeaderBg: '#062F57', colorFg: '#FFFFFF', emptySpaceBg: '#010B15', - textMuted: '#8b9cad' + textMuted: '#8b9cad', + erdCanvasBg: '#010B15', + erdGridColor: '#1F2932', } }); } diff --git a/web/pgadmin/static/js/Theme/standard.js b/web/pgadmin/static/js/Theme/standard.js index ddceb8b80..66e24ee3f 100644 --- a/web/pgadmin/static/js/Theme/standard.js +++ b/web/pgadmin/static/js/Theme/standard.js @@ -106,6 +106,8 @@ export default function(basicSettings) { cardHeaderBg: '#fff', emptySpaceBg: '#ebeef3', textMuted: '#646B82', + erdCanvasBg: '#fff', + erdGridColor: '#bac1cd', explain: { sev2: { color: '#222222', diff --git a/web/pgadmin/static/js/components/ExternalIcon.jsx b/web/pgadmin/static/js/components/ExternalIcon.jsx index b5c0fee90..94d0b4603 100644 --- a/web/pgadmin/static/js/components/ExternalIcon.jsx +++ b/web/pgadmin/static/js/components/ExternalIcon.jsx @@ -17,6 +17,8 @@ import Collapse from '../../img/fonticon/close_fullscreen.svg?svgr'; import AWS from '../../img/aws.svg?svgr'; import BigAnimal from '../../img/biganimal.svg?svgr'; import Azure from '../../img/azure.svg?svgr'; +import SQLFileSvg from '../../img/sql_file.svg?svgr'; +import MagicSvg from '../../img/magic.svg?svgr'; export default function ExternalIcon({Icon, ...props}) { return ; @@ -75,4 +77,10 @@ export const BigAnimalIcon = ({style})=>; -AzureIcon.propTypes = {style: PropTypes.object}; \ No newline at end of file +AzureIcon.propTypes = {style: PropTypes.object}; + +export const SQLFileIcon = ({style})=>; +SQLFileIcon.propTypes = {style: PropTypes.object}; + +export const MagicIcon = ({style})=>; +MagicIcon.propTypes = {style: PropTypes.object}; diff --git a/web/pgadmin/static/js/components/Loader.jsx b/web/pgadmin/static/js/components/Loader.jsx index 0232090be..48dd7f958 100644 --- a/web/pgadmin/static/js/components/Loader.jsx +++ b/web/pgadmin/static/js/components/Loader.jsx @@ -40,7 +40,7 @@ const useStyles = makeStyles((theme)=>({ } })); -export default function Loader({message, style, ...props}) { +export default function Loader({message, style, autoEllipsis=false, ...props}) { const classes = useStyles(); if(!message) { return <>; @@ -49,7 +49,7 @@ export default function Loader({message, style, ...props}) { - {message} + {message}{autoEllipsis ? '...':''} ); @@ -58,4 +58,5 @@ export default function Loader({message, style, ...props}) { Loader.propTypes = { message: PropTypes.string, style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]), + autoEllipsis: PropTypes.bool, }; diff --git a/web/pgadmin/static/js/helpers/ModalProvider.jsx b/web/pgadmin/static/js/helpers/ModalProvider.jsx index b7b9ee867..be18ded0d 100644 --- a/web/pgadmin/static/js/helpers/ModalProvider.jsx +++ b/web/pgadmin/static/js/helpers/ModalProvider.jsx @@ -98,7 +98,7 @@ export default function ModalProvider({ children }) { const [modals, setModals] = React.useState([]); const showModal = (title, content, modalOptions) => { - let id = getEpoch().toString() + crypto.getRandomValues(new Uint8Array(1)); + let id = getEpoch().toString() + crypto.getRandomValues(new Uint8Array(4)); setModals((prev) => [...prev, { id: id, title: title, diff --git a/web/pgadmin/static/scss/_tippy.overrides.scss b/web/pgadmin/static/scss/_tippy.overrides.scss deleted file mode 100644 index 27e959dbb..000000000 --- a/web/pgadmin/static/scss/_tippy.overrides.scss +++ /dev/null @@ -1,9 +0,0 @@ -@import "node_modules/tippy.js/dist/tippy.css"; - -.tippy-box { - background-color: $popover-bg; - color: $popover-body-color; - .tippy-arrow { - color: $popover-bg; - } -} diff --git a/web/pgadmin/static/scss/pgadmin.scss b/web/pgadmin/static/scss/pgadmin.scss index 78e3eecd0..892b370a5 100644 --- a/web/pgadmin/static/scss/pgadmin.scss +++ b/web/pgadmin/static/scss/pgadmin.scss @@ -31,7 +31,6 @@ $theme-colors: ( @import 'pgadmin.style'; @import 'bootstrap4-toggle.overrides'; @import 'pickr.overrides'; -@import 'tippy.overrides'; @import 'jsoneditor.overrides'; @import 'pgadmin4-tree.overrides'; @import 'pgadmin4-tree/src/css/styles'; diff --git a/web/pgadmin/tools/erd/__init__.py b/web/pgadmin/tools/erd/__init__.py index b1be8233e..5052fb544 100644 --- a/web/pgadmin/tools/erd/__init__.py +++ b/web/pgadmin/tools/erd/__init__.py @@ -399,8 +399,6 @@ def panel(trans_id): if 'gen' in params: params['gen'] = True if params['gen'] == 'true' else False - close_url = request.form['close_url'] - # We need client OS information to render correct Keyboard shortcuts user_agent = UserAgent(request.headers.get('User-Agent')) @@ -439,7 +437,6 @@ def panel(trans_id): return render_template( "erd/index.html", title=underscore_unescape(params['title']), - close_url=close_url, requirejs=True, basejs=True, params=json.dumps(params), diff --git a/web/pgadmin/tools/erd/static/js/ERDModule.js b/web/pgadmin/tools/erd/static/js/ERDModule.js new file mode 100644 index 000000000..33545fb3d --- /dev/null +++ b/web/pgadmin/tools/erd/static/js/ERDModule.js @@ -0,0 +1,240 @@ +///////////////////////////////////////////////////////////// +// +// pgAdmin 4 - PostgreSQL Tools +// +// Copyright (C) 2013 - 2022, The pgAdmin Development Team +// This software is released under the PostgreSQL Licence +// +////////////////////////////////////////////////////////////// +import pgWindow from 'sources/window'; +import {getPanelTitle} from 'tools/sqleditor/static/js/sqleditor_title'; +import {getRandomInt, registerDetachEvent} from 'sources/utils'; +import Notify from '../../../../static/js/helpers/Notifier'; +import url_for from 'sources/url_for'; +import gettext from 'sources/gettext'; +import React from 'react'; +import ReactDOM from 'react-dom'; +import ERDTool from './erd_tool/components/ERDTool'; +import ModalProvider from '../../../../static/js/helpers/ModalProvider'; +import Theme from '../../../../static/js/Theme'; +import $ from 'jquery'; + +const wcDocker = window.wcDocker; + +export function setPanelTitle(erdToolPanel, panelTitle) { + erdToolPanel?.title(''+panelTitle+''); +} +export default class ERDModule { + static instance; + + static getInstance(...args) { + if(!ERDModule.instance) { + ERDModule.instance = new ERDModule(...args); + } + return ERDModule.instance; + } + + constructor(pgAdmin, pgBrowser) { + this.pgAdmin = pgAdmin; + this.pgBrowser = pgBrowser; + } + + + init() { + if (this.initialized) + return; + + this.initialized = true; + + // Define the nodes on which the menus to be appear + this.pgBrowser.add_menus([{ + name: 'erd', + module: this, + applies: ['tools'], + callback: 'showErdTool', + priority: 1, + label: gettext('ERD Tool'), + enable: this.erdToolEnabled, + data: { + data_disabled: gettext('The selected tree node does not support this option.'), + }, + }]); + + // Creating a new this.pgBrowser frame to show the data. + const erdFrameType = new this.pgBrowser.Frame({ + name: 'frm_erdtool', + showTitle: true, + isCloseable: true, + isPrivate: true, + url: 'about:blank', + }); + + // Load the newly created frame + erdFrameType.load(this.pgBrowser.docker); + return this; + } + + erdToolEnabled(obj) { + /* Same as query tool */ + return (() => { + if (!_.isUndefined(obj) && !_.isNull(obj)) { + if (_.indexOf(this.pgAdmin.unsupported_nodes, obj._type) == -1) { + if (obj._type == 'database' && obj.allowConn) { + return true; + } else if (obj._type != 'database') { + return true; + } else { + return false; + } + } else { + return false; + } + } else { + return false; + } + })(); + } + + // Callback to draw ERD Tool for objects + showErdTool(_data, treeIdentifier, gen=false) { + if (treeIdentifier === undefined) { + Notify.alert( + gettext('ERD Error'), + gettext('No object selected.') + ); + return; + } + + const parentData = this.pgBrowser.tree.getTreeNodeHierarchy(treeIdentifier); + + if(_.isUndefined(parentData.database)) { + Notify.alert( + gettext('ERD Error'), + gettext('Please select a database/database object.') + ); + return; + } + + const transId = getRandomInt(1, 9999999); + const panelTitle = getPanelTitle(this.pgBrowser, treeIdentifier); + const panelUrl = this.getPanelUrl(transId, parentData, gen); + + let erdToolForm = ` +
+ +
+ + `; + + var open_new_tab = this.pgBrowser.get_preferences_for_module('browser').new_browser_tab_open; + if (open_new_tab && open_new_tab.includes('erd_tool')) { + var newWin = window.open('', '_blank'); + newWin.document.write(erdToolForm); + newWin.document.title = panelTitle; + // Send the signal to runtime, so that proper zoom level will be set. + setTimeout(function() { + this.pgBrowser.send_signal_to_runtime('Runtime new window opened'); + }, 500); + } else { + /* On successfully initialization find the dashboard panel, + * create new panel and add it to the dashboard panel. + */ + var propertiesPanel = this.pgBrowser.docker.findPanels('properties'); + var erdToolPanel = this.pgBrowser.docker.addPanel('frm_erdtool', wcDocker.DOCK.STACKED, propertiesPanel[0]); + + // Set panel title and icon + setPanelTitle(erdToolPanel, 'Untitled'); + erdToolPanel.icon('fa fa-sitemap'); + erdToolPanel.focus(); + + // Register detach event. + registerDetachEvent(erdToolPanel); + var openErdToolURL = function(j) { + // add spinner element + let $spinner_el = + $(`
+
+
+
+
+
+
`).appendTo($(j).data('embeddedFrame').$container); + + let init_poller_id = setInterval(function() { + var frameInitialized = $(j).data('frameInitialized'); + if (frameInitialized) { + clearInterval(init_poller_id); + var frame = $(j).data('embeddedFrame'); + if (frame) { + frame.onLoaded(()=>{ + $spinner_el.remove(); + }); + frame.openHTML(erdToolForm); + } + } + }, 100); + }; + + openErdToolURL(erdToolPanel); + } + } + + getPanelUrl(transId, parentData, gen) { + let openUrl = url_for('erd.panel', { + trans_id: transId, + }); + + openUrl += `?sgid=${parentData.server_group._id}` + +`&sid=${parentData.server._id}` + +`&server_type=${parentData.server.server_type}` + +`&did=${parentData.database._id}` + +`&gen=${gen}`; + + return openUrl; + } + + setupPreferencesWorker() { + if (window.location == window.parent?.location) { + /* Sync the local preferences with the main window if in new tab */ + setInterval(()=>{ + if(pgWindow?.pgAdmin) { + if(this.pgAdmin.Browser.preference_version() < pgWindow.pgAdmin.Browser.preference_version()){ + this.pgAdmin.Browser.preferences_cache = pgWindow.pgAdmin.Browser.preferences_cache; + this.pgAdmin.Browser.preference_version(pgWindow.pgAdmin.Browser.preference_version()); + this.pgAdmin.Browser.triggerPreferencesChange('browser'); + this.pgAdmin.Browser.triggerPreferencesChange('erd'); + } + } + }, 1000); + } + } + + loadComponent(container, params) { + let panel = null; + + /* Mount the React ERD tool to the container */ + _.each(pgWindow.pgAdmin.Browser.docker.findPanels('frm_erdtool'), function(p) { + if (p.isVisible()) { + panel = p; + } + }); + + this.setupPreferencesWorker(); + ReactDOM.render( + + + + + , + container + ); + } +} diff --git a/web/pgadmin/tools/erd/static/js/erd_module.js b/web/pgadmin/tools/erd/static/js/erd_module.js deleted file mode 100644 index 900025e5f..000000000 --- a/web/pgadmin/tools/erd/static/js/erd_module.js +++ /dev/null @@ -1,217 +0,0 @@ -///////////////////////////////////////////////////////////// -// -// pgAdmin 4 - PostgreSQL Tools -// -// Copyright (C) 2013 - 2022, The pgAdmin Development Team -// This software is released under the PostgreSQL Licence -// -////////////////////////////////////////////////////////////// - -import {getPanelTitle} from 'tools/sqleditor/static/js/sqleditor_title'; -import {getRandomInt, registerDetachEvent} from 'sources/utils'; -import Notify from '../../../../static/js/helpers/Notifier'; - - -export function setPanelTitle(erdToolPanel, panelTitle) { - erdToolPanel.title(''+panelTitle+''); -} - -export function initialize(gettext, url_for, $, _, pgAdmin, csrfToken, pgBrowser, wcDocker) { - /* Return back, this has been called more than once */ - if (pgBrowser.erd) - return pgBrowser.erd; - - pgBrowser.erd = { - init: function() { - if (this.initialized) - return; - - this.initialized = true; - csrfToken.setPGCSRFToken(pgAdmin.csrf_token_header, pgAdmin.csrf_token); - - - // Define the nodes on which the menus to be appear - var menus = [{ - name: 'erd', - module: this, - applies: ['tools'], - callback: 'showErdTool', - priority: 1, - label: gettext('ERD Tool'), - enable: this.erdToolEnabled, - data: { - data_disabled: gettext('The selected tree node does not support this option.'), - }, - }]; - - pgBrowser.add_menus(menus); - - // Creating a new pgBrowser frame to show the data. - var erdFrameType = new pgBrowser.Frame({ - name: 'frm_erdtool', - showTitle: true, - isCloseable: true, - isPrivate: true, - url: 'about:blank', - }); - - let self = this; - /* Cache may take time to load for the first time - * Keep trying till available - */ - let cacheIntervalId = setInterval(function() { - if(pgBrowser.preference_version() > 0) { - self.preferences = pgBrowser.get_preferences_for_module('erd'); - clearInterval(cacheIntervalId); - } - },0); - - pgBrowser.onPreferencesChange('erd', function() { - self.preferences = pgBrowser.get_preferences_for_module('erd'); - }); - - // Load the newly created frame - erdFrameType.load(pgBrowser.docker); - return this; - }, - - erdToolEnabled: function(obj) { - /* Same as query tool */ - return (() => { - if (!_.isUndefined(obj) && !_.isNull(obj)) { - if (_.indexOf(pgAdmin.unsupported_nodes, obj._type) == -1) { - if (obj._type == 'database' && obj.allowConn) { - return true; - } else if (obj._type != 'database') { - return true; - } else { - return false; - } - } else { - return false; - } - } else { - return false; - } - })(); - }, - - // Callback to draw ERD Tool for objects - showErdTool: function(data, treeIdentifier, gen=false) { - if (treeIdentifier === undefined) { - Notify.alert( - gettext('ERD Error'), - gettext('No object selected.') - ); - return; - } - - const parentData = pgBrowser.tree.getTreeNodeHierarchy(treeIdentifier); - - if(_.isUndefined(parentData.database)) { - Notify.alert( - gettext('ERD Error'), - gettext('Please select a database/database object.') - ); - return; - } - - const transId = getRandomInt(1, 9999999); - const panelTitle = getPanelTitle(pgBrowser, treeIdentifier); - const [panelUrl, panelCloseUrl] = this.getPanelUrls(transId, panelTitle, parentData, gen); - - let erdToolForm = ` -
- - -
- - `; - - var open_new_tab = pgBrowser.get_preferences_for_module('browser').new_browser_tab_open; - if (open_new_tab && open_new_tab.includes('erd_tool')) { - var newWin = window.open('', '_blank'); - newWin.document.write(erdToolForm); - newWin.document.title = panelTitle; - // Send the signal to runtime, so that proper zoom level will be set. - setTimeout(function() { - pgBrowser.send_signal_to_runtime('Runtime new window opened'); - }, 500); - } else { - /* On successfully initialization find the dashboard panel, - * create new panel and add it to the dashboard panel. - */ - var propertiesPanel = pgBrowser.docker.findPanels('properties'); - var erdToolPanel = pgBrowser.docker.addPanel('frm_erdtool', wcDocker.DOCK.STACKED, propertiesPanel[0]); - - // Set panel title and icon - setPanelTitle(erdToolPanel, 'Untitled'); - erdToolPanel.icon('fa fa-sitemap'); - erdToolPanel.focus(); - - // Listen on the panel closed event. - erdToolPanel.on(wcDocker.EVENT.CLOSED, function() { - $.ajax({ - url: panelCloseUrl, - method: 'DELETE', - }); - }); - // Register detach event. - registerDetachEvent(erdToolPanel); - var openErdToolURL = function(j) { - // add spinner element - let $spinner_el = - $(`
-
-
-
-
-
-
`).appendTo($(j).data('embeddedFrame').$container); - - let init_poller_id = setInterval(function() { - var frameInitialized = $(j).data('frameInitialized'); - if (frameInitialized) { - clearInterval(init_poller_id); - var frame = $(j).data('embeddedFrame'); - if (frame) { - frame.onLoaded(()=>{ - $spinner_el.remove(); - }); - frame.openHTML(erdToolForm); - } - } - }, 100); - }; - - openErdToolURL(erdToolPanel); - } - }, - - getPanelUrls: function(transId, panelTitle, parentData, gen) { - let openUrl = url_for('erd.panel', { - trans_id: transId, - }); - - openUrl += `?sgid=${parentData.server_group._id}` - +`&sid=${parentData.server._id}` - +`&server_type=${parentData.server.server_type}` - +`&did=${parentData.database._id}` - +`&gen=${gen}`; - - let closeUrl = url_for('erd.close', { - trans_id: transId, - sgid: parentData.server_group._id, - sid: parentData.server._id, - did: parentData.database._id, - }); - - return [openUrl, closeUrl]; - }, - }; - - return pgBrowser.erd; -} diff --git a/web/pgadmin/tools/erd/static/js/erd_tool/ERDConstants.js b/web/pgadmin/tools/erd/static/js/erd_tool/ERDConstants.js new file mode 100644 index 000000000..323e08155 --- /dev/null +++ b/web/pgadmin/tools/erd/static/js/erd_tool/ERDConstants.js @@ -0,0 +1,21 @@ +export const ERD_EVENTS = { + LOAD_DIAGRAM: 'LOAD_DIAGRAM', + SAVE_DIAGRAM: 'SAVE_DIAGRAM', + SHOW_SQL: 'SHOW_SQL', + DOWNLOAD_IMAGE: 'DOWNLOAD_IMAGE', + ADD_NODE: 'ADD_NODE', + EDIT_NODE: 'EDIT_NODE', + CLONE_NODE: 'CLONE_NODE', + DELETE_NODE: 'DELETE_NODE', + SHOW_NOTE: 'SHOW_NOTE', + ONE_TO_MANY: 'ONE_TO_MANY', + MANY_TO_MANY: 'MANY_TO_MANY', + AUTO_DISTRIBUTE: 'AUTO_DISTRIBUTE', + TOGGLE_DETAILS: 'TOGGLE_DETAILS', + ZOOM_FIT: 'ZOOM_FIT', + ZOOM_IN: 'ZOOM_IN', + ZOOM_OUT: 'ZOOM_OUT', + SINGLE_NODE_SELECTED: 'SINGLE_NODE_SELECTED', + ANY_ITEM_SELECTED: 'ANY_ITEM_SELECTED', + DIRTY: 'DIRTY', +}; diff --git a/web/pgadmin/tools/erd/static/js/erd_tool/components/ConnectionBar.jsx b/web/pgadmin/tools/erd/static/js/erd_tool/components/ConnectionBar.jsx new file mode 100644 index 000000000..7640a7e4f --- /dev/null +++ b/web/pgadmin/tools/erd/static/js/erd_tool/components/ConnectionBar.jsx @@ -0,0 +1,100 @@ +///////////////////////////////////////////////////////////// +// +// pgAdmin 4 - PostgreSQL Tools +// +// Copyright (C) 2013 - 2022, The pgAdmin Development Team +// This software is released under the PostgreSQL Licence +// +////////////////////////////////////////////////////////////// + +import React, { useMemo } from 'react'; +import gettext from 'sources/gettext'; +import PropTypes from 'prop-types'; +import { DefaultButton, PgButtonGroup, PgIconButton } from '../../../../../../static/js/components/Buttons'; +import { Box, makeStyles, Tooltip, CircularProgress } from '@material-ui/core'; +import { ConnectedIcon, DisonnectedIcon } from '../../../../../../static/js/components/ExternalIcon'; + +export const STATUS = { + CONNECTED: 1, + DISCONNECTED: 2, + CONNECTING: 3, + FAILED: 4, +}; + +function ConnectionStatusIcon({status}) { + if(status == STATUS.CONNECTING) { + return ; + } else if(status == STATUS.CONNECTED || status == STATUS.FAILED) { + return ; + } else { + return ; + } +} + +ConnectionStatusIcon.propTypes = { + status: PropTypes.oneOf(Object.values(STATUS)).isRequired, +}; + +const useStyles = makeStyles((theme)=>({ + root: { + padding: '2px 4px', + display: 'flex', + alignItems: 'center', + gap: '4px', + backgroundColor: theme.otherVars.editorToolbarBg, + flexWrap: 'wrap', + }, + connectionButton: { + display: 'flex', + width: '450px', + backgroundColor: theme.palette.default.main, + color: theme.palette.default.contrastText, + border: '1px solid ' + theme.palette.default.borderColor, + justifyContent: 'flex-start', + }, +})); + +/* The connection bar component */ +export default function ConnectionBar({status, bgcolor, fgcolor, title}) { + const classes = useStyles(); + const connTitle = useMemo(()=>{ + if(status == STATUS.CONNECTED) { + return gettext('Connected'); + } else if(status == STATUS.CONNECTING) { + return gettext('Connecting'); + } else if(status == STATUS.DISCONNECTED) { + return gettext('Disconnected'); + } else if(status == STATUS.FAILED) { + return gettext('Failed'); + } + }, [status]); + return ( + + + } + data-test="btn-conn-status" + /> + + + + + {status == STATUS.CONNECTING && (gettext('(Obtaining connection...)')+' ')} + {status == STATUS.FAILED && (gettext('(Connection failed)')+' ')} + {title} + + + + + + + ); +} + +ConnectionBar.propTypes = { + status: PropTypes.oneOf(Object.values(STATUS)).isRequired, + bgcolor: PropTypes.string, + fgcolor: PropTypes.string, + title: PropTypes.string.isRequired, +}; diff --git a/web/pgadmin/tools/erd/static/js/erd_tool/ui_components/BodyWidget.jsx b/web/pgadmin/tools/erd/static/js/erd_tool/components/ERDTool.jsx similarity index 71% rename from web/pgadmin/tools/erd/static/js/erd_tool/ui_components/BodyWidget.jsx rename to web/pgadmin/tools/erd/static/js/erd_tool/components/ERDTool.jsx index 6427292d3..116df9dda 100644 --- a/web/pgadmin/tools/erd/static/js/erd_tool/ui_components/BodyWidget.jsx +++ b/web/pgadmin/tools/erd/static/js/erd_tool/components/ERDTool.jsx @@ -9,25 +9,29 @@ import * as React from 'react'; import { CanvasWidget, Action, InputType } from '@projectstorm/react-canvas-core'; -import axios from 'axios'; import PropTypes from 'prop-types'; import _ from 'lodash'; import html2canvas from 'html2canvas'; import ERDCore from '../ERDCore'; -import ToolBar, {IconButton, DetailsToggleButton, ButtonGroup} from './ToolBar'; import ConnectionBar, { STATUS as CONNECT_STATUS } from './ConnectionBar'; -import Loader from './Loader'; import FloatingNote from './FloatingNote'; -import {setPanelTitle} from '../../erd_module'; +import {setPanelTitle} from '../../ERDModule'; import gettext from 'sources/gettext'; import url_for from 'sources/url_for'; import {showERDSqlTool} from 'tools/sqleditor/static/js/show_query_tool'; import 'wcdocker'; -import Theme from '../../../../../../static/js/Theme'; import TableSchema from '../../../../../../browser/server_groups/servers/databases/schemas/tables/static/js/table.ui'; import Notify from '../../../../../../static/js/helpers/Notifier'; import { ModalContext } from '../../../../../../static/js/helpers/ModalProvider'; +import ERDDialogs from '../dialogs'; +import ConfirmSaveContent from '../../../../../../static/js/Dialogs/ConfirmSaveContent'; +import Loader from '../../../../../../static/js/components/Loader'; +import { MainToolBar } from './MainToolBar'; +import { Box, withStyles } from '@material-ui/core'; +import EventBus from '../../../../../../static/js/helpers/EventBus'; +import { ERD_EVENTS } from '../ERDConstants'; +import getApiInstance, { parseApiError } from '../../../../../../static/js/api_instance'; /* Custom react-diagram action for keyboard events */ export class KeyboardShortcutAction extends Action { @@ -60,11 +64,41 @@ export class KeyboardShortcutAction extends Action { } } +const getCanvasGrid = (theme)=>{ + let erdCanvasBg = encodeURIComponent(theme.otherVars.erdCanvasBg); + let erdGridColor = encodeURIComponent(theme.otherVars.erdGridColor); + + return `url("data:image/svg+xml, %3Csvg width='100%25' viewBox='0 0 45 45' style='background-color:${erdCanvasBg}' height='100%25' xmlns='http://www.w3.org/2000/svg'%3E%3Cdefs%3E%3Cpattern id='smallGrid' width='15' height='15' patternUnits='userSpaceOnUse'%3E%3Cpath d='M 15 0 L 0 0 0 15' fill='none' stroke='${erdGridColor}' stroke-width='0.5'/%3E%3C/pattern%3E%3Cpattern id='grid' width='45' height='45' patternUnits='userSpaceOnUse'%3E%3Crect width='100' height='100' fill='url(%23smallGrid)'/%3E%3Cpath d='M 100 0 L 0 0 0 100' fill='none' stroke='${erdGridColor}' stroke-width='1'/%3E%3C/pattern%3E%3C/defs%3E%3Crect width='100%25' height='100%25' fill='url(%23grid)' /%3E%3C/svg%3E%0A")`; +}; + +const styles = ((theme)=>({ + diagramContainer: { + position: 'relative', + width: '100%', + height: '100%', + minHeight: 0, + }, + diagramCanvas: { + width: '100%', + height: '100%', + color: theme.palette.text.primary, + fontFamily: 'sans-serif', + backgroundColor: theme.otherVars.erdCanvasBg, + backgroundImage: getCanvasGrid(theme), + cursor: 'unset', + flexGrow: 1, + }, + html2canvasReset: { + backgroundImage: 'none !important', + overflow: 'auto !important', + } +})); + /* The main body container for the ERD */ -export default class BodyWidget extends React.Component { +class ERDTool extends React.Component { static contextType = ModalContext; - constructor() { - super(); + constructor(props) { + super(props); this.state = { conn_status: CONNECT_STATUS.DISCONNECTED, server_version: null, @@ -89,11 +123,16 @@ export default class BodyWidget extends React.Component { /* Flag for checking if user has opted for save before close */ this.closeOnSave = React.createRef(); this.fileInputRef = React.createRef(); + this.containerRef = React.createRef(); this.diagramContainerRef = React.createRef(); this.canvasEle = null; this.noteRefEle = null; this.noteNode = null; this.keyboardActionObj = null; + this.erdDialogs = new ERDDialogs(this.context); + this.apiObj = getApiInstance(); + + this.eventBus = new EventBus(); _.bindAll(this, ['onLoadDiagram', 'onSaveDiagram', 'onSaveAsDiagram', 'onSQLClick', 'onImageClick', 'onAddNewNode', 'onEditTable', 'onCloneNode', 'onDeleteNode', 'onNoteClick', @@ -125,22 +164,29 @@ export default class BodyWidget extends React.Component { singleNodeSelected = true; } } + const anyItemSelected = this.diagram.getSelectedNodes().length > 0 || this.diagram.getSelectedLinks().length > 0; this.setState({ single_node_selected: singleNodeSelected, - any_item_selected: this.diagram.getSelectedNodes().length > 0 || this.diagram.getSelectedLinks().length > 0, + any_item_selected: anyItemSelected, }); + this.eventBus.fireEvent(ERD_EVENTS.SINGLE_NODE_SELECTED, singleNodeSelected); + this.eventBus.fireEvent(ERD_EVENTS.ANY_ITEM_SELECTED, anyItemSelected); }, 'linksSelectionChanged': ()=>{ + const anyItemSelected = this.diagram.getSelectedNodes().length > 0 || this.diagram.getSelectedLinks().length > 0; this.setState({ single_link_selected: this.diagram.getSelectedLinks().length == 1, any_item_selected: this.diagram.getSelectedNodes().length > 0 || this.diagram.getSelectedLinks().length > 0, }); + this.eventBus.fireEvent(ERD_EVENTS.ANY_ITEM_SELECTED, anyItemSelected); }, 'linksUpdated': () => { this.setState({dirty: true}); + this.eventBus.fireEvent(ERD_EVENTS.DIRTY, true); }, 'nodesUpdated': ()=>{ this.setState({dirty: true}); + this.eventBus.fireEvent(ERD_EVENTS.DIRTY, true); }, 'showNote': (event)=>{ this.showNote(event.node); @@ -154,53 +200,94 @@ export default class BodyWidget extends React.Component { }); } + registerEvents() { + this.eventBus.registerListener(ERD_EVENTS.LOAD_DIAGRAM, this.onLoadDiagram); + 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.ADD_NODE, this.onAddNewNode); + this.eventBus.registerListener(ERD_EVENTS.EDIT_NODE, this.onEditTable); + this.eventBus.registerListener(ERD_EVENTS.CLONE_NODE, this.onCloneNode); + this.eventBus.registerListener(ERD_EVENTS.DELETE_NODE, this.onDeleteNode); + this.eventBus.registerListener(ERD_EVENTS.SHOW_NOTE, this.onNoteClick); + this.eventBus.registerListener(ERD_EVENTS.ONE_TO_MANY, this.onOneToManyClick); + this.eventBus.registerListener(ERD_EVENTS.MANY_TO_MANY, this.onManyToManyClick); + this.eventBus.registerListener(ERD_EVENTS.AUTO_DISTRIBUTE, this.onAutoDistribute); + this.eventBus.registerListener(ERD_EVENTS.TOGGLE_DETAILS, this.onDetailsToggle); + this.eventBus.registerListener(ERD_EVENTS.ZOOM_FIT, this.diagram.zoomToFit); + this.eventBus.registerListener(ERD_EVENTS.ZOOM_IN, this.diagram.zoomIn); + this.eventBus.registerListener(ERD_EVENTS.ZOOM_OUT, this.diagram.zoomOut); + } + registerKeyboardShortcuts() { /* First deregister to avoid double events */ this.keyboardActionObj && this.diagram.deregisterKeyAction(this.keyboardActionObj); this.keyboardActionObj = new KeyboardShortcutAction([ - [this.state.preferences.open_project, this.onLoadDiagram], - [this.state.preferences.save_project, this.onSaveDiagram], - [this.state.preferences.save_project_as, this.onSaveAsDiagram], - [this.state.preferences.generate_sql, this.onSQLClick], - [this.state.preferences.download_image, this.onImageClick], - [this.state.preferences.add_table, this.onAddNewNode], - [this.state.preferences.edit_table, this.onEditTable], - [this.state.preferences.clone_table, this.onCloneNode], - [this.state.preferences.drop_table, this.onDeleteNode], - [this.state.preferences.add_edit_note, this.onNoteClick], - [this.state.preferences.one_to_many, this.onOneToManyClick], - [this.state.preferences.many_to_many, this.onManyToManyClick], - [this.state.preferences.auto_align, this.onAutoDistribute], - [this.state.preferences.show_details, this.onDetailsToggle], - [this.state.preferences.zoom_to_fit, this.diagram.zoomToFit], - [this.state.preferences.zoom_in, this.diagram.zoomIn], - [this.state.preferences.zoom_out, this.diagram.zoomOut], + [this.state.preferences.open_project, ()=>{ + this.eventBus.fireEvent(ERD_EVENTS.LOAD_DIAGRAM); + }], + [this.state.preferences.save_project, ()=>{ + this.eventBus.fireEvent(ERD_EVENTS.SAVE_DIAGRAM); + }], + [this.state.preferences.save_project_as, ()=>{ + this.eventBus.fireEvent(ERD_EVENTS.SAVE_DIAGRAM, true); + }], + [this.state.preferences.generate_sql, ()=>{ + this.eventBus.fireEvent(ERD_EVENTS.SHOW_SQL); + }], + [this.state.preferences.download_image, ()=>{ + this.eventBus.fireEvent(ERD_EVENTS.DOWNLOAD_IMAGE); + }], + [this.state.preferences.add_table, ()=>{ + this.eventBus.fireEvent(ERD_EVENTS.ADD_NODE); + }], + [this.state.preferences.edit_table, ()=>{ + this.eventBus.fireEvent(ERD_EVENTS.EDIT_NODE); + }], + [this.state.preferences.clone_table, ()=>{ + this.eventBus.fireEvent(ERD_EVENTS.CLONE_NODE); + }], + [this.state.preferences.drop_table, ()=>{ + this.eventBus.fireEvent(ERD_EVENTS.DELETE_NODE); + }], + [this.state.preferences.add_edit_note, ()=>{ + this.eventBus.fireEvent(ERD_EVENTS.SHOW_NOTE); + }], + [this.state.preferences.one_to_many, ()=>{ + this.eventBus.fireEvent(ERD_EVENTS.ONE_TO_MANY); + }], + [this.state.preferences.many_to_many, ()=>{ + this.eventBus.fireEvent(ERD_EVENTS.MANY_TO_MANY); + }], + [this.state.preferences.auto_align, ()=>{ + this.eventBus.fireEvent(ERD_EVENTS.AUTO_DISTRIBUTE); + }], + [this.state.preferences.show_details, ()=>{ + this.eventBus.fireEvent(ERD_EVENTS.TOGGLE_DETAILS); + }], + [this.state.preferences.zoom_to_fit, ()=>{ + this.eventBus.fireEvent(ERD_EVENTS.ZOOM_FIT); + }], + [this.state.preferences.zoom_in, ()=>{ + this.eventBus.fireEvent(ERD_EVENTS.ZOOM_IN); + }], + [this.state.preferences.zoom_out, ()=>{ + this.eventBus.fireEvent(ERD_EVENTS.ZOOM_OUT); + }], ]); this.diagram.registerKeyAction(this.keyboardActionObj); } handleAxiosCatch(err) { - if (err.response) { - // client received an error response (5xx, 4xx) - Notify.alert( - gettext('Error'), - `${err.response.statusText} - ${err.response.data.errormsg}` - ); - console.error('response error', err.response); - } else if (err.request) { - // client never received a response, or request never left - Notify.alert(gettext('Error'), gettext('Client error') + ':' + err); - console.error('client eror', err); - } else { - Notify.alert(gettext('Error'), err.message); - console.error('other error', err); - } + console.error(err); + Notify.alert(gettext('Error'), parseApiError(err)); } async componentDidMount() { this.setLoading(gettext('Preparing...')); + this.registerEvents(); this.setState({ preferences: this.props.pgWindow.pgAdmin.Browser.get_preferences_for_module('erd'), @@ -216,7 +303,7 @@ export default class BodyWidget extends React.Component { backgroundPosition: '0px 0px', }); - this.props.pgAdmin.Browser.onPreferencesChange('erd', () => { + this.props.pgWindow.pgAdmin.Browser.onPreferencesChange('erd', () => { this.setState({ preferences: this.props.pgWindow.pgAdmin.Browser.get_preferences_for_module('erd'), }, ()=>this.registerKeyboardShortcuts()); @@ -232,6 +319,15 @@ export default class BodyWidget extends React.Component { return true; }); + window.addEventListener('unload', ()=>{ + this.apiObj.delete(url_for('erd.close', { + trans_id: this.props.params.trans_id, + sgid: this.props.params.sgid, + sid: this.props.params.sid, + did: this.props.params.did + })); + }); + let done = await this.initConnection(); if(!done) return; @@ -257,52 +353,18 @@ export default class BodyWidget extends React.Component { confirmBeforeClose() { let bodyObj = this; - this.props.alertify.confirmSave || this.props.alertify.dialog('confirmSave', function() { - return { - main: function(title, message) { - this.setHeader(title); - this.setContent(message); - }, - setup: function() { - return { - buttons: [{ - text: gettext('Cancel'), - key: 27, // ESC - invokeOnClose: true, - className: 'btn btn-secondary fa fa-lg fa-times pg-alertify-button', - }, { - text: gettext('Don\'t save'), - className: 'btn btn-secondary fa fa-lg fa-trash-alt pg-alertify-button', - }, { - text: gettext('Save'), - className: 'btn btn-primary fa fa-lg fa-save pg-alertify-button', - }], - focus: { - element: 0, - select: false, - }, - options: { - maximizable: false, - resizable: false, - }, - }; - }, - callback: function(closeEvent) { - switch (closeEvent.index) { - case 0: // Cancel - //Do nothing. - break; - case 1: // Don't Save - bodyObj.closePanel(); - break; - case 2: //Save - bodyObj.onSaveDiagram(false, true); - break; - } - }, - }; - }); - this.props.alertify.confirmSave(gettext('Save changes?'), gettext('The diagram has changed. Do you want to save changes?')); + this.context.showModal(gettext('Save changes?'), (closeModal)=>( + { + bodyObj.closePanel(); + }} + onSave={()=>{ + bodyObj.onSaveDiagram(false, true); + }} + /> + )); return false; } @@ -318,15 +380,18 @@ export default class BodyWidget extends React.Component { }; if(dialogName === 'table_dialog') { return (title, attributes, isNew, callback)=>{ - this.props.getDialog(dialogName).show( - title, attributes, isNew, this.diagram.getModel().getNodesDict(), this.diagram.getCache('colTypes'), this.diagram.getCache('schemas'), serverInfo, callback - ); + this.erdDialogs.showTableDialog({ + title, attributes, isNew, tableNodes: this.diagram.getModel().getNodesDict(), + colTypes: this.diagram.getCache('colTypes'), schemas: this.diagram.getCache('schemas'), + serverInfo, callback + }); }; } else if(dialogName === 'onetomany_dialog' || dialogName === 'manytomany_dialog') { return (title, attributes, callback)=>{ - this.props.getDialog(dialogName).show( - title, attributes, this.diagram.getModel().getNodesDict(), serverInfo, callback - ); + this.erdDialogs.showRelationDialog(dialogName, { + title, attributes, tableNodes: this.diagram.getModel().getNodesDict(), + serverInfo, callback + }); }; } } @@ -386,7 +451,7 @@ export default class BodyWidget extends React.Component { Notify.error(gettext('Cannot drop table from outside of the current database.')); } else { let dataPromise = new Promise((resolve, reject)=>{ - axios.get(nodeDropData.objUrl) + this.apiObj.get(nodeDropData.objUrl) .then((res)=>{ resolve(this.diagram.cloneTableData(TableSchema.getErdSupportedData(res.data))); }) @@ -467,7 +532,7 @@ export default class BodyWidget extends React.Component { } onLoadDiagram() { - var params = { + const params = { 'supported_types': ['*','pgerd'], // file types allowed 'dialog_type': 'select_file', // open select file dialog }; @@ -476,13 +541,14 @@ export default class BodyWidget extends React.Component { openFile(fileName) { this.setLoading(gettext('Loading project...')); - axios.post(url_for('sqleditor.load_file'), { + this.apiObj.post(url_for('sqleditor.load_file'), { 'file_name': decodeURI(fileName), }).then((res)=>{ this.setState({ current_file: fileName, dirty: false, }); + this.eventBus.fireEvent(ERD_EVENTS.DIRTY, false); this.setTitle(fileName); this.diagram.deserialize(res.data); this.diagram.clearSelection(); @@ -515,7 +581,7 @@ export default class BodyWidget extends React.Component { saveFile(fileName) { this.setLoading(gettext('Saving...')); - axios.post(url_for('sqleditor.save_file'), { + this.apiObj.post(url_for('sqleditor.save_file'), { 'file_name': decodeURI(fileName), 'file_content': JSON.stringify(this.diagram.serialize(this.props.pgAdmin.Browser.utils.app_version_int)), }).then(()=>{ @@ -524,6 +590,7 @@ export default class BodyWidget extends React.Component { current_file: fileName, dirty: false, }); + this.eventBus.fireEvent(ERD_EVENTS.DIRTY, false); this.setTitle(fileName); this.setLoading(null); if(this.closeOnSave) { @@ -564,7 +631,7 @@ export default class BodyWidget extends React.Component { }); this.setLoading(gettext('Preparing the SQL...')); - axios.post(url, this.diagram.serializeData()) + this.apiObj.post(url, this.diagram.serializeData()) .then((resp)=>{ let sqlScript = resp.data.data; sqlScript = scriptHeader + 'BEGIN;\n' + sqlScript + '\nEND;'; @@ -579,7 +646,7 @@ export default class BodyWidget extends React.Component { let sqlId = `erd${this.props.params.trans_id}`; localStorage.setItem(sqlId, sqlScript); - showERDSqlTool(parentData, sqlId, this.props.params.title, this.props.pgWindow.pgAdmin.Tools.SQLEditor, this.props.alertify); + showERDSqlTool(parentData, sqlId, this.props.params.title, this.props.pgWindow.pgAdmin.Tools.SQLEditor); }) .catch((error)=>{ this.handleAxiosCatch(error); @@ -617,7 +684,7 @@ export default class BodyWidget extends React.Component { }); /* Change the styles for suiting html2canvas */ - this.canvasEle.classList.add('html2canvas-reset'); + this.canvasEle.classList.add(this.props.classes.html2canvasReset); this.canvasEle.style.width = this.canvasEle.scrollWidth + 'px'; this.canvasEle.style.height = this.canvasEle.scrollHeight + 'px'; @@ -628,7 +695,8 @@ export default class BodyWidget extends React.Component { 'color', 'font-size', 'stroke', - 'font' + 'font', + 'display', ]; let svgElems = Array.from(targetElem.getElementsByTagName('svg')); for (let svgEle of svgElems) { @@ -638,6 +706,7 @@ export default class BodyWidget extends React.Component { let wrap = document.createElement('div'); wrap.setAttribute('style', svgEle.getAttribute('style')); svgEle.setAttribute('style', null); + svgEle.style.display = 'block'; svgEle.parentNode.insertBefore(wrap, svgEle); wrap.appendChild(svgEle); recurseElementChildren(svgEle); @@ -679,7 +748,7 @@ export default class BodyWidget extends React.Component { allowTaint: true, backgroundColor: window.getComputedStyle(this.canvasEle).backgroundColor, onclone: (clonedEle)=>{ - setSvgInlineStyles(clonedEle); + setSvgInlineStyles(clonedEle.body.querySelector('div[data-test="diagram-container"]')); return clonedEle; }, }).then((canvas)=>{ @@ -697,7 +766,7 @@ export default class BodyWidget extends React.Component { Notify.alert(gettext('Error'), msg); }).then(()=>{ /* Revert back to the original CSS styles */ - this.canvasEle.classList.remove('html2canvas-reset'); + this.canvasEle.classList.remove(this.props.classes.html2canvasReset); this.canvasEle.style.width = ''; this.canvasEle.style.height = ''; this.canvasEle.childNodes.forEach((ele)=>{ @@ -760,7 +829,7 @@ export default class BodyWidget extends React.Component { }); try { - let response = await axios.post(initUrl); + let response = await this.apiObj.post(initUrl); this.setState({ conn_status: CONNECT_STATUS.CONNECTED, server_version: response.data.data.serverVersion, @@ -789,7 +858,7 @@ export default class BodyWidget extends React.Component { }); try { - let response = await axios.get(url); + let response = await this.apiObj.get(url); let data = response.data.data; this.diagram.setCache('colTypes', data['col_types']); this.diagram.setCache('schemas', data['schemas']); @@ -812,7 +881,7 @@ export default class BodyWidget extends React.Component { }); try { - let response = await axios.get(url); + let response = await this.apiObj.get(url); this.diagram.deserializeData(response.data.data); return true; } catch (error) { @@ -824,74 +893,27 @@ export default class BodyWidget extends React.Component { } render() { + this.erdDialogs.modal = this.context; + return ( - - - - - {this.onSaveDiagram();}} title={gettext('Save project')} - shortcut={this.state.preferences.save_project} disabled={!this.state.dirty}/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + -
{e.preventDefault();}}> + anchorEl={this.noteRefEle} noteNode={this.state.note_node} appendTo={this.diagramContainerRef.current} rows={8}/> +
{e.preventDefault();}}> - {this.canvasEle = ele?.ref?.current;}} engine={this.diagram.getEngine()} /> + {this.canvasEle = ele?.ref?.current;}} engine={this.diagram.getEngine()} />
- + ); } } +export default withStyles(styles)(ERDTool); -BodyWidget.propTypes = { +ERDTool.propTypes = { params:PropTypes.shape({ trans_id: PropTypes.number.isRequired, sgid: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired, @@ -903,9 +925,8 @@ BodyWidget.propTypes = { fgcolor: PropTypes.string, gen: PropTypes.bool.isRequired, }), - getDialog: PropTypes.func.isRequired, pgWindow: PropTypes.object.isRequired, pgAdmin: PropTypes.object.isRequired, - alertify: PropTypes.object.isRequired, panel: PropTypes.object, + classes: PropTypes.object, }; 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 new file mode 100644 index 000000000..f7578db8b --- /dev/null +++ b/web/pgadmin/tools/erd/static/js/erd_tool/components/FloatingNote.jsx @@ -0,0 +1,99 @@ +///////////////////////////////////////////////////////////// +// +// pgAdmin 4 - PostgreSQL Tools +// +// Copyright (C) 2013 - 2022, The pgAdmin Development Team +// This software is released under the PostgreSQL Licence +// +////////////////////////////////////////////////////////////// + +import React, { useEffect, useState, useMemo } from 'react'; +import gettext from 'sources/gettext'; +import PropTypes from 'prop-types'; +import CustomPropTypes from 'sources/custom_prop_types'; +import { Box, makeStyles, Popper } from '@material-ui/core'; +import { DefaultButton } from '../../../../../../static/js/components/Buttons'; +import CheckIcon from '@material-ui/icons/Check'; + + +const useStyles = makeStyles((theme)=>({ + root: { + width: '250px', + marginLeft: '8px', + ...theme.mixins.panelBorder.all, + borderRadius: theme.shape.borderRadius, + backgroundColor: theme.palette.background.default, + color: theme.palette.text.primary, + }, + note: { + padding: '4px', + backgroundColor: theme.palette.primary.main, + color: theme.palette.primary.contrastText, + borderTopLeftRadius: 'inherit', + borderTopRightRadius: 'inherit', + }, + header: { + padding: '4px', + whiteSpace: 'nowrap', + overflow: 'hidden', + textOverflow: 'ellipsis', + ...theme.mixins.panelBorder.bottom, + }, + textarea: { + width: '100%', + border: 0, + display: 'block', + }, + buttons: { + padding: '4px', + ...theme.mixins.panelBorder.top, + textAlign: 'right', + }, +})); + +export default function FloatingNote({open, onClose, anchorEl, rows, noteNode}) { + const [text, setText] = useState(''); + const classes = useStyles(); + useEffect(()=>{ + if(noteNode) { + setText(noteNode.getNote()); + } + }, [noteNode]); + + const header = useMemo(()=>{ + if(noteNode) { + let [schema, name] = noteNode.getSchemaTableName(); + return `${name} (${schema})`; + } + return ''; + }, [open]); + + return ( + + + {gettext('Note')}: + {header} + -
- -
-
-
- )} - visible={open} - interactive={true} - animation={false} - reference={reference} - placement='auto-end' - {...tippyProps} - /> - ); -} - -FloatingNote.propTypes = { - open: PropTypes.bool.isRequired, - onClose: PropTypes.func.isRequired, - reference: CustomPropTypes.ref, - rows: PropTypes.number, - noteNode: PropTypes.object, -}; diff --git a/web/pgadmin/tools/erd/static/js/erd_tool/ui_components/Loader.jsx b/web/pgadmin/tools/erd/static/js/erd_tool/ui_components/Loader.jsx deleted file mode 100644 index 2aa2af448..000000000 --- a/web/pgadmin/tools/erd/static/js/erd_tool/ui_components/Loader.jsx +++ /dev/null @@ -1,34 +0,0 @@ -///////////////////////////////////////////////////////////// -// -// pgAdmin 4 - PostgreSQL Tools -// -// Copyright (C) 2013 - 2022, The pgAdmin Development Team -// This software is released under the PostgreSQL Licence -// -////////////////////////////////////////////////////////////// - -import React from 'react'; -import PropTypes from 'prop-types'; - -/* The loader/spinner component */ -export default function Loader({message, autoEllipsis=false}) { - if(message || message == '') { - return ( -
-
-
-
-
-
{message}{autoEllipsis ? '...':''}
-
-
- ); - } else { - return null; - } -} - -Loader.propTypes = { - message: PropTypes.string, - autoEllipsis: PropTypes.bool, -}; diff --git a/web/pgadmin/tools/erd/static/js/erd_tool/ui_components/ToolBar.jsx b/web/pgadmin/tools/erd/static/js/erd_tool/ui_components/ToolBar.jsx deleted file mode 100644 index 33a07e277..000000000 --- a/web/pgadmin/tools/erd/static/js/erd_tool/ui_components/ToolBar.jsx +++ /dev/null @@ -1,146 +0,0 @@ -///////////////////////////////////////////////////////////// -// -// pgAdmin 4 - PostgreSQL Tools -// -// Copyright (C) 2013 - 2022, The pgAdmin Development Team -// This software is released under the PostgreSQL Licence -// -////////////////////////////////////////////////////////////// - -import React, { forwardRef } from 'react'; -import Tippy from '@tippyjs/react'; -import {isMac} from 'sources/keyboard_shortcuts'; -import gettext from 'sources/gettext'; -import PropTypes from 'prop-types'; -import CustomPropTypes from 'sources/custom_prop_types'; - -/* The base icon button. -React does not pass ref prop to child component hierarchy. -Use forwardRef for the same -*/ -const BaseIconButton = forwardRef((props, ref)=>{ - const {icon, text, className, ...otherProps} = props; - - return( - - ); -}); -BaseIconButton.displayName = 'BaseIconButton'; - -BaseIconButton.propTypes = { - icon: PropTypes.string, - text: PropTypes.string, - className: PropTypes.string, - ref: CustomPropTypes.ref, -}; - - -/* The tooltip content to show shortcut details */ -export function Shortcut({shortcut}) { - let keys = []; - shortcut.alt && keys.push((isMac() ? 'Option' : 'Alt')); - shortcut.control && keys.push('Ctrl'); - shortcut.shift && keys.push('Shift'); - keys.push(shortcut.key.char.toUpperCase()); - return ( -
- {keys.map((key, i)=>{ - return
{key}
; - })} -
- ); -} - -const shortcutPropType = PropTypes.shape({ - alt: PropTypes.bool, - control: PropTypes.bool, - shift: PropTypes.bool, - key: PropTypes.shape({ - char: PropTypes.string, - }), -}); - -Shortcut.propTypes = { - shortcut: shortcutPropType, -}; - -/* The icon button component which can have a tooltip based on props. -React does not pass ref prop to child component hierarchy. -Use forwardRef for the same -*/ -export const IconButton = forwardRef((props, ref) => { - const {title, shortcut, className, ...otherProps} = props; - - if (title) { - return ( - - {
{title}
} - {shortcut && } - - }> - -
- ); - } else { - return ; - } -}); -IconButton.displayName = 'IconButton'; - -IconButton.propTypes = { - title: PropTypes.string, - shortcut: shortcutPropType, - className: PropTypes.string, -}; - -/* Toggle button, icon changes based on value */ -export function DetailsToggleButton({showDetails, ...props}) { - return ( - - ); -} - -DetailsToggleButton.propTypes = { - showDetails: PropTypes.bool, -}; - -/* Button group container */ -export function ButtonGroup({className, children}) { - return ( -
- {children} -
- ); -} - -ButtonGroup.propTypes = { - className: PropTypes.string, - children: PropTypes.oneOfType([ - PropTypes.arrayOf(PropTypes.node), - PropTypes.node - ]), -}; - -/* Toolbar container */ -export default function ToolBar({id, children}) { - return ( - - ); -} - -ToolBar.propTypes = { - id: PropTypes.string, - children: PropTypes.oneOfType([ - PropTypes.arrayOf(PropTypes.node), - PropTypes.node - ]), -}; diff --git a/web/pgadmin/tools/erd/static/js/erd_tool_hook.js b/web/pgadmin/tools/erd/static/js/erd_tool_hook.js deleted file mode 100644 index dafc69afd..000000000 --- a/web/pgadmin/tools/erd/static/js/erd_tool_hook.js +++ /dev/null @@ -1,35 +0,0 @@ -///////////////////////////////////////////////////////////// -// -// pgAdmin 4 - PostgreSQL Tools -// -// Copyright (C) 2013 - 2022, The pgAdmin Development Team -// This software is released under the PostgreSQL Licence -// -////////////////////////////////////////////////////////////// - -define([ - 'sources/pgadmin', 'pgadmin.tools.erd/erd_tool', 'pgadmin.browser', - 'pgadmin.browser.server.privilege', 'pgadmin.node.database', 'pgadmin.node.primary_key', - 'pgadmin.node.foreign_key', 'pgadmin.browser.datamodel', 'pgadmin.tools.file_manager', -], function( - pgAdmin, ERDToolModule -) { - var pgTools = pgAdmin.Tools = pgAdmin.Tools || {}; - var ERDTool = ERDToolModule.default; - - /* Return back, this has been called more than once */ - if (pgTools.ERDToolHook) - return pgTools.ERDToolHook; - - pgTools.ERDToolHook = { - load: function(params) { - /* Create the ERD Tool object and render it */ - let erdObj = new ERDTool('#erd-tool-container', params); - erdObj.render(); - }, - }; - - return pgTools.ERDToolHook; -}); - - diff --git a/web/pgadmin/tools/erd/static/js/index.js b/web/pgadmin/tools/erd/static/js/index.js index 2d8f2c1e3..71616c6c5 100644 --- a/web/pgadmin/tools/erd/static/js/index.js +++ b/web/pgadmin/tools/erd/static/js/index.js @@ -6,18 +6,16 @@ // This software is released under the PostgreSQL Licence // ////////////////////////////////////////////////////////////// -import gettext from 'sources/gettext'; -import url_for from 'sources/url_for'; -import $ from 'jquery'; -import _ from 'underscore'; import pgAdmin from 'sources/pgadmin'; import pgBrowser from 'top/browser/static/js/browser'; -import * as csrfToken from 'sources/csrf'; -import {initialize} from './erd_module'; -var wcDocker = window.wcDocker; +import 'pgadmin.tools.file_manager'; +import ERDModule from './ERDModule'; -let pgBrowserOut = initialize(gettext, url_for, $, _, pgAdmin, csrfToken, pgBrowser, wcDocker); +if(!pgAdmin.Tools) { + pgAdmin.Tools = {}; +} +pgAdmin.Tools.ERD = ERDModule.getInstance(pgAdmin, pgBrowser); module.exports = { - pgBrowser: pgBrowserOut, + ERD: pgAdmin.Tools.ERD, }; diff --git a/web/pgadmin/tools/erd/static/scss/_erd.scss b/web/pgadmin/tools/erd/static/scss/_erd.scss deleted file mode 100644 index 246ceab4b..000000000 --- a/web/pgadmin/tools/erd/static/scss/_erd.scss +++ /dev/null @@ -1,265 +0,0 @@ -.shortcut-key { - padding: 0 0.25rem; - border: 1px solid $border-color; - margin-right: 0.125rem; - border-radius: $btn-border-radius; -} - -.connection_status_wrapper { - width: 100%; - border-top: $panel-border; - border-bottom: $panel-border; -} - -.connection_status .obtaining-conn { - background-image: $loader-icon-small !important; - background-position: center center; - background-repeat: no-repeat; - &:before { - content:''; - } - min-width: 50%; - min-height: 100%; -} - -.connection_status { - background-color: $sql-title-bg; - color: $sql-title-fg; - border-right: $border-width solid $border-color; - padding: 0px 8px; -} - -.editor-title { - padding: $sql-title-padding; - background: $sql-title-bg; - color: $sql-title-fg; -} - -.connection-info { - background: $sql-title-bg; - color: $sql-title-fg; - width:100%; - display: inherit; -} - -.connection-data { - display: inherit; - cursor: pointer; - width: auto; -} - -#erd-tool-container { - width: 100%; - height: 100%; - - .file-input-hidden { - height: 0; - width: 0; - visibility: hidden; - } - - .text-icon { - font-weight: bold; - } - - .erd-hint-bar { - background: $sql-gutters-bg; - padding: 0.25rem 0.5rem; - } - - .diagram-container { - position: relative; - width: 100%; - height: 100%; - min-height: 0; - } - - .floating-note { - width: 250px; - border: $panel-border; - border-radius: $panel-border-radius; - box-shadow: $dialog-box-shadow; - background-color: $alert-dialog-body-bg !important; - color: $color-fg !important; - - .note-header { - padding: 0.25rem 0.5rem; - background-color: $alert-header-bg; - font-size: $font-size-base; - font-weight: bold; - color: $alert-header-fg; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - border-radius: 0rem; - border-top-left-radius: $panel-border-radius; - border-top-right-radius: $panel-border-radius; - border-bottom: none; - margin: -$alertify-borderremove-margin; //-24px is default by alertify - margin-bottom: 0px; - } - - .note-body { - word-break: break-all; - & textarea { - width: 100%; - border: none; - border-bottom: $border-width solid $erd-node-border-color; - border-top: $border-width solid $erd-node-border-color; - } - - & .pg_buttons { - padding: 0.25rem; - } - } - } - - .html2canvas-reset { - background-image: none !important; - overflow: auto !important; - } - - .diagram-canvas{ - width: 100%; - height: 100%; - color: $color-fg; - font-family: sans-serif; - background-color: $erd-canvas-bg; - background-image: $erd-bg-grid; - cursor: unset; - - .table-node { - background-color: $input-bg; - border: $border-width solid $erd-node-border-color; - border-radius: $input-border-radius; - position: relative; - width: 175px; - font-size: 0.8em; - - .table-icon { - padding: 0rem 0.125rem; - } - - &.selected { - border-color: $input-focus-border-color; - box-shadow: $input-btn-focus-box-shadow; - } - - .table-toolbar { - background: $editor-toolbar-bg; - border-bottom: $border-width solid $erd-node-border-color; - padding: 0.125rem; - border-top-left-radius: inherit; - border-top-right-radius: inherit; - display: flex; - - .btn { - &:not(:first-of-type) { - margin-left: 0.125rem; - } - } - } - - .table-schema-data { - border-bottom: $border-width solid $erd-node-border-color; - padding: $erd-row-padding; - - & .table-schema { - font-weight: bold; - word-break: break-all; - } - } - - .table-name-data { - border-bottom: $border-width*2 solid $erd-node-border-color; - padding: $erd-row-padding; - - & .table-name { - font-weight: bold; - word-break: break-all; - } - - & .fetch-error { - color: $color-danger; - } - } - - .table-cols { - .col-row { - border-bottom: $border-width solid $erd-node-border-color; - .col-row-data { - padding: $erd-row-padding; - width: 100%; - word-break: break-all; - } - .col-row-port { - padding: 0; - min-height: 0; - } - } - } - } - - .svg-link-ele { - stroke: $erd-link-color; - } - - .svg-link-ele.path { - pointer-events: all; - cursor: move; - } - - @keyframes svg-link-ele-selected { - from { stroke-dashoffset: 24; } to { stroke-dashoffset: 0; } - } - - .svg-link-ele.selected { - stroke: $erd-link-selected-color; - stroke-dasharray: 10, 2; - animation: svg-link-ele-selected 1s linear infinite; - } - - .svg-link-ele.svg-otom-circle { - fill: $erd-link-color; - } - - .custom-node-color{ - position: absolute; - top: 50%; - left: 50%; - width: 20px; - height: 20px; - transform: translate(-50%, -50%); - border-radius: 10px; - } - - .circle-port{ - width: 12px; - height: 12px; - margin: 2px; - border-radius: 4px; - background: darkgray; - cursor: pointer; - } - - .circle-port:hover{ - background: mediumpurple; - } - - .port { - display: inline-block; - margin: auto; - } - } -} - -.alertify { - .erd-dialog { - .ajs-body .ajs-content { - bottom: 0!important; - } - .ajs-footer { - display: none; - } - } -} diff --git a/web/pgadmin/tools/erd/templates/erd/index.html b/web/pgadmin/tools/erd/templates/erd/index.html index 10a0896f5..3987bc425 100644 --- a/web/pgadmin/tools/erd/templates/erd/index.html +++ b/web/pgadmin/tools/erd/templates/erd/index.html @@ -7,15 +7,23 @@ {% block body %}
+
+
+
+
+
+
+
{% endblock %} {% block init_script %} @@ -23,25 +31,9 @@ require( ['sources/generated/browser_nodes', 'sources/generated/codemirror'], function() { - require(['sources/generated/erd_tool'], function(erdToolHook) { - var erdToolHook = erdToolHook || pgAdmin.Tools.ERDToolHook; - erdToolHook.load({{ params|safe }}); - - if(window.opener) { - $(window).on('unload', function(ev) { - $.ajax({ - method: 'DELETE', - url: '{{close_url}}' - }); - }); - } else { - $(window).on('beforeunload', function(ev) { - $.ajax({ - method: 'DELETE', - url: '{{close_url}}' - }); - }); - } + require(['sources/generated/erd_tool'], function(module) { + window.pgAdmin.Tools.ERD.loadComponent( + document.getElementById('erd-tool-container'), {{ params|safe }}); }, function() { console.log(arguments); }); diff --git a/web/pgadmin/tools/sqleditor/static/js/SQLEditorModule.js b/web/pgadmin/tools/sqleditor/static/js/SQLEditorModule.js index 0edc39247..e2aa7b8ad 100644 --- a/web/pgadmin/tools/sqleditor/static/js/SQLEditorModule.js +++ b/web/pgadmin/tools/sqleditor/static/js/SQLEditorModule.js @@ -16,7 +16,6 @@ import $ from 'jquery'; import url_for from 'sources/url_for'; import _ from 'lodash'; import alertify from 'pgadmin.alertifyjs'; -var wcDocker = window.wcDocker; import pgWindow from 'sources/window'; import pgAdmin from 'sources/pgadmin'; import pgBrowser from 'pgadmin.browser'; @@ -29,6 +28,7 @@ import QueryToolComponent from './components/QueryToolComponent'; import ModalProvider from '../../../../static/js/helpers/ModalProvider'; import Theme from '../../../../static/js/Theme'; +const wcDocker = window.wcDocker; export function setPanelTitle(queryToolPanel, panelTitle) { queryToolPanel.title(''+panelTitle+''); diff --git a/web/pgadmin/tools/sqleditor/static/js/components/sections/Query.jsx b/web/pgadmin/tools/sqleditor/static/js/components/sections/Query.jsx index d246209bb..366384fc7 100644 --- a/web/pgadmin/tools/sqleditor/static/js/components/sections/Query.jsx +++ b/web/pgadmin/tools/sqleditor/static/js/components/sections/Query.jsx @@ -13,7 +13,7 @@ import CodeMirror from '../../../../../../static/js/components/CodeMirror'; import {PANELS, QUERY_TOOL_EVENTS} from '../QueryToolConstants'; import url_for from 'sources/url_for'; import { LayoutEventsContext, LAYOUT_EVENTS } from '../../../../../../static/js/helpers/Layout'; -import ConfirmSaveContent from '../dialogs/ConfirmSaveContent'; +import ConfirmSaveContent from '../../../../../../static/js/Dialogs/ConfirmSaveContent'; import gettext from 'sources/gettext'; import OrigCodeMirror from 'bundled_codemirror'; import Notifier from '../../../../../../static/js/helpers/Notifier'; diff --git a/web/pgadmin/tools/sqleditor/static/js/components/sections/ResultSet.jsx b/web/pgadmin/tools/sqleditor/static/js/components/sections/ResultSet.jsx index 54476d41a..84b046b14 100644 --- a/web/pgadmin/tools/sqleditor/static/js/components/sections/ResultSet.jsx +++ b/web/pgadmin/tools/sqleditor/static/js/components/sections/ResultSet.jsx @@ -25,7 +25,7 @@ import { QuerySources } from './QueryHistory'; import { getBrowser } from '../../../../../../static/js/utils'; import CopyData from '../QueryToolDataGrid/CopyData'; import moment from 'moment'; -import ConfirmSaveContent from '../dialogs/ConfirmSaveContent'; +import ConfirmSaveContent from '../../../../../../static/js/Dialogs/ConfirmSaveContent'; import { makeStyles } from '@material-ui/styles'; import EmptyPanelMessage from '../../../../../../static/js/components/EmptyPanelMessage'; import { GraphVisualiser } from './GraphVisualiser'; diff --git a/web/pgadmin/tools/sqleditor/templates/sqleditor/index.html b/web/pgadmin/tools/sqleditor/templates/sqleditor/index.html index cd71864ff..bda8dca48 100644 --- a/web/pgadmin/tools/sqleditor/templates/sqleditor/index.html +++ b/web/pgadmin/tools/sqleditor/templates/sqleditor/index.html @@ -15,13 +15,6 @@ #sqleditor-container:not(:empty) + .pg-sp-container { display: none; } - {% if is_desktop_mode and is_linux %} - .alertify .ajs-dimmer,.alertify .ajs-modal{-webkit-transform: none;} - .alertify-notifier{-webkit-transform: none;} - .alertify-notifier .ajs-message{-webkit-transform: none;} - .alertify .ajs-dialog.ajs-shake{-webkit-animation-name: none;} - .sql-editor-busy-icon.fa-pulse{-webkit-animation: none;} - {% endif %}
diff --git a/web/regression/javascript/erd/keyboard_shortcut_action_spec.js b/web/regression/javascript/erd/keyboard_shortcut_action_spec.js index b504f37b0..993684f83 100644 --- a/web/regression/javascript/erd/keyboard_shortcut_action_spec.js +++ b/web/regression/javascript/erd/keyboard_shortcut_action_spec.js @@ -6,7 +6,7 @@ // This software is released under the PostgreSQL Licence // ////////////////////////////////////////////////////////////// -import {KeyboardShortcutAction} from 'pgadmin.tools.erd/erd_tool/ui_components/BodyWidget'; +import {KeyboardShortcutAction} from 'pgadmin.tools.erd/erd_tool/components/ERDTool'; describe('KeyboardShortcutAction', ()=>{ let keyAction = null; diff --git a/web/regression/javascript/erd/table_node_spec.js b/web/regression/javascript/erd/table_node.spec.js similarity index 73% rename from web/regression/javascript/erd/table_node_spec.js rename to web/regression/javascript/erd/table_node.spec.js index 04fa4c75c..e516d71e8 100644 --- a/web/regression/javascript/erd/table_node_spec.js +++ b/web/regression/javascript/erd/table_node.spec.js @@ -5,7 +5,7 @@ import '../helper/enzyme.helper'; import { DefaultNodeModel } from '@projectstorm/react-diagrams'; import {TableNodeModel, TableNodeWidget} from 'pgadmin.tools.erd/erd_tool/nodes/TableNode'; -import { IconButton, DetailsToggleButton } from 'pgadmin.tools.erd/erd_tool/ui_components/ToolBar'; +import Theme from '../../../pgadmin/static/js/Theme'; describe('ERD TableNodeModel', ()=>{ @@ -211,63 +211,45 @@ describe('ERD TableNodeWidget', ()=>{ }); it('render', ()=>{ - let nodeWidget = mount(); - expect(nodeWidget.getDOMNode().className).toBe('table-node '); - expect(nodeWidget.find('.table-node .table-toolbar').length).toBe(1); - expect(nodeWidget.find('.table-node .table-schema').text()).toBe('erd'); - expect(nodeWidget.find('.table-node .table-name').text()).toBe('table1'); - expect(nodeWidget.find('.table-node .table-cols').length).toBe(1); - expect(nodeWidget.find(DetailsToggleButton).length).toBe(1); - expect(nodeWidget.find(IconButton).findWhere(n => n.prop('title')=='Check note').length).toBe(1); - }); - - it('node selected', ()=>{ - spyOn(node, 'isSelected').and.returnValue(true); - let nodeWidget = mount(); - expect(nodeWidget.getDOMNode().className).toBe('table-node selected'); + let nodeWidget = mount(); + expect(nodeWidget.find('DefaultButton[aria-label="Show Details"]').length).toBe(1); + expect(nodeWidget.find('DefaultButton[aria-label="Check Note"]').length).toBe(1); + expect(nodeWidget.find('div[data-test="schema-name"]').length).toBe(1); + expect(nodeWidget.find('div[data-test="table-name"]').length).toBe(1); + expect(nodeWidget.find('div[data-test="column-row"]').length).toBe(3); }); it('remove note', ()=>{ node.setNote(''); - let nodeWidget = mount(); - expect(nodeWidget.find(IconButton).findWhere(n => n.prop('title')=='Check note').length).toBe(0); + let nodeWidget = mount(); + expect(nodeWidget.find('PgIconButton[aria-label="Check Note"]').length).toBe(0); }); describe('generateColumn', ()=>{ let nodeWidget = null; beforeEach(()=>{ - nodeWidget = mount(); + nodeWidget = mount(); }); it('count', ()=>{ - expect(nodeWidget.find('.table-node .table-cols .col-row').length).toBe(3); + expect(nodeWidget.find('div[data-test="column-row"]').length).toBe(3); }); it('column names', ()=>{ - let cols = nodeWidget.find('.table-node .table-cols .col-row-data'); - expect(cols.at(0).find('.col-name').text()).toBe('id'); - expect(cols.at(1).find('.col-name').text()).toBe('amount'); - expect(cols.at(2).find('.col-name').text()).toBe('desc'); + let cols = nodeWidget.find('div[data-test="column-row"]'); + + expect(cols.at(0).find('span[data-test="column-name"]').text()).toBe('id'); + expect(cols.at(1).find('span[data-test="column-name"]').text()).toBe('amount'); + expect(cols.at(2).find('span[data-test="column-name"]').text()).toBe('desc'); }); it('data types', ()=>{ - let cols = nodeWidget.find('.table-node .table-cols .col-row-data'); - expect(cols.at(0).find('.col-datatype').text()).toBe('integer'); - expect(cols.at(1).find('.col-datatype').text()).toBe('number(10,5)'); - expect(cols.at(2).find('.col-datatype').text()).toBe('character varrying(50)'); - }); + let cols = nodeWidget.find('div[data-test="column-row"]'); - it('show_details', (done)=>{ - nodeWidget.setState({show_details: false}); - expect(nodeWidget.find('.table-node .table-cols .col-row-data .col-datatype').length).toBe(0); - - nodeWidget.instance().toggleShowDetails(jasmine.createSpyObj('event', ['preventDefault'])); - /* Dummy set state to wait for toggleShowDetails -> setState to complete */ - nodeWidget.setState({}, ()=>{ - expect(nodeWidget.find('.table-node .table-cols .col-row-data .col-datatype').length).toBe(3); - done(); - }); + expect(cols.at(0).find('span[data-test="column-type"]').text()).toBe('integer'); + expect(cols.at(1).find('span[data-test="column-type"]').text()).toBe('number(10,5)'); + expect(cols.at(2).find('span[data-test="column-type"]').text()).toBe('character varrying(50)'); }); }); }); diff --git a/web/regression/javascript/erd/ui_components/ConnectionBar.spec.js b/web/regression/javascript/erd/ui_components/ConnectionBar.spec.js new file mode 100644 index 000000000..92985e4dd --- /dev/null +++ b/web/regression/javascript/erd/ui_components/ConnectionBar.spec.js @@ -0,0 +1,32 @@ +import jasmineEnzyme from 'jasmine-enzyme'; +import React from 'react'; +import {mount} from 'enzyme'; +import '../../helper/enzyme.helper'; + +import ConnectionBar, {STATUS} from 'pgadmin.tools.erd/erd_tool/components/ConnectionBar'; +import Theme from '../../../../pgadmin/static/js/Theme'; + +describe('ERD ConnectionBar', ()=>{ + beforeEach(()=>{ + jasmineEnzyme(); + }); + + it(' comp', ()=>{ + const connBar = mount(); + + expect(connBar.find('DefaultButton[data-test="btn-conn-title"]').text()).toBe('test title'); + + connBar.setProps({ + children: + }); + expect(connBar.find('DefaultButton[data-test="btn-conn-title"]').text()).toBe('(Obtaining connection...) test title'); + + connBar.setProps({ + children: + }); + const titleEle = connBar.find('DefaultButton[data-test="btn-conn-title"]'); + + expect(titleEle.prop('style').backgroundColor).toBe('#000'); + expect(titleEle.prop('style').color).toBe('#fff'); + }); +}); diff --git a/web/regression/javascript/erd/ui_components/body_widget_spec.js b/web/regression/javascript/erd/ui_components/ERDTool.spec.js similarity index 86% rename from web/regression/javascript/erd/ui_components/body_widget_spec.js rename to web/regression/javascript/erd/ui_components/ERDTool.spec.js index 04f9fa13c..c65131113 100644 --- a/web/regression/javascript/erd/ui_components/body_widget_spec.js +++ b/web/regression/javascript/erd/ui_components/ERDTool.spec.js @@ -1,4 +1,3 @@ -import jasmineEnzyme from 'jasmine-enzyme'; import React from 'react'; import {mount} from 'enzyme'; import '../../helper/enzyme.helper'; @@ -6,12 +5,14 @@ import MockAdapter from 'axios-mock-adapter'; import axios from 'axios/index'; import ERDCore from 'pgadmin.tools.erd/erd_tool/ERDCore'; -import * as erdModule from 'pgadmin.tools.erd/erd_module'; +import * as erdModule from 'pgadmin.tools.erd/ERDModule'; import erdPref from './erd_preferences'; -import BodyWidget from 'pgadmin.tools.erd/erd_tool/ui_components/BodyWidget'; +import ERDTool from 'pgadmin.tools.erd/erd_tool/components/ERDTool'; import * as ERDSqlTool from 'tools/sqleditor/static/js/show_query_tool'; import { FakeLink, FakeNode, FakePort } from '../fake_item'; import Notify from '../../../../pgadmin/static/js/helpers/Notifier'; +import Theme from '../../../../pgadmin/static/js/Theme'; +import ModalProvider from '../../../../pgadmin/static/js/helpers/ModalProvider'; let pgAdmin = { @@ -50,18 +51,9 @@ let pgWindow = { pgAdmin: pgAdmin, }; -let alertify = jasmine.createSpyObj('alertify', { - 'success': null, - 'error': null, - 'confirm': null, - 'alert': { - 'set': ()=>{/*This is intentional (SonarQube)*/}, - }, -}); - -let tableDialog = jasmine.createSpyObj('TableDialog', ['show']); -let otmDialog = jasmine.createSpyObj('otmDialog', ['show']); -let mtmDialog = jasmine.createSpyObj('mtmDialog', ['show']); +let tableDialog = jasmine.createSpy('TableDialog'); +let otmDialog = jasmine.createSpy('otmDialog'); +let mtmDialog = jasmine.createSpy('mtmDialog'); let getDialog = (dialogName)=>{ switch(dialogName) { @@ -71,7 +63,8 @@ let getDialog = (dialogName)=>{ } }; -describe('ERD BodyWidget', ()=>{ +describe('ERDTool', ()=>{ + let erd = null; let body = null; let bodyInstance = null; let networkMock = null; @@ -129,36 +122,34 @@ describe('ERD BodyWidget', ()=>{ }); beforeEach(()=>{ - jasmineEnzyme(); - body = mount(); + erd = mount( + + + + + + ); + body = erd.find('ERDTool'); bodyInstance = body.instance(); + spyOn(bodyInstance, 'getDialog').and.callFake(getDialog); }); afterAll(() => { networkMock.restore(); - if(body) { - body.unmount(); + if(erd) { + erd.unmount(); } }); it('constructor', (done)=>{ - - expect(body.find('ToolBar').length).toBe(1); - expect(body.find('ConnectionBar').length).toBe(1); - expect(body.find('FloatingNote').length).toBe(1); - expect(body.find('.diagram-container Loader').length).toBe(1); - expect(body.find('.diagram-container CanvasWidget').length).toBe(1); - - body.instance().setState({}, ()=>{ - let instance = body.instance(); - + bodyInstance.setState({}, ()=>{ setTimeout(()=>{ expect(body.state()).toEqual(jasmine.objectContaining({ server_version: serverVersion, preferences: erdPref, })); - expect(instance.diagram.getCache('colTypes')).toEqual(colTypes); - expect(instance.diagram.getCache('schemas')).toEqual(schemas); + expect(bodyInstance.diagram.getCache('colTypes')).toEqual(colTypes); + expect(bodyInstance.diagram.getCache('schemas')).toEqual(schemas); done(); }); }); @@ -237,17 +228,6 @@ describe('ERD BodyWidget', ()=>{ }); }); - it('getDialog', ()=>{ - bodyInstance.getDialog('table_dialog')(); - expect(tableDialog.show).toHaveBeenCalled(); - - bodyInstance.getDialog('onetomany_dialog')(); - expect(otmDialog.show).toHaveBeenCalled(); - - bodyInstance.getDialog('manytomany_dialog')(); - expect(mtmDialog.show).toHaveBeenCalled(); - }); - it('addEditTable', ()=>{ let node1 = new FakeNode({'name': 'table1', schema: 'erd1', columns: [{name: 'col1', type: 'type1', attnum: 1}]}, 'id1'); let node2 = new FakeNode({'name': 'table2', schema: 'erd2', columns: [{name: 'col2', type: 'type2', attnum: 2}]}, 'id2'); @@ -261,23 +241,23 @@ describe('ERD BodyWidget', ()=>{ spyOn(bodyInstance.diagram, 'addLink'); spyOn(bodyInstance.diagram, 'syncTableLinks'); /* New */ - tableDialog.show.calls.reset(); + tableDialog.calls.reset(); bodyInstance.addEditTable(); - expect(tableDialog.show).toHaveBeenCalled(); + expect(tableDialog).toHaveBeenCalled(); - let saveCallback = tableDialog.show.calls.mostRecent().args[7]; + let saveCallback = tableDialog.calls.mostRecent().args[3]; let newData = {key: 'value'}; saveCallback(newData); expect(bodyInstance.diagram.addNode).toHaveBeenCalledWith(newData); /* Existing */ - tableDialog.show.calls.reset(); + tableDialog.calls.reset(); let node = new FakeNode({name: 'table1', schema: 'erd1'}); spyOn(node, 'setData'); bodyInstance.addEditTable(node); - expect(tableDialog.show).toHaveBeenCalled(); + expect(tableDialog).toHaveBeenCalled(); - saveCallback = tableDialog.show.calls.mostRecent().args[7]; + saveCallback = tableDialog.calls.mostRecent().args[3]; newData = {key: 'value'}; saveCallback(newData); expect(node.setData).toHaveBeenCalledWith(newData); @@ -435,11 +415,8 @@ describe('ERD BodyWidget', ()=>{ spyOn(bodyInstance.diagram, 'addLink'); spyOn(bodyInstance.diagram, 'getSelectedNodes').and.returnValue([node]); - otmDialog.show.calls.reset(); bodyInstance.onOneToManyClick(); - expect(otmDialog.show).toHaveBeenCalled(); - - let saveCallback = otmDialog.show.calls.mostRecent().args[4]; + let saveCallback = otmDialog.calls.mostRecent().args[2]; let newData = { local_table_uid: 'id1', local_column_attnum: 1, @@ -452,13 +429,6 @@ describe('ERD BodyWidget', ()=>{ it('onManyToManyClick', ()=>{ let node = new FakeNode({}, 'id1'); - spyOn(bodyInstance.diagram, 'getSelectedNodes').and.returnValue([node]); - - mtmDialog.show.calls.reset(); - bodyInstance.onManyToManyClick(); - expect(mtmDialog.show).toHaveBeenCalled(); - - /* onSave */ let node1 = new FakeNode({'name': 'table1', schema: 'erd1', columns: [{name: 'col1', type: 'type1', attnum: 1}]}, 'id1'); let node2 = new FakeNode({'name': 'table2', schema: 'erd2', columns: [{name: 'col2', type: 'type2', attnum: 2}]}, 'id2'); let nodesDict = { @@ -469,8 +439,13 @@ describe('ERD BodyWidget', ()=>{ spyOn(bodyInstance.diagram, 'getModel').and.returnValue({ 'getNodesDict': ()=>nodesDict, }); + spyOn(bodyInstance.diagram, 'getSelectedNodes').and.returnValue([node]); + + bodyInstance.onManyToManyClick(); + + /* onSave */ spyOn(bodyInstance.diagram, 'addLink'); - let saveCallback = mtmDialog.show.calls.mostRecent().args[4]; + let saveCallback = mtmDialog.calls.mostRecent().args[2]; let newData = { left_table_uid: 'id1', left_table_column_attnum: 1, diff --git a/web/regression/javascript/erd/ui_components/floating_note_spec.js b/web/regression/javascript/erd/ui_components/FloatingNote.spec.js similarity index 68% rename from web/regression/javascript/erd/ui_components/floating_note_spec.js rename to web/regression/javascript/erd/ui_components/FloatingNote.spec.js index f786267bf..3af8f2fba 100644 --- a/web/regression/javascript/erd/ui_components/floating_note_spec.js +++ b/web/regression/javascript/erd/ui_components/FloatingNote.spec.js @@ -3,7 +3,8 @@ import React from 'react'; import {mount} from 'enzyme'; import '../../helper/enzyme.helper'; -import FloatingNote from 'pgadmin.tools.erd/erd_tool/ui_components/FloatingNote'; +import FloatingNote from 'pgadmin.tools.erd/erd_tool/components/FloatingNote'; +import Theme from '../../../../pgadmin/static/js/Theme'; describe('ERD FloatingNote', ()=>{ @@ -24,15 +25,20 @@ describe('ERD FloatingNote', ()=>{ }, }; - floatNote = mount(); + floatNote = mount( + + + ); floatNote.find('textarea').simulate('change', { target: { value: 'the new note', }, }); - floatNote.find('button[data-label="OK"]').simulate('click'); + + floatNote.find('DefaultButton').simulate('click'); expect(noteNode.setNote).toHaveBeenCalledWith('the new note'); expect(onClose).toHaveBeenCalled(); }); diff --git a/web/regression/javascript/erd/ui_components/connection_bar_spec.js b/web/regression/javascript/erd/ui_components/connection_bar_spec.js deleted file mode 100644 index 17398a54e..000000000 --- a/web/regression/javascript/erd/ui_components/connection_bar_spec.js +++ /dev/null @@ -1,25 +0,0 @@ -import jasmineEnzyme from 'jasmine-enzyme'; -import React from 'react'; -import {mount} from 'enzyme'; -import '../../helper/enzyme.helper'; - -import ConnectionBar, {STATUS} from 'pgadmin.tools.erd/erd_tool/ui_components/ConnectionBar'; - -describe('ERD ConnectionBar', ()=>{ - beforeEach(()=>{ - jasmineEnzyme(); - }); - - it(' comp', ()=>{ - let connBar = mount(); - - expect(connBar.find('.editor-title').text()).toBe('test title'); - - connBar.setProps({status: STATUS.CONNECTING}); - expect(connBar.find('.editor-title').text()).toBe('(Obtaining connection...) test title'); - - connBar.setProps({bgcolor: '#000', fgcolor: '#fff'}); - expect(connBar.find('.editor-title').prop('style').backgroundColor).toBe('#000'); - expect(connBar.find('.editor-title').prop('style').color).toBe('#fff'); - }); -}); diff --git a/web/regression/javascript/erd/ui_components/loader_spec.js b/web/regression/javascript/erd/ui_components/loader_spec.js deleted file mode 100644 index b73b69098..000000000 --- a/web/regression/javascript/erd/ui_components/loader_spec.js +++ /dev/null @@ -1,23 +0,0 @@ -import jasmineEnzyme from 'jasmine-enzyme'; -import React from 'react'; -import {shallow} from 'enzyme'; -import '../../helper/enzyme.helper'; - -import Loader from 'pgadmin.tools.erd/erd_tool/ui_components/Loader'; - -describe('ERD Loader', ()=>{ - beforeEach(()=>{ - jasmineEnzyme(); - }); - - it(' comp', ()=>{ - let loaderComp = shallow(); - expect(loaderComp.isEmptyRender()).toBeTruthy(); - - loaderComp.setProps({message: 'test message'}); - expect(loaderComp.find('.pg-sp-text').text()).toBe('test message'); - - loaderComp.setProps({autoEllipsis: true}); - expect(loaderComp.find('.pg-sp-text').text()).toBe('test message...'); - }); -}); diff --git a/web/regression/javascript/erd/ui_components/toolbar_spec.js b/web/regression/javascript/erd/ui_components/toolbar_spec.js deleted file mode 100644 index 0429d718d..000000000 --- a/web/regression/javascript/erd/ui_components/toolbar_spec.js +++ /dev/null @@ -1,76 +0,0 @@ -import jasmineEnzyme from 'jasmine-enzyme'; -import React from 'react'; -import Tippy from '@tippyjs/react'; -import {mount, shallow} from 'enzyme'; -import '../../helper/enzyme.helper'; - -import ToolBar, {ButtonGroup, DetailsToggleButton, IconButton, Shortcut} from 'pgadmin.tools.erd/erd_tool/ui_components/ToolBar'; - -describe('ERD Toolbar', ()=>{ - beforeEach(()=>{ - jasmineEnzyme(); - }); - - it(' comp', ()=>{ - let toolBar = mount(
); - expect(toolBar.getDOMNode().id).toBe('id1'); - expect(toolBar.find('.test').length).toBe(1); - }); - - it(' comp', ()=>{ - let btnGrp = mount(
); - expect(btnGrp.getDOMNode().className).toBe('btn-group mr-1 '); - expect(btnGrp.find('.test').length).toBe(1); - btnGrp.unmount(); - - btnGrp = mount(); - expect(btnGrp.getDOMNode().className).toBe('btn-group mr-1 someclass'); - }); - - it(' comp', ()=>{ - let toggle = shallow(); - let btn = toggle.find(IconButton); - expect(btn.prop('icon')).toBe('far fa-eye'); - expect(btn.prop('title')).toBe('Show fewer details'); - - toggle.setProps({showDetails: false}); - btn = toggle.find(IconButton); - expect(btn.prop('icon')).toBe('fas fa-low-vision'); - expect(btn.prop('title')).toBe('Show more details'); - }); - - it(' comp', ()=>{ - let btn = mount(); - - let tippy = btn.find(Tippy); - expect(tippy.length).toBe(0); - - btn.setProps({title: 'test title'}); - tippy = btn.find(Tippy); - expect(tippy.length).toBe(1); - - expect(btn.find('button').getDOMNode().className).toBe('btn btn-sm btn-primary-icon '); - - btn.setProps({icon: 'fa fa-icon'}); - expect(btn.find('button .sql-icon-lg').getDOMNode().className).toBe('fa fa-icon sql-icon-lg'); - }); - - it(' comp', ()=>{ - let key = { - alt: true, - control: true, - shift: false, - key: { - key_code: 65, - char: 'a', - }, - }; - let shortcutComp = mount(); - - expect(shortcutComp.find('.shortcut-key').length).toBe(3); - - key.alt = false; - shortcutComp.setProps({shortcut: key}); - expect(shortcutComp.find('.shortcut-key').length).toBe(2); - }); -}); diff --git a/web/regression/javascript/jasmine_capture_warnings_beforeall.js b/web/regression/javascript/jasmine_capture_warnings_beforeall.js index 2eab2d9ac..2088b6529 100644 --- a/web/regression/javascript/jasmine_capture_warnings_beforeall.js +++ b/web/regression/javascript/jasmine_capture_warnings_beforeall.js @@ -13,6 +13,13 @@ beforeAll(function () { spyOn(console, 'warn').and.callThrough(); spyOn(console, 'error').and.callThrough(); jasmine.getEnv().allowRespy(true); + + window.addEventListener('error', e => { + if(e.message === 'ResizeObserver loop completed with undelivered notifications.' || + e.message === 'ResizeObserver loop limit exceeded') { + e.stopImmediatePropagation(); + } + }); }); afterEach(function (done) { diff --git a/web/webpack.config.js b/web/webpack.config.js index 5c2e590a8..266a7b2c6 100644 --- a/web/webpack.config.js +++ b/web/webpack.config.js @@ -379,7 +379,7 @@ module.exports = [{ slickgrid: sourceDir + '/bundle/slickgrid.js', sqleditor: './pgadmin/tools/sqleditor/static/js/index.js', schema_diff: './pgadmin/tools/schema_diff/static/js/schema_diff_hook.js', - erd_tool: './pgadmin/tools/erd/static/js/erd_tool_hook.js', + erd_tool: './pgadmin/tools/erd/static/js/index.js', psql_tool: './pgadmin/tools/psql/static/js/index.js', debugger: './pgadmin/tools/debugger/static/js/index.js', 'pgadmin.style': pgadminCssStyles, @@ -546,7 +546,7 @@ module.exports = [{ 'pure|pgadmin.tools.schema_diff', 'pure|pgadmin.tools.file_manager', 'pure|pgadmin.tools.search_objects', - 'pure|pgadmin.tools.erd_module', + 'pure|pgadmin.tools.erd', 'pure|pgadmin.tools.psql_module', 'pure|pgadmin.tools.sqleditor', 'pure|pgadmin.misc.cloud', diff --git a/web/webpack.shim.js b/web/webpack.shim.js index 1e641339d..a9d334d44 100644 --- a/web/webpack.shim.js +++ b/web/webpack.shim.js @@ -281,7 +281,6 @@ var webpackShimConfig = { 'pgadmin.tools.schema_diff': path.join(__dirname, './pgadmin/tools/schema_diff/static/js/schema_diff'), 'pgadmin.tools.schema_diff_ui': path.join(__dirname, './pgadmin/tools/schema_diff/static/js/schema_diff_ui'), 'pgadmin.tools.search_objects': path.join(__dirname, './pgadmin/tools/search_objects/static/js'), - 'pgadmin.tools.erd_module': path.join(__dirname, './pgadmin/tools/erd/static/js/erd_module'), 'pgadmin.tools.erd': path.join(__dirname, './pgadmin/tools/erd/static/js'), 'pgadmin.tools.psql_module': path.join(__dirname, './pgadmin/tools/psql/static/js/psql_module'), 'pgadmin.tools.psql': path.join(__dirname, './pgadmin/tools/psql/static/js'), diff --git a/web/yarn.lock b/web/yarn.lock index edd69d777..b9d666f34 100644 --- a/web/yarn.lock +++ b/web/yarn.lock @@ -2306,11 +2306,6 @@ resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.21.tgz#5de5a2385a35309427f6011992b544514d559aa1" integrity sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g== -"@popperjs/core@^2.9.0": - version "2.10.2" - resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.10.2.tgz#0798c03351f0dea1a5a4cabddf26a55a7cbee590" - integrity sha512-IXf3XA7+XyN7CP9gGh/XB0UxVMlvARGEgGXLubFICsUMGz6Q+DU+i4gGlpOxTjKvXjkJDJC8YdqdKkDj9qZHEQ== - "@projectstorm/geometry@^6.6.1": version "6.6.1" resolved "https://registry.yarnpkg.com/@projectstorm/geometry/-/geometry-6.6.1.tgz#4a42f5c8fdfcc3d951e73f5db7fe9546514acc3d" @@ -2501,13 +2496,6 @@ prop-types "^15.7.2" react-transition-state "^1.1.3" -"@tippyjs/react@^4.2.0": - version "4.2.6" - resolved "https://registry.yarnpkg.com/@tippyjs/react/-/react-4.2.6.tgz#971677a599bf663f20bb1c60a62b9555b749cc71" - integrity sha512-91RicDR+H7oDSyPycI13q3b7o4O60wa2oRbjlz2fyRLmHImc4vyDwuUP8NtZaN0VARJY5hybvDYrFzhY9+Lbyw== - dependencies: - tippy.js "^6.3.1" - "@tootallnate/once@2": version "2.0.0" resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf" @@ -11061,13 +11049,6 @@ tiny-warning@^1.0.2: resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== -tippy.js@^6.3.1: - version "6.3.5" - resolved "https://registry.yarnpkg.com/tippy.js/-/tippy.js-6.3.5.tgz#cbc99d34f87ccc127e6460032b86c8d47971d38f" - integrity sha512-B9hAQ5KNF+jDJRg6cRysV6Y3J+5fiNfD60GuXR5TP0sfrcltpgdzVc7f1wMtjQ3W0+Xsy80CDvk0Z+Vr0cM4sQ== - dependencies: - "@popperjs/core" "^2.9.0" - tmp@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14"