Skip to content

Commit 2a39e70

Browse files
committed
Added iframes, updated version number
1 parent d709a91 commit 2a39e70

File tree

9 files changed

+138
-34
lines changed

9 files changed

+138
-34
lines changed

package.json

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "neodash",
33
"description": "NeoDash - Neo4j Dashboard Builder",
4-
"version": "1.1",
4+
"version": "1.1.0",
55
"homepage": "./",
66
"neo4jDesktop": {
77
"apiVersion": "^1.2.0"
@@ -27,6 +27,7 @@
2727
"private": false,
2828
"dependencies": {
2929
"@apollo/react-hooks": "^3.1.2",
30+
"@react-leaflet/core": ">=1.0.0 <1.1.0 || ^1.1.1",
3031
"@testing-library/jest-dom": "^4.2.4",
3132
"@testing-library/react": "^9.5.0",
3233
"@testing-library/user-event": "^7.2.1",
@@ -37,16 +38,16 @@
3738
"graphql": "^14.5.8",
3839
"graphql-tag": "^2.10.1",
3940
"jquery": "^3.5.1",
41+
"leaflet": "latest",
4042
"materialize-css": "^1.0.0",
4143
"neo4j-driver": "latest",
42-
"leaflet": "latest",
4344
"react": "^16.13.1",
4445
"react-dom": "^16.13.1",
46+
"react-leaflet": ">=3.1.0 <3.2.0 || ^3.2.1",
47+
"react-leaflet-enhanced-marker": "^1.0.19",
4548
"react-markdown": "^5.0.3",
4649
"react-materialize": "^3.9.2",
4750
"react-scripts": "3.4.1",
48-
"react-leaflet": ">=3.1.0 <3.2.0 || ^3.2.1",
49-
"@react-leaflet/core": ">=1.0.0 <1.1.0 || ^1.1.1",
5051
"remark-gfm": "^1.0.0"
5152
},
5253
"scripts": {

public/style.css

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ code {
103103
margin-left: 33px;
104104
margin-top: -6px;
105105
-webkit-text-stroke-width: 1.5px;
106-
-webkit-text-stroke-color: #444;
106+
-webkit-text-stroke-color: #666;
107107
}
108108
.tabs .disabled {
109109
width: auto !important;
@@ -159,7 +159,9 @@ code {
159159
.btn-center-align :hover {
160160
opacity: 0.7;
161161
}
162-
162+
.section {
163+
padding-top: 0;
164+
}
163165
.card {
164166
padding-bottom: 55px;
165167
}

src/NeoDash.js

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,22 +113,25 @@ class NeoDash extends React.Component {
113113
*/
114114
componentDidMount() {
115115
this.createCardObjectsFromDashboardState()
116-
var select = document.getElementById('root');
117-
118116
// TODO - remove this hack to get rid of duplicate connection modals being shown
117+
this.removeDuplicateConnectionModal();
118+
}
119+
120+
121+
removeDuplicateConnectionModal() {
122+
var select = document.getElementById('root');
119123
if (select.childNodes.length == 9) {
120124
select.removeChild(select.childNodes.item(1));
121-
// select.removeChild(select.firstChild);
122125
}
123126
}
124127

125-
126128
/**
127129
* Will try to connect to Neo4j given the specified connection parameters.
128130
* On failure, will produce an error message and show it to the user.
129131
*/
130132
connect() {
131133
try {
134+
this.connected = false;
132135
var url = this.connection.url;
133136
if (!(url.startsWith("bolt://") || url.startsWith("bolt+routing://") || url.startsWith("neo4j://"))) {
134137
url = "neo4j://" + url;
@@ -168,6 +171,12 @@ class NeoDash extends React.Component {
168171
label: "CreateError",
169172
value: error['message']
170173
});
174+
} finally {
175+
176+
}
177+
if (!this.connected){
178+
this.createConnectionModal(this.connect, true);
179+
// TODO - this can produce duplicate connection modals
171180
}
172181
}
173182

@@ -617,6 +626,7 @@ class NeoDash extends React.Component {
617626
content = "Unable to connect to the specified Neo4j database. " +
618627
"The database might be unreachable, or it does not accept " +
619628
((encryption === "on") ? "encrypted" : "unencrypted") + " connections. " + content;
629+
this.state.page +=1;
620630

621631
}
622632
// Special case 3: we're dealing with someone clicking the 'Get in touch' button.

src/card/NeoCard.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import NeoLineChartFooter from "./footer/NeoLineChartFooter";
1818
import NeoPropertySelectReport from "./report/NeoPropertySelectReport";
1919
import NeoMapReport from "./report/NeoMapReport";
2020
import NeoMapFooter from "./footer/NeoMapFooter";
21+
import NeoIFrameReport from "./report/NeoIFrameReport";
2122

2223

2324
let emptyAction = <div key={0}/>;
@@ -268,6 +269,9 @@ export class NeoCard extends React.Component {
268269
if (this.state.type === 'text') {
269270
this.setCardTypeToMarkdown();
270271
}
272+
if (this.state.type === 'iframe') {
273+
this.setCardTypeToIFrame();
274+
}
271275
if (this.state.type === 'map') {
272276
this.setCardTypeToMap();
273277
}
@@ -416,6 +420,21 @@ export class NeoCard extends React.Component {
416420
this.state.action = emptyAction;
417421
}
418422

423+
/**
424+
* Update the card's report to a Markdown view.
425+
*/
426+
setCardTypeToIFrame() {
427+
this.state.content =
428+
<NeoIFrameReport
429+
connection={this.props.connection}
430+
query={'return true'}
431+
height={this.state.height}
432+
data={this.state.query}
433+
stateChanged={this.stateChanged}
434+
refresh={this.state.refresh}/>
435+
this.state.action = emptyAction;
436+
}
437+
419438
/**
420439
* Update the card's report to a property selection.
421440
*/

src/card/NeoCardSettings.js

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ class NeoCardSettings extends React.Component {
1919
'json': 'Raw JSON',
2020
'map': 'Map',
2121
'select': 'Selection',
22+
'iframe': 'iFrame',
2223
'text': 'Markdown',
2324
};
2425

@@ -51,7 +52,8 @@ class NeoCardSettings extends React.Component {
5152
*/
5253
setDefaultComponents() {
5354
this.settingsTextArea =
54-
<NeoTextArea placeholder={this.props.type == "text" ? "Enter Markdown here..." : this.props.placeholder}
55+
<NeoTextArea placeholder={this.getQueryBoxPlaceholder()}
56+
disclaimer={this.getDisclaimer()}
5557
defaultValue={this.props.query} name="Query"
5658
onChange={this.stateChanged}/>;
5759
this.cypherParamsInput = <NeoTextInput defaultValue={this.props.parameters} onChange={this.stateChanged}
@@ -76,6 +78,27 @@ class NeoCardSettings extends React.Component {
7678

7779
}
7880

81+
getQueryBoxPlaceholder() {
82+
if (this.props.type == "text") {
83+
return "Enter Markdown here..."
84+
}
85+
if(this.props.type == "iframe"){
86+
return "Enter URL here..."
87+
}
88+
return this.props.placeholder;
89+
}
90+
91+
getDisclaimer() {
92+
if (this.props.type == "text") {
93+
return "Enter your text in the query box above."
94+
}
95+
if(this.props.type == "iframe"){
96+
return "Enter a URL starting with 'http://' or 'https://'."
97+
}
98+
return this.props.placeholder;
99+
}
100+
101+
79102
setTypeAndSizeSelectionComponents(type) {
80103
this.cardTypeSelect = <NeoOptionSelect label="Type" defaultValue={type} onChange={this.stateChanged}
81104
options={this.vizOptions}/>;
@@ -187,7 +210,8 @@ class NeoCardSettings extends React.Component {
187210
*/
188211
updateQueryTextBox() {
189212
this.settingsTextArea =
190-
<NeoTextArea placeholder={this.props.type == "text" ? "Enter Markdown here..." : this.props.placeholder}
213+
<NeoTextArea placeholder={this.getQueryBoxPlaceholder()}
214+
disclaimer={this.getDisclaimer()}
191215
defaultValue={this.props.query} name="Query"
192216
onChange={this.stateChanged}/>;
193217
}

src/card/report/NeoGraphVisReport.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ class NeoGraphVisReport extends NeoReport {
147147
nodesMap["" + value['identity']['low']] = {
148148
id: value['identity']['low'],
149149
fill: 'seagreen',
150-
stroke: "#555",
150+
stroke: "#666",
151151
radius: 25,
152152
properties: value['properties'],
153153
labels: value['labels']
@@ -199,7 +199,7 @@ class NeoGraphVisReport extends NeoReport {
199199
nodesMap["" + value['start']['low']] = {
200200
id: value['start']['low'],
201201
fill: 'seagreen',
202-
stroke: "#555",
202+
stroke: "#666",
203203
radius: 25,
204204
properties: [],
205205
labels: []
@@ -209,7 +209,7 @@ class NeoGraphVisReport extends NeoReport {
209209
nodesMap["" + value['end']['low']] = {
210210
id: value['end']['low'],
211211
fill: 'seagreen',
212-
stroke: "#555",
212+
stroke: "#666",
213213
radius: 25,
214214
properties: [],
215215
labels: []

src/card/report/NeoIFrameReport.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import React from "react";
2+
import NeoReport from "./NeoReport";
3+
4+
class NeoIFrameReport extends NeoReport {
5+
constructor(props) {
6+
super(props);
7+
}
8+
9+
render() {
10+
let rendered = super.render();
11+
if (rendered) {
12+
return rendered;
13+
}
14+
if (this.props.data.startsWith("http://") || this.props.data.startsWith("https://")){
15+
let yShift = -10;
16+
let height = -140 + this.props.height * 100 - yShift;
17+
return <iframe style={{width: "100%", height: height}} src={this.props.data}/>;
18+
}else{
19+
return <p>Invalid iFrame URL. Make sure your url starts with <code>http://</code> or <code>https://</code>.</p>
20+
}
21+
22+
}
23+
}
24+
25+
export default (NeoIFrameReport);

src/card/report/NeoMapReport.js

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,29 +21,52 @@ class NeoTestReport extends NeoReport {
2121
this.state.height = -145 + this.props.height * 100;
2222
let colors = ["#588c7e", "#f2e394", "#f2ae72", "#d96459", "#5b9aa0", "#d6d4e0", "#b8a9c9", "#622569", "#ddd5af", "#d9ad7c", "#a2836e", "#674d3c", "grey"]
2323

24-
if (width !== this.props.clientWidth - 50 || height !== -145 + this.props.height * 100){
25-
const position = [51.4472055, 4.4601085]
26-
let position2 = [51.4972055, 4.4801085];
24+
if (width !== this.props.clientWidth - 50 || height !== -145 + this.props.height * 100) {
25+
let nodesAndPositions = [
26+
{
27+
pos: [51.4972055, 4.4801085],
28+
node: {
29+
id: 4
30+
}
31+
},
32+
{
33+
pos: [51.4472055, 4.4601085],
34+
node: {
35+
id: 6
36+
}
37+
}]
38+
;
39+
let xPositions = nodesAndPositions.map(i => i.pos[0]);
40+
let yPositions = nodesAndPositions.map(i => i.pos[1]);
41+
let centerX = xPositions.reduce((a, b) => a + b, 0) / nodesAndPositions.length;
42+
let centerY = yPositions.reduce((a, b) => a + b, 0) / nodesAndPositions.length;
43+
// let minX = Math.min.apply(null, xPositions);
44+
let maxX = Math.max.apply(null, xPositions);
45+
// let minY = Math.min.apply(null, yPositions);
46+
let maxY = Math.max.apply(null, yPositions);
47+
// Build map objects
48+
let markers = nodesAndPositions.map(i =>
49+
<Marker position={i.pos} icon={<div style={{color: colors[0]}}><Icon className="close">place</Icon></div>}>
50+
<Popup>{JSON.stringify(i.node)}</Popup>
51+
</Marker>)
52+
let lines = [<Polyline key={0} positions={[[51.4972055, 4.4801085], [51.4472055, 4.4601085]]} color={colors[0]}/>];
53+
54+
// Set visualization object
2755
this.state.visualization =
28-
<MapContainer key={0} style={{"width": this.state.width + "px", "height": this.state.height + "px"}} center={position} zoom={13}
56+
<MapContainer key={0} style={{"width": this.state.width + "px", "height": this.state.height + "px"}}
57+
center={
58+
[
59+
centerX,
60+
centerY
61+
]
62+
} zoom={13}
2963
scrollWheelZoom={false}>
3064
<TileLayer
3165
attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
3266
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
3367
/>
34-
<Marker position={position} icon={<div style={{color: colors[0]}}><Icon className="close">place</Icon></div>}>
35-
<Popup>
36-
A pretty CSS3 popup. <br/> Easily customizable. With a lot of text wooooooooooooooooh asdjadnas da sdas
37-
</Popup>
38-
</Marker>
39-
<Marker position={position2} icon={<div style={{color: colors[0]}}><Icon className="close">place</Icon></div>}>
40-
<Popup>
41-
A pretty CSS3 popup. <br/> Easily customizable. With a lot of text wooooooooooooooooh asdjadnas da sdas
42-
</Popup>
43-
</Marker>
44-
<Polyline key={0} positions={[
45-
position, position2,
46-
]} color={colors[0]} />
68+
{markers}
69+
{lines}
4770
</MapContainer>;
4871
this.forceUpdate();
4972
}

src/component/NeoTextArea.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import Textarea from "react-materialize/lib/Textarea";
66
* NeoTextAreas are used as Cypher-input boxes or to display errors.
77
*/
88
class NeoTextArea extends React.Component {
9-
disclaimer = 'Limit a query to 1000 result rows for best performance. Cypher parameter keys & values must be in quotes.';
9+
defaultDisclaimer = 'Limit a query to 1000 result rows for best performance. Cypher parameter keys & values must be in quotes.';
1010
defaultPlaceholder = "Enter Cypher here... \n";
1111

1212
/**
@@ -34,7 +34,7 @@ class NeoTextArea extends React.Component {
3434
m={12}
3535
s={12}
3636
placeholder={(this.props.placeholder) ? this.props.placeholder : this.defaultPlaceholder}
37-
xl={12}><p style={{fontSize: 12}}>{this.disclaimer}</p></Textarea>;
37+
xl={12}><p style={{fontSize: 12}}>{(this.props.disclaimer) ? this.props.disclaimer : this.defaultDisclaimer}</p></Textarea>;
3838
}
3939
}
4040

0 commit comments

Comments
 (0)