mirror of
https://github.com/grafana/grafana.git
synced 2025-07-31 21:32:20 +08:00
Chore: Remove code related to viz/widget split feature (#95614)
This commit is contained in:
@ -151,7 +151,6 @@ Experimental features might be changed or removed without prior notice.
|
|||||||
| `pluginsFrontendSandbox` | Enables the plugins frontend sandbox |
|
| `pluginsFrontendSandbox` | Enables the plugins frontend sandbox |
|
||||||
| `frontendSandboxMonitorOnly` | Enables monitor only in the plugin frontend sandbox (if enabled) |
|
| `frontendSandboxMonitorOnly` | Enables monitor only in the plugin frontend sandbox (if enabled) |
|
||||||
| `pluginsDetailsRightPanel` | Enables right panel for the plugins details page |
|
| `pluginsDetailsRightPanel` | Enables right panel for the plugins details page |
|
||||||
| `vizAndWidgetSplit` | Split panels between visualizations and widgets |
|
|
||||||
| `awsDatasourcesTempCredentials` | Support temporary security credentials in AWS plugins for Grafana Cloud customers |
|
| `awsDatasourcesTempCredentials` | Support temporary security credentials in AWS plugins for Grafana Cloud customers |
|
||||||
| `mlExpressions` | Enable support for Machine Learning in server-side expressions |
|
| `mlExpressions` | Enable support for Machine Learning in server-side expressions |
|
||||||
| `metricsSummary` | Enables metrics summary queries in the Tempo data source |
|
| `metricsSummary` | Enables metrics summary queries in the Tempo data source |
|
||||||
|
@ -80,7 +80,6 @@ export interface FeatureToggles {
|
|||||||
pluginsDetailsRightPanel?: boolean;
|
pluginsDetailsRightPanel?: boolean;
|
||||||
sqlDatasourceDatabaseSelection?: boolean;
|
sqlDatasourceDatabaseSelection?: boolean;
|
||||||
recordedQueriesMulti?: boolean;
|
recordedQueriesMulti?: boolean;
|
||||||
vizAndWidgetSplit?: boolean;
|
|
||||||
logsExploreTableVisualisation?: boolean;
|
logsExploreTableVisualisation?: boolean;
|
||||||
awsDatasourcesTempCredentials?: boolean;
|
awsDatasourcesTempCredentials?: boolean;
|
||||||
transformationsRedesign?: boolean;
|
transformationsRedesign?: boolean;
|
||||||
|
@ -463,13 +463,6 @@ var (
|
|||||||
Owner: grafanaObservabilityMetricsSquad,
|
Owner: grafanaObservabilityMetricsSquad,
|
||||||
AllowSelfServe: false,
|
AllowSelfServe: false,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
Name: "vizAndWidgetSplit",
|
|
||||||
Description: "Split panels between visualizations and widgets",
|
|
||||||
Stage: FeatureStageExperimental,
|
|
||||||
FrontendOnly: true,
|
|
||||||
Owner: grafanaDashboardsSquad,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
Name: "logsExploreTableVisualisation",
|
Name: "logsExploreTableVisualisation",
|
||||||
Description: "A table visualisation for logs in Explore",
|
Description: "A table visualisation for logs in Explore",
|
||||||
|
@ -61,7 +61,6 @@ frontendSandboxMonitorOnly,experimental,@grafana/plugins-platform-backend,false,
|
|||||||
pluginsDetailsRightPanel,experimental,@grafana/plugins-platform-backend,false,false,true
|
pluginsDetailsRightPanel,experimental,@grafana/plugins-platform-backend,false,false,true
|
||||||
sqlDatasourceDatabaseSelection,preview,@grafana/dataviz-squad,false,false,true
|
sqlDatasourceDatabaseSelection,preview,@grafana/dataviz-squad,false,false,true
|
||||||
recordedQueriesMulti,GA,@grafana/observability-metrics,false,false,false
|
recordedQueriesMulti,GA,@grafana/observability-metrics,false,false,false
|
||||||
vizAndWidgetSplit,experimental,@grafana/dashboards-squad,false,false,true
|
|
||||||
logsExploreTableVisualisation,GA,@grafana/observability-logs,false,false,true
|
logsExploreTableVisualisation,GA,@grafana/observability-logs,false,false,true
|
||||||
awsDatasourcesTempCredentials,experimental,@grafana/aws-datasources,false,false,false
|
awsDatasourcesTempCredentials,experimental,@grafana/aws-datasources,false,false,false
|
||||||
transformationsRedesign,GA,@grafana/observability-metrics,false,false,true
|
transformationsRedesign,GA,@grafana/observability-metrics,false,false,true
|
||||||
|
|
@ -255,10 +255,6 @@ const (
|
|||||||
// Enables writing multiple items from a single query within Recorded Queries
|
// Enables writing multiple items from a single query within Recorded Queries
|
||||||
FlagRecordedQueriesMulti = "recordedQueriesMulti"
|
FlagRecordedQueriesMulti = "recordedQueriesMulti"
|
||||||
|
|
||||||
// FlagVizAndWidgetSplit
|
|
||||||
// Split panels between visualizations and widgets
|
|
||||||
FlagVizAndWidgetSplit = "vizAndWidgetSplit"
|
|
||||||
|
|
||||||
// FlagLogsExploreTableVisualisation
|
// FlagLogsExploreTableVisualisation
|
||||||
// A table visualisation for logs in Explore
|
// A table visualisation for logs in Explore
|
||||||
FlagLogsExploreTableVisualisation = "logsExploreTableVisualisation"
|
FlagLogsExploreTableVisualisation = "logsExploreTableVisualisation"
|
||||||
|
@ -3297,7 +3297,8 @@
|
|||||||
"metadata": {
|
"metadata": {
|
||||||
"name": "vizAndWidgetSplit",
|
"name": "vizAndWidgetSplit",
|
||||||
"resourceVersion": "1718727528075",
|
"resourceVersion": "1718727528075",
|
||||||
"creationTimestamp": "2023-06-27T10:22:13Z"
|
"creationTimestamp": "2023-06-27T10:22:13Z",
|
||||||
|
"deletionTimestamp": "2024-10-30T14:21:33Z"
|
||||||
},
|
},
|
||||||
"spec": {
|
"spec": {
|
||||||
"description": "Split panels between visualizations and widgets",
|
"description": "Split panels between visualizations and widgets",
|
||||||
|
@ -2,26 +2,16 @@ import { css } from '@emotion/css';
|
|||||||
import { useCallback, useMemo, useState } from 'react';
|
import { useCallback, useMemo, useState } from 'react';
|
||||||
|
|
||||||
import { GrafanaTheme2, PanelPluginMeta, SelectableValue } from '@grafana/data';
|
import { GrafanaTheme2, PanelPluginMeta, SelectableValue } from '@grafana/data';
|
||||||
import { config } from '@grafana/runtime';
|
|
||||||
import { Icon, Button, MultiSelect, useStyles2 } from '@grafana/ui';
|
import { Icon, Button, MultiSelect, useStyles2 } from '@grafana/ui';
|
||||||
import { getAllPanelPluginMeta, getVizPluginMeta, getWidgetPluginMeta } from 'app/features/panel/state/util';
|
import { getAllPanelPluginMeta } from 'app/features/panel/state/util';
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
onChange: (plugins: PanelPluginMeta[]) => void;
|
onChange: (plugins: PanelPluginMeta[]) => void;
|
||||||
maxMenuHeight?: number;
|
maxMenuHeight?: number;
|
||||||
isWidget?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PanelTypeFilter = ({ onChange: propsOnChange, maxMenuHeight, isWidget = false }: Props): JSX.Element => {
|
export const PanelTypeFilter = ({ onChange: propsOnChange, maxMenuHeight }: Props): JSX.Element => {
|
||||||
const getPluginMetaData = (): PanelPluginMeta[] => {
|
const plugins = useMemo<PanelPluginMeta[]>(getAllPanelPluginMeta, []);
|
||||||
if (config.featureToggles.vizAndWidgetSplit) {
|
|
||||||
return isWidget ? getWidgetPluginMeta() : getVizPluginMeta();
|
|
||||||
} else {
|
|
||||||
return getAllPanelPluginMeta();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const plugins = useMemo<PanelPluginMeta[]>(getPluginMetaData, [isWidget]);
|
|
||||||
const options = useMemo(
|
const options = useMemo(
|
||||||
() =>
|
() =>
|
||||||
plugins
|
plugins
|
||||||
|
@ -17,5 +17,3 @@ export const EDIT_PANEL_ID = 23763571993;
|
|||||||
export const DEFAULT_PER_PAGE_PAGINATION = 40;
|
export const DEFAULT_PER_PAGE_PAGINATION = 40;
|
||||||
|
|
||||||
export const LS_VISUALIZATION_SELECT_TAB_KEY = 'VisualizationSelectPane.ListMode';
|
export const LS_VISUALIZATION_SELECT_TAB_KEY = 'VisualizationSelectPane.ListMode';
|
||||||
|
|
||||||
export const LS_WIDGET_SELECT_TAB_KEY = 'WidgetSelectPane.ListMode';
|
|
||||||
|
@ -8,7 +8,7 @@ import { selectors } from '@grafana/e2e-selectors';
|
|||||||
import { reportInteraction } from '@grafana/runtime';
|
import { reportInteraction } from '@grafana/runtime';
|
||||||
import { VizPanel } from '@grafana/scenes';
|
import { VizPanel } from '@grafana/scenes';
|
||||||
import { Button, CustomScrollbar, Field, FilterInput, RadioButtonGroup, useStyles2 } from '@grafana/ui';
|
import { Button, CustomScrollbar, Field, FilterInput, RadioButtonGroup, useStyles2 } from '@grafana/ui';
|
||||||
import { LS_VISUALIZATION_SELECT_TAB_KEY, LS_WIDGET_SELECT_TAB_KEY } from 'app/core/constants';
|
import { LS_VISUALIZATION_SELECT_TAB_KEY } from 'app/core/constants';
|
||||||
import { VisualizationSelectPaneTab } from 'app/features/dashboard/components/PanelEditor/types';
|
import { VisualizationSelectPaneTab } from 'app/features/dashboard/components/PanelEditor/types';
|
||||||
import { VisualizationSuggestions } from 'app/features/panel/components/VizTypePicker/VisualizationSuggestions';
|
import { VisualizationSuggestions } from 'app/features/panel/components/VizTypePicker/VisualizationSuggestions';
|
||||||
import { VizTypePicker } from 'app/features/panel/components/VizTypePicker/VizTypePicker';
|
import { VizTypePicker } from 'app/features/panel/components/VizTypePicker/VizTypePicker';
|
||||||
@ -48,18 +48,12 @@ export function PanelVizTypePicker({ panel, data, onChange, onClose }: Props) {
|
|||||||
setSearchQuery(value);
|
setSearchQuery(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
const isWidgetEnabled = false;
|
const tabKey = LS_VISUALIZATION_SELECT_TAB_KEY;
|
||||||
const tabKey = isWidgetEnabled ? LS_WIDGET_SELECT_TAB_KEY : LS_VISUALIZATION_SELECT_TAB_KEY;
|
const defaultTab = VisualizationSelectPaneTab.Visualizations;
|
||||||
const defaultTab = isWidgetEnabled ? VisualizationSelectPaneTab.Widgets : VisualizationSelectPaneTab.Visualizations;
|
|
||||||
const panelModel = useMemo(() => new PanelModelCompatibilityWrapper(panel), [panel]);
|
const panelModel = useMemo(() => new PanelModelCompatibilityWrapper(panel), [panel]);
|
||||||
|
|
||||||
const supportedListModes = useMemo(
|
const supportedListModes = useMemo(
|
||||||
() =>
|
() => new Set([VisualizationSelectPaneTab.Visualizations, VisualizationSelectPaneTab.Suggestions]),
|
||||||
new Set([
|
|
||||||
VisualizationSelectPaneTab.Widgets,
|
|
||||||
VisualizationSelectPaneTab.Visualizations,
|
|
||||||
VisualizationSelectPaneTab.Suggestions,
|
|
||||||
]),
|
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
const [listMode, setListMode] = useLocalStorage(tabKey, defaultTab);
|
const [listMode, setListMode] = useLocalStorage(tabKey, defaultTab);
|
||||||
|
@ -3,7 +3,6 @@ import { act, fireEvent, render, screen } from '@testing-library/react';
|
|||||||
import { PluginType } from '@grafana/data';
|
import { PluginType } from '@grafana/data';
|
||||||
import { locationService, reportInteraction } from '@grafana/runtime';
|
import { locationService, reportInteraction } from '@grafana/runtime';
|
||||||
import { defaultDashboard } from '@grafana/schema';
|
import { defaultDashboard } from '@grafana/schema';
|
||||||
import config from 'app/core/config';
|
|
||||||
import { createDashboardModelFixture } from 'app/features/dashboard/state/__fixtures__/dashboardFixtures';
|
import { createDashboardModelFixture } from 'app/features/dashboard/state/__fixtures__/dashboardFixtures';
|
||||||
import {
|
import {
|
||||||
onCreateNewPanel,
|
onCreateNewPanel,
|
||||||
@ -45,7 +44,6 @@ function setup() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
config.featureToggles = { vizAndWidgetSplit: false };
|
|
||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -141,10 +139,3 @@ it('renders menu list without Widget button when feature flag is disabled', () =
|
|||||||
setup();
|
setup();
|
||||||
expect(screen.queryByText('Widget')).not.toBeInTheDocument();
|
expect(screen.queryByText('Widget')).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders menu list with Widget button when feature flag is enabled', () => {
|
|
||||||
config.featureToggles.vizAndWidgetSplit = true;
|
|
||||||
setup();
|
|
||||||
|
|
||||||
expect(screen.getByText('Widget')).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
import { selectors } from '@grafana/e2e-selectors';
|
import { selectors } from '@grafana/e2e-selectors';
|
||||||
import { config, locationService } from '@grafana/runtime';
|
import { locationService } from '@grafana/runtime';
|
||||||
import { Menu } from '@grafana/ui';
|
import { Menu } from '@grafana/ui';
|
||||||
import { t } from 'app/core/internationalization';
|
import { t } from 'app/core/internationalization';
|
||||||
import { DashboardModel } from 'app/features/dashboard/state';
|
import { DashboardModel } from 'app/features/dashboard/state';
|
||||||
@ -39,17 +39,6 @@ const AddPanelMenu = ({ dashboard }: Props) => {
|
|||||||
dispatch(setInitialDatasource(undefined));
|
dispatch(setInitialDatasource(undefined));
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{config.featureToggles.vizAndWidgetSplit && (
|
|
||||||
<Menu.Item
|
|
||||||
key="add-widget"
|
|
||||||
testId={selectors.pages.AddDashboard.itemButton('Add new widget menu item')}
|
|
||||||
label={t('dashboard.add-menu.widget', 'Widget')}
|
|
||||||
onClick={() => {
|
|
||||||
DashboardInteractions.toolbarAddButtonClicked({ item: 'add_widget' });
|
|
||||||
locationService.partial({ addWidget: true });
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
key="add-row"
|
key="add-row"
|
||||||
testId={selectors.pages.AddDashboard.itemButton('Add new row menu item')}
|
testId={selectors.pages.AddDashboard.itemButton('Add new row menu item')}
|
||||||
|
@ -4,10 +4,9 @@ import { useLocalStorage } from 'react-use';
|
|||||||
|
|
||||||
import { GrafanaTheme2, PanelData, SelectableValue } from '@grafana/data';
|
import { GrafanaTheme2, PanelData, SelectableValue } from '@grafana/data';
|
||||||
import { selectors } from '@grafana/e2e-selectors';
|
import { selectors } from '@grafana/e2e-selectors';
|
||||||
import { config } from '@grafana/runtime';
|
|
||||||
import { Button, CustomScrollbar, FilterInput, RadioButtonGroup, useStyles2 } from '@grafana/ui';
|
import { Button, CustomScrollbar, FilterInput, RadioButtonGroup, useStyles2 } from '@grafana/ui';
|
||||||
import { Field } from '@grafana/ui/src/components/Forms/Field';
|
import { Field } from '@grafana/ui/src/components/Forms/Field';
|
||||||
import { LS_VISUALIZATION_SELECT_TAB_KEY, LS_WIDGET_SELECT_TAB_KEY } from 'app/core/constants';
|
import { LS_VISUALIZATION_SELECT_TAB_KEY } from 'app/core/constants';
|
||||||
import { PanelLibraryOptionsGroup } from 'app/features/library-panels/components/PanelLibraryOptionsGroup/PanelLibraryOptionsGroup';
|
import { PanelLibraryOptionsGroup } from 'app/features/library-panels/components/PanelLibraryOptionsGroup/PanelLibraryOptionsGroup';
|
||||||
import { VisualizationSuggestions } from 'app/features/panel/components/VizTypePicker/VisualizationSuggestions';
|
import { VisualizationSuggestions } from 'app/features/panel/components/VizTypePicker/VisualizationSuggestions';
|
||||||
import { VizTypeChangeDetails } from 'app/features/panel/components/VizTypePicker/types';
|
import { VizTypeChangeDetails } from 'app/features/panel/components/VizTypePicker/types';
|
||||||
@ -30,12 +29,8 @@ export const VisualizationSelectPane = ({ panel, data }: Props) => {
|
|||||||
const plugin = useSelector(getPanelPluginWithFallback(panel.type));
|
const plugin = useSelector(getPanelPluginWithFallback(panel.type));
|
||||||
const [searchQuery, setSearchQuery] = useState('');
|
const [searchQuery, setSearchQuery] = useState('');
|
||||||
|
|
||||||
// Add support to show widgets in the visualization picker
|
const tabKey = LS_VISUALIZATION_SELECT_TAB_KEY;
|
||||||
const isWidget = !!plugin.meta.skipDataQuery;
|
const defaultTab = VisualizationSelectPaneTab.Visualizations;
|
||||||
const isWidgetEnabled = Boolean(isWidget && config.featureToggles.vizAndWidgetSplit);
|
|
||||||
|
|
||||||
const tabKey = isWidgetEnabled ? LS_WIDGET_SELECT_TAB_KEY : LS_VISUALIZATION_SELECT_TAB_KEY;
|
|
||||||
const defaultTab = isWidgetEnabled ? VisualizationSelectPaneTab.Widgets : VisualizationSelectPaneTab.Visualizations;
|
|
||||||
|
|
||||||
const [listMode, setListMode] = useLocalStorage(tabKey, defaultTab);
|
const [listMode, setListMode] = useLocalStorage(tabKey, defaultTab);
|
||||||
|
|
||||||
@ -73,15 +68,6 @@ export const VisualizationSelectPane = ({ panel, data }: Props) => {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const radioOptionsWidgetFlow: Array<SelectableValue<VisualizationSelectPaneTab>> = [
|
|
||||||
{ label: 'Widgets', value: VisualizationSelectPaneTab.Widgets },
|
|
||||||
{
|
|
||||||
label: 'Library panels',
|
|
||||||
value: VisualizationSelectPaneTab.LibraryPanels,
|
|
||||||
description: 'Reusable panels you can share between multiple dashboards.',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.openWrapper}>
|
<div className={styles.openWrapper}>
|
||||||
<div className={styles.formBox}>
|
<div className={styles.formBox}>
|
||||||
@ -103,12 +89,7 @@ export const VisualizationSelectPane = ({ panel, data }: Props) => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Field className={styles.customFieldMargin}>
|
<Field className={styles.customFieldMargin}>
|
||||||
<RadioButtonGroup
|
<RadioButtonGroup options={radioOptions} value={listMode} onChange={setListMode} fullWidth />
|
||||||
options={isWidgetEnabled ? radioOptionsWidgetFlow : radioOptions}
|
|
||||||
value={listMode}
|
|
||||||
onChange={setListMode}
|
|
||||||
fullWidth
|
|
||||||
/>
|
|
||||||
</Field>
|
</Field>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.scrollWrapper}>
|
<div className={styles.scrollWrapper}>
|
||||||
@ -117,20 +98,11 @@ export const VisualizationSelectPane = ({ panel, data }: Props) => {
|
|||||||
{listMode === VisualizationSelectPaneTab.Visualizations && (
|
{listMode === VisualizationSelectPaneTab.Visualizations && (
|
||||||
<VizTypePicker pluginId={plugin.meta.id} onChange={onVizChange} searchQuery={searchQuery} />
|
<VizTypePicker pluginId={plugin.meta.id} onChange={onVizChange} searchQuery={searchQuery} />
|
||||||
)}
|
)}
|
||||||
{listMode === VisualizationSelectPaneTab.Widgets && (
|
|
||||||
<VizTypePicker pluginId={plugin.meta.id} onChange={onVizChange} searchQuery={searchQuery} isWidget />
|
|
||||||
)}
|
|
||||||
|
|
||||||
{listMode === VisualizationSelectPaneTab.Suggestions && (
|
{listMode === VisualizationSelectPaneTab.Suggestions && (
|
||||||
<VisualizationSuggestions onChange={onVizChange} searchQuery={searchQuery} panel={panel} data={data} />
|
<VisualizationSuggestions onChange={onVizChange} searchQuery={searchQuery} panel={panel} data={data} />
|
||||||
)}
|
)}
|
||||||
{listMode === VisualizationSelectPaneTab.LibraryPanels && (
|
{listMode === VisualizationSelectPaneTab.LibraryPanels && (
|
||||||
<PanelLibraryOptionsGroup
|
<PanelLibraryOptionsGroup searchQuery={searchQuery} panel={panel} key="Panel Library" />
|
||||||
searchQuery={searchQuery}
|
|
||||||
panel={panel}
|
|
||||||
key="Panel Library"
|
|
||||||
isWidget={isWidget}
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</CustomScrollbar>
|
</CustomScrollbar>
|
||||||
|
@ -72,5 +72,4 @@ export enum VisualizationSelectPaneTab {
|
|||||||
Visualizations,
|
Visualizations,
|
||||||
LibraryPanels,
|
LibraryPanels,
|
||||||
Suggestions,
|
Suggestions,
|
||||||
Widgets,
|
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,6 @@ import { PanelEditEnteredEvent, PanelEditExitedEvent } from 'app/types/events';
|
|||||||
|
|
||||||
import { cancelVariables, templateVarsChangedInUrl } from '../../variables/state/actions';
|
import { cancelVariables, templateVarsChangedInUrl } from '../../variables/state/actions';
|
||||||
import { findTemplateVarChanges } from '../../variables/utils';
|
import { findTemplateVarChanges } from '../../variables/utils';
|
||||||
import { AddWidgetModal } from '../components/AddWidgetModal/AddWidgetModal';
|
|
||||||
import { DashNav } from '../components/DashNav';
|
import { DashNav } from '../components/DashNav';
|
||||||
import { DashboardFailed } from '../components/DashboardLoading/DashboardFailed';
|
import { DashboardFailed } from '../components/DashboardLoading/DashboardFailed';
|
||||||
import { DashboardLoading } from '../components/DashboardLoading/DashboardLoading';
|
import { DashboardLoading } from '../components/DashboardLoading/DashboardLoading';
|
||||||
@ -494,7 +493,6 @@ export class UnthemedDashboardPage extends PureComponent<Props, State> {
|
|||||||
sectionNav={sectionNav}
|
sectionNav={sectionNav}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{queryParams.addWidget && config.featureToggles.vizAndWidgetSplit && <AddWidgetModal />}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ import { act, fireEvent, render, screen } from '@testing-library/react';
|
|||||||
|
|
||||||
import { locationService, reportInteraction } from '@grafana/runtime';
|
import { locationService, reportInteraction } from '@grafana/runtime';
|
||||||
import { defaultDashboard } from '@grafana/schema';
|
import { defaultDashboard } from '@grafana/schema';
|
||||||
import config from 'app/core/config';
|
|
||||||
|
|
||||||
import { createDashboardModelFixture } from '../state/__fixtures__/dashboardFixtures';
|
import { createDashboardModelFixture } from '../state/__fixtures__/dashboardFixtures';
|
||||||
import { onCreateNewPanel, onImportDashboard, onAddLibraryPanel } from '../utils/dashboard';
|
import { onCreateNewPanel, onImportDashboard, onAddLibraryPanel } from '../utils/dashboard';
|
||||||
@ -40,7 +39,6 @@ function setup(options?: Partial<Props>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
config.featureToggles = { vizAndWidgetSplit: false };
|
|
||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -110,13 +108,3 @@ it('renders page without Add Widget button when feature flag is disabled', () =>
|
|||||||
expect(screen.getByRole('button', { name: 'Add library panel' })).toBeInTheDocument();
|
expect(screen.getByRole('button', { name: 'Add library panel' })).toBeInTheDocument();
|
||||||
expect(screen.queryByRole('button', { name: 'Add widget' })).not.toBeInTheDocument();
|
expect(screen.queryByRole('button', { name: 'Add widget' })).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders page with Add Widget button when feature flag is enabled', () => {
|
|
||||||
config.featureToggles.vizAndWidgetSplit = true;
|
|
||||||
setup();
|
|
||||||
|
|
||||||
expect(screen.getByRole('button', { name: 'Add visualization' })).toBeInTheDocument();
|
|
||||||
expect(screen.getByRole('button', { name: 'Import dashboard' })).toBeInTheDocument();
|
|
||||||
expect(screen.getByRole('button', { name: 'Add library panel' })).toBeInTheDocument();
|
|
||||||
expect(screen.getByRole('button', { name: 'Add widget' })).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
|
@ -2,7 +2,7 @@ import { css } from '@emotion/css';
|
|||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { selectors } from '@grafana/e2e-selectors';
|
import { selectors } from '@grafana/e2e-selectors';
|
||||||
import { config, locationService } from '@grafana/runtime';
|
import { locationService } from '@grafana/runtime';
|
||||||
import { Button, useStyles2, Text, Box, Stack } from '@grafana/ui';
|
import { Button, useStyles2, Text, Box, Stack } from '@grafana/ui';
|
||||||
import { Trans } from 'app/core/internationalization';
|
import { Trans } from 'app/core/internationalization';
|
||||||
import { DashboardModel } from 'app/features/dashboard/state';
|
import { DashboardModel } from 'app/features/dashboard/state';
|
||||||
@ -83,32 +83,6 @@ const DashboardEmpty = ({ dashboard, canCreate }: Props) => {
|
|||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
<Stack direction={{ xs: 'column', md: 'row' }} wrap="wrap" gap={4}>
|
<Stack direction={{ xs: 'column', md: 'row' }} wrap="wrap" gap={4}>
|
||||||
{config.featureToggles.vizAndWidgetSplit && (
|
|
||||||
<Box borderColor="strong" borderStyle="dashed" padding={3} flex={1}>
|
|
||||||
<Stack direction="column" alignItems="center" gap={1}>
|
|
||||||
<Text element="h3" textAlignment="center" weight="medium">
|
|
||||||
<Trans i18nKey="dashboard.empty.add-widget-header">Add a widget</Trans>
|
|
||||||
</Text>
|
|
||||||
<Box marginBottom={2}>
|
|
||||||
<Text element="p" textAlignment="center" color="secondary">
|
|
||||||
<Trans i18nKey="dashboard.empty.add-widget-body">Create lists, markdowns and other widgets</Trans>
|
|
||||||
</Text>
|
|
||||||
</Box>
|
|
||||||
<Button
|
|
||||||
icon="plus"
|
|
||||||
fill="outline"
|
|
||||||
data-testid={selectors.pages.AddDashboard.itemButton('Create new widget button')}
|
|
||||||
onClick={() => {
|
|
||||||
DashboardInteractions.emptyDashboardButtonClicked({ item: 'add_widget' });
|
|
||||||
locationService.partial({ addWidget: true });
|
|
||||||
}}
|
|
||||||
disabled={!canCreate}
|
|
||||||
>
|
|
||||||
<Trans i18nKey="dashboard.empty.add-widget-button">Add widget</Trans>
|
|
||||||
</Button>
|
|
||||||
</Stack>
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
<Box borderColor="strong" borderStyle="dashed" padding={3} flex={1}>
|
<Box borderColor="strong" borderStyle="dashed" padding={3} flex={1}>
|
||||||
<Stack direction="column" alignItems="center" gap={1}>
|
<Stack direction="column" alignItems="center" gap={1}>
|
||||||
<Text element="h3" textAlignment="center" weight="medium">
|
<Text element="h3" textAlignment="center" weight="medium">
|
||||||
|
@ -21,7 +21,6 @@ interface LibraryPanelViewProps {
|
|||||||
panelFilter?: string[];
|
panelFilter?: string[];
|
||||||
folderFilter?: string[];
|
folderFilter?: string[];
|
||||||
perPage?: number;
|
perPage?: number;
|
||||||
isWidget?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const LibraryPanelsView = ({
|
export const LibraryPanelsView = ({
|
||||||
@ -33,7 +32,6 @@ export const LibraryPanelsView = ({
|
|||||||
showSecondaryActions,
|
showSecondaryActions,
|
||||||
currentPanelId: currentPanel,
|
currentPanelId: currentPanel,
|
||||||
perPage: propsPerPage = 40,
|
perPage: propsPerPage = 40,
|
||||||
isWidget,
|
|
||||||
}: LibraryPanelViewProps) => {
|
}: LibraryPanelViewProps) => {
|
||||||
const styles = useStyles2(getPanelViewStyles);
|
const styles = useStyles2(getPanelViewStyles);
|
||||||
const [{ libraryPanels, page, perPage, numberOfPages, loadingState, currentPanelId }, dispatch] = useReducer(
|
const [{ libraryPanels, page, perPage, numberOfPages, loadingState, currentPanelId }, dispatch] = useReducer(
|
||||||
@ -56,7 +54,6 @@ export const LibraryPanelsView = ({
|
|||||||
page,
|
page,
|
||||||
perPage,
|
perPage,
|
||||||
currentPanelId,
|
currentPanelId,
|
||||||
isWidget,
|
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
300,
|
300,
|
||||||
|
@ -3,11 +3,6 @@ import { Dispatch } from 'react';
|
|||||||
import { from, merge, of, Subscription, timer } from 'rxjs';
|
import { from, merge, of, Subscription, timer } from 'rxjs';
|
||||||
import { catchError, finalize, mapTo, mergeMap, share, takeUntil } from 'rxjs/operators';
|
import { catchError, finalize, mapTo, mergeMap, share, takeUntil } from 'rxjs/operators';
|
||||||
|
|
||||||
import { PanelPluginMeta } from '@grafana/data';
|
|
||||||
import { config } from '@grafana/runtime';
|
|
||||||
import { LibraryPanel } from '@grafana/schema';
|
|
||||||
import { getAllPanelPluginMeta } from 'app/features/panel/state/util';
|
|
||||||
|
|
||||||
import { deleteLibraryPanel as apiDeleteLibraryPanel, getLibraryPanels } from '../../state/api';
|
import { deleteLibraryPanel as apiDeleteLibraryPanel, getLibraryPanels } from '../../state/api';
|
||||||
|
|
||||||
import { initialLibraryPanelsViewState, initSearch, searchCompleted } from './reducer';
|
import { initialLibraryPanelsViewState, initSearch, searchCompleted } from './reducer';
|
||||||
@ -21,29 +16,11 @@ interface SearchArgs {
|
|||||||
panelFilter?: string[];
|
panelFilter?: string[];
|
||||||
folderFilterUIDs?: string[];
|
folderFilterUIDs?: string[];
|
||||||
currentPanelId?: string;
|
currentPanelId?: string;
|
||||||
isWidget?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function searchForLibraryPanels(args: SearchArgs): DispatchResult {
|
export function searchForLibraryPanels(args: SearchArgs): DispatchResult {
|
||||||
// Functions to support filtering out library panels per plugin type that have skipDataQuery set to true
|
// Functions to support filtering out library panels per plugin type that have skipDataQuery set to true
|
||||||
|
|
||||||
const findPluginMeta = (pluginMeta: PanelPluginMeta, libraryPanel: LibraryPanel) =>
|
|
||||||
pluginMeta.id === libraryPanel.type;
|
|
||||||
|
|
||||||
const filterLibraryPanels = (libraryPanels: LibraryPanel[], isWidget: boolean) => {
|
|
||||||
const pluginMetaList = getAllPanelPluginMeta();
|
|
||||||
|
|
||||||
return libraryPanels.filter((libraryPanel) => {
|
|
||||||
const matchingPluginMeta = pluginMetaList.find((pluginMeta) => findPluginMeta(pluginMeta, libraryPanel));
|
|
||||||
// widget mode filter
|
|
||||||
if (isWidget) {
|
|
||||||
return !!matchingPluginMeta?.skipDataQuery;
|
|
||||||
}
|
|
||||||
// non-widget mode filter
|
|
||||||
return !matchingPluginMeta?.skipDataQuery;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return function (dispatch) {
|
return function (dispatch) {
|
||||||
const subscription = new Subscription();
|
const subscription = new Subscription();
|
||||||
const dataObservable = from(
|
const dataObservable = from(
|
||||||
@ -60,12 +37,6 @@ export function searchForLibraryPanels(args: SearchArgs): DispatchResult {
|
|||||||
//filter out library panels per plugin type that have skipDataQuery set to true
|
//filter out library panels per plugin type that have skipDataQuery set to true
|
||||||
mergeMap((libraryPanelsResult) => {
|
mergeMap((libraryPanelsResult) => {
|
||||||
const { elements: libraryPanels } = libraryPanelsResult;
|
const { elements: libraryPanels } = libraryPanelsResult;
|
||||||
|
|
||||||
if (config.featureToggles.vizAndWidgetSplit && args.isWidget !== undefined) {
|
|
||||||
const filteredLibraryPanels = filterLibraryPanels(libraryPanels, args.isWidget);
|
|
||||||
return of({ ...libraryPanelsResult, elements: filteredLibraryPanels });
|
|
||||||
}
|
|
||||||
|
|
||||||
return of({ ...libraryPanelsResult, elements: libraryPanels });
|
return of({ ...libraryPanelsResult, elements: libraryPanels });
|
||||||
}),
|
}),
|
||||||
mergeMap(({ perPage, elements: libraryPanels, page, totalCount }) =>
|
mergeMap(({ perPage, elements: libraryPanels, page, totalCount }) =>
|
||||||
|
@ -17,10 +17,9 @@ import { LibraryPanelsView } from '../LibraryPanelsView/LibraryPanelsView';
|
|||||||
interface Props {
|
interface Props {
|
||||||
panel: PanelModel;
|
panel: PanelModel;
|
||||||
searchQuery: string;
|
searchQuery: string;
|
||||||
isWidget?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PanelLibraryOptionsGroup = ({ panel, searchQuery, isWidget = false }: Props) => {
|
export const PanelLibraryOptionsGroup = ({ panel, searchQuery }: Props) => {
|
||||||
const [showingAddPanelModal, setShowingAddPanelModal] = useState(false);
|
const [showingAddPanelModal, setShowingAddPanelModal] = useState(false);
|
||||||
const [changeToPanel, setChangeToPanel] = useState<LibraryElementDTO | undefined>(undefined);
|
const [changeToPanel, setChangeToPanel] = useState<LibraryElementDTO | undefined>(undefined);
|
||||||
const [panelFilter, setPanelFilter] = useState<string[]>([]);
|
const [panelFilter, setPanelFilter] = useState<string[]>([]);
|
||||||
@ -54,7 +53,7 @@ export const PanelLibraryOptionsGroup = ({ panel, searchQuery, isWidget = false
|
|||||||
</VerticalGroup>
|
</VerticalGroup>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<PanelTypeFilter onChange={onPanelFilterChange} isWidget={isWidget} />
|
<PanelTypeFilter onChange={onPanelFilterChange} />
|
||||||
|
|
||||||
<div className={styles.libraryPanelsView}>
|
<div className={styles.libraryPanelsView}>
|
||||||
<LibraryPanelsView
|
<LibraryPanelsView
|
||||||
@ -63,7 +62,6 @@ export const PanelLibraryOptionsGroup = ({ panel, searchQuery, isWidget = false
|
|||||||
panelFilter={panelFilter}
|
panelFilter={panelFilter}
|
||||||
onClickCard={setChangeToPanel}
|
onClickCard={setChangeToPanel}
|
||||||
showSecondaryActions
|
showSecondaryActions
|
||||||
isWidget={isWidget}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -2,10 +2,9 @@ import { css } from '@emotion/css';
|
|||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { config } from '@grafana/runtime';
|
|
||||||
import { EmptySearchResult, useStyles2 } from '@grafana/ui';
|
import { EmptySearchResult, useStyles2 } from '@grafana/ui';
|
||||||
|
|
||||||
import { filterPluginList, getAllPanelPluginMeta, getVizPluginMeta, getWidgetPluginMeta } from '../../state/util';
|
import { filterPluginList, getAllPanelPluginMeta } from '../../state/util';
|
||||||
|
|
||||||
import { VizTypePickerPlugin } from './VizTypePickerPlugin';
|
import { VizTypePickerPlugin } from './VizTypePickerPlugin';
|
||||||
import { VizTypeChangeDetails } from './types';
|
import { VizTypeChangeDetails } from './types';
|
||||||
@ -14,18 +13,12 @@ export interface Props {
|
|||||||
pluginId: string;
|
pluginId: string;
|
||||||
searchQuery: string;
|
searchQuery: string;
|
||||||
onChange: (options: VizTypeChangeDetails) => void;
|
onChange: (options: VizTypeChangeDetails) => void;
|
||||||
isWidget?: boolean;
|
|
||||||
trackSearch?: (q: string, count: number) => void;
|
trackSearch?: (q: string, count: number) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function VizTypePicker({ pluginId, searchQuery, onChange, isWidget = false, trackSearch }: Props) {
|
export function VizTypePicker({ pluginId, searchQuery, onChange, trackSearch }: Props) {
|
||||||
const styles = useStyles2(getStyles);
|
const styles = useStyles2(getStyles);
|
||||||
const pluginsList = useMemo(() => {
|
const pluginsList = useMemo(getAllPanelPluginMeta, []);
|
||||||
if (config.featureToggles.vizAndWidgetSplit) {
|
|
||||||
return isWidget ? getWidgetPluginMeta() : getVizPluginMeta();
|
|
||||||
}
|
|
||||||
return getAllPanelPluginMeta();
|
|
||||||
}, [isWidget]);
|
|
||||||
|
|
||||||
const filteredPluginTypes = useMemo(() => {
|
const filteredPluginTypes = useMemo(() => {
|
||||||
const result = filterPluginList(pluginsList, searchQuery, pluginId);
|
const result = filterPluginList(pluginsList, searchQuery, pluginId);
|
||||||
|
@ -39,7 +39,7 @@ export async function getAllSuggestions(data?: PanelData, panel?: PanelModel): P
|
|||||||
|
|
||||||
const list = builder.getList();
|
const list = builder.getList();
|
||||||
|
|
||||||
if (!config.featureToggles.vizAndWidgetSplit && builder.dataSummary.fieldCount === 0) {
|
if (builder.dataSummary.fieldCount === 0) {
|
||||||
for (const plugin of Object.values(config.panels)) {
|
for (const plugin of Object.values(config.panels)) {
|
||||||
if (!plugin.skipDataQuery || plugin.hideFromList) {
|
if (!plugin.skipDataQuery || plugin.hideFromList) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -615,8 +615,7 @@
|
|||||||
"import": "Import from library",
|
"import": "Import from library",
|
||||||
"paste-panel": "Paste panel",
|
"paste-panel": "Paste panel",
|
||||||
"row": "Row",
|
"row": "Row",
|
||||||
"visualization": "Visualization",
|
"visualization": "Visualization"
|
||||||
"widget": "Widget"
|
|
||||||
},
|
},
|
||||||
"alert-rules-drawer": {
|
"alert-rules-drawer": {
|
||||||
"redirect-link": "List in Grafana Alerting",
|
"redirect-link": "List in Grafana Alerting",
|
||||||
@ -629,9 +628,6 @@
|
|||||||
"add-visualization-body": "Select a data source and then query and visualize your data with charts, stats and tables or create lists, markdowns and other widgets.",
|
"add-visualization-body": "Select a data source and then query and visualize your data with charts, stats and tables or create lists, markdowns and other widgets.",
|
||||||
"add-visualization-button": "Add visualization",
|
"add-visualization-button": "Add visualization",
|
||||||
"add-visualization-header": "Start your new dashboard by adding a visualization",
|
"add-visualization-header": "Start your new dashboard by adding a visualization",
|
||||||
"add-widget-body": "Create lists, markdowns and other widgets",
|
|
||||||
"add-widget-button": "Add widget",
|
|
||||||
"add-widget-header": "Add a widget",
|
|
||||||
"import-a-dashboard-body": "Import dashboards from files or <1>grafana.com</1>.",
|
"import-a-dashboard-body": "Import dashboards from files or <1>grafana.com</1>.",
|
||||||
"import-a-dashboard-header": "Import a dashboard",
|
"import-a-dashboard-header": "Import a dashboard",
|
||||||
"import-dashboard-button": "Import dashboard"
|
"import-dashboard-button": "Import dashboard"
|
||||||
|
@ -615,8 +615,7 @@
|
|||||||
"import": "Ĩmpőřŧ ƒřőm ľįþřäřy",
|
"import": "Ĩmpőřŧ ƒřőm ľįþřäřy",
|
||||||
"paste-panel": "Päşŧę päʼnęľ",
|
"paste-panel": "Päşŧę päʼnęľ",
|
||||||
"row": "Ŗőŵ",
|
"row": "Ŗőŵ",
|
||||||
"visualization": "Vįşūäľįžäŧįőʼn",
|
"visualization": "Vįşūäľįžäŧįőʼn"
|
||||||
"widget": "Ŵįđģęŧ"
|
|
||||||
},
|
},
|
||||||
"alert-rules-drawer": {
|
"alert-rules-drawer": {
|
||||||
"redirect-link": "Ŀįşŧ įʼn Ğřäƒäʼnä Åľęřŧįʼnģ",
|
"redirect-link": "Ŀįşŧ įʼn Ğřäƒäʼnä Åľęřŧįʼnģ",
|
||||||
@ -629,9 +628,6 @@
|
|||||||
"add-visualization-body": "Ŝęľęčŧ ä đäŧä şőūřčę äʼnđ ŧĥęʼn qūęřy äʼnđ vįşūäľįžę yőūř đäŧä ŵįŧĥ čĥäřŧş, şŧäŧş äʼnđ ŧäþľęş őř čřęäŧę ľįşŧş, mäřĸđőŵʼnş äʼnđ őŧĥęř ŵįđģęŧş.",
|
"add-visualization-body": "Ŝęľęčŧ ä đäŧä şőūřčę äʼnđ ŧĥęʼn qūęřy äʼnđ vįşūäľįžę yőūř đäŧä ŵįŧĥ čĥäřŧş, şŧäŧş äʼnđ ŧäþľęş őř čřęäŧę ľįşŧş, mäřĸđőŵʼnş äʼnđ őŧĥęř ŵįđģęŧş.",
|
||||||
"add-visualization-button": "Åđđ vįşūäľįžäŧįőʼn",
|
"add-visualization-button": "Åđđ vįşūäľįžäŧįőʼn",
|
||||||
"add-visualization-header": "Ŝŧäřŧ yőūř ʼnęŵ đäşĥþőäřđ þy äđđįʼnģ ä vįşūäľįžäŧįőʼn",
|
"add-visualization-header": "Ŝŧäřŧ yőūř ʼnęŵ đäşĥþőäřđ þy äđđįʼnģ ä vįşūäľįžäŧįőʼn",
|
||||||
"add-widget-body": "Cřęäŧę ľįşŧş, mäřĸđőŵʼnş äʼnđ őŧĥęř ŵįđģęŧş",
|
|
||||||
"add-widget-button": "Åđđ ŵįđģęŧ",
|
|
||||||
"add-widget-header": "Åđđ ä ŵįđģęŧ",
|
|
||||||
"import-a-dashboard-body": "Ĩmpőřŧ đäşĥþőäřđş ƒřőm ƒįľęş őř <1>ģřäƒäʼnä.čőm</1>.",
|
"import-a-dashboard-body": "Ĩmpőřŧ đäşĥþőäřđş ƒřőm ƒįľęş őř <1>ģřäƒäʼnä.čőm</1>.",
|
||||||
"import-a-dashboard-header": "Ĩmpőřŧ ä đäşĥþőäřđ",
|
"import-a-dashboard-header": "Ĩmpőřŧ ä đäşĥþőäřđ",
|
||||||
"import-dashboard-button": "Ĩmpőřŧ đäşĥþőäřđ"
|
"import-dashboard-button": "Ĩmpőřŧ đäşĥþőäřđ"
|
||||||
|
Reference in New Issue
Block a user