Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
0776d64
feat: add entity-specific panels and improve visual hierarchy
bburda Jan 26, 2026
5871c4b
feat: add skeleton loading states and theme toggle
bburda Jan 26, 2026
7e21a5a
feat: add server info panel showing SOVD capabilities
bburda Jan 26, 2026
857748f
feat: add Ctrl+K keyboard shortcut for entity search
bburda Jan 26, 2026
dab1abe
feat: add FaultsDashboard for system-wide fault monitoring
bburda Jan 26, 2026
bb3601f
feat: add ErrorBoundary component for graceful error handling
bburda Jan 26, 2026
aa04841
feat(a11y): add ARIA labels to tree navigation
bburda Jan 26, 2026
2bdaef9
feat(responsive): add mobile-first responsive layout
bburda Jan 26, 2026
778694e
refactor: show entity resources in detail panel instead of tree subfo…
bburda Jan 26, 2026
0c0e5c2
feat: add SOVD Server as root entity in tree
bburda Jan 26, 2026
cbf430d
fix: address PR #21 review comments
bburda Jan 27, 2026
c5b0a5e
refactor: remove dead VirtualFolderData code
bburda Jan 27, 2026
1782e78
feat: add tree view mode toggle (Logical/Functional)
bburda Jan 27, 2026
73be4ac
feat(panels): add resource tabs (Data, Operations, Config, Faults) to…
bburda Jan 27, 2026
b3eb69b
fix(detail-panel): hide redundant 'No detailed information' card for …
bburda Jan 27, 2026
fa8cfd0
fix(apps-panel): use ConfigurationPanel for inline parameter editing
bburda Jan 27, 2026
a5d3bb4
fix(apps-panel): use FaultsPanel for detailed fault view with clear s…
bburda Jan 27, 2026
333a3fb
fix(api): transform data items response to ComponentTopic format
bburda Jan 28, 2026
b1b2a21
refactor(api): unify resource fetching with generic getResources method
bburda Jan 28, 2026
6caa504
refactor: rename componentId to entityId in resource panels
bburda Jan 28, 2026
dd58829
fix: unify FaultsPanel across all entity views and fix fault clearing
bburda Jan 28, 2026
59b8925
refactor: address PR review feedback for code quality improvements
bburda Jan 29, 2026
66f4a0b
docs: update copilot instructions and add search limitation note
bburda Jan 29, 2026
75579d8
fix: improve accessibility and state management
bburda Jan 29, 2026
3594a87
fix: add validation logging for data quality issues
bburda Jan 29, 2026
a7eeac4
fix: improve error messaging and clarify tree node consistency
bburda Jan 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 116 additions & 36 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,92 +8,172 @@ React 19 + Vite + TypeScript SPA for browsing SOVD (Service-Oriented Vehicle Dia

```
src/
├── components/ # React components
│ ├── ui/ # shadcn/ui primitives (Button, Card, Dialog, etc.)
│ ├── EntityTreeSidebar.tsx # Main navigation tree
│ ├── EntityDetailPanel.tsx # Entity details view
│ ├── OperationsPanel.tsx # ROS 2 service/action invocation
│ ├── ConfigurationPanel.tsx # ROS 2 parameter management
│ └── DataFolderPanel.tsx # Topic subscriptions
├── components/ # React components
│ ├── ui/ # shadcn/ui primitives (Button, Card, Dialog, etc.)
│ ├── EntityTreeSidebar.tsx # Main navigation tree with collapsible nodes
│ ├── EntityTreeNode.tsx # Tree node component with expand/collapse
│ ├── EntityDetailPanel.tsx # Entity details view (dispatch to type-specific panels)
│ ├── EntityResourceTabs.tsx # Tabbed interface for data/operations/configs/faults
│ ├── ServerInfoPanel.tsx # Server connection info and capabilities
│ ├── OperationsPanel.tsx # ROS 2 service/action invocation
│ ├── ConfigurationPanel.tsx # ROS 2 parameter management
│ ├── FaultsDashboard.tsx # System-wide faults view with filtering
│ ├── FaultsPanel.tsx # Entity-specific faults
│ ├── SearchCommand.tsx # Ctrl+K command palette for entity search
│ └── ServerConnectionDialog.tsx # Server URL input dialog
├── lib/
│ ├── sovd-api.ts # Typed HTTP client for gateway REST API
│ ├── store.ts # Zustand state management
│ ├── types.ts # TypeScript interfaces for API types
│ ├── schema-utils.ts # JSON Schema utilities
│ └── utils.ts # Utility functions
│ ├── sovd-api.ts # Typed HTTP client for gateway REST API
│ ├── store.ts # Zustand state management (entity tree, selection, faults)
│ ├── types.ts # TypeScript interfaces for API types
│ ├── schema-utils.ts # JSON Schema utilities for form generation
│ └── utils.ts # Utility functions
└── test/
└── setup.ts # Vitest setup
└── setup.ts # Vitest setup
```

## Entity Model

**SOVD entity hierarchy:**

- **Area** → namespace grouping (e.g., `/powertrain`, `/chassis`)
- **Subarea** → nested namespace
- **Component** → logical grouping, contains apps
- **Subcomponent** → nested component
- **App** → individual ROS 2 node
- **Function** → capability grouping (functional view)

**Resources** (available on components/apps/functions/areas):

- `data` → ROS 2 topics
- `operations` → ROS 2 services and actions
- `configurations` → ROS 2 parameters
- `faults` → diagnostic trouble codes

## Key Patterns

### State Management (Zustand)

```typescript
// src/lib/store.ts
export const useStore = create<AppState>()(
export const useAppStore = create<AppState>()(
persist(
(set, get) => ({
// Connection state
serverUrl: 'http://localhost:8080',
serverUrl: null,
client: null,
isConnected: false,

// Entity tree
entities: [],
selectedEntityPath: null,
rootEntities: [],
selectedPath: null,
selectedEntity: null,
expandedPaths: [],

// Shared faults state (used by FaultsDashboard and FaultsCountBadge)
faults: [],
isLoadingFaults: false,

// Actions
selectEntity: (path) => set({ selectedEntityPath: path }),
connect: async (url) => {
/* ... */
},
selectEntity: async (path) => {
/* ... */
},
loadChildren: async (path) => {
/* ... */
},
fetchFaults: async () => {
/* ... */
},
}),
{ name: 'sovd-ui-storage' }
{ name: 'sovd_web_ui_server_url', partialize: (state) => ({ serverUrl, baseEndpoint }) }
)
);
```

### Entity Selection Handlers

The `selectEntity` action uses type-specific handlers for cleaner code:

```typescript
// Handlers extracted from selectEntity for maintainability
handleTopicSelection(ctx, client); // Async - may fetch full topic data
handleServerSelection(ctx); // Show server info panel
handleComponentSelection(ctx); // Auto-expand, show resources
handleAreaSelection(ctx); // Auto-expand
handleFunctionSelection(ctx); // Show function with hosts
handleAppSelection(ctx); // Show app details
handleFaultSelection(ctx); // Show fault details
handleParameterSelection(ctx); // Show parameter editor
handleOperationSelection(ctx); // Show operation invocation
```

### API Client

```typescript
// src/lib/sovd-api.ts
export class SovdApiClient {
constructor(private baseUrl: string) {}

async getComponents(): Promise<Component[]> {
const response = await fetch(`${this.baseUrl}/api/v1/components`);
return response.json();
}
// Entity listing
async getAreas(): Promise<Area[]>;
async getComponents(): Promise<Component[]>;
async getApps(): Promise<App[]>;
async getFunctions(): Promise<SovdFunction[]>;

// Entity resources
async getEntityData(entityType, entityId): Promise<ComponentTopic[]>;
async listOperations(entityId, entityType): Promise<Operation[]>;
async listConfigurations(entityId, entityType): Promise<ConfigurationResponse>;
async listEntityFaults(entityType, entityId): Promise<FaultsResponse>;

// Operations (SOVD Execution Model)
async createExecution(entityId, operationName, request): Promise<CreateExecutionResponse>;
async getExecutionStatus(entityId, operationName, executionId): Promise<Execution>;
async cancelExecution(entityId, operationName, executionId): Promise<void>;
}
```

## Conventions

- Use Zustand for client state
- Use `useAppStore` with `useShallow` for selective subscriptions
- All API types defined in `lib/types.ts`
- Use `@/` path alias for imports from src
- Prefer composition over inheritance
- Use shadcn/ui components from `components/ui/`
- Resources (data, operations, configurations, faults) shown in detail panel tabs, not as tree nodes
- Lazy load resources per tab in `EntityResourceTabs` to avoid unnecessary API calls
- Format with Prettier (automatic via husky pre-commit)

## Testing

- Unit tests: `*.test.ts` next to source files
- Integration tests: `src/test/integration/`
- Use `@testing-library/react` for component tests
- Run tests: `npm test`
- Run lint: `npm run lint`

## Gateway API Reference

Default base URL: `http://localhost:8080/api/v1`

| Method | Endpoint | Description |
| ------ | ---------------------------------------- | ------------------------------------ |
| GET | `/areas` | List all areas (namespace groupings) |
| GET | `/components` | List all components |
| GET | `/apps` | List all apps (ROS 2 nodes) |
| GET | `/components/{id}/data` | List data topics for component |
| GET | `/components/{id}/operations` | List operations (services/actions) |
| GET | `/components/{id}/configurations` | List configurations (parameters) |
| POST | `/components/{id}/operations/{name}` | Call operation |
| PUT | `/components/{id}/configurations/{name}` | Update configuration |
| Method | Endpoint | Description |
| ------ | ------------------------------------------- | ------------------------------------ |
| GET | `/areas` | List all areas (namespace groupings) |
| GET | `/components` | List all components |
| GET | `/apps` | List all apps (ROS 2 nodes) |
| GET | `/functions` | List all functions |
| GET | `/{entity_type}/{id}/data` | List data topics for entity |
| GET | `/{entity_type}/{id}/operations` | List operations (services/actions) |
| GET | `/{entity_type}/{id}/configurations` | List configurations (parameters) |
| GET | `/{entity_type}/{id}/faults` | List faults for entity |
| GET | `/faults` | List all faults across system |
| POST | `/{entity_type}/{id}/operations/{name}` | Create execution (call operation) |
| DELETE | `/{entity_type}/{id}/faults/{code}` | Clear a fault |
| PUT | `/{entity_type}/{id}/configurations/{name}` | Update configuration value |

## Important Notes

- This UI connects to `ros2_medkit_gateway` running on port 8080
- Entity IDs are alphanumeric + underscore + hyphen only
- Virtual folders (data/, operations/, configurations/) are UI constructs, not API entities
- Entity types for API: `areas`, `components`, `apps`, `functions` (plural)
Loading