add update service
This commit is contained in:
@@ -8,7 +8,7 @@
|
|||||||
version="1.1"
|
version="1.1"
|
||||||
id="svg1"
|
id="svg1"
|
||||||
inkscape:version="1.4.3 (0d15f75, 2025-12-25)"
|
inkscape:version="1.4.3 (0d15f75, 2025-12-25)"
|
||||||
sodipodi:docname="argonode.svg"
|
sodipodi:docname="favicon.svg"
|
||||||
inkscape:export-filename="tono.png"
|
inkscape:export-filename="tono.png"
|
||||||
inkscape:export-xdpi="130.05"
|
inkscape:export-xdpi="130.05"
|
||||||
inkscape:export-ydpi="130.05"
|
inkscape:export-ydpi="130.05"
|
||||||
@@ -49,28 +49,17 @@
|
|||||||
height="194.43169"
|
height="194.43169"
|
||||||
x="2.5203834"
|
x="2.5203834"
|
||||||
y="2.9819231"
|
y="2.9819231"
|
||||||
rx="52.916668"
|
rx="97.484589"
|
||||||
ry="52.916668" />
|
ry="97.215843" />
|
||||||
<path
|
<path
|
||||||
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:8.251;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:9.87521;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||||
d="m 80.438549,119.47945 85.556771,-87.012984 4.46561,16.665896 -16.7032,-4.47561"
|
d="M 62.915486,149.85992 165.31436,45.718188 l 5.34467,19.946625 -19.99127,-5.356646"
|
||||||
id="path6"
|
id="path6"
|
||||||
sodipodi:nodetypes="cccc" />
|
sodipodi:nodetypes="cccc" />
|
||||||
<path
|
<path
|
||||||
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:3.95096;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:4.72872;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||||
d="M 133.7656,68.457841 H 103.74962 L 50.836303,122.45621 80.512342,121.94367"
|
d="M 126.74012,88.794566 H 90.815406 l -63.329451,64.628104 35.51785,-0.61344"
|
||||||
id="path7"
|
id="path7"
|
||||||
sodipodi:nodetypes="cccc" />
|
sodipodi:nodetypes="cccc" />
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:80px;line-height:0;font-family:Futura;-inkscape-font-specification:'Futura, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;writing-mode:lr-tb;direction:ltr;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:2.75827;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
|
||||||
x="18.009901"
|
|
||||||
y="172.8485"
|
|
||||||
id="text8"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan8"
|
|
||||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:80px;font-family:Futura;-inkscape-font-specification:'Futura, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:2.75827;stroke-dasharray:none"
|
|
||||||
x="18.009901"
|
|
||||||
y="172.8485">tono</tspan></text>
|
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 2.3 KiB |
@@ -897,6 +897,7 @@ function Flow() {
|
|||||||
const [executingNodeId, setExecutingNodeId] = useState<string | null>(null);
|
const [executingNodeId, setExecutingNodeId] = useState<string | null>(null);
|
||||||
const [helpTabs, setHelpTabs] = useState<{ label: string; type?: string; content: string | null }[]>([]);
|
const [helpTabs, setHelpTabs] = useState<{ label: string; type?: string; content: string | null }[]>([]);
|
||||||
const [activeHelpTab, setActiveHelpTab] = useState<string | null>(null);
|
const [activeHelpTab, setActiveHelpTab] = useState<string | null>(null);
|
||||||
|
const [updateInfo, setUpdateInfo] = useState<{ latest: string; url: string } | null>(null);
|
||||||
|
|
||||||
const flowContainerRef = useRef<HTMLDivElement | null>(null);
|
const flowContainerRef = useRef<HTMLDivElement | null>(null);
|
||||||
const panTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
const panTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||||
@@ -918,6 +919,19 @@ function Flow() {
|
|||||||
const reactFlow = useReactFlow<TonoNode, TonoEdge>() as ReturnType<typeof useReactFlow<TonoNode, TonoEdge>> & { updateNodeInternals: (id: string) => void };
|
const reactFlow = useReactFlow<TonoNode, TonoEdge>() as ReturnType<typeof useReactFlow<TonoNode, TonoEdge>> & { updateNodeInternals: (id: string) => void };
|
||||||
const undoRedo = useUndoRedo();
|
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(() => {
|
const scheduleAutoRun = useCallback(() => {
|
||||||
if (autoRunTimer.current) clearTimeout(autoRunTimer.current);
|
if (autoRunTimer.current) clearTimeout(autoRunTimer.current);
|
||||||
autoRunTimer.current = setTimeout(() => autoRunRef.current?.(), 300);
|
autoRunTimer.current = setTimeout(() => autoRunRef.current?.(), 300);
|
||||||
@@ -3179,6 +3193,15 @@ function Flow() {
|
|||||||
<div className={`status-bar ${status.level}`}>{status.text}</div>
|
<div className={`status-bar ${status.level}`}>{status.text}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{updateInfo && (
|
||||||
|
<div className="update-banner">
|
||||||
|
tono {updateInfo.latest} is available.
|
||||||
|
{' '}
|
||||||
|
<a href={updateInfo.url} target="_blank" rel="noopener noreferrer">Download</a>
|
||||||
|
<button className="update-banner-dismiss" onClick={() => setUpdateInfo(null)} title="Dismiss">✕</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* React Flow canvas */}
|
{/* React Flow canvas */}
|
||||||
<div
|
<div
|
||||||
ref={flowContainerRef}
|
ref={flowContainerRef}
|
||||||
|
|||||||
@@ -212,6 +212,34 @@ html, body, #root {
|
|||||||
.status-bar.info { color: var(--accent-light); }
|
.status-bar.info { color: var(--accent-light); }
|
||||||
.status-bar.error { color: var(--error-text); background: var(--error-bg); }
|
.status-bar.error { color: var(--error-text); background: var(--error-bg); }
|
||||||
|
|
||||||
|
.update-banner {
|
||||||
|
background: var(--accent);
|
||||||
|
color: #fff;
|
||||||
|
text-align: center;
|
||||||
|
padding: 4px 12px;
|
||||||
|
font-size: 12px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.update-banner a {
|
||||||
|
color: #fff;
|
||||||
|
font-weight: 600;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
.update-banner-dismiss {
|
||||||
|
position: absolute;
|
||||||
|
right: 8px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: #fff;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 13px;
|
||||||
|
padding: 2px 4px;
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
.update-banner-dismiss:hover { opacity: 1; }
|
||||||
|
|
||||||
/* ── React Flow container ──────────────────────────────────────────── */
|
/* ── React Flow container ──────────────────────────────────────────── */
|
||||||
.flow-container {
|
.flow-container {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ export default defineConfig({
|
|||||||
'/file-content': 'http://127.0.0.1:8188',
|
'/file-content': 'http://127.0.0.1:8188',
|
||||||
'/help-docs': { target: 'http://127.0.0.1:8188', changeOrigin: true },
|
'/help-docs': { target: 'http://127.0.0.1:8188', changeOrigin: true },
|
||||||
'/prompt': 'http://127.0.0.1:8188',
|
'/prompt': 'http://127.0.0.1:8188',
|
||||||
|
'/check-update': 'http://127.0.0.1:8188',
|
||||||
'/ws': {
|
'/ws': {
|
||||||
target: 'http://127.0.0.1:8188',
|
target: 'http://127.0.0.1:8188',
|
||||||
ws: true,
|
ws: true,
|
||||||
|
|||||||
Reference in New Issue
Block a user