fix: scope FP workflow counts donut by BU

- Rewrite /fp-workflow-counts endpoint to query ivanti_findings table
  directly with optional teams ILIKE filter (replaces pre-computed JSON blob)
- Frontend passes getActiveTeamsParam() to FP counts fetch
- FP counts refresh on scope toggle change alongside open/closed counts
- Both FP Finding Status and FP Workflow Status donuts now respect BU scope
This commit is contained in:
Jordan Ramos
2026-05-06 15:19:34 -06:00
parent 6163be626e
commit cf43e85c38
2 changed files with 51 additions and 7 deletions

View File

@@ -1222,18 +1222,56 @@ function createIvantiFindingsRouter(db, requireAuth) {
*
* Return FP finding counts and unique workflow ID counts (open + closed),
* broken down by workflow status.
* Accepts optional `teams` query parameter to scope to specific BUs.
*
* @query {string} [teams] - Comma-separated team names (e.g. 'STEAM,ACCESS-ENG')
* @returns {Object} 200 - { findingCounts: Object, findingTotal: number, idCounts: Object, idTotal: number }
* @returns {Object} 500 - { error: string } on database error
*/
router.get('/fp-workflow-counts', async (req, res) => {
try {
const { rows } = await pool.query('SELECT fp_workflow_counts_json, fp_id_counts_json FROM ivanti_counts_cache WHERE id=1');
const row = rows[0];
let findingCounts = {};
let idCounts = {};
try { findingCounts = JSON.parse(row?.fp_workflow_counts_json || '{}'); } catch (_) {}
try { idCounts = JSON.parse(row?.fp_id_counts_json || '{}'); } catch (_) {}
const teamsParam = req.query.teams;
let whereExtra = '';
const params = [];
let paramIndex = 1;
if (teamsParam) {
const teams = teamsParam.split(',').map(t => t.trim()).filter(Boolean);
if (teams.length > 0) {
const patterns = teams.map(t => `%${t}%`);
whereExtra = ` AND bu_ownership ILIKE ANY($${paramIndex++}::text[])`;
params.push(patterns);
}
}
// Finding counts: number of findings per workflow state
const findingResult = await pool.query(
`SELECT workflow_state, COUNT(*) as count
FROM ivanti_findings
WHERE workflow_id IS NOT NULL ${whereExtra}
GROUP BY workflow_state`,
params
);
const findingCounts = {};
findingResult.rows.forEach(r => {
const state = r.workflow_state || 'Unknown';
findingCounts[state] = parseInt(r.count);
});
// ID counts: number of unique workflow IDs per state
const idResult = await pool.query(
`SELECT workflow_state, COUNT(DISTINCT workflow_id) as count
FROM ivanti_findings
WHERE workflow_id IS NOT NULL ${whereExtra}
GROUP BY workflow_state`,
params
);
const idCounts = {};
idResult.rows.forEach(r => {
const state = r.workflow_state || 'Unknown';
idCounts[state] = parseInt(r.count);
});
res.json({
findingCounts,
findingTotal: Object.values(findingCounts).reduce((a, b) => a + b, 0),