From de7fd5057c966bc3c809be5651011ced3add5ef6 Mon Sep 17 00:00:00 2001 From: hriday-panchasara Date: Thu, 23 Dec 2021 10:29:40 -0600 Subject: [PATCH] Set keyboard focus on graph/table when selecting an analysis MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fixes #414 When clicking on an analysis in the Available Analysis list, the analysis is scrolled into view and given keyboard focus. When clicking on an analysis title in the trace tab, keyboard focus should be the analysis' graph/chart region. If a View that is already open is selected in the sidebar, the View's title area should pulse to temporarily bring attention to the View panel.  Signed-off-by: hriday-panchasara --- .../components/abstract-output-component.tsx | 12 ++++++++--- .../components/datatree-output-component.tsx | 19 ++++++++++++++++-- .../src/components/null-output-component.tsx | 5 +++++ .../src/components/table-output-component.tsx | 20 +++++++++++++++++-- .../components/timegraph-output-component.tsx | 16 ++++++++++++--- .../components/trace-context-component.tsx | 2 +- .../utils/timegraph-container-component.tsx | 2 +- .../src/components/xy-output-component.tsx | 18 +++++++++++++++-- .../trace-explorer-views-widget.tsx | 2 -- .../style/output-components-style.css | 9 ++++++++- .../viewer-prototype/package.json | 3 ++- .../src/browser/trace-viewer/trace-viewer.tsx | 20 +++++++++++++++++-- yarn.lock | 5 +++++ 13 files changed, 113 insertions(+), 20 deletions(-) diff --git a/packages/react-components/src/components/abstract-output-component.tsx b/packages/react-components/src/components/abstract-output-component.tsx index 47e5c421f..0f529d345 100644 --- a/packages/react-components/src/components/abstract-output-component.tsx +++ b/packages/react-components/src/components/abstract-output-component.tsx @@ -63,7 +63,8 @@ export abstract class AbstractOutputComponent

-

+
{this.renderTitleBar()}
-
+
this.setFocus()}> {outputName}
; @@ -120,6 +125,7 @@ export abstract class AbstractOutputComponent

+ ?

{this.state.outputStatus === ResponseStatus.COMPLETED ? @@ -102,13 +107,22 @@ export class DataTreeOutputComponent extends AbstractOutputComponent {this.renderTree()}
: -
+
Analysis running
} ; } + + setFocus(): void { + if (document.getElementById(this.props.traceId + this.props.outputDescriptor.id + 'focusContainer')) { + document.getElementById(this.props.traceId + this.props.outputDescriptor.id + 'focusContainer')?.focus(); + } else { + document.getElementById(this.props.traceId + this.props.outputDescriptor.id)?.focus(); + } + } + private onToggleCollapse(id: number, nodes: TreeNode[]) { let newList = [...this.state.collapsedNodes]; @@ -122,6 +136,7 @@ export class DataTreeOutputComponent extends AbstractOutputComponentthis.checkFocus(event)} className={this.props.backgroundTheme === 'light' ? 'ag-theme-balham' : 'ag-theme-balham-dark'} style={{ height: this.props.style.height, width: this.props.widthWPBugWorkaround }}> { this.handleTimeSelectionChange(range); }); } + private checkFocus(event: React.FocusEvent): void { + if (!event.currentTarget?.contains(event.relatedTarget as Node)) { + this.setFocus(); + } + } + + setFocus(): void { + if (document.getElementById(this.props.traceId + this.props.outputDescriptor.id + 'focusContainer')) { + document.getElementById(this.props.traceId + this.props.outputDescriptor.id + 'focusContainer')?.focus(); + } else { + document.getElementById(this.props.traceId + this.props.outputDescriptor.id)?.focus(); + } + } + componentWillUnmount(): void { // TODO: replace with removing the handler from unit controller // See timeline-chart issue #98 diff --git a/packages/react-components/src/components/timegraph-output-component.tsx b/packages/react-components/src/components/timegraph-output-component.tsx index 13ff46e98..64d5788a8 100644 --- a/packages/react-components/src/components/timegraph-output-component.tsx +++ b/packages/react-components/src/components/timegraph-output-component.tsx @@ -300,7 +300,9 @@ export class TimegraphOutputComponent extends AbstractTreeOutputComponent
this.synchronizeTreeScroll()} - style={{ height: parseInt(this.props.style.height.toString()) - this.getMarkersLayerHeight() }}> + style={{ height: parseInt(this.props.style.height.toString()) - this.getMarkersLayerHeight() }} + tabIndex={0} + > ; } + setFocus(): void { + if (document.getElementById(this.props.traceId + this.props.outputDescriptor.id + 'focusContainer')) { + document.getElementById(this.props.traceId + this.props.outputDescriptor.id + 'focusContainer')?.focus(); + } else { + document.getElementById(this.props.traceId + this.props.outputDescriptor.id)?.focus(); + } + } + protected getVerticalScrollbar(): JSX.Element { return this.ref = ref || undefined } onWheel={ e => e.preventDefault() } tabIndex={ 1 }>; + return this.ref = ref || undefined } onWheel={ e => e.preventDefault() } tabIndex={ 0 }>; } private resize(): void { diff --git a/packages/react-components/src/components/xy-output-component.tsx b/packages/react-components/src/components/xy-output-component.tsx index 95c9ce50c..490d848ae 100644 --- a/packages/react-components/src/components/xy-output-component.tsx +++ b/packages/react-components/src/components/xy-output-component.tsx @@ -324,7 +324,10 @@ export class XYOutputComponent extends AbstractTreeOutputComponent {this.state.outputStatus === ResponseStatus.COMPLETED ? -
this.onKeyDown(event)} onWheel={event => this.onWheel(event)} onMouseMove={event => this.onMouseMove(event)} @@ -336,7 +339,10 @@ export class XYOutputComponent extends AbstractTreeOutputComponent {this.chooseChart()}
: -
+
Analysis running
@@ -374,6 +380,14 @@ export class XYOutputComponent extends AbstractTreeOutputComponent { + const titleHandle = document.getElementById(traceId + exist.id + 'handle'); + titleHandle?.classList.add('animate__animated', 'animate__pulse'); + titleHandle?.addEventListener('animationend', event => { + event.stopPropagation(); + titleHandle?.classList.remove('animate__animated', 'animate__pulse'); + resolve('Animation ended'); + }, {once: true}); + }); } } } diff --git a/yarn.lock b/yarn.lock index dca7f9359..09764914a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4556,6 +4556,11 @@ alphanum-sort@^1.0.1, alphanum-sort@^1.0.2: resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" integrity sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM= +animate.css@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/animate.css/-/animate.css-4.1.1.tgz#614ec5a81131d7e4dc362a58143f7406abd68075" + integrity sha512-+mRmCTv6SbCmtYJCN4faJMNFVNN5EuCTTprDTAo7YzIGji2KADmakjVA3+8mVDkZ2Bf09vayB35lSQIex2+QaQ== + anser@^2.0.1: version "2.1.0" resolved "https://registry.yarnpkg.com/anser/-/anser-2.1.0.tgz#a7309c9f29886f19af56cb30c79fc60ea483944e"