1d3848f85e
- bincio/render/merge.py: parse sidecar .md files (YAML frontmatter +
markdown body), produce data/_merged/ with symlinks for unmodified
activities and real merged files for overridden ones; filters private
activities from index.json; sorts highlighted activities first.
Keeps extracted data pristine — re-running extract never clobbers edits.
- bincio/edit/: FastAPI edit server (port 4041) with embedded HTML/JS
edit UI; GET/POST /api/activity/{id} reads/writes sidecars; multipart
image upload to edits/images/{id}/; DELETE for image cleanup.
- bincio render now calls merge_all() before build/serve and symlinks
public/data → data/_merged/ instead of data/ directly.
- ActivityDetail.svelte: edit button (links to edit server) when
PUBLIC_EDIT_URL env var is set; respects custom.hide_stats to suppress
stat panels; description supports whitespace-preserving rendering.
- 15 unit tests covering parse_sidecar, apply_sidecar, and merge_all.
80 lines
2.5 KiB
Python
80 lines
2.5 KiB
Python
"""bincio edit — local edit server for activity sidecar files."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
from typing import Optional
|
|
|
|
import click
|
|
from rich.console import Console
|
|
|
|
console = Console()
|
|
|
|
|
|
@click.command()
|
|
@click.option("--data-dir", default=None,
|
|
help="BAS data store directory (output of bincio extract).")
|
|
@click.option("--port", default=4041, show_default=True,
|
|
help="Port for the edit server.")
|
|
@click.option("--site-url", default="http://localhost:4321", show_default=True,
|
|
help="URL of the Astro dev server (for the Back link).")
|
|
@click.option("--config", "config_path", default=None,
|
|
help="Path to extract_config.yaml (reads output.dir from it).")
|
|
def edit(
|
|
data_dir: Optional[str],
|
|
port: int,
|
|
site_url: str,
|
|
config_path: Optional[str],
|
|
) -> None:
|
|
"""Start a local web UI for editing activity sidecar files.
|
|
|
|
Writes sidecar .md files to <data-dir>/edits/ which bincio render picks
|
|
up and applies at build time.
|
|
|
|
Run alongside the Astro dev server:
|
|
|
|
\b
|
|
bincio render --serve # port 4321 (or npm run dev)
|
|
bincio edit # port 4041
|
|
"""
|
|
try:
|
|
import uvicorn
|
|
except ImportError:
|
|
raise click.ClickException(
|
|
"uvicorn is required for the edit server.\n"
|
|
"Install with: uv add 'bincio[edit]'"
|
|
)
|
|
|
|
data = _resolve_data_dir(data_dir, config_path)
|
|
console.print(f"Data dir: [cyan]{data}[/cyan]")
|
|
console.print(f"Edit UI: [cyan]http://localhost:{port}/edit/<activity-id>[/cyan]")
|
|
console.print(f"Site URL: [cyan]{site_url}[/cyan]")
|
|
console.print("Press [bold]Ctrl+C[/bold] to stop.\n")
|
|
|
|
import bincio.edit.server as srv
|
|
srv.data_dir = data
|
|
srv.site_url = site_url
|
|
|
|
uvicorn.run(srv.app, host="127.0.0.1", port=port, log_level="warning")
|
|
|
|
|
|
def _resolve_data_dir(explicit: Optional[str], config_path: Optional[str]) -> Path:
|
|
if explicit:
|
|
return Path(explicit).expanduser().resolve()
|
|
|
|
if config_path and Path(config_path).exists():
|
|
import yaml
|
|
raw = yaml.safe_load(Path(config_path).read_text())
|
|
out = raw.get("output", {}).get("dir")
|
|
if out:
|
|
return Path(out).expanduser().resolve()
|
|
|
|
default = Path.cwd() / "bincio_data"
|
|
if default.exists():
|
|
return default
|
|
|
|
raise click.UsageError(
|
|
"Could not find the BAS data directory. "
|
|
"Run `bincio extract` first, or pass --data-dir."
|
|
)
|