Skip to content

Commit edf5868

Browse files
authored
SCM - more improvements to the repositories view (#274438)
* SCM - tweak artifact folder compression * SCM - fixed more commands and layout * SCM - more compression changes
1 parent ff488e3 commit edf5868

File tree

4 files changed

+118
-54
lines changed

4 files changed

+118
-54
lines changed

extensions/git/package.json

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,6 @@
496496
{
497497
"command": "git.branch",
498498
"title": "%command.branch%",
499-
"icon": "$(plus)",
500499
"category": "Git",
501500
"enablement": "!operationInProgress"
502501
},
@@ -1046,6 +1045,20 @@
10461045
"title": "%command.graphCompareRef%",
10471046
"category": "Git",
10481047
"enablement": "!operationInProgress"
1048+
},
1049+
{
1050+
"command": "git.repositories.createBranch",
1051+
"title": "%command.branch%",
1052+
"icon": "$(plus)",
1053+
"category": "Git",
1054+
"enablement": "!operationInProgress"
1055+
},
1056+
{
1057+
"command": "git.repositories.createTag",
1058+
"title": "%command.createTag%",
1059+
"icon": "$(plus)",
1060+
"category": "Git",
1061+
"enablement": "!operationInProgress"
10491062
}
10501063
],
10511064
"continueEditSession": [
@@ -1681,6 +1694,14 @@
16811694
{
16821695
"command": "git.repositories.compareRef",
16831696
"when": "false"
1697+
},
1698+
{
1699+
"command": "git.repositories.createBranch",
1700+
"when": "false"
1701+
},
1702+
{
1703+
"command": "git.repositories.createTag",
1704+
"when": "false"
16841705
}
16851706
],
16861707
"scm/title": [
@@ -1873,12 +1894,12 @@
18731894
],
18741895
"scm/artifactGroup/context": [
18751896
{
1876-
"command": "git.branch",
1897+
"command": "git.repositories.createBranch",
18771898
"group": "inline@1",
18781899
"when": "scmProvider == git && scmArtifactGroup == branches"
18791900
},
18801901
{
1881-
"command": "git.createTag",
1902+
"command": "git.repositories.createTag",
18821903
"group": "inline@1",
18831904
"when": "scmProvider == git && scmArtifactGroup == tags"
18841905
}

extensions/git/src/commands.ts

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3363,24 +3363,7 @@ export class CommandCenter {
33633363

33643364
@command('git.createTag', { repository: true })
33653365
async createTag(repository: Repository, historyItem?: SourceControlHistoryItem): Promise<void> {
3366-
const inputTagName = await window.showInputBox({
3367-
placeHolder: l10n.t('Tag name'),
3368-
prompt: l10n.t('Please provide a tag name'),
3369-
ignoreFocusOut: true
3370-
});
3371-
3372-
if (!inputTagName) {
3373-
return;
3374-
}
3375-
3376-
const inputMessage = await window.showInputBox({
3377-
placeHolder: l10n.t('Message'),
3378-
prompt: l10n.t('Please provide a message to annotate the tag'),
3379-
ignoreFocusOut: true
3380-
});
3381-
3382-
const name = inputTagName.replace(/^\.|\/\.|\.\.|~|\^|:|\/$|\.lock$|\.lock\/|\\|\*|\s|^\s*$|\.$/g, '-');
3383-
await repository.tag({ name, message: inputMessage, ref: historyItem?.id });
3366+
await this._createTag(repository, historyItem?.id);
33843367
}
33853368

33863369
@command('git.deleteTag', { repository: true })
@@ -5259,6 +5242,24 @@ export class CommandCenter {
52595242
config.update(setting, !enabled, true);
52605243
}
52615244

5245+
@command('git.repositories.createBranch', { repository: true })
5246+
async artifactGroupCreateBranch(repository: Repository): Promise<void> {
5247+
if (!repository) {
5248+
return;
5249+
}
5250+
5251+
await this._branch(repository, undefined, false);
5252+
}
5253+
5254+
@command('git.repositories.createTag', { repository: true })
5255+
async artifactGroupCreateTag(repository: Repository): Promise<void> {
5256+
if (!repository) {
5257+
return;
5258+
}
5259+
5260+
await this._createTag(repository);
5261+
}
5262+
52625263
@command('git.repositories.checkout', { repository: true })
52635264
async artifactCheckout(repository: Repository, artifact: SourceControlArtifact): Promise<void> {
52645265
if (!repository || !artifact) {
@@ -5312,6 +5313,27 @@ export class CommandCenter {
53125313
`${sourceRef.ref.name}${artifact.name}`);
53135314
}
53145315

5316+
private async _createTag(repository: Repository, ref?: string): Promise<void> {
5317+
const inputTagName = await window.showInputBox({
5318+
placeHolder: l10n.t('Tag name'),
5319+
prompt: l10n.t('Please provide a tag name'),
5320+
ignoreFocusOut: true
5321+
});
5322+
5323+
if (!inputTagName) {
5324+
return;
5325+
}
5326+
5327+
const inputMessage = await window.showInputBox({
5328+
placeHolder: l10n.t('Message'),
5329+
prompt: l10n.t('Please provide a message to annotate the tag'),
5330+
ignoreFocusOut: true
5331+
});
5332+
5333+
const name = inputTagName.replace(/^\.|\/\.|\.\.|~|\^|:|\/$|\.lock$|\.lock\/|\\|\*|\s|^\s*$|\.$/g, '-');
5334+
await repository.tag({ name, message: inputMessage, ref });
5335+
}
5336+
53155337
private createCommand(id: string, key: string, method: Function, options: ScmCommandOptions): (...args: any[]) => any {
53165338
const result = (...args: any[]) => {
53175339
let result: Promise<any>;

src/vs/workbench/contrib/scm/browser/media/scm.css

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -538,17 +538,18 @@
538538
.scm-repositories-view .scm-artifact-group,
539539
.scm-repositories-view .scm-artifact {
540540
display: flex;
541+
align-items: center;
542+
543+
.icon {
544+
margin-right: 2px;
545+
}
541546
}
542547

543548
.scm-repositories-view .scm-artifact-group .monaco-icon-label,
544549
.scm-repositories-view .scm-artifact .monaco-icon-label {
545550
flex-grow: 1;
546551
}
547552

548-
.scm-repositories-view .scm-artifact .monaco-icon-label-container {
549-
display: flex;
550-
}
551-
552553
.scm-repositories-view .scm-artifact-group .monaco-highlighted-label,
553554
.scm-repositories-view .scm-artifact .monaco-highlighted-label {
554555
display: flex;

src/vs/workbench/contrib/scm/browser/scmRepositoriesViewPane.ts

Lines changed: 49 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import { basename } from '../../../../base/common/resources.js';
4343
import { ICompressibleTreeRenderer } from '../../../../base/browser/ui/tree/objectTree.js';
4444
import { ICompressedTreeNode } from '../../../../base/browser/ui/tree/compressedObjectTreeModel.js';
4545
import { ITreeCompressionDelegate } from '../../../../base/browser/ui/tree/asyncDataTree.js';
46+
import { Codicon } from '../../../../base/common/codicons.js';
4647

4748
type TreeElement = ISCMRepository | SCMArtifactGroupTreeElement | SCMArtifactTreeElement | IResourceNode<SCMArtifactTreeElement, SCMArtifactGroupTreeElement>;
4849

@@ -66,6 +67,7 @@ class ListDelegate implements IListVirtualDelegate<ISCMRepository> {
6667
}
6768

6869
interface ArtifactGroupTemplate {
70+
readonly icon: HTMLElement;
6971
readonly label: IconLabel;
7072
readonly actionBar: WorkbenchToolBar;
7173
readonly elementDisposables: DisposableStore;
@@ -89,21 +91,23 @@ class ArtifactGroupRenderer implements ICompressibleTreeRenderer<SCMArtifactGrou
8991

9092
renderTemplate(container: HTMLElement): ArtifactGroupTemplate {
9193
const element = append(container, $('.scm-artifact-group'));
92-
const label = new IconLabel(element, { supportIcons: true });
94+
const icon = append(element, $('.icon'));
95+
const label = new IconLabel(element, { supportIcons: false });
9396

9497
const actionsContainer = append(element, $('.actions'));
9598
const actionBar = new WorkbenchToolBar(actionsContainer, undefined, this._menuService, this._contextKeyService, this._contextMenuService, this._keybindingService, this._commandService, this._telemetryService);
9699

97-
return { label, actionBar, elementDisposables: new DisposableStore(), templateDisposable: combinedDisposable(label, actionBar) };
100+
return { icon, label, actionBar, elementDisposables: new DisposableStore(), templateDisposable: combinedDisposable(label, actionBar) };
98101
}
99102

100103
renderElement(node: ITreeNode<SCMArtifactGroupTreeElement, FuzzyScore>, index: number, templateData: ArtifactGroupTemplate): void {
101104
const provider = node.element.repository.provider;
102105
const artifactGroup = node.element.artifactGroup;
103-
const artifactGroupIcon = ThemeIcon.isThemeIcon(artifactGroup.icon)
104-
? `$(${artifactGroup.icon.id}) ` : '';
105106

106-
templateData.label.setLabel(`${artifactGroupIcon}${artifactGroup.name}`);
107+
templateData.icon.className = ThemeIcon.isThemeIcon(artifactGroup.icon)
108+
? `icon ${ThemeIcon.asClassName(artifactGroup.icon)}`
109+
: '';
110+
templateData.label.setLabel(artifactGroup.name);
107111

108112
const repositoryMenus = this._scmViewService.menus.getRepositoryMenus(provider);
109113
templateData.elementDisposables.add(connectPrimaryMenu(repositoryMenus.getArtifactGroupMenu(artifactGroup), primary => {
@@ -127,6 +131,7 @@ class ArtifactGroupRenderer implements ICompressibleTreeRenderer<SCMArtifactGrou
127131
}
128132

129133
interface ArtifactTemplate {
134+
readonly icon: HTMLElement;
130135
readonly label: IconLabel;
131136
readonly actionBar: WorkbenchToolBar;
132137
readonly elementDisposables: DisposableStore;
@@ -150,32 +155,35 @@ class ArtifactRenderer implements ICompressibleTreeRenderer<SCMArtifactTreeEleme
150155

151156
renderTemplate(container: HTMLElement): ArtifactTemplate {
152157
const element = append(container, $('.scm-artifact'));
153-
const label = new IconLabel(element, { supportIcons: true });
158+
const icon = append(element, $('.icon'));
159+
const label = new IconLabel(element, { supportIcons: false });
154160

155161
const actionsContainer = append(element, $('.actions'));
156162
const actionBar = new WorkbenchToolBar(actionsContainer, undefined, this._menuService, this._contextKeyService, this._contextMenuService, this._keybindingService, this._commandService, this._telemetryService);
157163

158-
return { label, actionBar, elementDisposables: new DisposableStore(), templateDisposable: combinedDisposable(label, actionBar) };
164+
return { icon, label, actionBar, elementDisposables: new DisposableStore(), templateDisposable: combinedDisposable(label, actionBar) };
159165
}
160166

161167
renderElement(nodeOrElement: ITreeNode<SCMArtifactTreeElement | IResourceNode<SCMArtifactTreeElement, SCMArtifactGroupTreeElement>, FuzzyScore>, index: number, templateData: ArtifactTemplate): void {
162168
const artifactOrFolder = nodeOrElement.element;
163169

164170
if (isSCMArtifactNode(artifactOrFolder)) {
165171
// Folder
166-
templateData.label.setLabel(`$(folder) ${basename(artifactOrFolder.uri)}`);
172+
templateData.icon.className = `icon ${ThemeIcon.asClassName(Codicon.folder)}`;
173+
templateData.label.setLabel(basename(artifactOrFolder.uri));
167174

168175
templateData.actionBar.setActions([]);
169176
templateData.actionBar.context = undefined;
170177
} else {
171178
// Artifact
172179
const artifact = artifactOrFolder.artifact;
173-
const artifactIcon = ThemeIcon.isThemeIcon(artifactOrFolder.group.icon)
174-
? `$(${artifactOrFolder.group.icon.id}) `
180+
181+
templateData.icon.className = ThemeIcon.isThemeIcon(artifactOrFolder.group.icon)
182+
? `icon ${ThemeIcon.asClassName(artifactOrFolder.group.icon)}`
175183
: '';
176184

177185
const artifactLabel = artifact.name.split('/').pop() ?? artifact.name;
178-
templateData.label.setLabel(`${artifactIcon}${artifactLabel}`, artifact.description);
186+
templateData.label.setLabel(artifactLabel, artifact.description);
179187

180188
const provider = artifactOrFolder.repository.provider;
181189
const repositoryMenus = this._scmViewService.menus.getRepositoryMenus(provider);
@@ -187,12 +195,30 @@ class ArtifactRenderer implements ICompressibleTreeRenderer<SCMArtifactTreeEleme
187195
}
188196

189197
renderCompressedElements(node: ITreeNode<ICompressedTreeNode<SCMArtifactTreeElement | IResourceNode<SCMArtifactTreeElement, SCMArtifactGroupTreeElement>>, FuzzyScore>, index: number, templateData: ArtifactTemplate, details?: ITreeElementRenderDetails): void {
190-
const compressed = node.element as ICompressedTreeNode<IResourceNode<SCMArtifactTreeElement, SCMArtifactGroupTreeElement>>;
191-
const folder = compressed.elements[compressed.elements.length - 1];
192-
templateData.label.setLabel(`$(folder) ${folder.uri.fsPath.substring(1)}`);
198+
const compressed = node.element;
199+
const artifactOrFolder = compressed.elements[compressed.elements.length - 1];
200+
201+
if (isSCMArtifactTreeElement(artifactOrFolder)) {
202+
const artifact = artifactOrFolder.artifact;
203+
204+
templateData.icon.className = ThemeIcon.isThemeIcon(artifactOrFolder.group.icon)
205+
? `icon ${ThemeIcon.asClassName(artifactOrFolder.group.icon)}`
206+
: '';
207+
templateData.label.setLabel(artifact.name, artifact.description);
208+
209+
const provider = artifactOrFolder.repository.provider;
210+
const repositoryMenus = this._scmViewService.menus.getRepositoryMenus(provider);
211+
templateData.elementDisposables.add(connectPrimaryMenu(repositoryMenus.getArtifactMenu(artifactOrFolder.group), primary => {
212+
templateData.actionBar.setActions(primary);
213+
}, 'inline', provider));
214+
templateData.actionBar.context = artifact;
215+
} else if (ResourceTree.isResourceNode(artifactOrFolder)) {
216+
templateData.icon.className = `icon ${ThemeIcon.asClassName(Codicon.folder)}`;
217+
templateData.label.setLabel(artifactOrFolder.uri.fsPath.substring(1));
193218

194-
templateData.actionBar.setActions([]);
195-
templateData.actionBar.context = undefined;
219+
templateData.actionBar.setActions([]);
220+
templateData.actionBar.context = undefined;
221+
}
196222
}
197223

198224
disposeElement(element: ITreeNode<SCMArtifactTreeElement | IResourceNode<SCMArtifactTreeElement, SCMArtifactGroupTreeElement>, FuzzyScore>, index: number, templateData: ArtifactTemplate, details?: ITreeElementRenderDetails): void {
@@ -306,10 +332,10 @@ class RepositoryTreeIdentityProvider implements IIdentityProvider<TreeElement> {
306332
class RepositoriesTreeCompressionDelegate implements ITreeCompressionDelegate<TreeElement> {
307333
isIncompressible(element: TreeElement): boolean {
308334
if (ResourceTree.isResourceNode(element)) {
309-
return element.childrenCount === 0 || !element.parent || !element.parent.parent;
335+
return element.childrenCount > 1;
336+
} else {
337+
return true;
310338
}
311-
312-
return true;
313339
}
314340
}
315341

@@ -440,18 +466,12 @@ export class SCMRepositoriesViewPane extends ViewPane {
440466
}
441467

442468
// Explorer mode
443-
// Expand artifact folders with one child only
444469
if (isSCMArtifactNode(e)) {
445-
if (e.childrenCount !== 1) {
446-
return true;
447-
}
448-
449-
// Check if the only child is a leaf node
450-
const firstChild = Iterable.first(e.children);
451-
return firstChild?.element !== undefined;
470+
// Only expand artifact folders as they are compressed by default
471+
return !(e.childrenCount === 1 && Iterable.first(e.children)?.element === undefined);
472+
} else {
473+
return true;
452474
}
453-
454-
return true;
455475
},
456476
compressionEnabled: true,
457477
overrideStyles: this.getLocationBasedColors().listOverrideStyles,

0 commit comments

Comments
 (0)