Improve Team-indeling dashboard UI and cache invalidation
- Replace 'TEAM' label with Type attribute (Business/Enabling/Staf) in team blocks - Make Type labels larger (text-sm) and brighter colors - Make SUBTEAM label less bright (indigo-300) and smaller (text-[10px]) - Add 'FTE' suffix to bandbreedte values in header and application blocks - Add Platform and Connected Device labels to application blocks - Show Platform FTE and Workloads FTE separately in Platform blocks - Add spacing between Regiemodel letter and count value - Add cache invalidation for Team Dashboard when applications are updated - Enrich team references with Type attribute in getSubteamToTeamMapping
This commit is contained in:
135
backend/src/routes/cache.ts
Normal file
135
backend/src/routes/cache.ts
Normal file
@@ -0,0 +1,135 @@
|
||||
/**
|
||||
* Cache management routes
|
||||
*
|
||||
* Provides endpoints for cache status and manual sync triggers.
|
||||
*/
|
||||
|
||||
import { Router, Request, Response } from 'express';
|
||||
import { cacheStore } from '../services/cacheStore.js';
|
||||
import { syncEngine } from '../services/syncEngine.js';
|
||||
import { logger } from '../services/logger.js';
|
||||
import { OBJECT_TYPES } from '../generated/jira-schema.js';
|
||||
import type { CMDBObjectTypeName } from '../generated/jira-types.js';
|
||||
|
||||
const router = Router();
|
||||
|
||||
// Get cache status
|
||||
router.get('/status', (req: Request, res: Response) => {
|
||||
try {
|
||||
const cacheStats = cacheStore.getStats();
|
||||
const syncStatus = syncEngine.getStatus();
|
||||
|
||||
res.json({
|
||||
cache: cacheStats,
|
||||
sync: syncStatus,
|
||||
supportedTypes: Object.keys(OBJECT_TYPES),
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('Failed to get cache status', error);
|
||||
res.status(500).json({ error: 'Failed to get cache status' });
|
||||
}
|
||||
});
|
||||
|
||||
// Trigger full sync
|
||||
router.post('/sync', async (req: Request, res: Response) => {
|
||||
try {
|
||||
logger.info('Manual full sync triggered');
|
||||
|
||||
// Don't wait for completion - return immediately
|
||||
syncEngine.fullSync().catch(err => {
|
||||
logger.error('Full sync failed', err);
|
||||
});
|
||||
|
||||
res.json({
|
||||
status: 'started',
|
||||
message: 'Full sync started in background',
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('Failed to trigger full sync', error);
|
||||
res.status(500).json({ error: 'Failed to trigger sync' });
|
||||
}
|
||||
});
|
||||
|
||||
// Trigger sync for a specific object type
|
||||
router.post('/sync/:objectType', async (req: Request, res: Response) => {
|
||||
try {
|
||||
const { objectType } = req.params;
|
||||
|
||||
// Validate object type
|
||||
if (!OBJECT_TYPES[objectType]) {
|
||||
res.status(400).json({
|
||||
error: `Unknown object type: ${objectType}`,
|
||||
supportedTypes: Object.keys(OBJECT_TYPES),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
logger.info(`Manual sync triggered for ${objectType}`);
|
||||
|
||||
const result = await syncEngine.syncType(objectType as CMDBObjectTypeName);
|
||||
|
||||
res.json({
|
||||
status: 'completed',
|
||||
objectType,
|
||||
stats: result,
|
||||
});
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : 'Failed to sync object type';
|
||||
logger.error(`Failed to sync object type ${req.params.objectType}`, error);
|
||||
|
||||
// Return 409 (Conflict) if sync is already in progress, otherwise 500
|
||||
const statusCode = errorMessage.includes('already in progress') ? 409 : 500;
|
||||
res.status(statusCode).json({
|
||||
error: errorMessage,
|
||||
objectType: req.params.objectType,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Clear cache for a specific type
|
||||
router.delete('/clear/:objectType', (req: Request, res: Response) => {
|
||||
try {
|
||||
const { objectType } = req.params;
|
||||
|
||||
if (!OBJECT_TYPES[objectType]) {
|
||||
res.status(400).json({
|
||||
error: `Unknown object type: ${objectType}`,
|
||||
supportedTypes: Object.keys(OBJECT_TYPES),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
logger.info(`Clearing cache for ${objectType}`);
|
||||
|
||||
const deleted = cacheStore.clearObjectType(objectType as CMDBObjectTypeName);
|
||||
|
||||
res.json({
|
||||
status: 'cleared',
|
||||
objectType,
|
||||
deletedCount: deleted,
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error(`Failed to clear cache for ${req.params.objectType}`, error);
|
||||
res.status(500).json({ error: 'Failed to clear cache' });
|
||||
}
|
||||
});
|
||||
|
||||
// Clear entire cache
|
||||
router.delete('/clear', (req: Request, res: Response) => {
|
||||
try {
|
||||
logger.info('Clearing entire cache');
|
||||
|
||||
cacheStore.clearAll();
|
||||
|
||||
res.json({
|
||||
status: 'cleared',
|
||||
message: 'Entire cache cleared',
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('Failed to clear cache', error);
|
||||
res.status(500).json({ error: 'Failed to clear cache' });
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
|
||||
Reference in New Issue
Block a user