Browse Source

Addition of Work In Progress row (#2154)

* Push in a wip node when repo status detects changes


Subscribe to repo file system changes


Start a separate handler area for selecting WIP node


Choose 'uncommitted changes' for commit details when selecting WIP row


Only add row if no cursor


Send workdir stats instead (component will render the wip node)


Fix spacing


Fix error after rebase

* Fix defaults
main
Ramin Tadayon 2 years ago
committed by GitHub
parent
commit
c3998f7111
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 94 additions and 4 deletions
  1. +70
    -4
      src/plus/webviews/graph/graphWebview.ts
  2. +11
    -0
      src/plus/webviews/graph/protocol.ts
  3. +5
    -0
      src/webviews/apps/plus/graph/GraphWrapper.tsx
  4. +8
    -0
      src/webviews/apps/plus/graph/graph.tsx

+ 70
- 4
src/plus/webviews/graph/graphWebview.ts View File

@ -1,13 +1,20 @@
import type {
ColorTheme,
ConfigurationChangeEvent,
Disposable,
Event,
StatusBarItem,
WebviewOptions,
WebviewPanelOptions,
} from 'vscode';
import { CancellationTokenSource, EventEmitter, MarkdownString, StatusBarAlignment, ViewColumn, window } from 'vscode';
import {
CancellationTokenSource,
Disposable,
EventEmitter,
MarkdownString,
StatusBarAlignment,
ViewColumn,
window,
} from 'vscode';
import type { CreatePullRequestActionContext } from '../../../api/gitlens';
import { getAvatarUri } from '../../../avatars';
import type {
@ -33,8 +40,9 @@ import type {
GitTagReference,
} from '../../../git/models/reference';
import { GitReference, GitRevision } from '../../../git/models/reference';
import type { Repository, RepositoryChangeEvent } from '../../../git/models/repository';
import type { Repository, RepositoryChangeEvent, RepositoryFileSystemChangeEvent } from '../../../git/models/repository';
import { RepositoryChange, RepositoryChangeComparisonMode } from '../../../git/models/repository';
import type { GitStatus } from '../../../git/models/status';
import type { GitSearch } from '../../../git/search';
import { getSearchQueryComparisonKey } from '../../../git/search';
import { executeActionCommand, executeCommand, executeCoreGitCommand, registerCommand } from '../../../system/command';
@ -68,6 +76,7 @@ import type {
GraphColumnsSettings,
GraphComponentConfig,
GraphRepository,
GraphWorkDirStats,
SearchCommitsParams,
SearchOpenInViewParams,
State,
@ -83,6 +92,7 @@ import {
DidChangeNotificationType,
DidChangeSelectionNotificationType,
DidChangeSubscriptionNotificationType,
DidChangeWorkDirStatsNotificationType,
DidEnsureCommitNotificationType,
DidSearchCommitsNotificationType,
DismissBannerCommandType,
@ -133,7 +143,11 @@ export class GraphWebview extends WebviewBase {
this.resetRepositoryState();
if (value != null) {
this._repositoryEventsDisposable = value.onDidChange(this.onRepositoryChanged, this);
this._repositoryEventsDisposable = Disposable.from(
value.onDidChange(this.onRepositoryChanged, this),
value.startWatchingFileSystem(),
value.onDidChangeFileSystem(this.onRepositoryFileSystemChanged, this),
);
}
this.updateState();
@ -619,6 +633,11 @@ export class GraphWebview extends WebviewBase {
});
}
private onRepositoryFileSystemChanged(e: RepositoryFileSystemChangeEvent) {
if (!(e.repository?.path === this.repository?.path)) return;
this.updateWorkDirStats();
}
private onRepositorySelectionChanged(e: UpdateSelectedRepositoryParams) {
this.repository = this.container.git.getRepository(e.path);
}
@ -633,6 +652,8 @@ export class GraphWebview extends WebviewBase {
if (item.type === GitGraphRowType.Stash) {
const stash = await this.repository?.getStash();
commit = stash?.commits.get(item.id);
} else if (item.type === GitGraphRowType.Working) {
commit = await this.repository?.getCommit('0000000000000000000000000000000000000000');
} else {
commit = await this.repository?.getCommit(item?.id);
}
@ -683,6 +704,24 @@ export class GraphWebview extends WebviewBase {
this._notifyDidChangeAvatarsDebounced();
}
private _notifyDidChangeWorkDirStatsDebounced: Deferrable<() => void> | undefined = undefined;
@debug()
private updateWorkDirStats(immediate: boolean = false) {
if (!this.isReady || !this.visible) return;
if (immediate) {
void this.notifyDidChangeWorkDirStats();
return;
}
if (this._notifyDidChangeWorkDirStatsDebounced == null) {
this._notifyDidChangeWorkDirStatsDebounced = debounce(this.notifyDidChangeWorkDirStats.bind(this), 500);
}
this._notifyDidChangeWorkDirStatsDebounced();
}
@debug()
private async notifyDidChangeAvatars() {
if (this._graph == null) return;
@ -740,6 +779,15 @@ export class GraphWebview extends WebviewBase {
}
@debug()
private async notifyDidChangeWorkDirStats() {
if (!this.isReady || !this.visible) return false;
return this.notify(DidChangeWorkDirStatsNotificationType, {
workDirStats: await this.getWorkDirStats() ?? {added: 0, deleted: 0, modified: 0 },
});
}
@debug()
private async notifyDidChangeSelection() {
if (!this.isReady || !this.visible) {
this.addPendingIpcNotification(DidChangeSelectionNotificationType);
@ -890,6 +938,23 @@ export class GraphWebview extends WebviewBase {
return config;
}
private async getWorkDirStats(): Promise<GraphWorkDirStats | undefined> {
if (this.container.git.repositoryCount === 0) return undefined;
if (this.repository == null) {
this.repository = this.container.git.getBestRepositoryOrFirst();
if (this.repository == null) return undefined;
}
const status: GitStatus | undefined = await this.container.git.getStatusForRepo(this.repository.path);
const workingTreeStatus = status?.getDiffStatus();
return {
added: workingTreeStatus?.added ?? 0,
deleted: workingTreeStatus?.deleted ?? 0,
modified: workingTreeStatus?.changed ?? 0,
};
}
private async getGraphAccess() {
let access = await this.container.git.access(PlusFeatures.Graph, this.repository?.path);
this._etagSubscription = this.container.subscription.etag;
@ -981,6 +1046,7 @@ export class GraphWebview extends WebviewBase {
header: this.getColumnHeaderContext(columns),
},
nonce: this.cspNonce,
dirStats: await this.getWorkDirStats() ?? {added: 0, deleted: 0, modified: 0 },
};
}

+ 11
- 0
src/plus/webviews/graph/protocol.ts View File

@ -4,6 +4,7 @@ import type {
GraphRow,
GraphZoneType,
Remote,
WorkDirStats,
} from '@gitkraken/gitkraken-components';
import type { DateStyle } from '../../../config';
import type { RepositoryVisibility } from '../../../git/gitProvider';
@ -32,12 +33,15 @@ export interface State {
nonce?: string;
previewBanner?: boolean;
trialBanner?: boolean;
dirStats?: WorkDirStats;
// Props below are computed in the webview (not passed)
mixedColumnColors?: Record<string, string>;
searchResults?: DidSearchCommitsParams['results'];
}
export type GraphWorkDirStats = WorkDirStats;
export interface GraphPaging {
startingCursor?: string;
hasMore: boolean;
@ -215,3 +219,10 @@ export const DidSearchCommitsNotificationType = new IpcNotificationType
'graph/didSearch',
true,
);
export interface DidChangeWorkDirStatsParams {
workDirStats: WorkDirStats;
}
export const DidChangeWorkDirStatsNotificationType = new IpcNotificationType<DidChangeWorkDirStatsParams>(
'graph/workDirStats/didChange',
);

+ 5
- 0
src/webviews/apps/plus/graph/GraphWrapper.tsx View File

@ -173,6 +173,7 @@ export function GraphWrapper({
searchResults,
trialBanner = true,
onDismissBanner,
dirStats = { added: 0, modified: 0, deleted: 0 },
}: GraphWrapperProps) {
const [graphRows, setGraphRows] = useState(rows);
const [graphAvatars, setAvatars] = useState(avatars);
@ -210,6 +211,8 @@ export function GraphWrapper({
);
const [hasMoreSearchResults, setHasMoreSearchResults] = useState(searchResults?.paging?.hasMore ?? false);
const [selectedRow, setSelectedRow] = useState<GraphRow | undefined>(undefined);
// workdir state
const [workDirStats, setWorkDirStats] = useState(dirStats);
useEffect(() => {
if (graphRows.length === 0) {
@ -403,6 +406,7 @@ export function GraphWrapper({
setIsLoading(state.loading);
setSearchResultIds(state.searchResults != null ? Object.entries(state.searchResults.ids) : undefined);
setHasMoreSearchResults(state.searchResults?.paging?.hasMore ?? false);
setWorkDirStats(state.dirStats ?? { added: 0, modified: 0, deleted: 0 });
}
useEffect(() => subscriber?.(transformData), []);
@ -679,6 +683,7 @@ export function GraphWrapper({
themeOpacityFactor={styleProps.themeOpacityFactor}
useAuthorInitialsForAvatars={!graphConfig?.avatars}
width={mainWidth}
workDirStats={workDirStats}
/>
)}
</>

+ 8
- 0
src/webviews/apps/plus/graph/graph.tsx View File

@ -20,6 +20,7 @@ import {
DidChangeNotificationType,
DidChangeSelectionNotificationType,
DidChangeSubscriptionNotificationType,
DidChangeWorkDirStatsNotificationType,
DidEnsureCommitNotificationType,
DidSearchCommitsNotificationType,
DismissBannerCommandType,
@ -251,6 +252,13 @@ export class GraphApp extends App {
});
break;
case DidChangeWorkDirStatsNotificationType.method:
onIpc(DidChangeWorkDirStatsNotificationType, msg, params => {
this.setState({ ...this.state, dirStats: params.workDirStats });
this.refresh(this.state);
});
break;
default:
super.onMessageReceived?.(e);
}

Loading…
Cancel
Save