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

10 KiB

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

// 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

// 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:

// 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.