Skip to content

Commit 9cbc310

Browse files
committed
feat: enhance Git credential handling for local repositories
1 parent 91fe9ff commit 9cbc310

2 files changed

Lines changed: 34 additions & 25 deletions

File tree

packages/insomnia/src/ui/components/git-credentials/git-credential-select.tsx

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,18 @@ import { Icon } from '~/basic-components/icon';
66
import type { GitProviderOption } from '~/sync/git/providers/types';
77
import { showSettingsModal } from '~/ui/components/modals/settings-modal';
88

9-
const NONE_KEY = '__none__';
10-
119
interface Props {
1210
credentials: GitCredentials[];
1311
providers: GitProviderOption[];
1412
selectedCredentialsId: string | null | undefined;
15-
onChange: (credentialsId: string | null) => void;
13+
onChange: (credentialsId: string) => void;
1614
label?: string;
1715
}
1816

1917
/**
20-
* Picker for the Git credentials associated with a repository. Includes a "No
21-
* credentials" option since local repositories may not need a remote. Used by
22-
* the "Open existing folder" flow.
18+
* Picker for the Git credentials associated with a repository. Defaults to the
19+
* native (system git) credentials, which require no remote configuration. Used
20+
* by the "Open existing folder" flow.
2321
*/
2422
export const GitCredentialSelect: FC<Props> = ({
2523
credentials,
@@ -37,8 +35,8 @@ export const GitCredentialSelect: FC<Props> = ({
3735
isOpen={isOpen}
3836
onOpenChange={setIsOpen}
3937
aria-label={label}
40-
selectedKey={selected?._id || NONE_KEY}
41-
onSelectionChange={key => onChange(key === NONE_KEY ? null : (key as string))}
38+
selectedKey={selected?._id ?? null}
39+
onSelectionChange={key => onChange(key as string)}
4240
>
4341
<Label className="mb-2 px-0.5 pt-0 text-sm text-(--color-font)">{label}</Label>
4442
<Button className="flex w-full flex-1 items-center justify-between gap-2 rounded-xs border border-solid border-(--hl-sm) bg-(--color-bg) px-2 py-1 text-(--color-font) ring-1 ring-transparent transition-colors hover:bg-(--hl-xs) focus:ring-1 focus:ring-(--hl-md) focus:outline-hidden focus:ring-inset aria-pressed:bg-(--hl-sm)">
@@ -47,24 +45,21 @@ export const GitCredentialSelect: FC<Props> = ({
4745
<Fragment>
4846
{selectedProvider?.iconName && <Icon icon={selectedProvider.iconName} className="size-4" />}
4947
<span>{selectedProvider?.displayName}</span>
50-
<Separator orientation="vertical" className="mx-2 h-4 border-l border-(--color-font)" />
51-
<span className="truncate">{selected.author?.name}</span>
48+
{selected.author?.name && (
49+
<Fragment>
50+
<Separator orientation="vertical" className="mx-2 h-4 border-l border-(--color-font)" />
51+
<span className="truncate">{selected.author.name}</span>
52+
</Fragment>
53+
)}
5254
</Fragment>
5355
) : (
54-
'No credentials (set later)'
56+
'Select credentials'
5557
)}
5658
</span>
5759
<Icon icon="caret-down" />
5860
</Button>
5961
<Popover className="isolate flex w-(--trigger-width) min-w-max flex-col overflow-hidden rounded-md border border-solid border-(--hl-sm) bg-(--color-bg) text-sm shadow-lg select-none">
6062
<ListBox className="min-w-max overflow-y-auto py-2 focus:outline-hidden">
61-
<ListBoxItem
62-
id={NONE_KEY}
63-
textValue="No credentials"
64-
className="flex h-(--line-height-xs) w-full items-center gap-2 bg-transparent px-(--padding-md) whitespace-nowrap text-(--color-font) transition-colors hover:bg-(--hl-sm) focus:bg-(--hl-xs) focus:outline-hidden aria-selected:font-bold"
65-
>
66-
No credentials (set later)
67-
</ListBoxItem>
6863
{credentials.map(item => {
6964
const provider = providers.find(p => p.type === item.provider);
7065
return (
@@ -77,8 +72,12 @@ export const GitCredentialSelect: FC<Props> = ({
7772
>
7873
{provider?.iconName && <Icon icon={provider.iconName} className="size-4" />}
7974
<span>{provider?.displayName}</span>
80-
<Separator orientation="vertical" className="mx-2 h-4 border-l border-(--color-font)" />
81-
<span className="truncate">{item.author?.name}</span>
75+
{item.author?.name && (
76+
<Fragment>
77+
<Separator orientation="vertical" className="mx-2 h-4 border-l border-(--color-font)" />
78+
<span className="truncate">{item.author.name}</span>
79+
</Fragment>
80+
)}
8281
</ListBoxItem>
8382
);
8483
})}

packages/insomnia/src/ui/components/project/project-create-form.tsx

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ export const ProjectCreateForm: FC<Props> = ({
5959
const [gitMode, setGitMode] = useState<'clone' | 'open'>('clone');
6060
const [openExistingDir, setOpenExistingDir] = useState('');
6161

62+
// Local repositories default to the native (system git) credentials, which
63+
// are always present as a seeded singleton and need no remote configuration.
64+
const nativeCredentialsId = credentials.find(c => c.provider === 'native')?._id;
65+
6266
const [projectData, setProjectData] = useState<ProjectData>({
6367
name: defaultProjectName,
6468
uri: '',
@@ -94,6 +98,14 @@ export const ProjectCreateForm: FC<Props> = ({
9498

9599
const isGitOpen = storageType === 'git' && gitMode === 'open';
96100

101+
// Preselect native git credentials when adopting a local folder so the user
102+
// isn't forced to pick before continuing.
103+
useEffect(() => {
104+
if (isGitOpen && !projectData.credentialsId && nativeCredentialsId) {
105+
setProjectData(prev => ({ ...prev, credentialsId: nativeCredentialsId }));
106+
}
107+
}, [isGitOpen, projectData.credentialsId, nativeCredentialsId]);
108+
97109
const onUpsertProject = async () => {
98110
if (!storageType) {
99111
return;
@@ -229,11 +241,9 @@ export const ProjectCreateForm: FC<Props> = ({
229241
<GitCredentialSelect
230242
credentials={credentials}
231243
providers={providers}
232-
selectedCredentialsId={projectData.credentialsId}
233-
onChange={credentialsId =>
234-
setProjectData(prev => ({ ...prev, credentialsId: credentialsId ?? undefined }))
235-
}
236-
label="Git credentials (optional)"
244+
selectedCredentialsId={projectData.credentialsId ?? nativeCredentialsId}
245+
onChange={credentialsId => setProjectData(prev => ({ ...prev, credentialsId }))}
246+
label="Git credentials"
237247
/>
238248
</div>
239249
)}

0 commit comments

Comments
 (0)