Add API req to create new app/section

This commit is contained in:
dvirlabs 2025-06-03 06:55:28 +03:00
parent 59027c9ba6
commit 57d1156425
6 changed files with 101 additions and 27 deletions

View File

@ -1,24 +1,26 @@
- name: Gitea sections:
url: https://git.dvirlabs.com - apps:
icon: http://192.168.10.118:1111/icons/gitea.svg - description: Dashboards
description: Git server
- name: Grafana
url: https://grafana.dvirlabs.com
icon: http://192.168.10.118:1111/icons/grafana.svg icon: http://192.168.10.118:1111/icons/grafana.svg
description: Dashboards name: Grafana
url: https://grafana.dvirlabs.com
- name: Prometheus - description: Monitoring
url: https://prometheus.dvirlabs.com
icon: http://192.168.10.118:1111/icons/prometheus.svg icon: http://192.168.10.118:1111/icons/prometheus.svg
description: Monitoring name: Prometheus
url: https://prometheus.dvirlabs.com
- name: Harbor name: Monitoring
url: https://harbor.dvirlabs.com - apps:
- description: Git server
icon: http://192.168.10.118:1111/icons/gitea.svg
name: Gitea
url: https://git.dvirlabs.com
- description: Container registry
icon: http://192.168.10.118:1111/icons/harbor.svg icon: http://192.168.10.118:1111/icons/harbor.svg
description: Container registry name: Harbor
url: https://harbor.dvirlabs.com
- name: Woodpecker - description: CI/CD
url: https://woodpecker.dvirlabs.com
icon: http://192.168.10.118:1111/icons/woodpecker-ci.svg icon: http://192.168.10.118:1111/icons/woodpecker-ci.svg
description: CI/CD name: Woodpecker
url: https://woodpecker.dvirlabs.com
name: Dev-tools

View File

@ -2,6 +2,8 @@ from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.cors import CORSMiddleware
import yaml import yaml
from pathlib import Path from pathlib import Path
from pydantic import BaseModel
app = FastAPI() app = FastAPI()
# Allow CORS for all origins # Allow CORS for all origins
@ -27,6 +29,47 @@ def get_apps():
with open(APPS_FILE, "r") as f: with open(APPS_FILE, "r") as f:
return yaml.safe_load(f) return yaml.safe_load(f)
class AppEntry(BaseModel):
section: str
name: str
icon: str
description: str
url: str
@app.post("/add_app")
def add_app(entry: AppEntry):
if not APPS_FILE.exists():
current = {"sections": []}
else:
with open(APPS_FILE, "r") as f:
current = yaml.safe_load(f) or {"sections": []}
# Find or create section
for section in current["sections"]:
if section["name"] == entry.section:
section["apps"].append({
"name": entry.name,
"icon": entry.icon,
"description": entry.description,
"url": entry.url,
})
break
else:
current["sections"].append({
"name": entry.section,
"apps": [{
"name": entry.name,
"icon": entry.icon,
"description": entry.description,
"url": entry.url,
}]
})
with open(APPS_FILE, "w") as f:
yaml.safe_dump(current, f)
return {"status": "added"}
if __name__ == "__main__": if __name__ == "__main__":
import uvicorn import uvicorn
uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True) uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)

View File

@ -1,20 +1,22 @@
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import './App.css'; import './App.css';
import AppGrid from './components/AppGrid'; import SectionGrid from './components/SectionGrid';
function App() { function App() {
const [apps, setApps] = useState([]); const [sections, setSections] = useState([]);
useEffect(() => { useEffect(() => {
fetch('/apps') fetch('/apps')
.then(res => res.json()) .then(res => res.json())
.then(data => setApps(data)); .then(data => setSections(data.sections || []));
}, []); }, []);
return ( return (
<div className="App"> <div className="App">
<h1 className="main-title">🔷 Navix</h1> <h1 className="main-title">🔷 Navix</h1>
<AppGrid apps={apps} /> {sections.map((section) => (
<SectionGrid key={section.name} section={section} />
))}
</div> </div>
); );
} }

View File

@ -0,0 +1,13 @@
import AppGrid from './AppGrid';
import '../style/SectionGrid.css';
function SectionGrid({ section }) {
return (
<div className="section">
<h2 className="section-title">{section.name}</h2>
<AppGrid apps={section.apps} />
</div>
);
}
export default SectionGrid;

View File

@ -0,0 +1,14 @@
.section {
margin-bottom: 3rem;
width: 100%;
max-width: 1000px;
}
.section-title {
font-size: 1.5rem;
color: #ffffff;
margin-bottom: 1rem;
border-bottom: 1px solid #444;
padding-bottom: 0.5rem;
text-align: left;
}