소스 검색

Adds lazy loading for avatars on the Graph

main
Eric Amodio 2 년 전
부모
커밋
22009b9ba4
12개의 변경된 파일217개의 추가작업 그리고 58개의 파일을 삭제
  1. +1
    -1
      package.json
  2. +50
    -27
      src/avatars.ts
  3. +15
    -5
      src/env/node/git/localGitProvider.ts
  4. +5
    -1
      src/git/gitProviderService.ts
  5. +9
    -3
      src/git/models/commit.ts
  6. +2
    -0
      src/git/models/graph.ts
  7. +24
    -2
      src/plus/github/githubGitProvider.ts
  8. +63
    -3
      src/plus/webviews/graph/graphWebview.ts
  9. +14
    -3
      src/plus/webviews/graph/protocol.ts
  10. +12
    -1
      src/webviews/apps/plus/graph/GraphWrapper.tsx
  11. +18
    -8
      src/webviews/apps/plus/graph/graph.tsx
  12. +4
    -4
      yarn.lock

+ 1
- 1
package.json 파일 보기

@ -11680,7 +11680,7 @@
"vscode:prepublish": "yarn run bundle"
},
"dependencies": {
"@gitkraken/gitkraken-components": "1.0.0-rc.13",
"@gitkraken/gitkraken-components": "1.0.0-rc.14",
"@microsoft/fast-element": "^1.10.5",
"@octokit/core": "4.0.5",
"@vscode/codicons": "0.0.32",

+ 50
- 27
src/avatars.ts 파일 보기

@ -1,8 +1,8 @@
import { EventEmitter, Uri } from 'vscode';
import { GravatarDefaultStyle } from './config';
import { configuration } from './configuration';
import { ContextKeys } from './constants';
import { Container } from './container';
import type { GitRevisionReference } from './git/models/reference';
import { getContext } from './context';
import { getGitHubNoReplyAddressParts } from './git/remotes/github';
import type { StoredAvatar } from './storage';
import { debounce } from './system/function';
@ -69,19 +69,41 @@ const retryDecay = [
export function getAvatarUri(
email: string | undefined,
repoPathOrCommit: undefined,
repoPathOrCommit?: undefined,
options?: { defaultStyle?: GravatarDefaultStyle; size?: number },
): Uri;
export function getAvatarUri(
email: string | undefined,
repoPathOrCommit: string | GitRevisionReference,
repoPathOrCommit: string | { ref: string; repoPath: string },
options?: { defaultStyle?: GravatarDefaultStyle; size?: number },
): Uri | Promise<Uri>;
export function getAvatarUri(
email: string | undefined,
repoPathOrCommit: string | GitRevisionReference | undefined,
repoPathOrCommit: string | { ref: string; repoPath: string } | undefined,
options?: { defaultStyle?: GravatarDefaultStyle; size?: number },
): Uri | Promise<Uri> {
return getAvatarUriCore(email, repoPathOrCommit, options);
}
export function getCachedAvatarUri(email: string | undefined, options?: { size?: number }): Uri | undefined {
return getAvatarUriCore(email, undefined, { ...options, cached: true });
}
function getAvatarUriCore(
email: string | undefined,
repoPathOrCommit: string | { ref: string; repoPath: string } | undefined,
options?: { cached: true; defaultStyle?: GravatarDefaultStyle; size?: number },
): Uri | undefined;
function getAvatarUriCore(
email: string | undefined,
repoPathOrCommit: string | { ref: string; repoPath: string } | undefined,
options?: { defaultStyle?: GravatarDefaultStyle; size?: number },
): Uri | Promise<Uri>;
function getAvatarUriCore(
email: string | undefined,
repoPathOrCommit: string | { ref: string; repoPath: string } | undefined,
options?: { cached?: boolean; defaultStyle?: GravatarDefaultStyle; size?: number },
): Uri | Promise<Uri> | undefined {
ensureAvatarCache(avatarCache);
// Double the size to avoid blurring on the retina screen
@ -104,20 +126,22 @@ export function getAvatarUri(
const avatar = createOrUpdateAvatar(key, email, size, hash, options?.defaultStyle);
if (avatar.uri != null) return avatar.uri;
let query = avatarQueue.get(key);
if (query == null && repoPathOrCommit != null && hasAvatarExpired(avatar)) {
query = getAvatarUriFromRemoteProvider(avatar, key, email, repoPathOrCommit, { size: size }).then(
uri => uri ?? avatar.uri ?? avatar.fallback!,
);
avatarQueue.set(
key,
query.finally(() => avatarQueue.delete(key)),
);
}
if (!options?.cached && repoPathOrCommit != null && getContext(ContextKeys.HasConnectedRemotes)) {
let query = avatarQueue.get(key);
if (query == null && hasAvatarExpired(avatar)) {
query = getAvatarUriFromRemoteProvider(avatar, key, email, repoPathOrCommit, { size: size }).then(
uri => uri ?? avatar.uri ?? avatar.fallback!,
);
avatarQueue.set(
key,
query.finally(() => avatarQueue.delete(key)),
);
}
if (query != null) return query;
return query ?? avatar.fallback!;
}
return avatar.uri ?? avatar.fallback!;
return options?.cached ? avatar.uri : avatar.uri ?? avatar.fallback!;
}
function createOrUpdateAvatar(
@ -183,23 +207,22 @@ async function getAvatarUriFromRemoteProvider(
avatar: Avatar,
key: string,
email: string,
repoPathOrCommit: string | GitRevisionReference,
repoPathOrCommit: string | { ref: string; repoPath: string },
{ size = 16 }: { size?: number } = {},
) {
ensureAvatarCache(avatarCache);
try {
let account;
if (configuration.get('integrations.enabled')) {
// if (typeof repoPathOrCommit === 'string') {
// const remote = await Container.instance.git.getRichRemoteProvider(repoPathOrCommit);
// account = await remote?.provider.getAccountForEmail(email, { avatarSize: size });
// } else {
if (typeof repoPathOrCommit !== 'string') {
const remote = await Container.instance.git.getBestRemoteWithRichProvider(repoPathOrCommit.repoPath);
account = await remote?.provider.getAccountForCommit(repoPathOrCommit.ref, { avatarSize: size });
}
// if (typeof repoPathOrCommit === 'string') {
// const remote = await Container.instance.git.getRichRemoteProvider(repoPathOrCommit);
// account = await remote?.provider.getAccountForEmail(email, { avatarSize: size });
// } else {
if (typeof repoPathOrCommit !== 'string') {
const remote = await Container.instance.git.getBestRemoteWithRichProvider(repoPathOrCommit.repoPath);
account = await remote?.provider.getAccountForCommit(repoPathOrCommit.ref, { avatarSize: size });
}
if (account?.avatarUrl == null) {
// If we have no account assume that won't change (without a reset), so set the timestamp to "never expire"
avatar.uri = undefined;

+ 15
- 5
src/env/node/git/localGitProvider.ts 파일 보기

@ -12,7 +12,7 @@ import type {
Repository as BuiltInGitRepository,
GitExtension,
} from '../../../@types/vscode.git';
import { getAvatarUri } from '../../../avatars';
import { getCachedAvatarUri } from '../../../avatars';
import { configuration } from '../../../configuration';
import { CoreGitConfiguration, GlyphChars, Schemes } from '../../../constants';
import type { Container } from '../../../container';
@ -1635,7 +1635,6 @@ export class LocalGitProvider implements GitProvider, Disposable {
const remotes = getSettledValue(remotesResult);
const remoteMap = remotes != null ? new Map(remotes.map(r => [r.name, r])) : new Map();
const selectSha = first(refParser.parse(getSettledValue(refResult) ?? ''));
const skipStashParents = new Set();
let stdin: string | undefined;
// TODO@eamodio this is insanity -- there *HAS* to be a better way to get git log to return stashes
@ -1647,7 +1646,9 @@ export class LocalGitProvider implements GitProvider, Disposable {
);
}
const avatars = new Map<string, string>();
const ids = new Set<string>();
const skipStashParents = new Set();
let total = 0;
let iterations = 0;
@ -1698,7 +1699,9 @@ export class LocalGitProvider implements GitProvider, Disposable {
: data.indexOf(`\x00\x00${cursor.sha}\x00`);
if (cursorIndex === -1) {
// If we didn't find any new commits, we must have them all so return that we have everything
if (size === data.length) return { repoPath: repoPath, ids: ids, rows: [] };
if (size === data.length) {
return { repoPath: repoPath, avatars: avatars, ids: ids, rows: [] };
}
size = data.length;
nextPageLimit = (nextPageLimit === 0 ? defaultPageLimit : nextPageLimit) * 2;
@ -1723,7 +1726,7 @@ export class LocalGitProvider implements GitProvider, Disposable {
}
}
if (!data) return { repoPath: repoPath, ids: ids, rows: [] };
if (!data) return { repoPath: repoPath, avatars: avatars, ids: ids, rows: [] };
log = data;
if (limit !== 0) {
@ -1818,11 +1821,17 @@ export class LocalGitProvider implements GitProvider, Disposable {
parents.splice(1, 2);
}
if (!isStashCommit && !avatars.has(commit.authorEmail)) {
const uri = getCachedAvatarUri(commit.authorEmail);
if (uri != null) {
avatars.set(commit.authorEmail, uri.toString(true));
}
}
rows.push({
sha: commit.sha,
parents: parents,
author: commit.author,
avatarUrl: !isStashCommit ? getAvatarUri(commit.authorEmail, undefined).toString(true) : undefined,
email: commit.authorEmail ?? '',
date: Number(ordering === 'author-date' ? commit.authorDate : commit.committerDate) * 1000,
message: emojify(commit.message),
@ -1850,6 +1859,7 @@ export class LocalGitProvider implements GitProvider, Disposable {
return {
repoPath: repoPath,
avatars: avatars,
ids: ids,
rows: rows,
sha: sha,

+ 5
- 1
src/git/gitProviderService.ts 파일 보기

@ -201,6 +201,10 @@ export class GitProviderService implements Disposable {
if (configuration.changed(e, 'views.contributors.showAllBranches')) {
this.resetCaches('contributors');
}
if (e != null && configuration.changed(e, 'integrations.enabled')) {
this.updateContext();
}
}
@debug()
@ -739,7 +743,7 @@ export class GitProviderService implements Disposable {
let hasRemotes = false;
let hasRichRemotes = false;
let hasConnectedRemotes = false;
if (hasRepositories) {
if (hasRepositories && configuration.get('integrations.enabled')) {
for (const repo of this._repositories.values()) {
if (!hasConnectedRemotes) {
hasConnectedRemotes = await repo.hasRichRemote(true);

+ 9
- 3
src/git/models/commit.ts 파일 보기

@ -1,5 +1,5 @@
import { Uri } from 'vscode';
import { getAvatarUri } from '../../avatars';
import { getAvatarUri, getCachedAvatarUri } from '../../avatars';
import type { GravatarDefaultStyle } from '../../configuration';
import { DateSource, DateStyle } from '../../configuration';
import { GlyphChars } from '../../constants';
@ -437,6 +437,10 @@ export class GitCommit implements GitRevisionReference {
return this.author.getAvatarUri(this, options);
}
getCachedAvatarUri(options?: { size?: number }): Uri | undefined {
return this.author.getCachedAvatarUri(options);
}
async getCommitForFile(file: string | GitFile): Promise<GitCommit | undefined> {
const path = typeof file === 'string' ? this.container.git.getRelativePath(file, this.repoPath) : file.path;
const foundFile = await this.findFile(path);
@ -616,9 +620,11 @@ export class GitCommitIdentity implements GitCommitIdentityShape {
commit: GitCommit,
options?: { defaultStyle?: GravatarDefaultStyle; size?: number },
): Uri | Promise<Uri> {
if (this.avatarUrl != null) return Uri.parse(this.avatarUrl);
return this.avatarUrl != null ? Uri.parse(this.avatarUrl) : getAvatarUri(this.email, commit, options);
}
return getAvatarUri(this.email, commit, options);
getCachedAvatarUri(options?: { size?: number }): Uri | undefined {
return this.avatarUrl != null ? Uri.parse(this.avatarUrl) : getCachedAvatarUri(this.email, options);
}
}

+ 2
- 0
src/git/models/graph.ts 파일 보기

@ -21,6 +21,8 @@ export interface GitGraphRow extends GraphRow {
export interface GitGraph {
readonly repoPath: string;
/** A map of all avatar urls */
readonly avatars: Map<string, string>;
/** A set of all "seen" commit ids */
readonly ids: Set<string>;
/** The rows for the set of commits requested */

+ 24
- 2
src/plus/github/githubGitProvider.ts 파일 보기

@ -1075,6 +1075,7 @@ export class GitHubGitProvider implements GitProvider, Disposable {
this.getTags(repoPath),
]);
const avatars = new Map<string, string>();
const ids = new Set<string>();
return this.getCommitsForGraphCore(
@ -1084,6 +1085,7 @@ export class GitHubGitProvider implements GitProvider, Disposable {
getSettledValue(branchResult),
getSettledValue(remotesResult)?.[0],
getSettledValue(tagsResult)?.values,
avatars,
ids,
options,
);
@ -1096,6 +1098,7 @@ export class GitHubGitProvider implements GitProvider, Disposable {
branch: GitBranch | undefined,
remote: GitRemote | undefined,
tags: GitTag[] | undefined,
avatars: Map<string, string>,
ids: Set<string>,
options?: {
branch?: string;
@ -1107,6 +1110,7 @@ export class GitHubGitProvider implements GitProvider, Disposable {
if (log == null) {
return {
repoPath: repoPath,
avatars: avatars,
ids: ids,
rows: [],
};
@ -1116,6 +1120,7 @@ export class GitHubGitProvider implements GitProvider, Disposable {
if (commits == null) {
return {
repoPath: repoPath,
avatars: avatars,
ids: ids,
rows: [],
};
@ -1169,11 +1174,17 @@ export class GitHubGitProvider implements GitProvider, Disposable {
refTags = [];
}
if (commit.author.email && !avatars.has(commit.author.email)) {
const uri = commit.getCachedAvatarUri();
if (uri != null) {
avatars.set(commit.author.email, uri.toString(true));
}
}
rows.push({
sha: commit.sha,
parents: commit.parents,
author: commit.author.name,
avatarUrl: (await commit.getAvatarUri())?.toString(true),
email: commit.author.email ?? '',
date: commit.committer.date.getTime(),
message: emojify(commit.message && String(commit.message).length ? commit.message : commit.summary),
@ -1193,6 +1204,7 @@ export class GitHubGitProvider implements GitProvider, Disposable {
return {
repoPath: repoPath,
avatars: avatars,
ids: ids,
rows: rows,
sha: options?.ref,
@ -1205,7 +1217,17 @@ export class GitHubGitProvider implements GitProvider, Disposable {
},
more: async (limit: number | { until: string } | undefined): Promise<GitGraph | undefined> => {
const moreLog = await log.more?.(limit);
return this.getCommitsForGraphCore(repoPath, asWebviewUri, moreLog, branch, remote, tags, ids, options);
return this.getCommitsForGraphCore(
repoPath,
asWebviewUri,
moreLog,
branch,
remote,
tags,
avatars,
ids,
options,
);
},
};
}

+ 63
- 3
src/plus/webviews/graph/graphWebview.ts 파일 보기

@ -1,5 +1,6 @@
import type { ColorTheme, ConfigurationChangeEvent, Disposable, Event, StatusBarItem } from 'vscode';
import { EventEmitter, MarkdownString, ProgressLocation, StatusBarAlignment, ViewColumn, window } from 'vscode';
import { getAvatarUri } from '../../../avatars';
import { parseCommandContext } from '../../../commands/base';
import { GitActions } from '../../../commands/gitCommands.actions';
import type { GraphColumnConfig } from '../../../configuration';
@ -28,12 +29,14 @@ import type { SubscriptionChangeEvent } from '../../subscription/subscriptionSer
import { ensurePlusFeaturesEnabled } from '../../subscription/utils';
import type { DismissBannerParams, GraphCompositeConfig, GraphRepository, State } from './protocol';
import {
DidChangeAvatarsNotificationType,
DidChangeCommitsNotificationType,
DidChangeGraphConfigurationNotificationType,
DidChangeNotificationType,
DidChangeSelectionNotificationType,
DidChangeSubscriptionNotificationType,
DismissBannerCommandType,
GetMissingAvatarsCommandType,
GetMoreCommitsCommandType,
UpdateColumnCommandType,
UpdateSelectedRepositoryCommandType,
@ -181,8 +184,11 @@ export class GraphWebview extends WebviewBase {
case DismissBannerCommandType.method:
onIpc(DismissBannerCommandType, e, params => this.dismissBanner(params.key));
break;
case GetMissingAvatarsCommandType.method:
onIpc(GetMissingAvatarsCommandType, e, params => this.onGetMissingAvatars(params.emails));
break;
case GetMoreCommitsCommandType.method:
onIpc(GetMoreCommitsCommandType, e, params => this.onGetMoreCommits(params.limit));
onIpc(GetMoreCommitsCommandType, e, () => this.onGetMoreCommits());
break;
case UpdateColumnCommandType.method:
onIpc(UpdateColumnCommandType, e, params => this.onColumnUpdated(params.name, params.config));
@ -308,8 +314,32 @@ export class GraphWebview extends WebviewBase {
void this.notifyDidChangeGraphConfiguration();
}
private async onGetMissingAvatars(emails: { [email: string]: string }) {
if (this._graph == null) return;
const repoPath = this._graph.repoPath;
async function getAvatar(this: GraphWebview, email: string, sha: string) {
const uri = await getAvatarUri(email, { ref: sha, repoPath: repoPath });
this._graph!.avatars.set(email, uri.toString(true));
}
const promises: Promise<void>[] = [];
for (const [email, sha] of Object.entries(emails)) {
if (this._graph.avatars.has(email)) continue;
promises.push(getAvatar.call(this, email, sha));
}
if (promises.length) {
await Promise.allSettled(promises);
this.updateAvatars();
}
}
@gate()
private async onGetMoreCommits(limit?: number) {
private async onGetMoreCommits() {
if (this._graph?.more == null || this._repository?.etag !== this._etagRepository) {
this.updateState(true);
@ -317,7 +347,7 @@ export class GraphWebview extends WebviewBase {
}
const { defaultItemLimit, pageItemLimit } = this.getConfig();
const newGraph = await this._graph.more(limit ?? pageItemLimit ?? defaultItemLimit);
const newGraph = await this._graph.more(pageItemLimit ?? defaultItemLimit);
if (newGraph != null) {
this.setGraph(newGraph);
} else {
@ -375,6 +405,24 @@ export class GraphWebview extends WebviewBase {
this._notifyDidChangeStateDebounced();
}
private _notifyDidChangeAvatarsDebounced: Deferrable<() => void> | undefined = undefined;
@debug()
private updateAvatars(immediate: boolean = false) {
if (!this.isReady || !this.visible) return;
if (immediate) {
void this.notifyDidChangeAvatars();
return;
}
if (this._notifyDidChangeAvatarsDebounced == null) {
this._notifyDidChangeAvatarsDebounced = debounce(this.notifyDidChangeAvatars.bind(this), 100);
}
this._notifyDidChangeAvatarsDebounced();
}
@debug()
private async notifyDidChangeState() {
if (!this.isReady || !this.visible) return false;
@ -416,12 +464,23 @@ export class GraphWebview extends WebviewBase {
}
@debug()
private async notifyDidChangeAvatars() {
if (!this.isReady || !this.visible) return false;
const data = this._graph!;
return this.notify(DidChangeAvatarsNotificationType, {
avatars: Object.fromEntries(data.avatars),
});
}
@debug()
private async notifyDidChangeCommits() {
if (!this.isReady || !this.visible) return false;
const data = this._graph!;
return this.notify(DidChangeCommitsNotificationType, {
rows: data.rows,
avatars: Object.fromEntries(data.avatars),
paging: {
startingCursor: data.paging?.startingCursor,
more: data.paging?.more ?? false,
@ -486,6 +545,7 @@ export class GraphWebview extends WebviewBase {
selectedVisibility: visibility,
subscription: access.subscription.current,
allowed: access.allowed,
avatars: Object.fromEntries(data.avatars),
rows: data.rows,
paging: {
startingCursor: data.paging?.startingCursor,

+ 14
- 3
src/plus/webviews/graph/protocol.ts 파일 보기

@ -12,6 +12,7 @@ export interface State {
selectedRows?: { [id: string]: true };
subscription?: Subscription;
allowed?: boolean;
avatars?: { [email: string]: string };
rows?: GraphRow[];
paging?: GraphPaging;
config?: GraphCompositeConfig;
@ -68,10 +69,12 @@ export interface DismissBannerParams {
}
export const DismissBannerCommandType = new IpcCommandType<DismissBannerParams>('graph/dismissBanner');
export interface GetMoreCommitsParams {
limit?: number;
export interface GetMissingAvatarsParams {
emails: { [email: string]: string };
}
export const GetMoreCommitsCommandType = new IpcCommandType<GetMoreCommitsParams>('graph/getMoreCommits');
export const GetMissingAvatarsCommandType = new IpcCommandType<GetMissingAvatarsParams>('graph/getMissingAvatars');
export const GetMoreCommitsCommandType = new IpcCommandType<undefined>('graph/getMoreCommits');
export interface UpdateColumnParams {
name: string;
@ -112,8 +115,16 @@ export const DidChangeSubscriptionNotificationType = new IpcNotificationType
'graph/subscription/didChange',
);
export interface DidChangeAvatarsParams {
avatars: { [email: string]: string };
}
export const DidChangeAvatarsNotificationType = new IpcNotificationType<DidChangeAvatarsParams>(
'graph/avatars/didChange',
);
export interface DidChangeCommitsParams {
rows: GraphRow[];
avatars: { [email: string]: string };
paging?: GraphPaging;
}
export const DidChangeCommitsNotificationType = new IpcNotificationType<DidChangeCommitsParams>(

+ 12
- 1
src/webviews/apps/plus/graph/GraphWrapper.tsx 파일 보기

@ -28,7 +28,8 @@ export interface GraphWrapperProps extends State {
subscriber: (callback: CommitListCallback) => () => void;
onSelectRepository?: (repository: GraphRepository) => void;
onColumnChange?: (name: string, settings: GraphColumnConfig) => void;
onMoreCommits?: (limit?: number) => void;
onMissingAvatars?: (emails: { [email: string]: string }) => void;
onMoreCommits?: () => void;
onDismissBanner?: (key: DismissBannerParams['key']) => void;
onSelectionChange?: (selection: { id: string; type: GitGraphRowType }[]) => void;
}
@ -140,10 +141,12 @@ export function GraphWrapper({
subscription,
selectedVisibility,
allowed,
avatars,
config,
paging,
onSelectRepository,
onColumnChange,
onMissingAvatars,
onMoreCommits,
onSelectionChange,
nonce,
@ -153,6 +156,7 @@ export function GraphWrapper({
onDismissBanner,
}: GraphWrapperProps) {
const [graphList, setGraphList] = useState(rows);
const [graphAvatars, setAvatars] = useState(avatars);
const [reposList, setReposList] = useState(repositories);
const [currentRepository, setCurrentRepository] = useState<GraphRepository | undefined>(
reposList.find(item => item.path === selectedRepository),
@ -201,6 +205,7 @@ export function GraphWrapper({
function transformData(state: State) {
setGraphList(state.rows ?? []);
setAvatars(state.avatars ?? {});
setReposList(state.repositories ?? []);
setCurrentRepository(reposList.find(item => item.path === state.selectedRepository));
setSelectedRows(state.selectedRows);
@ -233,6 +238,10 @@ export function GraphWrapper({
setRepoExpanded(!repoExpanded);
};
const handleMissingAvatars = (emails: { [email: string]: string }) => {
onMissingAvatars?.(emails);
};
const handleMoreCommits = () => {
setIsLoading(true);
onMoreCommits?.();
@ -432,6 +441,7 @@ export function GraphWrapper({
columnsSettings={graphColSettings}
cssVariables={styleProps.cssVariables}
getExternalIcon={getIconElementLibrary}
avatarUrlByEmail={graphAvatars}
graphRows={graphList}
height={mainHeight}
isSelectedBySha={graphSelectedRows}
@ -440,6 +450,7 @@ export function GraphWrapper({
nonce={nonce}
onColumnResized={handleOnColumnResized}
onSelectGraphRows={handleSelectGraphRows}
onEmailsMissingAvatarUrls={handleMissingAvatars}
onShowMoreCommits={handleMoreCommits}
platform={clientPlatform}
width={mainWidth}

+ 18
- 8
src/webviews/apps/plus/graph/graph.tsx 파일 보기

@ -11,12 +11,14 @@ import type {
State,
} from '../../../../plus/webviews/graph/protocol';
import {
DidChangeAvatarsNotificationType,
DidChangeCommitsNotificationType,
DidChangeGraphConfigurationNotificationType,
DidChangeNotificationType,
DidChangeSelectionNotificationType,
DidChangeSubscriptionNotificationType,
DismissBannerCommandType,
GetMissingAvatarsCommandType,
GetMoreCommitsCommandType,
UpdateColumnCommandType,
UpdateSelectedRepositoryCommandType as UpdateRepositorySelectionCommandType,
@ -68,6 +70,7 @@ export class GraphApp extends App {
(path: GraphRepository) => this.onRepositorySelectionChanged(path),
250,
)}
onMissingAvatars={(...params) => this.onGetMissingAvatars(...params)}
onMoreCommits={(...params) => this.onGetMoreCommits(...params)}
onSelectionChange={debounce(
(selection: { id: string; type: GitGraphRowType }[]) => this.onSelectionChanged(selection),
@ -98,6 +101,13 @@ export class GraphApp extends App {
});
break;
case DidChangeAvatarsNotificationType.method:
onIpc(DidChangeAvatarsNotificationType, msg, params => {
this.setState({ ...this.state, avatars: params.avatars });
this.refresh(this.state);
});
break;
case DidChangeCommitsNotificationType.method:
onIpc(DidChangeCommitsNotificationType, msg, params => {
let rows;
@ -164,6 +174,7 @@ export class GraphApp extends App {
this.setState({
...this.state,
avatars: params.avatars,
rows: rows,
paging: params.paging,
});
@ -180,10 +191,7 @@ export class GraphApp extends App {
case DidChangeGraphConfigurationNotificationType.method:
onIpc(DidChangeGraphConfigurationNotificationType, msg, params => {
this.setState({
...this.state,
config: params.config,
});
this.setState({ ...this.state, config: params.config });
this.refresh(this.state);
});
break;
@ -261,10 +269,12 @@ export class GraphApp extends App {
});
}
private onGetMoreCommits(limit?: number) {
this.sendCommand(GetMoreCommitsCommandType, {
limit: limit,
});
private onGetMissingAvatars(emails: { [email: string]: string }) {
this.sendCommand(GetMissingAvatarsCommandType, { emails: emails });
}
private onGetMoreCommits() {
this.sendCommand(GetMoreCommitsCommandType, undefined);
}
private onSelectionChanged(selection: { id: string; type: GitGraphRowType }[]) {

+ 4
- 4
yarn.lock 파일 보기

@ -80,10 +80,10 @@
resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6"
integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==
"@gitkraken/gitkraken-components@1.0.0-rc.13":
version "1.0.0-rc.13"
resolved "https://registry.yarnpkg.com/@gitkraken/gitkraken-components/-/gitkraken-components-1.0.0-rc.13.tgz#9bfb5872dfa027bbf69ac94874b31fbe223d4784"
integrity sha512-QaMe9FF9kUnt4KGYzEdhNm8JsLqguE8/yDJzEJD4y1Y5gbe7CmldnTjmrRZQehJiEMrWs/sfDuBygJOZG893eg==
"@gitkraken/gitkraken-components@1.0.0-rc.14":
version "1.0.0-rc.14"
resolved "https://registry.yarnpkg.com/@gitkraken/gitkraken-components/-/gitkraken-components-1.0.0-rc.14.tgz#2aa57a9c88654bc772e70a6305ab8f1f408e1b6b"
integrity sha512-pCtVtsU1uNiVEjS/bUoIBqMkDAM7apJGZUvZm9ynoERZM8ZRt883nol8MpfZkid8cMaw91FBdzu3MfxSDAFi1Q==
dependencies:
"@axosoft/react-virtualized" "9.22.3-gitkraken.3"
classnames "2.2.3"

불러오는 중...
취소
저장