From b4758b4f26524b731ea48ad1ec4ae4603a02580f Mon Sep 17 00:00:00 2001 From: Johannes Date: Sun, 7 Sep 2025 11:05:29 +0200 Subject: [PATCH] security: clean repository without media files and sensitive data - Removed area/ directory with 816MB of media files - Removed sensitive FTP credentials from Git history - Implemented .env.upload system for secure deployments - Added comprehensive .gitignore for future protection This commit represents a clean slate with all sensitive data removed. --- .gitignore | 40 + .gitignore-temp | 40 + DEPLOYMENT.md | 228 + .../2025-09-07/09-56-59/cache-stats.txt | 4 + .../2025-09-07/09-56-59/changed-files.txt | 4 + .../09-56-59/object-id-map.old-new.txt | 13 + backend/public/.htaccess | 27 + backend/public/.nginx | 46 + backend/public/asset-manifest.json | 13 + backend/public/files.php | 17 + backend/public/index.html | 1 + backend/public/index.php | 33 + backend/public/static/css/main.7b221a61.css | 2 + .../public/static/css/main.7b221a61.css.map | 1 + backend/public/static/js/main.f30d7548.js | 3 + .../static/js/main.f30d7548.js.LICENSE.txt | 157 + backend/public/static/js/main.f30d7548.js.map | 1 + backend/src/Api/AuthController.php | 30 + backend/src/Api/EntityController.php | 197 + backend/src/Api/ProjectsController.php | 792 + backend/src/Api/UserController.php | 184 + backend/src/Core/Application.php | 8 + backend/src/Core/Router.php | 258 + backend/src/Helper/Helper.php | 12 + backend/src/Services/AuthService.php | 70 + backend/src/Services/JsonStorageService.php | 23 + backend/storage/.htaccess | 11 + backend/storage/data/admins.json | 20 + backend/storage/data/clients.json | 318 + backend/storage/data/viewers.json | 7 + deployment/nginx/README.md | 45 + .../nginx/adspreview-react.example.conf | 121 + deployment/scripts/.env.upload.example | 20 + deployment/scripts/README.md | 107 + deployment/scripts/deploy.sh | 97 + deployment/scripts/setup.sh | 52 + deployment/scripts/upload.sh | 90 + frontend/.env.development | 2 + frontend/.env.production | 10 + frontend/package-lock.json | 18541 ++++++++++++++++ frontend/package.json | 38 + frontend/public/index.html | 11 + frontend/src/App.js | 132 + frontend/src/components/ClientsManagement.js | 29 + frontend/src/components/FilePreview.js | 184 + frontend/src/components/SmartProjectRoute.js | 106 + frontend/src/components/UserManagement.js | 405 + frontend/src/components/UserMenu.js | 88 + frontend/src/global.css | 17 + frontend/src/index.js | 12 + frontend/src/pages/AdminDashboard.js | 47 + frontend/src/pages/ClientProjects.js | 303 + frontend/src/pages/LoginPage.js | 78 + frontend/src/pages/ProjectDetail.js | 320 + frontend/src/services/api.js | 7 + frontend/src/services/entityService.js | 42 + frontend/src/services/projectService.js | 6 + frontend/src/services/urlResolutionService.js | 147 + frontend/src/services/userService.js | 14 + frontend/src/utils/debugLogger.example.js | 77 + frontend/src/utils/debugLogger.js | 121 + 61 files changed, 23829 insertions(+) create mode 100644 .gitignore create mode 100644 .gitignore-temp create mode 100644 DEPLOYMENT.md create mode 100644 adspreview_react.bfg-report/2025-09-07/09-56-59/cache-stats.txt create mode 100644 adspreview_react.bfg-report/2025-09-07/09-56-59/changed-files.txt create mode 100644 adspreview_react.bfg-report/2025-09-07/09-56-59/object-id-map.old-new.txt create mode 100755 backend/public/.htaccess create mode 100644 backend/public/.nginx create mode 100755 backend/public/asset-manifest.json create mode 100644 backend/public/files.php create mode 100644 backend/public/index.html create mode 100755 backend/public/index.php create mode 100644 backend/public/static/css/main.7b221a61.css create mode 100755 backend/public/static/css/main.7b221a61.css.map create mode 100644 backend/public/static/js/main.f30d7548.js create mode 100755 backend/public/static/js/main.f30d7548.js.LICENSE.txt create mode 100755 backend/public/static/js/main.f30d7548.js.map create mode 100644 backend/src/Api/AuthController.php create mode 100644 backend/src/Api/EntityController.php create mode 100644 backend/src/Api/ProjectsController.php create mode 100644 backend/src/Api/UserController.php create mode 100644 backend/src/Core/Application.php create mode 100644 backend/src/Core/Router.php create mode 100644 backend/src/Helper/Helper.php create mode 100644 backend/src/Services/AuthService.php create mode 100644 backend/src/Services/JsonStorageService.php create mode 100644 backend/storage/.htaccess create mode 100644 backend/storage/data/admins.json create mode 100644 backend/storage/data/clients.json create mode 100644 backend/storage/data/viewers.json create mode 100644 deployment/nginx/README.md create mode 100644 deployment/nginx/adspreview-react.example.conf create mode 100644 deployment/scripts/.env.upload.example create mode 100644 deployment/scripts/README.md create mode 100755 deployment/scripts/deploy.sh create mode 100755 deployment/scripts/setup.sh create mode 100755 deployment/scripts/upload.sh create mode 100644 frontend/.env.development create mode 100644 frontend/.env.production create mode 100644 frontend/package-lock.json create mode 100644 frontend/package.json create mode 100644 frontend/public/index.html create mode 100644 frontend/src/App.js create mode 100644 frontend/src/components/ClientsManagement.js create mode 100644 frontend/src/components/FilePreview.js create mode 100644 frontend/src/components/SmartProjectRoute.js create mode 100644 frontend/src/components/UserManagement.js create mode 100644 frontend/src/components/UserMenu.js create mode 100644 frontend/src/global.css create mode 100644 frontend/src/index.js create mode 100644 frontend/src/pages/AdminDashboard.js create mode 100644 frontend/src/pages/ClientProjects.js create mode 100644 frontend/src/pages/LoginPage.js create mode 100644 frontend/src/pages/ProjectDetail.js create mode 100644 frontend/src/services/api.js create mode 100644 frontend/src/services/entityService.js create mode 100644 frontend/src/services/projectService.js create mode 100644 frontend/src/services/urlResolutionService.js create mode 100644 frontend/src/services/userService.js create mode 100644 frontend/src/utils/debugLogger.example.js create mode 100644 frontend/src/utils/debugLogger.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8dbe0c8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,40 @@ +# OS files +.DS_Store +Thumbs.db + +# Dependencies +node_modules/ +vendor/ + +# Environment files +.env +.env.local +.env.production +.env.upload + +# Build artifacts +/backend/public/static/ +/frontend/build/ +/build_temp/ + +# Log files +*.log + +# Temporary files +*.tmp +*.temp + +# Media files +area/ + +# Cache files +*.cache + +# IDE files +.vscode/ +.idea/ +*.swp +*.swo + +# Deployment +.env.upload diff --git a/.gitignore-temp b/.gitignore-temp new file mode 100644 index 0000000..8dbe0c8 --- /dev/null +++ b/.gitignore-temp @@ -0,0 +1,40 @@ +# OS files +.DS_Store +Thumbs.db + +# Dependencies +node_modules/ +vendor/ + +# Environment files +.env +.env.local +.env.production +.env.upload + +# Build artifacts +/backend/public/static/ +/frontend/build/ +/build_temp/ + +# Log files +*.log + +# Temporary files +*.tmp +*.temp + +# Media files +area/ + +# Cache files +*.cache + +# IDE files +.vscode/ +.idea/ +*.swp +*.swo + +# Deployment +.env.upload diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md new file mode 100644 index 0000000..80ad0a0 --- /dev/null +++ b/DEPLOYMENT.md @@ -0,0 +1,228 @@ +# 🚀 Deployment Guide + +## 🏠 Lokale Entwicklungsumgebung + +### Voraussetzungen +- **Node.js 16+** und **npm** +- **PHP 8.0+** (fĂŒr lokalen Backend-Server) +- **Git** (fĂŒr Versionskontrolle) + +### Projekt Setup +```bash +# Repository klonen +git clone +cd adspreview_react + +# Frontend Dependencies installieren +cd frontend/ +npm install +``` + +### Lokalen Development Server starten +```bash +# Im frontend/ Ordner +npm run start:all +``` + +Dieser Befehl startet **beide Server gleichzeitig**: +- **React Development Server**: http://localhost:3000 +- **PHP Backend Server**: http://localhost:8000 + +### Was passiert beim `npm run start:all`? +- Startet React App mit Live-Reload auf Port 3000 +- Startet PHP Built-in Server auf Port 8000 fĂŒr das Backend +- Verwendet `concurrently` um beide Prozesse parallel zu verwalten +- React App ist ĂŒber Proxy mit PHP Backend verbunden + +### Entwicklungsumgebung Features +- ✅ **Hot Reload**: Änderungen werden sofort sichtbar +- ✅ **API Proxy**: React App kommuniziert automatisch mit PHP Backend +- ✅ **Echte Daten**: Verwendet lokale JSON-Dateien als Datenbank +- ✅ **Debugging**: Console-Logs und Entwicklertools verfĂŒgbar + +### Lokale URLs +- **Frontend**: http://localhost:3000 (React App) +- **Backend API**: http://localhost:8000/api/* (PHP Endpoints) +- **Files**: http://localhost:8000/area/* (Projekt-Dateien) + +### Stoppen der Entwicklungsserver +DrĂŒcke `Ctrl+C` im Terminal um beide Server zu stoppen. + +--- + +## Webspace Anforderungen + +### ✅ Minimum Requirements +- **PHP 8.3+** +- **500 MB+ Speicherplatz** (je nach ProjektgrĂ¶ĂŸe) +- **Schreibrechte** fĂŒr PHP (fĂŒr Storage-Ordner) +- **URL Rewriting** (mod_rewrite fĂŒr Apache) + +### 📁 Webspace Struktur +``` +public_html/ (oder htdocs/) +├── index.html # React App Entry Point +├── static/ # CSS, JS, Media Files +├── area/ # Client Project Files +│ ├── Paramount/ +│ ├── Studiocanal/ +│ └── project_order.json +├── api/ # PHP Backend +├── storage/ # User Data (needs write permissions!) +│ └── data/ +│ ├── admins.json +│ ├── viewers.json +│ └── clients.json +└── vendor/ # PHP Dependencies +``` + +## 🔧 Deployment Prozess + +### 1. Setup (einmalig) +```bash +cd deployment/scripts/ +./setup.sh +``` + +### 2. Production Build erstellen +```bash +cd deployment/scripts/ +./deploy.sh +``` + +### 3. Upload auf Webspace +```bash +cd deployment/scripts/ + +#### Option A: FTP Client (FileZilla, WinSCP, etc.) +1. Öffne deinen FTP Client +2. Verbinde zu deinem Webspace +3. Navigiere zu `public_html/` oder `htdocs/` +4. Uploade den kompletten Inhalt von `backend/` + +#### Option B: Command Line (automatisiert) +```bash +cd scripts/ +nano upload.sh # Konfiguriere FTP-Zugangsdaten +./upload.sh +``` + +### 4. Webspace Konfiguration + +#### .htaccess fĂŒr URL Rewriting +Erstelle eine `.htaccess` Datei im Root-Verzeichnis: +```apache +RewriteEngine On + +# API Routes zu index.php weiterleiten +RewriteCond %{REQUEST_URI} ^/api/ +RewriteRule ^(.*)$ index.php [QSA,L] + +# React Router: Alle anderen Requests zu index.html +RewriteCond %{REQUEST_FILENAME} !-f +RewriteCond %{REQUEST_FILENAME} !-d +RewriteRule . index.html [L] +``` + +#### Ordner-Berechtigungen setzen +```bash +# Via FTP Client oder SSH +chmod 755 storage/ +chmod 755 storage/data/ +chmod 644 storage/data/*.json +``` + +## 🔒 Sicherheit + +### Sensible Dateien schĂŒtzen +Erstelle `.htaccess` in `storage/`: +```apache +# Zugriff auf Storage-Dateien verbieten + + Order allow,deny + Deny from all + +``` + +### Environment Variablen (optional) +Erstelle `.env` im Backend-Root: +``` +BACKEND_URL=https://deine-domain.de +JWT_SECRET=dein-super-sicherer-schlĂŒssel +``` + +## 🎯 Live-Betrieb + +### Domain Setup +- **Subdomain**: `adspreview.deine-domain.de` +- **Hauptdomain**: `deine-domain.de/adspreview/` + +### SSL/HTTPS +- Aktiviere SSL in deinem Webspace-Panel +- Moderne Browser benötigen HTTPS fĂŒr JWT-Tokens + +### Backup Strategy +```bash +# RegelmĂ€ĂŸige Backups der User-Daten +tar -czf backup_$(date +%Y%m%d).tar.gz storage/data/ area/ +``` + +## đŸ› ïž Troubleshooting + +### HĂ€ufige Probleme: + +1. **"404 Not Found" bei API-Calls** + → PrĂŒfe URL Rewriting (.htaccess) + +2. **"Permission denied" beim Login** + → PrĂŒfe Schreibrechte auf storage/ + +3. **React App lĂ€dt nicht** + → PrĂŒfe BACKEND_URL in der Konfiguration + +4. **Uploads funktionieren nicht** + → PrĂŒfe PHP upload_max_filesize und post_max_size + +### Debug-Modus aktivieren +In `backend/public/index.php`: +```php +// TemporĂ€r fĂŒr Debugging +error_reporting(E_ALL); +ini_set('display_errors', 1); +``` + +## 📊 Performance Optimierung + +### Gzip Compression +In `.htaccess`: +```apache +# Komprimierung aktivieren + + AddOutputFilterByType DEFLATE text/html text/css text/javascript application/javascript application/json + +``` + +### Caching Headers +```apache +# Browser-Caching fĂŒr statische Dateien + + ExpiresActive on + ExpiresByType text/css "access plus 1 month" + ExpiresByType application/javascript "access plus 1 month" + ExpiresByType image/png "access plus 1 month" + ExpiresByType image/jpg "access plus 1 month" + +``` + +## ✅ Deployment Checklist + +- [ ] PHP 8.3+ verfĂŒgbar +- [ ] Skripte ausgefĂŒhrt (`setup.sh` → `deploy.sh`) +- [ ] Backend-Ordner hochgeladen +- [ ] .htaccess konfiguriert +- [ ] Berechtigungen gesetzt +- [ ] SSL aktiviert +- [ ] Admin-User angelegt +- [ ] Test-Login erfolgreich + +**Anwendung ist live! 🎉** diff --git a/adspreview_react.bfg-report/2025-09-07/09-56-59/cache-stats.txt b/adspreview_react.bfg-report/2025-09-07/09-56-59/cache-stats.txt new file mode 100644 index 0000000..a7c2dc4 --- /dev/null +++ b/adspreview_react.bfg-report/2025-09-07/09-56-59/cache-stats.txt @@ -0,0 +1,4 @@ +(apply,CacheStats{hitCount=17, missCount=14, loadSuccessCount=14, loadExceptionCount=0, totalLoadTime=4444978210, evictionCount=0}) +(tree,CacheStats{hitCount=18, missCount=585, loadSuccessCount=554, loadExceptionCount=0, totalLoadTime=7468960507, evictionCount=0}) +(commit,CacheStats{hitCount=6, missCount=7, loadSuccessCount=7, loadExceptionCount=0, totalLoadTime=567782542, evictionCount=0}) +(tag,CacheStats{hitCount=0, missCount=0, loadSuccessCount=0, loadExceptionCount=0, totalLoadTime=0, evictionCount=0}) diff --git a/adspreview_react.bfg-report/2025-09-07/09-56-59/changed-files.txt b/adspreview_react.bfg-report/2025-09-07/09-56-59/changed-files.txt new file mode 100644 index 0000000..8cba8e4 --- /dev/null +++ b/adspreview_react.bfg-report/2025-09-07/09-56-59/changed-files.txt @@ -0,0 +1,4 @@ +fb91d2f9bbdc5d37217fe0c09be4713514515eca c06c8e9aa26a5e2bfc25bf3b4995b2b04ba68b1d server.txt +7466996e82872e83db22590f6682ee4e0cd02c70 e6a7b552b6e6a65260b43f7e8bfe2d353c6e7c8b server_backup.txt +0818c194d21a7187f40079014d35eb9002486f18 6d3e3054071ab8691bb1a19d70762e7a9f23650d server_working_partly.txt +9a02a4aed4f87e38d877511d6fe7d8df254c0cbd 58315c207f4d3379e3f638d396f495a443e96f65 upload.sh diff --git a/adspreview_react.bfg-report/2025-09-07/09-56-59/object-id-map.old-new.txt b/adspreview_react.bfg-report/2025-09-07/09-56-59/object-id-map.old-new.txt new file mode 100644 index 0000000..be7526b --- /dev/null +++ b/adspreview_react.bfg-report/2025-09-07/09-56-59/object-id-map.old-new.txt @@ -0,0 +1,13 @@ +0eedb990cf6e47c1bd9a6ee27d38e61093db4122 cec05d0919edf8a469de3d1d825d24ea8f7f82ff +1341c662138a88b42ff9b2e67f361d6e64114e72 f544e2074298e881b0e80d2e2a464548bf9a66b0 +1cde4d0b22533a0c673f3e4a35184aa50a76990b 7b8e13d76c3d1d4a663a1e3965d68ad36d4a5686 +25e309a0fc1438496972eb8d431cb47f2b077783 392f3ffacf5c410d10c713a3794baad5c60299a8 +30ace6cd8f71848b82b666473698a03f3102c346 3091f3ce2e6db63d6b064b4249578049d13abcd7 +424ef9061dcec9cb8c028c1a9fff4b538e402e68 2a9adb742a2dd42edf0b25ade4a90b866365c0a6 +5a68286a243579bb85fd14fbf133ee5403691285 20b66d360f056b1db42df69887b01a45c90a3ab0 +7a5d9fe6afad98dd5d38c367f3c6af2a1095fb6b e011d5b3cd3dd568d9d88116d49a0357cd6fea03 +a7b9708fb7189f208c118542cbd806ed74b444d8 7495b7c1db71f839345fd792d5fcb5927587c435 +d056c48b93fa218e08229f8198b1af8241f0f7b6 1dbc47a4499966ca4f320b07965e5a0f44e7f6d1 +d631fdc8e04b573eda04c877a96ebdb2f28a2db5 eacedf125866d78e85df3a7ddc2e0e23da1b39e2 +f381b65f0fe38f35531cfa9a83c3b06f0f3c0d6b ff2d7928b74714d6c5e2d1eb9fccdc8dd942b8f9 +f99c729712a7235166507eb36ec1851f8453a0ac 72dd450b1f30d5695cfbba5487969f1d4b2b1dea diff --git a/backend/public/.htaccess b/backend/public/.htaccess new file mode 100755 index 0000000..df030f1 --- /dev/null +++ b/backend/public/.htaccess @@ -0,0 +1,27 @@ +RewriteEngine On + +# API Routes zu index.php weiterleiten +RewriteCond %{REQUEST_URI} ^/api/ +RewriteRule ^(.*)$ index.php [QSA,L] + +# React Router: Alle anderen Requests zu index.html (außer existierende Dateien) +RewriteCond %{REQUEST_FILENAME} !-f +RewriteCond %{REQUEST_FILENAME} !-d +RewriteCond %{REQUEST_URI} !^/area/ +RewriteRule . index.html [L] + +# Optional: Gzip Komprimierung + + AddOutputFilterByType DEFLATE text/html text/css text/javascript application/javascript application/json + + +# Optional: Browser Caching + + ExpiresActive on + ExpiresByType text/css "access plus 1 month" + ExpiresByType application/javascript "access plus 1 month" + ExpiresByType image/png "access plus 1 month" + ExpiresByType image/jpg "access plus 1 month" + ExpiresByType image/jpeg "access plus 1 month" + ExpiresByType image/webp "access plus 1 month" + diff --git a/backend/public/.nginx b/backend/public/.nginx new file mode 100644 index 0000000..2ee4b45 --- /dev/null +++ b/backend/public/.nginx @@ -0,0 +1,46 @@ +# nginx Konfiguration fĂŒr React + PHP Backend +# Diese Datei sollte als .nginx im public/ Verzeichnis liegen + +# API-Routen an PHP weiterleiten +location /api/ { + try_files $uri /index.php?$args; +} + +# Area-Dateien an PHP weiterleiten (fĂŒr statische Asset-Auslieferung) +location /area/ { + try_files $uri /index.php?$args; +} + +# Statische React Assets direkt ausliefern +location /static/ { + expires 1y; + add_header Cache-Control "public, immutable"; + add_header Access-Control-Allow-Origin "*"; + try_files $uri =404; +} + +# React Assets (JSON, ICO, etc.) +location ~* \.(json|ico|txt)$ { + expires 1d; + add_header Access-Control-Allow-Origin "*"; + try_files $uri =404; +} + +# PHP-Dateien verarbeiten +location ~ \.php$ { + include fastcgi_params; + fastcgi_intercept_errors on; + fastcgi_index index.php; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + try_files $uri =404; + fastcgi_read_timeout 3600; + fastcgi_send_timeout 3600; + fastcgi_param HTTPS "on"; + fastcgi_param SERVER_PORT 443; + fastcgi_pass 127.0.0.1:9000; +} + +# React SPA Fallback - alle anderen Routen auf index.html weiterleiten +location / { + try_files $uri $uri/ /index.html; +} diff --git a/backend/public/asset-manifest.json b/backend/public/asset-manifest.json new file mode 100755 index 0000000..6b517d5 --- /dev/null +++ b/backend/public/asset-manifest.json @@ -0,0 +1,13 @@ +{ + "files": { + "main.css": "/static/css/main.7b221a61.css", + "main.js": "/static/js/main.f30d7548.js", + "index.html": "/index.html", + "main.7b221a61.css.map": "/static/css/main.7b221a61.css.map", + "main.f30d7548.js.map": "/static/js/main.f30d7548.js.map" + }, + "entrypoints": [ + "static/css/main.7b221a61.css", + "static/js/main.f30d7548.js" + ] +} \ No newline at end of file diff --git a/backend/public/files.php b/backend/public/files.php new file mode 100644 index 0000000..969e47f --- /dev/null +++ b/backend/public/files.php @@ -0,0 +1,17 @@ + true, + 'files' => $files, + 'rootPath' => $rootPath + ]); +} else { + echo json_encode([ + 'success' => false, + 'error' => 'Ordner nicht vorhanden oder keine Leserechte', + 'rootPath' => $rootPath + ]); +} \ No newline at end of file diff --git a/backend/public/index.html b/backend/public/index.html new file mode 100644 index 0000000..2ba6be0 --- /dev/null +++ b/backend/public/index.html @@ -0,0 +1 @@ +adspreview
\ No newline at end of file diff --git a/backend/public/index.php b/backend/public/index.php new file mode 100755 index 0000000..79668fc --- /dev/null +++ b/backend/public/index.php @@ -0,0 +1,33 @@ +run(); diff --git a/backend/public/static/css/main.7b221a61.css b/backend/public/static/css/main.7b221a61.css new file mode 100644 index 0000000..2ae8b7b --- /dev/null +++ b/backend/public/static/css/main.7b221a61.css @@ -0,0 +1,2 @@ +body,html{height:100%;width:100%}input::-ms-clear,input::-ms-reveal{display:none}*,:after,:before{box-sizing:border-box}html{-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:rgba(0,0,0,0);font-family:sans-serif;line-height:1.15}body{margin:0}[tabindex="-1"]:focus{outline:none}hr{box-sizing:initial;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{font-weight:500;margin-bottom:.5em;margin-top:0}p{margin-bottom:1em;margin-top:0}abbr[data-original-title],abbr[title]{border-bottom:0;cursor:help;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}address{font-style:normal;line-height:inherit;margin-bottom:1em}input[type=number],input[type=password],input[type=text],textarea{-webkit-appearance:none}dl,ol,ul{margin-bottom:1em;margin-top:0}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:500}dd{margin-bottom:.5em;margin-left:0}blockquote{margin:0 0 1em}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}code,kbd,pre,samp{font-family:SFMono-Regular,Consolas,Liberation Mono,Menlo,Courier,monospace;font-size:1em}pre{margin-bottom:1em;margin-top:0;overflow:auto}figure{margin:0 0 1em}img{border-style:none;vertical-align:middle}[role=button],a,area,button,input:not([type=range]),label,select,summary,textarea{touch-action:manipulation}table{border-collapse:collapse}caption{caption-side:bottom;padding-bottom:.3em;padding-top:.75em;text-align:left}button,input,optgroup,select,textarea{color:inherit;font-family:inherit;font-size:inherit;line-height:inherit;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{border:0;margin:0;min-width:0;padding:0}legend{color:inherit;display:block;font-size:1.5em;line-height:inherit;margin-bottom:.5em;max-width:100%;padding:0;white-space:normal;width:100%}progress{vertical-align:initial}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:none;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}output{display:inline-block}summary{display:list-item}template{display:none}[hidden]{display:none!important}mark{background-color:#feffe6;padding:.2em}.ant-tabs{border-radius:0;padding:0}.ant-tabs>.ant-tabs-nav{margin-bottom:0;padding:9px 32px;position:sticky;top:0;z-index:100}.ant-tabs-content{overflow:auto;padding:0 32px} +/*# sourceMappingURL=main.7b221a61.css.map*/ \ No newline at end of file diff --git a/backend/public/static/css/main.7b221a61.css.map b/backend/public/static/css/main.7b221a61.css.map new file mode 100755 index 0000000..a46e5ca --- /dev/null +++ b/backend/public/static/css/main.7b221a61.css.map @@ -0,0 +1 @@ +{"version":3,"file":"static/css/main.7b221a61.css","mappings":"AACA,UAGE,WAAY,CADZ,UAEF,CACA,mCAEE,YACF,CACA,iBAGE,qBACF,CACA,KAGE,6BAA8B,CAC9B,yBAA0B,CAC1B,4BAA6B,CAC7B,yCAA6C,CAL7C,sBAAuB,CACvB,gBAKF,CAIA,KACE,QACF,CACA,sBACE,YACF,CACA,GACE,kBAAuB,CACvB,QAAS,CACT,gBACF,CACA,kBAQE,eAAgB,CADhB,kBAAoB,CADpB,YAGF,CACA,EAEE,iBAAkB,CADlB,YAEF,CACA,sCAIE,eAAgB,CAChB,WAAY,CAHZ,wCAAyC,CACzC,gCAGF,CACA,QAEE,iBAAkB,CAClB,mBAAoB,CAFpB,iBAGF,CACA,kEAIE,uBACF,CACA,SAIE,iBAAkB,CADlB,YAEF,CACA,wBAIE,eACF,CACA,GACE,eACF,CACA,GACE,kBAAoB,CACpB,aACF,CACA,WACE,cACF,CACA,IACE,iBACF,CACA,SAEE,kBACF,CACA,MACE,aACF,CACA,QAGE,aAAc,CACd,aAAc,CAFd,iBAAkB,CAGlB,sBACF,CACA,IACE,aACF,CACA,IACE,SACF,CACA,kBAKE,2EAAqF,CADrF,aAEF,CACA,IAEE,iBAAkB,CADlB,YAAa,CAEb,aACF,CACA,OACE,cACF,CACA,IAEE,iBAAkB,CADlB,qBAEF,CACA,kFASE,yBACF,CACA,MACE,wBACF,CACA,QAIE,mBAAoB,CAFpB,mBAAqB,CADrB,iBAAmB,CAEnB,eAEF,CACA,sCAME,aAAc,CAEd,mBAAoB,CADpB,iBAAkB,CAElB,mBAAoB,CAJpB,QAKF,CACA,aAEE,gBACF,CACA,cAEE,mBACF,CACA,qDAIE,yBACF,CACA,wHAKE,iBAAkB,CADlB,SAEF,CACA,uCAEE,qBAAsB,CACtB,SACF,CACA,+EAIE,0BACF,CACA,SACE,aAAc,CACd,eACF,CACA,SAIE,QAAS,CAFT,QAAS,CADT,WAAY,CAEZ,SAEF,CACA,OAME,aAAc,CALd,aAAc,CAMd,eAAgB,CAChB,mBAAoB,CAJpB,kBAAoB,CADpB,cAAe,CAEf,SAAU,CAIV,kBAAmB,CAPnB,UAQF,CACA,SACE,sBACF,CACA,kFAEE,WACF,CACA,cAEE,uBAAwB,CADxB,mBAEF,CACA,qFAEE,uBACF,CACA,6BAEE,yBAA0B,CAD1B,YAEF,CACA,OACE,oBACF,CACA,QACE,iBACF,CACA,SACE,YACF,CACA,SACE,sBACF,CACA,KAEE,wBAAyB,CADzB,YAEF,CC3PA,UACI,eAAkB,CAClB,SACJ,CAEA,wBAKI,eAAkB,CADlB,gBAAiB,CAHjB,eAAgB,CAChB,KAAQ,CACR,WAGJ,CAEA,kBAEI,aAAc,CADd,cAEJ","sources":["../node_modules/antd/dist/reset.css","global.css"],"sourcesContent":["/* stylelint-disable */\nhtml,\nbody {\n width: 100%;\n height: 100%;\n}\ninput::-ms-clear,\ninput::-ms-reveal {\n display: none;\n}\n*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\nhtml {\n font-family: sans-serif;\n line-height: 1.15;\n -webkit-text-size-adjust: 100%;\n -ms-text-size-adjust: 100%;\n -ms-overflow-style: scrollbar;\n -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\n@-ms-viewport {\n width: device-width;\n}\nbody {\n margin: 0;\n}\n[tabindex='-1']:focus {\n outline: none;\n}\nhr {\n box-sizing: content-box;\n height: 0;\n overflow: visible;\n}\nh1,\nh2,\nh3,\nh4,\nh5,\nh6 {\n margin-top: 0;\n margin-bottom: 0.5em;\n font-weight: 500;\n}\np {\n margin-top: 0;\n margin-bottom: 1em;\n}\nabbr[title],\nabbr[data-original-title] {\n -webkit-text-decoration: underline dotted;\n text-decoration: underline dotted;\n border-bottom: 0;\n cursor: help;\n}\naddress {\n margin-bottom: 1em;\n font-style: normal;\n line-height: inherit;\n}\ninput[type='text'],\ninput[type='password'],\ninput[type='number'],\ntextarea {\n -webkit-appearance: none;\n}\nol,\nul,\ndl {\n margin-top: 0;\n margin-bottom: 1em;\n}\nol ol,\nul ul,\nol ul,\nul ol {\n margin-bottom: 0;\n}\ndt {\n font-weight: 500;\n}\ndd {\n margin-bottom: 0.5em;\n margin-left: 0;\n}\nblockquote {\n margin: 0 0 1em;\n}\ndfn {\n font-style: italic;\n}\nb,\nstrong {\n font-weight: bolder;\n}\nsmall {\n font-size: 80%;\n}\nsub,\nsup {\n position: relative;\n font-size: 75%;\n line-height: 0;\n vertical-align: baseline;\n}\nsub {\n bottom: -0.25em;\n}\nsup {\n top: -0.5em;\n}\npre,\ncode,\nkbd,\nsamp {\n font-size: 1em;\n font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace;\n}\npre {\n margin-top: 0;\n margin-bottom: 1em;\n overflow: auto;\n}\nfigure {\n margin: 0 0 1em;\n}\nimg {\n vertical-align: middle;\n border-style: none;\n}\na,\narea,\nbutton,\n[role='button'],\ninput:not([type='range']),\nlabel,\nselect,\nsummary,\ntextarea {\n touch-action: manipulation;\n}\ntable {\n border-collapse: collapse;\n}\ncaption {\n padding-top: 0.75em;\n padding-bottom: 0.3em;\n text-align: left;\n caption-side: bottom;\n}\ninput,\nbutton,\nselect,\noptgroup,\ntextarea {\n margin: 0;\n color: inherit;\n font-size: inherit;\n font-family: inherit;\n line-height: inherit;\n}\nbutton,\ninput {\n overflow: visible;\n}\nbutton,\nselect {\n text-transform: none;\n}\nbutton,\nhtml [type='button'],\n[type='reset'],\n[type='submit'] {\n -webkit-appearance: button;\n}\nbutton::-moz-focus-inner,\n[type='button']::-moz-focus-inner,\n[type='reset']::-moz-focus-inner,\n[type='submit']::-moz-focus-inner {\n padding: 0;\n border-style: none;\n}\ninput[type='radio'],\ninput[type='checkbox'] {\n box-sizing: border-box;\n padding: 0;\n}\ninput[type='date'],\ninput[type='time'],\ninput[type='datetime-local'],\ninput[type='month'] {\n -webkit-appearance: listbox;\n}\ntextarea {\n overflow: auto;\n resize: vertical;\n}\nfieldset {\n min-width: 0;\n margin: 0;\n padding: 0;\n border: 0;\n}\nlegend {\n display: block;\n width: 100%;\n max-width: 100%;\n margin-bottom: 0.5em;\n padding: 0;\n color: inherit;\n font-size: 1.5em;\n line-height: inherit;\n white-space: normal;\n}\nprogress {\n vertical-align: baseline;\n}\n[type='number']::-webkit-inner-spin-button,\n[type='number']::-webkit-outer-spin-button {\n height: auto;\n}\n[type='search'] {\n outline-offset: -2px;\n -webkit-appearance: none;\n}\n[type='search']::-webkit-search-cancel-button,\n[type='search']::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n::-webkit-file-upload-button {\n font: inherit;\n -webkit-appearance: button;\n}\noutput {\n display: inline-block;\n}\nsummary {\n display: list-item;\n}\ntemplate {\n display: none;\n}\n[hidden] {\n display: none !important;\n}\nmark {\n padding: 0.2em;\n background-color: #feffe6;\n}\n",".ant-tabs {\n border-radius: 0px;\n padding: 0px;\n}\n\n.ant-tabs > .ant-tabs-nav {\n position: sticky;\n top: 0px;\n z-index: 100;\n padding: 9px 32px;\n margin-bottom: 0px;\n}\n\n.ant-tabs-content {\n padding: 0px 32px;\n overflow: auto;\n}"],"names":[],"sourceRoot":""} \ No newline at end of file diff --git a/backend/public/static/js/main.f30d7548.js b/backend/public/static/js/main.f30d7548.js new file mode 100644 index 0000000..08e0802 --- /dev/null +++ b/backend/public/static/js/main.f30d7548.js @@ -0,0 +1,3 @@ +/*! For license information please see main.f30d7548.js.LICENSE.txt */ +(()=>{var e={43:(e,t,n)=>{"use strict";e.exports=n(202)},82:(e,t)=>{"use strict";var n,r=Symbol.for("react.element"),o=Symbol.for("react.portal"),i=Symbol.for("react.fragment"),a=Symbol.for("react.strict_mode"),l=Symbol.for("react.profiler"),s=Symbol.for("react.provider"),c=Symbol.for("react.context"),u=Symbol.for("react.server_context"),d=Symbol.for("react.forward_ref"),f=Symbol.for("react.suspense"),p=Symbol.for("react.suspense_list"),m=Symbol.for("react.memo"),g=Symbol.for("react.lazy"),v=Symbol.for("react.offscreen");function h(e){if("object"===typeof e&&null!==e){var t=e.$$typeof;switch(t){case r:switch(e=e.type){case i:case l:case a:case f:case p:return e;default:switch(e=e&&e.$$typeof){case u:case c:case d:case g:case m:case s:return e;default:return t}}case o:return t}}}n=Symbol.for("react.module.reference"),t.ForwardRef=d,t.isMemo=function(e){return h(e)===m}},86:(e,t,n)=>{"use strict";e.exports=n(82)},139:(e,t)=>{var n;!function(){"use strict";var r={}.hasOwnProperty;function o(){for(var e="",t=0;t{"use strict";var r=n(43),o=Symbol.for("react.element"),i=Symbol.for("react.fragment"),a=Object.prototype.hasOwnProperty,l=r.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,s={key:!0,ref:!0,__self:!0,__source:!0};function c(e,t,n){var r,i={},c=null,u=null;for(r in void 0!==n&&(c=""+n),void 0!==t.key&&(c=""+t.key),void 0!==t.ref&&(u=t.ref),t)a.call(t,r)&&!s.hasOwnProperty(r)&&(i[r]=t[r]);if(e&&e.defaultProps)for(r in t=e.defaultProps)void 0===i[r]&&(i[r]=t[r]);return{$$typeof:o,type:e,key:c,ref:u,props:i,_owner:l.current}}t.Fragment=i,t.jsx=c,t.jsxs=c},202:(e,t)=>{"use strict";var n=Symbol.for("react.element"),r=Symbol.for("react.portal"),o=Symbol.for("react.fragment"),i=Symbol.for("react.strict_mode"),a=Symbol.for("react.profiler"),l=Symbol.for("react.provider"),s=Symbol.for("react.context"),c=Symbol.for("react.forward_ref"),u=Symbol.for("react.suspense"),d=Symbol.for("react.memo"),f=Symbol.for("react.lazy"),p=Symbol.iterator;var m={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},g=Object.assign,v={};function h(e,t,n){this.props=e,this.context=t,this.refs=v,this.updater=n||m}function b(){}function y(e,t,n){this.props=e,this.context=t,this.refs=v,this.updater=n||m}h.prototype.isReactComponent={},h.prototype.setState=function(e,t){if("object"!==typeof e&&"function"!==typeof e&&null!=e)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")},h.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")},b.prototype=h.prototype;var w=y.prototype=new b;w.constructor=y,g(w,h.prototype),w.isPureReactComponent=!0;var x=Array.isArray,C=Object.prototype.hasOwnProperty,S={current:null},$={key:!0,ref:!0,__self:!0,__source:!0};function E(e,t,r){var o,i={},a=null,l=null;if(null!=t)for(o in void 0!==t.ref&&(l=t.ref),void 0!==t.key&&(a=""+t.key),t)C.call(t,o)&&!$.hasOwnProperty(o)&&(i[o]=t[o]);var s=arguments.length-2;if(1===s)i.children=r;else if(1{"use strict";function n(e,t){var n=e.length;e.push(t);e:for(;0>>1,o=e[r];if(!(0>>1;ri(s,n))ci(u,s)?(e[r]=u,e[c]=n,r=c):(e[r]=s,e[l]=n,r=l);else{if(!(ci(u,n)))break e;e[r]=u,e[c]=n,r=c}}}return t}function i(e,t){var n=e.sortIndex-t.sortIndex;return 0!==n?n:e.id-t.id}if("object"===typeof performance&&"function"===typeof performance.now){var a=performance;t.unstable_now=function(){return a.now()}}else{var l=Date,s=l.now();t.unstable_now=function(){return l.now()-s}}var c=[],u=[],d=1,f=null,p=3,m=!1,g=!1,v=!1,h="function"===typeof setTimeout?setTimeout:null,b="function"===typeof clearTimeout?clearTimeout:null,y="undefined"!==typeof setImmediate?setImmediate:null;function w(e){for(var t=r(u);null!==t;){if(null===t.callback)o(u);else{if(!(t.startTime<=e))break;o(u),t.sortIndex=t.expirationTime,n(c,t)}t=r(u)}}function x(e){if(v=!1,w(e),!g)if(null!==r(c))g=!0,R(C);else{var t=r(u);null!==t&&T(x,t.startTime-e)}}function C(e,n){g=!1,v&&(v=!1,b(k),k=-1),m=!0;var i=p;try{for(w(n),f=r(c);null!==f&&(!(f.expirationTime>n)||e&&!I());){var a=f.callback;if("function"===typeof a){f.callback=null,p=f.priorityLevel;var l=a(f.expirationTime<=n);n=t.unstable_now(),"function"===typeof l?f.callback=l:f===r(c)&&o(c),w(n)}else o(c);f=r(c)}if(null!==f)var s=!0;else{var d=r(u);null!==d&&T(x,d.startTime-n),s=!1}return s}finally{f=null,p=i,m=!1}}"undefined"!==typeof navigator&&void 0!==navigator.scheduling&&void 0!==navigator.scheduling.isInputPending&&navigator.scheduling.isInputPending.bind(navigator.scheduling);var S,$=!1,E=null,k=-1,O=5,j=-1;function I(){return!(t.unstable_now()-je||125a?(e.sortIndex=i,n(u,e),null===r(c)&&e===r(u)&&(v?(b(k),k=-1):v=!0,T(x,i-a))):(e.sortIndex=l,n(c,e),g||m||(g=!0,R(C))),e},t.unstable_shouldYield=I,t.unstable_wrapCallback=function(e){var t=p;return function(){var n=p;p=t;try{return e.apply(this,arguments)}finally{p=n}}}},270:(e,t,n)=>{"use strict";var r=n(520),o={"text/plain":"Text","text/html":"Url",default:"Text"};e.exports=function(e,t){var n,i,a,l,s,c,u=!1;t||(t={}),n=t.debug||!1;try{if(a=r(),l=document.createRange(),s=document.getSelection(),(c=document.createElement("span")).textContent=e,c.ariaHidden="true",c.style.all="unset",c.style.position="fixed",c.style.top=0,c.style.clip="rect(0, 0, 0, 0)",c.style.whiteSpace="pre",c.style.webkitUserSelect="text",c.style.MozUserSelect="text",c.style.msUserSelect="text",c.style.userSelect="text",c.addEventListener("copy",function(r){if(r.stopPropagation(),t.format)if(r.preventDefault(),"undefined"===typeof r.clipboardData){n&&console.warn("unable to use e.clipboardData"),n&&console.warn("trying IE specific stuff"),window.clipboardData.clearData();var i=o[t.format]||o.default;window.clipboardData.setData(i,e)}else r.clipboardData.clearData(),r.clipboardData.setData(t.format,e);t.onCopy&&(r.preventDefault(),t.onCopy(r.clipboardData))}),document.body.appendChild(c),l.selectNodeContents(c),s.addRange(l),!document.execCommand("copy"))throw new Error("copy command was unsuccessful");u=!0}catch(d){n&&console.error("unable to copy using execCommand: ",d),n&&console.warn("trying IE specific stuff");try{window.clipboardData.setData(t.format||"text",e),t.onCopy&&t.onCopy(window.clipboardData),u=!0}catch(d){n&&console.error("unable to copy using clipboardData: ",d),n&&console.error("falling back to prompt"),i=function(e){var t=(/mac os x/i.test(navigator.userAgent)?"\u2318":"Ctrl")+"+C";return e.replace(/#{\s*key\s*}/g,t)}("message"in t?t.message:"Copy to clipboard: #{key}, Enter"),window.prompt(i,e)}}finally{s&&("function"==typeof s.removeRange?s.removeRange(l):s.removeAllRanges()),c&&document.body.removeChild(c),a()}return u}},391:(e,t,n)=>{"use strict";var r=n(950);t.createRoot=r.createRoot,t.hydrateRoot=r.hydrateRoot},520:e=>{e.exports=function(){var e=document.getSelection();if(!e.rangeCount)return function(){};for(var t=document.activeElement,n=[],r=0;r{"use strict";e.exports=n(153)},730:(e,t,n)=>{"use strict";var r=n(43),o=n(853);function i(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n