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

improve column filters #443

Merged
merged 5 commits into from
Jun 13, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
8 changes: 8 additions & 0 deletions cypress/e2e/Search/search.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,4 +113,12 @@ describe('Search Incidents', { failFast: { enabled: true } }, () => {
cy.get('#service-filter-icon').realHover();
cy.get('button[aria-label="Clear Filter"]').filter(':visible').click();
});

it('Column filtering on Service column for `zzzzzz` returns no incidents and clear filters button', () => {
cy.get('#service-filter-icon').realHover();
cy.get('input[placeholder="Filter"]').filter(':visible').click().type('zzzzzz');
cy.get('.empty-incidents-badge').should('be.visible');
cy.get('#clear-filters-button').filter(':visible').click();
waitForIncidentTable();
});
});
55 changes: 31 additions & 24 deletions src/components/IncidentTable/IncidentTableComponent.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import {
import {
selectIncidentTableRows as selectIncidentTableRowsConnected,
updateIncidentTableState as updateIncidentTableStateConnected,
CLEAR_INCIDENT_TABLE_FILTERS_COMPLETED,
} from 'src/redux/incident_table/actions';

import EmptyIncidentsComponent from './subcomponents/EmptyIncidentsComponent';
Expand Down Expand Up @@ -120,7 +121,7 @@ const doCsvExport = (tableData) => {

const IncidentTableComponent = () => {
const {
incidentTableState, incidentTableColumns,
incidentTableState, incidentTableColumns, status: incidentTableStatus,
} = useSelector((state) => state.incidentTable);
const {
status: incidentActionsStatus,
Expand Down Expand Up @@ -221,7 +222,8 @@ const IncidentTableComponent = () => {
// Debouncing for table state
const debouncedUpdateIncidentTableState = useDebouncedCallback((state, action) => {
// Only update store with sorted and column resizing state
if (action.type === 'toggleSortBy' || action.type === 'columnDoneResizing') {
// and filter state
if (action.type === 'toggleSortBy' || action.type === 'columnDoneResizing' || action.type === 'setFilter') {
updateIncidentTableState(state);
}
}, 100);
Expand Down Expand Up @@ -251,7 +253,7 @@ const IncidentTableComponent = () => {
// Set initial state from store
initialState: incidentTableState,
// Handle updates to table
stateReducer: (newState, action) => debouncedUpdateIncidentTableState(newState, action),
stateReducer: debouncedUpdateIncidentTableState,
},
// Plugins
useFilters,
Expand Down Expand Up @@ -327,19 +329,17 @@ const IncidentTableComponent = () => {
},
);

// save filters when the user changes them
useEffect(() => {
updateIncidentTableState({
...incidentTableState,
filters: tableInstance.state.filters,
});
}, [tableInstance.state.filters]);

// Update table filters when columns change
useEffect(() => {
tableInstance.setAllFilters(incidentTableState.filters);
}, [columns]);

useEffect(() => {
if (incidentTableStatus === CLEAR_INCIDENT_TABLE_FILTERS_COMPLETED) {
tableInstance.setAllFilters(incidentTableState.filters);
}
}, [incidentTableStatus]);

const {
getTableProps,
getTableBodyProps,
Expand Down Expand Up @@ -536,19 +536,26 @@ const IncidentTableComponent = () => {
</MenuItem>
</ContextMenu>
</Box>
<Box {...getTableBodyProps()}>
<FixedSizeList
className="incident-table-fixed-list"
height={tableHeight - 45}
itemCount={rows.length}
itemSize={60}
itemKey={(index) => rows[index].id}
itemData={rows}
width={totalColumnsWidth + scrollBarSize}
>
{MyIncidentRow}
</FixedSizeList>
</Box>
{ rows.length > 0 && (
<Box {...getTableBodyProps()}>
<FixedSizeList
className="incident-table-fixed-list"
height={tableHeight - 45}
itemCount={rows.length}
itemSize={60}
itemKey={(index) => rows[index].id}
itemData={rows}
width={totalColumnsWidth + scrollBarSize}
>
{MyIncidentRow}
</FixedSizeList>
</Box>
)}
{ rows.length === 0 && (
<EmptyIncidentsComponent
message={t('No incidents match your search criteria.')}
/>
)}
<GetAllModal
isOpen={displayGetAllModal}
onClose={() => setDisplayGetAllModal(false)}
Expand Down
22 changes: 20 additions & 2 deletions src/components/QuerySettings/QuerySettingsComponent.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import React from 'react';
import React, {
useMemo,
} from 'react';

import {
useSelector, useDispatch,
Expand Down Expand Up @@ -28,6 +30,7 @@ import DatePickerComponent from './subcomponents/DatePickerComponent';
import StatusQueryComponent from './subcomponents/StatusQueryComponent';
import UrgencyQueryComponent from './subcomponents/UrgencyQueryComponent';
import PriorityQueryComponent from './subcomponents/PriorityQueryComponent';
import ColumnFilterIndicatorComponent from './subcomponents/ColumnFilterIndicatorComponent';

import './QuerySettingsComponent.scss';

Expand All @@ -52,6 +55,10 @@ const QuerySettingsComponent = () => {
} = useSelector(
(state) => state.querySettings,
);
const {
filters,
} = useSelector((state) => state.incidentTable.incidentTableState);

const dispatch = useDispatch();
const updateQuerySettingsServices = (newServiceIds) => {
dispatch(updateQuerySettingsServicesConnected(newServiceIds));
Expand All @@ -66,6 +73,13 @@ const QuerySettingsComponent = () => {
dispatch(updateQuerySettingsTeamsConnected(newTeamIds));
};

const filterCount = useMemo(() => {
if (filters instanceof Array) {
return filters.length;
}
return 0;
}, [filters]);

return (
<Box m={4}>
<Flex
Expand Down Expand Up @@ -117,7 +131,11 @@ const QuerySettingsComponent = () => {
isMulti
/>
</BoxForInput>
{/* <GlobalSearchComponent /> */}
{ filterCount > 0 && (
<BoxForInput label={`${t('Column Filters')}:`}>
<ColumnFilterIndicatorComponent />
</BoxForInput>
)}
</Flex>
</Box>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import React, {
useMemo,
} from 'react';

import {
useSelector,
useDispatch,
} from 'react-redux';

import {
useTranslation,
} from 'react-i18next';

import {
Flex,
Button,
Tag,
} from '@chakra-ui/react';

import {
clearIncidentTableFilters as clearIncidentTableFiltersConnected,
} from 'src/redux/incident_table/actions';

const ColumnFilterIndicatorComponent = () => {
const {
t,
} = useTranslation();
const {
filters,
} = useSelector((state) => state.incidentTable.incidentTableState);

const dispatch = useDispatch();
const clearIncidentTableFilters = () => {
dispatch(clearIncidentTableFiltersConnected());
};

const filterCount = useMemo(() => {
if (filters instanceof Array) {
return filters.length;
}
return 0;
}, [filters]);

return (
<Flex>
<Tag colorScheme="blue">
{filterCount}
</Tag>
<Button
id="clear-filters-button"
size="xs"
ml={1}
colorScheme="red"
aria-label="clear"
onClick={clearIncidentTableFilters}
>
{t('Clear')}
</Button>
</Flex>
);
};

export default ColumnFilterIndicatorComponent;
7 changes: 7 additions & 0 deletions src/redux/incident_table/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ export const UPDATE_INCIDENT_TABLE_STATE_COMPLETED = 'UPDATE_INCIDENT_TABLE_STAT
export const SELECT_INCIDENT_TABLE_ROWS_REQUESTED = 'SELECT_INCIDENT_TABLE_ROWS_REQUESTED';
export const SELECT_INCIDENT_TABLE_ROWS_COMPLETED = 'SELECT_INCIDENT_TABLE_ROWS_COMPLETED';

export const CLEAR_INCIDENT_TABLE_FILTERS_REQUESTED = 'CLEAR_INCIDENT_TABLE_FILTERS_REQUESTED';
export const CLEAR_INCIDENT_TABLE_FILTERS_COMPLETED = 'CLEAR_INCIDENT_TABLE_FILTERS_COMPLETED';

// Define Actions

export const saveIncidentTable = (updatedIncidentTableColumns) => ({
Expand All @@ -35,3 +38,7 @@ export const selectIncidentTableRows = (allSelected, selectedCount, selectedRows
selectedCount,
selectedRows,
});

export const clearIncidentTableFilters = () => ({
type: CLEAR_INCIDENT_TABLE_FILTERS_REQUESTED,
});
14 changes: 14 additions & 0 deletions src/redux/incident_table/reducers.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import {
UPDATE_INCIDENT_TABLE_STATE_COMPLETED,
SELECT_INCIDENT_TABLE_ROWS_REQUESTED,
SELECT_INCIDENT_TABLE_ROWS_COMPLETED,
CLEAR_INCIDENT_TABLE_FILTERS_REQUESTED,
CLEAR_INCIDENT_TABLE_FILTERS_COMPLETED,
} from './actions';

const defaultColumns = [
Expand Down Expand Up @@ -70,6 +72,18 @@ const incidentTable = produce(
draft.status = SELECT_INCIDENT_TABLE_ROWS_COMPLETED;
break;

case CLEAR_INCIDENT_TABLE_FILTERS_REQUESTED:
draft.status = CLEAR_INCIDENT_TABLE_FILTERS_REQUESTED;
break;

case CLEAR_INCIDENT_TABLE_FILTERS_COMPLETED:
draft.incidentTableState = {
...draft.incidentTableState,
filters: [],
};
draft.status = CLEAR_INCIDENT_TABLE_FILTERS_COMPLETED;
break;

default:
break;
}
Expand Down
12 changes: 12 additions & 0 deletions src/redux/incident_table/sagas.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import {
UPDATE_INCIDENT_TABLE_STATE_COMPLETED,
SELECT_INCIDENT_TABLE_ROWS_REQUESTED,
SELECT_INCIDENT_TABLE_ROWS_COMPLETED,
CLEAR_INCIDENT_TABLE_FILTERS_REQUESTED,
CLEAR_INCIDENT_TABLE_FILTERS_COMPLETED,
} from './actions';

import selectIncidentTable from './selectors';
Expand Down Expand Up @@ -122,3 +124,13 @@ export function* selectIncidentTableRowsImpl(action) {
selectedRows,
});
}

export function* clearIncidentTableFilters() {
yield takeLatest(CLEAR_INCIDENT_TABLE_FILTERS_REQUESTED, clearIncidentTableFiltersImpl);
}

export function* clearIncidentTableFiltersImpl() {
yield put({
type: CLEAR_INCIDENT_TABLE_FILTERS_COMPLETED,
});
}
1 change: 1 addition & 0 deletions src/redux/incidents/reducers.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ const incidents = produce(
case FETCH_INCIDENTS_REQUESTED:
draft.fetchingIncidents = true;
draft.status = FETCH_INCIDENTS_REQUESTED;
draft.error = null;
break;

case FETCH_INCIDENTS_COMPLETED:
Expand Down
12 changes: 10 additions & 2 deletions src/redux/log_entries/sagas.js
Original file line number Diff line number Diff line change
Expand Up @@ -169,9 +169,17 @@ export function* pollLogEntriesTask() {
},
incidents: {
fetchingIncidents,
error: incidentsError,
},
} = yield select();
if (userAuthorized && userAcceptedDisclaimer && !fetchingIncidents && !DEBUG_DISABLE_POLLING) {

const tooManyIncidentsError = (
incidentsError
&& typeof incidentsError === 'string'
&& incidentsError.startsWith('Too many records')
);

if (userAuthorized && userAcceptedDisclaimer && !fetchingIncidents && !DEBUG_DISABLE_POLLING && !tooManyIncidentsError) {
const lastPollStarted = new Date();
yield put({
type: UPDATE_LOG_ENTRIES_POLLING,
Expand Down Expand Up @@ -199,7 +207,7 @@ export function* pollLogEntriesTask() {
yield delay((LOG_ENTRIES_POLLING_INTERVAL_SECONDS * 1000) - timeTaken);
} else {
// eslint-disable-next-line no-console
console.log('skipping poll', { userAuthorized, userAcceptedDisclaimer, fetchingIncidents, DEBUG_DISABLE_POLLING });
console.log('skipping poll', { userAuthorized, userAcceptedDisclaimer, fetchingIncidents, DEBUG_DISABLE_POLLING, tooManyIncidentsError });
yield delay(LOG_ENTRIES_POLLING_INTERVAL_SECONDS * 1000);
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/redux/rootSaga.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import {
updateIncidentTableColumns,
updateIncidentTableState,
selectIncidentTableRows,
clearIncidentTableFilters,
} from './incident_table/sagas';

import {
Expand Down Expand Up @@ -185,6 +186,7 @@ export default function* rootSaga() {
updateIncidentTableColumns(),
updateIncidentTableState(),
selectIncidentTableRows(),
clearIncidentTableFilters(),

// Incident Actions
doAction(),
Expand Down
Loading