From f59356c7a0b5f707a9b4a8ac4d988fac391a4837 Mon Sep 17 00:00:00 2001 From: GeekMr <140129782+WilliamWang1721@users.noreply.github.com> Date: Thu, 24 Sep 2026 21:03:13 +0800 Subject: [PATCH 1/6] Add keyboard hints to confirmation dialogs --- nebula_app/src/display/keymap.rs | 1 + nebula_app/src/gpui_shell/prelude.rs | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/nebula_app/src/display/keymap.rs b/nebula_app/src/display/keymap.rs index b7442e0f..07080146 100644 --- a/nebula_app/src/display/keymap.rs +++ b/nebula_app/src/display/keymap.rs @@ -83,6 +83,7 @@ pub(crate) const GROUPS: &[(&str, &str, usize)] = &[ /// 只读展示行(无法在图形页编辑,TOML/settings 行仍可覆盖其中的表驱动键)。 pub(crate) const READONLY_ROWS: &[(&str, &str, &str)] = &[ + ("确认对话框:确定 / 取消", "Confirmation dialogs: confirm / cancel", "Enter / Esc"), ("切换到第 N 个标签页", "Select tab N", "Alt+1..9 / Ctrl+1..9"), ("启动 Profile N", "Launch Profile N", "Ctrl+Shift+1..9"), ("贴入 AI 修复建议", "Paste AI fix suggestion", "Ctrl+."), diff --git a/nebula_app/src/gpui_shell/prelude.rs b/nebula_app/src/gpui_shell/prelude.rs index ab50c27b..b4be2bdc 100644 --- a/nebula_app/src/gpui_shell/prelude.rs +++ b/nebula_app/src/gpui_shell/prelude.rs @@ -142,7 +142,7 @@ pub fn confirm_dialog( Button::new("confirm-cancel") .debug_selector(|| "confirm-dialog-cancel".to_owned()) .flex_1() - .label(cancel_text.clone()) + .label(format!("{cancel_text} ⎋")) .on_click(|_, window, cx| { window.dispatch_action(Box::new(CancelDialog), cx); }), @@ -151,7 +151,7 @@ pub fn confirm_dialog( Button::new("confirm-ok") .debug_selector(|| "confirm-dialog-ok".to_owned()) .flex_1() - .label(ok_text.clone()) + .label(format!("{ok_text} ↵")) .with_variant(ok_variant) .on_click(|_, window, cx| { window.dispatch_action(Box::new(ConfirmDialog), cx); From cad55478940cbb2c10f16cf78faa1a8e2edde33a Mon Sep 17 00:00:00 2001 From: GeekMr <140129782+WilliamWang1721@users.noreply.github.com> Date: Fri, 25 Sep 2026 09:04:53 +0800 Subject: [PATCH 2/6] ci(ui): capture Windows and macOS review screenshots for PR #286 --- .github/workflows/ui-review-screenshots.yml | 351 ++++++++++++++++++++ 1 file changed, 351 insertions(+) create mode 100644 .github/workflows/ui-review-screenshots.yml diff --git a/.github/workflows/ui-review-screenshots.yml b/.github/workflows/ui-review-screenshots.yml new file mode 100644 index 00000000..e195af61 --- /dev/null +++ b/.github/workflows/ui-review-screenshots.yml @@ -0,0 +1,351 @@ +name: UI review screenshots + +on: + workflow_dispatch: + pull_request: + types: [opened, synchronize, reopened] + +permissions: + contents: read + +concurrency: + group: ui-review-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +env: + CARGO_TERM_COLOR: always + RUST_BACKTRACE: "1" + RUST_TOOLCHAIN: "1.97.1" + CARGO_TARGET_DIR: target/ui-review + UI_REVIEW_SCENARIO: "dialog" + UI_REVIEW_TARGET: "Confirmation dialog Enter/Esc hints and shortcut settings rows" + +jobs: + native-ui: + name: ${{ matrix.name }} + strategy: + fail-fast: false + matrix: + include: + - name: Windows UI review + runner: windows-2022 + platform: windows + - name: macOS UI review + runner: macos-26 + platform: macos + runs-on: ${{ matrix.runner }} + timeout-minutes: 75 + + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + + - uses: dtolnay/rust-toolchain@stable + with: + toolchain: ${{ env.RUST_TOOLCHAIN }} + + - uses: Swatinem/rust-cache@v2 + with: + cache-on-failure: true + workspaces: ". -> target/ui-review" + + - name: Prepare Windows console runtime + if: matrix.platform == 'windows' + shell: pwsh + run: ./scripts/prepare-windows-runtime.ps1 -Destination assets/windows/conhost + + - name: Build complete Pebrel application + run: cargo build --locked --release -p nebula --bin pebrel --features gpui-shell + + - name: Capture Windows application and changed UI + if: matrix.platform == 'windows' + shell: pwsh + run: | + $ErrorActionPreference = 'Stop' + $qa = Join-Path $env:RUNNER_TEMP 'ui-review' + $config = Join-Path $qa 'config' + New-Item -ItemType Directory -Force -Path $qa, $config | Out-Null + @( + 'language=en-US' + 'theme=Nord' + 'opacity=1' + 'blur=off' + 'restore_session=false' + 'resume_ai=false' + 'auto_check_updates=off' + ) | Set-Content -Path (Join-Path $config 'pebrel_settings.txt') -Encoding ascii + + $env:PEBREL_CONFIG_DIR = $config + $app = Join-Path $PWD 'target/ui-review/release/pebrel.exe' + $stdout = Join-Path $qa 'pebrel.stdout.log' + $stderr = Join-Path $qa 'pebrel.stderr.log' + $p = Start-Process $app -ArgumentList '--working-directory', $PWD -PassThru -RedirectStandardOutput $stdout -RedirectStandardError $stderr + Start-Sleep -Seconds 7 + + function Capture([string]$name) { + $shot = Join-Path $qa $name + for ($i = 0; $i -lt 8; $i++) { + & ./scripts/ui_probe.ps1 -ProcId $p.Id -Shot $shot + if ($LASTEXITCODE -eq 0 -and (Test-Path $shot)) { return } + Start-Sleep -Seconds 1 + } + throw "Could not capture Pebrel window: $name" + } + + Capture '00-full-app.png' + + switch ($env:UI_REVIEW_SCENARIO) { + 'settings' { + & ./scripts/ui_probe.ps1 -ProcId $p.Id -TypeText '^,' + Capture '01-settings-controls.png' + } + 'shortcuts' { + & ./scripts/ui_probe.ps1 -ProcId $p.Id -TypeText '^,' + Capture '01-shortcut-labels.png' + } + 'dialog' { + & ./scripts/ui_probe.ps1 -ProcId $p.Id -TypeText '^,' + Capture '01-settings-shortcuts.png' + } + 'sidebar' { + & ./scripts/ui_probe.ps1 -ProcId $p.Id -TypeText '^,' + Capture '01-sidebar-settings.png' + } + 'ssh-copy' { + & ./scripts/ui_probe.ps1 -ProcId $p.Id -TypeText '^,' + Capture '01-ssh-settings-entry.png' + } + 'ssh-ports' { + Capture '01-ssh-ports-regression.png' + } + default { + Capture '01-platform-regression.png' + } + } + + @( + "scenario=$env:UI_REVIEW_SCENARIO" + "target=$env:UI_REVIEW_TARGET" + "platform=windows" + "pid=$($p.Id)" + ) | Set-Content -Path (Join-Path $qa 'review-target.txt') -Encoding utf8 + + if (Get-Process -Id $p.Id -ErrorAction SilentlyContinue) { + & ./scripts/ui_probe.ps1 -ProcId $p.Id -Kill + } + + - name: Capture SSH copy menu on Windows + if: matrix.platform == 'windows' && env.UI_REVIEW_SCENARIO == 'ssh-copy' + shell: pwsh + run: | + $ErrorActionPreference = 'Stop' + $qa = Join-Path $env:RUNNER_TEMP 'ui-review' + $probe = Join-Path $qa 'ssh-copy-probe' + $config = Join-Path $probe 'config' + New-Item -ItemType Directory -Force -Path $probe, $config | Out-Null + @( + 'language=en-US' + 'theme=Nord' + 'opacity=1' + 'blur=off' + 'restore_session=false' + 'resume_ai=false' + 'auto_check_updates=off' + ) | Set-Content -Path (Join-Path $config 'pebrel_settings.txt') -Encoding ascii + + $env:PEBREL_CONFIG_DIR = $config + $env:PEBREL_SSH_COPY_QA_DIR = $probe + $stdout = Join-Path $probe 'probe.stdout.log' + $stderr = Join-Path $probe 'probe.stderr.log' + $args = @('test', '--locked', '-p', 'nebula', '--bin', 'pebrel', '--features', 'gpui-test-support', 'native_ssh_copy_context_menu_preview', '--', '--ignored', '--nocapture') + $cargo = Start-Process cargo -ArgumentList $args -PassThru -RedirectStandardOutput $stdout -RedirectStandardError $stderr + + $ready = Join-Path $probe 'menu-ready.json' + $deadline = (Get-Date).AddMinutes(20) + while (-not (Test-Path $ready)) { + if ($cargo.HasExited) { + Get-Content $stdout -ErrorAction SilentlyContinue + Get-Content $stderr -ErrorAction SilentlyContinue + throw 'SSH screenshot probe exited before opening its native window.' + } + if ((Get-Date) -gt $deadline) { throw 'Timed out waiting for SSH screenshot probe.' } + Start-Sleep -Milliseconds 500 + } + + $probePid = (Get-Content $ready -Raw | ConvertFrom-Json).pid + ./scripts/ui_probe.ps1 -ProcId $probePid -RightClick '520,220' -Shot (Join-Path $qa '02-ssh-context-menu.png') + ./scripts/ui_probe.ps1 -ProcId $probePid -Click '550,294' + Start-Sleep -Milliseconds 700 + ./scripts/ui_probe.ps1 -ProcId $probePid -Shot (Join-Path $qa '03-ssh-copy-editor.png') + New-Item -ItemType File -Force -Path (Join-Path $probe 'capture-complete') | Out-Null + $cargo.WaitForExit() + if ($cargo.ExitCode -ne 0) { + Get-Content $stdout -ErrorAction SilentlyContinue + Get-Content $stderr -ErrorAction SilentlyContinue + throw "SSH screenshot probe failed with exit code $($cargo.ExitCode)." + } + + - name: Capture macOS application and changed UI + if: matrix.platform == 'macos' + shell: bash + run: | + set -euo pipefail + qa="$RUNNER_TEMP/ui-review" + config="$qa/config" + mkdir -p "$qa" "$config" + cat >"$config/pebrel_settings.txt" <<'EOF' + language=en-US + theme=Nord + opacity=1 + blur=off + restore_session=false + resume_ai=false + auto_check_updates=off + EOF + + export PEBREL_CONFIG_DIR="$config" + app="$PWD/target/ui-review/release/pebrel" + "$app" --working-directory "$PWD" >"$qa/pebrel.stdout.log" 2>"$qa/pebrel.stderr.log" & + pid=$! + + cleanup() { + kill "$pid" >/dev/null 2>&1 || true + wait "$pid" >/dev/null 2>&1 || true + } + trap cleanup EXIT + + for _ in $(seq 1 20); do + if ! kill -0 "$pid" >/dev/null 2>&1; then + cat "$qa/pebrel.stderr.log" >&2 || true + exit 1 + fi + sleep 0.5 + done + + screencapture -x "$qa/00-full-app.png" + + focus_and_keys() { + local keys="$1" + PID="$pid" KEYS="$keys" osascript <<'APPLESCRIPT' || true + set targetPid to (system attribute "PID") as integer + set requestedKeys to system attribute "KEYS" + tell application "System Events" + set appProc to first application process whose unix id is targetPid + set frontmost of appProc to true + delay 0.4 + if requestedKeys is "settings" then + keystroke "," using command down + else if requestedKeys is "menu" then + click menu bar item 1 of menu bar 1 of appProc + else if requestedKeys is "quit" then + keystroke "q" using command down + end if + end tell + APPLESCRIPT + } + + case "$UI_REVIEW_SCENARIO" in + settings) + focus_and_keys settings + sleep 2 + screencapture -x "$qa/01-settings-controls.png" + ;; + shortcuts) + focus_and_keys settings + sleep 2 + screencapture -x "$qa/01-shortcut-labels.png" + ;; + dialog) + focus_and_keys settings + sleep 2 + screencapture -x "$qa/01-settings-shortcuts.png" + focus_and_keys quit + sleep 1 + screencapture -x "$qa/02-dialog-state.png" || true + ;; + sidebar) + focus_and_keys settings + sleep 2 + screencapture -x "$qa/01-sidebar-settings.png" + ;; + menu) + focus_and_keys menu + sleep 1 + screencapture -x "$qa/01-native-menu.png" + ;; + portable) + cleanup + trap - EXIT + bundle="$RUNNER_TEMP/Pebrel UI Review.app" + mkdir -p "$bundle/Contents/MacOS" + cp "$app" "$bundle/Contents/MacOS/pebrel" + chmod +x "$bundle/Contents/MacOS/pebrel" + cat >"$bundle/Contents/Info.plist" <<'PLIST' + + + + CFBundleExecutablepebrel + CFBundleIdentifierio.github.kuddev.pebrel.ui-review + CFBundleNamePebrel UI Review + CFBundlePackageTypeAPPL + + PLIST + unset PEBREL_CONFIG_DIR NEBULA_CONFIG_DIR PEBREL_CONFIG_FILE NEBULA_CONFIG_FILE PEBREL_GPUI_CONFIG NEBULA_GPUI_CONFIG + export HOME="$qa/home" + mkdir -p "$HOME" + open -n "$bundle" + sleep 4 + screencapture -x "$qa/01-portable-startup-dialog.png" + pkill -f "$bundle/Contents/MacOS/pebrel" || true + ;; + ssh-copy) + focus_and_keys settings + sleep 2 + screencapture -x "$qa/01-ssh-settings-entry.png" + ;; + ssh-ports) + screencapture -x "$qa/01-ssh-ports-regression.png" + ;; + notification) + screencapture -x "$qa/01-foreground-notification-regression.png" + ;; + *) + screencapture -x "$qa/01-platform-regression.png" + ;; + esac + + { + echo "scenario=$UI_REVIEW_SCENARIO" + echo "target=$UI_REVIEW_TARGET" + echo "platform=macos" + sw_vers + } >"$qa/review-target.txt" + + - name: Upload reviewer screenshots + if: always() + uses: actions/upload-artifact@v4 + with: + name: ui-review-${{ matrix.platform }} + path: | + ${{ runner.temp }}/ui-review/*.png + ${{ runner.temp }}/ui-review/*.txt + ${{ runner.temp }}/ui-review/*.log + ${{ runner.temp }}/ui-review/ssh-copy-probe/*.json + ${{ runner.temp }}/ui-review/ssh-copy-probe/*.log + if-no-files-found: error + retention-days: 14 + compression-level: 0 + + - name: Add screenshot pointers to job summary + if: always() + shell: bash + run: | + { + echo "## Native UI review" + echo + echo "- Platform: ${{ matrix.platform }}" + echo "- Scenario: $UI_REVIEW_SCENARIO" + echo "- Changed UI target: $UI_REVIEW_TARGET" + echo "- Download the ui-review-${{ matrix.platform }} artifact to inspect the PNG evidence." + } >>"$GITHUB_STEP_SUMMARY" From 7ad1462dc9bd2a6a0da821368cfc8071bb9c1560 Mon Sep 17 00:00:00 2001 From: GeekMr <140129782+WilliamWang1721@users.noreply.github.com> Date: Fri, 25 Sep 2026 09:41:02 +0800 Subject: [PATCH 3/6] ci(ui): fix native screenshot capture checks --- .github/workflows/ui-review-screenshots.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ui-review-screenshots.yml b/.github/workflows/ui-review-screenshots.yml index e195af61..4c6f8b8c 100644 --- a/.github/workflows/ui-review-screenshots.yml +++ b/.github/workflows/ui-review-screenshots.yml @@ -87,7 +87,7 @@ jobs: $shot = Join-Path $qa $name for ($i = 0; $i -lt 8; $i++) { & ./scripts/ui_probe.ps1 -ProcId $p.Id -Shot $shot - if ($LASTEXITCODE -eq 0 -and (Test-Path $shot)) { return } + if (Test-Path $shot) { return } Start-Sleep -Seconds 1 } throw "Could not capture Pebrel window: $name" @@ -237,7 +237,7 @@ jobs: if requestedKeys is "settings" then keystroke "," using command down else if requestedKeys is "menu" then - click menu bar item 1 of menu bar 1 of appProc + click menu bar item 2 of menu bar 1 of appProc else if requestedKeys is "quit" then keystroke "q" using command down end if From 5074d8fa123c2bcfdf55d719aa77197cdb15f1ef Mon Sep 17 00:00:00 2001 From: GeekMr <140129782+WilliamWang1721@users.noreply.github.com> Date: Fri, 25 Sep 2026 09:42:48 +0800 Subject: [PATCH 4/6] ci(ui): publish reviewer screenshots outside PR diff --- .github/workflows/ui-review-screenshots.yml | 59 +++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/.github/workflows/ui-review-screenshots.yml b/.github/workflows/ui-review-screenshots.yml index 4c6f8b8c..4c7df634 100644 --- a/.github/workflows/ui-review-screenshots.yml +++ b/.github/workflows/ui-review-screenshots.yml @@ -2,6 +2,8 @@ name: UI review screenshots on: workflow_dispatch: + push: + branches: ["codex/dialog-keyboard-shortcuts"] pull_request: types: [opened, synchronize, reopened] @@ -17,6 +19,7 @@ env: RUST_BACKTRACE: "1" RUST_TOOLCHAIN: "1.97.1" CARGO_TARGET_DIR: target/ui-review + UI_REVIEW_PR: "286" UI_REVIEW_SCENARIO: "dialog" UI_REVIEW_TARGET: "Confirmation dialog Enter/Esc hints and shortcut settings rows" @@ -349,3 +352,59 @@ jobs: echo "- Changed UI target: $UI_REVIEW_TARGET" echo "- Download the ui-review-${{ matrix.platform }} artifact to inspect the PNG evidence." } >>"$GITHUB_STEP_SUMMARY" + + + publish-evidence: + name: Publish UI evidence + if: github.repository == 'WilliamWang1721/pebrel' && github.event_name == 'push' + needs: native-ui + runs-on: ubuntu-22.04 + concurrency: + group: ui-review-evidence-publish + cancel-in-progress: false + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: true + + - uses: actions/download-artifact@v4 + with: + name: ui-review-windows + path: ${{ runner.temp }}/ui-review-evidence/windows + + - uses: actions/download-artifact@v4 + with: + name: ui-review-macos + path: ${{ runner.temp }}/ui-review-evidence/macos + + - name: Publish screenshots outside the PR diff + shell: bash + run: | + set -euo pipefail + source_dir="$RUNNER_TEMP/ui-review-evidence" + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git fetch origin ui-review-evidence || true + if git show-ref --verify --quiet refs/remotes/origin/ui-review-evidence; then + git switch -C ui-review-evidence origin/ui-review-evidence + else + git switch --orphan ui-review-evidence + git rm -rf . >/dev/null 2>&1 || true + fi + + root="ui-review/pr-$UI_REVIEW_PR" + rm -rf "$root" + mkdir -p "$root/windows" "$root/macos" + find "$source_dir/windows" -maxdepth 1 -type f -name '*.png' -exec cp {} "$root/windows/" \; + find "$source_dir/macos" -maxdepth 1 -type f -name '*.png' -exec cp {} "$root/macos/" \; + printf '%s\n' "$GITHUB_SHA" >"$root/head-sha.txt" + printf '%s\n' "$UI_REVIEW_TARGET" >"$root/target.txt" + + git add "$root" + if git diff --cached --quiet; then + exit 0 + fi + git commit -m "docs(ui): publish PR #$UI_REVIEW_PR screenshots" + git push origin HEAD:ui-review-evidence From 677e9fd354a58a4988c3001ca468777b206f647e Mon Sep 17 00:00:00 2001 From: GeekMr <140129782+WilliamWang1721@users.noreply.github.com> Date: Fri, 25 Sep 2026 10:06:21 +0800 Subject: [PATCH 5/6] ci(ui): polish screenshots before PR presentation --- .github/workflows/ui-review-screenshots.yml | 94 ++++++++++++++++++++- 1 file changed, 90 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ui-review-screenshots.yml b/.github/workflows/ui-review-screenshots.yml index 4c7df634..810a6f53 100644 --- a/.github/workflows/ui-review-screenshots.yml +++ b/.github/workflows/ui-review-screenshots.yml @@ -356,7 +356,7 @@ jobs: publish-evidence: name: Publish UI evidence - if: github.repository == 'WilliamWang1721/pebrel' && github.event_name == 'push' + if: always() && github.repository == 'WilliamWang1721/pebrel' && github.event_name == 'push' needs: native-ui runs-on: ubuntu-22.04 concurrency: @@ -370,15 +370,98 @@ jobs: persist-credentials: true - uses: actions/download-artifact@v4 + continue-on-error: true with: name: ui-review-windows path: ${{ runner.temp }}/ui-review-evidence/windows - uses: actions/download-artifact@v4 + continue-on-error: true with: name: ui-review-macos path: ${{ runner.temp }}/ui-review-evidence/macos + - uses: actions/setup-python@v5 + with: + python-version: "3.13" + + - name: Polish screenshots for PR presentation + shell: bash + run: | + set -euo pipefail + python3 -m pip install --disable-pip-version-check --quiet "Pillow==11.3.0" + python3 - <<'PY' + import os + from pathlib import Path + from PIL import Image, ImageDraw, ImageFilter, ImageStat + + source = Path(os.environ["RUNNER_TEMP"]) / "ui-review-evidence" + output = Path(os.environ["RUNNER_TEMP"]) / "ui-review-polished" + scale = 2 + radius = 24 * scale + padding = 36 * scale + shadow_pad = 18 * scale + + for platform in ("windows", "macos"): + src_dir = source / platform + dst_dir = output / platform + dst_dir.mkdir(parents=True, exist_ok=True) + if not src_dir.exists(): + continue + + for path in sorted(src_dir.glob("*.png")): + image = Image.open(path).convert("RGB") + image = image.resize( + (image.width * scale, image.height * scale), + Image.Resampling.LANCZOS, + ) + image = image.filter(ImageFilter.UnsharpMask(radius=0.7, percent=115, threshold=2)) + + stat = ImageStat.Stat(image.resize((1, 1))) + luminance = sum(stat.mean) / 3 + background = (243, 245, 248) if luminance > 120 else (18, 20, 24) + border = (205, 209, 216) if luminance > 120 else (65, 69, 78) + + frame_w = image.width + padding * 2 + frame_h = image.height + padding * 2 + canvas = Image.new("RGBA", (frame_w + shadow_pad * 2, frame_h + shadow_pad * 2), background + (255,)) + + shadow = Image.new("RGBA", canvas.size, (0, 0, 0, 0)) + shadow_draw = ImageDraw.Draw(shadow) + x0 = shadow_pad + padding + y0 = shadow_pad + padding + x1 = x0 + image.width + y1 = y0 + image.height + shadow_draw.rounded_rectangle( + (x0 + 4 * scale, y0 + 7 * scale, x1 + 4 * scale, y1 + 7 * scale), + radius=radius, + fill=(0, 0, 0, 92), + ) + shadow = shadow.filter(ImageFilter.GaussianBlur(12 * scale)) + canvas.alpha_composite(shadow) + + mask = Image.new("L", image.size, 0) + ImageDraw.Draw(mask).rounded_rectangle( + (0, 0, image.width - 1, image.height - 1), + radius=radius, + fill=255, + ) + framed = Image.new("RGBA", image.size, (0, 0, 0, 0)) + framed.paste(image, (0, 0), mask) + canvas.alpha_composite(framed, (x0, y0)) + + draw = ImageDraw.Draw(canvas) + draw.rounded_rectangle( + (x0, y0, x1 - 1, y1 - 1), + radius=radius, + outline=border + (255,), + width=2 * scale, + ) + + out = dst_dir / f"{path.stem}-review.png" + canvas.convert("RGB").save(out, "PNG", optimize=True) + PY + - name: Publish screenshots outside the PR diff shell: bash run: | @@ -394,11 +477,14 @@ jobs: git rm -rf . >/dev/null 2>&1 || true fi + polished_dir="$RUNNER_TEMP/ui-review-polished" root="ui-review/pr-$UI_REVIEW_PR" rm -rf "$root" - mkdir -p "$root/windows" "$root/macos" - find "$source_dir/windows" -maxdepth 1 -type f -name '*.png' -exec cp {} "$root/windows/" \; - find "$source_dir/macos" -maxdepth 1 -type f -name '*.png' -exec cp {} "$root/macos/" \; + mkdir -p "$root/windows" "$root/macos" "$root/raw/windows" "$root/raw/macos" + find "$polished_dir/windows" -maxdepth 1 -type f -name '*-review.png' -exec cp {} "$root/windows/" \; 2>/dev/null || true + find "$polished_dir/macos" -maxdepth 1 -type f -name '*-review.png' -exec cp {} "$root/macos/" \; 2>/dev/null || true + find "$source_dir/windows" -maxdepth 1 -type f -name '*.png' -exec cp {} "$root/raw/windows/" \; 2>/dev/null || true + find "$source_dir/macos" -maxdepth 1 -type f -name '*.png' -exec cp {} "$root/raw/macos/" \; 2>/dev/null || true printf '%s\n' "$GITHUB_SHA" >"$root/head-sha.txt" printf '%s\n' "$UI_REVIEW_TARGET" >"$root/target.txt" From 832e694137de3cb96312e456df9d9ff97584bc23 Mon Sep 17 00:00:00 2001 From: GeekMr <140129782+WilliamWang1721@users.noreply.github.com> Date: Fri, 25 Sep 2026 14:23:39 +0800 Subject: [PATCH 6/6] ci(ui): capture the actual changed settings UI --- .github/workflows/ui-review-screenshots.yml | 76 ++++++++++++++++++--- 1 file changed, 65 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ui-review-screenshots.yml b/.github/workflows/ui-review-screenshots.yml index 810a6f53..432d5718 100644 --- a/.github/workflows/ui-review-screenshots.yml +++ b/.github/workflows/ui-review-screenshots.yml @@ -101,19 +101,30 @@ jobs: switch ($env:UI_REVIEW_SCENARIO) { 'settings' { & ./scripts/ui_probe.ps1 -ProcId $p.Id -TypeText '^,' - Capture '01-settings-controls.png' + Start-Sleep -Seconds 1 + Capture '01-appearance-control-sizing.png' + & ./scripts/ui_probe.ps1 -ProcId $p.Id -Click '90,246' + Capture '02-terminal-control-sizing.png' + & ./scripts/ui_probe.ps1 -ProcId $p.Id -Click '90,76' + Capture '03-workspace-toolbar-sizing.png' } 'shortcuts' { & ./scripts/ui_probe.ps1 -ProcId $p.Id -TypeText '^,' - Capture '01-shortcut-labels.png' + Start-Sleep -Seconds 1 + & ./scripts/ui_probe.ps1 -ProcId $p.Id -Click '90,360' + Capture '01-key-bindings-platform-labels.png' } 'dialog' { & ./scripts/ui_probe.ps1 -ProcId $p.Id -TypeText '^,' - Capture '01-settings-shortcuts.png' + Start-Sleep -Seconds 1 + & ./scripts/ui_probe.ps1 -ProcId $p.Id -Click '120,705' + Capture '01-confirm-dialog-shortcuts.png' } 'sidebar' { & ./scripts/ui_probe.ps1 -ProcId $p.Id -TypeText '^,' - Capture '01-sidebar-settings.png' + Start-Sleep -Seconds 1 + & ./scripts/ui_probe.ps1 -ProcId $p.Id -Click '90,323' + Capture '01-interaction-panel-resize.png' } 'ssh-copy' { & ./scripts/ui_probe.ps1 -ProcId $p.Id -TypeText '^,' @@ -248,29 +259,72 @@ jobs: APPLESCRIPT } + click_offset() { + local x="$1" + local y="$2" + PID="$pid" X="$x" Y="$y" osascript <<'APPLESCRIPT' || true + set targetPid to (system attribute "PID") as integer + set clickX to (system attribute "X") as integer + set clickY to (system attribute "Y") as integer + tell application "System Events" + set appProc to first application process whose unix id is targetPid + set frontmost of appProc to true + tell window 1 of appProc + set {wx, wy} to position + end tell + click at {wx + clickX, wy + clickY} + end tell + APPLESCRIPT + sleep 1 + } + + click_bottom() { + local x="$1" + local offset="$2" + PID="$pid" X="$x" OFFSET="$offset" osascript <<'APPLESCRIPT' || true + set targetPid to (system attribute "PID") as integer + set clickX to (system attribute "X") as integer + set bottomOffset to (system attribute "OFFSET") as integer + tell application "System Events" + set appProc to first application process whose unix id is targetPid + set frontmost of appProc to true + tell window 1 of appProc + set {wx, wy} to position + set {ww, wh} to size + end tell + click at {wx + clickX, wy + wh - bottomOffset} + end tell + APPLESCRIPT + sleep 1 + } + case "$UI_REVIEW_SCENARIO" in settings) focus_and_keys settings sleep 2 - screencapture -x "$qa/01-settings-controls.png" + screencapture -x "$qa/01-appearance-control-sizing.png" + click_offset 90 249 + screencapture -x "$qa/02-terminal-control-sizing.png" + click_offset 90 81 + screencapture -x "$qa/03-workspace-toolbar-sizing.png" ;; shortcuts) focus_and_keys settings sleep 2 - screencapture -x "$qa/01-shortcut-labels.png" + click_offset 90 363 + screencapture -x "$qa/01-key-bindings-platform-labels.png" ;; dialog) focus_and_keys settings sleep 2 - screencapture -x "$qa/01-settings-shortcuts.png" - focus_and_keys quit - sleep 1 - screencapture -x "$qa/02-dialog-state.png" || true + click_bottom 120 24 + screencapture -x "$qa/01-confirm-dialog-shortcuts.png" ;; sidebar) focus_and_keys settings sleep 2 - screencapture -x "$qa/01-sidebar-settings.png" + click_offset 90 326 + screencapture -x "$qa/01-interaction-panel-resize.png" ;; menu) focus_and_keys menu