work on improving stability

This commit is contained in:
2026-04-03 21:26:25 -07:00
parent 43ca381748
commit ab3b4d5ec3
5 changed files with 27 additions and 16 deletions

View File

@@ -8,7 +8,7 @@ tono is a node-based SPM image processing and analysis tool. The main focus is o
It is heavily inspired by [Gwyddion](https://gwyddion.net/), one of my favorite scientific FOSS programs on the web. It is heavily inspired by [Gwyddion](https://gwyddion.net/), one of my favorite scientific FOSS programs on the web.
<img src="frontend/public/default-workflow.png" width="600"> <img src="frontend/public/default-workflow.png" width="800">
## Quick start ## Quick start
Install a local binary from the Releases section, or run locally: Install a local binary from the Releases section, or run locally:
@@ -28,9 +28,10 @@ npm run dev # terminal 2 — Vite dev server, open the URL it prints
```bash ```bash
git clone https://github.com/VIPQualityPost/tono.git && cd tono git clone https://github.com/VIPQualityPost/tono.git && cd tono
python -m venv .venv && source .venv/bin/activate
pip install -e . pip install -e .
cd frontend && npm ci && npm run build && cd .. cd frontend && npm ci && npm run build && cd ..
TONO_HOST=0.0.0.0 tono TONO_HOST=0.0.0.0 python -m backend.main
``` ```
See [Self-Hosting](docs/self-hosting.md) for reverse proxy setup, environment variables, and configuration. See [Self-Hosting](docs/self-hosting.md) for reverse proxy setup, environment variables, and configuration.

View File

@@ -715,10 +715,18 @@ def create_app(
app.router.add_get("/check-update", check_update) app.router.add_get("/check-update", check_update)
app.router.add_get("/ws", websocket_handler) app.router.add_get("/ws", websocket_handler)
async def dist_file(request: web.Request) -> web.Response:
filename = request.match_info["filename"]
path = (DIST_DIR / filename).resolve()
if not path.is_relative_to(DIST_DIR.resolve()) or not path.is_file():
raise web.HTTPNotFound()
return web.FileResponse(path)
if (DIST_DIR / "assets").exists(): if (DIST_DIR / "assets").exists():
app.router.add_static("/assets", DIST_DIR / "assets") app.router.add_static("/assets", DIST_DIR / "assets")
if FRONTEND_DIR.exists(): if FRONTEND_DIR.exists():
app.router.add_static("/static", FRONTEND_DIR) app.router.add_static("/static", FRONTEND_DIR)
app.router.add_get("/{filename}", dist_file)
async def _cors_middleware(app_, handler): async def _cors_middleware(app_, handler):
async def middleware(request): async def middleware(request):

View File

@@ -9,7 +9,7 @@ git clone https://github.com/VIPQualityPost/tono.git && cd tono
python -m venv .venv && source .venv/bin/activate python -m venv .venv && source .venv/bin/activate
pip install -e . pip install -e .
cd frontend && npm ci && npm run build && cd .. cd frontend && npm ci && npm run build && cd ..
TONO_HOST=0.0.0.0 tono TONO_HOST=0.0.0.0 python -m backend.main
``` ```
The server will be available at `http://<your-server-ip>:8188`. The server will be available at `http://<your-server-ip>:8188`.
@@ -48,7 +48,7 @@ After=network.target
Type=simple Type=simple
User=tono User=tono
WorkingDirectory=/opt/tono WorkingDirectory=/opt/tono
ExecStart=/opt/tono/.venv/bin/tono ExecStart=/opt/tono/.venv/bin/python -m backend.main
Environment=TONO_HOST=127.0.0.1 Environment=TONO_HOST=127.0.0.1
Environment=TONO_PORT=8188 Environment=TONO_PORT=8188
Environment=TONO_APPDATA=/var/lib/tono Environment=TONO_APPDATA=/var/lib/tono

View File

@@ -4,16 +4,18 @@ import { marked } from 'marked';
import DOMPurify from 'dompurify'; import DOMPurify from 'dompurify';
// Open external links in new tabs // Open external links in new tabs
const renderer = new marked.Renderer(); marked.use({
const defaultLinkRenderer = renderer.link.bind(renderer); renderer: {
renderer.link = function (token) { link({ href, title, tokens }) {
const html = defaultLinkRenderer(token); const text = this.parser.parseInline(tokens ?? []);
if (token.href && /^https?:\/\//.test(token.href)) { const titleAttr = title ? ` title="${title}"` : '';
return html.replace(/^<a /, '<a target="_blank" rel="noopener noreferrer" '); if (href && /^https?:\/\//.test(href)) {
return `<a href="${href}"${titleAttr} target="_blank" rel="noopener noreferrer">${text}</a>`;
} }
return html; return `<a href="${href || ''}"${titleAttr}>${text}</a>`;
}; },
marked.use({ renderer }); },
});
interface Heading { interface Heading {
level: number; level: number;

View File

@@ -608,10 +608,10 @@ html, body, #root {
.node-help-panel { .node-help-panel {
position: fixed; position: fixed;
top: 60px; top: 12px;
right: 20px; right: 20px;
width: 620px; width: 620px;
max-height: calc(100vh - 80px); max-height: calc(100vh - 32px);
background: #1e293b; background: #1e293b;
border: 1px solid #334155; border: 1px solid #334155;
border-radius: 8px; border-radius: 8px;