LibraryPanelsSearch.tsx 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. import { css } from '@emotion/css';
  2. import React, { useReducer } from 'react';
  3. import { GrafanaTheme2, PanelPluginMeta, SelectableValue } from '@grafana/data';
  4. import { HorizontalGroup, useStyles2, VerticalGroup, FilterInput } from '@grafana/ui';
  5. import { FolderFilter } from '../../../../core/components/FolderFilter/FolderFilter';
  6. import { PanelTypeFilter } from '../../../../core/components/PanelTypeFilter/PanelTypeFilter';
  7. import { SortPicker } from '../../../../core/components/Select/SortPicker';
  8. import { DEFAULT_PER_PAGE_PAGINATION } from '../../../../core/constants';
  9. import { FolderInfo } from '../../../../types';
  10. import { LibraryElementDTO } from '../../types';
  11. import { LibraryPanelsView } from '../LibraryPanelsView/LibraryPanelsView';
  12. import {
  13. folderFilterChanged,
  14. initialLibraryPanelsSearchState,
  15. libraryPanelsSearchReducer,
  16. panelFilterChanged,
  17. searchChanged,
  18. sortChanged,
  19. } from './reducer';
  20. export enum LibraryPanelsSearchVariant {
  21. Tight = 'tight',
  22. Spacious = 'spacious',
  23. }
  24. export interface LibraryPanelsSearchProps {
  25. onClick: (panel: LibraryElementDTO) => void;
  26. variant?: LibraryPanelsSearchVariant;
  27. showSort?: boolean;
  28. showPanelFilter?: boolean;
  29. showFolderFilter?: boolean;
  30. showSecondaryActions?: boolean;
  31. currentPanelId?: string;
  32. currentFolderId?: number;
  33. perPage?: number;
  34. }
  35. export const LibraryPanelsSearch = ({
  36. onClick,
  37. variant = LibraryPanelsSearchVariant.Spacious,
  38. currentPanelId,
  39. currentFolderId,
  40. perPage = DEFAULT_PER_PAGE_PAGINATION,
  41. showPanelFilter = false,
  42. showFolderFilter = false,
  43. showSort = false,
  44. showSecondaryActions = false,
  45. }: LibraryPanelsSearchProps): JSX.Element => {
  46. const styles = useStyles2(getStyles);
  47. const [{ sortDirection, panelFilter, folderFilter, searchQuery }, dispatch] = useReducer(libraryPanelsSearchReducer, {
  48. ...initialLibraryPanelsSearchState,
  49. folderFilter: currentFolderId ? [currentFolderId.toString(10)] : [],
  50. });
  51. const onFilterChange = (searchString: string) => dispatch(searchChanged(searchString));
  52. const onSortChange = (sorting: SelectableValue<string>) => dispatch(sortChanged(sorting));
  53. const onFolderFilterChange = (folders: FolderInfo[]) => dispatch(folderFilterChanged(folders));
  54. const onPanelFilterChange = (plugins: PanelPluginMeta[]) => dispatch(panelFilterChanged(plugins));
  55. if (variant === LibraryPanelsSearchVariant.Spacious) {
  56. return (
  57. <div className={styles.container}>
  58. <VerticalGroup spacing="lg">
  59. <FilterInput
  60. value={searchQuery}
  61. onChange={onFilterChange}
  62. placeholder={'Search by name or description'}
  63. width={0}
  64. />
  65. <div className={styles.buttonRow}>
  66. <HorizontalGroup
  67. spacing="sm"
  68. justify={(showSort && showPanelFilter) || showFolderFilter ? 'space-between' : 'flex-end'}
  69. >
  70. {showSort && (
  71. <SortPicker value={sortDirection} onChange={onSortChange} filter={['alpha-asc', 'alpha-desc']} />
  72. )}
  73. <HorizontalGroup
  74. spacing="sm"
  75. justify={showFolderFilter && showPanelFilter ? 'space-between' : 'flex-end'}
  76. >
  77. {showFolderFilter && <FolderFilter onChange={onFolderFilterChange} />}
  78. {showPanelFilter && <PanelTypeFilter onChange={onPanelFilterChange} />}
  79. </HorizontalGroup>
  80. </HorizontalGroup>
  81. </div>
  82. <div className={styles.libraryPanelsView}>
  83. <LibraryPanelsView
  84. onClickCard={onClick}
  85. searchString={searchQuery}
  86. sortDirection={sortDirection}
  87. panelFilter={panelFilter}
  88. folderFilter={folderFilter}
  89. currentPanelId={currentPanelId}
  90. showSecondaryActions={showSecondaryActions}
  91. perPage={perPage}
  92. />
  93. </div>
  94. </VerticalGroup>
  95. </div>
  96. );
  97. }
  98. return (
  99. <div className={styles.container}>
  100. <VerticalGroup spacing="xs">
  101. <div className={styles.tightButtonRow}>
  102. <div className={styles.tightFilter}>
  103. <FilterInput value={searchQuery} onChange={onFilterChange} placeholder={'Search by name'} width={0} />
  104. </div>
  105. <div className={styles.tightSortFilter}>
  106. {showSort && <SortPicker value={sortDirection} onChange={onSortChange} />}
  107. {showFolderFilter && <FolderFilter onChange={onFolderFilterChange} maxMenuHeight={200} />}
  108. {showPanelFilter && <PanelTypeFilter onChange={onPanelFilterChange} maxMenuHeight={200} />}
  109. </div>
  110. </div>
  111. <div className={styles.libraryPanelsView}>
  112. <LibraryPanelsView
  113. onClickCard={onClick}
  114. searchString={searchQuery}
  115. sortDirection={sortDirection}
  116. panelFilter={panelFilter}
  117. folderFilter={folderFilter}
  118. currentPanelId={currentPanelId}
  119. showSecondaryActions={showSecondaryActions}
  120. perPage={perPage}
  121. />
  122. </div>
  123. </VerticalGroup>
  124. </div>
  125. );
  126. };
  127. function getStyles(theme: GrafanaTheme2) {
  128. return {
  129. container: css`
  130. width: 100%;
  131. overflow-y: auto;
  132. padding: ${theme.spacing(1)};
  133. `,
  134. buttonRow: css`
  135. display: flex;
  136. justify-content: space-between;
  137. width: 100%;
  138. margin-top: ${theme.spacing(2)}; // Clear types link
  139. `,
  140. tightButtonRow: css`
  141. display: flex;
  142. justify-content: space-between;
  143. width: 100%;
  144. margin-top: ${theme.spacing(4)}; // Clear types link
  145. `,
  146. tightFilter: css`
  147. flex-grow: 1;
  148. `,
  149. tightSortFilter: css`
  150. flex-grow: 1;
  151. padding: ${theme.spacing(0, 0, 0, 0.5)};
  152. `,
  153. libraryPanelsView: css`
  154. width: 100%;
  155. `,
  156. };
  157. }