Dashboards: A11y improvements for edit experience (#106321)

* Dashboards: A11y improvements for edit experience

* Pass descriptor to render function
pull/106210/head
kay delaney 3 weeks ago committed by GitHub
parent 5137995830
commit c30765bbea
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 11
      public/app/features/dashboard-scene/edit-pane/VizPanelEditableElement.tsx
  2. 34
      public/app/features/dashboard-scene/panel-edit/getPanelFrameOptions.tsx
  3. 7
      public/app/features/dashboard-scene/scene/layout-auto-grid/AutoGridItemEditor.tsx
  4. 7
      public/app/features/dashboard-scene/scene/layout-default/DashboardGridItemEditor.tsx
  5. 6
      public/app/features/dashboard/components/PanelEditor/OptionsPaneItemDescriptor.tsx
  6. 20
      public/app/features/dashboard/components/PanelEditor/getPanelFrameOptions.tsx

@ -55,22 +55,27 @@ export class VizPanelEditableElement implements EditableDashboardElement, BulkAc
.addItem( .addItem(
new OptionsPaneItemDescriptor({ new OptionsPaneItemDescriptor({
title: t('dashboard.viz-panel.options.title-option', 'Title'), title: t('dashboard.viz-panel.options.title-option', 'Title'),
id: 'PanelFrameTitle',
value: panel.state.title, value: panel.state.title,
popularRank: 1, popularRank: 1,
render: () => <PanelFrameTitleInput panel={panel} isNewElement={isNewElement} />, render: (descriptor) => (
<PanelFrameTitleInput id={descriptor.props.id} panel={panel} isNewElement={isNewElement} />
),
}) })
) )
.addItem( .addItem(
new OptionsPaneItemDescriptor({ new OptionsPaneItemDescriptor({
title: t('dashboard.viz-panel.options.description', 'Description'), title: t('dashboard.viz-panel.options.description', 'Description'),
id: 'description-text-area',
value: panel.state.description, value: panel.state.description,
render: () => <PanelDescriptionTextArea panel={panel} />, render: (descriptor) => <PanelDescriptionTextArea id={descriptor.props.id} panel={panel} />,
}) })
) )
.addItem( .addItem(
new OptionsPaneItemDescriptor({ new OptionsPaneItemDescriptor({
title: t('dashboard.viz-panel.options.transparent-background', 'Transparent background'), title: t('dashboard.viz-panel.options.transparent-background', 'Transparent background'),
render: () => <PanelBackgroundSwitch panel={panel} />, id: 'transparent-background',
render: (descriptor) => <PanelBackgroundSwitch id={descriptor.props.id} panel={panel} />,
}) })
); );
}, [panel, isNewElement]); }, [panel, isNewElement]);

@ -37,10 +37,11 @@ export function getPanelFrameOptions(panel: VizPanel): OptionsPaneCategoryDescri
.addItem( .addItem(
new OptionsPaneItemDescriptor({ new OptionsPaneItemDescriptor({
title: t('dashboard-scene.get-panel-frame-options.title.title', 'Title'), title: t('dashboard-scene.get-panel-frame-options.title.title', 'Title'),
id: 'PanelFrameTitle',
value: panel.state.title, value: panel.state.title,
popularRank: 1, popularRank: 1,
render: function renderTitle() { render: function renderTitle(descriptor) {
return <PanelFrameTitleInput panel={panel} />; return <PanelFrameTitleInput id={descriptor.props.id} panel={panel} />;
}, },
addon: config.featureToggles.dashgpt && ( addon: config.featureToggles.dashgpt && (
<GenAIPanelTitleButton <GenAIPanelTitleButton
@ -54,9 +55,10 @@ export function getPanelFrameOptions(panel: VizPanel): OptionsPaneCategoryDescri
.addItem( .addItem(
new OptionsPaneItemDescriptor({ new OptionsPaneItemDescriptor({
title: t('dashboard-scene.get-panel-frame-options.title.description', 'Description'), title: t('dashboard-scene.get-panel-frame-options.title.description', 'Description'),
id: 'description-text-area',
value: panel.state.description, value: panel.state.description,
render: function renderDescription() { render: function renderDescription(descriptor) {
return <PanelDescriptionTextArea panel={panel} />; return <PanelDescriptionTextArea id={descriptor.props.id} panel={panel} />;
}, },
addon: config.featureToggles.dashgpt && ( addon: config.featureToggles.dashgpt && (
<GenAIPanelDescriptionButton <GenAIPanelDescriptionButton
@ -69,8 +71,9 @@ export function getPanelFrameOptions(panel: VizPanel): OptionsPaneCategoryDescri
.addItem( .addItem(
new OptionsPaneItemDescriptor({ new OptionsPaneItemDescriptor({
title: t('dashboard-scene.get-panel-frame-options.title.transparent-background', 'Transparent background'), title: t('dashboard-scene.get-panel-frame-options.title.transparent-background', 'Transparent background'),
render: function renderTransparent() { id: 'transparent-background',
return <PanelBackgroundSwitch panel={panel} />; render: function renderTransparent(descriptor) {
return <PanelBackgroundSwitch id={descriptor.props.id} panel={panel} />;
}, },
}) })
) )
@ -112,7 +115,15 @@ function ScenePanelLinksEditor({ panelLinks }: ScenePanelLinksEditorProps) {
); );
} }
export function PanelFrameTitleInput({ panel, isNewElement }: { panel: VizPanel; isNewElement?: boolean }) { export function PanelFrameTitleInput({
panel,
isNewElement,
id,
}: {
panel: VizPanel;
isNewElement?: boolean;
id?: string;
}) {
const { title } = panel.useState(); const { title } = panel.useState();
const notInPanelEdit = panel.getPanelContext().app !== CoreApp.PanelEditor; const notInPanelEdit = panel.getPanelContext().app !== CoreApp.PanelEditor;
const [prevTitle, setPrevTitle] = React.useState(panel.state.title); const [prevTitle, setPrevTitle] = React.useState(panel.state.title);
@ -125,6 +136,7 @@ export function PanelFrameTitleInput({ panel, isNewElement }: { panel: VizPanel;
<Input <Input
ref={ref} ref={ref}
data-testid={selectors.components.PanelEditor.OptionsPane.fieldInput('Title')} data-testid={selectors.components.PanelEditor.OptionsPane.fieldInput('Title')}
id={id}
value={title} value={title}
onFocus={() => setPrevTitle(title)} onFocus={() => setPrevTitle(title)}
onBlur={() => editPanelTitleAction(panel, title, prevTitle)} onBlur={() => editPanelTitleAction(panel, title, prevTitle)}
@ -135,13 +147,13 @@ export function PanelFrameTitleInput({ panel, isNewElement }: { panel: VizPanel;
); );
} }
export function PanelDescriptionTextArea({ panel }: { panel: VizPanel }) { export function PanelDescriptionTextArea({ panel, id }: { panel: VizPanel; id?: string }) {
const { description } = panel.useState(); const { description } = panel.useState();
const [prevDescription, setPrevDescription] = React.useState(panel.state.description); const [prevDescription, setPrevDescription] = React.useState(panel.state.description);
return ( return (
<TextArea <TextArea
id="description-text-area" id={id}
value={description} value={description}
onChange={(evt) => panel.setState({ description: evt.currentTarget.value })} onChange={(evt) => panel.setState({ description: evt.currentTarget.value })}
onFocus={() => setPrevDescription(panel.state.description)} onFocus={() => setPrevDescription(panel.state.description)}
@ -157,7 +169,7 @@ export function PanelDescriptionTextArea({ panel }: { panel: VizPanel }) {
); );
} }
export function PanelBackgroundSwitch({ panel }: { panel: VizPanel }) { export function PanelBackgroundSwitch({ panel, id }: { panel: VizPanel; id?: string }) {
const { displayMode = 'default' } = panel.useState(); const { displayMode = 'default' } = panel.useState();
const onChange = () => { const onChange = () => {
@ -171,7 +183,7 @@ export function PanelBackgroundSwitch({ panel }: { panel: VizPanel }) {
}); });
}; };
return <Switch value={displayMode === 'transparent'} id="transparent-background" onChange={onChange} />; return <Switch value={displayMode === 'transparent'} id={id} onChange={onChange} />;
} }
function updatePanelTitleState(panel: VizPanel, title: string) { function updatePanelTitleState(panel: VizPanel, title: string) {

@ -15,11 +15,12 @@ export function getOptions(model: AutoGridItem): OptionsPaneCategoryDescriptor[]
}).addItem( }).addItem(
new OptionsPaneItemDescriptor({ new OptionsPaneItemDescriptor({
title: t('dashboard.auto-grid.item-options.repeat.variable.title', 'Repeat by variable'), title: t('dashboard.auto-grid.item-options.repeat.variable.title', 'Repeat by variable'),
id: 'repeat-by-variable-select',
description: t( description: t(
'dashboard.auto-grid.item-options.repeat.variable.description', 'dashboard.auto-grid.item-options.repeat.variable.description',
'Repeat this panel for each value in the selected variable. This is not visible while in edit mode. You need to go back to dashboard and then update the variable or reload the dashboard.' 'Repeat this panel for each value in the selected variable. This is not visible while in edit mode. You need to go back to dashboard and then update the variable or reload the dashboard.'
), ),
render: () => <RepeatByOption item={model} />, render: (descriptor) => <RepeatByOption id={descriptor.props.id} item={model} />,
}) })
); );
@ -28,12 +29,12 @@ export function getOptions(model: AutoGridItem): OptionsPaneCategoryDescriptor[]
return [repeatCategory, conditionalRenderingCategory]; return [repeatCategory, conditionalRenderingCategory];
} }
function RepeatByOption({ item }: { item: AutoGridItem }) { function RepeatByOption({ item, id }: { item: AutoGridItem; id?: string }) {
const { variableName } = item.useState(); const { variableName } = item.useState();
return ( return (
<RepeatRowSelect2 <RepeatRowSelect2
id="repeat-by-variable-select" id={id}
sceneContext={item} sceneContext={item}
repeat={variableName} repeat={variableName}
onChange={(value?: string) => item.setRepeatByVariable(value)} onChange={(value?: string) => item.setRepeatByVariable(value)}

@ -18,11 +18,12 @@ export function getDashboardGridItemOptions(gridItem: DashboardGridItem): Option
.addItem( .addItem(
new OptionsPaneItemDescriptor({ new OptionsPaneItemDescriptor({
title: t('dashboard.default-layout.item-options.repeat.variable.title', 'Repeat by variable'), title: t('dashboard.default-layout.item-options.repeat.variable.title', 'Repeat by variable'),
id: 'repeat-by-variable-select',
description: t( description: t(
'dashboard.default-layout.item-options.repeat.variable.description', 'dashboard.default-layout.item-options.repeat.variable.description',
'Repeat this panel for each value in the selected variable. This is not visible while in edit mode. You need to go back to dashboard and then update the variable or reload the dashboard.' 'Repeat this panel for each value in the selected variable. This is not visible while in edit mode. You need to go back to dashboard and then update the variable or reload the dashboard.'
), ),
render: () => <RepeatByOption gridItem={gridItem} />, render: (descriptor) => <RepeatByOption id={descriptor.props.id} gridItem={gridItem} />,
}) })
) )
.addItem( .addItem(
@ -86,12 +87,12 @@ function MaxPerRowOption({ gridItem }: OptionComponentProps) {
); );
} }
function RepeatByOption({ gridItem }: OptionComponentProps) { function RepeatByOption({ gridItem, id }: OptionComponentProps & { id?: string }) {
const { variableName, width } = gridItem.useState(); const { variableName, width } = gridItem.useState();
return ( return (
<RepeatRowSelect2 <RepeatRowSelect2
id="repeat-by-variable-select" id={id}
sceneContext={gridItem} sceneContext={gridItem}
repeat={variableName} repeat={variableName}
onChange={(value?: string) => { onChange={(value?: string) => {

@ -16,7 +16,7 @@ export interface OptionsPaneItemInfo {
value?: any; value?: any;
description?: string; description?: string;
popularRank?: number; popularRank?: number;
render: () => React.ReactElement; render: (descriptor: OptionsPaneItemDescriptor) => React.ReactElement;
skipField?: boolean; skipField?: boolean;
showIf?: () => boolean; showIf?: () => boolean;
/** Hook for controlling visibility */ /** Hook for controlling visibility */
@ -66,7 +66,7 @@ function OptionsPaneItem({ itemDescriptor, searchQuery }: OptionsPaneItemProps)
} }
if (skipField) { if (skipField) {
return render(); return render(itemDescriptor);
} }
return ( return (
@ -77,7 +77,7 @@ function OptionsPaneItem({ itemDescriptor, searchQuery }: OptionsPaneItemProps)
aria-label={selectors.components.PanelEditor.OptionsPane.fieldLabel(key)} aria-label={selectors.components.PanelEditor.OptionsPane.fieldLabel(key)}
htmlFor={id} htmlFor={id}
> >
{render()} {render(itemDescriptor)}
</Field> </Field>
); );
} }

@ -40,13 +40,14 @@ export function getPanelFrameCategory(props: OptionPaneRenderProps): OptionsPane
.addItem( .addItem(
new OptionsPaneItemDescriptor({ new OptionsPaneItemDescriptor({
title: t('dashboard.get-panel-frame-category.title.title', 'Title'), title: t('dashboard.get-panel-frame-category.title.title', 'Title'),
id: 'PanelFrameTitle',
value: panel.title, value: panel.title,
popularRank: 1, popularRank: 1,
render: function renderTitle() { render: function renderTitle(descriptor) {
return ( return (
<Input <Input
data-testid={selectors.components.PanelEditor.OptionsPane.fieldInput('Title')} data-testid={selectors.components.PanelEditor.OptionsPane.fieldInput('Title')}
id="PanelFrameTitle" id={descriptor.props.id}
defaultValue={panel.title} defaultValue={panel.title}
onBlur={(e) => onPanelConfigChange('title', e.currentTarget.value)} onBlur={(e) => onPanelConfigChange('title', e.currentTarget.value)}
/> />
@ -64,13 +65,14 @@ export function getPanelFrameCategory(props: OptionPaneRenderProps): OptionsPane
.addItem( .addItem(
new OptionsPaneItemDescriptor({ new OptionsPaneItemDescriptor({
title: t('dashboard.get-panel-frame-category.title.description', 'Description'), title: t('dashboard.get-panel-frame-category.title.description', 'Description'),
id: 'description-text-area',
description: panel.description, description: panel.description,
value: panel.description, value: panel.description,
render: function renderDescription() { render: function renderDescription(descriptor) {
return ( return (
<TextArea <TextArea
data-testid={selectors.components.PanelEditor.OptionsPane.fieldInput('Description')} data-testid={selectors.components.PanelEditor.OptionsPane.fieldInput('Description')}
id="description-text-area" id={descriptor.props.id}
defaultValue={panel.description} defaultValue={panel.description}
onBlur={(e) => onPanelConfigChange('description', e.currentTarget.value)} onBlur={(e) => onPanelConfigChange('description', e.currentTarget.value)}
/> />
@ -84,12 +86,13 @@ export function getPanelFrameCategory(props: OptionPaneRenderProps): OptionsPane
.addItem( .addItem(
new OptionsPaneItemDescriptor({ new OptionsPaneItemDescriptor({
title: t('dashboard.get-panel-frame-category.title.transparent-background', 'Transparent background'), title: t('dashboard.get-panel-frame-category.title.transparent-background', 'Transparent background'),
render: function renderTransparent() { id: 'transparent-background',
render: function renderTransparent(descriptor) {
return ( return (
<Switch <Switch
data-testid={selectors.components.PanelEditor.OptionsPane.fieldInput('Transparent background')} data-testid={selectors.components.PanelEditor.OptionsPane.fieldInput('Transparent background')}
value={panel.transparent} value={panel.transparent}
id="transparent-background" id={descriptor.props.id}
onChange={(e) => onPanelConfigChange('transparent', e.currentTarget.checked)} onChange={(e) => onPanelConfigChange('transparent', e.currentTarget.checked)}
/> />
); );
@ -127,12 +130,13 @@ export function getPanelFrameCategory(props: OptionPaneRenderProps): OptionsPane
.addItem( .addItem(
new OptionsPaneItemDescriptor({ new OptionsPaneItemDescriptor({
title: t('dashboard.get-panel-frame-category.title.repeat-by-variable', 'Repeat by variable'), title: t('dashboard.get-panel-frame-category.title.repeat-by-variable', 'Repeat by variable'),
id: 'repeat-by-variable-select',
description: description:
'Repeat this panel for each value in the selected variable. This is not visible while in edit mode. You need to go back to dashboard and then update the variable or reload the dashboard.', 'Repeat this panel for each value in the selected variable. This is not visible while in edit mode. You need to go back to dashboard and then update the variable or reload the dashboard.',
render: function renderRepeatOptions() { render: function renderRepeatOptions(descriptor) {
return ( return (
<RepeatRowSelect <RepeatRowSelect
id="repeat-by-variable-select" id={descriptor.props.id}
repeat={panel.repeat} repeat={panel.repeat}
onChange={(value?: string) => { onChange={(value?: string) => {
onPanelConfigChange('repeat', value); onPanelConfigChange('repeat', value);

Loading…
Cancel
Save