Skip to content

frontend: video-manager: Add support for MCM Idle state#3840

Merged
patrickelectric merged 3 commits intobluerobotics:1.4from
joaoantoniocardoso:1.4-add-mcm-idle-support
Mar 20, 2026
Merged

frontend: video-manager: Add support for MCM Idle state#3840
patrickelectric merged 3 commits intobluerobotics:1.4from
joaoantoniocardoso:1.4-add-mcm-idle-support

Conversation

@joaoantoniocardoso
Copy link
Member

@joaoantoniocardoso joaoantoniocardoso commented Mar 19, 2026

To test it, one should use MCM next-13 from my fork.

Cherry-picks to 1.4:

  • 6d909928 frontend: types: video: Add StreamStatusState and state field to StreamStatus
  • 6ea3962a frontend: components: video-manager: VideoDevice: Update stream status handling for new state field
  • 3eb791e2 frontend: components: video-manager: VideoStream: Update status display for new state field

Summary by Sourcery

Update video manager frontend to support extended stream states and configuration flags, including idle state handling and thumbnail control.

New Features:

  • Display human-readable stream state based on a new state field supporting running, idle, and stopped.
  • Expose additional extended configuration flags (lazy mode, thumbnails, zenoh) on video streams and prototypes.

Enhancements:

  • Adjust device-level status indicators and messaging to reflect overall stream health rather than simple running state.
  • Control thumbnail registration and disabled state based on stream health and per-stream configuration flags.

Summary by Sourcery

Update video manager frontend to use new stream state metadata and extended configuration flags for device status, stream display, and thumbnails.

New Features:

  • Show human-readable stream status based on a new state field supporting running, idle, stopped, and unknown states.
  • Expose additional extended stream configuration flags (lazy mode, thumbnails, zenoh) via the stream prototype model.

Enhancements:

  • Base device-level health indicators and tooltip messaging on overall stream state instead of simple running flags.
  • Control video thumbnail registration and disabled state using per-stream configuration and health, including support for disabling thumbnails globally on a device.

…amStatus

Add support for the new stream status state field from MCM with three
possible values: 'running', 'idle', and 'stopped'. This enables the
frontend to distinguish between healthy idle streams and stopped streams.
…s handling for new state field

Replace binary running check with state-based logic:
- Thumbnails now fetch when state is running or idle (not stopped)
- Status indicator shows green for running, blue for idle, red for stopped
- Add computed properties for has_healthy_streams, has_active_streams,
  has_idle_streams, and status_color
…ay for new state field

- Replace Running/Not running text with state-based display (Running, Idle, Stopped)
- Only show errors when stream state is stopped (not when idle)
- Add stream_state_text computed property for status text mapping
@sourcery-ai
Copy link

sourcery-ai bot commented Mar 19, 2026

Reviewer's Guide

Frontend video manager now supports richer stream state (running/idle/stopped) and extended configuration flags, updating device/stream status UI and thumbnail behavior to use the new state and flags instead of the legacy running boolean alone.

Sequence diagram for device status and thumbnail behavior based on stream state

sequenceDiagram
  actor User
  participant VideoDevice
  participant StreamStatus
  participant VideoThumbnail
  participant VideoControlsDialog

  User->>VideoDevice: Open device card
  VideoDevice->>StreamStatus: Read state and extended_configuration
  VideoDevice->>VideoDevice: has_healthy_streams = any stream.state != stopped
  VideoDevice->>VideoDevice: thumbnails_disabled = any extended_configuration.disable_thumbnails == true
  VideoDevice->>VideoDevice: status_color = grey|success|error
  VideoDevice->>VideoThumbnail: setProps(source, register, disabled)
  Note over VideoThumbnail: register = are_video_streams_available && has_healthy_streams && !thumbnails_disabled
  Note over VideoThumbnail: disabled = thumbnails_disabled

  User->>VideoControlsDialog: Open controls dialog
  VideoDevice->>VideoControlsDialog: pass thumbnail_register and thumbnail_disabled
  Note over VideoControlsDialog: Uses same health and thumbnail flags as device card
Loading

Class diagram for updated video stream types and configuration

classDiagram
  class ExtendedConfiguration {
    +boolean thermal
    +boolean disable_lazy
    +boolean disable_mavlink
    +boolean disable_thumbnails
    +boolean disable_zenoh
  }

  class StreamInformation {
    +CaptureConfiguration configuration
    +ExtendedConfiguration extended_configuration
    +string[] endpoints
  }

  class VideoAndStreamInformation {
    +string name
    +StreamInformation stream_information
    +VideoSourceLocal~VideoSourceGst~VideoSourceRedirect~VideoSourceOnvif video_source
  }

  class StreamStatusState {
    <<enumeration>>
    +running
    +idle
    +stopped
  }

  class StreamStatus {
    +string id
    +boolean running
    +StreamStatusState state
    +string error
    +VideoAndStreamInformation video_and_stream
  }

  class FrameInterval {
  }

  class StreamPrototype {
    +string name
    +string encode
    +FrameInterval interval
    +string[] endpoints
    +boolean thermal
    +boolean disable_lazy
    +boolean disable_mavlink
    +boolean disable_thumbnails
    +boolean disable_zenoh
  }

  StreamInformation "1" --> "1" ExtendedConfiguration : has
  VideoAndStreamInformation "1" --> "1" StreamInformation : has
  StreamStatus "1" --> "1" VideoAndStreamInformation : wraps
  StreamStatus "1" --> "1" StreamStatusState : has
  StreamPrototype ..> StreamInformation : derived_from
  StreamPrototype --> FrameInterval : uses
Loading

File-Level Changes

Change Details Files
Update device-level status indicators and thumbnail registration to use new stream state and thumbnail disable flag.
  • Replace inline color logic with computed status_color derived from stream availability and has_healthy_streams.
  • Change tooltip text and conditions to reflect healthy vs stopped streams rather than just running state.
  • Introduce has_healthy_streams computed using stream.state !== 'stopped' instead of stream.running.
  • Add thumbnails_disabled computed based on extended_configuration.disable_thumbnails across device streams.
  • Wire video-thumbnail and video-controls-dialog to use has_healthy_streams and thumbnails_disabled for register/disabled props.
core/frontend/src/components/video-manager/VideoDevice.vue
Expose new stream state and extended configuration flags at the stream level and in the prototype model.
  • Add stream_state_text computed to map stream.state to human-readable text including idle state.
  • Update status/error rendering to use stream.state === 'stopped' instead of !stream.running for error display.
  • Refactor stream_prototype construction to reuse a local extended configuration variable.
  • Extend StreamPrototype to include disable_lazy, disable_thumbnails, and disable_zenoh flags sourced from extended_configuration.
core/frontend/src/components/video-manager/VideoStream.vue
core/frontend/src/types/video.ts
Extend video stream typings to support stateful status and new extended configuration flags.
  • Introduce StreamStatusState union type with running
idle

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@joaoantoniocardoso joaoantoniocardoso marked this pull request as ready for review March 19, 2026 21:31
Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 2 issues, and left some high level feedback:

  • In has_healthy_streams, treating any stream.state that is not exactly 'stopped' as healthy may misclassify unknown or missing states; consider explicitly checking for known healthy states (e.g., 'running' | 'idle') and treating anything else as unhealthy.
  • The thumbnails_disabled computed property disables thumbnails at the device level if any one stream has disable_thumbnails set; if the intent is per-stream control rather than a global device switch, consider scoping this logic so that one stream’s setting doesn’t affect all thumbnails.
  • In VideoStream.vue, the error display now requires stream.state === 'stopped'; if there is any chance of older backends not sending state or sending unexpected values, it may be safer to fall back on the running flag or a broader condition (e.g., !stream.running) to ensure errors still render.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `has_healthy_streams`, treating any `stream.state` that is not exactly `'stopped'` as healthy may misclassify unknown or missing states; consider explicitly checking for known healthy states (e.g., `'running' | 'idle'`) and treating anything else as unhealthy.
- The `thumbnails_disabled` computed property disables thumbnails at the device level if any one stream has `disable_thumbnails` set; if the intent is per-stream control rather than a global device switch, consider scoping this logic so that one stream’s setting doesn’t affect all thumbnails.
- In `VideoStream.vue`, the error display now requires `stream.state === 'stopped'`; if there is any chance of older backends not sending `state` or sending unexpected values, it may be safer to fall back on the `running` flag or a broader condition (e.g., `!stream.running`) to ensure errors still render.

## Individual Comments

### Comment 1
<location path="core/frontend/src/components/video-manager/VideoStream.vue" line_range="212-213" />
<code_context>
     }
   },
   computed: {
+    stream_state_text(): string {
+      const stateMap: Record<string, string> = {
+        running: 'Running',
+        idle: 'Idle',
</code_context>
<issue_to_address>
**suggestion:** The `stateMap` typing loses the benefit of the `StreamStatusState` union.

`StreamStatusState` is defined, but `stateMap` uses `Record<string, string>`, so TypeScript won’t enforce that all states are covered. Typing it as `Record<StreamStatusState, string>` (or a mapped type over `StreamStatusState`) will give you compile-time checks when new states are added.

Suggested implementation:

```
  computed: {
    stream_state_text(): string {
      const stateMap: Record<StreamStatusState, string> = {
        running: 'Running',
        idle: 'Idle',
        stopped: 'Stopped',
      }

```

1. Ensure that the `StreamStatusState` type is imported or otherwise available in this `<script>` block. For example, if it lives in a shared/types file, add something like:
   `import type { StreamStatusState } from '@/types/stream'`
   near the top of the `<script>` section.
2. Confirm that `this.stream.state` is typed as `StreamStatusState`. If it is currently just `string`, consider tightening its type in the relevant interface/model so you get full compile-time coverage for all states.
</issue_to_address>

### Comment 2
<location path="core/frontend/src/types/video.ts" line_range="116-121" />
<code_context>

 export interface ExtendedConfiguration {
   thermal: boolean
+  disable_lazy: boolean
   disable_mavlink: boolean
+  disable_thumbnails: boolean
+  disable_zenoh: boolean
 }

</code_context>
<issue_to_address>
**suggestion:** New fields in `ExtendedConfiguration` are required booleans, but usage treats them as optional.

These fields are typed as required booleans, but callers use optional chaining and `?? false`, implying they may be absent. To align types with actual usage and avoid defensive access patterns, consider making them optional (e.g. `thermal?: boolean`) and defaulting to `false` at use sites.

Suggested implementation:

```typescript
export interface ExtendedConfiguration {
  thermal?: boolean
  disable_lazy?: boolean
  disable_mavlink?: boolean
  disable_thumbnails?: boolean
  disable_zenoh?: boolean
}

```

To fully implement the suggestion, callers that currently access these fields defensively (e.g. `config?.extended?.disable_lazy ?? false`) can safely keep that pattern, which now matches the optional typing. If you centralize defaults (for example, when normalizing configuration objects), you can set these fields to `false` there and then simplify call sites to non-optional access (`config.extended.disable_lazy`) in those normalized contexts.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +212 to +213
stream_state_text(): string {
const stateMap: Record<string, string> = {
Copy link

Choose a reason for hiding this comment

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

suggestion: The stateMap typing loses the benefit of the StreamStatusState union.

StreamStatusState is defined, but stateMap uses Record<string, string>, so TypeScript won’t enforce that all states are covered. Typing it as Record<StreamStatusState, string> (or a mapped type over StreamStatusState) will give you compile-time checks when new states are added.

Suggested implementation:

  computed: {
    stream_state_text(): string {
      const stateMap: Record<StreamStatusState, string> = {
        running: 'Running',
        idle: 'Idle',
        stopped: 'Stopped',
      }

  1. Ensure that the StreamStatusState type is imported or otherwise available in this <script> block. For example, if it lives in a shared/types file, add something like:
    import type { StreamStatusState } from '@/types/stream'
    near the top of the <script> section.
  2. Confirm that this.stream.state is typed as StreamStatusState. If it is currently just string, consider tightening its type in the relevant interface/model so you get full compile-time coverage for all states.

Comment on lines 116 to +121
export interface ExtendedConfiguration {
thermal: boolean
disable_lazy: boolean
disable_mavlink: boolean
disable_thumbnails: boolean
disable_zenoh: boolean
Copy link

Choose a reason for hiding this comment

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

suggestion: New fields in ExtendedConfiguration are required booleans, but usage treats them as optional.

These fields are typed as required booleans, but callers use optional chaining and ?? false, implying they may be absent. To align types with actual usage and avoid defensive access patterns, consider making them optional (e.g. thermal?: boolean) and defaulting to false at use sites.

Suggested implementation:

export interface ExtendedConfiguration {
  thermal?: boolean
  disable_lazy?: boolean
  disable_mavlink?: boolean
  disable_thumbnails?: boolean
  disable_zenoh?: boolean
}

To fully implement the suggestion, callers that currently access these fields defensively (e.g. config?.extended?.disable_lazy ?? false) can safely keep that pattern, which now matches the optional typing. If you centralize defaults (for example, when normalizing configuration objects), you can set these fields to false there and then simplify call sites to non-optional access (config.extended.disable_lazy) in those normalized contexts.

@patrickelectric patrickelectric merged commit 8b7ec5e into bluerobotics:1.4 Mar 20, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants