Skip to content

Add Vite + React 19 Blackhorse ʞ Graph dashboard frontend#21

Open
Igor Holt (igor-holt) wants to merge 1 commit into
mainfrom
codex/implement-blackhorse-kgraph-dashboard-8i1av7
Open

Add Vite + React 19 Blackhorse ʞ Graph dashboard frontend#21
Igor Holt (igor-holt) wants to merge 1 commit into
mainfrom
codex/implement-blackhorse-kgraph-dashboard-8i1av7

Conversation

@igor-holt
Copy link
Copy Markdown
Member

Motivation

  • Provide a standalone real-time UI for Blackhorse / ʞ Graph monitoring, visualization and operational controls.
  • Ship a Vite + React 19 + TypeScript frontend scaffold that can subscribe to Socket.IO telemetry and render knowledge-graph and telemetry visualizations.

Description

  • Scaffolded a new frontend/ app with package.json, tsconfig files, vite.config.ts, index.html, and README.md.
  • Implemented BlackhorseKGraph React component (frontend/src/BlackhorseKGraph.tsx) which includes Socket.IO subscriptions, tabbed panels for Threats/Knowledge/Modality/Sovereignty, Cytoscape graph rendering and Recharts charts, plus GLASS_BREAK and modality escalation controls.
  • Added styling in a CSS module (frontend/src/BlackhorseKGraph.module.css) providing the cyber-themed layout, responsive rules and UI components.
  • Added a TypeScript module declaration frontend/src/types/react-cytoscapejs.d.ts to satisfy missing types for react-cytoscapejs and a simple main.tsx entrypoint.

Testing

  • Ran npm install in frontend/ which completed successfully.
  • Ran npm run build in frontend/ which initially failed due to missing react-cytoscapejs types, then succeeded after adding src/types/react-cytoscapejs.d.ts.
  • Started the dev server with npm run dev -- --host 0.0.0.0 --port 4173 and captured a full-page screenshot via Playwright to validate the UI served correctly.
  • Committed the frontend/ files to the repo; build succeeded with a Vite chunk-size warning (noted) during production build.

Codex Task

@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello Igor Holt (@igor-holt), I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request adds a new frontend application to the repository, providing a user interface for monitoring and controlling the Blackhorse ʞ Graph system. The frontend is built using modern web technologies and offers real-time data visualization and interactive components for managing threats, knowledge graphs, and system modalities.

Highlights

  • Frontend Dashboard: This PR introduces a new frontend dashboard for Blackhorse ʞ Graph, built with React 19, TypeScript, and Vite.
  • Real-time Monitoring: The dashboard provides real-time monitoring, visualization, and operational controls for Blackhorse, subscribing to Socket.IO telemetry.
  • Interactive UI: The UI includes tabbed panels for Threats, Knowledge, Modality, and Sovereignty, with Cytoscape graph rendering and Recharts charts.
Changelog
  • frontend/README.md
    • Added a README file with basic information about the frontend application and instructions on how to run it.
  • frontend/index.html
    • Added the main HTML file for the frontend application, including the root div and script import.
  • frontend/package-lock.json
    • Added the package-lock.json file to manage dependencies.
  • frontend/package.json
    • Added the package.json file with dependencies and scripts for the frontend application.
  • frontend/src/BlackhorseKGraph.module.css
    • Added a CSS module for styling the BlackhorseKGraph component, providing a cyber-themed layout and responsive rules.
  • frontend/src/BlackhorseKGraph.tsx
    • Implemented the BlackhorseKGraph React component, including Socket.IO subscriptions, tabbed panels, Cytoscape graph rendering, and Recharts charts.
  • frontend/src/main.tsx
    • Added the main entry point for the React application.
  • frontend/src/types/react-cytoscapejs.d.ts
    • Added a TypeScript module declaration to provide types for react-cytoscapejs.
  • frontend/src/vite-env.d.ts
    • Added a type declaration file for Vite environment variables.
  • frontend/tsconfig.app.json
    • Added a TypeScript configuration file for the application.
  • frontend/tsconfig.json
    • Added a main TypeScript configuration file referencing the app and node configurations.
  • frontend/tsconfig.node.json
    • Added a TypeScript configuration file for Node.js.
  • frontend/vite.config.ts
    • Added a Vite configuration file with the React plugin.
Activity
  • The author scaffolded a new frontend/ app with necessary configuration files.
  • Implemented the BlackhorseKGraph React component with Socket.IO subscriptions and visualization components.
  • Added styling using a CSS module for layout and UI components.
  • Added a TypeScript module declaration for react-cytoscapejs types.
  • The author ran npm install and npm run build in frontend/ to test the build process.
  • The author started the dev server and validated the UI using Playwright.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment Gemini (@gemini-code-assist) Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on Gemini (@gemini-code-assist) comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new frontend dashboard for Blackhorse ʞ Graph monitoring. The implementation uses React 19, Vite, and TypeScript, and includes real-time data visualization with Socket.IO, Cytoscape.js, and Recharts. The code is well-structured, but there are several areas for improvement regarding maintainability and configuration. My feedback includes suggestions to use environment variables for configuration, improve type safety, and make the code more robust and easier to maintain by refactoring hardcoded values and complex logic.

const [activeTab, setActiveTab] = useState<'threats' | 'knowledge' | 'modality' | 'sovereignty'>('threats');

useEffect(() => {
const newSocket = io('ws://localhost:8080', {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The WebSocket URL is hardcoded. This makes it difficult to configure the application for different environments (development, staging, production). It's a best practice to use environment variables for such configurations.

With Vite, you can create a .env file and access the variable as import.meta.env.VITE_SOCKET_URL.

Suggested change
const newSocket = io('ws://localhost:8080', {
const newSocket = io(import.meta.env.VITE_SOCKET_URL || 'ws://localhost:8080', {

Comment on lines +1 to +6
.dashboard {
min-height: 100vh;
background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);
color: #f8fafc;
font-family: 'JetBrains Mono', 'Fira Code', monospace;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This stylesheet uses hardcoded color values in multiple places (e.g., #0f172a, #f8fafc, #334155). To improve maintainability and make theming easier, consider defining these colors as CSS custom properties (variables) in a :root block and reusing them throughout the file.

Example:

:root {
  --background-start: #0f172a;
  --text-color: #f8fafc;
  --border-color: #334155;
}

.dashboard {
  /* ... */
  background: linear-gradient(135deg, var(--background-start) 0%, #1e293b 100%);
  color: var(--text-color);
}

Comment on lines +192 to +193
target:
modality.current_model === 'Haiku' ? 'Sonnet' : modality.current_model === 'Sonnet' ? 'Opus' : 'Haiku',
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This nested ternary operator is difficult to read and maintain. Consider using a mapping object to determine the next model in the escalation sequence. This makes the logic clearer and easier to modify.

        target: ({ Haiku: 'Sonnet', Sonnet: 'Opus', Opus: 'Haiku' } as const)[modality.current_model],

<div className={styles.titleSection}>
<Shield className={styles.logoIcon} size={32} />
<h1>BLACKHORSE // ʞ GRAPH</h1>
<span className={styles.version}>v4.20-DELTA</span>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The version number is hardcoded. This can easily become out of sync with the actual version of the application in package.json. Consider injecting the version from package.json during the build process to ensure it's always up to date.

<span className={styles.version}>v4.20-DELTA</span>
</div>
<div className={styles.statusBar}>
<div className={`${styles.statusIndicator} ${styles[modality.thermal_status.toLowerCase()]}`}>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Dynamically constructing class names from API data using toLowerCase() can be fragile. If the API returns a value that doesn't have a corresponding CSS class, it will fail silently without applying the intended style. A safer approach is to use a mapping object to resolve the class name. This also applies to other similar cases in this component for sovereignty.status and threat.severity.

Comment on lines +286 to +290
cy={(cy: any) => {
cy.on('tap', 'node', (evt: any) => {
console.log('[ʞGRAPH] Node selected:', evt.target.data());
});
}}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using any for the Cytoscape instance (cy) and event (evt) bypasses TypeScript's type checking. You should provide proper types to ensure type safety. You can import Core and EventObject from the cytoscape library.

For example:

import { Core, EventObject } from 'cytoscape';

// ...
cy={(cy: Core) => {
  cy.on('tap', 'node', (evt: EventObject) => {
    console.log('[ʞGRAPH] Node selected:', evt.target.data());
  });
}}
                cy={(cy: import('cytoscape').Core) => {
                  cy.on('tap', 'node', (evt: import('cytoscape').EventObject) => {
                    console.log('[ʞGRAPH] Node selected:', evt.target.data());
                  });
                }}

@@ -0,0 +1 @@
declare module 'react-cytoscapejs';
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This module declaration is too generic and provides no type safety. To leverage TypeScript's benefits, you should define the props for the CytoscapeComponent. This will enable type checking and autocompletion where the component is used.

Example of a more complete declaration:

declare module 'react-cytoscapejs' {
  import { ElementDefinition, Stylesheet, LayoutOptions, Core } from 'cytoscape';
  import * as React from 'react';

  interface CytoscapeComponentProps {
    elements: ElementDefinition[];
    stylesheet?: Stylesheet[];
    style?: React.CSSProperties;
    layout?: LayoutOptions;
    cy?: (cy: Core) => void;
  }

  const CytoscapeComponent: React.FC<CytoscapeComponentProps>;
  export default CytoscapeComponent;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant