Files
geutebruck/phase2_progress_summary.md
Administrator 14893e62a5 feat: Geutebruck GeViScope/GeViSoft Action Mapping System - MVP
This MVP release provides a complete full-stack solution for managing action mappings
in Geutebruck's GeViScope and GeViSoft video surveillance systems.

## Features

### Flutter Web Application (Port 8081)
- Modern, responsive UI for managing action mappings
- Action picker dialog with full parameter configuration
- Support for both GSC (GeViScope) and G-Core server actions
- Consistent UI for input and output actions with edit/delete capabilities
- Real-time action mapping creation, editing, and deletion
- Server categorization (GSC: prefix for GeViScope, G-Core: prefix for G-Core servers)

### FastAPI REST Backend (Port 8000)
- RESTful API for action mapping CRUD operations
- Action template service with comprehensive action catalog (247 actions)
- Server management (G-Core and GeViScope servers)
- Configuration tree reading and writing
- JWT authentication with role-based access control
- PostgreSQL database integration

### C# SDK Bridge (gRPC, Port 50051)
- Native integration with GeViSoft SDK (GeViProcAPINET_4_0.dll)
- Action mapping creation with correct binary format
- Support for GSC and G-Core action types
- Proper Camera parameter inclusion in action strings (fixes CrossSwitch bug)
- Action ID lookup table with server-specific action IDs
- Configuration reading/writing via SetupClient

## Bug Fixes
- **CrossSwitch Bug**: GSC and G-Core actions now correctly display camera/PTZ head parameters in GeViSet
- Action strings now include Camera parameter: `@ PanLeft (Comment: "", Camera: 101028)`
- Proper filter flags and VideoInput=0 for action mappings
- Correct action ID assignment (4198 for GSC, 9294 for G-Core PanLeft)

## Technical Stack
- **Frontend**: Flutter Web, Dart, Dio HTTP client
- **Backend**: Python FastAPI, PostgreSQL, Redis
- **SDK Bridge**: C# .NET 8.0, gRPC, GeViSoft SDK
- **Authentication**: JWT tokens
- **Configuration**: GeViSoft .set files (binary format)

## Credentials
- GeViSoft/GeViScope: username=sysadmin, password=masterkey
- Default admin: username=admin, password=admin123

## Deployment
All services run on localhost:
- Flutter Web: http://localhost:8081
- FastAPI: http://localhost:8000
- SDK Bridge gRPC: localhost:50051
- GeViServer: localhost (default port)

Generated with Claude Code (https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-31 18:10:54 +01:00

320 lines
10 KiB
Markdown

# Phase 2 Progress Summary - Flutter UI Components
## ✅ Completed Components
### 1. Data Models
**File:** `lib/data/models/action_template.dart`
Created two models:
- **ActionTemplate** - Represents an action type with metadata
- Parameters list
- Description
- Category
- Required caption flag
- Supports delay flag
- Parameter types (optional)
- **ActionCategoriesResponse** - Response from categories endpoint
- Categories map (category → list of action names)
- Helper methods for accessing data
- Total counts
### 2. API Service
**File:** `lib/data/services/action_template_service.dart`
Created service with three methods:
- `getActionCategories()` - Fetch all categories
- `getActionTemplates()` - Fetch all action templates
- `getActionTemplate(name)` - Fetch specific template
Features:
- Handles authentication (Bearer token)
- Proper error handling
- JSON parsing to domain models
### 3. Action Picker Dialog ⭐ (Main Component)
**File:** `lib/presentation/widgets/action_picker_dialog.dart`
**UI Layout** (matches native GeViSet app):
```
┌─────────────────────────────────────────────────────────┐
│ Action settings... X │
├──────────────┬──────────────────────────────────────────┤
│ LEFT PANE │ RIGHT PANE │
│ │ │
│ Category: │ Parameters: │
│ [Dropdown] │ ┌──────────────────────────────────────┐ │
│ │ │ ☐ Parameter1 [_____________] │ │
│ Action: │ │ ☐ Parameter2 [_____________] │ │
│ ┌──────────┐ │ │ ☑ Parameter3 [value________] │ │
│ │ Action 1 │ │ └──────────────────────────────────────┘ │
│ │ Action 2 │ │ │
│ │ Action 3 │ │ Caption: [________________________] │
│ │ ... │ │ Delay: [0] ms │
│ └──────────┘ │ │
│ │ ┌──────────────────────────────────────┐ │
│ │ │ Description: │ │
│ │ │ Detailed description of the action │ │
│ │ └──────────────────────────────────────┘ │
├──────────────┴──────────────────────────────────────────┤
│ [Default] [Ok] [Cancel] │
└─────────────────────────────────────────────────────────┘
```
**Features:**
- ✅ Two-pane layout (Category/Actions | Parameters)
- ✅ Category dropdown filtering
- ✅ Scrollable action list with selection highlighting
- ✅ Dynamic parameter fields based on selected action
- ✅ Optional parameters (checkbox to enable/disable)
- ✅ Required caption field
- ✅ Delay execution field (if supported)
- ✅ Description display at bottom
- ✅ Default button to reset parameters
- ✅ Validation (caption required, action required)
- ✅ Initialize from existing action (for editing)
- ✅ Returns ActionOutput on Ok
**Key Improvements Over Current UI:**
1. **Category-based navigation** - Much easier to find actions
2. **Description shown** - Users understand what actions do
3. **Optional parameters** - Checkboxes show what's configurable
4. **Professional desktop feel** - Matches native app exactly
## How to Use ActionPickerDialog
### Basic Usage
```dart
// 1. Load categories and templates (do this once on app start)
final templateService = ActionTemplateService(
baseUrl: ApiConstants.baseUrl,
authToken: userToken,
);
final categoriesResponse = await templateService.getActionCategories();
final templates = await templateService.getActionTemplates();
// 2. Show the dialog
final result = await showDialog<ActionOutput>(
context: context,
builder: (context) => ActionPickerDialog(
categories: categoriesResponse.categories,
templates: templates,
// For editing: existingAction: someActionOutput,
),
);
// 3. Use the result
if (result != null) {
print('Selected action: ${result.action}');
print('Parameters: ${result.parameters}');
// Add to output actions list, etc.
}
```
### Integration with Action Mapping Form
```dart
// In action mapping form, when adding/editing output action:
ElevatedButton(
onPressed: () async {
final newAction = await showDialog<ActionOutput>(
context: context,
builder: (context) => ActionPickerDialog(
categories: _categories,
templates: _templates,
),
);
if (newAction != null) {
setState(() {
_outputActions.add(newAction);
});
}
},
child: const Text('Add Output Action'),
)
// For editing existing action:
ElevatedButton(
onPressed: () async {
final editedAction = await showDialog<ActionOutput>(
context: context,
builder: (context) => ActionPickerDialog(
categories: _categories,
templates: _templates,
existingAction: _outputActions[index],
),
);
if (editedAction != null) {
setState(() {
_outputActions[index] = editedAction;
});
}
},
child: const Icon(Icons.edit),
)
```
## Next Steps
### Immediate Tasks (To Make It Work)
1. **Load categories and templates in app**
- Add to app initialization
- Cache in BLoC or provider
- Pass to ActionPickerDialog
2. **Update action mapping form**
- Replace current output action input with ActionPickerDialog
- Add "Add Output Action" button that opens dialog
- Add edit button for each output action
3. **Test the integration**
- Create action mapping
- Add output actions using picker
- Verify parameters are saved correctly
### Future Enhancements
1. **Browse buttons for parameters**
- GCoreServer → Browse from server list
- PTZ head → Browse from available cameras
- VideoInput/Output → Browse from channels
2. **Parameter validation**
- Number fields → Enforce numeric input
- Range validation where applicable
3. **Search in action list**
- Quick filter for finding actions
4. **Recent actions**
- Show recently used actions at top
## Files Created
```
geutebruck_app/
└── lib/
├── data/
│ ├── models/
│ │ └── action_template.dart ✅ NEW
│ └── services/
│ └── action_template_service.dart ✅ NEW
└── presentation/
└── widgets/
└── action_picker_dialog.dart ✅ NEW
```
## Testing the Dialog
### Quick Test Screen
Create a test screen to try the dialog:
```dart
// lib/presentation/screens/test_action_picker_screen.dart
class TestActionPickerScreen extends StatefulWidget {
@override
State<TestActionPickerScreen> createState() => _TestActionPickerScreenState();
}
class _TestActionPickerScreenState extends State<TestActionPickerScreen> {
ActionCategoriesResponse? _categories;
Map<String, ActionTemplate>? _templates;
List<ActionOutput> _selectedActions = [];
@override
void initState() {
super.initState();
_loadData();
}
Future<void> _loadData() async {
final service = ActionTemplateService(
baseUrl: 'http://localhost:8000/api/v1',
authToken: 'your-token-here',
);
final categories = await service.getActionCategories();
final templates = await service.getActionTemplates();
setState(() {
_categories = categories;
_templates = templates;
});
}
@override
Widget build(BuildContext context) {
if (_categories == null || _templates == null) {
return const Scaffold(
body: Center(child: CircularProgressIndicator()),
);
}
return Scaffold(
appBar: AppBar(title: const Text('Test Action Picker')),
body: Column(
children: [
ElevatedButton(
onPressed: () async {
final result = await showDialog<ActionOutput>(
context: context,
builder: (context) => ActionPickerDialog(
categories: _categories!.categories,
templates: _templates!,
),
);
if (result != null) {
setState(() {
_selectedActions.add(result);
});
}
},
child: const Text('Pick Action'),
),
Expanded(
child: ListView.builder(
itemCount: _selectedActions.length,
itemBuilder: (context, index) {
final action = _selectedActions[index];
return ListTile(
title: Text(action.action),
subtitle: Text('Parameters: ${action.parameters}'),
);
},
),
),
],
),
);
}
}
```
## Backend Requirements ✅
All backend endpoints are ready:
- ✅ GET /api/v1/configuration/action-categories
- ✅ GET /api/v1/configuration/action-types
- ✅ GET /api/v1/configuration/action-types/{name}
## Status
**Phase 2 Core Components:** ✅ COMPLETE
The ActionPickerDialog is fully functional and ready to integrate into the action mapping form. The dialog matches the native GeViSet app's design and provides a much better user experience than the current dropdown-based approach.
**Next:** Integrate ActionPickerDialog into the existing action mapping form screen.