FolderView.tsx 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. import { css } from '@emotion/css';
  2. import React from 'react';
  3. import { useAsync } from 'react-use';
  4. import { GrafanaTheme2 } from '@grafana/data';
  5. import { selectors } from '@grafana/e2e-selectors';
  6. import { getBackendSrv } from '@grafana/runtime';
  7. import { Spinner, useStyles2 } from '@grafana/ui';
  8. import { contextSrv } from 'app/core/core';
  9. import impressionSrv from 'app/core/services/impression_srv';
  10. import { GENERAL_FOLDER_UID } from '../../constants';
  11. import { getGrafanaSearcher } from '../../service';
  12. import { SearchResultsProps } from '../components/SearchResultsTable';
  13. import { DashboardSection, FolderSection } from './FolderSection';
  14. type Props = Pick<SearchResultsProps, 'selection' | 'selectionToggle' | 'onTagSelected'> & {
  15. tags?: string[];
  16. hidePseudoFolders?: boolean;
  17. };
  18. export const FolderView = ({ selection, selectionToggle, onTagSelected, tags, hidePseudoFolders }: Props) => {
  19. const styles = useStyles2(getStyles);
  20. const results = useAsync(async () => {
  21. const folders: DashboardSection[] = [];
  22. if (!hidePseudoFolders) {
  23. if (contextSrv.isSignedIn) {
  24. const stars = await getBackendSrv().get('api/user/stars');
  25. if (stars.length > 0) {
  26. folders.push({ title: 'Starred', icon: 'star', kind: 'query-star', uid: '__starred', itemsUIDs: stars });
  27. }
  28. }
  29. const ids = impressionSrv.getDashboardOpened();
  30. if (ids.length) {
  31. const itemsUIDs = await getBackendSrv().get(`/api/dashboards/ids/${ids.slice(0, 30).join(',')}`);
  32. if (itemsUIDs.length) {
  33. folders.push({ title: 'Recent', icon: 'clock', kind: 'query-recent', uid: '__recent', itemsUIDs });
  34. }
  35. }
  36. }
  37. folders.push({ title: 'General', url: '/dashboards', kind: 'folder', uid: GENERAL_FOLDER_UID });
  38. const rsp = await getGrafanaSearcher().search({
  39. query: '*',
  40. kind: ['folder'],
  41. });
  42. for (const row of rsp.view) {
  43. folders.push({
  44. title: row.name,
  45. url: row.url,
  46. uid: row.uid,
  47. kind: row.kind,
  48. });
  49. }
  50. return folders;
  51. }, []);
  52. if (results.loading) {
  53. return <Spinner />;
  54. }
  55. if (!results.value) {
  56. return <div>?</div>;
  57. }
  58. return (
  59. <div className={styles.wrapper}>
  60. {results.value.map((section) => {
  61. return (
  62. <div data-testid={selectors.components.Search} className={styles.section} key={section.title}>
  63. {section.title && (
  64. <FolderSection
  65. selection={selection}
  66. selectionToggle={selectionToggle}
  67. onTagSelected={onTagSelected}
  68. section={section}
  69. tags={tags}
  70. />
  71. )}
  72. </div>
  73. );
  74. })}
  75. </div>
  76. );
  77. };
  78. const getStyles = (theme: GrafanaTheme2) => {
  79. const { md, sm } = theme.v1.spacing;
  80. return {
  81. virtualizedGridItemWrapper: css`
  82. padding: 4px;
  83. `,
  84. wrapper: css`
  85. display: flex;
  86. flex-direction: column;
  87. overflow: auto;
  88. > ul {
  89. list-style: none;
  90. }
  91. border: solid 1px ${theme.v1.colors.border2};
  92. `,
  93. section: css`
  94. display: flex;
  95. flex-direction: column;
  96. background: ${theme.v1.colors.panelBg};
  97. &:not(:last-child) {
  98. border-bottom: solid 1px ${theme.v1.colors.border2};
  99. }
  100. `,
  101. sectionItems: css`
  102. margin: 0 24px 0 32px;
  103. `,
  104. spinner: css`
  105. display: flex;
  106. justify-content: center;
  107. align-items: center;
  108. min-height: 100px;
  109. `,
  110. gridContainer: css`
  111. display: grid;
  112. gap: ${sm};
  113. grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  114. margin-bottom: ${md};
  115. `,
  116. resultsContainer: css`
  117. position: relative;
  118. flex-grow: 10;
  119. margin-bottom: ${md};
  120. background: ${theme.v1.colors.bg1};
  121. border: 1px solid ${theme.v1.colors.border1};
  122. border-radius: 3px;
  123. height: 100%;
  124. `,
  125. noResults: css`
  126. padding: ${md};
  127. background: ${theme.v1.colors.bg2};
  128. font-style: italic;
  129. margin-top: ${theme.v1.spacing.md};
  130. `,
  131. listModeWrapper: css`
  132. position: relative;
  133. height: 100%;
  134. padding: ${md};
  135. `,
  136. };
  137. };