fix(ui): label the archived repository sync button Sync

The button said "Manual Sync" for archived repositories, and the wider
label pushed the status badge in that row out of line with the others.
It now says Sync like every other row, with a tooltip that automatic
syncs are off for archived mirrors and the button syncs it now. The
Automation settings text, the README and the environment variable docs
point to Sync instead of Manual Sync.
This commit is contained in:
Arunavo Ray committed 2026-10-29 11:27:28 +05:30
1 parent 73c9d7693d
commit d05c3b29ad
7 files changed
+49 -28

No files matched your search

+1
View File
@@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Fixed
- The sync button on an archived repository says **Sync** like every other row instead of **Manual Sync**, so the wider label no longer pushes the row's status badge out of line. Hovering it explains that automatic syncs are off for archived mirrors
- The Activity Log summary no longer shows a repository as syncing after a quick sync finished (#454). Events are stored to the second, and a sync that starts and finishes in the same second could come back in the wrong order, so the start event was counted as the current state. Activities now come back newest first within the same second too, and the summary counts a finish over a start from the same second
- Issue and pull request passes over large repositories finish across rate limit resets (#449 follow-up)
- A pass stopped by the rate limit keeps the numbers it finished, and the next run repeats the same pass and skips them unless they changed since it started; before, every run started over from the first item, so a repository too large for one hour of budget never completed a pass
+1 -1
View File
@@ -309,7 +309,7 @@ CLEANUP_DRY_RUN=false # Set to true to test without changes
- Regular repositories: Made read-only using Gitea/Forgejo's archive feature
- Mirror repositories: Renamed with `archived-` prefix (Gitea/Forgejo API limitation prevents archiving mirrors)
- Failed operations: Repository remains fully accessible even if marking as archived fails
- **Manual Sync on Demand**: Archived mirrors stay in Gitea/Forgejo with automatic syncs disabled; trigger `Manual Sync` from the Repositories page whenever you need fresh data.
- **Sync on Demand**: Archived mirrors stay in Gitea/Forgejo with automatic syncs disabled; use `Sync` on the Repositories page whenever you need fresh data.
- **The Whole Point of Backups**: Your Gitea/Forgejo mirrors are preserved even when GitHub sources disappear - that's why you have backups!
- **Strongly Recommended**: Always use `CLEANUP_ORPHANED_REPO_ACTION=archive` (default) instead of `delete`
+1 -1
View File
@@ -333,7 +333,7 @@ Configure automatic cleanup of old events and data.
- Description updated with preservation notice and timestamp
- Mirror interval set to 8760h (1 year) to minimize sync attempts
- Repository remains fully accessible and cloneable
- **Manual Sync Option**: Archived mirrors are still available on the Repositories page with automatic syncs disabled—use the `Manual Sync` action to refresh them on demand.
- **Sync on Demand**: Archived mirrors are still available on the Repositories page with automatic syncs disabled; use the `Sync` action to refresh them on demand.
### Execution Settings
+1 -1
View File
@@ -117,7 +117,7 @@ const orphanActions = [
label: "Archive",
description: "Kept read-only with an archived prefix",
icon: Archive,
info: "Renames the mirror with an archived- prefix and disables automatic syncs. Nothing is lost; use Manual Sync to refresh.",
info: "Renames the mirror with an archived- prefix and disables automatic syncs. Nothing is lost; use Sync on the Repositories page to refresh.",
},
{
value: "delete" as const,
+39 -19
View File
@@ -1301,6 +1301,7 @@ function RepoActionButton({
let primaryIcon = <></>;
let primaryOnClick = () => {};
let primaryDisabled = isLoading;
let primaryTooltip: string | undefined;
let showPrimaryAction = true;
if (repo.status === "failed") {
@@ -1308,10 +1309,16 @@ function RepoActionButton({
primaryIcon = <RotateCcw className="h-4 w-4" />;
primaryOnClick = onRetry;
} else if (["mirrored", "synced", "syncing", "archived"].includes(repo.status)) {
primaryLabel = repo.status === "archived" ? "Manual Sync" : "Sync";
primaryLabel = "Sync";
primaryIcon = <RefreshCw className="h-4 w-4" />;
primaryOnClick = onSync;
primaryDisabled ||= repo.status === "syncing";
// Archived mirrors are left out of automatic syncs, so this button is the
// way to refresh one. The Archived badge already marks the row; the label
// stays "Sync" so the column lines up with the other rows.
if (repo.status === "archived") {
primaryTooltip = "Automatic syncs are off for archived mirrors. This syncs it now.";
}
} else if (["imported", "mirroring"].includes(repo.status)) {
primaryLabel = "Mirror";
primaryIcon = <FlipHorizontal className="h-4 w-4" />;
@@ -1336,28 +1343,41 @@ function RepoActionButton({
);
}
const primaryButton = (
<Button
variant="ghost"
disabled={primaryDisabled}
onClick={primaryOnClick}
className="min-w-[80px] justify-start rounded-r-none"
>
{isLoading ? (
<>
<RefreshCw className="h-4 w-4 animate-spin mr-1" />
{primaryLabel}
</>
) : (
<>
{primaryIcon}
<span className="ml-1">{primaryLabel}</span>
</>
)}
</Button>
);
// Show primary action with dropdown for additional actions
return (
<DropdownMenu>
<div className="flex">
<Button
variant="ghost"
disabled={primaryDisabled}
onClick={primaryOnClick}
className="min-w-[80px] justify-start rounded-r-none"
>
{isLoading ? (
<>
<RefreshCw className="h-4 w-4 animate-spin mr-1" />
{primaryLabel}
</>
) : (
<>
{primaryIcon}
<span className="ml-1">{primaryLabel}</span>
</>
)}
</Button>
{primaryTooltip ? (
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>{primaryButton}</TooltipTrigger>
<TooltipContent>{primaryTooltip}</TooltipContent>
</Tooltip>
</TooltipProvider>
) : (
primaryButton
)}
<DropdownMenuTrigger asChild>
<Button
variant="ghost"
+5 -5
View File
@@ -532,8 +532,8 @@ export async function syncGiteaRepoEnhanced({
// archiveGiteaRepo applies to mirror repos (see #331 follow-up).
// Repos archived before mirroredLocation was backfilled on rename, or
// any lingering false-positive orphan hit, would otherwise be
// unreachable from "Manual Sync" — the UI's documented way to refresh
// an archived mirror — because the recorded/expected name no longer
// unreachable from a manual Sync (the UI's documented way to refresh
// an archived mirror) because the recorded/expected name no longer
// exists and Gitea returns HTTP 405 for it.
const dependencies = deps ?? (await import("./gitea"));
const expectedOwner = await dependencies.getGiteaRepoOwnerAsync({ config, repository });
@@ -918,8 +918,8 @@ export async function syncGiteaRepoEnhanced({
//
// Skipped for archived repos: archiveGiteaRepo deliberately disabled
// Gitea's own periodic pulling, and the documented contract
// (AutomationSettings.tsx: "Archive ... disables automatic syncs—use
// Manual Sync when you want to refresh") says a Manual Sync refreshes
// (AutomationSettings.tsx: "Archive ... disables automatic syncs ... use
// Sync on the Repositories page to refresh") says a manual Sync refreshes
// once without re-enabling any automatic syncing.
if (config.giteaConfig?.mirrorInterval && !isArchivedRepo && !repoUsesGitHubApp) {
try {
@@ -1277,7 +1277,7 @@ export async function syncGiteaRepoEnhanced({
// Mark repo as "synced" in DB — unless it's archived. The documented
// contract (AutomationSettings.tsx: "Archive ... disables automatic
// syncs—use Manual Sync when you want to refresh") means a Manual Sync
// syncs ... use Sync on the Repositories page to refresh") means a manual Sync
// of an archived repo must NOT re-enroll it into the scheduler's
// auto-sync pool (which selects mirrored/synced/failed/pending) nor
// clear the archived errorMessage annotation shown in the UI; it still
+1 -1
View File
@@ -425,7 +425,7 @@ async function handleOrphanedRepository(
const { archivedName } = await archiveGiteaRepo(giteaClient, giteaOwner, giteaRepoName);
// If the archive call renamed the repo in Gitea (mirror path), persist
// the new location so a subsequent "Manual Sync" (the UI's documented
// the new location so a later manual Sync (the UI's documented
// path for refreshing an archived mirror) can find it by its actual
// current name instead of the stale pre-rename one — otherwise
// syncGiteaRepoEnhanced looks up a name that no longer exists and