Skip to content

Commit

Permalink
Merge PR #630 "Provide UI feedback during Git command execution"
Browse files Browse the repository at this point in the history
commit 1c2cb43
Author: Frederic Collonval <fcollonval@gmail.com>
Date:   Fri Jul 24 18:24:42 2020 +0200

    Post Merge branch 'master' corrections

commit 5ec36d7
Author: Frederic Collonval <fcollonval@gmail.com>
Date:   Fri Jul 24 17:41:07 2020 +0200

    Merge with master

commit ae71d8d
Author: Athan Reines <kgryte@gmail.com>
Date:   Sun Jun 14 23:30:28 2020 -0700

    Use finally blocks

commit 2cd0408
Author: Athan Reines <kgryte@gmail.com>
Date:   Sun Jun 14 23:21:23 2020 -0700

    Reorder properties and methods

commit 9f2d7ca
Author: Athan Reines <kgryte@gmail.com>
Date:   Mon Jun 8 11:08:57 2020 -0700

    Fix response consumption bug

commit e5d86d7
Merge: cab4132 6169af0
Author: Athan Reines <kgryte@gmail.com>
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 <kgryte@gmail.com>
Date:   Mon Jun 1 03:30:55 2020 -0700

    Fix broken tests

commit c4f0813
Author: Athan Reines <kgryte@gmail.com>
Date:   Mon Jun 1 03:30:02 2020 -0700

    Fix broken tests

commit c132ced
Author: Athan Reines <kgryte@gmail.com>
Date:   Mon Jun 1 03:06:07 2020 -0700

    Add private annotation

commit 28be7d5
Author: Athan Reines <kgryte@gmail.com>
Date:   Mon Jun 1 03:04:40 2020 -0700

    Reorder methods

commit f2d40d8
Author: Athan Reines <kgryte@gmail.com>
Date:   Mon Jun 1 02:57:31 2020 -0700

    Refactor to support UI feedback

commit b4d5513
Author: Athan Reines <kgryte@gmail.com>
Date:   Mon Jun 1 02:22:26 2020 -0700

    Fix broken test

commit ab68b01
Author: Athan Reines <kgryte@gmail.com>
Date:   Mon Jun 1 02:13:36 2020 -0700

    Refactor to support toast alerts

commit 99d6766
Author: Athan Reines <kgryte@gmail.com>
Date:   Mon Jun 1 02:00:47 2020 -0700

    Refactor to support toast alerts

commit b1d79d6
Merge: 3daf4ba 8e79eae
Author: Athan Reines <kgryte@gmail.com>
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 <kgryte@gmail.com>
Date:   Mon Jun 1 01:33:04 2020 -0700

    Refactor to support log message alerts

commit 2d48dda
Author: Athan Reines <kgryte@gmail.com>
Date:   Mon Jun 1 01:18:06 2020 -0700

    Rename file and refactor into smaller components to support toasts

commit d203738
Author: Athan Reines <kgryte@gmail.com>
Date:   Wed May 27 16:11:15 2020 -0700

    Refactor to use "toast" notifications

commit 1d5c364
Author: Athan Reines <kgryte@gmail.com>
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 <kgryte@gmail.com>
Date:   Wed May 27 13:34:04 2020 -0700

    Add support for providing UI feedback when committing changes

commit bf5c52a
Author: Athan Reines <kgryte@gmail.com>
Date:   Wed May 27 10:42:28 2020 -0700

    Fix broken tests

commit 4d84996
Author: Athan Reines <kgryte@gmail.com>
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 <kgryte@gmail.com>
Date:   Tue May 26 17:57:08 2020 -0700

    Fix broken tests

commit 29b9917
Author: Athan Reines <kgryte@gmail.com>
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 <kgryte@gmail.com>
Date:   Tue May 26 17:13:08 2020 -0700

    Provide UI feedback when switching branches

commit b1ec725
Author: Athan Reines <kgryte@gmail.com>
Date:   Tue May 26 16:01:19 2020 -0700

    Add backticks

commit fc2edb0
Merge: 62d88de c34abef
Author: Athan Reines <kgryte@gmail.com>
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 <kgryte@gmail.com>
Date:   Tue May 26 15:41:25 2020 -0700

    Document function

commit 1596dee
Author: Athan Reines <kgryte@gmail.com>
Date:   Tue May 26 15:39:47 2020 -0700

    Remove console.log

commit 697bab8
Author: Athan Reines <kgryte@gmail.com>
Date:   Tue May 26 15:32:06 2020 -0700

    Add support for toggling display of status bar updates

commit 2b9da5e
Author: Athan Reines <kgryte@gmail.com>
Date:   Tue May 26 14:45:30 2020 -0700

    Add setting to toggle status bar updates

commit c51a449
Author: Athan Reines <kgryte@gmail.com>
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 <kgryte@gmail.com>
Date:   Mon May 18 21:48:45 2020 -0700

    Fix operation order bug

commit 062a2a1
Author: Athan Reines <kgryte@gmail.com>
Date:   Mon May 18 21:40:06 2020 -0700

    Move status widget to separate file and add widget style

commit c34c33e
Author: Athan Reines <kgryte@gmail.com>
Date:   Mon May 18 21:22:16 2020 -0700

    Update lockfile

commit 5576d73
Author: Athan Reines <kgryte@gmail.com>
Date:   Mon May 18 21:20:55 2020 -0700

    Restore prior refresh status behavior when non-200 response

commit 6bdba11
Author: Athan Reines <kgryte@gmail.com>
Date:   Mon May 18 21:06:44 2020 -0700

    Throttle status widget to prevent flashing updates

commit cf3d9ac
Author: Athan Reines <kgryte@gmail.com>
Date:   Mon May 18 19:57:07 2020 -0700

    Update task names and map log events to status messages

commit 8d471f4
Author: Athan Reines <kgryte@gmail.com>
Date:   Mon May 18 19:29:12 2020 -0700

    Fix task queue management

commit ccbfb70
Author: Athan Reines <kgryte@gmail.com>
Date:   Mon May 18 18:29:02 2020 -0700

    Add lumino collections dependency

commit 2f155e5
Author: Athan Reines <kgryte@gmail.com>
Date:   Mon May 18 18:28:25 2020 -0700

    Refactor and clean-up the extension model

commit d373478
Author: Athan Reines <kgryte@gmail.com>
Date:   Mon May 18 11:26:12 2020 -0700

    Wire up model event logging

commit 3b3b915
Author: Athan Reines <kgryte@gmail.com>
Date:   Mon May 18 11:12:57 2020 -0700

    Fix capitalization

commit 0169c2a
Merge: a579a42 e923a5b
Author: Athan Reines <kgryte@gmail.com>
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 <kgryte@gmail.com>
Date:   Mon May 18 00:50:59 2020 -0700

    Fix capitalization

commit 71442cb
Author: Athan Reines <kgryte@gmail.com>
Date:   Mon May 18 00:48:38 2020 -0700

    Fix capitalization

commit f3e25ec
Author: Athan Reines <kgryte@gmail.com>
Date:   Mon May 18 00:32:52 2020 -0700

    Fix broken tests

commit f58b51f
Author: Athan Reines <kgryte@gmail.com>
Date:   Mon May 18 00:23:45 2020 -0700

    Toggle UI suspension based on plugin setting

commit 6a93b34
Author: Athan Reines <kgryte@gmail.com>
Date:   Mon May 18 00:23:05 2020 -0700

    Update setting description

commit 1e36470
Author: Athan Reines <kgryte@gmail.com>
Date:   Mon May 18 00:22:24 2020 -0700

    Update description

commit 4437e60
Author: Athan Reines <kgryte@gmail.com>
Date:   Mon May 11 11:22:06 2020 -0700

    Document new setting

commit 1bace21
Author: Athan Reines <kgryte@gmail.com>
Date:   Mon May 11 11:20:34 2020 -0700

    Document setting

commit da2ec0e
Author: Athan Reines <kgryte@gmail.com>
Date:   Mon May 11 11:18:38 2020 -0700

    Add setting for toggling UI suspension

commit 4ced5a8
Author: Athan Reines <kgryte@gmail.com>
Date:   Mon May 4 14:50:46 2020 -0700

    Ensure a minimum duration

commit 06300ff
Author: Athan Reines <kgryte@gmail.com>
Date:   Thu Apr 30 16:50:32 2020 -0700

    Add UI feedback during toolbar actions
  • Loading branch information
fcollonval committed Jul 26, 2020
1 parent 4e464ea commit dafc400
Show file tree
Hide file tree
Showing 29 changed files with 2,242 additions and 787 deletions.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,11 @@ jupyter lab build

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

- **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.
- **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.
- **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.
- **doubleClickDiff**: double click a file in the Git UI to open a diff of the file instead of opening the file for editing.
- **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.
- **doubleClickDiff**: double click a file in the Git extension panel to open a diff of the file instead of opening the file for editing.
- **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.
- **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.
- **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.
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,12 @@
"@jupyterlab/settingregistry": "^2.0.0",
"@jupyterlab/terminal": "^2.0.0",
"@jupyterlab/ui-components": "^2.0.0",
"@lumino/collections": "^1.2.3",
"@lumino/polling": "^1.0.4",
"@lumino/widgets": "^1.11.1",
"@material-ui/core": "^4.8.2",
"@material-ui/icons": "^4.5.1",
"@material-ui/lab": "^4.0.0-alpha.54",
"diff-match-patch": "^1.0.4",
"nbdime": "^6.0.0",
"react": "~16.9.0",
Expand Down
14 changes: 13 additions & 1 deletion schema/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@
"description": "jupyterlab-git settings.",
"type": "object",
"properties": {
"blockWhileCommandExecutes": {
"type": "boolean",
"title": "Suspend user interaction until commands finish",
"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.",
"default": true
},
"cancelPullMergeConflict": {
"type": "boolean",
"title": "Cancel pull merge conflict",
Expand All @@ -17,10 +23,16 @@
"description": "Disable all branch operations (new, switch) when there are changed/staged files",
"default": false
},
"displayStatus": {
"type": "boolean",
"title": "Display Git status updates",
"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.",
"default": true
},
"doubleClickDiff": {
"type": "boolean",
"title": "Show diff on double click",
"description": "If true, doubling clicking a file in the list of changed files will open a diff",
"description": "If true, doubling clicking a file in the list of changed files will open a diff.",
"default": false
},
"historyCount": {
Expand Down
61 changes: 60 additions & 1 deletion src/gitMenuCommands.ts → src/commandsAndMenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,23 @@ import {
import { FileBrowser } from '@jupyterlab/filebrowser';
import { ISettingRegistry } from '@jupyterlab/settingregistry';
import { ITerminal } from '@jupyterlab/terminal';
import { CommandRegistry } from '@lumino/commands';
import { Menu } from '@lumino/widgets';
import { IGitExtension } from './tokens';
import { GitCredentialsForm } from './widgets/CredentialsBox';
import { doGitClone } from './widgets/gitClone';
import { GitPullPushDialog, Operation } from './widgets/gitPushPull';
import { GitCredentialsForm } from './widgets/CredentialsBox';

const RESOURCES = [
{
text: 'Set Up Remotes',
url: 'https://www.atlassian.com/git/tutorials/setting-up-a-repository'
},
{
text: 'Git Documentation',
url: 'https://git-scm.com/doc'
}
];

/**
* The command IDs used by the git plugin.
Expand Down Expand Up @@ -210,6 +223,52 @@ export function addCommands(
});
}

/**
* Adds commands and menu items.
*
* @private
* @param app - Jupyter front end
* @param gitExtension - Git extension instance
* @param fileBrowser - file browser instance
* @param settings - extension settings
* @returns menu
*/
export function createGitMenu(commands: CommandRegistry): Menu {
const menu = new Menu({ commands });
menu.title.label = 'Git';
[
CommandIDs.gitInit,
CommandIDs.gitClone,
CommandIDs.gitPush,
CommandIDs.gitPull,
CommandIDs.gitAddRemote,
CommandIDs.gitTerminalCommand
].forEach(command => {
menu.addItem({ command });
});

menu.addItem({ type: 'separator' });

menu.addItem({ command: CommandIDs.gitToggleSimpleStaging });

menu.addItem({ command: CommandIDs.gitToggleDoubleClickDiff });

menu.addItem({ type: 'separator' });

const tutorial = new Menu({ commands });
tutorial.title.label = ' Help ';
RESOURCES.map(args => {
tutorial.addItem({
args,
command: CommandIDs.gitOpenUrl
});
});

menu.addItem({ type: 'submenu', submenu: tutorial });

return menu;
}

/* eslint-disable no-inner-declarations */
namespace Private {
/**
Expand Down
127 changes: 127 additions & 0 deletions src/components/Alert.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import * as React from 'react';
import Portal from '@material-ui/core/Portal';
import Snackbar from '@material-ui/core/Snackbar';
import Slide from '@material-ui/core/Slide';
import { default as MuiAlert } from '@material-ui/lab/Alert';
import { Severity } from '../tokens';

/**
* Returns a React component for "sliding-in" an alert.
*
* @private
* @param props - component properties
* @returns React element
*/
function SlideTransition(props: any): React.ReactElement {
return <Slide {...props} direction="up" />;
}

/**
* Interface describing component properties.
*/
export interface IAlertProps {
/**
* Boolean indicating whether to display an alert.
*/
open: boolean;

/**
* Alert message.
*/
message: string;

/**
* Alert severity.
*/
severity?: Severity;

/**
* Alert duration (in milliseconds).
*/
duration?: number;

/**
* Callback invoked upon clicking on an alert.
*/
onClick?: (event?: any) => void;

/**
* Callback invoked upon closing an alert.
*/
onClose: (event?: any) => void;
}

/**
* React component for rendering an alert.
*/
export class Alert extends React.Component<IAlertProps> {
/**
* Returns a React component for rendering an alert.
*
* @param props - component properties
* @returns React component
*/
constructor(props: IAlertProps) {
super(props);
}

/**
* Renders the component.
*
* @returns React element
*/
render(): React.ReactElement {
let duration: number | null = null;

const severity = this.props.severity || 'info';
if (severity === 'success') {
duration = this.props.duration || 5000; // milliseconds
}
return (
<Portal>
<Snackbar
key="git:alert"
open={this.props.open}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'right'
}}
autoHideDuration={duration}
TransitionComponent={SlideTransition}
onClick={this._onClick}
onClose={this._onClose}
>
<MuiAlert variant="filled" severity={severity}>
{this.props.message || '(missing message)'}
</MuiAlert>
</Snackbar>
</Portal>
);
}

/**
* Callback invoked upon clicking on an alert.
*
* @param event - event object
*/
private _onClick = (event: any): void => {
if (this.props.onClick) {
this.props.onClick(event);
return;
}
this._onClose(event, 'click');
};

/**
* Callback invoked upon closing an alert.
*
* @param event - event object
* @param reason - reason why the callback was invoked
*/
private _onClose = (event: any, reason: string): void => {
if (reason === 'clickaway') {
return;
}
this.props.onClose(event);
};
}
Loading

0 comments on commit dafc400

Please sign in to comment.