mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
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:
parent
f28c962dc8
commit
4b047b62a7
@ -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)}
|
||||
|
@ -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');
|
||||
});
|
||||
});
|
@ -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;
|
||||
}
|
@ -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>
|
||||
|
@ -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');
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user