|
19 | 19 | import { stagingBehaviorFeature } from '$lib/config/uiFeatureFlags'; |
20 | 20 | import { isParsedError } from '$lib/error/parser'; |
21 | 21 | import { DIFF_SERVICE } from '$lib/hunks/diffService.svelte'; |
| 22 | + import { RULES_SERVICE } from '$lib/rules/rulesService.svelte'; |
22 | 23 | import { FILE_SELECTION_MANAGER } from '$lib/selection/fileSelectionManager.svelte'; |
23 | 24 | import { |
24 | 25 | createBranchSelection, |
|
29 | 30 | } from '$lib/selection/key'; |
30 | 31 | import { UNCOMMITTED_SERVICE } from '$lib/selection/uncommittedService.svelte'; |
31 | 32 | import { STACK_SERVICE } from '$lib/stacks/stackService.svelte'; |
32 | | - import { mapResult } from '$lib/state/helpers'; |
| 33 | + import { combineResults } from '$lib/state/helpers'; |
33 | 34 | import { UI_STATE } from '$lib/state/uiState.svelte'; |
34 | 35 |
|
35 | 36 | import { createBranchRef } from '$lib/utils/branch'; |
|
319 | 320 |
|
320 | 321 | // Codegen related services and state |
321 | 322 | const claudeCodeService = inject(CLAUDE_CODE_SERVICE); |
| 323 | + const rulesService = inject(RULES_SERVICE); |
322 | 324 | const attachmentService = inject(ATTACHMENT_SERVICE); |
323 | 325 |
|
324 | 326 | let mcpConfigModal = $state<CodegenMcpConfigModal>(); |
|
327 | 329 | const isStackActiveQuery = $derived(claudeCodeService.isStackActive(projectId, stackId)); |
328 | 330 | const isStackActive = $derived(isStackActiveQuery?.response || false); |
329 | 331 | const events = $derived(claudeCodeService.messages({ projectId, stackId })); |
| 332 | + const hasRulesToClear = $derived(rulesService.hasRulesToClear(projectId, stackId)); |
330 | 333 | const permissionRequests = $derived(claudeCodeService.permissionRequests({ projectId })); |
331 | 334 | const attachments = $derived(attachmentService.getByBranch(branchName)); |
332 | 335 |
|
|
423 | 426 |
|
424 | 427 | {#snippet commitChangedFiles(commitId: string)} |
425 | 428 | {@const changesQuery = stackService.commitChanges(stableProjectId, commitId)} |
426 | | - <ReduxResult |
427 | | - projectId={stableProjectId} |
428 | | - stackId={stableStackId} |
429 | | - result={mapResult(changesQuery.result, (changes) => ({ changes, commitId }))} |
430 | | - > |
431 | | - {#snippet children({ changes, commitId }, { projectId, stackId })} |
| 429 | + <ReduxResult projectId={stableProjectId} stackId={stableStackId} result={changesQuery.result}> |
| 430 | + {#snippet children(changesResult, { projectId, stackId })} |
432 | 431 | {@const commitsQuery = branchName |
433 | 432 | ? stackService.commits(projectId, stackId, branchName) |
434 | 433 | : undefined} |
|
444 | 443 | noshrink={!!previewKey} |
445 | 444 | grow={!previewKey} |
446 | 445 | persistId={`commit-${commitId}`} |
447 | | - changes={changes.changes.filter( |
448 | | - (change) => !(change.path in (changes.conflictEntries?.entries ?? {})) |
| 446 | + changes={changesResult.changes.filter( |
| 447 | + (change) => !(change.path in (changesResult.conflictEntries?.entries ?? {})) |
449 | 448 | )} |
450 | | - stats={changes.stats} |
451 | | - conflictEntries={changes.conflictEntries} |
| 449 | + stats={changesResult.stats} |
| 450 | + conflictEntries={changesResult.conflictEntries} |
452 | 451 | {ancestorMostConflictedCommitId} |
453 | 452 | resizer={previewKey |
454 | 453 | ? { |
|
473 | 472 | branch: createBranchRef(branchName, undefined) |
474 | 473 | })} |
475 | 474 | <ReduxResult projectId={stableProjectId} stackId={stableStackId} result={changesQuery.result}> |
476 | | - {#snippet children(changes, { projectId, stackId })} |
| 475 | + {#snippet children(changesResult, { projectId, stackId })} |
477 | 476 | <ChangedFiles |
478 | 477 | title="Combined Changes" |
479 | 478 | {projectId} |
|
484 | 483 | noshrink={!!previewKey} |
485 | 484 | grow={!previewKey} |
486 | 485 | persistId={`branch-${branchName}`} |
487 | | - changes={changes.changes} |
488 | | - stats={changes.stats} |
| 486 | + changes={changesResult.changes} |
| 487 | + stats={changesResult.stats} |
489 | 488 | resizer={previewKey |
490 | 489 | ? { |
491 | 490 | persistId: `changed-files-${stackId}`, |
|
532 | 531 | } |
533 | 532 | }} |
534 | 533 | > |
535 | | - <ConfigurableScrollableContainer childrenWrapHeight="100%"> |
536 | | - <div |
537 | | - class="stack-view" |
538 | | - class:details-open={isDetailsViewOpen} |
539 | | - style:width="{$persistedStackWidth}rem" |
540 | | - use:focusable={{ vertical: true, onActive: (value) => (active = value) }} |
541 | | - bind:this={stackViewEl} |
542 | | - > |
543 | | - <ReduxResult projectId={stableProjectId} result={branchesQuery.result}> |
544 | | - {#snippet children(branches)} |
| 534 | + <ReduxResult |
| 535 | + projectId={stableProjectId} |
| 536 | + result={combineResults(branchesQuery.result, hasRulesToClear.result)} |
| 537 | + > |
| 538 | + {#snippet children([branches, hasRulesToClear])} |
| 539 | + <ConfigurableScrollableContainer childrenWrapHeight="100%"> |
| 540 | + <div |
| 541 | + class="stack-view" |
| 542 | + class:details-open={isDetailsViewOpen} |
| 543 | + style:width="{$persistedStackWidth}rem" |
| 544 | + use:focusable={{ vertical: true, onActive: (value) => (active = value) }} |
| 545 | + bind:this={stackViewEl} |
| 546 | + > |
545 | 547 | <div class="stack-v" data-fade-on-reorder> |
546 | 548 | <!-- If we are currently committing, we should keep this open so users can actually stop committing again :wink: --> |
547 | 549 | <StackDragHandle stackId={stableStackId} {projectId} disabled={isCommitting} /> |
|
639 | 641 | }} |
640 | 642 | /> |
641 | 643 | {/if} |
642 | | - {/snippet} |
643 | | - </ReduxResult> |
644 | | - </div> |
645 | | - </ConfigurableScrollableContainer> |
646 | | - |
647 | | - <!-- PREVIEW --> |
648 | | - {#if isDetailsViewOpen} |
649 | | - {@const selection = laneState.selection.current} |
650 | | - <div |
651 | | - in:fly={{ y: 20, duration: 200 }} |
652 | | - class="details-view deep-shadow" |
653 | | - bind:this={compactDiv} |
654 | | - data-details={stableStackId} |
655 | | - style:right="{DETAILS_RIGHT_PADDING_REM}rem" |
656 | | - use:focusable={{ vertical: true }} |
657 | | - data-testid={TestId.StackPreview} |
658 | | - > |
659 | | - {#if stableStackId && selection?.branchName && selection?.codegen} |
660 | | - <CodegenMessages |
661 | | - projectId={stableProjectId} |
662 | | - stackId={stableStackId} |
663 | | - {laneId} |
664 | | - branchName={selection.branchName} |
665 | | - onclose={onclosePreview} |
666 | | - onMcpSettings={() => { |
667 | | - mcpConfigModal?.open(); |
668 | | - }} |
669 | | - {onAbort} |
670 | | - {initialPrompt} |
671 | | - events={events.response || []} |
672 | | - permissionRequests={permissionRequests.response || []} |
673 | | - onSubmit={sendMessage} |
674 | | - onChange={(prompt) => messageSender?.setPrompt(prompt)} |
675 | | - {isStackActive} |
676 | | - /> |
677 | | - {:else} |
678 | | - <div class="details-view__inner"> |
679 | | - <!-- TOP SECTION: Branch/Commit Details (no resizer) --> |
680 | | - {#if branchName && commitId} |
681 | | - {@render commitView(branchName, commitId)} |
682 | | - {:else if branchName} |
683 | | - {@render branchView(branchName)} |
684 | | - {/if} |
| 644 | + </div> |
| 645 | + </ConfigurableScrollableContainer> |
| 646 | + |
| 647 | + <!-- PREVIEW --> |
| 648 | + {#if isDetailsViewOpen} |
| 649 | + {@const selection = laneState.selection.current} |
| 650 | + <div |
| 651 | + in:fly={{ y: 20, duration: 200 }} |
| 652 | + class="details-view deep-shadow" |
| 653 | + bind:this={compactDiv} |
| 654 | + data-details={stableStackId} |
| 655 | + style:right="{DETAILS_RIGHT_PADDING_REM}rem" |
| 656 | + use:focusable={{ vertical: true }} |
| 657 | + data-testid={TestId.StackPreview} |
| 658 | + > |
| 659 | + {#if stableStackId && selection?.branchName && selection?.codegen} |
| 660 | + <CodegenMessages |
| 661 | + projectId={stableProjectId} |
| 662 | + stackId={stableStackId} |
| 663 | + {laneId} |
| 664 | + branchName={selection.branchName} |
| 665 | + onclose={onclosePreview} |
| 666 | + onMcpSettings={() => { |
| 667 | + mcpConfigModal?.open(); |
| 668 | + }} |
| 669 | + {onAbort} |
| 670 | + {initialPrompt} |
| 671 | + events={events.response || []} |
| 672 | + permissionRequests={permissionRequests.response || []} |
| 673 | + onSubmit={sendMessage} |
| 674 | + onChange={(prompt) => messageSender?.setPrompt(prompt)} |
| 675 | + {isStackActive} |
| 676 | + {hasRulesToClear} |
| 677 | + /> |
| 678 | + {:else} |
| 679 | + <div class="details-view__inner"> |
| 680 | + <!-- TOP SECTION: Branch/Commit Details (no resizer) --> |
| 681 | + {#if branchName && commitId} |
| 682 | + {@render commitView(branchName, commitId)} |
| 683 | + {:else if branchName} |
| 684 | + {@render branchView(branchName)} |
| 685 | + {/if} |
685 | 686 |
|
686 | | - <!-- MIDDLE SECTION: Changed Files (with resizer) --> |
687 | | - <div class="changed-files-section" class:expand={!(assignedStackId || selectedFile)}> |
688 | | - {#if branchName && commitId} |
689 | | - {@render commitChangedFiles(commitId)} |
690 | | - {:else if branchName} |
691 | | - {@render branchChangedFiles(branchName)} |
692 | | - {/if} |
693 | | - </div> |
| 687 | + <!-- MIDDLE SECTION: Changed Files (with resizer) --> |
| 688 | + <div class="changed-files-section" class:expand={!(assignedStackId || selectedFile)}> |
| 689 | + {#if branchName && commitId} |
| 690 | + {@render commitChangedFiles(commitId)} |
| 691 | + {:else if branchName} |
| 692 | + {@render branchChangedFiles(branchName)} |
| 693 | + {/if} |
| 694 | + </div> |
694 | 695 |
|
695 | | - <!-- BOTTOM SECTION: File Preview (no resizer) --> |
696 | | - {#if assignedStackId || selectedFile} |
697 | | - <ReduxResult projectId={stableProjectId} result={previewChangeQuery?.result}> |
698 | | - {#snippet children(previewChange)} |
699 | | - {@const diffQuery = diffService.getDiff(stableProjectId, previewChange)} |
700 | | - {@const diffData = diffQuery.response} |
701 | | - |
702 | | - <div class="file-preview-section"> |
703 | | - {#if assignedStackId} |
704 | | - <ConfigurableScrollableContainer |
705 | | - zIndex="var(--z-lifted)" |
706 | | - bind:viewport={selectionPreviewScrollContainer} |
707 | | - > |
708 | | - {@render assignedChangePreview(assignedStackId)} |
709 | | - </ConfigurableScrollableContainer> |
710 | | - {:else if selectedFile} |
711 | | - <Drawer persistId="file-preview-drawer-{stableStackId}"> |
712 | | - {#snippet header()} |
713 | | - <FileViewHeader |
714 | | - noPaddings |
715 | | - transparent |
716 | | - filePath={previewChange.path} |
717 | | - fileStatus={computeChangeStatus(previewChange)} |
718 | | - linesAdded={diffData?.type === 'Patch' |
719 | | - ? diffData.subject.linesAdded |
720 | | - : undefined} |
721 | | - linesRemoved={diffData?.type === 'Patch' |
722 | | - ? diffData.subject.linesRemoved |
723 | | - : undefined} |
724 | | - /> |
725 | | - {/snippet} |
726 | | - {@render otherChangePreview(selectedFile)} |
727 | | - </Drawer> |
728 | | - {/if} |
729 | | - </div> |
730 | | - {/snippet} |
731 | | - </ReduxResult> |
| 696 | + <!-- BOTTOM SECTION: File Preview (no resizer) --> |
| 697 | + {#if assignedStackId || selectedFile} |
| 698 | + <ReduxResult projectId={stableProjectId} result={previewChangeQuery?.result}> |
| 699 | + {#snippet children(previewChange)} |
| 700 | + {@const diffQuery = diffService.getDiff(stableProjectId, previewChange)} |
| 701 | + {@const diffData = diffQuery.response} |
| 702 | + |
| 703 | + <div class="file-preview-section"> |
| 704 | + {#if assignedStackId} |
| 705 | + <ConfigurableScrollableContainer |
| 706 | + zIndex="var(--z-lifted)" |
| 707 | + bind:viewport={selectionPreviewScrollContainer} |
| 708 | + > |
| 709 | + {@render assignedChangePreview(assignedStackId)} |
| 710 | + </ConfigurableScrollableContainer> |
| 711 | + {:else if selectedFile} |
| 712 | + <Drawer persistId="file-preview-drawer-{stableStackId}"> |
| 713 | + {#snippet header()} |
| 714 | + <FileViewHeader |
| 715 | + noPaddings |
| 716 | + transparent |
| 717 | + filePath={previewChange.path} |
| 718 | + fileStatus={computeChangeStatus(previewChange)} |
| 719 | + linesAdded={diffData?.type === 'Patch' |
| 720 | + ? diffData.subject.linesAdded |
| 721 | + : undefined} |
| 722 | + linesRemoved={diffData?.type === 'Patch' |
| 723 | + ? diffData.subject.linesRemoved |
| 724 | + : undefined} |
| 725 | + /> |
| 726 | + {/snippet} |
| 727 | + {@render otherChangePreview(selectedFile)} |
| 728 | + </Drawer> |
| 729 | + {/if} |
| 730 | + </div> |
| 731 | + {/snippet} |
| 732 | + </ReduxResult> |
| 733 | + {/if} |
| 734 | + </div> |
732 | 735 | {/if} |
733 | 736 | </div> |
| 737 | + |
| 738 | + <!-- DETAILS VIEW WIDTH RESIZER - Only show when details view is open --> |
| 739 | + {#if compactDiv} |
| 740 | + <Resizer |
| 741 | + viewport={compactDiv} |
| 742 | + persistId="resizer-panel2-${stableStackId}" |
| 743 | + direction="right" |
| 744 | + showBorder |
| 745 | + minWidth={RESIZER_CONFIG.panel2.minWidth} |
| 746 | + maxWidth={RESIZER_CONFIG.panel2.maxWidth} |
| 747 | + defaultValue={RESIZER_CONFIG.panel2.defaultValue} |
| 748 | + syncName="panel2" |
| 749 | + onWidth={updateDetailsViewWidth} |
| 750 | + /> |
| 751 | + {/if} |
734 | 752 | {/if} |
735 | | - </div> |
736 | | - |
737 | | - <!-- DETAILS VIEW WIDTH RESIZER - Only show when details view is open --> |
738 | | - {#if compactDiv} |
739 | | - <Resizer |
740 | | - viewport={compactDiv} |
741 | | - persistId="resizer-panel2-${stableStackId}" |
742 | | - direction="right" |
743 | | - showBorder |
744 | | - minWidth={RESIZER_CONFIG.panel2.minWidth} |
745 | | - maxWidth={RESIZER_CONFIG.panel2.maxWidth} |
746 | | - defaultValue={RESIZER_CONFIG.panel2.defaultValue} |
747 | | - syncName="panel2" |
748 | | - onWidth={updateDetailsViewWidth} |
749 | | - /> |
750 | | - {/if} |
751 | | - {/if} |
| 753 | + {/snippet} |
| 754 | + </ReduxResult> |
752 | 755 | </div> |
753 | 756 |
|
754 | 757 | <ReduxResult result={mcpConfigQuery.result} {projectId} {stackId} hideError> |
|
0 commit comments