Handle the agent and agent version

This commit is contained in:
Owen
2026-09-14 14:07:26 -04:00
parent 888ccce397
commit f9f38fb3f0
9 changed files with 91 additions and 81 deletions
@@ -19,7 +19,6 @@ import {
InfoSections,
InfoSectionTitle
} from "@app/components/InfoSection";
import { Badge } from "@app/components/ui/badge";
import { Button } from "@app/components/ui/button";
import ActionBanner from "@app/components/ActionBanner";
import { PaidFeaturesAlert } from "@app/components/PaidFeaturesAlert";
@@ -41,13 +40,6 @@ import { useParams } from "next/navigation";
import { FaApple, FaWindows, FaLinux } from "react-icons/fa";
import { SiAndroid } from "react-icons/si";
import { tierMatrix } from "@server/lib/billing/tierMatrix";
import {
productUpdatesQueries,
type LatestVersionResponse
} from "@app/lib/queries";
import { useQuery } from "@tanstack/react-query";
import semver from "semver";
import { InfoPopup } from "@app/components/ui/info-popup";
function formatTimestamp(timestamp: number | null | undefined): string {
if (!timestamp) return "-";
@@ -173,34 +165,6 @@ export default function GeneralPage() {
}>(null);
const [isCheckingCache, setIsCheckingCache] = useState(false);
const [isRebuildingCache, setIsRebuildingCache] = useState(false);
const data = useQuery(productUpdatesQueries.latestVersion(true));
const latestPlatformVersions = data.data?.data;
const agentVersionMap: Record<string, string> = {
"Pangolin Windows": "windows",
"Pangolin Android": "android",
"Pangolin iOS": "ios",
"Pangolin iPadOS": "ios",
"Pangolin macOS": "mac",
"Pangolin CLI": "cli",
"Olm CLI": "olm"
};
let updateAvailable = false;
if (client.agent && client.olmVersion && latestPlatformVersions) {
const agent = agentVersionMap[
client.agent
] as keyof LatestVersionResponse;
if (agent in latestPlatformVersions) {
const agentVersion = latestPlatformVersions[agent];
updateAvailable = Boolean(
semver.valid(client.olmVersion) &&
semver.lt(client.olmVersion, agentVersion.latestVersion)
);
}
}
// get "imp" from local storage to determine if we should show the verify button (imp = "1" means show)
const showVerifyButton =
@@ -467,7 +431,7 @@ export default function GeneralPage() {
)}
{/* Device Information Section */}
{(client.fingerprint || (client.agent && client.olmVersion)) && (
{client.fingerprint && (
<SettingsSection>
<SettingsSectionHeader>
<SettingsSectionTitle>
@@ -479,33 +443,6 @@ export default function GeneralPage() {
</SettingsSectionHeader>
<SettingsSectionBody>
{client.agent && client.olmVersion && (
<div className="mb-6">
<InfoSection>
<InfoSectionTitle>
{t("agent")}
</InfoSectionTitle>
<InfoSectionContent>
<div className="flex items-center">
<Badge variant="secondary">
{client.agent +
" v" +
client.olmVersion}
</Badge>
{updateAvailable && (
<InfoPopup
info={t(
"updateAvailableInfo"
)}
/>
)}
</div>
</InfoSectionContent>
</InfoSection>
</div>
)}
{client.fingerprint &&
(() => {
const platform = client.fingerprint.platform;
+61 -1
View File
@@ -11,9 +11,26 @@ import {
import IdpTypeBadge from "@app/components/IdpTypeBadge";
import { getUserDisplayName } from "@app/lib/getUserDisplayName";
import { useTranslations } from "next-intl";
import {
productUpdatesQueries,
type LatestVersionResponse
} from "@app/lib/queries";
import { useQuery } from "@tanstack/react-query";
import semver from "semver";
import { InfoPopup } from "@app/components/ui/info-popup";
type ClientInfoCardProps = {};
const agentVersionMap: Record<string, string> = {
"Pangolin Windows": "windows",
"Pangolin Android": "android",
"Pangolin iOS": "ios",
"Pangolin iPadOS": "ios",
"Pangolin macOS": "mac",
"Pangolin CLI": "cli",
"Olm CLI": "olm"
};
export default function SiteInfoCard({}: ClientInfoCardProps) {
const { client, updateClient } = useClientContext();
const t = useTranslations();
@@ -24,14 +41,57 @@ export default function SiteInfoCard({}: ClientInfoCardProps) {
username: client.userUsername
});
const data = useQuery(productUpdatesQueries.latestVersion(true));
const latestPlatformVersions = data.data?.data;
let updateAvailable = false;
if (client.agent && client.olmVersion && latestPlatformVersions) {
const agent = agentVersionMap[
client.agent
] as keyof LatestVersionResponse;
if (agent in latestPlatformVersions) {
const agentVersion = latestPlatformVersions[agent];
updateAvailable = Boolean(
semver.valid(client.olmVersion) &&
semver.lt(client.olmVersion, agentVersion.latestVersion)
);
}
}
const cols =
2 +
(userDisplayName ? 1 : 0) +
(client.agent && client.olmVersion ? 1 : 0);
return (
<Alert>
<AlertDescription>
<InfoSections cols={userDisplayName ? 3 : 2}>
<InfoSections cols={cols}>
<InfoSection>
<InfoSectionTitle>{t("name")}</InfoSectionTitle>
<InfoSectionContent>{client.name}</InfoSectionContent>
</InfoSection>
{client.agent && client.olmVersion ? (
<InfoSection>
<InfoSectionTitle>{t("agent")}</InfoSectionTitle>
<InfoSectionContent>
<div className="flex items-center gap-2">
<span>
{client.agent +
" v" +
client.olmVersion}
</span>
{updateAvailable && (
<InfoPopup
info={t("updateAvailableInfo")}
/>
)}
</div>
</InfoSectionContent>
</InfoSection>
) : null}
{userDisplayName ? (
<InfoSection>
<InfoSectionTitle>{t("user")}</InfoSectionTitle>
+6 -5
View File
@@ -63,7 +63,6 @@ export default function SiteInfoCard({}: SiteInfoCardProps) {
) : null;
if (site.type === "newt") {
const isCli = site.agent === "cli";
return (
<Alert>
<AlertDescription>
@@ -74,14 +73,16 @@ export default function SiteInfoCard({}: SiteInfoCardProps) {
{t("connectionType")}
</InfoSectionTitle>
<InfoSectionContent>
{isCli ? "CLI" : "Newt"}
{t("pangolinSite")}
</InfoSectionContent>
</InfoSection>
<InfoSection>
<InfoSectionTitle>
{t("newtVersion")}
</InfoSectionTitle>
<InfoSectionTitle>{t("agent")}</InfoSectionTitle>
<InfoSectionContent>
{site.agent == "newt" ? "Newt" : null}
{site.agent == "cli"
? "Pangolin CLI"
: null}{" "}
{site.agentVersion
? `v${site.agentVersion}`
: "-"}
+10 -3
View File
@@ -371,7 +371,7 @@ export default function SitesTable({
},
{
accessorKey: "type",
friendlyName: t("type"),
friendlyName: t("agent"),
header: () => {
return <span className="p-3">{t("type")}</span>;
},
@@ -386,13 +386,20 @@ export default function SitesTable({
);
if (originalRow.type === "newt") {
const isCli = originalRow.agent === "cli";
if (!originalRow.agent) {
return <span>-</span>;
}
return (
<div className="flex items-center space-x-1">
<Badge variant="secondary">
<div className="flex items-center space-x-1">
<span>
{isCli ? "CLI" : "Newt"}
{originalRow.agent == "newt"
? "Newt"
: null}
{originalRow.agent == "cli"
? "Pangolin CLI"
: null}
</span>
{originalRow.agentVersion && (
<span>
+5 -5
View File
@@ -97,7 +97,7 @@ export function NewtSiteInstallCommands({
command: `${runAsRootPrefix}pangolin up site --id ${id} --secret ${secret} --endpoint ${endpoint}${acceptClientsFlag}${disableSshFlag}`
}
],
"Auto Systemd Service": [
"Systemd Service": [
{
title: t("install"),
command: `curl -fsSL https://static.pangolin.net/get-cli.sh | bash`
@@ -141,7 +141,7 @@ sudo chmod 600 /etc/pangolin/pangolin-site.env`
title: t("serviceFile"),
command: `sudo tee /etc/systemd/system/pangolin-site.service > /dev/null << 'EOF'
[Unit]
Description=Newt
Description=Pangolin Site
Wants=network-online.target
After=network-online.target
@@ -223,9 +223,9 @@ sudo systemctl enable --now pangolin-site`
docker: {
"Docker Compose": [
`services:
newt:
pangolin-site:
image: fosrl/pangolin-cli
container_name: newt
container_name: pangolin-site
restart: unless-stopped
environment:
- PANGOLIN_ENDPOINT=${endpoint}
@@ -521,7 +521,7 @@ function getPlatformName(platformName: Platform) {
function getArchitectures(platform: Platform) {
switch (platform) {
case "linux":
return ["Run", "Auto Systemd Service", "Manual Systemd Service"];
return ["Run", "Systemd Service", "Manual Systemd Service"];
case "macos":
return ["Run", "Service"];
case "windows":