From a13b4941cd213668e5acbe4ca705a7d0151e9145 Mon Sep 17 00:00:00 2001 From: tigattack <10629864+tigattack@users.noreply.github.com> Date: Wed, 1 Oct 2025 01:14:48 +0100 Subject: [PATCH 1/2] refactor(repository): use server icon in repository host count display --- frontend/src/pages/Repositories.jsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/frontend/src/pages/Repositories.jsx b/frontend/src/pages/Repositories.jsx index ef91b80..88b0fd5 100644 --- a/frontend/src/pages/Repositories.jsx +++ b/frontend/src/pages/Repositories.jsx @@ -16,7 +16,6 @@ import { Shield, ShieldCheck, Unlock, - Users, X, } from "lucide-react"; import { useMemo, useState } from "react"; @@ -513,8 +512,8 @@ const Repositories = () => { case "hostCount": return (
- - {repo.host_count} + + {repo.hostCount}
); case "actions": From 5ccd0aa163951fae4b6d2bf9f77654fffbfb30c3 Mon Sep 17 00:00:00 2001 From: tigattack <10629864+tigattack@users.noreply.github.com> Date: Thu, 2 Oct 2025 23:51:24 +0100 Subject: [PATCH 2/2] feat(repository): make hosts in repo detail more consistent with package detail --- frontend/src/pages/RepositoryDetail.jsx | 279 +++++++++++++++++------- 1 file changed, 201 insertions(+), 78 deletions(-) diff --git a/frontend/src/pages/RepositoryDetail.jsx b/frontend/src/pages/RepositoryDetail.jsx index 516f703..8253565 100644 --- a/frontend/src/pages/RepositoryDetail.jsx +++ b/frontend/src/pages/RepositoryDetail.jsx @@ -6,17 +6,17 @@ import { Database, Globe, Lock, + Search, Server, Shield, ShieldOff, Unlock, - Users, } from "lucide-react"; -import { useId, useState } from "react"; +import { useId, useMemo, useState } from "react"; -import { Link, useParams } from "react-router-dom"; -import { repositoryAPI } from "../utils/api"; +import { Link, useNavigate, useParams } from "react-router-dom"; +import { formatRelativeTime, repositoryAPI } from "../utils/api"; const RepositoryDetail = () => { const isActiveId = useId(); @@ -25,8 +25,12 @@ const RepositoryDetail = () => { const descriptionId = useId(); const { repositoryId } = useParams(); const queryClient = useQueryClient(); + const navigate = useNavigate(); const [editMode, setEditMode] = useState(false); const [formData, setFormData] = useState({}); + const [searchTerm, setSearchTerm] = useState(""); + const [currentPage, setCurrentPage] = useState(1); + const [pageSize, setPageSize] = useState(25); // Fetch repository details const { @@ -39,6 +43,49 @@ const RepositoryDetail = () => { enabled: !!repositoryId, }); + const hosts = repository?.host_repositories || []; + + // Filter and paginate hosts + const filteredAndPaginatedHosts = useMemo(() => { + let filtered = hosts; + + if (searchTerm) { + filtered = hosts.filter( + (hostRepo) => + hostRepo.hosts.friendly_name + ?.toLowerCase() + .includes(searchTerm.toLowerCase()) || + hostRepo.hosts.hostname + ?.toLowerCase() + .includes(searchTerm.toLowerCase()) || + hostRepo.hosts.ip?.toLowerCase().includes(searchTerm.toLowerCase()), + ); + } + + const startIndex = (currentPage - 1) * pageSize; + const endIndex = startIndex + pageSize; + return filtered.slice(startIndex, endIndex); + }, [hosts, searchTerm, currentPage, pageSize]); + + const totalPages = Math.ceil( + (searchTerm + ? hosts.filter( + (hostRepo) => + hostRepo.hosts.friendly_name + ?.toLowerCase() + .includes(searchTerm.toLowerCase()) || + hostRepo.hosts.hostname + ?.toLowerCase() + .includes(searchTerm.toLowerCase()) || + hostRepo.hosts.ip?.toLowerCase().includes(searchTerm.toLowerCase()), + ).length + : hosts.length) / pageSize, + ); + + const handleHostClick = (hostId) => { + navigate(`/hosts/${hostId}`); + }; + // Update repository mutation const updateRepositoryMutation = useMutation({ mutationFn: (data) => repositoryAPI.update(repositoryId, data), @@ -157,9 +204,6 @@ const RepositoryDetail = () => { {repository.is_active ? "Active" : "Inactive"} -

- Repository configuration and host assignments -

@@ -193,7 +237,7 @@ const RepositoryDetail = () => {
{/* Repository Information */} -
+

Repository Information @@ -369,80 +413,159 @@ const RepositoryDetail = () => {

{/* Hosts Using This Repository */} -
-
-

- - Hosts Using This Repository ( - {repository.host_repositories?.length || 0}) -

-
- {!repository.host_repositories || - repository.host_repositories.length === 0 ? ( -
- -

- No hosts using this repository -

-

- This repository hasn't been reported by any hosts yet. -

+
+
+
+
+ +

+ Hosts Using This Repository ({hosts.length}) +

+
- ) : ( -
- {repository.host_repositories.map((hostRepo) => ( -
-
-
-
-
- - {hostRepo.hosts.friendly_name} - -
- IP: {hostRepo.hosts.ip} - - OS: {hostRepo.hosts.os_type}{" "} - {hostRepo.hosts.os_version} - - - Last Update:{" "} - {new Date( - hostRepo.hosts.last_update, - ).toLocaleDateString()} - -
-
+ + {/* Search */} +
+ + { + setSearchTerm(e.target.value); + setCurrentPage(1); + }} + className="w-full pl-10 pr-4 py-2 border border-secondary-300 dark:border-secondary-600 rounded-md focus:ring-2 focus:ring-primary-500 focus:border-transparent bg-white dark:bg-secondary-800 text-secondary-900 dark:text-white placeholder-secondary-500 dark:placeholder-secondary-400" + /> +
+
+ +
+ {filteredAndPaginatedHosts.length === 0 ? ( +
+ +

+ {searchTerm + ? "No hosts match your search" + : "This repository hasn't been reported by any hosts yet."} +

+
+ ) : ( + <> + + + + + + + + + + + {filteredAndPaginatedHosts.map((hostRepo) => ( + handleHostClick(hostRepo.hosts.id)} + > + + + + + + ))} + +
+ Host + + Operating System + + Last Checked + + Last Update +
+
+
+ +
+
+ {hostRepo.hosts.friendly_name || + hostRepo.hosts.hostname} +
+ {hostRepo.hosts.friendly_name && + hostRepo.hosts.hostname && ( +
+ {hostRepo.hosts.hostname} +
+ )} +
+
+
+ {hostRepo.hosts.os_type} {hostRepo.hosts.os_version} + + {hostRepo.last_checked + ? formatRelativeTime(hostRepo.last_checked) + : "Never"} + + {hostRepo.hosts.last_update + ? formatRelativeTime(hostRepo.hosts.last_update) + : "Never"} +
+ + {/* Pagination */} + {totalPages > 1 && ( +
+
+ + Rows per page: + +
-
-
-
- Last Checked -
-
- {new Date(hostRepo.last_checked).toLocaleDateString()} -
-
+
+ + + Page {currentPage} of {totalPages} + +
-
- ))} -
- )} + )} + + )} +
);