Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extract NeoDash auth module to an abstract interface to allow for different providers #767

Open
wants to merge 19 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
"mui-color": "^2.0.0-beta.2",
"mui-nested-menu": "^3.2.1",
"neo4j-client-sso": "^1.2.2",
"neo4j-driver": "^5.18.0",
"openai": "^3.3.0",
"postcss": "^8.4.21",
"postcss-loader": "^7.2.4",
Expand Down
128 changes: 69 additions & 59 deletions src/application/Application.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { Suspense, useEffect } from 'react';
import React, { createContext, Suspense, useContext, useEffect } from 'react';
import NeoWelcomeScreenModal from '../modal/WelcomeScreenModal';
import { connect } from 'react-redux';
import {
Expand Down Expand Up @@ -45,6 +45,8 @@ import { downloadComponentAsImage } from '../chart/ChartUtils';
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';
import { resetSessionStorage } from '../sessionStorage/SessionStorageActions';
import { getDashboardTheme } from '../dashboard/DashboardSelectors';
import { ConnectionModuleState } from '../connection/ConnectionModule';
import { getConnectionModule } from '../connection/utils';

const NeoUpgradeOldDashboardModal = React.lazy(() => import('../modal/UpgradeOldDashboardModal'));
const NeoLoadSharedDashboardModal = React.lazy(() => import('../modal/LoadSharedDashboardModal'));
Expand All @@ -53,6 +55,12 @@ const NeoNotificationModal = React.lazy(() => import('../modal/NotificationModal
const NeoAboutModal = React.lazy(() => import('../modal/AboutModal'));
const Dashboard = React.lazy(() => import('../dashboard/Dashboard'));

const ConnectionModuleContext = createContext<ConnectionModuleState>(getConnectionModule());

export function useConnectionModuleContext() {
return useContext<ConnectionModuleState>(ConnectionModuleContext);
}

/**
* This is the main application component for NeoDash.
* It contains:
Expand Down Expand Up @@ -125,66 +133,68 @@ const Application = ({
ref={ref}
className={`n-bg-palette-neutral-bg-default n-h-screen n-w-screen n-flex n-flex-col n-overflow-hidden`}
>
{connected ? (
<ConnectionModuleContext.Provider value={getConnectionModule()}>
{connected ? (
<Suspense fallback=''>
<Dashboard
onDownloadDashboardAsImage={(_) => downloadComponentAsImage(ref)}
onAboutModalOpen={onAboutModalOpen}
resetApplication={resetApplication}
></Dashboard>
</Suspense>
) : (
<NeoDashboardPlaceholder></NeoDashboardPlaceholder>
)}
{/* TODO - move all models into a pop-ups (or modals) component. */}
<Suspense fallback=''>
<NeoAboutModal open={aboutModalOpen} handleClose={onAboutModalClose} getDebugState={getDebugState} />
</Suspense>
<NeoConnectionModal
open={connectionModalOpen}
connected={connected}
dismissable={!standalone}
connection={connection}
ssoSettings={ssoSettings}
standalone={standaloneSettings.standalone}
standaloneSettings={standaloneSettings}
createConnection={createConnection}
onSSOAttempt={onSSOAttempt}
setConnectionProperties={setConnectionDetails}
onConnectionModalClose={onConnectionModalClose}
setWelcomeScreenOpen={setWelcomeScreenOpen}
></NeoConnectionModal>
<NeoWelcomeScreenModal
welcomeScreenOpen={welcomeScreenOpen}
setWelcomeScreenOpen={setWelcomeScreenOpen}
hasCachedDashboard={hasCachedDashboard}
hasNeo4jDesktopConnection={hasNeo4jDesktopConnection}
onConnectionModalOpen={onConnectionModalOpen}
createConnectionFromDesktopIntegration={createConnectionFromDesktopIntegration}
onAboutModalOpen={onAboutModalOpen}
resetDashboard={resetDashboard}
></NeoWelcomeScreenModal>
<Suspense fallback=''>
<NeoUpgradeOldDashboardModal
open={oldDashboard}
text={oldDashboard}
loadDashboard={loadDashboard}
clearOldDashboard={clearOldDashboard}
/>
</Suspense>
<Suspense fallback=''>
<NeoLoadSharedDashboardModal
shareDetails={shareDetails}
onResetShareDetails={onResetShareDetails}
onConfirmLoadSharedDashboard={onConfirmLoadSharedDashboard}
/>
</Suspense>
<Suspense fallback=''>
<NeoReportHelpModal open={reportHelpModalOpen} handleClose={onReportHelpModalClose} />
</Suspense>
<Suspense fallback=''>
<Dashboard
onDownloadDashboardAsImage={(_) => downloadComponentAsImage(ref)}
onAboutModalOpen={onAboutModalOpen}
resetApplication={resetApplication}
></Dashboard>
<NeoNotificationModal></NeoNotificationModal>
</Suspense>
) : (
<NeoDashboardPlaceholder></NeoDashboardPlaceholder>
)}
{/* TODO - move all models into a pop-ups (or modals) component. */}
<Suspense fallback=''>
<NeoAboutModal open={aboutModalOpen} handleClose={onAboutModalClose} getDebugState={getDebugState} />
</Suspense>
<NeoConnectionModal
open={connectionModalOpen}
connected={connected}
dismissable={!standalone}
connection={connection}
ssoSettings={ssoSettings}
standalone={standaloneSettings.standalone}
standaloneSettings={standaloneSettings}
createConnection={createConnection}
onSSOAttempt={onSSOAttempt}
setConnectionProperties={setConnectionDetails}
onConnectionModalClose={onConnectionModalClose}
setWelcomeScreenOpen={setWelcomeScreenOpen}
></NeoConnectionModal>
<NeoWelcomeScreenModal
welcomeScreenOpen={welcomeScreenOpen}
setWelcomeScreenOpen={setWelcomeScreenOpen}
hasCachedDashboard={hasCachedDashboard}
hasNeo4jDesktopConnection={hasNeo4jDesktopConnection}
onConnectionModalOpen={onConnectionModalOpen}
createConnectionFromDesktopIntegration={createConnectionFromDesktopIntegration}
onAboutModalOpen={onAboutModalOpen}
resetDashboard={resetDashboard}
></NeoWelcomeScreenModal>
<Suspense fallback=''>
<NeoUpgradeOldDashboardModal
open={oldDashboard}
text={oldDashboard}
loadDashboard={loadDashboard}
clearOldDashboard={clearOldDashboard}
/>
</Suspense>
<Suspense fallback=''>
<NeoLoadSharedDashboardModal
shareDetails={shareDetails}
onResetShareDetails={onResetShareDetails}
onConfirmLoadSharedDashboard={onConfirmLoadSharedDashboard}
/>
</Suspense>
<Suspense fallback=''>
<NeoReportHelpModal open={reportHelpModalOpen} handleClose={onReportHelpModalClose} />
</Suspense>
<Suspense fallback=''>
<NeoNotificationModal></NeoNotificationModal>
</Suspense>
</ConnectionModuleContext.Provider>
</div>
);
};
Expand Down
30 changes: 18 additions & 12 deletions src/application/ApplicationThunks.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { createDriver } from 'use-neo4j';
import { initializeSSO } from '../component/sso/SSOUtils';
import { DEFAULT_SCREEN, Screens } from '../config/ApplicationConfig';
import { setDashboard } from '../dashboard/DashboardActions';
Expand All @@ -11,7 +10,6 @@ import {
upgradeDashboardVersion,
} from '../dashboard/DashboardThunks';
import { createNotificationThunk } from '../page/PageThunks';
import { runCypherQuery } from '../report/ReportQueryRunner';
import {
setPageNumberThunk,
updateParametersToNeo4jTypeThunk,
Expand Down Expand Up @@ -48,6 +46,8 @@ import { applicationIsStandalone } from './ApplicationSelectors';
import { applicationGetLoggingSettings } from './logging/LoggingSelectors';
import { createLogThunk } from './logging/LoggingThunk';
import { createUUID } from '../utils/uuid';
import { QueryCallback, QueryParams } from '../connection/interfaces';
import { getConnectionModule } from '../connection/utils';

/**
* Application Thunks (https://redux.js.org/usage/writing-logic-thunks) handle complex state manipulations.
Expand All @@ -69,7 +69,15 @@ export const createConnectionThunk =
const loggingSettings = applicationGetLoggingSettings(loggingState);
const neodashMode = applicationIsStandalone(loggingState) ? 'Standalone' : 'Editor';
try {
const driver = createDriver(protocol, url, port, username, password, { userAgent: `neodash/v${version}` });
const { connectionModule } = getConnectionModule();
const driver = connectionModule.createDriver({
scheme: protocol,
host: url,
port,
username,
password,
config: { userAgent: `neodash/v${version}` },
});
// eslint-disable-next-line no-console
console.log('Attempting to connect...');
const validateConnection = (records) => {
Expand Down Expand Up @@ -165,15 +173,13 @@ export const createConnectionThunk =
};
const query = 'RETURN true as connected';
const parameters = {};
runCypherQuery(
driver,
database,
query,
parameters,
1,
() => {},
(records) => validateConnection(records)
);
const queryParams: QueryParams = { query, database, parameters, rowLimit: 1 };

let queryCallback: QueryCallback = {
setRecords: (records) => validateConnection(records),
};

connectionModule.runQuery(driver, queryParams, queryCallback);
} catch (e) {
dispatch(createNotificationThunk('Unable to establish connection', e));
}
Expand Down
21 changes: 10 additions & 11 deletions src/application/logging/LoggingThunk.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { createNotificationThunk } from '../../page/PageThunks';
import { runCypherQuery } from '../../report/ReportQueryRunner';
import { setLogErrorNotification } from './LoggingActions';
import { applicationGetLoggingSettings } from './LoggingSelectors';
import { createUUID } from '../../utils/uuid';
import { QueryCallback, QueryParams } from '../../connection/interfaces';
import { getConnectionModule } from '../../connection/utils';

// Thunk to handle log events.

export const createLogThunk =
(loggingDriver, loggingDatabase, neodashMode, logUser, logAction, logDatabase, logDashboard = '', logMessage) =>
(dispatch: any, getState: any) => {
try {
const { connectionModule } = getConnectionModule();
const uuid = createUUID();
// Generate a cypher query to save the log.
const query =
Expand All @@ -24,14 +26,10 @@ export const createLogThunk =
logDashboard: logDashboard,
logMessage: logMessage,
};
runCypherQuery(
loggingDriver,
loggingDatabase,
query,
parameters,
1,
() => {},
(records) => {

const queryParams: QueryParams = { query, database: loggingDatabase, parameters, rowLimit: 1 };
const queryCallback: QueryCallback = {
setRecords: (records) => {
if (records && records[0] && records[0]._fields && records[0]._fields[0] && records[0]._fields[0] == uuid) {
console.log(`log created: ${uuid}`);
} else {
Expand All @@ -53,8 +51,9 @@ export const createLogThunk =
LogErrorNotificationNum -= 1;
dispatch(setLogErrorNotification(LogErrorNotificationNum.toString()));
}
}
);
},
};
connectionModule.runQuery(loggingDriver, queryParams, queryCallback);
} catch (e) {
// we only show error notification 3 times
const state = getState();
Expand Down
5 changes: 2 additions & 3 deletions src/chart/ChartUtils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import domtoimage from 'dom-to-image';
import { Date as Neo4jDate } from 'neo4j-driver-core/lib/temporal-types.js';
import { QueryResult, Record as Neo4jRecord } from 'neo4j-driver';
import { RenderSubValue } from '../report/ReportRecordProcessing';

/**
* Converts a neo4j record entry to a readable string representation.
Expand Down Expand Up @@ -249,9 +251,6 @@ export const downloadComponentAsImage = (ref) => {
});
};

import { QueryResult, Record as Neo4jRecord } from 'neo4j-driver';
import { RenderSubValue } from '../report/ReportRecordProcessing';

/**
* Function to cast a value received from the Neo4j Driver to its TS native type
* @param input Value to cast
Expand Down
28 changes: 18 additions & 10 deletions src/chart/parameter/ParameterSelectCardSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

import React, { useCallback, useContext, useEffect } from 'react';
import { RUN_QUERY_DELAY_MS } from '../../config/ReportConfig';
import { QueryStatus, runCypherQuery } from '../../report/ReportQueryRunner';
import { Neo4jContext, Neo4jContextState } from 'use-neo4j/dist/neo4j.context';
import { Autocomplete, debounce, TextField } from '@mui/material';
import NeoField from '../../component/field/Field';
import { Dropdown } from '@neo4j-ndl/react';
import NeoCodeEditorComponent from '../../component/editor/CodeEditorComponent';
import { QueryCallback, QueryParams, QueryStatus } from '../../connection/interfaces';
import { useConnectionModuleContext } from '../../application/Application';

type ParameterId = string | undefined | null;

Expand All @@ -18,10 +19,11 @@ const ParameterSelectCardSettings = ({ query, database, settings, onReportSettin
'`driver` not defined. Have you added it into your app as <Neo4jContext.Provider value={{driver}}> ?'
);
}
const { connectionModule } = useConnectionModuleContext();

const [queryText, setQueryText] = React.useState(query);
const debouncedQueryUpdate = useCallback(debounce(onQueryUpdate, 250), []);
const debouncedRunCypherQuery = useCallback(debounce(runCypherQuery, RUN_QUERY_DELAY_MS), []);
const debouncedRunQuery = useCallback(debounce(connectionModule.runQuery, RUN_QUERY_DELAY_MS), []);

const { manualPropertyNameSpecification } = settings;
const [labelInputText, setLabelInputText] = React.useState(settings.entityType);
Expand Down Expand Up @@ -60,21 +62,27 @@ const ParameterSelectCardSettings = ({ query, database, settings, onReportSettin

onReportSettingUpdate('parameterName', parameterName);
}
// Define query callback to allow reports to get extra data on interactions.

const queryCallback = useCallback(
(query, parameters, setRecords) => {
debouncedRunCypherQuery(
driver,
let queryParams: QueryParams = {
database,
query,
parameters,
10,
(status) => {
rowLimit: 10,
fields: [],
};

let queryCallback: QueryCallback = {
setStatus: (status) => {
status == QueryStatus.NO_DATA ? setRecords([]) : () => {};
},
(result) => setRecords(result),
() => {}
);
setRecords,
setFields: () => {},
setSchema: () => {},
};

debouncedRunQuery(driver, queryParams, queryCallback);
},
[database]
);
Expand Down
1 change: 1 addition & 0 deletions src/chart/table/TableChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { ThemeProvider, createTheme } from '@mui/material/styles';
import Button from '@mui/material/Button';
import { extensionEnabled } from '../../utils/ReportUtils';
import { getCheckboxes, hasCheckboxes, updateCheckBoxes } from './TableActionsHelper';
import { Neo4jRecordParser } from '../../connection/neo4j/Neo4jRecordParser';

const TABLE_HEADER_HEIGHT = 32;
const TABLE_FOOTER_HEIGHT = 62;
Expand Down
Loading
Loading