diff --git a/src/card/CardActions.ts b/src/card/CardActions.ts index 8b4fa765e..9a1489443 100644 --- a/src/card/CardActions.ts +++ b/src/card/CardActions.ts @@ -91,3 +91,9 @@ export const updateReportDatabase = (pagenumber: number, id: number, database: a type: UPDATE_REPORT_DATABASE, payload: { pagenumber, id, database }, }); + +export const UPDATE_LAST_POPULATE_QUERY_TIMESTAMP = 'PAGE/CARD/UPDATE_LAST_POPULATE_QUERY_TIMESTAMP'; +export const updateLastPopulateQueryTimestamp = (pagenumber: number, id: number, timestamp: number) => ({ + type: UPDATE_LAST_POPULATE_QUERY_TIMESTAMP, + payload: { pagenumber, id, lastPopulateQueryTimestamp: timestamp }, +}); diff --git a/src/card/CardReducer.ts b/src/card/CardReducer.ts index 9679b088e..c574eb9d0 100644 --- a/src/card/CardReducer.ts +++ b/src/card/CardReducer.ts @@ -13,6 +13,7 @@ import { UPDATE_REPORT_TYPE, UPDATE_SELECTION, UPDATE_REPORT_DATABASE, + UPDATE_LAST_POPULATE_QUERY_TIMESTAMP, } from './CardActions'; import { TOGGLE_CARD_SETTINGS } from './CardActions'; import { createUUID } from '../utils/uuid'; @@ -38,6 +39,7 @@ export const CARD_INITIAL_STATE = { selection: {}, settings: {}, collapseTimeout: 'auto', + lastPopulateQueryTimestamp: -1, }; export const cardReducer = (state = CARD_INITIAL_STATE, action: { type: any; payload: any }) => { @@ -48,6 +50,11 @@ export const cardReducer = (state = CARD_INITIAL_STATE, action: { type: any; pay } switch (type) { + case UPDATE_LAST_POPULATE_QUERY_TIMESTAMP: { + const { lastPopulateQueryTimestamp } = payload; + state = update(state, { lastPopulateQueryTimestamp }); + return state; + } case UPDATE_REPORT_TITLE: { const { title } = payload; state = update(state, { title: title }); diff --git a/src/card/CardThunks.ts b/src/card/CardThunks.ts index 18c68ae74..7d72f31fe 100644 --- a/src/card/CardThunks.ts +++ b/src/card/CardThunks.ts @@ -182,3 +182,15 @@ export const updateReportSettingThunk = (id, setting, value) => (dispatch: any, dispatch(createNotificationThunk('Error when updating report settings', e)); } }; + +/** GET thunk semaphore to be able to retrieve last timestamp to prevent displaying stale result */ +export const getLastPopulateQueryTimestampThunk = (id) => (dispatch: any, getState: any) => { + try { + const state = getState(); + const { pagenumber } = state.dashboard.settings; + const report = state.dashboard.pages[pagenumber].reports.find((o) => o.id === id); + return report ? report.lastPopulateQueryTimestamp : -1; + } catch (e) { + dispatch(createNotificationThunk('error', e)); + } +}; diff --git a/src/report/Report.tsx b/src/report/Report.tsx index 1255a3cb3..a61dc84cb 100644 --- a/src/report/Report.tsx +++ b/src/report/Report.tsx @@ -18,8 +18,10 @@ import { EXTENSIONS } from '../extensions/ExtensionConfig'; import { getPageNumber } from '../settings/SettingsSelectors'; import { getPrepopulateReportExtension } from '../extensions/state/ExtensionSelectors'; import { deleteSessionStoragePrepopulationReportFunction } from '../extensions/state/ExtensionActions'; -import { updateFieldsThunk } from '../card/CardThunks'; +import { getLastPopulateQueryTimestampThunk, updateFieldsThunk } from '../card/CardThunks'; import { getDashboardTheme } from '../dashboard/DashboardSelectors'; +import { getReportState } from '../card/CardSelectors'; +import { updateLastPopulateQueryTimestamp } from '../card/CardActions'; export const REPORT_LOADING_ICON = ; @@ -56,6 +58,9 @@ export const NeoReport = ({ prepopulateExtensionName, deletePrepopulationReportFunction, theme, + report, + setLastPopulateQueryTimestamp, + getLastTimestampDispatch, }) => { const [records, setRecords] = useState(null); const [timer, setTimer] = useState(null); @@ -67,6 +72,7 @@ export const NeoReport = ({ '`driver` not defined. Have you added it into your app as ?' ); } + const getLastTimestampDispatchWrap = () => getLastTimestampDispatch(id); const debouncedRunCypherQuery = useCallback(debounce(runCypherQuery, RUN_QUERY_DELAY_MS), []); const setSchema = (id, schema) => { @@ -111,6 +117,11 @@ export const NeoReport = ({ // Logic to run a query const executeQuery = (newQuery) => { setLoadingIcon(REPORT_LOADING_ICON); + + const ts = Date.now(); + if (!report.lastPopulateQueryTimestamp || ts > report.lastPopulateQueryTimestamp) { + setLastPopulateQueryTimestamp(pagenumber, id, ts); + } if (debounced) { debouncedRunCypherQuery( driver, @@ -128,7 +139,9 @@ export const NeoReport = ({ queryTimeLimit, (schema) => { setSchema(id, schema); - } + }, + ts, + getLastTimestampDispatchWrap ); } else { runCypherQuery( @@ -147,7 +160,9 @@ export const NeoReport = ({ queryTimeLimit, (schema) => { setSchema(id, schema); - } + }, + ts, + getLastTimestampDispatchWrap ); } }; @@ -342,6 +357,7 @@ export const NeoReport = ({ }; const mapStateToProps = (state, ownProps) => ({ + report: getReportState(state, ownProps.id), pagenumber: getPageNumber(state), prepopulateExtensionName: getPrepopulateReportExtension(state, ownProps.id), theme: getDashboardTheme(state), @@ -360,6 +376,12 @@ const mapDispatchToProps = (dispatch) => ({ setSchemaDispatch: (id: any, schema: any) => { dispatch(updateFieldsThunk(id, schema, true)); }, + setLastPopulateQueryTimestamp: (pageNumber: any, id: any, ts: number) => { + dispatch(updateLastPopulateQueryTimestamp(pageNumber, id, ts)); + }, + getLastTimestampDispatch: (id: any) => { + return dispatch(getLastPopulateQueryTimestampThunk(id)); + }, }); export default connect(mapStateToProps, mapDispatchToProps)(NeoReport); diff --git a/src/report/ReportQueryRunner.ts b/src/report/ReportQueryRunner.ts index 599e4afde..6265fda4d 100644 --- a/src/report/ReportQueryRunner.ts +++ b/src/report/ReportQueryRunner.ts @@ -53,7 +53,9 @@ export async function runCypherQuery( setSchema = () => { // eslint-disable-next-line no-console // console.log(`Query runner attempted to set schema: ${JSON.stringify(schema)}`); - } + }, + thisPopulateQueryTimestamp = -1, + getLastTimestampDispatch ) { // If no query specified, we don't do anything. if (query.trim() == '') { @@ -121,7 +123,16 @@ export async function runCypherQuery( return; } setStatus(QueryStatus.COMPLETE); - setRecords(records); + if (getLastTimestampDispatch && typeof getLastTimestampDispatch === 'function') { + const lastTimestamp = getLastTimestampDispatch(); + // console.log(thisPopulateQueryTimestamp, `Query complete, report.lastQueryTs =`, lastTimestamp); + if (!lastTimestamp || thisPopulateQueryTimestamp >= lastTimestamp) { + setRecords(records); + } + } else { + setRecords(records); + } + // console.log("TODO remove this - QUERY WAS EXECUTED SUCCESFULLY!") transaction.commit();