From a8186ba19bf1b30aed0d7ed86fe39e245a8bd280 Mon Sep 17 00:00:00 2001 From: Carmine Di Monaco Date: Mon, 5 Sep 2022 14:42:16 +0200 Subject: [PATCH 1/2] Style the "back to cluster button" in ChecksResult view The style of back to cluster CTA changes --- assets/js/components/Button/Button.jsx | 2 ++ .../ClusterDetails/ChecksResults.jsx | 23 +++++++++++-------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/assets/js/components/Button/Button.jsx b/assets/js/components/Button/Button.jsx index 5c1daf59e6..030f42a8c8 100644 --- a/assets/js/components/Button/Button.jsx +++ b/assets/js/components/Button/Button.jsx @@ -12,6 +12,8 @@ const getSizeClasses = (size) => { const getButtonClasses = (type) => { switch (type) { + case 'transparent': + return 'bg-transparent hover:opacity-75 focus:outline-none w-full transition ease-in duration-200 font-semibold'; case 'secondary': return 'bg-persimmon hover:opacity-75 focus:outline-none text-gray-800 w-full transition ease-in duration-200 text-center font-semibold rounded shadow'; default: diff --git a/assets/js/components/ClusterDetails/ChecksResults.jsx b/assets/js/components/ClusterDetails/ChecksResults.jsx index dfad7d9d70..8c37286d0d 100644 --- a/assets/js/components/ClusterDetails/ChecksResults.jsx +++ b/assets/js/components/ClusterDetails/ChecksResults.jsx @@ -234,6 +234,19 @@ export const ChecksResults = () => { {findCheckDataByID(selectedCheck)?.remediation} +
+
+ +
+

Checks Results for cluster{' '} @@ -241,16 +254,6 @@ export const ChecksResults = () => { {getClusterName(cluster)}

-
- -
{pageContent} From 958777231414ced6e4fa81c6872f007882b721e5 Mon Sep 17 00:00:00 2001 From: Carmine Di Monaco Date: Wed, 7 Sep 2022 12:22:55 +0200 Subject: [PATCH 2/2] Add filters to ChecksResult screen --- .../ClusterDetails/ChecksResultFilters.jsx | 81 +++++++++++++++++++ .../ClusterDetails/ChecksResults.jsx | 18 ++++- 2 files changed, 96 insertions(+), 3 deletions(-) create mode 100644 assets/js/components/ClusterDetails/ChecksResultFilters.jsx diff --git a/assets/js/components/ClusterDetails/ChecksResultFilters.jsx b/assets/js/components/ClusterDetails/ChecksResultFilters.jsx new file mode 100644 index 0000000000..b3c09153a2 --- /dev/null +++ b/assets/js/components/ClusterDetails/ChecksResultFilters.jsx @@ -0,0 +1,81 @@ +import React, { useState, useEffect } from 'react'; +import Filter from '@components/Table/Filter'; + +export const RESULT_FILTER_FIELD = 'result'; + +export const useFilteredChecks = (cluster) => { + const [filtersPredicates, setFiltersPredicates] = useState([]); + const [filteredChecks, setFilteredChecks] = useState([]); + + const filterChecks = (checks, predicates) => { + if (predicates.length === 0) return checks; + + return checks.filter((check) => + predicates.some((predicate) => predicate(check)) + ); + }; + + const checksForHost = (hostID) => + filteredChecks + .filter((result) => result.host_id === hostID) + .map((result) => result.check_id); + + useEffect(() => { + if (cluster?.checks_results.length > 0) { + const selectedCheckResults = cluster?.checks_results.filter((result) => + cluster?.selected_checks.includes(result?.check_id) + ); + + setFilteredChecks(filterChecks(selectedCheckResults, filtersPredicates)); + } + }, [cluster?.checks_results, cluster?.selected_checks, filtersPredicates]); + + return { + setFiltersPredicates, + filteredChecksyByHost: checksForHost, + }; +}; + +const ChecksResultFilters = ({ onChange }) => { + const [filtersForField, setFiltersForField] = useState({}); + + // This structure is the foundation for a multi field filters + // we can reuse later this structure in other parts of the application + + useEffect(() => { + if (Object.keys(filtersForField).length >= 0) { + const filtersToApply = Object.keys(filtersForField).reduce( + (acc, curr) => { + return [...acc, ...filtersForField[curr].predicates]; + }, + [] + ); + + onChange(filtersToApply); + } + }, [filtersForField]); + + return ( +
+ { + setFiltersForField((existingFilters) => ({ + ...existingFilters, + [RESULT_FILTER_FIELD]: { + predicates: list.map( + (value) => (checks) => checks[RESULT_FILTER_FIELD] === value + ), + values: list, + }, + })); + }} + /> +
+ ); +}; + +export default ChecksResultFilters; diff --git a/assets/js/components/ClusterDetails/ChecksResults.jsx b/assets/js/components/ClusterDetails/ChecksResults.jsx index 8c37286d0d..dda20c8e51 100644 --- a/assets/js/components/ClusterDetails/ChecksResults.jsx +++ b/assets/js/components/ClusterDetails/ChecksResults.jsx @@ -23,6 +23,9 @@ import { } from './ClusterDetails'; import { ExecutionIcon } from './ExecutionIcon'; import { getClusterName } from '@components/ClusterLink'; +import ChecksResultFilters, { + useFilteredChecks, +} from '@components/ClusterDetails/ChecksResultFilters'; import ReactMarkdown from 'react-markdown'; import remarkGfm from 'remark-gfm'; @@ -86,6 +89,9 @@ export const ChecksResults = () => { const hostname = getHostname(useSelector((state) => state.hostsList.hosts)); + const { filteredChecksyByHost, setFiltersPredicates } = + useFilteredChecks(cluster); + useEffect(() => { cluster?.provider && dispatchUpdateCatalog(); }, [cluster?.provider]); @@ -136,6 +142,7 @@ export const ChecksResults = () => { ); } else { const lastExecution = sortHosts(cluster?.hosts_executions.slice()); + pageContent = lastExecution.map( ({ _cluster_id, host_id, reachable, msg }, idx) => (
@@ -179,7 +186,7 @@ export const ChecksResults = () => { - {sortChecks(cluster?.selected_checks.slice()).map( + {sortChecks(filteredChecksyByHost(host_id)).map( (checkId) => ( { onClick={() => navigate(`/clusters/${cluster.id}`)} > {' '} - Back to Cluster Detail + Back to Cluster Details
-
+

Checks Results for cluster{' '} {getClusterName(cluster)}

+ + setFiltersPredicates(filtersPredicates) + } + />
{pageContent}