From 3aa8eb017620fd11b4bc311bce7afe3692936a51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 20 Apr 2020 08:47:25 +0200 Subject: [PATCH] NewPanelEdit: Improvements to angular panels and other fixes (#23678) * Removed old editor components * Angular panel improvements * Progress * Updated tests * Simple persistence for angular panel option state * Improving graph edit experiance * Improving series overrides * updated e2e test * Regstry: refactoring --- e2e/suite1/specs/queryVariableCrud.spec.ts | 12 +- e2e/suite1/specs/smoketests.spec.ts | 16 +- packages/grafana-data/src/utils/Registry.ts | 37 +- packages/grafana-e2e/src/noTypeCheck.ts | 3 +- packages/grafana-e2e/src/pages/graph/index.ts | 8 + .../src/pages/graph/visualizationTab.ts | 3 + packages/grafana-e2e/src/pages/index.ts | 33 +- .../PanelOptionsGroup/_PanelOptionsGroup.scss | 59 +--- .../src/themes/_variables.dark.scss.tmpl.ts | 3 +- .../src/themes/_variables.light.scss.tmpl.ts | 1 + .../core/components/BackButton/BackButton.tsx | 2 +- public/app/features/alerting/AlertTab.tsx | 12 +- .../PanelEditor/AngularPanelOptions.tsx | 32 +- .../PanelEditor/DynamicConfigValueEditor.tsx | 2 +- .../components/PanelEditor/OptionsGroup.tsx | 2 + .../PanelEditor/OptionsPaneContent.tsx | 10 +- .../components/PanelEditor/PanelEditor.tsx | 10 +- .../PanelEditor/PanelOptionsTab.tsx | 8 +- .../PanelEditor/state/actions.test.ts | 14 +- .../components/PanelEditor/state/actions.ts | 4 +- .../components/PanelEditor/state/reducers.ts | 8 +- .../components/PanelEditor/state/utils.ts | 9 + .../dashboard/components/PanelEditor/types.ts | 2 +- .../containers/DashboardPage.test.tsx | 4 +- .../dashboard/containers/DashboardPage.tsx | 8 +- .../dashboard/dashgrid/DashboardGrid.tsx | 2 +- .../dashgrid/PanelHeader/PanelHeader.tsx | 2 +- .../PanelHeader/PanelHeaderMenuItem.tsx | 5 +- .../panel_editor/AngularPanelOptions.tsx | 120 ------- .../dashboard/panel_editor/GeneralTab.tsx | 77 ---- .../dashboard/panel_editor/PanelEditor.tsx | 135 ------- .../panel_editor/VisualizationTab.tsx | 233 ------------ .../panel_editor/VizPickerSearch.tsx | 26 -- .../panel_editor/state/actions.test.ts | 127 ------- .../dashboard/panel_editor/state/actions.ts | 42 --- .../panel_editor/state/reducers.test.ts | 43 --- .../dashboard/panel_editor/state/reducers.ts | 62 ---- .../panel_editor/state/selectors.test.ts | 88 ----- .../dashboard/panel_editor/state/selectors.ts | 11 - .../app/features/dashboard/state/reducers.ts | 4 +- .../plugins/datasource/testdata/query_ctrl.ts | 4 +- .../panel/graph/Legend/LegendSeriesItem.tsx | 9 +- public/app/plugins/panel/graph/axes_editor.ts | 4 +- public/app/plugins/panel/graph/module.ts | 6 +- .../app/plugins/panel/graph/tab_display.html | 334 ++++++++---------- .../app/plugins/panel/graph/tab_legend.html | 187 ++++++---- .../panel/graph/tab_series_overrides.html | 51 +++ .../plugins/panel/graph/tab_thresholds.html | 1 + .../graph/tab_thresholds_time_regions.html | 2 - .../plugins/panel/graph/tab_time_regions.html | 1 + .../panel/graph/time_regions_form.html | 2 +- public/app/types/store.ts | 4 +- public/sass/_variables.dark.generated.scss | 3 +- public/sass/_variables.light.generated.scss | 1 + public/sass/components/_panel_graph.scss | 14 +- 55 files changed, 507 insertions(+), 1395 deletions(-) create mode 100644 public/app/features/dashboard/components/PanelEditor/state/utils.ts delete mode 100644 public/app/features/dashboard/panel_editor/AngularPanelOptions.tsx delete mode 100644 public/app/features/dashboard/panel_editor/GeneralTab.tsx delete mode 100644 public/app/features/dashboard/panel_editor/PanelEditor.tsx delete mode 100644 public/app/features/dashboard/panel_editor/VisualizationTab.tsx delete mode 100644 public/app/features/dashboard/panel_editor/VizPickerSearch.tsx delete mode 100644 public/app/features/dashboard/panel_editor/state/actions.test.ts delete mode 100644 public/app/features/dashboard/panel_editor/state/actions.ts delete mode 100644 public/app/features/dashboard/panel_editor/state/reducers.test.ts delete mode 100644 public/app/features/dashboard/panel_editor/state/reducers.ts delete mode 100644 public/app/features/dashboard/panel_editor/state/selectors.test.ts delete mode 100644 public/app/features/dashboard/panel_editor/state/selectors.ts create mode 100644 public/app/plugins/panel/graph/tab_series_overrides.html create mode 100644 public/app/plugins/panel/graph/tab_thresholds.html delete mode 100644 public/app/plugins/panel/graph/tab_thresholds_time_regions.html create mode 100644 public/app/plugins/panel/graph/tab_time_regions.html diff --git a/e2e/suite1/specs/queryVariableCrud.spec.ts b/e2e/suite1/specs/queryVariableCrud.spec.ts index 162392b274d..109c1a41991 100644 --- a/e2e/suite1/specs/queryVariableCrud.spec.ts +++ b/e2e/suite1/specs/queryVariableCrud.spec.ts @@ -203,7 +203,7 @@ const assertAdding3dependantQueryVariablesScenario = (queryVariables: QueryVaria e2e.pages.SaveDashboardModal.save().click(); e2e.flows.assertSuccessNotification(); - e2e.pages.Components.BackButton.backArrow().click(); + e2e.components.BackButton.backArrow().click(); assertVariableLabelsAndComponents(asserts); @@ -258,7 +258,7 @@ const assertDuplicateItem = (queryVariables: QueryVariableData[]) => { e2e.pages.SaveDashboardModal.save().click(); e2e.flows.assertSuccessNotification(); - e2e.pages.Components.BackButton.backArrow().click(); + e2e.components.BackButton.backArrow().click(); e2e.pages.Dashboard.SubMenu.submenuItemLabels(newItem.label).should('be.visible'); e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownValueLinkTexts(newItem.selectedOption) @@ -294,7 +294,7 @@ const assertDeleteItem = (queryVariables: QueryVariableData[]) => { e2e.pages.SaveDashboardModal.save().click(); e2e.flows.assertSuccessNotification(); - e2e.pages.Components.BackButton.backArrow().click(); + e2e.components.BackButton.backArrow().click(); e2e.pages.Dashboard.SubMenu.submenuItemLabels(itemToDelete.label).should('not.exist'); @@ -341,7 +341,7 @@ const assertUpdateItem = (data: QueryVariableData[]) => { e2e.pages.Dashboard.Settings.Variables.Edit.General.generalHideSelect().select(''); e2e.pages.Dashboard.Settings.Variables.Edit.ConstantVariable.constantOptionsQueryInput().type(updatedItem.query); - e2e.pages.Components.BackButton.backArrow().click(); + e2e.components.BackButton.backArrow().click(); e2e() .window() @@ -397,7 +397,7 @@ const assertMoveDownItem = (data: QueryVariableData[]) => { }); }); - e2e.pages.Components.BackButton.backArrow().click(); + e2e.components.BackButton.backArrow().click(); assertVariableLabelsAndComponents(queryVariables); @@ -542,7 +542,7 @@ const assertMoveUpItem = (data: QueryVariableData[]) => { }); }); - e2e.pages.Components.BackButton.backArrow().click(); + e2e.components.BackButton.backArrow().click(); assertVariableLabelsAndComponents(queryVariables); diff --git a/e2e/suite1/specs/smoketests.spec.ts b/e2e/suite1/specs/smoketests.spec.ts index b4410986e66..9d505909002 100644 --- a/e2e/suite1/specs/smoketests.spec.ts +++ b/e2e/suite1/specs/smoketests.spec.ts @@ -15,13 +15,17 @@ e2e.scenario({ e2e.pages.Dashboard.Toolbar.toolbarItems('Add panel').click(); e2e.pages.AddDashboard.ctaButtons('Add Query').click(); - e2e.pages.Dashboard.Panels.DataSource.TestData.QueryTab.scenarioSelect().select('CSV Metric Values'); + e2e.components.DataSource.TestData.QueryTab.scenarioSelect().select('CSV Metric Values'); - e2e.pages.Dashboard.Panels.Visualization.Graph.VisualizationTab.xAxisSection() - .contains('Show') - .click(); + // Make sure the graph renders via checking legend + e2e.components.Panels.Visualization.Graph.Legend.legendItemAlias('A-series').should('be.visible'); - // e2e.pages.Dashboard.Panels.Panel.title('Panel Title').click(); - // e2e.pages.Dashboard.Panels.Panel.headerItems('Inspect').click(); + // Expand options section + e2e.components.Panels.Visualization.Graph.VisualizationTab.legendSection().click(); + + // Disable legend + e2e.components.Panels.Visualization.Graph.Legend.showLegendSwitch().click(); + + e2e.components.Panels.Visualization.Graph.Legend.legendItemAlias('A-series').should('not.exist'); }, }); diff --git a/packages/grafana-data/src/utils/Registry.ts b/packages/grafana-data/src/utils/Registry.ts index 68fe183abc2..9ac7f0c5e4c 100644 --- a/packages/grafana-data/src/utils/Registry.ts +++ b/packages/grafana-data/src/utils/Registry.ts @@ -46,20 +46,26 @@ export class Registry { getIfExists(id: string | undefined): T | undefined { if (!this.initialized) { - if (this.init) { - for (const ext of this.init()) { - this.register(ext); - } - } - this.sort(); - this.initialized = true; + this.initialize(); } + if (id) { return this.byId.get(id); } + return undefined; } + private initialize() { + if (this.init) { + for (const ext of this.init()) { + this.register(ext); + } + } + this.sort(); + this.initialized = true; + } + get(id: string): T { const v = this.getIfExists(id); if (!v) { @@ -70,7 +76,7 @@ export class Registry { selectOptions(current?: string[], filter?: (ext: T) => boolean): RegistrySelectInfo { if (!this.initialized) { - this.getIfExists('xxx'); // will trigger init + this.initialize(); } const select = { @@ -111,6 +117,10 @@ export class Registry { * Return a list of values by ID, or all values if not specified */ list(ids?: any[]): T[] { + if (!this.initialized) { + this.initialize(); + } + if (ids) { const found: T[] = []; for (const id of ids) { @@ -121,16 +131,23 @@ export class Registry { } return found; } + + return this.ordered; + } + + isEmpty(): boolean { if (!this.initialized) { - this.getIfExists('xxx'); // will trigger init + this.initialize(); } - return this.ordered; // copy of everythign just in case + + return this.ordered.length === 0; } register(ext: T) { if (this.byId.has(ext.id)) { throw new Error('Duplicate Key:' + ext.id); } + this.byId.set(ext.id, ext); this.ordered.push(ext); diff --git a/packages/grafana-e2e/src/noTypeCheck.ts b/packages/grafana-e2e/src/noTypeCheck.ts index 34b860d9655..837b7152055 100644 --- a/packages/grafana-e2e/src/noTypeCheck.ts +++ b/packages/grafana-e2e/src/noTypeCheck.ts @@ -4,7 +4,7 @@ // toBe, toEqual and so forth. That's why this file is not type checked and will be so until we // can solve the above mentioned issue with Cypress/Jest. import { e2eScenario, ScenarioArguments } from './support/scenario'; -import { Pages } from './pages'; +import { Pages, Components } from './pages'; import { Flows } from './flows'; import { getScenarioContext, setScenarioContext } from './support/scenarioContext'; @@ -21,6 +21,7 @@ const e2eObject = { imgSrcToBlob: (url: string) => Cypress.Blob.imgSrcToBlob(url), scenario: (args: ScenarioArguments) => e2eScenario(args), pages: Pages, + components: Components, flows: Flows, getScenarioContext, setScenarioContext, diff --git a/packages/grafana-e2e/src/pages/graph/index.ts b/packages/grafana-e2e/src/pages/graph/index.ts index 62f1e7711e0..5ef19a026c4 100644 --- a/packages/grafana-e2e/src/pages/graph/index.ts +++ b/packages/grafana-e2e/src/pages/graph/index.ts @@ -1,5 +1,13 @@ import { VisualizationTab } from './visualizationTab'; +import { pageFactory } from '../../support'; export const Graph = { VisualizationTab, + Legend: pageFactory({ + url: '', + selectors: { + legendItemAlias: (name: string) => `gpl alias ${name}`, + showLegendSwitch: 'gpl show legend', + }, + }), }; diff --git a/packages/grafana-e2e/src/pages/graph/visualizationTab.ts b/packages/grafana-e2e/src/pages/graph/visualizationTab.ts index a059f95fec0..f058e917d94 100644 --- a/packages/grafana-e2e/src/pages/graph/visualizationTab.ts +++ b/packages/grafana-e2e/src/pages/graph/visualizationTab.ts @@ -4,5 +4,8 @@ export const VisualizationTab = pageFactory({ url: '', selectors: { xAxisSection: 'X-Axis section', + axesSection: 'Axes section', + legendSection: 'Legend section', + displaySection: 'Display section', }, }); diff --git a/packages/grafana-e2e/src/pages/index.ts b/packages/grafana-e2e/src/pages/index.ts index 70cef42b378..f9b068dad7d 100644 --- a/packages/grafana-e2e/src/pages/index.ts +++ b/packages/grafana-e2e/src/pages/index.ts @@ -39,26 +39,27 @@ export const Pages = { }, }, }, - Panels: { - Panel, - EditPanel, - DataSource: { - TestData, - }, - Visualization: { - Graph, - }, - }, }, Dashboards, SaveDashboardAsModal, SaveDashboardModal, SharePanelModal, - Components: { - BackButton: pageFactory({ - selectors: { - backArrow: 'Go Back button', - }, - }), +}; + +export const Components = { + DataSource: { + TestData, }, + Panels: { + Panel, + EditPanel, + Visualization: { + Graph, + }, + }, + BackButton: pageFactory({ + selectors: { + backArrow: 'Go Back button', + }, + }), }; diff --git a/packages/grafana-ui/src/components/PanelOptionsGroup/_PanelOptionsGroup.scss b/packages/grafana-ui/src/components/PanelOptionsGroup/_PanelOptionsGroup.scss index 2b1a401d1e4..75b60807e9a 100644 --- a/packages/grafana-ui/src/components/PanelOptionsGroup/_PanelOptionsGroup.scss +++ b/packages/grafana-ui/src/components/PanelOptionsGroup/_PanelOptionsGroup.scss @@ -1,67 +1,34 @@ .panel-options-group { - margin-bottom: 10px; - border: $panel-options-group-border; - border-radius: $border-radius; - background: $page-bg; + border-bottom: $panel-border; } .panel-options-group__header { - padding: 4px 8px; - background: $panel-options-group-header-bg; + padding: 8px 16px 8px 8px; position: relative; - border-radius: $border-radius $border-radius 0 0; display: flex; align-items: center; - - .btn { - position: absolute; - right: 0; - top: 0; - } -} - -.panel-options-group__add-btn { - background: none; - border: none; - display: flex; - align-items: center; - padding: 0; + cursor: pointer; + font-weight: 500; + color: $text-color-semi-weak; &:hover { - .panel-options-group__add-circle { - background-color: $btn-primary-bg; - color: $white; + color: $text-color; + + .panel-options-group__icon { + color: $text-color; } } } -.panel-options-group__add-circle { - @include gradientBar($btn-success-bg, $btn-success-bg-hl, #fff); - - border-radius: 50px; - width: 20px; - height: 20px; - display: flex; - align-items: center; - justify-content: center; - margin-right: 6px; - - i { - position: relative; - top: 1px; - } +.panel-options-group__icon { + color: $text-color-weak; + margin-right: 8px; } .panel-options-group__title { - font-size: 16px; position: relative; - top: 1px; } .panel-options-group__body { - padding: 20px; - - &--queries { - min-height: 200px; - } + padding: 8px 16px 16px 32px; } diff --git a/packages/grafana-ui/src/themes/_variables.dark.scss.tmpl.ts b/packages/grafana-ui/src/themes/_variables.dark.scss.tmpl.ts index 52c0ee0bb0f..09403b6a513 100644 --- a/packages/grafana-ui/src/themes/_variables.dark.scss.tmpl.ts +++ b/packages/grafana-ui/src/themes/_variables.dark.scss.tmpl.ts @@ -87,8 +87,9 @@ $body-bg: ${theme.colors.bodyBg}; $page-bg: ${theme.colors.bodyBg}; $dashboard-bg: ${theme.colors.dashboardBg}; -$text-color: ${theme.colors.text}; $text-color-strong: ${theme.colors.textStrong}; +$text-color: ${theme.colors.text}; +$text-color-semi-weak: ${theme.colors.textSemiWeak}; $text-color-weak: ${theme.colors.textWeak}; $text-color-faint: ${theme.colors.textFaint}; $text-color-emphasis: ${theme.colors.textStrong}; diff --git a/packages/grafana-ui/src/themes/_variables.light.scss.tmpl.ts b/packages/grafana-ui/src/themes/_variables.light.scss.tmpl.ts index eeb8a0932d4..89de2ef3819 100644 --- a/packages/grafana-ui/src/themes/_variables.light.scss.tmpl.ts +++ b/packages/grafana-ui/src/themes/_variables.light.scss.tmpl.ts @@ -83,6 +83,7 @@ $dashboard-bg: ${theme.colors.dashboardBg}; $text-color: ${theme.colors.text}; $text-color-strong: ${theme.colors.textStrong}; +$text-color-semi-weak: ${theme.colors.textSemiWeak}; $text-color-weak: ${theme.colors.textWeak}; $text-color-faint: ${theme.colors.textFaint}; $text-color-emphasis: ${theme.colors.textStrong}; diff --git a/public/app/core/components/BackButton/BackButton.tsx b/public/app/core/components/BackButton/BackButton.tsx index e4d1e5068b0..c951da4fd75 100644 --- a/public/app/core/components/BackButton/BackButton.tsx +++ b/public/app/core/components/BackButton/BackButton.tsx @@ -14,7 +14,7 @@ export const BackButton: React.FC = ({ surface, onClick }) => { tooltipPlacement="bottom" size="xxl" surface={surface} - aria-label={e2e.pages.Components.BackButton.selectors.backArrow} + aria-label={e2e.components.BackButton.selectors.backArrow} onClick={onClick} /> ); diff --git a/public/app/features/alerting/AlertTab.tsx b/public/app/features/alerting/AlertTab.tsx index b0d00a0f2b1..7c114bbdd35 100644 --- a/public/app/features/alerting/AlertTab.tsx +++ b/public/app/features/alerting/AlertTab.tsx @@ -16,9 +16,9 @@ import { DashboardModel } from '../dashboard/state/DashboardModel'; import { PanelModel } from '../dashboard/state/PanelModel'; import { TestRuleResult } from './TestRuleResult'; import { AppNotificationSeverity, StoreState } from 'app/types'; -import { PanelEditorTabIds, getPanelEditorTab } from '../dashboard/panel_editor/state/reducers'; -import { changePanelEditorTab } from '../dashboard/panel_editor/state/actions'; import { CoreEvents } from 'app/types'; +import { updateLocation } from 'app/core/actions'; +import { PanelEditorTabId } from '../dashboard/components/PanelEditor/types'; interface OwnProps { dashboard: DashboardModel; @@ -30,7 +30,7 @@ interface ConnectedProps { } interface DispatchProps { - changePanelEditorTab: typeof changePanelEditorTab; + updateLocation: typeof updateLocation; } export type Props = OwnProps & ConnectedProps & DispatchProps; @@ -161,8 +161,8 @@ class UnConnectedAlertTab extends PureComponent { }; switchToQueryTab = () => { - const { changePanelEditorTab } = this.props; - changePanelEditorTab(getPanelEditorTab(PanelEditorTabIds.Queries)); + const { updateLocation } = this.props; + updateLocation({ query: { tab: PanelEditorTabId.Query }, partial: true }); }; renderValidationMessage = () => { @@ -228,6 +228,6 @@ const mapStateToProps: MapStateToProps = ( }; }; -const mapDispatchToProps: MapDispatchToProps = { changePanelEditorTab }; +const mapDispatchToProps: MapDispatchToProps = { updateLocation }; export const AlertTab = connect(mapStateToProps, mapDispatchToProps)(UnConnectedAlertTab); diff --git a/public/app/features/dashboard/components/PanelEditor/AngularPanelOptions.tsx b/public/app/features/dashboard/components/PanelEditor/AngularPanelOptions.tsx index 21d06470927..158dffaa1b5 100644 --- a/public/app/features/dashboard/components/PanelEditor/AngularPanelOptions.tsx +++ b/public/app/features/dashboard/components/PanelEditor/AngularPanelOptions.tsx @@ -11,6 +11,7 @@ import { PanelPlugin, PanelPluginMeta } from '@grafana/data'; import { PanelCtrl } from 'app/plugins/sdk'; import { changePanelPlugin } from '../../state/actions'; import { StoreState } from 'app/types'; +import { getSectionOpenState, saveSectionOpenState } from './state/utils'; interface OwnProps { panel: PanelModel; @@ -84,16 +85,18 @@ export class AngularPanelOptionsUnconnected extends PureComponent { let template = ''; for (let i = 0; i < panelCtrl.editorTabs.length; i++) { - template += - ` -
` + - (i > 0 - ? `
- {{ctrl.editorTabs[${i}].title}} - -
` - : '') + - `
+ const tab = panelCtrl.editorTabs[i]; + tab.isOpen = getSectionOpenState(tab.title, i === 0); + + template += ` +
+
+
+ +
+
${tab.title}
+
+
@@ -101,7 +104,14 @@ export class AngularPanelOptionsUnconnected extends PureComponent { } const loader = getAngularLoader(); - const scopeProps = { ctrl: panelCtrl }; + const scopeProps = { + ctrl: panelCtrl, + toggleOptionGroup: (index: number) => { + const tab = panelCtrl.editorTabs[index]; + tab.isOpen = !tab.isOpen; + saveSectionOpenState(tab.title, tab.isOpen as boolean); + }, + }; this.angularOptions = loader.load(this.element, scopeProps, template); } diff --git a/public/app/features/dashboard/components/PanelEditor/DynamicConfigValueEditor.tsx b/public/app/features/dashboard/components/PanelEditor/DynamicConfigValueEditor.tsx index 7e640a5bb8e..09f6872d136 100644 --- a/public/app/features/dashboard/components/PanelEditor/DynamicConfigValueEditor.tsx +++ b/public/app/features/dashboard/components/PanelEditor/DynamicConfigValueEditor.tsx @@ -66,7 +66,7 @@ export const DynamicConfigValueEditor: React.FC = } else { editor = (
- + { diff --git a/public/app/features/dashboard/components/PanelEditor/OptionsGroup.tsx b/public/app/features/dashboard/components/PanelEditor/OptionsGroup.tsx index 3913d4a7556..cb537ff41d6 100644 --- a/public/app/features/dashboard/components/PanelEditor/OptionsGroup.tsx +++ b/public/app/features/dashboard/components/PanelEditor/OptionsGroup.tsx @@ -64,6 +64,8 @@ const getStyles = stylesFactory((theme: GrafanaTheme, isExpanded: boolean, isNes font-weight: ${theme.typography.weight.semibold}; &:hover { + color: ${theme.colors.text}; + .editor-options-group-toggle { color: ${theme.colors.text}; } diff --git a/public/app/features/dashboard/components/PanelEditor/OptionsPaneContent.tsx b/public/app/features/dashboard/components/PanelEditor/OptionsPaneContent.tsx index 6d7af993f26..2a5907ea1a0 100644 --- a/public/app/features/dashboard/components/PanelEditor/OptionsPaneContent.tsx +++ b/public/app/features/dashboard/components/PanelEditor/OptionsPaneContent.tsx @@ -86,7 +86,7 @@ export const OptionsPaneContent: React.FC = ({ = ({ export const TabsBarContent: React.FC<{ width: number; - showFields: boolean; + plugin: PanelPlugin; isSearching: boolean; activeTab: string; styles: OptionsPaneStyles; @@ -132,7 +132,7 @@ export const TabsBarContent: React.FC<{ setSearchMode: (mode: boolean) => void; setActiveTab: (tab: string) => void; panel: PanelModel; -}> = ({ width, showFields, isSearching, activeTab, onClose, setSearchMode, setActiveTab, styles, panel }) => { +}> = ({ width, plugin, isSearching, activeTab, onClose, setSearchMode, setActiveTab, styles, panel }) => { const overridesCount = panel.getFieldConfig().overrides.length === 0 ? undefined : panel.getFieldConfig().overrides.length; @@ -174,7 +174,9 @@ export const TabsBarContent: React.FC<{ // Show the appropriate tabs let tabs = tabSelections; let active = tabs.find(v => v.value === activeTab); - if (!showFields) { + + // If no field configs hide Fields & Override tab + if (plugin.fieldConfigRegistry.isEmpty()) { active = tabSelections[0]; tabs = [active]; } diff --git a/public/app/features/dashboard/components/PanelEditor/PanelEditor.tsx b/public/app/features/dashboard/components/PanelEditor/PanelEditor.tsx index 0f137e01516..bef1f014420 100644 --- a/public/app/features/dashboard/components/PanelEditor/PanelEditor.tsx +++ b/public/app/features/dashboard/components/PanelEditor/PanelEditor.tsx @@ -336,17 +336,17 @@ export class PanelEditorUnconnected extends PureComponent { } const mapStateToProps: MapStateToProps = (state, props) => { - const panel = state.panelEditorNew.getPanel(); + const panel = state.panelEditor.getPanel(); const { plugin } = getPanelStateById(state.dashboard, panel.id); return { location: state.location, plugin: plugin, - panel: state.panelEditorNew.getPanel(), - data: state.panelEditorNew.getData(), - initDone: state.panelEditorNew.initDone, + panel: state.panelEditor.getPanel(), + data: state.panelEditor.getData(), + initDone: state.panelEditor.initDone, tabs: getPanelEditorTabs(state.location, plugin), - uiState: state.panelEditorNew.ui, + uiState: state.panelEditor.ui, variables: getVariables(state), }; }; diff --git a/public/app/features/dashboard/components/PanelEditor/PanelOptionsTab.tsx b/public/app/features/dashboard/components/PanelEditor/PanelOptionsTab.tsx index 5adf137f36a..463fa70ce57 100644 --- a/public/app/features/dashboard/components/PanelEditor/PanelOptionsTab.tsx +++ b/public/app/features/dashboard/components/PanelEditor/PanelOptionsTab.tsx @@ -6,7 +6,7 @@ import { OptionsGroup } from './OptionsGroup'; import { getPanelLinksVariableSuggestions } from '../../../panel/panellinks/link_srv'; import { getVariables } from '../../../variables/state/selectors'; import { PanelOptionsEditor } from './PanelOptionsEditor'; -import { AngularPanelOptions } from '../../panel_editor/AngularPanelOptions'; +import { AngularPanelOptions } from './AngularPanelOptions'; interface Props { panel: PanelModel; @@ -29,7 +29,7 @@ export const PanelOptionsTab: FC = ({ }) => { const elements: JSX.Element[] = []; const linkVariablesSuggestions = useMemo(() => getPanelLinksVariableSuggestions(), []); - const panelLinksCount = panel && panel.links ? panel.links.length : undefined; + const panelLinksCount = panel && panel.links ? panel.links.length : 0; const variableOptions = getVariableOptions(); const directionOptions = [ @@ -92,9 +92,7 @@ export const PanelOptionsTab: FC = ({ elements.push( ( - <> - Panel links {!isExpanded && panelLinksCount && panelLinksCount !== 0 && } - + <>Panel links {!isExpanded && panelLinksCount > 0 && } )} key="panel links" defaultToClosed={true} diff --git a/public/app/features/dashboard/components/PanelEditor/state/actions.test.ts b/public/app/features/dashboard/components/PanelEditor/state/actions.test.ts index 14d01bbbf52..a640c4f14f3 100644 --- a/public/app/features/dashboard/components/PanelEditor/state/actions.test.ts +++ b/public/app/features/dashboard/components/PanelEditor/state/actions.test.ts @@ -1,5 +1,5 @@ import { thunkTester } from '../../../../../../test/core/thunk/thunkTester'; -import { closeCompleted, initialState, PanelEditorStateNew } from './reducers'; +import { closeCompleted, initialState, PanelEditorState } from './reducers'; import { initPanelEditor, panelEditorCleanUp } from './actions'; import { cleanUpEditPanel, panelModelAndPluginReady } from '../../../state/reducers'; import { DashboardModel, PanelModel } from '../../../state'; @@ -36,7 +36,7 @@ describe('panelEditor actions', () => { const panel = sourcePanel.getEditClone(); panel.updateOptions({ prop: true }); - const state: PanelEditorStateNew = { + const state: PanelEditorState = { ...initialState(), getPanel: () => panel, getSourcePanel: () => sourcePanel, @@ -44,7 +44,7 @@ describe('panelEditor actions', () => { }; const dispatchedActions = await thunkTester({ - panelEditorNew: state, + panelEditor: state, dashboard: { getModel: () => dashboard, }, @@ -70,7 +70,7 @@ describe('panelEditor actions', () => { panel.plugin = getPanelPlugin({ id: 'table' }); panel.updateOptions({ prop: true }); - const state: PanelEditorStateNew = { + const state: PanelEditorState = { ...initialState(), getPanel: () => panel, getSourcePanel: () => sourcePanel, @@ -78,7 +78,7 @@ describe('panelEditor actions', () => { }; const dispatchedActions = await thunkTester({ - panelEditorNew: state, + panelEditor: state, dashboard: { getModel: () => dashboard, }, @@ -103,7 +103,7 @@ describe('panelEditor actions', () => { const panel = sourcePanel.getEditClone(); panel.updateOptions({ prop: true }); - const state: PanelEditorStateNew = { + const state: PanelEditorState = { ...initialState(), shouldDiscardChanges: true, getPanel: () => panel, @@ -112,7 +112,7 @@ describe('panelEditor actions', () => { }; const dispatchedActions = await thunkTester({ - panelEditorNew: state, + panelEditor: state, dashboard: { getModel: () => dashboard, }, diff --git a/public/app/features/dashboard/components/PanelEditor/state/actions.ts b/public/app/features/dashboard/components/PanelEditor/state/actions.ts index 80a9f06cdc3..2220830ca55 100644 --- a/public/app/features/dashboard/components/PanelEditor/state/actions.ts +++ b/public/app/features/dashboard/components/PanelEditor/state/actions.ts @@ -34,7 +34,7 @@ export function initPanelEditor(sourcePanel: PanelModel, dashboard: DashboardMod export function panelEditorCleanUp(): ThunkResult { return (dispatch, getStore) => { const dashboard = getStore().dashboard.getModel(); - const { getPanel, getSourcePanel, querySubscription, shouldDiscardChanges } = getStore().panelEditorNew; + const { getPanel, getSourcePanel, querySubscription, shouldDiscardChanges } = getStore().panelEditor; if (!shouldDiscardChanges) { const panel = getPanel(); @@ -76,7 +76,7 @@ export function panelEditorCleanUp(): ThunkResult { export function updatePanelEditorUIState(uiState: Partial): ThunkResult { return (dispatch, getStore) => { - const nextState = { ...getStore().panelEditorNew.ui, ...uiState }; + const nextState = { ...getStore().panelEditor.ui, ...uiState }; dispatch(setPanelEditorUIState(nextState)); store.setObject(PANEL_EDITOR_UI_STATE_STORAGE_KEY, nextState); }; diff --git a/public/app/features/dashboard/components/PanelEditor/state/reducers.ts b/public/app/features/dashboard/components/PanelEditor/state/reducers.ts index 89c3dea0e95..89b989da4db 100644 --- a/public/app/features/dashboard/components/PanelEditor/state/reducers.ts +++ b/public/app/features/dashboard/components/PanelEditor/state/reducers.ts @@ -25,7 +25,7 @@ export interface PanelEditorUIState { mode: DisplayMode; } -export interface PanelEditorStateNew { +export interface PanelEditorState { /* These are functions as they are mutaded later on and redux toolkit will Object.freeze state so * we need to store these using functions instead */ getSourcePanel: () => PanelModel; @@ -38,7 +38,7 @@ export interface PanelEditorStateNew { ui: PanelEditorUIState; } -export const initialState = (): PanelEditorStateNew => { +export const initialState = (): PanelEditorState => { return { getPanel: () => new PanelModel({}), getSourcePanel: () => new PanelModel({}), @@ -64,7 +64,7 @@ interface InitEditorPayload { } const pluginsSlice = createSlice({ - name: 'panelEditorNew', + name: 'panelEditor', initialState: initialState(), reducers: { updateEditorInitState: (state, action: PayloadAction) => { @@ -99,4 +99,4 @@ export const { setPanelEditorUIState, } = pluginsSlice.actions; -export const panelEditorReducerNew = pluginsSlice.reducer; +export const panelEditorReducer = pluginsSlice.reducer; diff --git a/public/app/features/dashboard/components/PanelEditor/state/utils.ts b/public/app/features/dashboard/components/PanelEditor/state/utils.ts new file mode 100644 index 00000000000..0a180091187 --- /dev/null +++ b/public/app/features/dashboard/components/PanelEditor/state/utils.ts @@ -0,0 +1,9 @@ +import store from 'app/core/store'; + +export function saveSectionOpenState(id: string, isOpen: boolean) { + store.set(`panel-edit-section-${id}`, isOpen ? 'true' : 'false'); +} + +export function getSectionOpenState(id: string, defaultValue: boolean) { + return store.getBool(`panel-edit-section-${id}`, defaultValue); +} diff --git a/public/app/features/dashboard/components/PanelEditor/types.ts b/public/app/features/dashboard/components/PanelEditor/types.ts index 13e6dde2a96..3cb069e3696 100644 --- a/public/app/features/dashboard/components/PanelEditor/types.ts +++ b/public/app/features/dashboard/components/PanelEditor/types.ts @@ -6,7 +6,7 @@ export interface PanelEditorTab { } export enum PanelEditorTabId { - Query = 'Query', + Query = 'query', Transform = 'transform', Visualize = 'visualize', Alert = 'alert', diff --git a/public/app/features/dashboard/containers/DashboardPage.test.tsx b/public/app/features/dashboard/containers/DashboardPage.test.tsx index 3b45f401f50..8c977cd7509 100644 --- a/public/app/features/dashboard/containers/DashboardPage.test.tsx +++ b/public/app/features/dashboard/containers/DashboardPage.test.tsx @@ -245,7 +245,7 @@ describe('DashboardPage', () => { editPanel: '1', }, }, - panelEditorNew: {}, + panelEditor: {}, dashboard: { getModel: () => ({} as DashboardModel), }, @@ -262,7 +262,7 @@ describe('DashboardPage', () => { viewPanel: '2', }, }, - panelEditorNew: {}, + panelEditor: {}, dashboard: { getModel: () => ({} as DashboardModel), }, diff --git a/public/app/features/dashboard/containers/DashboardPage.tsx b/public/app/features/dashboard/containers/DashboardPage.tsx index 0da2fc0ffee..2c3ec361d66 100644 --- a/public/app/features/dashboard/containers/DashboardPage.tsx +++ b/public/app/features/dashboard/containers/DashboardPage.tsx @@ -56,7 +56,7 @@ export interface Props { notifyApp: typeof notifyApp; updateLocation: typeof updateLocation; inspectTab?: InspectTab; - isNewEditorOpen?: boolean; + isPanelEditorOpen?: boolean; } export interface State { @@ -260,7 +260,7 @@ export class DashboardPage extends PureComponent { isInitSlow, initError, inspectTab, - isNewEditorOpen, + isPanelEditorOpen, updateLocation, } = this.props; @@ -303,8 +303,8 @@ export class DashboardPage extends PureComponent { dashboard={dashboard} viewPanel={viewPanel} editPanel={editPanel} - isNewEditorOpen={isNewEditorOpen} scrollTop={approximateScrollTop} + isPanelEditorOpen={isPanelEditorOpen} />
@@ -333,7 +333,7 @@ export const mapStateToProps = (state: StoreState) => ({ initError: state.dashboard.initError, dashboard: state.dashboard.getModel() as DashboardModel, inspectTab: state.location.query.inspectTab, - isNewEditorOpen: state.panelEditorNew.isOpen, + isPanelEditorOpen: state.panelEditor.isOpen, }); const mapDispatchToProps = { diff --git a/public/app/features/dashboard/dashgrid/DashboardGrid.tsx b/public/app/features/dashboard/dashgrid/DashboardGrid.tsx index 2eaacce225e..894fcbc7c23 100644 --- a/public/app/features/dashboard/dashgrid/DashboardGrid.tsx +++ b/public/app/features/dashboard/dashgrid/DashboardGrid.tsx @@ -97,7 +97,7 @@ export interface Props { editPanel: PanelModel | null; viewPanel: PanelModel | null; scrollTop: number; - isNewEditorOpen?: boolean; + isPanelEditorOpen?: boolean; } export class DashboardGrid extends PureComponent { diff --git a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeader.tsx b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeader.tsx index 786be0abe90..2b2122f5650 100644 --- a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeader.tsx +++ b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeader.tsx @@ -159,7 +159,7 @@ export class PanelHeader extends Component { className="panel-title-container" onClick={this.onMenuToggle} onMouseDown={this.onMouseDown} - aria-label={e2e.pages.Dashboard.Panels.Panel.selectors.title(title)} + aria-label={e2e.components.Panels.Panel.selectors.title(title)} >
{Object.values(notices).map(this.renderNotice)} diff --git a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderMenuItem.tsx b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderMenuItem.tsx index 4502167cd9e..56792dd4ff0 100644 --- a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderMenuItem.tsx +++ b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderMenuItem.tsx @@ -30,10 +30,7 @@ export const PanelHeaderMenuItem: FC = props => {
  • {props.iconClassName && } - + {props.text} {isSubMenu && } diff --git a/public/app/features/dashboard/panel_editor/AngularPanelOptions.tsx b/public/app/features/dashboard/panel_editor/AngularPanelOptions.tsx deleted file mode 100644 index 471758e1c69..00000000000 --- a/public/app/features/dashboard/panel_editor/AngularPanelOptions.tsx +++ /dev/null @@ -1,120 +0,0 @@ -// Libraries -import React, { PureComponent } from 'react'; -import { connect, MapStateToProps, MapDispatchToProps } from 'react-redux'; -// Utils & Services -import { AngularComponent, getAngularLoader } from '@grafana/runtime'; -// Types -import { PanelModel, DashboardModel } from '../state'; -import { PanelPlugin, PanelPluginMeta } from '@grafana/data'; -import { PanelCtrl } from 'app/plugins/sdk'; -import { changePanelPlugin } from '../state/actions'; -import { StoreState } from 'app/types'; - -interface OwnProps { - panel: PanelModel; - dashboard: DashboardModel; - plugin: PanelPlugin; -} - -interface ConnectedProps { - angularPanelComponent: AngularComponent; -} - -interface DispatchProps { - changePanelPlugin: typeof changePanelPlugin; -} - -type Props = OwnProps & ConnectedProps & DispatchProps; - -export class AngularPanelOptionsUnconnected extends PureComponent { - element?: HTMLElement; - angularOptions: AngularComponent; - - constructor(props: Props) { - super(props); - } - - componentDidMount() { - this.loadAngularOptions(); - } - - componentDidUpdate(prevProps: Props) { - if (this.props.plugin !== prevProps.plugin) { - this.cleanUpAngularOptions(); - } - - this.loadAngularOptions(); - } - - componentWillUnmount() { - this.cleanUpAngularOptions(); - } - - cleanUpAngularOptions() { - if (this.angularOptions) { - this.angularOptions.destroy(); - this.angularOptions = null; - } - } - - loadAngularOptions() { - const { panel, angularPanelComponent, changePanelPlugin } = this.props; - - if (!this.element || !angularPanelComponent || this.angularOptions) { - return; - } - - const scope = angularPanelComponent.getScope(); - - // When full page reloading in edit mode the angular panel has on fully compiled & instantiated yet - if (!scope.$$childHead) { - setTimeout(() => { - this.forceUpdate(); - }); - return; - } - - const panelCtrl: PanelCtrl = scope.$$childHead.ctrl; - panelCtrl.initEditMode(); - panelCtrl.onPluginTypeChange = (plugin: PanelPluginMeta) => { - changePanelPlugin(panel, plugin.id); - }; - - let template = ''; - for (let i = 0; i < panelCtrl.editorTabs.length; i++) { - template += - ` -
    ` + - (i > 0 - ? `
    - {{ctrl.editorTabs[${i}].title}} - -
    ` - : '') + - `
    - -
    -
    - `; - } - - const loader = getAngularLoader(); - const scopeProps = { ctrl: panelCtrl }; - - this.angularOptions = loader.load(this.element, scopeProps, template); - } - - render() { - return
    (this.element = elem)} />; - } -} - -const mapStateToProps: MapStateToProps = (state, props) => { - return { - angularPanelComponent: state.dashboard.panels[props.panel.id].angularComponent, - }; -}; - -const mapDispatchToProps: MapDispatchToProps = { changePanelPlugin }; - -export const AngularPanelOptions = connect(mapStateToProps, mapDispatchToProps)(AngularPanelOptionsUnconnected); diff --git a/public/app/features/dashboard/panel_editor/GeneralTab.tsx b/public/app/features/dashboard/panel_editor/GeneralTab.tsx deleted file mode 100644 index cf899a6042b..00000000000 --- a/public/app/features/dashboard/panel_editor/GeneralTab.tsx +++ /dev/null @@ -1,77 +0,0 @@ -// Libraries -import React, { PureComponent } from 'react'; - -// Components -import { getAngularLoader, AngularComponent } from '@grafana/runtime'; -import { EditorTabBody } from './EditorTabBody'; -import './../../panel/GeneralTabCtrl'; - -// Types -import { PanelModel } from '../state/PanelModel'; -import { DataLink } from '@grafana/data'; -import { PanelOptionsGroup, DataLinksEditor } from '@grafana/ui'; -import { getPanelLinksVariableSuggestions } from 'app/features/panel/panellinks/link_srv'; - -interface Props { - panel: PanelModel; -} - -export class GeneralTab extends PureComponent { - element: any; - component: AngularComponent; - - constructor(props: Props) { - super(props); - } - - componentDidMount() { - if (!this.element) { - return; - } - - const { panel } = this.props; - - const loader = getAngularLoader(); - const template = ''; - const scopeProps = { - ctrl: { - panel: panel, - }, - }; - - this.component = loader.load(this.element, scopeProps, template); - } - - componentWillUnmount() { - if (this.component) { - this.component.destroy(); - } - } - - onDataLinksChanged = (links: DataLink[], callback?: () => void) => { - this.props.panel.links = links; - this.props.panel.render(); - this.forceUpdate(callback); - }; - - render() { - const { panel } = this.props; - const suggestions = getPanelLinksVariableSuggestions(); - - return ( - - <> -
    (this.element = element)} /> - - - - - - ); - } -} diff --git a/public/app/features/dashboard/panel_editor/PanelEditor.tsx b/public/app/features/dashboard/panel_editor/PanelEditor.tsx deleted file mode 100644 index 9f1642967f8..00000000000 --- a/public/app/features/dashboard/panel_editor/PanelEditor.tsx +++ /dev/null @@ -1,135 +0,0 @@ -import React, { PureComponent } from 'react'; -import classNames from 'classnames'; -import { connect } from 'react-redux'; -import { Tooltip } from '@grafana/ui'; -import { PanelPlugin, PanelPluginMeta } from '@grafana/data'; -import { config } from '@grafana/runtime'; -import { e2e } from '@grafana/e2e'; - -import { QueriesTab } from './QueriesTab'; -import VisualizationTab from './VisualizationTab'; -import { GeneralTab } from './GeneralTab'; -import { AlertTab } from '../../alerting/AlertTab'; -import { PanelModel } from '../state/PanelModel'; -import { DashboardModel } from '../state/DashboardModel'; -import { StoreState } from '../../../types'; -import { panelEditorCleanUp, PanelEditorTab, PanelEditorTabIds } from './state/reducers'; -import { changePanelEditorTab, refreshPanelEditor } from './state/actions'; -import { changePanelPlugin } from '../state/actions'; -import { getActiveTabAndTabs } from './state/selectors'; - -interface PanelEditorProps { - panel: PanelModel; - dashboard: DashboardModel; - plugin: PanelPlugin; - activeTab: PanelEditorTabIds; - tabs: PanelEditorTab[]; - refreshPanelEditor: typeof refreshPanelEditor; - panelEditorCleanUp: typeof panelEditorCleanUp; - changePanelEditorTab: typeof changePanelEditorTab; - changePanelPlugin: typeof changePanelPlugin; -} - -class UnConnectedPanelEditor extends PureComponent { - constructor(props: PanelEditorProps) { - super(props); - } - - componentDidMount(): void { - this.refreshFromState(); - } - - componentWillUnmount(): void { - const { panelEditorCleanUp } = this.props; - panelEditorCleanUp(); - } - - refreshFromState = (meta?: PanelPluginMeta) => { - const { refreshPanelEditor, plugin } = this.props; - meta = meta || plugin.meta; - - refreshPanelEditor({ - hasQueriesTab: !meta.skipDataQuery, - usesGraphPlugin: meta.id === 'graph', - alertingEnabled: config.alertingEnabled, - }); - }; - - onChangeTab = (tab: PanelEditorTab) => { - const { changePanelEditorTab } = this.props; - // Angular Query Components can potentially refresh the PanelModel - // onBlur so this makes sure we change tab after that - setTimeout(() => changePanelEditorTab(tab), 10); - }; - - onPluginTypeChange = (newType: PanelPluginMeta) => { - this.props.changePanelPlugin(this.props.panel, newType.id); - this.refreshFromState(newType); - }; - - renderCurrentTab(activeTab: string) { - const { panel, dashboard, plugin } = this.props; - switch (activeTab) { - case 'advanced': - return ; - case 'queries': - return ; - case 'alert': - return ; - case 'visualization': - return ( - - ); - default: - return null; - } - } - - render() { - const { activeTab, tabs } = this.props; - - return ( -
    -
    - {tabs.map(tab => { - return ; - })} -
    -
    {this.renderCurrentTab(activeTab)}
    -
    - ); - } -} - -const mapStateToProps = (state: StoreState) => getActiveTabAndTabs(state.location, state.panelEditor); -const mapDispatchToProps = { refreshPanelEditor, panelEditorCleanUp, changePanelEditorTab, changePanelPlugin }; - -export const PanelEditor = connect(mapStateToProps, mapDispatchToProps)(UnConnectedPanelEditor); - -interface TabItemParams { - tab: PanelEditorTab; - activeTab: string; - onClick: (tab: PanelEditorTab) => void; -} - -function TabItem({ tab, activeTab, onClick }: TabItemParams) { - const tabClasses = classNames({ - 'panel-editor-tabs__link': true, - active: activeTab === tab.id, - }); - - return ( -
    - ); -} diff --git a/public/app/features/dashboard/panel_editor/VisualizationTab.tsx b/public/app/features/dashboard/panel_editor/VisualizationTab.tsx deleted file mode 100644 index 365e1415063..00000000000 --- a/public/app/features/dashboard/panel_editor/VisualizationTab.tsx +++ /dev/null @@ -1,233 +0,0 @@ -// Libraries -import React, { PureComponent } from 'react'; -// Utils & Services -import { connect } from 'react-redux'; -import { StoreState } from 'app/types'; -import { updateLocation } from 'app/core/actions'; -// Components -import { EditorTabBody, EditorToolbarView } from './EditorTabBody'; -import { VizTypePicker } from './VizTypePicker'; -import { PluginHelp } from 'app/core/components/PluginHelp/PluginHelp'; -import { FadeIn } from 'app/core/components/Animations/FadeIn'; -import { AngularPanelOptions } from './AngularPanelOptions'; -// Types -import { PanelModel, DashboardModel } from '../state'; -import { VizPickerSearch } from './VizPickerSearch'; -import PluginStateinfo from 'app/features/plugins/PluginStateInfo'; -import { Unsubscribable } from 'rxjs'; -import { Icon } from '@grafana/ui'; -import { - PanelPlugin, - PanelPluginMeta, - PanelData, - LoadingState, - DefaultTimeRange, - FieldConfigSource, -} from '@grafana/data'; - -interface Props { - panel: PanelModel; - dashboard: DashboardModel; - plugin: PanelPlugin; - onPluginTypeChange: (newType: PanelPluginMeta) => void; - updateLocation: typeof updateLocation; - urlOpenVizPicker: boolean; -} - -interface State { - isVizPickerOpen: boolean; - searchQuery: string; - scrollTop: number; - hasBeenFocused: boolean; - data: PanelData; -} - -export class VisualizationTab extends PureComponent { - element: HTMLElement; - querySubscription: Unsubscribable; - - constructor(props: Props) { - super(props); - - this.state = { - isVizPickerOpen: this.props.urlOpenVizPicker, - hasBeenFocused: false, - searchQuery: '', - scrollTop: 0, - data: { - state: LoadingState.NotStarted, - series: [], - timeRange: DefaultTimeRange, - }, - }; - } - - getReactPanelOptions = () => { - const { panel } = this.props; - return panel.getOptions(); - }; - - getReactPanelFieldConfig = () => { - const { panel } = this.props; - return panel.getFieldConfig(); - }; - - renderPanelOptions() { - const { plugin, dashboard, panel } = this.props; - - if (plugin.angularPanelCtrl) { - return ; - } - - if (plugin.editor) { - return ( - - ); - } - - return

    Visualization has no options

    ; - } - - componentDidMount() { - const { panel } = this.props; - const queryRunner = panel.getQueryRunner(); - - this.querySubscription = queryRunner.getData().subscribe({ - next: (data: PanelData) => this.setState({ data }), - }); - } - - componentWillUnmount() { - if (this.querySubscription) { - this.querySubscription.unsubscribe(); - } - } - - clearQuery = () => { - this.setState({ searchQuery: '' }); - }; - - onPanelOptionsChanged = (options: any, callback?: () => void) => { - this.props.panel.updateOptions(options); - this.forceUpdate(callback); - }; - - // TODO[FieldConfig]: Remove when we switch old editor to new - onPanelFieldConfigChange = (config: FieldConfigSource, callback?: () => void) => { - this.props.panel.updateFieldConfig(config); - this.forceUpdate(callback); - }; - - onOpenVizPicker = () => { - this.setState({ isVizPickerOpen: true, scrollTop: 0 }); - }; - - onCloseVizPicker = () => { - if (this.props.urlOpenVizPicker) { - this.props.updateLocation({ query: { openVizPicker: null }, partial: true }); - } - - this.setState({ isVizPickerOpen: false, hasBeenFocused: false }); - }; - - onSearchQueryChange = (value: string) => { - this.setState({ - searchQuery: value, - }); - }; - - renderToolbar = (): JSX.Element => { - const { plugin } = this.props; - const { isVizPickerOpen, searchQuery } = this.state; - const { meta } = plugin; - - if (isVizPickerOpen) { - return ( - - ); - } else { - return ( - <> -
    - -
    {meta.name}
    - -
    - - - ); - } - }; - - onPluginTypeChange = (plugin: PanelPluginMeta) => { - if (plugin.id === this.props.plugin.meta.id) { - this.setState({ isVizPickerOpen: false }); - } else { - this.props.onPluginTypeChange(plugin); - } - }; - - renderHelp = () => ; - - setScrollTop = (event: React.MouseEvent) => { - const target = event.target as HTMLElement; - this.setState({ scrollTop: target.scrollTop }); - }; - - render() { - const { plugin } = this.props; - const { isVizPickerOpen, searchQuery, scrollTop } = this.state; - const { meta } = plugin; - - const pluginHelp: EditorToolbarView = { - heading: 'Help', - icon: 'question-circle', - render: this.renderHelp, - }; - - return ( - - <> - - - - {this.renderPanelOptions()} - - - ); - } -} - -const mapStateToProps = (state: StoreState) => ({ - urlOpenVizPicker: !!state.location.query.openVizPicker, -}); - -const mapDispatchToProps = { - updateLocation, -}; - -export default connect(mapStateToProps, mapDispatchToProps)(VisualizationTab); diff --git a/public/app/features/dashboard/panel_editor/VizPickerSearch.tsx b/public/app/features/dashboard/panel_editor/VizPickerSearch.tsx deleted file mode 100644 index 4faeae7fceb..00000000000 --- a/public/app/features/dashboard/panel_editor/VizPickerSearch.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import React, { PureComponent } from 'react'; - -import { FilterInput } from 'app/core/components/FilterInput/FilterInput'; -import { PanelPluginMeta } from '@grafana/data'; -import { Icon } from '@grafana/ui'; - -interface Props { - plugin: PanelPluginMeta; - searchQuery: string; - onChange: (query: string) => void; - onClose: () => void; -} - -export class VizPickerSearch extends PureComponent { - render() { - const { searchQuery, onChange, onClose } = this.props; - return ( - <> - - - - ); - } -} diff --git a/public/app/features/dashboard/panel_editor/state/actions.test.ts b/public/app/features/dashboard/panel_editor/state/actions.test.ts deleted file mode 100644 index 0803a4761d2..00000000000 --- a/public/app/features/dashboard/panel_editor/state/actions.test.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { thunkTester } from '../../../../../test/core/thunk/thunkTester'; -import { getPanelEditorTab, initialState, panelEditorInitCompleted, PanelEditorTabIds } from './reducers'; -import { changePanelEditorTab, refreshPanelEditor } from './actions'; -import { updateLocation } from '../../../../core/actions'; - -describe('refreshPanelEditor', () => { - describe('when called and there is no activeTab in state', () => { - it('then the dispatched action should default the activeTab to PanelEditorTabIds.Queries', async () => { - const activeTab = PanelEditorTabIds.Queries; - const tabs = [ - getPanelEditorTab(PanelEditorTabIds.Queries), - getPanelEditorTab(PanelEditorTabIds.Visualization), - getPanelEditorTab(PanelEditorTabIds.Advanced), - getPanelEditorTab(PanelEditorTabIds.Alert), - ]; - const dispatchedActions = await thunkTester({ panelEditor: { ...initialState, activeTab: null } }) - .givenThunk(refreshPanelEditor) - .whenThunkIsDispatched({ hasQueriesTab: true, alertingEnabled: true, usesGraphPlugin: true }); - - expect(dispatchedActions.length).toBe(1); - expect(dispatchedActions[0]).toEqual(panelEditorInitCompleted({ activeTab, tabs })); - }); - }); - - describe('when called and there is already an activeTab in state', () => { - it('then the dispatched action should include activeTab from state', async () => { - const activeTab = PanelEditorTabIds.Visualization; - const tabs = [ - getPanelEditorTab(PanelEditorTabIds.Queries), - getPanelEditorTab(PanelEditorTabIds.Visualization), - getPanelEditorTab(PanelEditorTabIds.Advanced), - getPanelEditorTab(PanelEditorTabIds.Alert), - ]; - const dispatchedActions = await thunkTester({ panelEditor: { ...initialState, activeTab } }) - .givenThunk(refreshPanelEditor) - .whenThunkIsDispatched({ hasQueriesTab: true, alertingEnabled: true, usesGraphPlugin: true }); - - expect(dispatchedActions.length).toBe(1); - expect(dispatchedActions[0]).toEqual(panelEditorInitCompleted({ activeTab, tabs })); - }); - }); - - describe('when called and plugin has no queries tab', () => { - it('then the dispatched action should not include Queries tab and default the activeTab to PanelEditorTabIds.Visualization', async () => { - const activeTab = PanelEditorTabIds.Visualization; - const tabs = [ - getPanelEditorTab(PanelEditorTabIds.Visualization), - getPanelEditorTab(PanelEditorTabIds.Advanced), - getPanelEditorTab(PanelEditorTabIds.Alert), - ]; - const dispatchedActions = await thunkTester({ panelEditor: { ...initialState } }) - .givenThunk(refreshPanelEditor) - .whenThunkIsDispatched({ hasQueriesTab: false, alertingEnabled: true, usesGraphPlugin: true }); - - expect(dispatchedActions.length).toBe(1); - expect(dispatchedActions[0]).toEqual(panelEditorInitCompleted({ activeTab, tabs })); - }); - }); - - describe('when called and alerting is enabled and the visualization is the graph plugin', () => { - it('then the dispatched action should include the alert tab', async () => { - const activeTab = PanelEditorTabIds.Queries; - const tabs = [ - getPanelEditorTab(PanelEditorTabIds.Queries), - getPanelEditorTab(PanelEditorTabIds.Visualization), - getPanelEditorTab(PanelEditorTabIds.Advanced), - getPanelEditorTab(PanelEditorTabIds.Alert), - ]; - const dispatchedActions = await thunkTester({ panelEditor: { ...initialState } }) - .givenThunk(refreshPanelEditor) - .whenThunkIsDispatched({ hasQueriesTab: true, alertingEnabled: true, usesGraphPlugin: true }); - - expect(dispatchedActions.length).toBe(1); - expect(dispatchedActions[0]).toEqual(panelEditorInitCompleted({ activeTab, tabs })); - }); - }); - - describe('when called and alerting is not enabled', () => { - it('then the dispatched action should not include the alert tab', async () => { - const activeTab = PanelEditorTabIds.Queries; - const tabs = [ - getPanelEditorTab(PanelEditorTabIds.Queries), - getPanelEditorTab(PanelEditorTabIds.Visualization), - getPanelEditorTab(PanelEditorTabIds.Advanced), - ]; - const dispatchedActions = await thunkTester({ panelEditor: { ...initialState } }) - .givenThunk(refreshPanelEditor) - .whenThunkIsDispatched({ hasQueriesTab: true, alertingEnabled: false, usesGraphPlugin: true }); - - expect(dispatchedActions.length).toBe(1); - expect(dispatchedActions[0]).toEqual(panelEditorInitCompleted({ activeTab, tabs })); - }); - }); - - describe('when called and the visualization is not the graph plugin', () => { - it('then the dispatched action should not include the alert tab', async () => { - const activeTab = PanelEditorTabIds.Queries; - const tabs = [ - getPanelEditorTab(PanelEditorTabIds.Queries), - getPanelEditorTab(PanelEditorTabIds.Visualization), - getPanelEditorTab(PanelEditorTabIds.Advanced), - ]; - const dispatchedActions = await thunkTester({ panelEditor: { ...initialState } }) - .givenThunk(refreshPanelEditor) - .whenThunkIsDispatched({ hasQueriesTab: true, alertingEnabled: true, usesGraphPlugin: false }); - - expect(dispatchedActions.length).toBe(1); - expect(dispatchedActions[0]).toEqual(panelEditorInitCompleted({ activeTab, tabs })); - }); - }); -}); - -describe('changePanelEditorTab', () => { - describe('when called', () => { - it('then it should dispatch correct actions', async () => { - const activeTab = getPanelEditorTab(PanelEditorTabIds.Visualization); - const dispatchedActions = await thunkTester({}) - .givenThunk(changePanelEditorTab) - .whenThunkIsDispatched(activeTab); - - expect(dispatchedActions.length).toBe(1); - expect(dispatchedActions).toEqual([ - updateLocation({ query: { tab: activeTab.id, openVizPicker: null }, partial: true }), - ]); - }); - }); -}); diff --git a/public/app/features/dashboard/panel_editor/state/actions.ts b/public/app/features/dashboard/panel_editor/state/actions.ts deleted file mode 100644 index bcaa0b9eddf..00000000000 --- a/public/app/features/dashboard/panel_editor/state/actions.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { getPanelEditorTab, panelEditorInitCompleted, PanelEditorTab, PanelEditorTabIds } from './reducers'; -import { ThunkResult } from '../../../../types'; -import { updateLocation } from '../../../../core/actions'; - -export const refreshPanelEditor = (props: { - hasQueriesTab?: boolean; - usesGraphPlugin?: boolean; - alertingEnabled?: boolean; -}): ThunkResult => { - return async (dispatch, getState) => { - let activeTab = getState().panelEditor.activeTab || PanelEditorTabIds.Queries; - const { hasQueriesTab, usesGraphPlugin, alertingEnabled } = props; - - const tabs: PanelEditorTab[] = [ - getPanelEditorTab(PanelEditorTabIds.Queries), - getPanelEditorTab(PanelEditorTabIds.Visualization), - getPanelEditorTab(PanelEditorTabIds.Advanced), - ]; - - // handle panels that do not have queries tab - if (!hasQueriesTab) { - // remove queries tab - tabs.shift(); - // switch tab - if (activeTab === PanelEditorTabIds.Queries) { - activeTab = PanelEditorTabIds.Visualization; - } - } - - if (alertingEnabled && usesGraphPlugin) { - tabs.push(getPanelEditorTab(PanelEditorTabIds.Alert)); - } - - dispatch(panelEditorInitCompleted({ activeTab, tabs })); - }; -}; - -export const changePanelEditorTab = (activeTab: PanelEditorTab): ThunkResult => { - return async dispatch => { - dispatch(updateLocation({ query: { tab: activeTab.id, openVizPicker: null }, partial: true })); - }; -}; diff --git a/public/app/features/dashboard/panel_editor/state/reducers.test.ts b/public/app/features/dashboard/panel_editor/state/reducers.test.ts deleted file mode 100644 index f9390296fa0..00000000000 --- a/public/app/features/dashboard/panel_editor/state/reducers.test.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { reducerTester } from '../../../../../test/core/redux/reducerTester'; -import { - getPanelEditorTab, - initialState, - panelEditorCleanUp, - panelEditorInitCompleted, - panelEditorReducer, - PanelEditorState, - PanelEditorTab, - PanelEditorTabIds, -} from './reducers'; - -describe('panelEditorReducer', () => { - describe('when panelEditorInitCompleted is dispatched', () => { - it('then state should be correct', () => { - const activeTab = PanelEditorTabIds.Alert; - const tabs: PanelEditorTab[] = [ - getPanelEditorTab(PanelEditorTabIds.Queries), - getPanelEditorTab(PanelEditorTabIds.Visualization), - getPanelEditorTab(PanelEditorTabIds.Advanced), - ]; - reducerTester() - .givenReducer(panelEditorReducer, initialState) - .whenActionIsDispatched(panelEditorInitCompleted({ activeTab, tabs })) - .thenStateShouldEqual({ activeTab, tabs }); - }); - }); - - describe('when panelEditorCleanUp is dispatched', () => { - it('then state should be intialState', () => { - const activeTab = PanelEditorTabIds.Alert; - const tabs: PanelEditorTab[] = [ - getPanelEditorTab(PanelEditorTabIds.Queries), - getPanelEditorTab(PanelEditorTabIds.Visualization), - getPanelEditorTab(PanelEditorTabIds.Advanced), - ]; - reducerTester() - .givenReducer(panelEditorReducer, { activeTab, tabs }) - .whenActionIsDispatched(panelEditorCleanUp()) - .thenStateShouldEqual(initialState); - }); - }); -}); diff --git a/public/app/features/dashboard/panel_editor/state/reducers.ts b/public/app/features/dashboard/panel_editor/state/reducers.ts deleted file mode 100644 index cb651f5717c..00000000000 --- a/public/app/features/dashboard/panel_editor/state/reducers.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { createSlice, PayloadAction } from '@reduxjs/toolkit'; - -export interface PanelEditorInitCompleted { - activeTab: PanelEditorTabIds; - tabs: PanelEditorTab[]; -} - -export interface PanelEditorTab { - id: string; - text: string; -} - -export enum PanelEditorTabIds { - Queries = 'queries', - Visualization = 'visualization', - Advanced = 'advanced', - Alert = 'alert', -} - -export const panelEditorTabTexts = { - [PanelEditorTabIds.Queries]: 'Queries', - [PanelEditorTabIds.Visualization]: 'Visualization', - [PanelEditorTabIds.Advanced]: 'General', - [PanelEditorTabIds.Alert]: 'Alert', -}; - -export const getPanelEditorTab = (tabId: PanelEditorTabIds): PanelEditorTab => { - return { - id: tabId, - text: panelEditorTabTexts[tabId], - }; -}; - -export interface PanelEditorState { - activeTab: PanelEditorTabIds; - tabs: PanelEditorTab[]; -} - -export const initialState: PanelEditorState = { - activeTab: null, - tabs: [], -}; - -const panelEditorSlice = createSlice({ - name: 'panelEditor', - initialState, - reducers: { - panelEditorInitCompleted: (state, action: PayloadAction): PanelEditorState => { - const { activeTab, tabs } = action.payload; - return { - ...state, - activeTab, - tabs, - }; - }, - panelEditorCleanUp: (state, action: PayloadAction): PanelEditorState => initialState, - }, -}); - -export const { panelEditorCleanUp, panelEditorInitCompleted } = panelEditorSlice.actions; - -export const panelEditorReducer = panelEditorSlice.reducer; diff --git a/public/app/features/dashboard/panel_editor/state/selectors.test.ts b/public/app/features/dashboard/panel_editor/state/selectors.test.ts deleted file mode 100644 index 0fe19983b9a..00000000000 --- a/public/app/features/dashboard/panel_editor/state/selectors.test.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { getActiveTabAndTabs } from './selectors'; -import { LocationState } from '../../../../types'; -import { getPanelEditorTab, PanelEditorState, PanelEditorTab, PanelEditorTabIds } from './reducers'; - -describe('getActiveTabAndTabs', () => { - describe('when called and location state contains tab', () => { - it('then it should return location state', () => { - const activeTabId = 1337; - const location: LocationState = { - path: 'a path', - lastUpdated: 1, - replace: false, - routeParams: {}, - query: { - tab: activeTabId, - }, - url: 'an url', - }; - const panelEditor: PanelEditorState = { - activeTab: PanelEditorTabIds.Queries, - tabs: [], - }; - - const result = getActiveTabAndTabs(location, panelEditor); - - expect(result).toEqual({ - activeTab: activeTabId, - tabs: [], - }); - }); - }); - - describe('when called without location state and PanelEditor state contains tabs', () => { - it('then it should return the id for the first tab in PanelEditor state', () => { - const activeTabId = PanelEditorTabIds.Visualization; - const tabs = [getPanelEditorTab(PanelEditorTabIds.Visualization), getPanelEditorTab(PanelEditorTabIds.Advanced)]; - const location: LocationState = { - path: 'a path', - lastUpdated: 1, - replace: false, - routeParams: {}, - query: { - tab: undefined, - }, - url: 'an url', - }; - const panelEditor: PanelEditorState = { - activeTab: PanelEditorTabIds.Advanced, - tabs, - }; - - const result = getActiveTabAndTabs(location, panelEditor); - - expect(result).toEqual({ - activeTab: activeTabId, - tabs, - }); - }); - }); - - describe('when called without location state and PanelEditor state does not contain tabs', () => { - it('then it should return PanelEditorTabIds.Queries', () => { - const activeTabId = PanelEditorTabIds.Queries; - const tabs: PanelEditorTab[] = []; - const location: LocationState = { - path: 'a path', - lastUpdated: 1, - replace: false, - routeParams: {}, - query: { - tab: undefined, - }, - url: 'an url', - }; - const panelEditor: PanelEditorState = { - activeTab: PanelEditorTabIds.Advanced, - tabs, - }; - - const result = getActiveTabAndTabs(location, panelEditor); - - expect(result).toEqual({ - activeTab: activeTabId, - tabs, - }); - }); - }); -}); diff --git a/public/app/features/dashboard/panel_editor/state/selectors.ts b/public/app/features/dashboard/panel_editor/state/selectors.ts deleted file mode 100644 index f6e6e80ecf9..00000000000 --- a/public/app/features/dashboard/panel_editor/state/selectors.ts +++ /dev/null @@ -1,11 +0,0 @@ -import memoizeOne from 'memoize-one'; -import { LocationState } from '../../../../types'; -import { PanelEditorState, PanelEditorTabIds } from './reducers'; - -export const getActiveTabAndTabs = memoizeOne((location: LocationState, panelEditor: PanelEditorState) => { - const panelEditorTab = panelEditor.tabs.length > 0 ? panelEditor.tabs[0].id : PanelEditorTabIds.Queries; - return { - activeTab: location.query.tab || panelEditorTab, - tabs: panelEditor.tabs, - }; -}); diff --git a/public/app/features/dashboard/state/reducers.ts b/public/app/features/dashboard/state/reducers.ts index 3dae6db55d4..f7fb457a30a 100644 --- a/public/app/features/dashboard/state/reducers.ts +++ b/public/app/features/dashboard/state/reducers.ts @@ -10,8 +10,7 @@ import { import { AngularComponent } from '@grafana/runtime'; import { EDIT_PANEL_ID } from 'app/core/constants'; import { processAclItems } from 'app/core/utils/acl'; -import { panelEditorReducer } from '../panel_editor/state/reducers'; -import { panelEditorReducerNew } from '../components/PanelEditor/state/reducers'; +import { panelEditorReducer } from '../components/PanelEditor/state/reducers'; import { DashboardModel } from './DashboardModel'; import { PanelModel } from './PanelModel'; import { PanelPlugin } from '@grafana/data'; @@ -131,5 +130,4 @@ export const dashboardReducer = dashbardSlice.reducer; export default { dashboard: dashboardReducer, panelEditor: panelEditorReducer, - panelEditorNew: panelEditorReducerNew, }; diff --git a/public/app/plugins/datasource/testdata/query_ctrl.ts b/public/app/plugins/datasource/testdata/query_ctrl.ts index 99b84c30e9d..21e923e0861 100644 --- a/public/app/plugins/datasource/testdata/query_ctrl.ts +++ b/public/app/plugins/datasource/testdata/query_ctrl.ts @@ -34,7 +34,7 @@ export class TestDataQueryCtrl extends QueryCtrl { digest: (promise: Promise) => Promise; showLabels = false; - selectors: typeof e2e.pages.Dashboard.Panels.DataSource.TestData.QueryTab.selectors; + selectors: typeof e2e.components.DataSource.TestData.QueryTab.selectors; /** @ngInject */ constructor($scope: IScope, $injector: any) { @@ -45,7 +45,7 @@ export class TestDataQueryCtrl extends QueryCtrl { this.newPointTime = dateTime(); this.selectedPoint = { text: 'Select point', value: null }; this.showLabels = showLabelsFor.includes(this.target.scenarioId); - this.selectors = e2e.pages.Dashboard.Panels.DataSource.TestData.QueryTab.selectors; + this.selectors = e2e.components.DataSource.TestData.QueryTab.selectors; } getPoints() { diff --git a/public/app/plugins/panel/graph/Legend/LegendSeriesItem.tsx b/public/app/plugins/panel/graph/Legend/LegendSeriesItem.tsx index 29e7aa9a3c2..13e161b7e13 100644 --- a/public/app/plugins/panel/graph/Legend/LegendSeriesItem.tsx +++ b/public/app/plugins/panel/graph/Legend/LegendSeriesItem.tsx @@ -2,6 +2,7 @@ import React, { PureComponent } from 'react'; import classNames from 'classnames'; import { TimeSeries } from 'app/core/core'; import { SeriesColorPicker, Icon } from '@grafana/ui'; +import { e2e } from '@grafana/e2e'; export const LEGEND_STATS = ['min', 'max', 'avg', 'current', 'total']; @@ -137,7 +138,13 @@ class LegendSeriesLabel extends PureComponent, - this.props.onLabelClick(e)}> + this.props.onLabelClick(e)} + aria-label={e2e.components.Panels.Visualization.Graph.Legend.selectors.legendItemAlias(label)} + > {label} , ]; diff --git a/public/app/plugins/panel/graph/axes_editor.ts b/public/app/plugins/panel/graph/axes_editor.ts index 7f301558e16..86dd84d8e74 100644 --- a/public/app/plugins/panel/graph/axes_editor.ts +++ b/public/app/plugins/panel/graph/axes_editor.ts @@ -8,7 +8,7 @@ export class AxesEditorCtrl { xAxisModes: any; xAxisStatOptions: any; xNameSegment: any; - selectors: typeof e2e.pages.Dashboard.Panels.Visualization.Graph.VisualizationTab.selectors; + selectors: typeof e2e.components.Panels.Visualization.Graph.VisualizationTab.selectors; /** @ngInject */ constructor(private $scope: any) { @@ -45,7 +45,7 @@ export class AxesEditorCtrl { this.panel.xaxis.name = 'specify field'; } } - this.selectors = e2e.pages.Dashboard.Panels.Visualization.Graph.VisualizationTab.selectors; + this.selectors = e2e.components.Panels.Visualization.Graph.VisualizationTab.selectors; } setUnitFormat(axis: { format: any }) { diff --git a/public/app/plugins/panel/graph/module.ts b/public/app/plugins/panel/graph/module.ts index 4229ef53cba..10feb9cddcc 100644 --- a/public/app/plugins/panel/graph/module.ts +++ b/public/app/plugins/panel/graph/module.ts @@ -168,10 +168,12 @@ class GraphCtrl extends MetricsPanelCtrl { } onInitEditMode() { - this.addEditorTab('Display options', 'public/app/plugins/panel/graph/tab_display.html'); + this.addEditorTab('Display', 'public/app/plugins/panel/graph/tab_display.html'); + this.addEditorTab('Series overides', 'public/app/plugins/panel/graph/tab_series_overrides.html'); this.addEditorTab('Axes', axesEditorComponent); this.addEditorTab('Legend', 'public/app/plugins/panel/graph/tab_legend.html'); - this.addEditorTab('Thresholds & Time Regions', 'public/app/plugins/panel/graph/tab_thresholds_time_regions.html'); + this.addEditorTab('Thresholds', 'public/app/plugins/panel/graph/tab_thresholds.html'); + this.addEditorTab('Time regions', 'public/app/plugins/panel/graph/time_regions.html'); this.addEditorTab('Data links', 'public/app/plugins/panel/graph/tab_drilldown_links.html'); this.subTabIndex = 0; this.hiddenSeriesTainted = false; diff --git a/public/app/plugins/panel/graph/tab_display.html b/public/app/plugins/panel/graph/tab_display.html index becc19828c1..c93a1e0c98d 100644 --- a/public/app/plugins/panel/graph/tab_display.html +++ b/public/app/plugins/panel/graph/tab_display.html @@ -1,205 +1,151 @@ -
    -
    -
    Draw Modes
    - - - -
    -
    -
    Mode Options
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    - - -
    - -
    - -
    -
    -
    -
    -
    Hover tooltip
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    +
    + + + + +
    + +
    +
    -
    -
    Stacking & Null value
    - - - - -
    - -
    - -
    + + +
    + +
    + +
    +
    + +
    + +
    + +
    +
    + + + +
    + +
    +
    -
    -
    -
    - -
    -
    - -
    -
    - -
    - -
    - - -
    - -
    -
    -
    - -
    - +
    +
    Hover tooltip
    +
    + +
    +
    -
    - +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    +
    Stacking & Null value
    + + + + +
    + +
    + +
    diff --git a/public/app/plugins/panel/graph/tab_legend.html b/public/app/plugins/panel/graph/tab_legend.html index b9c45447263..467d276d676 100644 --- a/public/app/plugins/panel/graph/tab_legend.html +++ b/public/app/plugins/panel/graph/tab_legend.html @@ -1,73 +1,134 @@
    -
    -
    Options
    - - - - - - -
    - - -
    -
    +
    +
    Options
    + + + + + + +
    + + +
    +
    -
    -
    Values
    +
    +
    Values
    -
    - - +
    + + - - -
    + + +
    -
    - - +
    + + - - -
    + + +
    -
    - - +
    + + -
    - - -
    -
    -
    +
    + + +
    +
    +
    -
    -
    Hide series
    - - - - -
    +
    +
    Hide series
    + + + + +
    diff --git a/public/app/plugins/panel/graph/tab_series_overrides.html b/public/app/plugins/panel/graph/tab_series_overrides.html new file mode 100644 index 00000000000..153447091e5 --- /dev/null +++ b/public/app/plugins/panel/graph/tab_series_overrides.html @@ -0,0 +1,51 @@ +
    +
    + + + +
    +
    +
    + +
    +
    + +
    +
    +
    +
    + +
    diff --git a/public/app/plugins/panel/graph/tab_thresholds.html b/public/app/plugins/panel/graph/tab_thresholds.html new file mode 100644 index 00000000000..87668a04159 --- /dev/null +++ b/public/app/plugins/panel/graph/tab_thresholds.html @@ -0,0 +1 @@ + diff --git a/public/app/plugins/panel/graph/tab_thresholds_time_regions.html b/public/app/plugins/panel/graph/tab_thresholds_time_regions.html deleted file mode 100644 index 1ee603f5d36..00000000000 --- a/public/app/plugins/panel/graph/tab_thresholds_time_regions.html +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/public/app/plugins/panel/graph/tab_time_regions.html b/public/app/plugins/panel/graph/tab_time_regions.html new file mode 100644 index 00000000000..b8a0c517995 --- /dev/null +++ b/public/app/plugins/panel/graph/tab_time_regions.html @@ -0,0 +1 @@ + diff --git a/public/app/plugins/panel/graph/time_regions_form.html b/public/app/plugins/panel/graph/time_regions_form.html index 3ed3bafc465..1bad0dde649 100644 --- a/public/app/plugins/panel/graph/time_regions_form.html +++ b/public/app/plugins/panel/graph/time_regions_form.html @@ -75,7 +75,7 @@ diff --git a/public/app/types/store.ts b/public/app/types/store.ts index 9f4ac8ee787..292fe735492 100644 --- a/public/app/types/store.ts +++ b/public/app/types/store.ts @@ -15,8 +15,7 @@ import { AppNotificationsState } from './appNotifications'; import { PluginsState } from './plugins'; import { ApplicationState } from './application'; import { LdapState } from './ldap'; -import { PanelEditorState } from '../features/dashboard/panel_editor/state/reducers'; -import { PanelEditorStateNew } from '../features/dashboard/components/PanelEditor/state/reducers'; +import { PanelEditorState } from '../features/dashboard/components/PanelEditor/state/reducers'; import { ApiKeysState } from './apiKeys'; import { TemplatingState } from '../features/variables/state/reducers'; import { ImportDashboardState } from '../features/manage-dashboards/state/reducers'; @@ -30,7 +29,6 @@ export interface StoreState { folder: FolderState; dashboard: DashboardState; panelEditor: PanelEditorState; - panelEditorNew: PanelEditorStateNew; dataSources: DataSourcesState; dataSourceSettings: DataSourceSettingsState; explore: ExploreState; diff --git a/public/sass/_variables.dark.generated.scss b/public/sass/_variables.dark.generated.scss index 0c3ee4e6c51..b6f24829b36 100644 --- a/public/sass/_variables.dark.generated.scss +++ b/public/sass/_variables.dark.generated.scss @@ -90,8 +90,9 @@ $body-bg: #141619; $page-bg: #141619; $dashboard-bg: #0b0c0e; -$text-color: #c7d0d9; $text-color-strong: #f7f8fa; +$text-color: #c7d0d9; +$text-color-semi-weak: #9fa7b3; $text-color-weak: #7b8087; $text-color-faint: #464c54; $text-color-emphasis: #f7f8fa; diff --git a/public/sass/_variables.light.generated.scss b/public/sass/_variables.light.generated.scss index 53f499255f6..153c0066a18 100644 --- a/public/sass/_variables.light.generated.scss +++ b/public/sass/_variables.light.generated.scss @@ -86,6 +86,7 @@ $dashboard-bg: #f7f8fa; $text-color: #464c54; $text-color-strong: #202226; +$text-color-semi-weak: #464c54; $text-color-weak: #7b8087; $text-color-faint: #9fa7b3; $text-color-emphasis: #202226; diff --git a/public/sass/components/_panel_graph.scss b/public/sass/components/_panel_graph.scss index 2464703d671..f2b0be9470d 100644 --- a/public/sass/components/_panel_graph.scss +++ b/public/sass/components/_panel_graph.scss @@ -220,18 +220,8 @@ color: $purple; } -.graph-series-override { - input { - float: left; - margin-right: 10px; - } - .graph-series-override-option { - float: left; - padding: 2px 6px; - } - .graph-series-override-selector { - float: left; - } +.graph-series-override__properties { + margin-left: $space-md; } .graph-tooltip {