diff --git a/CommonUI/src/Components/ModelTable/Column.ts b/CommonUI/src/Components/ModelTable/Column.ts index 0156b9f0d8..d41886a356 100644 --- a/CommonUI/src/Components/ModelTable/Column.ts +++ b/CommonUI/src/Components/ModelTable/Column.ts @@ -1,3 +1,4 @@ +import BaseModel from 'Common/Models/BaseModel'; import { JSONObject } from 'Common/Types/JSON'; import ObjectID from 'Common/Types/ObjectID'; import { ReactElement } from 'react'; @@ -18,6 +19,7 @@ export default interface Columns { disableSort?: boolean; type: FieldType; isFilterable: boolean; + filterEntityType?: BaseModel | undefined, actionButtons?: Array; getElement?: | (( diff --git a/CommonUI/src/Components/Table/Table.tsx b/CommonUI/src/Components/Table/Table.tsx index 15a168165c..152104d992 100644 --- a/CommonUI/src/Components/Table/Table.tsx +++ b/CommonUI/src/Components/Table/Table.tsx @@ -1,13 +1,11 @@ import { JSONObject } from 'Common/Types/JSON'; import React, { FunctionComponent, ReactElement } from 'react'; import TableBody from './TableBody'; -import TableHeader from './TableHeader'; +import TableHeader, { FilterData } from './TableHeader'; import Columns from './Types/Columns'; import Pagination from '../Pagination/Pagination'; import SortOrder from 'Common/Types/Database/SortOrder'; -import Dictionary from 'Common/Types/Dictionary'; import ActionButtonSchema from '../ActionButton/ActionButtonSchema'; -import Search from 'Common/Types/Database/Search'; import ErrorMessage from '../ErrorMessage/ErrorMessage'; import ComponentLoader from '../ComponentLoader/ComponentLoader'; @@ -30,8 +28,8 @@ export interface ComponentProps { onSortChanged: (sortBy: string, sortOrder: SortOrder) => void; showFilter?: undefined | boolean; onFilterChanged?: - | undefined - | ((filterData: Dictionary) => void); + | undefined + | ((filterData: FilterData) => void); } const Table: FunctionComponent = ( diff --git a/CommonUI/src/Components/Table/TableHeader.tsx b/CommonUI/src/Components/Table/TableHeader.tsx index e397acfe98..d6027ff3d4 100644 --- a/CommonUI/src/Components/Table/TableHeader.tsx +++ b/CommonUI/src/Components/Table/TableHeader.tsx @@ -13,6 +13,11 @@ import Input from '../Input/Input'; import FieldType from '../Types/FieldType'; import Search from 'Common/Types/Database/Search'; import OneUptimeDate from 'Common/Types/Date'; +import BaseModel from 'Common/Models/BaseModel'; +import ObjectID from 'Common/Types/ObjectID'; +import Dropdown, { DropdownValue } from '../Dropdown/Dropdown'; + +export type FilterData = Dictionary | boolean | Search | Date | BaseModel | Array | ObjectID | Array | number>; export interface ComponentProps { columns: Columns; @@ -20,8 +25,8 @@ export interface ComponentProps { onSortChanged: (sortBy: string, sortOrder: SortOrder) => void; showFilter: boolean; onFilterChanged?: - | undefined - | ((filterData: Dictionary) => void); + | undefined + | ((filterData: FilterData) => void); } const TableHeader: FunctionComponent = ( @@ -32,7 +37,7 @@ const TableHeader: FunctionComponent = ( // should filter on textboxes and checkboxes. const [filterData, setFilterData] = useState< - Dictionary + FilterData >({}); useEffect(() => { @@ -112,61 +117,92 @@ const TableHeader: FunctionComponent = ( {props.columns.map((column: Column, i: number) => { return ( - {column.isFilterable && ( - { - if (column.key) { - if (!changedValue) { - delete filterData[ - column.key - ]; - } - - if ( - changedValue && - column.type === - FieldType.Date - ) { - filterData[column.key] = - OneUptimeDate.asDateForDatabaseQuery( - changedValue as string - ); - } - - if ( - changedValue && - column.type === - FieldType.Text - ) { - filterData[column.key] = - new Search( - changedValue as string - ); - } - - setFilterData(filterData); - - if (props.onFilterChanged) { - props.onFilterChanged( - filterData - ); - } + {column.isFilterable && column.key && ( +
+ {(column.type === FieldType.Entity || column.type === FieldType.EntityArray) && column.filterDropdownOptions && ) => { + if (!column.key) { + return; } + + + if (!value || (Array.isArray(value) && value.length === 0)) { + delete filterData[ + column.key + ]; + } else { + filterData[column.key] = value; + } + + setFilterData(filterData); + + if (props.onFilterChanged) { + props.onFilterChanged( + filterData + ); + } + }} - initialValue={( - filterData[column.key || ''] || '' - ).toString()} - placeholder={`Filter by ${column.title}`} - className={'form-control'} - type={ - column.type === FieldType.Date - ? 'date' - : 'text' - } - /> + isMultiSelect={column.type === FieldType.EntityArray} + placeholder={`Filter by ${column.title}`} + className={'form-control'} + />} + + {(column.type === FieldType.Date || column.type === FieldType.ObjectID || column.type === FieldType.Text) && { + if (column.key) { + if (!changedValue) { + delete filterData[ + column.key + ]; + } + + if ( + changedValue && + column.type === + FieldType.Date + ) { + filterData[column.key] = + OneUptimeDate.asDateForDatabaseQuery( + changedValue as string + ); + } + + if ( + changedValue && + column.type === + FieldType.Text + ) { + filterData[column.key] = + new Search( + changedValue as string + ); + } + + setFilterData(filterData); + + if (props.onFilterChanged) { + props.onFilterChanged( + filterData + ); + } + } + }} + initialValue={( + filterData[column.key || ''] || '' + ).toString()} + placeholder={`Filter by ${column.title}`} + className={'form-control'} + type={ + column.type === FieldType.Date + ? 'date' + : 'text' + } + />} +
)} + ); })} diff --git a/CommonUI/src/Components/Table/Types/Column.ts b/CommonUI/src/Components/Table/Types/Column.ts index 756e74ec64..3a5b72e582 100644 --- a/CommonUI/src/Components/Table/Types/Column.ts +++ b/CommonUI/src/Components/Table/Types/Column.ts @@ -1,5 +1,6 @@ import { JSONObject } from 'Common/Types/JSON'; import { ReactElement } from 'react'; +import { DropdownOption } from '../../Dropdown/Dropdown'; import FieldType from '../../Types/FieldType'; export default interface Column { @@ -8,6 +9,7 @@ export default interface Column { disableSort?: boolean; type: FieldType; isFilterable?: boolean; + filterDropdownOptions?: Array | undefined; key?: string | null; //can be null because actions column does not have a key. getElement?: | (( diff --git a/CommonUI/src/Components/Types/FieldType.ts b/CommonUI/src/Components/Types/FieldType.ts index 404785fc26..6772e44699 100644 --- a/CommonUI/src/Components/Types/FieldType.ts +++ b/CommonUI/src/Components/Types/FieldType.ts @@ -17,6 +17,7 @@ enum FieldType { Actions = 'Actions', Boolean = 'Boolean', Entity = 'Entity', + EntityArray = 'EntityArray', Markdown = 'Markdown', } diff --git a/Dashboard/src/Pages/Incidents/Incidents.tsx b/Dashboard/src/Pages/Incidents/Incidents.tsx index 734558f3af..23448e9f5b 100644 --- a/Dashboard/src/Pages/Incidents/Incidents.tsx +++ b/Dashboard/src/Pages/Incidents/Incidents.tsx @@ -130,7 +130,7 @@ const IncidentsPage: FunctionComponent = ( }, }, title: 'Current State', - type: FieldType.Text, + type: FieldType.Entity, getElement: (item: JSONObject): ReactElement => { if (item['currentIncidentState']) { return ( @@ -165,7 +165,7 @@ const IncidentsPage: FunctionComponent = ( }, }, title: 'Monitors Affected', - type: FieldType.Text, + type: FieldType.EntityArray, getElement: (item: JSONObject): ReactElement => { return (