import React from "react"; import { useTranslation } from "react-i18next"; import { ArrowUpCircle, Check, CheckCircle2, Copy, ExternalLink, RefreshCw, } from "lucide-react"; import { AGENT_CANVAS_RELEASE_NOTES_URL, AGENT_CANVAS_UPDATE_COMMANDS, } from "#/api/agent-canvas-updates"; import { ModalBackdrop } from "#/components/shared/modals/modal-backdrop"; import { ModalCloseButton } from "#/components/shared/modals/modal-close-button"; import DockerIcon from "#/icons/docker.svg?react"; import NpmIcon from "#/icons/npm.svg?react"; import { I18nKey } from "#/i18n/declaration"; import { cn } from "#/utils/utils"; const COPY_FEEDBACK_MS = 2000; type UpdateCommandTab = "npm" | "docker"; const UPDATE_COMMAND_TABS: UpdateCommandTab[] = ["npm", "docker"]; interface AgentCanvasVersionModalProps { installedVersion: string; latestVersion: string | null; updateAvailable: boolean; isChecking: boolean; onCheckForUpdates: () => void; onClose: () => void; } function getUpdateCommandTabLabelKey(tab: UpdateCommandTab): I18nKey { return tab === "npm" ? I18nKey.SETTINGS$VERSION_NPM_RECOMMENDED : I18nKey.SETTINGS$VERSION_DOCKER; } function UpdateCommandTabIcon({ tab }: { tab: UpdateCommandTab }) { if (tab === "npm") { return ; } return ; } export function AgentCanvasVersionModal({ installedVersion, latestVersion, updateAvailable, isChecking, onCheckForUpdates, onClose, }: AgentCanvasVersionModalProps) { const { t } = useTranslation("openhands"); const [selectedTab, setSelectedTab] = React.useState("npm"); const [copied, setCopied] = React.useState(false); const copiedTimeoutRef = React.useRef(null); const command = selectedTab === "npm" ? AGENT_CANVAS_UPDATE_COMMANDS.npm : AGENT_CANVAS_UPDATE_COMMANDS.docker; React.useEffect( () => () => { if (copiedTimeoutRef.current !== null) { window.clearTimeout(copiedTimeoutRef.current); } }, [], ); React.useEffect(() => { setCopied(false); if (copiedTimeoutRef.current !== null) { window.clearTimeout(copiedTimeoutRef.current); copiedTimeoutRef.current = null; } }, [selectedTab]); const copyCommand = React.useCallback(() => { void navigator.clipboard?.writeText(command); setCopied(true); if (copiedTimeoutRef.current !== null) { window.clearTimeout(copiedTimeoutRef.current); } copiedTimeoutRef.current = window.setTimeout(() => { setCopied(false); copiedTimeoutRef.current = null; }, COPY_FEEDBACK_MS); }, [command]); return (
{updateAvailable ? ( ) : ( )}

{t( updateAvailable ? I18nKey.SETTINGS$VERSION_UPDATE_AVAILABLE : I18nKey.SETTINGS$VERSION_UP_TO_DATE_TITLE, )}

{updateAvailable && latestVersion ? ( {latestVersion} ) : null}
{updateAvailable && latestVersion ? (

{t(I18nKey.SETTINGS$VERSION_UPDATE_MESSAGE, { installed: installedVersion, latest: latestVersion, })}{" "} {t(I18nKey.SETTINGS$VERSION_RELEASE_NOTES)}

) : ( <>

{t(I18nKey.SETTINGS$VERSION_INSTALLED, { version: installedVersion, })}

{latestVersion ? (

{t(I18nKey.SETTINGS$VERSION_LATEST_MESSAGE)}{" "} {t(I18nKey.SETTINGS$VERSION_RELEASE_NOTES)}

) : (

{t(I18nKey.SETTINGS$VERSION_CHECK_UNAVAILABLE)}

)} )}
{updateAvailable ? (
{UPDATE_COMMAND_TABS.map((tab) => ( ))}
{command}
) : null} {!updateAvailable ? (
) : null}
); }