From 833ed5418e04ea12f6e60e729091cfedfc7c8c85 Mon Sep 17 00:00:00 2001 From: kay delaney <45561153+kaydelaney@users.noreply.github.com> Date: Tue, 9 Nov 2021 09:39:17 +0000 Subject: [PATCH] A11y/Dashboard: Change settings nav items from buttons to links (#41407) --- packages/grafana-data/src/utils/location.ts | 23 ++- .../DashboardSettings/DashboardSettings.tsx | 164 ++++++++---------- 2 files changed, 91 insertions(+), 96 deletions(-) diff --git a/packages/grafana-data/src/utils/location.ts b/packages/grafana-data/src/utils/location.ts index ac07baa4d94..fa9c2b45d24 100644 --- a/packages/grafana-data/src/utils/location.ts +++ b/packages/grafana-data/src/utils/location.ts @@ -36,12 +36,25 @@ const assureBaseUrl = (url: string): string => { return url; }; -const updateSearchParams = (href: string, searchParams: string) => { - const curURL = new URL(href); - const urlSearchParams = new URLSearchParams(searchParams); - urlSearchParams.forEach((val, key) => curURL.searchParams.set(key, val)); +/** + * Update URL or search param string `init` with new params `partial`. + */ +const updateSearchParams = (init: string, partial: string) => { + const urlSearchParams = new URLSearchParams(partial); - return curURL.href; + // Check if full URL + try { + const curURL = new URL(init); + urlSearchParams.forEach((val, key) => curURL.searchParams.set(key, val)); + return curURL.href; + } catch { + // assume search params + const newSearchParams = new URLSearchParams(init); + urlSearchParams.forEach((v, k) => { + newSearchParams.set(k, v); + }); + return '?' + newSearchParams.toString(); + } }; interface LocationUtilDependencies { diff --git a/public/app/features/dashboard/components/DashboardSettings/DashboardSettings.tsx b/public/app/features/dashboard/components/DashboardSettings/DashboardSettings.tsx index 33693fa2bdc..757ae1a4491 100644 --- a/public/app/features/dashboard/components/DashboardSettings/DashboardSettings.tsx +++ b/public/app/features/dashboard/components/DashboardSettings/DashboardSettings.tsx @@ -1,7 +1,7 @@ -import React, { PureComponent } from 'react'; +import React, { useCallback, useMemo } from 'react'; +import { Link } from 'react-router-dom'; import { css, cx } from '@emotion/css'; -import { selectors } from '@grafana/e2e-selectors'; -import { Button, CustomScrollbar, Icon, IconName, PageToolbar, stylesFactory } from '@grafana/ui'; +import { Button, CustomScrollbar, Icon, IconName, PageToolbar, stylesFactory, useForceUpdate } from '@grafana/ui'; import config from 'app/core/config'; import { contextSrv } from 'app/core/services/context_srv'; import { dashboardWatcher } from 'app/features/live/dashboard/dashboardWatcher'; @@ -14,7 +14,7 @@ import { AnnotationsSettings } from './AnnotationsSettings'; import { LinksSettings } from './LinksSettings'; import { VersionsSettings } from './VersionsSettings'; import { JsonEditorSettings } from './JsonEditorSettings'; -import { GrafanaTheme2 } from '@grafana/data'; +import { GrafanaTheme2, locationUtil } from '@grafana/data'; import { locationService } from '@grafana/runtime'; export interface Props { @@ -26,44 +26,58 @@ export interface SettingsPage { id: string; title: string; icon: IconName; - render: () => React.ReactNode; + component: React.ReactNode; } -export class DashboardSettings extends PureComponent { - onClose = () => { - locationService.partial({ editview: null }); - }; +const onClose = () => locationService.partial({ editview: null }); - onChangePage = (editview: string) => { - locationService.partial({ editview }); - }; +const MakeEditable = (props: { onMakeEditable: () => any }) => ( +
+
Dashboard not editable
+ +
+); - getPages(): SettingsPage[] { - const { dashboard } = this.props; +export function DashboardSettings({ dashboard, editview }: Props) { + const forceUpdate = useForceUpdate(); + const onMakeEditable = useCallback(() => { + dashboard.editable = true; + dashboard.meta.canMakeEditable = false; + dashboard.meta.canEdit = true; + dashboard.meta.canSave = true; + forceUpdate(); + }, [dashboard, forceUpdate]); + + const pages = useMemo((): SettingsPage[] => { const pages: SettingsPage[] = []; if (dashboard.meta.canEdit) { - pages.push(this.getGeneralPage()); + pages.push({ + title: 'General', + id: 'settings', + icon: 'sliders-v-alt', + component: , + }); pages.push({ title: 'Annotations', id: 'annotations', icon: 'comment-alt', - render: () => , + component: , }); pages.push({ title: 'Variables', id: 'templating', icon: 'calculator-alt', - render: () => , + component: , }); pages.push({ title: 'Links', id: 'links', icon: 'link', - render: () => , + component: , }); } @@ -72,7 +86,7 @@ export class DashboardSettings extends PureComponent { title: 'General', icon: 'sliders-v-alt', id: 'settings', - render: () => this.renderMakeEditable(), + component: , }); } @@ -81,7 +95,7 @@ export class DashboardSettings extends PureComponent { title: 'Versions', id: 'versions', icon: 'history', - render: () => , + component: , }); } @@ -90,7 +104,7 @@ export class DashboardSettings extends PureComponent { title: 'Permissions', id: 'permissions', icon: 'lock', - render: () => , + component: , }); } @@ -98,85 +112,53 @@ export class DashboardSettings extends PureComponent { title: 'JSON Model', id: 'dashboard_json', icon: 'arrow', - render: () => , + component: , }); return pages; - } + }, [dashboard, onMakeEditable]); - onMakeEditable = () => { - const { dashboard } = this.props; - dashboard.editable = true; - dashboard.meta.canMakeEditable = false; - dashboard.meta.canEdit = true; - dashboard.meta.canSave = true; - this.forceUpdate(); - }; - - onPostSave = () => { - this.props.dashboard.meta.hasUnsavedFolderChange = false; + const onPostSave = () => { + dashboard.meta.hasUnsavedFolderChange = false; dashboardWatcher.reloadPage(); }; - renderMakeEditable(): React.ReactNode { - return ( -
-
Dashboard not editable
- -
- ); - } + const folderTitle = dashboard.meta.folderTitle; + const currentPage = pages.find((page) => page.id === editview) ?? pages[0]; + const canSaveAs = contextSrv.hasEditPermissionInFolders; + const canSave = dashboard.meta.canSave; + const styles = getStyles(config.theme2); - getGeneralPage(): SettingsPage { - return { - title: 'General', - id: 'settings', - icon: 'sliders-v-alt', - render: () => , - }; - } - - render() { - const { dashboard, editview } = this.props; - const folderTitle = dashboard.meta.folderTitle; - const pages = this.getPages(); - const currentPage = pages.find((page) => page.id === editview) ?? pages[0]; - const canSaveAs = contextSrv.hasEditPermissionInFolders; - const canSave = dashboard.meta.canSave; - const styles = getStyles(config.theme2); - - return ( -
- - -
-
- -
{currentPage.render()}
-
+ return ( +
+ + +
+
+ +
{currentPage.component}
- -
- ); - } +
+ +
+ ); } const getStyles = stylesFactory((theme: GrafanaTheme2) => ({