mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
Fixed an issue in ERD tool where the downloaded images have a few links cut. #4995
This commit is contained in:
parent
9666bd6c8d
commit
5d2ce142dd
@ -33,6 +33,7 @@ Housekeeping
|
|||||||
Bug fixes
|
Bug fixes
|
||||||
*********
|
*********
|
||||||
|
|
||||||
|
| `Issue #4995 <https://github.com/pgadmin-org/pgadmin4/issues/4995>`_ - Fixed an issue in ERD tool where the downloaded images have a few links cut.
|
||||||
| `Issue #6482 <https://github.com/pgadmin-org/pgadmin4/issues/6482>`_ - Fixed an issue where the wrong message "Current database has been moved or renamed" is displayed when debugging any function.
|
| `Issue #6482 <https://github.com/pgadmin-org/pgadmin4/issues/6482>`_ - Fixed an issue where the wrong message "Current database has been moved or renamed" is displayed when debugging any function.
|
||||||
| `Issue #6674 <https://github.com/pgadmin-org/pgadmin4/issues/6674>`_ - Fix an issue where foreign table column name becomes "none" if the user changes any column data type.
|
| `Issue #6674 <https://github.com/pgadmin-org/pgadmin4/issues/6674>`_ - Fix an issue where foreign table column name becomes "none" if the user changes any column data type.
|
||||||
| `Issue #6718 <https://github.com/pgadmin-org/pgadmin4/issues/6718>`_ - Pin the cryptography version to fix PyO3 modules initialisation error.
|
| `Issue #6718 <https://github.com/pgadmin-org/pgadmin4/issues/6718>`_ - Pin the cryptography version to fix PyO3 modules initialisation error.
|
||||||
|
@ -116,7 +116,7 @@
|
|||||||
"dagre": "^0.8.4",
|
"dagre": "^0.8.4",
|
||||||
"date-fns": "^2.24.0",
|
"date-fns": "^2.24.0",
|
||||||
"diff-arrays-of-objects": "^1.1.8",
|
"diff-arrays-of-objects": "^1.1.8",
|
||||||
"html2canvas": "^1.0.0-rc.7",
|
"html-to-image": "^1.11.11",
|
||||||
"immutability-helper": "^3.0.0",
|
"immutability-helper": "^3.0.0",
|
||||||
"insert-if": "^1.1.0",
|
"insert-if": "^1.1.0",
|
||||||
"ip-address": "^7.1.0",
|
"ip-address": "^7.1.0",
|
||||||
|
@ -22,6 +22,7 @@ import ForeignKeySchema from '../../../../../browser/server_groups/servers/datab
|
|||||||
import diffArray from 'diff-arrays-of-objects';
|
import diffArray from 'diff-arrays-of-objects';
|
||||||
import TableSchema from '../../../../../browser/server_groups/servers/databases/schemas/tables/static/js/table.ui';
|
import TableSchema from '../../../../../browser/server_groups/servers/databases/schemas/tables/static/js/table.ui';
|
||||||
import ColumnSchema from '../../../../../browser/server_groups/servers/databases/schemas/tables/columns/static/js/column.ui';
|
import ColumnSchema from '../../../../../browser/server_groups/servers/databases/schemas/tables/columns/static/js/column.ui';
|
||||||
|
import { Polygon } from '@projectstorm/geometry';
|
||||||
|
|
||||||
export default class ERDCore {
|
export default class ERDCore {
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -175,6 +176,11 @@ export default class ERDCore {
|
|||||||
|
|
||||||
getModel() {return this.getEngine().getModel();}
|
getModel() {return this.getEngine().getModel();}
|
||||||
|
|
||||||
|
getBoundingLinksRect() {
|
||||||
|
return Polygon.boundingBoxFromPolygons(
|
||||||
|
this.getEngine().getModel().getLinks().map((l)=>l.getBoundingBox()));
|
||||||
|
}
|
||||||
|
|
||||||
getNewNode(initData, dataUrl=null) {
|
getNewNode(initData, dataUrl=null) {
|
||||||
return this.getEngine().getNodeFactories().getFactory('table').generateModel({
|
return this.getEngine().getNodeFactories().getFactory('table').generateModel({
|
||||||
initialConfig: {
|
initialConfig: {
|
||||||
|
@ -11,7 +11,7 @@ import * as React from 'react';
|
|||||||
import { CanvasWidget, Action, InputType } from '@projectstorm/react-canvas-core';
|
import { CanvasWidget, Action, InputType } from '@projectstorm/react-canvas-core';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import html2canvas from 'html2canvas';
|
import {toPng} from 'html-to-image';
|
||||||
|
|
||||||
import ERDCore from '../ERDCore';
|
import ERDCore from '../ERDCore';
|
||||||
import ConnectionBar, { STATUS as CONNECT_STATUS } from './ConnectionBar';
|
import ConnectionBar, { STATUS as CONNECT_STATUS } from './ConnectionBar';
|
||||||
@ -76,7 +76,7 @@ const styles = ((theme)=>({
|
|||||||
diagramContainer: {
|
diagramContainer: {
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
height: '100%',
|
flexGrow: 1,
|
||||||
minHeight: 0,
|
minHeight: 0,
|
||||||
},
|
},
|
||||||
diagramCanvas: {
|
diagramCanvas: {
|
||||||
@ -722,66 +722,49 @@ class ERDTool extends React.Component {
|
|||||||
* the canvas back to original state.
|
* the canvas back to original state.
|
||||||
* Code referred from - zoomToFitNodes function.
|
* Code referred from - zoomToFitNodes function.
|
||||||
*/
|
*/
|
||||||
let nodesRect = this.diagram.getEngine().getBoundingNodesRect(this.diagram.getModel().getNodes(), 10);
|
this.diagramContainerRef.current?.classList.add(this.props.classes.html2canvasReset);
|
||||||
|
const margin = 10;
|
||||||
|
let nodesRect = this.diagram.getEngine().getBoundingNodesRect(this.diagram.getModel().getNodes());
|
||||||
|
let linksRect = this.diagram.getBoundingLinksRect();
|
||||||
|
|
||||||
|
// Check what is to the most top left - links or nodes?
|
||||||
|
let topLeftXY = {
|
||||||
|
x: nodesRect.getTopLeft().x,
|
||||||
|
y: nodesRect.getTopLeft().y
|
||||||
|
};
|
||||||
|
if(topLeftXY.x > linksRect.getTopLeft().x) {
|
||||||
|
topLeftXY.x = linksRect.getTopLeft().x;
|
||||||
|
}
|
||||||
|
if(topLeftXY.y > linksRect.getTopLeft().y) {
|
||||||
|
topLeftXY.y = linksRect.getTopLeft().y;
|
||||||
|
}
|
||||||
|
topLeftXY.x -= margin;
|
||||||
|
topLeftXY.y -= margin;
|
||||||
|
|
||||||
let canvasRect = this.canvasEle.getBoundingClientRect();
|
let canvasRect = this.canvasEle.getBoundingClientRect();
|
||||||
let canvasTopLeftPoint = {
|
let canvasTopLeftOnScreen = {
|
||||||
x: canvasRect.left,
|
x: canvasRect.left,
|
||||||
y: canvasRect.top
|
y: canvasRect.top
|
||||||
};
|
};
|
||||||
let nodeLayerTopLeftPoint = {
|
let nodeLayerTopLeftPoint = {
|
||||||
x: canvasTopLeftPoint.x + this.diagram.getModel().getOffsetX(),
|
x: canvasTopLeftOnScreen.x + this.diagram.getModel().getOffsetX(),
|
||||||
y: canvasTopLeftPoint.y + this.diagram.getModel().getOffsetY()
|
y: canvasTopLeftOnScreen.y + this.diagram.getModel().getOffsetY()
|
||||||
};
|
};
|
||||||
let nodesRectTopLeftPoint = {
|
let nodesRectTopLeftPoint = {
|
||||||
x: nodeLayerTopLeftPoint.x + nodesRect.getTopLeft().x,
|
x: nodeLayerTopLeftPoint.x + topLeftXY.x,
|
||||||
y: nodeLayerTopLeftPoint.y + nodesRect.getTopLeft().y
|
y: nodeLayerTopLeftPoint.y + topLeftXY.y
|
||||||
};
|
};
|
||||||
|
|
||||||
let prevTransform = this.canvasEle.querySelector('div').style.transform;
|
let prevTransform = this.canvasEle.querySelector('div').style.transform;
|
||||||
this.canvasEle.childNodes.forEach((ele)=>{
|
this.canvasEle.childNodes.forEach((ele)=>{
|
||||||
ele.style.transform = `translate(${nodeLayerTopLeftPoint.x - nodesRectTopLeftPoint.x}px, ${nodeLayerTopLeftPoint.y - nodesRectTopLeftPoint.y}px) scale(1.0)`;
|
ele.style.transform = `translate(${nodeLayerTopLeftPoint.x - nodesRectTopLeftPoint.x}px, ${nodeLayerTopLeftPoint.y - nodesRectTopLeftPoint.y}px) scale(1.0)`;
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Change the styles for suiting html2canvas */
|
// Capture the links beyond the nodes as well.
|
||||||
this.canvasEle.classList.add(this.props.classes.html2canvasReset);
|
const linkOutsideWidth = linksRect.getBottomRight().x - nodesRect.getBottomRight().x;
|
||||||
this.canvasEle.style.width = this.canvasEle.scrollWidth + 'px';
|
const linkOutsideHeight = linksRect.getBottomRight().y - nodesRect.getBottomRight().y;
|
||||||
this.canvasEle.style.height = this.canvasEle.scrollHeight + 'px';
|
this.canvasEle.style.width = this.canvasEle.scrollWidth + (linkOutsideWidth > 0 ? linkOutsideWidth : 0) + margin + 'px';
|
||||||
|
this.canvasEle.style.height = this.canvasEle.scrollHeight + (linkOutsideHeight > 0 ? linkOutsideHeight : 0) + margin + 'px';
|
||||||
/* html2canvas ignores CSS styles, set the CSS styles to inline */
|
|
||||||
const setSvgInlineStyles = (targetElem) => {
|
|
||||||
const transformProperties = [
|
|
||||||
'fill',
|
|
||||||
'color',
|
|
||||||
'font-size',
|
|
||||||
'stroke',
|
|
||||||
'font',
|
|
||||||
'display',
|
|
||||||
];
|
|
||||||
let svgElems = Array.from(targetElem.getElementsByTagName('svg'));
|
|
||||||
for (let svgEle of svgElems) {
|
|
||||||
svgEle.setAttribute('width', svgEle.clientWidth);
|
|
||||||
svgEle.setAttribute('height', svgEle.clientHeight);
|
|
||||||
/* Wrap the SVG in a div tag so that transforms are consistent with html */
|
|
||||||
let wrap = document.createElement('div');
|
|
||||||
wrap.setAttribute('style', svgEle.getAttribute('style'));
|
|
||||||
svgEle.setAttribute('style', null);
|
|
||||||
svgEle.style.display = 'block';
|
|
||||||
svgEle.parentNode.insertBefore(wrap, svgEle);
|
|
||||||
wrap.appendChild(svgEle);
|
|
||||||
recurseElementChildren(svgEle);
|
|
||||||
}
|
|
||||||
function recurseElementChildren(node) {
|
|
||||||
if (!node.style)
|
|
||||||
return;
|
|
||||||
|
|
||||||
let styles = getComputedStyle(node);
|
|
||||||
for (let transformProperty of transformProperties) {
|
|
||||||
node.style[transformProperty] = styles[transformProperty];
|
|
||||||
}
|
|
||||||
for (let child of Array.from(node.childNodes)) {
|
|
||||||
recurseElementChildren(child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
setTimeout(()=>{
|
setTimeout(()=>{
|
||||||
let width = this.canvasEle.scrollWidth + 10;
|
let width = this.canvasEle.scrollWidth + 10;
|
||||||
@ -796,46 +779,34 @@ class ERDTool extends React.Component {
|
|||||||
height = 32766;
|
height = 32766;
|
||||||
isCut = true;
|
isCut = true;
|
||||||
}
|
}
|
||||||
html2canvas(this.canvasEle, {
|
toPng(this.canvasEle)
|
||||||
width: width,
|
.then((dataUrl)=>{
|
||||||
height: height,
|
let link = document.createElement('a');
|
||||||
scrollX: 0,
|
link.setAttribute('href', dataUrl);
|
||||||
scrollY: 0,
|
link.setAttribute('download', this.getCurrentProjectName() + '.png');
|
||||||
scale: 1,
|
link.click();
|
||||||
useCORS: true,
|
link.remove();
|
||||||
allowTaint: true,
|
}).catch((err)=>{
|
||||||
backgroundColor: window.getComputedStyle(this.canvasEle).backgroundColor,
|
console.error(err);
|
||||||
onclone: (clonedEle)=>{
|
let msg = gettext('Unknown error. Check console logs');
|
||||||
setSvgInlineStyles(clonedEle.body.querySelector('div[data-test="diagram-container"]'));
|
if(err.name) {
|
||||||
return clonedEle;
|
msg = `${err.name}: ${err.message}`;
|
||||||
},
|
}
|
||||||
}).then((canvas)=>{
|
Notify.alert(gettext('Error'), msg);
|
||||||
let link = document.createElement('a');
|
}).then(()=>{
|
||||||
link.setAttribute('href', canvas.toDataURL('image/png'));
|
/* Revert back to the original CSS styles */
|
||||||
link.setAttribute('download', this.getCurrentProjectName() + '.png');
|
this.diagramContainerRef.current.classList.remove(this.props.classes.html2canvasReset);
|
||||||
link.click();
|
this.canvasEle.style.width = '';
|
||||||
link.remove();
|
this.canvasEle.style.height = '';
|
||||||
}).catch((err)=>{
|
this.canvasEle.childNodes.forEach((ele)=>{
|
||||||
console.error(err);
|
ele.style.transform = prevTransform;
|
||||||
let msg = gettext('Unknown error. Check console logs');
|
});
|
||||||
if(err.name) {
|
this.setLoading(null);
|
||||||
msg = `${err.name}: ${err.message}`;
|
if(isCut) {
|
||||||
}
|
Notify.alert(gettext('Maximum image size limit'),
|
||||||
Notify.alert(gettext('Error'), msg);
|
gettext('The downloaded image has exceeded the maximum size of 32767 x 32767 pixels, and has been cropped to that size.'));
|
||||||
}).then(()=>{
|
}
|
||||||
/* Revert back to the original CSS styles */
|
|
||||||
this.canvasEle.classList.remove(this.props.classes.html2canvasReset);
|
|
||||||
this.canvasEle.style.width = '';
|
|
||||||
this.canvasEle.style.height = '';
|
|
||||||
this.canvasEle.childNodes.forEach((ele)=>{
|
|
||||||
ele.style.transform = prevTransform;
|
|
||||||
});
|
});
|
||||||
this.setLoading(null);
|
|
||||||
if(isCut) {
|
|
||||||
Notify.alert(gettext('Maximum image size limit'),
|
|
||||||
gettext('The downloaded image has exceeded the maximum size of 32767 x 32767 pixels, and has been cropped to that size.'));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -959,7 +930,7 @@ class ERDTool extends React.Component {
|
|||||||
this.erdDialogs.modal = this.context;
|
this.erdDialogs.modal = this.context;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box ref={this.containerRef} height="100%">
|
<Box ref={this.containerRef} height="100%" display="flex" flexDirection="column">
|
||||||
<ConnectionBar status={this.state.conn_status} bgcolor={this.props.params.bgcolor}
|
<ConnectionBar status={this.state.conn_status} bgcolor={this.props.params.bgcolor}
|
||||||
fgcolor={this.props.params.fgcolor} title={_.unescape(this.props.params.title)}/>
|
fgcolor={this.props.params.fgcolor} title={_.unescape(this.props.params.title)}/>
|
||||||
<MainToolBar preferences={this.state.preferences} eventBus={this.eventBus}
|
<MainToolBar preferences={this.state.preferences} eventBus={this.eventBus}
|
||||||
|
@ -3984,13 +3984,6 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"base64-arraybuffer@npm:^1.0.2":
|
|
||||||
version: 1.0.2
|
|
||||||
resolution: "base64-arraybuffer@npm:1.0.2"
|
|
||||||
checksum: 15e6400d2d028bf18be4ed97702b11418f8f8779fb8c743251c863b726638d52f69571d4cc1843224da7838abef0949c670bde46936663c45ad078e89fee5c62
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"base64-js@npm:^1.0.2, base64-js@npm:^1.3.1":
|
"base64-js@npm:^1.0.2, base64-js@npm:^1.3.1":
|
||||||
version: 1.5.1
|
version: 1.5.1
|
||||||
resolution: "base64-js@npm:1.5.1"
|
resolution: "base64-js@npm:1.5.1"
|
||||||
@ -5238,15 +5231,6 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"css-line-break@npm:^2.1.0":
|
|
||||||
version: 2.1.0
|
|
||||||
resolution: "css-line-break@npm:2.1.0"
|
|
||||||
dependencies:
|
|
||||||
utrie: ^1.0.2
|
|
||||||
checksum: 37b1fe632b03be7a287cd394cef8b5285666343443125c510df9cfb6a4734a2c71e154ec8f7bbff72d7c339e1e5872989b1c52d86162aed27d6cc114725bb4d0
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"css-loader@npm:^6.7.2":
|
"css-loader@npm:^6.7.2":
|
||||||
version: 6.8.1
|
version: 6.8.1
|
||||||
resolution: "css-loader@npm:6.8.1"
|
resolution: "css-loader@npm:6.8.1"
|
||||||
@ -7745,13 +7729,10 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"html2canvas@npm:^1.0.0-rc.7":
|
"html-to-image@npm:^1.11.11":
|
||||||
version: 1.4.1
|
version: 1.11.11
|
||||||
resolution: "html2canvas@npm:1.4.1"
|
resolution: "html-to-image@npm:1.11.11"
|
||||||
dependencies:
|
checksum: b453beca72a697bf06fae4945e5460d1d9b1751e8569a0d721dda9485df1dde093938cc9bd9172b8df5fc23133a53a4d619777b3d22f7211cd8a67e3197ab4e8
|
||||||
css-line-break: ^2.1.0
|
|
||||||
text-segmentation: ^1.0.3
|
|
||||||
checksum: c134324af57f3262eecf982e436a4843fded3c6cf61954440ffd682527e4dd350e0c2fafd217c0b6f9a455fe345d0c67b4505689796ab160d4ca7c91c3766739
|
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@ -13145,7 +13126,7 @@ __metadata:
|
|||||||
eslint-plugin-react-hooks: ^4.3.0
|
eslint-plugin-react-hooks: ^4.3.0
|
||||||
exports-loader: ^4.0.0
|
exports-loader: ^4.0.0
|
||||||
html-react-parser: ^4.2.0
|
html-react-parser: ^4.2.0
|
||||||
html2canvas: ^1.0.0-rc.7
|
html-to-image: ^1.11.11
|
||||||
image-minimizer-webpack-plugin: ^3.8.2
|
image-minimizer-webpack-plugin: ^3.8.2
|
||||||
imagemin: ^8.0.1
|
imagemin: ^8.0.1
|
||||||
imagemin-mozjpeg: ^10.0.0
|
imagemin-mozjpeg: ^10.0.0
|
||||||
@ -14463,15 +14444,6 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"text-segmentation@npm:^1.0.3":
|
|
||||||
version: 1.0.3
|
|
||||||
resolution: "text-segmentation@npm:1.0.3"
|
|
||||||
dependencies:
|
|
||||||
utrie: ^1.0.2
|
|
||||||
checksum: 2e24632d59567c55ab49ac324815e2f7a8043e63e26b109636322ac3e30692cee8679a448fd5d0f0598a345f407afd0e34ba612e22524cf576d382d84058c013
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"text-table@npm:^0.2.0":
|
"text-table@npm:^0.2.0":
|
||||||
version: 0.2.0
|
version: 0.2.0
|
||||||
resolution: "text-table@npm:0.2.0"
|
resolution: "text-table@npm:0.2.0"
|
||||||
@ -15056,15 +15028,6 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"utrie@npm:^1.0.2":
|
|
||||||
version: 1.0.2
|
|
||||||
resolution: "utrie@npm:1.0.2"
|
|
||||||
dependencies:
|
|
||||||
base64-arraybuffer: ^1.0.2
|
|
||||||
checksum: c96fbb7d4d8855a154327da0b18e39b7511cc70a7e4bcc3658e24f424bb884312d72b5ba777500b8858e34d365dc6b1a921dc5ca2f0d341182519c6b78e280a5
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"uuid@npm:^3.0.1":
|
"uuid@npm:^3.0.1":
|
||||||
version: 3.4.0
|
version: 3.4.0
|
||||||
resolution: "uuid@npm:3.4.0"
|
resolution: "uuid@npm:3.4.0"
|
||||||
|
Loading…
Reference in New Issue
Block a user