diff --git a/frontend/public/favicon.svg b/frontend/public/favicon.svg index 1bea0a9..a62bf24 100644 --- a/frontend/public/favicon.svg +++ b/frontend/public/favicon.svg @@ -8,7 +8,7 @@ version="1.1" id="svg1" inkscape:version="1.4.3 (0d15f75, 2025-12-25)" - sodipodi:docname="argonode.svg" + sodipodi:docname="favicon.svg" inkscape:export-filename="tono.png" inkscape:export-xdpi="130.05" inkscape:export-ydpi="130.05" @@ -49,28 +49,17 @@ height="194.43169" x="2.5203834" y="2.9819231" - rx="52.916668" - ry="52.916668" /> + rx="97.484589" + ry="97.215843" /> - tono diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 035c445..1011a7a 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -897,6 +897,7 @@ function Flow() { const [executingNodeId, setExecutingNodeId] = useState(null); const [helpTabs, setHelpTabs] = useState<{ label: string; type?: string; content: string | null }[]>([]); const [activeHelpTab, setActiveHelpTab] = useState(null); + const [updateInfo, setUpdateInfo] = useState<{ latest: string; url: string } | null>(null); const flowContainerRef = useRef(null); const panTimerRef = useRef | null>(null); @@ -918,6 +919,19 @@ function Flow() { const reactFlow = useReactFlow() as ReturnType> & { updateNodeInternals: (id: string) => void }; const undoRedo = useUndoRedo(); + // ── Update check (native builds only) ────────────────────────────── + useEffect(() => { + if (!(window as any).pywebview) return; + fetch('/check-update') + .then((r) => r.ok ? r.json() : null) + .then((data) => { + if (data?.update_available && data.latest) { + setUpdateInfo({ latest: data.latest, url: data.url }); + } + }) + .catch(() => {}); + }, []); + const scheduleAutoRun = useCallback(() => { if (autoRunTimer.current) clearTimeout(autoRunTimer.current); autoRunTimer.current = setTimeout(() => autoRunRef.current?.(), 300); @@ -3179,6 +3193,15 @@ function Flow() {
{status.text}
+ {updateInfo && ( +
+ tono {updateInfo.latest} is available. + {' '} + Download + +
+ )} + {/* React Flow canvas */}