Skip to content

Commit cd0d1e3

Browse files
authored
Merge pull request #12902 from gitbutlerapp/refactor/filelist-controller
Decompose StackView and FileList into compound components
2 parents 9c6947c + a0be5b9 commit cd0d1e3

20 files changed

Lines changed: 1887 additions & 1127 deletions

apps/desktop/src/components/BranchCard.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@
168168
>
169169
{#if args.type === "stack-branch"}
170170
{@const moveHandler = args.stackId
171-
? new MoveCommitDzHandler(stackService, args.stackId, projectId, uiState)
171+
? new MoveCommitDzHandler(args.stackId, projectId)
172172
: undefined}
173173
{#if !args.prNumber && args.stackId}
174174
<PrNumberUpdater {projectId} stackId={args.stackId} {branchName} />

apps/desktop/src/components/BranchCommitList.svelte

Lines changed: 50 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,11 @@
3232
import { HOOKS_SERVICE } from "$lib/hooks/hooksService";
3333
import { IRC_API_SERVICE } from "$lib/irc/ircApiService";
3434
import { createCommitSelection } from "$lib/selection/key";
35+
import { getStackContext } from "$lib/stack/stackController.svelte";
3536
import { STACK_SERVICE } from "$lib/stacks/stackService.svelte";
37+
3638
import { combineResults } from "$lib/state/helpers";
37-
import { UI_STATE } from "$lib/state/uiState.svelte";
39+
import { ensureValue } from "$lib/utils/validation";
3840
import { inject } from "@gitbutler/core/context";
3941
import { persisted } from "@gitbutler/shared/persisted";
4042
import { Button, Modal, RadioButton, TestId } from "@gitbutler/ui";
@@ -45,61 +47,35 @@
4547
import type { BranchDetails } from "$lib/stacks/stack";
4648
4749
interface Props {
48-
projectId: string;
49-
stackId?: string;
50-
laneId: string;
5150
branchName: string;
5251
lastBranch: boolean;
5352
branchDetails: BranchDetails;
5453
stackingReorderDropzoneManager: ReorderCommitDzFactory;
5554
roundedTop?: boolean;
56-
active?: boolean;
57-
visibleRange?: { start: number; end: number };
58-
59-
handleUncommit: (commitId: string, branchName: string) => Promise<void>;
60-
startEditingCommitMessage: (branchName: string, commitId: string) => void;
61-
onclick?: () => void;
62-
onFileClick?: (index: number) => void;
6355
}
6456
65-
let {
66-
projectId,
67-
stackId,
68-
laneId,
69-
branchName,
70-
branchDetails,
71-
lastBranch,
72-
stackingReorderDropzoneManager,
73-
roundedTop,
74-
active,
75-
visibleRange,
76-
handleUncommit,
77-
startEditingCommitMessage,
78-
onclick,
79-
onFileClick,
80-
}: Props = $props();
57+
let { branchName, branchDetails, lastBranch, stackingReorderDropzoneManager, roundedTop }: Props =
58+
$props();
8159
60+
const controller = getStackContext();
8261
const stackService = inject(STACK_SERVICE);
83-
const uiState = inject(UI_STATE);
8462
const forge = inject(DEFAULT_FORGE_FACTORY);
8563
const hooksService = inject(HOOKS_SERVICE);
8664
const ircApiService = inject(IRC_API_SERVICE);
8765
const dropzoneRegistry = inject(DROPZONE_REGISTRY);
8866
const dragStateService = inject(DRAG_STATE_SERVICE);
8967
68+
const projectId = $derived(controller.projectId);
69+
const stackId = $derived(controller.stackId);
70+
9071
const commitReactionsQuery = $derived(ircApiService.commitReactions());
9172
const commitReactions = $derived(commitReactionsQuery?.response ?? {});
9273
9374
const [integrateUpstreamCommits, integrating] = stackService.integrateUpstreamCommits;
9475
95-
const projectState = $derived(uiState.project(projectId));
96-
const exclusiveAction = $derived(projectState.exclusiveAction.current);
76+
const exclusiveAction = $derived(controller.exclusiveAction);
9777
const commitAction = $derived(exclusiveAction?.type === "commit" ? exclusiveAction : undefined);
98-
const isCommitting = $derived(
99-
exclusiveAction?.type === "commit" && exclusiveAction.stackId === stackId,
100-
);
101-
const laneState = $derived(uiState.lane(laneId));
102-
const selection = $derived(laneState.selection);
78+
const selection = $derived(controller.selection);
10379
const runHooks = $derived(projectRunCommitHooks(projectId));
10480
10581
const selectedBranchName = $derived(selection.current?.branchName);
@@ -113,14 +89,33 @@
11389
let integrationModal = $state<Modal>();
11490
11591
async function handleCommitClick(commitId: string, upstream: boolean) {
116-
const currentSelection = laneState.selection.current;
92+
const currentSelection = controller.selection.current;
11793
// Toggle: if this exact commit is already selected, clear the selection
11894
if (currentSelection?.commitId === commitId && currentSelection?.branchName === branchName) {
119-
laneState.selection.set(undefined);
95+
controller.selection.set(undefined);
12096
} else {
121-
laneState.selection.set({ branchName, commitId, upstream, previewOpen: true });
97+
controller.selection.set({ branchName, commitId, upstream, previewOpen: true });
12298
}
123-
onclick?.();
99+
controller.clearWorktreeSelection();
100+
}
101+
102+
async function handleUncommit(commitId: string) {
103+
await stackService.uncommit({
104+
projectId,
105+
stackId: ensureValue(stackId),
106+
branchName,
107+
commitId,
108+
});
109+
}
110+
111+
function startEditingCommitMessage(commitId: string) {
112+
controller.selection.set({ branchName, commitId, previewOpen: true });
113+
controller.projectState.exclusiveAction.set({
114+
type: "edit-commit-message",
115+
stackId,
116+
branchName,
117+
commitId,
118+
});
124119
}
125120
126121
function kickOffIntegration() {
@@ -215,7 +210,7 @@
215210
{/snippet}
216211

217212
{#snippet commitReorderDz(dropzone: ReorderCommitDzHandler)}
218-
{#if !isCommitting}
213+
{#if !controller.isCommitting}
219214
<Dropzone handlers={[dropzone]}>
220215
{#snippet overlay({ hovered, activated })}
221216
<CommitLineOverlay {hovered} {activated} />
@@ -247,7 +242,7 @@
247242
{@const lastCommit = i === upstreamOnlyCommits.length - 1}
248243
{@const selected = commit.id === selectedCommitId && branchName === selectedBranchName}
249244
{@const commitId = commit.id}
250-
{#if !isCommitting}
245+
{#if !controller.isCommitting}
251246
<CommitRow
252247
type="Remote"
253248
{stackId}
@@ -259,7 +254,7 @@
259254
{first}
260255
{lastCommit}
261256
{selected}
262-
{active}
257+
active={controller.active}
263258
reactions={commitReactions[commit.id]}
264259
onclick={() => handleCommitClick(commit.id, true)}
265260
disableCommitActions={false}
@@ -283,7 +278,7 @@
283278
{#snippet template(commit, { first, last })}
284279
{@const commitId = commit.id}
285280
{@const selected = commit.id === selectedCommitId && branchName === selectedBranchName}
286-
{#if isCommitting}
281+
{#if controller.isCommitting}
287282
<!-- Only commits to the base can be `last`, see next `CommitGoesHere`. -->
288283
<CommitGoesHere
289284
{commitId}
@@ -293,7 +288,7 @@
293288
{first}
294289
last={false}
295290
onclick={() => {
296-
projectState.exclusiveAction.set({
291+
controller.projectState.exclusiveAction.set({
297292
type: "commit",
298293
stackId,
299294
branchName,
@@ -311,17 +306,14 @@
311306
{@const { amendHandler, squashHandler, hunkHandler } = createCommitDropHandlers({
312307
projectId,
313308
stackId,
314-
stackService,
315-
hooksService,
316-
uiState,
317309
commit: dzCommit,
318310
runHooks: $runHooks,
319311
okWithForce: true,
320312
onCommitIdChange: (newId) => {
321-
const wasSelected = laneState.selection.current?.commitId === commitId;
313+
const wasSelected = controller.selection.current?.commitId === commitId;
322314
if (stackId && wasSelected) {
323315
const previewOpen = selection.current?.previewOpen ?? false;
324-
uiState.lane(stackId).selection.set({ branchName, commitId: newId, previewOpen });
316+
controller.laneState.selection.set({ branchName, commitId: newId, previewOpen });
325317
}
326318
},
327319
})}
@@ -378,7 +370,7 @@
378370
{lastBranch}
379371
{selected}
380372
{tooltip}
381-
{active}
373+
active={controller.active}
382374
reactions={commitReactions[commit.id]}
383375
onclick={() => handleCommitClick(commit.id, false)}
384376
disableCommitActions={false}
@@ -391,8 +383,8 @@
391383
commitMessage: commit.message,
392384
commitStatus: commit.state.type,
393385
commitUrl: forge.current.commitUrl(commitId),
394-
onUncommitClick: () => handleUncommit(commit.id, branchName),
395-
onEditMessageClick: () => startEditingCommitMessage(branchName, commit.id),
386+
onUncommitClick: () => handleUncommit(commit.id),
387+
onEditMessageClick: () => startEditingCommitMessage(commit.id),
396388
}}
397389
<CommitContextMenu
398390
showOnHover
@@ -417,7 +409,7 @@
417409
title="Changed files"
418410
{projectId}
419411
{stackId}
420-
{visibleRange}
412+
visibleRange={controller.visibleRange}
421413
draggableFiles
422414
selectionId={createCommitSelection({ commitId: commitId, stackId })}
423415
persistId={`commit-${commitId}`}
@@ -432,19 +424,19 @@
432424
allowUnselect={false}
433425
onFileClick={(index) => {
434426
// Ensure the commit is selected so the preview shows it
435-
const currentSelection = laneState.selection.current;
427+
const currentSelection = controller.selection.current;
436428
if (
437429
currentSelection?.commitId !== commitId ||
438430
currentSelection?.branchName !== branchName
439431
) {
440-
laneState.selection.set({
432+
controller.selection.set({
441433
branchName,
442434
commitId,
443435
upstream: false,
444436
previewOpen: true,
445437
});
446438
}
447-
onFileClick?.(index);
439+
controller.jumpToIndex(index);
448440
}}
449441
/>
450442
{/snippet}
@@ -456,7 +448,7 @@
456448
{@render commitReorderDz(
457449
stackingReorderDropzoneManager.belowCommit(branchName, commit.id),
458450
)}
459-
{#if isCommitting && last}
451+
{#if controller.isCommitting && last}
460452
<CommitGoesHere
461453
commitId={branchDetails.baseCommit}
462454
{first}
@@ -465,7 +457,7 @@
465457
exclusiveAction.parentCommitId === branchDetails.baseCommit &&
466458
commitAction?.branchName === branchName}
467459
onclick={() => {
468-
projectState.exclusiveAction.set({
460+
controller.projectState.exclusiveAction.set({
469461
type: "commit",
470462
stackId,
471463
branchName,

apps/desktop/src/components/BranchInsertion.svelte

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import Dropzone from "$components/Dropzone.svelte";
55
import { MoveBranchDzHandler } from "$lib/branches/dropHandler";
66
import type { ForgePrService } from "$lib/forge/interface/forgePrService";
7-
import type { StackService } from "$lib/stacks/stackService.svelte";
87
98
interface Props {
109
projectId: string;
@@ -13,7 +12,6 @@
1312
lineColor: string;
1413
isCommitting: boolean;
1514
baseBranchName: string | undefined;
16-
stackService: StackService;
1715
prService: ForgePrService | undefined;
1816
isFirst?: boolean;
1917
}
@@ -25,15 +23,13 @@
2523
lineColor,
2624
isCommitting,
2725
baseBranchName,
28-
stackService,
2926
prService,
3027
isFirst = false,
3128
}: Props = $props();
3229
</script>
3330

3431
{#if !isCommitting && baseBranchName}
3532
{@const moveBranchHandler = new MoveBranchDzHandler(
36-
stackService,
3733
prService,
3834
projectId,
3935
stackId,

0 commit comments

Comments
 (0)