2020-04-24 10:07:57 -05:00
|
|
|
import React, { FC } from 'react';
|
2020-04-24 12:23:45 -05:00
|
|
|
import { css } from 'emotion';
|
2020-04-24 03:08:06 -05:00
|
|
|
import { FixedSizeList } from 'react-window';
|
|
|
|
import AutoSizer from 'react-virtualized-auto-sizer';
|
2020-03-26 04:09:08 -05:00
|
|
|
import { GrafanaTheme } from '@grafana/data';
|
2020-04-24 03:08:06 -05:00
|
|
|
import { stylesFactory, useTheme, Spinner } from '@grafana/ui';
|
2020-04-27 07:08:48 -05:00
|
|
|
import { DashboardSection, OnToggleChecked, SearchLayout, DashboardSearchHit } from '../types';
|
2020-04-24 12:23:45 -05:00
|
|
|
import { SEARCH_ITEM_HEIGHT, SEARCH_ITEM_MARGIN } from '../constants';
|
2020-03-26 04:09:08 -05:00
|
|
|
import { SearchItem } from './SearchItem';
|
2020-04-24 03:08:06 -05:00
|
|
|
import { SectionHeader } from './SectionHeader';
|
2020-03-26 04:09:08 -05:00
|
|
|
|
|
|
|
export interface Props {
|
2020-04-08 10:14:03 -05:00
|
|
|
editable?: boolean;
|
|
|
|
loading?: boolean;
|
2020-03-26 04:09:08 -05:00
|
|
|
onTagSelected: (name: string) => any;
|
2020-04-17 07:29:20 -05:00
|
|
|
onToggleChecked?: OnToggleChecked;
|
|
|
|
onToggleSection: (section: DashboardSection) => void;
|
2020-04-27 07:08:48 -05:00
|
|
|
results: DashboardSearchHit[];
|
2020-04-23 00:18:53 -05:00
|
|
|
layout?: string;
|
2020-03-26 04:09:08 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
export const SearchResults: FC<Props> = ({
|
2020-04-08 10:14:03 -05:00
|
|
|
editable,
|
|
|
|
loading,
|
2020-03-26 04:09:08 -05:00
|
|
|
onTagSelected,
|
2020-04-17 07:29:20 -05:00
|
|
|
onToggleChecked,
|
2020-04-08 10:14:03 -05:00
|
|
|
onToggleSection,
|
|
|
|
results,
|
2020-04-23 00:18:53 -05:00
|
|
|
layout,
|
2020-03-26 04:09:08 -05:00
|
|
|
}) => {
|
|
|
|
const theme = useTheme();
|
|
|
|
const styles = getSectionStyles(theme);
|
2020-04-24 03:08:06 -05:00
|
|
|
const itemProps = { editable, onToggleChecked, onTagSelected };
|
|
|
|
const renderFolders = () => {
|
|
|
|
return (
|
2020-04-24 12:23:45 -05:00
|
|
|
<div className={styles.wrapper}>
|
2020-04-24 03:08:06 -05:00
|
|
|
{results.map(section => {
|
|
|
|
return (
|
2020-04-28 07:31:11 -05:00
|
|
|
<div aria-label="Search section" className={styles.section} key={section.id || section.title}>
|
2020-04-24 03:08:06 -05:00
|
|
|
<SectionHeader onSectionClick={onToggleSection} {...{ onToggleChecked, editable, section }} />
|
2020-04-24 12:23:45 -05:00
|
|
|
<div aria-label="Search items" className={styles.sectionItems}>
|
2020-04-24 03:08:06 -05:00
|
|
|
{section.expanded && section.items.map(item => <SearchItem key={item.id} {...itemProps} item={item} />)}
|
2020-04-24 12:23:45 -05:00
|
|
|
</div>
|
|
|
|
</div>
|
2020-04-24 03:08:06 -05:00
|
|
|
);
|
|
|
|
})}
|
2020-04-24 12:23:45 -05:00
|
|
|
</div>
|
2020-04-24 03:08:06 -05:00
|
|
|
);
|
|
|
|
};
|
2020-04-23 00:18:53 -05:00
|
|
|
|
2020-04-24 03:08:06 -05:00
|
|
|
const renderDashboards = () => {
|
|
|
|
return (
|
2020-04-24 12:23:45 -05:00
|
|
|
<div className={styles.listModeWrapper}>
|
|
|
|
<AutoSizer disableWidth>
|
|
|
|
{({ height }) => (
|
|
|
|
<FixedSizeList
|
|
|
|
aria-label="Search items"
|
|
|
|
className={styles.wrapper}
|
|
|
|
innerElementType="ul"
|
|
|
|
itemSize={SEARCH_ITEM_HEIGHT + SEARCH_ITEM_MARGIN}
|
|
|
|
height={height}
|
2020-04-27 07:08:48 -05:00
|
|
|
itemCount={results.length}
|
2020-04-24 12:23:45 -05:00
|
|
|
width="100%"
|
|
|
|
>
|
|
|
|
{({ index, style }) => {
|
2020-04-27 07:08:48 -05:00
|
|
|
const item = results[index];
|
2020-04-25 06:08:23 -05:00
|
|
|
// The wrapper div is needed as the inner SearchItem has margin-bottom spacing
|
|
|
|
// And without this wrapper there is no room for that margin
|
|
|
|
return (
|
|
|
|
<div style={style}>
|
|
|
|
<SearchItem key={item.id} {...itemProps} item={item} />
|
|
|
|
</div>
|
|
|
|
);
|
2020-04-24 12:23:45 -05:00
|
|
|
}}
|
|
|
|
</FixedSizeList>
|
|
|
|
)}
|
|
|
|
</AutoSizer>
|
|
|
|
</div>
|
2020-04-24 03:08:06 -05:00
|
|
|
);
|
2020-04-23 00:18:53 -05:00
|
|
|
};
|
|
|
|
|
2020-04-08 10:14:03 -05:00
|
|
|
if (loading) {
|
2020-04-17 07:29:20 -05:00
|
|
|
return <Spinner className={styles.spinner} />;
|
2020-04-08 10:14:03 -05:00
|
|
|
} else if (!results || !results.length) {
|
2020-04-25 06:08:23 -05:00
|
|
|
return <div className={styles.noResults}>No dashboards matching your query were found.</div>;
|
2020-03-26 04:09:08 -05:00
|
|
|
}
|
2020-04-24 12:23:45 -05:00
|
|
|
|
2020-03-26 04:09:08 -05:00
|
|
|
return (
|
2020-04-27 07:08:48 -05:00
|
|
|
<div className={styles.resultsContainer}>
|
|
|
|
{layout === SearchLayout.Folders ? renderFolders() : renderDashboards()}
|
|
|
|
</div>
|
2020-03-26 04:09:08 -05:00
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
const getSectionStyles = stylesFactory((theme: GrafanaTheme) => {
|
2020-04-24 12:23:45 -05:00
|
|
|
const { md } = theme.spacing;
|
|
|
|
|
2020-03-26 04:09:08 -05:00
|
|
|
return {
|
|
|
|
wrapper: css`
|
2020-04-24 12:23:45 -05:00
|
|
|
display: flex;
|
|
|
|
flex-direction: column;
|
2020-03-26 04:09:08 -05:00
|
|
|
`,
|
|
|
|
section: css`
|
2020-04-24 12:23:45 -05:00
|
|
|
display: flex;
|
|
|
|
flex-direction: column;
|
2020-03-26 04:09:08 -05:00
|
|
|
background: ${theme.colors.panelBg};
|
2020-04-24 12:23:45 -05:00
|
|
|
border-bottom: solid 1px ${theme.colors.border2};
|
|
|
|
`,
|
|
|
|
sectionItems: css`
|
|
|
|
margin: 0 24px 0 32px;
|
2020-03-26 04:09:08 -05:00
|
|
|
`,
|
2020-04-17 07:29:20 -05:00
|
|
|
spinner: css`
|
|
|
|
display: flex;
|
|
|
|
justify-content: center;
|
|
|
|
align-items: center;
|
|
|
|
min-height: 100px;
|
|
|
|
`,
|
2020-04-24 03:08:06 -05:00
|
|
|
resultsContainer: css`
|
|
|
|
position: relative;
|
|
|
|
flex-grow: 10;
|
|
|
|
margin-bottom: ${md};
|
2020-04-24 12:23:45 -05:00
|
|
|
background: ${theme.colors.bg1};
|
|
|
|
border: 1px solid ${theme.colors.border1};
|
2020-04-24 03:08:06 -05:00
|
|
|
border-radius: 3px;
|
|
|
|
height: 100%;
|
2020-04-14 08:15:36 -05:00
|
|
|
`,
|
2020-04-25 06:08:23 -05:00
|
|
|
noResults: css`
|
|
|
|
padding: ${md};
|
|
|
|
background: ${theme.colors.bg2};
|
2020-04-27 11:16:03 -05:00
|
|
|
font-style: italic;
|
|
|
|
margin-top: ${theme.spacing.md};
|
2020-04-25 06:08:23 -05:00
|
|
|
`,
|
2020-04-24 12:23:45 -05:00
|
|
|
listModeWrapper: css`
|
|
|
|
position: relative;
|
|
|
|
height: 100%;
|
|
|
|
padding: ${md};
|
|
|
|
`,
|
2020-03-26 04:09:08 -05:00
|
|
|
};
|
|
|
|
});
|