瀏覽代碼

Adds settings for Commit Details view

- Avatars, file layout, autolinks, & prs
main
Eric Amodio 2 年之前
父節點
當前提交
eaec695e4f
共有 11 個文件被更改,包括 464 次插入108 次删除
  1. +76
    -10
      package.json
  2. +13
    -0
      src/config.ts
  3. +0
    -1
      src/storage.ts
  4. +1
    -1
      src/webviews/apps/commitDetails/commitDetails.html
  5. +46
    -12
      src/webviews/apps/commitDetails/commitDetails.ts
  6. +152
    -0
      src/webviews/apps/settings/partials/views.commitDetails.html
  7. +10
    -0
      src/webviews/apps/settings/settings.html
  8. +11
    -1
      src/webviews/apps/shared/components/code-icon.ts
  9. +62
    -56
      src/webviews/apps/shared/components/commit/commit-identity.ts
  10. +86
    -23
      src/webviews/commitDetails/commitDetailsWebviewView.ts
  11. +7
    -4
      src/webviews/commitDetails/protocol.ts

+ 76
- 10
package.json 查看文件

@ -946,9 +946,75 @@
}
},
{
"id": "commit-details-view",
"title": "Commit Details View",
"order": 22,
"properties": {
"gitlens.views.commitDetails.autolinks.enabled": {
"type": "boolean",
"default": true,
"markdownDescription": "Specifies whether to automatically link external resources in commit messages",
"scope": "window",
"order": 31
},
"gitlens.views.commitDetails.autolinks.enhanced": {
"type": "boolean",
"default": true,
"markdownDescription": "Specifies whether to lookup additional details about automatically link external resources in commit messages. Requires a connection to a supported remote service (e.g. GitHub)",
"scope": "window",
"order": 32
},
"gitlens.views.commitDetails.pullRequests.enabled": {
"type": "boolean",
"default": true,
"markdownDescription": "Specifies whether to query for associated pull requests. Requires a connection to a supported remote service (e.g. GitHub)",
"scope": "window",
"order": 21
},
"gitlens.views.commitDetails.files.layout": {
"type": "string",
"default": "auto",
"enum": [
"auto",
"list",
"tree"
],
"enumDescriptions": [
"Automatically switches between displaying files as a `tree` or `list` based on the `#gitlens.views.commitDetails.files.threshold#` value and the number of files at each nesting level",
"Displays files as a list",
"Displays files as a tree"
],
"markdownDescription": "Specifies how the _Commit Details_ view will display files",
"scope": "window",
"order": 30
},
"gitlens.views.commitDetails.files.threshold": {
"type": "number",
"default": 5,
"markdownDescription": "Specifies when to switch between displaying files as a `tree` or `list` based on the number of files in a nesting level in the _Commit Details_ view. Only applies when `#gitlens.views.commitDetails.files.layout#` is set to `auto`",
"scope": "window",
"order": 31
},
"gitlens.views.commitDetails.files.compact": {
"type": "boolean",
"default": true,
"markdownDescription": "Specifies whether to compact (flatten) unnecessary file nesting in the _Commit Details_ view. Only applies when `#gitlens.views.commitDetails.files.layout#` is set to `tree` or `auto`",
"scope": "window",
"order": 32
},
"gitlens.views.commitDetails.avatars": {
"type": "boolean",
"default": true,
"markdownDescription": "Specifies whether to show avatar images instead of commit (or status) icons in the _Commit Details_ view",
"scope": "window",
"order": 40
}
}
},
{
"id": "repositories-view",
"title": "Repositories View",
"order": 22,
"order": 23,
"properties": {
"gitlens.views.repositories.showBranchComparison": {
"type": [
@ -1162,7 +1228,7 @@
{
"id": "file-history-view",
"title": "File History View",
"order": 23,
"order": 24,
"properties": {
"gitlens.views.fileHistory.files.layout": {
"type": "string",
@ -1221,7 +1287,7 @@
{
"id": "line-history-view",
"title": "Line History View",
"order": 24,
"order": 25,
"properties": {
"gitlens.views.lineHistory.avatars": {
"type": "boolean",
@ -1239,7 +1305,7 @@
{
"id": "branches-view",
"title": "Branches View",
"order": 25,
"order": 26,
"properties": {
"gitlens.views.branches.showBranchComparison": {
"type": [
@ -1364,7 +1430,7 @@
{
"id": "remotes-view",
"title": "Remotes View",
"order": 26,
"order": 27,
"properties": {
"gitlens.views.remotes.pullRequests.enabled": {
"type": "boolean",
@ -1452,7 +1518,7 @@
{
"id": "stashes-view",
"title": "Stashes View",
"order": 27,
"order": 28,
"properties": {
"gitlens.views.stashes.files.layout": {
"type": "string",
@ -1497,7 +1563,7 @@
{
"id": "tags-view",
"title": "Tags View",
"order": 28,
"order": 29,
"properties": {
"gitlens.views.tags.branches.layout": {
"type": "string",
@ -1583,7 +1649,7 @@
{
"id": "worktrees-view",
"title": "Worktrees View",
"order": 29,
"order": 30,
"properties": {
"gitlens.worktrees.promptForLocation": {
"type": "boolean",
@ -1688,7 +1754,7 @@
{
"id": "contributors-view",
"title": "Contributors View",
"order": 30,
"order": 31,
"properties": {
"gitlens.views.contributors.showAllBranches": {
"type": "boolean",
@ -1791,7 +1857,7 @@
{
"id": "search-compare-view",
"title": "Search & Compare View",
"order": 31,
"order": 32,
"properties": {
"gitlens.views.searchAndCompare.pullRequests.enabled": {
"type": "boolean",

+ 13
- 0
src/config.ts 查看文件

@ -587,6 +587,7 @@ export const viewsCommonConfigKeys: (keyof ViewsCommonConfig)[] = [
interface ViewsConfigs {
branches: BranchesViewConfig;
commits: CommitsViewConfig;
commitDetails: CommitDetailsViewConfig;
contributors: ContributorsViewConfig;
fileHistory: FileHistoryViewConfig;
lineHistory: LineHistoryViewConfig;
@ -643,6 +644,18 @@ export interface CommitsViewConfig {
showBranchComparison: false | ViewShowBranchComparison;
}
export interface CommitDetailsViewConfig {
avatars: boolean;
files: ViewsFilesConfig;
autolinks: {
enabled: boolean;
enhanced: boolean;
};
pullRequests: {
enabled: boolean;
};
}
export interface ContributorsViewConfig {
avatars: boolean;
files: ViewsFilesConfig;

+ 0
- 1
src/storage.ts 查看文件

@ -200,7 +200,6 @@ export interface WorkspaceStorage {
};
commitDetails: {
autolinksExpanded?: boolean;
filesAsTree?: boolean;
dismissed?: string[];
};
};

+ 1
- 1
src/webviews/apps/commitDetails/commitDetails.html 查看文件

@ -188,7 +188,7 @@
<span slot="title">Files changed </span>
<span slot="subtitle" data-region="stats"></span>
<action-nav slot="actions">
<action-item data-switch-value="list-tree" label="View as Tree" icon="list-tree"></action-item>
<action-item data-switch-value="tree" label="View as Tree" icon="list-tree"></action-item>
</action-nav>
<ul class="change-list" data-region="files">

+ 46
- 12
src/webviews/apps/commitDetails/commitDetails.ts 查看文件

@ -1,4 +1,5 @@
/*global*/
import { ViewFilesLayout } from '../../../config';
import type { HierarchicalItem } from '../../../system/array';
import { makeHierarchical } from '../../../system/array';
import type { Serialized } from '../../../system/serialize';
@ -75,7 +76,7 @@ export class CommitDetailsApp extends App> {
DOM.on('[data-action="pick-commit"]', 'click', e => this.onPickCommit(e)),
DOM.on('[data-action="search-commit"]', 'click', e => this.onSearchCommit(e)),
DOM.on('[data-action="autolink-settings"]', 'click', e => this.onAutolinkSettings(e)),
DOM.on('[data-switch-value]', 'click', e => this.onTreeSetting(e)),
DOM.on('[data-switch-value]', 'click', e => this.onToggleFilesLayout(e)),
DOM.on('[data-action="pin"]', 'click', e => this.onTogglePin(e)),
DOM.on<WebviewPane, WebviewPaneExpandedChangeEventDetail>(
'[data-region="rich-pane"]',
@ -140,15 +141,25 @@ export class CommitDetailsApp extends App> {
this.sendCommand(PreferencesCommandType, { dismissed: dismissed });
}
private onTreeSetting(e: MouseEvent) {
const isTree = (e.target as HTMLElement)?.getAttribute('data-switch-value') === 'list-tree';
if (!isTree === this.state.preferences?.filesAsTree) return;
private onToggleFilesLayout(e: MouseEvent) {
const layout = ((e.target as HTMLElement)?.getAttribute('data-switch-value') as ViewFilesLayout) ?? undefined;
if (layout === this.state.preferences?.files?.layout) return;
this.state.preferences = { ...this.state.preferences, filesAsTree: !isTree };
const files = {
...this.state.preferences?.files,
layout: layout ?? ViewFilesLayout.Auto,
compact: this.state.preferences?.files?.compact ?? true,
threshold: this.state.preferences?.files?.threshold ?? 5,
};
this.state.preferences = {
...this.state.preferences,
files: files,
};
this.renderFiles(this.state as CommitState);
this.sendCommand(PreferencesCommandType, { filesAsTree: !isTree });
this.sendCommand(PreferencesCommandType, { files: files });
}
private onExpandedChange(e: WebviewPaneExpandedChangeEventDetail) {
@ -358,12 +369,27 @@ export class CommitDetailsApp extends App> {
const $el = document.querySelector<HTMLElement>('[data-region="files"]');
if ($el == null) return;
const isTree = state.preferences?.filesAsTree === true;
const layout = state.preferences?.files?.layout ?? ViewFilesLayout.Auto;
const $toggle = document.querySelector('[data-switch-value]');
if ($toggle) {
$toggle.setAttribute('data-switch-value', isTree ? 'list-tree' : 'list');
$toggle.setAttribute('icon', isTree ? 'list-flat' : 'list-tree');
$toggle.setAttribute('label', isTree ? 'View as List' : 'View as Tree');
switch (layout) {
case ViewFilesLayout.Auto:
$toggle.setAttribute('data-switch-value', 'list');
$toggle.setAttribute('icon', 'list-flat');
$toggle.setAttribute('label', 'View as List');
break;
case ViewFilesLayout.List:
$toggle.setAttribute('data-switch-value', 'tree');
$toggle.setAttribute('icon', 'list-tree');
$toggle.setAttribute('label', 'View as Tree');
break;
case ViewFilesLayout.Tree:
$toggle.setAttribute('data-switch-value', 'auto');
$toggle.setAttribute('icon', 'gl-list-auto');
$toggle.setAttribute('label', 'View as Auto');
break;
}
}
if (!state.selected.files?.length) {
@ -371,6 +397,13 @@ export class CommitDetailsApp extends App> {
return;
}
let isTree: boolean;
if (layout === ViewFilesLayout.Auto) {
isTree = state.selected.files.length > (state.preferences?.files?.threshold ?? 5);
} else {
isTree = layout === ViewFilesLayout.Tree;
}
const stashAttr = state.selected.isStash
? 'stash '
: state.selected.sha === uncommittedSha
@ -382,7 +415,7 @@ export class CommitDetailsApp extends App> {
state.selected.files,
n => n.path.split('/'),
(...parts: string[]) => parts.join('/'),
true,
this.state.preferences?.files?.compact ?? true,
);
const flatTree = flattenHeirarchy(tree);
@ -461,7 +494,8 @@ export class CommitDetailsApp extends App> {
email="${state.selected.author.email}"
date=${state.selected.author.date}
dateFormat="${state.dateFormat}"
avatar="${state.selected.author.avatar}"
avatarUrl="${state.selected.author.avatar ?? ''}"
showAvatar="${state.preferences?.avatars ?? true}"
actionLabel="${state.selected.sha === uncommittedSha ? 'modified' : 'committed'}"
></commit-identity>
`;

+ 152
- 0
src/webviews/apps/settings/partials/views.commitDetails.html 查看文件

@ -0,0 +1,152 @@
<section id="commit-details-view" class="section--settings section--collapsible">
<div class="section__header">
<h2>
Commit Details view
<a
class="link__learn-more"
title="Learn more"
href="https://github.com/gitkraken/vscode-gitlens/#commit-details-view-"
>
<i class="icon icon__info"></i>
</a>
</h2>
<p class="section__header-hint">
Adds a
<a
class="command command--show-view"
title="Show View in Side Bar"
href="command:gitlens.showCommitDetailsView"
>Commit Details view</a
>
to see rich details for a commit
</p>
</div>
<div class="section__collapsible">
<div class="section__group">
<div class="section__content">
<div class="settings settings--fixed ml-1">
<div class="section__group">
<div class="section__content">
<div class="settings settings--fixed">
<div class="setting">
<div class="setting__input">
<input
id="views.commitDetails.autolinks.enabled"
name="views.commitDetails.autolinks.enabled"
type="checkbox"
data-setting
/>
<label for="views.commitDetails.autolinks.enabled"
>Show autolinks in commit messages</label
>
</div>
</div>
<div class="settings settings--fixed ml-2">
<div class="setting">
<div
class="setting__input"
data-enablement="views.commitDetails.autolinks.enabled"
>
<input
id="views.commitDetails.autolinks.enhanced"
name="views.commitDetails.autolinks.enhanced"
type="checkbox"
data-setting
disabled
/>
<label for="views.commitDetails.autolinks.enhanced"
>Enhance autolink details</label
>
</div>
<p class="setting__hint">
Requires a connection to a supported remote service (e.g. GitHub)
</p>
</div>
</div>
</div>
</div>
</div>
<div class="setting">
<div class="setting__input">
<input
id="views.commitDetails.pullRequests.enabled"
name="views.commitDetails.pullRequests.enabled"
type="checkbox"
data-setting
/>
<label for="views.commitDetails.pullRequests.enabled"
>Show the Pull Request (if any) that introduced the commit</label
>
</div>
<p class="setting__hint">Requires a connection to a supported remote service (e.g. GitHub)</p>
</div>
<div class="setting">
<div class="setting__input">
<label for="views.commitDetails.files.layout">Layout files</label>
<div class="select-container">
<select
id="views.commitDetails.files.layout"
name="views.commitDetails.files.layout"
data-setting
>
<option value="auto">automatically</option>
<option value="list">as a list</option>
<option value="tree">as a tree</option>
</select>
</div>
</div>
<p class="setting__hint" data-visibility="views.commitDetails.files.layout =auto">
Chooses the best layout based on the number of files at each nesting level
</p>
</div>
<div class="setting">
<div class="setting__input">
<input
id="views.commitDetails.files.compact"
name="views.commitDetails.files.compact"
type="checkbox"
data-setting
/>
<label for="views.commitDetails.files.compact">Use compact file layout</label>
</div>
<p class="setting__hint">Compacts (flattens) unnecessary nesting when using a tree layouts</p>
</div>
<div class="setting">
<div class="setting__input">
<input
id="views.commitDetails.avatars"
name="views.commitDetails.avatars"
type="checkbox"
data-setting
/>
<label for="views.commitDetails.avatars">Use author avatars</label>
</div>
</div>
</div>
</div>
<div class="section__preview"></div>
</div>
<div class="section__group">
<p class="section__hint">
<i class="icon icon__info"></i> For more options, open
<a
class="command"
title="Open Settings"
href="command:workbench.action.openSettings?%22gitlens.views.commitDetails%22"
>Settings</a
>
and search for <b><i>gitlens.views.commitDetails</i></b> or
<b><i>gitlens.views</i></b>
</p>
</div>
</div>
</section>

+ 10
- 0
src/webviews/apps/settings/settings.html 查看文件

@ -68,6 +68,7 @@
<%= require('html-loader?{"esModule":false}!./partials/hovers.html') %>
<%= require('html-loader?{"esModule":false}!./partials/views.html') %>
<%= require('html-loader?{"esModule":false}!./partials/views.commits.html') %>
<%= require('html-loader?{"esModule":false}!./partials/views.commitDetails.html') %>
<%= require('html-loader?{"esModule":false}!./partials/views.repositories.html') %>
<%= require('html-loader?{"esModule":false}!./partials/views.file-history.html') %>
<%= require('html-loader?{"esModule":false}!./partials/views.line-history.html') %>
@ -153,6 +154,15 @@
<a
class="sidebar__jump-link"
data-action="jump"
href="#commit-details-view"
title="Jump to Commit Details view settings"
>Commit Details view</a
>
</li>
<li>
<a
class="sidebar__jump-link"
data-action="jump"
href="#repositories-view"
title="Jump to Repositories view settings"
>Repositories view</a

+ 11
- 1
src/webviews/apps/shared/components/code-icon.ts 查看文件

@ -2,7 +2,7 @@ import { attr, css, customElement, FASTElement } from '@microsoft/fast-element';
const styles = css`
:host {
font: normal normal normal 16px/1 codicon;
font: normal normal normal var(--code-icon-size, 16px) / 1 codicon;
display: inline-block;
text-decoration: none;
text-rendering: auto;
@ -1501,6 +1501,10 @@ const styles = css`
font-family: 'glicons';
content: '\\f102';
}
:host([icon='gl-list-auto']):before {
font-family: 'glicons';
content: '\\f11a';
}
@keyframes codicon-spin {
100% {
@ -1529,4 +1533,10 @@ export class CodeIcon extends FASTElement {
@attr
modifier = '';
@attr
size = 16;
sizeChanged() {
this.style.setProperty('--code-icon-size', `${this.size}px`);
}
}

+ 62
- 56
src/webviews/apps/shared/components/commit/commit-identity.ts 查看文件

@ -1,72 +1,78 @@
import { css, html, LitElement } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import { attr, css, customElement, FASTElement, html, when } from '@microsoft/fast-element';
import '../code-icon';
import '../formatted-date';
@customElement('commit-identity')
export class CommitIdentity extends LitElement {
static override styles = css`
:host {
display: grid;
gap: 0rem 1rem;
justify-content: start;
}
a {
color: var(--color-link-foreground);
text-decoration: none;
}
.avatar {
grid-column: 1;
grid-row: 1 / 3;
width: 36px;
}
.thumb {
width: 100%;
height: auto;
border-radius: 0.4rem;
}
.name {
grid-column: 2;
grid-row: 1;
font-size: 1.5rem;
}
.date {
grid-column: 2;
grid-row: 2;
font-size: 1.3rem;
}
`;
const template = html<CommitIdentity>`
<template>
<a class="avatar" href="${x => (x.email ? `mailto:${x.email}` : '#')}">
${when(
x => x.showAvatar,
html<CommitIdentity>`<img class="thumb" lazy src="${x => x.avatarUrl}" alt="${x => x.name}" />`,
)}
${when(x => !x.showAvatar, html<CommitIdentity>`<code-icon icon="person" size="32"></code-icon>`)}
</a>
<a class="name" href="${x => (x.email ? `mailto:${x.email}` : '#')}">${x => x.name}</a>
<span class="date"
>${x => x.actionLabel} <formatted-date date=${x => x.date} format="${x => x.dateFormat}"></formatted-date
></span>
</template>
`;
@property()
const styles = css`
:host {
display: grid;
gap: 0rem 1rem;
justify-content: start;
}
a {
color: var(--color-link-foreground);
text-decoration: none;
}
.avatar {
grid-column: 1;
grid-row: 1 / 3;
width: 36px;
}
.thumb {
width: 100%;
height: auto;
border-radius: 0.4rem;
}
.name {
grid-column: 2;
grid-row: 1;
font-size: 1.5rem;
}
.date {
grid-column: 2;
grid-row: 2;
font-size: 1.3rem;
}
`;
@customElement({ name: 'commit-identity', template: template, styles: styles })
export class CommitIdentity extends FASTElement {
@attr({ mode: 'reflect' })
name = '';
@property()
@attr({ mode: 'reflect' })
email = '';
@property()
@attr({ mode: 'reflect' })
date = '';
@property()
avatar = 'https://www.gravatar.com/avatar/?s=64&d=robohash';
@attr({ mode: 'reflect' })
avatarUrl = 'https://www.gravatar.com/avatar/?s=64&d=robohash';
@attr({ mode: 'boolean' })
showAvatar = false;
@property()
@attr({ mode: 'reflect' })
dateFormat = 'MMMM Do, YYYY h:mma';
@property({ type: Boolean, reflect: true })
@attr({ mode: 'boolean' })
committer = false;
@property()
@attr({ mode: 'reflect' })
actionLabel = 'committed';
override render() {
const largerUrl = this.avatar.replace('s=32', 's=64');
return html`
<a class="avatar" href="${this.email ? `mailto:${this.email}` : '#'}"
><img class="thumb" lazy src="${largerUrl}" alt="${this.name}"
/></a>
<a class="name" href="${this.email ? `mailto:${this.email}` : '#'}">${this.name}</a>
<span class="date"
>${this.actionLabel} <formatted-date date=${this.date} format="${this.dateFormat}"></formatted-date
></span>
`;
}
}

+ 86
- 23
src/webviews/commitDetails/commitDetailsWebviewView.ts 查看文件

@ -43,7 +43,7 @@ import type { ViewNode } from '../../views/nodes/viewNode';
import type { IpcMessage } from '../protocol';
import { onIpc } from '../protocol';
import { WebviewViewBase } from '../webviewViewBase';
import type { CommitDetails, FileActionParams, SavedPreferences, State } from './protocol';
import type { CommitDetails, FileActionParams, Preferences, State } from './protocol';
import {
AutolinkSettingsCommandType,
CommitActionsCommandType,
@ -63,7 +63,7 @@ import {
interface Context {
pinned: boolean;
commit: GitCommit | undefined;
preferences: SavedPreferences | undefined;
preferences: Preferences | undefined;
richStateLoaded: boolean;
formattedMessage: string | undefined;
autolinkedIssues: IssueOrPullRequest[] | undefined;
@ -151,8 +151,9 @@ export class CommitDetailsWebviewView extends WebviewViewBase
this.updatePendingContext({
preferences: {
autolinksExpanded: this.container.storage.getWorkspace('views:commitDetails:autolinksExpanded'),
filesAsTree: this.container.storage.getWorkspace('views:commitDetails:filesAsTree'),
avatars: configuration.get('views.commitDetails.avatars'),
dismissed: this.container.storage.getWorkspace('views:commitDetails:dismissed'),
files: configuration.get('views.commitDetails.files'),
},
});
}
@ -196,11 +197,37 @@ export class CommitDetailsWebviewView extends WebviewViewBase
}
}
private onConfigurationChanged(e?: ConfigurationChangeEvent) {
private onConfigurationChanged(e: ConfigurationChangeEvent) {
if (configuration.changed(e, 'defaultDateFormat')) {
this.updatePendingContext({ dateFormat: configuration.get('defaultDateFormat') ?? 'MMMM Do, YYYY h:mma' });
this.updateState();
}
if (configuration.changed(e, 'views.commitDetails')) {
if (
configuration.changed(e, 'views.commitDetails.files') ||
configuration.changed(e, 'views.commitDetails.avatars')
) {
this.updatePendingContext({
preferences: {
...this._context.preferences,
...this._pendingContext?.preferences,
avatars: configuration.get('views.commitDetails.avatars'),
files: configuration.get('views.commitDetails.files'),
},
});
}
if (
this._context.commit != null &&
(configuration.changed(e, 'views.commitDetails.autolinks') ||
configuration.changed(e, 'views.commitDetails.pullRequests'))
) {
this.updateCommit(this._context.commit, { force: true });
}
this.updateState();
}
}
private ensureTrackers(): void {
@ -392,8 +419,13 @@ export class CommitDetailsWebviewView extends WebviewViewBase
if (remote?.provider != null) {
const [autolinkedIssuesOrPullRequestsResult, prResult] = await Promise.allSettled([
this.container.autolinks.getLinkedIssuesAndPullRequests(commit.message ?? commit.summary, remote),
commit.getAssociatedPullRequest({ remote: remote }),
configuration.get('views.commitDetails.autolinks.enabled') &&
configuration.get('views.commitDetails.autolinks.enhanced')
? this.container.autolinks.getLinkedIssuesAndPullRequests(commit.message ?? commit.summary, remote)
: undefined,
configuration.get('views.commitDetails.pullRequests.enabled')
? commit.getAssociatedPullRequest({ remote: remote })
: undefined,
]);
if (cancellation.isCancellationRequested) return;
@ -431,9 +463,12 @@ export class CommitDetailsWebviewView extends WebviewViewBase
private _commitDisposable: Disposable | undefined;
private updateCommit(commit: GitCommit | undefined, options?: { pinned?: boolean; immediate?: boolean }) {
private updateCommit(
commit: GitCommit | undefined,
options?: { force?: boolean; pinned?: boolean; immediate?: boolean },
) {
// this.commits = [commit];
if (this._context.commit?.sha === commit?.sha) return;
if (!options?.force && this._context.commit?.sha === commit?.sha) return;
this._commitDisposable?.dispose();
@ -449,13 +484,16 @@ export class CommitDetailsWebviewView extends WebviewViewBase
);
}
this.updatePendingContext({
commit: commit,
richStateLoaded: Boolean(commit?.isUncommitted) || !getContext(ContextKeys.HasConnectedRemotes),
formattedMessage: undefined,
autolinkedIssues: undefined,
pullRequest: undefined,
});
this.updatePendingContext(
{
commit: commit,
richStateLoaded: Boolean(commit?.isUncommitted) || !getContext(ContextKeys.HasConnectedRemotes),
formattedMessage: undefined,
autolinkedIssues: undefined,
pullRequest: undefined,
},
options?.force,
);
if (options?.pinned != null) {
this.updatePinned(options?.pinned);
@ -474,34 +512,56 @@ export class CommitDetailsWebviewView extends WebviewViewBase
this.updateState(immediate);
}
private updatePreferences(preferences: SavedPreferences) {
private updatePreferences(preferences: Preferences) {
if (
this._context.preferences?.autolinksExpanded === preferences.autolinksExpanded &&
this._context.preferences?.filesAsTree === preferences.filesAsTree &&
this._context.preferences?.dismissed === preferences.dismissed
this._context.preferences?.avatars === preferences.avatars &&
this._context.preferences?.dismissed === preferences.dismissed &&
this._context.preferences?.files === preferences.files &&
this._context.preferences?.files?.compact === preferences.files?.compact &&
this._context.preferences?.files?.layout === preferences.files?.layout &&
this._context.preferences?.files?.threshold === preferences.files?.threshold
) {
return;
}
const changes: SavedPreferences = {};
const changes: Preferences = {};
if (this._context.preferences?.autolinksExpanded !== preferences.autolinksExpanded) {
void this.container.storage.storeWorkspace(
'views:commitDetails:autolinksExpanded',
preferences.autolinksExpanded,
);
changes.autolinksExpanded = preferences.autolinksExpanded;
}
if (this._context.preferences?.filesAsTree !== preferences.filesAsTree) {
void this.container.storage.storeWorkspace('views:commitDetails:filesAsTree', preferences.filesAsTree);
changes.filesAsTree = preferences.filesAsTree;
if (this._context.preferences?.avatars !== preferences.avatars) {
void configuration.updateEffective('views.commitDetails.avatars', preferences.avatars);
changes.avatars = preferences.avatars;
}
if (this._context.preferences?.dismissed !== preferences.dismissed) {
void this.container.storage.storeWorkspace('views:commitDetails:dismissed', preferences.dismissed);
changes.dismissed = preferences.dismissed;
}
if (this._context.preferences?.files !== preferences.files) {
if (this._context.preferences?.files?.compact !== preferences.files?.compact) {
void configuration.updateEffective('views.commitDetails.files.compact', preferences.files?.compact);
}
if (this._context.preferences?.files?.layout !== preferences.files?.layout) {
void configuration.updateEffective('views.commitDetails.files.layout', preferences.files?.layout);
}
if (this._context.preferences?.files?.threshold !== preferences.files?.threshold) {
void configuration.updateEffective('views.commitDetails.files.threshold', preferences.files?.threshold);
}
changes.files = preferences.files;
}
this.updatePendingContext({ preferences: changes });
}
@ -627,7 +687,7 @@ export class CommitDetailsWebviewView extends WebviewViewBase
private async getDetailsModel(commit: GitCommit, formattedMessage?: string): Promise<CommitDetails> {
const [commitResult, avatarUriResult, remoteResult] = await Promise.allSettled([
!commit.hasFullDetails() ? commit.ensureFullDetails().then(() => commit) : commit,
commit.author.getAvatarUri(commit),
commit.author.getAvatarUri(commit, { size: 32 }),
this.container.git.getBestRemoteWithRichProvider(commit.repoPath, { includeDisconnected: true }),
]);
@ -677,6 +737,9 @@ export class CommitDetailsWebviewView extends WebviewViewBase
if (index !== -1) {
message = `${message.substring(0, index)}${messageHeadlineSplitterToken}${message.substring(index + 1)}`;
}
if (!configuration.get('views.commitDetails.autolinks.enabled')) return message;
return this.container.autolinks.linkify(
message,
'html',

+ 7
- 4
src/webviews/commitDetails/protocol.ts 查看文件

@ -1,4 +1,5 @@
import type { TextDocumentShowOptions } from 'vscode';
import type { Config } from '../../config';
import type { GitCommitIdentityShape, GitCommitStats } from '../../git/models/commit';
import type { GitFileChangeShape } from '../../git/models/file';
import type { IssueOrPullRequest } from '../../git/models/issue';
@ -25,15 +26,16 @@ export type CommitDetails = CommitSummary & {
stats?: GitCommitStats;
};
export type SavedPreferences = {
export type Preferences = {
autolinksExpanded?: boolean;
filesAsTree?: boolean;
avatars?: boolean;
dismissed?: string[];
files?: Config['views']['commitDetails']['files'];
};
export type State = {
pinned: boolean;
preferences?: SavedPreferences;
preferences?: Preferences;
// commits?: CommitSummary[];
includeRichContent?: boolean;
@ -79,8 +81,9 @@ export const PinCommitCommandType = new IpcCommandType('commit/pin');
export interface PreferenceParams {
autolinksExpanded?: boolean;
filesAsTree?: boolean;
avatars?: boolean;
dismissed?: string[];
files?: Config['views']['commitDetails']['files'];
}
export const PreferencesCommandType = new IpcCommandType<PreferenceParams>('commit/preferences');

Loading…
取消
儲存