@theia/scm 1.45.1 → 1.46.0-next.72
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -31
- package/lib/browser/decorations/scm-decorations-service.d.ts +14 -14
- package/lib/browser/decorations/scm-decorations-service.js +101 -101
- package/lib/browser/decorations/scm-navigator-decorator.d.ts +25 -25
- package/lib/browser/decorations/scm-navigator-decorator.js +132 -132
- package/lib/browser/decorations/scm-tab-bar-decorator.d.ts +17 -17
- package/lib/browser/decorations/scm-tab-bar-decorator.js +93 -93
- package/lib/browser/dirty-diff/content-lines.d.ts +12 -12
- package/lib/browser/dirty-diff/content-lines.js +106 -106
- package/lib/browser/dirty-diff/content-lines.spec.d.ts +1 -1
- package/lib/browser/dirty-diff/content-lines.spec.js +39 -39
- package/lib/browser/dirty-diff/diff-computer.d.ts +29 -29
- package/lib/browser/dirty-diff/diff-computer.js +102 -102
- package/lib/browser/dirty-diff/diff-computer.spec.d.ts +1 -1
- package/lib/browser/dirty-diff/diff-computer.spec.js +315 -315
- package/lib/browser/dirty-diff/dirty-diff-decorator.d.ts +14 -14
- package/lib/browser/dirty-diff/dirty-diff-decorator.js +98 -98
- package/lib/browser/dirty-diff/dirty-diff-module.d.ts +3 -3
- package/lib/browser/dirty-diff/dirty-diff-module.js +24 -24
- package/lib/browser/scm-amend-component.d.ts +123 -123
- package/lib/browser/scm-amend-component.js +463 -463
- package/lib/browser/scm-amend-widget.d.ts +20 -20
- package/lib/browser/scm-amend-widget.js +101 -101
- package/lib/browser/scm-avatar-service.d.ts +3 -3
- package/lib/browser/scm-avatar-service.js +36 -36
- package/lib/browser/scm-commit-widget.d.ts +52 -52
- package/lib/browser/scm-commit-widget.js +199 -199
- package/lib/browser/scm-context-key-service.d.ts +10 -10
- package/lib/browser/scm-context-key-service.js +58 -58
- package/lib/browser/scm-contribution.d.ts +83 -83
- package/lib/browser/scm-contribution.js +356 -356
- package/lib/browser/scm-frontend-module.d.ts +6 -6
- package/lib/browser/scm-frontend-module.js +130 -130
- package/lib/browser/scm-groups-tree-model.d.ts +14 -14
- package/lib/browser/scm-groups-tree-model.js +97 -97
- package/lib/browser/scm-input.d.ts +53 -53
- package/lib/browser/scm-input.js +127 -127
- package/lib/browser/scm-layout-migrations.d.ts +9 -9
- package/lib/browser/scm-layout-migrations.js +79 -79
- package/lib/browser/scm-no-repository-widget.d.ts +8 -8
- package/lib/browser/scm-no-repository-widget.js +49 -49
- package/lib/browser/scm-preferences.d.ts +11 -11
- package/lib/browser/scm-preferences.js +51 -51
- package/lib/browser/scm-provider.d.ts +58 -58
- package/lib/browser/scm-provider.js +19 -19
- package/lib/browser/scm-quick-open-service.d.ts +11 -11
- package/lib/browser/scm-quick-open-service.js +73 -73
- package/lib/browser/scm-repository.d.ts +17 -17
- package/lib/browser/scm-repository.js +41 -41
- package/lib/browser/scm-service.d.ts +26 -26
- package/lib/browser/scm-service.js +108 -108
- package/lib/browser/scm-tree-label-provider.d.ts +7 -7
- package/lib/browser/scm-tree-label-provider.js +57 -57
- package/lib/browser/scm-tree-model.d.ts +74 -74
- package/lib/browser/scm-tree-model.js +351 -351
- package/lib/browser/scm-tree-widget.d.ts +208 -208
- package/lib/browser/scm-tree-widget.js +703 -703
- package/lib/browser/scm-widget.d.ts +40 -40
- package/lib/browser/scm-widget.js +218 -218
- package/package.json +6 -6
- package/src/browser/decorations/scm-decorations-service.ts +78 -78
- package/src/browser/decorations/scm-navigator-decorator.ts +121 -121
- package/src/browser/decorations/scm-tab-bar-decorator.ts +83 -83
- package/src/browser/dirty-diff/content-lines.spec.ts +42 -42
- package/src/browser/dirty-diff/content-lines.ts +112 -112
- package/src/browser/dirty-diff/diff-computer.spec.ts +387 -387
- package/src/browser/dirty-diff/diff-computer.ts +129 -129
- package/src/browser/dirty-diff/dirty-diff-decorator.ts +107 -107
- package/src/browser/dirty-diff/dirty-diff-module.ts +24 -24
- package/src/browser/scm-amend-component.tsx +600 -600
- package/src/browser/scm-amend-widget.tsx +77 -77
- package/src/browser/scm-avatar-service.ts +27 -27
- package/src/browser/scm-commit-widget.tsx +215 -215
- package/src/browser/scm-context-key-service.ts +46 -46
- package/src/browser/scm-contribution.ts +361 -361
- package/src/browser/scm-frontend-module.ts +149 -149
- package/src/browser/scm-groups-tree-model.ts +78 -78
- package/src/browser/scm-input.ts +164 -164
- package/src/browser/scm-layout-migrations.ts +64 -64
- package/src/browser/scm-no-repository-widget.tsx +41 -41
- package/src/browser/scm-preferences.ts +63 -63
- package/src/browser/scm-provider.ts +91 -91
- package/src/browser/scm-quick-open-service.ts +48 -48
- package/src/browser/scm-repository.ts +52 -52
- package/src/browser/scm-service.ts +108 -108
- package/src/browser/scm-tree-label-provider.ts +44 -44
- package/src/browser/scm-tree-model.ts +405 -405
- package/src/browser/scm-tree-widget.tsx +838 -838
- package/src/browser/scm-widget.tsx +204 -204
- package/src/browser/style/dirty-diff-decorator.css +52 -52
- package/src/browser/style/dirty-diff.css +50 -50
- package/src/browser/style/index.css +271 -271
- package/src/browser/style/scm-amend-component.css +94 -94
- package/src/browser/style/scm.svg +4 -4
|
@@ -1,464 +1,464 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
// *****************************************************************************
|
|
3
|
-
// Copyright (C) 2019 Arm and others.
|
|
4
|
-
//
|
|
5
|
-
// This program and the accompanying materials are made available under the
|
|
6
|
-
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
7
|
-
// http://www.eclipse.org/legal/epl-2.0.
|
|
8
|
-
//
|
|
9
|
-
// This Source Code may also be made available under the following Secondary
|
|
10
|
-
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
11
|
-
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
12
|
-
// with the GNU Classpath Exception which is available at
|
|
13
|
-
// https://www.gnu.org/software/classpath/license.html.
|
|
14
|
-
//
|
|
15
|
-
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
16
|
-
// *****************************************************************************
|
|
17
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
-
exports.ScmAmendComponent = void 0;
|
|
19
|
-
require("../../src/browser/style/scm-amend-component.css");
|
|
20
|
-
const React = require("@theia/core/shared/react");
|
|
21
|
-
const browser_1 = require("@theia/core/lib/browser");
|
|
22
|
-
const core_1 = require("@theia/core");
|
|
23
|
-
const nls_1 = require("@theia/core/lib/common/nls");
|
|
24
|
-
const TRANSITION_TIME_MS = 300;
|
|
25
|
-
const REPOSITORY_STORAGE_KEY = 'scmRepository';
|
|
26
|
-
class ScmAmendComponent extends React.Component {
|
|
27
|
-
constructor(props) {
|
|
28
|
-
super(props);
|
|
29
|
-
/**
|
|
30
|
-
* a hint on how to animate an update, set by certain user action handlers
|
|
31
|
-
* and used when updating the view based on a repository change
|
|
32
|
-
*/
|
|
33
|
-
this.transitionHint = 'none';
|
|
34
|
-
this.lastCommitHeight = 0;
|
|
35
|
-
this.lastCommitScrollRef = (instance) => {
|
|
36
|
-
if (instance && this.lastCommitHeight === 0) {
|
|
37
|
-
this.lastCommitHeight = instance.getBoundingClientRect().height;
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
this.toDisposeOnUnmount = new core_1.DisposableCollection();
|
|
41
|
-
/**
|
|
42
|
-
* This function will update the 'model' (lastCommit, amendingCommits) only
|
|
43
|
-
* when the repository sees the last commit change.
|
|
44
|
-
* 'render' can be called at any time, so be sure we don't update any 'model'
|
|
45
|
-
* fields until we actually start the transition.
|
|
46
|
-
*/
|
|
47
|
-
this.amend = async () => {
|
|
48
|
-
if (this.state.transition.state !== 'none' && this.transitionHint !== 'none') {
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
this.transitionHint = 'amend';
|
|
52
|
-
await this.resetAndSetMessage('HEAD~', 'HEAD');
|
|
53
|
-
};
|
|
54
|
-
this.unamend = async () => {
|
|
55
|
-
if (this.state.transition.state !== 'none' && this.transitionHint !== 'none') {
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
const commitToRestore = (this.state.amendingCommits.length >= 1)
|
|
59
|
-
? this.state.amendingCommits[this.state.amendingCommits.length - 1]
|
|
60
|
-
: undefined;
|
|
61
|
-
const oldestAmendCommit = (this.state.amendingCommits.length >= 2)
|
|
62
|
-
? this.state.amendingCommits[this.state.amendingCommits.length - 2]
|
|
63
|
-
: undefined;
|
|
64
|
-
if (commitToRestore) {
|
|
65
|
-
const commitToUseForMessage = oldestAmendCommit
|
|
66
|
-
? oldestAmendCommit.commit.id
|
|
67
|
-
: undefined;
|
|
68
|
-
this.transitionHint = 'unamend';
|
|
69
|
-
await this.resetAndSetMessage(commitToRestore.commit.id, commitToUseForMessage);
|
|
70
|
-
}
|
|
71
|
-
};
|
|
72
|
-
this.unamendAll = () => this.doUnamendAll();
|
|
73
|
-
this.clearAmending = () => this.doClearAmending();
|
|
74
|
-
this.state = {
|
|
75
|
-
transition: { state: 'none' },
|
|
76
|
-
amendingCommits: [],
|
|
77
|
-
lastCommit: undefined
|
|
78
|
-
};
|
|
79
|
-
const setState = this.setState.bind(this);
|
|
80
|
-
this.setState = newState => {
|
|
81
|
-
if (!this.toDisposeOnUnmount.disposed) {
|
|
82
|
-
setState(newState);
|
|
83
|
-
}
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
async componentDidMount() {
|
|
87
|
-
this.toDisposeOnUnmount.push(core_1.Disposable.create(() => { }));
|
|
88
|
-
const lastCommit = await this.getLastCommit();
|
|
89
|
-
this.setState({ amendingCommits: await this.buildAmendingList(lastCommit ? lastCommit.commit : undefined), lastCommit });
|
|
90
|
-
if (this.toDisposeOnUnmount.disposed) {
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
this.toDisposeOnUnmount.push(this.props.repository.provider.onDidChange(() => this.fetchStatusAndSetState()));
|
|
94
|
-
}
|
|
95
|
-
componentWillUnmount() {
|
|
96
|
-
this.toDisposeOnUnmount.dispose();
|
|
97
|
-
}
|
|
98
|
-
async fetchStatusAndSetState() {
|
|
99
|
-
const storageKey = this.getStorageKey();
|
|
100
|
-
const nextCommit = await this.getLastCommit();
|
|
101
|
-
if (nextCommit && this.state.lastCommit && nextCommit.commit.id === this.state.lastCommit.commit.id) {
|
|
102
|
-
// No change here
|
|
103
|
-
}
|
|
104
|
-
else if (nextCommit === undefined && this.state.lastCommit === undefined) {
|
|
105
|
-
// No change here
|
|
106
|
-
}
|
|
107
|
-
else if (this.transitionHint === 'none') {
|
|
108
|
-
// If the 'last' commit changes, but we are not expecting an 'amend'
|
|
109
|
-
// or 'unamend' to occur, then we clear out the list of amended commits.
|
|
110
|
-
// This is because an unexpected change has happened to the repository,
|
|
111
|
-
// perhaps the user committed, merged, or something. The amended commits
|
|
112
|
-
// will no longer be valid.
|
|
113
|
-
// Note that there may or may not have been a previous lastCommit (if the
|
|
114
|
-
// repository was previously empty with no initial commit then lastCommit
|
|
115
|
-
// will be undefined). Either way we clear the amending commits.
|
|
116
|
-
await this.clearAmendingCommits();
|
|
117
|
-
// There is a change to the last commit, but no transition hint so
|
|
118
|
-
// the view just updates without transition.
|
|
119
|
-
this.setState({ amendingCommits: [], lastCommit: nextCommit });
|
|
120
|
-
}
|
|
121
|
-
else {
|
|
122
|
-
const amendingCommits = this.state.amendingCommits.concat([]); // copy the array
|
|
123
|
-
const direction = this.transitionHint === 'amend' ? 'up' : 'down';
|
|
124
|
-
switch (this.transitionHint) {
|
|
125
|
-
case 'amend':
|
|
126
|
-
if (this.state.lastCommit) {
|
|
127
|
-
amendingCommits.push(this.state.lastCommit);
|
|
128
|
-
const serializedState = JSON.stringify({
|
|
129
|
-
amendingHeadCommitSha: amendingCommits[0].commit.id,
|
|
130
|
-
latestCommitSha: nextCommit ? nextCommit.commit.id : undefined
|
|
131
|
-
});
|
|
132
|
-
this.props.storageService.setData(storageKey, serializedState);
|
|
133
|
-
}
|
|
134
|
-
break;
|
|
135
|
-
case 'unamend':
|
|
136
|
-
amendingCommits.pop();
|
|
137
|
-
if (amendingCommits.length === 0) {
|
|
138
|
-
this.props.storageService.setData(storageKey, undefined);
|
|
139
|
-
}
|
|
140
|
-
else {
|
|
141
|
-
const serializedState = JSON.stringify({
|
|
142
|
-
amendingHeadCommitSha: amendingCommits[0].commit.id,
|
|
143
|
-
latestCommitSha: nextCommit ? nextCommit.commit.id : undefined
|
|
144
|
-
});
|
|
145
|
-
this.props.storageService.setData(storageKey, serializedState);
|
|
146
|
-
}
|
|
147
|
-
break;
|
|
148
|
-
}
|
|
149
|
-
if (this.state.lastCommit && nextCommit) {
|
|
150
|
-
const transitionData = { direction, previousLastCommit: this.state.lastCommit };
|
|
151
|
-
this.setState({ lastCommit: nextCommit, amendingCommits, transition: { ...transitionData, state: 'start' } });
|
|
152
|
-
this.onNextFrame(() => {
|
|
153
|
-
this.setState({ transition: { ...transitionData, state: 'transitioning' } });
|
|
154
|
-
});
|
|
155
|
-
setTimeout(() => {
|
|
156
|
-
this.setState({ transition: { state: 'none' } });
|
|
157
|
-
}, TRANSITION_TIME_MS);
|
|
158
|
-
}
|
|
159
|
-
else {
|
|
160
|
-
// No previous last commit so no transition
|
|
161
|
-
this.setState({ transition: { state: 'none' }, amendingCommits, lastCommit: nextCommit });
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
this.transitionHint = 'none';
|
|
165
|
-
}
|
|
166
|
-
async clearAmendingCommits() {
|
|
167
|
-
const storageKey = this.getStorageKey();
|
|
168
|
-
await this.props.storageService.setData(storageKey, undefined);
|
|
169
|
-
}
|
|
170
|
-
async buildAmendingList(lastCommit) {
|
|
171
|
-
const storageKey = this.getStorageKey();
|
|
172
|
-
const storedState = await this.props.storageService.getData(storageKey, undefined);
|
|
173
|
-
// Restore list of commits from saved amending head commit up through parents until the
|
|
174
|
-
// current commit. (If we don't reach the current commit, the repository has been changed in such
|
|
175
|
-
// a way then unamending commits can no longer be done).
|
|
176
|
-
if (storedState) {
|
|
177
|
-
const { amendingHeadCommitSha, latestCommitSha } = JSON.parse(storedState);
|
|
178
|
-
if (!this.commitsAreEqual(lastCommit, latestCommitSha)) {
|
|
179
|
-
// The head commit in the repository has changed. It is not the same commit that was the
|
|
180
|
-
// head commit after the last 'amend'.
|
|
181
|
-
return [];
|
|
182
|
-
}
|
|
183
|
-
const commits = await this.props.scmAmendSupport.getInitialAmendingCommits(amendingHeadCommitSha, lastCommit ? lastCommit.id : undefined);
|
|
184
|
-
const amendingCommitPromises = commits.map(async (commit) => {
|
|
185
|
-
const avatar = await this.props.avatarService.getAvatar(commit.authorEmail);
|
|
186
|
-
return { commit, avatar };
|
|
187
|
-
});
|
|
188
|
-
return Promise.all(amendingCommitPromises);
|
|
189
|
-
}
|
|
190
|
-
else {
|
|
191
|
-
return [];
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
getStorageKey() {
|
|
195
|
-
return REPOSITORY_STORAGE_KEY + ':' + this.props.repository.provider.rootUri;
|
|
196
|
-
}
|
|
197
|
-
/**
|
|
198
|
-
* Commits are equal if the ids are equal or if both are undefined.
|
|
199
|
-
* (If a commit is undefined, it represents the initial empty state of a repository,
|
|
200
|
-
* before the initial commit).
|
|
201
|
-
*/
|
|
202
|
-
commitsAreEqual(lastCommit, savedLastCommitId) {
|
|
203
|
-
return lastCommit
|
|
204
|
-
? lastCommit.id === savedLastCommitId
|
|
205
|
-
: savedLastCommitId === undefined;
|
|
206
|
-
}
|
|
207
|
-
async resetAndSetMessage(commitToRestore, commitToUseForMessage) {
|
|
208
|
-
const message = commitToUseForMessage
|
|
209
|
-
? await this.props.scmAmendSupport.getMessage(commitToUseForMessage)
|
|
210
|
-
: '';
|
|
211
|
-
await this.props.scmAmendSupport.reset(commitToRestore);
|
|
212
|
-
this.props.setCommitMessage(message);
|
|
213
|
-
}
|
|
214
|
-
render() {
|
|
215
|
-
const neverShrink = this.state.amendingCommits.length <= 3;
|
|
216
|
-
const style = neverShrink
|
|
217
|
-
? {
|
|
218
|
-
...this.props.style,
|
|
219
|
-
flexShrink: 0,
|
|
220
|
-
}
|
|
221
|
-
: {
|
|
222
|
-
...this.props.style,
|
|
223
|
-
flexShrink: 1,
|
|
224
|
-
minHeight: 240 // height with three commits
|
|
225
|
-
};
|
|
226
|
-
return (React.createElement("div", { className: ScmAmendComponent.Styles.COMMIT_CONTAINER + ' no-select', style: style },
|
|
227
|
-
this.state.amendingCommits.length > 0 || (this.state.lastCommit && this.state.transition.state !== 'none' && this.state.transition.direction === 'down')
|
|
228
|
-
? this.renderAmendingCommits()
|
|
229
|
-
: '',
|
|
230
|
-
this.state.lastCommit ?
|
|
231
|
-
React.createElement("div", null,
|
|
232
|
-
React.createElement("div", { id: 'lastCommit', className: 'theia-scm-amend' },
|
|
233
|
-
React.createElement("div", { className: 'theia-header scm-theia-header' }, nls_1.nls.localize('theia/scm/amendHeadCommit', 'HEAD Commit')),
|
|
234
|
-
this.renderLastCommit()))
|
|
235
|
-
: ''));
|
|
236
|
-
}
|
|
237
|
-
async getLastCommit() {
|
|
238
|
-
const commit = await this.props.scmAmendSupport.getLastCommit();
|
|
239
|
-
if (commit) {
|
|
240
|
-
const avatar = await this.props.avatarService.getAvatar(commit.authorEmail);
|
|
241
|
-
return { commit, avatar };
|
|
242
|
-
}
|
|
243
|
-
return undefined;
|
|
244
|
-
}
|
|
245
|
-
renderAmendingCommits() {
|
|
246
|
-
const neverShrink = this.state.amendingCommits.length <= 3;
|
|
247
|
-
const style = neverShrink
|
|
248
|
-
? {
|
|
249
|
-
flexShrink: 0,
|
|
250
|
-
}
|
|
251
|
-
: {
|
|
252
|
-
flexShrink: 1,
|
|
253
|
-
// parent minHeight controls height, we just need any value smaller than
|
|
254
|
-
// what the height would be when the parent is at its minHeight
|
|
255
|
-
minHeight: 0
|
|
256
|
-
};
|
|
257
|
-
return React.createElement("div", { id: 'amendedCommits', className: 'theia-scm-amend-outer-container', style: style },
|
|
258
|
-
React.createElement("div", { className: 'theia-header scm-theia-header' },
|
|
259
|
-
React.createElement("div", { className: 'noWrapInfo' }, "Commits being Amended"),
|
|
260
|
-
this.renderAmendCommitListButtons(),
|
|
261
|
-
this.renderCommitCount(this.state.amendingCommits.length)),
|
|
262
|
-
React.createElement("div", { style: this.styleAmendedCommits() },
|
|
263
|
-
this.state.amendingCommits.map((commitData, index, array) => this.renderCommitBeingAmended(commitData, index === array.length - 1)),
|
|
264
|
-
this.state.lastCommit && this.state.transition.state !== 'none' && this.state.transition.direction === 'down'
|
|
265
|
-
? this.renderCommitBeingAmended(this.state.lastCommit, false)
|
|
266
|
-
: ''));
|
|
267
|
-
}
|
|
268
|
-
renderAmendCommitListButtons() {
|
|
269
|
-
return React.createElement("div", { className: 'theia-scm-inline-actions-container' },
|
|
270
|
-
React.createElement("div", { className: 'theia-scm-inline-actions' },
|
|
271
|
-
React.createElement("div", { className: 'theia-scm-inline-action' },
|
|
272
|
-
React.createElement("a", { className: (0, browser_1.codicon)('dash'), title: 'Unamend All Commits', onClick: this.unamendAll })),
|
|
273
|
-
React.createElement("div", { className: 'theia-scm-inline-action' },
|
|
274
|
-
React.createElement("a", { className: (0, browser_1.codicon)('close'), title: 'Clear Amending Commits', onClick: this.clearAmending }))));
|
|
275
|
-
}
|
|
276
|
-
renderLastCommit() {
|
|
277
|
-
if (!this.state.lastCommit) {
|
|
278
|
-
return '';
|
|
279
|
-
}
|
|
280
|
-
const canAmend = true;
|
|
281
|
-
return React.createElement("div", { className: ScmAmendComponent.Styles.COMMIT_AND_BUTTON, style: { flexGrow: 0, flexShrink: 0 }, key: this.state.lastCommit.commit.id },
|
|
282
|
-
this.renderLastCommitNoButton(this.state.lastCommit),
|
|
283
|
-
canAmend
|
|
284
|
-
? React.createElement("div", { className: ScmAmendComponent.Styles.FLEX_CENTER },
|
|
285
|
-
React.createElement("button", { className: 'theia-button', title: nls_1.nls.localize('theia/scm/amendLastCommit', 'Amend last commit'), onClick: this.amend }, nls_1.nls.localize('theia/scm/amend', 'Amend')))
|
|
286
|
-
: '');
|
|
287
|
-
}
|
|
288
|
-
renderLastCommitNoButton(lastCommit) {
|
|
289
|
-
switch (this.state.transition.state) {
|
|
290
|
-
case 'none':
|
|
291
|
-
return React.createElement("div", { ref: this.lastCommitScrollRef, className: 'theia-scm-scrolling-container' }, this.renderCommitAvatarAndDetail(lastCommit));
|
|
292
|
-
case 'start':
|
|
293
|
-
case 'transitioning':
|
|
294
|
-
switch (this.state.transition.direction) {
|
|
295
|
-
case 'up':
|
|
296
|
-
return React.createElement("div", { style: this.styleLastCommitMovingUp(this.state.transition.state) },
|
|
297
|
-
this.renderCommitAvatarAndDetail(this.state.transition.previousLastCommit),
|
|
298
|
-
this.renderCommitAvatarAndDetail(lastCommit));
|
|
299
|
-
case 'down':
|
|
300
|
-
return React.createElement("div", { style: this.styleLastCommitMovingDown(this.state.transition.state) },
|
|
301
|
-
this.renderCommitAvatarAndDetail(lastCommit),
|
|
302
|
-
this.renderCommitAvatarAndDetail(this.state.transition.previousLastCommit));
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
/**
|
|
307
|
-
* See https://stackoverflow.com/questions/26556436/react-after-render-code
|
|
308
|
-
*
|
|
309
|
-
* @param callback
|
|
310
|
-
*/
|
|
311
|
-
onNextFrame(callback) {
|
|
312
|
-
setTimeout(() => window.requestAnimationFrame(callback), 0);
|
|
313
|
-
}
|
|
314
|
-
renderCommitAvatarAndDetail(commitData) {
|
|
315
|
-
const { commit, avatar } = commitData;
|
|
316
|
-
return React.createElement("div", { className: ScmAmendComponent.Styles.COMMIT_AVATAR_AND_TEXT, key: commit.id },
|
|
317
|
-
React.createElement("div", { className: ScmAmendComponent.Styles.COMMIT_MESSAGE_AVATAR },
|
|
318
|
-
React.createElement("img", { src: avatar })),
|
|
319
|
-
React.createElement("div", { className: ScmAmendComponent.Styles.COMMIT_DETAILS },
|
|
320
|
-
React.createElement("div", { className: ScmAmendComponent.Styles.COMMIT_MESSAGE_SUMMARY }, commit.summary),
|
|
321
|
-
React.createElement("div", { className: ScmAmendComponent.Styles.LAST_COMMIT_MESSAGE_TIME }, `${commit.authorDateRelative} by ${commit.authorName}`)));
|
|
322
|
-
}
|
|
323
|
-
renderCommitCount(commits) {
|
|
324
|
-
return React.createElement("div", { className: 'notification-count-container scm-change-count' },
|
|
325
|
-
React.createElement("span", { className: 'notification-count' }, commits));
|
|
326
|
-
}
|
|
327
|
-
renderCommitBeingAmended(commitData, isOldestAmendCommit) {
|
|
328
|
-
if (isOldestAmendCommit && this.state.transition.state !== 'none' && this.state.transition.direction === 'up') {
|
|
329
|
-
return React.createElement("div", { className: ScmAmendComponent.Styles.COMMIT_AVATAR_AND_TEXT, style: { flexGrow: 0, flexShrink: 0 }, key: commitData.commit.id },
|
|
330
|
-
React.createElement("div", { className: 'fixed-height-commit-container' }, this.renderCommitAvatarAndDetail(commitData)));
|
|
331
|
-
}
|
|
332
|
-
else {
|
|
333
|
-
return React.createElement("div", { className: ScmAmendComponent.Styles.COMMIT_AVATAR_AND_TEXT, style: { flexGrow: 0, flexShrink: 0 }, key: commitData.commit.id },
|
|
334
|
-
this.renderCommitAvatarAndDetail(commitData),
|
|
335
|
-
isOldestAmendCommit
|
|
336
|
-
? React.createElement("div", { className: ScmAmendComponent.Styles.FLEX_CENTER },
|
|
337
|
-
React.createElement("button", { className: 'theia-button', title: nls_1.nls.localize('theia/scm/unamendCommit', 'Unamend commit'), onClick: this.unamend }, nls_1.nls.localize('theia/scm/unamend', 'Unamend')))
|
|
338
|
-
: '');
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
/*
|
|
342
|
-
* The style for the <div> containing the list of commits being amended.
|
|
343
|
-
* This div is scrollable.
|
|
344
|
-
*/
|
|
345
|
-
styleAmendedCommits() {
|
|
346
|
-
const base = {
|
|
347
|
-
display: 'flex',
|
|
348
|
-
whitespace: 'nowrap',
|
|
349
|
-
width: '100%',
|
|
350
|
-
minHeight: 0,
|
|
351
|
-
flexShrink: 1,
|
|
352
|
-
paddingTop: '2px',
|
|
353
|
-
};
|
|
354
|
-
switch (this.state.transition.state) {
|
|
355
|
-
case 'none':
|
|
356
|
-
return {
|
|
357
|
-
...base,
|
|
358
|
-
flexDirection: 'column',
|
|
359
|
-
overflowY: 'auto',
|
|
360
|
-
marginBottom: '0',
|
|
361
|
-
};
|
|
362
|
-
case 'start':
|
|
363
|
-
case 'transitioning':
|
|
364
|
-
let startingMargin = 0;
|
|
365
|
-
let endingMargin = 0;
|
|
366
|
-
switch (this.state.transition.direction) {
|
|
367
|
-
case 'down':
|
|
368
|
-
startingMargin = 0;
|
|
369
|
-
endingMargin = -32;
|
|
370
|
-
break;
|
|
371
|
-
case 'up':
|
|
372
|
-
startingMargin = -32;
|
|
373
|
-
endingMargin = 0;
|
|
374
|
-
break;
|
|
375
|
-
}
|
|
376
|
-
switch (this.state.transition.state) {
|
|
377
|
-
case 'start':
|
|
378
|
-
return {
|
|
379
|
-
...base,
|
|
380
|
-
flexDirection: 'column',
|
|
381
|
-
overflowY: 'hidden',
|
|
382
|
-
marginBottom: `${startingMargin}px`,
|
|
383
|
-
};
|
|
384
|
-
case 'transitioning':
|
|
385
|
-
return {
|
|
386
|
-
...base,
|
|
387
|
-
flexDirection: 'column',
|
|
388
|
-
overflowY: 'hidden',
|
|
389
|
-
marginBottom: `${endingMargin}px`,
|
|
390
|
-
transitionProperty: 'margin-bottom',
|
|
391
|
-
transitionDuration: `${TRANSITION_TIME_MS}ms`,
|
|
392
|
-
transitionTimingFunction: 'linear'
|
|
393
|
-
};
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
styleLastCommitMovingUp(transitionState) {
|
|
398
|
-
return this.styleLastCommit(transitionState, 0, -28);
|
|
399
|
-
}
|
|
400
|
-
styleLastCommitMovingDown(transitionState) {
|
|
401
|
-
return this.styleLastCommit(transitionState, -28, 0);
|
|
402
|
-
}
|
|
403
|
-
styleLastCommit(transitionState, startingMarginTop, startingMarginBottom) {
|
|
404
|
-
const base = {
|
|
405
|
-
display: 'flex',
|
|
406
|
-
width: '100%',
|
|
407
|
-
overflow: 'hidden',
|
|
408
|
-
paddingTop: 0,
|
|
409
|
-
paddingBottom: 0,
|
|
410
|
-
borderTop: 0,
|
|
411
|
-
borderBottom: 0,
|
|
412
|
-
height: this.lastCommitHeight * 2
|
|
413
|
-
};
|
|
414
|
-
// We end with top and bottom margins switched
|
|
415
|
-
const endingMarginTop = startingMarginBottom;
|
|
416
|
-
const endingMarginBottom = startingMarginTop;
|
|
417
|
-
switch (transitionState) {
|
|
418
|
-
case 'start':
|
|
419
|
-
return {
|
|
420
|
-
...base,
|
|
421
|
-
position: 'relative',
|
|
422
|
-
flexDirection: 'column',
|
|
423
|
-
marginTop: startingMarginTop,
|
|
424
|
-
marginBottom: startingMarginBottom,
|
|
425
|
-
};
|
|
426
|
-
case 'transitioning':
|
|
427
|
-
return {
|
|
428
|
-
...base,
|
|
429
|
-
position: 'relative',
|
|
430
|
-
flexDirection: 'column',
|
|
431
|
-
marginTop: endingMarginTop,
|
|
432
|
-
marginBottom: endingMarginBottom,
|
|
433
|
-
transitionProperty: 'margin-top margin-bottom',
|
|
434
|
-
transitionDuration: `${TRANSITION_TIME_MS}ms`,
|
|
435
|
-
transitionTimingFunction: 'linear'
|
|
436
|
-
};
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
async doUnamendAll() {
|
|
440
|
-
while (this.state.amendingCommits.length > 0) {
|
|
441
|
-
this.unamend();
|
|
442
|
-
await new Promise(resolve => setTimeout(resolve, TRANSITION_TIME_MS));
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
async doClearAmending() {
|
|
446
|
-
await this.clearAmendingCommits();
|
|
447
|
-
this.setState({ amendingCommits: [] });
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
exports.ScmAmendComponent = ScmAmendComponent;
|
|
451
|
-
(function (ScmAmendComponent) {
|
|
452
|
-
let Styles;
|
|
453
|
-
(function (Styles) {
|
|
454
|
-
Styles.COMMIT_CONTAINER = 'theia-scm-commit-container';
|
|
455
|
-
Styles.COMMIT_AND_BUTTON = 'theia-scm-commit-and-button';
|
|
456
|
-
Styles.COMMIT_AVATAR_AND_TEXT = 'theia-scm-commit-avatar-and-text';
|
|
457
|
-
Styles.COMMIT_DETAILS = 'theia-scm-commit-details';
|
|
458
|
-
Styles.COMMIT_MESSAGE_AVATAR = 'theia-scm-commit-message-avatar';
|
|
459
|
-
Styles.COMMIT_MESSAGE_SUMMARY = 'theia-scm-commit-message-summary';
|
|
460
|
-
Styles.LAST_COMMIT_MESSAGE_TIME = 'theia-scm-commit-message-time';
|
|
461
|
-
Styles.FLEX_CENTER = 'theia-scm-flex-container-center';
|
|
462
|
-
})(Styles = ScmAmendComponent.Styles || (ScmAmendComponent.Styles = {}));
|
|
463
|
-
})(ScmAmendComponent = exports.ScmAmendComponent || (exports.ScmAmendComponent = {}));
|
|
1
|
+
"use strict";
|
|
2
|
+
// *****************************************************************************
|
|
3
|
+
// Copyright (C) 2019 Arm and others.
|
|
4
|
+
//
|
|
5
|
+
// This program and the accompanying materials are made available under the
|
|
6
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
7
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
8
|
+
//
|
|
9
|
+
// This Source Code may also be made available under the following Secondary
|
|
10
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
11
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
12
|
+
// with the GNU Classpath Exception which is available at
|
|
13
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
14
|
+
//
|
|
15
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
16
|
+
// *****************************************************************************
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.ScmAmendComponent = void 0;
|
|
19
|
+
require("../../src/browser/style/scm-amend-component.css");
|
|
20
|
+
const React = require("@theia/core/shared/react");
|
|
21
|
+
const browser_1 = require("@theia/core/lib/browser");
|
|
22
|
+
const core_1 = require("@theia/core");
|
|
23
|
+
const nls_1 = require("@theia/core/lib/common/nls");
|
|
24
|
+
const TRANSITION_TIME_MS = 300;
|
|
25
|
+
const REPOSITORY_STORAGE_KEY = 'scmRepository';
|
|
26
|
+
class ScmAmendComponent extends React.Component {
|
|
27
|
+
constructor(props) {
|
|
28
|
+
super(props);
|
|
29
|
+
/**
|
|
30
|
+
* a hint on how to animate an update, set by certain user action handlers
|
|
31
|
+
* and used when updating the view based on a repository change
|
|
32
|
+
*/
|
|
33
|
+
this.transitionHint = 'none';
|
|
34
|
+
this.lastCommitHeight = 0;
|
|
35
|
+
this.lastCommitScrollRef = (instance) => {
|
|
36
|
+
if (instance && this.lastCommitHeight === 0) {
|
|
37
|
+
this.lastCommitHeight = instance.getBoundingClientRect().height;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
this.toDisposeOnUnmount = new core_1.DisposableCollection();
|
|
41
|
+
/**
|
|
42
|
+
* This function will update the 'model' (lastCommit, amendingCommits) only
|
|
43
|
+
* when the repository sees the last commit change.
|
|
44
|
+
* 'render' can be called at any time, so be sure we don't update any 'model'
|
|
45
|
+
* fields until we actually start the transition.
|
|
46
|
+
*/
|
|
47
|
+
this.amend = async () => {
|
|
48
|
+
if (this.state.transition.state !== 'none' && this.transitionHint !== 'none') {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
this.transitionHint = 'amend';
|
|
52
|
+
await this.resetAndSetMessage('HEAD~', 'HEAD');
|
|
53
|
+
};
|
|
54
|
+
this.unamend = async () => {
|
|
55
|
+
if (this.state.transition.state !== 'none' && this.transitionHint !== 'none') {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const commitToRestore = (this.state.amendingCommits.length >= 1)
|
|
59
|
+
? this.state.amendingCommits[this.state.amendingCommits.length - 1]
|
|
60
|
+
: undefined;
|
|
61
|
+
const oldestAmendCommit = (this.state.amendingCommits.length >= 2)
|
|
62
|
+
? this.state.amendingCommits[this.state.amendingCommits.length - 2]
|
|
63
|
+
: undefined;
|
|
64
|
+
if (commitToRestore) {
|
|
65
|
+
const commitToUseForMessage = oldestAmendCommit
|
|
66
|
+
? oldestAmendCommit.commit.id
|
|
67
|
+
: undefined;
|
|
68
|
+
this.transitionHint = 'unamend';
|
|
69
|
+
await this.resetAndSetMessage(commitToRestore.commit.id, commitToUseForMessage);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
this.unamendAll = () => this.doUnamendAll();
|
|
73
|
+
this.clearAmending = () => this.doClearAmending();
|
|
74
|
+
this.state = {
|
|
75
|
+
transition: { state: 'none' },
|
|
76
|
+
amendingCommits: [],
|
|
77
|
+
lastCommit: undefined
|
|
78
|
+
};
|
|
79
|
+
const setState = this.setState.bind(this);
|
|
80
|
+
this.setState = newState => {
|
|
81
|
+
if (!this.toDisposeOnUnmount.disposed) {
|
|
82
|
+
setState(newState);
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
async componentDidMount() {
|
|
87
|
+
this.toDisposeOnUnmount.push(core_1.Disposable.create(() => { }));
|
|
88
|
+
const lastCommit = await this.getLastCommit();
|
|
89
|
+
this.setState({ amendingCommits: await this.buildAmendingList(lastCommit ? lastCommit.commit : undefined), lastCommit });
|
|
90
|
+
if (this.toDisposeOnUnmount.disposed) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
this.toDisposeOnUnmount.push(this.props.repository.provider.onDidChange(() => this.fetchStatusAndSetState()));
|
|
94
|
+
}
|
|
95
|
+
componentWillUnmount() {
|
|
96
|
+
this.toDisposeOnUnmount.dispose();
|
|
97
|
+
}
|
|
98
|
+
async fetchStatusAndSetState() {
|
|
99
|
+
const storageKey = this.getStorageKey();
|
|
100
|
+
const nextCommit = await this.getLastCommit();
|
|
101
|
+
if (nextCommit && this.state.lastCommit && nextCommit.commit.id === this.state.lastCommit.commit.id) {
|
|
102
|
+
// No change here
|
|
103
|
+
}
|
|
104
|
+
else if (nextCommit === undefined && this.state.lastCommit === undefined) {
|
|
105
|
+
// No change here
|
|
106
|
+
}
|
|
107
|
+
else if (this.transitionHint === 'none') {
|
|
108
|
+
// If the 'last' commit changes, but we are not expecting an 'amend'
|
|
109
|
+
// or 'unamend' to occur, then we clear out the list of amended commits.
|
|
110
|
+
// This is because an unexpected change has happened to the repository,
|
|
111
|
+
// perhaps the user committed, merged, or something. The amended commits
|
|
112
|
+
// will no longer be valid.
|
|
113
|
+
// Note that there may or may not have been a previous lastCommit (if the
|
|
114
|
+
// repository was previously empty with no initial commit then lastCommit
|
|
115
|
+
// will be undefined). Either way we clear the amending commits.
|
|
116
|
+
await this.clearAmendingCommits();
|
|
117
|
+
// There is a change to the last commit, but no transition hint so
|
|
118
|
+
// the view just updates without transition.
|
|
119
|
+
this.setState({ amendingCommits: [], lastCommit: nextCommit });
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
const amendingCommits = this.state.amendingCommits.concat([]); // copy the array
|
|
123
|
+
const direction = this.transitionHint === 'amend' ? 'up' : 'down';
|
|
124
|
+
switch (this.transitionHint) {
|
|
125
|
+
case 'amend':
|
|
126
|
+
if (this.state.lastCommit) {
|
|
127
|
+
amendingCommits.push(this.state.lastCommit);
|
|
128
|
+
const serializedState = JSON.stringify({
|
|
129
|
+
amendingHeadCommitSha: amendingCommits[0].commit.id,
|
|
130
|
+
latestCommitSha: nextCommit ? nextCommit.commit.id : undefined
|
|
131
|
+
});
|
|
132
|
+
this.props.storageService.setData(storageKey, serializedState);
|
|
133
|
+
}
|
|
134
|
+
break;
|
|
135
|
+
case 'unamend':
|
|
136
|
+
amendingCommits.pop();
|
|
137
|
+
if (amendingCommits.length === 0) {
|
|
138
|
+
this.props.storageService.setData(storageKey, undefined);
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
const serializedState = JSON.stringify({
|
|
142
|
+
amendingHeadCommitSha: amendingCommits[0].commit.id,
|
|
143
|
+
latestCommitSha: nextCommit ? nextCommit.commit.id : undefined
|
|
144
|
+
});
|
|
145
|
+
this.props.storageService.setData(storageKey, serializedState);
|
|
146
|
+
}
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
if (this.state.lastCommit && nextCommit) {
|
|
150
|
+
const transitionData = { direction, previousLastCommit: this.state.lastCommit };
|
|
151
|
+
this.setState({ lastCommit: nextCommit, amendingCommits, transition: { ...transitionData, state: 'start' } });
|
|
152
|
+
this.onNextFrame(() => {
|
|
153
|
+
this.setState({ transition: { ...transitionData, state: 'transitioning' } });
|
|
154
|
+
});
|
|
155
|
+
setTimeout(() => {
|
|
156
|
+
this.setState({ transition: { state: 'none' } });
|
|
157
|
+
}, TRANSITION_TIME_MS);
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
// No previous last commit so no transition
|
|
161
|
+
this.setState({ transition: { state: 'none' }, amendingCommits, lastCommit: nextCommit });
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
this.transitionHint = 'none';
|
|
165
|
+
}
|
|
166
|
+
async clearAmendingCommits() {
|
|
167
|
+
const storageKey = this.getStorageKey();
|
|
168
|
+
await this.props.storageService.setData(storageKey, undefined);
|
|
169
|
+
}
|
|
170
|
+
async buildAmendingList(lastCommit) {
|
|
171
|
+
const storageKey = this.getStorageKey();
|
|
172
|
+
const storedState = await this.props.storageService.getData(storageKey, undefined);
|
|
173
|
+
// Restore list of commits from saved amending head commit up through parents until the
|
|
174
|
+
// current commit. (If we don't reach the current commit, the repository has been changed in such
|
|
175
|
+
// a way then unamending commits can no longer be done).
|
|
176
|
+
if (storedState) {
|
|
177
|
+
const { amendingHeadCommitSha, latestCommitSha } = JSON.parse(storedState);
|
|
178
|
+
if (!this.commitsAreEqual(lastCommit, latestCommitSha)) {
|
|
179
|
+
// The head commit in the repository has changed. It is not the same commit that was the
|
|
180
|
+
// head commit after the last 'amend'.
|
|
181
|
+
return [];
|
|
182
|
+
}
|
|
183
|
+
const commits = await this.props.scmAmendSupport.getInitialAmendingCommits(amendingHeadCommitSha, lastCommit ? lastCommit.id : undefined);
|
|
184
|
+
const amendingCommitPromises = commits.map(async (commit) => {
|
|
185
|
+
const avatar = await this.props.avatarService.getAvatar(commit.authorEmail);
|
|
186
|
+
return { commit, avatar };
|
|
187
|
+
});
|
|
188
|
+
return Promise.all(amendingCommitPromises);
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
return [];
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
getStorageKey() {
|
|
195
|
+
return REPOSITORY_STORAGE_KEY + ':' + this.props.repository.provider.rootUri;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Commits are equal if the ids are equal or if both are undefined.
|
|
199
|
+
* (If a commit is undefined, it represents the initial empty state of a repository,
|
|
200
|
+
* before the initial commit).
|
|
201
|
+
*/
|
|
202
|
+
commitsAreEqual(lastCommit, savedLastCommitId) {
|
|
203
|
+
return lastCommit
|
|
204
|
+
? lastCommit.id === savedLastCommitId
|
|
205
|
+
: savedLastCommitId === undefined;
|
|
206
|
+
}
|
|
207
|
+
async resetAndSetMessage(commitToRestore, commitToUseForMessage) {
|
|
208
|
+
const message = commitToUseForMessage
|
|
209
|
+
? await this.props.scmAmendSupport.getMessage(commitToUseForMessage)
|
|
210
|
+
: '';
|
|
211
|
+
await this.props.scmAmendSupport.reset(commitToRestore);
|
|
212
|
+
this.props.setCommitMessage(message);
|
|
213
|
+
}
|
|
214
|
+
render() {
|
|
215
|
+
const neverShrink = this.state.amendingCommits.length <= 3;
|
|
216
|
+
const style = neverShrink
|
|
217
|
+
? {
|
|
218
|
+
...this.props.style,
|
|
219
|
+
flexShrink: 0,
|
|
220
|
+
}
|
|
221
|
+
: {
|
|
222
|
+
...this.props.style,
|
|
223
|
+
flexShrink: 1,
|
|
224
|
+
minHeight: 240 // height with three commits
|
|
225
|
+
};
|
|
226
|
+
return (React.createElement("div", { className: ScmAmendComponent.Styles.COMMIT_CONTAINER + ' no-select', style: style },
|
|
227
|
+
this.state.amendingCommits.length > 0 || (this.state.lastCommit && this.state.transition.state !== 'none' && this.state.transition.direction === 'down')
|
|
228
|
+
? this.renderAmendingCommits()
|
|
229
|
+
: '',
|
|
230
|
+
this.state.lastCommit ?
|
|
231
|
+
React.createElement("div", null,
|
|
232
|
+
React.createElement("div", { id: 'lastCommit', className: 'theia-scm-amend' },
|
|
233
|
+
React.createElement("div", { className: 'theia-header scm-theia-header' }, nls_1.nls.localize('theia/scm/amendHeadCommit', 'HEAD Commit')),
|
|
234
|
+
this.renderLastCommit()))
|
|
235
|
+
: ''));
|
|
236
|
+
}
|
|
237
|
+
async getLastCommit() {
|
|
238
|
+
const commit = await this.props.scmAmendSupport.getLastCommit();
|
|
239
|
+
if (commit) {
|
|
240
|
+
const avatar = await this.props.avatarService.getAvatar(commit.authorEmail);
|
|
241
|
+
return { commit, avatar };
|
|
242
|
+
}
|
|
243
|
+
return undefined;
|
|
244
|
+
}
|
|
245
|
+
renderAmendingCommits() {
|
|
246
|
+
const neverShrink = this.state.amendingCommits.length <= 3;
|
|
247
|
+
const style = neverShrink
|
|
248
|
+
? {
|
|
249
|
+
flexShrink: 0,
|
|
250
|
+
}
|
|
251
|
+
: {
|
|
252
|
+
flexShrink: 1,
|
|
253
|
+
// parent minHeight controls height, we just need any value smaller than
|
|
254
|
+
// what the height would be when the parent is at its minHeight
|
|
255
|
+
minHeight: 0
|
|
256
|
+
};
|
|
257
|
+
return React.createElement("div", { id: 'amendedCommits', className: 'theia-scm-amend-outer-container', style: style },
|
|
258
|
+
React.createElement("div", { className: 'theia-header scm-theia-header' },
|
|
259
|
+
React.createElement("div", { className: 'noWrapInfo' }, "Commits being Amended"),
|
|
260
|
+
this.renderAmendCommitListButtons(),
|
|
261
|
+
this.renderCommitCount(this.state.amendingCommits.length)),
|
|
262
|
+
React.createElement("div", { style: this.styleAmendedCommits() },
|
|
263
|
+
this.state.amendingCommits.map((commitData, index, array) => this.renderCommitBeingAmended(commitData, index === array.length - 1)),
|
|
264
|
+
this.state.lastCommit && this.state.transition.state !== 'none' && this.state.transition.direction === 'down'
|
|
265
|
+
? this.renderCommitBeingAmended(this.state.lastCommit, false)
|
|
266
|
+
: ''));
|
|
267
|
+
}
|
|
268
|
+
renderAmendCommitListButtons() {
|
|
269
|
+
return React.createElement("div", { className: 'theia-scm-inline-actions-container' },
|
|
270
|
+
React.createElement("div", { className: 'theia-scm-inline-actions' },
|
|
271
|
+
React.createElement("div", { className: 'theia-scm-inline-action' },
|
|
272
|
+
React.createElement("a", { className: (0, browser_1.codicon)('dash'), title: 'Unamend All Commits', onClick: this.unamendAll })),
|
|
273
|
+
React.createElement("div", { className: 'theia-scm-inline-action' },
|
|
274
|
+
React.createElement("a", { className: (0, browser_1.codicon)('close'), title: 'Clear Amending Commits', onClick: this.clearAmending }))));
|
|
275
|
+
}
|
|
276
|
+
renderLastCommit() {
|
|
277
|
+
if (!this.state.lastCommit) {
|
|
278
|
+
return '';
|
|
279
|
+
}
|
|
280
|
+
const canAmend = true;
|
|
281
|
+
return React.createElement("div", { className: ScmAmendComponent.Styles.COMMIT_AND_BUTTON, style: { flexGrow: 0, flexShrink: 0 }, key: this.state.lastCommit.commit.id },
|
|
282
|
+
this.renderLastCommitNoButton(this.state.lastCommit),
|
|
283
|
+
canAmend
|
|
284
|
+
? React.createElement("div", { className: ScmAmendComponent.Styles.FLEX_CENTER },
|
|
285
|
+
React.createElement("button", { className: 'theia-button', title: nls_1.nls.localize('theia/scm/amendLastCommit', 'Amend last commit'), onClick: this.amend }, nls_1.nls.localize('theia/scm/amend', 'Amend')))
|
|
286
|
+
: '');
|
|
287
|
+
}
|
|
288
|
+
renderLastCommitNoButton(lastCommit) {
|
|
289
|
+
switch (this.state.transition.state) {
|
|
290
|
+
case 'none':
|
|
291
|
+
return React.createElement("div", { ref: this.lastCommitScrollRef, className: 'theia-scm-scrolling-container' }, this.renderCommitAvatarAndDetail(lastCommit));
|
|
292
|
+
case 'start':
|
|
293
|
+
case 'transitioning':
|
|
294
|
+
switch (this.state.transition.direction) {
|
|
295
|
+
case 'up':
|
|
296
|
+
return React.createElement("div", { style: this.styleLastCommitMovingUp(this.state.transition.state) },
|
|
297
|
+
this.renderCommitAvatarAndDetail(this.state.transition.previousLastCommit),
|
|
298
|
+
this.renderCommitAvatarAndDetail(lastCommit));
|
|
299
|
+
case 'down':
|
|
300
|
+
return React.createElement("div", { style: this.styleLastCommitMovingDown(this.state.transition.state) },
|
|
301
|
+
this.renderCommitAvatarAndDetail(lastCommit),
|
|
302
|
+
this.renderCommitAvatarAndDetail(this.state.transition.previousLastCommit));
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* See https://stackoverflow.com/questions/26556436/react-after-render-code
|
|
308
|
+
*
|
|
309
|
+
* @param callback
|
|
310
|
+
*/
|
|
311
|
+
onNextFrame(callback) {
|
|
312
|
+
setTimeout(() => window.requestAnimationFrame(callback), 0);
|
|
313
|
+
}
|
|
314
|
+
renderCommitAvatarAndDetail(commitData) {
|
|
315
|
+
const { commit, avatar } = commitData;
|
|
316
|
+
return React.createElement("div", { className: ScmAmendComponent.Styles.COMMIT_AVATAR_AND_TEXT, key: commit.id },
|
|
317
|
+
React.createElement("div", { className: ScmAmendComponent.Styles.COMMIT_MESSAGE_AVATAR },
|
|
318
|
+
React.createElement("img", { src: avatar })),
|
|
319
|
+
React.createElement("div", { className: ScmAmendComponent.Styles.COMMIT_DETAILS },
|
|
320
|
+
React.createElement("div", { className: ScmAmendComponent.Styles.COMMIT_MESSAGE_SUMMARY }, commit.summary),
|
|
321
|
+
React.createElement("div", { className: ScmAmendComponent.Styles.LAST_COMMIT_MESSAGE_TIME }, `${commit.authorDateRelative} by ${commit.authorName}`)));
|
|
322
|
+
}
|
|
323
|
+
renderCommitCount(commits) {
|
|
324
|
+
return React.createElement("div", { className: 'notification-count-container scm-change-count' },
|
|
325
|
+
React.createElement("span", { className: 'notification-count' }, commits));
|
|
326
|
+
}
|
|
327
|
+
renderCommitBeingAmended(commitData, isOldestAmendCommit) {
|
|
328
|
+
if (isOldestAmendCommit && this.state.transition.state !== 'none' && this.state.transition.direction === 'up') {
|
|
329
|
+
return React.createElement("div", { className: ScmAmendComponent.Styles.COMMIT_AVATAR_AND_TEXT, style: { flexGrow: 0, flexShrink: 0 }, key: commitData.commit.id },
|
|
330
|
+
React.createElement("div", { className: 'fixed-height-commit-container' }, this.renderCommitAvatarAndDetail(commitData)));
|
|
331
|
+
}
|
|
332
|
+
else {
|
|
333
|
+
return React.createElement("div", { className: ScmAmendComponent.Styles.COMMIT_AVATAR_AND_TEXT, style: { flexGrow: 0, flexShrink: 0 }, key: commitData.commit.id },
|
|
334
|
+
this.renderCommitAvatarAndDetail(commitData),
|
|
335
|
+
isOldestAmendCommit
|
|
336
|
+
? React.createElement("div", { className: ScmAmendComponent.Styles.FLEX_CENTER },
|
|
337
|
+
React.createElement("button", { className: 'theia-button', title: nls_1.nls.localize('theia/scm/unamendCommit', 'Unamend commit'), onClick: this.unamend }, nls_1.nls.localize('theia/scm/unamend', 'Unamend')))
|
|
338
|
+
: '');
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
/*
|
|
342
|
+
* The style for the <div> containing the list of commits being amended.
|
|
343
|
+
* This div is scrollable.
|
|
344
|
+
*/
|
|
345
|
+
styleAmendedCommits() {
|
|
346
|
+
const base = {
|
|
347
|
+
display: 'flex',
|
|
348
|
+
whitespace: 'nowrap',
|
|
349
|
+
width: '100%',
|
|
350
|
+
minHeight: 0,
|
|
351
|
+
flexShrink: 1,
|
|
352
|
+
paddingTop: '2px',
|
|
353
|
+
};
|
|
354
|
+
switch (this.state.transition.state) {
|
|
355
|
+
case 'none':
|
|
356
|
+
return {
|
|
357
|
+
...base,
|
|
358
|
+
flexDirection: 'column',
|
|
359
|
+
overflowY: 'auto',
|
|
360
|
+
marginBottom: '0',
|
|
361
|
+
};
|
|
362
|
+
case 'start':
|
|
363
|
+
case 'transitioning':
|
|
364
|
+
let startingMargin = 0;
|
|
365
|
+
let endingMargin = 0;
|
|
366
|
+
switch (this.state.transition.direction) {
|
|
367
|
+
case 'down':
|
|
368
|
+
startingMargin = 0;
|
|
369
|
+
endingMargin = -32;
|
|
370
|
+
break;
|
|
371
|
+
case 'up':
|
|
372
|
+
startingMargin = -32;
|
|
373
|
+
endingMargin = 0;
|
|
374
|
+
break;
|
|
375
|
+
}
|
|
376
|
+
switch (this.state.transition.state) {
|
|
377
|
+
case 'start':
|
|
378
|
+
return {
|
|
379
|
+
...base,
|
|
380
|
+
flexDirection: 'column',
|
|
381
|
+
overflowY: 'hidden',
|
|
382
|
+
marginBottom: `${startingMargin}px`,
|
|
383
|
+
};
|
|
384
|
+
case 'transitioning':
|
|
385
|
+
return {
|
|
386
|
+
...base,
|
|
387
|
+
flexDirection: 'column',
|
|
388
|
+
overflowY: 'hidden',
|
|
389
|
+
marginBottom: `${endingMargin}px`,
|
|
390
|
+
transitionProperty: 'margin-bottom',
|
|
391
|
+
transitionDuration: `${TRANSITION_TIME_MS}ms`,
|
|
392
|
+
transitionTimingFunction: 'linear'
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
styleLastCommitMovingUp(transitionState) {
|
|
398
|
+
return this.styleLastCommit(transitionState, 0, -28);
|
|
399
|
+
}
|
|
400
|
+
styleLastCommitMovingDown(transitionState) {
|
|
401
|
+
return this.styleLastCommit(transitionState, -28, 0);
|
|
402
|
+
}
|
|
403
|
+
styleLastCommit(transitionState, startingMarginTop, startingMarginBottom) {
|
|
404
|
+
const base = {
|
|
405
|
+
display: 'flex',
|
|
406
|
+
width: '100%',
|
|
407
|
+
overflow: 'hidden',
|
|
408
|
+
paddingTop: 0,
|
|
409
|
+
paddingBottom: 0,
|
|
410
|
+
borderTop: 0,
|
|
411
|
+
borderBottom: 0,
|
|
412
|
+
height: this.lastCommitHeight * 2
|
|
413
|
+
};
|
|
414
|
+
// We end with top and bottom margins switched
|
|
415
|
+
const endingMarginTop = startingMarginBottom;
|
|
416
|
+
const endingMarginBottom = startingMarginTop;
|
|
417
|
+
switch (transitionState) {
|
|
418
|
+
case 'start':
|
|
419
|
+
return {
|
|
420
|
+
...base,
|
|
421
|
+
position: 'relative',
|
|
422
|
+
flexDirection: 'column',
|
|
423
|
+
marginTop: startingMarginTop,
|
|
424
|
+
marginBottom: startingMarginBottom,
|
|
425
|
+
};
|
|
426
|
+
case 'transitioning':
|
|
427
|
+
return {
|
|
428
|
+
...base,
|
|
429
|
+
position: 'relative',
|
|
430
|
+
flexDirection: 'column',
|
|
431
|
+
marginTop: endingMarginTop,
|
|
432
|
+
marginBottom: endingMarginBottom,
|
|
433
|
+
transitionProperty: 'margin-top margin-bottom',
|
|
434
|
+
transitionDuration: `${TRANSITION_TIME_MS}ms`,
|
|
435
|
+
transitionTimingFunction: 'linear'
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
async doUnamendAll() {
|
|
440
|
+
while (this.state.amendingCommits.length > 0) {
|
|
441
|
+
this.unamend();
|
|
442
|
+
await new Promise(resolve => setTimeout(resolve, TRANSITION_TIME_MS));
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
async doClearAmending() {
|
|
446
|
+
await this.clearAmendingCommits();
|
|
447
|
+
this.setState({ amendingCommits: [] });
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
exports.ScmAmendComponent = ScmAmendComponent;
|
|
451
|
+
(function (ScmAmendComponent) {
|
|
452
|
+
let Styles;
|
|
453
|
+
(function (Styles) {
|
|
454
|
+
Styles.COMMIT_CONTAINER = 'theia-scm-commit-container';
|
|
455
|
+
Styles.COMMIT_AND_BUTTON = 'theia-scm-commit-and-button';
|
|
456
|
+
Styles.COMMIT_AVATAR_AND_TEXT = 'theia-scm-commit-avatar-and-text';
|
|
457
|
+
Styles.COMMIT_DETAILS = 'theia-scm-commit-details';
|
|
458
|
+
Styles.COMMIT_MESSAGE_AVATAR = 'theia-scm-commit-message-avatar';
|
|
459
|
+
Styles.COMMIT_MESSAGE_SUMMARY = 'theia-scm-commit-message-summary';
|
|
460
|
+
Styles.LAST_COMMIT_MESSAGE_TIME = 'theia-scm-commit-message-time';
|
|
461
|
+
Styles.FLEX_CENTER = 'theia-scm-flex-container-center';
|
|
462
|
+
})(Styles = ScmAmendComponent.Styles || (ScmAmendComponent.Styles = {}));
|
|
463
|
+
})(ScmAmendComponent = exports.ScmAmendComponent || (exports.ScmAmendComponent = {}));
|
|
464
464
|
//# sourceMappingURL=scm-amend-component.js.map
|