diff --git a/grafana-plugin/e2e-tests/settings/tabs.test.ts b/grafana-plugin/e2e-tests/settings/tabs.test.ts new file mode 100644 index 00000000..c878e0b0 --- /dev/null +++ b/grafana-plugin/e2e-tests/settings/tabs.test.ts @@ -0,0 +1,12 @@ +import { test, expect } from '../fixtures'; +import { goToOnCallPage } from '../utils/navigation'; + +test(`tab query param is used to show proper page tab`, async ({ adminRolePage }) => { + const { page } = adminRolePage; + goToOnCallPage(page, `settings`, { tab: 'ChatOps' }); + + const tab = page.getByRole('tab', { name: 'Chat Ops' }); + const isSelected = await tab.getAttribute('aria-selected'); + + expect(isSelected).toBe('true'); +}); diff --git a/grafana-plugin/e2e-tests/utils/navigation.ts b/grafana-plugin/e2e-tests/utils/navigation.ts index af9435df..2c53125a 100644 --- a/grafana-plugin/e2e-tests/utils/navigation.ts +++ b/grafana-plugin/e2e-tests/utils/navigation.ts @@ -1,4 +1,6 @@ +import { KeyValue } from '@grafana/data'; import type { Page } from '@playwright/test'; +import qs from 'query-string'; import { BASE_URL } from './constants'; @@ -17,8 +19,9 @@ const _goToPage = async (page: Page, url = '') => page.goto(`${BASE_URL}${url}`) export const goToGrafanaPage = async (page: Page, url = '') => _goToPage(page, url); -export const goToOnCallPage = async (page: Page, onCallPage: OnCallPage) => { - await _goToPage(page, `/a/grafana-oncall-app/${onCallPage}`); +export const goToOnCallPage = async (page: Page, onCallPage: OnCallPage, queryParams?: KeyValue) => { + const queryParamsString = queryParams ? `?${qs.stringify(queryParams)}` : ''; + await _goToPage(page, `/a/grafana-oncall-app/${onCallPage}${queryParamsString}`); await page.waitForLoadState('networkidle'); await page.waitForTimeout(1000); }; diff --git a/grafana-plugin/src/pages/settings/SettingsPage.tsx b/grafana-plugin/src/pages/settings/SettingsPage.tsx index 4d2926f5..71828696 100644 --- a/grafana-plugin/src/pages/settings/SettingsPage.tsx +++ b/grafana-plugin/src/pages/settings/SettingsPage.tsx @@ -1,5 +1,6 @@ import React from 'react'; +import { AppRootProps } from '@grafana/data'; import { Tab, TabsBar } from '@grafana/ui'; import cn from 'classnames/bind'; import { observer } from 'mobx-react'; @@ -8,8 +9,9 @@ import { ChatOpsPage } from 'pages/settings/tabs/ChatOps/ChatOps'; import { MainSettings } from 'pages/settings/tabs/MainSettings/MainSettings'; import { isTopNavbar } from 'plugin/GrafanaPluginRootPage.helpers'; import { AppFeature } from 'state/features'; -import { RootBaseStore } from 'state/rootBaseStore/RootBaseStore'; +import { WithStoreProps } from 'state/types'; import { withMobXProviderContext } from 'state/withStore'; +import { LocationHelper } from 'utils/LocationHelper'; import { isUserActionAllowed, UserActions } from 'utils/authorization/authorization'; import { SettingsPageTab } from './SettingsPage.types'; @@ -21,18 +23,22 @@ import styles from './SettingsPage.module.css'; const cx = cn.bind(styles); -interface SettingsPageProps { - store: RootBaseStore; -} +interface SettingsPageProps extends AppRootProps, WithStoreProps {} interface SettingsPageState { activeTab: string; } @observer class Settings extends React.Component { - state: SettingsPageState = { - activeTab: SettingsPageTab.MainSettings.key, // should read from route instead - }; + constructor(props: SettingsPageProps) { + super(props); + + const tab = LocationHelper.getQueryParam('tab'); + + this.state = { + activeTab: tab || SettingsPageTab.MainSettings.key, + }; + } render() { return
{this.renderContent()}
; @@ -44,6 +50,7 @@ class Settings extends React.Component { const onTabChange = (tab: string) => { this.setState({ activeTab: tab }); + LocationHelper.update({ tab }, 'partial'); }; const hasLiveSettings = store.hasFeature(AppFeature.LiveSettings); diff --git a/grafana-plugin/src/pages/settings/tabs/ChatOps/ChatOps.tsx b/grafana-plugin/src/pages/settings/tabs/ChatOps/ChatOps.tsx index ab89488c..b43e7510 100644 --- a/grafana-plugin/src/pages/settings/tabs/ChatOps/ChatOps.tsx +++ b/grafana-plugin/src/pages/settings/tabs/ChatOps/ChatOps.tsx @@ -36,9 +36,9 @@ export class _ChatOpsPage extends React.Component { }; componentDidMount() { - const { query } = this.props; // eslint-disable-line + const tab = LocationHelper.getQueryParam('chatOpsTab'); - this.handleChatopsTabChange(query?.tab || ChatOpsTab.Slack); + this.handleChatopsTabChange(tab || ChatOpsTab.Slack); } componentWillUnmount() { @@ -94,7 +94,7 @@ export class _ChatOpsPage extends React.Component { handleChatopsTabChange(tab: ChatOpsTab) { this.setState({ activeTab: tab }); - LocationHelper.update({ tab: tab }, 'partial'); + LocationHelper.update({ chatOpsTab: tab }, 'partial'); } }