@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
|
@@ -0,0 +1,213 @@
|
|
|
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 { MarkdownRenderer } from '@theia/core/lib/browser/markdown-rendering/markdown-renderer';
|
|
18
|
+
import { MarkdownStringImpl } from '@theia/core/lib/common/markdown-rendering/markdown-string';
|
|
19
|
+
import { codicon } from '@theia/core/lib/browser/widgets/widget';
|
|
20
|
+
import { nls } from '@theia/core/lib/common/nls';
|
|
21
|
+
import { ScmHistoryItemRef } from './scm-provider';
|
|
22
|
+
import { HistoryGraphEntry } from './scm-history-graph-model';
|
|
23
|
+
import { laneColor, getRefBadgeClass, deduplicateRefs, isTagRef, isRemoteRef } from './scm-history-graph-helpers';
|
|
24
|
+
|
|
25
|
+
export function formatRelativeTime(ms: number): string {
|
|
26
|
+
const now = Date.now();
|
|
27
|
+
const diffMs = now - ms;
|
|
28
|
+
const diffSec = Math.floor(diffMs / 1000);
|
|
29
|
+
const diffMin = Math.floor(diffSec / 60);
|
|
30
|
+
const diffHour = Math.floor(diffMin / 60);
|
|
31
|
+
const diffDay = Math.floor(diffHour / 24);
|
|
32
|
+
|
|
33
|
+
if (diffDay > 30) {
|
|
34
|
+
return new Date(ms).toLocaleDateString();
|
|
35
|
+
}
|
|
36
|
+
if (diffDay >= 1) {
|
|
37
|
+
return diffDay === 1
|
|
38
|
+
? nls.localizeByDefault('{0} day ago', diffDay)
|
|
39
|
+
: nls.localizeByDefault('{0} days ago', diffDay);
|
|
40
|
+
}
|
|
41
|
+
if (diffHour >= 1) {
|
|
42
|
+
return diffHour === 1
|
|
43
|
+
? nls.localize('theia/scm/1HourAgo', '1 hour ago')
|
|
44
|
+
: nls.localizeByDefault('{0} hours ago', diffHour);
|
|
45
|
+
}
|
|
46
|
+
if (diffMin >= 1) {
|
|
47
|
+
return diffMin === 1
|
|
48
|
+
? nls.localize('theia/scm/1MinuteAgo', '1 minute ago')
|
|
49
|
+
: nls.localizeByDefault('{0} minutes ago', diffMin);
|
|
50
|
+
}
|
|
51
|
+
return nls.localize('theia/scm/justNow', 'just now');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function formatAbsoluteDate(ms: number): string {
|
|
55
|
+
return new Date(ms).toLocaleString(undefined, {
|
|
56
|
+
year: 'numeric',
|
|
57
|
+
month: 'long',
|
|
58
|
+
day: 'numeric',
|
|
59
|
+
hour: 'numeric',
|
|
60
|
+
minute: '2-digit',
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Appends a theme icon `<i>` element followed by a text node into a container.
|
|
66
|
+
*/
|
|
67
|
+
export function appendIconText(container: HTMLElement, iconName: string, text: string): void {
|
|
68
|
+
const icon = document.createElement('i');
|
|
69
|
+
icon.className = codicon(iconName) + ' icon-inline';
|
|
70
|
+
container.appendChild(icon);
|
|
71
|
+
container.appendChild(document.createTextNode(` ${text}`));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function createHoverHr(): HTMLElement {
|
|
75
|
+
return document.createElement('hr');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Creates a ref badge element for the HTML tooltip. */
|
|
79
|
+
export function buildTooltipRefBadge(
|
|
80
|
+
ref: ScmHistoryItemRef,
|
|
81
|
+
iconClass: string,
|
|
82
|
+
showText: boolean,
|
|
83
|
+
bgColor: string,
|
|
84
|
+
extraClass?: string
|
|
85
|
+
): HTMLElement {
|
|
86
|
+
const badge = document.createElement('span');
|
|
87
|
+
badge.className = `scm-history-ref-badge ${getRefBadgeClass(ref)} tooltip-badge${extraClass ? ' ' + extraClass : ''}`;
|
|
88
|
+
badge.title = ref.description ?? ref.name;
|
|
89
|
+
badge.style.backgroundColor = bgColor;
|
|
90
|
+
badge.style.color = 'var(--theia-scmGraph-historyItemRefForeground, var(--theia-badge-foreground))';
|
|
91
|
+
const icon = document.createElement('i');
|
|
92
|
+
icon.className = `codicon ${iconClass} scm-history-ref-icon`;
|
|
93
|
+
badge.appendChild(icon);
|
|
94
|
+
if (showText) {
|
|
95
|
+
const text = document.createElement('span');
|
|
96
|
+
text.className = 'scm-history-ref-text';
|
|
97
|
+
text.textContent = ref.name;
|
|
98
|
+
badge.appendChild(text);
|
|
99
|
+
}
|
|
100
|
+
return badge;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function buildHtmlTooltip(entry: HistoryGraphEntry, markdownRenderer: MarkdownRenderer): HTMLElement {
|
|
104
|
+
const { item } = entry;
|
|
105
|
+
const badgeColor = laneColor(entry.graphRow.color);
|
|
106
|
+
const container = document.createElement('div');
|
|
107
|
+
container.className = 'scm-history-tooltip';
|
|
108
|
+
|
|
109
|
+
// Header
|
|
110
|
+
if (item.author || item.timestamp !== undefined) {
|
|
111
|
+
const header = document.createElement('div');
|
|
112
|
+
header.className = 'scm-history-tooltip-header';
|
|
113
|
+
header.style.fontWeight = 'bold';
|
|
114
|
+
header.style.marginBottom = '4px';
|
|
115
|
+
|
|
116
|
+
if (item.author) {
|
|
117
|
+
appendIconText(header, 'account', item.author);
|
|
118
|
+
}
|
|
119
|
+
if (item.timestamp !== undefined) {
|
|
120
|
+
if (item.author) {
|
|
121
|
+
header.appendChild(document.createTextNode('\u00a0\u00a0'));
|
|
122
|
+
}
|
|
123
|
+
const timeSpan = document.createElement('span');
|
|
124
|
+
appendIconText(timeSpan, 'clock', `${formatRelativeTime(item.timestamp)} (${formatAbsoluteDate(item.timestamp)})`);
|
|
125
|
+
header.appendChild(timeSpan);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
container.appendChild(header);
|
|
129
|
+
container.appendChild(createHoverHr());
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Body
|
|
133
|
+
const bodyText = (item.message && item.message.trim() !== item.subject.trim())
|
|
134
|
+
? item.message.trim()
|
|
135
|
+
: item.subject;
|
|
136
|
+
const bodyMd = new MarkdownStringImpl(bodyText);
|
|
137
|
+
const rendered = markdownRenderer.render(bodyMd);
|
|
138
|
+
container.appendChild(rendered.element);
|
|
139
|
+
|
|
140
|
+
// Stats
|
|
141
|
+
if (item.statistics) {
|
|
142
|
+
const s = item.statistics;
|
|
143
|
+
container.appendChild(createHoverHr());
|
|
144
|
+
|
|
145
|
+
const stats = document.createElement('div');
|
|
146
|
+
stats.className = 'scm-history-tooltip-stats';
|
|
147
|
+
|
|
148
|
+
const fileCount = s.files === 1 ? '1 file changed' : `${s.files} files changed`;
|
|
149
|
+
const filesStrong = document.createElement('strong');
|
|
150
|
+
filesStrong.textContent = fileCount;
|
|
151
|
+
stats.appendChild(filesStrong);
|
|
152
|
+
|
|
153
|
+
if (s.insertions > 0) {
|
|
154
|
+
stats.appendChild(document.createTextNode(', '));
|
|
155
|
+
const ins = document.createElement('span');
|
|
156
|
+
ins.className = 'scm-history-stat-added';
|
|
157
|
+
ins.textContent = `${s.insertions} insertion${s.insertions === 1 ? '' : 's'}(+)`;
|
|
158
|
+
stats.appendChild(ins);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (s.deletions > 0) {
|
|
162
|
+
stats.appendChild(document.createTextNode(', '));
|
|
163
|
+
const del = document.createElement('span');
|
|
164
|
+
del.className = 'scm-history-stat-deleted';
|
|
165
|
+
del.textContent = `${s.deletions} deletion${s.deletions === 1 ? '' : 's'}(-)`;
|
|
166
|
+
stats.appendChild(del);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
container.appendChild(stats);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Refs + hash
|
|
173
|
+
const hasRefs = item.references && item.references.length > 0;
|
|
174
|
+
if (hasRefs || item.displayId) {
|
|
175
|
+
container.appendChild(createHoverHr());
|
|
176
|
+
|
|
177
|
+
const refsRow = document.createElement('div');
|
|
178
|
+
refsRow.className = 'scm-history-tooltip-refs';
|
|
179
|
+
refsRow.style.display = 'flex';
|
|
180
|
+
refsRow.style.flexWrap = 'wrap';
|
|
181
|
+
refsRow.style.gap = '4px';
|
|
182
|
+
refsRow.style.alignItems = 'center';
|
|
183
|
+
|
|
184
|
+
if (hasRefs) {
|
|
185
|
+
const deduplicated = deduplicateRefs(item.references!);
|
|
186
|
+
for (const { ref, hasBoth } of deduplicated) {
|
|
187
|
+
const isTag = isTagRef(ref);
|
|
188
|
+
const isRemote = isRemoteRef(ref);
|
|
189
|
+
|
|
190
|
+
if (isTag) {
|
|
191
|
+
refsRow.appendChild(buildTooltipRefBadge(ref, 'codicon-tag', true, badgeColor));
|
|
192
|
+
} else if (isRemote) {
|
|
193
|
+
refsRow.appendChild(buildTooltipRefBadge(ref, 'codicon-cloud', true, badgeColor));
|
|
194
|
+
} else {
|
|
195
|
+
refsRow.appendChild(buildTooltipRefBadge(ref, 'codicon-git-branch', true, badgeColor));
|
|
196
|
+
if (hasBoth) {
|
|
197
|
+
refsRow.appendChild(buildTooltipRefBadge(ref, 'codicon-cloud', false, badgeColor, 'scm-history-ref-badge-cloud'));
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (item.displayId) {
|
|
204
|
+
const hash = document.createElement('code');
|
|
205
|
+
hash.textContent = item.displayId;
|
|
206
|
+
refsRow.appendChild(hash);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
container.appendChild(refsRow);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return container;
|
|
213
|
+
}
|