Skip to content

Commit dafc400

Browse files
committed
Merge PR #630 "Provide UI feedback during Git command execution"
commit 1c2cb43 Author: Frederic Collonval <[email protected]> Date: Fri Jul 24 18:24:42 2020 +0200 Post Merge branch 'master' corrections commit 5ec36d7 Author: Frederic Collonval <[email protected]> Date: Fri Jul 24 17:41:07 2020 +0200 Merge with master commit ae71d8d Author: Athan Reines <[email protected]> Date: Sun Jun 14 23:30:28 2020 -0700 Use finally blocks commit 2cd0408 Author: Athan Reines <[email protected]> Date: Sun Jun 14 23:21:23 2020 -0700 Reorder properties and methods commit 9f2d7ca Author: Athan Reines <[email protected]> Date: Mon Jun 8 11:08:57 2020 -0700 Fix response consumption bug commit e5d86d7 Merge: cab4132 6169af0 Author: Athan Reines <[email protected]> Date: Mon Jun 8 10:33:38 2020 -0700 Merge branch 'master' of https://github.com/jupyterlab/jupyterlab-git into ui-feedback commit cab4132 Author: Athan Reines <[email protected]> Date: Mon Jun 1 03:30:55 2020 -0700 Fix broken tests commit c4f0813 Author: Athan Reines <[email protected]> Date: Mon Jun 1 03:30:02 2020 -0700 Fix broken tests commit c132ced Author: Athan Reines <[email protected]> Date: Mon Jun 1 03:06:07 2020 -0700 Add private annotation commit 28be7d5 Author: Athan Reines <[email protected]> Date: Mon Jun 1 03:04:40 2020 -0700 Reorder methods commit f2d40d8 Author: Athan Reines <[email protected]> Date: Mon Jun 1 02:57:31 2020 -0700 Refactor to support UI feedback commit b4d5513 Author: Athan Reines <[email protected]> Date: Mon Jun 1 02:22:26 2020 -0700 Fix broken test commit ab68b01 Author: Athan Reines <[email protected]> Date: Mon Jun 1 02:13:36 2020 -0700 Refactor to support toast alerts commit 99d6766 Author: Athan Reines <[email protected]> Date: Mon Jun 1 02:00:47 2020 -0700 Refactor to support toast alerts commit b1d79d6 Merge: 3daf4ba 8e79eae Author: Athan Reines <[email protected]> Date: Mon Jun 1 01:44:23 2020 -0700 Merge branch 'master' of https://github.com/jupyterlab/jupyterlab-git into ui-feedback commit 3daf4ba Author: Athan Reines <[email protected]> Date: Mon Jun 1 01:33:04 2020 -0700 Refactor to support log message alerts commit 2d48dda Author: Athan Reines <[email protected]> Date: Mon Jun 1 01:18:06 2020 -0700 Rename file and refactor into smaller components to support toasts commit d203738 Author: Athan Reines <[email protected]> Date: Wed May 27 16:11:15 2020 -0700 Refactor to use "toast" notifications commit 1d5c364 Author: Athan Reines <[email protected]> Date: Wed May 27 16:10:17 2020 -0700 Add Material UI dep for displaying alert messages within toast notifications commit e0e6a5e Author: Athan Reines <[email protected]> Date: Wed May 27 13:34:04 2020 -0700 Add support for providing UI feedback when committing changes commit bf5c52a Author: Athan Reines <[email protected]> Date: Wed May 27 10:42:28 2020 -0700 Fix broken tests commit 4d84996 Author: Athan Reines <[email protected]> Date: Wed May 27 10:40:37 2020 -0700 Add src documentation and rename variables to be in line with project conventions commit 018444b Author: Athan Reines <[email protected]> Date: Tue May 26 17:57:08 2020 -0700 Fix broken tests commit 29b9917 Author: Athan Reines <[email protected]> Date: Tue May 26 17:54:23 2020 -0700 Add support for providing feedback when creating a new branch and refactor error handling commit 126389f Author: Athan Reines <[email protected]> Date: Tue May 26 17:13:08 2020 -0700 Provide UI feedback when switching branches commit b1ec725 Author: Athan Reines <[email protected]> Date: Tue May 26 16:01:19 2020 -0700 Add backticks commit fc2edb0 Merge: 62d88de c34abef Author: Athan Reines <[email protected]> Date: Tue May 26 15:55:28 2020 -0700 Merge branch 'master' of https://github.com/jupyterlab/jupyterlab-git into ui-feedback commit 62d88de Author: Athan Reines <[email protected]> Date: Tue May 26 15:41:25 2020 -0700 Document function commit 1596dee Author: Athan Reines <[email protected]> Date: Tue May 26 15:39:47 2020 -0700 Remove console.log commit 697bab8 Author: Athan Reines <[email protected]> Date: Tue May 26 15:32:06 2020 -0700 Add support for toggling display of status bar updates commit 2b9da5e Author: Athan Reines <[email protected]> Date: Tue May 26 14:45:30 2020 -0700 Add setting to toggle status bar updates commit c51a449 Author: Athan Reines <[email protected]> Date: Mon May 18 22:00:56 2020 -0700 Allow the user to dismiss the modal I am not convinced this is an entirely good idea, as why bother with a blocking modal at all if a user can dismiss. The main hope is that less technical users will simply respect the modal and wait until completion before moving on. The risk is that users will catch on and disregard the warning, allowing for potential footguns. However, reviewers appear hostile to a blocking modal which cannot be readily dismissed. commit b0a1c44 Author: Athan Reines <[email protected]> Date: Mon May 18 21:48:45 2020 -0700 Fix operation order bug commit 062a2a1 Author: Athan Reines <[email protected]> Date: Mon May 18 21:40:06 2020 -0700 Move status widget to separate file and add widget style commit c34c33e Author: Athan Reines <[email protected]> Date: Mon May 18 21:22:16 2020 -0700 Update lockfile commit 5576d73 Author: Athan Reines <[email protected]> Date: Mon May 18 21:20:55 2020 -0700 Restore prior refresh status behavior when non-200 response commit 6bdba11 Author: Athan Reines <[email protected]> Date: Mon May 18 21:06:44 2020 -0700 Throttle status widget to prevent flashing updates commit cf3d9ac Author: Athan Reines <[email protected]> Date: Mon May 18 19:57:07 2020 -0700 Update task names and map log events to status messages commit 8d471f4 Author: Athan Reines <[email protected]> Date: Mon May 18 19:29:12 2020 -0700 Fix task queue management commit ccbfb70 Author: Athan Reines <[email protected]> Date: Mon May 18 18:29:02 2020 -0700 Add lumino collections dependency commit 2f155e5 Author: Athan Reines <[email protected]> Date: Mon May 18 18:28:25 2020 -0700 Refactor and clean-up the extension model commit d373478 Author: Athan Reines <[email protected]> Date: Mon May 18 11:26:12 2020 -0700 Wire up model event logging commit 3b3b915 Author: Athan Reines <[email protected]> Date: Mon May 18 11:12:57 2020 -0700 Fix capitalization commit 0169c2a Merge: a579a42 e923a5b Author: Athan Reines <[email protected]> Date: Mon May 18 00:51:45 2020 -0700 Merge branch 'master' of https://github.com/jupyterlab/jupyterlab-git into ui-feedback commit a579a42 Author: Athan Reines <[email protected]> Date: Mon May 18 00:50:59 2020 -0700 Fix capitalization commit 71442cb Author: Athan Reines <[email protected]> Date: Mon May 18 00:48:38 2020 -0700 Fix capitalization commit f3e25ec Author: Athan Reines <[email protected]> Date: Mon May 18 00:32:52 2020 -0700 Fix broken tests commit f58b51f Author: Athan Reines <[email protected]> Date: Mon May 18 00:23:45 2020 -0700 Toggle UI suspension based on plugin setting commit 6a93b34 Author: Athan Reines <[email protected]> Date: Mon May 18 00:23:05 2020 -0700 Update setting description commit 1e36470 Author: Athan Reines <[email protected]> Date: Mon May 18 00:22:24 2020 -0700 Update description commit 4437e60 Author: Athan Reines <[email protected]> Date: Mon May 11 11:22:06 2020 -0700 Document new setting commit 1bace21 Author: Athan Reines <[email protected]> Date: Mon May 11 11:20:34 2020 -0700 Document setting commit da2ec0e Author: Athan Reines <[email protected]> Date: Mon May 11 11:18:38 2020 -0700 Add setting for toggling UI suspension commit 4ced5a8 Author: Athan Reines <[email protected]> Date: Mon May 4 14:50:46 2020 -0700 Ensure a minimum duration commit 06300ff Author: Athan Reines <[email protected]> Date: Thu Apr 30 16:50:32 2020 -0700 Add UI feedback during toolbar actions
1 parent 4e464ea commit dafc400

29 files changed

+2242
-787
lines changed

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,11 @@ jupyter lab build
3333

3434
Once installed, extension behavior can be modified via the following settings which can be set in JupyterLab's advanced settings editor:
3535

36+
- **blockWhileCommandExecutes**: suspend JupyterLab user interaction until Git commands (e.g., `commit`, `pull`, `reset`, `revert`) finish executing. Setting this to `true` helps mitigate potential race conditions leading to data loss, conflicts, and a broken Git history. Unless running a slow network, UI suspension should not interfere with standard workflows. Setting this to `false` allows for actions to trigger multiple concurrent Git actions.
37+
- **cancelPullMergeConflict**: cancel pulling changes from a remote repository if there exists a merge conflict. If set to `true`, when fetching and integrating changes from a remote repository, a conflicting merge is canceled and the working tree left untouched.
3638
- **disableBranchWithChanges**: disable all branch operations, such as creating a new branch or switching to a different branch, when there are changed/staged files. When set to `true`, this setting guards against overwriting and/or losing uncommitted changes.
37-
- **doubleClickDiff**: double click a file in the Git UI to open a diff of the file instead of opening the file for editing.
39+
- **displayStatus**: display Git extension status updates in the JupyterLab status bar. If `true`, the extension displays status updates in the JupyterLab status bar, such as when pulling and pushing changes, switching branches, and polling for changes. Depending on the level of extension activity, some users may find the status updates distracting. In which case, setting this to `false` should reduce visual noise.
40+
- **doubleClickDiff**: double click a file in the Git extension panel to open a diff of the file instead of opening the file for editing.
3841
- **historyCount**: number of commits shown in the history log, beginning with the most recent. Displaying a larger number of commits can lead to performance degradation, so use caution when modifying this setting.
3942
- **refreshInterval**: number of milliseconds between polling the file system for changes. In order to ensure that the UI correctly displays the current repository status, the extension must poll the file system for changes. Longer polling times increase the likelihood that the UI does not reflect the current status; however, longer polling times also incur less performance overhead.
4043
- **simpleStaging**: enable a simplified concept of staging. When this setting is `true`, all files with changes are automatically staged. When we develop in JupyterLab, we often only care about what files have changed (in the broadest sense) and don't need to distinguish between "tracked" and "untracked" files. Accordingly, this setting allows us to simplify the visual presentation of changes, which is especially useful for those less acquainted with Git.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,12 @@
6262
"@jupyterlab/settingregistry": "^2.0.0",
6363
"@jupyterlab/terminal": "^2.0.0",
6464
"@jupyterlab/ui-components": "^2.0.0",
65+
"@lumino/collections": "^1.2.3",
6566
"@lumino/polling": "^1.0.4",
6667
"@lumino/widgets": "^1.11.1",
6768
"@material-ui/core": "^4.8.2",
6869
"@material-ui/icons": "^4.5.1",
70+
"@material-ui/lab": "^4.0.0-alpha.54",
6971
"diff-match-patch": "^1.0.4",
7072
"nbdime": "^6.0.0",
7173
"react": "~16.9.0",

schema/plugin.json

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@
55
"description": "jupyterlab-git settings.",
66
"type": "object",
77
"properties": {
8+
"blockWhileCommandExecutes": {
9+
"type": "boolean",
10+
"title": "Suspend user interaction until commands finish",
11+
"description": "Suspend JupyterLab user interaction until Git commands (e.g., commit, pull, reset, revert) finish executing. Setting this to true helps mitigate potential race conditions leading to data loss, conflicts, and a broken Git history. Unless running a slow network, UI suspension should not interfere with standard workflows. Setting this to false allows for actions to trigger multiple concurrent Git actions.",
12+
"default": true
13+
},
814
"cancelPullMergeConflict": {
915
"type": "boolean",
1016
"title": "Cancel pull merge conflict",
@@ -17,10 +23,16 @@
1723
"description": "Disable all branch operations (new, switch) when there are changed/staged files",
1824
"default": false
1925
},
26+
"displayStatus": {
27+
"type": "boolean",
28+
"title": "Display Git status updates",
29+
"description": "Display Git extension status updates in the JupyterLab status bar. If true, the extension displays status updates in the JupyterLab status bar, such as when pulling and pushing changes, switching branches, and polling for changes. Depending on the level of extension activity, some users may find the status updates distracting. In which case, setting this to false should reduce visual noise.",
30+
"default": true
31+
},
2032
"doubleClickDiff": {
2133
"type": "boolean",
2234
"title": "Show diff on double click",
23-
"description": "If true, doubling clicking a file in the list of changed files will open a diff",
35+
"description": "If true, doubling clicking a file in the list of changed files will open a diff.",
2436
"default": false
2537
},
2638
"historyCount": {

src/gitMenuCommands.ts renamed to src/commandsAndMenu.ts

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,23 @@ import {
99
import { FileBrowser } from '@jupyterlab/filebrowser';
1010
import { ISettingRegistry } from '@jupyterlab/settingregistry';
1111
import { ITerminal } from '@jupyterlab/terminal';
12+
import { CommandRegistry } from '@lumino/commands';
13+
import { Menu } from '@lumino/widgets';
1214
import { IGitExtension } from './tokens';
15+
import { GitCredentialsForm } from './widgets/CredentialsBox';
1316
import { doGitClone } from './widgets/gitClone';
1417
import { GitPullPushDialog, Operation } from './widgets/gitPushPull';
15-
import { GitCredentialsForm } from './widgets/CredentialsBox';
18+
19+
const RESOURCES = [
20+
{
21+
text: 'Set Up Remotes',
22+
url: 'https://www.atlassian.com/git/tutorials/setting-up-a-repository'
23+
},
24+
{
25+
text: 'Git Documentation',
26+
url: 'https://git-scm.com/doc'
27+
}
28+
];
1629

1730
/**
1831
* The command IDs used by the git plugin.
@@ -210,6 +223,52 @@ export function addCommands(
210223
});
211224
}
212225

226+
/**
227+
* Adds commands and menu items.
228+
*
229+
* @private
230+
* @param app - Jupyter front end
231+
* @param gitExtension - Git extension instance
232+
* @param fileBrowser - file browser instance
233+
* @param settings - extension settings
234+
* @returns menu
235+
*/
236+
export function createGitMenu(commands: CommandRegistry): Menu {
237+
const menu = new Menu({ commands });
238+
menu.title.label = 'Git';
239+
[
240+
CommandIDs.gitInit,
241+
CommandIDs.gitClone,
242+
CommandIDs.gitPush,
243+
CommandIDs.gitPull,
244+
CommandIDs.gitAddRemote,
245+
CommandIDs.gitTerminalCommand
246+
].forEach(command => {
247+
menu.addItem({ command });
248+
});
249+
250+
menu.addItem({ type: 'separator' });
251+
252+
menu.addItem({ command: CommandIDs.gitToggleSimpleStaging });
253+
254+
menu.addItem({ command: CommandIDs.gitToggleDoubleClickDiff });
255+
256+
menu.addItem({ type: 'separator' });
257+
258+
const tutorial = new Menu({ commands });
259+
tutorial.title.label = ' Help ';
260+
RESOURCES.map(args => {
261+
tutorial.addItem({
262+
args,
263+
command: CommandIDs.gitOpenUrl
264+
});
265+
});
266+
267+
menu.addItem({ type: 'submenu', submenu: tutorial });
268+
269+
return menu;
270+
}
271+
213272
/* eslint-disable no-inner-declarations */
214273
namespace Private {
215274
/**

src/components/Alert.tsx

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
import * as React from 'react';
2+
import Portal from '@material-ui/core/Portal';
3+
import Snackbar from '@material-ui/core/Snackbar';
4+
import Slide from '@material-ui/core/Slide';
5+
import { default as MuiAlert } from '@material-ui/lab/Alert';
6+
import { Severity } from '../tokens';
7+
8+
/**
9+
* Returns a React component for "sliding-in" an alert.
10+
*
11+
* @private
12+
* @param props - component properties
13+
* @returns React element
14+
*/
15+
function SlideTransition(props: any): React.ReactElement {
16+
return <Slide {...props} direction="up" />;
17+
}
18+
19+
/**
20+
* Interface describing component properties.
21+
*/
22+
export interface IAlertProps {
23+
/**
24+
* Boolean indicating whether to display an alert.
25+
*/
26+
open: boolean;
27+
28+
/**
29+
* Alert message.
30+
*/
31+
message: string;
32+
33+
/**
34+
* Alert severity.
35+
*/
36+
severity?: Severity;
37+
38+
/**
39+
* Alert duration (in milliseconds).
40+
*/
41+
duration?: number;
42+
43+
/**
44+
* Callback invoked upon clicking on an alert.
45+
*/
46+
onClick?: (event?: any) => void;
47+
48+
/**
49+
* Callback invoked upon closing an alert.
50+
*/
51+
onClose: (event?: any) => void;
52+
}
53+
54+
/**
55+
* React component for rendering an alert.
56+
*/
57+
export class Alert extends React.Component<IAlertProps> {
58+
/**
59+
* Returns a React component for rendering an alert.
60+
*
61+
* @param props - component properties
62+
* @returns React component
63+
*/
64+
constructor(props: IAlertProps) {
65+
super(props);
66+
}
67+
68+
/**
69+
* Renders the component.
70+
*
71+
* @returns React element
72+
*/
73+
render(): React.ReactElement {
74+
let duration: number | null = null;
75+
76+
const severity = this.props.severity || 'info';
77+
if (severity === 'success') {
78+
duration = this.props.duration || 5000; // milliseconds
79+
}
80+
return (
81+
<Portal>
82+
<Snackbar
83+
key="git:alert"
84+
open={this.props.open}
85+
anchorOrigin={{
86+
vertical: 'bottom',
87+
horizontal: 'right'
88+
}}
89+
autoHideDuration={duration}
90+
TransitionComponent={SlideTransition}
91+
onClick={this._onClick}
92+
onClose={this._onClose}
93+
>
94+
<MuiAlert variant="filled" severity={severity}>
95+
{this.props.message || '(missing message)'}
96+
</MuiAlert>
97+
</Snackbar>
98+
</Portal>
99+
);
100+
}
101+
102+
/**
103+
* Callback invoked upon clicking on an alert.
104+
*
105+
* @param event - event object
106+
*/
107+
private _onClick = (event: any): void => {
108+
if (this.props.onClick) {
109+
this.props.onClick(event);
110+
return;
111+
}
112+
this._onClose(event, 'click');
113+
};
114+
115+
/**
116+
* Callback invoked upon closing an alert.
117+
*
118+
* @param event - event object
119+
* @param reason - reason why the callback was invoked
120+
*/
121+
private _onClose = (event: any, reason: string): void => {
122+
if (reason === 'clickaway') {
123+
return;
124+
}
125+
this.props.onClose(event);
126+
};
127+
}

0 commit comments

Comments
 (0)