Skip to content

Commit c504094

Browse files
authoredMay 7, 2024··
Merge pull request #886 from neo4j-labs/develop
Release notes for release 2.4.7
2 parents 2fc0983 + ce7a21d commit c504094

File tree

20 files changed

+625
-376
lines changed

20 files changed

+625
-376
lines changed
 

‎.github/workflows/master-deployment.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ jobs:
7979
context: .
8080
file: ./Dockerfile
8181
push: true
82-
tags: ${{ secrets.DOCKER_HUB_LABS_USERNAME }}/neodash:latest,${{ secrets.DOCKER_HUB_LABS_USERNAME }}/neodash:2.4.6
82+
tags: ${{ secrets.DOCKER_HUB_LABS_USERNAME }}/neodash:latest,${{ secrets.DOCKER_HUB_LABS_USERNAME }}/neodash:2.4.7
8383
build-docker-legacy:
8484
needs: build-test
8585
runs-on: neodash-runners
@@ -103,7 +103,7 @@ jobs:
103103
context: .
104104
file: ./Dockerfile
105105
push: true
106-
tags: ${{ secrets.DOCKER_HUB_USERNAME }}/neodash:latest,${{ secrets.DOCKER_HUB_USERNAME }}/neodash:2.4.6
106+
tags: ${{ secrets.DOCKER_HUB_USERNAME }}/neodash:latest,${{ secrets.DOCKER_HUB_USERNAME }}/neodash:2.4.7
107107
deploy-gallery:
108108
runs-on: neodash-runners
109109
strategy:

‎Dockerfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,4 @@ USER nginx
4444
EXPOSE $NGINX_PORT
4545

4646
HEALTHCHECK cmd curl --fail "http://localhost:$NGINX_PORT" || exit 1
47-
LABEL version="2.4.6"
47+
LABEL version="2.4.7"

‎changelog.md

+12
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1+
## NeoDash 2.4.7
2+
This is a minor release containing a few critical fixes and general code quality improvements:
3+
4+
- Fix multiple parameter select ([881](https://github.com/neo4j-labs/neodash/pull/881)).
5+
- Fix parameter casting error when loading dashboards([874](https://github.com/neo4j-labs/neodash/pull/874)).
6+
- Fix the fraud demo in the [Example Gallery](https://neodash-gallery.graphapp.io/).
7+
8+
Thanks to all the contributors for this release:
9+
- [alfredorubin96](https://github.com/alfredorubin96),
10+
- [MariusC](https://github.com/mariusconjeaud),
11+
- [elizarp](https://github.com/elizarp).
12+
113
## NeoDash 2.4.6
214
This is a minor release containing a few critical fixes and some extra style customizations:
315

‎cypress/e2e/render/array.cy.js

+154
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
import { stringArrayCypherQuery, intArrayCypherQuery, pathArrayCypherQuery } from '../../fixtures/cypher_queries';
2+
import {
3+
enableReportActions,
4+
createReportOfType,
5+
closeSettings,
6+
toggleTableTranspose,
7+
openReportActionsMenu,
8+
selectReportOfType,
9+
openAdvancedSettings,
10+
updateDropdownAdvancedSetting,
11+
} from '../utils';
12+
13+
const WAITING_TIME = 20000;
14+
const CARD_SELECTOR = 'main .react-grid-item:eq(2)';
15+
// Ignore warnings that may appear when using the Cypress dev server
16+
Cypress.on('uncaught:exception', (err, runnable) => {
17+
console.log(err, runnable);
18+
return false;
19+
});
20+
21+
describe('Testing array rendering', () => {
22+
beforeEach('open neodash', () => {
23+
cy.viewport(1920, 1080);
24+
cy.visit('/', {
25+
onBeforeLoad(win) {
26+
win.localStorage.clear();
27+
},
28+
});
29+
30+
cy.get('#form-dialog-title', { WAITING_TIME: WAITING_TIME })
31+
.should('contain', 'NeoDash - Neo4j Dashboard Builder')
32+
.click();
33+
34+
cy.get('#form-dialog-title').then(($div) => {
35+
const text = $div.text();
36+
if (text == 'NeoDash - Neo4j Dashboard Builder') {
37+
cy.wait(500);
38+
// Create new dashboard
39+
cy.contains('New Dashboard').click();
40+
}
41+
});
42+
43+
cy.get('#form-dialog-title', { WAITING_TIME: WAITING_TIME }).should('contain', 'Connect to Neo4j');
44+
45+
cy.get('#url').clear().type('localhost');
46+
cy.get('#dbusername').clear().type('neo4j');
47+
cy.get('#dbpassword').type('test1234');
48+
cy.get('button').contains('Connect').click();
49+
cy.wait(100);
50+
});
51+
52+
it('creates a table that contains string arrays', () => {
53+
cy.checkInitialState();
54+
enableReportActions();
55+
createReportOfType('Table', stringArrayCypherQuery, true, true);
56+
57+
// Standard array, displays strings joined with comma and whitespace
58+
cy.get(`${CARD_SELECTOR} .MuiDataGrid-cell:eq(0)`).should('have.text', 'initial, list');
59+
cy.get(`${CARD_SELECTOR} .MuiDataGrid-cell:eq(1)`).should('have.text', 'other, list');
60+
61+
// Now, transpose the table
62+
toggleTableTranspose(CARD_SELECTOR, true);
63+
cy.get(`${CARD_SELECTOR} .MuiDataGrid-columnHeaderTitle:eq(1)`, { timeout: WAITING_TIME }).should(
64+
'have.text',
65+
'initial,list'
66+
);
67+
cy.get(`${CARD_SELECTOR} .MuiDataGrid-cell:eq(1)`).should('have.text', 'other, list');
68+
69+
// Transpose back
70+
// And add a report action
71+
toggleTableTranspose(CARD_SELECTOR, false);
72+
openReportActionsMenu(CARD_SELECTOR);
73+
cy.get('.ndl-modal').find('button[aria-label="add"]').click();
74+
cy.get('.ndl-modal').find('input:eq(2)').type('column');
75+
cy.get('.ndl-modal').find('input:eq(5)').type('test_param');
76+
cy.get('.ndl-modal').find('input:eq(6)').type('column');
77+
cy.get('.ndl-modal').find('button').contains('Save').click();
78+
closeSettings(CARD_SELECTOR);
79+
cy.get(`${CARD_SELECTOR} .MuiDataGrid-cell:eq(0)`)
80+
.find('button')
81+
.should('be.visible')
82+
.should('have.text', 'initial, list')
83+
.click();
84+
85+
// Previous step's click set a parameter from the array
86+
// Test that parameter rendering works
87+
cy.get(`${CARD_SELECTOR} .MuiCardHeader-root`).find('input').type('$neodash_test_param').blur();
88+
cy.get(`${CARD_SELECTOR} .MuiCardHeader-root`).find('input').should('have.value', 'initial, list');
89+
});
90+
91+
it('creates a table that contains int arrays', () => {
92+
cy.checkInitialState();
93+
createReportOfType('Table', intArrayCypherQuery, true, true);
94+
95+
// Standard array, displays strings joined with comma and whitespace
96+
cy.get(`${CARD_SELECTOR} .MuiDataGrid-cell:eq(0)`).should('have.text', '1, 2');
97+
cy.get(`${CARD_SELECTOR} .MuiDataGrid-cell:eq(1)`).should('have.text', '3, 4');
98+
99+
// Now, transpose the table
100+
toggleTableTranspose(CARD_SELECTOR, true);
101+
cy.get(`${CARD_SELECTOR} .MuiDataGrid-columnHeaderTitle:eq(1)`, { timeout: WAITING_TIME }).should(
102+
'have.text',
103+
'1,2'
104+
);
105+
cy.get(`${CARD_SELECTOR} .MuiDataGrid-cell:eq(1)`).should('have.text', '3, 4');
106+
});
107+
108+
it('creates a table that contains nodes and rels', () => {
109+
cy.checkInitialState();
110+
createReportOfType('Table', pathArrayCypherQuery, true, true);
111+
112+
// Standard array, displays a path with two nodes and a relationship
113+
cy.get(`${CARD_SELECTOR} .MuiDataGrid-cell:eq(0)`).should('have.text', 'PersonACTED_INMovie');
114+
cy.get(`${CARD_SELECTOR} .MuiDataGrid-cell:eq(0) button`).should('have.length', 2);
115+
cy.get(`${CARD_SELECTOR} .MuiDataGrid-cell:eq(0) button:eq(0)`).should('have.text', 'Person');
116+
cy.get(`${CARD_SELECTOR} .MuiDataGrid-cell:eq(0) button:eq(1)`).should('have.text', 'Movie');
117+
cy.get(`${CARD_SELECTOR} .MuiDataGrid-cell:eq(0) .MuiChip-root`).should('have.length', 1);
118+
cy.get(`${CARD_SELECTOR} .MuiDataGrid-cell:eq(0) .MuiChip-root`).should('have.text', 'ACTED_IN');
119+
});
120+
121+
it('creates a single value report which is an array', () => {
122+
cy.checkInitialState();
123+
createReportOfType('Single Value', stringArrayCypherQuery, true, true);
124+
cy.get(CARD_SELECTOR).should('have.text', 'initial, list');
125+
});
126+
127+
it('creates a multi parameter select', () => {
128+
cy.checkInitialState();
129+
selectReportOfType('Parameter Select');
130+
cy.get('main .react-grid-item:eq(2) label[for="Selection Type"]').siblings('div').click();
131+
// Set up the parameter select
132+
cy.contains('Node Property').click();
133+
cy.wait(100);
134+
cy.contains('Node Label').click();
135+
cy.contains('Node Label').siblings('div').find('input').type('Movie');
136+
cy.wait(1000);
137+
cy.get('.MuiAutocomplete-popper').contains('Movie').click();
138+
cy.contains('Property Name').click();
139+
cy.contains('Property Name').siblings('div').find('input').type('title');
140+
cy.wait(1000);
141+
cy.get('.MuiAutocomplete-popper').contains('title').click();
142+
// Enable multiple selection
143+
closeSettings(CARD_SELECTOR);
144+
updateDropdownAdvancedSetting(CARD_SELECTOR, 'Multiple Selection', 'on');
145+
// Finally, select a few values in the parameter select
146+
cy.get(CARD_SELECTOR).contains('Movie title').click();
147+
cy.get(CARD_SELECTOR).contains('Movie title').siblings('div').find('input').type('a');
148+
cy.get('.MuiAutocomplete-popper').contains('Apollo 13').click();
149+
cy.get(CARD_SELECTOR).contains('Movie title').siblings('div').find('input').type('t');
150+
cy.get('.MuiAutocomplete-popper').contains('The Matrix').click();
151+
cy.get(CARD_SELECTOR).contains('Apollo 13').should('be.visible');
152+
cy.get(CARD_SELECTOR).contains('The Matrix').should('be.visible');
153+
});
154+
});

‎cypress/e2e/start_page.cy.js

+1-43
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
gaugeChartCypherQuery,
1111
formCypherQuery,
1212
} from '../fixtures/cypher_queries';
13+
import { createReportOfType, selectReportOfType, enableAdvancedVisualizations, enableFormsExtension } from './utils';
1314

1415
const WAITING_TIME = 20000;
1516
// Ignore warnings that may appear when using the Cypress dev server
@@ -293,46 +294,3 @@ describe('NeoDash E2E Tests', () => {
293294
}
294295
});
295296
});
296-
297-
function enableAdvancedVisualizations() {
298-
cy.get('main button[aria-label="Extensions').should('be.visible').click();
299-
cy.get('#checkbox-advanced-charts').should('be.visible').click();
300-
cy.get('.ndl-dialog-close').scrollIntoView().should('be.visible').click();
301-
cy.wait(200);
302-
}
303-
304-
function enableFormsExtension() {
305-
cy.get('main button[aria-label="Extensions').should('be.visible').click();
306-
cy.get('#checkbox-forms').scrollIntoView();
307-
cy.get('#checkbox-forms').should('be.visible').click();
308-
cy.get('.ndl-dialog-close').scrollIntoView().should('be.visible').click();
309-
cy.wait(200);
310-
}
311-
312-
function selectReportOfType(type) {
313-
cy.get('main .react-grid-item button[aria-label="add report"]').should('be.visible').click();
314-
cy.get('main .react-grid-item')
315-
.contains('No query specified.')
316-
.parentsUntil('.react-grid-item')
317-
.find('button[aria-label="settings"]', { timeout: 2000 })
318-
.should('be.visible')
319-
.click();
320-
cy.get('main .react-grid-item:eq(2) #type', { timeout: 2000 }).should('be.visible').click();
321-
cy.contains(type).click();
322-
cy.wait(100);
323-
}
324-
325-
function createReportOfType(type, query, fast = false, run = true) {
326-
selectReportOfType(type);
327-
if (fast) {
328-
cy.get('main .react-grid-item:eq(2) .ReactCodeMirror').type(query, { delay: 1, parseSpecialCharSequences: false });
329-
} else {
330-
cy.get('main .react-grid-item:eq(2) .ReactCodeMirror').type(query, { parseSpecialCharSequences: false });
331-
}
332-
cy.wait(400);
333-
334-
cy.get('main .react-grid-item:eq(2)').contains('Advanced settings').click();
335-
if (run) {
336-
cy.get('main .react-grid-item:eq(2) button[aria-label="run"]').click();
337-
}
338-
}

‎cypress/e2e/utils.js

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
export function enableReportActions() {
2+
cy.get('main button[aria-label="Extensions').should('be.visible').click();
3+
cy.get('#checkbox-actions').scrollIntoView();
4+
cy.get('#checkbox-actions').should('be.visible').click();
5+
cy.get('.ndl-dialog-close').scrollIntoView().should('be.visible').click();
6+
cy.wait(200);
7+
}
8+
9+
export function enableAdvancedVisualizations() {
10+
cy.get('main button[aria-label="Extensions').should('be.visible').click();
11+
cy.get('#checkbox-advanced-charts').should('be.visible').click();
12+
cy.get('.ndl-dialog-close').scrollIntoView().should('be.visible').click();
13+
cy.wait(200);
14+
}
15+
16+
export function enableFormsExtension() {
17+
cy.get('main button[aria-label="Extensions').should('be.visible').click();
18+
cy.get('#checkbox-forms').scrollIntoView();
19+
cy.get('#checkbox-forms').should('be.visible').click();
20+
cy.get('.ndl-dialog-close').scrollIntoView().should('be.visible').click();
21+
cy.wait(200);
22+
}
23+
24+
export function selectReportOfType(type) {
25+
cy.get('main .react-grid-item button[aria-label="add report"]').should('be.visible').click();
26+
cy.get('main .react-grid-item')
27+
.contains('No query specified.')
28+
.parentsUntil('.react-grid-item')
29+
.find('button[aria-label="settings"]', { timeout: 2000 })
30+
.should('be.visible')
31+
.click();
32+
cy.get('main .react-grid-item:eq(2) #type', { timeout: 2000 }).should('be.visible').click();
33+
cy.contains(type).click();
34+
cy.wait(100);
35+
}
36+
37+
export function createReportOfType(type, query, fast = false, run = true) {
38+
selectReportOfType(type);
39+
if (fast) {
40+
cy.get('main .react-grid-item:eq(2) .ReactCodeMirror').type(query, { delay: 1, parseSpecialCharSequences: false });
41+
} else {
42+
cy.get('main .react-grid-item:eq(2) .ReactCodeMirror').type(query, { parseSpecialCharSequences: false });
43+
}
44+
cy.wait(400);
45+
46+
if (run) {
47+
closeSettings('main .react-grid-item:eq(2)');
48+
}
49+
}
50+
51+
export function openSettings(cardSelector) {
52+
cy.get(cardSelector).find('button[aria-label="settings"]', { WAITING_TIME: 2000 }).click();
53+
}
54+
55+
export function closeSettings(cardSelector) {
56+
cy.get(`${cardSelector} button[aria-label="run"]`).click();
57+
}
58+
59+
export function openAdvancedSettings(cardSelector) {
60+
openSettings(cardSelector);
61+
cy.get(cardSelector).contains('Advanced settings').click();
62+
}
63+
64+
export function closeAdvancedSettings(cardSelector) {
65+
cy.get(cardSelector).contains('Advanced settings').click();
66+
closeSettings(cardSelector);
67+
}
68+
69+
export function openReportActionsMenu(cardSelector) {
70+
openSettings(cardSelector);
71+
cy.get(cardSelector).find('button[aria-label="custom actions"]').click();
72+
}
73+
74+
export function updateDropdownAdvancedSetting(cardSelector, settingLabel, targetValue) {
75+
openAdvancedSettings(cardSelector);
76+
cy.get(`${cardSelector} .ndl-dropdown`).contains(settingLabel).siblings('div').click();
77+
cy.contains(targetValue).click();
78+
closeAdvancedSettings(cardSelector);
79+
}
80+
81+
export function toggleTableTranspose(cardSelector, enable) {
82+
let transpose = enable ? 'on' : 'off';
83+
updateDropdownAdvancedSetting(cardSelector, 'Transpose Rows & Columns', transpose);
84+
}

‎cypress/fixtures/cypher_queries.js

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎docs/modules/ROOT/pages/developer-guide/deploy-a-build.adoc

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ Depending on the webserver type and version, this could be different directory.
3737
As an example - to copy the files to an nginx webserver using `scp`:
3838

3939
```bash
40-
scp neodash-2.4.6 username@host:/usr/share/nginx/html
40+
scp neodash-2.4.7 username@host:/usr/share/nginx/html
4141
```
4242

4343
NeoDash should now be visible by visiting your (sub)domain in the browser.

0 commit comments

Comments
 (0)
Please sign in to comment.