Переглянути джерело

Graph: add setting to show status of local branch relative to its upstream (#2441)

* Send local branch upstream status as metadata

* Add setting and use to toggle feature

* Use mini icons

* Use branch fns for upstream name components

* Stop asking for upstream if no upstream found, ask if missing

* Stop asking again on missing upstream

* Move missing type loop into getRefMetadata, get branch once for id

* Uses rem for fontsize
main
Ramin Tadayon 1 рік тому
committed by GitHub
джерело
коміт
a14c9a15b9
Не вдалося знайти GPG ключ що відповідає даному підпису Ідентифікатор GPG ключа: 4AEE18F83AFDEB23
7 змінених файлів з 131 додано та 37 видалено
  1. +7
    -0
      package.json
  2. +1
    -0
      src/config.ts
  3. +77
    -37
      src/plus/webviews/graph/graphWebview.ts
  4. +3
    -0
      src/plus/webviews/graph/protocol.ts
  5. +10
    -0
      src/webviews/apps/plus/graph/GraphWrapper.tsx
  6. +19
    -0
      src/webviews/apps/plus/graph/graph.scss
  7. +14
    -0
      src/webviews/apps/settings/partials/commit-graph.html

+ 7
- 0
package.json Переглянути файл

@ -2243,6 +2243,13 @@
"scope": "window",
"order": 25
},
"gitlens.graph.showUpstreamStatus": {
"type": "boolean",
"default": false,
"markdownDescription": "Specifies whether to show a local branch's upstream status in the _Commit Graph_",
"scope": "window",
"order": 26
},
"gitlens.graph.commitOrdering": {
"type": "string",
"default": "date",

+ 1
- 0
src/config.ts Переглянути файл

@ -393,6 +393,7 @@ export interface GraphConfig {
showDetailsView: 'open' | 'selection' | false;
showGhostRefsOnRowHover: boolean;
showRemoteNames: boolean;
showUpstreamStatus: boolean;
pageItemLimit: number;
searchItemLimit: number;
statusBar: {

+ 77
- 37
src/plus/webviews/graph/graphWebview.ts Переглянути файл

@ -98,6 +98,7 @@ import type {
GraphRefMetadata,
GraphRepository,
GraphSelectedRows,
GraphUpstreamMetadata,
GraphWorkingTreeStats,
SearchOpenInViewParams,
SearchParams,
@ -545,7 +546,8 @@ export class GraphWebview extends WebviewBase {
configuration.changed(e, 'graph.highlightRowsOnRefHover') ||
configuration.changed(e, 'graph.scrollRowPadding') ||
configuration.changed(e, 'graph.showGhostRefsOnRowHover') ||
configuration.changed(e, 'graph.showRemoteNames')
configuration.changed(e, 'graph.showRemoteNames') ||
configuration.changed(e, 'graph.showUpstreamStatus')
) {
void this.notifyDidChangeConfiguration();
}
@ -718,58 +720,95 @@ export class GraphWebview extends WebviewBase {
const repoPath = this._graph.repoPath;
async function getRefMetadata(this: GraphWebview, id: string, type: GraphMissingRefsMetadataType) {
async function getRefMetadata(this: GraphWebview, id: string, missingTypes: GraphMissingRefsMetadataType[]) {
if (this._refsMetadata == null) {
this._refsMetadata = new Map();
}
const branch = (await this.container.git.getBranches(repoPath, { filter: b => b.id === id }))?.values?.[0];
const metadata = { ...this._refsMetadata.get(id) };
if (type !== 'pullRequests') {
(metadata as any)[type] = null;
this._refsMetadata.set(id, metadata);
return;
}
const branch = (await this.container.git.getBranches(repoPath, { filter: b => b.id === id && b.remote }))
?.values?.[0];
const pr = await branch?.getAssociatedPullRequest();
if (pr == null) {
if (metadata.pullRequests === undefined || metadata.pullRequests?.length === 0) {
metadata.pullRequests = null;
if (branch == null) {
for (const type of missingTypes) {
(metadata as any)[type] = null;
this._refsMetadata.set(id, metadata);
}
this._refsMetadata.set(id, metadata);
return;
}
const prMetadata: GraphPullRequestMetadata = {
// TODO@eamodio: This is iffy, but works right now since `github` and `gitlab` are the only values possible currently
hostingServiceType: pr.provider.id as GraphHostingServiceType,
id: Number.parseInt(pr.id) || 0,
title: pr.title,
author: pr.author.name,
date: (pr.mergedDate ?? pr.closedDate ?? pr.date)?.getTime(),
state: pr.state,
url: pr.url,
context: serializeWebviewItemContext<GraphItemContext>({
webviewItem: 'gitlens:pullrequest',
webviewItemValue: {
type: 'pullrequest',
id: pr.id,
for (const type of missingTypes) {
if (type !== 'pullRequests' && type !== 'upstream') {
(metadata as any)[type] = null;
this._refsMetadata.set(id, metadata);
continue;
}
if (type === 'pullRequests') {
const pr = await branch?.getAssociatedPullRequest();
if (pr == null) {
if (metadata.pullRequests === undefined || metadata.pullRequests?.length === 0) {
metadata.pullRequests = null;
}
this._refsMetadata.set(id, metadata);
continue;
}
const prMetadata: GraphPullRequestMetadata = {
// TODO@eamodio: This is iffy, but works right now since `github` and `gitlab` are the only values possible currently
hostingServiceType: pr.provider.id as GraphHostingServiceType,
id: Number.parseInt(pr.id) || 0,
title: pr.title,
author: pr.author.name,
date: (pr.mergedDate ?? pr.closedDate ?? pr.date)?.getTime(),
state: pr.state,
url: pr.url,
},
}),
};
context: serializeWebviewItemContext<GraphItemContext>({
webviewItem: 'gitlens:pullrequest',
webviewItemValue: {
type: 'pullrequest',
id: pr.id,
url: pr.url,
},
}),
};
metadata.pullRequests = [prMetadata];
this._refsMetadata.set(id, metadata);
continue;
}
if (type === 'upstream') {
const upstream = branch?.upstream;
if (upstream == null || upstream == undefined || upstream.missing) {
metadata.upstream = null;
this._refsMetadata.set(id, metadata);
continue;
}
metadata.pullRequests = [prMetadata];
this._refsMetadata.set(id, metadata);
const upstreamMetadata: GraphUpstreamMetadata = {
name: getBranchNameWithoutRemote(upstream.name),
owner: getRemoteNameFromBranchName(upstream.name),
ahead: branch.state.ahead,
behind: branch.state.behind,
};
metadata.upstream = upstreamMetadata;
this._refsMetadata.set(id, metadata);
}
}
}
const promises: Promise<void>[] = [];
for (const [id, missingTypes] of Object.entries(e.metadata)) {
for (const missingType of missingTypes) {
promises.push(getRefMetadata.call(this, id, missingType));
}
for (const id of Object.keys(e.metadata)) {
promises.push(getRefMetadata.call(this, id, e.metadata[id]));
}
if (promises.length) {
@ -1521,6 +1560,7 @@ export class GraphWebview extends WebviewBase {
scrollRowPadding: configuration.get('graph.scrollRowPadding'),
showGhostRefsOnRowHover: configuration.get('graph.showGhostRefsOnRowHover'),
showRemoteNamesOnRefs: configuration.get('graph.showRemoteNames'),
showUpstreamStatus: configuration.get('graph.showUpstreamStatus'),
idLength: configuration.get('advanced.abbreviatedShaLength'),
};
return config;

+ 3
- 0
src/plus/webviews/graph/protocol.ts Переглянути файл

@ -16,6 +16,7 @@ import type {
RefMetadataType,
Remote,
Tag,
UpstreamMetadata,
WorkDirStats,
} from '@gitkraken/gitkraken-components';
import type { DateStyle } from '../../../config';
@ -33,6 +34,7 @@ export type GraphSelectedRows = Record;
export type GraphAvatars = Record</*email*/ string, /*url*/ string>;
export type GraphRefMetadata = RefMetadata | null;
export type GraphUpstreamMetadata = UpstreamMetadata | null;
export type GraphRefsMetadata = Record</* id */ string, GraphRefMetadata>;
export type GraphHostingServiceType = HostingServiceType;
export type GraphMissingRefsMetadataType = RefMetadataType;
@ -115,6 +117,7 @@ export interface GraphComponentConfig {
scrollRowPadding?: number;
showGhostRefsOnRowHover?: boolean;
showRemoteNamesOnRefs?: boolean;
showUpstreamStatus?: boolean;
idLength?: number;
}

+ 10
- 0
src/webviews/apps/plus/graph/GraphWrapper.tsx Переглянути файл

@ -110,10 +110,19 @@ const createIconElements = (): { [key: string]: ReactElement } => {
'show',
'hide',
];
const miniIconList = [
'upstream-ahead',
'upstream-behind',
];
const elementLibrary: { [key: string]: ReactElement<any> } = {};
iconList.forEach(iconKey => {
elementLibrary[iconKey] = createElement('span', { className: `graph-icon icon--${iconKey}` });
});
miniIconList.forEach(iconKey => {
elementLibrary[iconKey] = createElement('span', { className: `graph-icon mini-icon icon--${iconKey}` });
});
return elementLibrary;
};
@ -1035,6 +1044,7 @@ export function GraphWrapper({
platform={clientPlatform}
refMetadataById={refsMetadata}
shaLength={graphConfig?.idLength}
showUpstreamStatus={graphConfig?.showUpstreamStatus}
themeOpacityFactor={styleProps?.themeOpacityFactor}
useAuthorInitialsForAvatars={!graphConfig?.avatars}
workDirStats={workingTreeStats}

+ 19
- 0
src/webviews/apps/plus/graph/graph.scss Переглянути файл

@ -372,6 +372,11 @@ button:not([disabled]),
vertical-align: middle;
line-height: 2rem;
letter-spacing: normal;
&.mini-icon {
font-size: 1rem;
line-height: 1.6rem;
}
}
.icon {
@ -474,6 +479,20 @@ button:not([disabled]),
content: '\ea64';
}
}
&--upstream-ahead {
&::before {
// codicon-arrow-up
font-family: codicon;
content: '\eaa1';
}
}
&--upstream-behind {
&::before {
// codicon-arrow-down
font-family: codicon;
content: '\ea9a';
}
}
}
.titlebar {

+ 14
- 0
src/webviews/apps/settings/partials/commit-graph.html Переглянути файл

@ -160,6 +160,20 @@
<div class="setting">
<div class="setting__input">
<input
id="graph.showUpstreamStatus"
name="graph.showUpstreamStatus"
type="checkbox"
data-setting
/>
<label for="graph.showUpstreamStatus"
>Show upstream status on local branches with remotes</label
>
</div>
</div>
<div class="setting">
<div class="setting__input">
<input id="graph.avatars" name="graph.avatars" type="checkbox" data-setting />
<label for="graph.avatars">Use author and remote avatars</label>
</div>

Завантаження…
Відмінити
Зберегти