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
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17511,7 +17511,7 @@
"vscode:prepublish": "yarn run bundle"
},
"dependencies": {
"@gitkraken/gitkraken-components": "10.3.0",
"@gitkraken/gitkraken-components": "10.4.0",
"@gitkraken/provider-apis": "0.22.9",
"@gitkraken/shared-web-components": "0.1.1-rc.15",
"@lit/react": "1.0.5",
Expand All @@ -17531,6 +17531,7 @@
"https-proxy-agent": "5.0.1",
"iconv-lite": "0.6.3",
"lit": "3.1.4",
"marked": "12.0.2",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yarn.lock is not updated

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was on purpose to avoid conflicts. I think that is something we should do generally, because it just causes issues when merging. Though it is needed for the ultimate merge so it adds another merge step.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't it a good thing that it causes conflicts (i.e. wouldn't we want to catch/fix these conflicts ahead of time, rather than on merge?) or am I missing something?

"node-fetch": "2.7.0",
"os-browserify": "0.3.0",
"path-browserify": "1.0.1",
Expand Down
3 changes: 2 additions & 1 deletion src/git/models/commit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,7 @@ export class GitCommit implements GitRevisionReference {
parents?: string[];
files?: { file?: GitFileChange | null; files?: GitFileChange[] | null } | null;
lines?: GitCommitLine[];
stats?: GitCommitStats;
}): GitCommit {
let files;
if (changes.files != null) {
Expand Down Expand Up @@ -593,7 +594,7 @@ export class GitCommit implements GitRevisionReference {
this.getChangedValue(changes.parents, this.parents) ?? [],
this.message,
files,
this.stats,
this.getChangedValue(changes.stats, this.stats),
this.getChangedValue(changes.lines, this.lines),
this.tips,
this.stashName,
Expand Down
168 changes: 166 additions & 2 deletions src/plus/webviews/graph/graphWebview.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ColorTheme, ConfigurationChangeEvent, Uri } from 'vscode';
import type { CancellationToken, ColorTheme, ConfigurationChangeEvent, Uri } from 'vscode';
import { CancellationTokenSource, Disposable, env, window } from 'vscode';
import type { CreatePullRequestActionContext, OpenPullRequestActionContext } from '../../../api/gitlens';
import { getAvatarUri } from '../../../avatars';
Expand Down Expand Up @@ -36,11 +36,14 @@ import * as StashActions from '../../../git/actions/stash';
import * as TagActions from '../../../git/actions/tag';
import * as WorktreeActions from '../../../git/actions/worktree';
import { GitSearchError } from '../../../git/errors';
import { CommitFormatter } from '../../../git/formatters/commitFormatter';
import { getBranchId, getBranchNameWithoutRemote, getRemoteNameFromBranchName } from '../../../git/models/branch';
import type { GitCommit } from '../../../git/models/commit';
import { isStash } from '../../../git/models/commit';
import { uncommitted } from '../../../git/models/constants';
import { GitContributor } from '../../../git/models/contributor';
import type { GitGraph, GitGraphRowType } from '../../../git/models/graph';
import { getGkProviderThemeIconString } from '../../../git/models/graph';
import { getComparisonRefsForPullRequest, serializePullRequest } from '../../../git/models/pullRequest';
import type {
GitBranchReference,
Expand Down Expand Up @@ -77,7 +80,7 @@ import type { Deferrable } from '../../../system/function';
import { debounce, disposableInterval } from '../../../system/function';
import { find, last, map } from '../../../system/iterable';
import { updateRecordValue } from '../../../system/object';
import { getSettledValue } from '../../../system/promise';
import { getSettledValue, pauseOnCancelOrTimeoutMapTuplePromise } from '../../../system/promise';
import { isDarkTheme, isLightTheme } from '../../../system/utils';
import { isWebviewItemContext, isWebviewItemGroupContext, serializeWebviewItemContext } from '../../../system/webview';
import { RepositoryFolderNode } from '../../../views/nodes/abstract/repositoryFolderNode';
Expand All @@ -88,6 +91,7 @@ import { isSerializedState } from '../../../webviews/webviewsController';
import type { SubscriptionChangeEvent } from '../../gk/account/subscriptionService';
import type {
BranchState,
DidGetRowHoverParams,
DidSearchParams,
DoubleClickedParams,
GetMissingAvatarsParams,
Expand Down Expand Up @@ -157,6 +161,7 @@ import {
GetMissingAvatarsCommand,
GetMissingRefsMetadataCommand,
GetMoreRowsCommand,
GetRowHoverRequest,
OpenPullRequestDetailsCommand,
SearchOpenInViewCommand,
SearchRequest,
Expand Down Expand Up @@ -222,6 +227,9 @@ export class GraphWebviewProvider implements WebviewProvider<State, State, Graph
private _etagRepository?: number;
private _firstSelection = true;
private _graph?: GitGraph;
private _hoverCache = new Map<string, Promise<string | undefined>>();
private _hoverCancellation: CancellationTokenSource | undefined;

private readonly _ipcNotificationMap = new Map<IpcNotification<any>, () => Promise<boolean>>([
[DidChangeColumnsNotification, this.notifyDidChangeColumns],
[DidChangeGraphConfigurationNotification, this.notifyDidChangeConfiguration],
Expand Down Expand Up @@ -629,6 +637,9 @@ export class GraphWebviewProvider implements WebviewProvider<State, State, Graph
case GetMoreRowsCommand.is(e):
void this.onGetMoreRows(e.params);
break;
case GetRowHoverRequest.is(e):
void this.onHoverRowRequest(GetRowHoverRequest, e);
break;
case OpenPullRequestDetailsCommand.is(e):
void this.onOpenPullRequestDetails(e.params);
break;
Expand Down Expand Up @@ -896,6 +907,152 @@ export class GraphWebviewProvider implements WebviewProvider<State, State, Graph
return Promise.resolve();
}

private async onHoverRowRequest<T extends typeof GetRowHoverRequest>(requestType: T, msg: IpcCallMessageType<T>) {
const hover: DidGetRowHoverParams = {
id: msg.params.id,
markdown: undefined,
};

if (this._hoverCancellation != null) {
this._hoverCancellation.cancel();
}

if (this._graph != null) {
const id = msg.params.id;

let markdown = this._hoverCache.get(id);
if (markdown == null) {
const cancellation = new CancellationTokenSource();
this._hoverCancellation = cancellation;

let cache = true;
let commit;
switch (msg.params.type) {
case 'work-dir-changes':
cache = false;
commit = await this.container.git.getCommit(this._graph.repoPath, uncommitted);
break;
case 'stash-node': {
const stash = await this.container.git.getStash(this._graph.repoPath);
commit = stash?.commits.get(msg.params.id);
break;
}
default: {
commit = await this.container.git.getCommit(this._graph.repoPath, msg.params.id);
break;
}
}

if (commit != null && !cancellation.token.isCancellationRequested) {
// Check if we have calculated stats for the row and if so apply it to the commit
const stats = this._graph.rowsStats?.get(commit.sha);
if (stats != null) {
commit = commit.with({
stats: {
...commit.stats,
additions: stats.additions,
deletions: stats.deletions,
// If `changedFiles` already exists, then use it, otherwise use the files count
changedFiles: commit.stats?.changedFiles ? commit.stats.changedFiles : stats.files,
},
});
}

markdown = this.getCommitTooltip(commit, cancellation.token).catch(() => {
this._hoverCache.delete(id);
return undefined;
});
if (cache) {
this._hoverCache.set(id, markdown);
}
}
}

if (markdown != null) {
hover.markdown = await markdown;
}
}

void this.host.respond(requestType, msg, hover);
}

private async getCommitTooltip(commit: GitCommit, cancellation: CancellationToken) {
const [remotesResult, _] = await Promise.allSettled([
this.container.git.getBestRemotesWithProviders(commit.repoPath),
commit.ensureFullDetails(),
]);

if (cancellation.isCancellationRequested) throw new CancellationError();

const remotes = getSettledValue(remotesResult, []);
const [remote] = remotes;

let enrichedAutolinks;
let pr;

if (remote?.hasIntegration()) {
const [enrichedAutolinksResult, prResult] = await Promise.allSettled([
pauseOnCancelOrTimeoutMapTuplePromise(commit.getEnrichedAutolinks(remote), cancellation),
commit.getAssociatedPullRequest(remote),
]);

if (cancellation.isCancellationRequested) throw new CancellationError();

const enrichedAutolinksMaybeResult = getSettledValue(enrichedAutolinksResult);
if (!enrichedAutolinksMaybeResult?.paused) {
enrichedAutolinks = enrichedAutolinksMaybeResult?.value;
}
pr = getSettledValue(prResult);
}

let template;
if (isStash(commit)) {
template = configuration.get('views.formats.stashes.tooltip');
} else {
template = configuration.get('views.formats.commits.tooltip');
}

const tooltip = await CommitFormatter.fromTemplateAsync(template, commit, {
enrichedAutolinks: enrichedAutolinks,
dateFormat: configuration.get('defaultDateFormat'),
getBranchAndTagTips: this.getBranchAndTagTips.bind(this),
messageAutolinks: true,
messageIndent: 4,
pullRequest: pr,
outputFormat: 'markdown',
remotes: remotes,
// unpublished: this.unpublished,
});

return tooltip;
}

private getBranchAndTagTips(sha: string, options?: { compact?: boolean; icons?: boolean }): string | undefined {
if (this._graph == null) return undefined;

const row = this._graph.rows.find(r => r.sha === sha);
if (row == null) return undefined;

const tips = [];
if (row.heads?.length) {
tips.push(...row.heads.map(h => (options?.icons ? `$(git-branch) ${h.name}` : h.name)));
}

if (row.remotes?.length) {
tips.push(
...row.remotes.map(h => {
const name = `${h.owner ? `${h.owner}/` : ''}${h.name}`;
return options?.icons ? `$(${getGkProviderThemeIconString(h.hostingServiceType)}) ${name}` : name;
}),
);
}
if (row.tags?.length) {
tips.push(...row.tags.map(h => (options?.icons ? `$(tag) ${h.name}` : h.name)));
}

return tips.join(', ') || undefined;
}

@debug()
private async onEnsureRowRequest<T extends typeof EnsureRowRequest>(requestType: T, msg: IpcCallMessageType<T>) {
if (this._graph == null) return;
Expand Down Expand Up @@ -2147,6 +2304,12 @@ export class GraphWebviewProvider implements WebviewProvider<State, State, Graph
void this.notifyDidChangeRefsVisibility();
}

private resetHoverCache() {
this._hoverCache.clear();
this._hoverCancellation?.dispose();
this._hoverCancellation = undefined;
}

private resetRefsMetadata(): null | undefined {
this._refsMetadata = getContext('gitlens:repos:withHostingIntegrationsConnected') ? undefined : null;
return this._refsMetadata;
Expand Down Expand Up @@ -2176,6 +2339,7 @@ export class GraphWebviewProvider implements WebviewProvider<State, State, Graph
private setGraph(graph: GitGraph | undefined) {
this._graph = graph;
if (graph == null) {
this.resetHoverCache();
this.resetRefsMetadata();
this.resetSearchState();
} else {
Expand Down
10 changes: 10 additions & 0 deletions src/plus/webviews/graph/protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,16 @@ export interface DidEnsureRowParams {
}
export const EnsureRowRequest = new IpcRequest<EnsureRowParams, DidEnsureRowParams>(scope, 'rows/ensure');

export type GetRowHoverParams = {
type: GitGraphRowType;
id: string;
};
export interface DidGetRowHoverParams {
id: string;
markdown?: string;
}
export const GetRowHoverRequest = new IpcRequest<GetRowHoverParams, DidGetRowHoverParams>(scope, 'row/hover/get');

export interface SearchParams {
search?: SearchQuery;
limit?: number;
Expand Down
2 changes: 1 addition & 1 deletion src/webviews/apps/commitDetails/commitDetails.scss
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ hr {
}

.md-code {
background: rgba(255, 255, 255, 0.05);
background: var(--vscode-textCodeBlock-background);
border-radius: 3px;
padding: 0px 4px 2px 4px;
font-family: var(--vscode-editor-font-family);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export class GlStatusNav extends LitElement {
}

.md-code {
background: rgba(255, 255, 255, 0.05);
background: var(--vscode-textCodeBlock-background);
border-radius: 3px;
padding: 0px 4px 2px 4px;
font-family: var(--vscode-editor-font-family);
Expand Down
Loading