grafana/public/app/features/search/components/ManageDashboards.tsx
Alex Khomenko 531e658123
Search: support URL query params (#25541)
* Search: connect DashboardSearch

* Search: set url params

* Search: handle tag params

* Search: handle sort params

* Search: use getLocationQuery

* Search: fix type errors

* Docs: Save query params for manage dashboards

* Search: extract connect

* Search: add layout to URL params

* Search: update options

* Search: simplify options loading

* Search: Fix strict null errors

* Search: Change params order

* Search: Add tests

* Search: handle folder query
2020-06-16 11:52:10 +03:00

174 lines
5.1 KiB
TypeScript

import React, { FC, memo, useState } from 'react';
import { css } from 'emotion';
import { HorizontalGroup, stylesFactory, useTheme, Spinner } from '@grafana/ui';
import { GrafanaTheme } from '@grafana/data';
import { contextSrv } from 'app/core/services/context_srv';
import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA';
import { FilterInput } from 'app/core/components/FilterInput/FilterInput';
import { FolderDTO } from 'app/types';
import { useManageDashboards } from '../hooks/useManageDashboards';
import { SearchLayout } from '../types';
import { ConfirmDeleteModal } from './ConfirmDeleteModal';
import { MoveToFolderModal } from './MoveToFolderModal';
import { useSearchQuery } from '../hooks/useSearchQuery';
import { SearchResultsFilter } from './SearchResultsFilter';
import { SearchResults } from './SearchResults';
import { DashboardActions } from './DashboardActions';
import { connectWithRouteParams, ConnectProps, DispatchProps } from '../connect';
export interface Props {
folder?: FolderDTO;
}
const { isEditor } = contextSrv;
export const ManageDashboards: FC<Props & ConnectProps & DispatchProps> = memo(({ folder, params, updateLocation }) => {
const folderId = folder?.id;
const folderUid = folder?.uid;
const theme = useTheme();
const styles = getStyles(theme);
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
const [isMoveModalOpen, setIsMoveModalOpen] = useState(false);
const defaultLayout = folderId ? SearchLayout.List : SearchLayout.Folders;
const queryParams = {
skipRecent: true,
skipStarred: true,
folderIds: folderId ? [folderId] : [],
layout: defaultLayout,
...params,
};
const {
query,
hasFilters,
onQueryChange,
onTagFilterChange,
onStarredFilterChange,
onTagAdd,
onSortChange,
onLayoutChange,
} = useSearchQuery(queryParams, updateLocation);
const {
results,
loading,
initialLoading,
canSave,
allChecked,
hasEditPermissionInFolders,
canMove,
canDelete,
onToggleSection,
onToggleChecked,
onToggleAllChecked,
onDeleteItems,
onMoveItems,
noFolders,
} = useManageDashboards(query, {}, folder);
const onMoveTo = () => {
setIsMoveModalOpen(true);
};
const onItemDelete = () => {
setIsDeleteModalOpen(true);
};
if (initialLoading) {
return <Spinner className={styles.spinner} />;
}
if (noFolders && !hasFilters) {
return (
<EmptyListCTA
title="This folder doesn't have any dashboards yet"
buttonIcon="plus"
buttonTitle="Create Dashboard"
buttonLink={`dashboard/new?folderId=${folderId}`}
proTip="Add/move dashboards to your folder at ->"
proTipLink="dashboards"
proTipLinkTitle="Manage dashboards"
proTipTarget=""
/>
);
}
return (
<div className={styles.container}>
<div>
<HorizontalGroup justify="space-between">
<FilterInput
labelClassName="gf-form--has-input-icon"
inputClassName="gf-form-input width-20"
value={query.query}
onChange={onQueryChange}
placeholder={'Search dashboards by name'}
/>
<DashboardActions isEditor={isEditor} canEdit={hasEditPermissionInFolders || canSave} folderId={folderId} />
</HorizontalGroup>
</div>
<div className={styles.results}>
<SearchResultsFilter
allChecked={allChecked}
canDelete={hasEditPermissionInFolders && canDelete}
canMove={hasEditPermissionInFolders && canMove}
deleteItem={onItemDelete}
moveTo={onMoveTo}
onToggleAllChecked={onToggleAllChecked}
onStarredFilterChange={onStarredFilterChange}
onSortChange={onSortChange}
onTagFilterChange={onTagFilterChange}
query={query}
hideLayout={!!folderUid}
onLayoutChange={onLayoutChange}
editable={hasEditPermissionInFolders}
/>
<SearchResults
loading={loading}
results={results}
editable={hasEditPermissionInFolders}
onTagSelected={onTagAdd}
onToggleSection={onToggleSection}
onToggleChecked={onToggleChecked}
layout={query.layout}
/>
</div>
<ConfirmDeleteModal
onDeleteItems={onDeleteItems}
results={results}
isOpen={isDeleteModalOpen}
onDismiss={() => setIsDeleteModalOpen(false)}
/>
<MoveToFolderModal
onMoveItems={onMoveItems}
results={results}
isOpen={isMoveModalOpen}
onDismiss={() => setIsMoveModalOpen(false)}
/>
</div>
);
});
export default connectWithRouteParams(ManageDashboards);
const getStyles = stylesFactory((theme: GrafanaTheme) => {
return {
container: css`
height: 100%;
`,
results: css`
display: flex;
flex-direction: column;
flex: 1;
height: 100%;
margin-top: ${theme.spacing.xl};
`,
spinner: css`
display: flex;
justify-content: center;
align-items: center;
min-height: 200px;
`,
};
});