diff --git a/.woodpecker.yaml b/.woodpecker.yaml index 47f62a2..7a354da 100644 --- a/.woodpecker.yaml +++ b/.woodpecker.yaml @@ -14,7 +14,7 @@ steps: - echo "TAGS=latest,$TAG_DATE-$SHORT_SHA" > .tags.env - name: build-frontend - image: woodpeckerci/plugin-docker + image: woodpeckerci/plugin-docker-buildx settings: repo: harbor.dvirlabs.com/my-apps/navix-frontend tag_file: .tags.env @@ -27,7 +27,7 @@ steps: from_secret: harbor_password - name: build-backend - image: woodpeckerci/plugin-docker + image: woodpeckerci/plugin-docker-buildx settings: repo: harbor.dvirlabs.com/my-apps/navix-backend tag_file: .tags.env diff --git a/backend/.env b/backend/.env new file mode 100644 index 0000000..901386b --- /dev/null +++ b/backend/.env @@ -0,0 +1,4 @@ +MINIO_ACCESS_KEY=TDJvsBmbkpUXpCw5M7LA +MINIO_SECRET_KEY=n9scR7W0MZy6FF0bznV98fSgXpdebIQjqZvEr1Yu +MINIO_ENDPOINT=s3.dvirlabs.com +MINIO_BUCKET=navix-icons \ No newline at end of file diff --git a/backend/__pycache__/main.cpython-312.pyc b/backend/__pycache__/main.cpython-312.pyc new file mode 100644 index 0000000..1d80115 Binary files /dev/null and b/backend/__pycache__/main.cpython-312.pyc differ diff --git a/backend/apps.yaml b/backend/apps.yaml index 120f639..5d815ea 100644 --- a/backend/apps.yaml +++ b/backend/apps.yaml @@ -1,27 +1,25 @@ sections: - apps: - description: Dashboards - icon: http://192.168.10.118:1111/icons/grafana.svg + icon: grafana.svg name: Grafana url: https://grafana.dvirlabs.com - description: Monitoring - icon: http://192.168.10.118:1111/icons/prometheus.svg + icon: prometheus.svg name: Prometheus url: https://prometheus.dvirlabs.com name: Monitoring - apps: - description: Git server - icon: http://192.168.10.118:1111/icons/gitea.svg + icon: gitea.svg name: Gitea url: https://git.dvirlabs.com - description: Container registry - icon: http://192.168.10.118:1111/icons/harbor.svg + icon: harbor.svg name: Harbor url: https://harbor.dvirlabs.com - description: CI/CD - icon: http://192.168.10.118:1111/icons/woodpecker-ci.svg + icon: woodpecker-ci.svg name: Woodpecker url: https://woodpecker.dvirlabs.com - name: Dev-tools - - + name: Dev-tools \ No newline at end of file diff --git a/backend/main.py b/backend/main.py index 51ad3d0..7f6354f 100644 --- a/backend/main.py +++ b/backend/main.py @@ -1,8 +1,13 @@ from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware +from fastapi.responses import JSONResponse +import os +from dotenv import load_dotenv import yaml from pathlib import Path from pydantic import BaseModel +from minio import Minio +from datetime import timedelta app = FastAPI() @@ -15,6 +20,24 @@ app.add_middleware( allow_headers=["*"], ) +load_dotenv() + +# Load ENV variables +MINIO_ENDPOINT = os.getenv("MINIO_ENDPOINT") +MINIO_ACCESS_KEY = os.getenv("MINIO_ACCESS_KEY") +MINIO_SECRET_KEY = os.getenv("MINIO_SECRET_KEY") +MINIO_BUCKET = os.getenv("MINIO_BUCKET") + +# MinIO connection with access and secret keys +minio_client = Minio( + MINIO_ENDPOINT, + access_key=MINIO_ACCESS_KEY, + secret_key=MINIO_SECRET_KEY, + secure=True +) + +BUCKET = "navix-icons" + @app.get("/") async def root(): return {"message": "Welcome to the FastAPI application!"} @@ -63,6 +86,12 @@ def add_app(entry: AppEntry): return {"status": "added"} +@app.get("/icon/{filename}") +def get_public_icon_url(filename: str): + url = f"https://{MINIO_ENDPOINT}/{MINIO_BUCKET}/{filename}" + return JSONResponse(content={"url": url}) + + if __name__ == "__main__": import uvicorn diff --git a/frontend/src/components/AppCard.jsx b/frontend/src/components/AppCard.jsx index 95cebe9..9fe7f08 100644 --- a/frontend/src/components/AppCard.jsx +++ b/frontend/src/components/AppCard.jsx @@ -1,14 +1,37 @@ +import { useEffect, useState } from 'react'; import '../style/AppCard.css'; +import { getIconUrl } from '../services/api'; function AppCard({ app }) { + const [iconUrl, setIconUrl] = useState(null); + + useEffect(() => { + if (app.icon) { + getIconUrl(app.icon) + .then((url) => { + console.log('Presigned icon URL for', app.name, ':', url); + setIconUrl(url); + }) + .catch((err) => { + console.error(`Failed to load icon for ${app.name}:`, err); + }); + } +}, [app.icon, app.name]); + return ( - -
- {app.name} -
-

{app.name}

-

{app.description}

-
+
+ +
+ {iconUrl ? ( + {app.name} + ) : ( + ⚠️ + )} +
+

{app.name}

+

{app.description}

+
+
); } diff --git a/frontend/src/services/api.js b/frontend/src/services/api.js index 290463b..d9929ed 100644 --- a/frontend/src/services/api.js +++ b/frontend/src/services/api.js @@ -12,4 +12,11 @@ export async function addAppToSection({ section, app }) { }); if (!res.ok) throw new Error(await res.text()); return res.json(); -} \ No newline at end of file +} + +export async function getIconUrl(filename) { + const res = await fetch(`/icon/${filename}`); + if (!res.ok) throw new Error(`Failed to fetch icon for ${filename}`); + const data = await res.json(); + return data.url; // ✅ must return the actual URL string +} diff --git a/frontend/vite.config.js b/frontend/vite.config.js index 04886e1..ea8be0a 100644 --- a/frontend/vite.config.js +++ b/frontend/vite.config.js @@ -8,6 +8,7 @@ export default defineConfig({ proxy: { '/apps': 'http://localhost:8000', '/add_app': 'http://localhost:8000', + '/icon': 'http://localhost:8000', } } });