fix: Gitea Traefik routing and connection pool optimization
Some checks failed
🚀 Build & Deploy Image / Determine Build Necessity (push) Failing after 10m14s
🚀 Build & Deploy Image / Build Runtime Base Image (push) Has been skipped
🚀 Build & Deploy Image / Build Docker Image (push) Has been skipped
🚀 Build & Deploy Image / Run Tests & Quality Checks (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Staging (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Production (push) Has been skipped
Security Vulnerability Scan / Check for Dependency Changes (push) Failing after 11m25s
Security Vulnerability Scan / Composer Security Audit (push) Has been cancelled
Some checks failed
🚀 Build & Deploy Image / Determine Build Necessity (push) Failing after 10m14s
🚀 Build & Deploy Image / Build Runtime Base Image (push) Has been skipped
🚀 Build & Deploy Image / Build Docker Image (push) Has been skipped
🚀 Build & Deploy Image / Run Tests & Quality Checks (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Staging (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Production (push) Has been skipped
Security Vulnerability Scan / Check for Dependency Changes (push) Failing after 11m25s
Security Vulnerability Scan / Composer Security Audit (push) Has been cancelled
- Remove middleware reference from Gitea Traefik labels (caused routing issues) - Optimize Gitea connection pool settings (MAX_IDLE_CONNS=30, authentication_timeout=180s) - Add explicit service reference in Traefik labels - Fix intermittent 504 timeouts by improving PostgreSQL connection handling Fixes Gitea unreachability via git.michaelschiemer.de
This commit is contained in:
@@ -20,6 +20,9 @@ import { ComponentFileUploader } from './ComponentFileUploader.js';
|
||||
import { FileUploadWidget } from './FileUploadWidget.js';
|
||||
import { optimisticStateManager } from './OptimisticStateManager.js';
|
||||
import { accessibilityManager } from './AccessibilityManager.js';
|
||||
import { ErrorBoundary } from './ErrorBoundary.js';
|
||||
import { RequestDeduplicator } from './RequestDeduplicator.js';
|
||||
import * as StateSerializer from './StateSerializer.js';
|
||||
|
||||
class LiveComponentManager {
|
||||
constructor() {
|
||||
@@ -42,6 +45,30 @@ class LiveComponentManager {
|
||||
|
||||
// DevTools Integration
|
||||
this.devTools = null; // Will be set by DevTools when available
|
||||
|
||||
// Error Handling
|
||||
this.errorBoundary = new ErrorBoundary(this);
|
||||
|
||||
// Request Deduplication
|
||||
this.requestDeduplicator = new RequestDeduplicator();
|
||||
|
||||
// Shared Configuration
|
||||
this.config = sharedConfig;
|
||||
|
||||
// Tooltip Manager
|
||||
this.tooltipManager = tooltipManager;
|
||||
|
||||
// Action Loading Manager
|
||||
this.actionLoadingManager = actionLoadingManager;
|
||||
|
||||
// UI Helper
|
||||
this.uiHelper = new LiveComponentUIHelper(this);
|
||||
|
||||
// Loading State Manager
|
||||
this.loadingStateManager = new LoadingStateManager(
|
||||
this.actionLoadingManager,
|
||||
optimisticStateManager
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -140,6 +167,9 @@ class LiveComponentManager {
|
||||
// Setup accessibility features
|
||||
this.setupAccessibility(componentId, element);
|
||||
|
||||
// Initialize tooltips for component
|
||||
this.tooltipManager.initComponent(element);
|
||||
|
||||
console.log(`[LiveComponent] Initialized: ${componentId}`);
|
||||
}
|
||||
|
||||
@@ -282,9 +312,9 @@ class LiveComponentManager {
|
||||
this.setupFileUploadHandlers(config.element);
|
||||
}
|
||||
|
||||
// Update state
|
||||
// Update state using StateSerializer
|
||||
if (state) {
|
||||
config.element.dataset.state = JSON.stringify(state);
|
||||
StateSerializer.setStateOnElement(config.element, state);
|
||||
}
|
||||
|
||||
// Restore focus after update
|
||||
@@ -614,18 +644,46 @@ class LiveComponentManager {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for pending duplicate request
|
||||
const pendingRequest = this.requestDeduplicator.getPendingRequest(componentId, method, params);
|
||||
if (pendingRequest) {
|
||||
console.log(`[LiveComponent] Deduplicating request: ${componentId}.${method}`);
|
||||
return await pendingRequest;
|
||||
}
|
||||
|
||||
// Check for cached result
|
||||
const cachedResult = this.requestDeduplicator.getCachedResult(componentId, method, params);
|
||||
if (cachedResult) {
|
||||
console.log(`[LiveComponent] Using cached result: ${componentId}.${method}`);
|
||||
return cachedResult;
|
||||
}
|
||||
|
||||
let operationId = null;
|
||||
const startTime = performance.now();
|
||||
|
||||
try {
|
||||
// Get current state from element
|
||||
const stateJson = config.element.dataset.state || '{}';
|
||||
const stateWrapper = JSON.parse(stateJson);
|
||||
// Show loading state (uses LoadingStateManager for configurable indicators)
|
||||
const loadingConfig = this.loadingStateManager.getConfig(componentId);
|
||||
this.loadingStateManager.showLoading(componentId, config.element, {
|
||||
fragments,
|
||||
type: loadingConfig.type,
|
||||
optimistic: true // Check optimistic UI first
|
||||
});
|
||||
|
||||
// Create request promise
|
||||
const requestPromise = (async () => {
|
||||
try {
|
||||
// Get current state from element using StateSerializer
|
||||
const stateWrapper = StateSerializer.getStateFromElement(config.element) || {
|
||||
id: componentId,
|
||||
component: '',
|
||||
data: {},
|
||||
version: 1
|
||||
};
|
||||
|
||||
// Extract actual state data from wrapper format
|
||||
// Wrapper format: {id, component, data, version}
|
||||
// Server expects just the data object
|
||||
const state = stateWrapper.data || stateWrapper;
|
||||
const state = stateWrapper.data || {};
|
||||
|
||||
// Apply optimistic update for immediate UI feedback
|
||||
// This updates the UI before server confirmation
|
||||
@@ -741,9 +799,12 @@ class LiveComponentManager {
|
||||
this.setupActionHandlers(config.element);
|
||||
}
|
||||
|
||||
// Update component state
|
||||
// Re-initialize tooltips after DOM update
|
||||
this.tooltipManager.initComponent(config.element);
|
||||
|
||||
// Update component state using StateSerializer
|
||||
if (data.state) {
|
||||
config.element.dataset.state = JSON.stringify(data.state);
|
||||
StateSerializer.setStateOnElement(config.element, data.state);
|
||||
}
|
||||
|
||||
// Handle server events
|
||||
@@ -753,29 +814,50 @@ class LiveComponentManager {
|
||||
|
||||
console.log(`[LiveComponent] Action executed: ${componentId}.${method}`, data);
|
||||
|
||||
// Log successful action to DevTools
|
||||
const endTime = performance.now();
|
||||
this.logActionToDevTools(componentId, method, params, startTime, endTime, true);
|
||||
// Log successful action to DevTools
|
||||
const endTime = performance.now();
|
||||
this.logActionToDevTools(componentId, method, params, startTime, endTime, true);
|
||||
|
||||
} catch (error) {
|
||||
console.error(`[LiveComponent] Action failed:`, error);
|
||||
// Cache successful result
|
||||
this.requestDeduplicator.cacheResult(componentId, method, params, data);
|
||||
|
||||
// Log failed action to DevTools
|
||||
const endTime = performance.now();
|
||||
this.logActionToDevTools(componentId, method, params, startTime, endTime, false, error.message);
|
||||
// Hide loading state
|
||||
this.loadingStateManager.hideLoading(componentId);
|
||||
|
||||
// Rollback optimistic update on error
|
||||
if (operationId) {
|
||||
const snapshot = optimisticStateManager.getSnapshot(componentId);
|
||||
if (snapshot) {
|
||||
config.element.dataset.state = JSON.stringify(snapshot);
|
||||
optimisticStateManager.clearPendingOperations(componentId);
|
||||
optimisticStateManager.clearSnapshot(componentId);
|
||||
return data;
|
||||
|
||||
} catch (error) {
|
||||
console.error(`[LiveComponent] Action failed:`, error);
|
||||
|
||||
// Log failed action to DevTools
|
||||
const endTime = performance.now();
|
||||
this.logActionToDevTools(componentId, method, params, startTime, endTime, false, error.message);
|
||||
|
||||
// Rollback optimistic update on error
|
||||
if (operationId) {
|
||||
const snapshot = optimisticStateManager.getSnapshot(componentId);
|
||||
if (snapshot) {
|
||||
StateSerializer.setStateOnElement(config.element, snapshot);
|
||||
optimisticStateManager.clearPendingOperations(componentId);
|
||||
optimisticStateManager.clearSnapshot(componentId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.handleError(componentId, error);
|
||||
}
|
||||
// Hide loading state on error
|
||||
this.loadingStateManager.hideLoading(componentId);
|
||||
|
||||
// Handle error via ErrorBoundary
|
||||
await this.errorBoundary.handleError(componentId, method, error, {
|
||||
params,
|
||||
fragments
|
||||
});
|
||||
|
||||
throw error;
|
||||
}
|
||||
})();
|
||||
|
||||
// Register pending request for deduplication
|
||||
return this.requestDeduplicator.registerPendingRequest(componentId, method, params, requestPromise);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1154,9 +1236,9 @@ class LiveComponentManager {
|
||||
this.setupFileUploadHandlers(config.element);
|
||||
}
|
||||
|
||||
// Update component state
|
||||
// Update component state using StateSerializer
|
||||
if (data.state) {
|
||||
config.element.dataset.state = JSON.stringify(data.state);
|
||||
StateSerializer.setStateOnElement(config.element, data.state);
|
||||
}
|
||||
|
||||
// Handle server events
|
||||
@@ -1260,6 +1342,22 @@ class LiveComponentManager {
|
||||
// Cleanup accessibility features
|
||||
this.accessibilityManager.cleanup(componentId);
|
||||
|
||||
// Cleanup error handler
|
||||
this.errorBoundary.clearErrorHandler(componentId);
|
||||
|
||||
// Cleanup request deduplication
|
||||
this.requestDeduplicator.clearComponent(componentId);
|
||||
|
||||
// Cleanup tooltips
|
||||
this.tooltipManager.cleanupComponent(config.element);
|
||||
|
||||
// Hide any active loading states
|
||||
this.loadingStateManager.hideLoading(componentId);
|
||||
this.loadingStateManager.clearConfig(componentId);
|
||||
|
||||
// Cleanup UI components
|
||||
this.uiHelper.cleanup(componentId);
|
||||
|
||||
// Remove from registry
|
||||
this.components.delete(componentId);
|
||||
|
||||
@@ -1413,9 +1511,9 @@ class LiveComponentManager {
|
||||
this.setupActionHandlers(config.element);
|
||||
}
|
||||
|
||||
// Update state
|
||||
// Update state using StateSerializer
|
||||
if (result.state) {
|
||||
config.element.dataset.state = JSON.stringify(result.state);
|
||||
StateSerializer.setStateOnElement(config.element, result.state);
|
||||
}
|
||||
|
||||
// Dispatch events
|
||||
@@ -1584,4 +1682,11 @@ export { ComponentPlayground };
|
||||
export { ComponentFileUploader } from './ComponentFileUploader.js';
|
||||
export { FileUploadWidget } from './FileUploadWidget.js';
|
||||
export { ChunkedUploader } from './ChunkedUploader.js';
|
||||
|
||||
// Export UI integration modules
|
||||
export { tooltipManager } from './TooltipManager.js';
|
||||
export { actionLoadingManager } from './ActionLoadingManager.js';
|
||||
export { LiveComponentUIHelper } from './LiveComponentUIHelper.js';
|
||||
export { LoadingStateManager } from './LoadingStateManager.js';
|
||||
|
||||
export default LiveComponent;
|
||||
|
||||
Reference in New Issue
Block a user