Apps fixes#400
Merged
Merged
Conversation
Adding a shared catalog listing to "my apps" discarded the publisher's custom name/description and used the freshly-fetched manifest's values instead. The add_from_catalog endpoint already loaded the listing, so capture and persist its name/description while still fetching the manifest for current capabilities/branch. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a share/unshare icon button to each My Apps card, between the info and trash buttons, styled like the catalog's ghost IconButton. When the app is shared it unshares directly; when not shared it opens the app info dialog straight into the share form (via a new startInShareView prop) so the name/description can still be customized. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The name a user customizes when adding an app from the catalog (or sharing) now appears instead of the raw manifest name. submit_job labels jobs with the user's saved app name (falling back to the manifest name), so the jobs list and job detail pages reflect it, and the launch page/form prefer the installed app's name. The internal job work_dir still uses the manifest name as a stable path identifier. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The launch form's Parameters tab now displays "There are no parameters to set for this app." when the entry point defines no parameters, instead of rendering an empty panel. The all-hidden case is unchanged (handled by the existing "Show hidden" toggle). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The job detail Execution card now labels "App" as "<app name> — <entry point>" and moves the GitHub repository to its own "Repository" row that links to and displays the repo URL (hidden when the URL isn't parseable). Replaces the previous setup where the app name linked to the repo and the entry point had a separate row. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Show the repository link as "owner/repo" with "(branch)" appended only for non-default branches, instead of the full URL. Lay out the Status and Execution cards as 40%/60% (a 5-column grid spanning 2 and 3) on md+ screens; InfoCard now forwards an optional className. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Relabel the branch field/rows as "Revision" in the add app dialog (with helper text "Tag or branch name") and the app/listing info dialogs. Code identifiers and the manifest's branch field are unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adding an app from a private GitHub repo failed because the clone ran over HTTPS with prompts disabled. Now the add dialog accepts both HTTPS and SSH (git@github.com / ssh://) URLs, and the backend clone/ls-remote tries HTTPS first, then retries over SSH as the user on an auth/access error — using BatchMode + accept-new so it never hangs. When both transports fail, surface a clear message naming the repo/revision and the SSH-key requirement instead of a nested "500: Git command failed". - manifest.py: _parse_github_url accepts SSH forms; _clone_repo and _resolve_default_branch do HTTPS->SSH fallback; _run_git gains extra_env; auth-error detection + user-facing error helpers. - server.py: add_user_app re-raises the worker's HTTPException so its clean message isn't double-wrapped. - frontend: parseGithubUrl accepts SSH; new isGithubRepoUrl/buildAppUrl; AddAppDialog validation/help text updated for HTTPS or SSH. - tests: backend SSH parsing + clone fallback; frontend parser helpers. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The pixi adapter named apps "<repo>/<branch>", and git rev-parse on a detached-HEAD clone returns "HEAD" — producing names like "SmartSPIMGlancer/HEAD". Use the pixi project's declared name first, falling back to the git repo name, then the directory name. The app's branch/revision is still tracked separately on the UserApp record. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two private-repo papercuts: - A mistyped tag produced a misleading "can't access / maybe private" message (HTTPS auth-fails, SSH reaches the repo and reveals the real "ref not found"). _clone_repo now detects ref-not-found at both the HTTPS and SSH stages and reports the revision plainly, and add_user_app surfaces it as 400 instead of a scary 500. - Pulling a cached tag/SHA failed with "ambiguous argument 'origin/<ref>'" because origin/<ref> only exists for branches. The update path now resets to FETCH_HEAD (valid for branches, tags and SHAs) and passes the SSH env so SSH-origin private repos don't prompt. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The launch page decided "installed" by exact string match against a URL rebuilt into canonical form, so any stored app whose URL carried a ".git" suffix, trailing slash, or "/tree/main" wrongly showed as not in the library — common for shared apps, whose URL is whatever the sharer entered. Fix it at the root by giving every GitHub URL one canonical form: - new fileglancer/giturls.py (standalone, no app deps) with canonical_github_url, mirroring the frontend helper - database.py canonicalizes on write (upsert_user_app, create_app_listing, create_job) and on lookup (get_user_app, delete_user_app, get_app_listing_for_app), so any cosmetic variant resolves to one row (also fixes the submit_job custom-name lookup) - migration b8e4f1a92c37 rewrites existing user_apps/app_listings/jobs URLs, deduping rows that collapse under the unique constraint - frontend AppLaunch matches installed apps via canonicalGithubUrl Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
os.geteuid() doesn't exist on Windows, breaking test_pull_resets_to_fetch_head_not_origin_branch. Fall back to 'n/a' when unavailable. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a confirmation dialog when canceling/stopping a job from the jobs list page, matching the existing dialog on the job detail page. Extract the shared dialog into a CancelJobDialog component used by both pages. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Resolve the revision once when an app is added and bake it into the
stored canonical URL: a repo whose default is e.g. "master" is stored
as ".../tree/master" rather than a bare URL, so it dedups against an
explicit "/tree/master" and the URL always names the revision actually
cloned. This closes the bare-vs-default-branch dedup hole where the same
app could be added twice.
The branch column now records the user's requested revision ("" = took
the default at add time) instead of the resolved one, and the Revision
shown in the app/listing dialogs is parsed from the URL.
The revision is fixed at add time: update just re-pulls the stored URL
and refreshes the manifest, without re-resolving the default branch or
moving the row to a new URL. To follow a changed default branch, delete
and re-add the app.
Includes a migration that bakes the resolved revision (from the old
branch column) into existing URLs and derives the requested revision
from the URL shape, de-duplicating any rows that collapse together.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
add_user_app resolved the default branch in the shared server process, which has no access to a user's SSH key — so for a private repo with a non-main default the resolution failed and fell back to "main", storing a bare URL instead of e.g. ".../tree/master" and defeating the dedup and pin-at-add-time guarantees. Resolve the branch in the per-user worker (which holds the user's SSH credentials) and return it from discover_manifests, then build the canonical URL from that worker-resolved branch via the new pure canonical_app_url helper. The server no longer makes a network call to resolve branches. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Treat stored bare app URLs as the fixed main revision for clone/fetch/update paths so they do not follow later default-branch moves. Preserve the folded storage URL for dedupe/UI compatibility while using explicit operational URLs. Co-authored-by: Codex <codex@openai.com>
A bare stored URL whose branch column is NULL is a legacy app migrated from user_preferences, whose default branch was never recorded. Treating it as the fixed "main" revision (as the prior pass did) breaks apps whose repo defaults to e.g. "master", since "main" may not exist. clone_url_for_stored_app now takes the row's branch: NULL means "unknown default", so the stored URL is returned unchanged and git resolves the current default (the row's historical behavior); "" or an explicit name means pinned, so the revision is made explicit. The migration leaves NULL-branch rows untouched instead of rewriting them to main. Such rows get pinned the next time the app is re-added. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Register unchanged null-branch legacy rows as collision winners before rewriting known app URLs, so rows that bake to the same URL are dropped instead of violating the unique constraint. Co-authored-by: Codex <codex@openai.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A batch of fixes and refinements to the Apps feature, covering private-repo support over SSH, consistent app naming, accurate error messages, pinned/canonical GitHub URLs that fix the false "not in your library" state, and assorted UI polish.
Changes
Private repository support (SSH)
git@github.com:owner/repo.gitandssh://git@github.com/owner/repo) in addition to HTTPS, in both the backend parser and the frontend.BatchMode=yesandStrictHostKeyChecking=accept-newso the worker never hangs on an interactive prompt.Accurate clone errors and tag-safe pulls
fetchthe ref andreset --hard FETCH_HEADinstead oforigin/<branch>, so updating an app pinned to a tag or commit (not a branch) works correctly. The fetch carries the SSH env so private-repo origins don't prompt.Canonical, pinned GitHub URLs
canonical_github_url(backend) /canonicalGithubUrl(frontend) that fold URLs to a single canonical https form — stripping.git, trailing slashes, and a redundant/tree/main, and converting SSH to https.masteris stored as.../tree/master, so it dedups against an explicit/tree/masterand the URL always names the revision actually cloned. This closes the bare-vs-default-branch dedup hole where the same app could be added twice.branchcolumn records the user's requested revision (""= took the default at add time) rather than the resolved one; the Revision shown in the dialogs is parsed from the URL. Once added, a revision is fixed — update just re-pulls the stored URL and refreshes the manifest without re-resolving or moving the row. To follow a changed default branch, delete and re-add the app.user_preferenceshave a NULLbranch(their default was never recorded). These are left to track the current default (stored URL returned unchanged, git resolves the default) rather than being wrongly pinned tomain; they get pinned the next time the app is re-added.App naming
pixi.tomlproject name (falling back to the git repo name, then the directory) instead ofrepo/branch, which produced poor names likeSmartSPIMGlancer/HEADsince a detached-HEAD clone's leaf directory is the revision.work_dirstill uses the manifest name as a stable path identifier.UI refinements
<app name> — <entry point>), add a separate repository link labeledowner/repowith(branch)appended only for non-default branches, and use a 40/60 (Status/Execution) card layout.CancelJobDialogcomponent).Tests
tests/test_apps.py,tests/test_apps_endpoints.py,tests/test_catalog_endpoints.py, andtests/test_url_migration.py.frontend/src/__tests__/unitTests/appUrls.test.ts.Migration note
Running this branch applies two migrations:
b8e4f1a92c37canonicalizes existing app/listing/job GitHub URLs in place, dropping rows that would collide with an already-canonical row under theUNIQUE(owner, url, manifest_path)constraint.c1f9a4e7b2d8bakes the resolved revision (from the oldbranchcolumn) into existing URLs and derives the requested revision from the URL shape, de-duplicating any rows that collapse together. NULL-branch legacy rows are left untouched (and registered as collision winners so known-app rewrites that fold onto them are dropped rather than violating the unique constraint).Both downgrades are no-ops since canonicalization is lossy.
@StephanPreibisch @JaneliaSciComp/fileglancer