diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 712af100..09b9f200 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -12,6 +12,7 @@
"@patternfly/react-table": "^5.2.4",
"@reduxjs/toolkit": "^2.2.3",
"axios": "^1.6.8",
+ "lodash": "^4.17.21",
"plotly.js": "^2.32.0",
"react": "^18.2.0",
"react-date-picker": "^10.6.0",
diff --git a/frontend/package.json b/frontend/package.json
index 6e9fd634..edb6cc1b 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -14,6 +14,7 @@
"@patternfly/react-table": "^5.2.4",
"@reduxjs/toolkit": "^2.2.3",
"axios": "^1.6.8",
+ "lodash": "^4.17.21",
"plotly.js": "^2.32.0",
"react": "^18.2.0",
"react-date-picker": "^10.6.0",
diff --git a/frontend/src/actions/commonActions.js b/frontend/src/actions/commonActions.js
index 60976963..81546e7b 100644
--- a/frontend/src/actions/commonActions.js
+++ b/frontend/src/actions/commonActions.js
@@ -1,9 +1,10 @@
import * as TYPES from "@/actions/types.js";
+import { setCatFilters, sliceTableRows } from "./homeActions";
import { setOCPCatFilters, sliceOCPTableRows } from "./ocpActions";
import { DEFAULT_PER_PAGE } from "@/assets/constants/paginationConstants";
-import { sliceTableRows } from "./homeActions";
+import { cloneDeep } from "lodash";
const getSortableRowValues = (result, tableColumns) => {
const tableKeys = tableColumns.map((item) => item.value);
@@ -75,7 +76,8 @@ export const calculateMetrics = (results) => {
};
export const buildFilterData = (currState) => (dispatch, getState) => {
- const results = [...getState()[currState].results];
+ const results = [...getState()[currState].filteredResults];
+ const categoryFilterValue = getState()[currState].categoryFilterValue;
const tableFilters = [...getState()[currState].tableFilters];
@@ -85,11 +87,19 @@ export const buildFilterData = (currState) => (dispatch, getState) => {
let obj = {
name: filter.name,
key,
- value: [...new Set(results.map((item) => item[key]))],
+ value: [
+ ...new Set(results.map((item) => item[key]?.toString()?.toLowerCase())),
+ ],
};
filterData.push(obj);
}
- dispatch(setFilterData(filterData, currState, tableFilters[0].name));
+ dispatch(
+ setFilterData(
+ filterData,
+ currState,
+ categoryFilterValue || tableFilters[0].name
+ )
+ );
};
const setFilterData = (filterData, currState, activeFilter) => (dispatch) => {
@@ -99,6 +109,12 @@ const setFilterData = (filterData, currState, activeFilter) => (dispatch) => {
payload: filterData,
});
dispatch(setOCPCatFilters(activeFilter));
+ } else if (currState === "cpt") {
+ dispatch({
+ type: TYPES.SET_CPT_FILTER_DATA,
+ payload: filterData,
+ });
+ dispatch(setCatFilters(activeFilter));
}
};
@@ -111,10 +127,10 @@ export const getFilteredData = (appliedFilters, results) => {
if (isFilterApplied) {
filtered = results.filter((el) => {
for (const key in appliedFilters) {
- if (
- el[key]?.toString()?.toLowerCase() !==
- appliedFilters[key]?.toString()?.toLowerCase()
- ) {
+ const valueMap = appliedFilters[key]?.map((i) =>
+ i?.toString()?.toLowerCase()
+ );
+ if (!valueMap.includes(el[key]?.toString()?.toLowerCase())) {
return false;
}
}
@@ -124,15 +140,40 @@ export const getFilteredData = (appliedFilters, results) => {
return filtered;
};
-export const getAppliedFilters =
- (currState, selectedOption) => (dispatch, getState) => {
- const { categoryFilterValue, filterData } = getState()[currState];
- const appliedFilters = { ...getState()[currState].appliedFilters };
+export const deleteAppliedFilters =
+ (filterKey, filterValue, currState) => (dispatch, getState) => {
+ const appliedFilters = cloneDeep(getState()[currState].appliedFilters);
+
+ const index = appliedFilters[filterKey].indexOf(
+ filterValue?.toString()?.toLowerCase()
+ );
+ if (index >= 0) {
+ appliedFilters[filterKey].splice(index, 1);
+ if (appliedFilters[filterKey].length === 0) {
+ delete appliedFilters[filterKey];
+ }
+ }
+ return appliedFilters;
+ };
- const category = filterData.filter(
- (item) => item.name === categoryFilterValue
- )[0].key;
- appliedFilters[category] = selectedOption;
+export const getSelectedFilter =
+ (selectedCategory, selectedOption, currState, isFromMetrics) =>
+ (dispatch, getState) => {
+ const selectedFilters = cloneDeep(getState()[currState].selectedFilters);
- return appliedFilters;
+ const obj = selectedFilters.find((i) => i.name === selectedCategory);
+ selectedOption = selectedOption?.toString()?.toLowerCase();
+
+ const objValue = obj.value.map((i) => i?.toString()?.toLowerCase());
+
+ if (objValue.includes(selectedOption)) {
+ const arr = objValue.filter((selection) => selection !== selectedOption);
+ obj.value = arr;
+ } else {
+ obj.value = isFromMetrics
+ ? [selectedOption]
+ : [...obj.value, selectedOption];
+ }
+
+ return selectedFilters;
};
diff --git a/frontend/src/actions/homeActions.js b/frontend/src/actions/homeActions.js
index d050b494..84296a98 100644
--- a/frontend/src/actions/homeActions.js
+++ b/frontend/src/actions/homeActions.js
@@ -6,9 +6,17 @@ import {
START_PAGE,
} from "@/assets/constants/paginationConstants";
import { appendDateFilter, appendQueryString } from "@/utils/helper";
-import { calculateMetrics, getFilteredData, sortTable } from "./commonActions";
+import {
+ buildFilterData,
+ calculateMetrics,
+ deleteAppliedFilters,
+ getFilteredData,
+ getSelectedFilter,
+ sortTable,
+} from "./commonActions";
import API from "@/utils/axiosInstance";
+import { cloneDeep } from "lodash";
import { showFailureToast } from "@/actions/toastActions";
export const fetchOCPJobsData = () => async (dispatch, getState) => {
@@ -20,8 +28,6 @@ export const fetchOCPJobsData = () => async (dispatch, getState) => {
pretty: true,
...(start_date && { start_date }),
...(end_date && { end_date }),
- // start_date: "2024-04-21",
- // end_date: "2024-04-22",
},
});
if (response?.data?.results?.length > 0) {
@@ -43,10 +49,7 @@ export const fetchOCPJobsData = () => async (dispatch, getState) => {
});
dispatch(applyFilters());
dispatch(sortTable("cpt"));
- dispatch(getCPTSummary());
- dispatch(setPageOptions(START_PAGE, DEFAULT_PER_PAGE));
- dispatch(sliceTableRows(0, DEFAULT_PER_PAGE));
- dispatch(buildFilterData());
+ dispatch(tableReCalcValues());
}
} catch (error) {
dispatch(showFailureToast());
@@ -73,28 +76,6 @@ export const sliceTableRows = (startIdx, endIdx) => (dispatch, getState) => {
});
};
-export const buildFilterData = () => (dispatch, getState) => {
- const results = [...getState().cpt.results];
-
- const tableFilters = [...getState().cpt.tableFilters];
-
- const filterData = [];
- for (const filter of tableFilters) {
- const key = filter.value;
- let obj = {
- name: filter.name,
- key,
- value: [...new Set(results.map((item) => item[key]?.toLowerCase()))],
- };
- filterData.push(obj);
- }
- dispatch({
- type: TYPES.SET_CPT_FILTER_DATA,
- payload: filterData,
- });
- dispatch(setCatFilters(tableFilters[0].name));
-};
-
export const setCatFilters = (category) => (dispatch, getState) => {
const filterData = [...getState().cpt.filterData];
const options = filterData.filter((item) => item.name === category)[0].value;
@@ -110,64 +91,70 @@ export const setCatFilters = (category) => (dispatch, getState) => {
});
};
-export const setAppliedFilters =
- (selectedOption, navigate) => (dispatch, getState) => {
- const { categoryFilterValue, filterData, start_date, end_date } =
- getState().cpt;
- const appliedFilters = { ...getState().cpt.appliedFilters };
-
- const category = filterData.filter(
- (item) => item.name === categoryFilterValue
- )[0].key;
- appliedFilters[category] = selectedOption;
-
+export const setSelectedFilterFromUrl = (params) => (dispatch, getState) => {
+ const selectedFilters = cloneDeep(getState().cpt.selectedFilters);
+ for (const key in params) {
+ selectedFilters.find((i) => i.name === key).value = params[key].split(",");
+ }
+ dispatch({
+ type: TYPES.SET_SELECTED_FILTERS,
+ payload: selectedFilters,
+ });
+};
+export const setSelectedFilter =
+ (selectedCategory, selectedOption, isFromMetrics) => (dispatch) => {
+ const selectedFilters = dispatch(
+ getSelectedFilter(selectedCategory, selectedOption, "cpt", isFromMetrics)
+ );
dispatch({
- type: TYPES.SET_APPLIED_FILTERS,
- payload: appliedFilters,
+ type: TYPES.SET_SELECTED_FILTERS,
+ payload: selectedFilters,
});
- appendQueryString({ ...appliedFilters, start_date, end_date }, navigate);
- dispatch(applyFilters());
};
-export const filterFromSummary =
- (category, value, navigate) => (dispatch, getState) => {
- const { start_date, end_date } = getState().cpt;
- const appliedFilters = { ...getState().cpt.appliedFilters };
- appliedFilters[category] = value;
- dispatch({
- type: TYPES.SET_APPLIED_FILTERS,
- payload: appliedFilters,
- });
- appendQueryString({ ...appliedFilters, start_date, end_date }, navigate);
- dispatch(applyFilters());
- };
+export const setAppliedFilters = (navigate) => (dispatch, getState) => {
+ const { selectedFilters, start_date, end_date } = getState().cpt;
+
+ const appliedFilterArr = selectedFilters.filter((i) => i.value.length > 0);
+
+ const appliedFilters = {};
+ appliedFilterArr.forEach((item) => {
+ appliedFilters[item["name"]] = item.value;
+ });
+
+ dispatch({
+ type: TYPES.SET_APPLIED_FILTERS,
+ payload: appliedFilters,
+ });
+ appendQueryString({ ...appliedFilters, start_date, end_date }, navigate);
+ dispatch(applyFilters());
+};
+
export const setOtherSummaryFilter = () => (dispatch, getState) => {
const filteredResults = [...getState().cpt.filteredResults];
- const keyWordArr = ["SUCCESS", "FAILURE"];
+ const keyWordArr = ["success", "failure"];
const data = filteredResults.filter(
- (item) => !keyWordArr.includes(item.jobStatus)
+ (item) => !keyWordArr.includes(item.jobStatus?.toLowerCase())
);
dispatch({
type: TYPES.SET_FILTERED_DATA,
payload: data,
});
- dispatch(getCPTSummary());
- dispatch(setPageOptions(START_PAGE, DEFAULT_PER_PAGE));
- dispatch(sliceTableRows(0, DEFAULT_PER_PAGE));
+ dispatch(tableReCalcValues());
};
export const removeAppliedFilters =
- (filterKey, navigate) => (dispatch, getState) => {
- const appliedFilters = { ...getState().cpt.appliedFilters };
+ (filterKey, filterValue, navigate) => (dispatch, getState) => {
const { start_date, end_date } = getState().cpt;
- const name = filterKey;
- // eslint-disable-next-line no-unused-vars
- const { [name]: removedProperty, ...remainingObject } = appliedFilters;
+
+ const appliedFilters = dispatch(
+ deleteAppliedFilters(filterKey, filterValue, "cpt")
+ );
dispatch({
type: TYPES.SET_APPLIED_FILTERS,
- payload: remainingObject,
+ payload: appliedFilters,
});
- appendQueryString({ ...remainingObject, start_date, end_date }, navigate);
+ appendQueryString({ ...appliedFilters, start_date, end_date }, navigate);
dispatch(applyFilters());
};
@@ -178,17 +165,18 @@ export const applyFilters = () => (dispatch, getState) => {
const isFilterApplied =
Object.keys(appliedFilters).length > 0 &&
- !Object.values(appliedFilters).includes("");
+ Object.values(appliedFilters).flat().length > 0;
- const filtered = getFilteredData(appliedFilters, results);
+ const filtered = isFilterApplied
+ ? getFilteredData(appliedFilters, results)
+ : results;
dispatch({
type: TYPES.SET_FILTERED_DATA,
- payload: isFilterApplied ? filtered : results,
+ payload: filtered,
});
- dispatch(getCPTSummary());
- dispatch(setPageOptions(START_PAGE, DEFAULT_PER_PAGE));
- dispatch(sliceTableRows(0, DEFAULT_PER_PAGE));
+ dispatch(tableReCalcValues());
+ dispatch(buildFilterData("cpt"));
};
export const setFilterFromURL = (searchParams) => ({
@@ -232,3 +220,9 @@ export const getCPTSummary = () => (dispatch, getState) => {
payload: countObj,
});
};
+
+export const tableReCalcValues = () => (dispatch) => {
+ dispatch(getCPTSummary());
+ dispatch(setPageOptions(START_PAGE, DEFAULT_PER_PAGE));
+ dispatch(sliceTableRows(0, DEFAULT_PER_PAGE));
+};
diff --git a/frontend/src/actions/ocpActions.js b/frontend/src/actions/ocpActions.js
index eff9cfa9..aae00a40 100644
--- a/frontend/src/actions/ocpActions.js
+++ b/frontend/src/actions/ocpActions.js
@@ -1,5 +1,5 @@
import * as API_ROUTES from "@/utils/apiConstants";
-import * as TYPES from "@/actions/types.js";
+import * as TYPES from "./types.js";
import {
DEFAULT_PER_PAGE,
@@ -9,13 +9,15 @@ import { appendDateFilter, appendQueryString } from "@/utils/helper.js";
import {
buildFilterData,
calculateMetrics,
+ deleteAppliedFilters,
getFilteredData,
+ getSelectedFilter,
sortTable,
-} from "@/actions/commonActions.js";
+} from "./commonActions";
import API from "@/utils/axiosInstance";
-import { getAppliedFilters } from "./commonActions";
-import { showFailureToast } from "@/actions/toastActions";
+import { cloneDeep } from "lodash";
+import { showFailureToast } from "./toastActions";
export const fetchOCPJobs = () => async (dispatch, getState) => {
try {
@@ -26,8 +28,6 @@ export const fetchOCPJobs = () => async (dispatch, getState) => {
pretty: true,
...(start_date && { start_date }),
...(end_date && { end_date }),
- // start_date: "2024-04-21",
- // end_date: "2024-04-22",
},
});
if (response?.data?.results?.length > 0) {
@@ -48,10 +48,7 @@ export const fetchOCPJobs = () => async (dispatch, getState) => {
});
dispatch(applyFilters());
dispatch(sortTable("ocp"));
- dispatch(setPageOptions(START_PAGE, DEFAULT_PER_PAGE));
- dispatch(sliceOCPTableRows(0, DEFAULT_PER_PAGE));
- dispatch(buildFilterData("ocp"));
- dispatch(getOCPSummary());
+ dispatch(tableReCalcValues());
}
} catch (error) {
dispatch(showFailureToast());
@@ -112,42 +109,66 @@ export const applyFilters = () => (dispatch, getState) => {
Object.keys(appliedFilters).length > 0 &&
!Object.values(appliedFilters).includes("");
- const filtered = getFilteredData(appliedFilters, results);
+ const filtered = isFilterApplied
+ ? getFilteredData(appliedFilters, results)
+ : results;
dispatch({
type: TYPES.SET_OCP_FILTERED_DATA,
- payload: isFilterApplied ? filtered : results,
+ payload: filtered,
});
- dispatch(getOCPSummary());
- dispatch(setPageOptions(START_PAGE, DEFAULT_PER_PAGE));
- dispatch(sliceOCPTableRows(0, DEFAULT_PER_PAGE));
+ dispatch(tableReCalcValues());
+ dispatch(buildFilterData("ocp"));
};
-export const setAppliedFilters =
- (selectedOption, navigate) => (dispatch, getState) => {
- const appliedFilters = dispatch(getAppliedFilters("ocp", selectedOption));
- const { start_date, end_date } = getState().ocp;
+export const setSelectedFilterFromUrl = (params) => (dispatch, getState) => {
+ const selectedFilters = cloneDeep(getState().ocp.selectedFilters);
+ for (const key in params) {
+ selectedFilters.find((i) => i.name === key).value = params[key].split(",");
+ }
+ dispatch({
+ type: TYPES.SET_SELECTED_OCP_FILTERS,
+ payload: selectedFilters,
+ });
+};
+export const setSelectedFilter =
+ (selectedCategory, selectedOption, isFromMetrics) => (dispatch) => {
+ const selectedFilters = dispatch(
+ getSelectedFilter(selectedCategory, selectedOption, "ocp", isFromMetrics)
+ );
dispatch({
- type: TYPES.SET_OCP_APPLIED_FILTERS,
- payload: appliedFilters,
+ type: TYPES.SET_SELECTED_OCP_FILTERS,
+ payload: selectedFilters,
});
- appendQueryString({ ...appliedFilters, start_date, end_date }, navigate);
- dispatch(applyFilters());
};
+export const setAppliedFilters = (navigate) => (dispatch, getState) => {
+ const { start_date, end_date, selectedFilters } = getState().ocp;
+ const appliedFilterArr = selectedFilters.filter((i) => i.value.length > 0);
+
+ const appliedFilters = {};
+ appliedFilterArr.forEach((item) => {
+ appliedFilters[item["name"]] = item.value;
+ });
+
+ dispatch({
+ type: TYPES.SET_OCP_APPLIED_FILTERS,
+ payload: appliedFilters,
+ });
+ appendQueryString({ ...appliedFilters, start_date, end_date }, navigate);
+ dispatch(applyFilters());
+};
export const removeAppliedFilters =
- (filterKey, navigate) => (dispatch, getState) => {
- const appliedFilters = { ...getState().ocp.appliedFilters };
+ (filterKey, filterValue, navigate) => (dispatch, getState) => {
+ const appliedFilters = dispatch(
+ deleteAppliedFilters(filterKey, filterValue, "ocp")
+ );
const { start_date, end_date } = getState().ocp;
- const name = filterKey;
- // eslint-disable-next-line no-unused-vars
- const { [name]: removedProperty, ...remainingObject } = appliedFilters;
-
dispatch({
type: TYPES.SET_OCP_APPLIED_FILTERS,
- payload: remainingObject,
+ payload: appliedFilters,
});
- appendQueryString({ ...remainingObject, start_date, end_date }, navigate);
+ appendQueryString({ ...appliedFilters, start_date, end_date }, navigate);
dispatch(applyFilters());
};
@@ -173,32 +194,17 @@ export const setFilterFromURL = (searchParams) => ({
payload: searchParams,
});
-export const filterFromSummary =
- (category, value, navigate) => (dispatch, getState) => {
- const { start_date, end_date } = getState().ocp;
- const appliedFilters = { ...getState().ocp.appliedFilters };
- appliedFilters[category] = value;
- dispatch({
- type: TYPES.SET_OCP_APPLIED_FILTERS,
- payload: appliedFilters,
- });
- appendQueryString({ ...appliedFilters, start_date, end_date }, navigate);
- dispatch(applyFilters());
- };
-
export const setOtherSummaryFilter = () => (dispatch, getState) => {
const filteredResults = [...getState().ocp.filteredResults];
- const keyWordArr = ["SUCCESS", "FAILURE"];
+ const keyWordArr = ["success", "failure"];
const data = filteredResults.filter(
- (item) => !keyWordArr.includes(item.jobStatus)
+ (item) => !keyWordArr.includes(item.jobStatus?.toLowerCase())
);
dispatch({
type: TYPES.SET_OCP_FILTERED_DATA,
payload: data,
});
- dispatch(getOCPSummary());
- dispatch(setPageOptions(START_PAGE, DEFAULT_PER_PAGE));
- dispatch(sliceOCPTableRows(0, DEFAULT_PER_PAGE));
+ dispatch(tableReCalcValues());
};
export const getOCPSummary = () => (dispatch, getState) => {
@@ -249,3 +255,8 @@ export const setTableColumns = (key, isAdding) => (dispatch, getState) => {
payload: tableColumns,
});
};
+export const tableReCalcValues = () => (dispatch) => {
+ dispatch(getOCPSummary());
+ dispatch(setPageOptions(START_PAGE, DEFAULT_PER_PAGE));
+ dispatch(sliceOCPTableRows(0, DEFAULT_PER_PAGE));
+};
diff --git a/frontend/src/actions/types.js b/frontend/src/actions/types.js
index 173ac44c..77db108b 100644
--- a/frontend/src/actions/types.js
+++ b/frontend/src/actions/types.js
@@ -25,7 +25,7 @@ export const SET_APPLIED_FILTERS = "SET_APPLIED_FILTERS";
export const SET_PAGE = "SET_PAGE";
export const SET_PAGE_OPTIONS = "SET_PAGE_OPTIONS";
export const SET_CPT_SUMMARY = "SET_CPT_SUMMARY";
-
+export const SET_SELECTED_FILTERS = "SET_SELECTED_FILTERS";
/* OCP Jobs */
export const SET_OCP_JOBS_DATA = "SET_OCP_JOBS_DATA";
export const SET_OCP_DATE_FILTER = "SET_OCP_DATE_FILTER";
@@ -42,3 +42,4 @@ export const SET_OCP_FILTERED_DATA = "SET_OCP_FILTERED_DATA";
export const SET_OCP_APPLIED_FILTERS = "SET_OCP_APPLIED_FILTERS";
export const SET_OCP_GRAPH_DATA = "SET_OCP_GRAPH_DATA";
export const SET_OCP_COLUMNS = "SET_OCP_COLUMNS";
+export const SET_SELECTED_OCP_FILTERS = "SET_SELECTED_OCP_FILTERS";
diff --git a/frontend/src/components/molecules/MultiSelectBox/index.jsx b/frontend/src/components/molecules/MultiSelectBox/index.jsx
new file mode 100644
index 00000000..7acbf263
--- /dev/null
+++ b/frontend/src/components/molecules/MultiSelectBox/index.jsx
@@ -0,0 +1,118 @@
+import {
+ Chip,
+ ChipGroup,
+ MenuToggle,
+ Select,
+ SelectList,
+ SelectOption,
+ TextInputGroup,
+ TextInputGroupMain,
+} from "@patternfly/react-core";
+
+import PropTypes from "prop-types";
+import { useState } from "react";
+
+const MultiSelectBox = (props) => {
+ const [isOpen, setIsOpen] = useState(false);
+ const [isDirty, setIsDirty] = useState(false);
+ const onSelect = (value) => {
+ console.log("selected", value);
+ setIsDirty(true);
+ props.onChange(props.currCategory, value);
+ };
+
+ const onToggleClick = () => {
+ setIsOpen(!isOpen);
+ };
+
+ const closeMenu = () => {
+ setIsOpen(false);
+ if (isDirty) {
+ props.applyMethod();
+ }
+ setIsDirty(false);
+ };
+ const toggle = (toggleRef) => {
+ console.log(props.selected);
+ return (
+
+ {Array.isArray(props.selected.value) &&
+ props.selected.value.length > 0 ? (
+
+
+
+ {props.selected.value.map((selection, index) => (
+ {
+ // ev.stopPropagation();
+ // onSelect(selection);
+ // }}
+ >
+ {selection}
+
+ ))}
+
+
+
+ ) : (
+
+
+
+ )}
+
+ );
+ };
+ const createItemId = (value) =>
+ `select-multi-typeahead-${value.replace(" ", "-")}`;
+ return (
+ <>
+
+ >
+ );
+};
+
+MultiSelectBox.propTypes = {
+ options: PropTypes.array,
+ onChange: PropTypes.func,
+ selected: PropTypes.array,
+ applyMethod: PropTypes.func,
+ currCategory: PropTypes.string,
+ width: PropTypes.string,
+};
+export default MultiSelectBox;
diff --git a/frontend/src/components/molecules/SelectBox/index.jsx b/frontend/src/components/molecules/SelectBox/index.jsx
index bff775f8..ac73eed2 100644
--- a/frontend/src/components/molecules/SelectBox/index.jsx
+++ b/frontend/src/components/molecules/SelectBox/index.jsx
@@ -26,6 +26,7 @@ const SelectBox = (props) => {
isExpanded={isOpen}
style={{
width: props.width,
+ height: "36px",
}}
>
{props.selected}
diff --git a/frontend/src/components/organisms/TableFilters/index.jsx b/frontend/src/components/organisms/TableFilters/index.jsx
index 81160121..ddd44368 100644
--- a/frontend/src/components/organisms/TableFilters/index.jsx
+++ b/frontend/src/components/organisms/TableFilters/index.jsx
@@ -4,6 +4,7 @@ import "./index.less";
import {
Chip,
+ ChipGroup,
Toolbar,
ToolbarContent,
ToolbarItem,
@@ -12,6 +13,7 @@ import {
import ColumnMenuFilter from "@/components/molecules/ColumnMenuFilter";
import DatePicker from "react-date-picker";
import { FilterIcon } from "@patternfly/react-icons";
+import MultiSelectBox from "@/components/molecules/MultiSelectBox";
import PropTypes from "prop-types";
import SelectBox from "@/components/molecules/SelectBox";
import { formatDate } from "@/utils/helper";
@@ -33,39 +35,48 @@ const TableFilter = (props) => {
type,
showColumnMenu,
setColumns,
+ selectedFilters,
+ updateSelectedFilter,
} = props;
- const category = filterData.filter(
- (item) => item.name === categoryFilterValue
- )[0].key;
+ const category =
+ filterData?.length > 0 &&
+ filterData.filter((item) => item.name === categoryFilterValue)[0].key;
const getFilterName = (key) => {
- const filter = tableFilters.find((item) => item.value === key);
+ const filter =
+ tableFilters?.length > 0 &&
+ tableFilters?.find((item) => item.value === key);
return filter.name;
};
return (
<>
-
-
- }
- width={"200px"}
- />
-
-
-
-
-
+ {tableFilters?.length > 0 && filterOptions?.length > 0 && (
+
+
+ }
+ width={"200px"}
+ />
+
+
+ i.name === category)}
+ width={"300px"}
+ />
+
+
+ )}
+
{
{Object.keys(appliedFilters).length > 0 &&
Object.keys(appliedFilters).map((key) => (
- deleteItem(key)}>
- {getFilterName(key)} : {appliedFilters[key]}
-
+
+ {getFilterName(key)} :
+ {appliedFilters[key].map((i) => (
+ deleteItem(key, i)} key={i}>
+ {i}
+
+ ))}
+
))}
>
);
@@ -120,5 +136,7 @@ TableFilter.propTypes = {
type: PropTypes.string,
showColumnMenu: PropTypes.bool,
setColumns: PropTypes.func,
+ selectedFilters: PropTypes.array,
+ updateSelectedFilter: PropTypes.func,
};
export default TableFilter;
diff --git a/frontend/src/components/templates/Home/index.jsx b/frontend/src/components/templates/Home/index.jsx
index 45590a1e..8e6d8254 100644
--- a/frontend/src/components/templates/Home/index.jsx
+++ b/frontend/src/components/templates/Home/index.jsx
@@ -1,6 +1,5 @@
import {
fetchOCPJobsData,
- filterFromSummary,
removeAppliedFilters,
setAppliedFilters,
setCPTSortDir,
@@ -11,6 +10,8 @@ import {
setOtherSummaryFilter,
setPage,
setPageOptions,
+ setSelectedFilter,
+ setSelectedFilterFromUrl,
sliceTableRows,
} from "@/actions/homeActions.js";
import { useCallback, useEffect } from "react";
@@ -43,6 +44,7 @@ const Home = () => {
page,
perPage,
summary,
+ selectedFilters,
} = useSelector((state) => state.cpt);
useEffect(() => {
@@ -54,7 +56,12 @@ const Home = () => {
searchParams.delete("start_date");
searchParams.delete("end_date");
const params = Object.fromEntries(searchParams);
- dispatch(setFilterFromURL(params));
+ const obj = {};
+ for (const key in params) {
+ obj[key] = params[key].split(",");
+ }
+ dispatch(setFilterFromURL(obj));
+ dispatch(setSelectedFilterFromUrl(params));
dispatch(setDateFilter(startDate, endDate, navigate));
}
}, []);
@@ -95,11 +102,12 @@ const Home = () => {
const onCategoryChange = (_event, value) => {
dispatch(setCatFilters(value));
};
- const onOptionsChange = (_event, value) => {
- dispatch(setAppliedFilters(value, navigate));
+ const onOptionsChange = () => {
+ dispatch(setAppliedFilters(navigate));
};
- const deleteItem = (key) => {
- dispatch(removeAppliedFilters(key, navigate));
+ const deleteItem = (key, value) => {
+ dispatch(removeAppliedFilters(key, value, navigate));
+ updateSelectedFilter(key, value, false);
};
const startDateChangeHandler = (date, key) => {
dispatch(setDateFilter(date, key, navigate));
@@ -108,15 +116,27 @@ const Home = () => {
dispatch(setDateFilter(key, date, navigate));
};
const removeStatusFilter = () => {
- dispatch(removeAppliedFilters("jobStatus", navigate));
+ if (
+ Array.isArray(appliedFilters["jobStatus"]) &&
+ appliedFilters["jobStatus"].length > 0
+ ) {
+ appliedFilters["jobStatus"].forEach((element) => {
+ updateSelectedFilter("jobStatus", element, true);
+ dispatch(removeAppliedFilters("jobStatus", element, navigate));
+ });
+ }
};
const applyStatusFilter = (value) => {
- dispatch(filterFromSummary("jobStatus", value, navigate));
+ updateSelectedFilter("jobStatus", value, true);
+ dispatch(setAppliedFilters(navigate));
};
const applyOtherFilter = () => {
- dispatch(removeAppliedFilters("jobStatus", navigate));
+ removeStatusFilter();
dispatch(setOtherSummaryFilter());
};
+ const updateSelectedFilter = (category, value, isFromMetrics) => {
+ dispatch(setSelectedFilter(category, value, isFromMetrics));
+ };
// Filter Helper
return (
<>
@@ -127,24 +147,25 @@ const Home = () => {
applyStatusFilter={applyStatusFilter}
applyOtherFilter={applyOtherFilter}
/>
- {tableFilters?.length > 0 && filterOptions?.length > 0 && (
-
- )}
+
+
{
start_date,
end_date,
graphData,
+ selectedFilters,
} = useSelector((state) => state.ocp);
const modifidedTableFilters = useMemo(
@@ -63,7 +65,12 @@ const OCP = () => {
searchParams.delete("start_date");
searchParams.delete("end_date");
const params = Object.fromEntries(searchParams);
- dispatch(setFilterFromURL(params));
+ const obj = {};
+ for (const key in params) {
+ obj[key] = params[key].split(",");
+ }
+ dispatch(setFilterFromURL(obj));
+ dispatch(setSelectedFilterFromUrl(params));
dispatch(setDateFilter(startDate, endDate, navigate));
}
}, []);
@@ -102,26 +109,39 @@ const OCP = () => {
// Pagination helper
/* Summary Tab Filter*/
const removeStatusFilter = () => {
- dispatch(removeAppliedFilters("jobStatus", navigate));
+ if (
+ Array.isArray(appliedFilters["jobStatus"]) &&
+ appliedFilters["jobStatus"].length > 0
+ ) {
+ appliedFilters["jobStatus"].forEach((element) => {
+ updateSelectedFilter("jobStatus", element, true);
+ dispatch(removeAppliedFilters("jobStatus", element, navigate));
+ });
+ }
};
const applyStatusFilter = (value) => {
- dispatch(filterFromSummary("jobStatus", value, navigate));
+ updateSelectedFilter("jobStatus", value, true);
+ dispatch(setAppliedFilters(navigate));
};
const applyOtherFilter = () => {
- dispatch(removeAppliedFilters("jobStatus", navigate));
+ removeStatusFilter();
dispatch(setOtherSummaryFilter());
};
+ const updateSelectedFilter = (category, value, isFromMetrics = false) => {
+ dispatch(setSelectedFilter(category, value, isFromMetrics));
+ };
/* Filter helper */
const onCategoryChange = (_event, value) => {
dispatch(setOCPCatFilters(value));
};
- const onOptionsChange = (_event, value) => {
- dispatch(setAppliedFilters(value, navigate));
+ const onOptionsChange = () => {
+ dispatch(setAppliedFilters(navigate));
};
- const deleteItem = (key) => {
- dispatch(removeAppliedFilters(key, navigate));
+ const deleteItem = (key, value) => {
+ dispatch(removeAppliedFilters(key, value, navigate));
+ updateSelectedFilter(key, value);
};
const startDateChangeHandler = (date, key) => {
dispatch(setDateFilter(date, key, navigate));
@@ -160,25 +180,25 @@ const OCP = () => {
applyOtherFilter={applyOtherFilter}
/>
- {tableFilters?.length > 0 && filterOptions?.length > 0 && (
-
- )}
+
{
return { ...state, page: payload.page, perPage: payload.perPage };
case TYPES.SET_CPT_SUMMARY:
return { ...state, summary: payload };
+ case TYPES.SET_SELECTED_FILTERS:
+ return { ...state, selectedFilters: payload };
default:
return state;
}
diff --git a/frontend/src/reducers/ocpReducer.js b/frontend/src/reducers/ocpReducer.js
index bacfddb9..99b4d160 100644
--- a/frontend/src/reducers/ocpReducer.js
+++ b/frontend/src/reducers/ocpReducer.js
@@ -79,6 +79,27 @@ const initialState = {
{ name: "Infra", value: "infraNodesCount" },
{ name: "Total", value: "totalNodesCount" },
],
+ selectedFilters: [
+ { name: "ciSystem", value: [] },
+ { name: "platform", value: [] },
+ { name: "benchmark", value: [] },
+ { name: "releaseStream", value: [] },
+ { name: "build", value: [] },
+ { name: "workerNodesCount", value: [] },
+ { name: "networkType", value: [] },
+ { name: "shortVersion", value: [] },
+ { name: "jobType", value: [] },
+ { name: "isRehearse", value: [] },
+ { name: "ipsec", value: [] },
+ { name: "fips", value: [] },
+ { name: "encrypted", value: [] },
+ { name: "publish", value: [] },
+ { name: "computeArch", value: [] },
+ { name: "controlPlaneArch", value: [] },
+ { name: "jobStatus", value: [] },
+ { name: "startDate", value: [] },
+ { name: "endDate", value: [] },
+ ],
};
const OCPReducer = (state = initialState, action = {}) => {
@@ -122,6 +143,8 @@ const OCPReducer = (state = initialState, action = {}) => {
return { ...state, graphData: [...state.graphData, payload] };
case TYPES.SET_OCP_COLUMNS:
return { ...state, tableColumns: payload };
+ case TYPES.SET_SELECTED_OCP_FILTERS:
+ return { ...state, selectedFilters: payload };
default:
return state;
}