EditDataSources: Add EditDataSourceActions to EditDataSourcePages (#64487)

* add EditDataSourceActions to EditDataSourcePages

* fix tests

* EditDSPage: do not show buttons in header if topnav is off

* remove delete button from the header

* EditDSPage: hide buttons from footer when topnav is on

* update tests

* rename ActionProps to Props

* wrap setting of feature toggle in act in jest test

* fix jest test by using waitFor
pull/66442/head
mikkancso 2 years ago committed by GitHub
parent 92b69dfb97
commit 659024f672
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      public/app/features/connections/pages/EditDataSourcePage.tsx
  2. 5
      public/app/features/datasources/components/ButtonRow.tsx
  3. 80
      public/app/features/datasources/components/EditDataSourceActions.tsx
  4. 25
      public/app/features/datasources/pages/EditDataSourcePage.test.tsx
  5. 8
      public/app/features/datasources/pages/EditDataSourcePage.tsx

@ -1,8 +1,10 @@
import * as React from 'react';
import { useLocation, useParams } from 'react-router-dom';
import { config } from '@grafana/runtime';
import { Page } from 'app/core/components/Page/Page';
import { EditDataSource } from 'app/features/datasources/components/EditDataSource';
import { EditDataSourceActions } from 'app/features/datasources/components/EditDataSourceActions';
import { useDataSourceSettingsNav } from '../hooks/useDataSourceSettingsNav';
@ -14,7 +16,11 @@ export function EditDataSourcePage() {
const { navId, pageNav } = useDataSourceSettingsNav();
return (
<Page navId={navId} pageNav={pageNav}>
<Page
navId={navId}
pageNav={pageNav}
actions={config.featureToggles.topnav ? <EditDataSourceActions uid={uid} /> : undefined}
>
<Page.Contents>
<EditDataSource uid={uid} pageId={pageId} />
</Page.Contents>

@ -1,6 +1,7 @@
import React from 'react';
import { selectors } from '@grafana/e2e-selectors';
import { config } from '@grafana/runtime';
import { Button, LinkButton } from '@grafana/ui';
import { contextSrv } from 'app/core/core';
import { AccessControlAction } from 'app/types';
@ -19,12 +20,15 @@ export function ButtonRow({ canSave, canDelete, onDelete, onSubmit, onTest, expl
return (
<div className="gf-form-button-row">
{!config.featureToggles.topnav && (
<Button variant="secondary" fill="solid" type="button" onClick={() => history.back()}>
Back
</Button>
)}
<LinkButton variant="secondary" fill="solid" href={exploreUrl} disabled={!canExploreDataSources}>
Explore
</LinkButton>
{!config.featureToggles.topnav && (
<Button
type="button"
variant="destructive"
@ -34,6 +38,7 @@ export function ButtonRow({ canSave, canDelete, onDelete, onSubmit, onTest, expl
>
Delete
</Button>
)}
{canSave && (
<Button
type="submit"

@ -0,0 +1,80 @@
import { css } from '@emotion/css';
import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { config } from '@grafana/runtime';
import { Button, LinkButton, useStyles2 } from '@grafana/ui';
import { contextSrv } from 'app/core/core';
import { AccessControlAction } from 'app/types';
import { useDataSource, useDataSourceRights, useDeleteLoadedDataSource } from '../state';
import { trackCreateDashboardClicked, trackExploreClicked } from '../tracking';
import { constructDataSourceExploreUrl } from '../utils';
const getStyles = (theme: GrafanaTheme2) => {
return {
button: css({
marginLeft: theme.spacing(2),
}),
};
};
interface Props {
uid: string;
}
export function EditDataSourceActions({ uid }: Props) {
const styles = useStyles2(getStyles);
const dataSource = useDataSource(uid);
const onDelete = useDeleteLoadedDataSource();
const { readOnly, hasDeleteRights } = useDataSourceRights(uid);
const hasExploreRights = contextSrv.hasPermission(AccessControlAction.DataSourcesExplore);
const canDelete = !readOnly && hasDeleteRights;
return (
<>
<LinkButton
icon="apps"
fill="outline"
variant="secondary"
href={`dashboard/new-with-ds/${dataSource.uid}`}
onClick={() => {
trackCreateDashboardClicked({
grafana_version: config.buildInfo.version,
datasource_uid: dataSource.uid,
plugin_name: dataSource.typeName,
path: location.pathname,
});
}}
>
Build a dashboard
</LinkButton>
{hasExploreRights && (
<LinkButton
icon="compass"
fill="outline"
variant="secondary"
className={styles.button}
href={constructDataSourceExploreUrl(dataSource)}
onClick={() => {
trackExploreClicked({
grafana_version: config.buildInfo.version,
datasource_uid: dataSource.uid,
plugin_name: dataSource.typeName,
path: location.pathname,
});
}}
>
Explore
</LinkButton>
)}
<Button type="button" variant="destructive" disabled={!canDelete} onClick={onDelete} className={styles.button}>
Delete
</Button>
</>
);
}

@ -1,10 +1,11 @@
import { screen, render } from '@testing-library/react';
import { screen, render, waitFor } from '@testing-library/react';
import React from 'react';
import { Store } from 'redux';
import { TestProvider } from 'test/helpers/TestProvider';
import { LayoutModes } from '@grafana/data';
import { setAngularLoader } from '@grafana/runtime';
import config from 'app/core/config';
import { getRouteComponentProps } from 'app/core/navigation/__mocks__/routeProps';
import { configureStore } from 'app/store/configureStore';
@ -57,6 +58,7 @@ describe('<EditDataSourcePage>', () => {
const dataSourceMeta = getMockDataSourceMeta();
const dataSourceSettings = getMockDataSourceSettingsState();
let store: Store;
const topnavValue = config.featureToggles.topnav;
beforeAll(() => {
setAngularLoader({
@ -94,7 +96,12 @@ describe('<EditDataSourcePage>', () => {
});
});
afterAll(() => {
config.featureToggles.topnav = topnavValue;
});
it('should render the edit page without an issue', async () => {
config.featureToggles.topnav = false;
setup(uid, store);
expect(screen.queryByText('Loading ...')).not.toBeInTheDocument();
@ -106,9 +113,23 @@ describe('<EditDataSourcePage>', () => {
expect(screen.queryByRole('button', { name: /Back/i })).toBeVisible();
expect(screen.queryByRole('button', { name: /Delete/i })).toBeVisible();
expect(screen.queryByRole('button', { name: /Save (.*) test/i })).toBeVisible();
expect(screen.queryByText('Explore')).toBeVisible();
expect(screen.queryByRole('link', { name: /Explore/i })).toBeVisible();
// wait for the rest of the async processes to finish
expect(await screen.findByText(name)).toBeVisible();
});
it('should show updated action buttons when topnav is on', async () => {
config.featureToggles.topnav = true;
setup(uid, store);
await waitFor(() => {
// Buttons
expect(screen.queryAllByRole('button', { name: /Back/i })).toHaveLength(0);
expect(screen.queryByRole('button', { name: /Delete/i })).toBeVisible();
expect(screen.queryByRole('button', { name: /Save (.*) test/i })).toBeVisible();
expect(screen.queryByRole('link', { name: /Build a dashboard/i })).toBeVisible();
expect(screen.queryAllByRole('link', { name: /Explore/i })).toHaveLength(2);
});
});
});

@ -1,9 +1,11 @@
import React from 'react';
import { config } from '@grafana/runtime';
import { Page } from 'app/core/components/Page/Page';
import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
import { EditDataSource } from '../components/EditDataSource';
import { EditDataSourceActions } from '../components/EditDataSourceActions';
import { useDataSourceSettingsNav } from '../state';
export interface Props extends GrafanaRouteComponentProps<{ uid: string }> {}
@ -15,7 +17,11 @@ export function EditDataSourcePage(props: Props) {
const nav = useDataSourceSettingsNav(uid, pageId);
return (
<Page navId="datasources" pageNav={nav.main}>
<Page
navId="datasources"
pageNav={nav.main}
actions={config.featureToggles.topnav ? <EditDataSourceActions uid={uid} /> : undefined}
>
<Page.Contents>
<EditDataSource uid={uid} pageId={pageId} />
</Page.Contents>

Loading…
Cancel
Save