Files
cve-dashboard/frontend/src/utils/queueGrouping.js

64 lines
1.8 KiB
JavaScript
Raw Normal View History

/**
* Queue grouping utility extracts the hybrid Inventory + vendor grouping logic
* from IvantiTodoQueuePage into a testable pure function.
*
* Spec: .kiro/specs/queue-collapsible-sections
* Requirements: 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7
*/
const INVENTORY_TYPES = new Set(['CARD', 'GRANITE', 'DECOM']);
/**
* Groups visible queue items into the hybrid section layout.
*
* @param {Array} visibleItems - Queue items with status 'pending'
* @returns {Array<{key: string, label: string, type: string, items: Array}>}
*
* Rules:
* - Items with workflow_type CARD, GRANITE, or DECOM Inventory section
* - Items with workflow_type FP or Archer grouped by vendor field
* - Items with null/undefined/empty vendor placed in "Unknown" vendor section
* - Inventory section appears first (if non-empty)
* - Vendor sections sorted alphabetically by label
* - Sections with zero items are omitted from output
*/
export function groupQueueItems(visibleItems) {
const inventoryItems = [];
const vendorMap = new Map();
for (const item of visibleItems) {
if (INVENTORY_TYPES.has(item.workflow_type)) {
inventoryItems.push(item);
} else {
const vendor = item.vendor?.trim() || 'Unknown';
if (!vendorMap.has(vendor)) vendorMap.set(vendor, []);
vendorMap.get(vendor).push(item);
}
}
const sections = [];
if (inventoryItems.length > 0) {
sections.push({
key: 'inventory',
label: 'Inventory',
type: 'inventory',
items: inventoryItems,
});
}
const sortedVendors = [...vendorMap.entries()]
.sort((a, b) => a[0].localeCompare(b[0]));
for (const [vendor, items] of sortedVendors) {
sections.push({
key: `vendor:${vendor}`,
label: vendor,
type: 'vendor',
items,
});
}
return sections;
}