Skip to content

Commit b2f4544

Browse files
committed
Plugins tab, logo, license, release workflow
1 parent 394ddcb commit b2f4544

24 files changed

Lines changed: 990 additions & 66 deletions

File tree

‎.github/workflows/ci.yml‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: CI
2+
on:
3+
push:
4+
branches: [main]
5+
pull_request:
6+
7+
jobs:
8+
test:
9+
runs-on: ubuntu-22.04
10+
steps:
11+
- uses: actions/checkout@v4
12+
- name: System libraries
13+
run: |
14+
sudo apt-get update
15+
sudo apt-get install -y libwebkit2gtk-4.1-dev build-essential libxdo-dev libssl-dev libayatana-appindicator3-dev librsvg2-dev poppler-utils
16+
- uses: actions/setup-node@v4
17+
with: { node-version: 20, cache: npm }
18+
- uses: dtolnay/rust-toolchain@stable
19+
- uses: Swatinem/rust-cache@v2
20+
with: { workspaces: src-tauri }
21+
- run: npm ci
22+
- name: Type check
23+
run: npx tsc --noEmit -p .
24+
- name: Rust tests
25+
run: cargo test --manifest-path src-tauri/Cargo.toml
26+
- name: Plugin tests
27+
run: |
28+
python3 plugins/nextcloud/test_nextcloud.py
29+
python3 plugins/bitwarden/test_bitwarden.py

‎.github/workflows/release.yml‎

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
name: Release
2+
# Push a tag like v1.2.0 (matching the version in tauri.conf.json): builds the AppImage and .deb on Ubuntu 22.04
3+
# (so they run on older glibc too) and publishes a GitHub release whose notes list the commits since the last tag.
4+
on:
5+
push:
6+
tags: ["v*"]
7+
8+
permissions:
9+
contents: write
10+
11+
jobs:
12+
release:
13+
runs-on: ubuntu-22.04
14+
steps:
15+
- uses: actions/checkout@v4
16+
with: { fetch-depth: 0 }
17+
- name: System libraries
18+
run: |
19+
sudo apt-get update
20+
sudo apt-get install -y libwebkit2gtk-4.1-dev build-essential libxdo-dev libssl-dev libayatana-appindicator3-dev librsvg2-dev patchelf libfuse2 file
21+
- uses: actions/setup-node@v4
22+
with: { node-version: 20, cache: npm }
23+
- uses: dtolnay/rust-toolchain@stable
24+
- uses: Swatinem/rust-cache@v2
25+
with: { workspaces: src-tauri }
26+
- run: npm ci
27+
- name: Build
28+
run: npm run tauri build -- --bundles appimage,deb
29+
- name: Bundle plugins
30+
run: tar -czf whale-cabinet-plugins-${GITHUB_REF_NAME}.tar.gz --exclude=__pycache__ --exclude='test_*' plugins
31+
- name: Changelog
32+
run: |
33+
prev=$(git describe --tags --abbrev=0 "${GITHUB_REF_NAME}^" 2>/dev/null || true)
34+
{
35+
echo "## What's new"
36+
echo
37+
git log --no-merges --pretty='- %s' ${prev:+$prev..}"$GITHUB_REF_NAME"
38+
echo
39+
echo "**Install:** download the AppImage (\`chmod +x\` and run it) or the .deb. From source: \`scripts/install.sh\`."
40+
echo "Plugins: unpack \`whale-cabinet-plugins-*.tar.gz\` into \`~/.local/share/whale-cabinet/\`."
41+
if [ -n "$prev" ]; then echo; echo "Full diff: https://github.com/${GITHUB_REPOSITORY}/compare/${prev}...${GITHUB_REF_NAME}"; fi
42+
} > notes.md
43+
cat notes.md
44+
- uses: softprops/action-gh-release@v2
45+
with:
46+
body_path: notes.md
47+
files: |
48+
src-tauri/target/release/bundle/appimage/*.AppImage
49+
src-tauri/target/release/bundle/deb/*.deb
50+
whale-cabinet-plugins-*.tar.gz

‎.gitignore‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ node_modules/
22
dist/
33
src-tauri/target/
44
src-tauri/gen/
5+
__pycache__/

‎LICENSE‎

Lines changed: 674 additions & 0 deletions
Large diffs are not rendered by default.

‎README.md‎

Lines changed: 34 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,22 @@
1-
# Whale Cabinet
1+
<p align="center"><img src="docs/logo.png" width="128" alt="Whale Cabinet logo"></p>
22

3-
A native Linux file manager with a flat filing-cabinet look (Tauri 2: Rust backend + TypeScript/Vite frontend).
4-
Window class / Wayland app id: `whale-cabinet`.
3+
# Whale Cabinet
54

5+
A Linux file manager with a flat filing-cabinet look: folders are drawers you pull out, files are paper.
6+
Built with Tauri 2 (Rust + TypeScript), made for Wayland/Hyprland and DankMaterialShell, and a drop-in
7+
replacement for Dolphin (same places, tags and ratings). Window class / Wayland app id: `whale-cabinet`.
68

9+
**Highlights:** tabs and split view · fuzzy quick open (Ctrl+P) and zoxide jumps (Ctrl+J) · a command palette
10+
(Ctrl+Shift+P) · git badges and actions · network locations (SFTP, SMB, WebDAV, NFS) · a built-in viewer for
11+
pictures, PDFs, video, code and Markdown · tags, colours and ratings shared with Dolphin · duplicate finder and
12+
disk-usage map · encryption · administrator actions through polkit · live theming from DMS and Hyprland ·
13+
**plugins** (Nextcloud, Immich and Bitwarden included).
714

815
## Install
916

17+
Download the AppImage or the .deb from [Releases](https://github.com/PluginMike/whale-cabinet/releases)
18+
(plus the plugins archive, unpacked into `~/.local/share/whale-cabinet/`), or build it yourself:
19+
1020
```sh
1121
scripts/install.sh # build + install to ~/.local/bin (Dolphin stays the default)
1222
scripts/install.sh --default # …and take over from Dolphin: default for folders + "Show in folder" (D-Bus)
@@ -86,7 +96,7 @@ fish users with a user-local rustup: `fish_add_path ~/.cargo/bin`.
8696
## Tests
8797

8898
```sh
89-
(cd src-tauri && cargo test) # 68 Rust unit tests: file ops, tags/xattrs, theme parsing (dank-colors.css,
99+
(cd src-tauri && cargo test) # 69 Rust unit tests: file ops, tags/xattrs, theme parsing (dank-colors.css,
90100
# dms-colors.json, hyprctl JSON), .desktop/mimeapps/globs, thumbnails, xbel, search, pty,
91101
# fuzzy ranking, git porcelain, recently-used.xbel, gio prompts, admin helper, duplicates, plugins…
92102
(cd src-tauri && cargo test real_system -- --ignored --nocapture) # Open With / icons against this machine
@@ -166,6 +176,16 @@ file), asking for the password — or, for key-encrypted files, gpg's own pinent
166176

167177
### Plugins
168178

179+
Settings → **Plugins** (also Tools → *Plugins…* in the sidebar) lists the installed plugins with their settings
180+
and instructions. Included:
181+
182+
- [**Nextcloud**](plugins/nextcloud/README.md): sync-status badges from the desktop client, Share… / Copy Public
183+
Link / Open in Browser
184+
- [**Immich**](plugins/immich/README.md): your photo library as folders, smart search, upload and delete
185+
- [**Bitwarden**](plugins/bitwarden/README.md): search your vault from the palette, copy passwords and TOTP codes
186+
187+
#### Writing a plugin
188+
169189
A plugin is a folder in `~/.local/share/whale-cabinet/plugins/<name>/` with a `plugin.json` and an executable in
170190
any language. Whale Cabinet starts it once (it runs as you, so the first time it asks whether to allow it; Settings
171191
→ Plugins turns it off again) and keeps it running, talking JSON lines over stdin/stdout.
@@ -211,37 +231,6 @@ in any order (so a plugin can work on several at once). Unasked messages `{"even
211231
An entry is `{name, path, dir?, size?, mtime? (ms), score? (sort order, highest first), thumb? (true), count?
212232
(a folder's "12 photos"), where?, info?: [[label, value]…]}`; its `path` is a location of the plugin's scheme.
213233

214-
#### Nextcloud (bundled)
215-
216-
With the Nextcloud desktop client running, items in your synced folders (from `~/.config/Nextcloud/nextcloud.cfg`)
217-
get its sync state as a badge — **✓** synced (blue when shared), **↻** syncing, **!** a problem, **⊘** excluded —
218-
updated live as the client syncs (it's the client's local socket, the one Dolphin's overlays use).
219-
Right-click → Nextcloud: *Share…* (the client's share dialog), *Copy Public Link* (reuses the item's public link
220-
or creates one; needs an app password from Nextcloud → Settings → Security in Settings → Plugins, kept in your
221-
keyring), *Open in Browser* (the item in the web UI). Check: `python3 plugins/nextcloud/test_nextcloud.py`.
222-
223-
#### Immich (bundled)
224-
225-
Settings → Plugins → Immich: your server's URL and an API key (Immich → Account Settings → API Keys; the key goes
226-
to your keyring). The sidebar's Immich section opens **Timeline** (a folder per month), **Albums** and
227-
**Favorites** as thumbnail folders, with EXIF in the info panel and Quick Look (Space) on the preview image.
228-
Opening a photo downloads the original (kept in `~/.cache/whale-cabinet/plugins/immich/`) and opens it with your
229-
app; Ctrl+C, *Copy To…* and dragging out copy the originals. **Ctrl+F** in Immich (or "Immich: search…" in
230-
Ctrl+Shift+P) is smart search: type what's in the picture; Enter opens a result, Shift+Enter shows all of them.
231-
Paste or drop files onto an Immich location to upload them (into an album: added to it; into Favorites: marked),
232-
or right-click local photos → Immich → *Upload to Immich*; Del moves photos to Immich's trash (it asks first).
233-
Reading needs asset.read/view/download, album.read, timeline.read; changing needs asset.upload, albumAsset.create,
234-
asset.update and asset.delete.
235-
236-
#### Bitwarden (bundled)
237-
238-
Needs [rbw](https://github.com/doy/rbw) (`sudo pacman -S rbw`). Settings → Plugins → Bitwarden: your server (empty
239-
for bitwarden.com; a self-hosted Bitwarden or Vaultwarden URL otherwise) and email. Ctrl+Shift+P → *Bitwarden:
240-
search…*: type part of a name, username or folder; **Enter** copies the password, **Shift+Enter** the username,
241-
**Ctrl+Enter** the TOTP code. rbw's agent asks for your master password (pinentry) and keeps the vault unlocked
242-
for its `lock_timeout`; the plugin never sees it. Passwords and codes are copied marked sensitive and cleared
243-
after 30 s (unless you copied something else). Check: `python3 plugins/bitwarden/test_bitwarden.py`.
244-
245234
### Recent files
246235

247236
Recent (sidebar) lists what you opened lately, grouped Today / Yesterday / This week / … with bigger rows and
@@ -444,3 +433,13 @@ windowrulev2 = opacity 0.95 0.9, class:^(whale-cabinet)$
444433
windowrulev2 = float, class:^(whale-cabinet-dialog)$
445434
windowrulev2 = center, class:^(whale-cabinet-dialog)$
446435
```
436+
437+
## Contributing
438+
439+
Issues and pull requests are welcome. `cargo test` (in `src-tauri`) and `npx tsc --noEmit` should pass;
440+
`WC_SUITES=browse,ops,plugins scripts/smoke.sh` runs the app end to end. Releases are built by GitHub Actions
441+
when a `v*` tag is pushed.
442+
443+
## License
444+
445+
[GPL-3.0-or-later](LICENSE)

‎assets/whale-cabinet.svg‎

Lines changed: 41 additions & 8 deletions
Loading

‎docs/logo.png‎

14 KB
Loading

‎package.json‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "whale-cabinet",
33
"private": true,
4-
"version": "0.1.0",
4+
"version": "1.0.0",
55
"type": "module",
66
"scripts": {
77
"dev": "vite",
@@ -21,5 +21,6 @@
2121
"@tauri-apps/cli": "^2.12.0",
2222
"typescript": "^7.0.2",
2323
"vite": "^8.3.1"
24-
}
24+
},
25+
"license": "GPL-3.0-or-later"
2526
}

‎plugins/bitwarden/README.md‎

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Bitwarden
2+
3+
Search your Bitwarden vault from the command palette and copy a password, username or TOTP code. Works with
4+
bitwarden.com and self-hosted servers (Bitwarden, Vaultwarden).
5+
6+
## What it does
7+
8+
Ctrl+Shift+P → *Bitwarden: search…*, then type part of an item's name, username or folder:
9+
10+
- **Enter** copies the password
11+
- **Shift+Enter** copies the username
12+
- **Ctrl+Enter** copies the TOTP code
13+
14+
Passwords and codes are copied marked as sensitive (so clipboard managers can skip them) and cleared after
15+
30 seconds, unless you've copied something else since.
16+
17+
## Setup
18+
19+
1. Install [rbw](https://github.com/doy/rbw), the unofficial Bitwarden CLI: `sudo pacman -S rbw` (Arch),
20+
`cargo install rbw` elsewhere. It also needs `pinentry` and `wl-clipboard`.
21+
2. Settings → Plugins → Bitwarden: your server URL (leave empty for bitwarden.com) and email.
22+
3. Search. The first time, rbw asks you to log in; after that it asks for your master password when the vault
23+
is locked.
24+
25+
## Security
26+
27+
The plugin never sees your master password: rbw's agent unlocks the vault through pinentry and keeps it
28+
unlocked for its `lock_timeout` (`rbw config set lock_timeout 3600`). Secrets go from rbw straight to the
29+
clipboard; search results only carry names, usernames and folders.
30+
31+
Test: `python3 test_bitwarden.py`

‎plugins/immich/README.md‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Immich
2+
3+
Your [Immich](https://immich.app) photos in the file manager: browse, search, download, upload and delete.
4+
5+
## What it does
6+
7+
- A sidebar section with **Timeline** (a folder per month), **Albums** and **Favorites**, shown as thumbnails,
8+
with the photo's details (date, camera, exposure, place) in the info panel.
9+
- **Space** previews a photo; **Enter** opens the original (downloaded to `~/.cache/whale-cabinet/plugins/immich/`).
10+
- **Copy / Copy To… / drag out** copy the originals anywhere, or into other apps.
11+
- **Smart search**: Ctrl+F inside Immich (or Ctrl+Shift+P → *Immich: search…*). Describe what's in the picture;
12+
Enter opens a result, Shift+Enter shows all of them.
13+
- **Upload**: paste (Ctrl+V) or drop files onto an Immich location or its sidebar entry, or right-click local
14+
photos → Immich → *Upload to Immich*. Into an album adds them to it; into Favorites marks them.
15+
- **Delete**: Del moves photos to Immich's trash (after asking), so they can be restored there.
16+
- Right-click → *Open in Immich* opens the photo in the web app.
17+
18+
## Setup
19+
20+
1. In Immich: Account Settings → API Keys → *New API Key*. For browsing it needs `asset.read`, `asset.view`,
21+
`asset.download`, `album.read` and `timeline.read`; for uploading and deleting also `asset.upload`,
22+
`albumAsset.create`, `asset.update` and `asset.delete`.
23+
2. Settings → Plugins → Immich: your server URL (`https://photos.example.com`) and the API key (kept in your keyring).
24+
25+
## Notes
26+
27+
- Months are cut in UTC, so a photo taken just after midnight on the 1st can show up in the month before.
28+
- Uses only Python's standard library.

0 commit comments

Comments
 (0)