feat: click-drag drawing, layer tree, settings modal, UI improvements
- interaction: click-drag drawing for 2-point tools (line, rect, circle, dimension, leader) - interaction: preview rendering during drag with setPreviewElement - interaction: handleDrawDown only sets phase=drawing on first point - CanvasArea: sync activeLayerId to LayerManager - CanvasArea: callback refresh useEffect prevents stale closures - App.tsx: functional setElements updates for handleElementCreated/Deleted/Modified - LayerPanel: tree structure with sub-layers (onReorder, onAddSubLayer) - TreeView: drag-and-drop reordering support - RightSidebar: onReorder, onAddSubLayer, onUpdateElement props - PropertiesPanel: onUpdateElement prop - SettingsModal: personal/password/language/theme/users/plugins/AI tabs - styles.css: extensive UI styling additions - types: updated RightSidebarProps, CanvasAreaProps, LayerPanelProps
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Simple Forgejo push webhook receiver that triggers deploy.sh"""
|
||||
from http.server import HTTPServer, BaseHTTPRequestHandler
|
||||
import hmac, hashlib, subprocess, json, os, datetime
|
||||
|
||||
SECRET = os.environ.get("WEBHOOK_SECRET", "web-cad-neu-deploy-2026")
|
||||
DEPLOY_SCRIPT = "/data/web-cad-neu/deploy.sh"
|
||||
LOG_FILE = "/var/log/webhook-deploy.log"
|
||||
PORT = int(os.environ.get("WEBHOOK_PORT", "9876"))
|
||||
|
||||
class WebhookHandler(BaseHTTPRequestHandler):
|
||||
def do_POST(self):
|
||||
if self.path != "/webhook":
|
||||
self.send_response(404)
|
||||
self.end_headers()
|
||||
return
|
||||
|
||||
content_length = int(self.headers.get("Content-Length", 0))
|
||||
body = self.rfile.read(content_length)
|
||||
|
||||
# Verify signature
|
||||
signature = self.headers.get("X-Gitea-Signature", "")
|
||||
computed = hmac.new(SECRET.encode(), body, hashlib.sha256).hexdigest()
|
||||
|
||||
if not hmac.compare_digest(signature, computed):
|
||||
self.send_response(403)
|
||||
self.end_headers()
|
||||
self.wfile.write(b"Invalid signature")
|
||||
return
|
||||
|
||||
# Parse event
|
||||
event = self.headers.get("X-Gitea-Event", "")
|
||||
if event != "push":
|
||||
self.send_response(200)
|
||||
self.end_headers()
|
||||
self.wfile.write(b"Ignored: not a push event")
|
||||
return
|
||||
|
||||
payload = json.loads(body)
|
||||
ref = payload.get("ref", "")
|
||||
if ref != "refs/heads/main":
|
||||
self.send_response(200)
|
||||
self.end_headers()
|
||||
self.wfile.write(b"Ignored: not main branch")
|
||||
return
|
||||
|
||||
# Trigger deploy in background
|
||||
ts = datetime.datetime.now().isoformat()
|
||||
self.log_msg(f"[{ts}] Push to main detected, triggering deploy...")
|
||||
subprocess.Popen(
|
||||
["bash", DEPLOY_SCRIPT],
|
||||
stdout=open(LOG_FILE, "a"),
|
||||
stderr=subprocess.STDOUT
|
||||
)
|
||||
|
||||
self.send_response(200)
|
||||
self.end_headers()
|
||||
self.wfile.write(b"Deploy triggered")
|
||||
|
||||
def log_msg(self, msg):
|
||||
with open(LOG_FILE, "a") as f:
|
||||
f.write(msg + "\n")
|
||||
|
||||
if __name__ == "__main__":
|
||||
server = HTTPServer(("0.0.0.0", PORT), WebhookHandler)
|
||||
print(f"Webhook receiver listening on port {PORT}")
|
||||
server.serve_forever()
|
||||
Reference in New Issue
Block a user