diff --git a/client/src/components/Widgets/LlmAlChangesQuadPlot.jsx b/client/src/components/Widgets/LlmAlChangesQuadPlot.jsx new file mode 100644 index 0000000..f8ff839 --- /dev/null +++ b/client/src/components/Widgets/LlmAlChangesQuadPlot.jsx @@ -0,0 +1,84 @@ +import VdapApi from '../../hooks/useVdapApi.js'; +import {Flex, Spinner, Text, Box, Center} from "@chakra-ui/react"; // Adjust path as needed + + +export default function LlmAlChangesQuadPlot(props) { + console.log("3. Quad Plot loaded"); + let tp_percent = 0; + let tn_percent = 0; + let fp_percent = 0; + let fn_percent = 0; + + // Clean, single-line data fetching + const { data: apiData, isLoading, error } = VdapApi('/api/v2/llm_quadrant_plot'); + + if (isLoading) return ( + + + + ); + + if (error) return ( + + {error} + + ); + + if (apiData.length === 0) return ( + + No alert level quad plot data available. + + ); + + if (apiData) { + console.log(apiData); + tp_percent = ((apiData[0]['tp_count']/apiData[0]['tot_count'])*100).toFixed(2); + tn_percent = ((apiData[0]['tn_count']/apiData[0]['tot_count'])*100).toFixed(2); + fp_percent = ((apiData[0]['fp_count']/apiData[0]['tot_count'])*100).toFixed(2); + fn_percent = ((apiData[0]['fn_count']/apiData[0]['tot_count'])*100).toFixed(2); + } + + return ( + + + {/*Alert Level Changes Quad Plot*/} + All time + + + +
+ + True Positive + {tp_percent}% + {apiData[0]['tp_count']}/{apiData[0]['tot_count']} + +
+
+ + True Negative + {tn_percent}% + {apiData[0]['tn_count']}/{apiData[0]['tot_count']} + +
+
+ +
+ + False Positive + {fp_percent}% + {apiData[0]['fp_count']}/{apiData[0]['tot_count']} + +
+
+ + False Negative + {fn_percent}% + {apiData[0]['fn_count']}/{apiData[0]['tot_count']} + +
+
+
+
+ ) + +} \ No newline at end of file diff --git a/client/src/components/Widgets/LlmAlChangesQuadPlot.stories.jsx b/client/src/components/Widgets/LlmAlChangesQuadPlot.stories.jsx new file mode 100644 index 0000000..42ba8fc --- /dev/null +++ b/client/src/components/Widgets/LlmAlChangesQuadPlot.stories.jsx @@ -0,0 +1,73 @@ +import React from 'react'; +import { Box } from '@chakra-ui/react'; +import { http, HttpResponse } from 'msw'; // Import MSW +import LlmAlChangesQuadPlot from './LlmAlChangesQuadPlot'; + +export default { + title: 'Dashboard Widgets/LLM AL Changes Quad Plot', + component: LlmAlChangesQuadPlot, + decorators: [ + (Story) => ( + + + + ), + ], +}; + +const mockData = [ + { tp: 50 }, + { tn: 250 }, + { fp: 10 }, + { fn: 5 }, + { tot_count: 315} +]; + +// Scenario LIVE: call our API for real +export const LivePopulated = {}; + +// Scenario 1: Successful API Call +export const Populated = { + parameters: { + msw: { + handlers: [ + // Intercept the exact URL your component is trying to fetch + http.get('*/api/v2/llm_quadrant_plot', () => { + // Return a 200 OK with the mock JSON + return HttpResponse.json(mockData); + }), + ], + }, + }, +}; + +// Scenario 2: The 500 Server Crash +export const ServerCrash = { + parameters: { + msw: { + handlers: [ + http.get('*/api/v2/llm_quad_plot', () => { + // Return a 500 Error + return new HttpResponse(null, { status: 500 }); + }), + ], + }, + }, +}; + +// Scenario 3: Empty State (API works, but no data returned) +export const EmptyData = { + parameters: { + msw: { + handlers: [ + http.get('*/api/v2/llm_quad_plot', () => { + return HttpResponse.json([]); + }), + ], + }, + }, +}; \ No newline at end of file diff --git a/client/src/constants/widgetRegistry.jsx b/client/src/constants/widgetRegistry.jsx index 3e763da..5b547bd 100644 --- a/client/src/constants/widgetRegistry.jsx +++ b/client/src/constants/widgetRegistry.jsx @@ -85,4 +85,15 @@ export const WIDGET_REGISTRY = { } }, + "llm_al_changes_quad_plot": { + name: "Alert Level Changes Quad Plot", + category: "Computer Science", + description: "Percentage of True-Positive, True-Negative, False-Positive, and False-Negative changes in all " + + "alert levels.", + component: lazy(() => import('../components/Widgets/LlmAlChangesQuadPlot.jsx')), + allowedSizes: { + small: { w: 3, h: 12 } + } + } + }; \ No newline at end of file