8000 chore: display the stop button in a compose section by vzhukovs · Pull Request #13519 · podman-desktop/podman-desktop · GitHub
[go: up one dir, main page]

Skip to content

Conversation

vzhukovs
Copy link
Contributor
@vzhukovs vzhukovs commented Aug 7, 2025

What does this PR do?

Display the stop button if any container in the compose section has running status.

Screenshot / video of UI

What issues does this PR fix or reference?

#10406

How to test this PR?

Deploy the following compose file:

# compose.yml
version: "3.9"

services:
  service_one:
    image: alpine:latest
    container_name: service_one
    command: ["sleep", "infinity"]
    restart: "no"

  service_two:
    image: alpine:latest
    container_name: service_two
    command: ["sleep", "infinity"]
    restart: "no"

  service_three:
    image: alpine:latest
    container_name: service_three
    command: ["sleep", "infinity"]
    restart: "no"

  service_four:
    image: alpine:latest
    container_name: service_four
    command: ["sleep", "infinity"]
    restart: "no"

and try to manually run/stop the containers in compose section of Container List.

  • Tests are covering the bug fix or the new feature

Signed-off-by: Vladyslav Zhukovskyi <vzhukovs@redhat.com>
@vzhukovs vzhukovs requested review from benoitf and a team as code owners August 7, 2025 11:26
@vzhukovs vzhukovs requested review from cdrage and MarsKubeX and removed request for a team August 7, 2025 11:26
Copy link
Contributor
coderabbitai bot commented Aug 7, 2025
📝 Walkthrough

Walkthrough

Adds unit tests for ComposeActions covering Start/Stop visibility across container-state combinations and during asynchronous start/stop operations (introduces Deferred helper and window.startContainersByLabel / window.stopContainersByLabel stubs). Modifies ComposeActions.svelte internals: introduces derived booleans someNeedStart, someNeedStop and toggles hideStartForStop, hideStopForStart; startCompose/stopCompose set these toggles before initiating actions. Start/Stop button bindings (hidden, enabled, inProgress) are updated to use the new reactive variables. No public/exported API changes.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~15 minutes

Suggested reviewers

  • benoitf
  • axel7083
  • SoniaSandler
  • odockal

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
8000

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor
@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 @vzhukovs - I've reviewed your changes - here's some feedback:

  • Consider defining explicit showStart and showStop reactive helpers (e.g. $: showStart = someStopped && !isStarting) instead of negating someStopped/someRunning in the hidden prop for better readability.
  • The new test only checks that the buttons get hidden—add complementary assertions for when the buttons should be visible under different container states to cover both show/hide paths.
  • Add a safe fallback (compose.containers ?? []) in your reactive someRunning/someStopped declarations to avoid potential runtime errors if containers ever becomes undefined.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- Consider defining explicit showStart and showStop reactive helpers (e.g. `$: showStart = someStopped && !isStarting`) instead of negating someStopped/someRunning in the hidden prop for better readability.
- The new test only checks that the buttons get hidden—add complementary assertions for when the buttons should be visible under different container states to cover both show/hide paths.
- Add a safe fallback (`compose.containers ?? []`) in your reactive someRunning/someStopped declarations to avoid potential runtime errors if containers ever becomes undefined.

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.

Copy link
codecov bot commented Aug 7, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Copy link
Contributor
@MarsKubeX MarsKubeX left a comment

Choose a reason for hiding this comment

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

Grabacion.de.pantalla.2025-08-08.a.las.10.07.04.mov

While testing the PR, I noticed an issue with the bulk stop functionality. When stopping all services from the parent compose resource, the Run and Stop buttons disappear immediately. This prevents the user from receiving any visual feedback from buttons (loader spinner around buttons) that the services are in the process of shutting down.

Signed-off-by: Vladyslav Zhukovskyi <vzhukovs@redhat.com>
@vzhukovs
Copy link
Contributor Author

Grabacion.de.pantalla.2025-08-08.a.las.10.07.04.mov

While testing the PR, I noticed an issue with the bulk stop functionality. When stopping all services from the parent compose resource, the Run and Stop buttons disappear immediately. This prevents the user from receiving any visual feedback from buttons (loader spinner around buttons) that the services are in the process of shutting down.

Updated a bit behaviour. Now buttons don't disappear during toggling state:
compose_controls

Copy link
Contributor
@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (7)
packages/renderer/src/lib/compose/ComposeActions.svelte (4)

31-36: Normalize derived flags to booleans; consider resetting toggle flags after actions

  • Derivations can become undefined when compose.containers is falsy, which then flips semantics in !someNeedStart/Stop. Make them explicitly boolean.
  • Also consider resetting hideStartForStop/hideStopForStart once actions complete to avoid stale state lingering (even if not currently used when actionInProgress is false).

Apply this diff to normalize booleans:

-$: someNeedStart = compose.containers?.some(c => c.state !== 'RUNNING');
-$: someNeedStop = compose.containers?.some(c => c.state === 'RUNNING');
+$: someNeedStart = compose.containers?.some(c => c.state !== 'RUNNING') ?? false;
+$: someNeedStop = compose.containers?.some(c => c.state === 'RUNNING') ?? false;

And update inProgress to reset toggles after completion (outside the selected range):

function inProgress(inProgress: boolean, state?: string): void {
  compose.actionInProgress = inProgress;
  if (inProgress) {
    compose.actionError = '';
  } else {
    // reset visibility guards after any action
    hideStartForStop = false;
    hideStopForStart = false;
  }
  if (state) compose.status = state;
  for (const container of compose.containers) {
    container.actionInProgress = inProgress;
    if (inProgress) container.actionError = '';
    if (state) container.state = state;
  }
  onUpdate(compose);
}

67-77: Guard against re-entrancy/double-clicks in startCompose

Even though the UI disables the button while in progress, it’s cheap to harden the handler against rapid clicks or programmatic calls.

async function startCompose(): Promise<void> {
+  if (compose.actionInProgress) return;
   hideStopForStart = !someNeedStop;
   inProgress(true, 'STARTING');
   try {
     await window.startContainersByLabel(compose.engineId, composeLabel, compose.name);
   } catch (error) {
     handleError(String(error));
   } finally {
     inProgress(false);
   }
}

78-88: Guard against re-entrancy/double-clicks in stopCompose

Same rationale as startCompose.

async function stopCompose(): Promise<void> {
+  if (compose.actionInProgress) return;
   hideStartForStop = !someNeedStart;
   inProgress(true, 'STOPPING');
   try {
     await window.stopContainersByLabel(compose.engineId, composeLabel, compose.name);
   } catch (error) {
     handleError(String(error));
   } finally {
     inProgress(false);
   }
}

133-139: Readable hidden logic: extract to named reactive variables

The ternary with nested conditions is correct but a bit dense. Extracting into startHidden improves readability and keeps template clean.

Inside the script (outside this range):

$: startHidden = !compose.actionInProgress
  ? !someNeedStart
  : (compose.status === 'STOPPING' && hideStartForStop);

Then update here:

-  hidden={
-    !compose.actionInProgress
-      ? !someNeedStart
-      : (compose.status === 'STOPPING' && hideStartForStop)
-  }
+  hidden={startHidden}
packages/renderer/src/lib/compose/ComposeActions.spec.ts (3)

163-197: Stabilize the STOPPING-phase test; avoid resolving if you only assert “during STOPPING”

You resolve the deferred promise but don’t wait for the action to complete, so assertions still run in the STOPPING phase by accident. Either remove the resolve or assert both the in-progress and post-completion states to make the test intention explicit.

Option A (keep it “during STOPPING”): remove the resolve

-  dStop.resolve();
-
   expect(ui.getByRole('button', { name: 'Start Compose', hidden: true })).toHaveClass('hidden');
   expect(ui.getByRole('button', { name: 'Stop Compose' })).not.toHaveClass('hidden');

Option B (also assert after completion): wait for completion and then assert the final visibility

dStop.resolve();
await waitFor(() => expect(composeAllRunning.actionInProgress).toBe(false));
// add final-state assertions here

199-233: Same stabilization for the STARTING-phase test

Mirror the approach from the STOPPING test: either don’t resolve when asserting “during STARTING” or explicitly wait for completion and assert final state.

Option A (STOPPING-phase only):

-  dStart.resolve();
-
   expect(ui.getByRole('button', { name: 'Stop Compose', hidden: true })).toHaveClass('hidden');
   expect(ui.getByRole('button', { name: 'Start Compose' })).not.toHaveClass('hidden');

Option B (also assert after completion):

dStart.resolve();
await waitFor(() => expect(composeAllStopped.actionInProgress).toBe(false));
// add final-state assertions here

235-270: Clarify intent for partial RUNNING set; avoid accidental timing dependence

Same pattern: if the goal is to assert “during STOPPING”, don’t resolve; if you want to assert both phases, wait for completion before final assertions.

Option A:

-  dStop.resolve();
-
   expect(ui.getByRole('button', { name: 'Start Compose' })).not.toHaveClass('hidden');
   expect(ui.getByRole('button', { name: 'Stop Compose' })).not.toHaveClass('hidden');

Option B:

dStop.resolve();
await waitFor(() => expect(composePartial.actionInProgress).toBe(false));
// add final-state assertions here
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled
  • Linear integration is disabled

You can enable these settings in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between ddaf361 and 2f63a61.

📒 Files selected for processing (2)
  • packages/renderer/src/lib/compose/ComposeActions.spec.ts (3 hunks)
  • packages/renderer/src/lib/compose/ComposeActions.svelte (5 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
packages/renderer/src/lib/compose/ComposeActions.spec.ts (1)
packages/renderer/src/lib/container/ContainerInfoUI.ts (1)
  • ContainerInfoUI (47-74)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
  • GitHub Check: unit tests / ubuntu-24.04
  • GitHub Check: smoke e2e tests (development)
  • GitHub Check: unit tests / macos-15
  • GitHub Check: linter, formatters
  • GitHub Check: smoke e2e tests (production)
  • GitHub Check: unit tests / windows-2025
  • GitHub Check: typecheck
  • GitHub Check: Linux
  • GitHub Check: macOS
  • GitHub Check: Windows
  • GitHub Check: build website
🔇 Additional comments (4)
packages/renderer/src/lib/compose/ComposeActions.svelte (1)

147-154: LGTM: Stop button visibility now correctly reflects running containers

The updated hidden logic ensures the Stop button is shown whenever any container is running, matching the PR objective. Enabling/disabling tied to actionInProgress is consistent.

packages/renderer/src/lib/compose/ComposeActions.spec.ts (3)

21-21: LGTM: Scoped queries with within

Using within(container) avoids global-query leakage and keeps assertions localized.


23-23: LGTM: Importing Mock type for safe casting

Explicit Mock typing for window stubs makes intent clear and avoids brittle any-casts.


68-82: LGTM: Deferred helper to simulate async actions

The Deferred pattern cleanly simulates long-running start/stop operations and keeps tests deterministic.

@vzhukovs vzhukovs merged commit ce73e5f into podman-desktop:main Aug 18, 2025
24 of 38 checks passed
@podman-desktop-bot podman-desktop-bot added this to the 1.21.0 milestone Aug 18, 2025
gastoner pushed a commit to gastoner/podman-desktop that referenced this pull request Aug 27, 2025
…3519)

* chore: display the stop button in a compose section

Signed-off-by: Vladyslav Zhukovskyi <vzhukovs@redhat.com>

* chore: display the stop button in a compose section

Signed-off-by: Vladyslav Zhukovskyi <vzhukovs@redhat.com>

---------

Signed-off-by: Vladyslav Zhukovskyi <vzhukovs@redhat.com>
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.

Compose: Showing the stop button even if not all containers are running
5 participants
0