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