diff --git a/apps/frontend/src/components/cluster-topology/cluster-node.tsx b/apps/frontend/src/components/cluster-topology/cluster-node.tsx index c7e8a34e..db24429c 100644 --- a/apps/frontend/src/components/cluster-topology/cluster-node.tsx +++ b/apps/frontend/src/components/cluster-topology/cluster-node.tsx @@ -43,8 +43,8 @@ export function ClusterNode({ const connectionDetails: ConnectionDetails = { host: primary.host, port: primary.port.toString(), - ...(primary.username && primary.password && { - username: primary.username, + ...(primary.password && { + username: primary.username ?? "", password: await secureStorage.encrypt(primary.password), }), tls: primary.tls, diff --git a/apps/frontend/src/components/ui/app-header.tsx b/apps/frontend/src/components/ui/app-header.tsx index 42a0351e..6692613b 100644 --- a/apps/frontend/src/components/ui/app-header.tsx +++ b/apps/frontend/src/components/ui/app-header.tsx @@ -19,9 +19,11 @@ type AppHeaderProps = { function AppHeader({ title, icon, className }: AppHeaderProps) { const [isOpen, setIsOpen] = useState(false) const dropdownRef = useRef(null) + const badgeRef = useRef(null) const navigate = useNavigate() const { id, clusterId } = useParams<{ id: string; clusterId: string }>() - const { host, port, username, alias } = useSelector(selectConnectionDetails(id!)) + const connectionDetails = useSelector(selectConnectionDetails(id!)) ?? {} as Partial>> + const { host, port, username, alias } = connectionDetails as { host?: string; port?: string; username?: string; alias?: string } const clusterData = useSelector(selectCluster(clusterId!)) const ToggleIcon = isOpen ? CircleChevronUp : CircleChevronDown @@ -34,6 +36,14 @@ function AppHeader({ title, icon, className }: AppHeaderProps) { state.valkeyConnection?.connections, ) + // For cluster mode, consider connected if any node in the cluster is connected + const isClusterConnected = clusterId + ? Object.values(allConnections ?? {}).some( + (conn) => conn.connectionDetails.clusterId === clusterId && conn.status === CONNECTED, + ) + : isConnected + const effectiveConnected = isConnected || isClusterConnected + const handleNavigate = (primaryKey: string) => { navigate(`/${clusterId}/${primaryKey}/dashboard`) setIsOpen(false) @@ -42,7 +52,10 @@ function AppHeader({ title, icon, className }: AppHeaderProps) { // for closing the dropdown when we click anywhere in screen useEffect(() => { const handleClickOutside = (event: MouseEvent) => { - if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) { + if ( + dropdownRef.current && !dropdownRef.current.contains(event.target as Node) && + badgeRef.current && !badgeRef.current.contains(event.target as Node) + ) { setIsOpen(false) } } @@ -75,7 +88,12 @@ function AppHeader({ title, icon, className }: AppHeaderProps) {
effectiveConnected && setIsOpen(!isOpen)} + ref={badgeRef} variant="default" >
@@ -83,33 +101,30 @@ function AppHeader({ title, icon, className }: AppHeaderProps) { className="flex items-center" variant="bodySm" > - + {id}
- +
{isOpen && (
    {Object.entries(clusterData.clusterNodes).map(([primaryKey, primary]) => { - const nodeIsConnected = allConnections?.[primaryKey]?.status === CONNECTED + const isCurrentNode = primaryKey === id return (
  • -