diff --git a/.gitignore b/.gitignore index 07d8b9a..91b8328 100644 --- a/.gitignore +++ b/.gitignore @@ -1,29 +1,342 @@ +# ============================================ +# Certigo Addon - Comprehensive .gitignore +# ============================================ + +# ============================================ +# Go / Backend +# ============================================ + +# Binaries and executables +*.exe +*.exe~ +*.dll +*.so +*.dylib +backend/bin/ +backend/myapp +backend/certigo-addon +backend/certigo-addon-* +/tmp/certigo-addon-* + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool +*.out +coverage.html +coverage.txt + +# Go workspace file +go.work +go.work.sum + +# Go module cache (optional, but recommended for CI/CD) +# .go/ + +# ============================================ +# Node.js / Frontend +# ============================================ + # Dependencies node_modules/ frontend/node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* # Build outputs dist/ +dist-ssr/ frontend/dist/ -backend/bin/ +*.local +# Vite +.vite/ +vite.config.js.timestamp-* +vite.config.ts.timestamp-* + +# Environment +.env +.env.local +.env.development.local +.env.test.local +.env.production.local +.env*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +# ============================================ # Database +# ============================================ + +# SQLite databases *.db +*.db-shm +*.db-wal *.sqlite *.sqlite3 backend/spaces.db +backend/*.db -# Environment variables -.env -.env.local +# Database backups +*.sql.backup +*.db.backup -# IDE +# ============================================ +# Uploads & User-generated Content +# ============================================ + +# User uploads (avatars, files, etc.) +backend/uploads/ +backend/uploads/** +!backend/uploads/.gitkeep +frontend/public/uploads/ + +# ============================================ +# Logs +# ============================================ + +logs/ +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* +backend/*.log + +# ============================================ +# IDE & Editors +# ============================================ + +# VSCode .vscode/ +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# IntelliJ IDEA / WebStorm .idea/ +*.iml +*.iws +*.ipr +out/ + +# Sublime Text +*.sublime-project +*.sublime-workspace + +# Vim *.swp *.swo +*~ +.vim/ -# OS +# Emacs +*~ +\#*\# +/.emacs.desktop +/.emacs.desktop.lock +*.elc +auto-save-list +tramp +.\#* + +# ============================================ +# OS Files +# ============================================ + +# macOS .DS_Store -Thumbs.db +.AppleDouble +.LSOverride +Icon +._* +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk +# Windows +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db +*.stackdump +[Dd]esktop.ini +$RECYCLE.BIN/ +*.cab +*.msi +*.msix +*.msm +*.msp +*.lnk + +# Linux +*~ +.fuse_hidden* +.directory +.Trash-* +.nfs* + +# ============================================ +# Temporary & Cache Files +# ============================================ + +# Temporary files +*.tmp +*.temp +*.bak +*.backup +*.swp +*~.nib +*.orig + +# Cache directories +.cache/ +.parcel-cache/ +.eslintcache +.stylelintcache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ +.node_repl_history +.yarn-integrity + +# ============================================ +# Testing & Coverage +# ============================================ + +# Test coverage +coverage/ +*.lcov +.nyc_output/ +.coverage/ +htmlcov/ +.pytest_cache/ +.tox/ + +# Jest +.jest/ + +# ============================================ +# Build Tools & CI/CD +# ============================================ + +# Build artifacts +build/ +out/ +target/ +.next/ +.nuxt/ +.cache/ + +# CI/CD +.github/workflows/*.yml.local +.circleci/ +.travis.yml.local + +# ============================================ +# Security & Secrets +# ============================================ + +# Secrets and credentials +*.pem +*.key +*.crt +*.cert +secrets/ +.secrets/ +*.secret +config/secrets.* + +# API keys and tokens +.env.secret +.env.production +.env.staging + +# ============================================ +# Documentation Build +# ============================================ + +# Generated documentation +docs/_build/ +site/ + +# ============================================ +# Misc +# ============================================ + +# Package manager lock files (optional - uncomment if you want to ignore) +# package-lock.json +# yarn.lock +# pnpm-lock.yaml + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env.development +.env.test +.env.production + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +# ============================================ +# Project-specific +# ============================================ + +# OpenAPI generated files (if any) +backend/generated/ +backend/api/ + +# Provider test outputs +backend/test-outputs/ + +# Script outputs +backend/scripts/output/ + +# Keep directory structure but ignore contents +!backend/uploads/.gitkeep +!backend/config/providers/.gitkeep diff --git a/backend/myapp b/backend/myapp deleted file mode 100755 index 60f232f..0000000 Binary files a/backend/myapp and /dev/null differ diff --git a/backend/spaces.db-shm b/backend/spaces.db-shm deleted file mode 100644 index 22d9bfb..0000000 Binary files a/backend/spaces.db-shm and /dev/null differ diff --git a/backend/spaces.db-wal b/backend/spaces.db-wal deleted file mode 100644 index 8b30f99..0000000 Binary files a/backend/spaces.db-wal and /dev/null differ diff --git a/backend/uploads/avatars/5ff86878-5277-4c18-af6b-1a63faaf3371.png b/backend/uploads/avatars/5ff86878-5277-4c18-af6b-1a63faaf3371.png deleted file mode 100644 index aaf893a..0000000 Binary files a/backend/uploads/avatars/5ff86878-5277-4c18-af6b-1a63faaf3371.png and /dev/null differ diff --git a/backend/uploads/avatars/7124facd-9b11-40d1-83b1-ca747f2a8b0f.png b/backend/uploads/avatars/7124facd-9b11-40d1-83b1-ca747f2a8b0f.png deleted file mode 100644 index d601cd8..0000000 Binary files a/backend/uploads/avatars/7124facd-9b11-40d1-83b1-ca747f2a8b0f.png and /dev/null differ diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index d030f7a..9de4620 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -1,7 +1,8 @@ import { useState } from 'react' import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom' import { AuthProvider, useAuth } from './contexts/AuthContext' -import { PermissionsProvider, usePermissions } from './contexts/PermissionsContext' +import { PermissionsProvider } from './contexts/PermissionsContext' +import { usePermissions } from './hooks/usePermissions' import Sidebar from './components/Sidebar' import Footer from './components/Footer' import Home from './pages/Home' diff --git a/frontend/src/components/Sidebar.jsx b/frontend/src/components/Sidebar.jsx index 9b7ce3a..a5968e5 100644 --- a/frontend/src/components/Sidebar.jsx +++ b/frontend/src/components/Sidebar.jsx @@ -1,6 +1,6 @@ import { Link, useLocation, useNavigate } from 'react-router-dom' import { useAuth } from '../contexts/AuthContext' -import { usePermissions } from '../contexts/PermissionsContext' +import { usePermissions } from '../hooks/usePermissions' import { useState, useEffect } from 'react' const Sidebar = ({ isOpen, setIsOpen }) => { diff --git a/frontend/src/hooks/usePermissions.js b/frontend/src/hooks/usePermissions.js new file mode 100644 index 0000000..dd61383 --- /dev/null +++ b/frontend/src/hooks/usePermissions.js @@ -0,0 +1 @@ +export { usePermissions } from '../contexts/PermissionsContext' \ No newline at end of file diff --git a/frontend/src/pages/Home.jsx b/frontend/src/pages/Home.jsx index 0bcf51e..c486274 100644 --- a/frontend/src/pages/Home.jsx +++ b/frontend/src/pages/Home.jsx @@ -1,7 +1,7 @@ import { useEffect, useState, useRef, useCallback } from 'react' import { useLocation } from 'react-router-dom' import { useAuth } from '../contexts/AuthContext' -import { usePermissions } from '../contexts/PermissionsContext' +import { usePermissions } from '../hooks/usePermissions' const Home = () => { const { authFetch } = useAuth() diff --git a/frontend/src/pages/Profile.jsx b/frontend/src/pages/Profile.jsx index ade551d..b5f1b63 100644 --- a/frontend/src/pages/Profile.jsx +++ b/frontend/src/pages/Profile.jsx @@ -1,6 +1,6 @@ import { useState, useEffect } from 'react' import { useAuth } from '../contexts/AuthContext' -import { usePermissions } from '../contexts/PermissionsContext' +import { usePermissions } from '../hooks/usePermissions' const Profile = () => { const { authFetch, user } = useAuth() diff --git a/frontend/src/pages/SpaceDetail.jsx b/frontend/src/pages/SpaceDetail.jsx index 353c5b3..62ed2ee 100644 --- a/frontend/src/pages/SpaceDetail.jsx +++ b/frontend/src/pages/SpaceDetail.jsx @@ -232,18 +232,50 @@ const SpaceDetail = () => { if (response.ok) { const csr = await response.json() - // Füge den neuen CSR zur History hinzu (nur wenn der Bereich bereits geöffnet ist) - if (showCSRDropdown[fqdn.id]) { - const newCsrWithFqdnId = { ...csr, fqdnId: fqdn.id } - setCsrHistory(prev => { - const filtered = prev.filter(csrItem => csrItem.fqdnId !== fqdn.id) - // Füge den neuen CSR am Anfang hinzu (neuester zuerst) - return [newCsrWithFqdnId, ...filtered] - }) - } - setCsrData(csr) setSelectedFqdn(fqdn) + + // Lade die komplette CSR History neu, um den neuen CSR anzuzeigen + // WICHTIG: Warte auf die History bevor der Dropdown geöffnet wird + try { + const historyResponse = await authFetch(`/api/spaces/${id}/fqdns/${fqdn.id}/csr`) + if (historyResponse.ok) { + const history = await historyResponse.json() + + // Stelle sicher, dass history ein Array ist + const historyArray = Array.isArray(history) ? history : [] + + // Füge fqdnId zu jedem CSR hinzu und stelle sicher dass sie immer gesetzt ist + // Auch wenn die API fqdnId bereits zurückgibt, überschreiben wir sie mit fqdn.id für Konsistenz + // Stelle sicher dass alle CSRs gültig sind und fqdnId gesetzt ist + const historyWithFqdnId = historyArray + .filter(csrItem => csrItem && csrItem.id) // Stelle sicher dass CSR gültig ist + .map(csrItem => ({ + ...csrItem, + fqdnId: String(fqdn.id) // Immer als String für konsistente Filterung + })) + + setCsrHistory(prev => { + // Entferne alte CSRs für diesen FQDN und füge die neuen hinzu + // Verwende String-Vergleich für Robustheit + const filtered = prev.filter(csrItem => String(csrItem?.fqdnId) !== String(fqdn.id)) + return [...filtered, ...historyWithFqdnId] + }) + + // Öffne den CSR History Dropdown NACH dem Laden der History + setShowCSRDropdown(prev => ({ ...prev, [fqdn.id]: true })) + } else { + setCsrHistory(prev => { + // Bei Fehler, entferne nur CSRs für diesen FQDN, behalte andere + return prev.filter(csrItem => String(csrItem?.fqdnId) !== String(fqdn.id)) + }) + } + } catch (err) { + console.error('Error fetching CSR history after upload:', err) + // Bei Fehler, entferne nur CSRs für diesen FQDN + setCsrHistory(prev => prev.filter(csrItem => String(csrItem?.fqdnId) !== String(fqdn.id))) + } + setShowCSRModal(true) // Aktualisiere die FQDN-Liste @@ -298,14 +330,23 @@ const SpaceDetail = () => { const historyResponse = await authFetch(`/api/spaces/${id}/fqdns/${fqdn.id}/csr`) if (historyResponse.ok) { const history = await historyResponse.json() - setCsrHistory(Array.isArray(history) ? history : []) + const historyArray = Array.isArray(history) ? history : [] + // Stelle sicher dass fqdnId gesetzt ist für konsistente Filterung + const historyWithFqdnId = historyArray + .filter(csr => csr && csr.id) + .map(csr => ({ ...csr, fqdnId: String(fqdn.id) })) + setCsrHistory(prev => { + const filtered = prev.filter(csr => String(csr?.fqdnId) !== String(fqdn.id)) + return [...filtered, ...historyWithFqdnId] + }) } else { - setCsrHistory([]) + setCsrHistory(prev => prev.filter(csr => String(csr?.fqdnId) !== String(fqdn.id))) } } catch (err) { console.error('Error fetching CSR:', err) setCsrData(null) - setCsrHistory([]) + // Entferne nur CSRs für diesen FQDN, behalte andere + setCsrHistory(prev => prev.filter(csr => String(csr?.fqdnId) !== String(fqdn.id))) } } @@ -319,7 +360,7 @@ const SpaceDetail = () => { setSelectedFqdn(null) setCsrData(null) setCsrError('') - setCsrHistory([]) + // csrHistory NICHT zurücksetzen - bleibt für Dropdown-Anzeige erhalten } const handleChange = (e) => { @@ -822,11 +863,12 @@ const SpaceDetail = () => { if (response.ok) { const history = await response.json() // Speichere History mit FQDN-ID als Key - const historyWithFqdnId = Array.isArray(history) - ? history.map(csr => ({ ...csr, fqdnId: fqdn.id })) - : [] + const historyArray = Array.isArray(history) ? history : [] + const historyWithFqdnId = historyArray + .filter(csr => csr && csr.id) + .map(csr => ({ ...csr, fqdnId: String(fqdn.id) })) setCsrHistory(prev => { - const filtered = prev.filter(csr => csr.fqdnId !== fqdn.id) + const filtered = prev.filter(csr => String(csr?.fqdnId) !== String(fqdn.id)) return [...filtered, ...historyWithFqdnId] }) } @@ -890,12 +932,13 @@ const SpaceDetail = () => {
CSR History
{(() => { + // Filtere CSRs für diesen FQDN - verwende String-Vergleich für Robustheit const fqdnHistory = csrHistory - .filter(csr => csr.fqdnId === fqdn.id) + .filter(csr => csr && String(csr.fqdnId) === String(fqdn.id)) .sort((a, b) => { // Sortiere nach created_at, neueste zuerst - const dateA = new Date(a.createdAt).getTime() - const dateB = new Date(b.createdAt).getTime() + const dateA = a.createdAt ? new Date(a.createdAt).getTime() : 0 + const dateB = b.createdAt ? new Date(b.createdAt).getTime() : 0 return dateB - dateA }) return fqdnHistory.length > 0 ? (