Search: Add ManageDashboardNew to integrate new search (#49266)

* Search: created ManageDashboardNew to integrate new search

* hide pseudo folders in ManageDashboardNew

* ManageDashboardNew - Fix overflow table

Co-authored-by: Ryan McKinley <ryantxu@gmail.com>
This commit is contained in:
Maria Alexandra 2022-05-23 15:03:05 +02:00 committed by GitHub
parent 9e5292d32d
commit 84a8a1aaa6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 138 additions and 19 deletions

View File

@ -1,9 +1,10 @@
import { css } from '@emotion/css';
import React, { FC, memo } from 'react';
import { connect, MapStateToProps } from 'react-redux';
import { useAsync } from 'react-use';
import { NavModel, locationUtil } from '@grafana/data';
import { locationService } from '@grafana/runtime';
import { config, locationService } from '@grafana/runtime';
import Page from 'app/core/components/Page/Page';
import { getNavModel } from 'app/core/selectors/navModel';
import { FolderDTO, StoreState } from 'app/types';
@ -12,6 +13,7 @@ import { GrafanaRouteComponentProps } from '../../../core/navigation/types';
import { loadFolderPage } from '../loaders';
import ManageDashboards from './ManageDashboards';
import ManageDashboardsNew from './ManageDashboardsNew';
export interface DashboardListPageRouteParams {
uid?: string;
@ -44,9 +46,23 @@ export const DashboardListPage: FC<Props> = memo(({ navModel, match, location })
return (
<Page navModel={value?.pageNavModel ?? navModel}>
<Page.Contents isLoading={loading}>
<ManageDashboards folder={value?.folder} />
</Page.Contents>
{/*Todo: remove the false to test, or when we feel confident with thsi approach */}
{false && config.featureToggles.panelTitleSearch ? (
<Page.Contents
isLoading={loading}
className={css`
display: flex;
flex-direction: column;
overflow: hidden;
`}
>
<ManageDashboardsNew folder={value?.folder} />
</Page.Contents>
) : (
<Page.Contents isLoading={loading}>
<ManageDashboards folder={value?.folder} />
</Page.Contents>
)}
</Page>
);
});

View File

@ -0,0 +1,89 @@
import { css } from '@emotion/css';
import React, { useState } from 'react';
import { useDebounce } from 'react-use';
import { GrafanaTheme2 } from '@grafana/data';
import { Input, useStyles2, Spinner } from '@grafana/ui';
import { contextSrv } from 'app/core/services/context_srv';
import { FolderDTO } from 'app/types';
import { useSearchQuery } from '../hooks/useSearchQuery';
import { SearchView } from '../page/components/SearchView';
import { DashboardActions } from './DashboardActions';
export interface Props {
folder?: FolderDTO;
}
export const ManageDashboardsNew = React.memo(({ folder }: Props) => {
const styles = useStyles2(getStyles);
// since we don't use "query" from use search... it is not actually loaded from the URL!
const { query, onQueryChange } = useSearchQuery({});
// TODO: we need to refactor DashboardActions to use folder.uid instead
const folderId = folder?.id;
// const folderUid = folder?.uid;
const canSave = folder?.canSave;
const hasEditPermissionInFolders = folder ? canSave : contextSrv.hasEditPermissionInFolders;
const { isEditor } = contextSrv;
const [inputValue, setInputValue] = useState(query.query ?? '');
const onSearchQueryChange = (e: React.ChangeEvent<HTMLInputElement>) => {
e.preventDefault();
setInputValue(e.currentTarget.value);
};
useDebounce(() => onQueryChange(inputValue), 200, [inputValue]);
return (
<>
<div className="page-action-bar">
<div className="gf-form gf-form--grow m-r-2">
<Input
value={inputValue}
onChange={onSearchQueryChange}
autoFocus
spellCheck={false}
placeholder="Search for dashboards and panels"
className={styles.searchInput}
suffix={false ? <Spinner /> : null}
/>
</div>
<DashboardActions isEditor={isEditor} canEdit={hasEditPermissionInFolders || canSave} folderId={folderId} />
</div>
<SearchView
showManage={isEditor || hasEditPermissionInFolders || canSave}
folderDTO={folder}
queryText={query.query}
hidePseudoFolders={true}
/>
</>
);
});
ManageDashboardsNew.displayName = 'ManageDashboardsNew';
export default ManageDashboardsNew;
const getStyles = (theme: GrafanaTheme2) => ({
searchInput: css`
margin-bottom: 6px;
min-height: ${theme.spacing(4)};
`,
unsupported: css`
padding: 10px;
display: flex;
align-items: center;
justify-content: center;
height: 100%;
font-size: 18px;
`,
noResults: css`
padding: ${theme.v1.spacing.md};
background: ${theme.v1.colors.bg2};
font-style: italic;
margin-top: ${theme.v1.spacing.md};
`,
});

View File

@ -21,6 +21,7 @@ export interface DashboardSection {
selected?: boolean; // not used ? keyboard
url?: string;
icon?: string;
itemsUIDs?: string[]; // for pseudo folders
}
interface SectionHeaderProps {
@ -57,12 +58,9 @@ export const FolderSection: FC<SectionHeaderProps> = ({
location: section.uid,
};
if (section.title === 'Starred') {
const stars = await getBackendSrv().get('api/user/stars');
if (stars.length > 0) {
query = {
uid: stars, // array of UIDs
};
}
query = {
uid: section.itemsUIDs, // array of UIDs
};
folderUid = undefined;
folderTitle = undefined;
} else if (section.title === 'Recent') {

View File

@ -4,6 +4,7 @@ import { useAsync } from 'react-use';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { getBackendSrv } from '@grafana/runtime';
import { Spinner, useStyles2 } from '@grafana/ui';
import { GENERAL_FOLDER_UID } from '../../constants';
@ -12,20 +13,28 @@ import { SearchResultsProps } from '../components/SearchResultsTable';
import { DashboardSection, FolderSection } from './FolderSection';
type Props = Pick<SearchResultsProps, 'selection' | 'selectionToggle' | 'onTagSelected'> & { tags?: string[] };
export const FolderView = ({ selection, selectionToggle, onTagSelected, tags }: Props) => {
type Props = Pick<SearchResultsProps, 'selection' | 'selectionToggle' | 'onTagSelected'> & {
tags?: string[];
hidePseudoFolders?: boolean;
};
export const FolderView = ({ selection, selectionToggle, onTagSelected, tags, hidePseudoFolders }: Props) => {
const styles = useStyles2(getStyles);
const results = useAsync(async () => {
const folders: DashboardSection[] = [];
if (!hidePseudoFolders) {
const stars = await getBackendSrv().get('api/user/stars');
if (stars.length > 0) {
folders.push({ title: 'Starred', icon: 'star', kind: 'query-star', uid: '__starred', itemsUIDs: stars });
}
folders.push({ title: 'Recent', icon: 'clock', kind: 'query-recent', uid: '__recent' });
}
folders.push({ title: 'General', url: '/dashboards', kind: 'folder', uid: GENERAL_FOLDER_UID });
const rsp = await getGrafanaSearcher().search({
query: '*',
kind: ['folder'],
});
const folders: DashboardSection[] = [
{ title: 'Recent', icon: 'clock', kind: 'query-recent', uid: '__recent' },
{ title: 'Starred', icon: 'star', kind: 'query-star', uid: '__starred' },
{ title: 'General', url: '/dashboards', kind: 'folder', uid: GENERAL_FOLDER_UID }, // not sure why this is not in the index
];
for (const row of rsp.view) {
folders.push({
title: row.name,

View File

@ -26,9 +26,10 @@ type SearchViewProps = {
queryText: string; // odd that it is not from query.query
showManage: boolean;
folderDTO?: FolderDTO;
hidePseudoFolders?: boolean; // Recent + starred
};
export const SearchView = ({ showManage, folderDTO, queryText }: SearchViewProps) => {
export const SearchView = ({ showManage, folderDTO, queryText, hidePseudoFolders }: SearchViewProps) => {
const styles = useStyles2(getStyles);
const { query, onQueryChange, onTagFilterChange, onTagAdd, onDatasourceChange, onSortChange, onLayoutChange } =
@ -132,7 +133,13 @@ export const SearchView = ({ showManage, folderDTO, queryText }: SearchViewProps
);
}
return (
<FolderView selection={selection} selectionToggle={toggleSelection} tags={query.tag} onTagSelected={onTagAdd} />
<FolderView
selection={selection}
selectionToggle={toggleSelection}
tags={query.tag}
onTagSelected={onTagAdd}
hidePseudoFolders={hidePseudoFolders}
/>
);
}