|
1 |
| -import { ISettingRegistry } from '@jupyterlab/coreutils'; |
2 |
| - |
3 | 1 | import * as React from 'react';
|
4 | 2 | import TextareaAutosize from 'react-textarea-autosize';
|
5 | 3 | import { classes } from 'typestyle';
|
6 |
| - |
7 | 4 | import {
|
8 |
| - stagedCommitButtonDisabledStyle, |
9 |
| - stagedCommitButtonReadyStyle, |
10 |
| - stagedCommitButtonStyle, |
11 |
| - stagedCommitMessageStyle, |
12 |
| - stagedCommitStyle, |
13 |
| - textInputStyle |
14 |
| -} from '../style/BranchHeaderStyle'; |
| 5 | + commitFormClass, |
| 6 | + commitSummaryClass, |
| 7 | + commitDescriptionClass, |
| 8 | + commitButtonClass, |
| 9 | + commitButtonDisabledClass |
| 10 | +} from '../style/CommitBox'; |
15 | 11 |
|
| 12 | +/** |
| 13 | + * Interface describing component properties. |
| 14 | + */ |
16 | 15 | export interface ICommitBoxProps {
|
| 16 | + /** |
| 17 | + * Boolean indicating whether files currently exist which have changes to commit. |
| 18 | + */ |
17 | 19 | hasFiles: boolean;
|
18 |
| - commitFunc: (message: string) => Promise<void>; |
19 |
| - settings: ISettingRegistry.ISettings; |
| 20 | + |
| 21 | + /** |
| 22 | + * Callback to invoke in order to commit changes. |
| 23 | + * |
| 24 | + * @param msg - commit message |
| 25 | + * @returns a promise which commits changes |
| 26 | + */ |
| 27 | + onCommit: (msg: string) => Promise<void>; |
20 | 28 | }
|
21 | 29 |
|
| 30 | +/** |
| 31 | + * Interface describing component state. |
| 32 | + */ |
22 | 33 | export interface ICommitBoxState {
|
23 | 34 | /**
|
24 |
| - * Commit message |
| 35 | + * Commit message summary. |
25 | 36 | */
|
26 |
| - value: string; |
| 37 | + summary: string; |
| 38 | + |
| 39 | + /** |
| 40 | + * Commit message description. |
| 41 | + */ |
| 42 | + description: string; |
27 | 43 | }
|
28 | 44 |
|
| 45 | +/** |
| 46 | + * React component for entering a commit message. |
| 47 | + */ |
29 | 48 | export class CommitBox extends React.Component<
|
30 | 49 | ICommitBoxProps,
|
31 | 50 | ICommitBoxState
|
32 | 51 | > {
|
| 52 | + /** |
| 53 | + * Returns a React component for entering a commit message. |
| 54 | + * |
| 55 | + * @param props - component properties |
| 56 | + * @returns React component |
| 57 | + */ |
33 | 58 | constructor(props: ICommitBoxProps) {
|
34 | 59 | super(props);
|
35 | 60 | this.state = {
|
36 |
| - value: '' |
| 61 | + summary: '', |
| 62 | + description: '' |
37 | 63 | };
|
38 | 64 | }
|
39 | 65 |
|
40 |
| - /** Prevent enter key triggered 'submit' action during commit message input */ |
41 |
| - onKeyPress(event: any): void { |
42 |
| - if (event.which === 13) { |
43 |
| - event.preventDefault(); |
44 |
| - this.setState({ value: this.state.value + '\n' }); |
45 |
| - } |
46 |
| - } |
47 |
| - |
48 |
| - /** Initalize commit message input box */ |
49 |
| - initializeInput = (): void => { |
50 |
| - this.setState({ |
51 |
| - value: '' |
52 |
| - }); |
53 |
| - }; |
54 |
| - |
55 |
| - /** Handle input inside commit message box */ |
56 |
| - handleChange = (event: any): void => { |
57 |
| - this.setState({ |
58 |
| - value: event.target.value |
59 |
| - }); |
60 |
| - }; |
61 |
| - |
62 |
| - /** Update state of commit message input box */ |
63 |
| - commitButtonStyle = (hasStagedFiles: boolean) => { |
64 |
| - if (hasStagedFiles) { |
65 |
| - if (this.state.value.length === 0) { |
66 |
| - return classes(stagedCommitButtonStyle, stagedCommitButtonReadyStyle); |
67 |
| - } else { |
68 |
| - return stagedCommitButtonStyle; |
69 |
| - } |
70 |
| - } else { |
71 |
| - return classes(stagedCommitButtonStyle, stagedCommitButtonDisabledStyle); |
72 |
| - } |
73 |
| - }; |
74 |
| - |
| 66 | + /** |
| 67 | + * Renders the component. |
| 68 | + * |
| 69 | + * @returns fragment |
| 70 | + */ |
75 | 71 | render() {
|
| 72 | + const disabled = !(this.props.hasFiles && this.state.summary); |
76 | 73 | return (
|
77 |
| - <form |
78 |
| - className={stagedCommitStyle} |
79 |
| - onKeyPress={event => this.onKeyPress(event)} |
80 |
| - > |
| 74 | + <form className={commitFormClass}> |
| 75 | + <input |
| 76 | + className={commitSummaryClass} |
| 77 | + type="text" |
| 78 | + placeholder="Summary (required)" |
| 79 | + title="Enter a commit message summary (a single line, preferably less than 50 characters)" |
| 80 | + value={this.state.summary} |
| 81 | + onChange={this._onSummaryChange} |
| 82 | + onKeyPress={this._onSummaryKeyPress} |
| 83 | + /> |
81 | 84 | <TextareaAutosize
|
82 |
| - className={classes(textInputStyle, stagedCommitMessageStyle)} |
83 |
| - disabled={!this.props.hasFiles} |
84 |
| - minRows={2} |
85 |
| - onChange={this.handleChange} |
86 |
| - placeholder={this._placeholder()} |
87 |
| - value={this.state.value} |
| 85 | + className={commitDescriptionClass} |
| 86 | + minRows={5} |
| 87 | + placeholder="Description" |
| 88 | + title="Enter a commit message description" |
| 89 | + value={this.state.description} |
| 90 | + onChange={this._onDescriptionChange} |
88 | 91 | />
|
89 | 92 | <input
|
90 |
| - className={this.commitButtonStyle(this.props.hasFiles)} |
| 93 | + className={classes( |
| 94 | + commitButtonClass, |
| 95 | + disabled ? commitButtonDisabledClass : null |
| 96 | + )} |
91 | 97 | type="button"
|
92 | 98 | title="Commit"
|
93 |
| - disabled={!(this.props.hasFiles && this.state.value)} |
94 |
| - onClick={() => { |
95 |
| - this.props.commitFunc(this.state.value); |
96 |
| - this.initializeInput(); |
97 |
| - }} |
| 99 | + value="Commit" |
| 100 | + disabled={disabled} |
| 101 | + onClick={this._onCommitClick} |
98 | 102 | />
|
99 | 103 | </form>
|
100 | 104 | );
|
101 | 105 | }
|
102 | 106 |
|
103 |
| - protected _placeholder = (): string => { |
104 |
| - if (this.props.settings.composite['simpleStaging']) { |
105 |
| - return this.props.hasFiles |
106 |
| - ? 'Input message to commit selected changes' |
107 |
| - : 'Select changes to enable commit'; |
108 |
| - } else { |
109 |
| - return this.props.hasFiles |
110 |
| - ? 'Input message to commit staged changes' |
111 |
| - : 'Stage your changes before commit'; |
| 107 | + /** |
| 108 | + * Callback invoked upon clicking a commit message submit button. |
| 109 | + * |
| 110 | + * @param event - event object |
| 111 | + */ |
| 112 | + private _onCommitClick = () => { |
| 113 | + const msg = this.state.summary + '\n' + this.state.description + '\n'; |
| 114 | + this.props.onCommit(msg); |
| 115 | + |
| 116 | + // NOTE: we assume here that committing changes always works and we can safely clear component state |
| 117 | + this._reset(); |
| 118 | + }; |
| 119 | + |
| 120 | + /** |
| 121 | + * Callback invoked upon updating a commit message description. |
| 122 | + * |
| 123 | + * @param event - event object |
| 124 | + */ |
| 125 | + private _onDescriptionChange = (event: any): void => { |
| 126 | + this.setState({ |
| 127 | + description: event.target.value |
| 128 | + }); |
| 129 | + }; |
| 130 | + |
| 131 | + /** |
| 132 | + * Callback invoked upon updating a commit message summary. |
| 133 | + * |
| 134 | + * @param event - event object |
| 135 | + */ |
| 136 | + private _onSummaryChange = (event: any): void => { |
| 137 | + this.setState({ |
| 138 | + summary: event.target.value |
| 139 | + }); |
| 140 | + }; |
| 141 | + |
| 142 | + /** |
| 143 | + * Callback invoked upon a `'keypress'` event when entering a commit message summary. |
| 144 | + * |
| 145 | + * ## Notes |
| 146 | + * |
| 147 | + * - Prevents triggering a `'submit'` action when hitting the `ENTER` key while entering a commit message summary. |
| 148 | + * |
| 149 | + * @param event - event object |
| 150 | + */ |
| 151 | + private _onSummaryKeyPress(event: any): void { |
| 152 | + if (event.which === 13) { |
| 153 | + event.preventDefault(); |
112 | 154 | }
|
| 155 | + } |
| 156 | + |
| 157 | + /** |
| 158 | + * Resets component state (e.g., in order to re-initialize the commit message input box). |
| 159 | + */ |
| 160 | + private _reset = (): void => { |
| 161 | + this.setState({ |
| 162 | + summary: '', |
| 163 | + description: '' |
| 164 | + }); |
113 | 165 | };
|
114 | 166 | }
|
0 commit comments