diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md new file mode 100644 index 000000000..392fea334 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -0,0 +1,25 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: bug +assignees: '' + +--- + +## Guidelines +Please note that GitHub issues are only meant for bug reports/feature requests. + + +Before creating a new issue, please check whether someone else has raised the same issue. You may be able to add context to that issue instead of duplicating the report. However, each issue should also only be focussed on a _single_ problem, so do not describe new problems within an existing thread - these are very hard to track and manage, and your problem may be ignored. Finally, do not append comments to closed issues; if the same problem re-occurs, open a new issue, and include a link to the old one. + +To help us understand your issue, please specify important details, primarily: + +- NeoDash version: X.Y.Z +- Neo4j Database version: X.Y.Z (Community/Enterprise/Aura). + +- **Steps to reproduce** +- Expected behavior +- Actual behavior + +Additionally, include (as appropriate) screenshots, drawings, etc. diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md new file mode 100644 index 000000000..632385c5d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request.md @@ -0,0 +1,25 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: feature +assignees: '' + +--- + +## Guidelines +Please note that GitHub issues are only meant for bug reports/feature requests. + +## Feature request template + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. \ No newline at end of file diff --git a/.github/workflows/master-deployment.yml b/.github/workflows/master-deployment.yml index eabd65bbf..74884df39 100644 --- a/.github/workflows/master-deployment.yml +++ b/.github/workflows/master-deployment.yml @@ -71,7 +71,7 @@ jobs: context: . file: ./Dockerfile push: true - tags: ${{ secrets.DOCKER_HUB_USERNAME }}/neodash:latest,${{ secrets.DOCKER_HUB_USERNAME }}/neodash:2.1 + tags: ${{ secrets.DOCKER_HUB_USERNAME }}/neodash:latest,${{ secrets.DOCKER_HUB_USERNAME }}/neodash:2.1.2 build-npm: needs: build-test runs-on: ubuntu-latest @@ -87,6 +87,7 @@ jobs: - run: rm -rf docs - run: npm install - run: npm run-script build + - run: curl ${{ secrets.INDEX_HTML_DEPLOYMENT_URL }} > dist/index.html - run: npm pack - run: rm -rf target - run: mkdir target diff --git a/Dockerfile b/Dockerfile index f105c2ae8..aa10c0dd6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,7 +6,7 @@ WORKDIR /usr/local/src/neodash # Pull source code if you have not cloned the repository #RUN apk add --no-cache git -#RUN git clone https://github.com/nielsdejong/neodash.git /usr/local/src/neodash +#RUN git clone https://github.com/neo4j-labs/neodash.git /usr/local/src/neodash # Copy sources and install/build COPY ./package.json /usr/local/src/neodash/package.json @@ -38,4 +38,4 @@ RUN chown -R nginx:nginx /usr/share/nginx/html/ USER nginx EXPOSE 5005 HEALTHCHECK cmd curl --fail http://localhost:5005 || exit 1 -LABEL version="2.1.1" +LABEL version="2.1.2" \ No newline at end of file diff --git a/README.md b/README.md index ff7f624c4..2c0f50b80 100644 --- a/README.md +++ b/README.md @@ -20,18 +20,20 @@ docker run -it --rm -p 5005:5005 nielsdejong/neodash > Windows users may need to prefix the `docker run` command with `winpty`. -See the [Developer Guide](https://github.com/nielsdejong/neodash/wiki/Developer%20Guide) for more on installing, building, and running the application. +See the [Developer Guide](https://github.com/neo4j-labs/neodash/wiki/Developer%20Guide) for more on installing, building, and running the application. ## User Guide NeoDash comes with built-in examples of dashboards and reports. For more details on the types of reports and how to customize them, see the [User Guide]( -https://github.com/nielsdejong/neodash/wiki/User-Guide). +https://github.com/neo4j-labs/neodash/wiki/User-Guide). ## Publish Dashboards -After building a dashboard, you can chose to deploy a read-only, standalone instance for users. See [Publishing](https://github.com/nielsdejong/neodash/wiki/Publishing) for more on publishing dashboards. +After building a dashboard, you can chose to deploy a read-only, standalone instance for users. See [Publishing](https://github.com/neo4j-labs/neodash/wiki/Publishing) for more on publishing dashboards. ## Questions / Suggestions -If you have any questions about NeoDash, please reach out to the maintainers. For feature requests, consider opening an issue on GitHub. - +If you have any questions about NeoDash, please reach out to the maintainers: +- Create an [Issue](https://github.com/nielsdejong/neodash/issues/new) on GitHub for feature requests/bugs. +- Connect with us on the [Neo4j Discord](https://neo4j.com/developer/discord/). +- Create a post on the Neo4j [Community Forum](https://community.neo4j.com/). > NeoDash is a free and open-source tool developed by the Neo4j community - not an official Neo4j product. If you have a need for a commercial agreement around training, custom extensions or other services, please contact the [Neo4j Professional Services](https://neo4j.com/professional-services/) team. \ No newline at end of file diff --git a/changelog.md b/changelog.md index 9a7dd9c83..6a629af03 100644 --- a/changelog.md +++ b/changelog.md @@ -15,8 +15,8 @@ Main updates: Other changes: - Added continuous integration and deployment workflows. -- Created a new [User Guide](https://github.com/nielsdejong/neodash/wiki/User-Guide) with documentation on all report customizations is available. -- Added a new [Developer Guide](https://github.com/nielsdejong/neodash/wiki/Developer-Guide) with info on installing, building and extending the application. +- Created a new [User Guide](https://github.com/neo4j-labs/neodash/wiki/User-Guide) with documentation on all report customizations is available. +- Added a new [Developer Guide](https://github.com/neo4j-labs/neodash/wiki/Developer-Guide) with info on installing, building and extending the application. ## NeoDash 2.0.15 diff --git a/cypress/integration/start_page.spec.js b/cypress/integration/start_page.spec.js index 9ec7dc4fe..2a8ddd811 100644 --- a/cypress/integration/start_page.spec.js +++ b/cypress/integration/start_page.spec.js @@ -166,7 +166,7 @@ describe('NeoDash E2E Tests', () => { }) // Test load stress-test dashboard from file - it.only('test load dashboard from file and stress test report customizations', () => { + it('test load dashboard from file and stress test report customizations', () => { try { var NUMBER_OF_PAGES_IN_STRESS_TEST_DASHBOARD = 5; const file = cy.request(loadDashboardURL).should((response) => { diff --git a/docs/Adding-Visualizations.adoc b/docs/Adding-Visualizations.adoc new file mode 100644 index 000000000..d00862bf6 --- /dev/null +++ b/docs/Adding-Visualizations.adoc @@ -0,0 +1,95 @@ +You can extend NeoDash with your own visualizations without diving deep +into the core application. Likewise, adding a new customization to an +existing report requires minimal changes. + +== Add a Visualization + +You can add a new chart to NeoDash in three steps: + +[arabic] +. Make sure you have a local copy of NeoDash installed and running: + +.... +git clone git@github.com:nielsdejong/neodash.git +git checkout develop +npm install +npm run dev +.... + +[arabic, start=2] +. Create a new file `src/charts/ABCChart.tsx`. In here, add a new object +that implements the `ChartProps` interface: + +.... +export interface ChartProps { + records: Neo4jRecord[]; // Query output, Neo4j records as returned from the driver. + selection?: Record; // A dictionary with the selection made in the report footer. + settings?: Record; // A dictionary with the 'advanced settings' specified through the NeoDash interface. + dimensions?: Number[]; // a 2D array with the dimensions of the report (likely not needed, charts automatically fill up space). + fullscreen?: boolean; // flag indicating whether the report is rendered in a fullscreen view. + queryCallback?: (query: string, parameters: Record, records: Neo4jRecord[]) => null; // Optionally, a way for the report to read more data from Neo4j. + setGlobalParameter?: (name: string, value: string) => void; // Allows a chart to update a global dashboard parameter to be used in Cypher queries for other reports. + getGlobalParameter?: (name) => string; // Allows a chart to get a global dashboard parameter. +} +.... + +Note that the only mandatory property is `records`. This contains a list +of +https://neo4j.com/docs/api/javascript-driver/current/class/lib6/record.js~Record.html[records] +returned from the Cypher query specified by the user. + +For inspiration, below is a basic example of a component that renders +all returned data as a list: + +.... +import React from 'react'; +import { ChartProps } from './Chart'; +import { renderValueByType } from '../report/ReportRecordProcessing'; + +const NeoListReport = (props: ChartProps) => { + const records = props.records; + return records.map(r => { + return
{ + r["_fields"].map(value => { + return <>{renderValueByType(value)}, + })} +
+ }) +} + +export default NeoListReport; +.... + +[arabic, start=3] +. Make your component selectable. Now that you’ve created a new chart +type, you need to tell the card settings window that it can be chosen by +a user. + +To accomplish this, open `config/ReportConfig.tsx`. Add a new entry to +the `REPORT_TYPES` dictionary: + +.... +export const REPORT_TYPES = { + ... + "list": { + label: "List", + helperText: "I'm a list", + component: NeoListReport, + maxRecords: 10, + settings: {} + }, + ... +} +.... + +Inspect the other entries for examples of the fields that each entry can +have. Restart the application, and you should be able to select your new +chart type. Finally, *Cypress* can be used to develop an end-to-end test +for your component in a matter of minutes. See Testing for more on +Cypress testing. + +____ +After you added a visualization or a new customization, consider +contributing it to the NeoDash project by creating a +https://github.com/nielsdejong/neodash/pulls[Pull Request]. +____ diff --git a/docs/Bar-Chart.adoc b/docs/Bar-Chart.adoc new file mode 100644 index 000000000..30d8f84f1 --- /dev/null +++ b/docs/Bar-Chart.adoc @@ -0,0 +1,99 @@ +A bar chart will draw categories and values in a familiar bar-layout. +The bar chart will require you to choose the following selections: + +* *Category*: a text field. These will be the labels on the bars. +* *Value*: a numeric field. This will be the height of the bars. +* *Group*: Optionally, a second textual field. When ``Grouping'' is +enabled in the advanced settings, the group can be used to draw a +stacked bar chart, with several groups per category. + +== Examples + +=== Simple Bar Chart + +[source,cypher] +---- +MATCH (p:Person)-[e]->(m:Movie) +RETURN m.title as Title, COUNT(p) as People +---- + +image::./img/bar.png[Basic Table] + +=== Stacked Bar Chart + +[source,cypher] +---- +Match (n:Person)-[e]->(m:Movie) +RETURN m.title, COUNT(p) as People, type(e) as Role +---- + +image::./img/barstacked.png[Basic Table] + +== Advanced Settings + +[width="100%",cols="19%,17%,26%,38%",options="header",] +|=== +|Name |Type |Default Value |Description +|Show Legend |on/off |off |If enabled, shows a legend at the top right +of the visualization. + +|Grouping |on/off |off |If enabled, lets users specify a third, grouping +field. This is used to distinguish between different groups in the +stacked bar chart. + +|Value Scale |List |linear |When set to symlog, uses a Symmetric +logarithmic scale instead of the default linear scale. + +|Min Value |Number |auto |If not set to ``auto'', this variable is +minimum value for the bar chart. + +|Max Value |Number |auto |If not set to ``auto'', this variable is the +maximum value for the bar chart. + +|Group Mode |List |stacked |This setting determines how different groups +are visualized when grouping is enabled. If set to stacked, different +groups of the same category are stacked on top of each other. If set to +grouped, they are placed alongside each other. + +|Layout |List |vertical |Whether to use a vertical or horizontal bar +chart layout. + +|Color Scheme |List | |The color scheme to use for the category groups. +Colors are assigned automatically (consequitevely) to the different +groups returned by the Cypher query. + +|Show Values on Bars |on/off |off |If enabled, shows the category value +inside the respective bar. + +|Label Rotation (degrees) |number |45 |the angle at which the bar labels +are rotated. + +|Margin Left (px) |number |50 |The margin in pixels on the left side of +the visualization. + +|Margin Right (px) |number |24 |The margin in pixels on the right side +of the visualization. + +|Margin Top (px) |number |24 |The margin in pixels on the top side of +the visualization. + +|Margin Bottom (px) |number |40 |The margin in pixels on the bottom side +of the visualization. + +|Legend Width (px) |number |128 |The width in pixels of each legend +label on top of the visualization (if enabled). + +|Hide Selections |on/off |off |If enabled, hides the property selector +(footer of the visualization). + +|Auto-run query |on/off |on |when activated automatically runs the query +when the report is displayed. When set to `off', the query is displayed +and will need to be executed manually. +|=== + +== Rule-Based Styling + +Using the link:Reports#rule-based-styling[Rule-Based Styling] menu, the +following style rules can be applied to the bar chart: + +- The color of the bar. diff --git a/docs/Bloom-Integration.adoc b/docs/Bloom-Integration.adoc new file mode 100644 index 000000000..3f2d02bb7 --- /dev/null +++ b/docs/Bloom-Integration.adoc @@ -0,0 +1,25 @@ +NeoDash can be linked to Neo4j Bloom perspectives by using +https://neo4j.com/docs/bloom-user-guide/current/bloom-tutorial/deep-links/[Bloom +Deep Links]. This functionality allows you to combine the power of graph +reporting (NeoDash) with intuitive graph exploration (Bloom). + +== Bloom Deep-Linking + +To link NeoDash to a Bloom perspective, you will need to: + +1. Create a Neo4j Bloom https://neo4j.com/docs/bloom-user-guide/current/bloom-perspectives/bloom-perspectives/[perspective]. +2. Define a https://neo4j.com/docs/bloom-user-guide/current/bloom-tutorial/search-phrases-advanced/[Bloom +Search Phrase] for the perspective. +3. Generate a https://neo4j.com/docs/bloom-user-guide/current/bloom-tutorial/deep-links/#_server_hosted_bloom[Deep +Link] for your perspective and respective search phrase. This requires +that you have a +https://neo4j.com/docs/bloom-user-guide/current/bloom-installation/installation-activation/#installing-server-plugin[Server-hosted +Bloom installation] running. + +4. Use the deep link you created in either: +- an iFrame Report (optionally passing in the dashboard parameters into +the search phrase). +- a Graph Report (Adding your deep link inside the +`Drilldown Link' field under advanced settings): + +image::./img/graphdrilldown.png[Graph Drilldown] diff --git a/docs/Build-&-Run.adoc b/docs/Build-&-Run.adoc new file mode 100644 index 000000000..70e4120f5 --- /dev/null +++ b/docs/Build-&-Run.adoc @@ -0,0 +1,69 @@ +To start developing the application, you’ll need to set up the +development environment. + +== Run & Build using npm + +NeoDash is built with React. You’ll need `npm` installed to run the web +app. + +____ +Use a recent version of `npm` and `node` to build NeoDash. The +application has been tested with npm 8.6 & node v17.4.0. +____ + +To run the application in development mode: + +- clone this repository. +- open a terminal and navigate to the directory you just cloned. +- execute `npm install` to install the necessary dependencies. +- execute `npm run dev` to run the app in development mode. +- the application should be available at http://localhost:3000. + +To build the app for production: + +- follow the steps above to clone the repository and install dependencies. +- execute `npm run build`. This will create a `build` folder in your project directory. +- deploy the contents of the build folder to a web server. You should then be able to run the web app. + +== Run locally with Docker + +Pull the latest image from Docker Hub to run the application locally: + +.... +# Run the application on http://localhost:5005 +docker pull nielsdejong/neodash:latest +docker run -it --rm -p 5005:5005 nielsdejong/neodash +.... + +____ +Windows users may need to prefix the `docker run` command with `winpty`. +____ + +== Build Docker image + +A pre-built Docker image is available +https://hub.docker.com/r/nielsdejong/neodash[on DockerHub]. This image +is built using the default configuration (running in editor mode, +without SSO). + +=== To build the image yourself: + +Make sure you have a recent version of `docker` installed to build the +multi-stage NeoDash image and run it. + +On Unix (Mac/Linux) systems: + +.... +docker build . -t neodash +.... + +If you use Windows, you might need to prefix the command with `winpty`: + +.... +winpty docker build . -t neodash +.... + +After building, you can run the image with: +.... +docker run -it –rm -p 5005:5005 neodash +.... diff --git a/docs/Circle-Packing.adoc b/docs/Circle-Packing.adoc new file mode 100644 index 000000000..0df38cf09 --- /dev/null +++ b/docs/Circle-Packing.adoc @@ -0,0 +1,51 @@ +A circle packing chart will render hierarchical data in a group of +nested circles. It takes two fields: + +- *Path*: a list of strings. This represents the hierarchy (from highest to lowest level). + - *Value*: a number that matches the size of the element at the lowest level. Sizes of non-leaf levels are determined from the sum of their children. + +== Examples + +=== Basic Circle Packing Chart + +[source,cypher] +---- +MATCH path=(:Company{name:'NeoDash'})-[:HAS_DEPARTMENT*]->(:Department) +WITH nodes(path) as no +WITH no, last(no) as leaf +WITH [n IN no[..-1] | n.name] AS result, sum(leaf.employees) as val +RETURN result, val +---- + +image::./img/circlepacking.png[Circle Packing Chart] + +== Advanced Settings + +[width="100%",cols="13%,3%,6%,78%",options="header",] +|=== +|Name |Type |Default Value |Description +|Enable interactivity |on/off |on |If enabled, turn on animations when a +user hovers over an circle. + +|Color Scheme |List | |The color scheme to use for the circles. Colors +are assigned automatically for each of the sub-hierarchies. + +|Circle border width (px) |number |0 |The width of the border of each +circle. + +|Margin Left (px) |number |24 |The margin in pixels on the left side of +the visualization. + +|Margin Right (px) |number |24 |The margin in pixels on the right side +of the visualization. + +|Margin Top (px) |number |24 |The margin in pixels on the top side of +the visualization. + +|Margin Bottom (px) |number |40 |The margin in pixels on the bottom side +of the visualization. + +|Auto-run query |on/off |on |When activated, automatically runs the +query when the report is displayed. When set to `off', the query is +displayed and will need to be executed manually. +|=== diff --git a/docs/Component-Overview.adoc b/docs/Component-Overview.adoc new file mode 100644 index 000000000..98adc54e1 --- /dev/null +++ b/docs/Component-Overview.adoc @@ -0,0 +1,51 @@ +The image below contains a high-level overview of the component +hierarchy within the application. The following conceptual building +blocks are used to create the interface: + +image::./img/component-hierarchy.png[NeoDash Component Hierarchy] + +* *Application* - highest level in the component structure. Handles all +application-level logic (e.g. initalizing the app). +* *Modals* - all pop-up windows used by the tool. (Connection modal, +save-dashboard modal, errors/warnings, etc.) +* *Drawer* - the sidebar on the left side of the screen. Contains +buttons to perform application-level actions. +* *The Dashboard* - Main dashboard component. Renders components +dynamically based on the current state. +* *Dashboard Header* - the textbox at the top of the screen that lets +you set a title for the dashboard, plus the page selector. +* *Pages* - a dashboard has one or more pages, each of which can have a +list of cards. +* *Cards* - a `block' inside a dashboard. Each card contains a `view' +window, and a `settings' window. +* *Card View* - the front of the card containing the selected report. +* *Card Settings* - the back of the card, containing the cypher editor +and advanced settings for the report. +* *Card View Header* - the header of the card, containing a text box +that acts as the name of the report. +* *Report* - the component inside the card view that handles query +execution and result parsing. Contains a single chart (visualization) +* *Card View Footer* - The footer of the card view. Depending on the +type, contains several `selectors' that modify the visualization. +* *Card Settings Header* - Header of the card settings, used for +moving/deleting the card. +* *Card Settings Content* - the component containing the main content of +the report. This is most often the Cypher query editor. +* *Card Settings Footer* - the `footer' of the card. This contains the +`advanced settings' window for reports. +* *Charts* - the different visualizations used by the application: bar +charts, tables, graphs, etc. + + +== A note on Cards v.s. Reports + +Whereas a user might associate a `Card' in NeoDash to a report directly, +the application has a more nuanced seggration of responsibilities; + +* The *Card* is responsible for positioning the component in a page. +* The *Card Content* is the core element of the card (exclusive of the +title header and any optional footer). +* A *Report* sits inside the card content, and handles the running of +queries and displaying errors. +* A *Chart* is rendered by the report and is solely responsible for +rendering a specific visualization. diff --git a/docs/Configuration.adoc b/docs/Configuration.adoc new file mode 100644 index 000000000..cd38e1669 --- /dev/null +++ b/docs/Configuration.adoc @@ -0,0 +1,134 @@ +When using a custom NeoDash deployment, there are several settings that +can be configured. These mostly relate to +link:Standalone%20Mode[Standalone Mode] and SSO configurations. + +For a simple (non-Dockerized) deployment, these configuration parameters +can be changed by modifying `dist/config.json` after you have built the +application. When Docker image, these can be passed as environment +variables. See link:Standalone%20Mode[Standalone Mode] for more on +Docker deployments. + +An example configuration for NeoDash (default, running in editor mode) +will look like this: + +.... +{ + "ssoEnabled": false, + "ssoDiscoveryUrl": "https://example.com", + "standalone": false, + "standaloneProtocol": "neo4j", + "standaloneHost": "localhost", + "standalonePort": "7687", + "standaloneDatabase": "neo4j", + "standaloneDashboardName": "My Dashboard", + "standaloneDashboardDatabase": "dashboards", + "standaloneDashboardURL": "" +} +.... + +== Configuration Options + +[width="100%",cols="19%,17%,26%,38%",options="header",] +|=== +|Name |Type |Default Value |Description +|ssoEnabled |boolean |false |If enabled, lets users connect to Neo4j +using SSO. This requires the app to be running in standalone mode, and a +valid ssoDiscoveryUrl to be set. + +|ssoDiscoveryUrl |string |https://example.com |If ssoEnabled is true & +standalone mode is enabled, the URL to retrieve SSO auth config from. + +|standalone |boolean |false |Determines whether to run NeoDash in editor +mode (false), or reader mode (true). The terms ``Reader mode'' and +``Standalone mode'' are used interchangibly. + +|standaloneProtocol |string |neo4j |When running in standalone mode, the +protocol to used for the Neo4j driver. This shoudl be set to one of +`neo4j`, `neo4j+s`, `neo4j+ssc`, `bolt`, `bolt+s`, or `bolt+ssc`. + +|standaloneHost |string |localhost |When running in standalone mode, the +hostname to connect to. This should be *just* the hostname, no protocols +or ports. + +|standalonePort |string |7687 |When running in standalone mode, the Bolt +port to connect to. + +|standaloneDatabase |string |neo4j |When running in standalone mode, the +database to use for reporting. Cypher queries used in reports will read +data from this database. + +|standaloneUsername ⚠️ |string |… |A hidden config parameter enables you +to set the username for standalone mode by default. Keep in mind this is +a security risk, as it exposes the Neo4j username to anyone who can +access the NeoDash deployment. + +|standalonePassword ⚠️ |string |… |A hidden config parameter enables you +to set the password for standalone mode by default. If this value is set +connections are also made automatically. Keep in mind this is a security +risk, as it exposes the Neo4j username to anyone who can access the +NeoDash deployment. + +|standaloneDashboardName |string |My Dashboard |The exact name +(case-sensentive) of the dashboard to be loaded when running in +standalone mode. This must be a dashboard that is saved as a node in the +graph. + +|standaloneDashboardDatabase |string |neo4j |The name of the Neo4j +database that contains the saved dashboard node. This is neo4j by +default, _unless you are using Neo4j Enterprise Edition_, which lets you +use multiple databases. + +|standaloneDashboardURL |string |neo4j |If you do not save a dashboard +inside Neo4j and would like to run a standalone mode deployment with a +dashboard from a URL, set this parameter to the complete URL pointing to +the dashboard JSON. +|=== + +== Configuring SSO + +NeoDash can use SSO as an alternative for password-based sign-in, if +your Neo4j database is enabled to use single sign on. To enable SSO, set +`ssoEnabled` to `true`. Then, set `ssoDiscoveryUrl` to the place where +your `discovery.json` is located (This will often be the hostname of +your database, appended by `/discovery.json`). + +____ +Note that SSO is only available when Standalone Mode is enabled. +____ + +== Auth Provider + +To set up NeoDash to use an external identity provider, you can add a +/auth_provider resource to nginx (in `/conf/default.conf`): + +.... +location /auth_provider { + default_type application/json; + return 200 '{ + "auth_config" : { + "oidc_providers" : [ ... ] + } + }'; + } +.... + +For basic deployments it might suffice to route requests to +`/auth_provider` on the https port of the neo4j database. + +== Configuring Standalone Mode + +Standalone mode, or reader-mode, overrides the functionality of NeoDash, +allowing you to deploy a fixed dashboard to users. Standalone mode can +be enabled by changing the `standalone` config parameter: + +* If standalone mode is `false`, all other configuration parameters are +ignored. NeoDash will run in Editor mode, and require a manual sign-in. +* If standalone mode is `true`, NeoDash will read all configuration +parameters. A *fixed dashboard* will be auto-loaded, and no changes to +the dashboard can be made. There are two types of valid standalone +deployments: +** A standalone deployment that *reads the fixed dashboard from Neo4j*. +The `standaloneDashboardName` and `standaloneDashboardDatabase` config +parameters are used to define these. +** A standalone deployment that *reads the fixed dashboard from a URL*. +The `standaloneDashboardURL` config parameter is used to define this. diff --git a/docs/Contributing.adoc b/docs/Contributing.adoc new file mode 100644 index 000000000..3ab4d1964 --- /dev/null +++ b/docs/Contributing.adoc @@ -0,0 +1,19 @@ +Contributions to the project are highly welcomed. Please consider +creating a https://github.com/nielsdejong/neodash/pulls[Pull Request]. +Ensure you start from the `develop` branch, and set the merge base to +`develop` as well. + +For your feature to be accepted, ensure: + +1. The component is tested (if relevant, see Testing). +2. Your code is aligned with +https://www.w3.org/wiki/JavaScript_best_practices[JS Best Practises]. +3. The component is well documented in the documentation portal (if +applicable). + +== Feature Requests / Bugs + +If you have a request for a feature, or have found a bug, consider +creating an https://github.com/nielsdejong/neodash/issues[issue] on +GitHub. Please include a link:./Testing#debug-report[Debug Report] if +available. diff --git a/docs/Dashboards.adoc b/docs/Dashboards.adoc new file mode 100644 index 000000000..1739b6245 --- /dev/null +++ b/docs/Dashboards.adoc @@ -0,0 +1,179 @@ +In NeoDash, a dashboard consists of several pages, each of which can +consist of multiple reports. + +image::./img/dashboard2.png[Dashboard] + +As an example: The screenshot above shows a dashboard with three pages: +`Breweries`, `Beer Ratings` and `Styles`. The dashboard title `My +Beer Database Dashboard 🍺` is displayed on the top of the window. + +The first page is selected, and contains three reports, a table, a graph +and a map. Each report can be given their own name, and has exactly one +Cypher query used to populate the report. See Reports for more info on +how reports work. + +== Dashboard Management + +After startup up NeoDash, you will be given the choice to create a new +dashboard or open an existing one (if available). After being connected, +the buttons on the sidebar can be used to save, load or share a +dashboard. + +image::./img/saveloadshare.png[Save/Load/Share Button] + +=== Save a Dashboard + +A NeoDash dashboard is, simply put, a JSON file. As an example, the +default dashboard has the following structure: + +.... +{ + "title": "", + "version": "2.0", + "settings": { + "pagenumber": 0, + "editable": true, + "fullscreenEnabled": true, + "parameters": {} + }, + "pages": [ + { + "title": "Main Page", + "reports": [ + { + "title": "Hi there 👋", + "query": "**This is your first dashboard!** \n \nYou can click (⋮) to edit this report, or add a new report to get started. You can run any Cypher query directly from each report and render data in a variety of formats. \n \nTip: try _renaming_ this report by editing the title text. You can also edit the dashboard header at the top of the screen.\n\n\n", + "width": 3, + "type": "text", + "height": 3, + "selection": {}, + "settings": {} + }, + { + "title": "", + "query": "MATCH (n)-[e]->(m) RETURN n,e,m LIMIT 20\n\n\n", + "width": 3, + "type": "graph", + "height": 3, + "selection": { + "Movie": "title", + "Genre": "name" + }, + "settings": { + "nodePositions": {} + } + } + ] + } + ] +} +.... + +After opening the save dialog, there are three options for saving your +dashboard: + +1. Save as a file. This triggers a download of the current +dashboard as `.json` file. +2. Save inside Neo4j. This stores a +stringified representation of the dashboard as a node in the database. +When using Neo4j multi-database, you will be given the choice of which +database to save the dashboard in. +3. Copy-paste the JSON file directly. + +=== Load a Dashboard + +Just like in the save screen, a dashboard can be loaded in one of three +ways: + +1. Load from a file. This requires you to select a `.json` +somewhere on your computer. +2. Load from Neo4j. This requires you to +select a dashboard node stored in the database. When loading from Neo4j, +you will be presented with the list of dashboards in reverse +chronological order. +3. Loading a JSON file by pasting it directly into +the editor. + +=== Share a Dashboard + +A dashboard can be shared with other users by generating a direct link +to it. This link will contain: + +- A link to the dashboard (either a +direct URL or the name of the dashboard inside Neo4j). +- (Optionally), +the credentials of the database that the dashboard is reporting on. *Be +warned*, when using this feature, the share link will contain the +database credentials, which can be a security risk. +- If the dashboard should be viewed in `editor mode', or `standalone mode'. The latter configures neodash to run in a stripped down UI without any of the editor features enabled. + +When creating a NeoDash deployment on a production database, it is not +recommended to use the `Share' feature. Rather, set up a dedicated +standalone deployment of NeoDash. See Publishing for more infomation. + +== Dashboard Settings + +Settings for the entire dashboard can be accessed by clicking the +*Settings ⚙️* button in the dashboard sidebar. + +image::./img/dashboardsettings.png[Dashboard Settings] + +This window can be used to control the followng settings: + +[width="100%",cols="19%,17%,26%,38%",options="header",] +|=== +|Name |Changeable |Default Value |Description +|Editable |Yes |on |If enabled, show the dashboard in `editing mode'. If +not, show it in `view mode'. In view mode, all editing is disabled, +pages and reports can not be moved, edited or renamed. + +|Enable Fullscreen Report Views |Yes |on |If enabled, show the *🔳 +Fullscreen* button on the top-right of a report, letting users maximize +a visualization. + +|Maximum Query Time (seconds) |Yes |20 |The maximum time is a query is +allowed to take before being cancelled automatically. Increase this if +you have complex analytical queries. + +|Disable Row Limiting |Yes |off |If enabled, the automatic +link:Reports#row-limiting[row limiting] feature of dashboards is +disabled. + +|Page Number |No |0 |The current page number of the dashboard being +viewed. This can only be changed by switching pages in the dashboard +header. + +|Global Parameters |No | {} |The global parameters that are shared among +all reports in the dashboard. See the next section for more on global +parameters. +|=== + +== Parameters + +Dashboard parameters are key-value pairs that can be used inside the +queries of reports. A convention is that a dashboard parameter in +NeoDash will always start with `$neodash_`. + +Parameters can only be set (and unset) using the +link:Parameter%20Select[`Parameter Select'] reports. After setting a +parameter, it will be available to all reports in the dashboard. A query +that uses a dashboard parameter will look like this: + +.... +MATCH (m:Movie)<-[a:ACTED_IN]-(p:Person) +WHERE m.title = $neodash_movie_title +RETURN m, a, p +.... + +=== Deep-Linking Parameters + +For browser-based NeoDash deployments, you set NeoDash parameters by +means of URL parameters. For example, when a user visits the following +URL: + +.... +https://neodash.graphapp.io/?neodash_person_name=Adam +.... + +This will set the parameter `$neodash_person_name` to `Adam` after +loading the dashboard. diff --git a/docs/Design.adoc b/docs/Design.adoc new file mode 100644 index 000000000..b140ffd72 --- /dev/null +++ b/docs/Design.adoc @@ -0,0 +1,46 @@ +This page contains some key guidelines for design of the application. +This entails code architecture, as well as UX/UI design. + +== File Structure + +The source code of NeoDash is organized as a flat file structure based +on components. Given a component `ABC` is to be added, you should create +a directory called `abc` with the following files: + +* `ABC.tsx` (component renderer) +* `ABCActions.ts` (objects defining state manipulation) +* `ABCReducer.ts` (handling state changes based on actions) +* `ABCSelectors.ts` (used by components to retrieve part of the state) +* `ABCThunks.ts` (Complex state handling logic, to fire one or more +actions) + +=== Structure of the other folders + +.... +conf: nginx configuration for Docker image. +dist: directory for generated webpack files. +doc: documentation (to be moved to wiki) +node_modules: downloaded dependencies +public: style files/images. Runtime app config. +scripts: utility scripts for deployment. +src: source code. +target: compiled package as tgz file. +.babelrc: javascript compiled settings. +.gitignore: gitignore files. +.npmignore: files ignored by the npm package. +Dockerfile: docker image definition. +.... + +== UX Design + +At it’s core, NeoDash aims to be a tool that is _easy to learn, but hard +to master_. This translates into the following five design principles in +mind: + +[arabic] +. Use a limited set of core visualizations, with high customizability. +. It should be easy to get started without reading documentation. +. The tool should be self-documenting. +. Complex data transformations should be done by dashboard builders in +Cypher, and not by the application. +. The tool should be easy to extend with custom visualizations. diff --git a/docs/Developer Guide.adoc b/docs/Developer Guide.adoc new file mode 100644 index 000000000..832a11235 --- /dev/null +++ b/docs/Developer Guide.adoc @@ -0,0 +1,39 @@ +The following pages will guide developers who want to dive deeper into +NeoDash, and extend it for their own needs. In case you just want to run +NeoDash, see the Quickstart page. + +This guide has the following sections: + +- link:Build%20&%20Run[Build & Run] +- link:Configuration[Configuration] +- link:Standalone%20Mode[Standalone Mode] +- link:Component%20Overview[Component Overview] +- link:Design[Design] +- link:Adding%20Visualizations[Adding Visualizations] +- link:State%20Management[State Management] +- link:Testing[Testing] +- link:Contributing[Contributing] + +== Prerequisites + +NeoDash is a web application written in TypeScript. Knowledge of React & +Redux is also highly recommended when extending the application. +Concretely, the following languages and frameworks make up the core of +NeoDash: + +- https://reactjs.org/[React] +- https://redux.js.org/[Redux] +- https://redux.js.org/usage/writing-logic-thunks[Redux Thunks] +- https://www.cypress.io/[Cypress] +- https://mui.com/[Material UI] +- https://webpack.js.org/[Webpack] + +The following core libraries are used to build the visualizations for +reports: + +- https://github.com/vasturiano/react-force-graph[react-force-graph +(Graph)] +- https://mui.com/components/data-grid/[@mui/datagrid (Table)] +- https://nivo.rocks/[@nivo (Bar, Line, Pie charts)] +- https://leafletjs.com/[leaflet (Map)] +- https://github.com/remarkjs/react-markdown[react-markdown (Markdown)] diff --git a/docs/FAQ.adoc b/docs/FAQ.adoc new file mode 100644 index 000000000..d2e797547 --- /dev/null +++ b/docs/FAQ.adoc @@ -0,0 +1,89 @@ +== 1. How can I learn more about NeoDash? + +To learn more, check out the following list of resources (blogs, videos +and sites): + +- https://www.youtube.com/watch?v=Ygzj0Y4cYm4[NeoDash 2.0 in +Five Minutes] +- https://www.youtube.com/watch?v=vjZ9M7JpExA[NeoDash 2.0 - Hands On at Neo4j Live] +- https://medium.com/p/ddc938ff82fa[Investigating Supply Chains with NeoDash] +- https://thatdavestevens.medium.com/social-recommendations-slack-neo4j-and-neodash-fe916588e65b[Social Recommendations with Neo4j & NeoDash] +- https://neo4j.com/developer-blog/bitcoin-transactions-dashboard-neo4j-neodash/[Real-Time Dashboard of Bitcoin Transactions With Neo4j and NeoDash] +- https://medium.com/@a.emrevarol/european-natural-gas-network-via-knowledge-graph-3c3decb5f2ec[European +Natural Gas Pipelines] +- http://blog.bruggen.com/2020/11/exporting-spotify-playlists-into-neo4j.html[Exporting Spotify Playlists into Neo4j] +- https://nielsdejong.nl/neo4j%20projects/2021/12/14/neodash-2.0-a-brand-new-way-of-visualizing-neo4j-data.html[NeoDash +2.0 Release Overview] +- https://nielsdejong.nl/neo4j%20projects/2021/06/06/neodash-1.1-extensible-interactive-dashboards.html[NeoDash +1.1 Release Overview] +- https://nielsdejong.nl/neo4j%20projects/2020/11/16/neodash[NeoDash 1.0 +Release Overview] + +_Have a blog post about NeoDash you’d like to share? Let us know and we +can add it to this list!_ + +== 2. Is NeoDash free to use? + +NeoDash 2.X is available under the +https://www.apache.org/licenses/LICENSE-2.0[Apache 2.0 license], which +means you can use it for free for with your project. + +____ +Keep in mind! As NeoDash is a https://neo4j.com/labs/[Neo4j Labs] +project, it is not part of the official Neo4j product suite, and is not +supported as part of a Neo4j license. (See also question #8 below…) +____ + +== 3. Can I publish the dashboard that I built? + +When you’re done building a dashboard and want to show to others as a +read-only web page, you can set up a link:Standalone%20Mode[Standalone +Mode] deployment of NeoDash. + +If you need help setting this up, please contact the +mailto:niels.dejong@neo4j.com[team] and we can help out. + +== 4. Is NeoDash Production Ready? + +NeoDash is safe to be used in a production environment. As it is a +reporting tool, keep the following things in mind: + +- Always use *read-only* Neo4j accounts when connecting to a dashboard. +- Always deploy NeoDash with SSL, so that an encrypted Neo4j connection must be +used. +- As NeoDash accesses Neo4j directly, make sure you only give +access to the right people. As a rule of thumb, you should give NeoDash +access to the people that can also see Bloom. + +For other questions regarding setting up your own production deployment, +please mailto:niels.dejong@neo4j.com[contact us]. + +== 5. Can I use NeoDash with Neo4j Community Edition? + +Yes, NeoDash can be used with any type of Neo4j deployment (On-premise, +cloud, or fully managed in Neo4j Aura). We do however recommend that you use the +Enterprise version, as it lets you create a +dedicated read-only user for reporting. + +== 6. I’m missing a feature. Can I ask for help? +Feature requests and bug reports are more than welcome. Please open an +issue on https://github.com/nielsdejong/neodash/issues[Github]. Issues +will be addressed on a best-effort basis. + +If you’re looking for a specific feature with high priority, you can +reach out to the mailto:niels.dejong@neo4j.com[Neo4j Team]. + +== 7. How can I contribute to NeoDash myself? + +NeoDash is an open-source tool that can be extended by anyone. If you +are interested in contributing, please check out the +https://github.com/nielsdejong/neodash[Github repository]. + +Aside from code contributions, we are also very happy to hear about how +you use NeoDash. If you have a blog post, podcast or video of your graph +dashboard, let us know! + +== 8. Can I pay for help with NeoDash? + +If you are interested in a services agreement to support your NeoDash deployment, please reach out to the +mailto:niels.dejong@neo4j.com[Neo4j Services Team]. diff --git a/docs/Graph.adoc b/docs/Graph.adoc new file mode 100644 index 000000000..d67563d9c --- /dev/null +++ b/docs/Graph.adoc @@ -0,0 +1,132 @@ +The graph report will render all returned nodes, relationships and paths +in a force-directed graph layout. This includes collections (lists) of +these objects. + +The library `react-force-graph` is used to create the visualizations. +Depending on your browser, the visualization should be able to handle +drawing 1000-3000 nodes/relationships with custom styling options. + +The graph layout contains an extensive set of features, including: + +- Drag and drop nodes. +- Custom node/relationship styling. +- Tooltips/inspect window on nodes/relationships. + +== Examples + +=== Basic Graph + +.... +MATCH (p:Person)-[a:ACTED_IN]->(m:Movie) +WHERE m.title = 'The Matrix' +RETURN p, a, m +.... + +image::./img/graph.png[Basic Graph] + +== Virtual Graph (apoc is required) + +.... +MATCH (p:Person)-[:ACTED_IN]->(m:Movie)<-[:ACTED_IN]-(p2:Person) +WHERE m.title = "The Matrix" +RETURN p, p2, apoc.create.vRelationship(p, "KNOWS", {}, p2) +.... + +image::./img/graph2.png[Virtual Graph] + +== Advanced Settings + +[width="100%",cols="12%,2%,3%,83%",options="header",] +|=== +|Name |Type |Default Value |Description +|Node Color Scheme |List |neodash |The color scheme to use for the node +labels. Colors are assigned automatically (consequitevely) to the +different labels returned by the Cypher query. + +|Node Label Color |Text |black |The color of the labels drawn on the +nodes. + +|Node Label Font Size |Number |3.5 |Size of the labels drawn on the +nodes. + +|Node Size |Number |2 |Default size of a node in the graph +visualization. This size is applied if no custom size styling is defined +and no Rule-Based styling is active. + +|Node Size Property |Text |size |Optionally, the name of the node +property to map to the node size. This lets you define sizes on a +node-specific level, if you have a property that directly maps to the +numeric size value. + +|Node Color Property |Text |color |Optionally, the name of the node +property to map to the node color. This lets you define colors on a +node-specific level, if you have a property that directly maps to the +HTML color value. + +|Relationship Color |Text |#a0a0a0 |The color used for drawing the +relationship arrows in the visualization. + +|Relationship Width |Text |1 |The (default) width of the relationship +arrows in the visualization. + +|Relationship Label Color |Text |#a0a0a0 |The color of the labels +(relationship type) drawn next to the relationship arrows. + +|Relationship Label Font Size |Text |2.75 |The font size of the labels +(relationship type) drawn next to the relationship arrows. + +|Relationship Color Property |Text |color |Optionally, the name of the +relationship property to map to the arrow color. This lets you define +colors on a relationship-specific level, if you have a property that +directly maps to the HTML color value. + +|Relationship Width Property |Text |width |Optionally, the name of the +relationship property to map to the arrow width. This lets you define +widths on a relationship-specific level, if you have a property that +directly maps to the width value. + +|Animated Particles on Relationships |on/off |off |If enabled, draw +relationships with animated particles on them, moving in the direction +of the relationship. + +|Background Color |Text |#fafafa |The background color of the +visualization. + +|Layout (experimental) |List |force-directed |Use this to switch from +the main (force-directed) layout to one of the two experimental layouts +(tree/radial). For the experimental layouts, make sure your graph is a +DAG (directed acyclic graph). + +|Show pop-up on Hover |on/off |on |if enabled, shows a pop-up when a +user hovers over one of the nodes/relationships in the visualization. +The pop-up contains the label and properties of the node/relationship. + +|Show properties on Click |on/off |on |if enabled, opens up a window +when a user clicks on one of the nodes/relationships in the +visualization. The window contains the label and properties of the +node/relationship. + +|Fix node positions after drag |on/off |on |If enabled, locks in +(freezes) the node positions after a user drags them. + +|Drilldown Link |Text (URL) |(no value) |Specifying a URL here will +display a floating button on the top right of the visualization. This +button can be used to drilldown into a different tool (e.g. Bloom) so +that the graph can be explored further. Dynamic Dashboard Parameters +(e.g. $neodash_person_name) can be used in these links as well. + +|Hide Selections |on/off |off |If enabled, hides the property selector +(footer of the visualization). + +|Auto-run query |on/off |on |when activated automatically runs the query +when the report is displayed. When set to `off', the query is displayed +and will need to be executed manually. +|=== + +== Rule-Based Styling + +Using the link:Reports#rule-based-styling[Rule-Based Styling] menu, the +following style rules can be applied to the graph: + +- The background color of a node. +- The label color of a node. diff --git a/docs/Home.adoc b/docs/Home.adoc new file mode 100644 index 000000000..845c70d87 --- /dev/null +++ b/docs/Home.adoc @@ -0,0 +1,67 @@ += NeoDash - Neo4j Dashboard Builder +:imagesdir: https://s3.amazonaws.com/dev.assets.neo4j.com/wp-content/uploads +:slug: neodash +:author: Niels de Jong +:category: labs +:tags: visualization, dashboard +:neo4j-versions: 3.5, 4.0, 4.1, 4.2, 4.3, 4.4 +:page-pagination: +:page-product: NeoDash + +image::https://raw.githubusercontent.com/nielsdejong/neodash/16cab52f96ed234042b11e1e5c87cba6d4a0e3a5/public/screenshot.png[width=800] + + + +NeoDash is an open-source, low-code Dashboard Builder for Neo4j. It lets you build an interactive dashboard with tables, graphs, bar charts, line charts, maps and more, in minutes. + +== Availability & Installation + +- Web Browser: https://neodash.graphapp.io +- Neo4j Desktop: Install it from the https://install.graphapp.io[Graph App Gallery]. +- Docker: https://hub.docker.com/r/nielsdejong/neodash + +== Functionality Includes +- A low-code dashboard builder with a drag-and-drop interface +- Create visualizations directly from Cypher +- The ability to add customization and interactivity to dashboards +- Build and publish dashboards for read-only access + +== Documentation +* To start building dashboards, see the link:./User-Guide[User Guide]. +* For deploying, configuring and extending NeoDash, check out the +link:./Developer-Guide[Developer Guide]. + +== Relevant Links + +[cols="1,4"] +|=== +| icon:comments[] Support | https://community.neo4j.com/c/neo4j-graph-platform/visualization/17[Neo4j Online Community] +| icon:user[] Authors | https://github.com/nielsdejong[Niels de Jong], https://github.com/mariusconjeaud[Marius Conjeaud], https://github.com/BennuFire[Harold Agudelo Ramirez], https://github.com/AleSim94[Aleksandar Simeunovic] +| icon:gift[] Releases | https://github.com/nielsdejong/neodash/releases +| icon:github[] Source | https://github.com/nielsdejong/neodash +| icon:book[] Docs | https://github.com/nielsdejong/neodash/wiki +| icon:gift[] Graph App | Install from your Neo4j Desktop via https://install.graphapp.io +// | icon:book[] Article | +// | icon:play-circle[] Example | +|=== + + + +== Recent Articles + + +- https://www.youtube.com/watch?v=Ygzj0Y4cYm4[NeoDash 2.0 in +Five Minutes] +- https://www.youtube.com/watch?v=vjZ9M7JpExA[NeoDash 2.0 Hands On at Neo4j Live] +- https://medium.com/p/ddc938ff82fa[Investigating Supply Chains with +NeoDash] +- https://thatdavestevens.medium.com/social-recommendations-slack-neo4j-and-neodash-fe916588e65b[Social +Recommendations with Neo4j & NeoDash] +- https://neo4j.com/developer-blog/bitcoin-transactions-dashboard-neo4j-neodash/[Real-Time +Dashboard of Bitcoin Transactions With Neo4j and NeoDash] +- https://medium.com/@a.emrevarol/european-natural-gas-network-via-knowledge-graph-3c3decb5f2ec[European +Natural Gas Pipelines] +- http://blog.bruggen.com/2020/11/exporting-spotify-playlists-into-neo4j.html[Exporting Spotify Playlists into Neo4j] +- https://nielsdejong.nl/neo4j%20projects/2021/12/14/neodash-2.0-a-brand-new-way-of-visualizing-neo4j-data.html[NeoDash 2.0 Release Overview] +- https://nielsdejong.nl/neo4j%20projects/2021/06/06/neodash-1.1-extensible-interactive-dashboards.html[NeoDash 1.1 Release Overview] +- https://nielsdejong.nl/neo4j%20projects/2020/11/16/neodash[NeoDash 1.0 Release Overview] \ No newline at end of file diff --git a/docs/Line-Chart.adoc b/docs/Line-Chart.adoc new file mode 100644 index 000000000..91452552a --- /dev/null +++ b/docs/Line-Chart.adoc @@ -0,0 +1,124 @@ +A line chart can be used to draw one or more lines in a two-dimensional +plane. It requires two numeric fields: + +* *X-value*: a numeric field. These will be the values used as an +X-coordinate. +* *Y-Value*: a numeric field. These will be the values used as an +Y-coordinate. + +Always ensure that the X-value are sorted in ascending order. If not, +the chart will not be displayed correctly. + +The line chart supports plotting both simple numbers and time values on +the x-axis. If you select a Neo4j datetime property on the x-axis, the +chart will automatically be drawn as a time series. + +== Examples + +=== Basic Line Chart (Actors born by decade) + +.... +MATCH (p:Person) +RETURN (p.born/10)*10 as Decade, COUNT(p) as People +ORDER BY Decade ASC +.... + +image::./img/line1.png[Basic Line Chart] + +=== Multi-Line Chart (Actors born & movies released by decade) + +.... +MATCH (p:Person) +WITH (p.born/10)*10 as Decade, COUNT(p) as People +ORDER BY Decade ASC +MATCH (m:Movie) +WHERE (m.released/10)*10 = Decade +RETURN Decade, People, COUNT(DISTINCT m) as Movies +.... + +image::./img/line2.png[Multi Line Chart] + +== Advanced Settings + +[width="100%",cols="13%,2%,6%,79%",options="header",] +|=== +|Name |Type |Default Value |Description +|Show Legend |on/off |off |If enabled, shows a legend at the top right +of the visualization. + +|Color Scheme |List |neodash |The color scheme to use for the lines. +Colors are assigned automatically to the different fields selected in +the report footer. + +|X Scale |List |linear |How to scale the values on the x-axis. Can be +either linear or logarithmic. + +|Y Scale |List |linear |How to scale the values on the y-axis. Can be +either linear or logarithmic. + +|Min X Value |Number |auto |If not set to ``auto'', this variable is the +minimum value on the x-axis. + +|Max X Value |Number |auto |If not set to ``auto'', this variable is the +maximum value on the x-axis. + +|Min Y Value |Number |auto |If not set to ``auto'', this variable is the +minimum value on the y-axis. + +|Max Y Value |Number |auto |If not set to ``auto'', this variable is the +maximum value on the y-axis. + +|X-axis Tick Count |Number |auto |If not set to ``auto'', the number of +ticks to be made on the x-axis. This is an approximate number that the +visualization tries to adhere to (numeric X-axis only) + +|X-axis Format (Time chart) |Text |%Y-%m-%dT%H:%M:%SZ |When using a time +chart, this setting lets you override how time values are rendered on +the x-axis. This uses the ISO 8601 time notations. + +|X-axis Tick Size (Time chart) |Text |every 1 year |When using a time +chart, this setting helps you set the frequency of ticks. The text +format should look like this: +`"every [number] ['years', 'months', 'weeks', 'days', 'hours', 'seconds', 'milliseconds']"`. + +|Line Smoothing |List |linear |Determines how the lines in the chart are +smoothened. One of linear (no smoothing), basis (interpolating), +cardinal (through each point) and step (step-based interpolation). + +|Show Grid |on/off |on |If enabled, shows a grid in the line chart that +intersects at the axis ticks. + +|Point Radius (px) |number |10 |The size of a point on each line. + +|Line Width (px) |number |2 |The width (in pixels) of each line in the +chart. + +|Margin Left (px) |number |50 |The margin in pixels on the left side of +the visualization. + +|Margin Right (px) |number |24 |The margin in pixels on the right side +of the visualization. + +|Margin Top (px) |number |24 |The margin in pixels on the top side of +the visualization. + +|Margin Bottom (px) |number |40 |The margin in pixels on the bottom side +of the visualization. + +|Legend Width (px) |number |128 |The width in pixels of each legend +label on top of the visualization (if enabled). + +|Hide Property Selection |on/off |off |If enabled, hides the property +selector (footer of the visualization). + +|Auto-run query |on/off |on |when activated automatically runs the query +when the report is displayed. When set to `off', the query is displayed +and will need to be executed manually. +|=== + +== Rule-Based Styling + +Using the link:Reports#rule-based-styling[Rule-Based Styling] menu, the +following style rules can be applied to the line chart: + +- The color of the line. diff --git a/docs/Map.adoc b/docs/Map.adoc new file mode 100644 index 000000000..03618892f --- /dev/null +++ b/docs/Map.adoc @@ -0,0 +1,102 @@ +The map report will render all returned nodes, relationships and paths +on a geomap. https://www.openstreetmap.org[Open Street Map] is used to +visualize the data on the map. + +Map visualizations work best with +https://neo4j.com/docs/cypher-manual/current/syntax/spatial/#cypher-spatial-specifying-spatial-instants[Neo4j +Spatial Data]. Make sure that the nodes in your database have their +locations stored as a spatial property. + +Customizations are available to change several parts of the +visualization, including the label for each node as well as the colors +and sizes of the markers/lines. + +== Examples + +=== Nodes on a map + +____ +Note that the nodes returned here have +https://neo4j.com/docs/cypher-manual/current/syntax/spatial/[spatial] +properties on them, so they can be visualized on a map. +____ + +.... +MATCH (b:Brewery) +RETURN b +.... + +image::./img/map.png[Basic Map] + +=== Nodes and relationships on a map + +.... +MATCH (b:Brewery)-[e]->(b2:Brewery) +RETURN b, e, b2 +.... + +image::./img/map2.png[Relationships on a Map] + +=== Artificial map data + +By returning a dictionary instead of a node directly, you can work +around the visualization expecting nodes and relationships directly. + +.... +MATCH (l1:Location)<--(a:Person), + (a:Person)-[:KNOWS]-(b:Person), + (b:Person)-->(l2:Location) +RETURN {id: a.name, label: "Person", point: l1.point}, + {id: b.name, label: "Person", point: l2.point}, + {start: a.name, end: b.name, type: "KNOWS", id: 1} +.... + +image::./img/map3.png[Artificial Map Data] + +== Advanced Settings + +[width="100%",cols="19%,17%,26%,38%",options="header",] +|=== +|Name |Type |Default Value |Description +|Node Color Scheme |List |neodash |The color scheme to use for the node +labels. Colors are assigned automatically (consequitevely) to the +different labels returned by the Cypher query. + +|Node Marker Size |List |large |The size of the markers for the nodes on +the map. One of [small, medium, large]. + +|Node Color Property |Text |color |Optionally, the name of the node +property to map to the node color. This lets you define colors on a +node-specific level, if you have a property that directly maps to the +HTML color value. + +|Relationship Color |Text |#a0a0a0 |The color used for drawing the +relationships on the map. + +|Relationship Width |Text |1 |The (default) width of the relationships +on the map. + +|Relationship Color Property |Text |color |Optionally, the name of the +relationship property to map to the relationship color. This lets you +define colors on a relationship-specific level, if you have a property +that directly maps to the HTML color value. + +|Relationship Width Property |Text |width |Optionally, the name of the +relationship property to map to the arrow width. This lets you define +widths on a relationship-specific level, if you have a property that +directly maps to the width value. + +|Hide Property Selection |on/off |off |If enabled, hides the property +selector (footer of the visualization). + +|Auto-run query |on/off |on |when activated automatically runs the query +when the report is displayed. When set to `off', the query is displayed +and will need to be executed manually. +|=== + +== Rule-Based Styling + +Using the link:Reports#rule-based-styling[Rule-Based Styling] menu, the +following style rules can be applied to the map: + +- The color of a node marker. diff --git a/docs/Markdown.adoc b/docs/Markdown.adoc new file mode 100644 index 000000000..a3a96db2f --- /dev/null +++ b/docs/Markdown.adoc @@ -0,0 +1,30 @@ +Markdown reports let you specify +https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#styling-text[Markdown] +text, to be renderer as rich HTML. This lets you turn your dashboards +into a storybook with textual descriptions, hyperlinks, images and +videos. + +== Examples + +=== Basic Markdown + +.... +## Hello there! +I'm a **Markdown** file. + +Check out this cool image: + +![image](https://hips.hearstapps.com/hmg-prod.s3.amazonaws.com/images/how-to-keep-ducks-call-ducks-1615457181.jpg?resize=240:*) +.... + +image::./img/markdown.png[Basic Markdown] + +== Advanced Settings + +[width="100%",cols="19%,17%,26%,38%",options="header",] +|=== +|Name |Type |Default Value |Description +|Replace global parameters in Markdown |on/off |on |If enabled, replaces +all instances of query parameters (e.g. $neodash_person_name) inside the +markdown source. +|=== diff --git a/docs/Pages.adoc b/docs/Pages.adoc new file mode 100644 index 000000000..ede738c5e --- /dev/null +++ b/docs/Pages.adoc @@ -0,0 +1,17 @@ +A page is a collection of link:Reports[reports] that can be viewed at +the same time. Each page can have an unlimited number of reports in it, +and will switch to a scrollable view when the number of reports do not +fit in the user’s window. + +An example of a dashboard with 4 pages can be seen below: + +image::img/page.png[Page] + +A dashboard may have as many pages as required by the dashboard builder. +To switch pages, simply click on the page title in the dashboard header. + +== Editing Pages + +Pages can be added, renamed, and deleted by using the buttons in the +dashboard header (if editing is enabled). Pages can additionally be +*re-ordered* by dragging and dropping them in the header. diff --git a/docs/Parameter-Select.adoc b/docs/Parameter-Select.adoc new file mode 100644 index 000000000..7ac494d25 --- /dev/null +++ b/docs/Parameter-Select.adoc @@ -0,0 +1,52 @@ +Parameter select reports provide you with an easy way to add +interactivity into your dashboards. + +Simply put, a parameter select report lets users set a Neo4j query +parameter (e.g. *$neodash_person_name*) dynamically. This means that +your reports can be created to show different data depending on the +value of a parameter. + +There are three types of parameter select reports: + +- Node property-based selections +- Relationship property-based selections +- Free text selections + +The first two are straightforward for users to understand, as the list +of choices is auto-populated from Neo4j. The third is a bit more +complex, as it allows users to enter any text value, but, it gives them +the complete freedom to enter any value they want. + +== Examples + +== Node Property Select + +image::./img/select.png[Node Property Select] + +== Relationship Property Select + +image::./img/select2.png[Relationship Property Select] + +== Free Text Select + +image::./img/select3.png[Free Text Select] + +== Advanced Settings + +[width="100%",cols="19%,17%,26%,38%",options="header",] +|=== +|Name |Type |Default Value |Description +|Clear Parameter on Field Reset |on/off |off |If enabled, removes the +global parameter completely when the field is cleared. This may break +some visualizations. If disabled, sets the parameter value to “” (empty +string) when the input field is cleared. + +|Enable Manual Label/Property Name Specification |on/off |off |If +enabled, does not enforce you to select a node label/property using an +auto-complete field, instead, you can enter any value. This is useful +for large datasets where the autocomplete field is too slow to render. + +|Helper Text (Override) |Text |(none) |Text to show above the user input +field. This will override the autogenerated text from the +node/relationship property pair. +|=== diff --git a/docs/Pie-Chart.adoc b/docs/Pie-Chart.adoc new file mode 100644 index 000000000..9c96fd109 --- /dev/null +++ b/docs/Pie-Chart.adoc @@ -0,0 +1,96 @@ +A pie chart will draw categories and values in a circular disc layout. +The pie chart will require you to choose the following selections: + +* *Category*: a text field. These will be the labels on the pie slices. +* *Value*: a numeric field. This will be the size of the slices. + +The pie chart can be additionally be customized to become a donut chart, +show categories as a legend, and to show the percentage of the total +value of the pie. See *Advanced Settings* for more information. + +== Examples + +=== Basic Pie Chart + +[source,cypher] +---- +Match (n:Person)-[e]->(m:Movie) +RETURN m.title as Title, COUNT(p) as People +LIMIT 8 +---- + +image::./img/pie.png[Pie Chart] + +=== Donut Chart + +[source,cypher] +---- +MATCH (p:Person)-[e]->(m:Movie) +WHERE m.title = "Cloud Atlas" +WITH TYPE(e) as Role +RETURN Role, COUNT(Role) as Count +---- + +image::./img/piedonut.png[Donut Chart] + +== Advanced Settings + +[width="100%",cols="15%,2%,6%,77%",options="header",] +|=== +|Name |Type |Default Value |Description +|Show Legend |on/off |off |If enabled, shows a legend on the bottom of +the visualization. + +|Auto-sort slices by value |on/off |off |If enabled, automatically sorts +the pie slices in order of size. + +|Show Values in Slices |on/off |off |If enabled, show the category +values inside the pie slices. + +|Show categories next to Slices |on/off |off |If enabled, show the +category values next to the pie slices. + +|Enable interactivity |on/off |on |If enabled, turn on animations when a +user hovers over a pie slice. + +|Color Scheme |List | |The color scheme to use for the slices. Colors +are assigned automatically (consequitevely) to the different categories +returned by the Cypher query. + +|Pie inner radius |Number |0 |The radius of the ``donut hole'' inside +the pie. When set to zero, no hole is present, when set to 0.99, the pie +will be almost completely visualized as a thin disc. + +|Slice padding angle (degrees) |number |0 |the angle between each pie +slice reserved for white space. For example, when set to 3.6, there will +be 1/100th of the total circle space reserved between each slice. + +|Slice border with (px) |number |0 |The width of the border of each +slice. + +|Margin Left (px) |number |50 |The margin in pixels on the left side of +the visualization. + +|Margin Right (px) |number |24 |The margin in pixels on the right side +of the visualization. + +|Margin Top (px) |number |24 |The margin in pixels on the top side of +the visualization. + +|Margin Bottom (px) |number |40 |The margin in pixels on the bottom side +of the visualization. + +|Hide Selections |on/off |off |If enabled, hides the property selector +(footer of the visualization). + +|Auto-run query |on/off |on |when activated automatically runs the query +when the report is displayed. When set to `off', the query is displayed +and will need to be executed manually. +|=== + +== Rule-Based Styling + +Using the link:Reports#rule-based-styling[Rule-Based Styling] menu, the +following style rules can be applied to the pie chart: + +- The background color of a pie slice. diff --git a/docs/Publishing.adoc b/docs/Publishing.adoc new file mode 100644 index 000000000..25b05535b --- /dev/null +++ b/docs/Publishing.adoc @@ -0,0 +1,36 @@ +When you are done building a dashboard, you may want to *publish* that +dashboard for others to view. The workflow for a continuous dashboarding +cycle may look something like this: + +image::./img/publish.png[Workflow] + +Keep in mind that the purpose of an application in the `View' phase is +very different from the `Build' phase: + +1. A dashboard cannot be edited +after it has been published. +2. A fixed dashboard must be loaded and a fixed database must be connected to. +3. Users in the `View' phase should not see the Cypher queries configuration powering the visualizations. + +== Architecture + +NeoDash enables the Build, Publish, View workflow by having two seperate +deployments of the NeoDash application: + +1. An `editor` deployment for the build phase. +2. A `viewer` deployment for the view phase. + +The *editor* deployment is the app you are using from Neo4j Desktop, +from https://neodash.graphapp.io, or from your own deployment. + +The *viewer* deployment will require some configuration to be set up. +These three configurations must be set for NeoDash to be able to run in +`View' mode: + +1. A flag telling the app to disable all editing features. +2. A hardcoded Neo4j database to connect to. +3. A hardcoded dashboard to load. + +Technical details on setting this up are documented in the link:Standalone%20Mode[Standalone +Mode] page. If you need help setting this up, please reach out to the +mailto:niels.dejong@neo4j.com[Neo4j Team]. diff --git a/docs/Quickstart.adoc b/docs/Quickstart.adoc new file mode 100644 index 000000000..1f4d07048 --- /dev/null +++ b/docs/Quickstart.adoc @@ -0,0 +1,28 @@ +There are four ways to run NeoDash and start dashboarding your Neo4j +data: + +[arabic] +. The latest version is always available online: +https://neodash.graphapp.io. +. Neo4j Desktop: Install it from the https://install.graphapp.io[Graph +App Gallery]. +. Using Docker: +`docker pull nielsdejong/neodash:latest docker run -it --rm -p 5005:5005 nielsdejong/neodash` +. Build it yourself: +`git clone https://github.com/nielsdejong/neodash npm install npm run dev` + +NeoDash connects to any recent version of the Neo4j database. (Neo4j 4.0 +or later). The quickest way to get started is to create a free cloud +database on https://neo4j.io[Neo4j Aura]. + +To get started with building your own dashboard, see the Dashboards +page. + +== NeoDash in Five Minutes + +The video below explains how to get started with NeoDash in 5 minutes: +https://www.youtube.com/watch?v=Ygzj0Y4cYm4[image:https://img.youtube.com/vi/Ygzj0Y4cYm4/0.jpg[Youtube +Video]] + +See also the link:./FAQ#1-how-can-i-learn-more-about-neodash[list of +blog posts] in the FAQ. diff --git a/docs/Raw-JSON.adoc b/docs/Raw-JSON.adoc new file mode 100644 index 000000000..bbfbb7963 --- /dev/null +++ b/docs/Raw-JSON.adoc @@ -0,0 +1,24 @@ +The Raw JSON report renders the JSON response received from Neo4j +directly. This is typically used for debugging queries, or, +understanding the exact data types being returned from Neo4j. + +== Examples + +=== Raw JSON + +.... +MATCH (n) +RETURN COUNT(n) +.... + +image::./img/json.png[Basic Value] + +== Advanced Settings + +[width="100%",cols="19%,17%,26%,38%",options="header",] +|=== +|Name |Type |Default Value |Description +|Auto-run query |on/off |on |when activated automatically runs the query +when the report is displayed. When set to `off', the query is displayed +and will need to be executed manually. +|=== diff --git a/docs/Reports.adoc b/docs/Reports.adoc new file mode 100644 index 000000000..062d456fa --- /dev/null +++ b/docs/Reports.adoc @@ -0,0 +1,118 @@ +A report is the smallest building build of your dashboard. Each report +will have a single Cypher query behind it that is used to populate the +report. Reports can be of several types (graph, table, bar chart, etc.), +each of which expect different types of data. See the relevant +documentation pages for more information. + +A report can be given a title, which will be displayed in the dashboard +header. To change the query of a report, open the settings by clicking +the (⋮) icon on the top right of the report. + +image::./img/report.gif[Report] + +The settings window additionally allows you to change the type of +report, the refresh rate of the report, and a number of *Advanced +Settings*. The advanced settings differ between the different report +types, and can be viewed by toggling the switch on the bottom left of +the settings page. + +== Create and Delete Reports + +A new report can be added to a page by clicking the large (+) button at +the end of the page. By default, a report will have nothing defined, so +you will need to set the query before any data is visualized. + +Reports can be deleted by opening the report settings, and clicking the +🗑️ icon in the report header. + +== Re-order Reports + +As of NeoDash 2.1, reports can be re-ordered by dragging and dropping +them around the page. To move a report, grab it by the handle (top left +corner), and drag it to the desired location. + +image::./img/movereport.gif[Report] + +== Resize Reports + +As of NeoDash 2.1, reports can be resized by grabbing their bottom-right +corner, and dragging your mouse to the desired size. + +image::./img/resizereport.gif[Report] + +== Writing Queries + +A single Cypher query is used to populate each report. As any Cypher +syntax is supported, this includes +https://neo4j.com/developer/neo4j-apoc/[APOC], +https://neo4j.com/docs/graph-data-science/current/[GDS], and even +https://neo4j.com/docs/operations-manual/current/fabric/queries/[Fabric]! + +Keep the following best practises in mind when writing your Cypher +queries: + +1. Always use a `LIMIT` in your query to keep the result size +manageable. +2. Ensure you return the right data types for the right +report type. For example, a graph report expects nodes and +relationships, whereas a line chart expects numbers. + +== Row Limiting + +NeoDash has a built-in post-query *row limiter*. This means that results +are truncated to a maximum number of rows, depending on the report type. +The row limiter is in place to ensure that visualizations do not become +too complex for the browser to handle. + +Note that even though the row limiter is enabled by default, rows are +only limited after the query is executed. For this reason, it is +recommended to use the `LIMIT` clause in your query at all times. + +== Rule-Based Styling + +On several report types, rule-based styling can be applied to the +visualization. To do this, open up the report settings, Then, click the +*Rule-Based Styling* button on the bottom right (marked with the red +circle): + +image::./img/rulebasedstylingbutton.png[Report] + +This will open up the rule definition window. Inside this screen, a list +of rules can be defined. Each rule will have the following structure: + +`IF [CONDITION] THEN [STYLE]` + +image::./img/rulebasedstyling.png[Report] + +Conditions are always based on one of the return fields of the query. +This can be a simple field (text, number) or a node property. Style +rules are (as of NeoDash 2.1) always color-based. + +For example, the following rule will set the color of all `Warning` +nodes to red: + +`IF Warning.level = "critical" THEN 'Node Color' = "red"` + +Ultimately, it is important to understand that the order of the rules is +important. If a node matches multiple rules, the first rule that matches +will be used. If no rules are matched, the default style will be used. + +== Report Types + +To learn more about a specific report type, see one of the following +pages: + +- link:Table[Table] +- link:Graph[Graph] +- link:Bar%20Chart[Bar Chart] +- link:Pie%20Chart[Pie Chart] +- link:Line%20Chart[Line Chart] +- link:Sunburst[Sunburst] +- link:Circle%20Packing[Circle Packing] +- link:Treemap[Treemap] +- link:Map[Map] +- link:Single%20Value[Single Value] +- link:Raw%20JSON[Raw JSON] +- link:Parameter%20Select[Parameter Select] +- link:iFrame[iFrame] +- link:Markdown[Markdown] diff --git a/docs/Single-Value.adoc b/docs/Single-Value.adoc new file mode 100644 index 000000000..a8a585219 --- /dev/null +++ b/docs/Single-Value.adoc @@ -0,0 +1,54 @@ +A single value report will render the first column of the first row +returned by the Cypher query. Single value reports are typically used +for key metrics: + +- The total number of nodes +- The total number of data integrity violations +- The name of a node or relationship that is standing out in the data. + +== Examples + +=== Number value + +.... +MATCH (n) +RETURN COUNT(n) +.... + +image::./img/value.png[Basic Value] + +=== Text value with custom styling + +.... +// Who's the biggest Fraudster? +MATCH (n:Person)-[:CREATED]->(t:Transaction{fraud:true}) +RETURN n.name, COUNT(t) +ORDER BY COUNT(t) DESC +.... + +image::./img/value2.png[Styled Value] + +== Advanced Settings + +[width="100%",cols="10%,3%,9%,78%",options="header",] +|=== +|Name |Type |Default Value |Description +|Font Size |Number |64 |The font size of the value text. + +|Color |Text |rgba(0, 0, 0, 0.87) |The HTML color value of the text. + +|Horizontal Align |List |left |The horizontal alignment of the text. + +|Vertical Align |List |top |The vertical alignment of the text. + +|Auto-run query |on/off |on |when activated automatically runs the query +when the report is displayed. When set to `off', the query is displayed +and will need to be executed manually. +|=== + +== Rule-Based Styling + +Using the link:Reports#rule-based-styling[Rule-Based Styling] menu, the +following style rules can be applied to the map: + +- The color of the text. diff --git a/docs/Standalone-Mode.adoc b/docs/Standalone-Mode.adoc new file mode 100644 index 000000000..50444ae3b --- /dev/null +++ b/docs/Standalone-Mode.adoc @@ -0,0 +1,57 @@ +Next to being a dashboard editor, NeoDash can be deployed in a +`standalone mode' - allowing you set up a architecture to publish and +read dashboards. + +Running in standalone modec mode will: + +- Disable all editing options +- Have a hardcoded Neo4j URL and database name +- Load a dashboard from Neo4j with a fixed name. + +The diagram below illustrates how NeoDash standalone mode can be +deployed next to a standard `Editor Mode' instance: + +image:./img/standalone-architecture.png[image] + +== Option 1 - Standard Deployment (Non-Docker) + +First, build NeoDash as described link:Run%20&%20Build[here]. After +building, you’ll have a `dist` directory that you can deploy to a web +server. + +To configure the app to run in standalone mode, you’ll need to edit +`dist/config.json` and change the `standalone` property to `true`. The +other variables inside `config.json` should also be configured to match +the hostname, port and database name of your Neo4j instance. See +Configuration for more on configuration variables. + +As `config.json` gets picked up at runtime by the application, users +viewing the application will now access the dashboard in standalone +mode. + +== Option 2 - Docker Deployment + +You can configure the app to run in standalone by passing environment +variables to Docker: + +.... +docker run -it --rm -p 5005:5005 \ + -e ssoEnabled=false \ + -e ssoDiscoveryUrl="https://example.com" \ + -e standalone=true \ + -e standaloneProtocol="neo4j" \ + -e standaloneHost="localhost" \ + -e standalonePort="7687" \ + -e standaloneDatabase="neo4j" \ + -e standaloneDashboardName="My Dashboard" \ + -e standaloneDashboardDatabase="dashboards" \ + nielsdejong/neodash +.... + +Make sure that all of the environment variables are set to the correct +values. This is described in more detail link:Configuration[here]. + +____ +Alternatively, environment variables from docker compose or a kubernetes +deployment can be used. +____ diff --git a/docs/State Management.adoc b/docs/State Management.adoc new file mode 100644 index 000000000..bbfd26601 --- /dev/null +++ b/docs/State Management.adoc @@ -0,0 +1,137 @@ +NeoDash is an application with a complex internal state. If you are +planning to extend the application state in some way, make sure you are +familiar with https://redux.js.org/[Redux] design patterns. + +The app’s entire state object is encapsulated in the following JSON +structure: + +.... +{ + "dashboard": { + "title": "My Dashboard Name", + "version": "2.1", + "settings": { + "pagenumber": 0, + "editable": true, + ... + "parameters": { + ... + } + }, + "pages": [ + ... + ] + }, + "application": { + ... + }, + "version": "2.1.0" +} +.... + +At the highest level, this object consists of three entries: + +- `dashboard`: all state related to the currently active dashboard. This +is changed when a dashboard gets loaded, modified or removed. +- `application`: all state related to the application itself. This +describes which windows are open, what database you are connected to, +etc. +- `version`: the version of NeoDash that is running. Note that +these are complete version numbers (of the shape X.Y.Z), unlike +dashboard versions, which have a different versioning scheme. + +____ +Want to see the complete state object for your application? Generate a +*Debug Report* from the About window. +____ + +== Dashboard State + +The dashboard entry contains the entire state of the currently loaded +dashboard. Take the following simple dashboard as an example. + +.... +{ + "dashboard": { + "title": "A Simple Dashboard", + "version": "2.1", + "settings": { + "pagenumber": 0, + "editable": true, + "fullscreenEnabled": true, + "parameters": { + "neodash_person_name": "Bob" + } + }, + "pages": [ + { + title: “My Page” + reports: [ + { + "title": "My Report", + "query": "MATCH (n)-[e]->(m) RETURN n,e,m", + "type": "graph", + "x": "1", + "y": "2", + "width": "6", + "height": "3", + "settings": { + "nodeColorSchmeme": "blue" + } + } + ] + } + ] + } +} +.... + +Key entries of the object are: + +- `title`: the title of the dashboard. This is displayed on the top of the window. +- `version`: _Main_ version of the dashboard that is loaded. +- `settings`: contains settings for the dashboard. This includes the current page number, whether the dashboard +is editable, whether the dashboard is in fullscreen mode, and the +dashboard parameters that are currently set. +- `pages`: contains the list of all pages in the dashboard. Each page has a title and a list of +reports. + +== Application State + +The application state is a flat dictionary of values that determine what +the user’s window looks like (which windows are open?) as well as the +current database connection, and whether the app is running in +standalone mode. + +.... +"application": { + "notificationTitle": null, + "notificationMessage": null, + "connectionModalOpen": false, + "welcomeScreenOpen": true, + "aboutModalOpen": true, + "connection": { + "protocol": "neo4j+s", + "url": "localhost", + "port": "", + "database": "", + "username": "neo4j", + "password": "************" + }, + "desktopConnection": null, + "connected": false, + "dashboardToLoadAfterConnecting": null, + "waitForSSO": false, + "standalone": false, + "oldDashboard": null, + "ssoEnabled": false, + "ssoDiscoveryUrl": "https://example.com", + "standaloneProtocol": "neo4j", + "standaloneHost": "localhost", + "standalonePort": "7687", + "standaloneDatabase": "neo4j", + "standaloneDashboardName": "My Dashboard", + "standaloneDashboardDatabase": "dashboards", + "notificationIsDismissable": null +} +.... diff --git a/docs/Sunburst.adoc b/docs/Sunburst.adoc new file mode 100644 index 000000000..0da4151c3 --- /dev/null +++ b/docs/Sunburst.adoc @@ -0,0 +1,59 @@ +A sunburst chart will render hierarchical data in a multi-level pie +visualization. It takes two fields: + +- *Path*: a list of strings. This represents the hierarchy (from highest to lowest level). +- *Value*: a number that matches the size of the element at the lowest level. Sizes of non-leaf levels are determined from the sum of their children. + +== Examples + +=== Basic Sunburst Chart + +[source,cypher] +---- +MATCH path=(:Company{name:'NeoDash'})-[:HAS_DEPARTMENT*]->(:Department) +WITH nodes(path) as no +WITH no, last(no) as leaf +WITH [n IN no[..-1] | n.name] AS result, sum(leaf.employees) as val +RETURN result, val +---- + +image::./img/sunburst.png[Sunburst Chart] + +== Advanced Settings + +[width="100%",cols="19%,2%,6%,73%",options="header",] +|=== +|Name |Type |Default Value |Description +|Show Values on Arcs |on/off |off |If enabled, show the category values +inside the sunburst arcs. + +|Enable interactivity |on/off |on |If enabled, turn on animations when a +user hovers over an arc. + +|Color Scheme |List | |The color scheme to use for the arcs. Colors are +assigned automatically for each of the sub-hierarchies. + +|Arc border width (px) |number |0 |The width of the border of each arc. + +|Margin Left (px) |number |24 |The margin in pixels on the left side of +the visualization. + +|Margin Right (px) |number |24 |The margin in pixels on the right side +of the visualization. + +|Margin Top (px) |number |24 |The margin in pixels on the top side of +the visualization. + +|Margin Bottom (px) |number |40 |The margin in pixels on the bottom side +of the visualization. + +|Minimum Arc Angle for Label (degrees) |number |10 |The minimum angle of +an arc needed to display a label (if labels are enabled). + +|Slice Corner Radius |number |3 |The rounding angle of each of the arcs +in the visualization. + +|Auto-run query |on/off |on |When activated, automatically runs the +query when the report is displayed. When set to `off', the query is +displayed and will need to be executed manually. +|=== diff --git a/docs/Table.adoc b/docs/Table.adoc new file mode 100644 index 000000000..720b29a0e --- /dev/null +++ b/docs/Table.adoc @@ -0,0 +1,63 @@ +The most common report in a dashboard is often a simple table view. +NeoDash contains a powerful table component that can render all the data +returned by a Cypher query. This includes simple data like numbers or +text, but also Neo4j native data like nodes, relationships, and paths. + +The table report supports the following additional features: + +- automatic pagination of results. +- Sorting/filtering by clicking on the table headers. +- Downloading your data as a CSV file. + +== Examples + +=== Basic Table + +.... +MATCH (n:Movie)<-[:ACTED_IN]-(p:Person) +RETURN n.title, n.released, count(p) as actors +.... + +image::./img/table1.png[Basic Table] + +=== Table with nodes / collections + +.... +MATCH (n:Movie)<-[:ACTED_IN]-(p:Person) +RETURN n, collect(p.name) as actors LIMIT 200 +.... + +image::./img/table2.png[Table with nodes / collections] + +== Advanced Settings + +[width="100%",cols="12%,6%,6%,76%",options="header",] +|=== +|Name |Type |Default Value |Description +|Transpose Rows & Columns |on/off |off |when activated, transposes the +rows and columns of the table. This means that each of the returned rows +from Neo4j will be shown as a column instead of a row. + +|Relative Column Sizes |List of numbers |[1, 1, 1, …] |The relative +width between each of the columns in the table. For example, if the +first column should be twice the width of the 2nd and 3rd, this will be +set to ``[2, 1, 1]''. + +|Enable CSV Download |on/off |off |when activated, displays a button on +the bottom right of the table footer. This button lets the user download +the complete set of table results (all pages) as a CSV file. + +|Auto-run query |on/off |on |when activated automatically runs the query +when the report is displayed. When set to `off', the query is displayed +and will need to be executed manually. +|=== + +== Rule-Based Styling + +Using the link:Reports#rule-based-styling[Rule-Based Styling] menu, the +following style rules can be applied to the table: + +- The background color of an entire row in a table. +- The text color of an entire row in a table. +- The background color of a single cell in the table. +- The text color of a single cell in the table. diff --git a/docs/Testing.adoc b/docs/Testing.adoc new file mode 100644 index 000000000..8ce269752 --- /dev/null +++ b/docs/Testing.adoc @@ -0,0 +1,34 @@ +NeoDash uses *Cypress* for automated testing. To install Cypress, check +out the official +https://docs.cypress.io/guides/getting-started/installing-cypress#What-you-ll-learn[installation +instructions]. + +After cypress is installed, you can use: + +.... +npm run test +.... + +To open the Cypress GUN. Alternatively, use: + +.... +npm run test-headless +.... + +To run Cypress from the UI. + +Before starting the tests, make sure you have a local instance of +NeoDash running at `http://localhost:3000` using `npm run dev`. + +image:./img/cypress.png[Cypress] Above: a screenshot of the Cypress GUI. + +== Debug Report + +For ad-hoc testing, a debug report can be generated by NeoDash. This +report contains a JSON representation of the current state of the +NeoDash application. + +To generate a debug report, open the `About' screen. Then, click the +'Debug Report' button in the bottom left corner. + +image::./img/about.png[About] diff --git a/docs/Treemap.adoc b/docs/Treemap.adoc new file mode 100644 index 000000000..8094bb974 --- /dev/null +++ b/docs/Treemap.adoc @@ -0,0 +1,51 @@ +A treemap chart will render hierarchical data in a nested rectangle +layout. It takes two fields: + +- *Path*: a list of strings. This represents the hierarchy (from highest to lowest level). +- *Value*: a number that matches the size of the element at the lowest level. Sizes of non-leaf levels are determined from the sum of their children. + +== Examples + +=== Basic Treemap + +[source,cypher] +---- +MATCH path=(:Company{name:'NeoDash'})-[:HAS_DEPARTMENT*]->(:Department) +WITH nodes(path) as no +WITH no, last(no) as leaf +WITH [n IN no[..-1] | n.name] AS result, sum(leaf.employees) as val +RETURN result, val +---- + +image::./img/treemap.png[Treemap Chart] + +== Advanced Settings + +[width="100%",cols="15%,2%,6%,77%",options="header",] +|=== +|Name |Type |Default Value |Description +|Enable interactivity |on/off |on |If enabled, turn on animations when a +user hovers over a rectangle. + +|Color Scheme |List | |The color scheme to use for the rectangle. Colors +are assigned automatically for each of the sub-hierarchies. + +|Rectangle border width (px) |number |0 |The width of the border of each +rectangle. + +|Margin Left (px) |number |24 |The margin in pixels on the left side of +the visualization. + +|Margin Right (px) |number |24 |The margin in pixels on the right side +of the visualization. + +|Margin Top (px) |number |24 |The margin in pixels on the top side of +the visualization. + +|Margin Bottom (px) |number |40 |The margin in pixels on the bottom side +of the visualization. + +|Auto-run query |on/off |on |When activated, automatically runs the +query when the report is displayed. When set to `off', the query is +displayed and will need to be executed manually. +|=== diff --git a/docs/User-Guide.adoc b/docs/User-Guide.adoc new file mode 100644 index 000000000..1389f15b8 --- /dev/null +++ b/docs/User-Guide.adoc @@ -0,0 +1,18 @@ +NeoDash is an open source tool for visualizing your Neo4j data. It lets +you group visualizations together as dashboards, and allow for +interactions between reports. The tool supports presenting your data as +tables, graphs, bar charts, line charts, maps and more. + +image::./img/dashboard.png[Dashboard] + +NeoDash contains a Cypher editor to directly write the Cypher queries +that populate the reports. You can save dashboards to your database, and +share them with others. + +* link:Quickstart[Quickstart] tells you how to get started with NeoDash right away. +* link:Dashboards[Dashboards] elaborates on how dashboards are created and used in +NeoDash. +* link:Pages[Pages] explains how to manage pages inside a dashboard. +* link:Reports[Reports] contains information on how a report works, and lists the +different types that can be used. +* link:Publishing[Publishing] explains how to publish a dashboard for others to view. diff --git a/docs/iFrame.adoc b/docs/iFrame.adoc new file mode 100644 index 000000000..1b8a1c916 --- /dev/null +++ b/docs/iFrame.adoc @@ -0,0 +1,36 @@ +An iFrame report lets you embed a webpage inside your NeoDash dashboard. +The page can be loaded from any web address starting with `http://` or +`https://`, with some exceptions*. + +____ +The webpage must not explicitly disallow itself to be embedded, such as +https://google.com. +____ + +To render iFrames interactively based on the dashboard state, your +global dashboard parameters can be passed into it dynamically. See the +*Advanced Settings* below for more information. + +== Examples + +=== Basic iFrame + +image::./img/iframe.png[Basic iFrame] + +=== Dynamic iFrame + +image::./img/iframe2.png[Dynamic iFrame] + +== Advanced Settings + +[width="100%",cols="19%,17%,26%,38%",options="header",] +|=== +|Name |Type |Default Value |Description +|Replace global parameters in URL |on/off |on |If enabled, replaces all +instances of query parameters (e.g. $neodash_person_name) inside the +iFrame URL. + +|Append global parameters to iFrame URL |on/off |off |If enabled, +appends the full list of global parameters as URL parameters to the +specified URL. +|=== diff --git a/docs/img/about.png b/docs/img/about.png new file mode 100644 index 000000000..5efc14e6c Binary files /dev/null and b/docs/img/about.png differ diff --git a/docs/img/bar.png b/docs/img/bar.png new file mode 100644 index 000000000..5cd6173ee Binary files /dev/null and b/docs/img/bar.png differ diff --git a/docs/img/barstacked.png b/docs/img/barstacked.png new file mode 100644 index 000000000..8b16b05d0 Binary files /dev/null and b/docs/img/barstacked.png differ diff --git a/docs/img/circlepacking.png b/docs/img/circlepacking.png new file mode 100644 index 000000000..c851fdc29 Binary files /dev/null and b/docs/img/circlepacking.png differ diff --git a/docs/img/component-hierarchy.png b/docs/img/component-hierarchy.png new file mode 100644 index 000000000..715001169 Binary files /dev/null and b/docs/img/component-hierarchy.png differ diff --git a/docs/img/cypress.png b/docs/img/cypress.png new file mode 100644 index 000000000..4cecf5fbd Binary files /dev/null and b/docs/img/cypress.png differ diff --git a/docs/img/dashboard.png b/docs/img/dashboard.png new file mode 100644 index 000000000..0ee4fe28d Binary files /dev/null and b/docs/img/dashboard.png differ diff --git a/docs/img/dashboard2.png b/docs/img/dashboard2.png new file mode 100644 index 000000000..3dfca5005 Binary files /dev/null and b/docs/img/dashboard2.png differ diff --git a/docs/img/dashboardsettings.png b/docs/img/dashboardsettings.png new file mode 100644 index 000000000..6c2fb90cc Binary files /dev/null and b/docs/img/dashboardsettings.png differ diff --git a/docs/img/graph.png b/docs/img/graph.png new file mode 100644 index 000000000..4eac01c05 Binary files /dev/null and b/docs/img/graph.png differ diff --git a/docs/img/graph2.png b/docs/img/graph2.png new file mode 100644 index 000000000..424013adb Binary files /dev/null and b/docs/img/graph2.png differ diff --git a/docs/img/graphdrilldown.png b/docs/img/graphdrilldown.png new file mode 100644 index 000000000..7d9cb55e9 Binary files /dev/null and b/docs/img/graphdrilldown.png differ diff --git a/docs/img/iframe.png b/docs/img/iframe.png new file mode 100644 index 000000000..6230099f3 Binary files /dev/null and b/docs/img/iframe.png differ diff --git a/docs/img/iframe2.png b/docs/img/iframe2.png new file mode 100644 index 000000000..c82983ce1 Binary files /dev/null and b/docs/img/iframe2.png differ diff --git a/docs/img/json.png b/docs/img/json.png new file mode 100644 index 000000000..5a9febd16 Binary files /dev/null and b/docs/img/json.png differ diff --git a/docs/img/line1.png b/docs/img/line1.png new file mode 100644 index 000000000..039d210ce Binary files /dev/null and b/docs/img/line1.png differ diff --git a/docs/img/line2.png b/docs/img/line2.png new file mode 100644 index 000000000..f96feaddd Binary files /dev/null and b/docs/img/line2.png differ diff --git a/docs/img/map.png b/docs/img/map.png new file mode 100644 index 000000000..e63496329 Binary files /dev/null and b/docs/img/map.png differ diff --git a/docs/img/map2.png b/docs/img/map2.png new file mode 100644 index 000000000..f1b5deb53 Binary files /dev/null and b/docs/img/map2.png differ diff --git a/docs/img/map3.png b/docs/img/map3.png new file mode 100644 index 000000000..08d445595 Binary files /dev/null and b/docs/img/map3.png differ diff --git a/docs/img/markdown.png b/docs/img/markdown.png new file mode 100644 index 000000000..6892344d3 Binary files /dev/null and b/docs/img/markdown.png differ diff --git a/docs/img/movereport.gif b/docs/img/movereport.gif new file mode 100644 index 000000000..2ef8e57d2 Binary files /dev/null and b/docs/img/movereport.gif differ diff --git a/docs/img/page.png b/docs/img/page.png new file mode 100644 index 000000000..c8efef564 Binary files /dev/null and b/docs/img/page.png differ diff --git a/docs/img/pie.png b/docs/img/pie.png new file mode 100644 index 000000000..88fc12378 Binary files /dev/null and b/docs/img/pie.png differ diff --git a/docs/img/piedonut.png b/docs/img/piedonut.png new file mode 100644 index 000000000..f70c93800 Binary files /dev/null and b/docs/img/piedonut.png differ diff --git a/docs/img/publish.png b/docs/img/publish.png new file mode 100644 index 000000000..b55287544 Binary files /dev/null and b/docs/img/publish.png differ diff --git a/docs/img/report.gif b/docs/img/report.gif new file mode 100644 index 000000000..e8a115139 Binary files /dev/null and b/docs/img/report.gif differ diff --git a/docs/img/resizereport.gif b/docs/img/resizereport.gif new file mode 100644 index 000000000..28aa60f7f Binary files /dev/null and b/docs/img/resizereport.gif differ diff --git a/docs/img/rulebasedstyling.png b/docs/img/rulebasedstyling.png new file mode 100644 index 000000000..ac7c2b985 Binary files /dev/null and b/docs/img/rulebasedstyling.png differ diff --git a/docs/img/rulebasedstylingbutton.png b/docs/img/rulebasedstylingbutton.png new file mode 100644 index 000000000..7760633c1 Binary files /dev/null and b/docs/img/rulebasedstylingbutton.png differ diff --git a/docs/img/saveloadshare.png b/docs/img/saveloadshare.png new file mode 100644 index 000000000..f1d9ae94e Binary files /dev/null and b/docs/img/saveloadshare.png differ diff --git a/docs/img/select.png b/docs/img/select.png new file mode 100644 index 000000000..4058676d6 Binary files /dev/null and b/docs/img/select.png differ diff --git a/docs/img/select2.png b/docs/img/select2.png new file mode 100644 index 000000000..c3fe467ea Binary files /dev/null and b/docs/img/select2.png differ diff --git a/docs/img/select3.png b/docs/img/select3.png new file mode 100644 index 000000000..0f7a7c427 Binary files /dev/null and b/docs/img/select3.png differ diff --git a/docs/img/standalone-architecture.png b/docs/img/standalone-architecture.png new file mode 100644 index 000000000..39edc7d1d Binary files /dev/null and b/docs/img/standalone-architecture.png differ diff --git a/docs/img/sunburst.png b/docs/img/sunburst.png new file mode 100644 index 000000000..4c3411699 Binary files /dev/null and b/docs/img/sunburst.png differ diff --git a/docs/img/table1.png b/docs/img/table1.png new file mode 100644 index 000000000..71bd1a67c Binary files /dev/null and b/docs/img/table1.png differ diff --git a/docs/img/table2.png b/docs/img/table2.png new file mode 100644 index 000000000..1570aa010 Binary files /dev/null and b/docs/img/table2.png differ diff --git a/docs/img/treemap.png b/docs/img/treemap.png new file mode 100644 index 000000000..b90da188a Binary files /dev/null and b/docs/img/treemap.png differ diff --git a/docs/img/value.png b/docs/img/value.png new file mode 100644 index 000000000..327e05051 Binary files /dev/null and b/docs/img/value.png differ diff --git a/docs/img/value2.png b/docs/img/value2.png new file mode 100644 index 000000000..2935d8a93 Binary files /dev/null and b/docs/img/value2.png differ diff --git a/docs/readme.adoc b/docs/readme.adoc deleted file mode 100644 index 390aa7231..000000000 --- a/docs/readme.adoc +++ /dev/null @@ -1 +0,0 @@ -Documentation is currently available at https://github.com/nielsdejong/neodash/wiki. \ No newline at end of file diff --git a/package.json b/package.json index 09d93596b..e70980d65 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "neodash", - "version": "2.1.1", + "version": "2.1.2", "description": "NeoDash - Neo4j Dashboard Builder", "neo4jDesktop": { "apiVersion": "^1.2.0" @@ -8,7 +8,7 @@ "main": "index.js", "repository": { "type": "git", - "url": "https://github.com/nielsdejong/neodash/" + "url": "https://github.com/neo4j-labs/neodash/" }, "license": "Apache-2.0", "icons": [ diff --git a/public/manifest.json b/public/manifest.json index 990f3c2b2..7fb738c08 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -1,7 +1,7 @@ { "short_name": "NeoDash", "name": "NeoDash", - "homepage": "https://github.com/nielsdejong/neodash/", + "homepage": "https://github.com/neo4j-labs/neodash/", "neo4jDesktop": { "apiVersion": "^1.2.0" }, diff --git a/public/style.css b/public/style.css index 155fd9747..0bb304213 100644 --- a/public/style.css +++ b/public/style.css @@ -84,8 +84,8 @@ } .react-grid-item>.react-resizable-handle::after { - border-right: 2px solid rgba(0, 0, 0, 0.1) !important; - border-bottom: 2px solid rgba(0, 0, 0, 0.1) !important; + border-right: 2px solid rgba(0, 0, 0, 0.4) !important; + border-bottom: 2px solid rgba(0, 0, 0, 0.4) !important; } /* .MuiDataGrid-columnHeaders { @@ -193,3 +193,7 @@ .not-animated .react-grid-item.cssTransforms { transition-property: none !important; } + +.react-grid-layout { + overflow: hidden; +} \ No newline at end of file diff --git a/release-notes.history.md b/release-notes.history.md new file mode 100644 index 000000000..a421ad52a --- /dev/null +++ b/release-notes.history.md @@ -0,0 +1,218 @@ +## NeoDash 2.1 +The 2.1 release is a major update to the NeoDash application. + +Main updates: +- Added new drag-and-drop dashboard layout - reports can be **moved** and **resized** freely within the dashboard. +- Updated dashboard file format for new layout (2.0 dashboards are automatically migrated). +- Pages can now be reordered by dragging and dropping. +- Added three new hierarchical report types: + - Treemaps + - Sunburst Charts + - Circle Packing Charts +- Styling/usability improvements for pie charts. +- Improved image download (screenshot functionality) for all report types. +- Parameter select reports now resize the selector to fit the available space. + +Other changes: +- Added continuous integration and deployment workflows. +- Created a new [User Guide](https://github.com/neo4j-labs/neodash/wiki/User-Guide) with documentation on all report customizations is available. +- Added a new [Developer Guide](https://github.com/neo4j-labs/neodash/wiki/Developer-Guide) with info on installing, building and extending the application. + + +## NeoDash 2.0.15 +This is the final minor update before the 2.1 release. + +Changes: +- Several stability improvements before the 2.1 release. +- Updated Dockerfile to make better use of caching, and pick up environment variables at run time. +- Added option to replace dashboard parameters in Markdown/iFrames to make them dynamic. +- Removed unneeded index column from the CSV download for tables. +- Added optional dashboard setting to enable image downloads for reports/the entire dashboard. + + +## NeoDash 2.0.14 +Report features: +- Added optional "Download as CSV" button to table reports. +- Dashboard parameters can now be used in iFrames/Graph drilldown links, and they are automatically replaced when parameters get updated. +- Updating a dashboard parameter now only refreshes the reports that use the parameter. + +Standalone mode: +- Enabled deploying standalone dashboards with a direct URL to the dashboard. +- Added functionality to deep link into a NeoDash dashboard with dashboard parameters (use ?neodash_variable_name=value in the URL). + + +Miscellaneous Bug fixes and improvements: +- Resolved crash caused by invalid geospatial properties in a Map visualization. +- Saving a dashboard now lets users override an existing dashboard with the same name (enabled by default). +- Increased the default row limits for line/bar/pie charts to 250. Added option to override the row limiter in the dashboard settings. +- Updated project README file to refer to the correct port number on Docker deployments. +- Enabled a configurable timeout for parameter selection reports, both a timeout for the suggestion retrieval and a timeout for updating the parameters. +- Fixed dependency issues when installing the application on Windows systems. Bumped suggested npm version to 8.6. + +## NeoDash 2.0.13 +This is a bug fix/minor usability update. + +Changes: +- Resolved error where the float value 0.0 was rendered as 'null' in tables. +- Added alphabetical sorting to all node/relationship inspection pop-ups & parameter select reports. +- Resolved bug where switching pages quickly resulting in an error message. +- Resolved bug where rule-based styling would break on null values. +- Replaced margin-based styling on single value reports with a vertical alignment option. + +## NeoDash 2.0.12 +Added **rule-based styling**: +- Use the card settings to specify styling rules for tables, graphs, bar/pie/line charts and single values. +- Conditional rules are evaluated on each report render in order of priority. +- Rules can customize colors in tables, node colors & dynamically set the colors of components in your chart. + +Minor improvements: +- Better handling of null values in tables. +- Tweaking/reorganization of the Docker file and deployment scripts. +- Renaming/restructuring of source code. + +## NeoDash 2.0.8 / 2.0.9 / 2.0.10 / 2.0.11 +Stability fixes to supplement 2.0.7: +- Hotfix for missing config file in Neo4j Desktop causing startup issue. +- Hotfix for application crashes caused by rendering custom data types in transposed table views. +- Hotfix for object rendering in tables & line-chart type detection. +- Fix for rendering dictionaries in tables/single value charts. +- Added resize handler for fullscreen map views. +- Added missing auto-run config to pie charts. +- Fixed broken value scale parameter for bar charts. + +## NeoDash 2.0.7 +Application functionality: +- Added standalone 'dashboard viewer' mode. +- Added option to save/load dashboards from other Neo4j databases. + +Reports/Visualizations: +- Fixed bug in creating line charts. +- Added support for datetime axis in line charts. +- Added auto-locale formatting to number values in single value / table reports. +- Added unified renderer for value types. +- Updated default font size for single value reports. +- Added optional deep-link button for graph visualizations. +- Added option to disable auto-running a report, to let users explore the query first. +- Minor styling tweaks to the graph views. + +For Developers: +- Added more documentation on extending the app. +- New security-vetted docker image available on Docker hub. + + +## NeoDash 2.0.6 +Major version updates to all internal dependencies. +NeoDash 2.0.6 uses Node 17+, react 17+ and recent versions of all visualization libraries. + +Visualizations: +- Added pie charts (Including examples and new demo dashboard). +- Added setting to transpose table rows and columns. +- Improved styling on graph pop-up windows. +- Graph visualizations now auto-fit to the report size. +- Added button to reset the zoom on a graph report. + +Parameter selection: +- Added relationship property / free text selection options. + +Editor: +- Improved performance of inbuilt Cypher editor. +- Added button to maximize cards while in edit-mode. +- All reports are now maximizable by default. +- Added tiny report sizes. +- Added option to override the default query timeout of twenty seconds. + +Other: +- Updated docker image build scripts. +- Fixed share link geneneration incorrectly removing capitals from usernames/passwords. + +## NeoDash 2.0.5 +Graph report: +- Fixed node position after dragging nodes. +- Added option to 'lock' graph views, storing the current positions of the nodes in the graph. +- Added experimental graph layouts. + +Table: +- Fixed bug where the report freezes for very wide tables. +- Added support for rendering native/custom Neo4j types in the table. + +Parameter select: +- Fixed issue where the dashboard crashes for slow connections. + +Editor: +- Added button to create a debug file from the 'About' screen. + + +## NeoDash 2.0.4 +New features: +- Added option dashboard setting to let users view reports in a fullscreen pop-up. +- Added inspection pop-up for graph visualizations. +- Added option to manually specify node labels/property names in parameter selection reports (for large databases). +- Added example of how to user map visualizations from derived properties. +- Added button to return to the welcome screen. +- iFrames can now take live parameter selections in the hash-part of the URL. + +Bug fixes: +- Dashboards will now remember the active selection(s) made in parameter select reports. +- Graph visualizations will no longer draw overlapping lines when a pair of nodes shares bidirectional relationships. +- connection screen is now dismissable if an existing connection exists. + +Special thanks to @JipSogeti for their contributions to this release. + +## NeoDash 2.0.3 +UX improvements + bug fixes. +- Parameter selection report: + - fixed bug to allow for selecting properties from nodes with >5 distinct properties. + - Added support for nodes and properties with spaces in their name. +- Sharing: + - Removed persisted URL in share links to avoid getting stuck on shared dashboards +- Table: + - Added option to specify relative column sizes +- Graph: + - Changed node styling to use the last (most specific label) for applying customizations + - Fixed error where incorrect properties were extracted from graphs with multi-labeled nodes + - Fixed node display to hide "undefined" when a non-existing property is selected for that node. + +## NeoDash 2.0.0, 2.0.1 & 2.0.2 + +**New & Improved Dashboard Editor** +- Added new Cypher editor with syntax highlighting / live syntax validation. +- Redesigned Cypher query runner to be 2x more performant. +- Easy custom styling of reports with the "advanced report settings" window. +- Added in-built documentation with example queries and visualizations. +- Updated dashboard layout to better use screen real estate. + +**Visualizations** +- Table View + - New table view with post-query sorting and filtering, and highlighting of native Neo4j types. + - Fixed array property display in table reports. + - Added automatic link generation from URL properties in the table report. +- Graph View + - Updated graph visualization library to a canvas-based renderer, handling 4x larger graphs. + - Added custom node/relationship styling with custom colors, width, and font-size. + - Better property display on graph visualization hover. +- Bar/Line Chart + - New bar/line chart visualizations based on the Charts graph app. + - Added support for multi-line charts, stacked/grouped bar charts. + - Added log scale + explicit limit setting to bar/line charts. + - Line chart hover values are no longer rounded and incorrectly stacked. +- Map View + - Added custom styling options to map visualizations. + - Added dictionary-based point property rendering on maps. + - Stability improvement of map views for offline deployments. +- Single Value Report + - Improved single value report. + - Custom styling (text alignment) of single value reports. +- Property Selection: + - Improved property selection documentation. + - Added optional "clear parameter" setting to parameter selection report. + - property selector now uses the filter to gather more results. + +**Saving, loading and sharing** +- Added setting to turn entire dashboard into 'Standalone mode' from a share link. +- Added option to save/load dashboards from both files and text. +- New "Try a demo" button on the welcome screen. +- added save/load to Neo4j database feature. +- Auto-convert older versions of NeoDash on load. + + + diff --git a/release-notes.md b/release-notes.md index 727c751d5..e982dcbc3 100644 --- a/release-notes.md +++ b/release-notes.md @@ -1,19 +1,12 @@ -## NeoDash 2.1 -The 2.1 release is a major update to the NeoDash application. +## NeoDash 2.1.2 +The 2.1.2 release contains some bug fixes and minor improvements to the application. -Main updates: -- Added new drag-and-drop dashboard layout - reports can be **moved** and **resized** freely within the dashboard. -- Updated dashboard file format for new layout (2.0 dashboards are automatically migrated). -- Pages can now be reordered by dragging and dropping. -- Added three new hierarchical report types: - - Treemaps - - Sunburst Charts - - Circle Packing Charts -- Styling/usability improvements for pie charts. -- Improved image download (screenshot functionality) for all report types. -- Parameter select reports now resize the selector to fit the available space. +Application changes: +- Added button to clone (duplicate) a report inside a dashboard. +- Added option to show/hide labels inside circle packing charts. +- Changed dashboard layout compaction strategy to be more natural. +- Fixed card headers not rendering correctly in read-only mode. +- Fixed rendering issues for table columns containing null values. -Other changes: -- Added continuous integration and deployment workflows. -- Created a new [User Guide](https://github.com/nielsdejong/neodash/wiki/User-Guide) with documentation on all report customizations is available. -- Added a new [Developer Guide](https://github.com/nielsdejong/neodash/wiki/Developer-Guide) with info on installing, building and extending the application. +Operational changes: +- Added support for username/password environment variables in Docker. diff --git a/scripts/config-entrypoint.sh b/scripts/config-entrypoint.sh index 84e2a659a..7e2671778 100644 --- a/scripts/config-entrypoint.sh +++ b/scripts/config-entrypoint.sh @@ -11,6 +11,8 @@ echo " \ \"standaloneHost\": \"${standaloneHost:='test.databases.neo4j.io'}\", \ \"standalonePort\": ${standalonePort:=7687}, \ \"standaloneDatabase\": \"${standaloneDatabase:='neo4j'}\", \ + \"standaloneUsername\": \"${standaloneUsername:=}\", \ + \"standalonePassword\": \"${standalonePassword:=}\", \ \"standaloneDashboardName\": \"${standaloneDashboardName:='My Dashboard'}\", \ \"standaloneDashboardDatabase\": \"${standaloneDashboardDatabase:='neo4j'}\" \ }" > /usr/share/nginx/html/config.json diff --git a/src/card/Card.tsx b/src/card/Card.tsx index 3b9482e3b..92672cbea 100644 --- a/src/card/Card.tsx +++ b/src/card/Card.tsx @@ -26,6 +26,7 @@ const NeoCard = ({ globalParameters, // Query parameters that are globally set for the entire dashboard. dashboardSettings, // Dictionary of settings for the entire dashboard. onRemovePressed, // action to take when the card is removed. (passed from parent) + onClonePressed, // action to take when user presses the clone button onReportHelpButtonPressed, // action to take when someone clicks the 'help' button in the report settings. onTitleUpdate, // action to take when the card title is updated. onTypeUpdate, // action to take when the card report type is updated. @@ -142,6 +143,7 @@ const NeoCard = ({ onTypeUpdate={(type) => onTypeUpdate(index, type)} onReportHelpButtonPressed={() => onReportHelpButtonPressed()} onRemovePressed={() => onRemovePressed(index)} + onClonePressed={() => onClonePressed(index)} onCreateNotification={(title, message) => onCreateNotification(title, message)} onToggleCardSettings={() => { setSettingsOpen(false); diff --git a/src/card/settings/CardSettings.tsx b/src/card/settings/CardSettings.tsx index 808525628..a407234c2 100644 --- a/src/card/settings/CardSettings.tsx +++ b/src/card/settings/CardSettings.tsx @@ -8,7 +8,7 @@ import { CARD_HEADER_HEIGHT } from '../../config/CardConfig'; const NeoCardSettings = ({ settingsOpen, query, database, refreshRate, width, height, type, reportSettings, reportSettingsOpen, fields, widthPx, heightPx, - onQueryUpdate, onRefreshRateUpdate, onRemovePressed, onReportSettingUpdate, + onQueryUpdate, onRefreshRateUpdate, onRemovePressed, onClonePressed, onReportSettingUpdate, onToggleCardSettings, onTypeUpdate, setActive, onReportHelpButtonPressed, onToggleReportSettings, dashboardSettings, expanded, onToggleCardExpand, onCreateNotification }) => { @@ -18,6 +18,7 @@ const NeoCardSettings = ({ settingsOpen, query, database, refreshRate, width, he expanded={expanded} onToggleCardExpand={onToggleCardExpand} onRemovePressed={onRemovePressed} + onClonePressed={onClonePressed} onReportHelpButtonPressed={onReportHelpButtonPressed} fullscreenEnabled={dashboardSettings.fullscreenEnabled} onToggleCardSettings={(e) => { setActive(reportSettings.autorun !== undefined ? reportSettings.autorun : true); onToggleCardSettings(e) }} /> diff --git a/src/card/settings/CardSettingsHeader.tsx b/src/card/settings/CardSettingsHeader.tsx index 0a7168ec4..21c18c9b7 100644 --- a/src/card/settings/CardSettingsHeader.tsx +++ b/src/card/settings/CardSettingsHeader.tsx @@ -2,17 +2,16 @@ import React from 'react'; import CardHeader from '@material-ui/core/CardHeader'; import IconButton from '@material-ui/core/IconButton'; import SaveIcon from '@material-ui/icons/Save'; -import SaveAltIcon from '@material-ui/icons/SaveAlt'; -import MoreVertIcon from '@material-ui/icons/MoreVert'; import HelpOutlineIcon from '@material-ui/icons/HelpOutline'; import DeleteOutlineIcon from '@material-ui/icons/DeleteOutline'; +import FileCopyOutlinedIcon from '@material-ui/icons/FileCopyOutlined'; import FullscreenIcon from '@material-ui/icons/Fullscreen'; import { FullscreenExit } from '@material-ui/icons'; import DragIndicatorIcon from '@material-ui/icons/DragIndicator'; import { Tooltip } from '@material-ui/core'; const NeoCardSettingsHeader = ({ onRemovePressed, onToggleCardSettings, onToggleCardExpand, - expanded, fullscreenEnabled, onReportHelpButtonPressed }) => { + expanded, fullscreenEnabled, onReportHelpButtonPressed, onClonePressed }) => { const maximizeButton = @@ -40,6 +39,12 @@ const NeoCardSettingsHeader = ({ onRemovePressed, onToggleCardSettings, onToggle + + + + + } action={<> {fullscreenEnabled ? (expanded ? unMaximizeButton : maximizeButton) : <>} diff --git a/src/card/view/CardView.tsx b/src/card/view/CardView.tsx index aab8b355f..6e3bd1264 100644 --- a/src/card/view/CardView.tsx +++ b/src/card/view/CardView.tsx @@ -82,8 +82,7 @@ const NeoCardView = ({ title, database, query, globalParameters, {active ? - +
{editable ?
diff --git a/src/chart/BarChart.tsx b/src/chart/BarChart.tsx index 9488ee2c8..53129d46d 100644 --- a/src/chart/BarChart.tsx +++ b/src/chart/BarChart.tsx @@ -6,6 +6,7 @@ import BarVisualization from './visualizations/BarVisualization'; /** * Embeds a BarReport (from Charts) into NeoDash. + * This visualization was extracted from https://github.com/neo4j-labs/charts. */ const NeoBarChart = (props: ChartProps) => { diff --git a/src/chart/IFrameChart.tsx b/src/chart/IFrameChart.tsx index d151bea1c..6438ec112 100644 --- a/src/chart/IFrameChart.tsx +++ b/src/chart/IFrameChart.tsx @@ -13,7 +13,7 @@ const NeoIFrameChart = (props: ChartProps) => { const passGlobalParameters = props.settings && props.settings.passGlobalParameters ? props.settings.passGlobalParameters : false; const replaceGlobalParameters = props.settings && props.settings.replaceGlobalParameters !== undefined ? props.settings.replaceGlobalParameters : true; const url = records[0]["input"].trim(); - const mapParameters = records[0]["mapParameters"] || {}; + const mapParameters = records[0]["parameters"] || {}; const queryString = Object.keys(mapParameters).map(key => key + '=' + mapParameters[key]).join('&'); const modifiedUrl = (replaceGlobalParameters ? replaceDashboardParameters(url, parameters) : url) + (passGlobalParameters ? "#" + queryString : ""); diff --git a/src/chart/visualizations/CirclePackingVisualization.tsx b/src/chart/visualizations/CirclePackingVisualization.tsx index d5d840702..c9e69d8a8 100644 --- a/src/chart/visualizations/CirclePackingVisualization.tsx +++ b/src/chart/visualizations/CirclePackingVisualization.tsx @@ -1,8 +1,7 @@ import React from 'react' import { ResponsiveCirclePacking } from '@nivo/circle-packing' -import { ChartReportProps, ExtendedChartReportProps } from './VisualizationProps' +import { ExtendedChartReportProps } from './VisualizationProps' import { checkResultKeys, mutateName, processHierarchyFromRecords, findObject, flatten } from './Utils' -import { evaluateRulesOnDict } from '../../report/ReportRuleEvaluator' import { useState } from 'react' import { Tooltip } from '@material-ui/core' import RefreshIcon from '@material-ui/icons/Refresh'; @@ -27,7 +26,8 @@ export default function CirclePackingVisualization(props: ExtendedChartReportPro // as Nivo needs a common root, so in that case, we create it for them. const commonProperties = { data: dataPre.length == 1 ? dataPre[0] : { name: "Total", children: dataPre } }; - const [data, setData] = useState(commonProperties.data) + const [data, setData] = useState(commonProperties.data); + const [refreshable, setRefreshable] = useState(false); const settings = (props.settings) ? props.settings : {}; const legendHeight = 20; const marginRight = (settings["marginRight"]) ? settings["marginRight"] : 24; @@ -38,13 +38,27 @@ export default function CirclePackingVisualization(props: ExtendedChartReportPro const borderWidth = (settings["borderWidth"]) ? settings["borderWidth"] : 0; const legend = (settings["legend"]) ? settings["legend"] : false; const colorScheme = (settings["colors"]) ? settings["colors"] : 'nivo'; + const showLabels = (settings["showLabels"] !== undefined) ? settings["showLabels"] : true; + + /** + * Helper function to decide whether to show labels for a specific node in the hierarchy, + * @param n - the entity + * @returns a boolean + */ + const showLabelsForNode = (n) => { + return n.node.height == 0; + } return ( <>
- - setData(commonProperties.data)} style={{ fontSize: "1.3rem", opacity: 0.6, bottom: 12, right: 12, position: "absolute", borderRadius: "12px", zIndex: 5, background: "#eee" }} color="disabled" fontSize="small"> - + {refreshable ? + {setData(commonProperties.data); setRefreshable(false);}} + style={{ fontSize: "1.3rem", opacity: 0.6, bottom: 12, right: 12, position: "absolute", borderRadius: "12px", zIndex: 5, background: "#eee" }} + color="disabled" fontSize="small"> + + :
+ } { const foundObject = findObject(flatten(data.children), clickedData.id) if (foundObject && foundObject.children) { - setData(foundObject) + setData(foundObject); + setRefreshable(true); } }} isInteractive={interactive} @@ -65,7 +80,10 @@ export default function CirclePackingVisualization(props: ExtendedChartReportPro left: marginLeft }} animate={true} + enableLabels={showLabels} + labelsFilter={showLabelsForNode} colors={{ scheme: colorScheme }} + />
) diff --git a/src/chart/visualizations/SunburstVisualization.tsx b/src/chart/visualizations/SunburstVisualization.tsx index e32016ed4..4cd1a37cd 100644 --- a/src/chart/visualizations/SunburstVisualization.tsx +++ b/src/chart/visualizations/SunburstVisualization.tsx @@ -1,8 +1,7 @@ import React from 'react' import { ResponsiveSunburst } from '@nivo/sunburst' -import { ChartReportProps, ExtendedChartReportProps } from './VisualizationProps' +import { ExtendedChartReportProps } from './VisualizationProps' import { checkResultKeys, mutateName, processHierarchyFromRecords, findObject, flatten } from './Utils' -import { evaluateRulesOnDict } from '../../report/ReportRuleEvaluator' import { useState } from 'react' import { Tooltip } from '@material-ui/core' import RefreshIcon from '@material-ui/icons/Refresh'; @@ -28,7 +27,8 @@ export default function SunburstVisualization(props: ExtendedChartReportProps) { // as Nivo needs a common root, so in that case, we create it for them. const commonProperties = { data : dataPre.length == 1 ? dataPre[0] : {name : "Total", children : dataPre}}; - const [data, setData] = useState(commonProperties.data) + const [data, setData] = useState(commonProperties.data); + const [refreshable, setRefreshable] = useState(false); const settings = (props.settings) ? props.settings : {}; const legendHeight = 20; const marginRight = (settings["marginRight"]) ? settings["marginRight"] : 24; @@ -46,9 +46,13 @@ export default function SunburstVisualization(props: ExtendedChartReportProps) { return ( <>
- - setData(commonProperties.data)} style={{ fontSize: "1.3rem", opacity: 0.6, bottom: 12, right: 12, position: "absolute", borderRadius: "12px", zIndex: 5, background: "#eee" }} color="disabled" fontSize="small"> - + {refreshable ? + {setData(commonProperties.data); setRefreshable(false);}} + style={{ fontSize: "1.3rem", opacity: 0.6, bottom: 12, right: 12, position: "absolute", borderRadius: "12px", zIndex: 5, background: "#eee" }} + color="disabled" fontSize="small"> + + :
+ } { const foundObject = findObject(flatten(data.children), clickedData.id) if (foundObject && foundObject.children) { - setData(foundObject) + setData(foundObject); + setRefreshable(true); } }} enableArcLabels={enableArcLabels} diff --git a/src/chart/visualizations/TreeMapVisualization.tsx b/src/chart/visualizations/TreeMapVisualization.tsx index fd36b10f2..29280b317 100644 --- a/src/chart/visualizations/TreeMapVisualization.tsx +++ b/src/chart/visualizations/TreeMapVisualization.tsx @@ -1,8 +1,7 @@ import React from 'react' import { ResponsiveTreeMap } from '@nivo/treemap' -import { ChartReportProps, ExtendedChartReportProps } from './VisualizationProps' +import { ExtendedChartReportProps } from './VisualizationProps' import { checkResultKeys, mutateName, processHierarchyFromRecords, findObject, flatten } from './Utils' -import { evaluateRulesOnDict } from '../../report/ReportRuleEvaluator' import { useState } from 'react' import { Tooltip } from '@material-ui/core' import RefreshIcon from '@material-ui/icons/Refresh'; @@ -28,7 +27,8 @@ export default function TreeMapVisualization(props: ExtendedChartReportProps) { // as Nivo needs a common root, so in that case, we create it for them. const commonProperties = { data : dataPre.length == 1 ? dataPre[0] : {name : "Total", children : dataPre}}; - const [data, setData] = useState(commonProperties.data) + const [data, setData] = useState(commonProperties.data); + const [refreshable, setRefreshable] = useState(false); const settings = (props.settings) ? props.settings : {}; const legendHeight = 20; const marginRight = (settings["marginRight"]) ? settings["marginRight"] : 24; @@ -40,12 +40,24 @@ export default function TreeMapVisualization(props: ExtendedChartReportProps) { const legend = (settings["legend"]) ? settings["legend"] : false; const colorScheme = (settings["colors"]) ? settings["colors"] : 'nivo'; + /** + * Helper function to determine which label to draw on a node in the hierarchy. + * @param n the node. + * @returns a string (label). + */ + const getLabelForNode = (n) => { + return n.formattedValue + } return ( <>
- - setData(commonProperties.data)} style={{ fontSize: "1.3rem", opacity: 0.6, bottom: 12, right: 12, position: "absolute", borderRadius: "12px", zIndex: 5, background: "#eee" }} color="disabled" fontSize="small"> - + {refreshable ? + {setData(commonProperties.data); setRefreshable(false);}} + style={{ fontSize: "1.3rem", opacity: 0.6, bottom: 12, right: 12, position: "absolute", borderRadius: "12px", zIndex: 5, background: "#eee" }} + color="disabled" fontSize="small"> + + :
+ } { const foundObject = findObject(flatten(data.children), clickedData.id) if (foundObject && foundObject.children) { - setData(foundObject) + setData(foundObject); + setRefreshable(true); } }} isInteractive={interactive} @@ -67,6 +80,7 @@ export default function TreeMapVisualization(props: ExtendedChartReportProps) { }} animate={true} colors={{ scheme: colorScheme }} + label = { getLabelForNode } />
) diff --git a/src/config/PageConfig.ts b/src/config/PageConfig.ts index e0136f7b2..e6498ae4a 100644 --- a/src/config/PageConfig.ts +++ b/src/config/PageConfig.ts @@ -1,2 +1,2 @@ -export const GRID_COMPACTION_TYPE = "horizontal"; // Can be set to vertical or horizontal or none. \ No newline at end of file +export const GRID_COMPACTION_TYPE = "vertical"; // Can be set to vertical or horizontal or none. \ No newline at end of file diff --git a/src/config/ReportConfig.tsx b/src/config/ReportConfig.tsx index c44d6ed3f..edc593e88 100644 --- a/src/config/ReportConfig.tsx +++ b/src/config/ReportConfig.tsx @@ -25,7 +25,7 @@ export enum SELECTION_TYPES { DICTIONARY, COLOR, NODE_PROPERTIES -}; +} // Use Neo4j 4.0 subqueries to limit the number of rows returned by overriding the query. export const HARD_ROW_LIMITING = false; @@ -808,6 +808,12 @@ export const REPORT_TYPES = { values: ["nivo", "category10", "accent", "dark2", "paired", "pastel1", "pastel2", "set1", "set2", "set3"], default: "set2" }, + "showLabels": { + label: "Show Circle Labels", + type: SELECTION_TYPES.LIST, + values: [true, false], + default: true + }, "borderWidth": { label: "Circle border width (px)", type: SELECTION_TYPES.NUMBER, diff --git a/src/dashboard/drawer/DashboardDrawer.tsx b/src/dashboard/drawer/DashboardDrawer.tsx index 96a211cbb..ad0ddd090 100644 --- a/src/dashboard/drawer/DashboardDrawer.tsx +++ b/src/dashboard/drawer/DashboardDrawer.tsx @@ -95,7 +95,7 @@ export const NeoDrawer = ({ open, hidden, connection, dashboardSettings, updateD - window.open("https://github.com/nielsdejong/neodash/wiki/User-Guide", "_blank")}> + window.open("https://github.com/neo4j-labs/neodash/wiki/User-Guide", "_blank")}> diff --git a/src/modal/AboutModal.tsx b/src/modal/AboutModal.tsx index 9eaab7102..cf847a835 100644 --- a/src/modal/AboutModal.tsx +++ b/src/modal/AboutModal.tsx @@ -13,7 +13,7 @@ import BugReportIcon from '@material-ui/icons/BugReport'; export const NeoAboutModal = ({ open, handleClose, getDebugState }) => { const app = "NeoDash - Neo4j Dashboard Builder"; const email = "niels.dejong@neo4j.com"; - const version = "2.1.1"; + const version = "2.1.2"; const downloadDebugFile = () => { const element = document.createElement("a"); @@ -58,7 +58,7 @@ export const NeoAboutModal = ({ open, handleClose, getDebugState }) => {

Extending NeoDash

NeoDash is built with React and use-neo4j, It uses charts to power some of the visualizations, and openstreetmap for the map view.
- You can also extend NeoDash with your own visualizations. Check out the developer guide in the project repository. + You can also extend NeoDash with your own visualizations. Check out the developer guide in the project repository.

Contact

For suggestions, feature requests and other feedback: contact the project's maintainer(s) via the Github repository,
diff --git a/src/modal/ReportExamplesModal.tsx b/src/modal/ReportExamplesModal.tsx index b9c060eaf..b6b93378e 100644 --- a/src/modal/ReportExamplesModal.tsx +++ b/src/modal/ReportExamplesModal.tsx @@ -71,7 +71,7 @@ export const NeoReportExamplesModal = ({ database }) => { database={database} disabled={!open} selection={example.selection} - mapParameters={example.globalParameters} + parameters={example.globalParameters} settings={example.settings} fields={example.fields} dimensions={example.dimensions} diff --git a/src/modal/ReportHelpModal.tsx b/src/modal/ReportHelpModal.tsx index ab66986b2..f7ca86e8d 100644 --- a/src/modal/ReportHelpModal.tsx +++ b/src/modal/ReportHelpModal.tsx @@ -31,7 +31,7 @@ export const NeoReportHelpModal = ({ open, handleClose }) => { A report is the smallest building block of your dashboard. Each report runs a single Cypher query that loads data from your database. By changing the report type, different visualizations can be created for the data. - See the Documentation for more on reports. + See the Documentation for more on reports.



diff --git a/src/modal/ShareModal.tsx b/src/modal/ShareModal.tsx index 8cc95135d..f47e4a917 100644 --- a/src/modal/ShareModal.tsx +++ b/src/modal/ShareModal.tsx @@ -107,7 +107,7 @@ export const NeoShareModal = ({ connection, loadDashboardListFromNeo4j, loadData This window lets you create a temporary share link for your dashboard. - Keep in mind that share links are not intended as a way to publish your dashboard for users, see the wiki for more on publishing. + Keep in mind that share links are not intended as a way to publish your dashboard for users, see the wiki for more on publishing.


Step 1: Select a dashboard to share. diff --git a/src/page/Page.tsx b/src/page/Page.tsx index 1d85d3ec7..2200be9ee 100644 --- a/src/page/Page.tsx +++ b/src/page/Page.tsx @@ -3,7 +3,7 @@ import { connect } from 'react-redux'; import NeoAddCard from '../card/CardAddButton'; import NeoCard from '../card/Card'; import { getReports } from './PageSelectors'; -import { addReportThunk, removeReportThunk, updatePageLayoutThunk } from './PageThunks'; +import { addReportThunk, removeReportThunk, updatePageLayoutThunk, cloneReportThunk } from './PageThunks'; import Grid from '@material-ui/core/Grid'; import { getDashboardIsEditable, getPageNumber } from '../settings/SettingsSelectors'; import { getDashboardSettings } from '../dashboard/DashboardSelectors'; @@ -22,6 +22,7 @@ export const NeoPage = ( pagenumber, // The page number to render. reports = [], // list of reports as defined in the dashboard state. onCreatePressed = () => {}, // callback for when the user wants to add a new report. + onClonePressed = (index: number, x: number, y: number) => {}, // callback/action to take when a user wants to clone a report onRemovePressed = (index: number) => {}, // action to take when a report gets removed. isLoaded = true, // Whether the page is loaded and the cards can be displayed. onPageLayoutUpdate = (newLayout: object) => { } // action to take when the page layout is updated. @@ -155,7 +156,11 @@ export const NeoPage = ( return + onRemovePressed={onRemovePressed} + onClonePressed={(index) => { + const { x, y } = getAddCardButtonPosition(); + onClonePressed(index, x, y); + }} /> })} {editable && !isDragging ? lastElement :
} @@ -175,7 +180,8 @@ const mapStateToProps = state => ({ const mapDispatchToProps = dispatch => ({ onRemovePressed: index => dispatch(removeReportThunk(index)), - onCreatePressed: (x, y, width, height) => dispatch(addReportThunk(x, y, width, height)), + onClonePressed: (index, x, y) => dispatch(cloneReportThunk(index, x, y)), + onCreatePressed: (x, y, width, height) => dispatch(addReportThunk(x, y, width, height, undefined)), onPageLayoutUpdate: layout => dispatch(updatePageLayoutThunk(layout)) }); diff --git a/src/page/PageThunks.ts b/src/page/PageThunks.ts index b6d4c7290..a2a7e04a4 100644 --- a/src/page/PageThunks.ts +++ b/src/page/PageThunks.ts @@ -1,15 +1,16 @@ import { createNotification } from "../application/ApplicationActions"; import { CARD_INITIAL_STATE } from "../card/CardReducer"; -import { createReport, removeReport, updateAllCardPositionsInPage } from "./PageActions"; +import { createReport, removeReport,updateAllCardPositionsInPage } from "./PageActions"; export const createNotificationThunk = (title: any, message: any) => (dispatch: any) => { dispatch(createNotification(title, message)); }; -export const addReportThunk = (x: number, y: number, width: number, height: number) => (dispatch: any, getState: any) => { +export const addReportThunk = (x: number, y: number, width: number, height: number, data:any) => (dispatch: any, getState: any) => { try { - const report = {...CARD_INITIAL_STATE, x: x, y: y, width: width, height: height}; + const initialState = data !== undefined ? data : CARD_INITIAL_STATE; + const report = {...initialState, x: x, y: y, width: width, height: height}; const state = getState(); const pagenumber = state.dashboard.settings.pagenumber; dispatch(createReport(pagenumber, report)); @@ -28,6 +29,18 @@ export const removeReportThunk = (index: number) => (dispatch: any, getState: an } } +export const cloneReportThunk = (index: number, x:number, y:number) => (dispatch: any, getState: any) => { + try { + const state = getState(); + const pagenumber = state.dashboard.settings.pagenumber; + const data = {... state.dashboard.pages[pagenumber].reports[index]}; + data.settingsOpen = false; + dispatch(addReportThunk(x , y, data.width, data.height, data)); + } catch (e) { + dispatch(createNotificationThunk("Cannot clone report", e)); + } +} + export const updatePageLayoutThunk = (layout: any) => (dispatch: any, getState: any) => { try { const pagenumber = getState().dashboard.settings.pagenumber; diff --git a/src/report/Report.tsx b/src/report/Report.tsx index 5478d7f9e..7376c2f55 100644 --- a/src/report/Report.tsx +++ b/src/report/Report.tsx @@ -16,8 +16,7 @@ import NeoTableChart from "../chart/TableChart"; export const NeoReport = ({ database = "neo4j", // The Neo4j database to run queries onto. query = "", // The Cypher query used to populate the report. - stringParameters = "", // A string, to be parsed as JSON, which contains cypher parameters. TODO - remove this, replaced by mapParameters. - mapParameters = {}, // A dictionary of parameters to pass into the query. + parameters = {}, // A dictionary of parameters to pass into the query. disabled = false, // Whether to disable query execution. selection = {}, // A selection of return fields to send to the report. fields = [], // A list of the return data fields that the query produces. @@ -48,28 +47,13 @@ export const NeoReport = ({ // If this is a 'text-only' report, no queries are ran, instead we pass the input directly to the report. if (REPORT_TYPES[type].textOnly) { setStatus(QueryStatus.COMPLETE); - setRecords([{ input: query, mapParameters: mapParameters }]); + setRecords([{ input: query, parameters: parameters }]); return; } // Reset the report records before we run the query. setRecords([]); - // Try and parse the provided query parameters. - var parsedParameters = {}; - try { - parsedParameters = JSON.parse(stringParameters != "" ? stringParameters : "{}") - } catch (e) { - const message = "Unable to parse Cypher parameters: \"" - + stringParameters + "\"\n" + e.message + '.\n\n' + - "Ensure you specify parameters in a valid JSON format." - // @ts-ignore - setRecords([{ "error": message }]); - setStatus(QueryStatus.ERROR) - return - } - const parameters = Object.assign({}, parsedParameters, mapParameters); - // Determine the set of fields from the configurations. var numericFields = (REPORT_TYPES[type].selection && fields) ? Object.keys(REPORT_TYPES[type].selection).filter(field => REPORT_TYPES[type].selection[field].type == SELECTION_TYPES.NUMBER && !REPORT_TYPES[type].selection[field].multiple) : []; var numericOrDatetimeFields = (REPORT_TYPES[type].selection && fields) ? Object.keys(REPORT_TYPES[type].selection).filter(field => REPORT_TYPES[type].selection[field].type == SELECTION_TYPES.NUMBER_OR_DATETIME && !REPORT_TYPES[type].selection[field].multiple) : []; @@ -122,8 +106,8 @@ export const NeoReport = ({ } } }, REPORT_TYPES[type].useRecordMapper == true ? - [disabled, query, JSON.stringify(mapParameters), fields ? fields : [], JSON.stringify(selection)] : - [disabled, query, JSON.stringify(mapParameters), null, null]) + [disabled, query, JSON.stringify(parameters), fields ? fields : [], JSON.stringify(selection)] : + [disabled, query, JSON.stringify(parameters), null, null]) // Define query callback to allow reports to get extra data on interactions. const queryCallback = useCallback( @@ -167,7 +151,7 @@ export const NeoReport = ({ settings={settings} fullscreen={expanded} dimensions={dimensions} - parameters={mapParameters} + parameters={parameters} queryCallback={queryCallback} setGlobalParameter={setGlobalParameter} getGlobalParameter={getGlobalParameter} /> @@ -191,7 +175,7 @@ export const NeoReport = ({ settings={settings} fullscreen={expanded} dimensions={dimensions} - parameters={mapParameters} + parameters={parameters} queryCallback={queryCallback} setGlobalParameter={setGlobalParameter} getGlobalParameter={getGlobalParameter} /> diff --git a/src/report/ReportRecordProcessing.tsx b/src/report/ReportRecordProcessing.tsx index 44b564cae..05245bd9f 100644 --- a/src/report/ReportRecordProcessing.tsx +++ b/src/report/ReportRecordProcessing.tsx @@ -469,7 +469,7 @@ export const rendererForType: any = { }, "null": { type: 'string', - renderValue: (c) => "null" + renderValue: (c) => RenderString(c.value) }, "undefined": { type: 'string'