grafana/public/app/features/search/components/ManageDashboards.tsx
Torkel Ödegaard 9d6c8f8512
PanelEdit: v8 Panel Edit UX (#32124)
* Initial commit

* Progress

* Update

* Progress

* updates

* Minor fix

* fixed ts issue

* fixed e2e tests

* More explorations

* Making progress

* Panel options and field options unified

* With nested categories

* Starting to find something

* fix paddings

* Progress

* Breakthrough ux layout

* Progress

* Updates

* New way of composing options with search

* added regex search

* Refactoring to react note tree

* Show overrides

* Adding overrides radio button support

* Added popular view

* Separate stat/gauge/bargauge options into value options and display options

* Initial work on getting library panels into viz picker flow

* Fixed issues switching to panel library panel

* Move search input put of LibraryPanelsView

* Changing design again to have content inside boxes

* Style updates

* Refactoring to fix scroll issue

* Option category naming

* Fixed FilterInput issue

* Updated snapshots

* Fix padding

* Updated viz picker design

* Unify library panel an viz picker card

* Updated card with delete action

* Major refactoring back to an object model instead of searching and filtering react node tree

* More refactoring

* Show option category in label when searching

* Nice logic for categories rendering when searching or when only child

* Make getSuggestions more lazy for DataLinksEditor

* Add missing repeat options and handle conditional options

* Prepping options category to be more flexibly and control state from outside

* Added option count to search result

* Minor style tweak

* Added button to close viz picker

* Rewrote overrides to enable searching overrides

* New search engine and tests

* Searching overrides works

* Hide radio buttons while searching

* Added angular options back

* Added memoize for all options so they are not rebuilt for every search key stroke

* Added back support for category counters

* Started unit test work

* Refactoring and base popular options list

* Initial update to e2e test, more coming to add e2e test for search features

* Minor fix

* Review updates

* Fixing category open states

* Unit test progress

* Do not show visualization list mode radio button if library panels is not enabled

* Use boolean

* More unit tests

* Increase library panels per page count and give search focus when switching list mode

* field config change test and search test

* Feedback updates

* Minor tweaks

* Minor refactorings

* More minimal override collapse state
2021-03-25 08:33:13 +01:00

167 lines
4.7 KiB
TypeScript

import React, { FC, memo, useState } from 'react';
import { css } from 'emotion';
import { HorizontalGroup, stylesFactory, useTheme, Spinner } from '@grafana/ui';
import { GrafanaTheme } from '@grafana/data';
import { contextSrv } from 'app/core/services/context_srv';
import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA';
import { FilterInput } from 'app/core/components/FilterInput/FilterInput';
import { FolderDTO } from 'app/types';
import { useManageDashboards } from '../hooks/useManageDashboards';
import { SearchLayout } from '../types';
import { ConfirmDeleteModal } from './ConfirmDeleteModal';
import { MoveToFolderModal } from './MoveToFolderModal';
import { useSearchQuery } from '../hooks/useSearchQuery';
import { SearchResultsFilter } from './SearchResultsFilter';
import { SearchResults } from './SearchResults';
import { DashboardActions } from './DashboardActions';
export interface Props {
folder?: FolderDTO;
}
const { isEditor } = contextSrv;
export const ManageDashboards: FC<Props> = memo(({ folder }) => {
const folderId = folder?.id;
const folderUid = folder?.uid;
const theme = useTheme();
const styles = getStyles(theme);
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
const [isMoveModalOpen, setIsMoveModalOpen] = useState(false);
const defaultLayout = folderId ? SearchLayout.List : SearchLayout.Folders;
const queryParamsDefaults = {
skipRecent: true,
skipStarred: true,
folderIds: folderId ? [folderId] : [],
layout: defaultLayout,
};
const {
query,
hasFilters,
onQueryChange,
onTagFilterChange,
onStarredFilterChange,
onTagAdd,
onSortChange,
onLayoutChange,
} = useSearchQuery(queryParamsDefaults);
const {
results,
loading,
initialLoading,
canSave,
allChecked,
hasEditPermissionInFolders,
canMove,
canDelete,
onToggleSection,
onToggleChecked,
onToggleAllChecked,
onDeleteItems,
onMoveItems,
noFolders,
} = useManageDashboards(query, {}, folder);
const onMoveTo = () => {
setIsMoveModalOpen(true);
};
const onItemDelete = () => {
setIsDeleteModalOpen(true);
};
if (initialLoading) {
return <Spinner className={styles.spinner} />;
}
if (noFolders && !hasFilters) {
return (
<EmptyListCTA
title="This folder doesn't have any dashboards yet"
buttonIcon="plus"
buttonTitle="Create Dashboard"
buttonLink={`dashboard/new?folderId=${folderId}`}
proTip="Add/move dashboards to your folder at ->"
proTipLink="dashboards"
proTipLinkTitle="Manage dashboards"
proTipTarget=""
/>
);
}
return (
<div className={styles.container}>
<div>
<HorizontalGroup justify="space-between">
<FilterInput value={query.query} onChange={onQueryChange} placeholder={'Search dashboards by name'} />
<DashboardActions isEditor={isEditor} canEdit={hasEditPermissionInFolders || canSave} folderId={folderId} />
</HorizontalGroup>
</div>
<div className={styles.results}>
<SearchResultsFilter
allChecked={allChecked}
canDelete={hasEditPermissionInFolders && canDelete}
canMove={hasEditPermissionInFolders && canMove}
deleteItem={onItemDelete}
moveTo={onMoveTo}
onToggleAllChecked={onToggleAllChecked}
onStarredFilterChange={onStarredFilterChange}
onSortChange={onSortChange}
onTagFilterChange={onTagFilterChange}
query={query}
hideLayout={!!folderUid}
onLayoutChange={onLayoutChange}
editable={hasEditPermissionInFolders}
/>
<SearchResults
loading={loading}
results={results}
editable={hasEditPermissionInFolders}
onTagSelected={onTagAdd}
onToggleSection={onToggleSection}
onToggleChecked={onToggleChecked}
layout={query.layout}
/>
</div>
<ConfirmDeleteModal
onDeleteItems={onDeleteItems}
results={results}
isOpen={isDeleteModalOpen}
onDismiss={() => setIsDeleteModalOpen(false)}
/>
<MoveToFolderModal
onMoveItems={onMoveItems}
results={results}
isOpen={isMoveModalOpen}
onDismiss={() => setIsMoveModalOpen(false)}
/>
</div>
);
});
export default ManageDashboards;
const getStyles = stylesFactory((theme: GrafanaTheme) => {
return {
container: css`
height: 100%;
`,
results: css`
display: flex;
flex-direction: column;
flex: 1;
height: 100%;
margin-top: ${theme.spacing.xl};
`,
spinner: css`
display: flex;
justify-content: center;
align-items: center;
min-height: 200px;
`,
};
});