Skip to content

Add refresh button to menu-bar Model row#224

Merged
FuJacob merged 2 commits into
mainfrom
refresh-models-button
May 25, 2026
Merged

Add refresh button to menu-bar Model row#224
FuJacob merged 2 commits into
mainfrom
refresh-models-button

Conversation

@FuJacob
Copy link
Copy Markdown
Owner

@FuJacob FuJacob commented May 25, 2026

Summary

Adds an arrow.clockwise refresh button next to the folder shortcut in
the menu-bar Model row so users can rescan the Models folder without
opening Settings or relaunching. The picker label now truncates
middle-style so the second icon fits without crowding longer model names.

Validation

xcodebuild -project Cotabby.xcodeproj -scheme Cotabby -destination 'platform=macOS' build
# ** BUILD SUCCEEDED **

xcodebuild -project Cotabby.xcodeproj -scheme Cotabby -destination 'platform=macOS' build-for-testing
# ** TEST BUILD SUCCEEDED **

swiftlint lint --quiet Cotabby/UI/MenuBarView.swift
# exit 0

Did not run the UI end-to-end — change is a one-button wire-up using the
exact two-call refresh pattern already used by SettingsView.refreshModels().

Linked issues

None.

Risk / rollout notes

  • Same two-call refresh as SettingsView (modelDownloadManager.refreshModelStates() +
    runtimeModel.refreshAvailableModels()), so behavior matches the existing path.
  • Both refresh calls are synchronous and cheap; no debounce needed.
  • The new icon eats ~26pt of row width. Picker label gains .lineLimit(1)
    • .truncationMode(.middle) so longer filenames (e.g.
      Qwen3-0.6B-Q4_K_M.gguf) truncate gracefully instead of pushing the
      icons off-row.

Greptile Summary

This PR adds a refresh button (arrow.clockwise) alongside the existing folder shortcut in the menu-bar Model row, letting users rescan the local model directory without opening Settings. It also applies .frame(maxWidth: .infinity) to the Picker — the correct way to prevent long filenames from pushing trailing icons off-row on AppKit's native popup button — and includes a /// comment explaining why per-item text modifiers are unreliable in this context.

  • Refresh button: calls modelDownloadManager.refreshModelStates() + runtimeModel.refreshAvailableModels(), mirroring the exact two-call sequence already used by SettingsView.refreshModels() and WelcomeView.
  • Picker layout fix: .frame(maxWidth: .infinity) constrains the Picker to fill remaining row width, matching the approach endorsed in the code comment and consistent with the rest of the layout hierarchy inside the fixed-width (340 pt) menu panel.

Confidence Score: 5/5

Safe to merge — the change is a one-button wire-up that delegates to two well-established synchronous refresh calls, with no new state or side-effect paths.

Both refreshModelStates() and refreshAvailableModels() are synchronous, @MainActor-confined, and called identically in SettingsView and WelcomeView. The .frame(maxWidth: .infinity) layout fix is correct and well-documented. No new async work, no new state, no error paths added.

No files require special attention.

Important Files Changed

Filename Overview
Cotabby/UI/MenuBarView.swift Adds a refresh button and .frame(maxWidth: .infinity) to the Picker in modelRow; both changes are correct, well-documented, and consistent with the existing codebase patterns.

Sequence Diagram

sequenceDiagram
    actor User
    participant MenuBarView
    participant ModelDownloadManager
    participant RuntimeBootstrapModel
    participant LlamaRuntimeManager

    User->>MenuBarView: Tap refresh button
    MenuBarView->>ModelDownloadManager: refreshModelStates()
    Note over ModelDownloadManager: Re-checks download tasks and file presence
    MenuBarView->>RuntimeBootstrapModel: refreshAvailableModels()
    RuntimeBootstrapModel->>LlamaRuntimeManager: refreshAvailableModels()
    Note over LlamaRuntimeManager: Re-scans runtime directories for GGUF files
    LlamaRuntimeManager-->>RuntimeBootstrapModel: availableModels updated
    RuntimeBootstrapModel-->>MenuBarView: ObservedObject triggers re-render
    MenuBarView-->>User: Picker shows updated model list
Loading

Reviews (2): Last reviewed commit: "Constrain model Picker frame instead of ..." | Re-trigger Greptile

The Model picker only got rescanned through Settings or after an app
relaunch, so users who dropped a GGUF into the Models folder had to leave
the menu-bar surface to pick it up. Add an arrow.clockwise button beside
the folder shortcut that triggers the same refresh path as the Settings
"Refresh" action.

Also truncate the picker label middle-style so two trailing icons fit
without crowding longer model names like "Qwen3-0.6B-Q4_K_M.gguf".
Comment thread Cotabby/UI/MenuBarView.swift
NSPopUpButton ignores .lineLimit/.truncationMode on the selected-value
label, so the previous per-item modifiers did not actually keep long
filenames from pushing the trailing icons off-row. Drop the item-level
modifiers and give the Picker .frame(maxWidth: .infinity) so the popup
fills remaining row width and AppKit truncates the button label inside
its own bounds.
@FuJacob FuJacob merged commit 28c961b into main May 25, 2026
3 checks passed
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