From d3f24b2bfd895c4afa42d3851b197ff2ff622209 Mon Sep 17 00:00:00 2001 From: Jacob Suhr Date: Mon, 10 Jun 2024 22:05:35 +1000 Subject: [PATCH] Add new method of fetching scenarios using fetchScenariosPost which allows filtering by any item on the scenario during the Post. Add this methodology into the ScenariosOld component allowing users to input the QueryFilter as a prop which scenarios will then be fetched using. This allows for more efficient fetching of data as only the scenarios matching the required filters are pulled across, reducing required filtering on the frontend and load on the api. --- .../src/Scenarios/ScenariosOLD/Scenarios.tsx | 62 ++++++++++++++++--- .../src/Scenarios/ScenariosOLD/types.ts | 6 +- .../src/api/Scenarios/ScenariosApi.ts | 27 +++++++- packages/react-components/src/api/types.ts | 14 ++++- 4 files changed, 95 insertions(+), 14 deletions(-) diff --git a/packages/react-components/src/Scenarios/ScenariosOLD/Scenarios.tsx b/packages/react-components/src/Scenarios/ScenariosOLD/Scenarios.tsx index c656e72d..3d6b2fa9 100644 --- a/packages/react-components/src/Scenarios/ScenariosOLD/Scenarios.tsx +++ b/packages/react-components/src/Scenarios/ScenariosOLD/Scenarios.tsx @@ -10,7 +10,7 @@ import { postScenario, updateScenario, } from '../../api'; -import { JobParameters } from '../../api/types'; +import { JobParameters, QueryFilter } from '../../api/types'; import GeneralDialog from '../../common/GeneralDialog/GeneralDialog'; import GeneralDialogProps from '../../common/GeneralDialog/types'; import { checkConditions, getObjectProperty, setObjectProperty } from '../../utils/Utils'; @@ -18,6 +18,7 @@ import { ScenarioListOLD } from '../ScenarioListOLD/ScenarioList'; import { MenuItem, QueryDates, ScenarioOLD } from '../types'; import ScenariosOLDProps from './types'; import useStyles from './useStyles'; +import { fetchScenariosPost } from '../../api/Scenarios/ScenariosApi'; const ScenariosOLD = (props: ScenariosOLDProps) => { const { @@ -41,6 +42,7 @@ const ScenariosOLD = (props: ScenariosOLDProps) => { showStatus, status, queryDates, + queryFilter, frequency = 10, onContextMenuClick, onScenarioSelected, @@ -61,10 +63,10 @@ const ScenariosOLD = (props: ScenariosOLDProps) => { useEffect(() => { let interval: ReturnType; - if (queryDates) { - fetchScenariosByDateList(queryDates); + if (queryDates || queryFilter) { + fetchScenariosByQuery(queryDates, queryFilter); - interval = setInterval(() => fetchScenariosByDateList(queryDates), frequency * 1000); + interval = setInterval(() => fetchScenariosByQuery(queryDates, queryFilter), frequency * 1000); } else { fetchScenariosList(); @@ -98,18 +100,58 @@ const ScenariosOLD = (props: ScenariosOLDProps) => { } }, [addScenario]); - const fetchScenariosByDateList = (queryDates: QueryDates) => { + const fetchScenariosByQuery = (queryDates: QueryDates, queryFilter?: QueryFilter[]) => { + const dataSelectors = [ + nameField, + ...descriptionFields!.map((descriptionField) => descriptionField.field), + ...extraFields!.map((descriptionField) => descriptionField.field), + ]; + if (queryFilter) { + fetchScenariosByQueryFilter(queryFilter, dataSelectors); + } else { + fetchScenariosByDateList(queryDates, dataSelectors); + } + } + + const fetchScenariosByQueryFilter = (queryFilter: QueryFilter[], dataSelectors: any[]) => { + fetchScenariosPost( + { + host, + connection: scenarioConnection, + dataSelectors, + queryFilter, + }, + token, + ).subscribe( + (res) => { + const rawScenarios = res.map((s: { data: string }) => { + s.data = s.data ? JSON.parse(s.data) : s.data; + + return s; + }); + + const newScenarios = rawScenarios.filter((scenario) => checkConditions(scenario, dataFilterbyProperty)); + + setScenarios(newScenarios); + + if (onScenariosReceived) { + onScenariosReceived(newScenarios); + } + }, + (error) => { + console.log(error); + }, + ); + } + + const fetchScenariosByDateList = (queryDates: QueryDates, dataSelectors: any[]) => { fetchScenariosByDate( { host, connection: scenarioConnection, from: queryDates.from, to: queryDates.to, - dataSelectors: [ - nameField, - ...descriptionFields!.map((descriptionField) => descriptionField.field), - ...extraFields!.map((descriptionField) => descriptionField.field), - ], + dataSelectors, }, token, ).subscribe( diff --git a/packages/react-components/src/Scenarios/ScenariosOLD/types.ts b/packages/react-components/src/Scenarios/ScenariosOLD/types.ts index fb40c6e8..b218fada 100644 --- a/packages/react-components/src/Scenarios/ScenariosOLD/types.ts +++ b/packages/react-components/src/Scenarios/ScenariosOLD/types.ts @@ -1,4 +1,4 @@ -import { JobParameters } from '../../api/types'; +import { JobParameters, QueryFilter } from '../../api/types'; import { DescriptionField, MenuItem, QueryDates, Scenario, Status, StatusOverride } from '../types'; interface ScenariosOLDProps { @@ -72,6 +72,10 @@ interface ScenariosOLDProps { * Value range to fetch scenario by date */ queryDates?: QueryDates; + /** + * Query filters to use when fetching the scenarios data. + */ + queryFilter?: QueryFilter[]; /** * Customising translation dialog */ diff --git a/packages/react-components/src/api/Scenarios/ScenariosApi.ts b/packages/react-components/src/api/Scenarios/ScenariosApi.ts index 26993e71..aec5540f 100644 --- a/packages/react-components/src/api/Scenarios/ScenariosApi.ts +++ b/packages/react-components/src/api/Scenarios/ScenariosApi.ts @@ -1,6 +1,5 @@ import { tap } from 'rxjs/operators'; import { DataSource } from '../../api/types'; -import { ScenarioItem } from '../../Scenarios/ScenarioItem/ScenarioItem'; import { fetchUrl } from '../helpers'; /** @@ -40,6 +39,30 @@ const fetchScenarios = (dataSource: DataSource, token: string) => { }); }; +/** + * /api/scenarios/{connectionId}/query + * Gets all scenarios that match the given filtering criteria: + * @param dataSource + * @param filtering + * @param token + */ +const fetchScenariosPost = (dataSource: DataSource, token: string) => { + const dataSelectors = + dataSource.dataSelectors && dataSource.dataSelectors.length > 0 + ? `?dataSelectors=[${dataSource.dataSelectors + .map((dataSelector) => dataSelector.replace('data.', '')) + .join(',')}]` + : ''; + + return fetchUrl(`${dataSource.host}/api/scenarios/${dataSource.connection}/query${dataSelectors}`, { + method: 'Post', + additionalHeaders: { + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify(dataSource?.queryFilter), + }); +}; + /** * /api/scenarios/{connectionId} * Gets all scenarios within the given time span @@ -126,4 +149,4 @@ const updateScenario = (dataSource: DataSource, token: string, scenario: any) => body: JSON.stringify(scenario), }); -export { fetchScenario, fetchScenarios, fetchScenariosByDate, deleteScenario, postScenario, updateScenario }; +export { fetchScenario, fetchScenarios, fetchScenariosPost, fetchScenariosByDate, deleteScenario, postScenario, updateScenario }; diff --git a/packages/react-components/src/api/types.ts b/packages/react-components/src/api/types.ts index 4951c6fa..53d59ba0 100644 --- a/packages/react-components/src/api/types.ts +++ b/packages/react-components/src/api/types.ts @@ -25,6 +25,10 @@ interface DataSource { * Format: new Date(); */ to?: string; + /** + * Query filters to apply to the request. + */ + queryFilter?: QueryFilter[]; sheetName?: string; tokenJobLog?: string; hostJobLog?: string; @@ -71,4 +75,12 @@ interface JobParameters { [key: string]: string | string[]; } -export { Options, DataSource, Header, JobQuery, JobParameters, User }; + +interface QueryFilter { + item: string; + queryOperator: string; + value: string; + negation?: boolean; +} + +export { Options, DataSource, Header, JobQuery, JobParameters, User, QueryFilter };