diff --git a/package.json b/package.json
index ab4b940..0e2e379 100644
--- a/package.json
+++ b/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",
diff --git a/src/config.ts b/src/config.ts
index b9647a8..842a87c 100644
--- a/src/config.ts
+++ b/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;
diff --git a/src/storage.ts b/src/storage.ts
index 25e520f..85af6d0 100644
--- a/src/storage.ts
+++ b/src/storage.ts
@@ -200,7 +200,6 @@ export interface WorkspaceStorage {
};
commitDetails: {
autolinksExpanded?: boolean;
- filesAsTree?: boolean;
dismissed?: string[];
};
};
diff --git a/src/webviews/apps/commitDetails/commitDetails.html b/src/webviews/apps/commitDetails/commitDetails.html
index 037a98f..c4eaa18 100644
--- a/src/webviews/apps/commitDetails/commitDetails.html
+++ b/src/webviews/apps/commitDetails/commitDetails.html
@@ -188,7 +188,7 @@
Files changed
-
+
diff --git a/src/webviews/apps/commitDetails/commitDetails.ts b/src/webviews/apps/commitDetails/commitDetails.ts
index e4da524..9bf5603 100644
--- a/src/webviews/apps/commitDetails/commitDetails.ts
+++ b/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(
'[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('[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'}"
>
`;
diff --git a/src/webviews/apps/settings/partials/views.commitDetails.html b/src/webviews/apps/settings/partials/views.commitDetails.html
new file mode 100644
index 0000000..05f6598
--- /dev/null
+++ b/src/webviews/apps/settings/partials/views.commitDetails.html
@@ -0,0 +1,152 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Requires a connection to a supported remote service (e.g. GitHub)
+
+
+
+
+
+
+
+
+
+
+
+
+
Requires a connection to a supported remote service (e.g. GitHub)
+
+
+
+
+
+ Chooses the best layout based on the number of files at each nesting level
+
+
+
+
+
+
+
+
+
Compacts (flattens) unnecessary nesting when using a tree layouts
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ For more options, open
+ Settings
+ and search for gitlens.views.commitDetails or
+ gitlens.views
+
+
+
+
diff --git a/src/webviews/apps/settings/settings.html b/src/webviews/apps/settings/settings.html
index 50b4a22..10af95c 100644
--- a/src/webviews/apps/settings/settings.html
+++ b/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 @@
+
+ -
+ `
+
+
+ ${when(
+ x => x.showAvatar,
+ html``,
+ )}
+ ${when(x => !x.showAvatar, html``)}
+
+ ${x => x.name}
+ ${x => x.actionLabel} x.date} format="${x => x.dateFormat}">
+
+`;
- @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`
-
- ${this.name}
- ${this.actionLabel}
- `;
- }
}
diff --git a/src/webviews/commitDetails/commitDetailsWebviewView.ts b/src/webviews/commitDetails/commitDetailsWebviewView.ts
index bc3d61b..93baeeb 100644
--- a/src/webviews/commitDetails/commitDetailsWebviewView.ts
+++ b/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 {
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('commit/pin');
export interface PreferenceParams {
autolinksExpanded?: boolean;
- filesAsTree?: boolean;
+ avatars?: boolean;
dismissed?: string[];
+ files?: Config['views']['commitDetails']['files'];
}
export const PreferencesCommandType = new IpcCommandType('commit/preferences');