Skip to content

Commit 40d1edc

Browse files
committed
First commit, beta version
0 parents  commit 40d1edc

84 files changed

Lines changed: 15011 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/release.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags: ['v*']
6+
7+
jobs:
8+
build:
9+
strategy:
10+
matrix:
11+
include:
12+
- runner: macos-14 # Apple Silicon
13+
target: aarch64-apple-darwin
14+
- runner: macos-13 # Intel
15+
target: x86_64-apple-darwin
16+
runs-on: ${{ matrix.runner }}
17+
18+
steps:
19+
- uses: actions/checkout@v4
20+
21+
- uses: actions/setup-node@v4
22+
with:
23+
node-version: '20'
24+
cache: 'npm'
25+
26+
- uses: dtolnay/rust-toolchain@stable
27+
with:
28+
targets: ${{ matrix.target }}
29+
30+
- run: npm install
31+
32+
- run: npx tauri build --target ${{ matrix.target }}
33+
34+
- uses: softprops/action-gh-release@v2
35+
with:
36+
draft: true
37+
files: |
38+
src-tauri/target/${{ matrix.target }}/release/bundle/dmg/*.dmg

.gitignore

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Dependencies
2+
node_modules/
3+
4+
# Build output
5+
dist/
6+
src-tauri/target/
7+
8+
# OS
9+
.DS_Store
10+
11+
# IDE
12+
.vscode/
13+
.idea/
14+
*.swp
15+
16+
# Environment
17+
.env
18+
.env.*

CLAUDE.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## What is DockerLens
6+
7+
A macOS menu bar app that monitors and cleans unused Docker images. Built with Tauri v2 (Rust backend + React frontend). Runs as a tray icon (no dock icon), shows a popover window on click.
8+
9+
## Build & Run
10+
11+
```bash
12+
npm install # frontend deps (first time)
13+
npx tauri dev # development with hot reload (Vite on :1420 + Rust rebuild)
14+
npx tauri build # production .app bundle
15+
cargo check --manifest-path src-tauri/Cargo.toml # Rust-only type check
16+
```
17+
18+
### Key Constraints
19+
20+
- **hyperlocal 0.8** pins hyper to 0.14 — uses `hyper::Client::unix()` and `hyper::Body` which were removed in hyper 1.0. Do not upgrade hyper.
21+
- **tauri-plugin-positioner** `move_window()` panics if the OS hasn't reported tray position yet — wrapped in `catch_unwind` in `toggle_window()`.
22+
- **macOSPrivateApi** is enabled in `tauri.conf.json` for transparent window support.
23+
- Docker socket detection checks `/var/run/docker.sock` first, then `$HOME/.docker/run/docker.sock` (Docker Desktop on macOS).
24+
25+
## Architecture
26+
27+
### Rust Backend (Tauri)
28+
29+
Three modules under `src-tauri/src/`:
30+
31+
- **`lib.rs`** — App entry point. Sets up tray icon, hides dock icon (`ActivationPolicy::Accessory`), manages window toggle/positioning via `tauri-plugin-positioner`, and runs a tokio background polling loop. The polling loop checks unused image size against the user's limit and either auto-cleans or sends a macOS notification (once per breach, reset when usage drops).
32+
- **`docker.rs`** — Direct Docker Engine API client over Unix socket using `hyperlocal`. No Docker CLI dependency. Provides `list_unused_images()`, `remove_image()`, `remove_all_unused()`, `get_storage_stats()`. V1 only tracks dangling images (no tags).
33+
- **`commands.rs`** — Thin IPC bridge: each `#[tauri::command]` delegates directly to `docker.rs` or reads/writes settings via `tauri-plugin-store`.
34+
- **`settings.rs`**`Settings` struct with `limit_gb`, `auto_clean`, `poll_interval_secs`, `breach_notified`. Persisted via tauri-plugin-store as `settings.json`.
35+
36+
### Frontend (React + Vite)
37+
38+
Source lives in `src/`. Vite dev server runs on `:1420`.
39+
40+
- **`hooks/useDockerImages.ts`** — Central hook that owns all `invoke()` calls. Fetches images, stats, settings in parallel on mount. Listens for `docker-stats-updated` events from the backend polling loop to auto-refresh.
41+
- **`App.tsx`** — Two tabs: Images (list of dangling images with remove buttons) and Settings (limit slider, auto-clean toggle, poll interval).
42+
- **`components/`**`TrayHeader`, `StorageBar`, `ImageList`, `SettingsPanel`.
43+
- **`types.ts`** — Shared TypeScript interfaces (`DockerImage`, `StorageStats`, `Settings`) mirroring the Rust structs.
44+
- **`index.css`** — Complete dark-mode styling targeting macOS popover aesthetic. Uses CSS custom properties for theming.
45+
46+
### Data Flow
47+
48+
1. Backend polling loop (`lib.rs`) runs on an interval, checks `docker.rs` for stats, emits `docker-stats-updated` event to frontend.
49+
2. Frontend hook listens for that event and calls `refresh()` which re-invokes all commands in parallel.
50+
3. Settings are persisted via `tauri-plugin-store` and read by both the polling loop (Rust side) and the settings panel (frontend side).
51+
52+
### Tauri Plugins Used
53+
54+
- `tauri-plugin-store` — JSON key-value persistence for settings
55+
- `tauri-plugin-positioner` — Window positioning relative to tray icon
56+
- `tauri-plugin-notification` — macOS notifications for storage alerts
57+
58+
### IPC Commands
59+
60+
| Command | Args | Returns |
61+
|---------|------|---------|
62+
| `list_unused_images` || `Vec<DockerImage>` |
63+
| `remove_image` | `imageId: String` | `()` |
64+
| `remove_all_unused` || `usize` (count removed) |
65+
| `get_storage_stats` || `StorageStats` |
66+
| `is_docker_running` || `bool` |
67+
| `get_settings` || `Settings` |
68+
| `save_settings` | `settings: Settings` | `()` |

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 DockerLens Contributors
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# DockerLens
2+
3+
A lightweight macOS menu bar app that monitors and cleans unused Docker images. Sits in your tray, shows storage usage at a glance, and lets you reclaim disk space in one click.
4+
5+
![macOS](https://img.shields.io/badge/macOS-Ventura%2B-black?logo=apple)
6+
![Tauri](https://img.shields.io/badge/Tauri-v2-blue)
7+
![License](https://img.shields.io/badge/license-MIT-green)
8+
9+
## Features
10+
11+
- **Menu bar native** — runs as a tray icon, no dock clutter
12+
- **Real-time monitoring** — background polling detects unused Docker images automatically
13+
- **Storage bar** — visual indicator with warning/danger thresholds
14+
- **One-click cleanup** — remove individual images or all unused at once
15+
- **Auto-clean mode** — automatically remove images when your storage limit is hit
16+
- **macOS notifications** — get alerted when unused images exceed your threshold
17+
- **Configurable** — set storage limits (1-50 GB), poll intervals (30s to 10m)
18+
- **No Docker CLI dependency** — talks directly to the Docker Engine API over Unix socket
19+
20+
## Install
21+
22+
### Download (recommended)
23+
24+
Grab the latest `.dmg` from [Releases](../../releases), open it, and drag DockerLens to Applications.
25+
26+
> **Note:** The app is not yet code-signed. On first launch, right-click the app and select **Open**, then click **Open** in the dialog. You only need to do this once. Alternatively, run:
27+
> ```bash
28+
> xattr -cr ****/Applications/DockerLens.app
29+
> ```
30+
31+
### Homebrew (coming soon)
32+
33+
```bash
34+
brew tap InumanSoul/tap
35+
brew install --cask dockerlens
36+
```
37+
38+
## Usage
39+
40+
1. **Click the tray icon** to open the popover
41+
2. **Images tab** — see all dangling/unused images with size, age, and a delete button
42+
3. **Settings tab** — configure storage limit, auto-clean, and poll interval
43+
4. The app polls Docker in the background and updates automatically
44+
45+
## Requirements
46+
47+
- macOS 13 (Ventura) or later
48+
- Docker Desktop or Docker Engine running
49+
50+
## Building from source
51+
52+
```bash
53+
git clone https://github.com/InumanSoul/dockerlens.git
54+
cd dockerlens
55+
npm install
56+
npx tauri dev # dev mode with hot reload
57+
npx tauri build # production .app + .dmg
58+
```
59+
60+
**Prerequisites:** Node.js 20+, Rust (stable), Xcode Command Line Tools.
61+
62+
## Tech Stack
63+
64+
| Layer | Tech |
65+
|-------|------|
66+
| Backend | Rust, Tauri v2, hyper 0.14 + hyperlocal (Unix socket) |
67+
| Frontend | React 18, TypeScript, Vite |
68+
| Persistence | tauri-plugin-store |
69+
| Notifications | tauri-plugin-notification |
70+
71+
## Contributing
72+
73+
Pull requests welcome. For major changes, open an issue first.
74+
75+
## License
76+
77+
[MIT](LICENSE)

index.html

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>DockerLens</title>
7+
</head>
8+
<body>
9+
<div id="root"></div>
10+
<script type="module" src="/src/main.tsx"></script>
11+
</body>
12+
</html>

0 commit comments

Comments
 (0)