feat: Enhance frontend with theme support and offline capabilities
Some checks failed
Integration Tests / integration-tests (push) Failing after 24s
Integration Tests / performance-tests (push) Has been skipped
API Docs (Node.js Express) / test (20) (push) Failing after 42s
API Docs (Node.js Express) / build (push) Has been skipped
Service Adapters (Python FastAPI) / test (3.11) (push) Successful in 1m8s
Service Adapters (Python FastAPI) / test (3.12) (push) Successful in 1m13s
Frontend (React) / test (20) (push) Successful in 1m46s
Frontend (React) / build (push) Failing after 52s
Frontend (React) / lighthouse (push) Has been skipped
Service Adapters (Python FastAPI) / test (3.13) (push) Successful in 2m4s
Service Adapters (Python FastAPI) / build (push) Failing after 17s
Some checks failed
Integration Tests / integration-tests (push) Failing after 24s
Integration Tests / performance-tests (push) Has been skipped
API Docs (Node.js Express) / test (20) (push) Failing after 42s
API Docs (Node.js Express) / build (push) Has been skipped
Service Adapters (Python FastAPI) / test (3.11) (push) Successful in 1m8s
Service Adapters (Python FastAPI) / test (3.12) (push) Successful in 1m13s
Frontend (React) / test (20) (push) Successful in 1m46s
Frontend (React) / build (push) Failing after 52s
Frontend (React) / lighthouse (push) Has been skipped
Service Adapters (Python FastAPI) / test (3.13) (push) Successful in 2m4s
Service Adapters (Python FastAPI) / build (push) Failing after 17s
### Summary of Changes - Introduced theme-aware CSS variables for consistent styling across light and dark modes. - Updated `App.jsx` to manage theme settings and improve layout responsiveness. - Refactored `OfflineMode` component to provide detailed connection status and quick actions for users. - Enhanced `Dashboard`, `Settings`, and `SystemMetrics` components to utilize new theme variables and improve UI consistency. - Updated service URLs in constants and API documentation to reflect new configurations. ### Expected Results - Improved user experience with a cohesive design that adapts to user preferences. - Enhanced offline functionality, providing users with better feedback and control during service outages. - Streamlined codebase with consistent styling practices, making future updates easier.
This commit is contained in:
@@ -43,7 +43,7 @@ const SERVICES = {
|
||||
},
|
||||
'service-adapters': {
|
||||
name: 'Service Adapters',
|
||||
url: process.env.SERVICE_ADAPTERS_URL || 'http://localhost:8000',
|
||||
url: process.env.SERVICE_ADAPTERS_URL || 'http://localhost:8001',
|
||||
openapiPath: '/openapi.json',
|
||||
description: 'Integration adapters for Home Assistant, Frigate, Immich, and other services'
|
||||
},
|
||||
@@ -84,7 +84,8 @@ async function fetchServiceSpec (serviceKey, service) {
|
||||
}
|
||||
|
||||
const response = await axios.get(`${service.url}${service.openapiPath}`, {
|
||||
timeout: 5000
|
||||
timeout: 5000,
|
||||
rejectUnauthorized: false
|
||||
})
|
||||
return response.data
|
||||
} catch (error) {
|
||||
@@ -126,7 +127,7 @@ async function generateUnifiedSpec () {
|
||||
description: 'API Gateway (Production)'
|
||||
},
|
||||
{
|
||||
url: 'http://localhost:8000',
|
||||
url: 'http://localhost:8001',
|
||||
description: 'Service Adapters (Production)'
|
||||
},
|
||||
{
|
||||
@@ -155,12 +156,45 @@ async function generateUnifiedSpec () {
|
||||
// Fetch specs from all services
|
||||
for (const [serviceKey, service] of Object.entries(SERVICES)) {
|
||||
const spec = await fetchServiceSpec(serviceKey, service)
|
||||
|
||||
// Collect original tags before modifying them
|
||||
const subCategories = new Set()
|
||||
if (spec.paths) {
|
||||
for (const [path, methods] of Object.entries(spec.paths)) {
|
||||
for (const [method, operation] of Object.entries(methods)) {
|
||||
if (operation.tags) {
|
||||
operation.tags.forEach(tag => {
|
||||
subCategories.add(tag)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Merge paths with service prefix
|
||||
if (spec.paths) {
|
||||
for (const [path, methods] of Object.entries(spec.paths)) {
|
||||
const prefixedPath = `/${serviceKey}${path}`
|
||||
unifiedSpec.paths[prefixedPath] = methods
|
||||
const updatedMethods = {}
|
||||
|
||||
for (const [method, operation] of Object.entries(methods)) {
|
||||
// Use only the main service name as the primary tag
|
||||
// Store original category in metadata for internal organization
|
||||
const originalTags = operation.tags || ['General']
|
||||
const category = originalTags[0] || 'General'
|
||||
|
||||
updatedMethods[method] = {
|
||||
...operation,
|
||||
tags: [service.name], // Only main service tag for top-level grouping
|
||||
summary: `[${category}] ${operation.summary || `${method.toUpperCase()} ${path}`}`,
|
||||
'x-service': serviceKey,
|
||||
'x-service-url': service.url,
|
||||
'x-original-tags': originalTags,
|
||||
'x-category': category
|
||||
}
|
||||
}
|
||||
|
||||
unifiedSpec.paths[prefixedPath] = updatedMethods
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,7 +210,9 @@ async function generateUnifiedSpec () {
|
||||
name: service.name,
|
||||
description: service.description,
|
||||
'x-service-url': service.url,
|
||||
'x-service-status': service.status || 'active'
|
||||
'x-service-status': service.status || 'active',
|
||||
'x-service-key': serviceKey,
|
||||
'x-categories': Array.from(subCategories) // Store available categories for reference
|
||||
})
|
||||
}
|
||||
|
||||
@@ -314,12 +350,42 @@ app.get('/', swaggerUi.setup(null, {
|
||||
displayRequestDuration: true,
|
||||
filter: true,
|
||||
showExtensions: true,
|
||||
showCommonExtensions: true
|
||||
showCommonExtensions: true,
|
||||
operationsSorter: function(a, b) {
|
||||
// Sort by summary (which includes category tags)
|
||||
const summaryA = a.get('summary') || '';
|
||||
const summaryB = b.get('summary') || '';
|
||||
return summaryA.localeCompare(summaryB);
|
||||
},
|
||||
tagsSorter: 'alpha'
|
||||
},
|
||||
customCss: `
|
||||
.swagger-ui .topbar { display: none; }
|
||||
.swagger-ui .info { margin: 20px 0; }
|
||||
.swagger-ui .info .title { color: #1890ff; }
|
||||
|
||||
/* Style service tags */
|
||||
.swagger-ui .opblock-tag {
|
||||
margin: 20px 0 10px 0;
|
||||
padding: 10px 0;
|
||||
border-bottom: 2px solid #1890ff;
|
||||
}
|
||||
|
||||
/* Style operation blocks */
|
||||
.swagger-ui .opblock {
|
||||
margin: 10px 0;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
/* Style operation summaries with category badges */
|
||||
.swagger-ui .opblock-summary-description {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* Add some spacing between operations */
|
||||
.swagger-ui .opblock-tag-section .opblock {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
`,
|
||||
customSiteTitle: 'LabFusion API Documentation'
|
||||
}))
|
||||
|
||||
@@ -11,7 +11,7 @@ app = FastAPI(
|
||||
version="1.0.0",
|
||||
license_info={"name": "MIT License", "url": "https://opensource.org/licenses/MIT"},
|
||||
servers=[
|
||||
{"url": "http://localhost:8000", "description": "Development Server"},
|
||||
{"url": "http://localhost:8001", "description": "Development Server"},
|
||||
{"url": "https://adapters.labfusion.dev", "description": "Production Server"},
|
||||
],
|
||||
)
|
||||
@@ -35,4 +35,4 @@ app.include_router(events.router)
|
||||
if __name__ == "__main__":
|
||||
import uvicorn
|
||||
|
||||
uvicorn.run(app, host="127.0.0.1", port=8000)
|
||||
uvicorn.run(app, host="127.0.0.1", port=8001)
|
||||
|
||||
Reference in New Issue
Block a user