Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 54 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,73 @@ on:

jobs:
build:
name: Build ${{ matrix.config }}
runs-on: ubuntu-latest
name: Build ${{ matrix.config }} ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
config: [cli, library, daemon]
include:
- os: ubuntu-latest
config: cli
- os: ubuntu-24.04-arm
config: cli
- os: windows-latest
config: cli
- os: windows-11-arm
config: cli
- os: macos-latest
config: cli
- os: ubuntu-latest
config: library
- os: windows-latest
config: library
- os: ubuntu-latest
config: daemon
- os: windows-latest
config: daemon
steps:
- uses: actions/checkout@v4
- name: Install D
uses: dlang-community/setup-dlang@v1
with:
compiler: dmd-latest
compiler: ldc-latest
- name: Build
run: dub build --config=${{ matrix.config }}
build-tray-windows:
name: Build tray (Windows)
runs-on: windows-latest

build-tray:
name: Build tray ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
steps:
- uses: actions/checkout@v4
- name: Install D
uses: dlang-community/setup-dlang@v1
with:
compiler: dmd-latest
compiler: ldc-latest
- name: Install Qt (Linux)
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y qt6-base-dev
- name: Install Qt (macOS)
if: runner.os == 'macOS'
run: brew install qt
- name: Install Qt (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
python -m pip install aqtinstall
python -m aqt install-qt windows desktop 6.7.3 win64_msvc2019_64 -O "$env:RUNNER_TEMP\Qt"
$qt = Get-ChildItem "$env:RUNNER_TEMP\Qt\6.7.3" -Directory | Select-Object -First 1
"DFLAGS=-L/LIBPATH:$($qt.FullName)\lib" | Out-File -FilePath $env:GITHUB_ENV -Append
"PATH=$($qt.FullName)\bin;$env:PATH" | Out-File -FilePath $env:GITHUB_ENV -Append
- name: Qt paths (macOS)
if: runner.os == 'macOS'
run: |
echo "PATH=$(brew --prefix qt)/bin:$PATH" >> "$GITHUB_ENV"
echo "LIBRARY_PATH=$(brew --prefix qt)/lib:${LIBRARY_PATH:-}" >> "$GITHUB_ENV"
- name: Build tray
run: dub build --config=tray
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,6 @@ Thumbs.db
installer/*.exe
installer/*.msi
installer/output/
bootstrap.sdl
forge-profiles.sdl
vcs-profiles.sdl
3 changes: 2 additions & 1 deletion docs/modules/ROOT/pages/architecture.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,6 @@ Shared schema also lands in `dlang-supplemental/repo-get` (`getForge`).

* `AMDphreak/ver` — no CI/releases; multi-VCS UX mostly stubs — not a dependency
* `dev-centr/rules-manager` — IPC pattern reused; Electron tray not adopted; no published releases
* `tim-dlang/dqt` — `QSystemTrayIcon` binding proposed upstream; temporary fork `dlang-supplemental/dqt` for git dependencies (prefer git over Dub registry for interim forks). Tray still uses Win32 until the binding lands.
* `dlang-supplemental/dqt` (git dep, pinned commit) — `QSystemTrayIcon` for the tray app; upstream PR pending on `tim-dlang/dqt`
* `repo-get` (DUB `~>0.3.0`) — forge profile schema (`getForge` / `forge-profiles.sdl`)
* `repo-get` — Linux release artifacts only; forge profiles added for metadata tooling
4 changes: 3 additions & 1 deletion docs/modules/ROOT/pages/installation.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@
----
dub build --config=cli # issues-browser
dub build --config=daemon # issuesd
dub build --config=tray # issues-browser-tray (Windows tray)
dub build --config=tray # issues-browser-tray (needs Qt 6 + dqt git fork)
dub build --config=application # GUI (dlangui)
dub build --config=library
----

Forge profiles come from the DUB package `repo-get` (`~>0.3.0`). The tray config depends on `dqt:widgets` via git (`dlang-supplemental/dqt` pinned commit), not the Dub registry.

Windows CLI/daemon link against vendored `sqlite3.lib`; `sqlite3.dll` is copied beside the executable.

== ProHelp-compatible help
Expand Down
3 changes: 1 addition & 2 deletions docs/modules/ROOT/pages/usage.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,7 @@ IPC (localhost only): `GET /health`, `GET /status`, `GET /monitor`, `POST /monit

issues-browser-tray --port 17365

Windows system tray (Win32). Start `issuesd` first. Menu: status, sync now, open archives, quit.
Qt settings UI can wrap the same IPC later; tray icon uses a native shim because `dqt` lacks `QSystemTrayIcon` today.
Cross-platform system tray via Qt/`dqt` (`QSystemTrayIcon` from `dlang-supplemental/dqt`). Start `issuesd` first. Menu: status, sync now, open archives, quit.

== GUI

Expand Down
14 changes: 10 additions & 4 deletions dub.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@
"dependencies": {
"d2sqlite3": "~>1.0.0",
"stdx-allocator": "~>3.0.2",
"sdlang-d": "~>0.10.6"
"sdlang-d": "~>0.10.6",
"repo-get": "~>0.3.0"
},
"subConfigurations": {
"d2sqlite3": "all-included"
},
"copyFiles": [
"profiles/forge-profiles.sdl",
"help.sdl"
],
"configurations": [
Expand Down Expand Up @@ -92,9 +92,15 @@
"excludedSourceFiles": [
"source/app_gui.d",
"source/app_cli.d",
"source/app_daemon.d"
"source/app_daemon.d",
"source/tray/win_tray.d"
],
"libs-windows": ["user32", "shell32", "gdi32"],
"dependencies": {
"dqt:widgets": {
"repository": "git+https://github.com/dlang-supplemental/dqt.git",
"version": "297b81b2cb7e0e40dc0c7192252c4f150f735865"
}
},
"lflags-windows-x86_64": [
"/LIBPATH:$PACKAGE_DIR/vendor/sqlite/win64"
]
Expand Down
79 changes: 47 additions & 32 deletions source/app_tray.d
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/** issues-browser-tray — system tray client for issuesd (Win32 tray; Qt settings later). */
/** issues-browser-tray — system tray client for issuesd (Qt / dqt). */
module app_tray;

import std.stdio;
Expand All @@ -9,52 +9,67 @@ import std.net.curl;
import std.process;
import std.path;
import std.file;
import tray.win_tray;
import tray.qt_tray;
import issuesbrowser.paths;
import issuesbrowser.ipc : defaultPort;

void main(string[] args) {
void main(string[] args)
{
string root;
ushort port = defaultPort;
getopt(args, "root", &root, "port", &port);
auto archiveRootPath = archiveRoot(root);
auto base = "http://127.0.0.1:" ~ to!string(port);

// Ensure daemon is up (best-effort)
try {
try
{
get(base ~ "/health");
} catch (Exception) {
}
catch (Exception)
{
stderr.writeln("issuesd not reachable at ", base, " — start issuesd first.");
}

version (Windows) {
if (!startTray("issues-browser", (uint cmd) {
try {
if (cmd == ID_SYNC) {
post(base ~ "/sync-now", `{"repo":""}`);
setTrayTip("Sync requested");
} else if (cmd == ID_STATUS) {
auto st = get(base ~ "/status").idup;
setTrayTip(st.length > 120 ? st[0 .. 120] : st);
stderr.writeln(st);
} else if (cmd == ID_OPEN_ARCHIVES) {
auto dir = archivesDir(archiveRootPath);
mkdirRecurse(dir);
if (!startTray("issues-browser", (uint cmd) {
try
{
if (cmd == ID_SYNC)
{
post(base ~ "/sync-now", `{"repo":""}`);
setTrayTip("Sync requested");
}
else if (cmd == ID_STATUS)
{
auto st = get(base ~ "/status").idup;
setTrayTip(st.length > 120 ? st[0 .. 120] : st);
stderr.writeln(st);
}
else if (cmd == ID_OPEN_ARCHIVES)
{
auto dir = archivesDir(archiveRootPath);
mkdirRecurse(dir);
version (Windows)
spawnProcess(["explorer", dir]);
} else if (cmd == ID_QUIT) {
stopTray();
}
} catch (Exception e) {
setTrayTip("Error: " ~ e.msg);
else version (OSX)
spawnProcess(["open", dir]);
else
spawnProcess(["xdg-open", dir]);
}
})) {
stderr.writeln("Failed to create tray icon.");
return;
else if (cmd == ID_QUIT)
{
stopTray();
}
}
catch (Exception e)
{
setTrayTip("Error: " ~ e.msg);
}
stderr.writeln("Tray running. Archives: ", archiveRootPath);
runTrayLoop();
} else {
stderr.writeln("Tray UI is Windows-first (Win32). Use CLI/daemon on this platform.");
stderr.writeln("IPC: ", base, " archives: ", archiveRootPath);
}))
{
stderr.writeln("Failed to create system tray (is a tray host available?).");
return;
}

stderr.writeln("Tray running. Archives: ", archiveRootPath);
runTrayLoop();
}
Loading
Loading