mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-24 09:35:37 -05:00
update welcome page to use context menu service and some code clean up (#12643)
* use existing menu service and cleanup code * fix mac issue * button width
This commit is contained in:
@@ -27,11 +27,7 @@ export default () => `
|
||||
<div class="caption-container">
|
||||
<span class="icon xs"></span><h1 class="caption"></h1>
|
||||
</div>
|
||||
<div class="flex btn-container">
|
||||
<div id="dropdown-btn-container" class="btn btn-primary dropdown">
|
||||
</div>
|
||||
<div id="open-file-btn-container" class="btn btn-secondary">
|
||||
</div>
|
||||
<div id="welcome-page-button-container" class="flex btn-container">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -154,7 +154,7 @@
|
||||
|
||||
.ads-homepage.XS .btn {
|
||||
margin: 0 8px 0 0;
|
||||
width: 77px;
|
||||
min-width: 77px;
|
||||
line-height: 18px
|
||||
}
|
||||
|
||||
|
||||
@@ -43,13 +43,15 @@ import { IRecentlyOpened, isRecentWorkspace, IRecentWorkspace, IRecentFolder, is
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IHostService } from 'vs/workbench/services/host/browser/host';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { joinPath } from 'vs/base/common/resources';
|
||||
import { addStandardDisposableListener, EventHelper, clearNode } from 'vs/base/browser/dom';
|
||||
import { clearNode } from 'vs/base/browser/dom';
|
||||
import { GuidedTour } from 'sql/workbench/contrib/welcome/page/browser/gettingStartedTour';
|
||||
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { ILayoutService } from 'vs/platform/layout/browser/layoutService';
|
||||
import { Button } from 'sql/base/browser/ui/button/button';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { ICommandAction, MenuItemAction } from 'vs/platform/actions/common/actions';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
const configurationKey = 'workbench.startupEditor';
|
||||
const oldConfigurationKey = 'workbench.welcome.enabled';
|
||||
const telemetryFrom = 'welcomePage';
|
||||
@@ -204,6 +206,22 @@ const extensionPackStrings = {
|
||||
extensionNotFound: (extensionName: string, extensionId: string) => { return localize('welcomePage.extensionPackNotFound', "Support for {0} with id {1} could not be found.", extensionName, extensionId); },
|
||||
};
|
||||
|
||||
const NewActionItems: ICommandAction[] = [
|
||||
{
|
||||
title: localize('welcomePage.newConnection', "New connection"),
|
||||
id: 'registeredServers.addConnection'
|
||||
}, {
|
||||
title: localize('welcomePage.newQuery', "New query"),
|
||||
id: 'workbench.action.files.newUntitledFile'
|
||||
}, {
|
||||
title: localize('welcomePage.newNotebook', "New notebook"),
|
||||
id: 'notebook.command.new'
|
||||
}, {
|
||||
title: localize('welcomePage.deployServer', "Deploy a server"),
|
||||
id: 'azdata.resource.deploy'
|
||||
}
|
||||
];
|
||||
|
||||
const welcomeInputTypeId = 'workbench.editors.welcomePageInput';
|
||||
class WelcomePage extends Disposable {
|
||||
|
||||
@@ -227,7 +245,9 @@ class WelcomePage extends Disposable {
|
||||
@IFileService fileService: IFileService,
|
||||
@IProductService private readonly productService: IProductService,
|
||||
@IWorkbenchLayoutService protected layoutService: IWorkbenchLayoutService,
|
||||
@ICommandService private readonly commandService: ICommandService) {
|
||||
@ICommandService private readonly commandService: ICommandService,
|
||||
@IContextMenuService private readonly contextMenuService: IContextMenuService,
|
||||
@IContextKeyService private readonly contextKeyService: IContextKeyService) {
|
||||
super();
|
||||
this._register(lifecycleService.onShutdown(() => this.dispose()));
|
||||
const recentlyOpened = this.workspacesService.getRecentlyOpened();
|
||||
@@ -245,9 +265,11 @@ class WelcomePage extends Disposable {
|
||||
onReady: (container: HTMLElement) => this.onReady(container, recentlyOpened, installedExtensions, fileService, layoutService)
|
||||
});
|
||||
}
|
||||
|
||||
public openEditor() {
|
||||
return this.editorService.openEditor(this.editorInput, { pinned: false });
|
||||
}
|
||||
|
||||
private onReady(container: HTMLElement, recentlyOpened: Promise<IRecentlyOpened>, installedExtensions: Promise<IExtensionStatus[]>, fileService: IFileService, layoutService: ILayoutService): void {
|
||||
const enabled = isWelcomePageEnabled(this.configurationService, this.contextService);
|
||||
const showOnStartup = <HTMLInputElement>container.querySelector('#showOnStartup');
|
||||
@@ -327,74 +349,67 @@ class WelcomePage extends Disposable {
|
||||
}
|
||||
}
|
||||
}));
|
||||
this.createButtons();
|
||||
this.createDropDown();
|
||||
this.createButtons(container);
|
||||
}
|
||||
|
||||
private createButtons(): void {
|
||||
const container = document.querySelector('.ads-homepage .hero');
|
||||
const dropdownButtonContainer = document.querySelector('#dropdown-btn-container') as HTMLElement;
|
||||
const dropdownUl = document.createElement('ul');
|
||||
const i = document.createElement('div');
|
||||
const nav = document.createElement('nav');
|
||||
const newText = localize('welcomePage.new', "New");
|
||||
let dropdownBtn = this._register(new Button(dropdownButtonContainer));
|
||||
dropdownBtn.label = newText;
|
||||
private createButtons(welcomePageContainer: HTMLElement): void {
|
||||
const container = welcomePageContainer.querySelector('#welcome-page-button-container');
|
||||
|
||||
const iconClassList = ['twisties', 'codicon', 'codicon-chevron-right'];
|
||||
// New button, contains a down arrow, invoking the button will open a context menu.
|
||||
const newButtonContainer = document.createElement('div');
|
||||
newButtonContainer.classList.add('btn', 'btn-primary');
|
||||
container.appendChild(newButtonContainer);
|
||||
const newButton = this._register(new Button(newButtonContainer));
|
||||
newButton.label = localize('welcomePage.new', "New");
|
||||
const newButtonHtmlElement = newButton.element;
|
||||
newButtonHtmlElement.setAttribute('aria-haspopup', 'true');
|
||||
newButtonHtmlElement.setAttribute('aria-controls', 'dropdown');
|
||||
newButtonHtmlElement.setAttribute('aria-expanded', 'false');
|
||||
const newButtonIcon = document.createElement('div');
|
||||
newButtonIcon.classList.add('codicon', 'codicon-chevron-down');
|
||||
newButtonHtmlElement.appendChild(newButtonIcon);
|
||||
|
||||
i.classList.add(...iconClassList);
|
||||
const openFileCopy = localize('welcomePage.openFile', "Open file");
|
||||
dropdownUl.classList.add('dropdown-content');
|
||||
dropdownUl.setAttribute('aria-hidden', 'true');
|
||||
dropdownUl.setAttribute('aria-label', 'submenu');
|
||||
dropdownUl.setAttribute('role', 'menu');
|
||||
dropdownUl.setAttribute('aria-labelledby', 'dropdown-btn');
|
||||
dropdownUl.id = 'dropdown';
|
||||
dropdownUl.innerHTML =
|
||||
`<li role="none"><a role="menuitem" tabIndex="-1" class="move" href="command:registeredServers.addConnection">${(localize('welcomePage.newConnection', "New connection"))} </a></li>
|
||||
<li role="none"><a role="menuitem" tabIndex="-1" class="move" href="command:workbench.action.files.newUntitledFile">${(localize('welcomePage.newQuery', "New query"))}</a></li>
|
||||
<li role="none"><a role="menuitem" tabIndex="-1" class="move" href="command:notebook.command.new">${(localize('welcomePage.newNotebook', "New notebook"))}</a></li>
|
||||
<li role="none"><a role="menuitem" tabIndex="-1" class="move" href="command:azdata.resource.deploy">${(localize('welcomePage.deployServer', "Deploy a Server"))}</a></li>
|
||||
<li role="none" id="dropdown-mac-only"><a role="menuitem" tabIndex="-1" class="move mac-only" href="command:workbench.action.files.openLocalFileFolder">${openFileCopy}</a></li>
|
||||
<li role="none" id="dropdown-windows-linux-only"><a role="menuitem" tabIndex="-1" class="move windows-only linux-only" href="command:workbench.action.files.openFile">${openFileCopy}</a></li`;
|
||||
newButton.onDidClick(() => {
|
||||
this.contextMenuService.showContextMenu({
|
||||
getAnchor: () => newButtonHtmlElement,
|
||||
getActions: () => NewActionItems.map(command => new MenuItemAction(command, undefined, {}, this.contextKeyService, this.commandService))
|
||||
});
|
||||
});
|
||||
|
||||
const getDropdownBtn = container.querySelector('#dropdown-btn-container .monaco-button') as HTMLElement;
|
||||
getDropdownBtn.id = 'dropdown-btn';
|
||||
getDropdownBtn.setAttribute('role', 'button');
|
||||
getDropdownBtn.setAttribute('aria-haspopup', 'true');
|
||||
getDropdownBtn.setAttribute('aria-controls', 'dropdown');
|
||||
nav.setAttribute('role', 'navigation');
|
||||
nav.classList.add('dropdown-nav');
|
||||
dropdownUl.classList.add('dropdown');
|
||||
getDropdownBtn.setAttribute('aria-expanded', 'false');
|
||||
getDropdownBtn.appendChild(i);
|
||||
nav.appendChild(dropdownUl);
|
||||
dropdownButtonContainer.appendChild(nav);
|
||||
const fileBtnWindowsClasses = ['windows-only', 'linux-only', 'btn-secondary'];
|
||||
const fileBtnMacClasses = ['mac-only', 'btn-secondary'];
|
||||
|
||||
const fileBtnContainer = container.querySelector('#open-file-btn-container') as HTMLElement;
|
||||
const openFileText = openFileCopy;
|
||||
let openFileButton = this._register(new Button(fileBtnContainer));
|
||||
openFileButton.label = openFileText;
|
||||
const getNewFileBtn = container.querySelector('#open-file-btn-container .monaco-button') as HTMLAnchorElement;
|
||||
getNewFileBtn.setAttribute('role', 'button');
|
||||
const body = document.querySelector('body');
|
||||
|
||||
if (body.classList.contains('windows') || body.classList.contains('linux')) {
|
||||
getNewFileBtn.classList.add(...fileBtnWindowsClasses);
|
||||
openFileButton.onDidClick(async () => {
|
||||
await this.commandService.executeCommand('workbench.action.files.openFile');
|
||||
// Secondary buttons
|
||||
// We are handling macOS specially here because the same dialog is being used to select both file and folder on macOS.
|
||||
const macSecondaryButtons = [
|
||||
{
|
||||
command: 'workbench.action.files.openLocalFileFolder',
|
||||
title: localize('welcomePage.open', "Open…")
|
||||
}
|
||||
);
|
||||
} else if (body.classList.contains('mac')) {
|
||||
getNewFileBtn.classList.add(...fileBtnMacClasses);
|
||||
openFileButton.onDidClick(async () => {
|
||||
await this.commandService.executeCommand('workbench.action.files.openLocalFileFolder');
|
||||
];
|
||||
|
||||
const nonMacSecondaryButtons = [
|
||||
{
|
||||
command: 'workbench.action.files.openFile',
|
||||
title: localize('welcomePage.openFile', "Open file…")
|
||||
},
|
||||
{
|
||||
command: 'workbench.action.files.openFolder',
|
||||
title: localize('welcomePage.openFolder', "Open folder…")
|
||||
}
|
||||
);
|
||||
}
|
||||
];
|
||||
|
||||
const secondaryButtons = document.body.classList.contains('mac') ? macSecondaryButtons : nonMacSecondaryButtons;
|
||||
|
||||
secondaryButtons.forEach(item => {
|
||||
|
||||
const btnContainer = document.createElement('div');
|
||||
btnContainer.classList.add('btn', 'btn-secondary');
|
||||
container.appendChild(btnContainer);
|
||||
const secondaryButton = this._register(new Button(btnContainer));
|
||||
secondaryButton.label = item.title;
|
||||
secondaryButton.element.classList.add('btn-secondary');
|
||||
secondaryButton.onDidClick(async () => {
|
||||
await this.commandService.executeCommand(item.command);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private enableGuidedTour(): void {
|
||||
@@ -454,74 +469,6 @@ class WelcomePage extends Disposable {
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
private createDropDown(): void {
|
||||
const container = document.querySelector('.ads-homepage .hero');
|
||||
const dropdownBtn = container.querySelector('#dropdown-btn') as HTMLElement;
|
||||
const dropdown = container.querySelector('#dropdown') as HTMLInputElement;
|
||||
addStandardDisposableListener(dropdownBtn, 'click', () => {
|
||||
dropdown.classList.toggle('show');
|
||||
});
|
||||
addStandardDisposableListener(dropdownBtn, 'keydown', event => {
|
||||
if (event.equals(KeyCode.Enter) || event.equals(KeyCode.Space)) {
|
||||
const dropdownFirstElement = document.querySelector('#dropdown').firstElementChild.children[0] as HTMLInputElement;
|
||||
dropdown.classList.toggle('show');
|
||||
dropdownFirstElement.focus();
|
||||
}
|
||||
});
|
||||
addStandardDisposableListener(dropdown, 'keydown', event => {
|
||||
if (event.equals(KeyCode.Escape)) {
|
||||
if (dropdown.classList.contains('show')) {
|
||||
dropdown.classList.remove('show');
|
||||
const currentSelection = document.querySelector('.move:focus') as HTMLInputElement;
|
||||
currentSelection.blur();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const body = document.querySelector('body');
|
||||
if (body.classList.contains('windows') || body.classList.contains('linux')) {
|
||||
const macOnly = container.querySelector('#dropdown-mac-only');
|
||||
macOnly.remove();
|
||||
} else if (body.classList.contains('mac')) {
|
||||
const windowsLinuxOnly = container.querySelector('#dropdown-windows-linux-only');
|
||||
windowsLinuxOnly.remove();
|
||||
}
|
||||
window.addEventListener('click', (event) => {
|
||||
const target = event.target as HTMLTextAreaElement;
|
||||
if (!target.matches('#dropdown-btn')) {
|
||||
if (dropdown.classList.contains('show')) {
|
||||
dropdown.classList.toggle('show');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
addStandardDisposableListener(dropdown, 'keydown', event => {
|
||||
const container = document.querySelector('.ads-homepage .hero');
|
||||
const dropdownLastElement = container.querySelector('#dropdown').lastElementChild.children[0] as HTMLInputElement;
|
||||
const dropdownFirstElement = container.querySelector('#dropdown').firstElementChild.children[0] as HTMLInputElement;
|
||||
if (event.equals(KeyCode.Tab)) {
|
||||
EventHelper.stop(event);
|
||||
return;
|
||||
}
|
||||
else if (event.equals(KeyCode.UpArrow) || event.equals(KeyCode.LeftArrow)) {
|
||||
if (event.target === dropdownFirstElement) {
|
||||
dropdownLastElement.focus();
|
||||
} else {
|
||||
const movePrev = <HTMLElement>container.querySelector('.move:focus').parentElement.previousElementSibling.children[0] as HTMLElement;
|
||||
movePrev.focus();
|
||||
}
|
||||
}
|
||||
else if (event.equals(KeyCode.DownArrow) || event.equals(KeyCode.RightArrow)) {
|
||||
if (event.target === dropdownLastElement) {
|
||||
dropdownFirstElement.focus();
|
||||
} else {
|
||||
const moveNext = <HTMLElement>container.querySelector('.move:focus').parentElement.nextElementSibling.children[0] as HTMLElement;
|
||||
moveNext.focus();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private async createListEntries(container: HTMLElement, fileService: IFileService, fullPath: URI, windowOpenable: IWindowOpenable, relativePath: string): Promise<HTMLElement[]> {
|
||||
let result: HTMLElement[] = [];
|
||||
const value = await fileService.resolve(fullPath);
|
||||
@@ -585,6 +532,7 @@ class WelcomePage extends Disposable {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private addExtensionList(container: HTMLElement, listSelector: string): void {
|
||||
const list = container.querySelector(listSelector);
|
||||
if (list) {
|
||||
|
||||
Reference in New Issue
Block a user