feat: Enhance frontend loading experience and service status handling
Some checks failed
Integration Tests / integration-tests (push) Failing after 20s
Integration Tests / performance-tests (push) Has been skipped
Service Adapters (Python FastAPI) / test (3.11) (push) Failing after 23s
Frontend (React) / test (20) (push) Failing after 1m3s
Frontend (React) / build (push) Has been skipped
Frontend (React) / lighthouse (push) Has been skipped
Service Adapters (Python FastAPI) / test (3.12) (push) Failing after 23s
Service Adapters (Python FastAPI) / test (3.13) (push) Failing after 20s
Service Adapters (Python FastAPI) / build (push) Has been skipped
Some checks failed
Integration Tests / integration-tests (push) Failing after 20s
Integration Tests / performance-tests (push) Has been skipped
Service Adapters (Python FastAPI) / test (3.11) (push) Failing after 23s
Frontend (React) / test (20) (push) Failing after 1m3s
Frontend (React) / build (push) Has been skipped
Frontend (React) / lighthouse (push) Has been skipped
Service Adapters (Python FastAPI) / test (3.12) (push) Failing after 23s
Service Adapters (Python FastAPI) / test (3.13) (push) Failing after 20s
Service Adapters (Python FastAPI) / build (push) Has been skipped
### Summary of Changes - Removed proxy configuration in `rsbuild.config.js` as the API Gateway is not running. - Added smooth transitions and gentle loading overlays in CSS for improved user experience during data loading. - Updated `Dashboard` component to conditionally display loading spinner and gentle loading overlay based on data fetching state. - Enhanced `useOfflineAwareServiceStatus` and `useOfflineAwareSystemData` hooks to manage loading states and service status more effectively. - Increased refresh intervals for service status and system data to reduce API call frequency. ### Expected Results - Improved user experience with smoother loading transitions and better feedback during data refreshes. - Enhanced handling of service status checks, providing clearer information when services are unavailable. - Streamlined code for managing loading states, making it easier to maintain and extend in the future.
This commit is contained in:
104
frontend/src/utils/requestManager.js
Normal file
104
frontend/src/utils/requestManager.js
Normal file
@@ -0,0 +1,104 @@
|
||||
import { serviceAdapters, apiDocs } from '../services/api';
|
||||
|
||||
class RequestManager {
|
||||
constructor() {
|
||||
this.pendingRequests = new Map();
|
||||
this.requestTimeouts = new Map();
|
||||
}
|
||||
|
||||
/**
|
||||
* Debounced request function that cancels previous requests of the same type
|
||||
* @param {string} requestType - Type of request (e.g., 'serviceStatus', 'systemData')
|
||||
* @param {Function} requestFunction - The actual request function to execute
|
||||
* @param {number} debounceMs - Debounce delay in milliseconds
|
||||
* @returns {Promise} - Promise that resolves with the request result
|
||||
*/
|
||||
async debouncedRequest(requestType, requestFunction, _debounceMs = 1000) {
|
||||
// Cancel any pending request of the same type
|
||||
if (this.pendingRequests.has(requestType)) {
|
||||
const { controller, timeoutId } = this.pendingRequests.get(requestType);
|
||||
controller.abort();
|
||||
clearTimeout(timeoutId);
|
||||
}
|
||||
|
||||
// Create new abort controller for this request
|
||||
const controller = new AbortController();
|
||||
const timeoutId = setTimeout(() => {
|
||||
controller.abort();
|
||||
}, 30000); // 30 second timeout
|
||||
|
||||
// Store the request info
|
||||
this.pendingRequests.set(requestType, { controller, timeoutId });
|
||||
|
||||
try {
|
||||
const result = await requestFunction(controller.signal);
|
||||
this.pendingRequests.delete(requestType);
|
||||
clearTimeout(timeoutId);
|
||||
return result;
|
||||
} catch (error) {
|
||||
this.pendingRequests.delete(requestType);
|
||||
clearTimeout(timeoutId);
|
||||
|
||||
if (error.name === 'AbortError') {
|
||||
throw new Error('Request was cancelled');
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get service status with debouncing
|
||||
*/
|
||||
async getServiceStatus(_signal) {
|
||||
const [adaptersResult, docsResult] = await Promise.allSettled([
|
||||
serviceAdapters.health(),
|
||||
apiDocs.health()
|
||||
]);
|
||||
|
||||
return {
|
||||
adapters: adaptersResult,
|
||||
docs: docsResult
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get system data with debouncing
|
||||
*/
|
||||
async getSystemData(_signal) {
|
||||
const [servicesResult, eventsResult] = await Promise.allSettled([
|
||||
serviceAdapters.getServices(),
|
||||
serviceAdapters.getEvents(10)
|
||||
]);
|
||||
|
||||
return {
|
||||
services: servicesResult,
|
||||
events: eventsResult
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel all pending requests
|
||||
*/
|
||||
cancelAllRequests() {
|
||||
this.pendingRequests.forEach(({ controller, timeoutId }) => {
|
||||
controller.abort();
|
||||
clearTimeout(timeoutId);
|
||||
});
|
||||
this.pendingRequests.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel specific request type
|
||||
*/
|
||||
cancelRequest(requestType) {
|
||||
if (this.pendingRequests.has(requestType)) {
|
||||
const { controller, timeoutId } = this.pendingRequests.get(requestType);
|
||||
controller.abort();
|
||||
clearTimeout(timeoutId);
|
||||
this.pendingRequests.delete(requestType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Export singleton instance
|
||||
export const requestManager = new RequestManager();
|
||||
Reference in New Issue
Block a user