diff --git a/.github/workflows/master-deployment.yml b/.github/workflows/master-deployment.yml index 8838807ac..c7c3afe16 100644 --- a/.github/workflows/master-deployment.yml +++ b/.github/workflows/master-deployment.yml @@ -79,7 +79,7 @@ jobs: context: . file: ./Dockerfile push: true - tags: ${{ secrets.DOCKER_HUB_LABS_USERNAME }}/neodash:latest,${{ secrets.DOCKER_HUB_LABS_USERNAME }}/neodash:2.4.5 + tags: ${{ secrets.DOCKER_HUB_LABS_USERNAME }}/neodash:latest,${{ secrets.DOCKER_HUB_LABS_USERNAME }}/neodash:2.4.6 build-docker-legacy: needs: build-test runs-on: neodash-runners @@ -103,7 +103,7 @@ jobs: context: . file: ./Dockerfile push: true - tags: ${{ secrets.DOCKER_HUB_USERNAME }}/neodash:latest,${{ secrets.DOCKER_HUB_USERNAME }}/neodash:2.4.5 + tags: ${{ secrets.DOCKER_HUB_USERNAME }}/neodash:latest,${{ secrets.DOCKER_HUB_USERNAME }}/neodash:2.4.6 deploy-gallery: runs-on: neodash-runners strategy: diff --git a/Dockerfile b/Dockerfile index 0bbdf284b..1e78a8511 100644 --- a/Dockerfile +++ b/Dockerfile @@ -44,4 +44,4 @@ USER nginx EXPOSE $NGINX_PORT HEALTHCHECK cmd curl --fail "http://localhost:$NGINX_PORT" || exit 1 -LABEL version="2.4.5" +LABEL version="2.4.6" diff --git a/changelog.md b/changelog.md index b34b6d2bd..aceee2e41 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,11 @@ +## NeoDash 2.4.6 +This is a minor release containing a few critical fixes and some extra style customizations: + +- Fix bad text wrapping for arrays in tables ([868](https://github.com/neo4j-labs/neodash/pull/868)). +- Make wrapping in table optional, disabled by default ([872](https://github.com/neo4j-labs/neodash/pull/872)). +- Fixed issues where cross database dashboard sharing always reverted back to the default database ([873](https://github.com/neo4j-labs/neodash/pull/873)). +- Added option to define style config using environment variables for the Docker image ([876](https://github.com/neo4j-labs/neodash/pull/876)). + ## NeoDash 2.4.5 This is a small release containing a few fixes: - Fixed rendering of string arrays inside tables, report titles, and report action buttons [849](https://github.com/neo4j-labs/neodash/pull/849) diff --git a/docs/modules/ROOT/pages/developer-guide/deploy-a-build.adoc b/docs/modules/ROOT/pages/developer-guide/deploy-a-build.adoc index 1b7d4a371..6fadeb4b7 100644 --- a/docs/modules/ROOT/pages/developer-guide/deploy-a-build.adoc +++ b/docs/modules/ROOT/pages/developer-guide/deploy-a-build.adoc @@ -37,7 +37,7 @@ Depending on the webserver type and version, this could be different directory. As an example - to copy the files to an nginx webserver using `scp`: ```bash -scp neodash-2.4.5 username@host:/usr/share/nginx/html +scp neodash-2.4.6 username@host:/usr/share/nginx/html ``` NeoDash should now be visible by visiting your (sub)domain in the browser. diff --git a/docs/modules/ROOT/pages/developer-guide/style-configuration.adoc b/docs/modules/ROOT/pages/developer-guide/style-configuration.adoc index e9d5af5c4..b82124d2f 100644 --- a/docs/modules/ROOT/pages/developer-guide/style-configuration.adoc +++ b/docs/modules/ROOT/pages/developer-guide/style-configuration.adoc @@ -6,9 +6,15 @@ link:https://cdn.jsdelivr.net/npm/@neo4j-ndl/base@1.4.0/lib/tokens/css/tokens.cs For a simple (non-Dockerized) deployment, these configuration parameters can be changed by modifying `dist/style.config.json` after you have built the -application. When Docker image, these can not be passed as environment -variables. +application. When using the NeoDash Docker image, these can be passed as environment +variables. For example: +.... +docker run -p 5005:5005 \ + -e DASHBOARD_HEADER_BRAND_LOGO=https://picsum.photos/500/100 \ + neo4jlabs/neodash +.... + An example configuration for NeoDash .... diff --git a/package.json b/package.json index f15e63413..f97d7fa5a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "neodash", - "version": "2.4.5", + "version": "2.4.6", "description": "NeoDash - Neo4j Dashboard Builder", "neo4jDesktop": { "apiVersion": "^1.2.0" diff --git a/release-notes.md b/release-notes.md index 2c8fb27d3..d8b929222 100644 --- a/release-notes.md +++ b/release-notes.md @@ -1,11 +1,7 @@ -## NeoDash 2.4.5 -This is a small release containing a few fixes: -- Fixed rendering of string arrays inside tables, report titles, and report action buttons [849](https://github.com/neo4j-labs/neodash/pull/849) -- Allowed text to wrap in tables, preserving the number of rows [852](https://github.com/neo4j-labs/neodash/pull/852) -- Disabled auto-sorting of Cypher query-based Parameter Select ; use Cypher ORDER BY to control result order [857](https://github.com/neo4j-labs/neodash/pull/857) -- Updated role selector menu, and made user updates more robust [854](https://github.com/neo4j-labs/neodash/pull/854) +## NeoDash 2.4.6 +This is a minor release containing a few critical fixes and some extra style customizations: -Thanks to all the contributors for this release: -- [MariusC](https://github.com/mariusconjeaud), -- [LiamEdwardsLamarche](https://github.com/LiamEdwardsLamarche), -- [AleSim94](https://github.com/AleSim94) \ No newline at end of file +- Fix bad text wrapping for arrays in tables ([868](https://github.com/neo4j-labs/neodash/pull/868)). +- Make wrapping in table optional, disabled by default ([872](https://github.com/neo4j-labs/neodash/pull/872)). +- Fixed issues where cross database dashboard sharing always reverted back to the default database ([873](https://github.com/neo4j-labs/neodash/pull/873)). +- Added option to define style config using environment variables for the Docker image ([876](https://github.com/neo4j-labs/neodash/pull/876)). \ No newline at end of file diff --git a/scripts/config-entrypoint.sh b/scripts/config-entrypoint.sh index 8c4ebadbe..3e2a063ec 100644 --- a/scripts/config-entrypoint.sh +++ b/scripts/config-entrypoint.sh @@ -27,4 +27,17 @@ echo " \ \"customHeader\": \"${customHeader:=}\" \ }" > /usr/share/nginx/html/config.json -echo "${styleConfigJson:={\}}" > /usr/share/nginx/html/style.config.json +echo " \ + { \ + \"DASHBOARD_HEADER_BRAND_LOGO\": \"${DASHBOARD_HEADER_BRAND_LOGO:=}\", \ + \"DASHBOARD_HEADER_COLOR\" : \"${DASHBOARD_HEADER_COLOR:=}\", \ + \"DASHBOARD_HEADER_BUTTON_COLOR\" : \"${DASHBOARD_HEADER_BUTTON_COLOR:=}\", \ + \"DASHBOARD_HEADER_TITLE_COLOR\" : \"${DASHBOARD_HEADER_TITLE_COLOR:=}\", \ + \"DASHBOARD_PAGE_LIST_COLOR\" : \"${DASHBOARD_PAGE_LIST_COLOR:=}\", \ + \"DASHBOARD_PAGE_LIST_ACTIVE_COLOR\": \"${DASHBOARD_PAGE_LIST_ACTIVE_COLOR:=}\", \ + \"style\": { \ + \"--palette-light-neutral-bg-weak\": \"${STYLE_PALETTE_LIGHT_NEUTRAL_BG_WEAK:=}\" \ + } \ +}" > /usr/share/nginx/html/style.config.json + + diff --git a/src/application/ApplicationActions.ts b/src/application/ApplicationActions.ts index 0b556f2dc..b8fe3d063 100644 --- a/src/application/ApplicationActions.ts +++ b/src/application/ApplicationActions.ts @@ -178,7 +178,7 @@ export const setStandaloneEnabled = ( export const SET_STANDALONE_MODE = 'APPLICATION/SET_STANDALONE_MODE'; export const setStandaloneMode = (standalone: boolean) => ({ - type: SET_STANDALONE_ENABLED, + type: SET_STANDALONE_MODE, payload: { standalone }, }); diff --git a/src/application/ApplicationThunks.ts b/src/application/ApplicationThunks.ts index fc880fd3a..e3ddc8ce0 100644 --- a/src/application/ApplicationThunks.ts +++ b/src/application/ApplicationThunks.ts @@ -259,7 +259,10 @@ export const handleSharedDashboardsThunk = () => (dispatch: any) => { const skipConfirmation = urlParams.get('skipConfirmation') == 'Yes'; const dashboardDatabase = urlParams.get('dashboardDatabase'); - dispatch(setStandaloneDashboardDatabase(dashboardDatabase)); + if (dashboardDatabase) { + dispatch(setStandaloneDashboardDatabase(dashboardDatabase)); + } + if (urlParams.get('credentials')) { setWelcomeScreenOpen(false); const connection = decodeURIComponent(urlParams.get('credentials')); @@ -363,6 +366,8 @@ export const onConfirmLoadSharedDashboardThunk = () => (dispatch: any, getState: if (shareDetails.dashboardDatabase) { dispatch(setStandaloneDashboardDatabase(shareDetails.dashboardDatabase)); + } else if (!state.application.standaloneDashboardDatabase) { + // No standalone dashboard database configured, fall back to default dispatch(setStandaloneDashboardDatabase(shareDetails.database)); } if (shareDetails.url) { @@ -452,6 +457,9 @@ export const loadApplicationConfigThunk = () => async (dispatch: any, getState: dispatch(setSSOProviders(config.ssoProviders)); const { standalone } = config; + // if a dashboard database was previously set, remember to use it. + const dashboardDatabase = state.application.standaloneDashboardDatabase; + dispatch( setStandaloneEnabled( standalone, @@ -460,7 +468,7 @@ export const loadApplicationConfigThunk = () => async (dispatch: any, getState: config.standalonePort, config.standaloneDatabase, config.standaloneDashboardName, - config.standaloneDashboardDatabase, + dashboardDatabase || config.standaloneDashboardDatabase, config.standaloneDashboardURL, config.standaloneUsername, config.standalonePassword, diff --git a/src/chart/table/TableChart.tsx b/src/chart/table/TableChart.tsx index c6bdf3637..58e54e71f 100644 --- a/src/chart/table/TableChart.tsx +++ b/src/chart/table/TableChart.tsx @@ -46,11 +46,9 @@ function renderAsButtonWrapper(renderer) { return <>; } return ( - + ); }; } @@ -73,6 +71,7 @@ export const generateSafeColumnKey = (key) => { export const NeoTableChart = (props: ChartProps) => { const transposed = props.settings && props.settings.transposed ? props.settings.transposed : false; + const wrapContent = props.settings && props.settings.wrapContent ? props.settings.wrapContent : false; const allowDownload = props.settings && props.settings.allowDownload !== undefined ? props.settings.allowDownload : false; @@ -214,6 +213,49 @@ export const NeoTableChart = (props: ChartProps) => { : Math.floor(availableRowHeight) - pageSizeReducer; const pageNames = getPageNumbersAndNamesList(); + const commonGridProps = { + key: 'tableKey', + headerHeight: 32, + density: compact ? 'compact' : 'standard', + rows: rows, + columns: columns, + columnVisibilityModel: columnVisibilityModel, + onColumnVisibilityModelChange: (newModel) => setColumnVisibilityModel(newModel), + onCellClick: (e) => performActionOnElement(e, actionsRules, { ...props, pageNames: pageNames }, 'Click', 'Table'), + onCellDoubleClick: (e) => { + let rules = getRule(e, actionsRules, 'doubleClick'); + if (rules !== null) { + rules.forEach((rule) => executeActionRule(rule, e, { ...props, pageNames: pageNames }, 'table')); + } else { + setNotificationOpen(true); + navigator.clipboard.writeText(e.value); + } + }, + checkboxSelection: hasCheckboxes(actionsRules), + selectionModel: getCheckboxes(actionsRules, rows, props.getGlobalParameter), + onSelectionModelChange: (selection) => updateCheckBoxes(actionsRules, rows, selection, props.setGlobalParameter), + pageSize: tablePageSize > 0 ? tablePageSize : 5, + rowsPerPageOptions: rows.length < 5 ? [rows.length, 5] : [5], + disableSelectionOnClick: true, + components: { + ColumnSortedDescendingIcon: () => <>, + ColumnSortedAscendingIcon: () => <>, + }, + getRowClassName: (params) => { + return ['row color', 'row text color'] + .map((e) => { + return `rule${evaluateRulesOnDict(params.row, styleRules, [e])}`; + }) + .join(' '); + }, + getCellClassName: (params) => { + return ['cell color', 'cell text color'] + .map((e) => { + return `rule${evaluateRulesOnDict({ [params.field]: params.value }, styleRules, [e])}`; + }) + .join(' '); + }, + }; return ( @@ -259,61 +301,21 @@ export const NeoTableChart = (props: ChartProps) => { <> )} - 'auto'} - rows={rows} - columns={columns} - columnVisibilityModel={columnVisibilityModel} - onColumnVisibilityModelChange={(newModel) => setColumnVisibilityModel(newModel)} - onCellClick={(e) => - performActionOnElement(e, actionsRules, { ...props, pageNames: pageNames }, 'Click', 'Table') - } - onCellDoubleClick={(e) => { - let rules = getRule(e, actionsRules, 'doubleClick'); - if (rules !== null) { - rules.forEach((rule) => executeActionRule(rule, e, { ...props, pageNames: pageNames }, 'table')); - } else { - setNotificationOpen(true); - navigator.clipboard.writeText(e.value); - } - }} - checkboxSelection={hasCheckboxes(actionsRules)} - selectionModel={getCheckboxes(actionsRules, rows, props.getGlobalParameter)} - onSelectionModelChange={(selection) => - updateCheckBoxes(actionsRules, rows, selection, props.setGlobalParameter) - } - pageSize={tablePageSize > 0 ? tablePageSize : 5} - rowsPerPageOptions={rows.length < 5 ? [rows.length, 5] : [5]} - disableSelectionOnClick - components={{ - ColumnSortedDescendingIcon: () => <>, - ColumnSortedAscendingIcon: () => <>, - }} - getRowClassName={(params) => { - return ['row color', 'row text color'] - .map((e) => { - return `rule${evaluateRulesOnDict(params.row, styleRules, [e])}`; - }) - .join(' '); - }} - getCellClassName={(params) => { - return ['cell color', 'cell text color'] - .map((e) => { - return `rule${evaluateRulesOnDict({ [params.field]: params.value }, styleRules, [e])}`; - }) - .join(' '); - }} - sx={{ - '&.MuiDataGrid-root--densityCompact .MuiDataGrid-cell': { py: '3px' }, - '&.MuiDataGrid-root--densityCompact .MuiDataGrid-cell:has(button)': { py: '0px' }, - '&.MuiDataGrid-root--densityStandard .MuiDataGrid-cell': { py: '15px' }, - '&.MuiDataGrid-root--densityComfortable .MuiDataGrid-cell': { py: '22px' }, - '&.MuiDataGrid-root .MuiDataGrid-cell': { wordBreak: 'break-word' }, - }} - /> + {wrapContent ? ( + 'auto'} + sx={{ + '&.MuiDataGrid-root--densityCompact .MuiDataGrid-cell': { py: '3px' }, + '&.MuiDataGrid-root--densityCompact .MuiDataGrid-cell:has(button)': { py: '0px' }, + '&.MuiDataGrid-root--densityStandard .MuiDataGrid-cell': { py: '15px' }, + '&.MuiDataGrid-root--densityComfortable .MuiDataGrid-cell': { py: '22px' }, + '&.MuiDataGrid-root .MuiDataGrid-cell': { wordBreak: 'break-word' }, + }} + /> + ) : ( + + )} ); diff --git a/src/config/ReportConfig.tsx b/src/config/ReportConfig.tsx index e9270c314..97b6bc913 100644 --- a/src/config/ReportConfig.tsx +++ b/src/config/ReportConfig.tsx @@ -46,6 +46,12 @@ const _REPORT_TYPES = { values: [true, false], default: false, }, + wrapContent: { + label: 'Wrap overflowing content', + type: SELECTION_TYPES.LIST, + values: [true, false], + default: false, + }, columnWidthsType: { label: 'Column Widths Specification', type: SELECTION_TYPES.LIST, diff --git a/src/modal/AboutModal.tsx b/src/modal/AboutModal.tsx index 8c1be47e5..826b032d5 100644 --- a/src/modal/AboutModal.tsx +++ b/src/modal/AboutModal.tsx @@ -3,7 +3,7 @@ import { Button, Dialog, TextLink } from '@neo4j-ndl/react'; import { BookOpenIconOutline, BeakerIconOutline } from '@neo4j-ndl/react/icons'; import { Section, SectionTitle, SectionContent } from './ModalUtils'; -export const version = '2.4.5'; +export const version = '2.4.6'; export const NeoAboutModal = ({ open, handleClose, getDebugState }) => { const downloadDebugFile = () => { diff --git a/src/report/ReportRecordProcessing.tsx b/src/report/ReportRecordProcessing.tsx index 726beaebe..f30908577 100644 --- a/src/report/ReportRecordProcessing.tsx +++ b/src/report/ReportRecordProcessing.tsx @@ -247,12 +247,15 @@ function RenderPath(value) { } function RenderArray(value) { + if (value.length > 0 && !valueIsNode(value[0]) && !valueIsRelationship(value[0])) { + return RenderString(value.join(', ')); + } const mapped = value.map((v, i) => { return ( -
+ {RenderSubValue(v)} {i < value.length - 1 && !valueIsNode(v) && !valueIsRelationship(v) ? : <>} -
+ ); }); return mapped;