317 lines
8.3 KiB
Python
317 lines
8.3 KiB
Python
#!/usr/bin/env python3
|
|
"""Homarr dashboard — alle actieve Foodlinkk links + tiles op board."""
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import random
|
|
import sqlite3
|
|
import string
|
|
|
|
DB = "/opt/homarr_db/db.sqlite"
|
|
BOARD_ID = "jnyjc9756utndw62gsg78ssb"
|
|
SECTION_ID = "lvq9qc0p59sllgek92n77qi8"
|
|
LAYOUT_ID = "lft1byu8yp01glpe006l7cuq"
|
|
|
|
ICON = "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons"
|
|
|
|
# (name, description, href, ping_url, icon_url)
|
|
APPS: list[tuple[str, str, str, str | None, str]] = [
|
|
# —— Kern (Foodlinkk) ——
|
|
(
|
|
"Foodlinkk Cockpit",
|
|
"Command Center — hoofd-UI",
|
|
"http://10.4.7.18:8600/",
|
|
"http://10.4.7.18:8600/",
|
|
f"{ICON}/svg/home-assistant.svg",
|
|
),
|
|
(
|
|
"Wereldexport",
|
|
"Export Intel · kaart · distributeurs",
|
|
"http://10.4.7.18:8600/export-intel",
|
|
"http://10.4.7.18:8600/export-intel",
|
|
f"{ICON}/svg/world.svg",
|
|
),
|
|
(
|
|
"Voice Live",
|
|
"Herman voice · hands-free",
|
|
"http://10.4.7.18:8600/voice",
|
|
"http://10.4.7.18:8600/voice",
|
|
f"{ICON}/svg/google-assistant.svg",
|
|
),
|
|
(
|
|
"Herman Chat",
|
|
"Browser chat + agy builds",
|
|
"http://10.4.7.18:8600/herman",
|
|
"http://10.4.7.18:8600/herman",
|
|
f"{ICON}/svg/open-webui.svg",
|
|
),
|
|
(
|
|
"Agents",
|
|
"Mesh · terminals · webbuilder",
|
|
"http://10.4.7.18:8600/agents",
|
|
"http://10.4.7.18:8600/agents",
|
|
f"{ICON}/svg/portainer.svg",
|
|
),
|
|
(
|
|
"Revenue Cockpit",
|
|
"Excel-live dashboard",
|
|
"http://10.4.7.18:8600/revenue-cockpit",
|
|
"http://10.4.7.18:8600/revenue-cockpit",
|
|
f"{ICON}/svg/grafana.svg",
|
|
),
|
|
(
|
|
"Gitea",
|
|
"Git · backups · repo",
|
|
"http://10.4.7.18:3001/aissa/foodlinkk-command-center",
|
|
"http://10.4.7.18:3001/",
|
|
f"{ICON}/svg/gitea.svg",
|
|
),
|
|
# —— Infra ——
|
|
(
|
|
"Proxmox",
|
|
"Hypervisor R340",
|
|
"https://10.4.7.14:8006/",
|
|
"https://10.4.7.14:8006/",
|
|
f"{ICON}/svg/proxmox.svg",
|
|
),
|
|
(
|
|
"Synology NAS",
|
|
"FL-nas DSM",
|
|
"http://10.4.7.11:5000/",
|
|
"http://10.4.7.11:5000/",
|
|
f"{ICON}/png/synology-dsm.png",
|
|
),
|
|
(
|
|
"Homarr",
|
|
"Dit dashboard",
|
|
"http://10.4.7.13:3000/",
|
|
"http://10.4.7.13:3000/",
|
|
f"{ICON}/svg/homarr.svg",
|
|
),
|
|
(
|
|
"Dockhand",
|
|
"Docker beheer VM106",
|
|
"http://10.4.7.18:3000/",
|
|
"http://10.4.7.18:3000/",
|
|
f"{ICON}/svg/dockge.svg",
|
|
),
|
|
# —— AI VM105 / VM107 ——
|
|
(
|
|
"Herman Orchestrator",
|
|
"VM105 · agent routing",
|
|
"http://10.4.7.19:8090/",
|
|
"http://10.4.7.19:8090/health",
|
|
f"{ICON}/svg/ollama-light.svg",
|
|
),
|
|
(
|
|
"Open WebUI",
|
|
"Ollama chat UI",
|
|
"http://10.4.7.19:8080/",
|
|
"http://10.4.7.19:8080/",
|
|
f"{ICON}/svg/open-webui.svg",
|
|
),
|
|
(
|
|
"Doc Ingest",
|
|
"NAS documenten · RAG",
|
|
"http://10.4.7.19:8750/",
|
|
"http://10.4.7.19:8750/health",
|
|
f"{ICON}/svg/paperless-ngx.svg",
|
|
),
|
|
(
|
|
"Browser Use",
|
|
"AI browser agent",
|
|
"http://10.4.7.19:7788/",
|
|
"http://10.4.7.19:7788/",
|
|
f"{ICON}/svg/chromium.svg",
|
|
),
|
|
(
|
|
"n8n",
|
|
"Workflow automation",
|
|
"http://10.4.7.19:5678/",
|
|
"http://10.4.7.19:5678/",
|
|
f"{ICON}/svg/n8n.svg",
|
|
),
|
|
(
|
|
"Web Builder (agy)",
|
|
"Antigravity · VM107 API",
|
|
"http://10.4.7.27:8798/health",
|
|
"http://10.4.7.27:8798/health",
|
|
f"{ICON}/svg/nginx.svg",
|
|
),
|
|
(
|
|
"Website Preview",
|
|
"agy build preview",
|
|
"http://10.4.7.27:8080/",
|
|
"http://10.4.7.27:8080/",
|
|
f"{ICON}/svg/nginx.svg",
|
|
),
|
|
# —— Tools VM106 ——
|
|
(
|
|
"ComfyUI",
|
|
"Image generation",
|
|
"http://10.4.7.18:8188/",
|
|
"http://10.4.7.18:8188/",
|
|
f"{ICON}/svg/comfyui.svg",
|
|
),
|
|
(
|
|
"Browser VNC",
|
|
"Live browser VM106",
|
|
"http://10.4.7.18:6080/",
|
|
"http://10.4.7.18:6080/",
|
|
f"{ICON}/svg/chromium.svg",
|
|
),
|
|
(
|
|
"MinIO",
|
|
"Object storage",
|
|
"http://10.4.7.18:9001/",
|
|
"http://10.4.7.18:9001/",
|
|
f"{ICON}/svg/minio-light.svg",
|
|
),
|
|
(
|
|
"Grafana",
|
|
"Monitoring dashboards",
|
|
"http://10.4.7.18:3002/",
|
|
"http://10.4.7.18:3002/",
|
|
f"{ICON}/svg/grafana.svg",
|
|
),
|
|
(
|
|
"Prometheus",
|
|
"Metrics",
|
|
"http://10.4.7.18:9090/",
|
|
"http://10.4.7.18:9090/",
|
|
f"{ICON}/svg/prometheus.svg",
|
|
),
|
|
# —— Overig ——
|
|
(
|
|
"BentoPDF",
|
|
"PDF tools",
|
|
"http://10.4.7.17:8080/",
|
|
"http://10.4.7.17:8080/",
|
|
f"{ICON}/svg/stirling-pdf.svg",
|
|
),
|
|
(
|
|
"Excalidraw",
|
|
"Whiteboard",
|
|
"http://10.4.7.16:3000/",
|
|
"http://10.4.7.16:3000/",
|
|
f"{ICON}/svg/excalidraw.svg",
|
|
),
|
|
]
|
|
|
|
# Volgorde op het board (namen)
|
|
BOARD_ORDER = [
|
|
"Foodlinkk Cockpit",
|
|
"Wereldexport",
|
|
"Voice Live",
|
|
"Herman Chat",
|
|
"Agents",
|
|
"Revenue Cockpit",
|
|
"Gitea",
|
|
"Proxmox",
|
|
"Synology NAS",
|
|
"Homarr",
|
|
"Dockhand",
|
|
"Herman Orchestrator",
|
|
"Open WebUI",
|
|
"Web Builder (agy)",
|
|
"Website Preview",
|
|
"Doc Ingest",
|
|
"Browser Use",
|
|
"n8n",
|
|
"ComfyUI",
|
|
"Browser VNC",
|
|
"MinIO",
|
|
"Grafana",
|
|
"Prometheus",
|
|
"BentoPDF",
|
|
"Excalidraw",
|
|
]
|
|
|
|
MOBILE_CSS = """
|
|
@media (max-width: 900px) {
|
|
html { font-size: 18px !important; }
|
|
[data-testid="app-tile"] { min-height: 72px !important; }
|
|
button, .mantine-Button-root { min-height: 44px !important; }
|
|
}
|
|
"""
|
|
|
|
|
|
def gen_id() -> str:
|
|
return "".join(random.choices(string.ascii_lowercase + string.digits, k=24))
|
|
|
|
|
|
def upsert_app(cur: sqlite3.Cursor, name: str, desc: str, href: str, ping: str | None, icon: str) -> str:
|
|
row = cur.execute("SELECT id FROM app WHERE name=?", (name,)).fetchone()
|
|
if row:
|
|
aid = row[0]
|
|
cur.execute(
|
|
"UPDATE app SET description=?, href=?, ping_url=?, icon_url=? WHERE id=?",
|
|
(desc, href, ping, icon, aid),
|
|
)
|
|
else:
|
|
aid = gen_id()
|
|
cur.execute(
|
|
"INSERT INTO app (id, name, description, icon_url, href, ping_url) VALUES (?,?,?,?,?,?)",
|
|
(aid, name, desc, icon, href, ping),
|
|
)
|
|
return aid
|
|
|
|
|
|
def main() -> None:
|
|
conn = sqlite3.connect(DB)
|
|
cur = conn.cursor()
|
|
|
|
cur.execute("UPDATE board SET custom_css=?, item_radius=? WHERE id=?", (MOBILE_CSS.strip(), "md", BOARD_ID))
|
|
cur.execute("UPDATE layout SET column_count=? WHERE id=?", (4, LAYOUT_ID))
|
|
|
|
name_to_id: dict[str, str] = {}
|
|
for name, desc, href, ping, icon in APPS:
|
|
name_to_id[name] = upsert_app(cur, name, desc, href, ping, icon)
|
|
|
|
# Verwijder oude board-tiles (behoud app-records)
|
|
old_items = [r[0] for r in cur.execute("SELECT id FROM item WHERE board_id=?", (BOARD_ID,)).fetchall()]
|
|
for iid in old_items:
|
|
cur.execute("DELETE FROM item_layout WHERE item_id=?", (iid,))
|
|
cur.execute("DELETE FROM item WHERE id=?", (iid,))
|
|
|
|
cols = 4
|
|
for slot, name in enumerate(BOARD_ORDER):
|
|
aid = name_to_id.get(name)
|
|
if not aid:
|
|
continue
|
|
item_id = gen_id()
|
|
opts = json.dumps(
|
|
{
|
|
"json": {
|
|
"appId": aid,
|
|
"openInNewTab": True,
|
|
"showTitle": True,
|
|
"pingEnabled": True,
|
|
}
|
|
}
|
|
)
|
|
cur.execute(
|
|
"INSERT INTO item (id, board_id, kind, options, advanced_options) VALUES (?,?,?,?,?)",
|
|
(item_id, BOARD_ID, "app", opts, "{}"),
|
|
)
|
|
x = slot % cols
|
|
y = slot // cols
|
|
cur.execute(
|
|
"""INSERT INTO item_layout
|
|
(item_id, section_id, layout_id, x_offset, y_offset, width, height)
|
|
VALUES (?,?,?,?,?,?,?)""",
|
|
(item_id, SECTION_ID, LAYOUT_ID, x, y, 1, 1),
|
|
)
|
|
|
|
conn.commit()
|
|
print(f"Board tiles: {len(BOARD_ORDER)}")
|
|
for name in BOARD_ORDER:
|
|
href = cur.execute("SELECT href FROM app WHERE name=?", (name,)).fetchone()
|
|
if href:
|
|
print(f" ✓ {name}: {href[0]}")
|
|
conn.close()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|