NestedFolders: Button for creating new dashboards and and folders (#67260)

* Add CreateNewButton and tests

* Add translation support

* Move reused phrases to temp common file

* Use just a simple button

---------

Co-authored-by: joshhunt <josh@trtr.co>
This commit is contained in:
Tobias Skarhed 2023-04-27 12:43:20 +02:00 committed by GitHub
parent f28c962dc8
commit 4b047b62a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 97 additions and 6 deletions

View File

@ -15,6 +15,7 @@ import { skipToken, useGetFolderQuery } from './api/browseDashboardsAPI';
import { BrowseActions } from './components/BrowseActions/BrowseActions';
import { BrowseFilters } from './components/BrowseFilters';
import { BrowseView } from './components/BrowseView';
import { CreateNewButton } from './components/CreateNewButton';
import { SearchView } from './components/SearchView';
import { useHasSelection } from './state';
@ -49,7 +50,7 @@ const BrowseDashboardsPage = memo(({ match }: Props) => {
const hasSelection = useHasSelection();
return (
<Page navId="dashboards/browse" pageNav={navModel}>
<Page navId="dashboards/browse" pageNav={navModel} actions={<CreateNewButton inFolder={folderUID} />}>
<Page.Contents className={styles.pageContents}>
<FilterInput
placeholder={getSearchPlaceholder(searchState.includePanels)}

View File

@ -0,0 +1,29 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { CreateNewButton } from './CreateNewButton';
async function renderAndOpen(folderUID?: string) {
render(<CreateNewButton inFolder={folderUID} />);
const newButton = screen.getByText('New');
await userEvent.click(newButton);
}
describe('NewActionsButton', () => {
it('should display the correct urls with a given folderUID', async () => {
await renderAndOpen('123');
expect(screen.getByText('New Dashboard')).toHaveAttribute('href', '/dashboard/new?folderUid=123');
expect(screen.getByText('New Folder')).toHaveAttribute('href', '/dashboards/folder/new?folderUid=123');
expect(screen.getByText('Import')).toHaveAttribute('href', '/dashboard/import?folderUid=123');
});
it('should display urls without params when there is no folderUID', async () => {
await renderAndOpen();
expect(screen.getByText('New Dashboard')).toHaveAttribute('href', '/dashboard/new');
expect(screen.getByText('New Folder')).toHaveAttribute('href', '/dashboards/folder/new');
expect(screen.getByText('Import')).toHaveAttribute('href', '/dashboard/import');
});
});

View File

@ -0,0 +1,45 @@
import React from 'react';
import { Button, Dropdown, Icon, Menu, MenuItem } from '@grafana/ui';
import {
getNewDashboardPhrase,
getNewFolderPhrase,
getImportPhrase,
getNewPhrase,
} from 'app/features/search/tempI18nPhrases';
interface Props {
/**
* Pass a folder UID in which the dashboard or folder will be created
*/
inFolder?: string;
}
export function CreateNewButton({ inFolder }: Props) {
const newMenu = (
<Menu>
<MenuItem url={addFolderUidToUrl('/dashboard/new', inFolder)} label={getNewDashboardPhrase()} />
<MenuItem url={addFolderUidToUrl('/dashboards/folder/new', inFolder)} label={getNewFolderPhrase()} />
<MenuItem url={addFolderUidToUrl('/dashboard/import', inFolder)} label={getImportPhrase()} />
</Menu>
);
return (
<Dropdown overlay={newMenu}>
<Button>
{getNewPhrase()}
<Icon name="angle-down" />
</Button>
</Dropdown>
);
}
/**
*
* @param url without any parameters
* @param folderUid folder id
* @returns url with paramter if folder is present
*/
function addFolderUidToUrl(url: string, folderUid: string | undefined) {
return folderUid ? url + '?folderUid=' + folderUid : url;
}

View File

@ -2,10 +2,10 @@ import React, { useMemo, useState } from 'react';
import { config, reportInteraction } from '@grafana/runtime';
import { Menu, Dropdown, Button, Icon, HorizontalGroup } from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { FolderDTO } from 'app/types';
import { MoveToFolderModal } from '../page/components/MoveToFolderModal';
import { getImportPhrase, getNewDashboardPhrase, getNewFolderPhrase, getNewPhrase } from '../tempI18nPhrases';
export interface Props {
folder: FolderDTO | undefined;
@ -43,7 +43,7 @@ export const DashboardActions = ({ folder, canCreateFolders = false, canCreateDa
{canCreateDashboards && (
<Menu.Item
url={actionUrl('new')}
label={t('search.dashboard-actions.new-dashboard', 'New Dashboard')}
label={getNewDashboardPhrase()}
onClick={() =>
reportInteraction('grafana_menu_item_clicked', { url: actionUrl('new'), from: '/dashboards' })
}
@ -52,7 +52,7 @@ export const DashboardActions = ({ folder, canCreateFolders = false, canCreateDa
{canCreateFolders && (config.featureToggles.nestedFolders || !folder?.uid) && (
<Menu.Item
url={actionUrl('new_folder')}
label={t('search.dashboard-actions.new-folder', 'New Folder')}
label={getNewFolderPhrase()}
onClick={() =>
reportInteraction('grafana_menu_item_clicked', { url: actionUrl('new_folder'), from: '/dashboards' })
}
@ -61,7 +61,7 @@ export const DashboardActions = ({ folder, canCreateFolders = false, canCreateDa
{canCreateDashboards && (
<Menu.Item
url={actionUrl('import')}
label={t('search.dashboard-actions.import', 'Import')}
label={getImportPhrase()}
onClick={() =>
reportInteraction('grafana_menu_item_clicked', { url: actionUrl('import'), from: '/dashboards' })
}
@ -82,7 +82,7 @@ export const DashboardActions = ({ folder, canCreateFolders = false, canCreateDa
)}
<Dropdown overlay={MenuActions} placement="bottom-start">
<Button variant="primary">
{t('search.dashboard-actions.new', 'New')}
{getNewPhrase()}
<Icon name="angle-down" />
</Button>
</Dropdown>

View File

@ -8,3 +8,19 @@ export function getSearchPlaceholder(includePanels = false) {
? t('search.search-input.include-panels-placeholder', 'Search for dashboards, folders, and panels')
: t('search.search-input.placeholder', 'Search for dashboards and folders');
}
export function getNewDashboardPhrase() {
return t('search.dashboard-actions.new-dashboard', 'New Dashboard');
}
export function getNewFolderPhrase() {
return t('search.dashboard-actions.new-folder', 'New Folder');
}
export function getImportPhrase() {
return t('search.dashboard-actions.import', 'Import');
}
export function getNewPhrase() {
return t('search.dashboard-actions.new', 'New');
}