Skip to content

Commit

Permalink
Use new APIs and refactor navigation
Browse files Browse the repository at this point in the history
- stack/branch/commit selection now uses the URL
  • Loading branch information
mtsgrd committed Feb 24, 2025
1 parent baeb8ed commit ebda07f
Show file tree
Hide file tree
Showing 35 changed files with 786 additions and 559 deletions.
2 changes: 1 addition & 1 deletion apps/desktop/src/components/ChromeHeader.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
disabled={newProjectLoading || cloneProjectLoading}
onselect={(value: string) => {
selectedProjectId = value;
goto(routes.changeProjectPath(selectedProjectId));
goto(routes.projectPath(selectedProjectId));
}}
popupAlign="center"
customWidth={300}
Expand Down
8 changes: 3 additions & 5 deletions apps/desktop/src/components/ReduxResult.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script lang="ts" generics="A">
import Icon from '@gitbutler/ui/Icon.svelte';
import type { QueryStatus } from '@reduxjs/toolkit/query';
import { QueryStatus } from '@reduxjs/toolkit/query';
import type { Snippet } from 'svelte';
type Result<A> = {
Expand All @@ -16,16 +16,14 @@
};
// eslint-disable-next-line no-undef
const { result, children, empty }: Props<A> = $props();
const { result, children }: Props<A> = $props();
const { data, status, error } = $derived(result);
</script>

{#if status === 'fulfilled'}
<!-- Show empty message if data is an empty array. -->
{#if data !== undefined && (!Array.isArray(data) || data.length > 0)}
{#if data !== undefined}
{@render children(data)}
{:else}
{@render empty?.()}
{/if}
{:else if status === 'pending'}
<div class="loading-spinner">
Expand Down
59 changes: 35 additions & 24 deletions apps/desktop/src/components/v3/Branch.svelte
Original file line number Diff line number Diff line change
@@ -1,46 +1,57 @@
<script lang="ts">
import BranchDividerLine from './BranchDividerLine.svelte';
import ReduxResult from '$components/ReduxResult.svelte';
import BranchCommitList from '$components/v3/BranchCommitList.svelte';
import BranchHeader from '$components/v3/BranchHeader.svelte';
import EmptyBranch from '$components/v3/EmptyBranch.svelte';
import { isStackedBranch } from '$components/v3/lib';
import type { WorkspaceBranch } from '$lib/branches/v3';
import { StackService } from '$lib/stacks/stackService.svelte';
import { combineQueries } from '$lib/state/helpers';
import { inject } from '@gitbutler/shared/context';
interface Props {
branch: WorkspaceBranch;
projectId: string;
stackId: string;
branchName: string;
first: boolean;
last: boolean;
selected: boolean;
selectedCommitId?: string;
}
let { branch, first, last, selectedCommitId = $bindable() }: Props = $props();
let {
projectId,
stackId,
branchName,
first,
last,
selected,
selectedCommitId = $bindable()
}: Props = $props();
const localAndRemoteCommits = $derived(
isStackedBranch(branch.state) ? branch.state.subject.localAndRemote : []
);
const upstreamOnlyCommits = $derived(
isStackedBranch(branch.state) ? branch.state.subject.upstreamOnly : []
);
const [stackService] = inject(StackService);
const branchQuery = stackService.branchByName(projectId, stackId, branchName).current;
const commitQuery = $derived(stackService.commits(projectId, stackId, branchName).current);
</script>

{#if !first}
<BranchDividerLine topPatchStatus={localAndRemoteCommits[0]?.state.type ?? 'Error'} />
{/if}
<div class="branch" data-series-name={branch.name}>
<BranchHeader {branch} isTopBranch={first} />
{#if !localAndRemoteCommits.length && !upstreamOnlyCommits.length}
<EmptyBranch {last} />
{/if}
{#if isStackedBranch(branch.state)}
<BranchCommitList commits={branch.state.subject} lastBranch={last} bind:selectedCommitId />
{/if}
</div>
<ReduxResult result={combineQueries(branchQuery, commitQuery)}>
{#snippet children([branch, commits])}
{#if !first}
<BranchDividerLine topPatchStatus={commits.at(0)?.state.type ?? 'Error'} />
{/if}
<div class="branch" class:selected data-series-name={branchName}>
<BranchHeader {projectId} {stackId} {branch} isTopBranch={first} />
<BranchCommitList {projectId} {stackId} {branchName} lastBranch={last} {selectedCommitId} />
</div>
{/snippet}
</ReduxResult>

<style>
.branch {
position: relative;
border: 1px solid var(--clr-border-2);
border-radius: var(--radius-m);
background: var(--clr-bg-1);
background: var(--clr-bg-2);
&.selected {
background: var(--clr-bg-1);
}
}
</style>
108 changes: 42 additions & 66 deletions apps/desktop/src/components/v3/BranchCommitList.svelte
Original file line number Diff line number Diff line change
@@ -1,32 +1,56 @@
<script lang="ts">
import EmptyBranch from './EmptyBranch.svelte';
import ReduxResult from '$components/ReduxResult.svelte';
import CommitRow from '$components/v3/CommitRow.svelte';
import type { Commits } from '$lib/branches/v3';
import { StackService } from '$lib/stacks/stackService.svelte';
import { combineQueries } from '$lib/state/helpers';
import { inject } from '@gitbutler/shared/context';
interface Props {
commits: Commits;
projectId: string;
stackId: string;
branchName: string;
lastBranch?: boolean;
selectedCommitId?: string;
}
let { commits, lastBranch, selectedCommitId = $bindable() }: Props = $props();
let { projectId, stackId, branchName, lastBranch, selectedCommitId }: Props = $props();
const localAndRemoteCommits = $derived(commits.localAndRemote);
const upstreamOnlyCommits = $derived(commits.upstreamOnly);
</script>
const [stackService] = inject(StackService);
<div class="commit-list">
{#each upstreamOnlyCommits as commit, i (commit.id)}
{@const first = i === 0}
{@const last = i === upstreamOnlyCommits.length - 1}
<CommitRow {first} {last} {commit} bind:selectedCommitId />
{/each}
const localAndRemoteCommits = $derived(
stackService.commits(projectId, stackId, branchName).current
);
const upstreamOnlyCommits = $derived(
stackService.upstreamCommits(projectId, stackId, branchName).current
);
</script>

{#each localAndRemoteCommits as commit, i (commit.id)}
{@const first = i === 0}
{@const last = i === localAndRemoteCommits.length - 1}
<CommitRow {first} {last} {commit} {lastBranch} bind:selectedCommitId />
{/each}
</div>
<ReduxResult result={combineQueries(upstreamOnlyCommits, localAndRemoteCommits)}>
{#snippet children([upstreamOnlyCommits, localAndRemoteCommits])}
{#if !upstreamOnlyCommits.length && !localAndRemoteCommits.length}
<EmptyBranch {lastBranch} />
{:else}
<div class="commit-list">
{#each upstreamOnlyCommits as commit, i (commit.id)}
{@const first = i === 0}
{@const last = i === upstreamOnlyCommits.length - 1}
{@const commitKey = { stackId, branchName, commitId: commit.id, upstream: true }}
{@const selected = selectedCommitId === commit.id}
<CommitRow {projectId} {commitKey} {first} {last} {commit} {selected} />
{/each}

{#each localAndRemoteCommits as commit, i (commit.id)}
{@const first = i === 0}
{@const last = i === localAndRemoteCommits.length - 1}
{@const commitKey = { stackId, branchName, commitId: commit.id, upstream: false }}
{@const selected = selectedCommitId === commit.id}
<CommitRow {projectId} {commitKey} {first} {last} {commit} {lastBranch} {selected} />
{/each}
</div>
{/if}
{/snippet}
</ReduxResult>

<style lang="postcss">
.commit-list {
Expand All @@ -35,52 +59,4 @@
flex-direction: column;
border-radius: 0 0 var(--radius-m) var(--radius-m);
}
.commit {
position: relative;
display: flex;
gap: 12px;
width: 100%;
padding: 16px;
background-color: var(--clr-bg-1);
transition: background-color var(--transition-fast);
&:focus {
outline: none;
}
&:hover {
& :global(.commit-actions-menu) {
--show: true;
}
}
&:not(.is-commit-open) {
&:hover {
background-color: var(--clr-bg-1-muted);
& .commit__drag-icon {
opacity: 1;
}
}
}
&.not-draggable {
&:hover {
& .commit__drag-icon {
pointer-events: none;
opacity: 0;
}
}
}
&:not(.no-border) {
border-bottom: 1px solid var(--clr-border-2);
}
&.last {
border-radius: 0 0 var(--radius-m) var(--radius-m);
border-bottom: 0;
}
}
</style>
111 changes: 56 additions & 55 deletions apps/desktop/src/components/v3/BranchHeader.svelte
Original file line number Diff line number Diff line change
@@ -1,32 +1,27 @@
<script lang="ts">
import BranchLabel from '$components/BranchLabel.svelte';
import ReduxResult from '$components/ReduxResult.svelte';
import SeriesDescription from '$components/SeriesDescription.svelte';
import SeriesHeaderStatusIcon from '$components/SeriesHeaderStatusIcon.svelte';
import { getColorFromBranchType, isStackedBranch } from '$components/v3/lib';
import type { CommitStateType, WorkspaceBranch } from '$lib/branches/v3';
import { getColorFromBranchType } from '$components/v3/lib';
import { branchPath } from '$lib/routes/routes.svelte';
import { StackService } from '$lib/stacks/stackService.svelte';
import { inject } from '@gitbutler/shared/context';
import type { CommitStateType, StackBranch } from '$lib/branches/v3';
interface Props {
branch: WorkspaceBranch;
projectId: string;
stackId: string;
branch: StackBranch;
isTopBranch: boolean;
}
const { branch, isTopBranch }: Props = $props();
const { projectId, stackId, branch, isTopBranch }: Props = $props();
const topPatch = $derived(
isStackedBranch(branch.state) && branch?.state.subject.localAndRemote.length > 0
? branch?.state.subject.localAndRemote[0]
: undefined
);
const [stackService] = inject(StackService);
let branchType = $derived(topPatch?.state.type ?? 'LocalOnly') as CommitStateType;
const lineColor = $derived(getColorFromBranchType(branchType));
const commitsQuery = $derived(stackService.commits(projectId, stackId, branch.name).current);
const descriptionVisible = $derived(!!branch.description);
const remoteName = $derived(
branch.remoteTrackingBranch
? branch.remoteTrackingBranch.replace('refs/remotes/', '').replace(`/${branch.name}`, '')
: ''
);
let seriesDescriptionEl = $state<HTMLTextAreaElement>();
function editTitle(title: string) {
Expand All @@ -42,46 +37,52 @@
}
</script>

<div class="branch-header">
<div class="branch-info">
<SeriesHeaderStatusIcon
lineTop={isTopBranch ? false : true}
icon={branchType === 'Integrated' ? 'tick-small' : 'branch-small'}
iconColor="var(--clr-core-ntrl-100)"
color={lineColor}
/>
<div class="branch-info__content">
<div class="text-14 text-bold branch-info__name">
{#if branch.remoteTrackingBranch}
<span class="remote-name">
{remoteName ? `${remoteName} /` : 'origin /'}
</span>
{/if}
<BranchLabel
name={branch.name}
onChange={(name) => editTitle(name)}
readonly={!!branch.remoteTrackingBranch}
onDblClick={() => {
if (branchType !== 'Integrated') {
// stackingContextMenu?.showSeriesRenameModal?.(branch.name);
}
}}
<a href={branchPath(projectId, stackId, branch.name)} class="branch-header">
<ReduxResult result={commitsQuery}>
{#snippet children(commits)}
{@const branchType: CommitStateType = commits.at(0)?.state.type ?? 'LocalOnly'}
{@const lineColor = getColorFromBranchType(branchType)}
<div class="branch-info">
<SeriesHeaderStatusIcon
lineTop={isTopBranch ? false : true}
icon={branchType === 'Integrated' ? 'tick-small' : 'branch-small'}
iconColor="var(--clr-core-ntrl-100)"
color={lineColor}
/>
</div>
{#if descriptionVisible}
<div class="branch-info__description">
<div class="branch-info__line" style:--bg-color={lineColor}></div>
<SeriesDescription
bind:textAreaEl={seriesDescriptionEl}
value={branch.description || ''}
onBlur={(value) => editDescription(value)}
onEmpty={() => toggleDescription()}
/>
<div class="branch-info__content">
<div class="text-14 text-bold branch-info__name">
{#if branch.remoteTrackingBranch}
<span class="remote-name">
{branch.remoteTrackingBranch}
</span>
{/if}
<BranchLabel
name={branch.name}
onChange={(name) => editTitle(name)}
readonly={!!branch.remoteTrackingBranch}
onDblClick={() => {
if (branchType !== 'Integrated') {
// stackingContextMenu?.showSeriesRenameModal?.(branch.name);
}
}}
/>
</div>
{#if branch.description}
<div class="branch-info__description">
<div class="branch-info__line" style:--bg-color={lineColor}></div>
<SeriesDescription
bind:textAreaEl={seriesDescriptionEl}
value={branch.description || ''}
onBlur={(value) => editDescription(value)}
onEmpty={() => toggleDescription()}
/>
</div>
{/if}
</div>
{/if}
</div>
</div>
</div>
</div>
{/snippet}
</ReduxResult>
</a>

<style lang="postcss">
.branch-header {
Expand Down
Loading

0 comments on commit ebda07f

Please sign in to comment.