mirror of
https://github.com/Portabase/portabase.git
synced 2026-07-14 11:16:13 +02:00
add: agent update notifier, pagination
This commit is contained in:
@@ -15,6 +15,8 @@ export type paginationNavigationProps = {
|
||||
export const PaginationNavigation = (props: paginationNavigationProps) => {
|
||||
const { className, totalPages, currentPage, goToPage, goToPrevPage, goToNextPage, maxVisiblePages = 3 } = props;
|
||||
|
||||
if (totalPages <= 1) return null;
|
||||
|
||||
return (
|
||||
<Pagination className={cn("", className)}>
|
||||
<PaginationContent>
|
||||
|
||||
@@ -6,10 +6,12 @@ import {Card} from "@/components/ui/card";
|
||||
import {ConnectionIndicator} from "@/components/wrappers/common/connection-indicator";
|
||||
import {formatDateLastContact} from "@/utils/date-formatting";
|
||||
import {AgentWith} from "@/db/schema/08_agent";
|
||||
import {Activity, ChevronRight, Copy, Check, Fingerprint, Server, Database} from "lucide-react";
|
||||
import {Activity, ChevronRight, Copy, Check, Fingerprint, Server, Database, AlertCircle} from "lucide-react";
|
||||
import {Badge} from "@/components/ui/badge";
|
||||
import {truncateWords} from "@/utils/text";
|
||||
import {useIsMobile} from "@/hooks/use-mobile";
|
||||
import {Tooltip, TooltipContent, TooltipTrigger} from "@/components/ui/tooltip";
|
||||
import {useAgentUpdateCheck} from "@/features/agents/hooks/use-agent-update-check";
|
||||
|
||||
export type agentCardProps = {
|
||||
data: AgentWith;
|
||||
@@ -20,6 +22,8 @@ export const AgentCard = (props: agentCardProps) => {
|
||||
const isMobile = useIsMobile();
|
||||
const [isCopied, setIsCopied] = useState(false);
|
||||
|
||||
const {newRelease, isUpdateAvailable} = useAgentUpdateCheck(agent.version);
|
||||
|
||||
const handleCopy = (e: React.MouseEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
@@ -44,9 +48,23 @@ export const AgentCard = (props: agentCardProps) => {
|
||||
{isMobile ? truncateWords(agent.name, 2) : agent.name}
|
||||
</h3>
|
||||
{agent.version && (
|
||||
<Badge variant="secondary" className="h-5 px-1.5 text-[10px] font-bold tracking-wider">
|
||||
v{agent.version}
|
||||
</Badge>
|
||||
<div className="flex items-center gap-2">
|
||||
<Badge variant="secondary" className="h-5 px-1.5 text-[10px] font-bold tracking-wider">
|
||||
v{agent.version}
|
||||
</Badge>
|
||||
{isUpdateAvailable && (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<div className="flex items-center justify-center w-5 h-5 bg-yellow-500/10 rounded-full border border-yellow-500/20 text-yellow-600">
|
||||
<AlertCircle className="w-3 h-3" />
|
||||
</div>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>Update available: {newRelease?.tag_name}</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
"use client";
|
||||
|
||||
import {useQuery} from "@tanstack/react-query";
|
||||
import {getNewAgentRelease} from "@/features/updates/services/github";
|
||||
|
||||
export const useAgentUpdateCheck = (currentVersion?: string | null) => {
|
||||
const {data: newRelease, isLoading} = useQuery({
|
||||
queryKey: ["agent-new-release", currentVersion],
|
||||
queryFn: () => currentVersion ? getNewAgentRelease(currentVersion) : Promise.resolve(null),
|
||||
staleTime: 1000 * 60 * 60,
|
||||
enabled: !!currentVersion,
|
||||
});
|
||||
|
||||
return {
|
||||
newRelease,
|
||||
isLoading,
|
||||
isUpdateAvailable: !!newRelease,
|
||||
};
|
||||
};
|
||||
@@ -14,7 +14,7 @@ type ParsedVersion = {
|
||||
};
|
||||
|
||||
function parseVersion(version: string): ParsedVersion {
|
||||
const match = version.match(/^(\d+)\.(\d+)\.(\d+)(?:-rc\.(\d+))?$/);
|
||||
const match = version.match(/^v?(\d+)\.(\d+)\.(\d+)(?:-rc\.(\d+))?$/);
|
||||
if (!match) return {
|
||||
major: 0,
|
||||
minor: 0,
|
||||
@@ -30,6 +30,49 @@ function parseVersion(version: string): ParsedVersion {
|
||||
};
|
||||
}
|
||||
|
||||
const findLatestVersion = (currentVersion: string, releases: GitHubRelease[]): GitHubRelease | null => {
|
||||
const cleanCurrentVersion = currentVersion.replace(/^v/, "");
|
||||
const isStable = /^\d+\.\d+\.\d+$/.test(cleanCurrentVersion);
|
||||
const isRc = /^\d+\.\d+\.\d+-rc\.\d+$/.test(cleanCurrentVersion);
|
||||
|
||||
const currentParsedVersion = parseVersion(cleanCurrentVersion);
|
||||
|
||||
if (isRc) {
|
||||
const latestStableVersion = releases.find(r => !r.prerelease);
|
||||
const latestRcVersion = releases.find(r => r.prerelease && (r.tag_name.includes("rc") || (r.name && r.name.includes("rc"))));
|
||||
|
||||
if (latestStableVersion) {
|
||||
const versionStr = latestStableVersion.tag_name || latestStableVersion.name;
|
||||
const latestStableParsedVersion = parseVersion(versionStr);
|
||||
if (latestStableParsedVersion.major > currentParsedVersion.major) return latestStableVersion;
|
||||
if (latestStableParsedVersion.major === currentParsedVersion.major && latestStableParsedVersion.minor > currentParsedVersion.minor) return latestStableVersion;
|
||||
if (latestStableParsedVersion.major === currentParsedVersion.major && latestStableParsedVersion.minor === currentParsedVersion.minor && latestStableParsedVersion.patch >= currentParsedVersion.patch) return latestStableVersion;
|
||||
}
|
||||
|
||||
if (latestRcVersion) {
|
||||
const versionStr = latestRcVersion.tag_name || latestRcVersion.name;
|
||||
const latestRcParsedVersion = parseVersion(versionStr);
|
||||
if (latestRcParsedVersion.major > currentParsedVersion.major) return latestRcVersion;
|
||||
if (latestRcParsedVersion.major === currentParsedVersion.major && latestRcParsedVersion.minor > currentParsedVersion.minor) return latestRcVersion;
|
||||
if (latestRcParsedVersion.major === currentParsedVersion.major && latestRcParsedVersion.minor === currentParsedVersion.minor && latestRcParsedVersion.patch > currentParsedVersion.patch) return latestRcVersion;
|
||||
if (latestRcParsedVersion.major === currentParsedVersion.major && latestRcParsedVersion.minor === currentParsedVersion.minor && latestRcParsedVersion.patch === currentParsedVersion.patch &&
|
||||
latestRcParsedVersion.rc !== undefined && currentParsedVersion.rc !== undefined && latestRcParsedVersion.rc > currentParsedVersion.rc) return latestRcVersion;
|
||||
}
|
||||
} else if (isStable) {
|
||||
const latestStableVersion = releases.find(r => !r.prerelease);
|
||||
if (latestStableVersion) {
|
||||
const versionStr = latestStableVersion.tag_name || latestStableVersion.name;
|
||||
const latestStableParsedVersion = parseVersion(versionStr);
|
||||
|
||||
if (latestStableParsedVersion.major > currentParsedVersion.major) return latestStableVersion;
|
||||
if (latestStableParsedVersion.major === currentParsedVersion.major && latestStableParsedVersion.minor > currentParsedVersion.minor) return latestStableVersion;
|
||||
if (latestStableParsedVersion.major === currentParsedVersion.major && latestStableParsedVersion.minor === currentParsedVersion.minor && latestStableParsedVersion.patch > currentParsedVersion.patch) return latestStableVersion;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
export const getNewRelease = async (currentVersion: string): Promise<GitHubRelease | null> => {
|
||||
try {
|
||||
const response = await fetch("https://api.github.com/repos/Portabase/portabase/releases");
|
||||
@@ -38,49 +81,28 @@ export const getNewRelease = async (currentVersion: string): Promise<GitHubRelea
|
||||
}
|
||||
|
||||
const releases: GitHubRelease[] = await response.json();
|
||||
|
||||
const isStable = /^\d+\.\d+\.\d+$/.test(currentVersion);
|
||||
const isRc = /^\d+\.\d+\.\d+-rc\.\d+$/.test(currentVersion);
|
||||
|
||||
console.log("isStable", isStable)
|
||||
console.log("isRc", isRc)
|
||||
|
||||
|
||||
const currentParsedVersion = parseVersion(currentVersion)
|
||||
|
||||
const latestStableVersion = releases.find(r => !r.prerelease)
|
||||
const latestRcVersion = releases.find(r => r.name.includes("rc"))!
|
||||
|
||||
if (isRc) {
|
||||
if (!latestRcVersion) return null
|
||||
const latestRcParsedVersion = parseVersion(latestRcVersion.name)
|
||||
if (currentParsedVersion.major < latestRcParsedVersion.major) return latestRcVersion;
|
||||
if (currentParsedVersion.minor < latestRcParsedVersion.minor) return latestRcVersion;
|
||||
if (currentParsedVersion.patch < latestRcParsedVersion.patch) return latestRcVersion;
|
||||
if (currentParsedVersion.rc! < latestRcParsedVersion.rc!) return latestRcVersion;
|
||||
|
||||
if (!latestStableVersion) return null
|
||||
const latestStableParsedVersion = parseVersion(latestStableVersion.name)
|
||||
if (currentParsedVersion.major < latestStableParsedVersion.major) return latestStableVersion;
|
||||
if (currentParsedVersion.minor < latestStableParsedVersion.minor) return latestStableVersion;
|
||||
if (currentParsedVersion.patch < latestStableParsedVersion.patch) return latestStableVersion;
|
||||
|
||||
return null;
|
||||
|
||||
} else if (isStable) {
|
||||
if (!latestStableVersion) return null
|
||||
const latestStableParsedVersion = parseVersion(latestStableVersion.name)
|
||||
if (currentParsedVersion.major < latestStableParsedVersion.major) return latestStableVersion;
|
||||
if (currentParsedVersion.minor < latestStableParsedVersion.minor) return latestStableVersion;
|
||||
if (currentParsedVersion.patch < latestStableParsedVersion.patch) return latestStableVersion;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
return findLatestVersion(currentVersion, releases);
|
||||
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch latest release", error);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
export const getNewAgentRelease = async (currentVersion: string): Promise<GitHubRelease | null> => {
|
||||
try {
|
||||
const response = await fetch("https://api.github.com/repos/Portabase/agent-rust/releases", {
|
||||
next: { revalidate: 3600 }
|
||||
});
|
||||
if (!response.ok) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const releases: GitHubRelease[] = await response.json();
|
||||
return findLatestVersion(currentVersion, releases);
|
||||
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch latest agent release", error);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user