From 97bb1947bb98ae699a0ceaa6207f3bb9b6480c05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Collonval?= Date: Wed, 23 Mar 2022 08:51:04 +0100 Subject: [PATCH 1/2] Branch list is not updated after a branch is deleted Fixes #833 --- src/components/BranchMenu.tsx | 4 ++-- src/components/GitPanel.tsx | 16 ++++++++++++---- src/model.ts | 24 ++++++++++++++++++++++-- 3 files changed, 36 insertions(+), 8 deletions(-) diff --git a/src/components/BranchMenu.tsx b/src/components/BranchMenu.tsx index 037dfff7d..d2cffe76d 100644 --- a/src/components/BranchMenu.tsx +++ b/src/components/BranchMenu.tsx @@ -284,9 +284,9 @@ export class BranchMenu extends React.Component< className={hiddenButtonStyle} icon={trashIcon} title={this.props.trans.__('Delete this branch locally')} - onClick={(event: React.MouseEvent) => { + onClick={async (event: React.MouseEvent) => { event.stopPropagation(); - this._onDeleteBranch(branch.name); + await this._onDeleteBranch(branch.name); }} /> { nCommitsBehind: model.status.behind }); }, this); + model.branchesChanged.connect(async () => { + await this.refreshBranches(); + }, this); model.headChanged.connect(async () => { - await this.refreshBranch(); + await this.refreshCurrentBranch(); if (this.state.tab === 1) { this.refreshHistory(); } @@ -215,11 +218,16 @@ export class GitPanel extends React.Component { Signal.clearData(this); } - refreshBranch = async (): Promise => { + refreshBranches = async (): Promise => { + this.setState({ + branches: this.props.model.branches + }); + }; + + refreshCurrentBranch = async (): Promise => { const { currentBranch } = this.props.model; this.setState({ - branches: this.props.model.branches, currentBranch: currentBranch ? currentBranch.name : 'master' }); }; @@ -246,7 +254,7 @@ export class GitPanel extends React.Component { */ refreshView = async (): Promise => { if (this.props.model.pathRepository !== null) { - await this.refreshBranch(); + await this.refreshBranches(); await this.refreshHistory(); } }; diff --git a/src/model.ts b/src/model.ts index b415e4f7e..90f610e7b 100644 --- a/src/model.ts +++ b/src/model.ts @@ -2,7 +2,7 @@ import { IChangedArgs, PathExt, URLExt } from '@jupyterlab/coreutils'; import { IDocumentManager } from '@jupyterlab/docmanager'; import { DocumentRegistry } from '@jupyterlab/docregistry'; import { ISettingRegistry } from '@jupyterlab/settingregistry'; -import { JSONObject } from '@lumino/coreutils'; +import { JSONExt, JSONObject } from '@lumino/coreutils'; import { Poll } from '@lumino/polling'; import { ISignal, Signal } from '@lumino/signaling'; import { requestAPI } from './git'; @@ -206,6 +206,13 @@ export class GitExtension implements IGitExtension { return this._status; } + /** + * A signal emitted when the branches of the Git repository changes. + */ + get branchesChanged(): ISignal { + return this._branchesChanged; + } + /** * A signal emitted when the `HEAD` of the Git repository changes. */ @@ -912,7 +919,12 @@ export class GitExtension implements IGitExtension { this._currentBranch.top_commit !== data.current_branch.top_commit; } - this._branches = data.branches; + const branchesChanged = !JSONExt.deepEqual( + this._branches as any, + (data.branches ?? []) as any + ); + + this._branches = data.branches ?? []; this._currentBranch = data.current_branch; if (this._currentBranch) { // Set up the marker obj for the current (valid) repo/branch combination @@ -921,6 +933,9 @@ export class GitExtension implements IGitExtension { if (headChanged) { this._headChanged.emit(); } + if (branchesChanged) { + this._branchesChanged.emit(); + } // Start fetch remotes if the repository has remote branches const hasRemote = this._branches.some(branch => branch.is_remote_branch); @@ -930,6 +945,7 @@ export class GitExtension implements IGitExtension { this._fetchPoll.stop(); } } catch (error) { + const branchesChanged = this._branches.length > 0; const headChanged = this._currentBranch !== null; this._branches = []; this._currentBranch = null; @@ -937,6 +953,9 @@ export class GitExtension implements IGitExtension { if (headChanged) { this._headChanged.emit(); } + if (branchesChanged) { + this._branchesChanged.emit(); + } if (!(error instanceof Git.NotInRepository)) { throw error; @@ -1610,6 +1629,7 @@ export class GitExtension implements IGitExtension { private _selectedHistoryFile: Git.IStatusFile | null = null; private _hasDirtyStagedFiles = false; + private _branchesChanged = new Signal(this); private _headChanged = new Signal(this); private _markChanged = new Signal(this); private _selectedHistoryFileChanged = new Signal< From 39cbb8d92465fa02600190e8c63e2b4844279145 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Collonval?= Date: Wed, 23 Mar 2022 09:08:44 +0100 Subject: [PATCH 2/2] Fix unit test and extend interface --- src/tokens.ts | 5 +++++ tests/test-components/GitPanel.spec.tsx | 3 +++ 2 files changed, 8 insertions(+) diff --git a/src/tokens.ts b/src/tokens.ts index 8c03c2669..0ac781bd0 100644 --- a/src/tokens.ts +++ b/src/tokens.ts @@ -24,6 +24,11 @@ export interface IGitExtension extends IDisposable { */ currentBranch: Git.IBranch; + /** + * A signal emitted when the branches of the Git repository changes. + */ + readonly branchesChanged: ISignal; + /** * A signal emitted when the `HEAD` of the Git repository changes. */ diff --git a/tests/test-components/GitPanel.spec.tsx b/tests/test-components/GitPanel.spec.tsx index 4ce65f821..51aaa3d49 100644 --- a/tests/test-components/GitPanel.spec.tsx +++ b/tests/test-components/GitPanel.spec.tsx @@ -233,6 +233,9 @@ describe('GitPanel', () => { } as any; props.model = { branches: [], + branchesChanged: { + connect: jest.fn() + }, headChanged: { connect: jest.fn() },