Skip to content

Commit c82d50a

Browse files
committed
Enable single branch mode
1 parent 06538d6 commit c82d50a

39 files changed

+356
-254
lines changed

apps/desktop/cypress/e2e/support/mock/settings.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ export const MOCK_FEATURE_FLAGS: FeatureFlags = {
1111
ws3: false,
1212
actions: false,
1313
butbot: false,
14-
rules: false
14+
rules: false,
15+
singleBranch: false
1516
};
1617

1718
export const MOCK_APP_SETTINGS: AppSettings = {

apps/desktop/src/components/BranchCard.svelte

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@
5454
interface StackBranchProps extends BranchCardProps {
5555
type: 'stack-branch';
5656
iconName: keyof typeof iconsJson;
57-
stackId: string;
57+
stackId?: string;
58+
laneId: string;
5859
selected: boolean;
5960
trackingBranch?: string;
6061
isNewBranch?: boolean;
@@ -99,7 +100,7 @@
99100
);
100101
101102
const stackState = $derived(
102-
args.type === 'stack-branch' ? uiState.stack(args.stackId) : undefined
103+
args.type === 'stack-branch' ? uiState.stack(args.laneId) : undefined
103104
);
104105
const selection = $derived(stackState ? stackState.selection.current : undefined);
105106
const selected = $derived(selection?.branchName === branchName);
@@ -113,9 +114,11 @@
113114
uiState.global.draftBranchName.set(normalized);
114115
}
115116
} else if (args.type === 'stack-branch') {
117+
if (!args.stackId) return;
116118
updateName({
117119
projectId,
118120
stackId: args.stackId,
121+
laneId: args.laneId,
119122
branchName,
120123
newName: title
121124
});
@@ -135,11 +138,15 @@
135138
data-testid={TestId.BranchCard}
136139
>
137140
{#if args.type === 'stack-branch'}
138-
{@const moveHandler = new MoveCommitDzHandler(stackService, args.stackId, projectId)}
139-
{#if !args.prNumber}
141+
{@const moveHandler = args.stackId
142+
? new MoveCommitDzHandler(stackService, args.stackId, projectId)
143+
: undefined}
144+
{#if !args.prNumber && args.stackId}
140145
<PrNumberUpdater {projectId} stackId={args.stackId} {branchName} />
141146
{/if}
142-
<Dropzone handlers={args.first ? [moveHandler, ...args.dropzones] : args.dropzones}>
147+
<Dropzone
148+
handlers={args.first && moveHandler ? [moveHandler, ...args.dropzones] : args.dropzones}
149+
>
143150
{#snippet overlay({ hovered, activated, handler })}
144151
{@const label =
145152
handler instanceof MoveCommitDzHandler

apps/desktop/src/components/BranchCommitList.svelte

Lines changed: 54 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import { inject } from '@gitbutler/shared/context';
3535
import { Button, Modal, TestId } from '@gitbutler/ui';
3636
import { getTimeAgo } from '@gitbutler/ui/utils/timeAgo';
37+
import { isDefined } from '@gitbutler/ui/utils/typeguards';
3738
import type { Commit } from '$lib/branches/v3';
3839
import type { CommitStatusType } from '$lib/commits/commit';
3940
import type { BranchDetails } from '$lib/stacks/stack';
@@ -60,7 +61,8 @@
6061
interface Props {
6162
active: boolean;
6263
projectId: string;
63-
stackId: string;
64+
stackId?: string;
65+
laneId: string;
6466
branchName: string;
6567
firstBranch: boolean;
6668
lastBranch: boolean;
@@ -82,6 +84,7 @@
8284
active,
8385
projectId,
8486
stackId,
87+
laneId,
8588
branchName,
8689
branchDetails,
8790
firstBranch,
@@ -108,7 +111,7 @@
108111
const isCommitting = $derived(
109112
exclusiveAction?.type === 'commit' && exclusiveAction.stackId === stackId
110113
);
111-
const stackState = $derived(uiState.stack(stackId));
114+
const stackState = $derived(uiState.stack(laneId));
112115
const selection = $derived(stackState.selection);
113116
const runHooks = $derived(projectRunCommitHooks(projectId));
114117
@@ -127,6 +130,7 @@
127130
let confirmResetModal = $state<ReturnType<typeof Modal>>();
128131
129132
async function integrate(strategy?: SeriesIntegrationStrategy): Promise<void> {
133+
if (!stackId) return;
130134
await integrateUpstreamCommits({
131135
projectId,
132136
stackId,
@@ -315,35 +319,41 @@
315319
isIntegrated: isLocalAndRemoteCommit(commit) && commit.state.type === 'Integrated',
316320
hasConflicts: isLocalAndRemoteCommit(commit) && commit.hasConflicts,
317321
}}
318-
{@const amendHandler = new AmendCommitWithChangeDzHandler(
319-
projectId,
320-
stackService,
321-
hooksService,
322-
stackId,
323-
$runHooks,
324-
dzCommit,
325-
(newId) => uiState.stack(stackId).selection.set({ branchName, commitId: newId }),
326-
uiState
327-
)}
328-
{@const squashHandler = new SquashCommitDzHandler({
329-
stackService,
330-
projectId,
331-
stackId,
332-
commit: dzCommit
333-
})}
334-
{@const hunkHandler = new AmendCommitWithHunkDzHandler({
335-
stackService,
336-
hooksService,
337-
projectId,
338-
stackId,
339-
commit: dzCommit,
340-
runHooks: $runHooks,
341-
// TODO: Use correct value!
342-
okWithForce: true,
343-
uiState
344-
})}
322+
{@const amendHandler = stackId
323+
? new AmendCommitWithChangeDzHandler(
324+
projectId,
325+
stackService,
326+
hooksService,
327+
stackId,
328+
$runHooks,
329+
dzCommit,
330+
(newId) => uiState.stack(stackId).selection.set({ branchName, commitId: newId }),
331+
uiState
332+
)
333+
: undefined}
334+
{@const squashHandler = stackId
335+
? new SquashCommitDzHandler({
336+
stackService,
337+
projectId,
338+
stackId,
339+
commit: dzCommit
340+
})
341+
: undefined}
342+
{@const hunkHandler = stackId
343+
? new AmendCommitWithHunkDzHandler({
344+
stackService,
345+
hooksService,
346+
projectId,
347+
stackId,
348+
commit: dzCommit,
349+
runHooks: $runHooks,
350+
// TODO: Use correct value!
351+
okWithForce: true,
352+
uiState
353+
})
354+
: undefined}
345355
{@const tooltip = commitStatusLabel(commit.state.type)}
346-
<Dropzone handlers={[amendHandler, squashHandler, hunkHandler]}>
356+
<Dropzone handlers={[amendHandler, squashHandler, hunkHandler].filter(isDefined)}>
347357
{#snippet overlay({ hovered, activated, handler })}
348358
{@const label =
349359
handler instanceof AmendCommitWithChangeDzHandler ||
@@ -361,18 +371,20 @@
361371
date: getTimeAgo(commit.createdAt),
362372
authorImgUrl: undefined,
363373
commitType: commit.state.type,
364-
data: new CommitDropData(
365-
stackId,
366-
{
367-
id: commitId,
368-
isRemote: !!branchDetails.remoteTrackingBranch,
369-
hasConflicts: isLocalAndRemoteCommit(commit) && commit.hasConflicts,
370-
isIntegrated:
371-
isLocalAndRemoteCommit(commit) && commit.state.type === 'Integrated'
372-
},
373-
false,
374-
branchName
375-
),
374+
data: stackId
375+
? new CommitDropData(
376+
stackId,
377+
{
378+
id: commitId,
379+
isRemote: !!branchDetails.remoteTrackingBranch,
380+
hasConflicts: isLocalAndRemoteCommit(commit) && commit.hasConflicts,
381+
isIntegrated:
382+
isLocalAndRemoteCommit(commit) && commit.state.type === 'Integrated'
383+
},
384+
false,
385+
branchName
386+
)
387+
: undefined,
376388
viewportId: 'board-viewport',
377389
dropzoneRegistry,
378390
dragStateService

apps/desktop/src/components/BranchHeaderContextMenu.svelte

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
type Props = {
4141
projectId: string;
4242
stackId?: string;
43+
laneId: string;
4344
openId?: string;
4445
rightClickTrigger?: HTMLElement;
4546
contextData: BranchHeaderContextData;
@@ -48,6 +49,7 @@
4849
let {
4950
projectId,
5051
stackId,
52+
laneId,
5153
openId = $bindable(),
5254
rightClickTrigger,
5355
contextData
@@ -116,6 +118,7 @@
116118
await updateBranchNameMutation({
117119
projectId: projectId,
118120
stackId,
121+
laneId,
119122
branchName,
120123
newName: newBranchName
121124
});
@@ -259,6 +262,7 @@
259262
renameBranchModalContext = {
260263
projectId,
261264
stackId,
265+
laneId,
262266
branchName,
263267
isPushed: !!branch.remoteTrackingBranch
264268
};

apps/desktop/src/components/BranchList.svelte

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,14 @@
3131
3232
type Props = {
3333
projectId: string;
34-
stackId: string;
34+
stackId?: string;
35+
laneId: string;
3536
branches: BranchDetails[];
3637
focusedStackId?: string;
3738
onselect?: () => void;
3839
};
3940
40-
const { projectId, branches, stackId, focusedStackId, onselect }: Props = $props();
41+
const { projectId, branches, stackId, laneId, focusedStackId, onselect }: Props = $props();
4142
const stackService = inject(STACK_SERVICE);
4243
const uiState = inject(UI_STATE);
4344
const modeService = inject(MODE_SERVICE);
@@ -54,7 +55,7 @@
5455
const isCommitting = $derived(
5556
exclusiveAction?.type === 'commit' && exclusiveAction?.stackId === stackId
5657
);
57-
const stackState = $derived(uiState.stack(stackId));
58+
const stackState = $derived(uiState.stack(laneId));
5859
const selection = $derived(stackState.selection);
5960
const selectedCommitId = $derived(selection.current?.commitId);
6061
@@ -64,6 +65,7 @@
6465
$state<ReturnType<typeof ConflictResolutionConfirmModal>>();
6566
6667
async function handleUncommit(commitId: string, branchName: string) {
68+
if (!stackId) return;
6769
await stackService.uncommit({ projectId, stackId, branchName, commitId: commitId });
6870
}
6971
@@ -83,6 +85,7 @@
8385
hasConflicts: boolean;
8486
isAncestorMostConflicted: boolean;
8587
}) {
88+
if (!stackId) return;
8689
if (args.type === 'LocalAndRemote' && args.hasConflicts && !args.isAncestorMostConflicted) {
8790
conflictResolutionConfirmationModal?.show();
8891
return;
@@ -111,7 +114,7 @@
111114
const stackingReorderDropzoneManagerFactory = inject(STACKING_REORDER_DROPZONE_MANAGER_FACTORY);
112115
const stackingReorderDropzoneManager = $derived(
113116
stackingReorderDropzoneManagerFactory.build(
114-
stackId,
117+
laneId,
115118
branches.map((s) => ({ name: s.name, commitIds: s.commits.map((p) => p.id) }))
116119
)
117120
);
@@ -164,6 +167,7 @@
164167
type="stack-branch"
165168
{projectId}
166169
{stackId}
170+
{laneId}
167171
{branchName}
168172
{lineColor}
169173
{first}
@@ -181,8 +185,8 @@
181185
trackingBranch={branch.remoteTrackingBranch ?? undefined}
182186
readonly={!!branch.remoteTrackingBranch}
183187
onclick={() => {
184-
uiState.stack(stackId).selection.set({ branchName });
185-
intelligentScrollingService.show(projectId, stackId, 'details');
188+
uiState.stack(laneId).selection.set({ branchName });
189+
intelligentScrollingService.show(projectId, laneId, 'details');
186190
onselect?.();
187191
}}
188192
>
@@ -193,6 +197,7 @@
193197
kind="outline"
194198
tooltip="Create empty commit"
195199
onclick={async () => {
200+
if (!stackId) return;
196201
await insertBlankCommitInBranch({
197202
projectId,
198203
stackId,
@@ -218,6 +223,7 @@
218223
kind="outline"
219224
tooltip="Create new branch"
220225
onclick={async () => {
226+
if (!stackId) return;
221227
addDependentBranchModalContext = {
222228
projectId,
223229
stackId
@@ -284,7 +290,13 @@
284290
first,
285291
stackLength: branches.length
286292
}}
287-
<BranchHeaderContextMenu {projectId} {stackId} {rightClickTrigger} contextData={data} />
293+
<BranchHeaderContextMenu
294+
{projectId}
295+
{stackId}
296+
{laneId}
297+
{rightClickTrigger}
298+
contextData={data}
299+
/>
288300
{/snippet}
289301

290302
{#snippet branchContent()}
@@ -294,6 +306,7 @@
294306
active={focusedStackId === stackId}
295307
{projectId}
296308
{stackId}
309+
{laneId}
297310
{branchName}
298311
{branchDetails}
299312
{stackingReorderDropzoneManager}

apps/desktop/src/components/BranchRenameModal.svelte

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
<script lang="ts" module>
22
export type BranchRenameModalProps = {
33
projectId: string;
4-
stackId: string;
4+
stackId?: string;
5+
laneId: string;
56
branchName: string;
67
isPushed: boolean;
78
};
@@ -12,7 +13,7 @@
1213
import { inject } from '@gitbutler/shared/context';
1314
import { Button, ElementId, Modal, TestId, Textbox } from '@gitbutler/ui';
1415
15-
const { projectId, stackId, branchName, isPushed }: BranchRenameModalProps = $props();
16+
const { projectId, stackId, laneId, branchName, isPushed }: BranchRenameModalProps = $props();
1617
const stackService = inject(STACK_SERVICE);
1718
1819
const [renameBranch, renameResult] = stackService.updateBranchName;
@@ -34,7 +35,7 @@
3435
bind:this={modal}
3536
onSubmit={async (close) => {
3637
if (newName) {
37-
renameBranch({ projectId, stackId, branchName, newName });
38+
renameBranch({ projectId, stackId, laneId, branchName, newName });
3839
}
3940
close();
4041
}}

0 commit comments

Comments
 (0)