UI styling improvements: dashboard headers and navigation
- Restore blue PageHeader on Dashboard (/app-components) - Update homepage (/) with subtle header design without blue bar - Add uniform PageHeader styling to application edit page - Fix Rapporten link on homepage to point to /reports overview - Improve header descriptions spacing for better readability
This commit is contained in:
176
backend/src/api/controllers/ObjectsController.ts
Normal file
176
backend/src/api/controllers/ObjectsController.ts
Normal file
@@ -0,0 +1,176 @@
|
||||
/**
|
||||
* ObjectsController - API handlers for object operations
|
||||
*
|
||||
* NO SQL, NO parsing - delegates to services.
|
||||
*/
|
||||
|
||||
import { Request, Response } from 'express';
|
||||
import { logger } from '../../services/logger.js';
|
||||
import { getServices } from '../../services/ServiceFactory.js';
|
||||
import type { CMDBObject, CMDBObjectTypeName } from '../../generated/jira-types.js';
|
||||
import { getParamString, getQueryString, getQueryNumber } from '../../utils/queryHelpers.js';
|
||||
|
||||
export class ObjectsController {
|
||||
/**
|
||||
* Get a single object by ID or objectKey
|
||||
* GET /api/v2/objects/:type/:id?refresh=true
|
||||
* Supports both object ID and objectKey (checks objectKey if ID lookup fails)
|
||||
*/
|
||||
async getObject(req: Request, res: Response): Promise<void> {
|
||||
try {
|
||||
const type = getParamString(req, 'type');
|
||||
const idOrKey = getParamString(req, 'id');
|
||||
const forceRefresh = getQueryString(req, 'refresh') === 'true';
|
||||
|
||||
const services = getServices();
|
||||
|
||||
// Try to find object ID if idOrKey might be an objectKey
|
||||
let objectId = idOrKey;
|
||||
let objRecord = await services.cacheRepo.getObject(idOrKey);
|
||||
if (!objRecord) {
|
||||
// Try as objectKey
|
||||
objRecord = await services.cacheRepo.getObjectByKey(idOrKey);
|
||||
if (objRecord) {
|
||||
objectId = objRecord.id;
|
||||
}
|
||||
}
|
||||
|
||||
// Force refresh if requested
|
||||
if (forceRefresh && objectId) {
|
||||
const enabledTypes = await services.schemaRepo.getEnabledObjectTypes();
|
||||
const enabledTypeSet = new Set(enabledTypes.map(t => t.typeName));
|
||||
|
||||
const refreshResult = await services.refreshService.refreshObject(objectId, enabledTypeSet);
|
||||
if (!refreshResult.success) {
|
||||
res.status(500).json({ error: refreshResult.error || 'Failed to refresh object' });
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Get from cache
|
||||
if (!objectId) {
|
||||
res.status(404).json({ error: 'Object not found (by ID or key)' });
|
||||
return;
|
||||
}
|
||||
|
||||
const object = await services.queryService.getObject<CMDBObject>(type as CMDBObjectTypeName, objectId);
|
||||
|
||||
if (!object) {
|
||||
res.status(404).json({ error: 'Object not found' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json(object);
|
||||
} catch (error) {
|
||||
logger.error('ObjectsController: Failed to get object', error);
|
||||
res.status(500).json({ error: 'Failed to get object' });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all objects of a type
|
||||
* GET /api/v2/objects/:type?limit=100&offset=0&search=term
|
||||
*/
|
||||
async getObjects(req: Request, res: Response): Promise<void> {
|
||||
try {
|
||||
const type = getParamString(req, 'type');
|
||||
const limit = getQueryNumber(req, 'limit', 1000);
|
||||
const offset = getQueryNumber(req, 'offset', 0);
|
||||
const search = getQueryString(req, 'search');
|
||||
|
||||
const services = getServices();
|
||||
|
||||
logger.info(`ObjectsController.getObjects: Querying for type="${type}" with limit=${limit}, offset=${offset}, search=${search || 'none'}`);
|
||||
|
||||
let objects: CMDBObject[];
|
||||
if (search) {
|
||||
objects = await services.queryService.searchByLabel<CMDBObject>(
|
||||
type as CMDBObjectTypeName,
|
||||
search,
|
||||
{ limit, offset }
|
||||
);
|
||||
} else {
|
||||
objects = await services.queryService.getObjects<CMDBObject>(
|
||||
type as CMDBObjectTypeName,
|
||||
{ limit, offset }
|
||||
);
|
||||
}
|
||||
|
||||
const totalCount = await services.queryService.countObjects(type as CMDBObjectTypeName);
|
||||
|
||||
logger.info(`ObjectsController.getObjects: Found ${objects.length} objects of type "${type}" (total count: ${totalCount})`);
|
||||
|
||||
// If no objects found, provide diagnostic information
|
||||
if (objects.length === 0) {
|
||||
// Check what object types actually exist in the database
|
||||
const db = services.cacheRepo.db;
|
||||
try {
|
||||
const availableTypes = await db.query<{ object_type_name: string; count: number }>(
|
||||
`SELECT object_type_name, COUNT(*) as count
|
||||
FROM objects
|
||||
GROUP BY object_type_name
|
||||
ORDER BY count DESC
|
||||
LIMIT 10`
|
||||
);
|
||||
|
||||
if (availableTypes.length > 0) {
|
||||
logger.warn(`ObjectsController.getObjects: No objects found for type "${type}". Available types in database:`, {
|
||||
requestedType: type,
|
||||
availableTypes: availableTypes.map(t => ({ typeName: t.object_type_name, count: t.count })),
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
logger.debug('ObjectsController.getObjects: Failed to query available types', error);
|
||||
}
|
||||
}
|
||||
|
||||
res.json({
|
||||
objectType: type,
|
||||
objects,
|
||||
count: objects.length,
|
||||
totalCount,
|
||||
offset,
|
||||
limit,
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('ObjectsController: Failed to get objects', error);
|
||||
res.status(500).json({ error: 'Failed to get objects' });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an object
|
||||
* PUT /api/v2/objects/:type/:id
|
||||
*/
|
||||
async updateObject(req: Request, res: Response): Promise<void> {
|
||||
try {
|
||||
const type = getParamString(req, 'type');
|
||||
const id = getParamString(req, 'id');
|
||||
const updates = req.body as Record<string, unknown>;
|
||||
|
||||
const services = getServices();
|
||||
|
||||
const result = await services.writeThroughService.updateObject(
|
||||
type as CMDBObjectTypeName,
|
||||
id,
|
||||
updates
|
||||
);
|
||||
|
||||
if (!result.success) {
|
||||
res.status(400).json({ error: result.error || 'Failed to update object' });
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch updated object
|
||||
const updated = await services.queryService.getObject<CMDBObject>(
|
||||
type as CMDBObjectTypeName,
|
||||
id
|
||||
);
|
||||
|
||||
res.json(updated || { success: true });
|
||||
} catch (error) {
|
||||
logger.error('ObjectsController: Failed to update object', error);
|
||||
res.status(500).json({ error: 'Failed to update object' });
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user