|
|
@ -76,7 +76,7 @@ import { getSettledValue } from '../../../system/promise'; |
|
|
|
import { isDarkTheme, isLightTheme } from '../../../system/utils'; |
|
|
|
import { isWebviewItemContext, isWebviewItemGroupContext, serializeWebviewItemContext } from '../../../system/webview'; |
|
|
|
import { RepositoryFolderNode } from '../../../views/nodes/viewNode'; |
|
|
|
import type { IpcMessage, IpcMessageParams, IpcNotificationType } from '../../../webviews/protocol'; |
|
|
|
import type { IpcMessage, IpcNotificationType } from '../../../webviews/protocol'; |
|
|
|
import { onIpc } from '../../../webviews/protocol'; |
|
|
|
import type { WebviewController, WebviewProvider } from '../../../webviews/webviewController'; |
|
|
|
import type { SubscriptionChangeEvent } from '../../subscription/subscriptionService'; |
|
|
@ -205,7 +205,17 @@ export class GraphWebviewProvider implements WebviewProvider { |
|
|
|
private _etagRepository?: number; |
|
|
|
private _firstSelection = true; |
|
|
|
private _graph?: GitGraph; |
|
|
|
private _pendingIpcNotifications = new Map<IpcNotificationType, IpcMessage | (() => Promise<boolean>)>(); |
|
|
|
private readonly _ipcNotificationMap = new Map<IpcNotificationType<any>, () => Promise<boolean>>([ |
|
|
|
[DidChangeColumnsNotificationType, this.notifyDidChangeColumns], |
|
|
|
[DidChangeGraphConfigurationNotificationType, this.notifyDidChangeConfiguration], |
|
|
|
[DidChangeNotificationType, this.notifyDidChangeState], |
|
|
|
[DidChangeRefsVisibilityNotificationType, this.notifyDidChangeRefsVisibility], |
|
|
|
[DidChangeSelectionNotificationType, this.notifyDidChangeSelection], |
|
|
|
[DidChangeSubscriptionNotificationType, this.notifyDidChangeSubscription], |
|
|
|
[DidChangeWorkingTreeNotificationType, this.notifyDidChangeWorkingTree], |
|
|
|
[DidChangeWindowFocusNotificationType, this.notifyDidChangeWindowFocus], |
|
|
|
[DidFetchNotificationType, this.notifyDidFetch], |
|
|
|
]); |
|
|
|
private _refsMetadata: Map<string, GraphRefMetadata | null> | null | undefined; |
|
|
|
private _search: GitSearch | undefined; |
|
|
|
private _searchCancellation: CancellationTokenSource | undefined; |
|
|
@ -294,7 +304,6 @@ export class GraphWebviewProvider implements WebviewProvider { |
|
|
|
onRefresh(force?: boolean) { |
|
|
|
if (force) { |
|
|
|
this.resetRepositoryState(); |
|
|
|
this._pendingIpcNotifications.clear(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@ -388,10 +397,6 @@ export class GraphWebviewProvider implements WebviewProvider { |
|
|
|
void this.notifyDidChangeWindowFocus(); |
|
|
|
} |
|
|
|
|
|
|
|
onReady(): void { |
|
|
|
this.sendPendingIpcNotifications(); |
|
|
|
} |
|
|
|
|
|
|
|
onFocusChanged(focused: boolean): void { |
|
|
|
if (!focused || this.activeSelection == null || !this.container.commitDetailsView.visible) { |
|
|
|
this._showActiveSelectionDetailsDebounced?.cancel(); |
|
|
@ -417,7 +422,7 @@ export class GraphWebviewProvider implements WebviewProvider { |
|
|
|
|
|
|
|
if (visible) { |
|
|
|
if (this.host.ready) { |
|
|
|
this.sendPendingIpcNotifications(); |
|
|
|
this.host.sendPendingIpcNotifications(); |
|
|
|
} |
|
|
|
|
|
|
|
const { activeSelection } = this; |
|
|
@ -734,7 +739,7 @@ export class GraphWebviewProvider implements WebviewProvider { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void this.notify(DidEnsureRowNotificationType, { id: id }, completionId); |
|
|
|
void this.host.notify(DidEnsureRowNotificationType, { id: id }, completionId); |
|
|
|
} |
|
|
|
|
|
|
|
private async onGetMissingAvatars(e: GetMissingAvatarsParams) { |
|
|
@ -910,7 +915,7 @@ export class GraphWebviewProvider implements WebviewProvider { |
|
|
|
this._search = search; |
|
|
|
void (await this.ensureSearchStartsInRange(this._graph!, search)); |
|
|
|
|
|
|
|
void this.notify( |
|
|
|
void this.host.notify( |
|
|
|
DidSearchNotificationType, |
|
|
|
{ |
|
|
|
results: |
|
|
@ -953,7 +958,7 @@ export class GraphWebviewProvider implements WebviewProvider { |
|
|
|
} catch (ex) { |
|
|
|
this._search = undefined; |
|
|
|
|
|
|
|
void this.notify( |
|
|
|
void this.host.notify( |
|
|
|
DidSearchNotificationType, |
|
|
|
{ |
|
|
|
results: { |
|
|
@ -967,7 +972,7 @@ export class GraphWebviewProvider implements WebviewProvider { |
|
|
|
|
|
|
|
if (cancellation.token.isCancellationRequested) { |
|
|
|
if (completionId != null) { |
|
|
|
void this.notify(DidSearchNotificationType, { results: undefined }, completionId); |
|
|
|
void this.host.notify(DidSearchNotificationType, { results: undefined }, completionId); |
|
|
|
} |
|
|
|
return; |
|
|
|
} |
|
|
@ -985,7 +990,7 @@ export class GraphWebviewProvider implements WebviewProvider { |
|
|
|
this.setSelectedRows(firstResult); |
|
|
|
} |
|
|
|
|
|
|
|
void this.notify( |
|
|
|
void this.host.notify( |
|
|
|
DidSearchNotificationType, |
|
|
|
{ |
|
|
|
results: |
|
|
@ -1103,7 +1108,7 @@ export class GraphWebviewProvider implements WebviewProvider { |
|
|
|
|
|
|
|
@debug() |
|
|
|
private updateState(immediate: boolean = false) { |
|
|
|
this._pendingIpcNotifications.clear(); |
|
|
|
this.host.clearPendingIpcNotifications(); |
|
|
|
|
|
|
|
if (immediate) { |
|
|
|
void this.notifyDidChangeState(); |
|
|
@ -1120,11 +1125,11 @@ export class GraphWebviewProvider implements WebviewProvider { |
|
|
|
@debug() |
|
|
|
private async notifyDidChangeWindowFocus(): Promise<boolean> { |
|
|
|
if (!this.host.ready || !this.host.visible) { |
|
|
|
this.addPendingIpcNotification(DidChangeWindowFocusNotificationType); |
|
|
|
this.host.addPendingIpcNotification(DidChangeWindowFocusNotificationType, this._ipcNotificationMap, this); |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
return this.notify(DidChangeWindowFocusNotificationType, { |
|
|
|
return this.host.notify(DidChangeWindowFocusNotificationType, { |
|
|
|
focused: this.isWindowFocused, |
|
|
|
}); |
|
|
|
} |
|
|
@ -1151,7 +1156,7 @@ export class GraphWebviewProvider implements WebviewProvider { |
|
|
|
if (this._graph == null) return; |
|
|
|
|
|
|
|
const data = this._graph; |
|
|
|
return this.notify(DidChangeAvatarsNotificationType, { |
|
|
|
return this.host.notify(DidChangeAvatarsNotificationType, { |
|
|
|
avatars: Object.fromEntries(data.avatars), |
|
|
|
}); |
|
|
|
} |
|
|
@ -1176,7 +1181,7 @@ export class GraphWebviewProvider implements WebviewProvider { |
|
|
|
|
|
|
|
@debug() |
|
|
|
private async notifyDidChangeRefsMetadata() { |
|
|
|
return this.notify(DidChangeRefsMetadataNotificationType, { |
|
|
|
return this.host.notify(DidChangeRefsMetadataNotificationType, { |
|
|
|
metadata: this._refsMetadata != null ? Object.fromEntries(this._refsMetadata) : this._refsMetadata, |
|
|
|
}); |
|
|
|
} |
|
|
@ -1184,13 +1189,13 @@ export class GraphWebviewProvider implements WebviewProvider { |
|
|
|
@debug() |
|
|
|
private async notifyDidChangeColumns() { |
|
|
|
if (!this.host.ready || !this.host.visible) { |
|
|
|
this.addPendingIpcNotification(DidChangeColumnsNotificationType); |
|
|
|
this.host.addPendingIpcNotification(DidChangeColumnsNotificationType, this._ipcNotificationMap, this); |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
const columns = this.getColumns(); |
|
|
|
const columnSettings = this.getColumnSettings(columns); |
|
|
|
return this.notify(DidChangeColumnsNotificationType, { |
|
|
|
return this.host.notify(DidChangeColumnsNotificationType, { |
|
|
|
columns: columnSettings, |
|
|
|
context: this.getColumnHeaderContext(columnSettings), |
|
|
|
}); |
|
|
@ -1199,11 +1204,15 @@ export class GraphWebviewProvider implements WebviewProvider { |
|
|
|
@debug() |
|
|
|
private async notifyDidChangeRefsVisibility() { |
|
|
|
if (!this.host.ready || !this.host.visible) { |
|
|
|
this.addPendingIpcNotification(DidChangeRefsVisibilityNotificationType); |
|
|
|
this.host.addPendingIpcNotification( |
|
|
|
DidChangeRefsVisibilityNotificationType, |
|
|
|
this._ipcNotificationMap, |
|
|
|
this, |
|
|
|
); |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
return this.notify(DidChangeRefsVisibilityNotificationType, { |
|
|
|
return this.host.notify(DidChangeRefsVisibilityNotificationType, { |
|
|
|
excludeRefs: this.getExcludedRefs(this._graph), |
|
|
|
excludeTypes: this.getExcludedTypes(this._graph), |
|
|
|
includeOnlyRefs: this.getIncludeOnlyRefs(this._graph), |
|
|
@ -1213,11 +1222,15 @@ export class GraphWebviewProvider implements WebviewProvider { |
|
|
|
@debug() |
|
|
|
private async notifyDidChangeConfiguration() { |
|
|
|
if (!this.host.ready || !this.host.visible) { |
|
|
|
this.addPendingIpcNotification(DidChangeGraphConfigurationNotificationType); |
|
|
|
this.host.addPendingIpcNotification( |
|
|
|
DidChangeGraphConfigurationNotificationType, |
|
|
|
this._ipcNotificationMap, |
|
|
|
this, |
|
|
|
); |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
return this.notify(DidChangeGraphConfigurationNotificationType, { |
|
|
|
return this.host.notify(DidChangeGraphConfigurationNotificationType, { |
|
|
|
config: this.getComponentConfig(), |
|
|
|
}); |
|
|
|
} |
|
|
@ -1225,12 +1238,12 @@ export class GraphWebviewProvider implements WebviewProvider { |
|
|
|
@debug() |
|
|
|
private async notifyDidFetch() { |
|
|
|
if (!this.host.ready || !this.host.visible) { |
|
|
|
this.addPendingIpcNotification(DidFetchNotificationType); |
|
|
|
this.host.addPendingIpcNotification(DidFetchNotificationType, this._ipcNotificationMap, this); |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
const lastFetched = await this.repository!.getLastFetched(); |
|
|
|
return this.notify(DidFetchNotificationType, { |
|
|
|
return this.host.notify(DidFetchNotificationType, { |
|
|
|
lastFetched: new Date(lastFetched), |
|
|
|
}); |
|
|
|
} |
|
|
@ -1240,7 +1253,7 @@ export class GraphWebviewProvider implements WebviewProvider { |
|
|
|
if (this._graph == null) return; |
|
|
|
|
|
|
|
const data = this._graph; |
|
|
|
return this.notify( |
|
|
|
return this.host.notify( |
|
|
|
DidChangeRowsNotificationType, |
|
|
|
{ |
|
|
|
rows: data.rows, |
|
|
@ -1260,11 +1273,11 @@ export class GraphWebviewProvider implements WebviewProvider { |
|
|
|
@debug() |
|
|
|
private async notifyDidChangeWorkingTree() { |
|
|
|
if (!this.host.ready || !this.host.visible) { |
|
|
|
this.addPendingIpcNotification(DidChangeWorkingTreeNotificationType); |
|
|
|
this.host.addPendingIpcNotification(DidChangeWorkingTreeNotificationType, this._ipcNotificationMap, this); |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
return this.notify(DidChangeWorkingTreeNotificationType, { |
|
|
|
return this.host.notify(DidChangeWorkingTreeNotificationType, { |
|
|
|
stats: (await this.getWorkingTreeStats()) ?? { added: 0, deleted: 0, modified: 0 }, |
|
|
|
}); |
|
|
|
} |
|
|
@ -1272,11 +1285,11 @@ export class GraphWebviewProvider implements WebviewProvider { |
|
|
|
@debug() |
|
|
|
private async notifyDidChangeSelection() { |
|
|
|
if (!this.host.ready || !this.host.visible) { |
|
|
|
this.addPendingIpcNotification(DidChangeSelectionNotificationType); |
|
|
|
this.host.addPendingIpcNotification(DidChangeSelectionNotificationType, this._ipcNotificationMap, this); |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
return this.notify(DidChangeSelectionNotificationType, { |
|
|
|
return this.host.notify(DidChangeSelectionNotificationType, { |
|
|
|
selection: this._selectedRows ?? {}, |
|
|
|
}); |
|
|
|
} |
|
|
@ -1284,12 +1297,12 @@ export class GraphWebviewProvider implements WebviewProvider { |
|
|
|
@debug() |
|
|
|
private async notifyDidChangeSubscription() { |
|
|
|
if (!this.host.ready || !this.host.visible) { |
|
|
|
this.addPendingIpcNotification(DidChangeSubscriptionNotificationType); |
|
|
|
this.host.addPendingIpcNotification(DidChangeSubscriptionNotificationType, this._ipcNotificationMap, this); |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
const [access] = await this.getGraphAccess(); |
|
|
|
return this.notify(DidChangeSubscriptionNotificationType, { |
|
|
|
return this.host.notify(DidChangeSubscriptionNotificationType, { |
|
|
|
subscription: access.subscription.current, |
|
|
|
allowed: access.allowed !== false, |
|
|
|
}); |
|
|
@ -1298,77 +1311,11 @@ export class GraphWebviewProvider implements WebviewProvider { |
|
|
|
@debug() |
|
|
|
private async notifyDidChangeState() { |
|
|
|
if (!this.host.ready || !this.host.visible) { |
|
|
|
this.addPendingIpcNotification(DidChangeNotificationType); |
|
|
|
this.host.addPendingIpcNotification(DidChangeNotificationType, this._ipcNotificationMap, this); |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
return this.notify(DidChangeNotificationType, { state: await this.getState() }); |
|
|
|
} |
|
|
|
|
|
|
|
private async notify<T extends IpcNotificationType<any>>( |
|
|
|
type: T, |
|
|
|
params: IpcMessageParams<T>, |
|
|
|
completionId?: string, |
|
|
|
): Promise<boolean> { |
|
|
|
const msg: IpcMessage = { |
|
|
|
id: this.host.nextIpcId(), |
|
|
|
method: type.method, |
|
|
|
params: params, |
|
|
|
completionId: completionId, |
|
|
|
}; |
|
|
|
const success = await this.host.postMessage(msg); |
|
|
|
if (success) { |
|
|
|
this._pendingIpcNotifications.clear(); |
|
|
|
} else { |
|
|
|
this.addPendingIpcNotification(type, msg); |
|
|
|
} |
|
|
|
return success; |
|
|
|
} |
|
|
|
|
|
|
|
private readonly _ipcNotificationMap = new Map<IpcNotificationType<any>, () => Promise<boolean>>([ |
|
|
|
[DidChangeColumnsNotificationType, this.notifyDidChangeColumns], |
|
|
|
[DidChangeGraphConfigurationNotificationType, this.notifyDidChangeConfiguration], |
|
|
|
[DidChangeNotificationType, this.notifyDidChangeState], |
|
|
|
[DidChangeRefsVisibilityNotificationType, this.notifyDidChangeRefsVisibility], |
|
|
|
[DidChangeSelectionNotificationType, this.notifyDidChangeSelection], |
|
|
|
[DidChangeSubscriptionNotificationType, this.notifyDidChangeSubscription], |
|
|
|
[DidChangeWorkingTreeNotificationType, this.notifyDidChangeWorkingTree], |
|
|
|
[DidChangeWindowFocusNotificationType, this.notifyDidChangeWindowFocus], |
|
|
|
[DidFetchNotificationType, this.notifyDidFetch], |
|
|
|
]); |
|
|
|
|
|
|
|
private addPendingIpcNotification(type: IpcNotificationType<any>, msg?: IpcMessage) { |
|
|
|
if (type === DidChangeNotificationType) { |
|
|
|
this._pendingIpcNotifications.clear(); |
|
|
|
} else if (type.overwriteable) { |
|
|
|
this._pendingIpcNotifications.delete(type); |
|
|
|
} |
|
|
|
|
|
|
|
let msgOrFn: IpcMessage | (() => Promise<boolean>) | undefined; |
|
|
|
if (msg == null) { |
|
|
|
msgOrFn = this._ipcNotificationMap.get(type)?.bind(this); |
|
|
|
if (msgOrFn == null) { |
|
|
|
debugger; |
|
|
|
return; |
|
|
|
} |
|
|
|
} else { |
|
|
|
msgOrFn = msg; |
|
|
|
} |
|
|
|
this._pendingIpcNotifications.set(type, msgOrFn); |
|
|
|
} |
|
|
|
|
|
|
|
private sendPendingIpcNotifications() { |
|
|
|
if (this._pendingIpcNotifications.size === 0) return; |
|
|
|
|
|
|
|
const ipcs = new Map(this._pendingIpcNotifications); |
|
|
|
this._pendingIpcNotifications.clear(); |
|
|
|
for (const msgOrFn of ipcs.values()) { |
|
|
|
if (typeof msgOrFn === 'function') { |
|
|
|
void msgOrFn(); |
|
|
|
} else { |
|
|
|
void this.host.postMessage(msgOrFn); |
|
|
|
} |
|
|
|
} |
|
|
|
return this.host.notify(DidChangeNotificationType, { state: await this.getState() }); |
|
|
|
} |
|
|
|
|
|
|
|
private ensureRepositorySubscriptions(force?: boolean) { |
|
|
|