feat(dashboard): expose mergeAdvanceAutoSync in the project settings modal
Adds the missing form control for the auto-sync mode introduced by the merger hook. Lives next to Direct merge commit routing / Integration worktree inside the merge-strategy panel and only renders when mergeStrategy === "direct". Three options with descriptions cribbed from docs/settings-reference.md: - Stash + fast-forward (default): preserve local edits across the snap - Fast-forward only: skip dirty worktrees, surface the banner instead - Off: legacy behavior; project root stays stale until manual pull Value is normalized through normalizeMergeAdvanceAutoSyncMode on both the merged-settings and scoped-settings load paths so a missing/invalid stored value cleanly falls back to the default. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
13
.changeset/merge-advance-auto-sync-settings-ui.md
Normal file
13
.changeset/merge-advance-auto-sync-settings-ui.md
Normal file
@@ -0,0 +1,13 @@
|
||||
---
|
||||
"@fusion/dashboard": patch
|
||||
---
|
||||
|
||||
feat(dashboard): expose `mergeAdvanceAutoSync` in the project settings modal
|
||||
|
||||
Adds the missing form control for the auto-sync mode introduced by the merger hook. Lives next to the existing Direct merge commit routing / Integration worktree controls inside the merge-strategy panel and only renders when `mergeStrategy === "direct"`. Three options with the same labels and descriptions as `docs/settings-reference.md`:
|
||||
|
||||
- **Stash + fast-forward (default)** — preserve local edits across the auto-snap
|
||||
- **Fast-forward only** — skip dirty worktrees, surface the banner instead
|
||||
- **Off** — legacy behavior, project root stays stale until manual pull
|
||||
|
||||
Value is normalized through `normalizeMergeAdvanceAutoSyncMode` on both the merged-settings and scoped-settings load paths so a missing/invalid stored value cleanly falls back to the default without spamming validation errors.
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
resolveProjectDefaultModel,
|
||||
resolveTitleSummarizerSettingsModel,
|
||||
normalizeMergeIntegrationWorktreeMode,
|
||||
normalizeMergeAdvanceAutoSyncMode,
|
||||
} from "@fusion/core";
|
||||
import type { AgentPermissionPolicyRules, Settings, GlobalSettings, ThemeMode, ColorTheme, ModelPreset, NtfyNotificationEvent, AgentPromptsConfig, ThinkingLevel } from "@fusion/core";
|
||||
import { fetchSettings, fetchSettingsByScope, updateSettings, updateGlobalSettings, fetchAuthStatus, loginProvider, logoutProvider, cancelProviderLogin, saveApiKey, clearApiKey, fetchModels, testNotification, fetchBackups, createBackup, exportSettings, importSettings, fetchMemoryFile, fetchMemoryFiles, saveMemoryFile, compactMemory, fetchGlobalConcurrency, updateGlobalConcurrency, installQmd, testMemoryRetrieval, triggerMemoryDreams, fetchGitRemotes, fetchGitRemotesDetailed, fetchProjects, fetchDashboardHealth, checkForUpdates, fetchRemoteSettings, updateRemoteSettings, fetchRemoteStatus, installCloudflared, startRemoteTunnel, stopRemoteTunnel, killExternalTunnel, regenerateRemotePersistentToken, generateShortLivedRemoteToken, fetchRemoteQr, fetchRemoteUrl, submitProviderManualCode } from "../api";
|
||||
@@ -443,6 +444,7 @@ export function SettingsModal({
|
||||
autoMerge: true,
|
||||
mergeStrategy: "direct",
|
||||
mergeIntegrationWorktree: "reuse-task-worktree",
|
||||
mergeAdvanceAutoSync: "stash-and-ff",
|
||||
recycleWorktrees: false,
|
||||
executorAllowSiblingBranchRename: false,
|
||||
worktreeNaming: "random",
|
||||
@@ -688,6 +690,7 @@ export function SettingsModal({
|
||||
const normalizedSettings = {
|
||||
...s,
|
||||
mergeIntegrationWorktree: normalizeMergeIntegrationWorktreeMode(s.mergeIntegrationWorktree),
|
||||
mergeAdvanceAutoSync: normalizeMergeAdvanceAutoSyncMode(s.mergeAdvanceAutoSync),
|
||||
};
|
||||
setForm(normalizedSettings);
|
||||
setInitialValues(normalizedSettings); // Store initial values to detect explicit clears
|
||||
@@ -699,6 +702,9 @@ export function SettingsModal({
|
||||
mergeIntegrationWorktree: scoped.project.mergeIntegrationWorktree === undefined
|
||||
? undefined
|
||||
: normalizeMergeIntegrationWorktreeMode(scoped.project.mergeIntegrationWorktree),
|
||||
mergeAdvanceAutoSync: scoped.project.mergeAdvanceAutoSync === undefined
|
||||
? undefined
|
||||
: normalizeMergeAdvanceAutoSyncMode(scoped.project.mergeAdvanceAutoSync),
|
||||
},
|
||||
}); // Store initial scoped values for null-as-delete
|
||||
setLoading(false);
|
||||
@@ -4673,6 +4679,40 @@ export function SettingsModal({
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label htmlFor="mergeAdvanceAutoSync">Auto-sync project checkout after merge</label>
|
||||
<select
|
||||
id="mergeAdvanceAutoSync"
|
||||
className="select"
|
||||
value={form.mergeAdvanceAutoSync ?? "stash-and-ff"}
|
||||
onChange={(e) =>
|
||||
setForm((f) => ({
|
||||
...f,
|
||||
mergeAdvanceAutoSync: e.target.value as "off" | "ff-only" | "stash-and-ff",
|
||||
}))
|
||||
}
|
||||
data-testid="merge-advance-auto-sync-select"
|
||||
>
|
||||
<option value="stash-and-ff">Stash + fast-forward (default) — preserve local edits</option>
|
||||
<option value="ff-only">Fast-forward only — skip dirty worktrees</option>
|
||||
<option value="off">Off — leave the project root stale (legacy behavior)</option>
|
||||
</select>
|
||||
<details className="settings-option-details">
|
||||
<summary>More details</summary>
|
||||
<small>
|
||||
After Fusion advances the integration branch ref, the merger can auto-sync other
|
||||
worktrees still checked out on that branch (typically your project-root
|
||||
checkout). <code>Stash + fast-forward</code> snapshots real local edits as a patch
|
||||
against the previous tip, snaps the worktree to the new tip, then reapplies the
|
||||
patch — untracked files that collide with newly-tracked paths are left in a temp
|
||||
dir for manual recovery. <code>Fast-forward only</code> snaps cleanly when the
|
||||
worktree has no edits and skips otherwise. <code>Off</code> is the legacy
|
||||
behavior: <code>git status</code> in your project root will show the new commits
|
||||
inverted as "staged changes" until you pull manually. Only applies to direct
|
||||
merges.
|
||||
</small>
|
||||
</details>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{form.mergeStrategy === "pull-request" && (
|
||||
|
||||
Reference in New Issue
Block a user