{this.props.node.fireEvent({}, 'editTable');}}>
{e.stopPropagation();}} />
{this.props.node.getNote() &&
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 0e69c0b9a..4ff8825c1 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
@@ -25,6 +25,7 @@ import gettext from 'sources/gettext';
import url_for from 'sources/url_for';
import {showERDSqlTool} from 'tools/datagrid/static/js/show_query_tool';
import 'wcdocker';
+import Theme from '../../../../../../static/js/Theme';
/* Custom react-diagram action for keyboard events */
export class KeyboardShortcutAction extends Action {
@@ -76,6 +77,9 @@ export default class BodyWidget extends React.Component {
show_details: true,
is_new_tab: false,
preferences: {},
+ table_dialog_open: true,
+ oto_dialog_open: true,
+ otm_dialog_open: true,
};
this.diagram = new ERDCore();
/* Flag for checking if user has opted for save before close */
@@ -88,7 +92,7 @@ export default class BodyWidget extends React.Component {
this.keyboardActionObj = null;
_.bindAll(this, ['onLoadDiagram', 'onSaveDiagram', 'onSaveAsDiagram', 'onSQLClick',
- 'onImageClick', 'onAddNewNode', 'onEditNode', 'onCloneNode', 'onDeleteNode', 'onNoteClick',
+ 'onImageClick', 'onAddNewNode', 'onEditTable', 'onCloneNode', 'onDeleteNode', 'onNoteClick',
'onNoteClose', 'onOneToManyClick', 'onManyToManyClick', 'onAutoDistribute', 'onDetailsToggle',
'onDetailsToggle', 'onHelpClick'
]);
@@ -130,8 +134,8 @@ export default class BodyWidget extends React.Component {
'showNote': (event)=>{
this.showNote(event.node);
},
- 'editNode': (event) => {
- this.addEditNode(event.node);
+ 'editTable': (event) => {
+ this.addEditTable(event.node);
},
};
Object.keys(diagramEvents).forEach(eventName => {
@@ -150,7 +154,7 @@ export default class BodyWidget extends React.Component {
[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.onEditNode],
+ [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],
@@ -297,19 +301,20 @@ export default class BodyWidget extends React.Component {
}
getDialog(dialogName) {
- if(dialogName === 'entity_dialog') {
- let allTables = this.diagram.getModel().getNodes().map((node)=>{
- return node.getSchemaTableName();
- });
+ let serverInfo = {
+ type: this.props.params.server_type,
+ version: this.state.server_version,
+ };
+ if(dialogName === 'table_dialog') {
return (title, attributes, isNew, callback)=>{
this.props.getDialog(dialogName).show(
- title, attributes, isNew, allTables, this.diagram.getCache('colTypes'), this.diagram.getCache('schemas'), this.state.server_version, callback
+ title, attributes, isNew, this.diagram.getModel().getNodesDict(), this.diagram.getCache('colTypes'), 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(), this.state.server_version, callback
+ title, attributes, this.diagram.getModel().getNodesDict(), serverInfo, callback
);
};
}
@@ -328,17 +333,20 @@ export default class BodyWidget extends React.Component {
}
}
- addEditNode(node) {
- let dialog = this.getDialog('entity_dialog');
+ addEditTable(node) {
+ let dialog = this.getDialog('table_dialog');
if(node) {
let [schema, table] = node.getSchemaTableName();
dialog(gettext('Table: %s (%s)', _.escape(table),_.escape(schema)), node.getData(), false, (newData)=>{
+ let oldData = node.getData();
node.setData(newData);
+ this.diagram.syncTableLinks(node, oldData);
this.diagram.repaint();
});
} else {
- dialog(gettext('New table'), {name: this.diagram.getNextTableName()}, true, (newData)=>{
+ dialog(gettext('New table'), {}, true, (newData)=>{
let newNode = this.diagram.addNode(newData);
+ this.diagram.syncTableLinks(newNode);
newNode.setSelected(true);
});
}
@@ -353,15 +361,15 @@ export default class BodyWidget extends React.Component {
}
}
- onEditNode() {
+ onEditTable() {
const selected = this.diagram.getSelectedNodes();
if(selected.length == 1) {
- this.addEditNode(selected[0]);
+ this.addEditTable(selected[0]);
}
}
onAddNewNode() {
- this.addEditNode();
+ this.addEditTable();
}
onCloneNode() {
@@ -385,10 +393,7 @@ export default class BodyWidget extends React.Component {
node.remove();
});
this.diagram.getSelectedLinks().forEach((link)=>{
- link.getTargetPort().remove();
- link.getSourcePort().remove();
- link.setSelected(false);
- link.remove();
+ this.diagram.removeOneToManyLink(link);
});
this.diagram.repaint();
},
@@ -656,10 +661,7 @@ export default class BodyWidget extends React.Component {
let dialog = this.getDialog('onetomany_dialog');
let initData = {local_table_uid: this.diagram.getSelectedNodes()[0].getID()};
dialog(gettext('One to many relation'), initData, (newData)=>{
- let newLink = this.diagram.addLink(newData, 'onetomany');
- this.diagram.clearSelection();
- newLink.setSelected(true);
- this.diagram.repaint();
+ this.diagram.addOneToManyLink(newData);
});
}
@@ -667,46 +669,7 @@ export default class BodyWidget extends React.Component {
let dialog = this.getDialog('manytomany_dialog');
let initData = {left_table_uid: this.diagram.getSelectedNodes()[0].getID()};
dialog(gettext('Many to many relation'), initData, (newData)=>{
- let nodes = this.diagram.getModel().getNodesDict();
- let left_table = nodes[newData.left_table_uid];
- let right_table = nodes[newData.right_table_uid];
- let tableData = {
- name: `${left_table.getData().name}_${right_table.getData().name}`,
- schema: left_table.getData().schema,
- columns: [{
- ...left_table.getColumnAt(newData.left_table_column_attnum),
- 'name': `${left_table.getData().name}_${left_table.getColumnAt(newData.left_table_column_attnum).name}`,
- 'is_primary_key': false,
- 'attnum': 0,
- },{
- ...right_table.getColumnAt(newData.right_table_column_attnum),
- '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);
-
- let linkData = {
- local_table_uid: newNode.getID(),
- 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 = {
- local_table_uid: newNode.getID(),
- 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');
-
- this.diagram.repaint();
+ this.diagram.addManyToManyLink(newData);
});
}
@@ -794,10 +757,7 @@ export default class BodyWidget extends React.Component {
try {
let response = await axios.get(url);
- let tables = response.data.data.map((table)=>{
- return this.props.transformToSupported('table', table);
- });
- this.diagram.deserializeData(tables);
+ this.diagram.deserializeData(response.data.data);
return true;
} catch (error) {
this.handleAxiosCatch(error);
@@ -809,7 +769,7 @@ export default class BodyWidget extends React.Component {
render() {
return (
- <>
+
-
@@ -869,7 +829,7 @@ export default class BodyWidget extends React.Component {
{this.canvasEle = ele?.ref?.current;}} engine={this.diagram.getEngine()} />
- >
+
);
}
}
@@ -888,7 +848,6 @@ BodyWidget.propTypes = {
gen: PropTypes.bool.isRequired,
}),
getDialog: PropTypes.func.isRequired,
- transformToSupported: PropTypes.func.isRequired,
pgWindow: PropTypes.object.isRequired,
pgAdmin: PropTypes.object.isRequired,
alertify: PropTypes.object.isRequired,
diff --git a/web/pgadmin/tools/erd/static/scss/_erd.scss b/web/pgadmin/tools/erd/static/scss/_erd.scss
index f48d65b4c..150ef6778 100644
--- a/web/pgadmin/tools/erd/static/scss/_erd.scss
+++ b/web/pgadmin/tools/erd/static/scss/_erd.scss
@@ -205,3 +205,14 @@
}
}
}
+
+.alertify {
+ .erd-dialog {
+ .ajs-body .ajs-content {
+ bottom: 0!important;
+ }
+ .ajs-footer {
+ display: none;
+ }
+ }
+}
diff --git a/web/regression/javascript/erd/erd_core_spec.js b/web/regression/javascript/erd/erd_core_spec.js
index b26a5fc05..635d488d4 100644
--- a/web/regression/javascript/erd/erd_core_spec.js
+++ b/web/regression/javascript/erd/erd_core_spec.js
@@ -9,6 +9,7 @@
import ERDCore from 'pgadmin.tools.erd/erd_tool/ERDCore';
import * as createEngineLib from '@projectstorm/react-diagrams';
import TEST_TABLES_DATA from './test_tables';
+import { FakeLink, FakeNode } from './fake_item';
describe('ERDCore', ()=>{
let eleFactory = jasmine.createSpyObj('nodeFactories', {
@@ -132,7 +133,8 @@ describe('ERDCore', ()=>{
});
it('addNode', ()=>{
- let newNode = jasmine.createSpyObj('newNode', ['setPosition']);
+ let newNode = new FakeNode({});
+ spyOn(newNode, 'setPosition');
spyOn(erdCoreObj, 'getNewNode').and.returnValue(newNode);
spyOn(erdCoreObj, 'clearSelection');
@@ -151,33 +153,17 @@ describe('ERDCore', ()=>{
it('addLink', ()=>{
+ let node1 = new FakeNode({'name': 'table1'}, 'id1');
+ let node2 = new FakeNode({'name': 'table2'}, 'id2');
+ spyOn(node1, 'addPort').and.callThrough();
+ spyOn(node2, 'addPort').and.callThrough();
let nodesDict = {
- 'id1': {
- serializeData: function(){ return {
- 'name': 'table1',
- };},
- getPortName: function(attnum) {
- return `port-${attnum}`;
- },
- getPort: function() {
- return null;
- },
- addPort: jasmine.createSpy('addPort').and.callFake((obj)=>obj),
- },
- 'id2': {
- serializeData: function(){ return {
- 'name': 'table2',
- };},
- getPortName: function(attnum) {
- return `port-${attnum}`;
- },
- getPort: function() {
- return null;
- },
- addPort: jasmine.createSpy('addPort').and.callFake((obj)=>obj),
- },
+ 'id1': node1,
+ 'id2': node2,
};
- let link = jasmine.createSpyObj('link', ['setSourcePort', 'setTargetPort']);
+ let link = new FakeLink();
+ spyOn(link, 'setSourcePort').and.callThrough();
+ spyOn(link, 'setTargetPort').and.callThrough();
spyOn(erdEngine.getModel(), 'getNodesDict').and.returnValue(nodesDict);
spyOn(erdCoreObj, 'getNewLink').and.callFake(function() {
return link;
@@ -199,7 +185,6 @@ describe('ERDCore', ()=>{
expect(nodesDict['id2'].addPort).toHaveBeenCalledWith({name: 'port-3'});
expect(link.setSourcePort).toHaveBeenCalledWith({name: 'port-1'});
expect(link.setTargetPort).toHaveBeenCalledWith({name: 'port-3'});
-
});
it('serialize', ()=>{
@@ -222,41 +207,26 @@ describe('ERDCore', ()=>{
});
it('serializeData', ()=>{
- spyOn(erdEngine.getModel(), 'getNodesDict').and.returnValue({
- 'id1': {
- serializeData: function(){ return {
- 'name': 'table1',
- };},
- },
- 'id2': {
- serializeData: function(){ return {
- 'name': 'table2',
- };},
- },
- });
+ let node1 = new FakeNode({'name': 'table1'}, 'id1');
+ let node2 = new FakeNode({'name': 'table2'}, 'id2');
+ let nodesDict = {
+ 'id1': node1,
+ 'id2': node2,
+ };
+ spyOn(erdEngine.getModel(), 'getNodesDict').and.returnValue(nodesDict);
spyOn(erdEngine.getModel(), 'getLinks').and.returnValue([
- {
- serializeData: function(){ return {
- 'name': 'link1',
- };},
- getID: function(){ return 'lid1'; },
- },
- {
- serializeData: function(){ return {
- 'name': 'link2',
- };},
- getID: function(){ return 'lid2'; },
- },
+ new FakeLink({
+ 'name': 'link1',
+ }, 'lid1'),
+ new FakeLink({
+ 'name': 'link2',
+ }, 'lid2'),
]);
expect(JSON.stringify(erdCoreObj.serializeData())).toEqual(JSON.stringify({
nodes: {
'id1': {'name': 'table1'},
'id2': {'name': 'table2'},
},
- links: {
- 'lid1': {'name': 'link1'},
- 'lid2': {'name': 'link2'},
- },
}));
});
@@ -276,6 +246,9 @@ describe('ERDCore', ()=>{
addPort: function() {
},
+ getData: function() {
+ return table;
+ }
};
});
spyOn(erdEngine.getModel(), 'getNodesDict').and.returnValue(nodesDict);
@@ -288,11 +261,7 @@ describe('ERDCore', ()=>{
});
spyOn(erdCoreObj, 'getNewPort').and.returnValue({id: 'id'});
spyOn(erdCoreObj, 'addNode').and.callFake(function(data) {
- return {
- getID: function() {
- return `id-${data.name}`;
- },
- };
+ return new FakeNode({}, `id-${data.name}`);
});
spyOn(erdCoreObj, 'addLink');
spyOn(erdCoreObj, 'dagreDistributeNodes');
@@ -319,8 +288,8 @@ describe('ERDCore', ()=>{
it('getNodesData', ()=>{
spyOn(erdEngine.getModel(), 'getNodes').and.returnValue([
- {getData: function () {return {name:'node1'};}},
- {getData: function () {return {name:'node2'};}},
+ new FakeNode({name:'node1'}),
+ new FakeNode({name:'node2'}),
]);
expect(JSON.stringify(erdCoreObj.getNodesData())).toEqual(JSON.stringify([
{name:'node1'}, {name:'node2'},
diff --git a/web/regression/javascript/erd/fake_item.js b/web/regression/javascript/erd/fake_item.js
new file mode 100644
index 000000000..498ef1db1
--- /dev/null
+++ b/web/regression/javascript/erd/fake_item.js
@@ -0,0 +1,42 @@
+import _ from 'lodash';
+
+export class FakeNode {
+ constructor(data, id='nid1') {
+ this.data = data || {};
+ this.id = id;
+ }
+ setSelected() {}
+ getColumns() {return this.data.columns;}
+ getID() {return this.id;}
+ setData(data) {this.data = data;}
+ getData() {return this.data;}
+ getPosition() {return {x: 30, y: 30};}
+ setPosition() {}
+ serializeData() {return this.getData();}
+ getPortName(attnum) {return `port-${attnum}`;}
+ getPort() {return null;}
+ addPort(obj) {return obj;}
+ getColumnAt(pos) {return _.find(this.getColumns()||[], (c)=>c.attnum==pos);}
+ remove() {}
+ getSchemaTableName() {return [this.data.schema, this.data.name];}
+ cloneData(tabName) {
+ let retVal = {...this.data};
+ retVal.name = tabName;
+ return retVal;
+ }
+}
+
+export class FakeLink {
+ constructor(data, id='lid1') {
+ this.data = data;
+ this.id = id;
+ }
+ setSelected() {}
+ getID() {return this.id;}
+ getData() {return this.data;}
+ getSourcePort() {return {remove: ()=>{}};}
+ setSourcePort() {}
+ getTargetPort() {return {remove: ()=>{}};}
+ setTargetPort() {}
+ remove() {}
+}
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 2095ecd90..ca30f63ff 100644
--- a/web/regression/javascript/erd/ui_components/body_widget_spec.js
+++ b/web/regression/javascript/erd/ui_components/body_widget_spec.js
@@ -10,6 +10,7 @@ import * as erdModule from 'pgadmin.tools.erd/erd_module';
import erdPref from './erd_preferences';
import BodyWidget from 'pgadmin.tools.erd/erd_tool/ui_components/BodyWidget';
import * as ERDSqlTool from 'tools/datagrid/static/js/show_query_tool';
+import { FakeLink, FakeNode } from '../fake_item';
let pgAdmin = {
Browser: {
@@ -60,7 +61,7 @@ let mtmDialog = jasmine.createSpyObj('mtmDialog', ['show']);
let getDialog = (dialogName)=>{
switch(dialogName) {
- case 'entity_dialog': return tableDialog;
+ case 'table_dialog': return tableDialog;
case 'onetomany_dialog': return otmDialog;
case 'manytomany_dialog': return mtmDialog;
}
@@ -93,19 +94,16 @@ describe('ERD BodyWidget', ()=>{
title: 'postgres/postgres@PostgreSQL 12',
trans_id: 110008,
};
+ let newNode = new FakeNode({
+ columns: [{attnum: 0}, {attnum: 1}],
+ }, 'newid1');
beforeAll(()=>{
spyOn(erdModule, 'setPanelTitle');
spyOn(ERDCore.prototype, 'repaint');
spyOn(ERDCore.prototype, 'deserializeData');
- spyOn(ERDCore.prototype, 'addNode').and.returnValue({
- setSelected: ()=>{},
- getColumns: ()=>([{attnum: 0}, {attnum: 1}]),
- getID: ()=>'newid1',
- });
- spyOn(ERDCore.prototype, 'addLink').and.returnValue({
- setSelected: ()=>{},
- });
+ spyOn(ERDCore.prototype, 'addNode').and.returnValue(newNode);
+ spyOn(ERDCore.prototype, 'addLink').and.returnValue(new FakeLink());
spyOn(alertify, 'confirm').and.callFake((arg1, arg2, okCallback)=>{
okCallback();
});
@@ -128,7 +126,7 @@ describe('ERD BodyWidget', ()=>{
beforeEach(()=>{
jasmineEnzyme();
- body = mount(
{}} alertify={alertify}/>);
+ body = mount();
bodyInstance = body.instance();
});
@@ -225,18 +223,18 @@ describe('ERD BodyWidget', ()=>{
});
});
- it('event editNode', (done)=>{
+ it('event editTable', (done)=>{
let node = {key: 'value', getNote: ()=>'a note'};
- spyOn(bodyInstance, 'addEditNode');
- bodyInstance.diagram.fireEvent({node: node}, 'editNode', true);
+ spyOn(bodyInstance, 'addEditTable');
+ bodyInstance.diagram.fireEvent({node: node}, 'editTable', true);
setTimeout(()=>{
- expect(bodyInstance.addEditNode).toHaveBeenCalledWith(node);
+ expect(bodyInstance.addEditTable).toHaveBeenCalledWith(node);
done();
});
});
it('getDialog', ()=>{
- bodyInstance.getDialog('entity_dialog')();
+ bodyInstance.getDialog('table_dialog')();
expect(tableDialog.show).toHaveBeenCalled();
bodyInstance.getDialog('onetomany_dialog')();
@@ -246,10 +244,20 @@ describe('ERD BodyWidget', ()=>{
expect(mtmDialog.show).toHaveBeenCalled();
});
- it('addEditNode', ()=>{
+ 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');
+ let nodesDict = {
+ 'id1': node1,
+ 'id2': node2,
+ };
+ spyOn(bodyInstance.diagram, 'getModel').and.returnValue({
+ 'getNodesDict': ()=>nodesDict,
+ });
+ spyOn(bodyInstance.diagram, 'addLink');
/* New */
tableDialog.show.calls.reset();
- bodyInstance.addEditNode();
+ bodyInstance.addEditTable();
expect(tableDialog.show).toHaveBeenCalled();
let saveCallback = tableDialog.show.calls.mostRecent().args[7];
@@ -259,12 +267,9 @@ describe('ERD BodyWidget', ()=>{
/* Existing */
tableDialog.show.calls.reset();
- let node = jasmine.createSpyObj('node',{
- getSchemaTableName: ['erd1', 'table1'],
- setData: null,
- getData: null,
- });
- bodyInstance.addEditNode(node);
+ let node = new FakeNode({name: 'table1', schema: 'erd1'});
+ spyOn(node, 'setData');
+ bodyInstance.addEditTable(node);
expect(tableDialog.show).toHaveBeenCalled();
saveCallback = tableDialog.show.calls.mostRecent().args[7];
@@ -273,49 +278,44 @@ describe('ERD BodyWidget', ()=>{
expect(node.setData).toHaveBeenCalledWith(newData);
});
- it('onEditNode', ()=>{
+ it('onEditTable', ()=>{
let node = {key: 'value'};
- spyOn(bodyInstance, 'addEditNode');
+ spyOn(bodyInstance, 'addEditTable');
spyOn(bodyInstance.diagram, 'getSelectedNodes').and.returnValue([node]);
- bodyInstance.onEditNode();
- expect(bodyInstance.addEditNode).toHaveBeenCalledWith(node);
+ bodyInstance.onEditTable();
+ expect(bodyInstance.addEditTable).toHaveBeenCalledWith(node);
});
it('onAddNewNode', ()=>{
- spyOn(bodyInstance, 'addEditNode');
+ spyOn(bodyInstance, 'addEditTable');
bodyInstance.onAddNewNode();
- expect(bodyInstance.addEditNode).toHaveBeenCalled();
+ expect(bodyInstance.addEditTable).toHaveBeenCalled();
});
it('onCloneNode', ()=>{
- let node = jasmine.createSpyObj('node',{
- getSchemaTableName: ['erd1', 'table1'],
- setData: null,
- getData: null,
- cloneData: {key: 'value'},
- getPosition: {x: 30, y: 30},
- });
+ let node = new FakeNode({name: 'table1', schema: 'erd1'});
spyOn(bodyInstance.diagram, 'getSelectedNodes').and.returnValue([node]);
spyOn(bodyInstance.diagram, 'getNextTableName').and.returnValue('newtable1');
+ bodyInstance.diagram.addNode.calls.reset();
bodyInstance.onCloneNode();
- expect(bodyInstance.diagram.addNode).toHaveBeenCalledWith({key: 'value'}, [50, 50]);
+ let cloneArgs = bodyInstance.diagram.addNode.calls.argsFor(0);
+ expect(cloneArgs[0]).toEqual(jasmine.objectContaining({
+ name: 'newtable1',
+ schema: 'erd1',
+ }));
+ expect(cloneArgs[1]).toEqual([50, 50]);
});
it('onDeleteNode', (done)=>{
- let node = jasmine.createSpyObj('node',{
- getSchemaTableName: ['erd1', 'table1'],
- setData: null,
- getData: null,
- cloneData: {key: 'value'},
- getPosition: {x: 30, y: 30},
- remove: null,
- setSelected: null,
- });
- let link = jasmine.createSpyObj('link', {
- remove: null,
- setSelected: null,
- getTargetPort: jasmine.createSpyObj('port', ['remove']),
- getSourcePort: jasmine.createSpyObj('port', ['remove']),
+ let node = new FakeNode({name: 'table1', schema: 'erd1'});
+ spyOn(node, 'remove');
+ let link = new FakeLink({local_table_uid: 'tid1'});
+ spyOn(link, 'remove');
+ let nodesDict = {
+ 'tid1': node
+ };
+ spyOn(bodyInstance.diagram, 'getModel').and.returnValue({
+ 'getNodesDict': ()=>nodesDict,
});
spyOn(bodyInstance.diagram, 'getSelectedNodes').and.returnValue([node]);
spyOn(bodyInstance.diagram, 'getSelectedLinks').and.returnValue([link]);
@@ -413,9 +413,17 @@ describe('ERD BodyWidget', ()=>{
});
it('onOneToManyClick', ()=>{
- let node = jasmine.createSpyObj('node',{
- getID: 'id1',
+ let node = new FakeNode({}, 'id1');
+ 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 = {
+ 'id1': node1,
+ 'id2': node2,
+ };
+ spyOn(bodyInstance.diagram, 'getModel').and.returnValue({
+ 'getNodesDict': ()=>nodesDict,
});
+ spyOn(bodyInstance.diagram, 'addLink');
spyOn(bodyInstance.diagram, 'getSelectedNodes').and.returnValue([node]);
otmDialog.show.calls.reset();
@@ -423,15 +431,18 @@ describe('ERD BodyWidget', ()=>{
expect(otmDialog.show).toHaveBeenCalled();
let saveCallback = otmDialog.show.calls.mostRecent().args[4];
- let newData = {key: 'value'};
+ let newData = {
+ local_table_uid: 'id1',
+ local_column_attnum: 1,
+ referenced_table_uid: 'id2',
+ referenced_column_attnum: 2,
+ };
saveCallback(newData);
expect(bodyInstance.diagram.addLink).toHaveBeenCalledWith(newData, 'onetomany');
});
it('onManyToManyClick', ()=>{
- let node = jasmine.createSpyObj('node',{
- getID: 'id1',
- });
+ let node = new FakeNode({}, 'id1');
spyOn(bodyInstance.diagram, 'getSelectedNodes').and.returnValue([node]);
mtmDialog.show.calls.reset();
@@ -439,19 +450,12 @@ describe('ERD BodyWidget', ()=>{
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 = {
- 'id1': {
- getID: ()=>'id1',
- getData: ()=>({name: 'table1', schema: 'erd1'}),
- getColumnAt: ()=>({name: 'col1', type: 'type1', attnum: 0}),
- addPort: jasmine.createSpy('addPort').and.callFake((obj)=>obj),
- },
- 'id2': {
- getID: ()=>'id2',
- getData: ()=>({name: 'table2', schema: 'erd2'}),
- getColumnAt: ()=>({name: 'col2', type: 'type2', attnum: 1}),
- addPort: jasmine.createSpy('addPort').and.callFake((obj)=>obj),
- },
+ 'id1': node1,
+ 'id2': node2,
+ 'newid1': newNode,
};
spyOn(bodyInstance.diagram, 'getModel').and.returnValue({
'getNodesDict': ()=>nodesDict,
@@ -468,24 +472,21 @@ describe('ERD BodyWidget', ()=>{
bodyInstance.diagram.addNode.calls.reset();
bodyInstance.diagram.addLink.calls.reset();
saveCallback(newData);
- expect(bodyInstance.diagram.addNode).toHaveBeenCalledWith({
+ let tableData = bodyInstance.diagram.addNode.calls.argsFor(0)[0];
+ expect(tableData).toEqual(jasmine.objectContaining({
name: 'table1_table2',
schema: 'erd1',
- columns: [
- {
- type: 'type1',
- name: 'table1_col1',
- is_primary_key: false,
- attnum: 0,
- },
- {
- type: 'type2',
- name: 'table2_col2',
- is_primary_key: false,
- attnum: 1,
- },
- ],
- });
+ }));
+ expect(tableData.columns[0]).toEqual(jasmine.objectContaining({
+ type: 'type1',
+ name: 'table1_col1',
+ attnum: 0,
+ }));
+ expect(tableData.columns[1]).toEqual(jasmine.objectContaining({
+ type: 'type2',
+ name: 'table2_col2',
+ attnum: 1,
+ }));
let linkData = {
local_table_uid: 'newid1',
diff --git a/web/regression/javascript/schema_ui_files/column.ui.spec.js b/web/regression/javascript/schema_ui_files/column.ui.spec.js
index a6528ab16..bde3aff27 100644
--- a/web/regression/javascript/schema_ui_files/column.ui.spec.js
+++ b/web/regression/javascript/schema_ui_files/column.ui.spec.js
@@ -202,13 +202,13 @@ describe('ColumnSchema', ()=>{
expect(schemaObj.inSchemaWithColumnCheck(state)).toBe(true);
schemaObj.nodeInfo = {};
- expect(schemaObj.inSchemaWithColumnCheck(state)).toBe(true);
+ expect(schemaObj.inSchemaWithColumnCheck(state)).toBe(false);
});
it('editableCheckForTable', ()=>{
let state = {};
schemaObj.nodeInfo = {};
- expect(schemaObj.editableCheckForTable(state)).toBe(false);
+ expect(schemaObj.editableCheckForTable(state)).toBe(true);
});
it('depChange', ()=>{
diff --git a/web/yarn.lock b/web/yarn.lock
index b92c49a2d..254a37a9d 100644
--- a/web/yarn.lock
+++ b/web/yarn.lock
@@ -1464,50 +1464,50 @@
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.9.0.tgz#32e63212293dd3efbb521cd35a5020ab66eaa546"
integrity sha512-wjtKehFAIARq2OxK8j3JrggNlEslJfNuSm2ArteIbKyRMts2g0a7KzTxfRVNUM+O0gnBJ2hNV8nWPOYBgI1sew==
-"@projectstorm/geometry@^6.5.2":
- version "6.5.2"
- resolved "https://registry.yarnpkg.com/@projectstorm/geometry/-/geometry-6.5.2.tgz#76ccc7280a49c64953036aa96287f408981e5913"
- integrity sha512-PGrcMXr6CkdH1DvcY+MDYzg6suWnOXehP8S69DhiEeWUFmQhKJSCAPEovdQOpohL6urlKaSNbDM8auUypFbTfw==
-
-"@projectstorm/react-canvas-core@^6.5.2":
- version "6.5.2"
- resolved "https://registry.yarnpkg.com/@projectstorm/react-canvas-core/-/react-canvas-core-6.5.2.tgz#65726df39c15487d9c6b23616cfa6b182d82fcbe"
- integrity sha512-tFfWpaPZ71lMDFRL69jRFTjmYit6FKNpkAiI9sqYeH2I4Y7OjuxmCqYomlzh8ZSLVwKHtcI6Vd7hhoatEBupEQ==
- dependencies:
- "@projectstorm/geometry" "^6.5.2"
-
-"@projectstorm/react-diagrams-core@^6.5.2":
- version "6.5.2"
- resolved "https://registry.yarnpkg.com/@projectstorm/react-diagrams-core/-/react-diagrams-core-6.5.2.tgz#4c8c92ed288b2934de11c1a52fda72249b151932"
- integrity sha512-7ganJGs7lcRB1sTvUs+MQ9RiSCGD+IHgISo45aS81+XFllO8u7uZRaPdIyObhz+khwZvMk2pWmXYPNJwGThOZQ==
- dependencies:
- "@projectstorm/geometry" "^6.5.2"
- "@projectstorm/react-canvas-core" "^6.5.2"
-
-"@projectstorm/react-diagrams-defaults@^6.5.2":
- version "6.5.2"
- resolved "https://registry.yarnpkg.com/@projectstorm/react-diagrams-defaults/-/react-diagrams-defaults-6.5.2.tgz#084138e8b2ac2643bcfa115fb543f69c0eaf88f3"
- integrity sha512-8+hAe88Lj7uBsugAT7f5SsjqxmjYfeBYwViaFpnIilmuYF/uXN0w/ns8Mcq2FE49wGOXtBoxFusoWmDWwgE+fQ==
- dependencies:
- "@projectstorm/react-diagrams-core" "^6.5.2"
-
-"@projectstorm/react-diagrams-routing@^6.5.2":
- version "6.5.2"
- resolved "https://registry.yarnpkg.com/@projectstorm/react-diagrams-routing/-/react-diagrams-routing-6.5.2.tgz#824dadbcd8c14c647829bdd4761afef69dec5622"
- integrity sha512-pWsDmk/4hbx6Ii2Z3Uvd9dZ/xB9F7u66mGVGMWb3txxTT68Y6mwdVJRQFu/frm/Sk3sZv7gNf1EqadsilIh7vg==
- dependencies:
- "@projectstorm/geometry" "^6.5.2"
- "@projectstorm/react-diagrams-core" "^6.5.2"
- "@projectstorm/react-diagrams-defaults" "^6.5.2"
-
-"@projectstorm/react-diagrams@^6.4.2":
- version "6.5.2"
- resolved "https://registry.yarnpkg.com/@projectstorm/react-diagrams/-/react-diagrams-6.5.2.tgz#3f65a903b1853e51d68109a513d91d190d278864"
- integrity sha512-1xlz1jVffWq5R7Oqj/BEY06Cf+2uLV5eEY6pGxuGFfp5SXeTNCSIS/khkbFou707Gor3D8MOqdBpZvF2NfoLmA==
- dependencies:
- "@projectstorm/react-diagrams-core" "^6.5.2"
- "@projectstorm/react-diagrams-defaults" "^6.5.2"
- "@projectstorm/react-diagrams-routing" "^6.5.2"
+"@projectstorm/geometry@^6.6.1":
+ version "6.6.1"
+ resolved "https://registry.yarnpkg.com/@projectstorm/geometry/-/geometry-6.6.1.tgz#4a42f5c8fdfcc3d951e73f5db7fe9546514acc3d"
+ integrity sha512-gWRkv+fm+VIpoffHzDHPmGYlEqx8xWGfE/JR7TXAZweNdjEIxyhT++hVlCJiFJS+/cGqgN3z+eP7PNjwZUPGRg==
+
+"@projectstorm/react-canvas-core@^6.6.1":
+ version "6.6.1"
+ resolved "https://registry.yarnpkg.com/@projectstorm/react-canvas-core/-/react-canvas-core-6.6.1.tgz#93cc6e70e986fe620b6fad6b597d3aa038075244"
+ integrity sha512-wAxEh4Wja2Au0QAuLqxJNaWpVxYIffTFUZhjH8wtW8MKCWS6W9RnP6upeC8QVQi29NS59UIX4wXNzb6e6ht5ww==
+ dependencies:
+ "@projectstorm/geometry" "^6.6.1"
+
+"@projectstorm/react-diagrams-core@^6.6.1":
+ version "6.6.1"
+ resolved "https://registry.yarnpkg.com/@projectstorm/react-diagrams-core/-/react-diagrams-core-6.6.1.tgz#f626c6253dd6f4b04c3256976b55377ffac2b1bb"
+ integrity sha512-TiDwpcH+t2b2tG/UHDQvhlyx3gOQRJXxTyNDo7p+430ikTrvz1f8uNe5Rt3SrzyqxeUazLFXYBgbGpEanqOykQ==
+ dependencies:
+ "@projectstorm/geometry" "^6.6.1"
+ "@projectstorm/react-canvas-core" "^6.6.1"
+
+"@projectstorm/react-diagrams-defaults@^6.6.1":
+ version "6.6.1"
+ resolved "https://registry.yarnpkg.com/@projectstorm/react-diagrams-defaults/-/react-diagrams-defaults-6.6.1.tgz#a97cdda56d7336b84775f76a925b90286ea2833d"
+ integrity sha512-FJu8BNBjvANVZ8N99WXS/f6Mu5/yMC4Pi55kTG3vq7o14tsVMcghosmxst5eoeL251O4I+ulNvQ/yCc1Mc5org==
+ dependencies:
+ "@projectstorm/react-diagrams-core" "^6.6.1"
+
+"@projectstorm/react-diagrams-routing@^6.6.1":
+ version "6.6.1"
+ resolved "https://registry.yarnpkg.com/@projectstorm/react-diagrams-routing/-/react-diagrams-routing-6.6.1.tgz#06b77ab1f94f4567391099ffe5e1d91db34408ff"
+ integrity sha512-m8akJynhanxmpc/A2U7bcgFxIMxsjb3zmYBRGFltVJve87mir8ACaH2gmiHYcAfgEHxdh+x7mCuUlfNP242Ytw==
+ dependencies:
+ "@projectstorm/geometry" "^6.6.1"
+ "@projectstorm/react-diagrams-core" "^6.6.1"
+ "@projectstorm/react-diagrams-defaults" "^6.6.1"
+
+"@projectstorm/react-diagrams@^6.6.1":
+ version "6.6.1"
+ resolved "https://registry.yarnpkg.com/@projectstorm/react-diagrams/-/react-diagrams-6.6.1.tgz#3af4007613f487ba58801cdcded955683b3f01c5"
+ integrity sha512-tLSXfEf/dGFUN8JCCRMrYyIBhhn+eVw24xQodmtcReJxQpKa31EWh9CmJ6UEg7xUnabMG9f2plOPyJqyFssGTA==
+ dependencies:
+ "@projectstorm/react-diagrams-core" "^6.6.1"
+ "@projectstorm/react-diagrams-defaults" "^6.6.1"
+ "@projectstorm/react-diagrams-routing" "^6.6.1"
"@simonwep/pickr@^1.5.1":
version "1.8.1"