public inbox for [email protected]
help / color / mirror / Atom feedFrom: Aditya Toshniwal <[email protected]>
To: pgadmin-hackers <[email protected]>
Cc: Akshay Joshi <[email protected]>
Cc: Khushboo Vashi <[email protected]>
Cc: Dave Page <[email protected]>
Subject: Re: [pgAdmin][RM1802] ERD Tool (Beta)
Date: Mon, 25 Jan 2021 17:17:40 +0530
Message-ID: <CAM9w-_kYsHOi+AEDxVKAEG5z9m=OhisSYfPKTDQjG8ogu03DUA@mail.gmail.com> (raw)
In-Reply-To: <CAM9w-_nuo6d-xO1a2PASSBLeb9Q2603cXeoGrqUQioCc1=7x_g@mail.gmail.com>
References: <CAM9w-_kowrenfKpiRLYWEpHJOOT2k9zRg6KCVpA0FR4Q=CA4hw@mail.gmail.com>
<CANxoLDda-CPNuU76FM1kOTdhNpRW170fr3FFQnaWxOpG=aeu2A@mail.gmail.com>
<CAFOhELd4JNuX82Vw3ZNdiKHHwBgu+rTdm9RfwY-qNjGkH47taQ@mail.gmail.com>
<CAFOhELdL0-M_itS4z-qNKUq6=RieWqc9UPos=oJTJFjyLrYQQw@mail.gmail.com>
<CAM9w-_kRdox8wvsHTwJ+vTOT2-kY1M4LvWFkm-799pEqJvHMsw@mail.gmail.com>
<CANxoLDcKjG-X=i7mrxVunS3oA+tBM3QmHgJN7y69CzT63y7a9A@mail.gmail.com>
<CAM9w-_=AFpLB-7aUVF2NZn4xRXe0o-LALJSjMsN8yBHqwd19fg@mail.gmail.com>
<CANxoLDcB4=x6qfL3HhW2E30c4N0pDLZtrKooMcocuRePM6v+sA@mail.gmail.com>
<CAM9w-_=Yn9wyEBxV2iBj5CLtyuqohLxD_263Z996jRNioXXGfQ@mail.gmail.com>
<CANxoLDcPBDfvXiPzLQGUL7tFxCkDmRWFD0vyirAQsbHR6Zzfdg@mail.gmail.com>
<CAM9w-_nmJP5aTpLqc02GmhpvDmesF5TCiOJkuR6jzTmgs7SuvQ@mail.gmail.com>
<CANxoLDfWqayrwbZkiCZ2dn+3m75hg+xN+LYzQwqVTb5o=Q21dw@mail.gmail.com>
<CA+OCxowvnkU-5kZK+ccxv_jGX=2Q_uHEGcYEZ9KEieSMnVuYvA@mail.gmail.com>
<CAM9w-_nr1mJdnnGj3UBWNNcJCCcFunOzZTu+_q+PeMWixyUnVA@mail.gmail.com>
<CA+OCxoz7zny2JW3uxft7ZBBeOjm45pWkj_L97Z8n+bUXT3v=OQ@mail.gmail.com>
<CAM9w-_nJDL0v4xb4U6RJNbpL-frSf7zVou4osB3EA9nqx8CyNA@mail.gmail.com>
<CAM9w-_nuo6d-xO1a2PASSBLeb9Q2603cXeoGrqUQioCc1=7x_g@mail.gmail.com>
Hi,
Please find the rebased patch from the latest pull.
On Mon, Jan 25, 2021 at 5:12 PM Aditya Toshniwal <
[email protected]> wrote:
> Hi Hackers,
>
> Attached is the patch to fix below issues in ERD:
>
> 1. After opening an existing project, the first table is already
> selected but edit, clone, delete buttons are disable. Fixed.
> 2. ERD project title gets changed when 2 ERD projects are open &
> anyone of it edited. Fixed.
> 3. Closing ERD tab, does not ask for confirmation pop up. Added.
> 4. Shortcut for 'Show more/Fewer details' is missing. Added.
> 5. Deleting primary key does not delete associated links. Fixed.
> 6. Long table & schema name are getting out of box. Fixed.
> 7. Long table name in notes pop-up need re-alignment. Fixed.
> 8. Same table name present in ERD/canvas is allowed in Add Table
> dialogue. Added validation in the dialog.
> 9. Download image option is added, but it is not perfect yet. Image
> icons (table, schema, etc.) are not showing up.
> 10. Rename panel option should be disabled by default. It should be
> enabled for the tools which implement rename functionality.
> 11. The Toolbar is not visible in Safari for the ERD tool. Fixed.
>
> Please review.
>
> On Thu, Jan 21, 2021 at 4:32 PM Aditya Toshniwal <
> [email protected]> wrote:
>
>> Hi,
>>
>>
>> On Thu, Jan 21, 2021 at 3:08 PM Dave Page <[email protected]> wrote:
>>
>>>
>>>
>>> On Thu, Jan 21, 2021 at 4:48 AM Aditya Toshniwal <
>>> [email protected]> wrote:
>>>
>>>> Hi Dave,
>>>>
>>>> On Wed, Jan 20, 2021 at 9:20 PM Dave Page <[email protected]> wrote:
>>>>
>>>>> Hi
>>>>>
>>>>> Where's the Save Image button gone? I know Aditya was removing it
>>>>> whilst working on other things, but it's still required for phase 1 release.
>>>>>
>>>> It was not working 100% right. :(
>>>> So I've removed it for the time being. I'm still working on it.
>>>>
>>>
>>> OK, so that work will be completed in time for the build next week?
>>>
>> I'm trying my best to make it available before release. I'm struggling to
>> make it work perfectly.
>>
>>>
>>>
>>>>
>>>>> On Mon, Jan 18, 2021 at 11:45 AM Akshay Joshi <
>>>>> [email protected]> wrote:
>>>>>
>>>>>> Thanks, patch applied.
>>>>>>
>>>>>> On Mon, Jan 18, 2021 at 5:08 PM Aditya Toshniwal <
>>>>>> [email protected]> wrote:
>>>>>>
>>>>>>> OK, So the changes have worked. But still failing at one more place.
>>>>>>> Attached the patch fixes it.
>>>>>>>
>>>>>>> On Mon, Jan 18, 2021 at 4:40 PM Akshay Joshi <
>>>>>>> [email protected]> wrote:
>>>>>>>
>>>>>>>> Thanks, patch applied.
>>>>>>>>
>>>>>>>> On Mon, Jan 18, 2021 at 2:58 PM Aditya Toshniwal <
>>>>>>>> [email protected]> wrote:
>>>>>>>>
>>>>>>>>> Hi,
>>>>>>>>>
>>>>>>>>> The jasmine test cases are working fine on my local machine. The
>>>>>>>>> test cases are successful on jenkins other than on linux, not sure why.
>>>>>>>>> I have made some fixes by looking at the log. Please review and
>>>>>>>>> try.
>>>>>>>>>
>>>>>>>>> On Mon, Jan 18, 2021 at 1:10 PM Akshay Joshi <
>>>>>>>>> [email protected]> wrote:
>>>>>>>>>
>>>>>>>>>> Thanks, patch applied.
>>>>>>>>>>
>>>>>>>>>> On Mon, Jan 18, 2021 at 10:34 AM Aditya Toshniwal <
>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>
>>>>>>>>>>> Hi Akshay,
>>>>>>>>>>>
>>>>>>>>>>> I forgot to remove few of the dependencies which are not
>>>>>>>>>>> required as of now (may be in future). Attached patch removes those
>>>>>>>>>>> dependencies from package.json.
>>>>>>>>>>>
>>>>>>>>>>> On Sat, Jan 16, 2021 at 5:08 PM Akshay Joshi <
>>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>>
>>>>>>>>>>>> Thanks, patch applied.
>>>>>>>>>>>>
>>>>>>>>>>>> On Fri, Jan 15, 2021 at 7:01 PM Aditya Toshniwal <
>>>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>>>
>>>>>>>>>>>>> Hi,
>>>>>>>>>>>>>
>>>>>>>>>>>>> I've fixed the issues. You can find the comments inline.
>>>>>>>>>>>>> I've also added PropTypes for the components for increased
>>>>>>>>>>>>> validation.
>>>>>>>>>>>>>
>>>>>>>>>>>>> On Tue, Jan 12, 2021 at 12:18 PM Khushboo Vashi <
>>>>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>>>>
>>>>>>>>>>>>>> Hi Aditya,
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> The functionalities and the code looks good to me, however some of the comments as below:
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> - Correct the comments at some places (3 occurrences found in /erd/__init__.py) which mention Schema diff instead of ERD.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Some comments in the JS/JSX file regarding components/functions (For example, IconButton (forwardRef), Bodywidget etc.) would
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> be great help as we all are new to React.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Done. Added comments to the components.
>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> - Remove the unused imports (for ex bad_request) in /erd/__init__.py
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Removed.
>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> - Remove commented code
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> # req_args = request.args
>>>>>>>>>>>>>> # if ('recreate' in req_args and
>>>>>>>>>>>>>> # req_args['recreate'] == '1'):
>>>>>>>>>>>>>> # connect = False
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Removed.
>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> - TableNode.jsx, below two lines can be combined.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> import { PortModelAlignment, DefaultNodeModel } from
>>>>>>>>>>>>>> '@projectstorm/react-diagrams';
>>>>>>>>>>>>>> import { PortWidget } from '@projectstorm/react-diagrams';
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Done.
>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> - onImageClick function in BodyWidget.jsx is no use I think, so it should be removed.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> I wanted to keep the code as it will be used in future.
>>>>>>>>>>>>> Anyway, I've removed the code.
>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> - I got some console errors while adding/editing tables. Refer to the attached screenshot.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> I tried but I didn't get any. Looking at the screenshot, the
>>>>>>>>>>>>> error is from the underlying library. Can't do much in this.
>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> - In the column Edit Mode, while deleting the primary key, it gives the error, which does not go away with any further modifications.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Fixed.
>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> - While generating the SQL, if the server is disconnected, a proper error message should be thrown, right now some server side error is coming.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> It will show connection lost error now. Fixed.
>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> - Please remove ... from the menu title (New ERD Project(Beta)...) as it is not opening a dialog.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Done.
>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> - For large data sets, generate ERD hangs.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> It shows the spinner and waits for the response to come from
>>>>>>>>>>>>> the back end. I've used the existing table fetching code which is used at
>>>>>>>>>>>>> other places. I'll create an RM to improve the back end code for fetching
>>>>>>>>>>>>> the tables data which will help the schema diff tool as well.
>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> - Opening the ERD panel in a new window is not working, it opens in the same tab even if you have set the Preference "Open in new browser tab" to True.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Fixed. Added the setting in "Tab settings".
>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> - No shortcut is provided to open the ERD Tool.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> A shortcut is helpful if we are using it frequently. ERD tool
>>>>>>>>>>>>> won't be used that frequently. We already have a limited
>>>>>>>>>>>>> number of keys available for shortcuts. I think we should roll out without
>>>>>>>>>>>>> shortcut for now. If there is a user demand for it then we can think of
>>>>>>>>>>>>> adding it.
>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> - SonarQube fixes required.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Fixed.
>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> -
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> *Suggestion:*
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> While removal of the FK link, If any of the table is selected, it is being deleted with FK link.
>>>>>>>>>>>>>> Either we should warn the user OR make 2 different buttons for FK removal and table removal as the user may be confused if the selected table is also removed with the FK.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> I've added a confirmation dialog which will show the number
>>>>>>>>>>>>> of tables and links selected. This way user will know what he has selected
>>>>>>>>>>>>> before deleting.
>>>>>>>>>>>>>
>>>>>>>>>>>>>> *Observations:*
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Lodash has been used in this module in place of Underscore,
>>>>>>>>>>>>>> though the dependency is already introduced by another module,
>>>>>>>>>>>>>> but we have mentioned it in the package.json file, which is
>>>>>>>>>>>>>> somewhat not convincing to me.
>>>>>>>>>>>>>> Lodash is more advanced than Underscore but we should pick
>>>>>>>>>>>>>> anyone as it will be easy to manage.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> TL;DR; we cannot.
>>>>>>>>>>>>> lodash is a peer dependency for react-diagrams (and some
>>>>>>>>>>>>> existing modules in pgAdmin) so it will come to package.json without
>>>>>>>>>>>>> choice. We cannot remove underscore because it is a dependency of backbone.
>>>>>>>>>>>>> Underscore is outdated, and I cannot migrate the complete pgAdmin code. So,
>>>>>>>>>>>>> I decided to go with 100/0 method. All the new codes will use lodash only
>>>>>>>>>>>>> as we'll phase out underscore with time. Just like jQuery vs ReactJS.
>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Table dialog code is duplicate of the table node, as it was
>>>>>>>>>>>>>> difficult to extend it because it was attached to the tree.
>>>>>>>>>>>>>> So, we need to keep in mind that while implementing React in
>>>>>>>>>>>>>> pgAdmin, the nodes should be properly detached from the tree itself, so we
>>>>>>>>>>>>>> can reuse it.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Yes. I agree. We need to separate out data source from UI
>>>>>>>>>>>>> going forward with React.
>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Thanks,
>>>>>>>>>>>>>> Khushboo
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> On Mon, Dec 28, 2020 at 10:53 AM Khushboo Vashi <
>>>>>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> On Fri, Dec 25, 2020 at 4:34 PM Akshay Joshi <
>>>>>>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> Hi Khushboo,
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> Can you please review it?
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> On it.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> On Fri, Dec 25, 2020 at 3:31 PM Aditya Toshniwal <
>>>>>>>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> Hi Hackers,
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> Attached patch introduces ERD Tool(Beta) to pgAdmin. Below
>>>>>>>>>>>>>>>>> are the details:
>>>>>>>>>>>>>>>>> 1) Create a diagram from scratch or generate for an
>>>>>>>>>>>>>>>>> existing DB.
>>>>>>>>>>>>>>>>> 2) Generate "Create" DDL from the diagram.
>>>>>>>>>>>>>>>>> 3) Save the diagram and resume it later.
>>>>>>>>>>>>>>>>> 4) Supports basic table fields, one-to-many relationships,
>>>>>>>>>>>>>>>>> many-to-many relationships, adding notes.
>>>>>>>>>>>>>>>>> 5) Test cases added with 75-80% test coverage.
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> Please review.
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> --
>>>>>>>>>>>>>>>>> Thanks,
>>>>>>>>>>>>>>>>> Aditya Toshniwal
>>>>>>>>>>>>>>>>> pgAdmin hacker | Sr. Software Engineer | *edbpostgres.com*
>>>>>>>>>>>>>>>>> <http://edbpostgres.com;
>>>>>>>>>>>>>>>>> "Don't Complain about Heat, Plant a TREE"
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> --
>>>>>>>>>>>>>>>> *Thanks & Regards*
>>>>>>>>>>>>>>>> *Akshay Joshi*
>>>>>>>>>>>>>>>> *pgAdmin Hacker | Principal Software Architect*
>>>>>>>>>>>>>>>> *EDB Postgres <http://edbpostgres.com>*
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> *Mobile: +91 976-788-8246*
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>> --
>>>>>>>>>>>>> Thanks,
>>>>>>>>>>>>> Aditya Toshniwal
>>>>>>>>>>>>> pgAdmin hacker | Sr. Software Engineer | *edbpostgres.com*
>>>>>>>>>>>>> <http://edbpostgres.com;
>>>>>>>>>>>>> "Don't Complain about Heat, Plant a TREE"
>>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> --
>>>>>>>>>>>> *Thanks & Regards*
>>>>>>>>>>>> *Akshay Joshi*
>>>>>>>>>>>> *pgAdmin Hacker | Principal Software Architect*
>>>>>>>>>>>> *EDB Postgres <http://edbpostgres.com>*
>>>>>>>>>>>>
>>>>>>>>>>>> *Mobile: +91 976-788-8246*
>>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> --
>>>>>>>>>>> Thanks,
>>>>>>>>>>> Aditya Toshniwal
>>>>>>>>>>> pgAdmin hacker | Sr. Software Engineer | *edbpostgres.com*
>>>>>>>>>>> <http://edbpostgres.com;
>>>>>>>>>>> "Don't Complain about Heat, Plant a TREE"
>>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> --
>>>>>>>>>> *Thanks & Regards*
>>>>>>>>>> *Akshay Joshi*
>>>>>>>>>> *pgAdmin Hacker | Principal Software Architect*
>>>>>>>>>> *EDB Postgres <http://edbpostgres.com>*
>>>>>>>>>>
>>>>>>>>>> *Mobile: +91 976-788-8246*
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> --
>>>>>>>>> Thanks,
>>>>>>>>> Aditya Toshniwal
>>>>>>>>> pgAdmin hacker | Sr. Software Engineer | *edbpostgres.com*
>>>>>>>>> <http://edbpostgres.com;
>>>>>>>>> "Don't Complain about Heat, Plant a TREE"
>>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> --
>>>>>>>> *Thanks & Regards*
>>>>>>>> *Akshay Joshi*
>>>>>>>> *pgAdmin Hacker | Principal Software Architect*
>>>>>>>> *EDB Postgres <http://edbpostgres.com>*
>>>>>>>>
>>>>>>>> *Mobile: +91 976-788-8246*
>>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> --
>>>>>>> Thanks,
>>>>>>> Aditya Toshniwal
>>>>>>> pgAdmin hacker | Sr. Software Engineer | *edbpostgres.com*
>>>>>>> <http://edbpostgres.com;
>>>>>>> "Don't Complain about Heat, Plant a TREE"
>>>>>>>
>>>>>>
>>>>>>
>>>>>> --
>>>>>> *Thanks & Regards*
>>>>>> *Akshay Joshi*
>>>>>> *pgAdmin Hacker | Principal Software Architect*
>>>>>> *EDB Postgres <http://edbpostgres.com>*
>>>>>>
>>>>>> *Mobile: +91 976-788-8246*
>>>>>>
>>>>>
>>>>>
>>>>> --
>>>>> Dave Page
>>>>> Blog: http://pgsnake.blogspot.com
>>>>> Twitter: @pgsnake
>>>>>
>>>>> EDB: http://www.enterprisedb.com
>>>>>
>>>>>
>>>>
>>>> --
>>>> Thanks,
>>>> Aditya Toshniwal
>>>> pgAdmin hacker | Sr. Software Engineer | *edbpostgres.com*
>>>> <http://edbpostgres.com;
>>>> "Don't Complain about Heat, Plant a TREE"
>>>>
>>>
>>>
>>> --
>>> Dave Page
>>> Blog: http://pgsnake.blogspot.com
>>> Twitter: @pgsnake
>>>
>>> EDB: http://www.enterprisedb.com
>>>
>>>
>>
>> --
>> Thanks,
>> Aditya Toshniwal
>> pgAdmin hacker | Sr. Software Engineer | *edbpostgres.com*
>> <http://edbpostgres.com;
>> "Don't Complain about Heat, Plant a TREE"
>>
>
>
> --
> Thanks,
> Aditya Toshniwal
> pgAdmin hacker | Sr. Software Engineer | *edbpostgres.com*
> <http://edbpostgres.com;
> "Don't Complain about Heat, Plant a TREE"
>
--
Thanks,
Aditya Toshniwal
pgAdmin hacker | Sr. Software Engineer | *edbpostgres.com*
<http://edbpostgres.com;
"Don't Complain about Heat, Plant a TREE"
Attachments:
[application/octet-stream] RM1802.fixes_v2.patch (68.6K, 3-RM1802.fixes_v2.patch)
download | inline diff:
diff --git a/web/package.json b/web/package.json
index 9d4c060dc..9e55eb674 100644
--- a/web/package.json
+++ b/web/package.json
@@ -46,6 +46,7 @@
"prop-types": "^15.7.2",
"raw-loader": "^3.1.0",
"resize-observer-polyfill": "^1.5.1",
+ "resolve-url-loader": "^3.1.2",
"sass": "^1.24.4",
"sass-loader": "^7.1.0",
"sass-resources-loader": "^2.0.0",
@@ -87,6 +88,7 @@
"dagre": "^0.8.4",
"dropzone": "^5.5.1",
"exports-loader": "~0.7.0",
+ "html2canvas": "^1.0.0-rc.7",
"immutability-helper": "^3.0.0",
"imports-loader": "^0.8.0",
"ip-address": "^5.8.9",
diff --git a/web/pgadmin/browser/static/js/frame.js b/web/pgadmin/browser/static/js/frame.js
index b72df7b0f..0d3b91273 100644
--- a/web/pgadmin/browser/static/js/frame.js
+++ b/web/pgadmin/browser/static/js/frame.js
@@ -30,7 +30,7 @@ define([
height: 600,
showTitle: true,
isClosable: true,
- isRenamable: true,
+ isRenamable: false,
isPrivate: false,
url: '',
icon: '',
diff --git a/web/pgadmin/static/js/chartjs/index.jsx b/web/pgadmin/static/js/chartjs/index.jsx
index 52623bd24..022e63875 100644
--- a/web/pgadmin/static/js/chartjs/index.jsx
+++ b/web/pgadmin/static/js/chartjs/index.jsx
@@ -41,11 +41,11 @@ export default function BaseChart({type='line', id, options, data, redraw=false,
options: optionsMerged,
});
props.onInit && props.onInit(chartObj.current);
- }
+ };
const destroyChart = function() {
chartObj.current && chartObj.current.destroy();
- }
+ };
useEffect(()=>{
initChart();
@@ -72,7 +72,7 @@ export default function BaseChart({type='line', id, options, data, redraw=false,
destroyChart();
initChart();
}
- }, [redraw])
+ }, [redraw]);
return (
<canvas id={id} ref={chartRef}></canvas>
diff --git a/web/pgadmin/tools/datagrid/static/js/datagrid.js b/web/pgadmin/tools/datagrid/static/js/datagrid.js
index a7d056683..c9b8b5b7e 100644
--- a/web/pgadmin/tools/datagrid/static/js/datagrid.js
+++ b/web/pgadmin/tools/datagrid/static/js/datagrid.js
@@ -180,7 +180,7 @@ define('pgadmin.datagrid', [
name: 'frm_datagrid',
showTitle: true,
isCloseable: true,
- isRenameable: true,
+ isRenamable: true,
isPrivate: true,
url: 'about:blank',
});
diff --git a/web/pgadmin/tools/datagrid/static/js/datagrid_panel_title.js b/web/pgadmin/tools/datagrid/static/js/datagrid_panel_title.js
index 46db6a70a..b3bd793e0 100644
--- a/web/pgadmin/tools/datagrid/static/js/datagrid_panel_title.js
+++ b/web/pgadmin/tools/datagrid/static/js/datagrid_panel_title.js
@@ -78,11 +78,11 @@ export function setQueryToolDockerTitle(panel, is_query_tool, panel_title, is_fi
export function set_renamable_option(panel, is_file) {
if(is_file || is_file == 'true') {
- panel._isRenamable = false;
+ panel.renamable(false);
$('.conn-info-dd').hide();
$('.connection-data').css({pointerEvents: 'none', cursor: 'arrow'});
} else {
- panel._isRenamable = true;
+ panel.renamable(true);
}
}
diff --git a/web/pgadmin/tools/erd/__init__.py b/web/pgadmin/tools/erd/__init__.py
index 301aca9c9..1ce742186 100644
--- a/web/pgadmin/tools/erd/__init__.py
+++ b/web/pgadmin/tools/erd/__init__.py
@@ -288,6 +288,24 @@ class ERDModule(PgAdminModule):
fields=shortcut_fields
)
+ self.preference.register(
+ 'keyboard_shortcuts',
+ 'show_details',
+ gettext('Show more/fewer details'),
+ 'keyboardshortcut',
+ {
+ 'alt': True,
+ 'shift': False,
+ 'control': True,
+ 'key': {
+ 'key_code': 84,
+ 'char': 't'
+ }
+ },
+ category_label=PREF_LABEL_KEYBOARD_SHORTCUTS,
+ fields=shortcut_fields
+ )
+
self.preference.register(
'keyboard_shortcuts',
'zoom_to_fit',
diff --git a/web/pgadmin/tools/erd/static/js/erd_tool/ERDCore.js b/web/pgadmin/tools/erd/static/js/erd_tool/ERDCore.js
index ea0e22a29..8faae4d01 100644
--- a/web/pgadmin/tools/erd/static/js/erd_tool/ERDCore.js
+++ b/web/pgadmin/tools/erd/static/js/erd_tool/ERDCore.js
@@ -212,14 +212,14 @@ export default class ERDCore {
let sourcePort = sourceNode.getPort(portName);
/* Create the port if not there */
if(!sourcePort) {
- sourcePort = sourceNode.addPort(this.getNewPort(type, null, {name:portName, alignment:PortModelAlignment.RIGHT}));
+ sourcePort = sourceNode.addPort(this.getNewPort(type, null, {name:portName, subtype: 'one', alignment:PortModelAlignment.RIGHT}));
}
portName = targetNode.getPortName(data.local_column_attnum);
let targetPort = targetNode.getPort(portName);
/* Create the port if not there */
if(!targetPort) {
- targetPort = targetNode.addPort(this.getNewPort(type, null, {name:portName, alignment:PortModelAlignment.RIGHT}));
+ targetPort = targetNode.addPort(this.getNewPort(type, null, {name:portName, subtype: 'many', alignment:PortModelAlignment.RIGHT}));
}
/* Link the ports */
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 e1fee815f..2b56ea1c4 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
@@ -50,7 +50,7 @@ export default class TableDialog {
return 'entity_dialog';
}
- getDataModel(attributes, colTypes, schemas, sVersion) {
+ getDataModel(attributes, existingTables, colTypes, schemas, sVersion) {
let dialogObj = this;
let columnsModel = this.pgBrowser.DataModel.extend({
idAttribute: 'attnum',
@@ -694,6 +694,10 @@ export default class TableDialog {
msg = gettext('Table name cannot be empty.');
this.errorModel.set('name', msg);
return msg;
+ } else if(_.findIndex(existingTables, (table)=>table[0]==schema&&table[1]==name) >= 0) {
+ msg = gettext('Table name already exists.');
+ this.errorModel.set('name', msg);
+ return msg;
}
this.errorModel.unset('name');
if (
@@ -705,6 +709,8 @@ export default class TableDialog {
return msg;
}
this.errorModel.unset('schema');
+
+
return null;
},
});
@@ -731,9 +737,9 @@ export default class TableDialog {
return Alertify[dialogName];
}
- show(title, attributes, colTypes, schemas, sVersion, callback) {
+ show(title, attributes, existingTables, colTypes, schemas, sVersion, callback) {
let dialogTitle = title || gettext('Unknown');
const dialog = this.createOrGetDialog('table_dialog');
- dialog(dialogTitle, this.getDataModel(attributes, colTypes, schemas, sVersion), callback).resizeTo(this.pgBrowser.stdW.md, this.pgBrowser.stdH.md);
+ dialog(dialogTitle, this.getDataModel(attributes, existingTables, colTypes, schemas, sVersion), callback).resizeTo(this.pgBrowser.stdW.md, this.pgBrowser.stdH.md);
}
}
diff --git a/web/pgadmin/tools/erd/static/js/erd_tool/index.js b/web/pgadmin/tools/erd/static/js/erd_tool/index.js
index 523ebd14f..e865c29bd 100644
--- a/web/pgadmin/tools/erd/static/js/erd_tool/index.js
+++ b/web/pgadmin/tools/erd/static/js/erd_tool/index.js
@@ -9,10 +9,13 @@
import React from 'react';
import ReactDOM from 'react-dom';
+import _ from 'lodash';
+
import BodyWidget from './ui_components/BodyWidget';
import getDialog, {transformToSupported} from './dialogs';
import Alertify from 'pgadmin.alertifyjs';
import pgWindow from 'sources/window';
+import pgAdmin from 'sources/pgadmin';
export default class ERDTool {
constructor(container, params) {
@@ -20,10 +23,28 @@ export default class ERDTool {
this.params = params;
}
+ getPreferencesForModule() {
+
+ }
+
render() {
/* Mount the React ERD tool to the container */
+ let panel = null;
+ _.each(pgWindow.pgAdmin.Browser.docker.findPanels('frm_erdtool'), function(p) {
+ if (p.isVisible()) {
+ panel = p;
+ }
+ });
+
ReactDOM.render(
- <BodyWidget params={this.params} getDialog={getDialog} transformToSupported={transformToSupported} pgAdmin={pgWindow.pgAdmin} alertify={Alertify} />,
+ <BodyWidget
+ params={this.params}
+ getDialog={getDialog}
+ transformToSupported={transformToSupported}
+ pgWindow={pgWindow}
+ pgAdmin={pgAdmin}
+ panel={panel}
+ alertify={Alertify} />,
this.container
);
}
diff --git a/web/pgadmin/tools/erd/static/js/erd_tool/links/OneToManyLink.jsx b/web/pgadmin/tools/erd/static/js/erd_tool/links/OneToManyLink.jsx
index be985afde..37b456825 100644
--- a/web/pgadmin/tools/erd/static/js/erd_tool/links/OneToManyLink.jsx
+++ b/web/pgadmin/tools/erd/static/js/erd_tool/links/OneToManyLink.jsx
@@ -9,12 +9,12 @@
import React from 'react';
import {
- RightAngleLinkModel,
- RightAngleLinkWidget,
- DefaultLinkFactory,
- PortModelAlignment,
- LinkWidget,
- PointModel
+ RightAngleLinkModel,
+ RightAngleLinkWidget,
+ DefaultLinkFactory,
+ PortModelAlignment,
+ LinkWidget,
+ PointModel,
} from '@projectstorm/react-diagrams';
import {Point} from '@projectstorm/geometry';
import _ from 'lodash';
@@ -24,7 +24,7 @@ export const OneToManyModel = {
local_column_attnum: undefined,
referenced_table_uid: undefined,
referenced_column_attnum: undefined,
-}
+};
export class OneToManyLinkModel extends RightAngleLinkModel {
constructor({data, ...options}) {
@@ -33,7 +33,7 @@ export class OneToManyLinkModel extends RightAngleLinkModel {
width: 1,
class: 'link-onetomany',
locked: true,
- ...options
+ ...options,
});
this._data = {
@@ -62,13 +62,13 @@ export class OneToManyLinkModel extends RightAngleLinkModel {
'local_column': _.find(target.columns, (col)=>data.local_column_attnum == col.attnum).name,
'referenced': _.find(source.columns, (col)=>data.referenced_column_attnum == col.attnum).name,
}],
- }
+ };
}
serialize() {
return {
...super.serialize(),
- data: this.getData()
+ data: this.getData(),
};
}
}
@@ -83,13 +83,13 @@ const CustomLinkEndWidget = props => {
<circle className="svg-link-ele svg-otom-circle" cx="0" cy="16" r={props.width*1.75} strokeWidth={props.width} />
<polyline className="svg-link-ele" points="-8,0 0,15 0,0 0,30 0,15 8,0" fill="none" strokeWidth={props.width} />
</>
- )
+ );
} else if (type == 'one') {
return (
<polyline className="svg-link-ele" points="-8,15 0,15 0,0 0,30 0,15 8,15" fill="none" strokeWidth={props.width} />
- )
+ );
}
- }
+ };
return (
<g transform={'translate(' + point.getPosition().x + ', ' + point.getPosition().y + ')'}>
@@ -111,21 +111,21 @@ export class OneToManyLinkWidget extends RightAngleLinkWidget {
let degree = 0;
let tx = 0, ty = 0;
switch(alignment) {
- case PortModelAlignment.BOTTOM:
- ty = -offset;
- break;
- case PortModelAlignment.LEFT:
- degree = 90;
- tx = offset
- break;
- case PortModelAlignment.TOP:
- degree = 180;
- ty = offset;
- break;
- case PortModelAlignment.RIGHT:
- degree = -90;
- tx = -offset;
- break;
+ case PortModelAlignment.BOTTOM:
+ ty = -offset;
+ break;
+ case PortModelAlignment.LEFT:
+ degree = 90;
+ tx = offset;
+ break;
+ case PortModelAlignment.TOP:
+ degree = 180;
+ ty = offset;
+ break;
+ case PortModelAlignment.RIGHT:
+ degree = -90;
+ tx = -offset;
+ break;
}
return [degree, tx, ty];
}
@@ -146,8 +146,8 @@ export class OneToManyLinkWidget extends RightAngleLinkWidget {
point: point,
rotation: rotation,
tx: tx,
- ty: ty
- }
+ ty: ty,
+ };
}
generateCustomEndWidget({type, point, rotation, tx, ty}) {
@@ -183,7 +183,7 @@ export class OneToManyLinkWidget extends RightAngleLinkWidget {
}
handleMove = function(event) {
- this.props.link.getTargetPort()
+ this.props.link.getTargetPort();
this.draggingEvent(event, this.dragging_index);
this.props.link.fireEvent({}, 'positionChanged');
}.bind(this);
@@ -220,7 +220,7 @@ export class OneToManyLinkWidget extends RightAngleLinkWidget {
this.props.link.addPoint(
new PointModel({
link: this.props.link,
- position: new Point(onePoint.point.getX(), manyPoint.point.getY())
+ position: new Point(onePoint.point.getX(), manyPoint.point.getY()),
})
);
}
@@ -246,7 +246,7 @@ export class OneToManyLinkWidget extends RightAngleLinkWidget {
onMouseEnter: (event) => {
this.setState({ selected: true });
this.props.link.lastHoverIndexOfPath = j;
- }
+ },
},
j
)
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 5e74d890b..383c621ce 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
@@ -19,7 +19,7 @@ export class TableNodeModel extends DefaultNodeModel {
constructor({otherInfo, ...options}) {
super({
...options,
- type: TYPE
+ type: TYPE,
});
this._note = otherInfo.note || '';
@@ -60,22 +60,22 @@ export class TableNodeModel extends DefaultNodeModel {
cloneData(name) {
let newData = {
- ...this.getData()
+ ...this.getData(),
};
if(name) {
- newData['name'] = name
+ newData['name'] = name;
}
return newData;
}
setData(data) {
let self = this;
- /* Remove the links if column dropped */
+ /* Remove the links if column dropped or primary key removed */
_.differenceWith(this._data.columns, data.columns, function(existing, incoming) {
- return existing.attnum == incoming.attnum;
+ return existing.attnum == incoming.attnum && incoming.is_primary_key == true;
}).forEach((col)=>{
let existPort = self.getPort(self.getPortName(col.attnum));
- if(existPort) {
+ if(existPort && existPort.getSubtype() == 'one') {
existPort.removeAllLinks();
self.removePort(existPort);
}
@@ -109,7 +109,7 @@ export class TableNodeModel extends DefaultNodeModel {
otherInfo: {
data: this.getData(),
note: this.getNote(),
- }
+ },
};
}
}
@@ -119,8 +119,8 @@ export class TableNodeWidget extends React.Component {
super(props);
this.state = {
- show_details: true
- }
+ show_details: true,
+ };
this.props.node.registerListener({
toggleDetails: (event) => {
@@ -143,13 +143,13 @@ export class TableNodeWidget extends React.Component {
</div>
<div className="ml-auto col-row-port">{this.generatePort(port)}</div>
</div>
- )
+ );
}
generatePort = port => {
if(port) {
return (
- <PortWidget engine={this.props.engine} port={port} key={port.getID()} className={"port-" + port.options.alignment} />
+ <PortWidget engine={this.props.engine} port={port} key={port.getID()} className={'port-' + port.options.alignment} />
);
}
return <></>;
@@ -163,21 +163,21 @@ export class TableNodeWidget extends React.Component {
render() {
let node_data = this.props.node.getData();
return (
- <div className={"table-node " + (this.props.node.isSelected() ? 'selected': '') } onDoubleClick={()=>{this.props.node.fireEvent({}, 'editNode')}}>
+ <div className={'table-node ' + (this.props.node.isSelected() ? 'selected': '') } onDoubleClick={()=>{this.props.node.fireEvent({}, 'editNode');}}>
<div className="table-toolbar">
<DetailsToggleButton className='btn-xs' showDetails={this.state.show_details} onClick={this.toggleShowDetails} onDoubleClick={(e)=>{e.stopPropagation();}} />
{this.props.node.getNote() &&
<IconButton icon="far fa-sticky-note" className="btn-xs btn-warning ml-auto" onClick={()=>{
- this.props.node.fireEvent({}, 'showNote')
+ this.props.node.fireEvent({}, 'showNote');
}} title="Check note" />}
</div>
- <div className="table-schema">
- <span className="wcTabIcon icon-schema"></span>
- {node_data.schema}
+ <div className="d-flex table-schema-data">
+ <div className="table-icon-schema"></div>
+ <div className="table-schema">{node_data.schema}</div>
</div>
- <div className="table-name">
- <span className="wcTabIcon icon-table"></span>
- {node_data.name}
+ <div className="d-flex table-name-data">
+ <div><span className="wcTabIcon icon-table"></span></div>
+ <div className="table-name">{node_data.name}</div>
</div>
<div className="table-cols">
{_.map(node_data.columns, (col)=>this.generateColumn(col))}
diff --git a/web/pgadmin/tools/erd/static/js/erd_tool/ports/OneToManyPort.js b/web/pgadmin/tools/erd/static/js/erd_tool/ports/OneToManyPort.js
index c412acd77..9bcbdc415 100644
--- a/web/pgadmin/tools/erd/static/js/erd_tool/ports/OneToManyPort.js
+++ b/web/pgadmin/tools/erd/static/js/erd_tool/ports/OneToManyPort.js
@@ -16,6 +16,7 @@ const TYPE = 'onetomany';
export default class OneToManyPortModel extends PortModel {
constructor({options}) {
super({
+ subtype: 'notset',
...options,
type: TYPE,
});
@@ -30,6 +31,22 @@ export default class OneToManyPortModel extends PortModel {
createLinkModel() {
return new OneToManyLinkModel({});
}
+
+ getSubtype() {
+ return this.options.subtype;
+ }
+
+ deserialize(event) {
+ super.deserialize(event);
+ this.options.subtype = event.data.subtype || 'notset';
+ }
+
+ serialize() {
+ return {
+ ...super.serialize(),
+ subtype: this.options.subtype,
+ };
+ }
}
export class OneToManyPortFactory extends AbstractModelFactory {
diff --git a/web/pgadmin/tools/erd/static/js/erd_tool/ui_components/BodyWidget.jsx b/web/pgadmin/tools/erd/static/js/erd_tool/ui_components/BodyWidget.jsx
index 22701bae2..e36aaf2f1 100644
--- a/web/pgadmin/tools/erd/static/js/erd_tool/ui_components/BodyWidget.jsx
+++ b/web/pgadmin/tools/erd/static/js/erd_tool/ui_components/BodyWidget.jsx
@@ -12,6 +12,10 @@ import { CanvasWidget } from '@projectstorm/react-canvas-core';
import axios from 'axios';
import { Action, InputType } from '@projectstorm/react-canvas-core';
import PropTypes from 'prop-types';
+import _ from 'lodash';
+import html2canvas from 'html2canvas';
+import * as htmlToImage from 'html-to-image';
+
import ERDCore from '../ERDCore';
import ToolBar, {IconButton, DetailsToggleButton, ButtonGroup} from './ToolBar';
@@ -22,22 +26,25 @@ import {setPanelTitle} from '../../erd_module';
import gettext from 'sources/gettext';
import url_for from 'sources/url_for';
import {showERDSqlTool} from 'tools/datagrid/static/js/show_query_tool';
+import 'wcdocker';
/* Custom react-diagram action for keyboard events */
export class KeyboardShortcutAction extends Action {
constructor(shortcut_handlers=[]) {
- super({
- type: InputType.KEY_DOWN,
- fire: ({ event })=>{
- this.callHandler(event);
- }
- });
- this.shortcuts = {};
+ super({
+ type: InputType.KEY_DOWN,
+ fire: ({ event })=>{
+ this.callHandler(event);
+ },
+ });
+ this.shortcuts = {};
- for(let i=0; i<shortcut_handlers.length; i++){
- let [key, handler] = shortcut_handlers[i];
+ for(let i=0; i<shortcut_handlers.length; i++){
+ let [key, handler] = shortcut_handlers[i];
+ if(key) {
this.shortcuts[this.shortcutKey(key.alt, key.control, key.shift, false, key.key.key_code)] = handler;
}
+ }
}
shortcutKey(altKey, ctrlKey, shiftKey, metaKey, keyCode) {
@@ -69,9 +76,12 @@ export default class BodyWidget extends React.Component {
current_file: null,
dirty: false,
show_details: true,
+ is_new_tab: false,
preferences: {},
- }
+ };
this.diagram = new ERDCore();
+ /* Flag for checking if user has opted for save before close */
+ this.closeOnSave = React.createRef();
this.fileInputRef = React.createRef();
this.diagramContainerRef = React.createRef();
this.canvasEle = null;
@@ -83,6 +93,7 @@ export default class BodyWidget extends React.Component {
this.onSaveDiagram = this.onSaveDiagram.bind(this);
this.onSaveAsDiagram = this.onSaveAsDiagram.bind(this);
this.onSQLClick = this.onSQLClick.bind(this);
+ this.onImageClick = this.onImageClick.bind(this);
this.onAddNewNode = this.onAddNewNode.bind(this);
this.onEditNode = this.onEditNode.bind(this);
this.onCloneNode = this.onCloneNode.bind(this);
@@ -133,7 +144,7 @@ export default class BodyWidget extends React.Component {
},
'editNode': (event) => {
this.addEditNode(event.node);
- }
+ },
};
Object.keys(diagramEvents).forEach(eventName => {
this.diagram.registerModelEvent(eventName, diagramEvents[eventName]);
@@ -157,9 +168,10 @@ export default class BodyWidget extends React.Component {
[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.zoom_out, this.diagram.zoomOut],
]);
this.diagram.registerKeyAction(this.keyboardActionObj);
@@ -182,11 +194,16 @@ export default class BodyWidget extends React.Component {
}
async componentDidMount() {
- this.setLoading('Preparing');
- this.setTitle(this.state.current_file);
+ this.setLoading(gettext('Preparing...'));
+
this.setState({
- preferences: this.props.pgAdmin.Browser.get_preferences_for_module('erd')
- }, this.registerKeyboardShortcuts);
+ preferences: this.props.pgWindow.pgAdmin.Browser.get_preferences_for_module('erd'),
+ is_new_tab: (this.props.pgWindow.pgAdmin.Browser.get_preferences_for_module('browser').new_browser_tab_open || '')
+ .includes('erd_tool'),
+ }, ()=>{
+ this.registerKeyboardShortcuts();
+ this.setTitle(this.state.current_file);
+ });
this.registerModelEvents();
this.realignGrid({
backgroundSize: '45px 45px',
@@ -197,10 +214,19 @@ export default class BodyWidget extends React.Component {
this.props.pgAdmin.Browser.Events.on('pgadmin-storage:finish_btn:create_file', this.saveFile, this);
this.props.pgAdmin.Browser.onPreferencesChange('erd', () => {
this.setState({
- preferences: this.props.pgAdmin.Browser.get_preferences_for_module('erd')
+ preferences: this.props.pgWindow.pgAdmin.Browser.get_preferences_for_module('erd'),
}, ()=>this.registerKeyboardShortcuts());
});
+ this.props.panel?.on(window.wcDocker?.EVENT.CLOSING, () => {
+ if(this.state.dirty) {
+ this.closeOnSave = false;
+ this.confirmBeforeClose();
+ return false;
+ }
+ return true;
+ });
+
let done = await this.initConnection();
if(!done) return;
@@ -218,18 +244,78 @@ 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?'));
+ return false;
+ }
+
+ closePanel() {
+ window.onbeforeunload = null;
+ this.props.panel.off(wcDocker.EVENT.CLOSING);
+ this.props.pgWindow.pgAdmin.Browser.docker.removePanel(this.props.panel);
+ }
+
getDialog(dialogName) {
if(dialogName === 'entity_dialog') {
+ let existingTables = this.diagram.getModel().getNodes().map((node)=>{
+ return node.getSchemaTableName();
+ });
return (title, attributes, callback)=>{
- this.props.getDialog(dialogName).show(
- title, attributes, this.diagram.getCache('colTypes'), this.diagram.getCache('schemas'), this.state.server_version, callback
- );
+ this.props.getDialog(dialogName).show(
+ title, attributes, existingTables, this.diagram.getCache('colTypes'), this.diagram.getCache('schemas'), this.state.server_version, callback
+ );
};
} else if(dialogName === 'onetomany_dialog' || dialogName === 'manytomany_dialog') {
return (title, attributes, callback)=>{
- this.props.getDialog(dialogName).show(
- title, attributes, this.diagram.getModel().getNodesDict(), this.state.server_version, callback
- );
+ this.props.getDialog(dialogName).show(
+ title, attributes, this.diagram.getModel().getNodesDict(), this.state.server_version, callback
+ );
};
}
}
@@ -289,20 +375,20 @@ export default class BodyWidget extends React.Component {
gettext('Delete ?'),
gettext('You have selected %s tables and %s links.', this.diagram.getSelectedNodes().length, this.diagram.getSelectedLinks().length)
+ '<br />' + gettext('Are you sure you want to delete ?'),
- () => {
- this.diagram.getSelectedNodes().forEach((node)=>{
- node.setSelected(false);
- node.remove();
- });
- this.diagram.getSelectedLinks().forEach((link)=>{
- link.getTargetPort().remove();
- link.getSourcePort().remove();
- link.setSelected(false);
- link.remove();
- });
- this.diagram.repaint();
- },
- () => {}
+ () => {
+ this.diagram.getSelectedNodes().forEach((node)=>{
+ node.setSelected(false);
+ node.remove();
+ });
+ this.diagram.getSelectedLinks().forEach((link)=>{
+ link.getTargetPort().remove();
+ link.getSourcePort().remove();
+ link.setSelected(false);
+ link.remove();
+ });
+ this.diagram.repaint();
+ },
+ () => {}
);
}
@@ -312,11 +398,11 @@ export default class BodyWidget extends React.Component {
onDetailsToggle() {
this.setState((prevState)=>({
- show_details: !prevState.show_details
+ show_details: !prevState.show_details,
}), ()=>{
this.diagram.getModel().getNodes().forEach((node)=>{
node.fireEvent({show_details: this.state.show_details}, 'toggleDetails');
- })
+ });
});
}
@@ -335,8 +421,9 @@ export default class BodyWidget extends React.Component {
}
openFile(fileName) {
+ this.setLoading(gettext('Loading project...'));
axios.post(url_for('sqleditor.load_file'), {
- 'file_name': decodeURI(fileName)
+ 'file_name': decodeURI(fileName),
}).then((res)=>{
this.setState({
current_file: fileName,
@@ -344,13 +431,17 @@ export default class BodyWidget extends React.Component {
});
this.setTitle(fileName);
this.diagram.deserialize(res.data);
+ this.diagram.clearSelection();
this.registerModelEvents();
}).catch((err)=>{
this.handleAxiosCatch(err);
+ }).then(()=>{
+ this.setLoading(null);
});
}
- onSaveDiagram(isSaveAs=false) {
+ onSaveDiagram(isSaveAs=false, closeOnSave=false) {
+ this.closeOnSave = closeOnSave;
if(this.state.current_file && !isSaveAs) {
this.saveFile(this.state.current_file);
} else {
@@ -370,9 +461,10 @@ export default class BodyWidget extends React.Component {
}
saveFile(fileName) {
+ this.setLoading(gettext('Saving...'));
axios.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))
+ 'file_content': JSON.stringify(this.diagram.serialize(this.props.pgAdmin.Browser.utils.app_version_int)),
}).then(()=>{
this.props.alertify.success(gettext('Project saved successfully.'));
this.setState({
@@ -380,7 +472,12 @@ export default class BodyWidget extends React.Component {
dirty: false,
});
this.setTitle(fileName);
+ this.setLoading(null);
+ if(this.closeOnSave) {
+ this.closePanel.call(this);
+ }
}).catch((err)=>{
+ this.setLoading(null);
this.handleAxiosCatch(err);
});
}
@@ -395,14 +492,10 @@ export default class BodyWidget extends React.Component {
title = 'Untitled';
}
title = this.getCurrentProjectName(title) + (dirty ? '*': '');
- if (this.new_browser_tab) {
+ if (this.state.is_new_tab) {
window.document.title = title;
} else {
- _.each(this.props.pgAdmin.Browser.docker.findPanels('frm_erdtool'), function(p) {
- if (p.isVisible()) {
- setPanelTitle(p, title);
- }
- });
+ setPanelTitle(this.props.panel, title);
}
}
@@ -414,7 +507,7 @@ export default class BodyWidget extends React.Component {
trans_id: this.props.params.trans_id,
sgid: this.props.params.sgid,
sid: this.props.params.sid,
- did: this.props.params.did
+ did: this.props.params.did,
});
this.setLoading(gettext('Preparing the SQL...'));
@@ -428,18 +521,53 @@ export default class BodyWidget extends React.Component {
sid: this.props.params.sid,
did: this.props.params.did,
stype: this.props.params.server_type,
- }
+ };
let sqlId = `erd${this.props.params.trans_id}`;
localStorage.setItem(sqlId, sqlScript);
- showERDSqlTool(parentData, sqlId, this.props.params.title, this.props.pgAdmin.DataGrid, this.props.alertify);
+ showERDSqlTool(parentData, sqlId, this.props.params.title, this.props.pgWindow.pgAdmin.DataGrid, this.props.alertify);
})
.catch((error)=>{
this.handleAxiosCatch(error);
})
.then(()=>{
this.setLoading(null);
- })
+ });
+ }
+
+ onImageClick() {
+ this.setLoading(gettext('Preparing the image...'));
+
+ /* Change the styles for suiting html2canvas */
+ this.canvasEle.classList.add('html2canvas-reset');
+ this.canvasEle.style.width = this.canvasEle.scrollWidth + 'px';
+ this.canvasEle.style.height = this.canvasEle.scrollHeight + 'px';
+
+ html2canvas(this.canvasEle, {
+ width: this.canvasEle.scrollWidth + 10,
+ height: this.canvasEle.scrollHeight + 10,
+ scrollX: 0,
+ scrollY: 0,
+ useCORS: true,
+ allowTaint: true,
+ backgroundColor: window.getComputedStyle(this.canvasEle).backgroundColor,
+ }).then((canvas)=>{
+ let link = document.createElement('a');
+ link.setAttribute('href', canvas.toDataURL('image/png'));
+ link.setAttribute('download', this.getCurrentProjectName() + '.png');
+ link.click();
+ }).catch((err)=>{
+ console.error(err);
+ this.props.alertify.alert()
+ .set('title', gettext('Error'))
+ .set('message', err).show();
+ }).then(()=>{
+ /* Revert back to the original CSS styles */
+ this.canvasEle.classList.remove('html2canvas-reset');
+ this.canvasEle.style.width = '';
+ this.canvasEle.style.height = '';
+ this.setLoading(null);
+ });
}
onOneToManyClick() {
@@ -473,8 +601,8 @@ export default class BodyWidget extends React.Component {
'name': `${right_table.getData().name}_${right_table.getColumnAt(newData.right_table_column_attnum).name}`,
'is_primary_key': false,
'attnum': 1,
- }]
- }
+ }],
+ };
let newNode = this.diagram.addNode(tableData);
this.diagram.clearSelection();
newNode.setSelected(true);
@@ -484,7 +612,7 @@ export default class BodyWidget extends React.Component {
local_column_attnum: newNode.getColumns()[0].attnum,
referenced_table_uid: newData.left_table_uid,
referenced_column_attnum : newData.left_table_column_attnum,
- }
+ };
this.diagram.addLink(linkData, 'onetomany');
linkData = {
@@ -492,7 +620,7 @@ export default class BodyWidget extends React.Component {
local_column_attnum: newNode.getColumns()[1].attnum,
referenced_table_uid: newData.right_table_uid,
referenced_column_attnum : newData.right_table_column_attnum,
- }
+ };
this.diagram.addLink(linkData, 'onetomany');
@@ -505,7 +633,7 @@ export default class BodyWidget extends React.Component {
this.noteRefEle = this.diagram.getEngine().getNodeElement(noteNode);
this.setState({
note_node: noteNode,
- note_open: true
+ note_open: true,
});
}
}
@@ -528,14 +656,14 @@ export default class BodyWidget extends React.Component {
trans_id: this.props.params.trans_id,
sgid: this.props.params.sgid,
sid: this.props.params.sid,
- did: this.props.params.did
+ did: this.props.params.did,
});
try {
let response = await axios.post(initUrl);
this.setState({
conn_status: CONNECT_STATUS.CONNECTED,
- server_version: response.data.data.serverVersion
+ server_version: response.data.data.serverVersion,
});
return true;
} catch (error) {
@@ -556,7 +684,7 @@ export default class BodyWidget extends React.Component {
trans_id: this.props.params.trans_id,
sgid: this.props.params.sgid,
sid: this.props.params.sid,
- did: this.props.params.did
+ did: this.props.params.did,
});
try {
@@ -579,7 +707,7 @@ export default class BodyWidget extends React.Component {
trans_id: this.props.params.trans_id,
sgid: this.props.params.sgid,
sid: this.props.params.sid,
- did: this.props.params.did
+ did: this.props.params.did,
});
try {
@@ -604,7 +732,7 @@ export default class BodyWidget extends React.Component {
<ButtonGroup>
<IconButton id="open-file" icon="fa fa-folder-open" onClick={this.onLoadDiagram} title={gettext('Load from file')}
shortcut={this.state.preferences.open_project}/>
- <IconButton id="save-erd" icon="fa fa-save" onClick={()=>{this.onSaveDiagram()}} title={gettext('Save project')}
+ <IconButton id="save-erd" icon="fa fa-save" onClick={()=>{this.onSaveDiagram();}} title={gettext('Save project')}
shortcut={this.state.preferences.save_project} disabled={!this.state.dirty}/>
<IconButton id="save-as-erd" icon="fa fa-share-square" onClick={this.onSaveAsDiagram} title={gettext('Save as')}
shortcut={this.state.preferences.save_project_as}/>
@@ -612,6 +740,8 @@ export default class BodyWidget extends React.Component {
<ButtonGroup>
<IconButton id="save-sql" icon="fa fa-file-code" onClick={this.onSQLClick} title={gettext('Generate SQL')}
shortcut={this.state.preferences.generate_sql}/>
+ <IconButton id="save-image" icon="fa fa-file-image" onClick={this.onImageClick} title={gettext('Generate SQL')}
+ shortcut={this.state.preferences.generate_sql}/>
</ButtonGroup>
<ButtonGroup>
<IconButton id="add-node" icon="fa fa-plus-square" onClick={this.onAddNewNode} title={gettext('Add table')}
@@ -634,7 +764,8 @@ export default class BodyWidget extends React.Component {
shortcut={this.state.preferences.add_edit_note} disabled={!this.state.single_node_selected || this.state.single_link_selected}/>
<IconButton id="auto-align" icon="fa fa-magic" onClick={this.onAutoDistribute} title={gettext('Auto align')}
shortcut={this.state.preferences.auto_align} />
- <DetailsToggleButton id="more-details" onClick={this.onDetailsToggle} showDetails={this.state.show_details} />
+ <DetailsToggleButton id="more-details" onClick={this.onDetailsToggle} showDetails={this.state.show_details}
+ shortcut={this.state.preferences.show_details} />
</ButtonGroup>
<ButtonGroup>
<IconButton id="zoom-to-fit" icon="fa fa-compress" onClick={this.diagram.zoomToFit} title={gettext('Zoom to fit')}
@@ -654,7 +785,7 @@ export default class BodyWidget extends React.Component {
reference={this.noteRefEle} noteNode={this.state.note_node} appendTo={this.diagramContainerRef.current} rows={8}/>
<div className="diagram-container" ref={this.diagramContainerRef}>
<Loader message={this.state.loading_msg} autoEllipsis={true}/>
- <CanvasWidget className="diagram-canvas flex-grow-1" ref={(ele)=>{this.canvasEle = ele?.ref?.current}} engine={this.diagram.getEngine()} />
+ <CanvasWidget className="diagram-canvas flex-grow-1" ref={(ele)=>{this.canvasEle = ele?.ref?.current;}} engine={this.diagram.getEngine()} />
</div>
</>
);
@@ -672,10 +803,11 @@ BodyWidget.propTypes = {
title: PropTypes.string.isRequired,
bgcolor: PropTypes.string,
fgcolor: PropTypes.string,
- gen: PropTypes.bool.isRequired
+ gen: PropTypes.bool.isRequired,
}),
getDialog: PropTypes.func.isRequired,
transformToSupported: PropTypes.func.isRequired,
+ pgWindow: PropTypes.object.isRequired,
pgAdmin: PropTypes.object.isRequired,
- alertify: PropTypes.object.isRequired
+ alertify: PropTypes.object.isRequired,
};
diff --git a/web/pgadmin/tools/erd/static/js/erd_tool/ui_components/ConnectionBar.jsx b/web/pgadmin/tools/erd/static/js/erd_tool/ui_components/ConnectionBar.jsx
index f191dc85e..3b71dbcc0 100644
--- a/web/pgadmin/tools/erd/static/js/erd_tool/ui_components/ConnectionBar.jsx
+++ b/web/pgadmin/tools/erd/static/js/erd_tool/ui_components/ConnectionBar.jsx
@@ -16,7 +16,7 @@ export const STATUS = {
DISCONNECTED: 2,
CONNECTING: 3,
FAILED: 4,
-}
+};
/* The connection bar component */
export default function ConnectionBar({statusId, status, bgcolor, fgcolor, title}) {
@@ -33,19 +33,19 @@ export default function ConnectionBar({statusId, status, bgcolor, fgcolor, title
+ (status == STATUS.CONNECTED ? 'icon-query-tool-connected' : '')
+ (status == (STATUS.DISCONNECTED || STATUS.FAILED) ? 'icon-query-tool-disconnected ' : '')
+ (status == STATUS.CONNECTING ? 'obtaining-conn' : '')}
- aria-hidden="true" title="" role="img">
+ aria-hidden="true" title="" role="img">
</span>
</div>
<div className="connection-info btn-group" role="group" aria-label="">
<div className="editor-title"
style={{backgroundColor: bgcolor, color: fgcolor}}>
- {status == STATUS.CONNECTING ? '(' + gettext('Obtaining connection...') + ') ' : ''}
- {status == STATUS.FAILED ? '(' + gettext('Connection failed') + ') ' : ''}
- {title}
+ {status == STATUS.CONNECTING ? '(' + gettext('Obtaining connection...') + ') ' : ''}
+ {status == STATUS.FAILED ? '(' + gettext('Connection failed') + ') ' : ''}
+ {title}
</div>
</div>
</div>
- )
+ );
}
ConnectionBar.propTypes = {
diff --git a/web/pgadmin/tools/erd/static/js/erd_tool/ui_components/FloatingNote.jsx b/web/pgadmin/tools/erd/static/js/erd_tool/ui_components/FloatingNote.jsx
index 19050512c..052829f93 100644
--- a/web/pgadmin/tools/erd/static/js/erd_tool/ui_components/FloatingNote.jsx
+++ b/web/pgadmin/tools/erd/static/js/erd_tool/ui_components/FloatingNote.jsx
@@ -51,13 +51,13 @@ export default function FloatingNote({open, onClose, reference, rows, noteNode,
</div>
</div>
</div>
- )}
- visible={open}
- interactive={true}
- animation={false}
- reference={reference}
- placement='auto-end'
- {...tippyProps}
+ )}
+ visible={open}
+ interactive={true}
+ animation={false}
+ reference={reference}
+ placement='auto-end'
+ {...tippyProps}
/>
);
}
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
index 2f376e4cb..fe4280af3 100644
--- 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
@@ -34,7 +34,7 @@ BaseIconButton.propTypes = {
text: PropTypes.string,
className: PropTypes.string,
ref: CustomPropTypes.ref,
-}
+};
/* The tooltip content to show shortcut details */
@@ -47,10 +47,10 @@ export function Shortcut({shortcut}) {
return (
<div style={{justifyContent: 'center', marginTop: '0.125rem'}} className="d-flex">
{keys.map((key, i)=>{
- return <div key={i} className="shortcut-key">{key}</div>
+ return <div key={i} className="shortcut-key">{key}</div>;
})}
</div>
- )
+ );
}
const shortcutPropType = PropTypes.shape({
@@ -85,7 +85,7 @@ export const IconButton = forwardRef((props, ref) => {
</Tippy>
);
} else {
- return <BaseIconButton ref={ref} className='btn btn-sm btn-primary-icon' {...otherProps}/>
+ return <BaseIconButton ref={ref} className='btn btn-sm btn-primary-icon' {...otherProps}/>;
}
});
@@ -93,21 +93,21 @@ IconButton.propTypes = {
title: PropTypes.string,
shortcut: shortcutPropType,
className: PropTypes.string,
-}
+};
/* Toggle button, icon changes based on value */
export function DetailsToggleButton({showDetails, ...props}) {
return (
<IconButton
icon={showDetails ? 'far fa-eye' : 'fas fa-low-vision'}
- title={showDetails ? gettext('Show fewer details') : gettext("Show more details") }
+ title={showDetails ? gettext('Show fewer details') : gettext('Show more details') }
{...props} />
);
}
DetailsToggleButton.propTypes = {
showDetails: PropTypes.bool,
-}
+};
/* Button group container */
export function ButtonGroup({className, children}) {
@@ -115,12 +115,12 @@ export function ButtonGroup({className, children}) {
<div className={'btn-group mr-1 ' + (className ? className : '')} role="group" aria-label="save group">
{children}
</div>
- )
+ );
}
ButtonGroup.propTypes = {
className: PropTypes.string,
-}
+};
/* Toolbar container */
export default function ToolBar({id, children}) {
@@ -128,9 +128,9 @@ export default function ToolBar({id, children}) {
<div id={id} className="editor-toolbar d-flex" role="toolbar" aria-label="">
{children}
</div>
- )
+ );
}
ButtonGroup.propTypes = {
id: PropTypes.string,
-}
+};
diff --git a/web/pgadmin/tools/erd/static/scss/_erd.scss b/web/pgadmin/tools/erd/static/scss/_erd.scss
index 733dd53c6..4fffcf4be 100644
--- a/web/pgadmin/tools/erd/static/scss/_erd.scss
+++ b/web/pgadmin/tools/erd/static/scss/_erd.scss
@@ -28,6 +28,7 @@
position: relative;
width: 100%;
height: 100%;
+ min-height: 0;
}
.floating-note {
@@ -56,6 +57,7 @@
}
.note-body {
+ word-break: break-all;
& textarea {
width: 100%;
border: none;
@@ -69,11 +71,21 @@
}
}
+ .html2canvas-reset {
+ background-image: none !important;
+ overflow: auto !important;
+
+ & > svg, & > div {
+ transform: none !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;
@@ -85,6 +97,22 @@
width: 175px;
font-size: 0.8em;
+ .table-icon-schema {
+ background-image: url('~top/browser/server_groups/servers/databases/schemas/static/img/schema.svg') !important;
+ // background-repeat: no-repeat;
+ // // background-size: 20px !important;
+ // align-content: center;
+ // vertical-align: middle;
+ // height: 100%;
+ // background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDIwLjAuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IgoJIHZpZXdCb3g9IjAgMCA2NCA2NCIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNjQgNjQ7IiB4bWw6c3BhY2U9InByZXNlcnZlIj4KPHN0eWxlIHR5cGU9InRleHQvY3NzIj4KCS5zdDB7ZmlsbDpub25lO3N0cm9rZTojOTk5OTk5O3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjEwO30KPC9zdHlsZT4KPHBhdGggY2xhc3M9InN0MCIgZD0iTTIxLjksMjIuMmMwLDMuNS0yLjksNi40LTYuNCw2LjRzLTYuNC0yLjktNi40LTYuNHMyLjktNi40LDYuNC02LjRTMjEuOSwxOC43LDIxLjksMjIuMnogTTQuMiw1MWwyMi4xLTE5CgkgTTQ2LjUsNTEuMUwyNi40LDMyIE0zNy42LDQyLjZsMTEuNi0xMCBNNjIuNCw0NS4xTDQ5LjIsMzIuNyBNNjMsMUgxdjYyaDYyVjF6IE0xLDUxLjRoNjIiLz4KPC9zdmc+Cg==');
+
+ width: 20px;
+ height: 20px;
+ // background: transparent url('~top/browser/server_groups/servers/databases/schemas/static/img/schema.svg') no-repeat center center;
+ // height: 100%;
+ // width: 20px;
+ }
+
&.selected {
border-color: $input-focus-border-color;
box-shadow: $input-btn-focus-box-shadow;
@@ -105,16 +133,24 @@
}
}
- .table-schema {
+ .table-schema-data {
border-bottom: $border-width solid $erd-node-border-color;
padding: $erd-row-padding;
- font-weight: bold;
+
+ & .table-schema {
+ font-weight: bold;
+ word-break: break-all;
+ }
}
- .table-name {
+ .table-name-data {
border-bottom: $border-width*2 solid $erd-node-border-color;
padding: $erd-row-padding;
- font-weight: bold;
+
+ & .table-name {
+ font-weight: bold;
+ word-break: break-all;
+ }
}
.table-cols {
@@ -123,10 +159,7 @@
.col-row-data {
padding: $erd-row-padding;
width: 100%;
-
- .col-name {
- word-break: break-all;
- }
+ word-break: break-all;
}
.col-row-port {
padding: 0;
diff --git a/web/regression/javascript/erd/table_node_spec.js b/web/regression/javascript/erd/table_node_spec.js
index 1c8bf74ee..4818d2a7a 100644
--- a/web/regression/javascript/erd/table_node_spec.js
+++ b/web/regression/javascript/erd/table_node_spec.js
@@ -73,7 +73,10 @@ describe('ERD TableNodeModel', ()=>{
});
describe('setData', ()=>{
- let existPort = jasmine.createSpyObj('port', ['removeAllLinks']);
+ let existPort = jasmine.createSpyObj('port', {
+ 'removeAllLinks': jasmine.createSpy('removeAllLinks'),
+ 'getSubtype': 'notset',
+ });
beforeEach(()=>{
modelObj._data.columns = [
@@ -93,6 +96,7 @@ describe('ERD TableNodeModel', ()=>{
});
it('add columns', ()=>{
+ spyOn(existPort, 'getSubtype').and.returnValue('many');
existPort.removeAllLinks.calls.reset();
modelObj.setData({
name: 'noname',
@@ -118,29 +122,31 @@ describe('ERD TableNodeModel', ()=>{
});
it('update columns', ()=>{
+ spyOn(existPort, 'getSubtype').and.returnValue('many');
existPort.removeAllLinks.calls.reset();
modelObj.setData({
name: 'noname',
schema: 'erd',
columns: [
- {name: 'col1', not_null:false, attnum: 0},
- {name: 'col2updated', not_null:false, attnum: 1},
- {name: 'col3', not_null:true, attnum: 2},
+ {name: 'col1', not_null:false, attnum: 0, is_primary_key: false},
+ {name: 'col2updated', not_null:false, attnum: 1, is_primary_key: false},
+ {name: 'col3', not_null:true, attnum: 2, is_primary_key: false},
],
});
expect(modelObj.getData()).toEqual({
name: 'noname',
schema: 'erd',
columns: [
- {name: 'col1', not_null:false, attnum: 0},
- {name: 'col2updated', not_null:false, attnum: 1},
- {name: 'col3', not_null:true, attnum: 2},
+ {name: 'col1', not_null:false, attnum: 0, is_primary_key: false},
+ {name: 'col2updated', not_null:false, attnum: 1, is_primary_key: false},
+ {name: 'col3', not_null:true, attnum: 2, is_primary_key: false},
],
});
expect(existPort.removeAllLinks).not.toHaveBeenCalled();
});
it('remove columns', ()=>{
+ spyOn(existPort, 'getSubtype').and.returnValue('one');
existPort.removeAllLinks.calls.reset();
modelObj.setData({
name: 'noname',
diff --git a/web/regression/javascript/erd/ui_components/body_widget_spec.js b/web/regression/javascript/erd/ui_components/body_widget_spec.js
index 16928980f..3114ba627 100644
--- a/web/regression/javascript/erd/ui_components/body_widget_spec.js
+++ b/web/regression/javascript/erd/ui_components/body_widget_spec.js
@@ -41,6 +41,10 @@ let pgAdmin = {
},
};
+let pgWindow = {
+ pgAdmin: pgAdmin,
+};
+
let alertify = jasmine.createSpyObj('alertify', {
'success': null,
'error': null,
@@ -124,7 +128,7 @@ describe('ERD BodyWidget', ()=>{
beforeEach(()=>{
jasmineEnzyme();
- body = mount(<BodyWidget params={params} pgAdmin={pgAdmin} getDialog={getDialog} transformToSupported={()=>{}} alertify={alertify}/>);
+ body = mount(<BodyWidget params={params} pgAdmin={pgAdmin} pgWindow={pgWindow} getDialog={getDialog} transformToSupported={()=>{}} alertify={alertify}/>);
bodyInstance = body.instance();
});
@@ -248,7 +252,7 @@ describe('ERD BodyWidget', ()=>{
bodyInstance.addEditNode();
expect(tableDialog.show).toHaveBeenCalled();
- let saveCallback = tableDialog.show.calls.mostRecent().args[5];
+ let saveCallback = tableDialog.show.calls.mostRecent().args[6];
let newData = {key: 'value'};
saveCallback(newData);
expect(bodyInstance.diagram.addNode).toHaveBeenCalledWith(newData);
@@ -263,7 +267,7 @@ describe('ERD BodyWidget', ()=>{
bodyInstance.addEditNode(node);
expect(tableDialog.show).toHaveBeenCalled();
- saveCallback = tableDialog.show.calls.mostRecent().args[5];
+ saveCallback = tableDialog.show.calls.mostRecent().args[6];
newData = {key: 'value'};
saveCallback(newData);
expect(node.setData).toHaveBeenCalledWith(newData);
diff --git a/web/yarn.lock b/web/yarn.lock
index 551213a27..5106e84d1 100644
--- a/web/yarn.lock
+++ b/web/yarn.lock
@@ -1281,6 +1281,14 @@ acorn@^7.0.0, acorn@^7.1.0, acorn@^7.1.1:
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
[email protected]:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/adjust-sourcemap-loader/-/adjust-sourcemap-loader-3.0.0.tgz#5ae12fb5b7b1c585e80bbb5a63ec163a1a45e61e"
+ integrity sha512-YBrGyT2/uVQ/c6Rr+t6ZJXniY03YtHGMJQYal368burRGYKqhx9qGTWqcBU5s1CwYY9E/ri63RYyG1IacMZtqw==
+ dependencies:
+ loader-utils "^2.0.0"
+ regex-parser "^2.2.11"
+
[email protected]:
version "0.8.2"
resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f"
@@ -1432,6 +1440,11 @@ argparse@^1.0.6, argparse@^1.0.7:
dependencies:
sprintf-js "~1.0.2"
+arity-n@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/arity-n/-/arity-n-1.0.4.tgz#d9e76b11733e08569c0847ae7b39b2860b30b745"
+ integrity sha1-2edrEXM+CFacCEeuezmyhgswt0U=
+
arr-diff@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520"
@@ -1813,6 +1826,11 @@ [email protected]:
resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8"
integrity sha1-c5JncZI7Whl0etZmqlzUv5xunOg=
+base64-arraybuffer@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.2.0.tgz#4b944fac0191aa5907afe2d8c999ccc57ce80f45"
+ integrity sha512-7emyCsu1/xiBXgQZrscw/8KPRT44I4Yq9Pe6EGs3aPRTsWuggML1/1DTuZUuIaJPIm1FTDUVXl4x/yW8s0kQDQ==
+
base64-js@^1.0.2, base64-js@^1.3.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
@@ -2437,16 +2455,16 @@ camelcase-keys@^2.0.0:
camelcase "^2.0.0"
map-obj "^1.0.0"
[email protected], camelcase@^5.0.0:
+ version "5.3.1"
+ resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
+ integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
+
camelcase@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f"
integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=
-camelcase@^5.0.0:
- version "5.3.1"
- resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
- integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
-
caniuse-api@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0"
@@ -2797,6 +2815,13 @@ [email protected]:
resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143"
integrity sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=
[email protected]:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/compose-function/-/compose-function-3.0.3.tgz#9ed675f13cc54501d30950a486ff6a7ba3ab185f"
+ integrity sha1-ntZ18TzFRQHTCVCkhv9qe6OrGF8=
+ dependencies:
+ arity-n "^1.0.4"
+
[email protected]:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
@@ -2857,13 +2882,18 @@ content-type@~1.0.4:
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==
-convert-source-map@^1.1.3, convert-source-map@^1.5.0, convert-source-map@^1.7.0:
[email protected], convert-source-map@^1.1.3, convert-source-map@^1.5.0, convert-source-map@^1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442"
integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==
dependencies:
safe-buffer "~5.1.1"
+convert-source-map@^0.3.3:
+ version "0.3.5"
+ resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-0.3.5.tgz#f1d802950af7dd2631a1febe0596550c86ab3190"
+ integrity sha1-8dgClQr33SYxof6+BZZVDIarMZA=
+
convert-source-map@~1.1.0:
version "1.1.3"
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.1.3.tgz#4829c877e9fe49b3161f3bf3673888e204699860"
@@ -3051,6 +3081,13 @@ css-declaration-sorter@^4.0.1:
postcss "^7.0.1"
timsort "^0.3.0"
[email protected]:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/css-line-break/-/css-line-break-1.1.1.tgz#d5e9bdd297840099eb0503c7310fd34927a026ef"
+ integrity sha512-1feNVaM4Fyzdj4mKPIQNL2n70MmuYzAXZ1aytlROFX1JsOo070OsugwGjj7nl6jnDJWHDM8zRZswkmeYVWZJQA==
+ dependencies:
+ base64-arraybuffer "^0.2.0"
+
[email protected]:
version "2.1.0"
resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-2.1.0.tgz#42952ac22bca5d076978638e9813abce49b8f0cc"
@@ -3119,6 +3156,16 @@ css-what@^4.0.0:
resolved "https://registry.yarnpkg.com/css-what/-/css-what-4.0.0.tgz#35e73761cab2eeb3d3661126b23d7aa0e8432233"
integrity sha512-teijzG7kwYfNVsUh2H/YN62xW3KK9YhXEgSlbxMlcyjPNvdKJqFx5lrwlJgoFP1ZHlB89iGDlo/JyshKeRhv5A==
+css@^2.0.0:
+ version "2.2.4"
+ resolved "https://registry.yarnpkg.com/css/-/css-2.2.4.tgz#c646755c73971f2bba6a601e2cf2fd71b1298929"
+ integrity sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==
+ dependencies:
+ inherits "^2.0.3"
+ source-map "^0.6.1"
+ source-map-resolve "^0.5.2"
+ urix "^0.1.0"
+
cssesc@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
@@ -3235,6 +3282,14 @@ cyclist@^1.0.1:
resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9"
integrity sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=
+d@1, d@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a"
+ integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==
+ dependencies:
+ es5-ext "^0.10.50"
+ type "^1.0.1"
+
dagre@^0.8.4:
version "0.8.5"
resolved "https://registry.yarnpkg.com/dagre/-/dagre-0.8.5.tgz#ba30b0055dac12b6c1fcc247817442777d06afee"
@@ -3664,6 +3719,11 @@ emoji-regex@^7.0.1:
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==
+emojis-list@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
+ integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k=
+
emojis-list@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78"
@@ -3870,6 +3930,32 @@ es-to-primitive@^1.2.1:
is-date-object "^1.0.1"
is-symbol "^1.0.2"
+es5-ext@^0.10.35, es5-ext@^0.10.50:
+ version "0.10.53"
+ resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.53.tgz#93c5a3acfdbef275220ad72644ad02ee18368de1"
+ integrity sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==
+ dependencies:
+ es6-iterator "~2.0.3"
+ es6-symbol "~3.1.3"
+ next-tick "~1.0.0"
+
[email protected], es6-iterator@~2.0.3:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7"
+ integrity sha1-p96IkUGgWpSwhUQDstCg+/qY87c=
+ dependencies:
+ d "1"
+ es5-ext "^0.10.35"
+ es6-symbol "^3.1.1"
+
+es6-symbol@^3.1.1, es6-symbol@~3.1.3:
+ version "3.1.3"
+ resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18"
+ integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==
+ dependencies:
+ d "^1.0.1"
+ ext "^1.1.2"
+
escalade@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
@@ -4176,6 +4262,13 @@ ext-name@^5.0.0:
ext-list "^2.0.0"
sort-keys-length "^1.0.0"
+ext@^1.1.2:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/ext/-/ext-1.4.0.tgz#89ae7a07158f79d35517882904324077e4379244"
+ integrity sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==
+ dependencies:
+ type "^2.0.0"
+
extend-shallow@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f"
@@ -4982,6 +5075,13 @@ html-escaper@^2.0.0:
resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453"
integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==
+html2canvas@^1.0.0-rc.7:
+ version "1.0.0-rc.7"
+ resolved "https://registry.yarnpkg.com/html2canvas/-/html2canvas-1.0.0-rc.7.tgz#70c159ce0e63954a91169531894d08ad5627ac98"
+ integrity sha512-yvPNZGejB2KOyKleZspjK/NruXVQuowu8NnV2HYG7gW7ytzl+umffbtUI62v2dCHQLDdsK6HIDtyJZ0W3neerA==
+ dependencies:
+ css-line-break "1.1.1"
+
htmlescape@^1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/htmlescape/-/htmlescape-1.1.1.tgz#3a03edc2214bca3b66424a3e7959349509cb0351"
@@ -6167,6 +6267,15 @@ loader-runner@^2.4.0:
resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357"
integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==
[email protected]:
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7"
+ integrity sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==
+ dependencies:
+ big.js "^5.2.2"
+ emojis-list "^2.0.0"
+ json5 "^1.0.1"
+
[email protected], loader-utils@^1.0.1, loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.1, loader-utils@^1.2.3, loader-utils@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613"
@@ -6837,6 +6946,11 @@ neo-async@^2.5.0, neo-async@^2.6.1:
resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f"
integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==
+next-tick@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c"
+ integrity sha1-yobR/ogoFpsBICCOPchCS524NCw=
+
nice-try@^1.0.4:
version "1.0.5"
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
@@ -7854,6 +7968,15 @@ postcss-value-parser@^4.0.2, postcss-value-parser@^4.1.0:
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb"
integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==
[email protected]:
+ version "7.0.21"
+ resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.21.tgz#06bb07824c19c2021c5d056d5b10c35b989f7e17"
+ integrity sha512-uIFtJElxJo29QC753JzhidoAhvp/e/Exezkdhfmt8AymWT6/5B7W1WmponYWkHk2eg6sONyTch0A3nkMPun3SQ==
+ dependencies:
+ chalk "^2.4.2"
+ source-map "^0.6.1"
+ supports-color "^6.1.0"
+
[email protected]:
version "7.0.27"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.27.tgz#cc67cdc6b0daa375105b7c424a85567345fc54d9"
@@ -8260,6 +8383,11 @@ regex-not@^1.0.0, regex-not@^1.0.2:
extend-shallow "^3.0.2"
safe-regex "^1.1.0"
+regex-parser@^2.2.11:
+ version "2.2.11"
+ resolved "https://registry.yarnpkg.com/regex-parser/-/regex-parser-2.2.11.tgz#3b37ec9049e19479806e878cabe7c1ca83ccfe58"
+ integrity sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==
+
regexp.prototype.flags@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz#7aba89b3c13a64509dabcf3ca8d9fbb9bdf5cb75"
@@ -8374,6 +8502,22 @@ resolve-from@^4.0.0:
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
+resolve-url-loader@^3.1.2:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/resolve-url-loader/-/resolve-url-loader-3.1.2.tgz#235e2c28e22e3e432ba7a5d4e305c59a58edfc08"
+ integrity sha512-QEb4A76c8Mi7I3xNKXlRKQSlLBwjUV/ULFMP+G7n3/7tJZ8MG5wsZ3ucxP1Jz8Vevn6fnJsxDx9cIls+utGzPQ==
+ dependencies:
+ adjust-sourcemap-loader "3.0.0"
+ camelcase "5.3.1"
+ compose-function "3.0.3"
+ convert-source-map "1.7.0"
+ es6-iterator "2.0.3"
+ loader-utils "1.2.3"
+ postcss "7.0.21"
+ rework "1.0.1"
+ rework-visit "1.0.0"
+ source-map "0.6.1"
+
resolve-url@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
@@ -8412,6 +8556,19 @@ ret@~0.1.10:
resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==
[email protected]:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/rework-visit/-/rework-visit-1.0.0.tgz#9945b2803f219e2f7aca00adb8bc9f640f842c9a"
+ integrity sha1-mUWygD8hni96ygCtuLyfZA+ELJo=
+
[email protected]:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/rework/-/rework-1.0.1.tgz#30806a841342b54510aa4110850cd48534144aa7"
+ integrity sha1-MIBqhBNCtUUQqkEQhQzUhTQUSqc=
+ dependencies:
+ convert-source-map "^0.3.3"
+ css "^2.0.0"
+
rfdc@^1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.1.4.tgz#ba72cc1367a0ccd9cf81a870b3b58bd3ad07f8c2"
@@ -8890,7 +9047,7 @@ source-list-map@^2.0.0:
resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34"
integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==
-source-map-resolve@^0.5.0:
+source-map-resolve@^0.5.0, source-map-resolve@^0.5.2:
version "0.5.3"
resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a"
integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==
@@ -8919,16 +9076,16 @@ [email protected]:
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.0.tgz#0fe96503ac86a5adb5de63f4e412ae4872cdbe86"
integrity sha1-D+llA6yGpa213mP05BKuSHLNvoY=
[email protected], source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1:
+ version "0.6.1"
+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
+ integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
+
source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.3:
version "0.5.7"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
-source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1:
- version "0.6.1"
- resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
- integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
-
source-map@^0.7.3:
version "0.7.3"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
@@ -9653,6 +9810,16 @@ type-is@~1.6.17, type-is@~1.6.18:
media-typer "0.3.0"
mime-types "~2.1.24"
+type@^1.0.1:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0"
+ integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==
+
+type@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/type/-/type-2.1.0.tgz#9bdc22c648cf8cf86dd23d32336a41cfb6475e3f"
+ integrity sha512-G9absDWvhAWCV2gmF1zKud3OyC61nZDwWvBL2DApaVFogI07CprggiQAOOjvp2NRjYWFzPyu7vwtDrQFq8jeSA==
+
typedarray@^0.0.6:
version "0.0.6"
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
view thread (21+ messages) latest in thread
reply
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: [email protected]
Cc: [email protected], [email protected], [email protected], [email protected]
Subject: Re: [pgAdmin][RM1802] ERD Tool (Beta)
In-Reply-To: <CAM9w-_kYsHOi+AEDxVKAEG5z9m=OhisSYfPKTDQjG8ogu03DUA@mail.gmail.com>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox