@theia/scm 1.71.0-next.8 → 1.71.0
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/lib/browser/dirty-diff/dirty-diff-widget.js +1 -1
- package/lib/browser/dirty-diff/dirty-diff-widget.js.map +1 -1
- package/lib/browser/merge-editor/merge-editor-module.d.ts +6 -0
- package/lib/browser/merge-editor/merge-editor-module.d.ts.map +1 -1
- package/lib/browser/merge-editor/merge-editor-module.js +21 -2
- package/lib/browser/merge-editor/merge-editor-module.js.map +1 -1
- package/lib/browser/scm-context-key-service.d.ts +8 -0
- package/lib/browser/scm-context-key-service.d.ts.map +1 -1
- package/lib/browser/scm-context-key-service.js +16 -0
- package/lib/browser/scm-context-key-service.js.map +1 -1
- package/lib/browser/scm-contribution.d.ts.map +1 -1
- package/lib/browser/scm-contribution.js +143 -1
- package/lib/browser/scm-contribution.js.map +1 -1
- package/lib/browser/scm-frontend-module.d.ts.map +1 -1
- package/lib/browser/scm-frontend-module.js +14 -0
- package/lib/browser/scm-frontend-module.js.map +1 -1
- package/lib/browser/scm-history-graph-helpers.d.ts +39 -0
- package/lib/browser/scm-history-graph-helpers.d.ts.map +1 -0
- package/lib/browser/scm-history-graph-helpers.js +167 -0
- package/lib/browser/scm-history-graph-helpers.js.map +1 -0
- package/lib/browser/scm-history-graph-lanes.d.ts +59 -0
- package/lib/browser/scm-history-graph-lanes.d.ts.map +1 -0
- package/lib/browser/scm-history-graph-lanes.js +183 -0
- package/lib/browser/scm-history-graph-lanes.js.map +1 -0
- package/lib/browser/scm-history-graph-lanes.spec.d.ts +2 -0
- package/lib/browser/scm-history-graph-lanes.spec.d.ts.map +1 -0
- package/lib/browser/scm-history-graph-lanes.spec.js +554 -0
- package/lib/browser/scm-history-graph-lanes.spec.js.map +1 -0
- package/lib/browser/scm-history-graph-model.d.ts +46 -0
- package/lib/browser/scm-history-graph-model.d.ts.map +1 -0
- package/lib/browser/scm-history-graph-model.js +184 -0
- package/lib/browser/scm-history-graph-model.js.map +1 -0
- package/lib/browser/scm-history-graph-model.spec.d.ts +2 -0
- package/lib/browser/scm-history-graph-model.spec.d.ts.map +1 -0
- package/lib/browser/scm-history-graph-model.spec.js +131 -0
- package/lib/browser/scm-history-graph-model.spec.js.map +1 -0
- package/lib/browser/scm-history-graph-tooltip.d.ts +14 -0
- package/lib/browser/scm-history-graph-tooltip.d.ts.map +1 -0
- package/lib/browser/scm-history-graph-tooltip.js +190 -0
- package/lib/browser/scm-history-graph-tooltip.js.map +1 -0
- package/lib/browser/scm-history-graph-widget.d.ts +77 -0
- package/lib/browser/scm-history-graph-widget.d.ts.map +1 -0
- package/lib/browser/scm-history-graph-widget.js +490 -0
- package/lib/browser/scm-history-graph-widget.js.map +1 -0
- package/lib/browser/scm-provider.d.ts +61 -0
- package/lib/browser/scm-provider.d.ts.map +1 -1
- package/lib/browser/scm-provider.js.map +1 -1
- package/lib/browser/scm-repositories-widget.d.ts +6 -1
- package/lib/browser/scm-repositories-widget.d.ts.map +1 -1
- package/lib/browser/scm-repositories-widget.js +11 -4
- package/lib/browser/scm-repositories-widget.js.map +1 -1
- package/lib/browser/scm-repositories-widget.spec.js +1 -1
- package/lib/browser/scm-repositories-widget.spec.js.map +1 -1
- package/lib/browser/scm-service.d.ts.map +1 -1
- package/lib/browser/scm-service.js +4 -1
- package/lib/browser/scm-service.js.map +1 -1
- package/lib/browser/scm-service.spec.d.ts +2 -0
- package/lib/browser/scm-service.spec.d.ts.map +1 -0
- package/lib/browser/scm-service.spec.js +77 -0
- package/lib/browser/scm-service.spec.js.map +1 -0
- package/package.json +11 -11
- package/src/browser/dirty-diff/dirty-diff-widget.ts +1 -1
- package/src/browser/merge-editor/merge-editor-module.ts +24 -6
- package/src/browser/scm-context-key-service.ts +24 -0
- package/src/browser/scm-contribution.ts +157 -0
- package/src/browser/scm-frontend-module.ts +15 -0
- package/src/browser/scm-history-graph-helpers.ts +175 -0
- package/src/browser/scm-history-graph-lanes.spec.ts +635 -0
- package/src/browser/scm-history-graph-lanes.ts +258 -0
- package/src/browser/scm-history-graph-model.spec.ts +171 -0
- package/src/browser/scm-history-graph-model.ts +207 -0
- package/src/browser/scm-history-graph-tooltip.ts +213 -0
- package/src/browser/scm-history-graph-widget.tsx +712 -0
- package/src/browser/scm-provider.ts +68 -0
- package/src/browser/scm-repositories-widget.spec.ts +1 -1
- package/src/browser/scm-repositories-widget.tsx +10 -3
- package/src/browser/scm-service.spec.ts +91 -0
- package/src/browser/scm-service.ts +4 -1
- package/src/browser/style/index.css +12 -13
- package/src/browser/style/scm-history-graph.css +313 -0
|
@@ -18,11 +18,13 @@
|
|
|
18
18
|
|
|
19
19
|
import { Disposable, Event } from '@theia/core/lib/common';
|
|
20
20
|
import URI from '@theia/core/lib/common/uri';
|
|
21
|
+
import { CancellationToken } from '@theia/core/lib/common/cancellation';
|
|
21
22
|
|
|
22
23
|
export interface ScmProvider extends Disposable {
|
|
23
24
|
readonly id: string;
|
|
24
25
|
readonly label: string;
|
|
25
26
|
readonly rootUri: string;
|
|
27
|
+
readonly handle?: number;
|
|
26
28
|
|
|
27
29
|
readonly acceptInputCommand?: ScmCommand;
|
|
28
30
|
|
|
@@ -41,6 +43,8 @@ export interface ScmProvider extends Disposable {
|
|
|
41
43
|
readonly onDidChangeActionButton?: Event<ScmActionButton | undefined>;
|
|
42
44
|
|
|
43
45
|
readonly providerContextValue?: string;
|
|
46
|
+
|
|
47
|
+
readonly historyProvider?: ScmHistoryProvider;
|
|
44
48
|
}
|
|
45
49
|
|
|
46
50
|
export const ScmResourceGroup = Symbol('ScmResourceGroup');
|
|
@@ -102,3 +106,67 @@ export interface ScmActionButton {
|
|
|
102
106
|
enabled?: boolean;
|
|
103
107
|
description?: string;
|
|
104
108
|
}
|
|
109
|
+
|
|
110
|
+
export interface ScmHistoryItemRef {
|
|
111
|
+
readonly id: string;
|
|
112
|
+
readonly name: string;
|
|
113
|
+
readonly description?: string;
|
|
114
|
+
readonly revision?: string;
|
|
115
|
+
readonly icon?: string;
|
|
116
|
+
readonly category?: string;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export interface ScmHistoryItemRefsChangeEvent {
|
|
120
|
+
readonly added: readonly ScmHistoryItemRef[];
|
|
121
|
+
readonly removed: readonly ScmHistoryItemRef[];
|
|
122
|
+
readonly modified: readonly ScmHistoryItemRef[];
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export interface ScmHistoryOptions {
|
|
126
|
+
readonly skip?: number;
|
|
127
|
+
readonly limit?: number | { id?: string };
|
|
128
|
+
readonly historyItemRefs?: readonly string[];
|
|
129
|
+
readonly filterText?: string;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export interface ScmHistoryItemStatistics {
|
|
133
|
+
readonly files: number;
|
|
134
|
+
readonly insertions: number;
|
|
135
|
+
readonly deletions: number;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export interface ScmHistoryItem {
|
|
139
|
+
readonly id: string;
|
|
140
|
+
readonly parentIds?: readonly string[];
|
|
141
|
+
readonly subject: string;
|
|
142
|
+
readonly message?: string;
|
|
143
|
+
readonly author?: string;
|
|
144
|
+
readonly authorEmail?: string;
|
|
145
|
+
readonly authorIcon?: string;
|
|
146
|
+
readonly displayId?: string;
|
|
147
|
+
readonly timestamp?: number;
|
|
148
|
+
readonly tooltip?: string;
|
|
149
|
+
readonly statistics?: ScmHistoryItemStatistics;
|
|
150
|
+
readonly references?: readonly ScmHistoryItemRef[];
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export interface ScmHistoryItemChange {
|
|
154
|
+
readonly uri: string;
|
|
155
|
+
readonly originalUri?: string;
|
|
156
|
+
readonly modifiedUri?: string;
|
|
157
|
+
readonly renameUri?: string;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export interface ScmHistoryProvider {
|
|
161
|
+
readonly currentHistoryItemRef?: ScmHistoryItemRef;
|
|
162
|
+
readonly currentHistoryItemRemoteRef?: ScmHistoryItemRef;
|
|
163
|
+
readonly currentHistoryItemBaseRef?: ScmHistoryItemRef;
|
|
164
|
+
readonly onDidChangeCurrentHistoryItemRefs: Event<void>;
|
|
165
|
+
readonly onDidChangeHistoryItemRefs: Event<ScmHistoryItemRefsChangeEvent>;
|
|
166
|
+
|
|
167
|
+
provideHistoryItemRefs(historyItemRefs: string[] | undefined, token: CancellationToken): Promise<ScmHistoryItemRef[] | undefined>;
|
|
168
|
+
provideHistoryItems(options: ScmHistoryOptions, token: CancellationToken): Promise<ScmHistoryItem[] | undefined>;
|
|
169
|
+
provideHistoryItemChanges(historyItemId: string, historyItemParentId: string | undefined, token: CancellationToken): Promise<ScmHistoryItemChange[] | undefined>;
|
|
170
|
+
resolveHistoryItem(historyItemId: string, token: CancellationToken): Promise<ScmHistoryItem | undefined>;
|
|
171
|
+
resolveHistoryItemRefsCommonAncestor(historyItemRefs: string[], token: CancellationToken): Promise<string | undefined>;
|
|
172
|
+
}
|
|
@@ -89,7 +89,7 @@ function createWidget(opts: CreateWidgetOptions): ScmRepositoriesWidget {
|
|
|
89
89
|
};
|
|
90
90
|
|
|
91
91
|
const mockContextMenuRenderer = { render: () => ({ dispose: () => { } }) };
|
|
92
|
-
const mockScmContextKeys = { scmProvider: { set: () => { } } };
|
|
92
|
+
const mockScmContextKeys = { scmProvider: { set: () => { } }, scmProviderContext: { set: () => { } } };
|
|
93
93
|
|
|
94
94
|
(widget as unknown as Record<string, unknown>).scmService = mockScmService;
|
|
95
95
|
(widget as unknown as Record<string, unknown>).labelProvider = mockLabelProvider;
|
|
@@ -32,10 +32,15 @@ import { ScmContextKeyService } from './scm-context-key-service';
|
|
|
32
32
|
export const SCM_TITLE_MENU: MenuPath = ['plugin_scm/title'];
|
|
33
33
|
/** Menu path matching the VS Code 'scm/sourceControl' contribution point (inline toolbar actions on repo entries). */
|
|
34
34
|
export const SCM_SOURCE_CONTROL_MENU: MenuPath = ['plugin_scm/sourceControl'];
|
|
35
|
-
/**
|
|
35
|
+
/**
|
|
36
|
+
* @deprecated The 'scm/sourceControl/context' contribution point does not exist in VS Code.
|
|
37
|
+
* Use {@link SCM_SOURCE_CONTROL_MENU} instead.
|
|
38
|
+
*/
|
|
36
39
|
export const SCM_SOURCE_CONTROL_CONTEXT_MENU: MenuPath = ['plugin_scm/sourceControl/context'];
|
|
37
40
|
/** Menu path matching the VS Code 'scm/sourceControl/title' contribution point (REPOSITORIES section header toolbar). */
|
|
38
41
|
export const SCM_SOURCE_CONTROL_TITLE_MENU: MenuPath = ['plugin_scm/sourceControl/title'];
|
|
42
|
+
/** Menu path matching the VS Code 'scm/repository' contribution point (per-repo \`...\` button). */
|
|
43
|
+
export const SCM_REPOSITORY_MENU: MenuPath = ['plugin_scm/repository'];
|
|
39
44
|
|
|
40
45
|
interface RepoGroup {
|
|
41
46
|
root: ScmRepository;
|
|
@@ -297,11 +302,12 @@ export class ScmRepositoriesWidget extends ReactWidget {
|
|
|
297
302
|
// Select the repo and set the context key so command when-clauses resolve correctly.
|
|
298
303
|
this.scmService.selectedRepository = repo;
|
|
299
304
|
this.scmContextKeys.scmProvider.set(repo.provider.id);
|
|
305
|
+
this.scmContextKeys.scmProviderContext.set(repo.provider.providerContextValue);
|
|
300
306
|
const anchor = e.nativeEvent;
|
|
301
307
|
// Defer one tick so the selectedRepository change propagates through context keys.
|
|
302
308
|
setTimeout(() => {
|
|
303
309
|
this.contextMenuRenderer.render({
|
|
304
|
-
menuPath:
|
|
310
|
+
menuPath: SCM_REPOSITORY_MENU,
|
|
305
311
|
anchor,
|
|
306
312
|
args: [repo],
|
|
307
313
|
context: this.node
|
|
@@ -312,10 +318,11 @@ export class ScmRepositoriesWidget extends ReactWidget {
|
|
|
312
318
|
protected showSourceControlContextMenu(e: React.MouseEvent, repo: ScmRepository): void {
|
|
313
319
|
this.scmService.selectedRepository = repo;
|
|
314
320
|
this.scmContextKeys.scmProvider.set(repo.provider.id);
|
|
321
|
+
this.scmContextKeys.scmProviderContext.set(repo.provider.providerContextValue);
|
|
315
322
|
const anchor = e.nativeEvent;
|
|
316
323
|
setTimeout(() => {
|
|
317
324
|
this.contextMenuRenderer.render({
|
|
318
|
-
menuPath:
|
|
325
|
+
menuPath: SCM_SOURCE_CONTROL_MENU,
|
|
319
326
|
anchor,
|
|
320
327
|
args: [repo],
|
|
321
328
|
context: this.node
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2026 EclipseSource GmbH and others.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
|
|
17
|
+
import { expect } from 'chai';
|
|
18
|
+
import { Emitter } from '@theia/core/lib/common/event';
|
|
19
|
+
import { ScmService } from './scm-service';
|
|
20
|
+
import { ScmProvider } from './scm-provider';
|
|
21
|
+
|
|
22
|
+
function makeProvider(id: string, rootUri: string): ScmProvider {
|
|
23
|
+
return {
|
|
24
|
+
id,
|
|
25
|
+
label: id,
|
|
26
|
+
rootUri,
|
|
27
|
+
groups: [],
|
|
28
|
+
onDidChange: new Emitter<void>().event,
|
|
29
|
+
onDidChangeCommitTemplate: new Emitter<string>().event,
|
|
30
|
+
dispose: () => { }
|
|
31
|
+
} as unknown as ScmProvider;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
describe('ScmService - repository removal event ordering', () => {
|
|
35
|
+
let service: ScmService;
|
|
36
|
+
|
|
37
|
+
beforeEach(() => {
|
|
38
|
+
service = new ScmService();
|
|
39
|
+
// ScmService declares a ScmContextKeyService injection but does not use it
|
|
40
|
+
// in the paths exercised here. Stub it to stay resilient against future use.
|
|
41
|
+
(service as unknown as Record<string, unknown>).contextKeys = {};
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('should update selectedRepository before firing onDidRemoveRepository', () => {
|
|
45
|
+
const repoA = service.registerScmProvider(makeProvider('git', '/a'));
|
|
46
|
+
const repoB = service.registerScmProvider(makeProvider('git', '/b'));
|
|
47
|
+
|
|
48
|
+
// Select repoA explicitly (registerScmProvider auto-selects the first one).
|
|
49
|
+
service.selectedRepository = repoA;
|
|
50
|
+
expect(service.selectedRepository).to.equal(repoA);
|
|
51
|
+
|
|
52
|
+
let selectedDuringRemoveEvent: unknown;
|
|
53
|
+
service.onDidRemoveRepository(() => {
|
|
54
|
+
selectedDuringRemoveEvent = service.selectedRepository;
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
repoA.dispose();
|
|
58
|
+
|
|
59
|
+
// When a subscriber of onDidRemoveRepository inspects selectedRepository,
|
|
60
|
+
// it must not observe the disposed repository as still being selected.
|
|
61
|
+
expect(selectedDuringRemoveEvent).to.not.equal(repoA);
|
|
62
|
+
expect(selectedDuringRemoveEvent).to.equal(repoB);
|
|
63
|
+
expect(service.selectedRepository).to.equal(repoB);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('should clear selectedRepository to undefined when the last repository is removed', () => {
|
|
67
|
+
const repo = service.registerScmProvider(makeProvider('git', '/a'));
|
|
68
|
+
expect(service.selectedRepository).to.equal(repo);
|
|
69
|
+
|
|
70
|
+
let selectedDuringRemoveEvent: unknown = 'unset';
|
|
71
|
+
service.onDidRemoveRepository(() => {
|
|
72
|
+
selectedDuringRemoveEvent = service.selectedRepository;
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
repo.dispose();
|
|
76
|
+
|
|
77
|
+
expect(selectedDuringRemoveEvent).to.be.undefined;
|
|
78
|
+
expect(service.selectedRepository).to.be.undefined;
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('should fire onDidRemoveRepository and leave _repositories empty after disposing the only repo', () => {
|
|
82
|
+
const repo = service.registerScmProvider(makeProvider('git', '/a'));
|
|
83
|
+
let removed: unknown;
|
|
84
|
+
service.onDidRemoveRepository(r => { removed = r; });
|
|
85
|
+
|
|
86
|
+
repo.dispose();
|
|
87
|
+
|
|
88
|
+
expect(removed).to.equal(repo);
|
|
89
|
+
expect(service.repositories).to.have.length(0);
|
|
90
|
+
});
|
|
91
|
+
});
|
|
@@ -92,10 +92,13 @@ export class ScmService {
|
|
|
92
92
|
repository.dispose = () => {
|
|
93
93
|
this._repositories.delete(key);
|
|
94
94
|
dispose.bind(repository)();
|
|
95
|
-
|
|
95
|
+
// Update the selected repository before firing the remove event so
|
|
96
|
+
// subscribers do not observe a stale selection pointing at the just
|
|
97
|
+
// disposed repository.
|
|
96
98
|
if (this._selectedRepository === repository) {
|
|
97
99
|
this.selectedRepository = this._repositories.values().next().value;
|
|
98
100
|
}
|
|
101
|
+
this.onDidRemoveRepositoryEmitter.fire(repository);
|
|
99
102
|
};
|
|
100
103
|
this._repositories.set(key, repository);
|
|
101
104
|
this.onDidAddRepositoryEmitter.fire(repository);
|
|
@@ -14,15 +14,14 @@
|
|
|
14
14
|
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
15
|
********************************************************************************/
|
|
16
16
|
|
|
17
|
+
@import './scm-history-graph.css';
|
|
18
|
+
|
|
17
19
|
.theia-scm-commit {
|
|
18
20
|
overflow: hidden;
|
|
19
21
|
font-size: var(--theia-ui-font-size1);
|
|
20
22
|
max-height: calc(100% - var(--theia-border-width));
|
|
21
23
|
position: relative;
|
|
22
|
-
padding: var(--theia-ui-padding)
|
|
23
|
-
max(var(--theia-ui-padding), var(--theia-scrollbar-width))
|
|
24
|
-
var(--theia-ui-padding)
|
|
25
|
-
calc(var(--theia-ui-padding) * 3);
|
|
24
|
+
padding: var(--theia-ui-padding) max(var(--theia-ui-padding), var(--theia-scrollbar-width)) var(--theia-ui-padding) calc(var(--theia-ui-padding) * 3);
|
|
26
25
|
}
|
|
27
26
|
|
|
28
27
|
.theia-scm {
|
|
@@ -141,9 +140,9 @@
|
|
|
141
140
|
.theia-scm-validation-message-info {
|
|
142
141
|
background-color: var(--theia-inputValidation-infoBackground) !important;
|
|
143
142
|
color: var(--theia-inputValidation-infoForeground);
|
|
144
|
-
border: var(--theia-border-width) solid
|
|
145
|
-
|
|
146
|
-
|
|
143
|
+
border: var(--theia-border-width) solid var(--theia-inputValidation-infoBorder);
|
|
144
|
+
border-top: none;
|
|
145
|
+
/* remove top border since the input declares it already */
|
|
147
146
|
}
|
|
148
147
|
|
|
149
148
|
.theia-scm-validation-message-success {
|
|
@@ -155,17 +154,17 @@
|
|
|
155
154
|
.theia-scm-validation-message-warning {
|
|
156
155
|
background-color: var(--theia-inputValidation-warningBackground) !important;
|
|
157
156
|
color: var(--theia-inputValidation-warningForeground);
|
|
158
|
-
border: var(--theia-border-width) solid
|
|
159
|
-
|
|
160
|
-
|
|
157
|
+
border: var(--theia-border-width) solid var(--theia-inputValidation-warningBorder);
|
|
158
|
+
border-top: none;
|
|
159
|
+
/* remove top border since the input declares it already */
|
|
161
160
|
}
|
|
162
161
|
|
|
163
162
|
.theia-scm-validation-message-error {
|
|
164
163
|
background-color: var(--theia-inputValidation-errorBackground) !important;
|
|
165
164
|
color: var(--theia-inputValidation-errorForeground);
|
|
166
|
-
border: var(--theia-border-width) solid
|
|
167
|
-
|
|
168
|
-
|
|
165
|
+
border: var(--theia-border-width) solid var(--theia-inputValidation-errorBorder);
|
|
166
|
+
border-top: none;
|
|
167
|
+
/* remove top border since the input declares it already */
|
|
169
168
|
}
|
|
170
169
|
|
|
171
170
|
.theia-scm-action-button-container {
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (C) 2026 EclipseSource GmbH and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
* http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
*
|
|
8
|
+
* This Source Code may also be made available under the following Secondary
|
|
9
|
+
* Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
* with the GNU Classpath Exception which is available at
|
|
12
|
+
* https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
*
|
|
14
|
+
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
********************************************************************************/
|
|
16
|
+
|
|
17
|
+
/* ── Widget container ────────────────────────────────────────────────────── */
|
|
18
|
+
.scm-history-graph-container {
|
|
19
|
+
display: flex;
|
|
20
|
+
flex-direction: column;
|
|
21
|
+
height: 100%;
|
|
22
|
+
overflow: hidden;
|
|
23
|
+
font-size: var(--theia-ui-font-size1);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/* ── Scrollable list area ────────────────────────────────────────────────── */
|
|
27
|
+
.scm-history-graph-list {
|
|
28
|
+
flex: 1;
|
|
29
|
+
overflow-y: auto;
|
|
30
|
+
overflow-x: hidden;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/* ── Individual commit row ───────────────────────────────────────────────── */
|
|
34
|
+
.scm-history-graph-row {
|
|
35
|
+
display: flex;
|
|
36
|
+
align-items: flex-start;
|
|
37
|
+
height: 22px;
|
|
38
|
+
cursor: pointer;
|
|
39
|
+
padding-right: var(--theia-ui-padding);
|
|
40
|
+
box-sizing: border-box;
|
|
41
|
+
overflow: hidden;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.scm-history-graph-row:hover {
|
|
45
|
+
background-color: var(--theia-list-hoverBackground);
|
|
46
|
+
color: var(--theia-list-hoverForeground);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.scm-history-graph-row.selected {
|
|
50
|
+
background-color: var(--theia-list-activeSelectionBackground);
|
|
51
|
+
color: var(--theia-list-activeSelectionForeground);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* ── SVG lane column ─────────────────────────────────────────────────────── */
|
|
55
|
+
.scm-history-graph-svg {
|
|
56
|
+
flex-shrink: 0;
|
|
57
|
+
overflow: visible;
|
|
58
|
+
display: block;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/* ── Commit info column ──────────────────────────────────────────────────── */
|
|
62
|
+
.scm-history-graph-info {
|
|
63
|
+
flex: 1;
|
|
64
|
+
display: flex;
|
|
65
|
+
align-items: center;
|
|
66
|
+
min-width: 0;
|
|
67
|
+
gap: 4px;
|
|
68
|
+
padding-left: 4px;
|
|
69
|
+
overflow: hidden;
|
|
70
|
+
height: 22px;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/* ── Subject line (primary content) ─────────────────────────────────────── */
|
|
74
|
+
.scm-history-subject {
|
|
75
|
+
flex-shrink: 1;
|
|
76
|
+
min-width: 0;
|
|
77
|
+
overflow: hidden;
|
|
78
|
+
text-overflow: ellipsis;
|
|
79
|
+
white-space: nowrap;
|
|
80
|
+
font-weight: normal;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/* ── Author name (dimmed, next to subject) ───────────────────────────────── */
|
|
84
|
+
.scm-history-author {
|
|
85
|
+
flex-shrink: 1;
|
|
86
|
+
min-width: 0;
|
|
87
|
+
font-size: var(--theia-ui-font-size0);
|
|
88
|
+
opacity: 0.7;
|
|
89
|
+
white-space: nowrap;
|
|
90
|
+
overflow: hidden;
|
|
91
|
+
text-overflow: ellipsis;
|
|
92
|
+
padding-left: 4px;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/* ── Badges container (pushed to the right) ─────────────────────────────── */
|
|
96
|
+
.scm-history-badges {
|
|
97
|
+
display: flex;
|
|
98
|
+
align-items: center;
|
|
99
|
+
gap: 2px;
|
|
100
|
+
flex-shrink: 0;
|
|
101
|
+
padding-left: 4px;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.scm-history-badges-right {
|
|
105
|
+
margin-left: auto;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/* ── Ref badges (branch / tag labels) ───────────────────────────────────── */
|
|
109
|
+
.scm-history-ref-badge {
|
|
110
|
+
display: inline-flex;
|
|
111
|
+
align-items: center;
|
|
112
|
+
gap: 3px;
|
|
113
|
+
padding: 0 6px;
|
|
114
|
+
border-radius: 10px;
|
|
115
|
+
font-size: var(--theia-ui-font-size0);
|
|
116
|
+
line-height: 1;
|
|
117
|
+
min-height: 15px;
|
|
118
|
+
white-space: nowrap;
|
|
119
|
+
flex-shrink: 0;
|
|
120
|
+
max-width: 140px;
|
|
121
|
+
overflow: hidden;
|
|
122
|
+
box-sizing: border-box;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.scm-history-ref-badge .scm-history-ref-text {
|
|
126
|
+
overflow: hidden;
|
|
127
|
+
text-overflow: ellipsis;
|
|
128
|
+
min-width: 0;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.scm-history-ref-badge .scm-history-ref-icon {
|
|
132
|
+
flex-shrink: 0;
|
|
133
|
+
font-size: 11px;
|
|
134
|
+
line-height: 1;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/* Tooltip badges always show text, override max-width */
|
|
138
|
+
.scm-history-ref-badge.tooltip-badge {
|
|
139
|
+
max-width: none;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/* Fallback colors when no inline lane color is set */
|
|
143
|
+
.scm-history-ref-badge.head {
|
|
144
|
+
background-color: var(--theia-scmGraph-historyItemRefColor, var(--theia-badge-background));
|
|
145
|
+
color: var(--theia-badge-foreground);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.scm-history-ref-badge.remote {
|
|
149
|
+
background-color: var(--theia-scmGraph-historyItemRemoteRefColor, var(--theia-statusBar-background));
|
|
150
|
+
color: var(--theia-statusBar-foreground);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.scm-history-ref-badge.tag {
|
|
154
|
+
background-color: var(--theia-scmGraph-historyItemBaseRefColor, var(--theia-inputValidation-warningBackground));
|
|
155
|
+
color: var(--theia-inputValidation-warningForeground);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.scm-history-ref-badge.base {
|
|
159
|
+
background-color: var(--theia-list-inactiveSelectionBackground);
|
|
160
|
+
color: var(--theia-list-inactiveSelectionForeground);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/* Icon-only cloud badge (remote tracking indicator) */
|
|
164
|
+
.scm-history-ref-badge-cloud {
|
|
165
|
+
padding: 0 4px;
|
|
166
|
+
max-width: none;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/* ── Changed files rows (expanded below a commit) ───────────────────────── */
|
|
170
|
+
.scm-history-change-row {
|
|
171
|
+
display: flex;
|
|
172
|
+
align-items: center;
|
|
173
|
+
height: 22px;
|
|
174
|
+
box-sizing: border-box;
|
|
175
|
+
padding-right: var(--theia-ui-padding);
|
|
176
|
+
cursor: pointer;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.scm-history-change-row:hover {
|
|
180
|
+
background-color: var(--theia-list-hoverBackground);
|
|
181
|
+
color: var(--theia-list-hoverForeground);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.scm-history-change-row.selected {
|
|
185
|
+
background-color: var(--theia-list-activeSelectionBackground);
|
|
186
|
+
color: var(--theia-list-activeSelectionForeground);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.scm-history-change-info {
|
|
190
|
+
flex: 1;
|
|
191
|
+
display: flex;
|
|
192
|
+
align-items: center;
|
|
193
|
+
min-width: 0;
|
|
194
|
+
gap: 4px;
|
|
195
|
+
padding-left: 4px;
|
|
196
|
+
overflow: hidden;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.scm-history-change-file-icon {
|
|
200
|
+
flex-shrink: 0;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.scm-history-change-name-container {
|
|
204
|
+
flex: 1;
|
|
205
|
+
display: flex;
|
|
206
|
+
align-items: center;
|
|
207
|
+
min-width: 0;
|
|
208
|
+
overflow: hidden;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.scm-history-change-name {
|
|
212
|
+
flex-shrink: 0;
|
|
213
|
+
overflow: hidden;
|
|
214
|
+
text-overflow: ellipsis;
|
|
215
|
+
white-space: nowrap;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.scm-history-change-dir {
|
|
219
|
+
flex: 1;
|
|
220
|
+
font-size: var(--theia-ui-font-size0);
|
|
221
|
+
opacity: 0.6;
|
|
222
|
+
overflow: hidden;
|
|
223
|
+
text-overflow: ellipsis;
|
|
224
|
+
white-space: nowrap;
|
|
225
|
+
padding-left: 4px;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
.scm-history-change-status {
|
|
229
|
+
flex-shrink: 0;
|
|
230
|
+
font-size: var(--theia-ui-font-size0);
|
|
231
|
+
font-weight: bold;
|
|
232
|
+
width: 14px;
|
|
233
|
+
text-align: center;
|
|
234
|
+
margin-left: auto;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
.scm-history-change-status.added {
|
|
238
|
+
color: var(--theia-gitDecoration-addedResourceForeground, #388a34);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
.scm-history-change-status.deleted {
|
|
242
|
+
color: var(--theia-gitDecoration-deletedResourceForeground, #a1260d);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
.scm-history-change-status.modified {
|
|
246
|
+
color: var(--theia-gitDecoration-modifiedResourceForeground, #0078d4);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
.scm-history-change-status.renamed {
|
|
250
|
+
color: var(--theia-gitDecoration-renamedResourceForeground, #b180d7);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
.scm-history-changes-loading,
|
|
254
|
+
.scm-history-changes-empty {
|
|
255
|
+
display: flex;
|
|
256
|
+
align-items: center;
|
|
257
|
+
height: 22px;
|
|
258
|
+
padding-left: 24px;
|
|
259
|
+
font-size: var(--theia-ui-font-size0);
|
|
260
|
+
opacity: 0.6;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/* ── Load-more button ────────────────────────────────────────────────────── */
|
|
264
|
+
.scm-history-load-more {
|
|
265
|
+
display: flex;
|
|
266
|
+
align-items: center;
|
|
267
|
+
justify-content: center;
|
|
268
|
+
height: 28px;
|
|
269
|
+
cursor: pointer;
|
|
270
|
+
font-size: var(--theia-ui-font-size1);
|
|
271
|
+
color: var(--theia-textLink-foreground);
|
|
272
|
+
flex-shrink: 0;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
.scm-history-load-more:hover {
|
|
276
|
+
text-decoration: underline;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/* ── Loading spinner placeholder ────────────────────────────────────────── */
|
|
280
|
+
.scm-history-loading {
|
|
281
|
+
display: flex;
|
|
282
|
+
align-items: center;
|
|
283
|
+
justify-content: center;
|
|
284
|
+
height: 28px;
|
|
285
|
+
font-size: var(--theia-ui-font-size1);
|
|
286
|
+
opacity: 0.6;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/* ── Tooltip header icon alignment ──────────────────────────────────────── */
|
|
290
|
+
.scm-history-tooltip-header .icon-inline {
|
|
291
|
+
vertical-align: middle;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/* ── Tooltip stat colors (used inside .theia-hover) ─────────────────────── */
|
|
295
|
+
.scm-history-stat-added {
|
|
296
|
+
color: var(--theia-gitDecoration-addedResourceForeground, #388a34);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
.scm-history-stat-deleted {
|
|
300
|
+
color: var(--theia-gitDecoration-deletedResourceForeground, #a1260d);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/* ── Empty state ─────────────────────────────────────────────────────────── */
|
|
304
|
+
.scm-history-empty {
|
|
305
|
+
display: flex;
|
|
306
|
+
align-items: center;
|
|
307
|
+
justify-content: center;
|
|
308
|
+
flex: 1;
|
|
309
|
+
opacity: 0.6;
|
|
310
|
+
font-size: var(--theia-ui-font-size1);
|
|
311
|
+
padding: var(--theia-ui-padding);
|
|
312
|
+
text-align: center;
|
|
313
|
+
}
|