Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions apps/desktop/src/components/GitForm.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import KeysForm from '$components/KeysForm.svelte';
import ReduxResult from '$components/ReduxResult.svelte';
import SettingsSection from '$components/SettingsSection.svelte';
import { BACKEND } from '$lib/backend';
import { PROJECTS_SERVICE } from '$lib/project/projectsService';
import { inject } from '@gitbutler/core/context';
import { CardGroup, Spacer, Toggle } from '@gitbutler/ui';
Expand All @@ -12,7 +11,6 @@
const { projectId }: { projectId: string } = $props();
const projectsService = inject(PROJECTS_SERVICE);
const projectQuery = $derived(projectsService.getProject(projectId));
const backend = inject(BACKEND);

async function onForcePushClick(project: Project, value: boolean) {
await projectsService.updateProject({ ...project, ok_with_force_push: value });
Expand All @@ -25,10 +23,8 @@

<SettingsSection>
<CommitSigningForm {projectId} />
{#if backend.platformName !== 'windows'}
<Spacer />
<KeysForm {projectId} showProjectName={false} />
{/if}
<Spacer />
<KeysForm {projectId} showProjectName={false} />

<Spacer />
<ReduxResult {projectId} result={projectQuery.result}>
Expand Down
111 changes: 63 additions & 48 deletions apps/desktop/src/components/KeysForm.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import ProjectNameLabel from '$components/ProjectNameLabel.svelte';
import ReduxResult from '$components/ReduxResult.svelte';
import SettingsSection from '$components/SettingsSection.svelte';
import { BACKEND } from '$lib/backend';
import { BASE_BRANCH_SERVICE } from '$lib/baseBranch/baseBranchService.svelte';
import { showError } from '$lib/notifications/toasts';
import { type AuthKey, type KeyType } from '$lib/project/project';
Expand Down Expand Up @@ -36,11 +37,18 @@
const projectsService = inject(PROJECTS_SERVICE);
const projectQuery = $derived(projectsService.getProject(projectId));
const project = $derived(projectQuery.response);
const backend = inject(BACKEND);
const isWindows = $derived(backend.platformName === 'windows');
let credentialCheck = $state<CredentialCheck>();
function getDefaultCredentialType(): KeyType {
// Use systemExecutable on Windows since other options are not available
return isWindows ? 'systemExecutable' : 'local';
}
let selectedType: KeyType = $derived(
typeof project?.preferred_key === 'string' ? project?.preferred_key : 'local'
typeof project?.preferred_key === 'string' ? project?.preferred_key : getDefaultCredentialType()
);
Comment on lines +45 to 52
Copy link

Copilot AI Dec 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The getDefaultCredentialType() function is being called inside a $derived block (line 51), but it references another $derived value (isWindows). This creates a reactivity issue where the function doesn't properly track the dependency on isWindows.

The selectedType derivation should inline the logic instead of calling a function, or the function should be converted to a $derived itself. Here's the recommended fix:

Replace the function call with inline logic:

let selectedType: KeyType = $derived(
	typeof project?.preferred_key === 'string' 
		? project?.preferred_key 
		: (isWindows ? 'systemExecutable' : 'local')
);

Then remove the getDefaultCredentialType() function as it's no longer needed.

Copilot uses AI. Check for mistakes.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be no problem as isWindows is static.

let privateKeyPath = $state('');
Expand Down Expand Up @@ -104,6 +112,11 @@
{#snippet description()}
Configure the authentication flow for GitButler when authenticating with your Git remote
provider.
{#if isWindows}
<br /><br />
<strong>On Windows,</strong> only the Git executable option is available for compatibility
reasons.
{/if}
{/snippet}
<CardGroup>
<form
Expand Down Expand Up @@ -132,58 +145,60 @@
{/snippet}
</CardGroup.Item>

<CardGroup.Item labelFor="credential-local">
{#snippet title()}
Use existing SSH key
{/snippet}

{#snippet actions()}
<RadioButton name="credentialType" id="credential-local" value="local" />
{/snippet}

{#snippet caption()}
{#if selectedType === 'local'}
Add the path to an existing SSH key that GitButler can use.
{/if}
{/snippet}
</CardGroup.Item>
{#if !isWindows}
<CardGroup.Item labelFor="credential-local">
{#snippet title()}
Use existing SSH key
{/snippet}

{#snippet actions()}
<RadioButton name="credentialType" id="credential-local" value="local" />
{/snippet}

{#snippet caption()}
{#if selectedType === 'local'}
Add the path to an existing SSH key that GitButler can use.
{/if}
{/snippet}
</CardGroup.Item>

{#if selectedType === 'local'}
<CardGroup.Item>
<div class="inputs-group">
<Textbox
label="Path to private key"
placeholder="for example: ~/.ssh/id_rsa"
bind:value={privateKeyPath}
oninput={(value) => {
debouncedUpdateLocalKey(value);
}}
{#if selectedType === 'local'}
<CardGroup.Item>
<div class="inputs-group">
<Textbox
label="Path to private key"
placeholder="for example: ~/.ssh/id_rsa"
bind:value={privateKeyPath}
oninput={(value) => {
debouncedUpdateLocalKey(value);
}}
/>
</div>
</CardGroup.Item>
{/if}

<CardGroup.Item labelFor="credential-helper">
{#snippet title()}
Use a Git credentials helper
{/snippet}

{#snippet caption()}
{#if selectedType === 'gitCredentialsHelper'}
GitButler will use the system's git credentials helper.
<Link href="https://git-scm.com/doc/credential-helpers">Learn more</Link>
{/if}
{/snippet}

{#snippet actions()}
<RadioButton
name="credentialType"
value="gitCredentialsHelper"
id="credential-helper"
/>
</div>
{/snippet}
</CardGroup.Item>
{/if}

<CardGroup.Item labelFor="credential-helper">
{#snippet title()}
Use a Git credentials helper
{/snippet}

{#snippet caption()}
{#if selectedType === 'gitCredentialsHelper'}
GitButler will use the system's git credentials helper.
<Link href="https://git-scm.com/doc/credential-helpers">Learn more</Link>
{/if}
{/snippet}

{#snippet actions()}
<RadioButton
name="credentialType"
value="gitCredentialsHelper"
id="credential-helper"
/>
{/snippet}
</CardGroup.Item>

<CardGroup.Item>
<CredentialCheck
bind:this={credentialCheck}
Expand Down
Loading