From 72ca275652d381e2d611e18cb60e9a54a1109e1b Mon Sep 17 00:00:00 2001 From: Giran Moodley Date: Sun, 5 Jun 2022 14:41:43 +0100 Subject: [PATCH 01/10] Initial commit of working branch - testing to be added. --- src/App.js | 18 +-- .../ConfirmQueryModalComponent.js | 79 ++++++++++ .../IncidentTable/IncidentTableComponent.js | 30 ++-- .../subcomponents/QueryActiveComponent.js | 17 ++ .../subcomponents/QueryCancelledComponent.js | 18 +++ src/config/constants.js | 1 + src/redux/incidents/sagas.js | 32 ++-- src/redux/persistence/config.js | 8 +- src/redux/query_settings/actions.js | 22 +++ src/redux/query_settings/reducers.js | 53 +++++++ src/redux/query_settings/sagas.js | 147 ++++++++++++++++-- src/redux/rootSaga.js | 8 + 12 files changed, 370 insertions(+), 63 deletions(-) create mode 100644 src/components/ConfirmQueryModal/ConfirmQueryModalComponent.js create mode 100644 src/components/IncidentTable/subcomponents/QueryActiveComponent.js create mode 100644 src/components/IncidentTable/subcomponents/QueryCancelledComponent.js diff --git a/src/App.js b/src/App.js index ba3f8ef4..068f38f0 100644 --- a/src/App.js +++ b/src/App.js @@ -22,11 +22,8 @@ import AddNoteModalComponent from 'components/AddNoteModal/AddNoteModalComponent import ReassignModalComponent from 'components/ReassignModal/ReassignModalComponent'; import AddResponderModalComponent from 'components/AddResponderModal/AddResponderModalComponent'; import MergeModalComponent from 'components/MergeModal/MergeModalComponent'; +import ConfirmQueryModalComponent from 'components/ConfirmQueryModal/ConfirmQueryModalComponent'; -import { - getIncidentsAsync as getIncidentsAsyncConnected, - getAllIncidentNotesAsync as getAllIncidentNotesAsyncConnected, -} from 'redux/incidents/actions'; import { getLogEntriesAsync as getLogEntriesAsyncConnected, cleanRecentLogEntriesAsync as cleanRecentLogEntriesAsyncConnected, @@ -90,8 +87,6 @@ const App = ({ getEscalationPoliciesAsync, getExtensionsAsync, getResponsePlaysAsync, - getIncidentsAsync, - getAllIncidentNotesAsync, getLogEntriesAsync, cleanRecentLogEntriesAsync, }) => { @@ -108,6 +103,7 @@ const App = ({ const { userAuthorized, userAcceptedDisclaimer, currentUserLocale, } = state.users; + const queryError = state.querySettings.error; useEffect(() => { userAuthorize(); if (userAuthorized) { @@ -120,8 +116,7 @@ const App = ({ getExtensionsAsync(); getResponsePlaysAsync(); getPrioritiesAsync(); - getIncidentsAsync(); - getAllIncidentNotesAsync(); + // NB: Get Incidents and Notes are implicitly done from query now checkConnectionStatus(); } }, [userAuthorized]); @@ -139,7 +134,7 @@ const App = ({ const { abilities, } = store.getState().connection; - if (userAuthorized && abilities.includes(PD_REQUIRED_ABILITY)) { + if (userAuthorized && abilities.includes(PD_REQUIRED_ABILITY) && !queryError) { const lastPolledDate = moment() .subtract(2 * LOG_ENTRIES_POLLING_INTERVAL_SECONDS, 'seconds') .toDate(); @@ -147,7 +142,7 @@ const App = ({ } }, LOG_ENTRIES_POLLING_INTERVAL_SECONDS * 1000); return () => clearInterval(pollingInterval); - }, [userAuthorized]); + }, [userAuthorized, queryError]); // Setup log entry clearing useEffect(() => { @@ -191,6 +186,7 @@ const App = ({ + ); @@ -210,8 +206,6 @@ const mapDispatchToProps = (dispatch) => ({ getEscalationPoliciesAsync: () => dispatch(getEscalationPoliciesAsyncConnected()), getExtensionsAsync: () => dispatch(getExtensionsAsyncConnected()), getResponsePlaysAsync: () => dispatch(getResponsePlaysAsyncConnected()), - getIncidentsAsync: () => dispatch(getIncidentsAsyncConnected()), - getAllIncidentNotesAsync: () => dispatch(getAllIncidentNotesAsyncConnected()), getLogEntriesAsync: (since) => dispatch(getLogEntriesAsyncConnected(since)), cleanRecentLogEntriesAsync: () => dispatch(cleanRecentLogEntriesAsyncConnected()), }); diff --git a/src/components/ConfirmQueryModal/ConfirmQueryModalComponent.js b/src/components/ConfirmQueryModal/ConfirmQueryModalComponent.js new file mode 100644 index 00000000..e1b6caaf --- /dev/null +++ b/src/components/ConfirmQueryModal/ConfirmQueryModalComponent.js @@ -0,0 +1,79 @@ +import { + connect, +} from 'react-redux'; + +import { + Modal, Button, +} from 'react-bootstrap'; + +import { + toggleDisplayConfirmQueryModal as toggleDisplayConfirmQueryModalConnected, + confirmIncidentQuery as confirmIncidentQueryConnected, +} from 'redux/query_settings/actions'; + +import { + MAX_INCIDENTS_LIMIT, +} from 'config/constants'; + +const ConfirmQueryModalComponent = ({ + querySettings, + toggleDisplayConfirmQueryModal, + confirmIncidentQuery, +}) => { + const { + displayConfirmQueryModal, totalIncidentsFromQuery, + } = querySettings; + + const handleCancel = () => { + confirmIncidentQuery(false); + toggleDisplayConfirmQueryModal(); + }; + + return ( +
+ + + Max Incidents Limit Reached + + + Current query parameters match  + {totalIncidentsFromQuery} +  incidents. +
+ Only the first  + {MAX_INCIDENTS_LIMIT} +  incidents will be retrieved. +
+
+ Continue? +
+ + + + +
+
+ ); +}; + +const mapStateToProps = (state) => ({ + querySettings: state.querySettings, +}); + +const mapDispatchToProps = (dispatch) => ({ + toggleDisplayConfirmQueryModal: () => dispatch(toggleDisplayConfirmQueryModalConnected()), + confirmIncidentQuery: (confirm) => dispatch(confirmIncidentQueryConnected(confirm)), +}); + +export default connect(mapStateToProps, mapDispatchToProps)(ConfirmQueryModalComponent); diff --git a/src/components/IncidentTable/IncidentTableComponent.js b/src/components/IncidentTable/IncidentTableComponent.js index 366beae4..f5cd1b81 100644 --- a/src/components/IncidentTable/IncidentTableComponent.js +++ b/src/components/IncidentTable/IncidentTableComponent.js @@ -18,9 +18,6 @@ import { FixedSizeList, } from 'react-window'; -import { - Container, Row, Spinner, -} from 'react-bootstrap'; import BTable from 'react-bootstrap/Table'; import { @@ -38,6 +35,8 @@ import { import CheckboxComponent from './subcomponents/CheckboxComponent'; import EmptyIncidentsComponent from './subcomponents/EmptyIncidentsComponent'; +import QueryActiveComponent from './subcomponents/QueryActiveComponent'; +import QueryCancelledComponent from './subcomponents/QueryCancelledComponent'; import './IncidentTableComponent.scss'; @@ -76,6 +75,7 @@ const IncidentTableComponent = ({ incidentTable, incidentActions, incidents, + querySettings, }) => { const { incidentTableState, incidentTableColumnsNames, @@ -86,6 +86,9 @@ const IncidentTableComponent = ({ const { filteredIncidentsByQuery, fetchingIncidents, } = incidents; + const { + displayConfirmQueryModal, + } = querySettings; // React Table Config const defaultColumn = useMemo( @@ -247,18 +250,16 @@ const IncidentTableComponent = ({ }, [status]); // Render components based on application state + if (displayConfirmQueryModal) { + return <>; + } + + if (!displayConfirmQueryModal && querySettings.error) { + return ; + } + if (fetchingIncidents) { - return ( - -
- - -
- Querying PagerDuty API -
-
-
- ); + return ; } // TODO: Find a better way to prevent Empty Incidents from being shown during render @@ -325,6 +326,7 @@ const mapStateToProps = (state) => ({ incidentTable: state.incidentTable, incidentActions: state.incidentActions, incidents: state.incidents, + querySettings: state.querySettings, }); const mapDispatchToProps = (dispatch) => ({ diff --git a/src/components/IncidentTable/subcomponents/QueryActiveComponent.js b/src/components/IncidentTable/subcomponents/QueryActiveComponent.js new file mode 100644 index 00000000..2a50403c --- /dev/null +++ b/src/components/IncidentTable/subcomponents/QueryActiveComponent.js @@ -0,0 +1,17 @@ +import { + Container, Row, Spinner, +} from 'react-bootstrap'; + +const QueryActiveComponent = () => ( + +
+ + +
+ Querying PagerDuty API +
+
+
+); + +export default QueryActiveComponent; diff --git a/src/components/IncidentTable/subcomponents/QueryCancelledComponent.js b/src/components/IncidentTable/subcomponents/QueryCancelledComponent.js new file mode 100644 index 00000000..21c75a4e --- /dev/null +++ b/src/components/IncidentTable/subcomponents/QueryCancelledComponent.js @@ -0,0 +1,18 @@ +import { + Container, Row, Alert, +} from 'react-bootstrap'; + +const QueryCancelledComponent = () => ( + +
+ + +

+ Query has been cancelled by user +

+
+
+
+); + +export default QueryCancelledComponent; diff --git a/src/config/constants.js b/src/config/constants.js index 1efd8d92..46b73931 100644 --- a/src/config/constants.js +++ b/src/config/constants.js @@ -24,6 +24,7 @@ export const DD_DEFAULT_PRIVACY_LEVEL = env.REACT_APP_DD_DEFAULT_PRIVACY_LEVEL | export const LOG_ENTRIES_POLLING_INTERVAL_SECONDS = 5; export const LOG_ENTRIES_CLEARING_INTERVAL_SECONDS = 30; export const INCIDENTS_PAGINATION_LIMIT = 100; +export const MAX_INCIDENTS_LIMIT = 200; // Date formatting (Locale Agnostic) export const DATE_FORMAT = 'LL \\at h:mm:ss A'; diff --git a/src/redux/incidents/sagas.js b/src/redux/incidents/sagas.js index fb25f08e..a14b291e 100644 --- a/src/redux/incidents/sagas.js +++ b/src/redux/incidents/sagas.js @@ -17,19 +17,14 @@ import { pushToArray, } from 'util/helpers'; import fuseOptions from 'config/fuse-config'; +import { + MAX_INCIDENTS_LIMIT, +} from 'config/constants'; import selectQuerySettings from 'redux/query_settings/selectors'; import { UPDATE_CONNECTION_STATUS_REQUESTED, } from 'redux/connection/actions'; -import { - UPDATE_QUERY_SETTING_SINCE_DATE_COMPLETED, - UPDATE_QUERY_SETTING_INCIDENT_STATUS_COMPLETED, - UPDATE_QUERY_SETTING_INCIDENT_URGENCY_COMPLETED, - UPDATE_QUERY_SETTING_INCIDENT_PRIORITY_COMPLETED, - UPDATE_QUERY_SETTINGS_TEAMS_COMPLETED, - UPDATE_QUERY_SETTINGS_SERVICES_COMPLETED, -} from 'redux/query_settings/actions'; import { FETCH_INCIDENTS_REQUESTED, FETCH_INCIDENTS_COMPLETED, @@ -77,16 +72,6 @@ export function* getIncidentsAsync() { } export function* getIncidents() { - // Wait for query actions to have been completed. - take([ - UPDATE_QUERY_SETTING_SINCE_DATE_COMPLETED, - UPDATE_QUERY_SETTING_INCIDENT_STATUS_COMPLETED, - UPDATE_QUERY_SETTING_INCIDENT_URGENCY_COMPLETED, - UPDATE_QUERY_SETTING_INCIDENT_PRIORITY_COMPLETED, - UPDATE_QUERY_SETTINGS_TEAMS_COMPLETED, - UPDATE_QUERY_SETTINGS_SERVICES_COMPLETED, - ]); - try { // Build params from query settings and call pd lib const { @@ -103,20 +88,21 @@ export function* getIncidents() { since: sinceDate.toISOString(), until: new Date().toISOString(), include: ['first_trigger_log_entries', 'external_references'], + limit: MAX_INCIDENTS_LIMIT, // FIXME: This applies limit per batched call }; if (incidentStatus) params.statuses = incidentStatus; - if (incidentUrgency) params.urgencies = incidentUrgency; - if (teamIds.length) params.team_ids = teamIds; - if (serviceIds.length) params.service_ids = serviceIds; - const incidents = yield pdParallelFetch('incidents', params); + const fetchedIncidents = yield pdParallelFetch('incidents', params); // Sort incidents by reverse created_at date (i.e. recent incidents at the top) - incidents.sort((a, b) => new Date(b.created_at) - new Date(a.created_at)); + fetchedIncidents.sort((a, b) => new Date(b.created_at) - new Date(a.created_at)); + + // FIXME: Temporary fix for batched calls over prescribed limit + const incidents = fetchedIncidents.slice(0, MAX_INCIDENTS_LIMIT); yield put({ type: FETCH_INCIDENTS_COMPLETED, diff --git a/src/redux/persistence/config.js b/src/redux/persistence/config.js index 2de6655f..22ca76fb 100644 --- a/src/redux/persistence/config.js +++ b/src/redux/persistence/config.js @@ -23,7 +23,13 @@ export const persistConfig = { export const querySettingsPersistConfig = { key: 'querySettings', storage, - blacklist: ['sinceDate', 'untilDate'], + blacklist: [ + 'sinceDate', + 'untilDate', + 'displayConfirmQueryModal', + 'totalIncidentsFromQuery', + 'error', + ], }; export const userPersistConfig = { diff --git a/src/redux/query_settings/actions.js b/src/redux/query_settings/actions.js index f5627759..6ad38524 100644 --- a/src/redux/query_settings/actions.js +++ b/src/redux/query_settings/actions.js @@ -24,6 +24,19 @@ export const UPDATE_QUERY_SETTINGS_SERVICES_COMPLETED = 'UPDATE_QUERY_SETTINGS_S export const UPDATE_SEARCH_QUERY_REQUESTED = 'UPDATE_SEARCH_QUERY_REQUESTED'; export const UPDATE_SEARCH_QUERY_COMPLETED = 'UPDATE_SEARCH_QUERY_COMPLETED'; +export const VALIDATE_INCIDENT_QUERY_REQUESTED = 'VALIDATE_INCIDENT_QUERY_REQUESTED'; +export const VALIDATE_INCIDENT_QUERY_COMPLETED = 'VALIDATE_INCIDENT_QUERY_COMPLETED'; + +export const TOGGLE_DISPLAY_CONFIRM_QUERY_MODAL_REQUESTED = 'TOGGLE_DISPLAY_CONFIRM_QUERY_MODAL_REQUESTED'; +export const TOGGLE_DISPLAY_CONFIRM_QUERY_MODAL_COMPLETED = 'TOGGLE_DISPLAY_CONFIRM_QUERY_MODAL_COMPLETED'; + +export const UPDATE_TOTAL_INCIDENTS_FROM_QUERY_REQUESTED = 'UPDATE_TOTAL_INCIDENTS_FROM_QUERY_REQUESTED'; +export const UPDATE_TOTAL_INCIDENTS_FROM_QUERY_COMPLETED = 'UPDATE_TOTAL_INCIDENTS_FROM_QUERY_COMPLETED'; + +export const CONFIRM_INCIDENT_QUERY_REQUESTED = 'CONFIRM_INCIDENT_QUERY_REQUESTED'; +export const CONFIRM_INCIDENT_QUERY_COMPLETED = 'CONFIRM_INCIDENT_QUERY_COMPLETED'; +export const CONFIRM_INCIDENT_QUERY_ERROR = 'CONFIRM_INCIDENT_QUERY_ERROR'; + // Define Actions export const toggleDisplayQuerySettings = () => ({ type: TOGGLE_DISPLAY_QUERY_SETTINGS_REQUESTED, @@ -63,3 +76,12 @@ export const updateSearchQuery = (searchQuery) => ({ type: UPDATE_SEARCH_QUERY_REQUESTED, searchQuery, }); + +export const toggleDisplayConfirmQueryModal = () => ({ + type: TOGGLE_DISPLAY_CONFIRM_QUERY_MODAL_REQUESTED, +}); + +export const confirmIncidentQuery = (confirm = true) => ({ + type: CONFIRM_INCIDENT_QUERY_REQUESTED, + confirm, +}); diff --git a/src/redux/query_settings/reducers.js b/src/redux/query_settings/reducers.js index caeee6d8..6363980c 100644 --- a/src/redux/query_settings/reducers.js +++ b/src/redux/query_settings/reducers.js @@ -21,6 +21,15 @@ import { UPDATE_QUERY_SETTINGS_SERVICES_COMPLETED, UPDATE_SEARCH_QUERY_REQUESTED, UPDATE_SEARCH_QUERY_COMPLETED, + VALIDATE_INCIDENT_QUERY_REQUESTED, + VALIDATE_INCIDENT_QUERY_COMPLETED, + TOGGLE_DISPLAY_CONFIRM_QUERY_MODAL_REQUESTED, + TOGGLE_DISPLAY_CONFIRM_QUERY_MODAL_COMPLETED, + UPDATE_TOTAL_INCIDENTS_FROM_QUERY_REQUESTED, + UPDATE_TOTAL_INCIDENTS_FROM_QUERY_COMPLETED, + CONFIRM_INCIDENT_QUERY_REQUESTED, + CONFIRM_INCIDENT_QUERY_COMPLETED, + CONFIRM_INCIDENT_QUERY_ERROR, } from './actions'; const querySettings = produce( @@ -97,6 +106,48 @@ const querySettings = produce( draft.searchQuery = action.searchQuery; draft.status = UPDATE_SEARCH_QUERY_COMPLETED; break; + + case VALIDATE_INCIDENT_QUERY_REQUESTED: + draft.status = VALIDATE_INCIDENT_QUERY_REQUESTED; + break; + + case VALIDATE_INCIDENT_QUERY_COMPLETED: + draft.status = VALIDATE_INCIDENT_QUERY_COMPLETED; + break; + + case TOGGLE_DISPLAY_CONFIRM_QUERY_MODAL_REQUESTED: + draft.status = TOGGLE_DISPLAY_CONFIRM_QUERY_MODAL_REQUESTED; + break; + + case TOGGLE_DISPLAY_CONFIRM_QUERY_MODAL_COMPLETED: + draft.displayConfirmQueryModal = action.displayConfirmQueryModal; + draft.status = TOGGLE_DISPLAY_CONFIRM_QUERY_MODAL_COMPLETED; + break; + + case UPDATE_TOTAL_INCIDENTS_FROM_QUERY_REQUESTED: + draft.status = UPDATE_TOTAL_INCIDENTS_FROM_QUERY_REQUESTED; + break; + + case UPDATE_TOTAL_INCIDENTS_FROM_QUERY_COMPLETED: + draft.totalIncidentsFromQuery = action.totalIncidentsFromQuery; + draft.status = UPDATE_TOTAL_INCIDENTS_FROM_QUERY_COMPLETED; + break; + + case CONFIRM_INCIDENT_QUERY_REQUESTED: + draft.status = CONFIRM_INCIDENT_QUERY_REQUESTED; + draft.error = null; + break; + + case CONFIRM_INCIDENT_QUERY_COMPLETED: + draft.status = CONFIRM_INCIDENT_QUERY_COMPLETED; + draft.error = null; + break; + + case CONFIRM_INCIDENT_QUERY_ERROR: + draft.status = CONFIRM_INCIDENT_QUERY_ERROR; + draft.error = CONFIRM_INCIDENT_QUERY_ERROR; + break; + default: break; } @@ -111,6 +162,8 @@ const querySettings = produce( teamIds: [], serviceIds: [], searchQuery: '', + displayConfirmQueryModal: false, + totalIncidentsFromQuery: 0, status: null, fetchingData: false, error: null, diff --git a/src/redux/query_settings/sagas.js b/src/redux/query_settings/sagas.js index 565db2b0..963ba61a 100644 --- a/src/redux/query_settings/sagas.js +++ b/src/redux/query_settings/sagas.js @@ -1,7 +1,18 @@ import { - put, select, takeLatest, + put, select, takeLatest, call, debounce, } from 'redux-saga/effects'; +import { + pd, +} from 'util/pd-api-wrapper'; + +import { + MAX_INCIDENTS_LIMIT, +} from 'config/constants'; + +import { + UPDATE_CONNECTION_STATUS_REQUESTED, +} from 'redux/connection/actions'; import { FETCH_INCIDENTS_REQUESTED, FILTER_INCIDENTS_LIST_BY_QUERY, @@ -27,6 +38,15 @@ import { UPDATE_QUERY_SETTINGS_SERVICES_COMPLETED, UPDATE_SEARCH_QUERY_REQUESTED, UPDATE_SEARCH_QUERY_COMPLETED, + VALIDATE_INCIDENT_QUERY_REQUESTED, + VALIDATE_INCIDENT_QUERY_COMPLETED, + TOGGLE_DISPLAY_CONFIRM_QUERY_MODAL_REQUESTED, + TOGGLE_DISPLAY_CONFIRM_QUERY_MODAL_COMPLETED, + UPDATE_TOTAL_INCIDENTS_FROM_QUERY_REQUESTED, + UPDATE_TOTAL_INCIDENTS_FROM_QUERY_COMPLETED, + CONFIRM_INCIDENT_QUERY_REQUESTED, + CONFIRM_INCIDENT_QUERY_COMPLETED, + CONFIRM_INCIDENT_QUERY_ERROR, } from './actions'; import selectQuerySettings from './selectors'; @@ -55,8 +75,7 @@ export function* updateQuerySettingsSinceDateImpl(action) { sinceDate, } = action; yield put({ type: UPDATE_QUERY_SETTING_SINCE_DATE_COMPLETED, sinceDate }); - yield put({ type: FETCH_INCIDENTS_REQUESTED }); - yield put({ type: FETCH_ALL_INCIDENT_NOTES_REQUESTED }); + yield put({ type: VALIDATE_INCIDENT_QUERY_REQUESTED }); } export function* updateQuerySettingsIncidentStatus() { @@ -75,8 +94,7 @@ export function* updateQuerySettingsIncidentStatusImpl(action) { type: UPDATE_QUERY_SETTING_INCIDENT_STATUS_COMPLETED, incidentStatus, }); - yield put({ type: FETCH_INCIDENTS_REQUESTED }); - yield put({ type: FETCH_ALL_INCIDENT_NOTES_REQUESTED }); + yield put({ type: VALIDATE_INCIDENT_QUERY_REQUESTED }); } export function* updateQuerySettingsIncidentUrgency() { @@ -95,8 +113,7 @@ export function* updateQuerySettingsIncidentUrgencyImpl(action) { type: UPDATE_QUERY_SETTING_INCIDENT_URGENCY_COMPLETED, incidentUrgency, }); - yield put({ type: FETCH_INCIDENTS_REQUESTED }); - yield put({ type: FETCH_ALL_INCIDENT_NOTES_REQUESTED }); + yield put({ type: VALIDATE_INCIDENT_QUERY_REQUESTED }); } export function* updateQuerySettingsIncidentPriority() { @@ -115,8 +132,7 @@ export function* updateQuerySettingsIncidentPriorityImpl(action) { type: UPDATE_QUERY_SETTING_INCIDENT_PRIORITY_COMPLETED, incidentPriority, }); - yield put({ type: FETCH_INCIDENTS_REQUESTED }); - yield put({ type: FETCH_ALL_INCIDENT_NOTES_REQUESTED }); + yield put({ type: VALIDATE_INCIDENT_QUERY_REQUESTED }); } export function* updateQuerySettingsTeams() { @@ -130,8 +146,7 @@ export function* updateQuerySettingsTeamsImpl(action) { } = action; yield put({ type: FETCH_SERVICES_REQUESTED, teamIds }); yield put({ type: UPDATE_QUERY_SETTINGS_TEAMS_COMPLETED, teamIds }); - yield put({ type: FETCH_INCIDENTS_REQUESTED }); - yield put({ type: FETCH_ALL_INCIDENT_NOTES_REQUESTED }); + yield put({ type: VALIDATE_INCIDENT_QUERY_REQUESTED }); } export function* updateQuerySettingsServices() { @@ -144,8 +159,7 @@ export function* updateQuerySettingsServicesImpl(action) { serviceIds, } = action; yield put({ type: UPDATE_QUERY_SETTINGS_SERVICES_COMPLETED, serviceIds }); - yield put({ type: FETCH_INCIDENTS_REQUESTED }); - yield put({ type: FETCH_ALL_INCIDENT_NOTES_REQUESTED }); + yield put({ type: VALIDATE_INCIDENT_QUERY_REQUESTED }); } export function* updateSearchQuery() { @@ -160,3 +174,110 @@ export function* updateSearchQueryImpl(action) { yield put({ type: UPDATE_SEARCH_QUERY_COMPLETED, searchQuery }); yield put({ type: FILTER_INCIDENTS_LIST_BY_QUERY, searchQuery }); } + +export function* validateIncidentQuery() { + yield debounce(2000, VALIDATE_INCIDENT_QUERY_REQUESTED, validateIncidentQueryImpl); +} + +export function* validateIncidentQueryImpl() { + try { + // Find total incidents from data query + const { + sinceDate, + incidentStatus, + incidentUrgency, + teamIds, + serviceIds, + // incidentPriority, // Unfortunately can't do this pre-API call. + } = yield select(selectQuerySettings); + + const params = { + since: sinceDate.toISOString(), + until: new Date().toISOString(), + limit: 1, + total: true, + }; + + if (incidentStatus) params['statuses[]'] = incidentStatus; + if (incidentUrgency) params['urgencies[]'] = incidentUrgency; + if (teamIds.length) params['team_ids[]'] = teamIds; + if (serviceIds.length) params['service_ids[]'] = serviceIds; + + const response = yield call(pd.get, 'incidents', { data: { ...params } }); + if (response.status !== 200) { + throw Error('Unable to fetch incidents'); + } + + const totalIncidentsFromQuery = response.data.total; + yield put({ type: VALIDATE_INCIDENT_QUERY_COMPLETED }); + yield put({ + type: UPDATE_TOTAL_INCIDENTS_FROM_QUERY_REQUESTED, + totalIncidentsFromQuery, + }); + + // Determine if Confirm Query Modal component should be rendered + if (totalIncidentsFromQuery > MAX_INCIDENTS_LIMIT) { + yield put({ type: TOGGLE_DISPLAY_CONFIRM_QUERY_MODAL_REQUESTED }); + } else { + yield put({ type: CONFIRM_INCIDENT_QUERY_REQUESTED, confirm: true }); + } + } catch (e) { + // Handle API auth failure + if (e.status === 401) { + e.message = 'Unauthorized Access'; + } + yield put({ + type: UPDATE_CONNECTION_STATUS_REQUESTED, + connectionStatus: 'neutral', + connectionStatusMessage: e.message, + }); + } +} + +export function* toggleDisplayConfirmQueryModal() { + yield takeLatest( + TOGGLE_DISPLAY_CONFIRM_QUERY_MODAL_REQUESTED, + toggleDisplayConfirmQueryModalImpl, + ); +} + +export function* toggleDisplayConfirmQueryModalImpl() { + const { + displayConfirmQueryModal, + } = yield select(selectQuerySettings); + yield put({ + type: TOGGLE_DISPLAY_CONFIRM_QUERY_MODAL_COMPLETED, + displayConfirmQueryModal: !displayConfirmQueryModal, + }); +} + +export function* updateTotalIncidentsFromQuery() { + yield takeLatest(UPDATE_TOTAL_INCIDENTS_FROM_QUERY_REQUESTED, updateTotalIncidentsFromQueryImpl); +} + +export function* updateTotalIncidentsFromQueryImpl(action) { + const { + totalIncidentsFromQuery, + } = action; + yield put({ + type: UPDATE_TOTAL_INCIDENTS_FROM_QUERY_COMPLETED, + totalIncidentsFromQuery, + }); +} + +export function* confirmIncidentQuery() { + yield takeLatest(CONFIRM_INCIDENT_QUERY_REQUESTED, confirmIncidentQueryImpl); +} + +export function* confirmIncidentQueryImpl(action) { + const { + confirm, + } = action; + if (confirm) { + yield put({ type: FETCH_INCIDENTS_REQUESTED }); + yield put({ type: FETCH_ALL_INCIDENT_NOTES_REQUESTED }); + yield put({ type: CONFIRM_INCIDENT_QUERY_COMPLETED }); + } else { + yield put({ type: CONFIRM_INCIDENT_QUERY_ERROR }); + } +} diff --git a/src/redux/rootSaga.js b/src/redux/rootSaga.js index 366d1000..caa7094d 100644 --- a/src/redux/rootSaga.js +++ b/src/redux/rootSaga.js @@ -15,6 +15,10 @@ import { updateQuerySettingsTeams, updateQuerySettingsServices, updateSearchQuery, + validateIncidentQuery, + toggleDisplayConfirmQueryModal, + updateTotalIncidentsFromQuery, + confirmIncidentQuery, } from './query_settings/sagas'; import { @@ -121,6 +125,10 @@ export default function* rootSaga() { updateQuerySettingsTeams(), updateQuerySettingsServices(), updateSearchQuery(), + validateIncidentQuery(), + toggleDisplayConfirmQueryModal(), + updateTotalIncidentsFromQuery(), + confirmIncidentQuery(), // Incidents getIncidentsAsync(), From 69c78deae2168fde5cc2405598bb3c0e0e1a1a59 Mon Sep 17 00:00:00 2001 From: Giran Moodley Date: Sun, 5 Jun 2022 22:38:24 +0100 Subject: [PATCH 02/10] Added component test coverage --- .../ConfirmQueryModalComponent.js | 2 +- .../ConfirmQueryModalComponent.test.js | 29 +++++++++++++++++++ .../subcomponents/QueryActiveComponent.js | 2 +- .../QueryActiveComponent.test.js | 13 +++++++++ .../subcomponents/QueryCancelledComponent.js | 2 +- .../QueryCancelledComponent.test.js | 13 +++++++++ .../QuerySettingsComponent.test.js | 4 +-- 7 files changed, 60 insertions(+), 5 deletions(-) create mode 100644 src/components/ConfirmQueryModal/ConfirmQueryModalComponent.test.js create mode 100644 src/components/IncidentTable/subcomponents/QueryActiveComponent.test.js create mode 100644 src/components/IncidentTable/subcomponents/QueryCancelledComponent.test.js diff --git a/src/components/ConfirmQueryModal/ConfirmQueryModalComponent.js b/src/components/ConfirmQueryModal/ConfirmQueryModalComponent.js index e1b6caaf..e7c05cb4 100644 --- a/src/components/ConfirmQueryModal/ConfirmQueryModalComponent.js +++ b/src/components/ConfirmQueryModal/ConfirmQueryModalComponent.js @@ -49,7 +49,7 @@ const ConfirmQueryModalComponent = ({ - diff --git a/src/components/IncidentTable/subcomponents/QueryActiveComponent.js b/src/components/IncidentTable/subcomponents/QueryActiveComponent.js index 9da71a95..c772404f 100644 --- a/src/components/IncidentTable/subcomponents/QueryActiveComponent.js +++ b/src/components/IncidentTable/subcomponents/QueryActiveComponent.js @@ -3,7 +3,7 @@ import { } from 'react-bootstrap'; const QueryActiveComponent = () => ( - +
diff --git a/src/components/IncidentTable/subcomponents/QueryCancelledComponent.js b/src/components/IncidentTable/subcomponents/QueryCancelledComponent.js index 485a5711..65a8354d 100644 --- a/src/components/IncidentTable/subcomponents/QueryCancelledComponent.js +++ b/src/components/IncidentTable/subcomponents/QueryCancelledComponent.js @@ -3,7 +3,7 @@ import { } from 'react-bootstrap'; const QueryCancelledComponent = () => ( - +