ManageDashboards.tsx 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. import { css } from '@emotion/css';
  2. import React, { FC, memo, useState } from 'react';
  3. import { GrafanaTheme } from '@grafana/data';
  4. import { FilterInput, Spinner, stylesFactory, useTheme } from '@grafana/ui';
  5. import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA';
  6. import { contextSrv } from 'app/core/services/context_srv';
  7. import { FolderDTO } from 'app/types';
  8. import { useManageDashboards } from '../hooks/useManageDashboards';
  9. import { useSearchQuery } from '../hooks/useSearchQuery';
  10. import { SearchLayout } from '../types';
  11. import { ConfirmDeleteModal } from './ConfirmDeleteModal';
  12. import { DashboardActions } from './DashboardActions';
  13. import { MoveToFolderModal } from './MoveToFolderModal';
  14. import { SearchResults } from './SearchResults';
  15. import { SearchResultsFilter } from './SearchResultsFilter';
  16. export interface Props {
  17. folder?: FolderDTO;
  18. }
  19. const { isEditor } = contextSrv;
  20. export const ManageDashboards: FC<Props> = memo(({ folder }) => {
  21. const folderId = folder?.id;
  22. const folderUid = folder?.uid;
  23. const theme = useTheme();
  24. const styles = getStyles(theme);
  25. const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
  26. const [isMoveModalOpen, setIsMoveModalOpen] = useState(false);
  27. const defaultLayout = folderId ? SearchLayout.List : SearchLayout.Folders;
  28. const queryParamsDefaults = {
  29. skipRecent: true,
  30. skipStarred: true,
  31. folderIds: folderId ? [folderId] : [],
  32. layout: defaultLayout,
  33. };
  34. const {
  35. query,
  36. hasFilters,
  37. onQueryChange,
  38. onTagFilterChange,
  39. onStarredFilterChange,
  40. onTagAdd,
  41. onSortChange,
  42. onLayoutChange,
  43. } = useSearchQuery(queryParamsDefaults);
  44. const {
  45. results,
  46. loading,
  47. initialLoading,
  48. canSave,
  49. allChecked,
  50. hasEditPermissionInFolders,
  51. canMove,
  52. canDelete,
  53. onToggleSection,
  54. onToggleChecked,
  55. onToggleAllChecked,
  56. onDeleteItems,
  57. onMoveItems,
  58. noFolders,
  59. showPreviews,
  60. setShowPreviews,
  61. } = useManageDashboards(query, {}, folder);
  62. const onMoveTo = () => {
  63. setIsMoveModalOpen(true);
  64. };
  65. const onItemDelete = () => {
  66. setIsDeleteModalOpen(true);
  67. };
  68. if (initialLoading) {
  69. return <Spinner className={styles.spinner} />;
  70. }
  71. if (noFolders && !hasFilters) {
  72. return (
  73. <EmptyListCTA
  74. title="This folder doesn't have any dashboards yet"
  75. buttonIcon="plus"
  76. buttonTitle="Create Dashboard"
  77. buttonLink={`dashboard/new?folderId=${folderId}`}
  78. proTip="Add/move dashboards to your folder at ->"
  79. proTipLink="dashboards"
  80. proTipLinkTitle="Manage dashboards"
  81. proTipTarget=""
  82. />
  83. );
  84. }
  85. return (
  86. <div className={styles.container}>
  87. <div className="page-action-bar">
  88. <div className="gf-form gf-form--grow m-r-2">
  89. <FilterInput value={query.query} onChange={onQueryChange} placeholder={'Search dashboards by name'} />
  90. </div>
  91. <DashboardActions isEditor={isEditor} canEdit={hasEditPermissionInFolders || canSave} folderId={folderId} />
  92. </div>
  93. <div className={styles.results}>
  94. <SearchResultsFilter
  95. allChecked={allChecked}
  96. canDelete={hasEditPermissionInFolders && canDelete}
  97. canMove={hasEditPermissionInFolders && canMove}
  98. deleteItem={onItemDelete}
  99. moveTo={onMoveTo}
  100. setShowPreviews={setShowPreviews}
  101. onToggleAllChecked={onToggleAllChecked}
  102. onStarredFilterChange={onStarredFilterChange}
  103. onSortChange={onSortChange}
  104. onTagFilterChange={onTagFilterChange}
  105. query={query}
  106. showPreviews={showPreviews}
  107. hideLayout={!!folderUid}
  108. onLayoutChange={onLayoutChange}
  109. editable={hasEditPermissionInFolders}
  110. />
  111. <SearchResults
  112. loading={loading}
  113. results={results}
  114. editable={hasEditPermissionInFolders}
  115. onTagSelected={onTagAdd}
  116. onToggleSection={onToggleSection}
  117. onToggleChecked={onToggleChecked}
  118. layout={query.layout}
  119. showPreviews={showPreviews}
  120. />
  121. </div>
  122. <ConfirmDeleteModal
  123. onDeleteItems={onDeleteItems}
  124. results={results}
  125. isOpen={isDeleteModalOpen}
  126. onDismiss={() => setIsDeleteModalOpen(false)}
  127. />
  128. <MoveToFolderModal
  129. onMoveItems={onMoveItems}
  130. results={results}
  131. isOpen={isMoveModalOpen}
  132. onDismiss={() => setIsMoveModalOpen(false)}
  133. />
  134. </div>
  135. );
  136. });
  137. ManageDashboards.displayName = 'ManageDashboards';
  138. export default ManageDashboards;
  139. const getStyles = stylesFactory((theme: GrafanaTheme) => {
  140. return {
  141. container: css`
  142. height: 100%;
  143. display: flex;
  144. flex-direction: column;
  145. `,
  146. results: css`
  147. display: flex;
  148. flex-direction: column;
  149. flex: 1 1 0;
  150. height: 100%;
  151. padding-top: ${theme.spacing.lg};
  152. `,
  153. spinner: css`
  154. display: flex;
  155. justify-content: center;
  156. align-items: center;
  157. min-height: 200px;
  158. `,
  159. };
  160. });