diff --git a/ui/src/components/pages/Cluster/partials/ClusterNamespaceListing/index.tsx b/ui/src/components/pages/Cluster/partials/ClusterNamespaceListing/index.tsx index ed1e98259..6c442cab8 100644 --- a/ui/src/components/pages/Cluster/partials/ClusterNamespaceListing/index.tsx +++ b/ui/src/components/pages/Cluster/partials/ClusterNamespaceListing/index.tsx @@ -1,5 +1,6 @@ import React, { useState, useEffect, useCallback, useMemo } from "react"; import Box from "@mui/material/Box"; +import { MenuItem, Select } from "@mui/material"; import Pagination from "@mui/material/Pagination"; import Grid from "@mui/material/Grid"; import { DebouncedSearchInput } from "../../../../common/DebouncedSearchInput"; @@ -9,6 +10,17 @@ import { ClusterNamespaceListingProps, ClusterNamespaceSummary, } from "../../../../../types/declarations/cluster"; +import { HEALTH } from "../../../Namespace/partials/NamespacePipelineListing"; +import { + ACTIVE, + ALL, + CRITICAL, + HEALTHY, + INACTIVE, + NO_PIPELINES, + WARNING, + WITH_PIPELINES, +} from "../../../../../utils"; import "./style.css"; @@ -19,6 +31,13 @@ export function ClusterNamespaceListing({ }: ClusterNamespaceListingProps) { const [search, setSearch] = useState(""); const [page, setPage] = useState(1); + const nFilter = + data?.nameSpaceSummaries?.filter((ns) => !ns.isEmpty).length > 0 + ? WITH_PIPELINES + : ALL; + const [namespaceFilter, setNamespaceFilter] = useState(nFilter); + const [healthFilter, setHealthFilter] = useState(ALL); + const [statusFilter, setStatusFilter] = useState(ALL); const [totalPages, setTotalPages] = useState( Math.ceil(data.namespacesCount / MAX_PAGE_SIZE) ); @@ -38,6 +57,37 @@ export function ClusterNamespaceListing({ // Sort by name filtered.sort((a, b) => (a.name > b.name ? 1 : -1)); + //Filter based on the empty pipelines filter + if (namespaceFilter === WITH_PIPELINES) { + filtered = filtered.filter((ns) => !ns.isEmpty); + } else if (namespaceFilter === NO_PIPELINES) { + filtered = filtered.filter((ns) => ns.isEmpty); + } + + //Filter namespaces with pipelines based on health + filtered = filtered.filter((ns) => { + if (healthFilter === HEALTHY) { + return ns.pipelinesHealthyCount > 0; + } else if (healthFilter === WARNING) { + return ns.pipelinesWarningCount > 0; + } else if (healthFilter === CRITICAL) { + return ns.pipelinesCriticalCount > 0; + } else { + return true; + } + }); + + //Filter namespaces with pipelines based on status + filtered = filtered.filter((ns) => { + if (statusFilter === ACTIVE) { + return ns.pipelinesActiveCount > 0; + } else if (statusFilter === INACTIVE) { + return ns.pipelinesInactiveCount > 0; + } else { + return true; + } + }); + // Break list into pages const pages = filtered.reduce((resultArray: any[], item, index) => { const chunkIndex = Math.floor(index / MAX_PAGE_SIZE); @@ -55,15 +105,27 @@ export function ClusterNamespaceListing({ // Set filtered namespaces with current page of namespaces setFilteredNamespaces(pages[page - 1] || []); setTotalPages(pages.length); - }, [data, search, page]); + }, [data, search, page, namespaceFilter, healthFilter, statusFilter]); const handlePageChange = useCallback( - (event: React.ChangeEvent, value: number) => { + (_: React.ChangeEvent, value: number) => { setPage(value); }, [] ); + const handleNamespaceFilterChange = useCallback((event: any) => { + setNamespaceFilter(event.target.value); + }, []); + + const handleHealthFilterChange = useCallback((event: any) => { + setHealthFilter(event.target.value); + }, []); + + const handleStatusFilterChange = useCallback((event: any) => { + setStatusFilter(event.target.value); + }, []); + const listing = useMemo(() => { if (!filteredNamespaces.length) { return ( @@ -125,6 +187,112 @@ export function ClusterNamespaceListing({ placeHolder="Search for namespace" onChange={setSearch} /> + + + + + + + + + + + + + + diff --git a/ui/src/components/pages/Namespace/partials/NamespacePipelineListing/index.tsx b/ui/src/components/pages/Namespace/partials/NamespacePipelineListing/index.tsx index 07c294183..28c9d7e25 100644 --- a/ui/src/components/pages/Namespace/partials/NamespacePipelineListing/index.tsx +++ b/ui/src/components/pages/Namespace/partials/NamespacePipelineListing/index.tsx @@ -43,6 +43,8 @@ import { import "./style.css"; const MAX_PAGE_SIZE = 4; +export const HEALTH = [ALL, HEALTHY, WARNING, CRITICAL]; +export const STATUS = [ALL, RUNNING, STOPPED, PAUSED]; const sortOptions = [ { @@ -99,8 +101,6 @@ export function NamespacePipelineListing({ isbData, refresh, }: NamespacePipelineListingProps) { - const HEALTH = [ALL, HEALTHY, WARNING, CRITICAL]; - const STATUS = [ALL, RUNNING, STOPPED, PAUSED]; const { setSidebarProps } = useContext(AppContext); const [search, setSearch] = useState(""); const [health, setHealth] = useState(ALL); diff --git a/ui/src/types/declarations/cluster.d.ts b/ui/src/types/declarations/cluster.d.ts index e5b91d766..794221aa7 100644 --- a/ui/src/types/declarations/cluster.d.ts +++ b/ui/src/types/declarations/cluster.d.ts @@ -1,5 +1,6 @@ export interface ClusterNamespaceSummary { name: string; + isEmpty: boolean; pipelinesCount: number; pipelinesActiveCount: number; pipelinesInactiveCount: number; diff --git a/ui/src/utils/fetchWrappers/clusterSummaryFetch.ts b/ui/src/utils/fetchWrappers/clusterSummaryFetch.ts index d1d5d3a4a..adb582035 100644 --- a/ui/src/utils/fetchWrappers/clusterSummaryFetch.ts +++ b/ui/src/utils/fetchWrappers/clusterSummaryFetch.ts @@ -50,6 +50,7 @@ const rawDataToClusterSummary = ( // Add ns summary to array nameSpaceSummaries.push({ name: ns.namespace || DEFAULT_NS_NAME, + isEmpty: !!ns.isEmpty, pipelinesCount: nsPipelinesCount, pipelinesActiveCount: nsPipelinesActiveCount, pipelinesInactiveCount: nsPipelinesInactiveCount, diff --git a/ui/src/utils/index.tsx b/ui/src/utils/index.tsx index 6f8944d53..15a1722ae 100644 --- a/ui/src/utils/index.tsx +++ b/ui/src/utils/index.tsx @@ -26,6 +26,8 @@ export const PAUSED = "Paused"; export const DELETING = "Deleting"; export const UNKNOWN = "Unknown"; export const STOPPED = "Stopped"; +export const WITH_PIPELINES = "With Pipelines"; +export const NO_PIPELINES = "No Pipelines"; // ISB types export const JETSTREAM = "jetstream";