Files
cve-dashboard/.kiro/specs/granite-loader-export/tasks.md
Jordan Ramos a61d254ff9 Sync .kiro/ from master — v2.2.0 release batch
New specs: archer-template-library, ccp-metrics-view-restructure,
compliance-list-stale-after-sidebar-edit, compliance-metric-estimated-resolution-date,
compliance-remediation-display-fix, flexible-jira-ticket-creation,
forecast-burndown-chart, granite-loader-export, ivanti-queue-clear-completed-fix,
multi-item-jira-ticket, queue-collapsible-sections, vendor-issue-type-dropdown

New steering: archer-template-gen.md

Updated: migration-registration-check hook, remediation-plan-history spec,
gitlab-workflow, tech, versioning steering files
2026-06-04 11:27:31 -06:00

8.7 KiB
Raw Blame History

Implementation Plan: Granite Loader Sheet Export

Overview

Add a Granite Team_Device Loader xlsx generator accessible from the Ivanti Queue (for CARD/GRANITE items) and as a standalone tool. The system enriches device data from the CARD API, allows bulk defaults with per-row overrides in an editable preview table, and generates a properly formatted xlsx for upload to SNIP XperLoad. Implementation proceeds from column configuration utility → backend enrichment endpoint → frontend modal → queue integration → standalone access.

Tasks

  • 1. Create column configuration utility module

    • 1.1 Create frontend/src/utils/graniteLoaderConfig.js

      • Define LOADER_COLUMNS array with all 41 columns: id, label (exact Granite header name), group, requiredFor array
      • Define COLUMN_GROUPS ordered array for UI grouping
      • Define OPERATION_TYPES array: Change, Add, Delete, Move
      • Export getRequiredColumns(operationType) helper that returns column IDs required for the given operation
      • Export getColumnsByGroup(group) helper that returns columns in a group
      • Requirements: 2.12.6, 3.13.5
    • 1.2 Create frontend/src/utils/graniteLoaderExport.js

      • Export generateLoaderXlsx(config) function that accepts { operationType, columnIds, rows } and returns a Blob
      • Use the xlsx library (already in frontend dependencies) to create a workbook with a single "Load_Sheet" worksheet
      • First row contains exact canonical column headers from LOADER_COLUMNS (matched by columnIds, in canonical order)
      • Subsequent rows contain device data; empty values become empty cells (not "null")
      • DELETE column auto-filled with "X" when operationType is "Delete"
      • EQUIPMENT CLASS defaults to "S" unless overridden
      • Export generateFilename(operationType, teamName) helper returning Loader_{op}_{team}_{YYYY-MM-DD}.xlsx
      • Requirements: 6.16.8
  • 2. Backend CARD enrichment endpoint

    • 2.1 Add POST /api/card/enrich-batch endpoint in backend/routes/cardApi.js

      • Accept { ips: string[] } in request body
      • Validate: ips is a non-empty array, max 200 items, each item is a non-empty string
      • Require Admin or Standard_User group
      • Require CARD API to be configured (return 503 if not)
      • For each IP, attempt owner lookup with known suffixes (CTEC, NATL, CHTR, etc.)
      • Extract from asset record: equip_inst_id (from ncim_discovery, netops_granite_allips, or ise_granite_equipment), hostname, site_name, mgmt_ip_asn, responsible_team, equipment_class, equip_template, equip_status
      • Return { results: [...], enriched_count, not_found_count, total }
      • Handle per-IP errors gracefully (mark as not-found, continue with others)
      • Handle CARD API auth failures (return 502 with error message)
      • Requirements: 5.15.8
    • 2.2 Add GET /api/card/configured endpoint (or extend existing /api/card/status)

      • Return { configured: boolean } so the frontend knows whether to show the "Enrich from CARD" option
      • This may already exist as GET /api/card/status — verify and reuse if so
      • Requirements: 5.8
  • 3. Frontend LoaderModal component

    • 3.1 Create frontend/src/components/LoaderModal.js

      • Accept props: isOpen, onClose, initialDevices (array of { ip_address, hostname } or null)
      • Render modal overlay with header "Generate Granite Loader Sheet"
      • Include Operation Type selector (dropdown, defaults to "Change")
      • Include Column Selection panel with collapsible groups and checkboxes
      • Required columns for selected operation are pre-checked and disabled
      • Include "Enrich from CARD" button (hidden if CARD not configured, checked via /api/card/status on mount)
      • Include Bulk Defaults section: one input per selected column, setting value applies to all non-overridden rows
      • Include editable Preview Table: rows = devices, columns = selected columns
      • Cells are inline-editable on click; overridden cells show amber dot indicator
      • Right-click or clear button on overridden cell reverts to bulk default
      • Sticky column headers and bulk default row when scrolling
      • Validation: highlight missing required fields in red, show warning count
      • Download button: merges bulk defaults + overrides into final row data, calls generateLoaderXlsx, triggers browser download
      • Cancel button closes modal
      • Requirements: 1.2, 2.12.6, 3.13.5, 4.14.7, 6.16.8, 8.18.5
    • 3.2 Implement CARD enrichment flow in LoaderModal

      • On "Enrich from CARD" click, collect all device IPs, POST to /api/card/enrich-batch
      • Show progress indicator during request
      • On response, populate enriched fields into device rows (equip_inst_id, hostname, site_name, mgmt_ip_asn, etc.)
      • Do NOT overwrite values the user has already manually entered
      • Show warning indicators on rows where IP was not found
      • Show error toast if CARD API auth fails
      • Requirements: 5.15.7
    • 3.3 Implement standalone mode (paste IPs)

      • When initialDevices is null, show a textarea for pasting IPs (one per line or comma-separated)
      • Parse input into device rows on "Load" button click
      • Allow manually adding/removing rows via + and trash icons
      • Requirements: 7.17.4
  • 4. Integrate with Ivanti Queue page

    • 4.1 Add "Generate Loader Sheet" button to IvantiTodoQueuePage floating action bar

      • Show button when one or more selected items have workflow_type CARD or GRANITE
      • Button label: "Generate Loader Sheet" with a FileSpreadsheet icon
      • On click, open LoaderModal with initialDevices populated from selected items' ip_address and hostname
      • Requirements: 1.11.5
    • 4.2 Add standalone access point

      • Add "Granite Loader" link in the navigation drawer under Tools section (or similar)
      • Clicking opens LoaderModal in standalone mode (initialDevices = null)
      • Alternatively, add a "Generate Loader Sheet" button on the CARD status section if one exists
      • Requirements: 7.1
  • 5. Checkpoint — Verify build and basic functionality

    • Build frontend: cd frontend && npm run build
    • Verify no lint errors or build failures
    • Ensure all existing tests still pass
    • Ask the user if questions arise
  • * 6. Property-based tests for enrichment endpoint

    • * 6.1 Write property test: Enrichment result count

      • Property 1: Result count equals input count — For any array of N IPs (1 ≤ N ≤ 200), the response results array has exactly N elements
      • File: backend/__tests__/granite-loader-enrichment.property.test.js
      • Validates: Requirements 5.1, 5.2
    • * 6.2 Write property test: Found results have equip_inst_id

      • Property 2: Found results have required fields — For any result where found === true, equip_inst_id is a non-empty string
      • Validates: Requirements 5.2
    • * 6.3 Write property test: Not-found results have null fields

      • Property 3: Not-found results have null equip_inst_id — For any result where found === false, equip_inst_id is null
      • Validates: Requirements 5.4
  • * 7. Unit tests for xlsx generation

    • * 7.1 Write unit tests for generateLoaderXlsx
      • Test correct column headers in canonical order
      • Test DELETE column auto-fill for Delete operation
      • Test EQUIPMENT CLASS defaults to "S"
      • Test empty values produce empty cells (not "null" string)
      • Test bulk default + override merge produces correct row values
      • File: backend/__tests__/granite-loader-xlsx-generation.test.js
      • Validates: Requirements 6.16.8
  • 8. Final checkpoint

    • Build frontend and verify no regressions
    • Ensure all tests pass
    • Ask the user if questions arise

Notes

  • Tasks marked with * are optional property-based and unit tests that can be skipped for faster MVP
  • The xlsx library is already a frontend dependency — no new packages needed for xlsx generation
  • The CARD API enrichment reuses the existing cardApi.js helper (token management, TLS skip, etc.)
  • No database schema changes are required — this feature reads from queue items and CARD API only
  • The LoaderModal follows the same pattern as ConsolidationModal (modal overlay, form state, action buttons)
  • The preview table follows the same inline-edit pattern as the Reporting page (click to edit, amber dot for overrides)
  • Maximum 200 devices per batch aligns with CARD API pagination limits and practical XperLoad batch sizes

Task Dependency Graph

{
  "waves": [
    { "id": 0, "tasks": ["1.1", "1.2"] },
    { "id": 1, "tasks": ["2.1", "2.2"] },
    { "id": 2, "tasks": ["3.1"] },
    { "id": 3, "tasks": ["3.2", "3.3"] },
    { "id": 4, "tasks": ["4.1", "4.2"] },
    { "id": 5, "tasks": ["5"] },
    { "id": 6, "tasks": ["6.1", "6.2", "6.3", "7.1"] }
  ]
}