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."}
+
+
+ ) : (
+ <>
+
+
+
+ |
+ Host
+ |
+
+ Operating System
+ |
+
+ Last Checked
+ |
+
+ Last Update
+ |
+
+
+
+ {filteredAndPaginatedHosts.map((hostRepo) => (
+ handleHostClick(hostRepo.hosts.id)}
+ >
+
+
+
+
+
+
+ {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}
+
+
-
- ))}
-
- )}
+ )}
+ >
+ )}
+
);