This is an automated email from the ASF dual-hosted git repository.

twice pushed a commit to branch unstable
in repository https://gitbox.apache.org/repos/asf/kvrocks-controller.git


The following commit(s) were added to refs/heads/unstable by this push:
     new c6380ef  feat(webui/cluster): redesign cluster page (#322)
c6380ef is described below

commit c6380efe04c953c2c2be7d171619218ac8dea75e
Author: Agnik Misra <[email protected]>
AuthorDate: Sun Jul 6 19:08:47 2025 +0530

    feat(webui/cluster): redesign cluster page (#322)
---
 webui/src/app/namespaces/[namespace]/page.tsx | 1198 ++++++++++++++++++++++---
 webui/src/app/ui/formCreation.tsx             |   13 +-
 webui/src/app/ui/formDialog.tsx               |    8 +-
 3 files changed, 1111 insertions(+), 108 deletions(-)

diff --git a/webui/src/app/namespaces/[namespace]/page.tsx 
b/webui/src/app/namespaces/[namespace]/page.tsx
index b36f50b..dfc336d 100644
--- a/webui/src/app/namespaces/[namespace]/page.tsx
+++ b/webui/src/app/namespaces/[namespace]/page.tsx
@@ -19,10 +19,23 @@
 
 "use client";
 
-import { Box, Typography, Chip } from "@mui/material";
+import {
+    Box,
+    Typography,
+    Chip,
+    Paper,
+    Grid,
+    Button,
+    IconButton,
+    Tooltip,
+    Popover,
+    RadioGroup,
+    FormControlLabel,
+    Radio,
+    Fade,
+} from "@mui/material";
 import { NamespaceSidebar } from "../../ui/sidebar";
-import { AddClusterCard, ResourceCard } from "../../ui/createCard";
-import { fetchCluster, fetchClusters, fetchNamespaces } from "@/app/lib/api";
+import { fetchCluster, fetchClusters, fetchNamespaces, listShards, listNodes } 
from "@/app/lib/api";
 import Link from "next/link";
 import { useRouter, notFound } from "next/navigation";
 import { useState, useEffect } from "react";
@@ -32,9 +45,72 @@ import FolderIcon from "@mui/icons-material/Folder";
 import EmptyState from "@/app/ui/emptyState";
 import GridViewIcon from "@mui/icons-material/GridView";
 
+import SearchIcon from "@mui/icons-material/Search";
+import FilterListIcon from "@mui/icons-material/FilterList";
+import SortIcon from "@mui/icons-material/Sort";
+import CheckIcon from "@mui/icons-material/Check";
+import ArrowUpwardIcon from "@mui/icons-material/ArrowUpward";
+import ArrowDownwardIcon from "@mui/icons-material/ArrowDownward";
+import DnsIcon from "@mui/icons-material/Dns";
+import DeviceHubIcon from "@mui/icons-material/DeviceHub";
+import ChevronRightIcon from "@mui/icons-material/ChevronRight";
+import AccessTimeIcon from "@mui/icons-material/AccessTime";
+import AddIcon from "@mui/icons-material/Add";
+import FileUploadIcon from "@mui/icons-material/FileUpload";
+import WarningIcon from "@mui/icons-material/Warning";
+import InfoIcon from "@mui/icons-material/Info";
+import { ClusterCreation, ImportCluster } from "@/app/ui/formCreation";
+
+interface ResourceCounts {
+    clusters: number;
+    shards: number;
+    nodes: number;
+}
+
+interface ClusterData {
+    name: string;
+    version: string;
+    shards: any[];
+    shardCount: number;
+    nodeCount: number;
+    hasSlots: boolean;
+    hasMigration: boolean;
+    hasNoMigration: boolean;
+    hasImporting: boolean;
+    slotRanges: string[];
+    migratingSlot: number;
+    importingSlot: number;
+    targetShardIndex: number;
+}
+
+type FilterOption =
+    | "all"
+    | "with-migration"
+    | "no-migration"
+    | "with-slots"
+    | "no-slots"
+    | "with-importing";
+type SortOption =
+    | "name-asc"
+    | "name-desc"
+    | "shards-desc"
+    | "shards-asc"
+    | "nodes-desc"
+    | "nodes-asc";
+
 export default function Namespace({ params }: { params: { namespace: string } 
}) {
-    const [clusterData, setClusterData] = useState<any[]>([]);
+    const [clusterData, setClusterData] = useState<ClusterData[]>([]);
+    const [resourceCounts, setResourceCounts] = useState<ResourceCounts>({
+        clusters: 0,
+        shards: 0,
+        nodes: 0,
+    });
     const [loading, setLoading] = useState<boolean>(true);
+    const [searchTerm, setSearchTerm] = useState<string>("");
+    const [filterAnchorEl, setFilterAnchorEl] = useState<null | 
HTMLElement>(null);
+    const [sortAnchorEl, setSortAnchorEl] = useState<null | HTMLElement>(null);
+    const [filterOption, setFilterOption] = useState<FilterOption>("all");
+    const [sortOption, setSortOption] = useState<SortOption>("name-asc");
     const router = useRouter();
 
     useEffect(() => {
@@ -49,15 +125,95 @@ export default function Namespace({ params }: { params: { 
namespace: string } })
                 }
 
                 const clusters = await fetchClusters(params.namespace);
+                let totalShards = 0;
+                let totalNodes = 0;
+
                 const data = await Promise.all(
-                    clusters.map((cluster) =>
-                        fetchCluster(params.namespace, cluster).catch((error) 
=> {
+                    clusters.map(async (cluster) => {
+                        try {
+                            const clusterInfo = await 
fetchCluster(params.namespace, cluster);
+                            if (
+                                clusterInfo &&
+                                typeof clusterInfo === "object" &&
+                                "shards" in clusterInfo
+                            ) {
+                                const shards = (clusterInfo as any).shards || 
[];
+
+                                let clusterNodeCount = 0;
+                                for (let i = 0; i < shards.length; i++) {
+                                    try {
+                                        const nodes = await listNodes(
+                                            params.namespace,
+                                            cluster,
+                                            i.toString()
+                                        );
+                                        if (Array.isArray(nodes)) {
+                                            clusterNodeCount += nodes.length;
+                                        }
+                                    } catch (error) {
+                                        console.error(
+                                            `Failed to fetch nodes for shard 
${i}:`,
+                                            error
+                                        );
+                                    }
+                                }
+
+                                totalShards += shards.length;
+                                totalNodes += clusterNodeCount;
+
+                                const hasSlots = shards.some(
+                                    (s: any) => s.slot_ranges && 
s.slot_ranges.length > 0
+                                );
+                                const hasMigration = shards.some((s: any) => 
s.migrating_slot >= 0);
+                                const hasNoMigration = shards.every(
+                                    (s: any) => s.migrating_slot === -1
+                                );
+                                const hasImporting = shards.some((s: any) => 
s.import_slot >= 0);
+
+                                const slotRanges =
+                                    shards.find(
+                                        (s: any) => s.slot_ranges && 
s.slot_ranges.length > 0
+                                    )?.slot_ranges || [];
+
+                                const migratingSlot =
+                                    shards.find((s: any) => s.migrating_slot 
>= 0)
+                                        ?.migrating_slot || -1;
+                                const importingSlot =
+                                    shards.find((s: any) => s.import_slot >= 
0)?.import_slot || -1;
+                                const targetShardIndex =
+                                    shards.find((s: any) => 
s.target_shard_index >= 0)
+                                        ?.target_shard_index || -1;
+
+                                return {
+                                    ...clusterInfo,
+                                    shards,
+                                    shardCount: shards.length,
+                                    nodeCount: clusterNodeCount,
+                                    hasSlots,
+                                    hasMigration,
+                                    hasNoMigration,
+                                    hasImporting,
+                                    slotRanges,
+                                    migratingSlot,
+                                    importingSlot,
+                                    targetShardIndex,
+                                };
+                            }
+                            return null;
+                        } catch (error) {
                             console.error(`Failed to fetch data for cluster 
${cluster}:`, error);
                             return null;
-                        })
-                    )
+                        }
+                    })
                 );
-                setClusterData(data.filter(Boolean));
+
+                const validData = data.filter(Boolean) as ClusterData[];
+                setClusterData(validData);
+                setResourceCounts({
+                    clusters: validData.length,
+                    shards: totalShards,
+                    nodes: totalNodes,
+                });
             } catch (error) {
                 console.error("Error fetching data:", error);
             } finally {
@@ -68,131 +224,969 @@ export default function Namespace({ params }: { params: 
{ namespace: string } })
         fetchData();
     }, [params.namespace, router]);
 
+    const handleFilterClick = (event: React.MouseEvent<HTMLElement>) => {
+        setFilterAnchorEl(event.currentTarget);
+    };
+
+    const handleSortClick = (event: React.MouseEvent<HTMLElement>) => {
+        setSortAnchorEl(event.currentTarget);
+    };
+
+    const handleFilterClose = () => {
+        setFilterAnchorEl(null);
+    };
+
+    const handleSortClose = () => {
+        setSortAnchorEl(null);
+    };
+
+    const filteredAndSortedClusters = clusterData
+        .filter((cluster) => {
+            if 
(!cluster.name.toLowerCase().includes(searchTerm.toLowerCase())) {
+                return false;
+            }
+
+            switch (filterOption) {
+                case "with-migration":
+                    return cluster.hasMigration;
+                case "no-migration":
+                    return !cluster.hasMigration;
+                case "with-slots":
+                    return cluster.hasSlots;
+                case "no-slots":
+                    return !cluster.hasSlots;
+                case "with-importing":
+                    return cluster.hasImporting;
+                default:
+                    return true;
+            }
+        })
+        .sort((a, b) => {
+            switch (sortOption) {
+                case "name-asc":
+                    return a.name.localeCompare(b.name);
+                case "name-desc":
+                    return b.name.localeCompare(a.name);
+                case "shards-desc":
+                    return b.shardCount - a.shardCount;
+                case "shards-asc":
+                    return a.shardCount - b.shardCount;
+                case "nodes-desc":
+                    return b.nodeCount - a.nodeCount;
+                case "nodes-asc":
+                    return a.nodeCount - b.nodeCount;
+                default:
+                    return 0;
+            }
+        });
+
+    const isFilterOpen = Boolean(filterAnchorEl);
+    const isSortOpen = Boolean(sortAnchorEl);
+    const filterId = isFilterOpen ? "filter-popover" : undefined;
+    const sortId = isSortOpen ? "sort-popover" : undefined;
+
     if (loading) {
         return <LoadingSpinner />;
     }
 
     return (
         <div className="flex h-full">
-            <NamespaceSidebar />
-            <div className="flex-1 overflow-auto">
-                <Box className="container-inner">
-                    <Box className="mb-6 flex items-center justify-between">
+            <div className="relative h-full">
+                <NamespaceSidebar />
+            </div>
+            <div className="no-scrollbar flex-1 overflow-y-auto bg-white pb-8 
dark:bg-dark">
+                <Box className="px-6 py-4 sm:px-8 sm:py-6">
+                    <div className="mb-4 flex flex-col gap-3 sm:mb-5 
lg:flex-row lg:items-center lg:justify-between">
                         <div>
                             <Typography
-                                variant="h5"
-                                className="flex items-center font-medium 
text-gray-800 dark:text-gray-100"
+                                variant="h4"
+                                className="flex items-center font-medium 
text-gray-900 dark:text-white"
                             >
-                                <FolderIcon className="mr-2 text-primary 
dark:text-primary-light" />
+                                <FolderIcon className="mr-3 text-primary 
dark:text-primary-light" />
                                 {params.namespace}
-                                <Chip
-                                    label={`${clusterData.length} clusters`}
-                                    size="small"
-                                    color="primary"
-                                    className="ml-3"
-                                />
                             </Typography>
                             <Typography
-                                variant="body2"
-                                className="mt-1 text-gray-500 
dark:text-gray-400"
+                                variant="body1"
+                                className="mt-0.5 text-gray-500 
dark:text-gray-400"
                             >
-                                Namespace
+                                Manage clusters in this namespace
                             </Typography>
                         </div>
-                    </Box>
-
-                    <div className="grid grid-cols-1 gap-4 sm:grid-cols-2 
lg:grid-cols-3 xl:grid-cols-4">
-                        <Box className="col-span-1">
-                            <AddClusterCard namespace={params.namespace} />
-                        </Box>
-
-                        {clusterData.length > 0 ? (
-                            clusterData.map(
-                                (data, index) =>
-                                    data && (
-                                        <Link
-                                            
href={`/namespaces/${params.namespace}/clusters/${data.name}`}
-                                            key={index}
-                                            className="col-span-1"
+
+                        <div className="flex w-full flex-row items-center 
gap-2 lg:w-auto">
+                            <div className="search-container relative max-w-md 
flex-grow transition-all duration-300 lg:min-w-[280px]">
+                                <div className="search-inner relative w-full 
rounded-lg bg-gray-50 transition-all duration-300 focus-within:bg-white 
focus-within:shadow-md dark:bg-dark-paper/90 dark:focus-within:bg-dark-paper">
+                                    <div className="pointer-events-none 
absolute inset-y-0 left-3 flex items-center">
+                                        <SearchIcon
+                                            className="text-gray-400"
+                                            sx={{ fontSize: 18 }}
+                                        />
+                                    </div>
+                                    <input
+                                        type="text"
+                                        placeholder="Search clusters..."
+                                        className="w-full rounded-lg border-0 
bg-transparent py-2.5 pl-9 pr-4 text-sm text-gray-800 outline-none ring-1 
ring-gray-200 transition-all focus:ring-2 focus:ring-primary dark:text-gray-200 
dark:ring-gray-700 dark:focus:ring-primary-light"
+                                        value={searchTerm}
+                                        onChange={(e) => 
setSearchTerm(e.target.value)}
+                                    />
+                                    {searchTerm && (
+                                        <button
+                                            className="absolute inset-y-0 
right-3 flex items-center text-gray-400 transition-colors hover:text-gray-600 
dark:hover:text-gray-300"
+                                            onClick={() => setSearchTerm("")}
                                         >
-                                            <ResourceCard
-                                                title={data.name}
-                                                description={`Version: 
${data.version}`}
-                                                tags={[
-                                                    {
-                                                        label: 
`${data.shards.length} shards`,
-                                                        color: "secondary",
-                                                    },
-                                                    ...(data.shards.some(
-                                                        (s: any) => 
s.migrating_slot >= 0
-                                                    )
-                                                        ? [{ label: 
"Migrating", color: "warning" }]
-                                                        : []),
-                                                ]}
+                                            <span className="text-xs">✕</span>
+                                        </button>
+                                    )}
+                                </div>
+                            </div>
+
+                            <div className="flex flex-shrink-0 gap-3">
+                                <ClusterCreation position="page" 
namespace={params.namespace}>
+                                    <Button
+                                        variant="outlined"
+                                        color="primary"
+                                        className="whitespace-nowrap 
rounded-lg px-5 py-2.5 font-medium shadow-sm transition-all hover:shadow-md"
+                                        startIcon={<AddIcon />}
+                                        disableElevation
+                                        size="medium"
+                                    >
+                                        Create Cluster
+                                    </Button>
+                                </ClusterCreation>
+                                <ImportCluster position="page" 
namespace={params.namespace}>
+                                    <Button
+                                        variant="outlined"
+                                        color="primary"
+                                        className="whitespace-nowrap 
rounded-lg px-5 py-2.5 font-medium shadow-sm transition-all hover:shadow-md"
+                                        startIcon={<FileUploadIcon />}
+                                        disableElevation
+                                        size="medium"
+                                    >
+                                        Import Cluster
+                                    </Button>
+                                </ImportCluster>
+                            </div>
+                        </div>
+                    </div>
+
+                    <div className="mb-4 sm:mb-5">
+                        <Grid container spacing={2}>
+                            <Grid item xs={12} sm={6} lg={3}>
+                                <Paper
+                                    elevation={0}
+                                    className="relative h-full overflow-hidden 
rounded-2xl border border-gray-100 p-4 transition-all hover:-translate-y-1 
hover:shadow-md dark:border-gray-800 dark:bg-dark-paper"
+                                >
+                                    <div className="flex items-center 
justify-between">
+                                        <div className="flex h-12 w-12 
items-center justify-center rounded-xl bg-purple-50 text-purple-500 
dark:bg-purple-900/30 dark:text-purple-400">
+                                            <StorageIcon sx={{ fontSize: 24 }} 
/>
+                                        </div>
+                                        <div className="flex flex-col 
items-end">
+                                            <Typography
+                                                variant="h4"
+                                                className="font-semibold 
text-gray-900 dark:text-white"
+                                            >
+                                                {resourceCounts.clusters}
+                                            </Typography>
+                                            <Typography
+                                                variant="body2"
+                                                className="text-gray-500 
dark:text-gray-400"
+                                            >
+                                                Clusters
+                                            </Typography>
+                                        </div>
+                                    </div>
+                                    <div className="absolute -bottom-4 
-right-4 h-24 w-24 rounded-full bg-purple-500/5 blur-xl"></div>
+                                </Paper>
+                            </Grid>
+
+                            <Grid item xs={12} sm={6} lg={3}>
+                                <Paper
+                                    elevation={0}
+                                    className="relative h-full overflow-hidden 
rounded-2xl border border-gray-100 p-4 transition-all hover:-translate-y-1 
hover:shadow-md dark:border-gray-800 dark:bg-dark-paper"
+                                >
+                                    <div className="flex items-center 
justify-between">
+                                        <div className="flex h-12 w-12 
items-center justify-center rounded-xl bg-green-50 text-green-500 
dark:bg-green-900/30 dark:text-green-400">
+                                            <DnsIcon sx={{ fontSize: 24 }} />
+                                        </div>
+                                        <div className="flex flex-col 
items-end">
+                                            <Typography
+                                                variant="h4"
+                                                className="font-semibold 
text-gray-900 dark:text-white"
+                                            >
+                                                {resourceCounts.shards}
+                                            </Typography>
+                                            <Typography
+                                                variant="body2"
+                                                className="text-gray-500 
dark:text-gray-400"
                                             >
-                                                <div className="my-2 space-y-2 
text-sm">
-                                                    <div className="flex 
justify-between">
-                                                        <span 
className="text-gray-500 dark:text-gray-400">
-                                                            Slots:
+                                                Shards
+                                            </Typography>
+                                        </div>
+                                    </div>
+                                    <div className="absolute -bottom-4 
-right-4 h-24 w-24 rounded-full bg-green-500/5 blur-xl"></div>
+                                </Paper>
+                            </Grid>
+
+                            <Grid item xs={12} sm={6} lg={3}>
+                                <Paper
+                                    elevation={0}
+                                    className="relative h-full overflow-hidden 
rounded-2xl border border-gray-100 p-4 transition-all hover:-translate-y-1 
hover:shadow-md dark:border-gray-800 dark:bg-dark-paper"
+                                >
+                                    <div className="flex items-center 
justify-between">
+                                        <div className="flex h-12 w-12 
items-center justify-center rounded-xl bg-amber-50 text-amber-500 
dark:bg-amber-900/30 dark:text-amber-400">
+                                            <DeviceHubIcon sx={{ fontSize: 24 
}} />
+                                        </div>
+                                        <div className="flex flex-col 
items-end">
+                                            <Typography
+                                                variant="h4"
+                                                className="font-semibold 
text-gray-900 dark:text-white"
+                                            >
+                                                {resourceCounts.nodes}
+                                            </Typography>
+                                            <Typography
+                                                variant="body2"
+                                                className="text-gray-500 
dark:text-gray-400"
+                                            >
+                                                Nodes
+                                            </Typography>
+                                        </div>
+                                    </div>
+                                    <div className="absolute -bottom-4 
-right-4 h-24 w-24 rounded-full bg-amber-500/5 blur-xl"></div>
+                                </Paper>
+                            </Grid>
+
+                            <Grid item xs={12} sm={6} lg={3}>
+                                <Paper
+                                    elevation={0}
+                                    className="relative h-full overflow-hidden 
rounded-2xl border border-gray-100 p-4 transition-all hover:-translate-y-1 
hover:shadow-md dark:border-gray-800 dark:bg-dark-paper"
+                                >
+                                    <div className="flex items-center 
justify-between">
+                                        <div className="flex h-12 w-12 
items-center justify-center rounded-xl bg-indigo-50 text-indigo-500 
dark:bg-indigo-900/30 dark:text-indigo-400">
+                                            <GridViewIcon sx={{ fontSize: 24 
}} />
+                                        </div>
+                                        <div className="flex flex-col 
items-end">
+                                            <Typography
+                                                variant="h4"
+                                                className="font-semibold 
text-gray-900 dark:text-white"
+                                            >
+                                                {clusterData.filter((c) => 
c.hasSlots).length}
+                                            </Typography>
+                                            <Typography
+                                                variant="body2"
+                                                className="text-gray-500 
dark:text-gray-400"
+                                            >
+                                                With Slots
+                                            </Typography>
+                                        </div>
+                                    </div>
+                                    <div className="absolute -bottom-4 
-right-4 h-24 w-24 rounded-full bg-indigo-500/5 blur-xl"></div>
+                                </Paper>
+                            </Grid>
+                        </Grid>
+                    </div>
+
+                    <Paper
+                        elevation={0}
+                        className="overflow-hidden rounded-2xl border 
border-gray-100 transition-all hover:shadow-md dark:border-gray-800 
dark:bg-dark-paper"
+                    >
+                        <div className="border-b border-gray-100 px-6 py-3 
dark:border-gray-800 sm:px-8">
+                            <div className="flex items-center justify-between">
+                                <Typography
+                                    variant="h6"
+                                    className="font-medium text-gray-800 
dark:text-gray-100"
+                                >
+                                    All Clusters
+                                </Typography>
+                                <div className="flex items-center gap-2">
+                                    <Tooltip title="Filter">
+                                        <IconButton
+                                            size="small"
+                                            onClick={handleFilterClick}
+                                            aria-describedby={filterId}
+                                            className="rounded-full bg-gray-50 
text-gray-500 hover:bg-gray-100 dark:bg-gray-800 dark:text-gray-400 
dark:hover:bg-gray-700"
+                                        >
+                                            <FilterListIcon fontSize="small" />
+                                        </IconButton>
+                                    </Tooltip>
+                                    <Tooltip title="Sort">
+                                        <IconButton
+                                            size="small"
+                                            onClick={handleSortClick}
+                                            aria-describedby={sortId}
+                                            className="rounded-full bg-gray-50 
text-gray-500 hover:bg-gray-100 dark:bg-gray-800 dark:text-gray-400 
dark:hover:bg-gray-700"
+                                        >
+                                            <SortIcon fontSize="small" />
+                                        </IconButton>
+                                    </Tooltip>
+                                </div>
+                            </div>
+                        </div>
+
+                        <Popover
+                            id={filterId}
+                            open={isFilterOpen}
+                            anchorEl={filterAnchorEl}
+                            onClose={handleFilterClose}
+                            anchorOrigin={{
+                                vertical: "bottom",
+                                horizontal: "right",
+                            }}
+                            transformOrigin={{
+                                vertical: "top",
+                                horizontal: "right",
+                            }}
+                            TransitionComponent={Fade}
+                            PaperProps={{
+                                className:
+                                    "rounded-xl shadow-xl border 
border-gray-100 dark:border-gray-700",
+                                elevation: 3,
+                                sx: { width: 280 },
+                            }}
+                        >
+                            <div className="p-4">
+                                <div className="mb-3 flex items-center 
justify-between border-b border-gray-100 pb-2 dark:border-gray-700">
+                                    <Typography variant="subtitle1" 
className="font-medium">
+                                        Filter Clusters
+                                    </Typography>
+                                </div>
+
+                                <RadioGroup
+                                    value={filterOption}
+                                    onChange={(e) =>
+                                        setFilterOption(e.target.value as 
FilterOption)
+                                    }
+                                >
+                                    <div className="space-y-2">
+                                        <div className="rounded-lg bg-gray-50 
p-2 dark:bg-gray-800">
+                                            <FormControlLabel
+                                                value="all"
+                                                control={
+                                                    <Radio
+                                                        size="small"
+                                                        
className="text-primary"
+                                                        checkedIcon={
+                                                            <div 
className="flex h-5 w-5 items-center justify-center rounded-full border-2 
border-primary bg-primary text-white">
+                                                                <CheckIcon
+                                                                    style={{ 
fontSize: 12 }}
+                                                                />
+                                                            </div>
+                                                        }
+                                                    />
+                                                }
+                                                label={
+                                                    <div className="flex 
items-center">
+                                                        <span 
className="text-sm font-medium">
+                                                            All clusters
                                                         </span>
-                                                        <span 
className="font-medium">
-                                                            
{data.shards[0]?.slot_ranges.length > 0
-                                                                ? 
data.shards[0].slot_ranges
-                                                                      .length 
> 2
-                                                                    ? 
`${data.shards[0].slot_ranges[0]}, ${data.shards[0].slot_ranges[1]}, ...`
-                                                                    : 
data.shards[0].slot_ranges.join(
-                                                                          ", "
-                                                                      )
-                                                                : "None"}
+                                                        <Chip
+                                                            size="small"
+                                                            
label={clusterData.length}
+                                                            className="ml-2"
+                                                            sx={{ height: 20, 
fontSize: "0.7rem" }}
+                                                        />
+                                                    </div>
+                                                }
+                                                className="m-0 w-full"
+                                            />
+                                        </div>
+
+                                        <div className="rounded-lg bg-gray-50 
p-2 dark:bg-gray-800">
+                                            <FormControlLabel
+                                                value="with-migration"
+                                                control={
+                                                    <Radio
+                                                        size="small"
+                                                        
className="text-primary"
+                                                        checkedIcon={
+                                                            <div 
className="flex h-5 w-5 items-center justify-center rounded-full border-2 
border-primary bg-primary text-white">
+                                                                <CheckIcon
+                                                                    style={{ 
fontSize: 12 }}
+                                                                />
+                                                            </div>
+                                                        }
+                                                    />
+                                                }
+                                                label={
+                                                    <div className="flex 
items-center">
+                                                        <span 
className="text-sm font-medium">
+                                                            With migration
                                                         </span>
+                                                        <Chip
+                                                            size="small"
+                                                            label={
+                                                                
clusterData.filter(
+                                                                    (cluster) 
=>
+                                                                        
cluster.hasMigration
+                                                                ).length
+                                                            }
+                                                            className="ml-2"
+                                                            sx={{ height: 20, 
fontSize: "0.7rem" }}
+                                                        />
                                                     </div>
+                                                }
+                                                className="m-0 w-full"
+                                            />
+                                        </div>
 
-                                                    
{data.shards[0]?.target_shard_index >= 0 && (
-                                                        <div className="flex 
justify-between">
-                                                            <span 
className="text-gray-500 dark:text-gray-400">
-                                                                Target Shard:
-                                                            </span>
-                                                            <span 
className="font-medium">
-                                                                
{data.shards[0].target_shard_index +
-                                                                    1}
-                                                            </span>
-                                                        </div>
-                                                    )}
+                                        <div className="rounded-lg bg-gray-50 
p-2 dark:bg-gray-800">
+                                            <FormControlLabel
+                                                value="no-migration"
+                                                control={
+                                                    <Radio
+                                                        size="small"
+                                                        
className="text-primary"
+                                                        checkedIcon={
+                                                            <div 
className="flex h-5 w-5 items-center justify-center rounded-full border-2 
border-primary bg-primary text-white">
+                                                                <CheckIcon
+                                                                    style={{ 
fontSize: 12 }}
+                                                                />
+                                                            </div>
+                                                        }
+                                                    />
+                                                }
+                                                label={
+                                                    <div className="flex 
items-center">
+                                                        <span 
className="text-sm font-medium">
+                                                            No migration
+                                                        </span>
+                                                        <Chip
+                                                            size="small"
+                                                            label={
+                                                                
clusterData.filter(
+                                                                    (cluster) 
=>
+                                                                        
!cluster.hasMigration
+                                                                ).length
+                                                            }
+                                                            className="ml-2"
+                                                            sx={{ height: 20, 
fontSize: "0.7rem" }}
+                                                        />
+                                                    </div>
+                                                }
+                                                className="m-0 w-full"
+                                            />
+                                        </div>
 
-                                                    
{data.shards[0]?.migrating_slot >= 0 && (
-                                                        <div className="flex 
justify-between">
-                                                            <span 
className="text-gray-500 dark:text-gray-400">
-                                                                Migrating:
-                                                            </span>
+                                        <div className="rounded-lg bg-gray-50 
p-2 dark:bg-gray-800">
+                                            <FormControlLabel
+                                                value="with-slots"
+                                                control={
+                                                    <Radio
+                                                        size="small"
+                                                        
className="text-primary"
+                                                        checkedIcon={
+                                                            <div 
className="flex h-5 w-5 items-center justify-center rounded-full border-2 
border-primary bg-primary text-white">
+                                                                <CheckIcon
+                                                                    style={{ 
fontSize: 12 }}
+                                                                />
+                                                            </div>
+                                                        }
+                                                    />
+                                                }
+                                                label={
+                                                    <div className="flex 
items-center">
+                                                        <span 
className="text-sm font-medium">
+                                                            With slots
+                                                        </span>
+                                                        <Chip
+                                                            size="small"
+                                                            label={
+                                                                
clusterData.filter(
+                                                                    (cluster) 
=> cluster.hasSlots
+                                                                ).length
+                                                            }
+                                                            className="ml-2"
+                                                            sx={{ height: 20, 
fontSize: "0.7rem" }}
+                                                        />
+                                                    </div>
+                                                }
+                                                className="m-0 w-full"
+                                            />
+                                        </div>
+
+                                        <div className="rounded-lg bg-gray-50 
p-2 dark:bg-gray-800">
+                                            <FormControlLabel
+                                                value="no-slots"
+                                                control={
+                                                    <Radio
+                                                        size="small"
+                                                        
className="text-primary"
+                                                        checkedIcon={
+                                                            <div 
className="flex h-5 w-5 items-center justify-center rounded-full border-2 
border-primary bg-primary text-white">
+                                                                <CheckIcon
+                                                                    style={{ 
fontSize: 12 }}
+                                                                />
+                                                            </div>
+                                                        }
+                                                    />
+                                                }
+                                                label={
+                                                    <div className="flex 
items-center">
+                                                        <span 
className="text-sm font-medium">
+                                                            No slots
+                                                        </span>
+                                                        <Chip
+                                                            size="small"
+                                                            label={
+                                                                
clusterData.filter(
+                                                                    (cluster) 
=> !cluster.hasSlots
+                                                                ).length
+                                                            }
+                                                            className="ml-2"
+                                                            sx={{ height: 20, 
fontSize: "0.7rem" }}
+                                                        />
+                                                    </div>
+                                                }
+                                                className="m-0 w-full"
+                                            />
+                                        </div>
+
+                                        <div className="rounded-lg bg-gray-50 
p-2 dark:bg-gray-800">
+                                            <FormControlLabel
+                                                value="with-importing"
+                                                control={
+                                                    <Radio
+                                                        size="small"
+                                                        
className="text-primary"
+                                                        checkedIcon={
+                                                            <div 
className="flex h-5 w-5 items-center justify-center rounded-full border-2 
border-primary bg-primary text-white">
+                                                                <CheckIcon
+                                                                    style={{ 
fontSize: 12 }}
+                                                                />
+                                                            </div>
+                                                        }
+                                                    />
+                                                }
+                                                label={
+                                                    <div className="flex 
items-center">
+                                                        <span 
className="text-sm font-medium">
+                                                            With importing
+                                                        </span>
+                                                        <Chip
+                                                            size="small"
+                                                            label={
+                                                                
clusterData.filter(
+                                                                    (cluster) 
=>
+                                                                        
cluster.hasImporting
+                                                                ).length
+                                                            }
+                                                            className="ml-2"
+                                                            sx={{ height: 20, 
fontSize: "0.7rem" }}
+                                                        />
+                                                    </div>
+                                                }
+                                                className="m-0 w-full"
+                                            />
+                                        </div>
+                                    </div>
+                                </RadioGroup>
+
+                                <div className="mt-4 flex justify-end">
+                                    <Button
+                                        variant="text"
+                                        size="small"
+                                        onClick={handleFilterClose}
+                                        className="rounded-lg px-3 py-1 
text-xs"
+                                    >
+                                        Close
+                                    </Button>
+                                </div>
+                            </div>
+                        </Popover>
+
+                        <Popover
+                            id={sortId}
+                            open={isSortOpen}
+                            anchorEl={sortAnchorEl}
+                            onClose={handleSortClose}
+                            anchorOrigin={{
+                                vertical: "bottom",
+                                horizontal: "right",
+                            }}
+                            transformOrigin={{
+                                vertical: "top",
+                                horizontal: "right",
+                            }}
+                            TransitionComponent={Fade}
+                            PaperProps={{
+                                className:
+                                    "rounded-xl shadow-xl border 
border-gray-100 dark:border-gray-700",
+                                elevation: 3,
+                                sx: { width: 280 },
+                            }}
+                        >
+                            <div className="p-4">
+                                <div className="mb-3 flex items-center 
justify-between border-b border-gray-100 pb-2 dark:border-gray-700">
+                                    <Typography variant="subtitle1" 
className="font-medium">
+                                        Sort Clusters
+                                    </Typography>
+                                </div>
+
+                                <RadioGroup
+                                    value={sortOption}
+                                    onChange={(e) => 
setSortOption(e.target.value as SortOption)}
+                                >
+                                    <div className="space-y-2">
+                                        <div className="rounded-lg bg-gray-50 
p-2 dark:bg-gray-800">
+                                            <FormControlLabel
+                                                value="name-asc"
+                                                control={
+                                                    <Radio
+                                                        size="small"
+                                                        
className="text-primary"
+                                                        checkedIcon={
+                                                            <div 
className="flex h-5 w-5 items-center justify-center rounded-full border-2 
border-primary bg-primary text-white">
+                                                                <CheckIcon
+                                                                    style={{ 
fontSize: 12 }}
+                                                                />
+                                                            </div>
+                                                        }
+                                                    />
+                                                }
+                                                label={
+                                                    <div className="flex 
items-center">
+                                                        <ArrowUpwardIcon
+                                                            style={{ fontSize: 
16 }}
+                                                            className="mr-1 
text-gray-500"
+                                                        />
+                                                        <span 
className="text-sm font-medium">
+                                                            Name A-Z
+                                                        </span>
+                                                    </div>
+                                                }
+                                                className="m-0 w-full"
+                                            />
+                                        </div>
+
+                                        <div className="rounded-lg bg-gray-50 
p-2 dark:bg-gray-800">
+                                            <FormControlLabel
+                                                value="name-desc"
+                                                control={
+                                                    <Radio
+                                                        size="small"
+                                                        
className="text-primary"
+                                                        checkedIcon={
+                                                            <div 
className="flex h-5 w-5 items-center justify-center rounded-full border-2 
border-primary bg-primary text-white">
+                                                                <CheckIcon
+                                                                    style={{ 
fontSize: 12 }}
+                                                                />
+                                                            </div>
+                                                        }
+                                                    />
+                                                }
+                                                label={
+                                                    <div className="flex 
items-center">
+                                                        <ArrowDownwardIcon
+                                                            style={{ fontSize: 
16 }}
+                                                            className="mr-1 
text-gray-500"
+                                                        />
+                                                        <span 
className="text-sm font-medium">
+                                                            Name Z-A
+                                                        </span>
+                                                    </div>
+                                                }
+                                                className="m-0 w-full"
+                                            />
+                                        </div>
+
+                                        <div className="rounded-lg bg-gray-50 
p-2 dark:bg-gray-800">
+                                            <FormControlLabel
+                                                value="shards-desc"
+                                                control={
+                                                    <Radio
+                                                        size="small"
+                                                        
className="text-primary"
+                                                        checkedIcon={
+                                                            <div 
className="flex h-5 w-5 items-center justify-center rounded-full border-2 
border-primary bg-primary text-white">
+                                                                <CheckIcon
+                                                                    style={{ 
fontSize: 12 }}
+                                                                />
+                                                            </div>
+                                                        }
+                                                    />
+                                                }
+                                                label={
+                                                    <div className="flex 
items-center">
+                                                        <ArrowDownwardIcon
+                                                            style={{ fontSize: 
16 }}
+                                                            className="mr-1 
text-gray-500"
+                                                        />
+                                                        <span 
className="text-sm font-medium">
+                                                            Most shards
+                                                        </span>
+                                                    </div>
+                                                }
+                                                className="m-0 w-full"
+                                            />
+                                        </div>
+
+                                        <div className="rounded-lg bg-gray-50 
p-2 dark:bg-gray-800">
+                                            <FormControlLabel
+                                                value="nodes-desc"
+                                                control={
+                                                    <Radio
+                                                        size="small"
+                                                        
className="text-primary"
+                                                        checkedIcon={
+                                                            <div 
className="flex h-5 w-5 items-center justify-center rounded-full border-2 
border-primary bg-primary text-white">
+                                                                <CheckIcon
+                                                                    style={{ 
fontSize: 12 }}
+                                                                />
+                                                            </div>
+                                                        }
+                                                    />
+                                                }
+                                                label={
+                                                    <div className="flex 
items-center">
+                                                        <ArrowDownwardIcon
+                                                            style={{ fontSize: 
16 }}
+                                                            className="mr-1 
text-gray-500"
+                                                        />
+                                                        <span 
className="text-sm font-medium">
+                                                            Most nodes
+                                                        </span>
+                                                    </div>
+                                                }
+                                                className="m-0 w-full"
+                                            />
+                                        </div>
+                                    </div>
+                                </RadioGroup>
+
+                                <div className="mt-4 flex justify-end">
+                                    <Button
+                                        variant="text"
+                                        size="small"
+                                        onClick={handleSortClose}
+                                        className="rounded-lg px-3 py-1 
text-xs"
+                                    >
+                                        Close
+                                    </Button>
+                                </div>
+                            </div>
+                        </Popover>
+
+                        {filteredAndSortedClusters.length > 0 ? (
+                            <div className="divide-y divide-gray-100 
dark:divide-gray-800">
+                                {filteredAndSortedClusters.map((cluster) => (
+                                    <div
+                                        key={cluster.name}
+                                        className="group p-2 transition-colors 
hover:bg-gray-50 dark:hover:bg-gray-800/30"
+                                    >
+                                        <Paper
+                                            elevation={0}
+                                            className="overflow-hidden 
rounded-xl border border-transparent bg-white p-4 transition-all 
group-hover:border-primary/10 group-hover:shadow-sm dark:bg-dark-paper 
dark:group-hover:border-primary-dark/20"
+                                        >
+                                            <div className="flex flex-col 
items-start sm:flex-row sm:items-center">
+                                                <div className="mb-3 flex h-14 
w-14 flex-shrink-0 items-center justify-center rounded-xl bg-purple-50 
text-purple-500 dark:bg-purple-900/30 dark:text-purple-400 sm:mb-0">
+                                                    <StorageIcon sx={{ 
fontSize: 28 }} />
+                                                </div>
+
+                                                <div className="flex flex-1 
flex-col sm:ml-5 sm:flex-row sm:items-center sm:overflow-hidden">
+                                                    <div className="flex-1 
overflow-hidden">
+                                                        <Link
+                                                            
href={`/namespaces/${params.namespace}/clusters/${cluster.name}`}
+                                                            className="block"
+                                                        >
+                                                            <div 
className="flex items-center gap-2">
+                                                                <Typography
+                                                                    
variant="h6"
+                                                                    
className="truncate font-medium text-gray-900 transition-colors 
hover:text-primary dark:text-gray-100 dark:hover:text-primary-light"
+                                                                >
+                                                                    
{cluster.name}
+                                                                </Typography>
+
+                                                                
{cluster.hasMigration &&
+                                                                    
cluster.migratingSlot >= 0 && (
+                                                                        <div 
className="flex items-center gap-1 rounded-full border border-orange-200 
bg-orange-50 px-2.5 py-1 dark:border-orange-800 dark:bg-orange-900/30">
+                                                                            
<div className="h-1.5 w-1.5 animate-pulse rounded-full bg-orange-500"></div>
+                                                                            
<span className="text-xs font-medium text-orange-700 dark:text-orange-300">
+                                                                               
 Migrating{" "}
+                                                                               
 {
+                                                                               
     cluster.migratingSlot
+                                                                               
 }
+                                                                            
</span>
+                                                                        </div>
+                                                                    )}
+
+                                                                
{(!cluster.hasMigration ||
+                                                                    
cluster.migratingSlot ===
+                                                                        -1) && 
(
+                                                                    <div 
className="flex items-center gap-1 rounded-full border border-green-200 
bg-green-50 px-2.5 py-1 dark:border-green-800 dark:bg-green-900/30">
+                                                                        <div 
className="h-1.5 w-1.5 rounded-full bg-green-500"></div>
+                                                                        <span 
className="text-xs font-medium text-green-700 dark:text-green-300">
+                                                                            
Stable
+                                                                        </span>
+                                                                    </div>
+                                                                )}
+
+                                                                
{cluster.hasImporting &&
+                                                                    
cluster.importingSlot >= 0 && (
+                                                                        <div 
className="flex items-center gap-1 rounded-full border border-blue-200 
bg-blue-50 px-2.5 py-1 dark:border-blue-800 dark:bg-blue-900/30">
+                                                                            
<div className="h-1.5 w-1.5 animate-pulse rounded-full bg-blue-500"></div>
+                                                                            
<span className="text-xs font-medium text-blue-700 dark:text-blue-300">
+                                                                               
 Importing{" "}
+                                                                               
 {
+                                                                               
     cluster.importingSlot
+                                                                               
 }
+                                                                            
</span>
+                                                                        </div>
+                                                                    )}
+                                                            </div>
+
+                                                            <Typography
+                                                                variant="body2"
+                                                                
className="flex items-center text-gray-500 dark:text-gray-400"
+                                                            >
+                                                                <AccessTimeIcon
+                                                                    sx={{ 
fontSize: 14 }}
+                                                                    
className="mr-1"
+                                                                />
+                                                                Version: 
{cluster.version}
+                                                            </Typography>
+                                                            {cluster.hasSlots 
&& (
+                                                                <Typography
+                                                                    
variant="caption"
+                                                                    
className="text-gray-400 dark:text-gray-500"
+                                                                >
+                                                                    Slots:{" "}
+                                                                    
{cluster.slotRanges.length > 2
+                                                                        ? 
`${cluster.slotRanges.slice(0, 2).join(", ")}, ...`
+                                                                        : 
cluster.slotRanges.join(
+                                                                              
", "
+                                                                          )}
+                                                                </Typography>
+                                                            )}
+                                                        </Link>
+                                                    </div>
+
+                                                    <div className="mt-3 flex 
space-x-2 overflow-x-auto sm:ml-6 sm:mt-0 md:hidden lg:flex xl:hidden 2xl:flex">
+                                                        <Chip
+                                                            icon={<DnsIcon 
fontSize="small" />}
+                                                            
label={`${cluster.shardCount} shards`}
+                                                            size="small"
+                                                            color="secondary"
+                                                            variant="outlined"
+                                                            
className="whitespace-nowrap"
+                                                        />
+
+                                                        <Chip
+                                                            icon={
+                                                                <DeviceHubIcon 
fontSize="small" />
+                                                            }
+                                                            
label={`${cluster.nodeCount} nodes`}
+                                                            size="small"
+                                                            color="default"
+                                                            variant="outlined"
+                                                            
className="whitespace-nowrap"
+                                                        />
+
+                                                        {!cluster.hasSlots && (
+                                                            <Chip
+                                                                
icon={<InfoIcon fontSize="small" />}
+                                                                label="No 
slots"
+                                                                size="small"
+                                                                color="info"
+                                                                
variant="outlined"
+                                                                
className="whitespace-nowrap"
+                                                            />
+                                                        )}
+
+                                                        
{cluster.targetShardIndex >= 0 && (
                                                             <Chip
-                                                                label={`Slot 
${data.shards[0].migrating_slot}`}
+                                                                label={`Target 
shard: ${cluster.targetShardIndex + 1}`}
                                                                 size="small"
-                                                                color="warning"
+                                                                color="primary"
+                                                                
variant="outlined"
+                                                                
className="whitespace-nowrap"
                                                             />
+                                                        )}
+                                                    </div>
+
+                                                    <div className="hidden 
space-x-3 sm:ml-8 md:flex lg:hidden xl:flex 2xl:hidden">
+                                                        <div className="flex 
flex-col items-center rounded-lg border border-gray-100 bg-gray-50 px-4 py-2 
dark:border-gray-800 dark:bg-gray-800/50">
+                                                            <Typography
+                                                                
variant="caption"
+                                                                
className="text-gray-500 dark:text-gray-400"
+                                                            >
+                                                                Shards
+                                                            </Typography>
+                                                            <Typography
+                                                                
variant="subtitle1"
+                                                                
className="font-semibold text-gray-900 dark:text-white"
+                                                            >
+                                                                
{cluster.shardCount}
+                                                            </Typography>
                                                         </div>
-                                                    )}
-                                                </div>
 
-                                                <div className="mt-3 flex 
justify-center">
-                                                    <GridViewIcon
-                                                        sx={{ fontSize: 40 }}
-                                                        
className="text-primary/20 dark:text-primary-light/30"
-                                                    />
+                                                        <div className="flex 
flex-col items-center rounded-lg border border-gray-100 bg-gray-50 px-4 py-2 
dark:border-gray-800 dark:bg-gray-800/50">
+                                                            <Typography
+                                                                
variant="caption"
+                                                                
className="text-gray-500 dark:text-gray-400"
+                                                            >
+                                                                Nodes
+                                                            </Typography>
+                                                            <Typography
+                                                                
variant="subtitle1"
+                                                                
className="font-semibold text-gray-900 dark:text-white"
+                                                            >
+                                                                
{cluster.nodeCount}
+                                                            </Typography>
+                                                        </div>
+                                                    </div>
+
+                                                    <div className="ml-2 mt-3 
flex items-center space-x-2 sm:mt-0">
+                                                        <Link
+                                                            
href={`/namespaces/${params.namespace}/clusters/${cluster.name}`}
+                                                            
className="rounded-full bg-primary/10 p-2 text-primary transition-colors 
hover:bg-primary/20 dark:bg-primary-dark/20 dark:text-primary-light 
dark:hover:bg-primary-dark/30"
+                                                        >
+                                                            <ChevronRightIcon 
/>
+                                                        </Link>
+                                                    </div>
                                                 </div>
-                                            </ResourceCard>
-                                        </Link>
-                                    )
-                            )
+                                            </div>
+                                        </Paper>
+                                    </div>
+                                ))}
+                            </div>
                         ) : (
-                            <Box className="col-span-full">
+                            <div className="p-12">
                                 <EmptyState
-                                    title="No clusters found"
-                                    description="Create a cluster to get 
started"
-                                    icon={<StorageIcon sx={{ fontSize: 60 }} 
/>}
+                                    title={
+                                        filterOption !== "all"
+                                            ? "No matching clusters"
+                                            : "No clusters found"
+                                    }
+                                    description={
+                                        filterOption !== "all"
+                                            ? "Try changing your filter 
settings"
+                                            : searchTerm
+                                              ? "Try adjusting your search 
term"
+                                              : "Create a cluster to get 
started"
+                                    }
+                                    icon={<StorageIcon sx={{ fontSize: 64 }} 
/>}
+                                    action={{
+                                        label: "Create Cluster",
+                                        onClick: () => {},
+                                    }}
                                 />
-                            </Box>
+                                <div className="hidden">
+                                    <ClusterCreation position="card" 
namespace={params.namespace} />
+                                </div>
+                            </div>
                         )}
-                    </div>
+
+                        {filteredAndSortedClusters.length > 0 && (
+                            <div className="bg-gray-50 px-6 py-4 
dark:bg-gray-800/30 sm:px-8">
+                                <Typography
+                                    variant="body2"
+                                    className="text-gray-500 
dark:text-gray-400"
+                                >
+                                    Showing {filteredAndSortedClusters.length} 
of{" "}
+                                    {clusterData.length} clusters
+                                </Typography>
+                            </div>
+                        )}
+                    </Paper>
                 </Box>
             </div>
         </div>
diff --git a/webui/src/app/ui/formCreation.tsx 
b/webui/src/app/ui/formCreation.tsx
index c7ab479..dbdcf0d 100644
--- a/webui/src/app/ui/formCreation.tsx
+++ b/webui/src/app/ui/formCreation.tsx
@@ -38,6 +38,7 @@ type NamespaceFormProps = {
 type ClusterFormProps = {
     position: string;
     namespace: string;
+    children?: React.ReactNode;
 };
 
 type ShardFormProps = {
@@ -96,7 +97,7 @@ export const NamespaceCreation: React.FC<NamespaceFormProps> 
= ({ position, chil
     );
 };
 
-export const ClusterCreation: React.FC<ClusterFormProps> = ({ position, 
namespace }) => {
+export const ClusterCreation: React.FC<ClusterFormProps> = ({ position, 
namespace, children }) => {
     const router = useRouter();
     const handleSubmit = async (formData: FormData) => {
         const fieldsToValidate = ["name", "replicas"];
@@ -151,7 +152,9 @@ export const ClusterCreation: React.FC<ClusterFormProps> = 
({ position, namespac
                 },
             ]}
             onSubmit={handleSubmit}
-        />
+        >
+            {children}
+        </FormDialog>
     );
 };
 
@@ -204,7 +207,7 @@ export const ShardCreation: React.FC<ShardFormProps> = ({ 
position, namespace, c
     );
 };
 
-export const ImportCluster: React.FC<ClusterFormProps> = ({ position, 
namespace }) => {
+export const ImportCluster: React.FC<ClusterFormProps> = ({ position, 
namespace, children }) => {
     const router = useRouter();
     const handleSubmit = async (formData: FormData) => {
         const fieldsToValidate = ["nodes"];
@@ -256,7 +259,9 @@ export const ImportCluster: React.FC<ClusterFormProps> = ({ 
position, namespace
                 },
             ]}
             onSubmit={handleSubmit}
-        />
+        >
+            {children}
+        </FormDialog>
     );
 };
 
diff --git a/webui/src/app/ui/formDialog.tsx b/webui/src/app/ui/formDialog.tsx
index 798ac97..d5adc25 100644
--- a/webui/src/app/ui/formDialog.tsx
+++ b/webui/src/app/ui/formDialog.tsx
@@ -55,6 +55,7 @@ interface FormDialogProps {
         values?: string[];
     }[];
     onSubmit: (formData: FormData) => Promise<string | undefined>;
+    children?: React.ReactNode;
 }
 
 const FormDialog: React.FC<FormDialogProps> = ({
@@ -63,6 +64,7 @@ const FormDialog: React.FC<FormDialogProps> = ({
     submitButtonLabel,
     formFields,
     onSubmit,
+    children,
 }) => {
     const [showDialog, setShowDialog] = useState(false);
     const openDialog = useCallback(() => setShowDialog(true), []);
@@ -101,7 +103,9 @@ const FormDialog: React.FC<FormDialogProps> = ({
 
     return (
         <>
-            {position === "card" ? (
+            {children ? (
+                <div onClick={openDialog}>{children}</div>
+            ) : position === "card" ? (
                 <Button
                     variant="contained"
                     onClick={openDialog}
@@ -166,7 +170,7 @@ const FormDialog: React.FC<FormDialogProps> = ({
                         }}
                     >
                         <Typography
-                            variant="h6"
+                            variant="subtitle1"
                             className="font-semibold text-gray-800 
dark:text-gray-100"
                         >
                             {title}

Reply via email to