Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,14 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
- Adds a `gitlens.ai.modelOptions.temperature` setting to specify the temperature (randomness) for AI models
- Adds a _Switch Model_ button to the AI confirmation prompts

### Changed

- Improves performance of updates to active and recent branches on the _Home_ view

### Fixed

- Fixes [#3938](https://github.com/gitkraken/vscode-gitlens/issues/3938) - GitLens automatically initiating an external sign-in after install on vscode.dev
- Fixes [#3946](https://github.com/gitkraken/vscode-gitlens/issues/3946) - Home View doesn't update repo state changes made when hidden

## [16.2.1] - 2025-01-21

Expand Down
4 changes: 2 additions & 2 deletions src/webviews/apps/home/components/onboarding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export class GlOnboarding extends LitElement {
private _openWalkthroughButton!: GlButton;

override render(): unknown {
if (!this._state.showWalkthroughProgress) {
if (this._state.walkthroughProgress == null) {
return undefined;
}

Expand Down Expand Up @@ -71,7 +71,7 @@ export class GlOnboarding extends LitElement {
}

private onDismissWalkthrough() {
this._state.showWalkthroughProgress = false;
this._state.walkthroughProgress = undefined;
this.requestUpdate();
this._ipc.sendCommand(DismissWalkthroughSection);
}
Expand Down
17 changes: 13 additions & 4 deletions src/webviews/apps/home/home.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ import { customElement, query } from 'lit/decorators.js';
import { when } from 'lit/directives/when.js';
import type { State } from '../../home/protocol';
import { DidFocusAccount } from '../../home/protocol';
import { OverviewState, overviewStateContext } from '../plus/home/components/overviewState';
import {
ActiveOverviewState,
activeOverviewStateContext,
InactiveOverviewState,
inactiveOverviewStateContext,
} from '../plus/home/components/overviewState';
import type { GLHomeHeader } from '../plus/shared/components/home-header';
import { GlApp } from '../shared/app';
import { scrollableBase } from '../shared/components/styles/lit/base.css';
Expand All @@ -27,16 +32,20 @@ import './components/repo-alerts';
export class GlHomeApp extends GlApp<State> {
static override styles = [homeBaseStyles, scrollableBase, homeStyles];

@provide({ context: overviewStateContext })
private _overviewState!: OverviewState;
@provide({ context: activeOverviewStateContext })
private _activeOverviewState!: ActiveOverviewState;

@provide({ context: inactiveOverviewStateContext })
private _inactiveOverviewState!: InactiveOverviewState;

@query('gl-home-header')
private _header!: GLHomeHeader;

private badgeSource = { source: 'home', detail: 'badge' };

protected override createStateProvider(state: State, ipc: HostIpc): HomeStateProvider {
this.disposables.push((this._overviewState = new OverviewState(ipc)));
this.disposables.push((this._activeOverviewState = new ActiveOverviewState(ipc)));
this.disposables.push((this._inactiveOverviewState = new InactiveOverviewState(ipc)));

return new HomeStateProvider(this, state, ipc);
}
Expand Down
32 changes: 15 additions & 17 deletions src/webviews/apps/plus/home/components/active-work.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ import { ifDefined } from 'lit/directives/if-defined.js';
import { when } from 'lit/directives/when.js';
import { createCommandLink } from '../../../../../system/commands';
import { createWebviewCommandLink } from '../../../../../system/webview';
import type { GetOverviewBranch, OpenInGraphParams, State } from '../../../../home/protocol';
import type { GetActiveOverviewResponse, GetOverviewBranch, OpenInGraphParams, State } from '../../../../home/protocol';
import { stateContext } from '../../../home/context';
import { linkStyles } from '../../shared/components/vscode.css';
import { branchCardStyles, GlBranchCardBase } from './branch-card';
import type { Overview, OverviewState } from './overviewState';
import { overviewStateContext } from './overviewState';
import type { ActiveOverviewState } from './overviewState';
import { activeOverviewStateContext } from './overviewState';
import '../../../shared/components/button';
import '../../../shared/components/code-icon';
import '../../../shared/components/skeleton-loader';
Expand Down Expand Up @@ -62,14 +62,14 @@ export class GlActiveWork extends SignalWatcher(LitElement) {
@state()
private _homeState!: State;

@consume({ context: overviewStateContext })
private _overviewState!: OverviewState;
@consume({ context: activeOverviewStateContext })
private _activeOverviewState!: ActiveOverviewState;

override connectedCallback(): void {
super.connectedCallback();

if (this._homeState.repositories.openCount > 0) {
this._overviewState.run();
this._activeOverviewState.run();
}
}

Expand All @@ -82,7 +82,7 @@ export class GlActiveWork extends SignalWatcher(LitElement) {
return nothing;
}

return this._overviewState.render({
return this._activeOverviewState.render({
pending: () => this.renderPending(),
complete: overview => this.renderComplete(overview),
error: () => html`<span>Error</span>`,
Expand All @@ -99,16 +99,16 @@ export class GlActiveWork extends SignalWatcher(LitElement) {
}

private renderPending() {
if (this._overviewState.state == null) {
if (this._activeOverviewState.state == null) {
return this.renderLoader();
}
return this.renderComplete(this._overviewState.state, true);
return this.renderComplete(this._activeOverviewState.state, true);
}

private renderComplete(overview: Overview, isFetching = false) {
private renderComplete(overview: GetActiveOverviewResponse, isFetching = false) {
const repo = overview?.repository;
const activeBranches = repo?.branches?.active;
if (!activeBranches) return html`<span>None</span>`;
const activeBranch = overview?.active;
if (!repo || !activeBranch) return html`<span>None</span>`;

return html`
<gl-section ?loading=${isFetching}>
Expand Down Expand Up @@ -138,7 +138,7 @@ export class GlActiveWork extends SignalWatcher(LitElement) {
tooltip="Open in Commit Graph"
href=${createCommandLink('gitlens.home.openInGraph', {
type: 'repo',
repoPath: this._overviewState.state!.repository.path,
repoPath: this._activeOverviewState.state!.repository.path,
} satisfies OpenInGraphParams)}
><code-icon icon="gl-graph"></code-icon
></gl-button>
Expand All @@ -152,9 +152,7 @@ export class GlActiveWork extends SignalWatcher(LitElement) {
><code-icon icon="repo-fetch"></code-icon
></gl-button>
</span>
${activeBranches.map(branch => {
return this.renderRepoBranchCard(branch, repo.path, isFetching);
})}
${this.renderRepoBranchCard(activeBranch, repo.path, isFetching)}
</gl-section>
`;
}
Expand Down Expand Up @@ -191,7 +189,7 @@ export class GlActiveWork extends SignalWatcher(LitElement) {
}

private onChange(_e: MouseEvent) {
void this._overviewState.changeRepository();
this._activeOverviewState.changeRepository();
}
}

Expand Down
36 changes: 17 additions & 19 deletions src/webviews/apps/plus/home/components/overview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,17 @@ import { SignalWatcher } from '@lit-labs/signals';
import { css, html, LitElement, nothing } from 'lit';
import { customElement, state } from 'lit/decorators.js';
import { when } from 'lit/directives/when.js';
import type { GetOverviewResponse, OverviewRecentThreshold, State } from '../../../../home/protocol';
import type { GetInactiveOverviewResponse, OverviewRecentThreshold, State } from '../../../../home/protocol';
import { SetOverviewFilter } from '../../../../home/protocol';
import { stateContext } from '../../../home/context';
import { ipcContext } from '../../../shared/context';
import type { HostIpc } from '../../../shared/ipc';
import { linkStyles } from '../../shared/components/vscode.css';
import type { OverviewState } from './overviewState';
import { overviewStateContext } from './overviewState';
import type { InactiveOverviewState } from './overviewState';
import { inactiveOverviewStateContext } from './overviewState';
import '../../../shared/components/skeleton-loader';
import './branch-threshold-filter';

type Overview = GetOverviewResponse;

export const overviewTagName = 'gl-overview';

@customElement(overviewTagName)
Expand All @@ -35,14 +33,14 @@ export class GlOverview extends SignalWatcher(LitElement) {
@state()
private _homeState!: State;

@consume({ context: overviewStateContext })
private _overviewState!: OverviewState;
@consume({ context: inactiveOverviewStateContext })
private _inactiveOverviewState!: InactiveOverviewState;

override connectedCallback(): void {
super.connectedCallback();

if (this._homeState.repositories.openCount > 0) {
this._overviewState.run();
this._inactiveOverviewState.run();
}
}

Expand All @@ -55,7 +53,7 @@ export class GlOverview extends SignalWatcher(LitElement) {
return nothing;
}

return this._overviewState.render({
return this._inactiveOverviewState.render({
pending: () => this.renderPending(),
complete: summary => this.renderComplete(summary),
error: () => html`<span>Error</span>`,
Expand All @@ -72,34 +70,34 @@ export class GlOverview extends SignalWatcher(LitElement) {
}

private renderPending() {
if (this._overviewState.state == null) {
if (this._inactiveOverviewState.state == null) {
return this.renderLoader();
}
return this.renderComplete(this._overviewState.state, true);
return this.renderComplete(this._inactiveOverviewState.state, true);
}

@consume({ context: ipcContext })
private readonly _ipc!: HostIpc;

private onChangeRecentThresholdFilter(e: CustomEvent<{ threshold: OverviewRecentThreshold }>) {
if (!this._overviewState.filter.stale || !this._overviewState.filter.recent) {
if (!this._inactiveOverviewState.filter.stale || !this._inactiveOverviewState.filter.recent) {
return;
}
this._ipc.sendCommand(SetOverviewFilter, {
stale: this._overviewState.filter.stale,
recent: { ...this._overviewState.filter.recent, threshold: e.detail.threshold },
stale: this._inactiveOverviewState.filter.stale,
recent: { ...this._inactiveOverviewState.filter.recent, threshold: e.detail.threshold },
});
}

private renderComplete(overview: Overview, isFetching = false) {
private renderComplete(overview: GetInactiveOverviewResponse, isFetching = false) {
if (overview == null) return nothing;
const { repository } = overview;
return html`
<gl-branch-section
label="recent"
.isFetching=${isFetching}
.repo=${repository.path}
.branches=${repository.branches.recent}
.branches=${overview.recent}
>
<gl-branch-threshold-filter
slot="heading-actions"
Expand All @@ -113,16 +111,16 @@ export class GlOverview extends SignalWatcher(LitElement) {
label: string;
}[]}
.disabled=${isFetching}
.value=${this._overviewState.filter.recent?.threshold}
.value=${this._inactiveOverviewState.filter.recent?.threshold}
></gl-branch-threshold-filter>
</gl-branch-section>
${when(
this._overviewState.filter.stale?.show === true,
this._inactiveOverviewState.filter.stale?.show === true && overview.stale,
() => html`
<gl-branch-section
label="stale"
.repo=${repository.path}
.branches=${repository.branches.stale}
.branches=${overview.stale!}
></gl-branch-section>
`,
)}
Expand Down
72 changes: 56 additions & 16 deletions src/webviews/apps/plus/home/components/overviewState.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,39 @@
import { createContext } from '@lit/context';
import { signalObject } from 'signal-utils/object';
import type { GetOverviewResponse, OverviewFilters } from '../../../../home/protocol';
import type {
GetActiveOverviewResponse,
GetInactiveOverviewResponse,
OverviewFilters,
} from '../../../../home/protocol';
import {
ChangeOverviewRepository,
ChangeOverviewRepositoryCommand,
DidChangeOverviewFilter,
DidChangeOverviewRepository,
DidChangeRepositories,
DidChangeRepositoryWip,
GetOverview,
GetActiveOverview,
GetInactiveOverview,
GetOverviewFilterState,
} from '../../../../home/protocol';
import { AsyncComputedState } from '../../../shared/components/signal-utils';
import type { Disposable } from '../../../shared/events';
import type { HostIpc } from '../../../shared/ipc';

export type Overview = GetOverviewResponse;
export type ActiveOverview = GetActiveOverviewResponse;
export type InactiveOverview = GetInactiveOverviewResponse;

export class OverviewState extends AsyncComputedState<Overview> {
export class ActiveOverviewState extends AsyncComputedState<ActiveOverview> {
private readonly _disposable: Disposable | undefined;

constructor(
private readonly _ipc: HostIpc,
options?: {
runImmediately?: boolean;
initial?: Overview;
initial?: ActiveOverview;
},
) {
super(async _abortSignal => {
const rsp: Overview = await this._ipc.sendRequest(GetOverview, {});

const rsp: ActiveOverview = await this._ipc.sendRequest(GetActiveOverview, undefined);
return rsp;
}, options);

Expand All @@ -39,11 +45,51 @@ export class OverviewState extends AsyncComputedState<Overview> {
case DidChangeRepositoryWip.is(msg):
this.run(true);
break;
case DidChangeOverviewRepository.is(msg):
this.run(true);
break;
}
});
}

dispose() {
this._disposable?.dispose();
}

changeRepository(): void {
this._ipc.sendCommand(ChangeOverviewRepositoryCommand, undefined);
}
}

export class InactiveOverviewState extends AsyncComputedState<InactiveOverview> {
private readonly _disposable: Disposable | undefined;
filter = signalObject<Partial<OverviewFilters>>({});

constructor(
private readonly _ipc: HostIpc,
options?: {
runImmediately?: boolean;
initial?: InactiveOverview;
},
) {
super(async _abortSignal => {
const rsp: InactiveOverview = await this._ipc.sendRequest(GetInactiveOverview, undefined);
return rsp;
}, options);

this._disposable = this._ipc.onReceiveMessage(msg => {
switch (true) {
case DidChangeRepositories.is(msg):
this.run(true);
break;
case DidChangeOverviewFilter.is(msg):
this.filter.recent = msg.params.filter.recent;
this.filter.stale = msg.params.filter.stale;
this.run(true);
break;
case DidChangeOverviewRepository.is(msg):
this.run(true);
break;
}
});
void this._ipc.sendRequest(GetOverviewFilterState, undefined).then(rsp => {
Expand All @@ -55,13 +101,7 @@ export class OverviewState extends AsyncComputedState<Overview> {
dispose(): void {
this._disposable?.dispose();
}

filter = signalObject<Partial<OverviewFilters>>({});

async changeRepository(): Promise<void> {
await this._ipc.sendRequest(ChangeOverviewRepository, undefined);
this.run(true);
}
}

export const overviewStateContext = createContext<Overview>('overviewState');
export const activeOverviewStateContext = createContext<ActiveOverview>('activeOverviewState');
export const inactiveOverviewStateContext = createContext<InactiveOverview>('inactiveOverviewState');
Loading