grafana/public/app/features/dashboard/dashgrid/PanelStateWrapper.tsx

767 lines
24 KiB
TypeScript
Raw Normal View History

import classNames from 'classnames';
import React, { PureComponent } from 'react';
import { Subscription } from 'rxjs';
import {
AbsoluteTimeRange,
AnnotationChangeEvent,
AnnotationEventUIModel,
CoreApp,
GraphNG - shared cursor (#33433) * Initial work * WIP add cursor in debug panel * shared cursor.sync filter * explicit uplot events * explicit uplot events * uplot events * uplot events * depend on master uplot * sync sync sync * Fix merge * Get rid of PlotSyncContext and sync tooltip positions * make sync optional * Improve shared tooltip positioning * Plugins: add level and signature badges to plugin details page (#33553) * feat(grafana-ui): badge can accept react node for text, add shield-exclamation to icons * feat(plugins): add PluginSignatureType type * feat(pluginpage): introduce PluginSignatureDetailsBadge. Fix sidebar icon margin * feat(pluginlistpage): update filterinput placeholder, introduce filter by plugin type * Variables: Removes the never refresh option (#33533) * Variables: Removes the never refresh option * Tests: fixes DashboardModel repeat tests * Tests: fixs snapshots * Tests: fixes processVariable test * Tests: fixes DashboardModel tests * PageLayout: Fixes max-width breakpoint so that it triggers only when there is room for margin+ (#33558) * Alerting: Remove datasource (name) from migration (#33544) no longer needed as of https://github.com/grafana/grafana/pull/33416 for https://github.com/grafana/alerting-squad/issues/126 * Library panels: Adds description to library panels tab (#33428) * CodeOwners: Set owners of unified alerting migration (#33571) * ButtonSelect: updates component with the new theme model (#33565) * EmptySearchResult: updates component with the new theme model (#33573) * DashboardSettings: Slight design tweak to fix page toolbar padding and align design (#33575) * DashboardSettings: Slight design tweak to fix page toolbar padding and align design * Fixed font weight * Removed comment * Update * gitignore: Ignore files for accesscontrol provisioning (#33577) * Alerting/metrics (#33547) * moves alerting metrics to their own pkg * adds grafana_alerting_alerts (by state) metric * alerts_received_{total,invalid} * embed alertmanager alerting struct in ng metrics & remove duplicated notification metrics (already embed alertmanager notifier metrics) * use silence metrics from alertmanager lib * fix - manager has metrics * updates ngalert tests * comment lint Signed-off-by: Owen Diehl <ow.diehl@gmail.com> * cleaner prom registry code * removes ngalert global metrics * new registry use in all tests * ngalert metrics impl service, hack testinfra code to prevent duplicate metric registrations * nilmetrics unexported * Add note to Snapshot API doc to specify that user has to provide the entire dashboard model (#33572) * Added note as suggested by Macus E. * Update docs/sources/http_api/snapshot.md Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com> Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com> * Alerting: backend "ng" code cleanup (#33578) * AlertMigration: remove alert_rule UID db check (#33568) do not believe this is needed due to uniqueness promised by shortid lib since there is no provisioning yet. https://github.com/teris-io/shortid * Live: persisting last message in cache for broadcast scope (#32938) * Alerting: Load annotations from rule into State cache (#33542) for https://github.com/grafana/alerting-squad/issues/127 * add template for dashboard url parameters (#33549) * Update dashboard-links.md parameters with plain text like `var-something=value` can make confusion. template it to clarify . * describe way for template link. * AlertingMigration: Create alert_rule_version entry (#33585) Create the alert rule version entry during the migration so it is consistent with rules created via api. for https://github.com/grafana/alerting-squad/issues/123 * Build: Fix with cleanup call maybe? (#33590) * add selector for code editor (#33554) * broadcast over eventBus * broadcasting to eventbus (but not useing it yet) * merge master * moved to context * fix yarn.lock * update snapshot * Fix direct state mutation * Persist location state on partial updates * GraphNG- use getStream rather than subscribe * Sync LegacyGraphHoverEvent with GraphNG * Chenge plotRef signature * use subscription * subscription * one fewer file * Update types * Remove unnecessary filtering * Disable cursor sync when in edit mode * GraphNG - bring back logging Co-authored-by: Ryan McKinley <ryantxu@gmail.com> Co-authored-by: Leon Sorokin <leeoniya@gmail.com> Co-authored-by: Jack Westbrook <jack.westbrook@gmail.com> Co-authored-by: Hugo Häggmark <hugo.haggmark@grafana.com> Co-authored-by: Torkel Ödegaard <torkel@grafana.org> Co-authored-by: Kyle Brandt <kyle@grafana.com> Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com> Co-authored-by: Uchechukwu Obasi <obasiuche62@gmail.com> Co-authored-by: gamab <gamab@users.noreply.github.com> Co-authored-by: Owen Diehl <ow.diehl@gmail.com> Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com> Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com> Co-authored-by: Alexander Emelin <frvzmb@gmail.com> Co-authored-by: Nagle Zhang <nagle.zhang@sap.com> Co-authored-by: Erik Sundell <erik.sundell@grafana.com>
2021-05-10 07:24:23 -05:00
DashboardCursorSync,
EventFilterOptions,
FieldConfigSource,
getDataSourceRef,
getDefaultTimeRange,
LinkModel,
LoadingState,
PanelData,
PanelPlugin,
PanelPluginMeta,
PluginContextProvider,
renderMarkdown,
TimeRange,
toDataFrameDTO,
toUtc,
} from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { getTemplateSrv, config, locationService, RefreshEvent, reportInteraction } from '@grafana/runtime';
import { VizLegendOptions } from '@grafana/schema';
import {
ErrorBoundary,
PanelChrome,
PanelContext,
PanelContextProvider,
PanelPadding,
SeriesVisibilityChangeMode,
AdHocFilterItem,
} from '@grafana/ui';
import { PANEL_BORDER } from 'app/core/constants';
import { profiler } from 'app/core/profiler';
import { applyPanelTimeOverrides } from 'app/features/dashboard/utils/panel';
PanelChrome: Implement Panel header with error, loading, and streaming data status (#60147) * dashboards squad mob! :trident: lastFile:packages/grafana-ui/src/components/LoadingBar/LoadingBar.tsx * dashboards squad mob! :trident: * dashboards squad mob! :trident: lastFile:packages/grafana-ui/src/components/LoadingBar/LoadingBar.tsx * user essentials mob! :trident: * create grafana/ui LoadingBar and set it up in Storybook * Remove test changes on PanelChrome * Fix mdx page reference * dashboards squad mob! :trident: lastFile:public/api-merged.json * dashboards squad mob! :trident: * dashboards squad mob! :trident: * dashboards squad mob! :trident: * dashboards squad mob! :trident: lastFile:public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderState.tsx * Implemented basic draft of panel header states. Using ToolbarButton instead of IconButton. * use 'warning' styled Button in ToolbarButton * make LoadingBar a simple JSX Element; do not use containerWidth; have a wrapper around the loading bar itself; * fix wrapper around LoadingBar: willChange css prop makes performance of rerendering better * States: Render general panel query error states and render notices next to the title * add streaming to PanelChrome if data is streaming instead of loading * PanelHeaderState with its own state 'mode' * clean up useEffect * notices have their own square space in the size of the panel header * clean up * minor fixes * moving the LoadingBar to core * LoadingBar is not in grafana/ui * always have a place for the loading bar in the PanelChrome, otherwise it moves everything when appearing; remove titleItemsNodes for now - in later development make no changes to Notice component, not part of this PR * Revert "moving the LoadingBar to core" This reverts commit 11f0f4ff2fe81d6755b6587c368284f0ea8f7b68. * do not use internal comment as it doesn't do anything * integrate LoadingBar in PanelChrome from grafana/ui directly * fix deprecated leftItems comment * Modify annimation to 1 second * remove comments * remove streaming stopped UI because we cannot know when the streaming has stopped * skip unnecessary test for now * no point in removing hoverHeader now, even though it's not yet implemented * small fixes * error state of the data in a panel is positioned in PanelChrome itself, not in PanelHeaderState * Fixed loading state jitter * remove warning state as we have none of it * streaming cannot be stopped from the icon * explicit content container width and height * explicit content container width and height * edit deprecated comment * fix LoadingBar to be relative to width of panel; remove explicit width and height on content strict * no warning state of the data * status of the panel data given directly to PanelChrome, not a node * clean up * clean up console log Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com> * panel title design fits typography h6 styles; render error status only if error or error message are passed to PanelChrome * add storybook examples; prepare PanelChrome for hoverHeader because this will be a breaking change and it will affect how the storybook example shows up * show storybook example for streaming panel with title because that's the condition for having a header * override margin-bottom: 0.45em of h6 Co-authored-by: Alexandra Vargas <alexa1866@gmail.com> Co-authored-by: Torkel Ödegaard <torkel@grafana.com> Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com>
2023-01-05 03:48:11 -06:00
import { InspectTab } from 'app/features/inspector/types';
import { getPanelLinksSupplier } from 'app/features/panel/panellinks/linkSuppliers';
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
import { applyFilterFromTable } from 'app/features/variables/adhoc/actions';
import { changeSeriesColorConfigFactory } from 'app/plugins/panel/timeseries/overrides/colorSeriesConfigFactory';
import { dispatch } from 'app/store/store';
import { RenderEvent } from 'app/types/events';
import { isSoloRoute } from '../../../routes/utils';
import { deleteAnnotation, saveAnnotation, updateAnnotation } from '../../annotations/api';
import { getDashboardQueryRunner } from '../../query/state/DashboardQueryRunner/DashboardQueryRunner';
import { getTimeSrv, TimeSrv } from '../services/TimeSrv';
import { DashboardModel, PanelModel } from '../state';
import { loadSnapshotData } from '../utils/loadSnapshotData';
import { PanelHeader } from './PanelHeader/PanelHeader';
import { PanelHeaderMenuWrapperNew } from './PanelHeader/PanelHeaderMenuWrapper';
import { PanelHeaderTitleItems } from './PanelHeader/PanelHeaderTitleItems';
import { seriesVisibilityConfigFactory } from './SeriesVisibilityConfigFactory';
import { liveTimer } from './liveTimer';
2018-06-19 07:51:57 -05:00
const DEFAULT_PLUGIN_ERROR = 'Error in plugin';
export interface Props {
2018-06-19 07:51:57 -05:00
panel: PanelModel;
dashboard: DashboardModel;
plugin: PanelPlugin;
isViewing: boolean;
isEditing: boolean;
isInView: boolean;
width: number;
height: number;
VisualizationSelection: Real previews of suitable visualisation and options based on current data (#40527) * Initial pass to move panel state to it's own, and make it by key not panel.id * Progress * Not making much progress, having panel.key be mutable is causing a lot of issues * Think this is starting to work * Began fixing tests * Add selector * Bug fixes and changes to cleanup, and fixing all flicking when switching library panels * Removed console.log * fixes after merge * fixing tests * fixing tests * Added new test for changePlugin thunk * Initial struture in place * responding to state changes in another part of the state * bha * going in a different direction * This is getting exciting * minor * More structure * More real * Added builder to reduce boiler plate * Lots of progress * Adding more visualizations * More smarts * tweaks * suggestions * Move to separate view * Refactoring to builder concept * Before hover preview test * Increase line width in preview * More suggestions * Removed old elements of onSuggestVisualizations * Don't call suggestion suppliers if there is no data * Restore card styles to only borders * Changing supplier interface to support data vs option suggestion scenario * Renamed functions * Add dynamic width support * not sure about this * Improve suggestions * Improve suggestions * Single grid/list * Store vis select pane & size * Prep for option suggestions * more suggestions * Name/title option for preview cards * Improve barchart suggestions * Support suggestions when there are no data * Minor change * reverted some changes * Improve suggestions for stacking * Removed size option * starting on unit tests, hit cyclic dependency issue * muuu * First test for getting suggestion seems to work, going to bed * add missing file * A basis for more unit tests * More tests * More unit tests * Fixed unit tests * Update * Some extreme scenarios * Added basic e2e test * Added another unit test for changePanelPlugin action * More cleanup * Minor tweak * add wait to e2e test * Renamed function and cleanup of unused function * Adding search support and adding search test to e2e test
2021-10-25 06:55:06 -05:00
onInstanceStateChange: (value: any) => void;
timezone?: string;
hideMenu?: boolean;
2018-06-19 07:51:57 -05:00
}
export interface State {
isFirstLoad: boolean;
2018-11-05 10:46:09 -06:00
renderCounter: number;
errorMessage?: string;
refreshWhenInView: boolean;
context: PanelContext;
data: PanelData;
liveTime?: TimeRange;
}
export class PanelStateWrapper extends PureComponent<Props, State> {
private readonly timeSrv: TimeSrv = getTimeSrv();
private subs = new Subscription();
private eventFilter: EventFilterOptions = { onlyLocal: true };
private descriptionInteractionReported = false;
constructor(props: Props) {
2018-06-19 07:51:57 -05:00
super(props);
// Can this eventBus be on PanelModel? when we have more complex event filtering, that may be a better option
const eventBus = props.dashboard.events.newScopedBus(`panel:${props.panel.id}`, this.eventFilter);
this.state = {
isFirstLoad: true,
2018-11-05 10:46:09 -06:00
renderCounter: 0,
refreshWhenInView: false,
context: {
eventBus,
app: this.getPanelContextApp(),
sync: this.getSync,
onSeriesColorChange: this.onSeriesColorChange,
onToggleSeriesVisibility: this.onSeriesVisibilityChange,
onAnnotationCreate: this.onAnnotationCreate,
onAnnotationUpdate: this.onAnnotationUpdate,
onAnnotationDelete: this.onAnnotationDelete,
onInstanceStateChange: this.onInstanceStateChange,
onToggleLegendSort: this.onToggleLegendSort,
canAddAnnotations: props.dashboard.canAddAnnotations.bind(props.dashboard),
canEditAnnotations: props.dashboard.canEditAnnotations.bind(props.dashboard),
canDeleteAnnotations: props.dashboard.canDeleteAnnotations.bind(props.dashboard),
onAddAdHocFilter: this.onAddAdHocFilter,
},
data: this.getInitialPanelDataState(),
};
}
// Due to a mutable panel model we get the sync settings via function that proactively reads from the model
getSync = () => (this.props.isEditing ? DashboardCursorSync.Off : this.props.dashboard.graphTooltip);
onInstanceStateChange = (value: any) => {
VisualizationSelection: Real previews of suitable visualisation and options based on current data (#40527) * Initial pass to move panel state to it's own, and make it by key not panel.id * Progress * Not making much progress, having panel.key be mutable is causing a lot of issues * Think this is starting to work * Began fixing tests * Add selector * Bug fixes and changes to cleanup, and fixing all flicking when switching library panels * Removed console.log * fixes after merge * fixing tests * fixing tests * Added new test for changePlugin thunk * Initial struture in place * responding to state changes in another part of the state * bha * going in a different direction * This is getting exciting * minor * More structure * More real * Added builder to reduce boiler plate * Lots of progress * Adding more visualizations * More smarts * tweaks * suggestions * Move to separate view * Refactoring to builder concept * Before hover preview test * Increase line width in preview * More suggestions * Removed old elements of onSuggestVisualizations * Don't call suggestion suppliers if there is no data * Restore card styles to only borders * Changing supplier interface to support data vs option suggestion scenario * Renamed functions * Add dynamic width support * not sure about this * Improve suggestions * Improve suggestions * Single grid/list * Store vis select pane & size * Prep for option suggestions * more suggestions * Name/title option for preview cards * Improve barchart suggestions * Support suggestions when there are no data * Minor change * reverted some changes * Improve suggestions for stacking * Removed size option * starting on unit tests, hit cyclic dependency issue * muuu * First test for getting suggestion seems to work, going to bed * add missing file * A basis for more unit tests * More tests * More unit tests * Fixed unit tests * Update * Some extreme scenarios * Added basic e2e test * Added another unit test for changePanelPlugin action * More cleanup * Minor tweak * add wait to e2e test * Renamed function and cleanup of unused function * Adding search support and adding search test to e2e test
2021-10-25 06:55:06 -05:00
this.props.onInstanceStateChange(value);
this.setState({
context: {
...this.state.context,
instanceState: value,
},
});
};
getPanelContextApp() {
if (this.props.isEditing) {
return CoreApp.PanelEditor;
}
if (this.props.isViewing) {
return CoreApp.PanelViewer;
}
return CoreApp.Dashboard;
}
onSeriesColorChange = (label: string, color: string) => {
this.onFieldConfigChange(changeSeriesColorConfigFactory(label, color, this.props.panel.fieldConfig));
};
onSeriesVisibilityChange = (label: string, mode: SeriesVisibilityChangeMode) => {
this.onFieldConfigChange(
seriesVisibilityConfigFactory(label, mode, this.props.panel.fieldConfig, this.state.data.series)
);
};
onToggleLegendSort = (sortKey: string) => {
const legendOptions: VizLegendOptions = this.props.panel.options.legend;
// We don't want to do anything when legend options are not available
if (!legendOptions) {
return;
}
let sortDesc = legendOptions.sortDesc;
let sortBy = legendOptions.sortBy;
if (sortKey !== sortBy) {
sortDesc = undefined;
}
// if already sort ascending, disable sorting
if (sortDesc === false) {
sortBy = undefined;
sortDesc = undefined;
} else {
sortDesc = !sortDesc;
sortBy = sortKey;
}
this.onOptionsChange({
...this.props.panel.options,
legend: { ...legendOptions, sortBy, sortDesc },
});
};
getInitialPanelDataState(): PanelData {
return {
state: LoadingState.NotStarted,
series: [],
timeRange: getDefaultTimeRange(),
};
}
componentDidMount() {
const { panel, dashboard } = this.props;
// Subscribe to panel events
this.subs.add(panel.events.subscribe(RefreshEvent, this.onRefresh));
this.subs.add(panel.events.subscribe(RenderEvent, this.onRender));
dashboard.panelInitialized(this.props.panel);
// Move snapshot data into the query response
if (this.hasPanelSnapshot) {
this.setState({
data: loadSnapshotData(panel, dashboard),
isFirstLoad: false,
});
return;
}
if (!this.wantsQueryExecution) {
this.setState({ isFirstLoad: false });
}
this.subs.add(
panel
.getQueryRunner()
.getData({ withTransforms: true, withFieldConfig: true })
.subscribe({
next: (data) => this.onDataUpdate(data),
})
);
// Listen for live timer events
liveTimer.listen(this);
}
componentWillUnmount() {
this.subs.unsubscribe();
liveTimer.remove(this);
}
liveTimeChanged(liveTime: TimeRange) {
const { data } = this.state;
if (data.timeRange) {
const delta = liveTime.to.valueOf() - data.timeRange.to.valueOf();
if (delta < 100) {
// 10hz
console.log('Skip tick render', this.props.panel.title, delta);
return;
}
}
this.setState({ liveTime });
}
componentDidUpdate(prevProps: Props) {
const { isInView, width } = this.props;
const { context } = this.state;
GraphNG - shared cursor (#33433) * Initial work * WIP add cursor in debug panel * shared cursor.sync filter * explicit uplot events * explicit uplot events * uplot events * uplot events * depend on master uplot * sync sync sync * Fix merge * Get rid of PlotSyncContext and sync tooltip positions * make sync optional * Improve shared tooltip positioning * Plugins: add level and signature badges to plugin details page (#33553) * feat(grafana-ui): badge can accept react node for text, add shield-exclamation to icons * feat(plugins): add PluginSignatureType type * feat(pluginpage): introduce PluginSignatureDetailsBadge. Fix sidebar icon margin * feat(pluginlistpage): update filterinput placeholder, introduce filter by plugin type * Variables: Removes the never refresh option (#33533) * Variables: Removes the never refresh option * Tests: fixes DashboardModel repeat tests * Tests: fixs snapshots * Tests: fixes processVariable test * Tests: fixes DashboardModel tests * PageLayout: Fixes max-width breakpoint so that it triggers only when there is room for margin+ (#33558) * Alerting: Remove datasource (name) from migration (#33544) no longer needed as of https://github.com/grafana/grafana/pull/33416 for https://github.com/grafana/alerting-squad/issues/126 * Library panels: Adds description to library panels tab (#33428) * CodeOwners: Set owners of unified alerting migration (#33571) * ButtonSelect: updates component with the new theme model (#33565) * EmptySearchResult: updates component with the new theme model (#33573) * DashboardSettings: Slight design tweak to fix page toolbar padding and align design (#33575) * DashboardSettings: Slight design tweak to fix page toolbar padding and align design * Fixed font weight * Removed comment * Update * gitignore: Ignore files for accesscontrol provisioning (#33577) * Alerting/metrics (#33547) * moves alerting metrics to their own pkg * adds grafana_alerting_alerts (by state) metric * alerts_received_{total,invalid} * embed alertmanager alerting struct in ng metrics & remove duplicated notification metrics (already embed alertmanager notifier metrics) * use silence metrics from alertmanager lib * fix - manager has metrics * updates ngalert tests * comment lint Signed-off-by: Owen Diehl <ow.diehl@gmail.com> * cleaner prom registry code * removes ngalert global metrics * new registry use in all tests * ngalert metrics impl service, hack testinfra code to prevent duplicate metric registrations * nilmetrics unexported * Add note to Snapshot API doc to specify that user has to provide the entire dashboard model (#33572) * Added note as suggested by Macus E. * Update docs/sources/http_api/snapshot.md Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com> Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com> * Alerting: backend "ng" code cleanup (#33578) * AlertMigration: remove alert_rule UID db check (#33568) do not believe this is needed due to uniqueness promised by shortid lib since there is no provisioning yet. https://github.com/teris-io/shortid * Live: persisting last message in cache for broadcast scope (#32938) * Alerting: Load annotations from rule into State cache (#33542) for https://github.com/grafana/alerting-squad/issues/127 * add template for dashboard url parameters (#33549) * Update dashboard-links.md parameters with plain text like `var-something=value` can make confusion. template it to clarify . * describe way for template link. * AlertingMigration: Create alert_rule_version entry (#33585) Create the alert rule version entry during the migration so it is consistent with rules created via api. for https://github.com/grafana/alerting-squad/issues/123 * Build: Fix with cleanup call maybe? (#33590) * add selector for code editor (#33554) * broadcast over eventBus * broadcasting to eventbus (but not useing it yet) * merge master * moved to context * fix yarn.lock * update snapshot * Fix direct state mutation * Persist location state on partial updates * GraphNG- use getStream rather than subscribe * Sync LegacyGraphHoverEvent with GraphNG * Chenge plotRef signature * use subscription * subscription * one fewer file * Update types * Remove unnecessary filtering * Disable cursor sync when in edit mode * GraphNG - bring back logging Co-authored-by: Ryan McKinley <ryantxu@gmail.com> Co-authored-by: Leon Sorokin <leeoniya@gmail.com> Co-authored-by: Jack Westbrook <jack.westbrook@gmail.com> Co-authored-by: Hugo Häggmark <hugo.haggmark@grafana.com> Co-authored-by: Torkel Ödegaard <torkel@grafana.org> Co-authored-by: Kyle Brandt <kyle@grafana.com> Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com> Co-authored-by: Uchechukwu Obasi <obasiuche62@gmail.com> Co-authored-by: gamab <gamab@users.noreply.github.com> Co-authored-by: Owen Diehl <ow.diehl@gmail.com> Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com> Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com> Co-authored-by: Alexander Emelin <frvzmb@gmail.com> Co-authored-by: Nagle Zhang <nagle.zhang@sap.com> Co-authored-by: Erik Sundell <erik.sundell@grafana.com>
2021-05-10 07:24:23 -05:00
const app = this.getPanelContextApp();
GraphNG - shared cursor (#33433) * Initial work * WIP add cursor in debug panel * shared cursor.sync filter * explicit uplot events * explicit uplot events * uplot events * uplot events * depend on master uplot * sync sync sync * Fix merge * Get rid of PlotSyncContext and sync tooltip positions * make sync optional * Improve shared tooltip positioning * Plugins: add level and signature badges to plugin details page (#33553) * feat(grafana-ui): badge can accept react node for text, add shield-exclamation to icons * feat(plugins): add PluginSignatureType type * feat(pluginpage): introduce PluginSignatureDetailsBadge. Fix sidebar icon margin * feat(pluginlistpage): update filterinput placeholder, introduce filter by plugin type * Variables: Removes the never refresh option (#33533) * Variables: Removes the never refresh option * Tests: fixes DashboardModel repeat tests * Tests: fixs snapshots * Tests: fixes processVariable test * Tests: fixes DashboardModel tests * PageLayout: Fixes max-width breakpoint so that it triggers only when there is room for margin+ (#33558) * Alerting: Remove datasource (name) from migration (#33544) no longer needed as of https://github.com/grafana/grafana/pull/33416 for https://github.com/grafana/alerting-squad/issues/126 * Library panels: Adds description to library panels tab (#33428) * CodeOwners: Set owners of unified alerting migration (#33571) * ButtonSelect: updates component with the new theme model (#33565) * EmptySearchResult: updates component with the new theme model (#33573) * DashboardSettings: Slight design tweak to fix page toolbar padding and align design (#33575) * DashboardSettings: Slight design tweak to fix page toolbar padding and align design * Fixed font weight * Removed comment * Update * gitignore: Ignore files for accesscontrol provisioning (#33577) * Alerting/metrics (#33547) * moves alerting metrics to their own pkg * adds grafana_alerting_alerts (by state) metric * alerts_received_{total,invalid} * embed alertmanager alerting struct in ng metrics & remove duplicated notification metrics (already embed alertmanager notifier metrics) * use silence metrics from alertmanager lib * fix - manager has metrics * updates ngalert tests * comment lint Signed-off-by: Owen Diehl <ow.diehl@gmail.com> * cleaner prom registry code * removes ngalert global metrics * new registry use in all tests * ngalert metrics impl service, hack testinfra code to prevent duplicate metric registrations * nilmetrics unexported * Add note to Snapshot API doc to specify that user has to provide the entire dashboard model (#33572) * Added note as suggested by Macus E. * Update docs/sources/http_api/snapshot.md Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com> Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com> * Alerting: backend "ng" code cleanup (#33578) * AlertMigration: remove alert_rule UID db check (#33568) do not believe this is needed due to uniqueness promised by shortid lib since there is no provisioning yet. https://github.com/teris-io/shortid * Live: persisting last message in cache for broadcast scope (#32938) * Alerting: Load annotations from rule into State cache (#33542) for https://github.com/grafana/alerting-squad/issues/127 * add template for dashboard url parameters (#33549) * Update dashboard-links.md parameters with plain text like `var-something=value` can make confusion. template it to clarify . * describe way for template link. * AlertingMigration: Create alert_rule_version entry (#33585) Create the alert rule version entry during the migration so it is consistent with rules created via api. for https://github.com/grafana/alerting-squad/issues/123 * Build: Fix with cleanup call maybe? (#33590) * add selector for code editor (#33554) * broadcast over eventBus * broadcasting to eventbus (but not useing it yet) * merge master * moved to context * fix yarn.lock * update snapshot * Fix direct state mutation * Persist location state on partial updates * GraphNG- use getStream rather than subscribe * Sync LegacyGraphHoverEvent with GraphNG * Chenge plotRef signature * use subscription * subscription * one fewer file * Update types * Remove unnecessary filtering * Disable cursor sync when in edit mode * GraphNG - bring back logging Co-authored-by: Ryan McKinley <ryantxu@gmail.com> Co-authored-by: Leon Sorokin <leeoniya@gmail.com> Co-authored-by: Jack Westbrook <jack.westbrook@gmail.com> Co-authored-by: Hugo Häggmark <hugo.haggmark@grafana.com> Co-authored-by: Torkel Ödegaard <torkel@grafana.org> Co-authored-by: Kyle Brandt <kyle@grafana.com> Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com> Co-authored-by: Uchechukwu Obasi <obasiuche62@gmail.com> Co-authored-by: gamab <gamab@users.noreply.github.com> Co-authored-by: Owen Diehl <ow.diehl@gmail.com> Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com> Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com> Co-authored-by: Alexander Emelin <frvzmb@gmail.com> Co-authored-by: Nagle Zhang <nagle.zhang@sap.com> Co-authored-by: Erik Sundell <erik.sundell@grafana.com>
2021-05-10 07:24:23 -05:00
if (context.app !== app) {
this.setState({
context: {
...context,
app,
},
GraphNG - shared cursor (#33433) * Initial work * WIP add cursor in debug panel * shared cursor.sync filter * explicit uplot events * explicit uplot events * uplot events * uplot events * depend on master uplot * sync sync sync * Fix merge * Get rid of PlotSyncContext and sync tooltip positions * make sync optional * Improve shared tooltip positioning * Plugins: add level and signature badges to plugin details page (#33553) * feat(grafana-ui): badge can accept react node for text, add shield-exclamation to icons * feat(plugins): add PluginSignatureType type * feat(pluginpage): introduce PluginSignatureDetailsBadge. Fix sidebar icon margin * feat(pluginlistpage): update filterinput placeholder, introduce filter by plugin type * Variables: Removes the never refresh option (#33533) * Variables: Removes the never refresh option * Tests: fixes DashboardModel repeat tests * Tests: fixs snapshots * Tests: fixes processVariable test * Tests: fixes DashboardModel tests * PageLayout: Fixes max-width breakpoint so that it triggers only when there is room for margin+ (#33558) * Alerting: Remove datasource (name) from migration (#33544) no longer needed as of https://github.com/grafana/grafana/pull/33416 for https://github.com/grafana/alerting-squad/issues/126 * Library panels: Adds description to library panels tab (#33428) * CodeOwners: Set owners of unified alerting migration (#33571) * ButtonSelect: updates component with the new theme model (#33565) * EmptySearchResult: updates component with the new theme model (#33573) * DashboardSettings: Slight design tweak to fix page toolbar padding and align design (#33575) * DashboardSettings: Slight design tweak to fix page toolbar padding and align design * Fixed font weight * Removed comment * Update * gitignore: Ignore files for accesscontrol provisioning (#33577) * Alerting/metrics (#33547) * moves alerting metrics to their own pkg * adds grafana_alerting_alerts (by state) metric * alerts_received_{total,invalid} * embed alertmanager alerting struct in ng metrics & remove duplicated notification metrics (already embed alertmanager notifier metrics) * use silence metrics from alertmanager lib * fix - manager has metrics * updates ngalert tests * comment lint Signed-off-by: Owen Diehl <ow.diehl@gmail.com> * cleaner prom registry code * removes ngalert global metrics * new registry use in all tests * ngalert metrics impl service, hack testinfra code to prevent duplicate metric registrations * nilmetrics unexported * Add note to Snapshot API doc to specify that user has to provide the entire dashboard model (#33572) * Added note as suggested by Macus E. * Update docs/sources/http_api/snapshot.md Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com> Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com> * Alerting: backend "ng" code cleanup (#33578) * AlertMigration: remove alert_rule UID db check (#33568) do not believe this is needed due to uniqueness promised by shortid lib since there is no provisioning yet. https://github.com/teris-io/shortid * Live: persisting last message in cache for broadcast scope (#32938) * Alerting: Load annotations from rule into State cache (#33542) for https://github.com/grafana/alerting-squad/issues/127 * add template for dashboard url parameters (#33549) * Update dashboard-links.md parameters with plain text like `var-something=value` can make confusion. template it to clarify . * describe way for template link. * AlertingMigration: Create alert_rule_version entry (#33585) Create the alert rule version entry during the migration so it is consistent with rules created via api. for https://github.com/grafana/alerting-squad/issues/123 * Build: Fix with cleanup call maybe? (#33590) * add selector for code editor (#33554) * broadcast over eventBus * broadcasting to eventbus (but not useing it yet) * merge master * moved to context * fix yarn.lock * update snapshot * Fix direct state mutation * Persist location state on partial updates * GraphNG- use getStream rather than subscribe * Sync LegacyGraphHoverEvent with GraphNG * Chenge plotRef signature * use subscription * subscription * one fewer file * Update types * Remove unnecessary filtering * Disable cursor sync when in edit mode * GraphNG - bring back logging Co-authored-by: Ryan McKinley <ryantxu@gmail.com> Co-authored-by: Leon Sorokin <leeoniya@gmail.com> Co-authored-by: Jack Westbrook <jack.westbrook@gmail.com> Co-authored-by: Hugo Häggmark <hugo.haggmark@grafana.com> Co-authored-by: Torkel Ödegaard <torkel@grafana.org> Co-authored-by: Kyle Brandt <kyle@grafana.com> Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com> Co-authored-by: Uchechukwu Obasi <obasiuche62@gmail.com> Co-authored-by: gamab <gamab@users.noreply.github.com> Co-authored-by: Owen Diehl <ow.diehl@gmail.com> Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com> Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com> Co-authored-by: Alexander Emelin <frvzmb@gmail.com> Co-authored-by: Nagle Zhang <nagle.zhang@sap.com> Co-authored-by: Erik Sundell <erik.sundell@grafana.com>
2021-05-10 07:24:23 -05:00
});
}
// View state has changed
if (isInView !== prevProps.isInView) {
if (isInView) {
// Check if we need a delayed refresh
if (this.state.refreshWhenInView) {
this.onRefresh();
}
}
}
// The timer depends on panel width
if (width !== prevProps.width) {
liveTimer.updateInterval(this);
}
}
// Updates the response with information from the stream
// The next is outside a react synthetic event so setState is not batched
// So in this context we can only do a single call to setState
2019-12-19 00:01:35 -06:00
onDataUpdate(data: PanelData) {
const { dashboard, panel, plugin } = this.props;
// Ignore this data update if we are now a non data panel
if (plugin.meta.skipDataQuery) {
this.setState({ data: this.getInitialPanelDataState() });
2019-12-19 00:01:35 -06:00
return;
}
2019-12-19 00:01:35 -06:00
let { isFirstLoad } = this.state;
let errorMessage: string | undefined;
2019-12-19 00:01:35 -06:00
switch (data.state) {
case LoadingState.Loading:
// Skip updating state data if it is already in loading state
// This is to avoid rendering partial loading responses
if (this.state.data.state === LoadingState.Loading) {
return;
}
break;
case LoadingState.Error:
const { error, errors } = data;
if (errors?.length) {
if (errors.length === 1) {
errorMessage = errors[0].message;
} else {
errorMessage = 'Multiple errors found. Click for more details';
}
} else if (error) {
2019-12-19 00:01:35 -06:00
if (errorMessage !== error.message) {
errorMessage = error.message;
}
2019-12-19 00:01:35 -06:00
}
break;
case LoadingState.Done:
// If we are doing a snapshot save data in panel model
if (dashboard.snapshot) {
panel.snapshotData = data.series.map((frame) => toDataFrameDTO(frame));
2019-12-19 00:01:35 -06:00
}
if (isFirstLoad) {
isFirstLoad = false;
}
break;
}
this.setState({ isFirstLoad, errorMessage, data, liveTime: undefined });
2019-12-19 00:01:35 -06:00
}
onRefresh = () => {
Public Dashboards: Pubdash panels get data from pubdash api (#50556) * Public dashboard query API * Create new API on service for building metric request * Flesh out testing, implement BuildPublicDashboardMetricRequest * Test for errors and missing panels * WIP: Test for multiple datasources * Refactor tests, add supporting code for multiple datasources * Gets the panel data from the pubdash query api * Adds tests to make sure we get the correct api url from retrieving panel data * Public dashboard query API * Create new API on service for building metric request * Flesh out testing, implement BuildPublicDashboardMetricRequest * Test for errors and missing panels * WIP: Test for multiple datasources * Refactor tests, add supporting code for multiple datasources * Handle queries from multiple datasources * Replace dashboard time range with pubdash time range settings * Fix comments from review, build failure * removes changes to DataSourceWithBackend.ts regarding getting the pubdash panel query url. Going to do this in a new class, PublicDashboardDataSource.ts * Include pubdash Uid in dashboard meta * Creates new PublicDashboardDataSource.ts and adds test * Passes pubdash uid down to PanelQueryRunner.ts to a PublicDashboardDatasource can be chosen when were looking at a public dashboard * removes comment * checks for error when unmarshalling json * Only replace dashboard time settings with pubdash time settings when pubdash time settings exist * formatting and added comment Co-authored-by: Jesse Weaver <jesse.weaver@grafana.com> Co-authored-by: Jeff Levin <jeff@levinology.com>
2022-06-13 19:03:43 -05:00
const { dashboard, panel, isInView, width } = this.props;
if (!isInView) {
this.setState({ refreshWhenInView: true });
return;
}
const timeData = applyPanelTimeOverrides(panel, this.timeSrv.timeRange());
// Issue Query
if (this.wantsQueryExecution) {
if (width < 0) {
return;
}
if (this.state.refreshWhenInView) {
this.setState({ refreshWhenInView: false });
}
panel.runAllPanelQueries({
dashboardUID: dashboard.uid,
dashboardTimezone: dashboard.getTimezone(),
publicDashboardAccessToken: dashboard.meta.publicDashboardAccessToken,
Public Dashboards: Pubdash panels get data from pubdash api (#50556) * Public dashboard query API * Create new API on service for building metric request * Flesh out testing, implement BuildPublicDashboardMetricRequest * Test for errors and missing panels * WIP: Test for multiple datasources * Refactor tests, add supporting code for multiple datasources * Gets the panel data from the pubdash query api * Adds tests to make sure we get the correct api url from retrieving panel data * Public dashboard query API * Create new API on service for building metric request * Flesh out testing, implement BuildPublicDashboardMetricRequest * Test for errors and missing panels * WIP: Test for multiple datasources * Refactor tests, add supporting code for multiple datasources * Handle queries from multiple datasources * Replace dashboard time range with pubdash time range settings * Fix comments from review, build failure * removes changes to DataSourceWithBackend.ts regarding getting the pubdash panel query url. Going to do this in a new class, PublicDashboardDataSource.ts * Include pubdash Uid in dashboard meta * Creates new PublicDashboardDataSource.ts and adds test * Passes pubdash uid down to PanelQueryRunner.ts to a PublicDashboardDatasource can be chosen when were looking at a public dashboard * removes comment * checks for error when unmarshalling json * Only replace dashboard time settings with pubdash time settings when pubdash time settings exist * formatting and added comment Co-authored-by: Jesse Weaver <jesse.weaver@grafana.com> Co-authored-by: Jeff Levin <jeff@levinology.com>
2022-06-13 19:03:43 -05:00
timeData,
width,
});
} else {
// The panel should render on refresh as well if it doesn't have a query, like clock panel
this.setState({
data: { ...this.state.data, timeRange: this.timeSrv.timeRange() },
renderCounter: this.state.renderCounter + 1,
liveTime: undefined,
});
}
};
2018-11-05 10:46:09 -06:00
onRender = () => {
const stateUpdate = { renderCounter: this.state.renderCounter + 1 };
this.setState(stateUpdate);
};
onOptionsChange = (options: any) => {
this.props.panel.updateOptions(options);
};
FieldOverrides: Move FieldConfigSource from fieldOptions to PanelModel.fieldConfig (#22600) * Apply field overrides in PanelChrome * Move applyFieldOverrides to panel query runner * Review updates * Make sure overrides are applied back on souce panel when exiting the new edit mode * TS ignores in est * Make field display work in viz repeater * Review updates * Review and test updates * Change the way overrides and trransformations are retrieved in PQR * Add fieldConfig property to PanelModel * Dashboard migration v1 * Use field config when exiting new panel edit mode * Gauge - use fieldConfig from panel model * FieldDisplayOptions - don's extend FieldConfigSource * Fix fieldDisplay ts * StatPanel updated * Stat panel defaults applied * Table2 panel options update * React graph updates * BarGauge updated * PieChart, Gauge, BarGauge and Stat updates * PieChart - remove field config defaults from options * FieldDisplayEditor - remove unused methos * PanelModel - remove debugger * Remove fieldConfig from field options when migrating dashboard * Update data links migrations * Update fieldDisaplay tests to respect new fieldConfig * Update dashboard schema version in snapshots * Fix BarGaugePanel test * Rebase fixes * Add onFieldConfigChange to PanelProps type * Update shared single stat migration * Pass PanelModel instead of options only for panel type change handler [breaking] * Renames * Don't mutate panel options * Migrations update * Remove obsolete snap * Minor updates after review * Fix null checks * Temporarily (until we decide to switch to new pane edit) bring back old aditors * Temporarily rename ValueMappingEditor and MappingRow to Legacy* * Migrations update * Updae setFieldConfigDefaults API * Update the way field config defaults are applied * Use standard field config for gauge, bar gauge and stat panels * refactoring * Revert dashboard fieldOptions migrations as those are handled by single stat migrator * Fix ts in tests * Strict null fix and some minor fixes Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
2020-03-19 05:50:31 -05:00
onFieldConfigChange = (config: FieldConfigSource) => {
this.props.panel.updateFieldConfig(config);
};
onPanelError = (error: Error) => {
const errorMessage = error.message || DEFAULT_PLUGIN_ERROR;
if (this.state.errorMessage !== errorMessage) {
this.setState({ errorMessage });
}
2019-01-30 03:39:42 -06:00
};
onPanelErrorRecover = () => {
this.setState({ errorMessage: undefined });
};
onAnnotationCreate = async (event: AnnotationEventUIModel) => {
const isRegion = event.from !== event.to;
const anno = {
dashboardUID: this.props.dashboard.uid,
panelId: this.props.panel.id,
isRegion,
time: event.from,
timeEnd: isRegion ? event.to : 0,
tags: event.tags,
text: event.description,
};
await saveAnnotation(anno);
getDashboardQueryRunner().run({ dashboard: this.props.dashboard, range: this.timeSrv.timeRange() });
this.state.context.eventBus.publish(new AnnotationChangeEvent(anno));
};
onAnnotationDelete = async (id: string) => {
await deleteAnnotation({ id });
getDashboardQueryRunner().run({ dashboard: this.props.dashboard, range: this.timeSrv.timeRange() });
this.state.context.eventBus.publish(new AnnotationChangeEvent({ id }));
};
onAnnotationUpdate = async (event: AnnotationEventUIModel) => {
const isRegion = event.from !== event.to;
const anno = {
id: event.id,
dashboardUID: this.props.dashboard.uid,
panelId: this.props.panel.id,
isRegion,
time: event.from,
timeEnd: isRegion ? event.to : 0,
tags: event.tags,
text: event.description,
};
await updateAnnotation(anno);
getDashboardQueryRunner().run({ dashboard: this.props.dashboard, range: this.timeSrv.timeRange() });
this.state.context.eventBus.publish(new AnnotationChangeEvent(anno));
};
get hasPanelSnapshot() {
const { panel } = this.props;
return panel.snapshotData && panel.snapshotData.length;
}
get wantsQueryExecution() {
return !(this.props.plugin.meta.skipDataQuery || this.hasPanelSnapshot);
}
onChangeTimeRange = (timeRange: AbsoluteTimeRange) => {
this.timeSrv.setTime({
from: toUtc(timeRange.from),
to: toUtc(timeRange.to),
});
};
shouldSignalRenderingCompleted(loadingState: LoadingState, pluginMeta: PanelPluginMeta) {
return loadingState === LoadingState.Done || loadingState === LoadingState.Error || pluginMeta.skipDataQuery;
}
skipFirstRender(loadingState: LoadingState) {
const { isFirstLoad } = this.state;
return (
this.wantsQueryExecution &&
isFirstLoad &&
(loadingState === LoadingState.Loading || loadingState === LoadingState.NotStarted)
);
}
onAddAdHocFilter = (filter: AdHocFilterItem) => {
const { key, value, operator } = filter;
// When the datasource is null/undefined (for a default datasource), we use getInstanceSettings
// to find the real datasource ref for the default datasource.
const datasourceInstance = getDatasourceSrv().getInstanceSettings(this.props.panel.datasource);
const datasourceRef = datasourceInstance && getDataSourceRef(datasourceInstance);
if (!datasourceRef) {
return;
}
dispatch(applyFilterFromTable({ datasource: datasourceRef, key, operator, value }));
};
renderPanelContent(innerWidth: number, innerHeight: number) {
const { panel, plugin, dashboard } = this.props;
const { renderCounter, data } = this.state;
const { state: loadingState } = data;
// do not render component until we have first data
if (this.skipFirstRender(loadingState)) {
return null;
}
// This is only done to increase a counter that is used by backend
// image rendering to know when to capture image
if (this.shouldSignalRenderingCompleted(loadingState, plugin.meta)) {
profiler.renderingCompleted();
}
const PanelComponent = plugin.panel!;
const timeRange = this.state.liveTime ?? data.timeRange ?? this.timeSrv.timeRange();
const panelOptions = panel.getOptions();
// Update the event filter (dashboard settings may have changed)
// Yes this is called ever render for a function that is triggered on every mouse move
this.eventFilter.onlyLocal = dashboard.graphTooltip === 0;
return (
<>
<PanelContextProvider value={this.state.context}>
<PanelComponent
id={panel.id}
data={data}
title={panel.title}
timeRange={timeRange}
timeZone={this.props.dashboard.getTimezone()}
options={panelOptions}
fieldConfig={panel.fieldConfig}
transparent={panel.transparent}
width={innerWidth}
height={innerHeight}
renderCounter={renderCounter}
replaceVariables={panel.replaceVariables}
onOptionsChange={this.onOptionsChange}
onFieldConfigChange={this.onFieldConfigChange}
onChangeTimeRange={this.onChangeTimeRange}
eventBus={dashboard.events}
/>
</PanelContextProvider>
</>
);
}
renderPanel(width: number, height: number) {
const { panel, plugin, dashboard } = this.props;
const { renderCounter, data } = this.state;
const { theme } = config;
const { state: loadingState } = data;
// do not render component until we have first data
if (this.skipFirstRender(loadingState)) {
return null;
}
2019-01-30 03:39:42 -06:00
// This is only done to increase a counter that is used by backend
// image rendering to know when to capture image
if (this.shouldSignalRenderingCompleted(loadingState, plugin.meta)) {
2019-05-13 02:38:19 -05:00
profiler.renderingCompleted();
}
const PanelComponent = plugin.panel!;
const timeRange = this.state.liveTime ?? data.timeRange ?? this.timeSrv.timeRange();
const headerHeight = this.hasOverlayHeader() ? 0 : theme.panelHeaderHeight;
const chromePadding = plugin.noPadding ? 0 : theme.panelPadding;
const panelWidth = width - chromePadding * 2 - PANEL_BORDER;
const innerPanelHeight = height - headerHeight - chromePadding * 2 - PANEL_BORDER;
const panelContentClassNames = classNames({
'panel-content': true,
'panel-content--no-padding': plugin.noPadding,
});
const panelOptions = panel.getOptions();
// Update the event filter (dashboard settings may have changed)
// Yes this is called ever render for a function that is triggered on every mouse move
this.eventFilter.onlyLocal = dashboard.graphTooltip === 0;
const timeZone = this.props.timezone || this.props.dashboard.getTimezone();
return (
<>
<div className={panelContentClassNames}>
<PluginContextProvider meta={plugin.meta}>
<PanelContextProvider value={this.state.context}>
<PanelComponent
id={panel.id}
data={data}
title={panel.title}
timeRange={timeRange}
timeZone={timeZone}
options={panelOptions}
fieldConfig={panel.fieldConfig}
transparent={panel.transparent}
width={panelWidth}
height={innerPanelHeight}
renderCounter={renderCounter}
replaceVariables={panel.replaceVariables}
onOptionsChange={this.onOptionsChange}
onFieldConfigChange={this.onFieldConfigChange}
onChangeTimeRange={this.onChangeTimeRange}
eventBus={dashboard.events}
/>
</PanelContextProvider>
</PluginContextProvider>
</div>
</>
);
}
hasOverlayHeader() {
const { panel } = this.props;
const { data } = this.state;
// always show normal header if we have time override
if (data.request && data.request.timeInfo) {
return false;
}
return !panel.hasTitle();
}
onShowPanelDescription = () => {
const { panel } = this.props;
const descriptionMarkdown = getTemplateSrv().replace(panel.description, panel.scopedVars);
const interpolatedDescription = renderMarkdown(descriptionMarkdown);
if (!this.descriptionInteractionReported) {
// Description rendering function can be called multiple times due to re-renders but we want to report the interaction once.
reportInteraction('dashboards_panelheader_description_displayed');
this.descriptionInteractionReported = true;
}
return interpolatedDescription;
};
onShowPanelLinks = (): LinkModel[] => {
const { panel } = this.props;
const linkSupplier = getPanelLinksSupplier(panel);
if (linkSupplier) {
const panelLinks = linkSupplier && linkSupplier.getLinks(panel.replaceVariables);
return panelLinks.map((panelLink) => ({
...panelLink,
onClick: (...args) => {
reportInteraction('dashboards_panelheader_datalink_clicked', { has_multiple_links: panelLinks.length > 1 });
panelLink.onClick?.(...args);
},
}));
}
return [];
};
onOpenInspector = (e: React.SyntheticEvent, tab: string) => {
e.stopPropagation();
locationService.partial({ inspect: this.props.panel.id, inspectTab: tab });
};
onOpenErrorInspect = (e: React.SyntheticEvent) => {
PanelChrome: Implement Panel header with error, loading, and streaming data status (#60147) * dashboards squad mob! :trident: lastFile:packages/grafana-ui/src/components/LoadingBar/LoadingBar.tsx * dashboards squad mob! :trident: * dashboards squad mob! :trident: lastFile:packages/grafana-ui/src/components/LoadingBar/LoadingBar.tsx * user essentials mob! :trident: * create grafana/ui LoadingBar and set it up in Storybook * Remove test changes on PanelChrome * Fix mdx page reference * dashboards squad mob! :trident: lastFile:public/api-merged.json * dashboards squad mob! :trident: * dashboards squad mob! :trident: * dashboards squad mob! :trident: * dashboards squad mob! :trident: lastFile:public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderState.tsx * Implemented basic draft of panel header states. Using ToolbarButton instead of IconButton. * use 'warning' styled Button in ToolbarButton * make LoadingBar a simple JSX Element; do not use containerWidth; have a wrapper around the loading bar itself; * fix wrapper around LoadingBar: willChange css prop makes performance of rerendering better * States: Render general panel query error states and render notices next to the title * add streaming to PanelChrome if data is streaming instead of loading * PanelHeaderState with its own state 'mode' * clean up useEffect * notices have their own square space in the size of the panel header * clean up * minor fixes * moving the LoadingBar to core * LoadingBar is not in grafana/ui * always have a place for the loading bar in the PanelChrome, otherwise it moves everything when appearing; remove titleItemsNodes for now - in later development make no changes to Notice component, not part of this PR * Revert "moving the LoadingBar to core" This reverts commit 11f0f4ff2fe81d6755b6587c368284f0ea8f7b68. * do not use internal comment as it doesn't do anything * integrate LoadingBar in PanelChrome from grafana/ui directly * fix deprecated leftItems comment * Modify annimation to 1 second * remove comments * remove streaming stopped UI because we cannot know when the streaming has stopped * skip unnecessary test for now * no point in removing hoverHeader now, even though it's not yet implemented * small fixes * error state of the data in a panel is positioned in PanelChrome itself, not in PanelHeaderState * Fixed loading state jitter * remove warning state as we have none of it * streaming cannot be stopped from the icon * explicit content container width and height * explicit content container width and height * edit deprecated comment * fix LoadingBar to be relative to width of panel; remove explicit width and height on content strict * no warning state of the data * status of the panel data given directly to PanelChrome, not a node * clean up * clean up console log Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com> * panel title design fits typography h6 styles; render error status only if error or error message are passed to PanelChrome * add storybook examples; prepare PanelChrome for hoverHeader because this will be a breaking change and it will affect how the storybook example shows up * show storybook example for streaming panel with title because that's the condition for having a header * override margin-bottom: 0.45em of h6 Co-authored-by: Alexandra Vargas <alexa1866@gmail.com> Co-authored-by: Torkel Ödegaard <torkel@grafana.com> Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com>
2023-01-05 03:48:11 -06:00
e.stopPropagation();
locationService.partial({ inspect: this.props.panel.id, inspectTab: InspectTab.Error });
reportInteraction('dashboards_panelheader_statusmessage_clicked');
};
PanelChrome: Implement Panel header with error, loading, and streaming data status (#60147) * dashboards squad mob! :trident: lastFile:packages/grafana-ui/src/components/LoadingBar/LoadingBar.tsx * dashboards squad mob! :trident: * dashboards squad mob! :trident: lastFile:packages/grafana-ui/src/components/LoadingBar/LoadingBar.tsx * user essentials mob! :trident: * create grafana/ui LoadingBar and set it up in Storybook * Remove test changes on PanelChrome * Fix mdx page reference * dashboards squad mob! :trident: lastFile:public/api-merged.json * dashboards squad mob! :trident: * dashboards squad mob! :trident: * dashboards squad mob! :trident: * dashboards squad mob! :trident: lastFile:public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderState.tsx * Implemented basic draft of panel header states. Using ToolbarButton instead of IconButton. * use 'warning' styled Button in ToolbarButton * make LoadingBar a simple JSX Element; do not use containerWidth; have a wrapper around the loading bar itself; * fix wrapper around LoadingBar: willChange css prop makes performance of rerendering better * States: Render general panel query error states and render notices next to the title * add streaming to PanelChrome if data is streaming instead of loading * PanelHeaderState with its own state 'mode' * clean up useEffect * notices have their own square space in the size of the panel header * clean up * minor fixes * moving the LoadingBar to core * LoadingBar is not in grafana/ui * always have a place for the loading bar in the PanelChrome, otherwise it moves everything when appearing; remove titleItemsNodes for now - in later development make no changes to Notice component, not part of this PR * Revert "moving the LoadingBar to core" This reverts commit 11f0f4ff2fe81d6755b6587c368284f0ea8f7b68. * do not use internal comment as it doesn't do anything * integrate LoadingBar in PanelChrome from grafana/ui directly * fix deprecated leftItems comment * Modify annimation to 1 second * remove comments * remove streaming stopped UI because we cannot know when the streaming has stopped * skip unnecessary test for now * no point in removing hoverHeader now, even though it's not yet implemented * small fixes * error state of the data in a panel is positioned in PanelChrome itself, not in PanelHeaderState * Fixed loading state jitter * remove warning state as we have none of it * streaming cannot be stopped from the icon * explicit content container width and height * explicit content container width and height * edit deprecated comment * fix LoadingBar to be relative to width of panel; remove explicit width and height on content strict * no warning state of the data * status of the panel data given directly to PanelChrome, not a node * clean up * clean up console log Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com> * panel title design fits typography h6 styles; render error status only if error or error message are passed to PanelChrome * add storybook examples; prepare PanelChrome for hoverHeader because this will be a breaking change and it will affect how the storybook example shows up * show storybook example for streaming panel with title because that's the condition for having a header * override margin-bottom: 0.45em of h6 Co-authored-by: Alexandra Vargas <alexa1866@gmail.com> Co-authored-by: Torkel Ödegaard <torkel@grafana.com> Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com>
2023-01-05 03:48:11 -06:00
onCancelQuery = () => {
this.props.panel.getQueryRunner().cancelQuery();
reportInteraction('dashboards_panelheader_cancelquery_clicked', { data_state: this.state.data.state });
};
render() {
const { dashboard, panel, isViewing, isEditing, width, height, plugin } = this.props;
const { errorMessage, data } = this.state;
const { transparent } = panel;
const alertState = data.alertState?.state;
const hasHoverHeader = this.hasOverlayHeader();
const containerClassNames = classNames({
'panel-container': true,
'panel-container--absolute': isSoloRoute(locationService.getLocation().pathname),
'panel-container--transparent': transparent,
'panel-container--no-title': hasHoverHeader,
[`panel-alert-state--${alertState}`]: alertState !== undefined,
});
const title = panel.getDisplayTitle();
PanelChrome: Implement Panel header with error, loading, and streaming data status (#60147) * dashboards squad mob! :trident: lastFile:packages/grafana-ui/src/components/LoadingBar/LoadingBar.tsx * dashboards squad mob! :trident: * dashboards squad mob! :trident: lastFile:packages/grafana-ui/src/components/LoadingBar/LoadingBar.tsx * user essentials mob! :trident: * create grafana/ui LoadingBar and set it up in Storybook * Remove test changes on PanelChrome * Fix mdx page reference * dashboards squad mob! :trident: lastFile:public/api-merged.json * dashboards squad mob! :trident: * dashboards squad mob! :trident: * dashboards squad mob! :trident: * dashboards squad mob! :trident: lastFile:public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderState.tsx * Implemented basic draft of panel header states. Using ToolbarButton instead of IconButton. * use 'warning' styled Button in ToolbarButton * make LoadingBar a simple JSX Element; do not use containerWidth; have a wrapper around the loading bar itself; * fix wrapper around LoadingBar: willChange css prop makes performance of rerendering better * States: Render general panel query error states and render notices next to the title * add streaming to PanelChrome if data is streaming instead of loading * PanelHeaderState with its own state 'mode' * clean up useEffect * notices have their own square space in the size of the panel header * clean up * minor fixes * moving the LoadingBar to core * LoadingBar is not in grafana/ui * always have a place for the loading bar in the PanelChrome, otherwise it moves everything when appearing; remove titleItemsNodes for now - in later development make no changes to Notice component, not part of this PR * Revert "moving the LoadingBar to core" This reverts commit 11f0f4ff2fe81d6755b6587c368284f0ea8f7b68. * do not use internal comment as it doesn't do anything * integrate LoadingBar in PanelChrome from grafana/ui directly * fix deprecated leftItems comment * Modify annimation to 1 second * remove comments * remove streaming stopped UI because we cannot know when the streaming has stopped * skip unnecessary test for now * no point in removing hoverHeader now, even though it's not yet implemented * small fixes * error state of the data in a panel is positioned in PanelChrome itself, not in PanelHeaderState * Fixed loading state jitter * remove warning state as we have none of it * streaming cannot be stopped from the icon * explicit content container width and height * explicit content container width and height * edit deprecated comment * fix LoadingBar to be relative to width of panel; remove explicit width and height on content strict * no warning state of the data * status of the panel data given directly to PanelChrome, not a node * clean up * clean up console log Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com> * panel title design fits typography h6 styles; render error status only if error or error message are passed to PanelChrome * add storybook examples; prepare PanelChrome for hoverHeader because this will be a breaking change and it will affect how the storybook example shows up * show storybook example for streaming panel with title because that's the condition for having a header * override margin-bottom: 0.45em of h6 Co-authored-by: Alexandra Vargas <alexa1866@gmail.com> Co-authored-by: Torkel Ödegaard <torkel@grafana.com> Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com>
2023-01-05 03:48:11 -06:00
const padding: PanelPadding = plugin.noPadding ? 'none' : 'md';
const showTitleItems =
(panel.links && panel.links.length > 0 && this.onShowPanelLinks) ||
(data.series.length > 0 && data.series.some((v) => (v.meta?.notices?.length ?? 0) > 0)) ||
(data.request && data.request.timeInfo) ||
alertState;
const titleItems = showTitleItems && (
<PanelHeaderTitleItems
key="title-items"
alertState={alertState}
data={data}
panelId={panel.id}
panelLinks={panel.links}
onShowPanelLinks={this.onShowPanelLinks}
/>
);
const dragClass = !(isViewing || isEditing) ? 'grid-drag-handle' : '';
if (config.featureToggles.newPanelChromeUI) {
// Shift the hover menu down if it's on the top row so it doesn't get clipped by topnav
const hoverHeaderOffset = (panel.gridPos?.y ?? 0) === 0 ? -16 : undefined;
const menu = (
<div data-testid="panel-dropdown">
<PanelHeaderMenuWrapperNew panel={panel} dashboard={dashboard} loadingState={data.state} />
</div>
);
return (
PanelChrome: Implement Panel header with error, loading, and streaming data status (#60147) * dashboards squad mob! :trident: lastFile:packages/grafana-ui/src/components/LoadingBar/LoadingBar.tsx * dashboards squad mob! :trident: * dashboards squad mob! :trident: lastFile:packages/grafana-ui/src/components/LoadingBar/LoadingBar.tsx * user essentials mob! :trident: * create grafana/ui LoadingBar and set it up in Storybook * Remove test changes on PanelChrome * Fix mdx page reference * dashboards squad mob! :trident: lastFile:public/api-merged.json * dashboards squad mob! :trident: * dashboards squad mob! :trident: * dashboards squad mob! :trident: * dashboards squad mob! :trident: lastFile:public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderState.tsx * Implemented basic draft of panel header states. Using ToolbarButton instead of IconButton. * use 'warning' styled Button in ToolbarButton * make LoadingBar a simple JSX Element; do not use containerWidth; have a wrapper around the loading bar itself; * fix wrapper around LoadingBar: willChange css prop makes performance of rerendering better * States: Render general panel query error states and render notices next to the title * add streaming to PanelChrome if data is streaming instead of loading * PanelHeaderState with its own state 'mode' * clean up useEffect * notices have their own square space in the size of the panel header * clean up * minor fixes * moving the LoadingBar to core * LoadingBar is not in grafana/ui * always have a place for the loading bar in the PanelChrome, otherwise it moves everything when appearing; remove titleItemsNodes for now - in later development make no changes to Notice component, not part of this PR * Revert "moving the LoadingBar to core" This reverts commit 11f0f4ff2fe81d6755b6587c368284f0ea8f7b68. * do not use internal comment as it doesn't do anything * integrate LoadingBar in PanelChrome from grafana/ui directly * fix deprecated leftItems comment * Modify annimation to 1 second * remove comments * remove streaming stopped UI because we cannot know when the streaming has stopped * skip unnecessary test for now * no point in removing hoverHeader now, even though it's not yet implemented * small fixes * error state of the data in a panel is positioned in PanelChrome itself, not in PanelHeaderState * Fixed loading state jitter * remove warning state as we have none of it * streaming cannot be stopped from the icon * explicit content container width and height * explicit content container width and height * edit deprecated comment * fix LoadingBar to be relative to width of panel; remove explicit width and height on content strict * no warning state of the data * status of the panel data given directly to PanelChrome, not a node * clean up * clean up console log Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com> * panel title design fits typography h6 styles; render error status only if error or error message are passed to PanelChrome * add storybook examples; prepare PanelChrome for hoverHeader because this will be a breaking change and it will affect how the storybook example shows up * show storybook example for streaming panel with title because that's the condition for having a header * override margin-bottom: 0.45em of h6 Co-authored-by: Alexandra Vargas <alexa1866@gmail.com> Co-authored-by: Torkel Ödegaard <torkel@grafana.com> Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com>
2023-01-05 03:48:11 -06:00
<PanelChrome
width={width}
height={height}
title={title}
loadingState={data.state}
statusMessage={errorMessage}
statusMessageOnClick={this.onOpenErrorInspect}
description={!!panel.description ? this.onShowPanelDescription : undefined}
titleItems={titleItems}
menu={this.props.hideMenu ? undefined : menu}
dragClass={dragClass}
dragClassCancel="grid-drag-cancel"
padding={padding}
hoverHeaderOffset={hoverHeaderOffset}
hoverHeader={this.hasOverlayHeader()}
displayMode={transparent ? 'transparent' : 'default'}
onCancelQuery={this.onCancelQuery}
PanelChrome: Implement Panel header with error, loading, and streaming data status (#60147) * dashboards squad mob! :trident: lastFile:packages/grafana-ui/src/components/LoadingBar/LoadingBar.tsx * dashboards squad mob! :trident: * dashboards squad mob! :trident: lastFile:packages/grafana-ui/src/components/LoadingBar/LoadingBar.tsx * user essentials mob! :trident: * create grafana/ui LoadingBar and set it up in Storybook * Remove test changes on PanelChrome * Fix mdx page reference * dashboards squad mob! :trident: lastFile:public/api-merged.json * dashboards squad mob! :trident: * dashboards squad mob! :trident: * dashboards squad mob! :trident: * dashboards squad mob! :trident: lastFile:public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderState.tsx * Implemented basic draft of panel header states. Using ToolbarButton instead of IconButton. * use 'warning' styled Button in ToolbarButton * make LoadingBar a simple JSX Element; do not use containerWidth; have a wrapper around the loading bar itself; * fix wrapper around LoadingBar: willChange css prop makes performance of rerendering better * States: Render general panel query error states and render notices next to the title * add streaming to PanelChrome if data is streaming instead of loading * PanelHeaderState with its own state 'mode' * clean up useEffect * notices have their own square space in the size of the panel header * clean up * minor fixes * moving the LoadingBar to core * LoadingBar is not in grafana/ui * always have a place for the loading bar in the PanelChrome, otherwise it moves everything when appearing; remove titleItemsNodes for now - in later development make no changes to Notice component, not part of this PR * Revert "moving the LoadingBar to core" This reverts commit 11f0f4ff2fe81d6755b6587c368284f0ea8f7b68. * do not use internal comment as it doesn't do anything * integrate LoadingBar in PanelChrome from grafana/ui directly * fix deprecated leftItems comment * Modify annimation to 1 second * remove comments * remove streaming stopped UI because we cannot know when the streaming has stopped * skip unnecessary test for now * no point in removing hoverHeader now, even though it's not yet implemented * small fixes * error state of the data in a panel is positioned in PanelChrome itself, not in PanelHeaderState * Fixed loading state jitter * remove warning state as we have none of it * streaming cannot be stopped from the icon * explicit content container width and height * explicit content container width and height * edit deprecated comment * fix LoadingBar to be relative to width of panel; remove explicit width and height on content strict * no warning state of the data * status of the panel data given directly to PanelChrome, not a node * clean up * clean up console log Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com> * panel title design fits typography h6 styles; render error status only if error or error message are passed to PanelChrome * add storybook examples; prepare PanelChrome for hoverHeader because this will be a breaking change and it will affect how the storybook example shows up * show storybook example for streaming panel with title because that's the condition for having a header * override margin-bottom: 0.45em of h6 Co-authored-by: Alexandra Vargas <alexa1866@gmail.com> Co-authored-by: Torkel Ödegaard <torkel@grafana.com> Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com>
2023-01-05 03:48:11 -06:00
>
{(innerWidth, innerHeight) => (
<>
<ErrorBoundary
dependencies={[data, plugin, panel.getOptions()]}
onError={this.onPanelError}
onRecover={this.onPanelErrorRecover}
>
{({ error }) => {
if (error) {
return null;
}
return this.renderPanelContent(innerWidth, innerHeight);
}}
</ErrorBoundary>
</>
)}
</PanelChrome>
);
} else {
return (
<section
className={containerClassNames}
aria-label={selectors.components.Panels.Panel.containerByTitle(panel.title)}
>
<PanelHeader
panel={panel}
dashboard={dashboard}
title={panel.title}
description={panel.description}
links={panel.links}
error={errorMessage}
isEditing={isEditing}
isViewing={isViewing}
alertState={alertState}
data={data}
/>
<ErrorBoundary
dependencies={[data, plugin, panel.getOptions()]}
onError={this.onPanelError}
onRecover={this.onPanelErrorRecover}
>
{({ error }) => {
if (error) {
return null;
}
return this.renderPanel(width, height);
}}
</ErrorBoundary>
</section>
);
}
2018-06-19 07:51:57 -05:00
}
}