mirror of
https://github.com/microsoft/vscode.git
synced 2025-12-24 12:19:20 +00:00
SCM - more improvements to the repositories view (#274438)
* SCM - tweak artifact folder compression * SCM - fixed more commands and layout * SCM - more compression changes
This commit is contained in:
@@ -496,7 +496,6 @@
|
||||
{
|
||||
"command": "git.branch",
|
||||
"title": "%command.branch%",
|
||||
"icon": "$(plus)",
|
||||
"category": "Git",
|
||||
"enablement": "!operationInProgress"
|
||||
},
|
||||
@@ -1046,6 +1045,20 @@
|
||||
"title": "%command.graphCompareRef%",
|
||||
"category": "Git",
|
||||
"enablement": "!operationInProgress"
|
||||
},
|
||||
{
|
||||
"command": "git.repositories.createBranch",
|
||||
"title": "%command.branch%",
|
||||
"icon": "$(plus)",
|
||||
"category": "Git",
|
||||
"enablement": "!operationInProgress"
|
||||
},
|
||||
{
|
||||
"command": "git.repositories.createTag",
|
||||
"title": "%command.createTag%",
|
||||
"icon": "$(plus)",
|
||||
"category": "Git",
|
||||
"enablement": "!operationInProgress"
|
||||
}
|
||||
],
|
||||
"continueEditSession": [
|
||||
@@ -1681,6 +1694,14 @@
|
||||
{
|
||||
"command": "git.repositories.compareRef",
|
||||
"when": "false"
|
||||
},
|
||||
{
|
||||
"command": "git.repositories.createBranch",
|
||||
"when": "false"
|
||||
},
|
||||
{
|
||||
"command": "git.repositories.createTag",
|
||||
"when": "false"
|
||||
}
|
||||
],
|
||||
"scm/title": [
|
||||
@@ -1873,12 +1894,12 @@
|
||||
],
|
||||
"scm/artifactGroup/context": [
|
||||
{
|
||||
"command": "git.branch",
|
||||
"command": "git.repositories.createBranch",
|
||||
"group": "inline@1",
|
||||
"when": "scmProvider == git && scmArtifactGroup == branches"
|
||||
},
|
||||
{
|
||||
"command": "git.createTag",
|
||||
"command": "git.repositories.createTag",
|
||||
"group": "inline@1",
|
||||
"when": "scmProvider == git && scmArtifactGroup == tags"
|
||||
}
|
||||
|
||||
@@ -3363,24 +3363,7 @@ export class CommandCenter {
|
||||
|
||||
@command('git.createTag', { repository: true })
|
||||
async createTag(repository: Repository, historyItem?: SourceControlHistoryItem): Promise<void> {
|
||||
const inputTagName = await window.showInputBox({
|
||||
placeHolder: l10n.t('Tag name'),
|
||||
prompt: l10n.t('Please provide a tag name'),
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
|
||||
if (!inputTagName) {
|
||||
return;
|
||||
}
|
||||
|
||||
const inputMessage = await window.showInputBox({
|
||||
placeHolder: l10n.t('Message'),
|
||||
prompt: l10n.t('Please provide a message to annotate the tag'),
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
|
||||
const name = inputTagName.replace(/^\.|\/\.|\.\.|~|\^|:|\/$|\.lock$|\.lock\/|\\|\*|\s|^\s*$|\.$/g, '-');
|
||||
await repository.tag({ name, message: inputMessage, ref: historyItem?.id });
|
||||
await this._createTag(repository, historyItem?.id);
|
||||
}
|
||||
|
||||
@command('git.deleteTag', { repository: true })
|
||||
@@ -5259,6 +5242,24 @@ export class CommandCenter {
|
||||
config.update(setting, !enabled, true);
|
||||
}
|
||||
|
||||
@command('git.repositories.createBranch', { repository: true })
|
||||
async artifactGroupCreateBranch(repository: Repository): Promise<void> {
|
||||
if (!repository) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this._branch(repository, undefined, false);
|
||||
}
|
||||
|
||||
@command('git.repositories.createTag', { repository: true })
|
||||
async artifactGroupCreateTag(repository: Repository): Promise<void> {
|
||||
if (!repository) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this._createTag(repository);
|
||||
}
|
||||
|
||||
@command('git.repositories.checkout', { repository: true })
|
||||
async artifactCheckout(repository: Repository, artifact: SourceControlArtifact): Promise<void> {
|
||||
if (!repository || !artifact) {
|
||||
@@ -5312,6 +5313,27 @@ export class CommandCenter {
|
||||
`${sourceRef.ref.name} ↔ ${artifact.name}`);
|
||||
}
|
||||
|
||||
private async _createTag(repository: Repository, ref?: string): Promise<void> {
|
||||
const inputTagName = await window.showInputBox({
|
||||
placeHolder: l10n.t('Tag name'),
|
||||
prompt: l10n.t('Please provide a tag name'),
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
|
||||
if (!inputTagName) {
|
||||
return;
|
||||
}
|
||||
|
||||
const inputMessage = await window.showInputBox({
|
||||
placeHolder: l10n.t('Message'),
|
||||
prompt: l10n.t('Please provide a message to annotate the tag'),
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
|
||||
const name = inputTagName.replace(/^\.|\/\.|\.\.|~|\^|:|\/$|\.lock$|\.lock\/|\\|\*|\s|^\s*$|\.$/g, '-');
|
||||
await repository.tag({ name, message: inputMessage, ref });
|
||||
}
|
||||
|
||||
private createCommand(id: string, key: string, method: Function, options: ScmCommandOptions): (...args: any[]) => any {
|
||||
const result = (...args: any[]) => {
|
||||
let result: Promise<any>;
|
||||
|
||||
@@ -538,6 +538,11 @@
|
||||
.scm-repositories-view .scm-artifact-group,
|
||||
.scm-repositories-view .scm-artifact {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.icon {
|
||||
margin-right: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.scm-repositories-view .scm-artifact-group .monaco-icon-label,
|
||||
@@ -545,10 +550,6 @@
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.scm-repositories-view .scm-artifact .monaco-icon-label-container {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.scm-repositories-view .scm-artifact-group .monaco-highlighted-label,
|
||||
.scm-repositories-view .scm-artifact .monaco-highlighted-label {
|
||||
display: flex;
|
||||
|
||||
@@ -43,6 +43,7 @@ import { basename } from '../../../../base/common/resources.js';
|
||||
import { ICompressibleTreeRenderer } from '../../../../base/browser/ui/tree/objectTree.js';
|
||||
import { ICompressedTreeNode } from '../../../../base/browser/ui/tree/compressedObjectTreeModel.js';
|
||||
import { ITreeCompressionDelegate } from '../../../../base/browser/ui/tree/asyncDataTree.js';
|
||||
import { Codicon } from '../../../../base/common/codicons.js';
|
||||
|
||||
type TreeElement = ISCMRepository | SCMArtifactGroupTreeElement | SCMArtifactTreeElement | IResourceNode<SCMArtifactTreeElement, SCMArtifactGroupTreeElement>;
|
||||
|
||||
@@ -66,6 +67,7 @@ class ListDelegate implements IListVirtualDelegate<ISCMRepository> {
|
||||
}
|
||||
|
||||
interface ArtifactGroupTemplate {
|
||||
readonly icon: HTMLElement;
|
||||
readonly label: IconLabel;
|
||||
readonly actionBar: WorkbenchToolBar;
|
||||
readonly elementDisposables: DisposableStore;
|
||||
@@ -89,21 +91,23 @@ class ArtifactGroupRenderer implements ICompressibleTreeRenderer<SCMArtifactGrou
|
||||
|
||||
renderTemplate(container: HTMLElement): ArtifactGroupTemplate {
|
||||
const element = append(container, $('.scm-artifact-group'));
|
||||
const label = new IconLabel(element, { supportIcons: true });
|
||||
const icon = append(element, $('.icon'));
|
||||
const label = new IconLabel(element, { supportIcons: false });
|
||||
|
||||
const actionsContainer = append(element, $('.actions'));
|
||||
const actionBar = new WorkbenchToolBar(actionsContainer, undefined, this._menuService, this._contextKeyService, this._contextMenuService, this._keybindingService, this._commandService, this._telemetryService);
|
||||
|
||||
return { label, actionBar, elementDisposables: new DisposableStore(), templateDisposable: combinedDisposable(label, actionBar) };
|
||||
return { icon, label, actionBar, elementDisposables: new DisposableStore(), templateDisposable: combinedDisposable(label, actionBar) };
|
||||
}
|
||||
|
||||
renderElement(node: ITreeNode<SCMArtifactGroupTreeElement, FuzzyScore>, index: number, templateData: ArtifactGroupTemplate): void {
|
||||
const provider = node.element.repository.provider;
|
||||
const artifactGroup = node.element.artifactGroup;
|
||||
const artifactGroupIcon = ThemeIcon.isThemeIcon(artifactGroup.icon)
|
||||
? `$(${artifactGroup.icon.id}) ` : '';
|
||||
|
||||
templateData.label.setLabel(`${artifactGroupIcon}${artifactGroup.name}`);
|
||||
templateData.icon.className = ThemeIcon.isThemeIcon(artifactGroup.icon)
|
||||
? `icon ${ThemeIcon.asClassName(artifactGroup.icon)}`
|
||||
: '';
|
||||
templateData.label.setLabel(artifactGroup.name);
|
||||
|
||||
const repositoryMenus = this._scmViewService.menus.getRepositoryMenus(provider);
|
||||
templateData.elementDisposables.add(connectPrimaryMenu(repositoryMenus.getArtifactGroupMenu(artifactGroup), primary => {
|
||||
@@ -127,6 +131,7 @@ class ArtifactGroupRenderer implements ICompressibleTreeRenderer<SCMArtifactGrou
|
||||
}
|
||||
|
||||
interface ArtifactTemplate {
|
||||
readonly icon: HTMLElement;
|
||||
readonly label: IconLabel;
|
||||
readonly actionBar: WorkbenchToolBar;
|
||||
readonly elementDisposables: DisposableStore;
|
||||
@@ -150,12 +155,13 @@ class ArtifactRenderer implements ICompressibleTreeRenderer<SCMArtifactTreeEleme
|
||||
|
||||
renderTemplate(container: HTMLElement): ArtifactTemplate {
|
||||
const element = append(container, $('.scm-artifact'));
|
||||
const label = new IconLabel(element, { supportIcons: true });
|
||||
const icon = append(element, $('.icon'));
|
||||
const label = new IconLabel(element, { supportIcons: false });
|
||||
|
||||
const actionsContainer = append(element, $('.actions'));
|
||||
const actionBar = new WorkbenchToolBar(actionsContainer, undefined, this._menuService, this._contextKeyService, this._contextMenuService, this._keybindingService, this._commandService, this._telemetryService);
|
||||
|
||||
return { label, actionBar, elementDisposables: new DisposableStore(), templateDisposable: combinedDisposable(label, actionBar) };
|
||||
return { icon, label, actionBar, elementDisposables: new DisposableStore(), templateDisposable: combinedDisposable(label, actionBar) };
|
||||
}
|
||||
|
||||
renderElement(nodeOrElement: ITreeNode<SCMArtifactTreeElement | IResourceNode<SCMArtifactTreeElement, SCMArtifactGroupTreeElement>, FuzzyScore>, index: number, templateData: ArtifactTemplate): void {
|
||||
@@ -163,19 +169,21 @@ class ArtifactRenderer implements ICompressibleTreeRenderer<SCMArtifactTreeEleme
|
||||
|
||||
if (isSCMArtifactNode(artifactOrFolder)) {
|
||||
// Folder
|
||||
templateData.label.setLabel(`$(folder) ${basename(artifactOrFolder.uri)}`);
|
||||
templateData.icon.className = `icon ${ThemeIcon.asClassName(Codicon.folder)}`;
|
||||
templateData.label.setLabel(basename(artifactOrFolder.uri));
|
||||
|
||||
templateData.actionBar.setActions([]);
|
||||
templateData.actionBar.context = undefined;
|
||||
} else {
|
||||
// Artifact
|
||||
const artifact = artifactOrFolder.artifact;
|
||||
const artifactIcon = ThemeIcon.isThemeIcon(artifactOrFolder.group.icon)
|
||||
? `$(${artifactOrFolder.group.icon.id}) `
|
||||
|
||||
templateData.icon.className = ThemeIcon.isThemeIcon(artifactOrFolder.group.icon)
|
||||
? `icon ${ThemeIcon.asClassName(artifactOrFolder.group.icon)}`
|
||||
: '';
|
||||
|
||||
const artifactLabel = artifact.name.split('/').pop() ?? artifact.name;
|
||||
templateData.label.setLabel(`${artifactIcon}${artifactLabel}`, artifact.description);
|
||||
templateData.label.setLabel(artifactLabel, artifact.description);
|
||||
|
||||
const provider = artifactOrFolder.repository.provider;
|
||||
const repositoryMenus = this._scmViewService.menus.getRepositoryMenus(provider);
|
||||
@@ -187,13 +195,31 @@ class ArtifactRenderer implements ICompressibleTreeRenderer<SCMArtifactTreeEleme
|
||||
}
|
||||
|
||||
renderCompressedElements(node: ITreeNode<ICompressedTreeNode<SCMArtifactTreeElement | IResourceNode<SCMArtifactTreeElement, SCMArtifactGroupTreeElement>>, FuzzyScore>, index: number, templateData: ArtifactTemplate, details?: ITreeElementRenderDetails): void {
|
||||
const compressed = node.element as ICompressedTreeNode<IResourceNode<SCMArtifactTreeElement, SCMArtifactGroupTreeElement>>;
|
||||
const folder = compressed.elements[compressed.elements.length - 1];
|
||||
templateData.label.setLabel(`$(folder) ${folder.uri.fsPath.substring(1)}`);
|
||||
const compressed = node.element;
|
||||
const artifactOrFolder = compressed.elements[compressed.elements.length - 1];
|
||||
|
||||
if (isSCMArtifactTreeElement(artifactOrFolder)) {
|
||||
const artifact = artifactOrFolder.artifact;
|
||||
|
||||
templateData.icon.className = ThemeIcon.isThemeIcon(artifactOrFolder.group.icon)
|
||||
? `icon ${ThemeIcon.asClassName(artifactOrFolder.group.icon)}`
|
||||
: '';
|
||||
templateData.label.setLabel(artifact.name, artifact.description);
|
||||
|
||||
const provider = artifactOrFolder.repository.provider;
|
||||
const repositoryMenus = this._scmViewService.menus.getRepositoryMenus(provider);
|
||||
templateData.elementDisposables.add(connectPrimaryMenu(repositoryMenus.getArtifactMenu(artifactOrFolder.group), primary => {
|
||||
templateData.actionBar.setActions(primary);
|
||||
}, 'inline', provider));
|
||||
templateData.actionBar.context = artifact;
|
||||
} else if (ResourceTree.isResourceNode(artifactOrFolder)) {
|
||||
templateData.icon.className = `icon ${ThemeIcon.asClassName(Codicon.folder)}`;
|
||||
templateData.label.setLabel(artifactOrFolder.uri.fsPath.substring(1));
|
||||
|
||||
templateData.actionBar.setActions([]);
|
||||
templateData.actionBar.context = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
disposeElement(element: ITreeNode<SCMArtifactTreeElement | IResourceNode<SCMArtifactTreeElement, SCMArtifactGroupTreeElement>, FuzzyScore>, index: number, templateData: ArtifactTemplate, details?: ITreeElementRenderDetails): void {
|
||||
templateData.elementDisposables.clear();
|
||||
@@ -306,12 +332,12 @@ class RepositoryTreeIdentityProvider implements IIdentityProvider<TreeElement> {
|
||||
class RepositoriesTreeCompressionDelegate implements ITreeCompressionDelegate<TreeElement> {
|
||||
isIncompressible(element: TreeElement): boolean {
|
||||
if (ResourceTree.isResourceNode(element)) {
|
||||
return element.childrenCount === 0 || !element.parent || !element.parent.parent;
|
||||
}
|
||||
|
||||
return element.childrenCount > 1;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class SCMRepositoriesViewPane extends ViewPane {
|
||||
|
||||
@@ -440,18 +466,12 @@ export class SCMRepositoriesViewPane extends ViewPane {
|
||||
}
|
||||
|
||||
// Explorer mode
|
||||
// Expand artifact folders with one child only
|
||||
if (isSCMArtifactNode(e)) {
|
||||
if (e.childrenCount !== 1) {
|
||||
// Only expand artifact folders as they are compressed by default
|
||||
return !(e.childrenCount === 1 && Iterable.first(e.children)?.element === undefined);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if the only child is a leaf node
|
||||
const firstChild = Iterable.first(e.children);
|
||||
return firstChild?.element !== undefined;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
compressionEnabled: true,
|
||||
overrideStyles: this.getLocationBasedColors().listOverrideStyles,
|
||||
|
||||
Reference in New Issue
Block a user