Skip to content

Docker#10

Merged
anirudhisonline merged 6 commits into
mainfrom
docker
May 16, 2026
Merged

Docker#10
anirudhisonline merged 6 commits into
mainfrom
docker

Conversation

@anirudhisonline
Copy link
Copy Markdown
Contributor

@anirudhisonline anirudhisonline commented May 16, 2026

Summary by CodeRabbit

  • New Features

    • Docker integration: manage containers/images, run Compose, start/stop engine, stream daemon events.
    • Docker logs viewer: real-time, searchable, virtualized logs with exec-in-container and env viewer.
    • File editing: new CodeMirror editor component and project-scoped read/write support.
    • Markdown WYSIWYG editor and README edit flow.
    • Commit view: inline image diffs.
  • Workspace / UI

    • Persistent Docker panel, docker-refresh ticks, and dirty-tab indicators.
  • Style

    • Global editor selection styling adjusted for consistency.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 16, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 2d802a4e-a821-4ed1-9c99-4335dc35ba15

📥 Commits

Reviewing files that changed from the base of the PR and between e6c7cf5 and bd0cd69.

📒 Files selected for processing (3)
  • src/lib/components/FileEditor.svelte
  • src/lib/components/MarkdownEditor.svelte
  • src/lib/components/workspace/DockerLogsTab.svelte
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/lib/components/workspace/DockerLogsTab.svelte
  • src/lib/components/MarkdownEditor.svelte
  • src/lib/components/FileEditor.svelte

📝 Walkthrough

Walkthrough

Adds full Docker management and secure project file I/O to anide: Rust Tauri commands (containers, images, compose, logs, events, engine control, exec), JS wrappers, CodeMirror/TipTap editors, Docker UI panel and logs viewer, CommitTab image diffs, and dependency/config updates.

Changes

Docker Management & File Operations Integration

Layer / File(s) Summary
Configuration and Dependencies
.claude/settings.json, package.json, src-tauri/Cargo.toml, src/routes/layout.css
Formatting/EOF update, @codemirror/lang-yaml added, Rust crates bollard, futures-util, tokio added; CodeMirror selection CSS override added.
Backend Docker Client and Types
src-tauri/src/commands/docker.rs (client/state/types)
Process-wide Bollard client (OnceLock), DockerStreamState and DockerEventState, serializable DTOs (ContainerInfo, ImageInfo, ComposeFile, DockerLogLine, ExecResult), and prewarm_docker().
Compose Scanning & Path Validation
src-tauri/src/commands/docker.rs (scan/validation)
Recursive compose-file discovery with depth/ignore heuristics and secure canonical path validation to prevent project-root escapes.
Container & Image Listing and Control
src-tauri/src/commands/docker.rs (list/control)
docker_list_containers, docker_list_images, docker_list_compose_files, and container/image start/stop/restart/remove commands.
Per-Container Log Streaming
src-tauri/src/commands/docker.rs (log stream)
docker_start_log_stream spawns cancellable followers, parses log outputs to structured lines, and emits frontend events; docker_stop_log_stream cancels.
Engine Control, Exec & Events
src-tauri/src/commands/docker.rs (ping/engine/exec/events)
docker_ping, cross-platform docker_start_engine/docker_stop_engine, docker_exec_cmd with 30s timeout, and docker_watch_events/docker_stop_watch_events.
Project File Read/Write Commands
src-tauri/src/commands/files.rs, src/lib/commands/files.js
resolve_in_project/resolve_write_in_project enforce canonical, in-project paths; read_project_file/write_project_file Tauri commands and JS wrappers added.
Module Exports & Command Registration
src-tauri/src/commands/mod.rs, src-tauri/src/lib.rs
Enable pub mod docker; and pub mod files;, register DockerStreamState and DockerEventState as managed Tauri states, extend invoke_handler with Docker/file/git commands, and call prewarm_docker() during setup.
Frontend Command Wrappers
src/lib/commands/docker.js, src/lib/commands/git.js, src/lib/commands/files.js
Thin wrappers that call Tauri invoke() for Docker, git blob-at-commit, and file commands with mapped arguments and defaults.
Docker Panel Component
src/lib/components/panels/DockerPanel.svelte
Persistent _cache, orchestrated loadAll(), event-driven debounced refresh, collapsible Containers/Compose/Images sections, per-item busy tracking, and workspace.bumpDocker() on changes.
Docker Logs Viewer Component
src/lib/components/workspace/DockerLogsTab.svelte
Session-gated log streaming via events, batched buffer capped at 20k lines, safe search/highlight, virtualized rendering, exec command integration, and env-vars modal.
File Editor & Tabs
src/lib/components/FileEditor.svelte, src/lib/components/workspace/FileTab.svelte, src/lib/components/MarkdownEditor.svelte, src/lib/components/workspace/ReadmeTab.svelte
New FileEditor (CodeMirror6) and MarkdownEditor (TipTap), FileTab delegates load/save to Tauri file commands, README editing moved to MarkdownEditor with load/save callbacks.
Workspace Store & Layout Integration
src/lib/stores/workspace.svelte.js, src/routes/app/+layout.svelte
Workspace adds dockerRefreshTick, bumpDocker(), dirtyTabIds and setTabDirty(); layout imports Docker/File components, registers docker-logs/file-edit tab types/icons, mounts Docker panel persistently, and renders new tab content branches.
Git Blob & CommitTab Image Diffs
src-tauri/src/commands/git.rs, src/lib/commands/git.js, src/lib/components/workspace/CommitTab.svelte
Adds git_read_blob_at_commit backend command and wrapper; CommitTab fetches base64 image blobs to render added/modified/deleted image diffs in the virtualized view.

Sequence Diagram(s)

sequenceDiagram
  participant Frontend as Frontend UI
  participant JS as JS Wrappers
  participant Tauri as Tauri Commands
  participant Docker as Docker Engine
  Frontend->>JS: dockerListContainers()
  JS->>Tauri: invoke docker_list_containers
  Tauri->>Docker: list containers (API)
  Docker-->>Tauri: raw container data
  Tauri-->>JS: ContainerInfo[]
  JS-->>Frontend: render containers
  Frontend->>JS: dockerStartLogStream(id)
  JS->>Tauri: invoke docker_start_log_stream
  Tauri->>Tauri: spawn background log follower (per-container flag)
  Tauri->>Frontend: emit docker:log events
  Frontend->>Frontend: append to logs buffer (cap 20k)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • anide-app/anide#9: Related changes to CommitTab virtualization and diff rendering used by this PR’s image-diff additions.
  • anide-app/anide#7: Overlaps with backend Git command changes and UI wiring touched by this PR.
  • anide-app/anide#6: Related README editing changes and Markdown editor work.

Poem

🐰 I hopped through code with tiny paws,

spun logs and compose in gentle laws,
editors hum with saved applause,
panels bloom without a pause,
carrots for every successful cause.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'Docker' is vague and generic. While it relates to the changeset (which adds Docker functionality), it is not sufficiently specific or descriptive. It fails to convey the main purpose or scope of the changes—whether it's adding Docker support, fixing Docker issues, or refactoring Docker code. Use a more descriptive title that captures the main intent, such as 'Add Docker container management UI and commands' or 'Implement Docker integration with container/compose/logs support'.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch docker

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@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: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.claude/settings.json:
- Around line 8-19: Remove the accidental debug permission entries and fix
malformed entries in the settings: delete the ad-hoc Bash-wrapped PowerShell
commands (e.g., entries that start with "Bash(Get-ChildItem ..." and the ones
that should be PowerShell(...)), remove the non-standard Read path
"Read(//d/takerest/gits/**)", and drop the malformed lines "Bash(tauri\")" and
"Bash(python -c ' *)"; if any of those commands are intentional, replace the
Bash(...) wrappers with the correct "PowerShell(...)" wrapper or supply the
complete, correctly quoted command, otherwise keep only the intended valid entry
(the original intentional line similar to the one at index 8).

In `@src-tauri/src/commands/docker.rs`:
- Line 376: The eprintln logging slices the container id with &cid[..12], which
will panic for ids shorter than 12; change these to use a safe substring
accessor like cid.get(..12).unwrap_or(&cid) (or
cid.chars().take(12).collect::<String>() if a String is preferred) when
formatting the log, and apply the same fix for the other two occurrences that
use the same pattern (the other eprintlns referencing cid at the two later
log_stream calls).

In `@src/lib/components/panels/DockerPanel.svelte`:
- Around line 55-61: The composeFiles update can come from a stale
dockerListComposeFiles() promise after projectPath changes; inside loadAll()
capture a local snapshot/token (e.g., const currentPath = projectPath or an
incremented requestId) before calling dockerListComposeFiles(), then when the
promise resolves only assign composeFiles = cf if the snapshot/token still
matches the current projectPath/requestId; alternatively await the call and
re-check projectPath before setting composeFiles to prevent out-of-order
updates.

In `@src/lib/components/workspace/DockerLogsTab.svelte`:
- Around line 68-80: The deactivate() flow stops listeners but doesn't clear any
queued requestAnimationFrame work or buffered log lines, so add logic to cancel
any scheduled RAF and clear the pending buffer: when deactivating (inside
deactivate() where streaming is set false and sessionId++ and before/after
unlistenLog/unlistenEnd), call cancelAnimationFrame(pendingRaf) if pendingRaf is
set, set pendingRaf = null, and set pending = [] (or pending.length = 0) to
discard queued lines; apply the same changes in the other deactivation branch
(the similar block around lines 83-90) so pending and pendingRaf are
consistently cleared whenever streaming stops (keep existing calls to
dockerStopLogStream and loading=false).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 24fb6ef1-9484-4715-8f1b-50680b3f0bb2

📥 Commits

Reviewing files that changed from the base of the PR and between e6b1e36 and 951e4b1.

⛔ Files ignored due to path filters (2)
  • bun.lock is excluded by !**/*.lock
  • src-tauri/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (14)
  • .claude/settings.json
  • package.json
  • src-tauri/Cargo.toml
  • src-tauri/src/commands/docker.rs
  • src-tauri/src/commands/files.rs
  • src-tauri/src/commands/mod.rs
  • src-tauri/src/lib.rs
  • src/lib/commands/docker.js
  • src/lib/commands/files.js
  • src/lib/components/panels/DockerPanel.svelte
  • src/lib/components/workspace/DockerLogsTab.svelte
  • src/lib/components/workspace/FileTab.svelte
  • src/lib/stores/workspace.svelte.js
  • src/routes/app/+layout.svelte

Comment thread .claude/settings.json Outdated
Comment thread src-tauri/src/commands/docker.rs Outdated
Comment thread src/lib/components/panels/DockerPanel.svelte
Comment thread src/lib/components/workspace/DockerLogsTab.svelte
Copy link
Copy Markdown

@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: 5

🧹 Nitpick comments (2)
src-tauri/src/commands/docker.rs (2)

185-188: 💤 Low value

Consider using buffered reading for compose file detection.

read_to_string loads the entire file into memory before checking only the first 50 lines. For large YAML files or cases where there are many files to scan, this could be inefficient.

♻️ Optional: use BufReader for efficiency
+use std::io::{BufRead, BufReader};
+
 fn is_compose_file(path: &Path) -> bool {
-    let Ok(content) = std::fs::read_to_string(path) else { return false };
-    content.lines().take(50).any(|line| line.starts_with("services:"))
+    let Ok(file) = std::fs::File::open(path) else { return false };
+    BufReader::new(file)
+        .lines()
+        .take(50)
+        .any(|line| line.as_ref().map(|l| l.starts_with("services:")).unwrap_or(false))
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src-tauri/src/commands/docker.rs` around lines 185 - 188, The is_compose_file
function currently uses std::fs::read_to_string which loads the whole file;
change it to open the file with std::fs::File and wrap it in std::io::BufReader,
then iterate its lines (using read_line/lines()) up to 50 lines checking for
line.starts_with("services:"); handle IO errors by returning false if the file
can't be opened or a line can't be read. This updates is_compose_file to use
buffered streaming so only the first 50 lines are read into memory.

280-327: ⚡ Quick win

Container lifecycle commands lack timeouts.

docker_container_start, stop, restart, and remove don't have timeouts, unlike list operations. If Docker is slow or hung, these commands could block indefinitely. Consider adding timeouts for consistency.

♻️ Example: Add timeout to container_start
 pub async fn docker_container_start(container_id: String) -> Result<(), AppError> {
     let docker = docker_client()?;
-    docker
-        .start_container(&container_id, None::<StartContainerOptions<String>>)
-        .await
-        .map_err(|e| AppError::Other(e.to_string()))
+    timeout(
+        Duration::from_secs(30),
+        docker.start_container(&container_id, None::<StartContainerOptions<String>>),
+    )
+    .await
+    .map_err(|_| AppError::Other("container start timed out".into()))?
+    .map_err(|e| AppError::Other(e.to_string()))
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src-tauri/src/commands/docker.rs` around lines 280 - 327, The container
lifecycle functions (docker_container_start, docker_container_stop,
docker_container_restart, docker_container_remove) and docker_image_remove
currently await Docker ops with no timeout; wrap each Docker call in
tokio::time::timeout with a reasonable Duration (e.g. Duration::from_secs(30))
so slow/hung Docker calls return quickly, handle the timeout error by mapping it
to an AppError (either add an AppError::Timeout variant or map to
AppError::Other with a clear "Docker operation timed out" message), and preserve
the existing mapping of the inner Docker Result to AppError::Other for
non-timeout errors; ensure you import tokio::time::timeout and
std::time::Duration and apply the same pattern to docker_image_remove
(unwrapping the timeout result then mapping the inner result).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/lib/components/FileEditor.svelte`:
- Around line 66-69: The dirty-state check currently closes over the initial
const orig (assigned from originalContent) inside updateListener, so after a
save it still compares to the first snapshot; change orig to a mutable
savedContent (e.g., let savedContent = originalContent) and update savedContent
to the latest saved text inside the save handler so updateListener compares
against the most recent savedContent; update all places that reference orig
(including the EditorView doc initialization and other dirty checks around
updateListener/save logic) to use savedContent instead.
- Around line 44-57: The effect handling load() needs to ignore out-of-order
completions: add a per-effect request token/counter (e.g., increment a local
requestId readonly inside the $effect) before calling untrack(() => load()),
capture the current token in the then/catch/finally handlers, and only assign
originalContent, error, isDirty or clear loading if the token still matches the
most recent request; update symbols referenced: $effect, load, untrack,
originalContent, isDirty, loading, error to use this request-id guard so stale
promises cannot overwrite newer results.
- Around line 73-79: The editor theme uses hsl(var(--...)) which nests complete
oklch() values and gets dropped; change the color values in EditorView.theme so
solid colors use bare CSS variables (e.g., replace hsl(var(--foreground)) with
var(--foreground) in the root '&' color) and replace opacity usages like
hsl(var(--muted) / 0.3) with the project's color-mix pattern (e.g., color-mix(in
oklch, var(--muted) 70% , transparent 30%) or an appropriate color-mix(in oklch,
var(--muted) <alpha> , transparent <rest>)) for '.cm-gutters',
'.cm-activeLineGutter', '.cm-activeLine' etc.; keep other declarations (padding,
fontFamily, lineHeight) unchanged and ensure all references use var(--...) or
color-mix(in oklch, ...) instead of wrapping variables in hsl().

In `@src/lib/components/MarkdownEditor.svelte`:
- Around line 67-121: The editor is only seeded from initialContent onMount so
if the parent swaps the content prop the editor keeps the old doc; add guarded
resync logic that reacts to changes to the incoming content prop (the prop named
`content`/`initialContent` used to initialize `originalMd`) and, when `editor`
exists and `isDirty` is false, compute const newMd = cleanMd(content) and if
newMd !== originalMd update `originalMd = newMd`, call the editor API to replace
the editor content (use the Editor instance `editor`/`inst` to set
content/markdown via its commands or setContent/setMarkdown method), and ensure
`isDirty` remains false; reference the existing symbols `onMount`, `editor`
(Editor instance), `originalMd`, `isDirty`, and `cleanMd` when implementing this
reactive update.

In `@src/lib/components/workspace/DockerLogsTab.svelte`:
- Around line 104-106: clearLogs currently only empties the rendered logs array
but leaves buffered items and any scheduled RAF/flush to re-add them; update
clearLogs to also clear the pending buffer (e.g., pending.length = 0 or pending
= []) and cancel any scheduled flush by storing and clearing the RAF id (e.g.,
cancelAnimationFrame(rafId) and set rafId = null) and clear/reset any related
scheduleFlush/flushPendingLogs state so no queued flush will repopulate logs
after Clear.

---

Nitpick comments:
In `@src-tauri/src/commands/docker.rs`:
- Around line 185-188: The is_compose_file function currently uses
std::fs::read_to_string which loads the whole file; change it to open the file
with std::fs::File and wrap it in std::io::BufReader, then iterate its lines
(using read_line/lines()) up to 50 lines checking for
line.starts_with("services:"); handle IO errors by returning false if the file
can't be opened or a line can't be read. This updates is_compose_file to use
buffered streaming so only the first 50 lines are read into memory.
- Around line 280-327: The container lifecycle functions
(docker_container_start, docker_container_stop, docker_container_restart,
docker_container_remove) and docker_image_remove currently await Docker ops with
no timeout; wrap each Docker call in tokio::time::timeout with a reasonable
Duration (e.g. Duration::from_secs(30)) so slow/hung Docker calls return
quickly, handle the timeout error by mapping it to an AppError (either add an
AppError::Timeout variant or map to AppError::Other with a clear "Docker
operation timed out" message), and preserve the existing mapping of the inner
Docker Result to AppError::Other for non-timeout errors; ensure you import
tokio::time::timeout and std::time::Duration and apply the same pattern to
docker_image_remove (unwrapping the timeout result then mapping the inner
result).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 06de2522-476a-4be0-bd49-149f6cecd1b3

📥 Commits

Reviewing files that changed from the base of the PR and between ff502c2 and e6c7cf5.

📒 Files selected for processing (12)
  • .claude/settings.json
  • src-tauri/src/commands/docker.rs
  • src/lib/commands/docker.js
  • src/lib/components/FileEditor.svelte
  • src/lib/components/MarkdownEditor.svelte
  • src/lib/components/panels/DockerPanel.svelte
  • src/lib/components/workspace/DockerLogsTab.svelte
  • src/lib/components/workspace/FileTab.svelte
  • src/lib/components/workspace/ReadmeTab.svelte
  • src/lib/stores/workspace.svelte.js
  • src/routes/app/+layout.svelte
  • src/routes/layout.css
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/lib/commands/docker.js
  • src/lib/components/panels/DockerPanel.svelte

Comment thread src/lib/components/FileEditor.svelte Outdated
Comment thread src/lib/components/FileEditor.svelte Outdated
Comment thread src/lib/components/FileEditor.svelte Outdated
Comment thread src/lib/components/MarkdownEditor.svelte
Comment thread src/lib/components/workspace/DockerLogsTab.svelte
@anirudhisonline anirudhisonline merged commit f688f42 into main May 16, 2026
1 check passed
@anirudhisonline anirudhisonline deleted the docker branch May 16, 2026 14:15
This was referenced May 16, 2026
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.

1 participant