diff --git a/public/app/features/search/components/PreviewsSystemRequirements.tsx b/public/app/features/search/components/PreviewsSystemRequirements.tsx
deleted file mode 100644
index c3ba284c01b..00000000000
--- a/public/app/features/search/components/PreviewsSystemRequirements.tsx
+++ /dev/null
@@ -1,94 +0,0 @@
-import { css } from '@emotion/css';
-import React from 'react';
-
-import { config } from '@grafana/runtime/src';
-import { Alert, useStyles2 } from '@grafana/ui';
-
-export interface Props {
- showPreviews?: boolean;
- /** On click handler for alert button, mostly used for dismissing the alert */
- onRemove?: (event: React.MouseEvent) => void;
- topSpacing?: number;
- bottomSpacing?: number;
-}
-
-const MessageLink = ({ text }: { text: string }) => (
-
- {text}
-
-);
-
-const Message = ({ requiredImageRendererPluginVersion }: { requiredImageRendererPluginVersion?: string }) => {
- if (requiredImageRendererPluginVersion) {
- return (
- <>
- You must update the to version{' '}
- {requiredImageRendererPluginVersion} to enable dashboard previews. Please contact your Grafana administrator to
- update the plugin.
- >
- );
- }
-
- return (
- <>
- You must install the to enable dashboard previews. Please
- contact your Grafana administrator to install the plugin.
- >
- );
-};
-
-export const PreviewsSystemRequirements = ({ showPreviews, onRemove, topSpacing, bottomSpacing }: Props) => {
- const styles = useStyles2(getStyles);
-
- const previewsEnabled = config.featureToggles.dashboardPreviews;
- const rendererAvailable = config.rendererAvailable;
-
- const {
- systemRequirements: { met: systemRequirementsMet, requiredImageRendererPluginVersion },
- thumbnailsExist,
- } = config.dashboardPreviews;
-
- const arePreviewsEnabled = previewsEnabled && showPreviews;
- const areRequirementsMet = (rendererAvailable && systemRequirementsMet) || thumbnailsExist;
- const shouldDisplayRequirements = arePreviewsEnabled && !areRequirementsMet;
-
- const title = requiredImageRendererPluginVersion
- ? 'Image renderer plugin needs to be updated'
- : 'Image renderer plugin not installed';
-
- return (
- <>
- {shouldDisplayRequirements && (
-
- )}
- >
- );
-};
-
-const getStyles = () => {
- return {
- wrapper: css`
- display: flex;
- justify-content: center;
- `,
- alert: css`
- max-width: 800px;
- `,
- };
-};
diff --git a/public/app/features/search/page/components/ActionRow.tsx b/public/app/features/search/page/components/ActionRow.tsx
index 74400e7847c..f9881c9351f 100644
--- a/public/app/features/search/page/components/ActionRow.tsx
+++ b/public/app/features/search/page/components/ActionRow.tsx
@@ -3,7 +3,7 @@ import React, { FormEvent } from 'react';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
import { config } from '@grafana/runtime';
-import { HorizontalGroup, RadioButtonGroup, useStyles2, Checkbox, Button } from '@grafana/ui';
+import { Button, Checkbox, HorizontalGroup, RadioButtonGroup, useStyles2 } from '@grafana/ui';
import { SortPicker } from 'app/core/components/Select/SortPicker';
import { TagFilter, TermCount } from 'app/core/components/TagFilter/TagFilter';
import { t, Trans } from 'app/core/internationalization';
@@ -11,20 +11,10 @@ import { t, Trans } from 'app/core/internationalization';
import { SearchLayout, SearchState } from '../../types';
function getLayoutOptions() {
- const layoutOptions = [
+ return [
{ value: SearchLayout.Folders, icon: 'folder', ariaLabel: t('search.actions.view-as-folders', 'View by folders') },
{ value: SearchLayout.List, icon: 'list-ul', ariaLabel: t('search.actions.view-as-list', 'View as list') },
];
-
- if (config.featureToggles.dashboardPreviews) {
- layoutOptions.push({
- value: SearchLayout.Grid,
- icon: 'apps',
- ariaLabel: t('search.actions.view-as-grid', 'Grid view'),
- });
- }
-
- return layoutOptions;
}
interface Props {
@@ -54,9 +44,6 @@ export function getValidQueryLayout(q: SearchState): SearchLayout {
}
}
- if (layout === SearchLayout.Grid && !config.featureToggles.dashboardPreviews) {
- return SearchLayout.List;
- }
return layout;
}
diff --git a/public/app/features/search/page/components/SearchResultsGrid.test.tsx b/public/app/features/search/page/components/SearchResultsGrid.test.tsx
deleted file mode 100644
index 05eb1187051..00000000000
--- a/public/app/features/search/page/components/SearchResultsGrid.test.tsx
+++ /dev/null
@@ -1,66 +0,0 @@
-import { fireEvent, render, screen, waitFor } from '@testing-library/react';
-import React, { KeyboardEvent } from 'react';
-import { Observable } from 'rxjs';
-
-import { ArrayVector, DataFrame, DataFrameView, FieldType } from '@grafana/data';
-import { selectors } from '@grafana/e2e-selectors';
-
-import { DashboardQueryResult, QueryResponse } from '../../service';
-import { DashboardSearchItemType } from '../../types';
-
-import { SearchResultsGrid } from './SearchResultsGrid';
-
-describe('SearchResultsGrid', () => {
- const dashboardsData: DataFrame = {
- fields: [
- {
- name: 'kind',
- type: FieldType.string,
- config: {},
- values: new ArrayVector([DashboardSearchItemType.DashDB]),
- },
- { name: 'name', type: FieldType.string, config: {}, values: new ArrayVector(['My dashboard 1', 'dash2']) },
- { name: 'uid', type: FieldType.string, config: {}, values: new ArrayVector(['my-dashboard-1', 'dash-2']) },
- { name: 'url', type: FieldType.string, config: {}, values: new ArrayVector(['/my-dashbaord-1', '/dash-2']) },
- ],
- length: 2,
- };
- const mockSearchResult: QueryResponse = {
- isItemLoaded: jest.fn(),
- loadMoreItems: jest.fn(),
- totalRows: dashboardsData.length,
- view: new DataFrameView(dashboardsData),
- };
-
- const baseProps = {
- response: mockSearchResult,
- width: 800,
- height: 600,
- clearSelection: jest.fn(),
- onTagSelected: jest.fn(),
- keyboardEvents: new Observable>(),
- };
-
- it('should render grid of dashboards', () => {
- render();
- expect(screen.getByTestId(selectors.components.Search.dashboardCard('My dashboard 1'))).toBeInTheDocument();
- expect(screen.getByTestId(selectors.components.Search.dashboardCard('dash2'))).toBeInTheDocument();
- });
-
- it('should not render checkboxes for non-editable results', async () => {
- render();
- expect(screen.queryByRole('checkbox')).toBeNull();
- await waitFor(() => expect(screen.queryAllByRole('checkbox')).toHaveLength(0));
- });
-
- it('should render checkboxes for editable results ', async () => {
- const mockSelectionToggle = jest.fn();
- const mockSelection = jest.fn();
- render();
-
- await waitFor(() => expect(screen.queryAllByRole('checkbox')).toHaveLength(2));
- fireEvent.click(await screen.findByRole('checkbox', { name: /Select dashboard dash2/i }));
- expect(mockSelectionToggle).toHaveBeenCalledWith('dashboard', 'dash-2');
- expect(mockSelectionToggle).toHaveBeenCalledTimes(1);
- });
-});
diff --git a/public/app/features/search/page/components/SearchResultsGrid.tsx b/public/app/features/search/page/components/SearchResultsGrid.tsx
deleted file mode 100644
index 037fe739886..00000000000
--- a/public/app/features/search/page/components/SearchResultsGrid.tsx
+++ /dev/null
@@ -1,134 +0,0 @@
-import { css } from '@emotion/css';
-import React from 'react';
-import { FixedSizeGrid } from 'react-window';
-import InfiniteLoader from 'react-window-infinite-loader';
-
-import { GrafanaTheme2 } from '@grafana/data';
-import { config } from '@grafana/runtime';
-import { useStyles2 } from '@grafana/ui';
-
-import { SearchCard } from '../../components/SearchCard';
-import { useSearchKeyboardNavigation } from '../../hooks/useSearchKeyboardSelection';
-import { queryResultToViewItem } from '../../service/utils';
-import { DashboardViewItem } from '../../types';
-
-import { SearchResultsProps } from './SearchResultsTable';
-
-export const SearchResultsGrid = ({
- response,
- width,
- height,
- selection,
- selectionToggle,
- onTagSelected,
- onClickItem,
- keyboardEvents,
-}: SearchResultsProps) => {
- const styles = useStyles2(getStyles);
-
- // Hacked to reuse existing SearchCard (and old DashboardSectionItem)
- const itemProps = {
- editable: selection != null,
- onToggleChecked: (item: DashboardViewItem) => {
- if (selectionToggle) {
- selectionToggle(item.kind, item.uid);
- }
- },
- onTagSelected,
- onClick: onClickItem,
- };
-
- const itemCount = response.totalRows ?? response.view.length;
- const view = response.view;
- const numColumns = Math.ceil(width / 320);
- const cellWidth = width / numColumns;
- const cellHeight = (cellWidth - 64) * 0.75 + 56 + 8;
- const numRows = Math.ceil(itemCount / numColumns);
- const highlightIndex = useSearchKeyboardNavigation(keyboardEvents, numColumns, response);
-
- return (
-
- {({ onItemsRendered, ref }) => (
- {
- onItemsRendered({
- visibleStartIndex: v.visibleRowStartIndex * numColumns,
- visibleStopIndex: v.visibleRowStopIndex * numColumns,
- overscanStartIndex: v.overscanRowStartIndex * numColumns,
- overscanStopIndex: v.overscanColumnStopIndex * numColumns,
- });
- }}
- columnCount={numColumns}
- columnWidth={cellWidth}
- rowCount={numRows}
- rowHeight={cellHeight}
- className={styles.wrapper}
- innerElementType="ul"
- height={height}
- width={width - 2}
- >
- {({ columnIndex, rowIndex, style }) => {
- const index = rowIndex * numColumns + columnIndex;
- if (index >= view.length) {
- return null;
- }
- const item = view.get(index);
- const kind = item.kind ?? 'dashboard';
-
- const facade = queryResultToViewItem(item, view);
-
- if (kind === 'panel') {
- const type = item.panel_type;
- facade.icon = 'public/img/icons/unicons/graph-bar.svg';
- if (type) {
- const info = config.panels[type];
- if (info?.name) {
- const v = info.info?.logos.small;
- if (v && v.endsWith('.svg')) {
- facade.icon = v;
- }
- }
- }
- }
-
- let className = styles.virtualizedGridItemWrapper;
- if (rowIndex === highlightIndex.y && columnIndex === highlightIndex.x) {
- className += ' ' + styles.selectedItem;
- }
-
- // 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 item ? (
-
-
-
- ) : null;
- }}
-
- )}
-
- );
-};
-
-const getStyles = (theme: GrafanaTheme2) => ({
- virtualizedGridItemWrapper: css`
- padding: 4px;
- `,
- wrapper: css`
- display: flex;
- flex-direction: column;
-
- > ul {
- list-style: none;
- }
- `,
- selectedItem: css`
- box-shadow: inset 1px 1px 3px 3px ${theme.colors.primary.border};
- `,
-});
diff --git a/public/app/features/search/page/components/SearchView.tsx b/public/app/features/search/page/components/SearchView.tsx
index ce46c4910fd..b1f65393187 100644
--- a/public/app/features/search/page/components/SearchView.tsx
+++ b/public/app/features/search/page/components/SearchView.tsx
@@ -10,7 +10,6 @@ import { useStyles2, Spinner, Button } from '@grafana/ui';
import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA';
import { FolderDTO } from 'app/types';
-import { PreviewsSystemRequirements } from '../../components/PreviewsSystemRequirements';
import { getGrafanaSearcher } from '../../service';
import { getSearchStateManager } from '../../state/SearchStateManager';
import { SearchLayout, DashboardViewItem } from '../../types';
@@ -21,7 +20,6 @@ import { FolderSection } from './FolderSection';
import { ManageActions } from './ManageActions';
import { RootFolderView } from './RootFolderView';
import { SearchResultsCards } from './SearchResultsCards';
-import { SearchResultsGrid } from './SearchResultsGrid';
import { SearchResultsTable, SearchResultsProps } from './SearchResultsTable';
export type SearchViewProps = {
@@ -133,10 +131,6 @@ export const SearchView = ({ showManage, folderDTO, hidePseudoFolders, keyboardE
onClickItem: stateManager.onSearchItemClicked,
};
- if (layout === SearchLayout.Grid) {
- return ;
- }
-
if (width < 800) {
return ;
}
@@ -193,13 +187,6 @@ export const SearchView = ({ showManage, folderDTO, hidePseudoFolders, keyboardE
/>
)}
- {layout === SearchLayout.Grid && (
- stateManager.onLayoutChange(SearchLayout.List)}
- />
- )}
{renderResults()}
>
);
diff --git a/public/app/features/search/page/reporting.ts b/public/app/features/search/page/reporting.ts
index 9c708ac069f..5b89b070c2e 100644
--- a/public/app/features/search/page/reporting.ts
+++ b/public/app/features/search/page/reporting.ts
@@ -1,4 +1,4 @@
-import { config, reportInteraction } from '@grafana/runtime';
+import { reportInteraction } from '@grafana/runtime';
import { InspectTab } from 'app/features/inspector/types';
import { EventTrackingNamespace, SearchLayout } from '../types';
@@ -40,12 +40,7 @@ export const reportPanelInspectInteraction = (
};
const getQuerySearchContext = (query: QueryProps) => {
- const showPreviews = query.layout === SearchLayout.Grid;
- const previewsEnabled = Boolean(config.featureToggles.panelTitleSearch);
- const previews = previewsEnabled ? (showPreviews ? 'on' : 'off') : 'feature_disabled';
-
return {
- previews,
layout: query.layout,
starredFilter: query.starred ?? false,
sort: query.sortValue ?? '',
diff --git a/public/app/features/search/types.ts b/public/app/features/search/types.ts
index 269727fa88f..d0f148da767 100644
--- a/public/app/features/search/types.ts
+++ b/public/app/features/search/types.ts
@@ -102,7 +102,6 @@ export type OnToggleChecked = (item: DashboardViewItem) => void;
export enum SearchLayout {
List = 'list',
Folders = 'folders',
- Grid = 'grid', // preview
}
export interface SearchQueryParams {
diff --git a/public/app/plugins/panel/dashlist/DashList.tsx b/public/app/plugins/panel/dashlist/DashList.tsx
index 102b0cc1f6b..c776990ea44 100644
--- a/public/app/plugins/panel/dashlist/DashList.tsx
+++ b/public/app/plugins/panel/dashlist/DashList.tsx
@@ -20,12 +20,11 @@ import { getBackendSrv } from 'app/core/services/backend_srv';
import impressionSrv from 'app/core/services/impression_srv';
import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv';
import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv';
-import { SearchCard } from 'app/features/search/components/SearchCard';
import { DashboardSearchItem } from 'app/features/search/types';
import { getVariablesUrlParams } from 'app/features/variables/getAllVariableValuesForUrl';
import { useDispatch } from 'app/types';
-import { PanelLayout, PanelOptions } from './panelcfg.gen';
+import { PanelOptions } from './panelcfg.gen';
import { getStyles } from './styles';
type Dashboard = DashboardSearchItem & { id?: number; isSearchResult?: boolean; isRecent?: boolean };
@@ -130,7 +129,7 @@ export function DashList(props: PanelProps) {
];
}, [dashboards]);
- const { showStarred, showRecentlyViewed, showHeadings, showSearch, layout } = props.options;
+ const { showStarred, showRecentlyViewed, showHeadings, showSearch } = props.options;
const dashboardGroups: DashboardGroup[] = [
{
@@ -198,16 +197,6 @@ export function DashList(props: PanelProps) {
);
- const renderPreviews = (dashboards: Dashboard[]) => (
-
- {dashboards.map((dash) => (
- -
-
-
- ))}
-
- );
-
return (
{dashboardGroups.map(
@@ -215,7 +204,7 @@ export function DashList(props: PanelProps) {
show && (
{showHeadings &&
{header}
}
- {layout === PanelLayout.Previews ? renderPreviews(dashboards) : renderList(dashboards)}
+ {renderList(dashboards)}
)
)}
diff --git a/public/app/plugins/panel/dashlist/module.tsx b/public/app/plugins/panel/dashlist/module.tsx
index d22c00e5094..19e5a85c64a 100644
--- a/public/app/plugins/panel/dashlist/module.tsx
+++ b/public/app/plugins/panel/dashlist/module.tsx
@@ -1,7 +1,6 @@
import React from 'react';
import { PanelModel, PanelPlugin } from '@grafana/data';
-import { config } from '@grafana/runtime';
import { TagsInput } from '@grafana/ui';
import {
@@ -11,24 +10,10 @@ import {
} from '../../../core/components/Select/ReadonlyFolderPicker/ReadonlyFolderPicker';
import { DashList } from './DashList';
-import { defaultPanelOptions, PanelLayout, PanelOptions } from './panelcfg.gen';
+import { defaultPanelOptions, PanelOptions } from './panelcfg.gen';
export const plugin = new PanelPlugin(DashList)
.setPanelOptions((builder) => {
- if (config.featureToggles.dashboardPreviews) {
- builder.addRadio({
- path: 'layout',
- name: 'Layout',
- defaultValue: PanelLayout.List,
- settings: {
- options: [
- { value: PanelLayout.List, label: 'List' },
- { value: PanelLayout.Previews, label: 'Preview' },
- ],
- },
- });
- }
-
builder
.addBooleanSwitch({
path: 'keepTime',
diff --git a/public/app/plugins/panel/dashlist/panelcfg.cue b/public/app/plugins/panel/dashlist/panelcfg.cue
index 600563bbf27..bd656a5e174 100644
--- a/public/app/plugins/panel/dashlist/panelcfg.cue
+++ b/public/app/plugins/panel/dashlist/panelcfg.cue
@@ -22,9 +22,7 @@ composableKinds: PanelCfg: {
{
schemas: [
{
- PanelLayout: "list" | "previews" @cuetsy(kind="enum")
PanelOptions: {
- layout?: PanelLayout | *"list"
keepTime: bool | *false
includeVars: bool | *false
showStarred: bool | *true
diff --git a/public/app/plugins/panel/dashlist/panelcfg.gen.ts b/public/app/plugins/panel/dashlist/panelcfg.gen.ts
index 19f89096fd7..a884e896d2b 100644
--- a/public/app/plugins/panel/dashlist/panelcfg.gen.ts
+++ b/public/app/plugins/panel/dashlist/panelcfg.gen.ts
@@ -10,16 +10,10 @@
export const PanelCfgModelVersion = Object.freeze([0, 0]);
-export enum PanelLayout {
- List = 'list',
- Previews = 'previews',
-}
-
export interface PanelOptions {
folderId?: number;
includeVars: boolean;
keepTime: boolean;
- layout?: PanelLayout;
maxItems: number;
query: string;
showHeadings: boolean;
@@ -32,7 +26,6 @@ export interface PanelOptions {
export const defaultPanelOptions: Partial = {
includeVars: false,
keepTime: false,
- layout: PanelLayout.List,
maxItems: 10,
query: '',
showHeadings: true,