@theia/scm 1.75.0-next.18 → 1.75.0-next.21
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/scm-frontend-module.d.ts.map +1 -1
- package/lib/browser/scm-frontend-module.js +6 -0
- package/lib/browser/scm-frontend-module.js.map +1 -1
- package/lib/browser/scm-history-graph-contribution.d.ts +42 -0
- package/lib/browser/scm-history-graph-contribution.d.ts.map +1 -0
- package/lib/browser/scm-history-graph-contribution.js +220 -0
- package/lib/browser/scm-history-graph-contribution.js.map +1 -0
- package/lib/browser/scm-history-graph-contribution.spec.d.ts +2 -0
- package/lib/browser/scm-history-graph-contribution.spec.d.ts.map +1 -0
- package/lib/browser/scm-history-graph-contribution.spec.js +66 -0
- package/lib/browser/scm-history-graph-contribution.spec.js.map +1 -0
- package/lib/browser/scm-history-graph-helpers.d.ts +8 -0
- package/lib/browser/scm-history-graph-helpers.d.ts.map +1 -1
- package/lib/browser/scm-history-graph-helpers.js +20 -0
- package/lib/browser/scm-history-graph-helpers.js.map +1 -1
- package/lib/browser/scm-history-graph-helpers.spec.js +25 -0
- package/lib/browser/scm-history-graph-helpers.spec.js.map +1 -1
- package/lib/browser/scm-history-graph-model.d.ts +43 -5
- package/lib/browser/scm-history-graph-model.d.ts.map +1 -1
- package/lib/browser/scm-history-graph-model.js +84 -10
- package/lib/browser/scm-history-graph-model.js.map +1 -1
- package/lib/browser/scm-history-graph-model.spec.js +145 -4
- package/lib/browser/scm-history-graph-model.spec.js.map +1 -1
- package/lib/browser/scm-history-graph-widget.d.ts +8 -1
- package/lib/browser/scm-history-graph-widget.d.ts.map +1 -1
- package/lib/browser/scm-history-graph-widget.js +23 -4
- package/lib/browser/scm-history-graph-widget.js.map +1 -1
- package/lib/browser/scm-history-graph-widget.spec.js +11 -1
- package/lib/browser/scm-history-graph-widget.spec.js.map +1 -1
- package/lib/common/scm-preferences.d.ts +3 -0
- package/lib/common/scm-preferences.d.ts.map +1 -1
- package/lib/common/scm-preferences.js +24 -0
- package/lib/common/scm-preferences.js.map +1 -1
- package/package.json +6 -6
- package/src/browser/scm-frontend-module.ts +7 -1
- package/src/browser/scm-history-graph-contribution.spec.ts +83 -0
- package/src/browser/scm-history-graph-contribution.ts +220 -0
- package/src/browser/scm-history-graph-helpers.spec.ts +34 -1
- package/src/browser/scm-history-graph-helpers.ts +25 -0
- package/src/browser/scm-history-graph-model.spec.ts +184 -9
- package/src/browser/scm-history-graph-model.ts +99 -11
- package/src/browser/scm-history-graph-widget.spec.ts +12 -1
- package/src/browser/scm-history-graph-widget.tsx +26 -6
- package/src/common/scm-preferences.ts +27 -0
|
@@ -19,12 +19,23 @@ import { Disposable, DisposableCollection } from '@theia/core/lib/common/disposa
|
|
|
19
19
|
import { Emitter } from '@theia/core/lib/common/event';
|
|
20
20
|
import { CancellationTokenSource } from '@theia/core/lib/common/cancellation';
|
|
21
21
|
import { ScmService } from './scm-service';
|
|
22
|
-
import { ScmHistoryItem, ScmHistoryProvider, ScmHistoryOptions } from './scm-provider';
|
|
22
|
+
import { ScmHistoryItem, ScmHistoryItemRef, ScmHistoryProvider, ScmHistoryOptions } from './scm-provider';
|
|
23
23
|
import { computeGraphRows, GraphRow } from './scm-history-graph-lanes';
|
|
24
24
|
import { getRefColorIndex } from './scm-history-graph-helpers';
|
|
25
|
+
import { ScmPreferences } from '../common/scm-preferences';
|
|
25
26
|
|
|
26
27
|
export const PAGE_SIZE = 50;
|
|
27
28
|
|
|
29
|
+
export const ScmHistoryGraphModelProvider = Symbol('ScmHistoryGraphModelProvider');
|
|
30
|
+
/**
|
|
31
|
+
* Resolves the {@link ScmHistoryGraphModel} singleton on first use. The model
|
|
32
|
+
* starts loading history and subscribing to provider events as soon as it is
|
|
33
|
+
* instantiated, so clients that may not need it (e.g. command contributions
|
|
34
|
+
* instantiated at application start) must inject this provider instead of the
|
|
35
|
+
* model itself.
|
|
36
|
+
*/
|
|
37
|
+
export type ScmHistoryGraphModelProvider = () => ScmHistoryGraphModel;
|
|
38
|
+
|
|
28
39
|
export interface HistoryGraphEntry {
|
|
29
40
|
readonly item: ScmHistoryItem;
|
|
30
41
|
readonly graphRow: GraphRow;
|
|
@@ -36,6 +47,7 @@ export interface HistoryGraphEntry {
|
|
|
36
47
|
export class ScmHistoryGraphModel {
|
|
37
48
|
|
|
38
49
|
@inject(ScmService) protected readonly scmService: ScmService;
|
|
50
|
+
@inject(ScmPreferences) protected readonly scmPreferences: ScmPreferences;
|
|
39
51
|
|
|
40
52
|
protected readonly toDispose = new DisposableCollection();
|
|
41
53
|
protected readonly toDisposeOnProviderChange = new DisposableCollection();
|
|
@@ -45,6 +57,8 @@ export class ScmHistoryGraphModel {
|
|
|
45
57
|
protected _loading = false;
|
|
46
58
|
protected _hasAttemptedLoad = false;
|
|
47
59
|
protected _provider: ScmHistoryProvider | undefined;
|
|
60
|
+
/** Explicitly picked ref ids to filter the graph by; `undefined` = auto (current/remote/base). */
|
|
61
|
+
protected _historyItemRefFilter: string[] | undefined;
|
|
48
62
|
|
|
49
63
|
protected readonly onDidChangeEmitter = new Emitter<void>();
|
|
50
64
|
readonly onDidChange = this.onDidChangeEmitter.event;
|
|
@@ -57,6 +71,11 @@ export class ScmHistoryGraphModel {
|
|
|
57
71
|
Disposable.create(() => this.toDisposeOnProviderChange.dispose()),
|
|
58
72
|
this.onDidChangeEmitter,
|
|
59
73
|
this.scmService.onDidChangeSelectedRepository(() => this.refresh()),
|
|
74
|
+
this.scmPreferences.onPreferenceChanged(e => {
|
|
75
|
+
if (e.preferenceName === 'scm.graph.pageSize') {
|
|
76
|
+
this.reload();
|
|
77
|
+
}
|
|
78
|
+
}),
|
|
60
79
|
]);
|
|
61
80
|
this.refresh();
|
|
62
81
|
}
|
|
@@ -70,6 +89,32 @@ export class ScmHistoryGraphModel {
|
|
|
70
89
|
return this._provider;
|
|
71
90
|
}
|
|
72
91
|
|
|
92
|
+
/** The explicitly picked ref ids filtering the graph, or `undefined` in auto mode. */
|
|
93
|
+
get historyItemRefFilter(): readonly string[] | undefined {
|
|
94
|
+
return this._historyItemRefFilter;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Sets the ref ids to filter the graph by (`undefined` returns to auto
|
|
99
|
+
* mode) and reloads the graph.
|
|
100
|
+
*/
|
|
101
|
+
setHistoryItemRefFilter(refIds: readonly string[] | undefined): void {
|
|
102
|
+
this._historyItemRefFilter = refIds && refIds.length > 0 ? [...refIds] : undefined;
|
|
103
|
+
this.reload();
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Whether the current history item ref is part of the graph's filter.
|
|
108
|
+
* Always true in auto mode, which includes the current ref.
|
|
109
|
+
*/
|
|
110
|
+
isCurrentRefInFilter(): boolean {
|
|
111
|
+
if (!this._historyItemRefFilter) {
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
const currentId = this._provider?.currentHistoryItemRef?.id;
|
|
115
|
+
return currentId !== undefined && this._historyItemRefFilter.includes(currentId);
|
|
116
|
+
}
|
|
117
|
+
|
|
73
118
|
get entries(): readonly HistoryGraphEntry[] {
|
|
74
119
|
return this._entries;
|
|
75
120
|
}
|
|
@@ -92,13 +137,14 @@ export class ScmHistoryGraphModel {
|
|
|
92
137
|
}
|
|
93
138
|
|
|
94
139
|
refresh(): void {
|
|
95
|
-
this.cancelSource.cancel();
|
|
96
|
-
this.cancelSource = new CancellationTokenSource();
|
|
97
|
-
|
|
98
140
|
this.toDisposeOnProviderChange.dispose();
|
|
99
141
|
|
|
100
142
|
const repo = this.scmService.selectedRepository;
|
|
101
143
|
const hp = repo?.provider.historyProvider;
|
|
144
|
+
if (hp !== this._provider) {
|
|
145
|
+
// The repository changed — a filter picked for the old provider does not apply.
|
|
146
|
+
this._historyItemRefFilter = undefined;
|
|
147
|
+
}
|
|
102
148
|
this._provider = hp;
|
|
103
149
|
|
|
104
150
|
if (this._provider) {
|
|
@@ -106,7 +152,10 @@ export class ScmHistoryGraphModel {
|
|
|
106
152
|
this._provider.onDidChangeCurrentHistoryItemRefs(() => this.refresh())
|
|
107
153
|
);
|
|
108
154
|
this.toDisposeOnProviderChange.push(
|
|
109
|
-
this._provider.onDidChangeHistoryItemRefs(
|
|
155
|
+
this._provider.onDidChangeHistoryItemRefs(e => {
|
|
156
|
+
this.pruneHistoryItemRefFilter(e.removed);
|
|
157
|
+
this.refresh();
|
|
158
|
+
})
|
|
110
159
|
);
|
|
111
160
|
} else if (repo) {
|
|
112
161
|
// historyProvider is not yet available; listen for provider changes
|
|
@@ -116,6 +165,31 @@ export class ScmHistoryGraphModel {
|
|
|
116
165
|
);
|
|
117
166
|
}
|
|
118
167
|
|
|
168
|
+
this.reload();
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Drops refs that no longer exist from the explicit filter, so that
|
|
173
|
+
* deleting or renaming a filtered ref does not leave the graph stuck
|
|
174
|
+
* requesting history for it. When the last filtered ref is removed,
|
|
175
|
+
* the filter falls back to auto mode.
|
|
176
|
+
*/
|
|
177
|
+
protected pruneHistoryItemRefFilter(removed: readonly ScmHistoryItemRef[]): void {
|
|
178
|
+
if (!this._historyItemRefFilter || removed.length === 0) {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
const removedIds = new Set(removed.map(ref => ref.id));
|
|
182
|
+
const remaining = this._historyItemRefFilter.filter(id => !removedIds.has(id));
|
|
183
|
+
if (remaining.length !== this._historyItemRefFilter.length) {
|
|
184
|
+
this._historyItemRefFilter = remaining.length > 0 ? remaining : undefined;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/** Clears the loaded entries and loads the first page again from the current provider. */
|
|
189
|
+
protected reload(): void {
|
|
190
|
+
this.cancelSource.cancel();
|
|
191
|
+
this.cancelSource = new CancellationTokenSource();
|
|
192
|
+
|
|
119
193
|
this._entries = [];
|
|
120
194
|
this._hasMore = false;
|
|
121
195
|
|
|
@@ -144,10 +218,11 @@ export class ScmHistoryGraphModel {
|
|
|
144
218
|
|
|
145
219
|
const token = this.cancelSource.token;
|
|
146
220
|
try {
|
|
221
|
+
const pageSize = this.pageSize;
|
|
147
222
|
const historyItemRefs = this.getCurrentHistoryItemRefs();
|
|
148
223
|
const options: ScmHistoryOptions = {
|
|
149
224
|
skip: this._entries.length,
|
|
150
|
-
limit:
|
|
225
|
+
limit: pageSize,
|
|
151
226
|
historyItemRefs: historyItemRefs.length > 0 ? historyItemRefs : undefined,
|
|
152
227
|
};
|
|
153
228
|
const items = await this._provider.provideHistoryItems(options, token);
|
|
@@ -157,7 +232,7 @@ export class ScmHistoryGraphModel {
|
|
|
157
232
|
}
|
|
158
233
|
|
|
159
234
|
const fetchedItems: ScmHistoryItem[] = items ?? [];
|
|
160
|
-
this._hasMore = fetchedItems.length >=
|
|
235
|
+
this._hasMore = fetchedItems.length >= pageSize;
|
|
161
236
|
|
|
162
237
|
// Filter out any items already loaded so the graph does not show duplicates.
|
|
163
238
|
const existingIds = new Set(this._entries.map(e => e.item.id));
|
|
@@ -189,13 +264,22 @@ export class ScmHistoryGraphModel {
|
|
|
189
264
|
}
|
|
190
265
|
}
|
|
191
266
|
|
|
267
|
+
/** The configured page size (`scm.graph.pageSize`). */
|
|
268
|
+
protected get pageSize(): number {
|
|
269
|
+
return this.scmPreferences['scm.graph.pageSize'] ?? PAGE_SIZE;
|
|
270
|
+
}
|
|
271
|
+
|
|
192
272
|
/**
|
|
193
273
|
* Resolves the ref-based color index of an item from its references,
|
|
194
|
-
* preferring current (0) over remote (1) over base (2).
|
|
274
|
+
* preferring current (0) over remote (1) over base (2). Refs excluded by
|
|
275
|
+
* an explicit filter get no role color, mirroring VS Code's color map.
|
|
195
276
|
*/
|
|
196
277
|
protected resolveColorIndex(item: ScmHistoryItem): number | undefined {
|
|
197
278
|
let result: number | undefined;
|
|
198
279
|
for (const ref of item.references ?? []) {
|
|
280
|
+
if (this._historyItemRefFilter && !this._historyItemRefFilter.includes(ref.id)) {
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
199
283
|
const index = getRefColorIndex(ref, this._provider);
|
|
200
284
|
if (index !== undefined && (result === undefined || index < result)) {
|
|
201
285
|
result = index;
|
|
@@ -205,11 +289,15 @@ export class ScmHistoryGraphModel {
|
|
|
205
289
|
}
|
|
206
290
|
|
|
207
291
|
/**
|
|
208
|
-
* Returns the
|
|
209
|
-
*
|
|
210
|
-
*
|
|
292
|
+
* Returns the refs to pass to `provideHistoryItems`: the explicitly picked
|
|
293
|
+
* ref ids when a filter is active, otherwise (auto mode) the revisions of
|
|
294
|
+
* the current branch ref, its remote tracking ref, and the merge-base ref.
|
|
295
|
+
* Providers walk history starting from these refs.
|
|
211
296
|
*/
|
|
212
297
|
protected getCurrentHistoryItemRefs(): string[] {
|
|
298
|
+
if (this._historyItemRefFilter) {
|
|
299
|
+
return [...this._historyItemRefFilter];
|
|
300
|
+
}
|
|
213
301
|
if (!this._provider) {
|
|
214
302
|
return [];
|
|
215
303
|
}
|
|
@@ -48,15 +48,17 @@ describe('ScmHistoryGraphWidget context keys', () => {
|
|
|
48
48
|
let widget: ScmHistoryGraphWidget;
|
|
49
49
|
let scmContextKeys: ScmContextKeyService;
|
|
50
50
|
let provider: Partial<ScmHistoryProvider> | undefined;
|
|
51
|
+
let currentRefInFilter: boolean;
|
|
51
52
|
|
|
52
53
|
beforeEach(() => {
|
|
53
54
|
restoreJSDOM = enableJSDOM();
|
|
54
55
|
scmContextKeys = createScmContextKeyService();
|
|
56
|
+
currentRefInFilter = true;
|
|
55
57
|
widget = new ScmHistoryGraphWidget();
|
|
56
58
|
const raw = widget as unknown as Record<string, unknown>;
|
|
57
59
|
raw.scmContextKeys = scmContextKeys;
|
|
58
60
|
Object.defineProperty(raw, 'model', {
|
|
59
|
-
get: () => ({ provider })
|
|
61
|
+
get: () => ({ provider, isCurrentRefInFilter: () => currentRefInFilter })
|
|
60
62
|
});
|
|
61
63
|
});
|
|
62
64
|
|
|
@@ -90,6 +92,15 @@ describe('ScmHistoryGraphWidget context keys', () => {
|
|
|
90
92
|
expect(scmContextKeys.scmCurrentHistoryItemRefInFilter.get()).to.equal(false);
|
|
91
93
|
});
|
|
92
94
|
|
|
95
|
+
it('should clear scmCurrentHistoryItemRefInFilter when the filter excludes the current ref', () => {
|
|
96
|
+
provider = {
|
|
97
|
+
currentHistoryItemRef: { id: 'refs/heads/main', name: 'main' }
|
|
98
|
+
};
|
|
99
|
+
currentRefInFilter = false;
|
|
100
|
+
updateContextKeys();
|
|
101
|
+
expect(scmContextKeys.scmCurrentHistoryItemRefInFilter.get()).to.equal(false);
|
|
102
|
+
});
|
|
103
|
+
|
|
93
104
|
it('should set scmCurrentHistoryItemRefHasRemote when the provider has a remote ref', () => {
|
|
94
105
|
provider = {
|
|
95
106
|
currentHistoryItemRef: { id: 'refs/heads/main', name: 'main' },
|
|
@@ -30,13 +30,16 @@ import URI from '@theia/core/lib/common/uri';
|
|
|
30
30
|
import { nls } from '@theia/core/lib/common/nls';
|
|
31
31
|
import { CancellationTokenSource } from '@theia/core/lib/common/cancellation';
|
|
32
32
|
import { DisposableCollection } from '@theia/core/lib/common/disposable';
|
|
33
|
+
import { Emitter, Event } from '@theia/core/lib/common/event';
|
|
34
|
+
import { DynamicToolbarWidget } from '@theia/core/lib/browser/view-container';
|
|
33
35
|
import { MenuPath } from '@theia/core/lib/common/menu/menu-types';
|
|
34
36
|
import { ContextMenuRenderer } from '@theia/core/lib/browser/context-menu-renderer';
|
|
35
37
|
import { OpenerService, open } from '@theia/core/lib/browser/opener-service';
|
|
36
38
|
import { DiffUris } from '@theia/core/lib/browser/diff-uris';
|
|
37
39
|
import { ScmContextKeyService } from './scm-context-key-service';
|
|
40
|
+
import { ScmPreferences } from '../common/scm-preferences';
|
|
38
41
|
import {
|
|
39
|
-
laneColor, getChangeStatus, getFileName, getFilePath, getRepoRelativePath,
|
|
42
|
+
laneColor, filterRefsForBadges, getChangeStatus, getFileName, getFilePath, getRepoRelativePath,
|
|
40
43
|
getRefBadgeClass, getRefBadgePresentation, isTagRef, isRemoteRef, deduplicateRefs, DeduplicatedRef
|
|
41
44
|
} from './scm-history-graph-helpers';
|
|
42
45
|
import { buildHtmlTooltip, buildProviderTooltip } from './scm-history-graph-tooltip';
|
|
@@ -82,7 +85,7 @@ function renderJsxRefBadge(
|
|
|
82
85
|
// ── Widget ──────────────────────────────────────────────────────────────────
|
|
83
86
|
|
|
84
87
|
@injectable()
|
|
85
|
-
export class ScmHistoryGraphWidget extends ReactWidget {
|
|
88
|
+
export class ScmHistoryGraphWidget extends ReactWidget implements DynamicToolbarWidget {
|
|
86
89
|
|
|
87
90
|
static readonly ID = 'scm-history-graph-widget';
|
|
88
91
|
static readonly LABEL = nls.localizeByDefault('Graph');
|
|
@@ -96,6 +99,7 @@ export class ScmHistoryGraphWidget extends ReactWidget {
|
|
|
96
99
|
@inject(ContextMenuRenderer) protected readonly contextMenuRenderer: ContextMenuRenderer;
|
|
97
100
|
@inject(OpenerService) protected readonly openerService: OpenerService;
|
|
98
101
|
@inject(ScmContextKeyService) protected readonly scmContextKeys: ScmContextKeyService;
|
|
102
|
+
@inject(ScmPreferences) protected readonly scmPreferences: ScmPreferences;
|
|
99
103
|
|
|
100
104
|
protected selectedIndex = -1;
|
|
101
105
|
/** Currently selected change row key (`${itemId}-${ci}`), or undefined. */
|
|
@@ -109,6 +113,10 @@ export class ScmHistoryGraphWidget extends ReactWidget {
|
|
|
109
113
|
/** Cleanup for the content of the hover currently being shown. */
|
|
110
114
|
protected readonly toDisposeOnHover = new DisposableCollection();
|
|
111
115
|
|
|
116
|
+
protected readonly onDidChangeToolbarItemsEmitter = new Emitter<void>();
|
|
117
|
+
/** Re-renders the part toolbar on model changes, e.g. to reflect the toggled state of the ref filter picker. */
|
|
118
|
+
readonly onDidChangeToolbarItems: Event<void> = this.onDidChangeToolbarItemsEmitter.event;
|
|
119
|
+
|
|
112
120
|
constructor() {
|
|
113
121
|
super();
|
|
114
122
|
this.id = ScmHistoryGraphWidget.ID;
|
|
@@ -121,10 +129,19 @@ export class ScmHistoryGraphWidget extends ReactWidget {
|
|
|
121
129
|
|
|
122
130
|
@postConstruct()
|
|
123
131
|
protected init(): void {
|
|
132
|
+
this.toDispose.push(this.onDidChangeToolbarItemsEmitter);
|
|
124
133
|
this.toDispose.push(
|
|
125
134
|
this.model.onDidChange(() => {
|
|
126
135
|
this.updateContextKeys();
|
|
127
136
|
this.update();
|
|
137
|
+
this.onDidChangeToolbarItemsEmitter.fire();
|
|
138
|
+
})
|
|
139
|
+
);
|
|
140
|
+
this.toDispose.push(
|
|
141
|
+
this.scmPreferences.onPreferenceChanged(e => {
|
|
142
|
+
if (e.preferenceName.startsWith('scm.graph.')) {
|
|
143
|
+
this.update();
|
|
144
|
+
}
|
|
128
145
|
})
|
|
129
146
|
);
|
|
130
147
|
this.toDispose.push({
|
|
@@ -144,9 +161,8 @@ export class ScmHistoryGraphWidget extends ReactWidget {
|
|
|
144
161
|
const provider = this.model.provider;
|
|
145
162
|
this.scmContextKeys.scmCurrentHistoryItemRefHasRemote.set(!!provider?.currentHistoryItemRemoteRef);
|
|
146
163
|
this.scmContextKeys.scmCurrentHistoryItemRefHasBase.set(!!provider?.currentHistoryItemBaseRef);
|
|
147
|
-
// The graph has no ref filter yet, so the current ref is always considered part of it.
|
|
148
164
|
// Commands like git.pullRef/git.pushRef gate their enablement on this key.
|
|
149
|
-
this.scmContextKeys.scmCurrentHistoryItemRefInFilter.set(!!provider?.currentHistoryItemRef);
|
|
165
|
+
this.scmContextKeys.scmCurrentHistoryItemRefInFilter.set(!!provider?.currentHistoryItemRef && this.model.isCurrentRefInFilter());
|
|
150
166
|
}
|
|
151
167
|
|
|
152
168
|
protected render(): React.ReactNode {
|
|
@@ -198,7 +214,7 @@ export class ScmHistoryGraphWidget extends ReactWidget {
|
|
|
198
214
|
className='scm-history-graph-list'
|
|
199
215
|
data={entries as HistoryGraphEntry[]}
|
|
200
216
|
itemContent={(idx, entry) => this.renderRow(entry, idx, svgWidth)}
|
|
201
|
-
endReached={hasMore && !loading ? this.handleEndReached : undefined}
|
|
217
|
+
endReached={hasMore && !loading && this.scmPreferences['scm.graph.pageOnScroll'] !== false ? this.handleEndReached : undefined}
|
|
202
218
|
overscan={500}
|
|
203
219
|
components={footer ? { Footer: footer } : {}}
|
|
204
220
|
style={{ overflowX: 'hidden' }}
|
|
@@ -606,8 +622,12 @@ export class ScmHistoryGraphWidget extends ReactWidget {
|
|
|
606
622
|
}
|
|
607
623
|
|
|
608
624
|
const provider = this.model.provider;
|
|
625
|
+
const visibleRefs = filterRefsForBadges(refs, provider, this.scmPreferences['scm.graph.badges'] ?? 'filter', this.model.historyItemRefFilter);
|
|
626
|
+
if (visibleRefs.length === 0) {
|
|
627
|
+
return undefined;
|
|
628
|
+
}
|
|
609
629
|
const laneColorValue = entry ? laneColor(entry.graphRow.color) : undefined;
|
|
610
|
-
const deduplicated = deduplicateRefs(
|
|
630
|
+
const deduplicated = deduplicateRefs(visibleRefs);
|
|
611
631
|
const badgeForeground = 'var(--theia-scmGraph-historyItemRefForeground, var(--theia-badge-foreground))';
|
|
612
632
|
|
|
613
633
|
const badges: React.ReactElement[] = [];
|
|
@@ -35,12 +35,39 @@ export const scmPreferenceSchema: PreferenceSchema = {
|
|
|
35
35
|
],
|
|
36
36
|
description: nls.localizeByDefault('Controls the default Source Control repository view mode.'),
|
|
37
37
|
default: 'list'
|
|
38
|
+
},
|
|
39
|
+
'scm.graph.badges': {
|
|
40
|
+
type: 'string',
|
|
41
|
+
enum: ['all', 'filter'],
|
|
42
|
+
enumDescriptions: [
|
|
43
|
+
nls.localizeByDefault('Show badges of all history item groups in the Source Control Graph view.'),
|
|
44
|
+
nls.localizeByDefault('Show only the badges of history item groups used as a filter in the Source Control Graph view.')
|
|
45
|
+
],
|
|
46
|
+
description: nls.localizeByDefault(
|
|
47
|
+
// eslint-disable-next-line max-len
|
|
48
|
+
'Controls which badges are shown in the Source Control Graph view. The badges are shown on the right side of the graph indicating the names of history item groups.'),
|
|
49
|
+
default: 'filter'
|
|
50
|
+
},
|
|
51
|
+
'scm.graph.pageOnScroll': {
|
|
52
|
+
type: 'boolean',
|
|
53
|
+
description: nls.localizeByDefault('Controls whether the Source Control Graph view will load the next page of items when you scroll to the end of the list.'),
|
|
54
|
+
default: true
|
|
55
|
+
},
|
|
56
|
+
'scm.graph.pageSize': {
|
|
57
|
+
type: 'number',
|
|
58
|
+
minimum: 1,
|
|
59
|
+
maximum: 1000,
|
|
60
|
+
description: nls.localizeByDefault('The number of items to show in the Source Control Graph view by default and when loading more items.'),
|
|
61
|
+
default: 50
|
|
38
62
|
}
|
|
39
63
|
}
|
|
40
64
|
};
|
|
41
65
|
|
|
42
66
|
export interface ScmConfiguration {
|
|
43
67
|
'scm.defaultViewMode': 'tree' | 'list'
|
|
68
|
+
'scm.graph.badges': 'all' | 'filter'
|
|
69
|
+
'scm.graph.pageOnScroll': boolean
|
|
70
|
+
'scm.graph.pageSize': number
|
|
44
71
|
}
|
|
45
72
|
|
|
46
73
|
export const ScmPreferenceContribution = Symbol('ScmPreferenceContribution');
|