Folder: Provide adhoc ui for nested folder creation (#59126)

chore: provide adhoc ui for nested folder creation
This commit is contained in:
Leo 2022-11-23 13:08:36 +01:00 committed by GitHub
parent 4e6b8f658e
commit 7d82a27835
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 54 additions and 47 deletions

View File

@ -1,10 +1,11 @@
import React, { PureComponent } from 'react'; import React from 'react';
import { connect, ConnectedProps } from 'react-redux'; import { connect, ConnectedProps } from 'react-redux';
import { NavModelItem } from '@grafana/data'; import { NavModelItem } from '@grafana/data';
import { config } from '@grafana/runtime'; import { config } from '@grafana/runtime';
import { Button, Input, Form, Field } from '@grafana/ui'; import { Button, Input, Form, Field } from '@grafana/ui';
import { Page } from 'app/core/components/Page/Page'; import { Page } from 'app/core/components/Page/Page';
import { useQueryParams } from 'app/core/hooks/useQueryParams';
import { validationSrv } from '../../manage-dashboards/services/ValidationSrv'; import { validationSrv } from '../../manage-dashboards/services/ValidationSrv';
import { createNewFolder } from '../state/actions'; import { createNewFolder } from '../state/actions';
@ -21,16 +22,22 @@ interface FormModel {
folderName: string; folderName: string;
} }
const initialFormModel: FormModel = { folderName: '' };
type Props = OwnProps & ConnectedProps<typeof connector>; type Props = OwnProps & ConnectedProps<typeof connector>;
export class NewDashboardsFolder extends PureComponent<Props> { const initialFormModel: FormModel = { folderName: '' };
onSubmit = (formData: FormModel) => {
this.props.createNewFolder(formData.folderName);
};
validateFolderName = (folderName: string) => { const pageNav: NavModelItem = {
text: 'Create a new folder',
subTitle: 'Folders provide a way to group dashboards and alert rules.',
breadcrumbs: [{ title: 'Dashboards', url: 'dashboards' }],
};
function NewDashboardsFolder({ createNewFolder }: Props) {
const [queryParams] = useQueryParams();
const onSubmit = (formData: FormModel) => {
createNewFolder(formData.folderName, String(queryParams['folderUid']));
};
const validateFolderName = (folderName: string) => {
return validationSrv return validationSrv
.validateNewFolderName(folderName) .validateNewFolderName(folderName)
.then(() => { .then(() => {
@ -41,41 +48,33 @@ export class NewDashboardsFolder extends PureComponent<Props> {
}); });
}; };
pageNav: NavModelItem = { return (
text: 'Create a new folder', <Page navId="dashboards/browse" pageNav={pageNav}>
subTitle: 'Folders provide a way to group dashboards and alert rules.', <Page.Contents>
breadcrumbs: [{ title: 'Dashboards', url: 'dashboards' }], {!config.featureToggles.topnav && <h3>New dashboard folder</h3>}
}; <Form defaultValues={initialFormModel} onSubmit={onSubmit}>
{({ register, errors }) => (
render() { <>
return ( <Field
<Page navId="dashboards/browse" pageNav={this.pageNav}> label="Folder name"
<Page.Contents> invalid={!!errors.folderName}
{!config.featureToggles.topnav && <h3>New dashboard folder</h3>} error={errors.folderName && errors.folderName.message}
<Form defaultValues={initialFormModel} onSubmit={this.onSubmit}> >
{({ register, errors }) => ( <Input
<> id="folder-name-input"
<Field {...register('folderName', {
label="Folder name" required: 'Folder name is required.',
invalid={!!errors.folderName} validate: async (v) => await validateFolderName(v),
error={errors.folderName && errors.folderName.message} })}
> />
<Input </Field>
id="folder-name-input" <Button type="submit">Create</Button>
{...register('folderName', { </>
required: 'Folder name is required.', )}
validate: async (v) => await this.validateFolderName(v), </Form>
})} </Page.Contents>
/> </Page>
</Field> );
<Button type="submit">Create</Button>
</>
)}
</Form>
</Page.Contents>
</Page>
);
}
} }
export default connector(NewDashboardsFolder); export default connector(NewDashboardsFolder);

View File

@ -143,9 +143,9 @@ export function addFolderPermission(newItem: NewDashboardAclItem): ThunkResult<v
}; };
} }
export function createNewFolder(folderName: string): ThunkResult<void> { export function createNewFolder(folderName: string, uid?: string): ThunkResult<void> {
return async (dispatch) => { return async (dispatch) => {
const newFolder = await getBackendSrv().post('/api/folders', { title: folderName }); const newFolder = await getBackendSrv().post('/api/folders', { title: folderName, parentUid: uid });
await contextSrv.fetchUserPermissions(); await contextSrv.fetchUserPermissions();
dispatch(notifyApp(createSuccessNotification('Folder Created', 'OK'))); dispatch(notifyApp(createSuccessNotification('Folder Created', 'OK')));
locationService.push(locationUtil.stripBaseFromUrl(newFolder.url)); locationService.push(locationUtil.stripBaseFromUrl(newFolder.url));

View File

@ -1,5 +1,6 @@
import React, { FC } from 'react'; import React, { FC } from 'react';
import { config } from '@grafana/runtime';
import { Menu, Dropdown, Button, Icon } from '@grafana/ui'; import { Menu, Dropdown, Button, Icon } from '@grafana/ui';
export interface Props { export interface Props {
@ -11,8 +12,13 @@ export interface Props {
export const DashboardActions: FC<Props> = ({ folderUid, canCreateFolders = false, canCreateDashboards = false }) => { export const DashboardActions: FC<Props> = ({ folderUid, canCreateFolders = false, canCreateDashboards = false }) => {
const actionUrl = (type: string) => { const actionUrl = (type: string) => {
let url = `dashboard/${type}`; let url = `dashboard/${type}`;
const isTypeNewFolder = type === 'new_folder';
if (folderUid) { if (isTypeNewFolder) {
url = `dashboards/folder/new/`;
}
if ((isTypeNewFolder && config.featureToggles.nestedFolders) || folderUid) {
url += `?folderUid=${folderUid}`; url += `?folderUid=${folderUid}`;
} }
@ -23,7 +29,9 @@ export const DashboardActions: FC<Props> = ({ folderUid, canCreateFolders = fals
return ( return (
<Menu> <Menu>
{canCreateDashboards && <Menu.Item url={actionUrl('new')} label="New Dashboard" />} {canCreateDashboards && <Menu.Item url={actionUrl('new')} label="New Dashboard" />}
{!folderUid && canCreateFolders && <Menu.Item url="dashboards/folder/new" label="New Folder" />} {canCreateFolders && (config.featureToggles.nestedFolders || !folderUid) && (
<Menu.Item url={actionUrl('new_folder')} label="New Folder" />
)}
{canCreateDashboards && <Menu.Item url={actionUrl('import')} label="Import" />} {canCreateDashboards && <Menu.Item url={actionUrl('import')} label="Import" />}
</Menu> </Menu>
); );