startStack, restartStack, stopStack, and downStack each ran a separate
getStackSource query just to determine isGitStack for useOverrideFile,
even though requireComposeFile -> getStackComposeFile already looks up
the same stack_sources record.
Return sourceType from getStackComposeFile (GetComposeFileResult) and
requireComposeFile (RequireComposeResult), and have all four callers
read result.sourceType instead of querying the database again. No
behavior change: useOverrideFile is still set to true exactly when the
stack's source type is 'git'.
startStack and restartStack compute isGitStack and pass useOverrideFile
accordingly, so executeLocalCompose writes .env.dockhand with the DB
non-secret overrides before invoking docker compose. stopStack and
downStack never set this option, so whenever a .env file exists in the
stack's working directory (e.g. committed alongside compose.yaml in a
git stack), the legacy shell-env fallback in executeLocalCompose is
suppressed and .env.dockhand is never written or attached via
--env-file. Any required variable that only exists as a Dockhand panel
override then fails interpolation on stop/down, even though the same
stack deploys and starts successfully.
Mirror startStack/restartStack: compute isGitStack from the stack
source and pass useOverrideFile through in both operations.
The badge inside Tooltip.Trigger had both a native title attribute
and Tooltip.Content with the same commit info, causing two overlapping
tooltips. Remove the title; keep Tooltip.Content as the sole tooltip.
The fallback branch (no commit hash) retains its title attribute.
Show the short commit hash next to 'Git' in the stack source column.
When a commit hash is available, the badge reads 'Git abc1234' with
a tooltip showing the full hash, repo URL, and branch. Falls back
to the original 'Git' label when no commit is recorded yet (e.g.
before first deploy).
Open Git-sourced stack compose files in a read-only editor and graph while keeping repository settings separate.
Co-authored-by: Cursor <cursoragent@cursor.com>
- isHarborRegistry: derive scheme and port from the registry URL via
parseRegistryUrl instead of hardcoding https:// so HTTP-only mirrors and
non-443 ports are detected (same scheme handling as getRegistryAuthHeader).
- isHarborRegistry: only cache the detection result when a definitive answer
was obtained; a transient network error no longer pins "not Harbor" for the
whole TTL and keeps returning _catalog 403s after Harbor recovers.
- getHarborBasicAuth: trim username/password (pasted credentials with trailing
whitespace silently broke Basic auth).
- harborListRepositories: implement real cross-project pagination for the
no-orgPath case (enumerate every project and all repos, paginate the
flattened list) so >100 projects / >100 repos no longer truncate silently
with a hardcoded hasMore=false.
- harborSearchRepositories: sanitize the search term against Harbor's query
grammar (, = ~ ( )) so special characters can't break or alter the q filter;
paginate the project list as well.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>