mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
Enhancements to the ERD when selecting a relationship. #4088
This commit is contained in:
@@ -15,7 +15,7 @@ import { ZoomCanvasAction } from '@projectstorm/react-canvas-core';
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
|
||||||
import {TableNodeFactory, TableNodeModel } from './nodes/TableNode';
|
import {TableNodeFactory, TableNodeModel } from './nodes/TableNode';
|
||||||
import {OneToManyLinkFactory, OneToManyLinkModel } from './links/OneToManyLink';
|
import {OneToManyLinkFactory, OneToManyLinkModel, POINTER_SIZE } from './links/OneToManyLink';
|
||||||
import { OneToManyPortFactory } from './ports/OneToManyPort';
|
import { OneToManyPortFactory } from './ports/OneToManyPort';
|
||||||
import ERDModel from './ERDModel';
|
import ERDModel from './ERDModel';
|
||||||
import ForeignKeySchema from '../../../../../browser/server_groups/servers/databases/schemas/tables/constraints/foreign_key/static/js/foreign_key.ui';
|
import ForeignKeySchema from '../../../../../browser/server_groups/servers/databases/schemas/tables/constraints/foreign_key/static/js/foreign_key.ui';
|
||||||
@@ -81,6 +81,7 @@ export default class ERDCore {
|
|||||||
if(!this.node_position_updating) {
|
if(!this.node_position_updating) {
|
||||||
this.node_position_updating = true;
|
this.node_position_updating = true;
|
||||||
this.fireEvent({}, 'nodesUpdated', true);
|
this.fireEvent({}, 'nodesUpdated', true);
|
||||||
|
this.optimizePortsPosition(node);
|
||||||
setTimeout(()=>{
|
setTimeout(()=>{
|
||||||
this.node_position_updating = false;
|
this.node_position_updating = false;
|
||||||
}, 500);
|
}, 500);
|
||||||
@@ -193,15 +194,44 @@ export default class ERDCore {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getNewPort(type, initData, initOptions) {
|
getNewPort(portName, alignment) {
|
||||||
return this.getEngine().getPortFactories().getFactory(type).generateModel({
|
return this.getEngine().getPortFactories().getFactory('onetomany').generateModel({
|
||||||
initialConfig: {
|
initialConfig: {
|
||||||
data:initData,
|
data: null,
|
||||||
options:initOptions,
|
options: {
|
||||||
|
name: portName,
|
||||||
|
alignment: alignment
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getLeftRightPorts(node, attnum) {
|
||||||
|
const leftPort = node.getPort(node.getPortName(attnum, PortModelAlignment.LEFT))
|
||||||
|
?? node.addPort(this.getNewPort(node.getPortName(attnum, PortModelAlignment.LEFT), PortModelAlignment.LEFT));
|
||||||
|
const rightPort = node.getPort(node.getPortName(attnum, PortModelAlignment.RIGHT))
|
||||||
|
?? node.addPort(this.getNewPort(node.getPortName(attnum, PortModelAlignment.RIGHT), PortModelAlignment.RIGHT));
|
||||||
|
|
||||||
|
return [leftPort, rightPort];
|
||||||
|
}
|
||||||
|
|
||||||
|
optimizePortsPosition(node) {
|
||||||
|
Object.values(node.getLinks()).forEach((link)=>{
|
||||||
|
const sourcePort = link.getSourcePort();
|
||||||
|
const targetPort = link.getTargetPort();
|
||||||
|
|
||||||
|
const [newSourcePort, newTargetPort] = this.getOptimumPorts(
|
||||||
|
sourcePort.getNode(),
|
||||||
|
sourcePort.getNode().getPortAttnum(sourcePort.getName()),
|
||||||
|
targetPort.getNode(),
|
||||||
|
targetPort.getNode().getPortAttnum(targetPort.getName())
|
||||||
|
);
|
||||||
|
|
||||||
|
sourcePort != newSourcePort && link.setSourcePort(newSourcePort);
|
||||||
|
targetPort != newTargetPort && link.setTargetPort(newTargetPort);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
addNode(data, position=[50, 50], metadata={}) {
|
addNode(data, position=[50, 50], metadata={}) {
|
||||||
let newNode = this.getNewNode(data);
|
let newNode = this.getNewNode(data);
|
||||||
this.clearSelection();
|
this.clearSelection();
|
||||||
@@ -231,24 +261,45 @@ export default class ERDCore {
|
|||||||
}).length > 0;
|
}).length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getOptimumPorts(sourceNode, sourceAttnum, targetNode, targetAttnum) {
|
||||||
|
const [sourceLeftPort, sourceRightPort] = this.getLeftRightPorts(sourceNode, sourceAttnum);
|
||||||
|
const [targetLeftPort, targetRightPort] = this.getLeftRightPorts(targetNode, targetAttnum);
|
||||||
|
|
||||||
|
/* Lets use right as default */
|
||||||
|
let sourcePort = sourceRightPort;
|
||||||
|
let targetPort = targetRightPort;
|
||||||
|
const sourceNodePos = sourceNode.getBoundingBox();
|
||||||
|
const targetNodePos = targetNode.getBoundingBox();
|
||||||
|
const sourceLeftX = sourceNodePos.getBottomLeft().x;
|
||||||
|
const sourceRightX = sourceNodePos.getBottomRight().x;
|
||||||
|
const targetLeftX = targetNodePos.getBottomLeft().x;
|
||||||
|
const targetRightX = targetNodePos.getBottomRight().x;
|
||||||
|
|
||||||
|
const OFFSET = POINTER_SIZE*2+10;
|
||||||
|
|
||||||
|
if(targetLeftX - sourceRightX >= OFFSET) {
|
||||||
|
sourcePort = sourceRightPort;
|
||||||
|
targetPort = targetLeftPort;
|
||||||
|
} else if(sourceLeftX - targetRightX >= OFFSET) {
|
||||||
|
sourcePort = sourceLeftPort;
|
||||||
|
targetPort = targetRightPort;
|
||||||
|
} else if(targetLeftX - sourceRightX < OFFSET || sourceLeftX - targetRightX < OFFSET) {
|
||||||
|
if(sourcePort.getAlignment() == PortModelAlignment.RIGHT) {
|
||||||
|
targetPort = targetRightPort;
|
||||||
|
} else {
|
||||||
|
targetPort = targetLeftPort;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [sourcePort, targetPort];
|
||||||
|
}
|
||||||
|
|
||||||
addLink(data, type) {
|
addLink(data, type) {
|
||||||
let tableNodesDict = this.getModel().getNodesDict();
|
let tableNodesDict = this.getModel().getNodesDict();
|
||||||
let sourceNode = tableNodesDict[data.referenced_table_uid];
|
let sourceNode = tableNodesDict[data.referenced_table_uid];
|
||||||
let targetNode = tableNodesDict[data.local_table_uid];
|
let targetNode = tableNodesDict[data.local_table_uid];
|
||||||
|
|
||||||
let portName = sourceNode.getPortName(data.referenced_column_attnum);
|
const [sourcePort, targetPort] = this.getOptimumPorts(
|
||||||
let sourcePort = sourceNode.getPort(portName);
|
sourceNode, data.referenced_column_attnum, targetNode, data.local_column_attnum);
|
||||||
/* Create the port if not there */
|
|
||||||
if(!sourcePort) {
|
|
||||||
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, subtype: 'many', alignment:PortModelAlignment.RIGHT}));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Link the ports */
|
/* Link the ports */
|
||||||
let newLink = this.getNewLink(type, data);
|
let newLink = this.getNewLink(type, data);
|
||||||
@@ -297,30 +348,30 @@ export default class ERDCore {
|
|||||||
}
|
}
|
||||||
let tableData = tableNode.getData();
|
let tableData = tableNode.getData();
|
||||||
/* Sync the name changes in references FK */
|
/* Sync the name changes in references FK */
|
||||||
Object.values(tableNode.getPorts()).forEach((port)=>{
|
Object.values(tableNode.getLinks()).forEach((link)=>{
|
||||||
if(port.getSubtype() != 'one') {
|
if(link.getSourcePort().getNode() != tableNode) {
|
||||||
|
/* SourcePort is the referred table */
|
||||||
|
/* If the link doesn't refer this table, skip it */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Object.values(port.getLinks()).forEach((link)=>{
|
let linkData = link.getData();
|
||||||
let linkData = link.getData();
|
let fkTableNode = this.getModel().getNodesDict()[linkData.local_table_uid];
|
||||||
let fkTableNode = this.getModel().getNodesDict()[linkData.local_table_uid];
|
|
||||||
|
|
||||||
let newForeingKeys = [];
|
let newForeingKeys = [];
|
||||||
/* Update the FK table with new references */
|
/* Update the FK table with new references */
|
||||||
fkTableNode.getData().foreign_key?.forEach((theFkRow)=>{
|
fkTableNode.getData().foreign_key?.forEach((theFkRow)=>{
|
||||||
for(let fkColumn of theFkRow.columns) {
|
for(let fkColumn of theFkRow.columns) {
|
||||||
if(fkColumn.references == tableNode.getID()) {
|
if(fkColumn.references == tableNode.getID()) {
|
||||||
let attnum = _.find(oldTableData.columns, (c)=>c.name==fkColumn.referenced).attnum;
|
let attnum = _.find(oldTableData.columns, (c)=>c.name==fkColumn.referenced).attnum;
|
||||||
fkColumn.referenced = _.find(tableData.columns, (colm)=>colm.attnum==attnum).name;
|
fkColumn.referenced = _.find(tableData.columns, (colm)=>colm.attnum==attnum).name;
|
||||||
fkColumn.references_table_name = tableData.name;
|
fkColumn.references_table_name = tableData.name;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
newForeingKeys.push(theFkRow);
|
}
|
||||||
});
|
newForeingKeys.push(theFkRow);
|
||||||
fkTableNode.setData({
|
});
|
||||||
...fkTableNode.getData(),
|
fkTableNode.setData({
|
||||||
foreign_key: newForeingKeys,
|
...fkTableNode.getData(),
|
||||||
});
|
foreign_key: newForeingKeys,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -352,12 +403,20 @@ export default class ERDCore {
|
|||||||
|
|
||||||
const removeLink = (theFk)=>{
|
const removeLink = (theFk)=>{
|
||||||
if(!theFk) return;
|
if(!theFk) return;
|
||||||
let attnum = _.find(tableNode.getColumns(), (col)=>col.name==theFk.local_column).attnum;
|
|
||||||
let existPort = tableNode.getPort(tableNode.getPortName(attnum));
|
let tableNodesDict = this.getModel().getNodesDict();
|
||||||
if(existPort && existPort.getSubtype() == 'many') {
|
let sourceNode = tableNodesDict[theFk.references];
|
||||||
existPort.removeAllLinks();
|
|
||||||
tableNode.removePort(existPort);
|
let localAttnum = _.find(tableNode.getColumns(), (col)=>col.name==theFk.local_column).attnum;
|
||||||
}
|
let refAttnum = _.find(sourceNode.getColumns(), (col)=>col.name==theFk.referenced).attnum;
|
||||||
|
const fkLink = Object.values(tableNode.getLinks()).find((link)=>{
|
||||||
|
const ldata = link.getData();
|
||||||
|
return ldata.local_column_attnum == localAttnum
|
||||||
|
&& ldata.local_table_uid == tableNode.getID()
|
||||||
|
&& ldata.referenced_column_attnum == refAttnum
|
||||||
|
&& ldata.referenced_table_uid == theFk.references;
|
||||||
|
});
|
||||||
|
fkLink?.remove();
|
||||||
};
|
};
|
||||||
|
|
||||||
const changeDiff = diffArray(
|
const changeDiff = diffArray(
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ import PropTypes from 'prop-types';
|
|||||||
import { makeStyles } from '@material-ui/core';
|
import { makeStyles } from '@material-ui/core';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
|
|
||||||
|
export const POINTER_SIZE = 30;
|
||||||
|
|
||||||
export const OneToManyModel = {
|
export const OneToManyModel = {
|
||||||
local_table_uid: undefined,
|
local_table_uid: undefined,
|
||||||
local_column_attnum: undefined,
|
local_column_attnum: undefined,
|
||||||
@@ -141,32 +143,31 @@ export class OneToManyLinkWidget extends RightAngleLinkWidget {
|
|||||||
super(props);
|
super(props);
|
||||||
}
|
}
|
||||||
|
|
||||||
endPointTranslation(alignment, offset) {
|
endPointTranslation(alignment) {
|
||||||
let degree = 0;
|
let degree = 0;
|
||||||
let tx = 0, ty = 0;
|
let tx = 0, ty = 0;
|
||||||
switch(alignment) {
|
switch(alignment) {
|
||||||
case PortModelAlignment.BOTTOM:
|
case PortModelAlignment.BOTTOM:
|
||||||
ty = -offset;
|
ty = -POINTER_SIZE;
|
||||||
break;
|
break;
|
||||||
case PortModelAlignment.LEFT:
|
case PortModelAlignment.LEFT:
|
||||||
degree = 90;
|
degree = 90;
|
||||||
tx = offset;
|
tx = POINTER_SIZE;
|
||||||
break;
|
break;
|
||||||
case PortModelAlignment.TOP:
|
case PortModelAlignment.TOP:
|
||||||
degree = 180;
|
degree = 180;
|
||||||
ty = offset;
|
ty = POINTER_SIZE;
|
||||||
break;
|
break;
|
||||||
case PortModelAlignment.RIGHT:
|
case PortModelAlignment.RIGHT:
|
||||||
degree = -90;
|
degree = -90;
|
||||||
tx = -offset;
|
tx = -POINTER_SIZE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return [degree, tx, ty];
|
return [degree, tx, ty];
|
||||||
}
|
}
|
||||||
|
|
||||||
addCustomWidgetPoint(type, endpoint, point) {
|
addCustomWidgetPoint(type, endpoint, point) {
|
||||||
let offset = 30;
|
const [rotation, tx, ty] = this.endPointTranslation(endpoint.options.alignment);
|
||||||
const [rotation, tx, ty] = this.endPointTranslation(endpoint.options.alignment, offset);
|
|
||||||
if(!point) {
|
if(!point) {
|
||||||
point = this.props.link.point(
|
point = this.props.link.point(
|
||||||
endpoint.getX()-tx, endpoint.getY()-ty, {'one': 1, 'many': 2}[type]
|
endpoint.getX()-tx, endpoint.getY()-ty, {'one': 1, 'many': 2}[type]
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
//////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { DefaultNodeModel, DiagramEngine, PortWidget } from '@projectstorm/react-diagrams';
|
import { DefaultNodeModel, DiagramEngine, PortModelAlignment, PortWidget } from '@projectstorm/react-diagrams';
|
||||||
import { AbstractReactFactory } from '@projectstorm/react-canvas-core';
|
import { AbstractReactFactory } from '@projectstorm/react-canvas-core';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import SchemaIcon from 'top/browser/server_groups/servers/databases/schemas/static/img/schema.svg';
|
import SchemaIcon from 'top/browser/server_groups/servers/databases/schemas/static/img/schema.svg';
|
||||||
@@ -29,6 +29,7 @@ import { Box } from '@material-ui/core';
|
|||||||
|
|
||||||
|
|
||||||
const TYPE = 'table';
|
const TYPE = 'table';
|
||||||
|
const TABLE_WIDTH = 175;
|
||||||
|
|
||||||
export class TableNodeModel extends DefaultNodeModel {
|
export class TableNodeModel extends DefaultNodeModel {
|
||||||
constructor({otherInfo, ...options}) {
|
constructor({otherInfo, ...options}) {
|
||||||
@@ -36,6 +37,7 @@ export class TableNodeModel extends DefaultNodeModel {
|
|||||||
...options,
|
...options,
|
||||||
type: TYPE,
|
type: TYPE,
|
||||||
});
|
});
|
||||||
|
this.width = TABLE_WIDTH;
|
||||||
|
|
||||||
this._note = otherInfo.note || '';
|
this._note = otherInfo.note || '';
|
||||||
this._metadata = {
|
this._metadata = {
|
||||||
@@ -72,8 +74,15 @@ export class TableNodeModel extends DefaultNodeModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getPortName(attnum) {
|
getPortName(attnum, alignment) {
|
||||||
return `coll-port-${attnum}`;
|
if(alignment) {
|
||||||
|
return `coll-port-${attnum}-${alignment}`;
|
||||||
|
}
|
||||||
|
return `coll-port-${attnum}-right`;
|
||||||
|
}
|
||||||
|
|
||||||
|
getPortAttnum(portName) {
|
||||||
|
return portName.split('-')[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
setNote(note) {
|
setNote(note) {
|
||||||
@@ -95,6 +104,18 @@ export class TableNodeModel extends DefaultNodeModel {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getLinks() {
|
||||||
|
let links = {};
|
||||||
|
this.getPorts();
|
||||||
|
Object.values(this.getPorts()).forEach((port)=>{
|
||||||
|
links = {
|
||||||
|
...links,
|
||||||
|
...port.getLinks(),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return links;
|
||||||
|
}
|
||||||
|
|
||||||
addColumn(col) {
|
addColumn(col) {
|
||||||
this._data.columns.push(col);
|
this._data.columns.push(col);
|
||||||
}
|
}
|
||||||
@@ -166,7 +187,7 @@ const styles = (theme)=>({
|
|||||||
...theme.mixins.panelBorder.all,
|
...theme.mixins.panelBorder.all,
|
||||||
borderRadius: theme.shape.borderRadius,
|
borderRadius: theme.shape.borderRadius,
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
width: '175px',
|
width: `${TABLE_WIDTH}px`,
|
||||||
fontSize: '0.8em',
|
fontSize: '0.8em',
|
||||||
'& div:last-child': {
|
'& div:last-child': {
|
||||||
borderBottomLeftRadius: 'inherit',
|
borderBottomLeftRadius: 'inherit',
|
||||||
@@ -227,7 +248,9 @@ class TableNodeWidgetRaw extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
generateColumn(col, localFkCols, localUkCols) {
|
generateColumn(col, localFkCols, localUkCols) {
|
||||||
let port = this.props.node.getPort(this.props.node.getPortName(col.attnum));
|
let leftPort = this.props.node.getPort(this.props.node.getPortName(col.attnum, PortModelAlignment.LEFT));
|
||||||
|
let rightPort = this.props.node.getPort(this.props.node.getPortName(col.attnum, PortModelAlignment.RIGHT));
|
||||||
|
|
||||||
let icon = ColumnIcon;
|
let icon = ColumnIcon;
|
||||||
/* Less priority */
|
/* Less priority */
|
||||||
if(localUkCols.indexOf(col.name) > -1) {
|
if(localUkCols.indexOf(col.name) > -1) {
|
||||||
@@ -247,6 +270,9 @@ class TableNodeWidgetRaw extends React.Component {
|
|||||||
const {classes} = this.props;
|
const {classes} = this.props;
|
||||||
return (
|
return (
|
||||||
<div className={classes.tableSection} key={col.attnum} data-test="column-row">
|
<div className={classes.tableSection} key={col.attnum} data-test="column-row">
|
||||||
|
<Box marginRight="auto" padding="0" minHeight="0" display="flex" alignItems="center">
|
||||||
|
{this.generatePort(leftPort)}
|
||||||
|
</Box>
|
||||||
<Box display="flex" width="100%" style={{wordBreak: 'break-all'}}>
|
<Box display="flex" width="100%" style={{wordBreak: 'break-all'}}>
|
||||||
<RowIcon icon={icon} />
|
<RowIcon icon={icon} />
|
||||||
<Box margin="auto 0">
|
<Box margin="auto 0">
|
||||||
@@ -256,13 +282,13 @@ class TableNodeWidgetRaw extends React.Component {
|
|||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
<Box marginLeft="auto" padding="0" minHeight="0" display="flex" alignItems="center">
|
<Box marginLeft="auto" padding="0" minHeight="0" display="flex" alignItems="center">
|
||||||
{this.generatePort(port)}
|
{this.generatePort(rightPort)}
|
||||||
</Box>
|
</Box>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
generatePort = port => {
|
generatePort = (port) => {
|
||||||
if(port) {
|
if(port) {
|
||||||
return (
|
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} />
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
//
|
//
|
||||||
//////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
import { PortModel } from '@projectstorm/react-diagrams-core';
|
import { PortModel, PortModelAlignment } from '@projectstorm/react-diagrams-core';
|
||||||
import {OneToManyLinkModel} from '../links/OneToManyLink';
|
import {OneToManyLinkModel} from '../links/OneToManyLink';
|
||||||
import { AbstractModelFactory } from '@projectstorm/react-canvas-core';
|
import { AbstractModelFactory } from '@projectstorm/react-canvas-core';
|
||||||
|
|
||||||
@@ -16,7 +16,6 @@ const TYPE = 'onetomany';
|
|||||||
export default class OneToManyPortModel extends PortModel {
|
export default class OneToManyPortModel extends PortModel {
|
||||||
constructor({options}) {
|
constructor({options}) {
|
||||||
super({
|
super({
|
||||||
subtype: 'notset',
|
|
||||||
...options,
|
...options,
|
||||||
type: TYPE,
|
type: TYPE,
|
||||||
});
|
});
|
||||||
@@ -32,21 +31,24 @@ export default class OneToManyPortModel extends PortModel {
|
|||||||
return new OneToManyLinkModel({});
|
return new OneToManyLinkModel({});
|
||||||
}
|
}
|
||||||
|
|
||||||
getSubtype() {
|
|
||||||
return this.options.subtype;
|
|
||||||
}
|
|
||||||
|
|
||||||
deserialize(event) {
|
deserialize(event) {
|
||||||
|
/* Make it backward compatible */
|
||||||
|
const alignment = event.data?.name?.split('-').slice(-1)[0];
|
||||||
|
if(event.data?.name && ![PortModelAlignment.LEFT, PortModelAlignment.RIGHT].includes(alignment)) {
|
||||||
|
event.data.name += '-' + PortModelAlignment.RIGHT;
|
||||||
|
}
|
||||||
super.deserialize(event);
|
super.deserialize(event);
|
||||||
this.options.subtype = event.data.subtype || 'notset';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
serialize() {
|
serialize() {
|
||||||
return {
|
return {
|
||||||
...super.serialize(),
|
...super.serialize(),
|
||||||
subtype: this.options.subtype,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getAlignment() {
|
||||||
|
return this.options.alignment;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class OneToManyPortFactory extends AbstractModelFactory {
|
export class OneToManyPortFactory extends AbstractModelFactory {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import ERDCore from 'pgadmin.tools.erd/erd_tool/ERDCore';
|
|||||||
import * as createEngineLib from '@projectstorm/react-diagrams';
|
import * as createEngineLib from '@projectstorm/react-diagrams';
|
||||||
import TEST_TABLES_DATA from './test_tables';
|
import TEST_TABLES_DATA from './test_tables';
|
||||||
import { FakeLink, FakeNode } from './fake_item';
|
import { FakeLink, FakeNode } from './fake_item';
|
||||||
|
import { PortModelAlignment } from '@projectstorm/react-diagrams';
|
||||||
|
|
||||||
describe('ERDCore', ()=>{
|
describe('ERDCore', ()=>{
|
||||||
let eleFactory = jasmine.createSpyObj('nodeFactories', {
|
let eleFactory = jasmine.createSpyObj('nodeFactories', {
|
||||||
@@ -120,15 +121,16 @@ describe('ERDCore', ()=>{
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('getNewPort', ()=>{
|
it('getNewPort', ()=>{
|
||||||
let data = {name: 'link1'};
|
erdEngine.getPortFactories().getFactory().generateModel.calls.reset();
|
||||||
let options = {opt1: 'val1'};
|
erdCoreObj.getNewPort('port1', PortModelAlignment.LEFT);
|
||||||
erdCoreObj.getNewPort('porttype', data, options);
|
expect(erdEngine.getPortFactories().getFactory).toHaveBeenCalledWith('onetomany');
|
||||||
|
|
||||||
expect(erdEngine.getPortFactories().getFactory).toHaveBeenCalledWith('porttype');
|
|
||||||
expect(erdEngine.getPortFactories().getFactory().generateModel).toHaveBeenCalledWith({
|
expect(erdEngine.getPortFactories().getFactory().generateModel).toHaveBeenCalledWith({
|
||||||
initialConfig: {
|
initialConfig: {
|
||||||
data:data,
|
data: null,
|
||||||
options:options,
|
options: {
|
||||||
|
name: 'port1',
|
||||||
|
alignment: PortModelAlignment.LEFT
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -156,8 +158,7 @@ describe('ERDCore', ()=>{
|
|||||||
it('addLink', ()=>{
|
it('addLink', ()=>{
|
||||||
let node1 = new FakeNode({'name': 'table1'}, 'id1');
|
let node1 = new FakeNode({'name': 'table1'}, 'id1');
|
||||||
let node2 = new FakeNode({'name': 'table2'}, 'id2');
|
let node2 = new FakeNode({'name': 'table2'}, 'id2');
|
||||||
spyOn(node1, 'addPort').and.callThrough();
|
spyOn(erdCoreObj, 'getOptimumPorts').and.returnValue([{name: 'port-1'}, {name: 'port-3'}]);
|
||||||
spyOn(node2, 'addPort').and.callThrough();
|
|
||||||
let nodesDict = {
|
let nodesDict = {
|
||||||
'id1': node1,
|
'id1': node1,
|
||||||
'id2': node2,
|
'id2': node2,
|
||||||
@@ -169,11 +170,6 @@ describe('ERDCore', ()=>{
|
|||||||
spyOn(erdCoreObj, 'getNewLink').and.callFake(function() {
|
spyOn(erdCoreObj, 'getNewLink').and.callFake(function() {
|
||||||
return link;
|
return link;
|
||||||
});
|
});
|
||||||
spyOn(erdCoreObj, 'getNewPort').and.callFake(function(type, initData, options) {
|
|
||||||
return {
|
|
||||||
name: options.name,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
erdCoreObj.addLink({
|
erdCoreObj.addLink({
|
||||||
'referenced_column_attnum': 1,
|
'referenced_column_attnum': 1,
|
||||||
@@ -182,8 +178,6 @@ describe('ERDCore', ()=>{
|
|||||||
'local_table_uid': 'id2',
|
'local_table_uid': 'id2',
|
||||||
}, 'onetomany');
|
}, 'onetomany');
|
||||||
|
|
||||||
expect(nodesDict['id1'].addPort).toHaveBeenCalledWith({name: 'port-1'});
|
|
||||||
expect(nodesDict['id2'].addPort).toHaveBeenCalledWith({name: 'port-3'});
|
|
||||||
expect(link.setSourcePort).toHaveBeenCalledWith({name: 'port-1'});
|
expect(link.setSourcePort).toHaveBeenCalledWith({name: 'port-1'});
|
||||||
expect(link.setTargetPort).toHaveBeenCalledWith({name: 'port-3'});
|
expect(link.setTargetPort).toHaveBeenCalledWith({name: 'port-3'});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ describe('ERD TableNodeModel', ()=>{
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('getPortName', ()=>{
|
it('getPortName', ()=>{
|
||||||
expect(modelObj.getPortName(2)).toBe('coll-port-2');
|
expect(modelObj.getPortName(2)).toBe('coll-port-2-right');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('setNote', ()=>{
|
it('setNote', ()=>{
|
||||||
@@ -66,7 +66,6 @@ describe('ERD TableNodeModel', ()=>{
|
|||||||
describe('setData', ()=>{
|
describe('setData', ()=>{
|
||||||
let existPort = jasmine.createSpyObj('port', {
|
let existPort = jasmine.createSpyObj('port', {
|
||||||
'removeAllLinks': jasmine.createSpy('removeAllLinks'),
|
'removeAllLinks': jasmine.createSpy('removeAllLinks'),
|
||||||
'getSubtype': 'notset',
|
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(()=>{
|
beforeEach(()=>{
|
||||||
@@ -87,7 +86,6 @@ describe('ERD TableNodeModel', ()=>{
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('add columns', ()=>{
|
it('add columns', ()=>{
|
||||||
spyOn(existPort, 'getSubtype').and.returnValue('many');
|
|
||||||
existPort.removeAllLinks.calls.reset();
|
existPort.removeAllLinks.calls.reset();
|
||||||
modelObj.setData({
|
modelObj.setData({
|
||||||
name: 'noname',
|
name: 'noname',
|
||||||
@@ -113,7 +111,6 @@ describe('ERD TableNodeModel', ()=>{
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('update columns', ()=>{
|
it('update columns', ()=>{
|
||||||
spyOn(existPort, 'getSubtype').and.returnValue('many');
|
|
||||||
existPort.removeAllLinks.calls.reset();
|
existPort.removeAllLinks.calls.reset();
|
||||||
modelObj.setData({
|
modelObj.setData({
|
||||||
name: 'noname',
|
name: 'noname',
|
||||||
|
|||||||
Reference in New Issue
Block a user