mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Page: Add inline rename functionality (#68828)
* initial attempt at inline rename * handle version correctly * refactor * minor tweaks * add unit tests * prettier... * add to other tabs, remove settings tab when feature toggle is enabled * fix truncation * allow title to span full width of page * fix h1 styling when no renderTitle/onEditTitle is present * better layout * use input from grafana/ui, fix imports * fix unit test * better error handling * don't use autosavefield * undo changes to AutoSaveField * remove timeout * remove maxWidth now we're not using AutoSaveField * rename isEditInProgress to isLoading * sync localValue with value * better responsive css
This commit is contained in:
@@ -12,7 +12,7 @@ import { buildNavModel, getDashboardsTabID } from '../folders/state/navModel';
|
||||
import { useSearchStateManager } from '../search/state/SearchStateManager';
|
||||
import { getSearchPlaceholder } from '../search/tempI18nPhrases';
|
||||
|
||||
import { skipToken, useGetFolderQuery } from './api/browseDashboardsAPI';
|
||||
import { skipToken, useGetFolderQuery, useSaveFolderMutation } from './api/browseDashboardsAPI';
|
||||
import { BrowseActions } from './components/BrowseActions/BrowseActions';
|
||||
import { BrowseFilters } from './components/BrowseFilters';
|
||||
import { BrowseView } from './components/BrowseView';
|
||||
@@ -59,6 +59,7 @@ const BrowseDashboardsPage = memo(({ match }: Props) => {
|
||||
}, [isSearching, searchState.result, stateManager]);
|
||||
|
||||
const { data: folderDTO } = useGetFolderQuery(folderUID ?? skipToken);
|
||||
const [saveFolder] = useSaveFolderMutation();
|
||||
const navModel = useMemo(() => {
|
||||
if (!folderDTO) {
|
||||
return undefined;
|
||||
@@ -78,10 +79,25 @@ const BrowseDashboardsPage = memo(({ match }: Props) => {
|
||||
|
||||
const { canEditInFolder, canCreateDashboards, canCreateFolder } = getFolderPermissions(folderDTO);
|
||||
|
||||
const onEditTitle = folderUID
|
||||
? async (newValue: string) => {
|
||||
if (folderDTO) {
|
||||
const result = await saveFolder({
|
||||
...folderDTO,
|
||||
title: newValue,
|
||||
});
|
||||
if ('error' in result) {
|
||||
throw result.error;
|
||||
}
|
||||
}
|
||||
}
|
||||
: undefined;
|
||||
|
||||
return (
|
||||
<Page
|
||||
navId="dashboards/browse"
|
||||
pageNav={navModel}
|
||||
onEditTitle={onEditTitle}
|
||||
actions={
|
||||
<>
|
||||
{folderDTO && <FolderActionsButton folder={folderDTO} />}
|
||||
|
||||
@@ -7,15 +7,16 @@ import { useSelector } from 'app/types';
|
||||
|
||||
import { AlertsFolderView } from '../alerting/unified/AlertsFolderView';
|
||||
|
||||
import { useGetFolderQuery } from './api/browseDashboardsAPI';
|
||||
import { useGetFolderQuery, useSaveFolderMutation } from './api/browseDashboardsAPI';
|
||||
import { FolderActionsButton } from './components/FolderActionsButton';
|
||||
|
||||
export interface OwnProps extends GrafanaRouteComponentProps<{ uid: string }> {}
|
||||
|
||||
export function BrowseFolderAlertingPage({ match }: OwnProps) {
|
||||
const { uid: folderUID } = match.params;
|
||||
const { data: folderDTO, isLoading } = useGetFolderQuery(folderUID);
|
||||
const { data: folderDTO } = useGetFolderQuery(folderUID);
|
||||
const folder = useSelector((state) => state.folder);
|
||||
const [saveFolder] = useSaveFolderMutation();
|
||||
|
||||
const navModel = useMemo(() => {
|
||||
if (!folderDTO) {
|
||||
@@ -32,13 +33,28 @@ export function BrowseFolderAlertingPage({ match }: OwnProps) {
|
||||
return model;
|
||||
}, [folderDTO]);
|
||||
|
||||
const onEditTitle = folderUID
|
||||
? async (newValue: string) => {
|
||||
if (folderDTO) {
|
||||
const result = await saveFolder({
|
||||
...folderDTO,
|
||||
title: newValue,
|
||||
});
|
||||
if ('error' in result) {
|
||||
throw result.error;
|
||||
}
|
||||
}
|
||||
}
|
||||
: undefined;
|
||||
|
||||
return (
|
||||
<Page
|
||||
navId="dashboards/browse"
|
||||
pageNav={navModel}
|
||||
onEditTitle={onEditTitle}
|
||||
actions={<>{folderDTO && <FolderActionsButton folder={folderDTO} />}</>}
|
||||
>
|
||||
<Page.Contents isLoading={isLoading}>
|
||||
<Page.Contents>
|
||||
<AlertsFolderView folder={folder} />
|
||||
</Page.Contents>
|
||||
</Page>
|
||||
|
||||
@@ -9,14 +9,15 @@ import { LibraryPanelsSearch } from '../library-panels/components/LibraryPanelsS
|
||||
import { OpenLibraryPanelModal } from '../library-panels/components/OpenLibraryPanelModal/OpenLibraryPanelModal';
|
||||
import { LibraryElementDTO } from '../library-panels/types';
|
||||
|
||||
import { useGetFolderQuery } from './api/browseDashboardsAPI';
|
||||
import { useGetFolderQuery, useSaveFolderMutation } from './api/browseDashboardsAPI';
|
||||
|
||||
export interface OwnProps extends GrafanaRouteComponentProps<{ uid: string }> {}
|
||||
|
||||
export function BrowseFolderLibraryPanelsPage({ match }: OwnProps) {
|
||||
const { uid: folderUID } = match.params;
|
||||
const { data: folderDTO, isLoading } = useGetFolderQuery(folderUID);
|
||||
const { data: folderDTO } = useGetFolderQuery(folderUID);
|
||||
const [selected, setSelected] = useState<LibraryElementDTO | undefined>(undefined);
|
||||
const [saveFolder] = useSaveFolderMutation();
|
||||
|
||||
const navModel = useMemo(() => {
|
||||
if (!folderDTO) {
|
||||
@@ -33,13 +34,28 @@ export function BrowseFolderLibraryPanelsPage({ match }: OwnProps) {
|
||||
return model;
|
||||
}, [folderDTO]);
|
||||
|
||||
const onEditTitle = folderUID
|
||||
? async (newValue: string) => {
|
||||
if (folderDTO) {
|
||||
const result = await saveFolder({
|
||||
...folderDTO,
|
||||
title: newValue,
|
||||
});
|
||||
if ('error' in result) {
|
||||
throw result.error;
|
||||
}
|
||||
}
|
||||
}
|
||||
: undefined;
|
||||
|
||||
return (
|
||||
<Page
|
||||
navId="dashboards/browse"
|
||||
pageNav={navModel}
|
||||
onEditTitle={onEditTitle}
|
||||
actions={<>{folderDTO && <FolderActionsButton folder={folderDTO} />}</>}
|
||||
>
|
||||
<Page.Contents isLoading={isLoading}>
|
||||
<Page.Contents>
|
||||
<LibraryPanelsSearch
|
||||
onClick={setSelected}
|
||||
currentFolderUID={folderUID}
|
||||
|
||||
@@ -40,6 +40,18 @@ export const browseDashboardsAPI = createApi({
|
||||
query: (folderUID) => ({ url: `/folders/${folderUID}`, params: { accesscontrol: true } }),
|
||||
providesTags: (_result, _error, arg) => [{ type: 'getFolder', id: arg }],
|
||||
}),
|
||||
saveFolder: builder.mutation<FolderDTO, FolderDTO>({
|
||||
invalidatesTags: (_result, _error, args) => [{ type: 'getFolder', id: args.uid }],
|
||||
query: (folder) => ({
|
||||
method: 'PUT',
|
||||
showErrorAlert: false,
|
||||
url: `/folders/${folder.uid}`,
|
||||
data: {
|
||||
title: folder.title,
|
||||
version: folder.version,
|
||||
},
|
||||
}),
|
||||
}),
|
||||
getAffectedItems: builder.query<DescendantCount, DashboardTreeSelection>({
|
||||
queryFn: async (selectedItems) => {
|
||||
const folderUIDs = Object.keys(selectedItems.folder).filter((uid) => selectedItems.folder[uid]);
|
||||
@@ -80,5 +92,6 @@ export const browseDashboardsAPI = createApi({
|
||||
}),
|
||||
});
|
||||
|
||||
export const { endpoints, useGetAffectedItemsQuery, useGetFolderQuery, useMoveFolderMutation } = browseDashboardsAPI;
|
||||
export const { endpoints, useGetAffectedItemsQuery, useGetFolderQuery, useMoveFolderMutation, useSaveFolderMutation } =
|
||||
browseDashboardsAPI;
|
||||
export { skipToken } from '@reduxjs/toolkit/query/react';
|
||||
|
||||
@@ -63,16 +63,16 @@ export function buildNavModel(folder: FolderDTO, parents = folder.parents): NavM
|
||||
url: `${folder.url}/permissions`,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (folder.canSave) {
|
||||
model.children!.push({
|
||||
active: false,
|
||||
icon: 'cog',
|
||||
id: getSettingsTabID(folder.uid),
|
||||
text: 'Settings',
|
||||
url: `${folder.url}/settings`,
|
||||
});
|
||||
if (folder.canSave) {
|
||||
model.children!.push({
|
||||
active: false,
|
||||
icon: 'cog',
|
||||
id: getSettingsTabID(folder.uid),
|
||||
text: 'Settings',
|
||||
url: `${folder.url}/settings`,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return model;
|
||||
|
||||
Reference in New Issue
Block a user