From 247259253339550d2fe3a95533194092292bef7c Mon Sep 17 00:00:00 2001 From: Andrew Fulton Date: Mon, 7 Jun 2021 12:19:56 -0400 Subject: [PATCH 01/29] adds Remote changed section to git panel file list --- src/components/FileList.tsx | 49 +++++++++++++++++++++++++++++++++++-- src/tokens.ts | 1 + 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/src/components/FileList.tsx b/src/components/FileList.tsx index bb5885b4d..a9d243e30 100644 --- a/src/components/FileList.tsx +++ b/src/components/FileList.tsx @@ -74,6 +74,12 @@ export const CONTEXT_COMMANDS: ContextCommands = { ContextCommandIDs.gitFileOpen, ContextCommandIDs.gitFileUnstage, ContextCommandIDs.gitFileDiff + ], + 'remote-changed': [ + ContextCommandIDs.gitFileOpen, + ContextCommandIDs.gitFileUnstage, + ContextCommandIDs.gitFileDiff + ] }; @@ -83,6 +89,11 @@ const SIMPLE_CONTEXT_COMMANDS: ContextCommands = { ContextCommandIDs.gitFileDiscard, ContextCommandIDs.gitFileDiff ], + 'remote-changed': [ + ContextCommandIDs.gitFileOpen, + ContextCommandIDs.gitFileUnstage, + ContextCommandIDs.gitFileDiff + ], staged: [ ContextCommandIDs.gitFileOpen, ContextCommandIDs.gitFileDiscard, @@ -254,7 +265,9 @@ export class FileList extends React.Component { * Render the modified files */ render(): JSX.Element { + console.log('rendering fileList'); if (this.props.settings.composite['simpleStaging']) { + console.log('rendering simpleStaging'); return (
@@ -266,6 +279,7 @@ export class FileList extends React.Component { const stagedFiles: Git.IStatusFile[] = []; const unstagedFiles: Git.IStatusFile[] = []; const untrackedFiles: Git.IStatusFile[] = []; + const remoteChangedFiles: Git.IStatusFile[] = []; this.props.files.forEach(file => { switch (file.status) { @@ -288,6 +302,9 @@ export class FileList extends React.Component { status: 'unstaged' }); break; + case 'remote-changed': + remoteChangedFiles.push(file); + break default: break; @@ -305,6 +322,7 @@ export class FileList extends React.Component { {this._renderStaged(stagedFiles, height)} {this._renderChanged(unstagedFiles, height)} {this._renderUntracked(untrackedFiles, height)} + {this._renderRemoteChanged(remoteChangedFiles, height)} )} @@ -580,6 +598,33 @@ export class FileList extends React.Component { ); }; + /** + * Render the untracked files list. + * + * @param files Untracked files + * @param height Height of the HTML element + */ + private _renderRemoteChanged(files: Git.IStatusFile[], height: number) { + return ( + void 0} + /> + } + collapsible + heading={this.props.trans.__('Remote Changes')} + height={height} + files={files} + rowRenderer={this._renderUntrackedRow} + /> + ); + } + /** * Render the untracked files list. * @@ -595,7 +640,7 @@ export class FileList extends React.Component { disabled={files.length === 0} icon={addIcon} title={this.props.trans.__('Track all untracked files')} - onClick={this.addAllUntrackedFiles} + onClick={this.addAllUntrackedFiles} /> } collapsible @@ -605,7 +650,7 @@ export class FileList extends React.Component { rowRenderer={this._renderUntrackedRow} /> ); - } + } /** * Render a modified file in simple mode. diff --git a/src/tokens.ts b/src/tokens.ts index 5b6902fc7..ce11827eb 100644 --- a/src/tokens.ts +++ b/src/tokens.ts @@ -863,6 +863,7 @@ export namespace Git { | 'staged' | 'unstaged' | 'partially-staged' + | 'remote-changed' | null; export interface ITagResult { From 03aaf77b82d4e707955b3919d8ddfb0d21e45a27 Mon Sep 17 00:00:00 2001 From: Andrew Fulton Date: Sat, 12 Jun 2021 12:37:14 -0400 Subject: [PATCH 02/29] adds code to add remote upstream changes to files list to report status --- src/model.ts | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/src/model.ts b/src/model.ts index 8e4c4b2f7..ff41f9ae6 100644 --- a/src/model.ts +++ b/src/model.ts @@ -844,19 +844,35 @@ export class GitExtension implements IGitExtension { ); } ); - - this._setStatus({ - branch: data.branch || null, - remote: data.remote || null, - ahead: data.ahead || 0, - behind: data.behind || 0, - files: data.files?.map(file => { + let files = data.files?.map(file => { return { ...file, status: decodeStage(file.x, file.y), type: this._resolveFileType(file.to) }; - }) + }); + // if a file is changed on remote add it to list of files with appropriate status. + let remoteChangedFiles: null | string[] = null; + if (data.remote && data.behind > 0) { + remoteChangedFiles = (await this._changedFiles('WORKING', data.remote)).files; + remoteChangedFiles?.forEach( (element) => { + files.push({ + status: "remote-changed", + type: this._resolveFileType(element), + x: "?", + y: "?", + to: element, + from: "?", + is_binary: false, + }) + }); + }; + this._setStatus({ + branch: data.branch || null, + remote: data.remote || null, + ahead: data.ahead || 0, + behind: data.behind || 0, + files: files }); } catch (err) { // TODO we should notify the user From 2e58a6518b45290a261edbdcd36d6d8169e1639a Mon Sep 17 00:00:00 2001 From: Andrew Fulton Date: Wed, 16 Jun 2021 11:44:49 -0400 Subject: [PATCH 03/29] changes status symbol for remote changes from U to B for behind remote --- src/components/FileItem.tsx | 1 + src/components/FileList.tsx | 90 ++++++++++++++++++++++++++++++------- src/model.ts | 2 +- 3 files changed, 75 insertions(+), 18 deletions(-) diff --git a/src/components/FileItem.tsx b/src/components/FileItem.tsx index eb0cd74f2..f1259bffa 100644 --- a/src/components/FileItem.tsx +++ b/src/components/FileItem.tsx @@ -22,6 +22,7 @@ export const STATUS_CODES = { R: 'Renamed', C: 'Copied', U: 'Updated', + B: 'Behind', '?': 'Untracked', '!': 'Ignored' }; diff --git a/src/components/FileList.tsx b/src/components/FileList.tsx index a9d243e30..3bfc6f56a 100644 --- a/src/components/FileList.tsx +++ b/src/components/FileList.tsx @@ -77,8 +77,8 @@ export const CONTEXT_COMMANDS: ContextCommands = { ], 'remote-changed': [ ContextCommandIDs.gitFileOpen, - ContextCommandIDs.gitFileUnstage, - ContextCommandIDs.gitFileDiff + // ContextCommandIDs.gitFileDiff // save this for later date. + // need to change diff to diff with upstream changes ] }; @@ -91,7 +91,6 @@ const SIMPLE_CONTEXT_COMMANDS: ContextCommands = { ], 'remote-changed': [ ContextCommandIDs.gitFileOpen, - ContextCommandIDs.gitFileUnstage, ContextCommandIDs.gitFileDiff ], staged: [ @@ -257,6 +256,11 @@ export class FileList extends React.Component { this.setState({ selectedFile: file }); }; + pullFromRemote = async (event: React.MouseEvent): Promise => { + event.stopPropagation(); + await this.props.model.pull(); + } + get markedFiles(): Git.IStatusFile[] { return this.props.files.filter(file => this.props.model.getMark(file.to)); } @@ -604,7 +608,7 @@ export class FileList extends React.Component { * @param files Untracked files * @param height Height of the HTML element */ - private _renderRemoteChanged(files: Git.IStatusFile[], height: number) { + private _renderUntracked(files: Git.IStatusFile[], height: number) { return ( { className={hiddenButtonStyle} disabled={files.length === 0} icon={addIcon} - title={this.props.trans.__('Track files changed on remote branch')} - onClick={()=>void 0} + title={this.props.trans.__('Track all untracked files')} + onClick={this.addAllUntrackedFiles} /> } collapsible - heading={this.props.trans.__('Remote Changes')} + heading={this.props.trans.__('Untracked')} height={height} files={files} rowRenderer={this._renderUntrackedRow} /> ); - } + } + /** - * Render the untracked files list. + * Render a untracked file. + * + * Note: This is actually a React.FunctionComponent but defined as + * a private method as it needs access to FileList properties. + * + * @param rowProps Row properties + */ + private _renderRemoteChangedRow = ( + rowProps: ListChildComponentProps + ): JSX.Element => { + const doubleClickDiff = this.props.settings.get('doubleClickDiff') + .composite as boolean; + const { data, index, style } = rowProps; + const file = data[index] as Git.IStatusFile; + // const diffButton = this._createDiffButton(file); + return ( + + {/** diffButton */} + { + this.props.commands.execute(ContextCommandIDs.gitFileOpen, { + files: [file] + } as CommandArguments.IGitContextAction as any); + }} + /> + + } + file={file} + contextMenu={this.openContextMenu} + model={this.props.model} + onDoubleClick={() => { + if (!doubleClickDiff) { + this.props.commands.execute(ContextCommandIDs.gitFileOpen, { + files: [file] + } as CommandArguments.IGitContextAction as any); + } + }} + selected={this._isSelectedFile(file)} + selectFile={this.updateSelectedFile} + style={style} + /> + ); + }; + + /** + * Render the a file that has changed on remote to files list. * * @param files Untracked files * @param height Height of the HTML element */ - private _renderUntracked(files: Git.IStatusFile[], height: number) { + private _renderRemoteChanged(files: Git.IStatusFile[], height: number) { return ( } collapsible - heading={this.props.trans.__('Untracked')} + heading={this.props.trans.__('Remote Changes')} height={height} files={files} - rowRenderer={this._renderUntrackedRow} + rowRenderer={this._renderRemoteChangedRow} /> ); - } + } /** * Render a modified file in simple mode. diff --git a/src/model.ts b/src/model.ts index ff41f9ae6..aab9cb2a0 100644 --- a/src/model.ts +++ b/src/model.ts @@ -860,7 +860,7 @@ export class GitExtension implements IGitExtension { status: "remote-changed", type: this._resolveFileType(element), x: "?", - y: "?", + y: "B", to: element, from: "?", is_binary: false, From e3f40080f6bfe3c64ba1720e12f089caf6db46f5 Mon Sep 17 00:00:00 2001 From: Andrew Fulton Date: Wed, 15 Sep 2021 20:29:59 -0400 Subject: [PATCH 04/29] moves remote changed files information from model.status.files and adds dialog notification for remote changed files that are opened --- src/components/GitPanel.tsx | 15 +++++--- src/model.ts | 76 +++++++++++++++++++++++++++++-------- src/tokens.ts | 6 +++ 3 files changed, 76 insertions(+), 21 deletions(-) diff --git a/src/components/GitPanel.tsx b/src/components/GitPanel.tsx index cf769c67c..5beb8c83b 100644 --- a/src/components/GitPanel.tsx +++ b/src/components/GitPanel.tsx @@ -86,6 +86,8 @@ export interface IGitPanelState { */ files: Git.IStatusFile[]; + remoteChangedFiles: Git.IStatusFile[]; + /** * Number of commits ahead */ @@ -125,6 +127,7 @@ export class GitPanel extends React.Component { branches: branches, currentBranch: currentBranch ? currentBranch.name : 'master', files: [], + remoteChangedFiles: [], nCommitsAhead: 0, nCommitsBehind: 0, pastCommits: [], @@ -145,9 +148,11 @@ export class GitPanel extends React.Component { }); this.refreshView(); }, this); - model.statusChanged.connect(() => { + model.statusChanged.connect(async () => { + let remotechangedFiles = await model.remoteChangedFiles(); this.setState({ files: model.status.files, + remoteChangedFiles: remotechangedFiles, nCommitsAhead: model.status.ahead, nCommitsBehind: model.status.behind }); @@ -564,10 +569,10 @@ export class GitPanel extends React.Component { * List of sorted modified files. */ private get _sortedFiles(): Git.IStatusFile[] { - const { files } = this.state; - - files.sort((a, b) => a.to.localeCompare(b.to)); - return files; + const { files, remoteChangedFiles } = this.state; + let sfiles = files.concat(remoteChangedFiles) + sfiles.sort((a, b) => a.to.localeCompare(b.to)); + return sfiles; } private _previousRepoPath: string = null; diff --git a/src/model.ts b/src/model.ts index aab9cb2a0..0e97a28aa 100644 --- a/src/model.ts +++ b/src/model.ts @@ -1,4 +1,5 @@ import { IChangedArgs, PathExt, URLExt } from '@jupyterlab/coreutils'; +import { showDialog, Dialog } from '@jupyterlab/apputils'; import { IDocumentManager } from '@jupyterlab/docmanager'; import { DocumentRegistry } from '@jupyterlab/docregistry'; import { ISettingRegistry } from '@jupyterlab/settingregistry'; @@ -790,6 +791,7 @@ export class GitExtension implements IGitExtension { this._setMarker(this.pathRepository, this._currentBranch.name); } if (headChanged) { + this._changeUpstreamNotified = []; this._headChanged.emit(); } @@ -806,6 +808,7 @@ export class GitExtension implements IGitExtension { this._currentBranch = null; this._fetchPoll.stop(); if (headChanged) { + this._changeUpstreamNotified = []; this._headChanged.emit(); } @@ -851,22 +854,6 @@ export class GitExtension implements IGitExtension { type: this._resolveFileType(file.to) }; }); - // if a file is changed on remote add it to list of files with appropriate status. - let remoteChangedFiles: null | string[] = null; - if (data.remote && data.behind > 0) { - remoteChangedFiles = (await this._changedFiles('WORKING', data.remote)).files; - remoteChangedFiles?.forEach( (element) => { - files.push({ - status: "remote-changed", - type: this._resolveFileType(element), - x: "?", - y: "B", - to: element, - from: "?", - is_binary: false, - }) - }); - }; this._setStatus({ branch: data.branch || null, remote: data.remote || null, @@ -882,6 +869,62 @@ export class GitExtension implements IGitExtension { } } + /** + * Collects files that have changed on the remote branch. If there is a + * changed file that is open, a Dialog is displayed to notify the user + * + */ + async remoteChangedFiles(): Promise { + // if a file is changed on remote add it to list of files with appropriate status. + let remoteChangedFiles: null | string[] = null; + let files: Git.IStatusFile[] = []; + if (this.status.remote && this.status.behind > 0) { + remoteChangedFiles = (await this._changedFiles('WORKING', this.status.remote)).files; + remoteChangedFiles?.forEach( (element) => { + files.push({ + status: "remote-changed", + type: this._resolveFileType(element), + x: "?", + y: "B", + to: element, + from: "?", + is_binary: false, + }) + }); + }; + for (var val of files) { + let docWidget = this._docmanager.findWidget( + this.getRelativeFilePath(val.to)); + let notifiedIndex = (this._changeUpstreamNotified.findIndex( + notified => + notified.from === val.from && + notified.to === val.to && + notified.x === val.x && + notified.y === val.y + )) + if (docWidget !== undefined && docWidget.isAttached) { + // notify if the user hasn't been notified yet + if (notifiedIndex === -1) { + showDialog({ + title: `${val.to} is out of date with your remote branch: ${this._currentBranch.upstream}`, + body: `You may want to pull from ${this._currentBranch.upstream} before editing this file.`, + buttons: [ + Dialog.okButton({ label: 'OK' }) + ] + }) + // add the file to the notified array + this._changeUpstreamNotified.push(val) + } + } else { + // remove from notified array if document is closed + if (notifiedIndex > -1) { + this._changeUpstreamNotified.splice(notifiedIndex, 1) + } + } + } + return files + } + /** * Move files from the "staged" to the "unstaged" area. * @@ -1378,6 +1421,7 @@ export class GitExtension implements IGitExtension { private _standbyCondition: () => boolean = () => false; private _statusPoll: Poll; private _taskHandler: TaskHandler; + private _changeUpstreamNotified: Git.IStatusFile[] = []; private _headChanged = new Signal(this); private _markChanged = new Signal(this); diff --git a/src/tokens.ts b/src/tokens.ts index ce11827eb..1d5e33de0 100644 --- a/src/tokens.ts +++ b/src/tokens.ts @@ -352,6 +352,12 @@ export interface IGitExtension extends IDisposable { */ refreshStatus(): Promise; + /** + * gets a list of files that have changed in the remote branch, notifies + * the user with a Dialog if an open file has a remote changed. + */ + remoteChangedFiles(): Promise; + /** * Register a new diff provider for specified file types * From 2f8e64d9537c6a066ad5b3de798588d33f607cf4 Mon Sep 17 00:00:00 2001 From: Andrew Fulton Date: Wed, 15 Sep 2021 20:35:46 -0400 Subject: [PATCH 05/29] linting --- src/components/FileList.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/components/FileList.tsx b/src/components/FileList.tsx index 3bfc6f56a..4b3b8e570 100644 --- a/src/components/FileList.tsx +++ b/src/components/FileList.tsx @@ -269,9 +269,7 @@ export class FileList extends React.Component { * Render the modified files */ render(): JSX.Element { - console.log('rendering fileList'); if (this.props.settings.composite['simpleStaging']) { - console.log('rendering simpleStaging'); return (
@@ -617,7 +615,7 @@ export class FileList extends React.Component { disabled={files.length === 0} icon={addIcon} title={this.props.trans.__('Track all untracked files')} - onClick={this.addAllUntrackedFiles} + onClick={this.addAllUntrackedFiles} /> } collapsible From eb860f14244e10ee3a99034bb0f1b35ad700cbb0 Mon Sep 17 00:00:00 2001 From: Andrew Fulton Date: Fri, 17 Sep 2021 16:29:31 -0400 Subject: [PATCH 06/29] seperates pulling from remote branch from notifying if a file has changed on remote --- src/components/FileList.tsx | 8 ++-- src/model.ts | 83 ++++++++++++++++++++++--------------- src/tokens.ts | 8 +++- 3 files changed, 59 insertions(+), 40 deletions(-) diff --git a/src/components/FileList.tsx b/src/components/FileList.tsx index b2a27c943..f0b9cae23 100644 --- a/src/components/FileList.tsx +++ b/src/components/FileList.tsx @@ -58,6 +58,9 @@ export const CONTEXT_COMMANDS: ContextCommands = { ContextCommandIDs.gitFileDiff, ContextCommandIDs.gitFileHistory ], + 'remote-changed': [ + ContextCommandIDs.gitFileOpen, + ], unstaged: [ ContextCommandIDs.gitFileOpen, ContextCommandIDs.gitFileStage, @@ -80,10 +83,7 @@ export const CONTEXT_COMMANDS: ContextCommands = { ContextCommandIDs.gitFileHistory ], unmodified: [ContextCommandIDs.gitFileHistory], - unmerged: [ContextCommandIDs.gitFileDiff], - 'remote-changed': [ - ContextCommandIDs.gitFileOpen, - ] + unmerged: [ContextCommandIDs.gitFileDiff] }; const SIMPLE_CONTEXT_COMMANDS: ContextCommands = { diff --git a/src/model.ts b/src/model.ts index d4d949554..a367dbe1d 100644 --- a/src/model.ts +++ b/src/model.ts @@ -856,7 +856,6 @@ export class GitExtension implements IGitExtension { this._setMarker(this.pathRepository, this._currentBranch.name); } if (headChanged) { - this._changeUpstreamNotified = []; this._headChanged.emit(); } @@ -873,7 +872,6 @@ export class GitExtension implements IGitExtension { this._currentBranch = null; this._fetchPoll.stop(); if (headChanged) { - this._changeUpstreamNotified = []; this._headChanged.emit(); } @@ -935,18 +933,17 @@ export class GitExtension implements IGitExtension { } /** - * Collects files that have changed on the remote branch. If there is a - * changed file that is open, a Dialog is displayed to notify the user + * Collects files that have changed on the remote branch. * */ async remoteChangedFiles(): Promise { // if a file is changed on remote add it to list of files with appropriate status. + this._remoteChangedFiles = []; let remoteChangedFiles: null | string[] = null; - let files: Git.IStatusFile[] = []; if (this.status.remote && this.status.behind > 0) { remoteChangedFiles = (await this._changedFiles('WORKING', this.status.remote)).files; remoteChangedFiles?.forEach( (element) => { - files.push({ + this._remoteChangedFiles.push({ status: "remote-changed", type: this._resolveFileType(element), x: "?", @@ -957,37 +954,53 @@ export class GitExtension implements IGitExtension { }) }); }; - for (var val of files) { - let docWidget = this._docmanager.findWidget( - this.getRelativeFilePath(val.to)); - let notifiedIndex = (this._changeUpstreamNotified.findIndex( - notified => - notified.from === val.from && - notified.to === val.to && - notified.x === val.x && - notified.y === val.y - )) - if (docWidget !== undefined && docWidget.isAttached) { - // notify if the user hasn't been notified yet - if (notifiedIndex === -1) { - showDialog({ - title: `${val.to} is out of date with your remote branch: ${this._currentBranch.upstream}`, - body: `You may want to pull from ${this._currentBranch.upstream} before editing this file.`, - buttons: [ - Dialog.okButton({ label: 'OK' }) - ] - }) - // add the file to the notified array - this._changeUpstreamNotified.push(val) - } - } else { - // remove from notified array if document is closed - if (notifiedIndex > -1) { - this._changeUpstreamNotified.splice(notifiedIndex, 1) + return this._remoteChangedFiles + } + + + /** + * Notifies user is a file that is attached has is behind changes in the remote branch with a pop-up Dialog + * + */ + async checkRemoteChangeNotified() { + if (this.status.remote && this.status.behind > 0) { + for (var val of this._remoteChangedFiles) { + let docWidget = this._docmanager.findWidget( + this.getRelativeFilePath(val.to)); + let notifiedIndex = (this._changeUpstreamNotified.findIndex( + notified => + notified.from === val.from && + notified.to === val.to && + notified.x === val.x && + notified.y === val.y + )) + if (docWidget !== undefined) { + if (docWidget.isAttached) { + + // notify if the user hasn't been notified yet + if (notifiedIndex === -1) { + showDialog({ + title: `${val.to} is out of date with your remote branch: ${this._currentBranch.upstream}`, + body: `You may want to pull from ${this._currentBranch.upstream} before editing this file.`, + buttons: [ + Dialog.okButton({ label: 'OK' }) + ] + }) + // add the file to the notified array + this._changeUpstreamNotified.push(val) + } + } + } else { + // remove from notified array if document is closed + if (notifiedIndex > -1) { + this._changeUpstreamNotified.splice(notifiedIndex, 1) + } } } + } else { + this._changeUpstreamNotified = []; + } } - return files } /** @@ -1426,6 +1439,7 @@ export class GitExtension implements IGitExtension { try { await this.refreshBranch(); await this.refreshStatus(); + await this.checkRemoteChangeNotified(); } catch (error) { console.error('Failed to refresh git status', error); } @@ -1486,6 +1500,7 @@ export class GitExtension implements IGitExtension { private _standbyCondition: () => boolean = () => false; private _statusPoll: Poll; private _taskHandler: TaskHandler; + private _remoteChangedFiles: Git.IStatusFile[] = []; private _changeUpstreamNotified: Git.IStatusFile[] = []; private _selectedHistoryFile: Git.IStatusFile | null = null; diff --git a/src/tokens.ts b/src/tokens.ts index a7f43eeca..66842ae88 100644 --- a/src/tokens.ts +++ b/src/tokens.ts @@ -366,11 +366,15 @@ export interface IGitExtension extends IDisposable { refreshStatus(): Promise; /** - * gets a list of files that have changed in the remote branch, notifies - * the user with a Dialog if an open file has a remote changed. + * gets a list of files that have changed in the remote branch */ remoteChangedFiles(): Promise; + /** + * Notifies user is a file that is attached has is behind changes in the remote branch with a pop-up Dialog + */ + checkRemoteChangeNotified(): void; + /** * Register a new diff provider for specified file types * From c3dfd0b702b71a27415b71ab2ac0777280e2ddae Mon Sep 17 00:00:00 2001 From: Andrew Fulton Date: Fri, 17 Sep 2021 16:48:21 -0400 Subject: [PATCH 07/29] fix bug --- src/model.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/model.ts b/src/model.ts index a367dbe1d..5e894fd26 100644 --- a/src/model.ts +++ b/src/model.ts @@ -998,8 +998,7 @@ export class GitExtension implements IGitExtension { } } } else { - this._changeUpstreamNotified = []; - } + this._changeUpstreamNotified = []; } } From 53870ffcffe62ad9798176a20bfce0dcbd133cfd Mon Sep 17 00:00:00 2001 From: Andrew Fulton Date: Fri, 17 Sep 2021 17:00:57 -0400 Subject: [PATCH 08/29] lint and prepare --- src/components/FileList.tsx | 13 +++----- src/components/GitPanel.tsx | 4 +-- src/model.ts | 63 ++++++++++++++++++------------------- src/tokens.ts | 2 +- 4 files changed, 39 insertions(+), 43 deletions(-) diff --git a/src/components/FileList.tsx b/src/components/FileList.tsx index f0b9cae23..5f12879f8 100644 --- a/src/components/FileList.tsx +++ b/src/components/FileList.tsx @@ -58,9 +58,7 @@ export const CONTEXT_COMMANDS: ContextCommands = { ContextCommandIDs.gitFileDiff, ContextCommandIDs.gitFileHistory ], - 'remote-changed': [ - ContextCommandIDs.gitFileOpen, - ], + 'remote-changed': [ContextCommandIDs.gitFileOpen], unstaged: [ ContextCommandIDs.gitFileOpen, ContextCommandIDs.gitFileStage, @@ -267,7 +265,7 @@ export class FileList extends React.Component { pullFromRemote = async (event: React.MouseEvent): Promise => { event.stopPropagation(); await this.props.model.pull(); - } + }; get markedFiles(): Git.IStatusFile[] { return this.props.files.filter(file => this.props.model.getMark(file.to)); @@ -680,8 +678,7 @@ export class FileList extends React.Component { rowRenderer={this._renderUntrackedRow} /> ); - } - + } /** * Render a untracked file. @@ -743,8 +740,8 @@ export class FileList extends React.Component { private _renderRemoteChanged(files: Git.IStatusFile[], height: number) { return ( { this.refreshView(); }, this); model.statusChanged.connect(async () => { - let remotechangedFiles = await model.remoteChangedFiles(); + const remotechangedFiles = await model.remoteChangedFiles(); this.setState({ files: model.status.files, remoteChangedFiles: remotechangedFiles, @@ -657,7 +657,7 @@ export class GitPanel extends React.Component { */ private get _sortedFiles(): Git.IStatusFile[] { const { files, remoteChangedFiles } = this.state; - let sfiles = files.concat(remoteChangedFiles) + const sfiles = files.concat(remoteChangedFiles); sfiles.sort((a, b) => a.to.localeCompare(b.to)); return sfiles; } diff --git a/src/model.ts b/src/model.ts index 5e894fd26..67bce9858 100644 --- a/src/model.ts +++ b/src/model.ts @@ -910,12 +910,12 @@ export class GitExtension implements IGitExtension { ); } ); - let files = data.files?.map(file => { - return { - ...file, - status: decodeStage(file.x, file.y), - type: this._resolveFileType(file.to) - }; + const files = data.files?.map(file => { + return { + ...file, + status: decodeStage(file.x, file.y), + type: this._resolveFileType(file.to) + }; }); this._setStatus({ branch: data.branch || null, @@ -941,64 +941,63 @@ export class GitExtension implements IGitExtension { this._remoteChangedFiles = []; let remoteChangedFiles: null | string[] = null; if (this.status.remote && this.status.behind > 0) { - remoteChangedFiles = (await this._changedFiles('WORKING', this.status.remote)).files; - remoteChangedFiles?.forEach( (element) => { + remoteChangedFiles = ( + await this._changedFiles('WORKING', this.status.remote) + ).files; + remoteChangedFiles?.forEach(element => { this._remoteChangedFiles.push({ - status: "remote-changed", + status: 'remote-changed', type: this._resolveFileType(element), - x: "?", - y: "B", + x: '?', + y: 'B', to: element, - from: "?", - is_binary: false, - }) + from: '?', + is_binary: false + }); }); - }; - return this._remoteChangedFiles + } + return this._remoteChangedFiles; } - /** * Notifies user is a file that is attached has is behind changes in the remote branch with a pop-up Dialog * */ - async checkRemoteChangeNotified() { + async checkRemoteChangeNotified(): Promise { if (this.status.remote && this.status.behind > 0) { - for (var val of this._remoteChangedFiles) { - let docWidget = this._docmanager.findWidget( - this.getRelativeFilePath(val.to)); - let notifiedIndex = (this._changeUpstreamNotified.findIndex( + for (const val of this._remoteChangedFiles) { + const docWidget = this._docmanager.findWidget( + this.getRelativeFilePath(val.to) + ); + const notifiedIndex = this._changeUpstreamNotified.findIndex( notified => notified.from === val.from && notified.to === val.to && notified.x === val.x && notified.y === val.y - )) + ); if (docWidget !== undefined) { if (docWidget.isAttached) { - // notify if the user hasn't been notified yet - if (notifiedIndex === -1) { + if (notifiedIndex === -1) { showDialog({ title: `${val.to} is out of date with your remote branch: ${this._currentBranch.upstream}`, body: `You may want to pull from ${this._currentBranch.upstream} before editing this file.`, - buttons: [ - Dialog.okButton({ label: 'OK' }) - ] - }) + buttons: [Dialog.okButton({ label: 'OK' })] + }); // add the file to the notified array - this._changeUpstreamNotified.push(val) + this._changeUpstreamNotified.push(val); } } } else { // remove from notified array if document is closed if (notifiedIndex > -1) { - this._changeUpstreamNotified.splice(notifiedIndex, 1) + this._changeUpstreamNotified.splice(notifiedIndex, 1); } } } } else { - this._changeUpstreamNotified = []; + this._changeUpstreamNotified = []; } } diff --git a/src/tokens.ts b/src/tokens.ts index 66842ae88..146cd2ab9 100644 --- a/src/tokens.ts +++ b/src/tokens.ts @@ -373,7 +373,7 @@ export interface IGitExtension extends IDisposable { /** * Notifies user is a file that is attached has is behind changes in the remote branch with a pop-up Dialog */ - checkRemoteChangeNotified(): void; + checkRemoteChangeNotified(): Promise; /** * Register a new diff provider for specified file types From 372b47e0a33583442556ce41846ff4a110360ede Mon Sep 17 00:00:00 2001 From: Andrew Fulton Date: Tue, 21 Sep 2021 14:53:03 -0400 Subject: [PATCH 09/29] Update src/components/FileList.tsx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit removes gitfilediff command Co-authored-by: Frédéric Collonval --- src/components/FileList.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/FileList.tsx b/src/components/FileList.tsx index 5f12879f8..3d931a465 100644 --- a/src/components/FileList.tsx +++ b/src/components/FileList.tsx @@ -93,7 +93,6 @@ const SIMPLE_CONTEXT_COMMANDS: ContextCommands = { ], 'remote-changed': [ ContextCommandIDs.gitFileOpen, - ContextCommandIDs.gitFileDiff ], staged: [ ContextCommandIDs.gitFileOpen, From 117287a0232208d10efbc5c6fe514e75473fcee3 Mon Sep 17 00:00:00 2001 From: Andrew Fulton Date: Tue, 21 Sep 2021 14:53:43 -0400 Subject: [PATCH 10/29] Update src/components/FileList.tsx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit puts remote changed section above untracked section Co-authored-by: Frédéric Collonval --- src/components/FileList.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/FileList.tsx b/src/components/FileList.tsx index 3d931a465..56a9886c0 100644 --- a/src/components/FileList.tsx +++ b/src/components/FileList.tsx @@ -332,8 +332,8 @@ export class FileList extends React.Component { {this._renderUnmerged(unmergedFiles, height)} {this._renderStaged(stagedFiles, height)} {this._renderChanged(unstagedFiles, height)} - {this._renderUntracked(untrackedFiles, height)} {this._renderRemoteChanged(remoteChangedFiles, height)} + {this._renderUntracked(untrackedFiles, height)} )} From 59da778f8749805688a5093ef753cca274badbab Mon Sep 17 00:00:00 2001 From: Andrew Fulton Date: Tue, 21 Sep 2021 14:54:25 -0400 Subject: [PATCH 11/29] Update src/components/FileList.tsx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit removed commented out diff button Co-authored-by: Frédéric Collonval --- src/components/FileList.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/FileList.tsx b/src/components/FileList.tsx index 56a9886c0..66b38f79f 100644 --- a/src/components/FileList.tsx +++ b/src/components/FileList.tsx @@ -700,7 +700,6 @@ export class FileList extends React.Component { trans={this.props.trans} actions={ - {/** diffButton */} Date: Tue, 21 Sep 2021 14:55:15 -0400 Subject: [PATCH 12/29] Update src/components/FileList.tsx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit removes commented out diffButton Co-authored-by: Frédéric Collonval --- src/components/FileList.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/FileList.tsx b/src/components/FileList.tsx index 66b38f79f..dd7724b2e 100644 --- a/src/components/FileList.tsx +++ b/src/components/FileList.tsx @@ -694,7 +694,6 @@ export class FileList extends React.Component { .composite as boolean; const { data, index, style } = rowProps; const file = data[index] as Git.IStatusFile; - // const diffButton = this._createDiffButton(file); return ( Date: Tue, 21 Sep 2021 14:55:43 -0400 Subject: [PATCH 13/29] Update src/model.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fixes docstring grammer Co-authored-by: Frédéric Collonval --- src/model.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/model.ts b/src/model.ts index 67bce9858..459ae4f5b 100644 --- a/src/model.ts +++ b/src/model.ts @@ -960,7 +960,7 @@ export class GitExtension implements IGitExtension { } /** - * Notifies user is a file that is attached has is behind changes in the remote branch with a pop-up Dialog + * Notifies user if an openend file is behind the remote branch with a pop-up Dialog * */ async checkRemoteChangeNotified(): Promise { From 0e1e1b32b960467cd1b916adc97e3cb73a0be6aa Mon Sep 17 00:00:00 2001 From: Andrew Fulton Date: Tue, 21 Sep 2021 14:56:04 -0400 Subject: [PATCH 14/29] Update src/model.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit removes redundant ok button label Co-authored-by: Frédéric Collonval --- src/model.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/model.ts b/src/model.ts index 459ae4f5b..eddff6cbf 100644 --- a/src/model.ts +++ b/src/model.ts @@ -983,7 +983,7 @@ export class GitExtension implements IGitExtension { showDialog({ title: `${val.to} is out of date with your remote branch: ${this._currentBranch.upstream}`, body: `You may want to pull from ${this._currentBranch.upstream} before editing this file.`, - buttons: [Dialog.okButton({ label: 'OK' })] + buttons: [Dialog.okButton()] }); // add the file to the notified array this._changeUpstreamNotified.push(val); From 6b6e7c8fd35ecff34ceeb944d699b64700859bbf Mon Sep 17 00:00:00 2001 From: Andrew Fulton Date: Tue, 21 Sep 2021 15:11:17 -0400 Subject: [PATCH 15/29] Update src/model.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Frédéric Collonval --- src/model.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/model.ts b/src/model.ts index eddff6cbf..97aa56632 100644 --- a/src/model.ts +++ b/src/model.ts @@ -922,7 +922,7 @@ export class GitExtension implements IGitExtension { remote: data.remote || null, ahead: data.ahead || 0, behind: data.behind || 0, - files: files + files }); } catch (err) { // TODO we should notify the user From 0d784beebfe9ddaaa046fcbb7cfc48e68910a777 Mon Sep 17 00:00:00 2001 From: Andrew Fulton Date: Tue, 21 Sep 2021 15:14:07 -0400 Subject: [PATCH 16/29] changes remote changes section git pull button command from model.pull to CommandIds.gitPull --- src/components/FileList.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/components/FileList.tsx b/src/components/FileList.tsx index 5f12879f8..087cfaf85 100644 --- a/src/components/FileList.tsx +++ b/src/components/FileList.tsx @@ -17,7 +17,7 @@ import { openIcon, removeIcon } from '../style/icons'; -import { ContextCommandIDs, Git } from '../tokens'; +import { ContextCommandIDs, CommandIDs, Git } from '../tokens'; import { ActionButton } from './ActionButton'; import { FileItem } from './FileItem'; import { GitStage } from './GitStage'; @@ -263,8 +263,7 @@ export class FileList extends React.Component { }; pullFromRemote = async (event: React.MouseEvent): Promise => { - event.stopPropagation(); - await this.props.model.pull(); + await this.props.commands.execute(CommandIDs.gitPull, {}) }; get markedFiles(): Git.IStatusFile[] { @@ -681,7 +680,7 @@ export class FileList extends React.Component { } /** - * Render a untracked file. + * Render the remote changed list. * * Note: This is actually a React.FunctionComponent but defined as * a private method as it needs access to FileList properties. From fd4b62f8cbe704f2192025c386200a245874ab30 Mon Sep 17 00:00:00 2001 From: Andrew Fulton Date: Tue, 21 Sep 2021 15:26:20 -0400 Subject: [PATCH 17/29] wraps remote changed files logic in try catch --- src/model.ts | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/model.ts b/src/model.ts index 97aa56632..4a82c0da2 100644 --- a/src/model.ts +++ b/src/model.ts @@ -939,22 +939,26 @@ export class GitExtension implements IGitExtension { async remoteChangedFiles(): Promise { // if a file is changed on remote add it to list of files with appropriate status. this._remoteChangedFiles = []; - let remoteChangedFiles: null | string[] = null; - if (this.status.remote && this.status.behind > 0) { - remoteChangedFiles = ( - await this._changedFiles('WORKING', this.status.remote) - ).files; - remoteChangedFiles?.forEach(element => { - this._remoteChangedFiles.push({ - status: 'remote-changed', - type: this._resolveFileType(element), - x: '?', - y: 'B', - to: element, - from: '?', - is_binary: false + try { + let remoteChangedFiles: null | string[] = null; + if (this.status.remote && this.status.behind > 0) { + remoteChangedFiles = ( + await this._changedFiles('WORKING', this.status.remote) + ).files; + remoteChangedFiles?.forEach(element => { + this._remoteChangedFiles.push({ + status: 'remote-changed', + type: this._resolveFileType(element), + x: '?', + y: 'B', + to: element, + from: '?', + is_binary: false + }); }); - }); + } + } catch (err) { + console.error(err); } return this._remoteChangedFiles; } From 962384bfc6a91e17872afd5c6e3f674d1f6e3413 Mon Sep 17 00:00:00 2001 From: Andrew Fulton Date: Mon, 4 Oct 2021 16:42:07 -0400 Subject: [PATCH 18/29] changes to improve remote behind dialog --- schema/plugin.json | 6 ++++ src/components/FileList.tsx | 6 ++-- src/components/GitPanel.tsx | 66 ++++++++++++++++++++++++++++++++++++- src/model.ts | 36 +++++++++++++++----- src/tokens.ts | 16 +++++++++ 5 files changed, 116 insertions(+), 14 deletions(-) diff --git a/schema/plugin.json b/schema/plugin.json index 68bf819b2..acd820059 100644 --- a/schema/plugin.json +++ b/schema/plugin.json @@ -64,6 +64,12 @@ "title": "Trigger push on commit", "description": "Whether to trigger or not a push for each commit.", "default": false + }, + "openFilesBehindWarning": { + "type": "boolean", + "title": "Open files behind warning", + "description": "If true, a popup dialog will be displayed if a user opens a file that is behind the remote branch, or if an open file is updated on the remote branch.", + "default": true } }, "jupyter.lab.shortcuts": [ diff --git a/src/components/FileList.tsx b/src/components/FileList.tsx index 1e4b1c3ca..5d22d2066 100644 --- a/src/components/FileList.tsx +++ b/src/components/FileList.tsx @@ -91,9 +91,7 @@ const SIMPLE_CONTEXT_COMMANDS: ContextCommands = { ContextCommandIDs.gitFileDiff, ContextCommandIDs.gitFileHistory ], - 'remote-changed': [ - ContextCommandIDs.gitFileOpen, - ], + 'remote-changed': [ContextCommandIDs.gitFileOpen], staged: [ ContextCommandIDs.gitFileOpen, ContextCommandIDs.gitFileDiscard, @@ -262,7 +260,7 @@ export class FileList extends React.Component { }; pullFromRemote = async (event: React.MouseEvent): Promise => { - await this.props.commands.execute(CommandIDs.gitPull, {}) + await this.props.commands.execute(CommandIDs.gitPull, {}); }; get markedFiles(): Git.IStatusFile[] { diff --git a/src/components/GitPanel.tsx b/src/components/GitPanel.tsx index 7759cd602..faec4b544 100644 --- a/src/components/GitPanel.tsx +++ b/src/components/GitPanel.tsx @@ -1,4 +1,4 @@ -import { showDialog } from '@jupyterlab/apputils'; +import { showDialog, Dialog } from '@jupyterlab/apputils'; import { PathExt } from '@jupyterlab/coreutils'; import { FileBrowserModel } from '@jupyterlab/filebrowser'; import { ISettingRegistry } from '@jupyterlab/settingregistry'; @@ -186,6 +186,7 @@ export class GitPanel extends React.Component { this.refreshHistory(); }, this); model.markChanged.connect(() => this.forceUpdate(), this); + model.notifyRemoteChanges.connect((_, args) => this.warningDialog(args)); settings.changed.connect(this.refreshView, this); } @@ -663,4 +664,67 @@ export class GitPanel extends React.Component { } private _previousRepoPath: string = null; + + /** + * Show a dialog when a notifyRemoteChanges signal is emitted from the model. + */ + private async warningDialog( + options: Git.IRemoteChangedNotification + ): Promise { + const title = `One or more open files are behind ${this.props.model.status.remote}`; + const dialog = new Dialog({ + title: this.props.trans.__(title), + body: this._renderBody(options.notNotified, options.notified), + buttons: [ + Dialog.createButton({ + label: this.props.trans.__('OK'), + accept: false + }), + Dialog.warnButton({ + label: this.props.trans.__('Pull'), + caption: this.props.trans.__('Git Pull from Remote Branch') + }) + ] + }); + dialog.launch().then(async result => { + console.log(result); + if (result.button.accept) { + await this.props.commands.execute(CommandIDs.gitPull, {}); + } + }); + } + + /** + * renders the body to be used in the remote changes warning dialog + */ + private _renderBody( + notNotifiedList: Git.IStatusFile[], + notifiedList: Git.IStatusFile[] = [] + ): JSX.Element { + const listedItems = notNotifiedList.map((item: Git.IStatusFile) => { + console.log(item.to); + const item_val = this.props.trans.__(item.to); + return
  • {item_val}
  • ; + }); + let elem: JSX.Element =
      {listedItems}
    ; + if (notifiedList.length > 0) { + const remaining = this.props.trans.__( + 'The following open files remain behind:' + ); + const alreadyListedItems = notifiedList.map((item: Git.IStatusFile) => { + console.log(item.to); + const item_val = this.props.trans.__(item.to); + return
  • {item_val}
  • ; + }); + const full: JSX.Element = ( +
    + {elem} + {remaining} +
      {alreadyListedItems}
    +
    + ); + elem = full; + } + return
    {elem}
    ; + } } diff --git a/src/model.ts b/src/model.ts index 4a82c0da2..79cb44b52 100644 --- a/src/model.ts +++ b/src/model.ts @@ -1,5 +1,4 @@ import { IChangedArgs, PathExt, URLExt } from '@jupyterlab/coreutils'; -import { showDialog, Dialog } from '@jupyterlab/apputils'; import { IDocumentManager } from '@jupyterlab/docmanager'; import { DocumentRegistry } from '@jupyterlab/docregistry'; import { ISettingRegistry } from '@jupyterlab/settingregistry'; @@ -252,6 +251,16 @@ export class GitExtension implements IGitExtension { return this._taskHandler.taskChanged; } + /** + * A signal emitted when the current Git repository changes. + */ + get notifyRemoteChanges(): ISignal< + IGitExtension, + Git.IRemoteChangedNotification + > { + return this._notifyRemoteChange; + } + /** * Get the current markers * @@ -939,7 +948,7 @@ export class GitExtension implements IGitExtension { async remoteChangedFiles(): Promise { // if a file is changed on remote add it to list of files with appropriate status. this._remoteChangedFiles = []; - try { + try { let remoteChangedFiles: null | string[] = null; if (this.status.remote && this.status.behind > 0) { remoteChangedFiles = ( @@ -964,11 +973,14 @@ export class GitExtension implements IGitExtension { } /** - * Notifies user if an openend file is behind the remote branch with a pop-up Dialog + * Determines if opened files are behind the remote and emits a signal if one + * or more are behind and the user hasn't been notified of them yet. * */ async checkRemoteChangeNotified(): Promise { if (this.status.remote && this.status.behind > 0) { + const notNotified = []; + const notified = []; for (const val of this._remoteChangedFiles) { const docWidget = this._docmanager.findWidget( this.getRelativeFilePath(val.to) @@ -984,13 +996,10 @@ export class GitExtension implements IGitExtension { if (docWidget.isAttached) { // notify if the user hasn't been notified yet if (notifiedIndex === -1) { - showDialog({ - title: `${val.to} is out of date with your remote branch: ${this._currentBranch.upstream}`, - body: `You may want to pull from ${this._currentBranch.upstream} before editing this file.`, - buttons: [Dialog.okButton()] - }); - // add the file to the notified array this._changeUpstreamNotified.push(val); + notNotified.push(val); + } else { + notified.push(val); } } } else { @@ -1000,6 +1009,11 @@ export class GitExtension implements IGitExtension { } } } + if (this._settings.composite['openFilesBehindWarning']) { + if (notNotified.length > 0) { + this._notifyRemoteChange.emit({ notNotified, notified }); + } + } } else { this._changeUpstreamNotified = []; } @@ -1517,6 +1531,10 @@ export class GitExtension implements IGitExtension { IChangedArgs >(this); private _statusChanged = new Signal(this); + private _notifyRemoteChange = new Signal< + IGitExtension, + Git.IRemoteChangedNotification + >(this); } export class BranchMarker implements Git.IBranchMarker { diff --git a/src/tokens.ts b/src/tokens.ts index 146cd2ab9..54ddb6584 100644 --- a/src/tokens.ts +++ b/src/tokens.ts @@ -83,6 +83,14 @@ export interface IGitExtension extends IDisposable { Git.IStatusFile | null >; + /** + * A signal emitted when files that are behind the remote branch are opened. + */ + readonly notifyRemoteChanges: ISignal< + IGitExtension, + Git.IRemoteChangedNotification + >; + /** * Add one or more files to the repository staging area. * @@ -796,6 +804,14 @@ export namespace Git { files?: string[]; } + /** Interface for notifying users of opened files that are behind + * the remote branch + */ + export interface IRemoteChangedNotification { + notNotified: IStatusFile[]; + notified: IStatusFile[]; + } + /** Interface for GitLog request result, * has the info of a single past commit */ From 8501837066d1b23d623dd042cd388354b5c01e60 Mon Sep 17 00:00:00 2001 From: Andrew Fulton Date: Tue, 5 Oct 2021 10:12:50 -0400 Subject: [PATCH 19/29] moves model.remoteChangedFiles returns --- src/model.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/model.ts b/src/model.ts index 79cb44b52..a48412fa1 100644 --- a/src/model.ts +++ b/src/model.ts @@ -965,11 +965,12 @@ export class GitExtension implements IGitExtension { is_binary: false }); }); + return this._remoteChangedFiles; } } catch (err) { console.error(err); + return this._remoteChangedFiles; } - return this._remoteChangedFiles; } /** From 003f3e4312dafd2f7da70e45f988b1829c1ce364 Mon Sep 17 00:00:00 2001 From: Andrew Fulton Date: Thu, 7 Oct 2021 09:57:04 -0400 Subject: [PATCH 20/29] Update src/components/GitPanel.tsx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit awaits gitPull command in remote behind dialog Co-authored-by: Frédéric Collonval --- src/components/GitPanel.tsx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/components/GitPanel.tsx b/src/components/GitPanel.tsx index faec4b544..7902fd813 100644 --- a/src/components/GitPanel.tsx +++ b/src/components/GitPanel.tsx @@ -686,12 +686,10 @@ export class GitPanel extends React.Component { }) ] }); - dialog.launch().then(async result => { - console.log(result); - if (result.button.accept) { - await this.props.commands.execute(CommandIDs.gitPull, {}); - } - }); + const result = await dialog.launch(); + if (result.button.accept) { + await this.props.commands.execute(CommandIDs.gitPull, {}); + } } /** From 5973b6175ab08c83d81b06d32ab8bc599003a33c Mon Sep 17 00:00:00 2001 From: Andrew Fulton Date: Thu, 7 Oct 2021 09:57:31 -0400 Subject: [PATCH 21/29] Update src/components/GitPanel.tsx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes cancelButton label on remote behind dialoog Co-authored-by: Frédéric Collonval --- src/components/GitPanel.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/components/GitPanel.tsx b/src/components/GitPanel.tsx index 7902fd813..9cba8f2bc 100644 --- a/src/components/GitPanel.tsx +++ b/src/components/GitPanel.tsx @@ -676,9 +676,8 @@ export class GitPanel extends React.Component { title: this.props.trans.__(title), body: this._renderBody(options.notNotified, options.notified), buttons: [ - Dialog.createButton({ - label: this.props.trans.__('OK'), - accept: false + Dialog.cancelButton({ + label: this.props.trans.__('Continue Without Pulling') }), Dialog.warnButton({ label: this.props.trans.__('Pull'), From 615b729dbc90163972edecaa8023ebdc49c4cb71 Mon Sep 17 00:00:00 2001 From: Andrew Fulton Date: Thu, 7 Oct 2021 09:58:10 -0400 Subject: [PATCH 22/29] Update src/components/GitPanel.tsx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit changes title of remote behind dialog to be explicitely pass as args to trans.__ Co-authored-by: Frédéric Collonval --- src/components/GitPanel.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/components/GitPanel.tsx b/src/components/GitPanel.tsx index 9cba8f2bc..c8fbc134e 100644 --- a/src/components/GitPanel.tsx +++ b/src/components/GitPanel.tsx @@ -671,9 +671,12 @@ export class GitPanel extends React.Component { private async warningDialog( options: Git.IRemoteChangedNotification ): Promise { - const title = `One or more open files are behind ${this.props.model.status.remote}`; + const title = this.props.trans.__( + 'One or more open files are behind %1 head. Do you want to pull the latest remote version?', + this.props.model.status.remote + ); const dialog = new Dialog({ - title: this.props.trans.__(title), + title, body: this._renderBody(options.notNotified, options.notified), buttons: [ Dialog.cancelButton({ From e7640a5bf044c7add1daf930d965f712c5be66af Mon Sep 17 00:00:00 2001 From: Andrew Fulton Date: Thu, 7 Oct 2021 09:58:46 -0400 Subject: [PATCH 23/29] Update schema/plugin.json MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Improve openFilesBehindWarning setting description Co-authored-by: Frédéric Collonval --- schema/plugin.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/schema/plugin.json b/schema/plugin.json index acd820059..e1dc52074 100644 --- a/schema/plugin.json +++ b/schema/plugin.json @@ -68,7 +68,7 @@ "openFilesBehindWarning": { "type": "boolean", "title": "Open files behind warning", - "description": "If true, a popup dialog will be displayed if a user opens a file that is behind the remote branch, or if an open file is updated on the remote branch.", + "description": "If true, a popup dialog will be displayed if a user opens a file that is behind its remote branch version, or if an opened file has updates on the remote branch.", "default": true } }, From bcbc862f1cbc4fdd7577bb017772e5cceb3bf903 Mon Sep 17 00:00:00 2001 From: Andrew Fulton Date: Thu, 7 Oct 2021 10:02:18 -0400 Subject: [PATCH 24/29] adds this to model.notifyRemoteChanges signal --- src/components/GitPanel.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/GitPanel.tsx b/src/components/GitPanel.tsx index faec4b544..a5afb41dd 100644 --- a/src/components/GitPanel.tsx +++ b/src/components/GitPanel.tsx @@ -186,7 +186,9 @@ export class GitPanel extends React.Component { this.refreshHistory(); }, this); model.markChanged.connect(() => this.forceUpdate(), this); - model.notifyRemoteChanges.connect((_, args) => this.warningDialog(args)); + model.notifyRemoteChanges.connect((_, args) => { + this.warningDialog(args); + }, this); settings.changed.connect(this.refreshView, this); } From 6b7e8afa7ef48b4cf9d1a55588ac932e94786f63 Mon Sep 17 00:00:00 2001 From: Andrew Fulton Date: Thu, 7 Oct 2021 10:02:55 -0400 Subject: [PATCH 25/29] defines types in model.checkRemoteChangeNotified --- src/model.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/model.ts b/src/model.ts index a48412fa1..0ba3f3525 100644 --- a/src/model.ts +++ b/src/model.ts @@ -980,8 +980,8 @@ export class GitExtension implements IGitExtension { */ async checkRemoteChangeNotified(): Promise { if (this.status.remote && this.status.behind > 0) { - const notNotified = []; - const notified = []; + const notNotified: Git.IStatusFile[] = []; + const notified: Git.IStatusFile[] = []; for (const val of this._remoteChangedFiles) { const docWidget = this._docmanager.findWidget( this.getRelativeFilePath(val.to) From d1733f303af134ea2009ba8112e1e6cc42c780f1 Mon Sep 17 00:00:00 2001 From: Andrew Fulton Date: Fri, 8 Oct 2021 15:13:05 -0400 Subject: [PATCH 26/29] changes --- src/components/GitPanel.tsx | 2 +- src/model.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/GitPanel.tsx b/src/components/GitPanel.tsx index c159811b9..1713501e6 100644 --- a/src/components/GitPanel.tsx +++ b/src/components/GitPanel.tsx @@ -660,7 +660,7 @@ export class GitPanel extends React.Component { */ private get _sortedFiles(): Git.IStatusFile[] { const { files, remoteChangedFiles } = this.state; - const sfiles = files.concat(remoteChangedFiles); + const sfiles: Git.IStatusFile[] = files.concat(remoteChangedFiles); sfiles.sort((a, b) => a.to.localeCompare(b.to)); return sfiles; } diff --git a/src/model.ts b/src/model.ts index 0ba3f3525..80f01394d 100644 --- a/src/model.ts +++ b/src/model.ts @@ -1534,7 +1534,7 @@ export class GitExtension implements IGitExtension { private _statusChanged = new Signal(this); private _notifyRemoteChange = new Signal< IGitExtension, - Git.IRemoteChangedNotification + Git.IRemoteChangedNotification | null >(this); } From 4f913b975980255e0298213a0678f5f3f6d29f4b Mon Sep 17 00:00:00 2001 From: Andrew Fulton Date: Fri, 8 Oct 2021 16:08:10 -0400 Subject: [PATCH 27/29] fix file.status undefined error --- src/components/GitPanel.tsx | 7 +++++-- src/model.ts | 1 - 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/components/GitPanel.tsx b/src/components/GitPanel.tsx index 1713501e6..3c846d41a 100644 --- a/src/components/GitPanel.tsx +++ b/src/components/GitPanel.tsx @@ -167,7 +167,7 @@ export class GitPanel extends React.Component { this.refreshView(); }, this); model.statusChanged.connect(async () => { - const remotechangedFiles = await model.remoteChangedFiles(); + const remotechangedFiles: Git.IStatusFile[] = await model.remoteChangedFiles(); this.setState({ files: model.status.files, remoteChangedFiles: remotechangedFiles, @@ -660,7 +660,10 @@ export class GitPanel extends React.Component { */ private get _sortedFiles(): Git.IStatusFile[] { const { files, remoteChangedFiles } = this.state; - const sfiles: Git.IStatusFile[] = files.concat(remoteChangedFiles); + let sfiles: Git.IStatusFile[] = files + if (remoteChangedFiles) { + sfiles = sfiles.concat(remoteChangedFiles); + } sfiles.sort((a, b) => a.to.localeCompare(b.to)); return sfiles; } diff --git a/src/model.ts b/src/model.ts index 80f01394d..9804a1fbf 100644 --- a/src/model.ts +++ b/src/model.ts @@ -947,7 +947,6 @@ export class GitExtension implements IGitExtension { */ async remoteChangedFiles(): Promise { // if a file is changed on remote add it to list of files with appropriate status. - this._remoteChangedFiles = []; try { let remoteChangedFiles: null | string[] = null; if (this.status.remote && this.status.behind > 0) { From 1742bc0941491636aff77c9af4cca59f33d14570 Mon Sep 17 00:00:00 2001 From: Andrew Fulton Date: Fri, 8 Oct 2021 16:40:57 -0400 Subject: [PATCH 28/29] fixes test error and linting --- src/components/GitPanel.tsx | 5 +++-- src/model.ts | 6 +++--- src/tokens.ts | 2 +- tests/test-components/GitPanel.spec.tsx | 3 +++ 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/components/GitPanel.tsx b/src/components/GitPanel.tsx index 3c846d41a..6a910099a 100644 --- a/src/components/GitPanel.tsx +++ b/src/components/GitPanel.tsx @@ -167,7 +167,8 @@ export class GitPanel extends React.Component { this.refreshView(); }, this); model.statusChanged.connect(async () => { - const remotechangedFiles: Git.IStatusFile[] = await model.remoteChangedFiles(); + const remotechangedFiles: Git.IStatusFile[] = + await model.remoteChangedFiles(); this.setState({ files: model.status.files, remoteChangedFiles: remotechangedFiles, @@ -660,7 +661,7 @@ export class GitPanel extends React.Component { */ private get _sortedFiles(): Git.IStatusFile[] { const { files, remoteChangedFiles } = this.state; - let sfiles: Git.IStatusFile[] = files + let sfiles: Git.IStatusFile[] = files; if (remoteChangedFiles) { sfiles = sfiles.concat(remoteChangedFiles); } diff --git a/src/model.ts b/src/model.ts index 9804a1fbf..95e8444fe 100644 --- a/src/model.ts +++ b/src/model.ts @@ -258,7 +258,7 @@ export class GitExtension implements IGitExtension { IGitExtension, Git.IRemoteChangedNotification > { - return this._notifyRemoteChange; + return this._notifyRemoteChanges; } /** @@ -1011,7 +1011,7 @@ export class GitExtension implements IGitExtension { } if (this._settings.composite['openFilesBehindWarning']) { if (notNotified.length > 0) { - this._notifyRemoteChange.emit({ notNotified, notified }); + this._notifyRemoteChanges.emit({ notNotified, notified }); } } } else { @@ -1531,7 +1531,7 @@ export class GitExtension implements IGitExtension { IChangedArgs >(this); private _statusChanged = new Signal(this); - private _notifyRemoteChange = new Signal< + private _notifyRemoteChanges = new Signal< IGitExtension, Git.IRemoteChangedNotification | null >(this); diff --git a/src/tokens.ts b/src/tokens.ts index 043142334..d2f2ea8ed 100644 --- a/src/tokens.ts +++ b/src/tokens.ts @@ -89,7 +89,7 @@ export interface IGitExtension extends IDisposable { */ readonly notifyRemoteChanges: ISignal< IGitExtension, - Git.IRemoteChangedNotification + Git.IRemoteChangedNotification | null >; /** diff --git a/tests/test-components/GitPanel.spec.tsx b/tests/test-components/GitPanel.spec.tsx index 8a29613c2..dbd3670de 100644 --- a/tests/test-components/GitPanel.spec.tsx +++ b/tests/test-components/GitPanel.spec.tsx @@ -247,6 +247,9 @@ describe('GitPanel', () => { }, selectedHistoryFileChanged: { connect: jest.fn() + }, + notifyRemoteChanges: { + connect: jest.fn() } } as any; From ac56b4b78b060576d09a320917c0f458522c0a8e Mon Sep 17 00:00:00 2001 From: Andrew Fulton Date: Sat, 9 Oct 2021 11:47:10 -0400 Subject: [PATCH 29/29] fix growing repeated list of remote behind --- src/model.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/model.ts b/src/model.ts index 95e8444fe..8da8e2f5d 100644 --- a/src/model.ts +++ b/src/model.ts @@ -947,6 +947,7 @@ export class GitExtension implements IGitExtension { */ async remoteChangedFiles(): Promise { // if a file is changed on remote add it to list of files with appropriate status. + this._remoteChangedFiles = []; try { let remoteChangedFiles: null | string[] = null; if (this.status.remote && this.status.behind > 0) {