Agent - Accessibility Bugs (WIP) (#5807)

* fix accessbility issue where tabbing would get wrong focus

* dialogs open one at a time

* get focus on filter headers

* added tool tips to proxy dialog

* added labels to step dialog
This commit is contained in:
Aditya Bist
2019-06-07 09:41:00 -07:00
committed by GitHub
parent cbaa0a132f
commit d9b48bae80
6 changed files with 65 additions and 20 deletions

View File

@@ -242,12 +242,14 @@ export class JobDialog extends AgentDialog<JobData> {
this.moveStepUpButton = view.modelBuilder.button() this.moveStepUpButton = view.modelBuilder.button()
.withProperties({ .withProperties({
label: this.MoveStepUpButtonString, label: this.MoveStepUpButtonString,
title: this.MoveStepUpButtonString,
width: 120 width: 120
}).component(); }).component();
this.moveStepDownButton = view.modelBuilder.button() this.moveStepDownButton = view.modelBuilder.button()
.withProperties({ .withProperties({
label: this.MoveStepDownButtonString, label: this.MoveStepDownButtonString,
title: this.MoveStepDownButtonString,
width: 120 width: 120
}).component(); }).component();
@@ -256,6 +258,7 @@ export class JobDialog extends AgentDialog<JobData> {
this.newStepButton = view.modelBuilder.button().withProperties({ this.newStepButton = view.modelBuilder.button().withProperties({
label: this.NewStepButtonString, label: this.NewStepButtonString,
title: this.NewStepButtonString,
width: 140 width: 140
}).component(); }).component();
@@ -283,11 +286,13 @@ export class JobDialog extends AgentDialog<JobData> {
this.editStepButton = view.modelBuilder.button().withProperties({ this.editStepButton = view.modelBuilder.button().withProperties({
label: this.EditStepButtonString, label: this.EditStepButtonString,
title: this.EditStepButtonString,
width: 140 width: 140
}).component(); }).component();
this.deleteStepButton = view.modelBuilder.button().withProperties({ this.deleteStepButton = view.modelBuilder.button().withProperties({
label: this.DeleteStepButtonString, label: this.DeleteStepButtonString,
title: this.DeleteStepButtonString,
width: 140 width: 140
}).component(); }).component();

View File

@@ -147,12 +147,14 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
this.openButton = view.modelBuilder.button() this.openButton = view.modelBuilder.button()
.withProperties({ .withProperties({
label: this.OpenCommandText, label: this.OpenCommandText,
title: this.OpenCommandText,
width: '80px', width: '80px',
isFile: true isFile: true
}).component(); }).component();
this.parseButton = view.modelBuilder.button() this.parseButton = view.modelBuilder.button()
.withProperties({ .withProperties({
label: this.ParseCommandText, label: this.ParseCommandText,
title: this.ParseCommandText,
width: '80px', width: '80px',
isFile: false isFile: false
}).component(); }).component();
@@ -176,7 +178,9 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
height: 300, height: 300,
width: 400, width: 400,
multiline: true, multiline: true,
inputType: 'text' inputType: 'text',
ariaLabel: this.CommandLabelString,
placeHolder: this.CommandLabelString
}) })
.component(); .component();
} }
@@ -185,6 +189,8 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
this.generalTab.registerContent(async (view) => { this.generalTab.registerContent(async (view) => {
this.nameTextBox = view.modelBuilder.inputBox() this.nameTextBox = view.modelBuilder.inputBox()
.withProperties({ .withProperties({
ariaLabel: this.StepNameLabelString,
placeHolder: this.StepNameLabelString
}).component(); }).component();
this.nameTextBox.required = true; this.nameTextBox.required = true;
this.nameTextBox.onTextChanged(() => { this.nameTextBox.onTextChanged(() => {
@@ -214,6 +220,8 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
this.processExitCodeBox = view.modelBuilder.inputBox() this.processExitCodeBox = view.modelBuilder.inputBox()
.withProperties({ .withProperties({
ariaLabel: this.ProcessExitCodeText,
placeHolder: this.ProcessExitCodeText
}).component(); }).component();
this.processExitCodeBox.enabled = false; this.processExitCodeBox.enabled = false;

View File

@@ -84,8 +84,11 @@ export class ProxyDialog extends AgentDialog<ProxyData> {
this.generalTab.registerContent(async view => { this.generalTab.registerContent(async view => {
this.proxyNameTextBox = view.modelBuilder.inputBox() this.proxyNameTextBox = view.modelBuilder.inputBox()
.withProperties({ width: 420 }) .withProperties({
.component(); width: 420,
ariaLabel: ProxyDialog.ProxyNameTextBoxLabel,
placeHolder: ProxyDialog.ProxyNameTextBoxLabel
}).component();
this.credentialNameDropDown = view.modelBuilder.dropDown() this.credentialNameDropDown = view.modelBuilder.dropDown()
.withProperties({ .withProperties({
@@ -100,9 +103,10 @@ export class ProxyDialog extends AgentDialog<ProxyData> {
.withProperties({ .withProperties({
width: 420, width: 420,
multiline: true, multiline: true,
height: 300 height: 300,
}) ariaLabel: ProxyDialog.DescriptionTextBoxLabel,
.component(); placeHolder: ProxyDialog.DescriptionTextBoxLabel
}).component();
this.subsystemCheckBox = view.modelBuilder.checkBox() this.subsystemCheckBox = view.modelBuilder.checkBox()
.withProperties({ .withProperties({

View File

@@ -22,7 +22,13 @@ const localize = nls.loadMessageBundle();
* The main controller class that initializes the extension * The main controller class that initializes the extension
*/ */
export class MainController { export class MainController {
protected _context: vscode.ExtensionContext; protected _context: vscode.ExtensionContext;
private jobDialog: JobDialog;
private jobStepDialog: JobStepDialog;
private alertDialog: AlertDialog;
private operatorDialog: OperatorDialog;
private proxyDialog: ProxyDialog;
// PUBLIC METHODS ////////////////////////////////////////////////////// // PUBLIC METHODS //////////////////////////////////////////////////////
public constructor(context: vscode.ExtensionContext) { public constructor(context: vscode.ExtensionContext) {
@@ -39,8 +45,12 @@ export class MainController {
*/ */
public activate(): void { public activate(): void {
vscode.commands.registerCommand('agent.openJobDialog', async (ownerUri: string, jobInfo: azdata.AgentJobInfo) => { vscode.commands.registerCommand('agent.openJobDialog', async (ownerUri: string, jobInfo: azdata.AgentJobInfo) => {
let dialog = new JobDialog(ownerUri, jobInfo); if (!this.jobDialog || (this.jobDialog && !this.jobDialog.isOpen)) {
dialog.dialogName ? await dialog.openDialog(dialog.dialogName) : await dialog.openDialog(); this.jobDialog = new JobDialog(ownerUri, jobInfo);
}
if (!this.jobDialog.isOpen) {
this.jobDialog.dialogName ? await this.jobDialog.openDialog(this.jobDialog.dialogName) : await this.jobDialog.openDialog();
}
}); });
vscode.commands.registerCommand('agent.openNewStepDialog', (ownerUri: string, server: string, jobInfo: azdata.AgentJobInfo, jobStepInfo: azdata.AgentJobStepInfo) => { vscode.commands.registerCommand('agent.openNewStepDialog', (ownerUri: string, server: string, jobInfo: azdata.AgentJobInfo, jobStepInfo: azdata.AgentJobStepInfo) => {
AgentUtils.getAgentService().then(async (agentService) => { AgentUtils.getAgentService().then(async (agentService) => {
@@ -53,20 +63,33 @@ export class MainController {
let dialog = new PickScheduleDialog(ownerUri, jobName); let dialog = new PickScheduleDialog(ownerUri, jobName);
await dialog.showDialog(); await dialog.showDialog();
}); });
vscode.commands.registerCommand('agent.openAlertDialog', (ownerUri: string, jobInfo: azdata.AgentJobInfo, alertInfo: azdata.AgentAlertInfo) => { vscode.commands.registerCommand('agent.openAlertDialog', async (ownerUri: string, jobInfo: azdata.AgentJobInfo, alertInfo: azdata.AgentAlertInfo) => {
AgentUtils.getAgentService().then(async (agentService) => { if (!this.alertDialog || (this.alertDialog && !this.alertDialog.isOpen)) {
await AgentUtils.getAgentService().then(async (agentService) => {
let jobData: JobData = new JobData(ownerUri, jobInfo, agentService); let jobData: JobData = new JobData(ownerUri, jobInfo, agentService);
let dialog = new AlertDialog(ownerUri, jobData, alertInfo, false); this.alertDialog = new AlertDialog(ownerUri, jobData, alertInfo, false);
dialog.dialogName ? await dialog.openDialog(dialog.dialogName) : await dialog.openDialog();
}); });
}
if (!this.alertDialog.isOpen) {
this.alertDialog.dialogName ? await this.alertDialog.openDialog(this.alertDialog.dialogName) : await this.alertDialog.openDialog();
}
}); });
vscode.commands.registerCommand('agent.openOperatorDialog', async (ownerUri: string, operatorInfo: azdata.AgentOperatorInfo) => { vscode.commands.registerCommand('agent.openOperatorDialog', async (ownerUri: string, operatorInfo: azdata.AgentOperatorInfo) => {
let dialog = new OperatorDialog(ownerUri, operatorInfo); if (!this.operatorDialog || (this.operatorDialog && !this.operatorDialog.isOpen)) {
dialog.dialogName ? await dialog.openDialog(dialog.dialogName) : await dialog.openDialog(); this.operatorDialog = new OperatorDialog(ownerUri, operatorInfo);
}
if (!this.operatorDialog.isOpen) {
this.operatorDialog.dialogName ? await this.operatorDialog.openDialog(this.operatorDialog.dialogName) : await this.operatorDialog.openDialog();
}
}); });
vscode.commands.registerCommand('agent.openProxyDialog', async (ownerUri: string, proxyInfo: azdata.AgentProxyInfo, credentials: azdata.CredentialInfo[]) => { vscode.commands.registerCommand('agent.openProxyDialog', async (ownerUri: string, proxyInfo: azdata.AgentProxyInfo, credentials: azdata.CredentialInfo[]) => {
let dialog = new ProxyDialog(ownerUri, proxyInfo, credentials); if (!this.proxyDialog || (this.proxyDialog && !this.proxyDialog.isOpen)) {
dialog.dialogName ? await dialog.openDialog(dialog.dialogName) : await dialog.openDialog(); this.proxyDialog = new ProxyDialog(ownerUri, proxyInfo, credentials);
}
if (!this.proxyDialog.isOpen) {
this.proxyDialog.dialogName ? await this.proxyDialog.openDialog(this.proxyDialog.dialogName) : await this.proxyDialog.openDialog();
}
this.proxyDialog.dialogName ? await this.proxyDialog.openDialog(this.proxyDialog.dialogName) : await this.proxyDialog.openDialog();
}); });
} }

View File

@@ -82,6 +82,7 @@ export class TabbedPanel extends Disposable {
this.header = DOM.$('.composite.title'); this.header = DOM.$('.composite.title');
this.tabList = DOM.$('.tabList'); this.tabList = DOM.$('.tabList');
this.tabList.setAttribute('role', 'tablist'); this.tabList.setAttribute('role', 'tablist');
this.tabList.setAttribute('tabindex', '0');
this.tabList.style.height = this.headersize + 'px'; this.tabList.style.height = this.headersize + 'px';
this.header.appendChild(this.tabList); this.header.appendChild(this.tabList);
let actionbarcontainer = DOM.$('.title-actions'); let actionbarcontainer = DOM.$('.title-actions');
@@ -95,7 +96,6 @@ export class TabbedPanel extends Disposable {
} }
this.body = DOM.$('.tabBody'); this.body = DOM.$('.tabBody');
this.body.setAttribute('role', 'tabpanel'); this.body.setAttribute('role', 'tabpanel');
this.body.setAttribute('tabindex', '0');
this.parent.appendChild(this.body); this.parent.appendChild(this.body);
} }

View File

@@ -74,11 +74,16 @@ export class HeaderFilter<T extends Slick.SlickData> {
if (column.id === '_detail_selector') { if (column.id === '_detail_selector') {
return; return;
} }
const $el = jQuery('<div></div>') const $el = jQuery('<div tabIndex="0"></div>')
.addClass('slick-header-menubutton') .addClass('slick-header-menubutton')
.data('column', column); .data('column', column);
$el.bind('click', (e) => this.showFilter(e)).appendTo(args.node); $el.bind('click', (e) => this.showFilter(e)).appendTo(args.node);
$el.bind('keydown', (e) => {
if (e.key === 'Enter' || e.keyCode === 13) {
this.showFilter(e);
}
}).appendTo(args.node);
} }
private handleBeforeHeaderCellDestroy(e: Event, args: Slick.OnBeforeHeaderCellDestroyEventArgs<T>) { private handleBeforeHeaderCellDestroy(e: Event, args: Slick.OnBeforeHeaderCellDestroyEventArgs<T>) {