UNPKG

@jupyterlab/git

Version:

A JupyterLab extension for version control using git

144 lines (143 loc) 7.52 kB
import { checkIcon } from '@jupyterlab/ui-components'; import { CommandRegistry } from '@lumino/commands'; import Button from '@mui/material/Button'; import ButtonGroup from '@mui/material/ButtonGroup'; import ClickAwayListener from '@mui/material/ClickAwayListener'; import Grow from '@mui/material/Grow'; import MenuItem from '@mui/material/MenuItem'; import MenuList from '@mui/material/MenuList'; import Paper from '@mui/material/Paper'; import Popper from '@mui/material/Popper'; import * as React from 'react'; import { classes } from 'typestyle'; import { listItemIconClass } from '../style/BranchMenu'; import { commitButtonClass, commitFormClass, commitPaperClass, commitRoot, commitVariantSelector, disabledStyle } from '../style/CommitBox'; import { verticalMoreIcon } from '../style/icons'; import { listItemBoldTitleClass, listItemContentClass, listItemDescClass } from '../style/NewBranchDialog'; import { CommandIDs } from '../tokens'; import { CommitMessage } from './CommitMessage'; /** * React component for entering a commit message. */ export class CommitBox extends React.Component { /** * Returns a React component for entering a commit message. * * @param props - component properties * @returns React component */ constructor(props) { super(props); /** * Get keystroke configured to act as a submit action. */ this._getSubmitKeystroke = () => { var _a; const binding = this.props.commands.keyBindings.find(binding => binding.command === CommandIDs.gitSubmitCommand); return (_a = binding === null || binding === void 0 ? void 0 : binding.keys.join(' ')) !== null && _a !== void 0 ? _a : ''; }; /** * Close the commit variant menu if needed. */ this._handleClose = (event) => { if (this._anchorRef.current && this._anchorRef.current.contains(event.target)) { return; } this.setState({ open: false }); }; /** * Handle commit variant menu item click */ this._handleMenuItemClick = (event, index) => { this.setState({ open: false }); this.props.setAmend(index === 1); }; /** * Toggle state of the commit variant menu visibility */ this._handleToggle = () => { this.setState({ open: !this.state.open }); }; /** * Callback invoked upon command execution activated when entering a commit message description. * * ## Notes * * - Triggers the `'submit'` action on appropriate command (and if commit is possible) * */ this._handleCommand = (_, commandArgs) => { if (commandArgs.id === CommandIDs.gitSubmitCommand && this._canCommit()) { this.props.onCommit(); } }; this._options = []; this._options.push({ title: this.props.trans.__('Create a new commit'), description: this.props.trans.__('New commit will be created and show up as a next one after the previous commit (default).') }, { title: this.props.trans.__('Amend previous commit'), description: this.props.trans.__('Staged changes will be added to the previous commit and its date will be updated.') }); this._anchorRef = React.createRef(); this.state = { open: false }; } componentDidMount() { this.props.commands.commandExecuted.connect(this._handleCommand); } componentWillUnmount() { this.props.commands.commandExecuted.disconnect(this._handleCommand); } /** * Renders the component. * * @returns React element */ render() { var _a; const disabled = !this._canCommit(); const title = !this.props.hasFiles ? this.props.trans.__('Disabled: No files are staged for commit') : !this.props.summary && !this.props.amend ? this.props.trans.__('Disabled: No commit message summary') : this.props.label; const shortcutHint = CommandRegistry.formatKeystroke(this._getSubmitKeystroke()); const summaryPlaceholder = this.props.trans.__('Summary (%1 to commit)', shortcutHint); return (React.createElement("div", { className: classes(commitFormClass, 'jp-git-CommitBox') }, (_a = this.props.warning) !== null && _a !== void 0 ? _a : null, !this.props.amend && (React.createElement(CommitMessage, { error: this.props.hasFiles && !this.props.amend && this.props.summary.length === 0, trans: this.props.trans, summary: this.props.summary, summaryPlaceholder: summaryPlaceholder, description: this.props.description, setSummary: this.props.setSummary, setDescription: this.props.setDescription })), React.createElement(ButtonGroup, { ref: this._anchorRef, fullWidth: true, size: "small" }, React.createElement(Button, { classes: { root: commitButtonClass, disabled: disabledStyle }, title: title, disabled: disabled, onClick: this.props.onCommit }, this.props.label), React.createElement(Button, { classes: { root: classes(commitButtonClass, commitVariantSelector), disabled: disabledStyle }, size: "small", disabled: !this.props.hasFiles, "aria-controls": this.state.open ? 'split-button-menu' : undefined, "aria-expanded": this.state.open ? 'true' : undefined, "aria-label": "select commit variant", "aria-haspopup": "menu", onClick: this._handleToggle }, React.createElement(verticalMoreIcon.react, { tag: "span" }))), React.createElement(Popper, { open: this.state.open, anchorEl: this._anchorRef.current, role: undefined, transition: true, disablePortal: true }, ({ TransitionProps }) => (React.createElement(Grow, { ...TransitionProps }, React.createElement(Paper, { classes: { root: classes(commitRoot, commitPaperClass) } }, React.createElement(ClickAwayListener, { onClickAway: this._handleClose }, React.createElement(MenuList, { id: "split-button-menu" }, this._options.map((option, index) => (React.createElement(MenuItem, { key: option.title, classes: { root: commitRoot }, selected: this.props.amend ? index === 1 : index === 0, onClick: event => this._handleMenuItemClick(event, index) }, (this.props.amend ? index === 1 : index === 0) ? (React.createElement(checkIcon.react, { className: listItemIconClass, tag: "span" })) : (React.createElement("span", { className: listItemIconClass })), React.createElement("div", { className: listItemContentClass }, React.createElement("p", { className: listItemBoldTitleClass }, option.title), React.createElement("p", { className: listItemDescClass }, option.description))))))))))))); } /** * Whether a commit can be performed (files are staged and summary is not empty). */ _canCommit() { if (this.props.amend) { return this.props.hasFiles; } return !!(this.props.hasFiles && this.props.summary); } }