|
|
@ -1,7 +1,7 @@ |
|
|
|
import { css } from '@emotion/css'; |
|
|
|
import { css } from '@emotion/css'; |
|
|
|
import React from 'react'; |
|
|
|
import React from 'react'; |
|
|
|
|
|
|
|
|
|
|
|
import { AdHocVariableFilter, GrafanaTheme2, VariableHide, urlUtil } from '@grafana/data'; |
|
|
|
import { AdHocVariableFilter, GrafanaTheme2, PageLayoutType, VariableHide, urlUtil } from '@grafana/data'; |
|
|
|
import { locationService } from '@grafana/runtime'; |
|
|
|
import { locationService } from '@grafana/runtime'; |
|
|
|
import { |
|
|
|
import { |
|
|
|
AdHocFiltersVariable, |
|
|
|
AdHocFiltersVariable, |
|
|
@ -25,6 +25,7 @@ import { |
|
|
|
VariableValueSelectors, |
|
|
|
VariableValueSelectors, |
|
|
|
} from '@grafana/scenes'; |
|
|
|
} from '@grafana/scenes'; |
|
|
|
import { useStyles2 } from '@grafana/ui'; |
|
|
|
import { useStyles2 } from '@grafana/ui'; |
|
|
|
|
|
|
|
import { Page } from 'app/core/components/Page/Page'; |
|
|
|
|
|
|
|
|
|
|
|
import { DataTrailSettings } from './DataTrailSettings'; |
|
|
|
import { DataTrailSettings } from './DataTrailSettings'; |
|
|
|
import { DataTrailHistory } from './DataTrailsHistory'; |
|
|
|
import { DataTrailHistory } from './DataTrailsHistory'; |
|
|
@ -35,6 +36,7 @@ import { getTrailStore } from './TrailStore/TrailStore'; |
|
|
|
import { MetricDatasourceHelper } from './helpers/MetricDatasourceHelper'; |
|
|
|
import { MetricDatasourceHelper } from './helpers/MetricDatasourceHelper'; |
|
|
|
import { reportChangeInLabelFilters } from './interactions'; |
|
|
|
import { reportChangeInLabelFilters } from './interactions'; |
|
|
|
import { MetricSelectedEvent, trailDS, VAR_DATASOURCE, VAR_FILTERS } from './shared'; |
|
|
|
import { MetricSelectedEvent, trailDS, VAR_DATASOURCE, VAR_FILTERS } from './shared'; |
|
|
|
|
|
|
|
import { getMetricName } from './utils'; |
|
|
|
|
|
|
|
|
|
|
|
export interface DataTrailState extends SceneObjectState { |
|
|
|
export interface DataTrailState extends SceneObjectState { |
|
|
|
topScene?: SceneObject; |
|
|
|
topScene?: SceneObject; |
|
|
@ -93,21 +95,11 @@ export class DataTrail extends SceneObjectBase<DataTrailState> { |
|
|
|
); |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Disconnects the current step history state from the current state, to prevent changes affecting history state
|
|
|
|
|
|
|
|
const currentState = this.state.history.state.steps[this.state.history.state.currentStep]?.trailState; |
|
|
|
|
|
|
|
if (currentState) { |
|
|
|
|
|
|
|
this.restoreFromHistoryStep(currentState); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.enableUrlSync(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Save the current trail as a recent if the browser closes or reloads
|
|
|
|
// Save the current trail as a recent if the browser closes or reloads
|
|
|
|
const saveRecentTrail = () => getTrailStore().setRecentTrail(this); |
|
|
|
const saveRecentTrail = () => getTrailStore().setRecentTrail(this); |
|
|
|
window.addEventListener('unload', saveRecentTrail); |
|
|
|
window.addEventListener('unload', saveRecentTrail); |
|
|
|
|
|
|
|
|
|
|
|
return () => { |
|
|
|
return () => { |
|
|
|
this.disableUrlSync(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!this.state.embedded) { |
|
|
|
if (!this.state.embedded) { |
|
|
|
saveRecentTrail(); |
|
|
|
saveRecentTrail(); |
|
|
|
} |
|
|
|
} |
|
|
@ -115,18 +107,6 @@ export class DataTrail extends SceneObjectBase<DataTrailState> { |
|
|
|
}; |
|
|
|
}; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private enableUrlSync() { |
|
|
|
|
|
|
|
if (!this.state.embedded) { |
|
|
|
|
|
|
|
getUrlSyncManager().initSync(this); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private disableUrlSync() { |
|
|
|
|
|
|
|
if (!this.state.embedded) { |
|
|
|
|
|
|
|
getUrlSyncManager().cleanUp(this); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected _variableDependency = new VariableDependencyConfig(this, { |
|
|
|
protected _variableDependency = new VariableDependencyConfig(this, { |
|
|
|
variableNames: [VAR_DATASOURCE], |
|
|
|
variableNames: [VAR_DATASOURCE], |
|
|
|
onReferencedVariableValueChanged: (variable: SceneVariable) => { |
|
|
|
onReferencedVariableValueChanged: (variable: SceneVariable) => { |
|
|
@ -167,8 +147,6 @@ export class DataTrail extends SceneObjectBase<DataTrailState> { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public restoreFromHistoryStep(state: DataTrailState) { |
|
|
|
public restoreFromHistoryStep(state: DataTrailState) { |
|
|
|
this.disableUrlSync(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!state.topScene && !state.metric) { |
|
|
|
if (!state.topScene && !state.metric) { |
|
|
|
// If the top scene for an is missing, correct it.
|
|
|
|
// If the top scene for an is missing, correct it.
|
|
|
|
state.topScene = new MetricSelectScene({}); |
|
|
|
state.topScene = new MetricSelectScene({}); |
|
|
@ -184,8 +162,6 @@ export class DataTrail extends SceneObjectBase<DataTrailState> { |
|
|
|
const urlState = getUrlSyncManager().getUrlState(this); |
|
|
|
const urlState = getUrlSyncManager().getUrlState(this); |
|
|
|
const fullUrl = urlUtil.renderUrl(locationService.getLocation().pathname, urlState); |
|
|
|
const fullUrl = urlUtil.renderUrl(locationService.getLocation().pathname, urlState); |
|
|
|
locationService.replace(fullUrl); |
|
|
|
locationService.replace(fullUrl); |
|
|
|
|
|
|
|
|
|
|
|
this.enableUrlSync(); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private _handleMetricSelectedEvent(evt: MetricSelectedEvent) { |
|
|
|
private _handleMetricSelectedEvent(evt: MetricSelectedEvent) { |
|
|
@ -227,24 +203,26 @@ export class DataTrail extends SceneObjectBase<DataTrailState> { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static Component = ({ model }: SceneComponentProps<DataTrail>) => { |
|
|
|
static Component = ({ model }: SceneComponentProps<DataTrail>) => { |
|
|
|
const { controls, topScene, history, settings } = model.useState(); |
|
|
|
const { controls, topScene, history, settings, metric } = model.useState(); |
|
|
|
const styles = useStyles2(getStyles); |
|
|
|
const styles = useStyles2(getStyles); |
|
|
|
const showHeaderForFirstTimeUsers = getTrailStore().recent.length < 2; |
|
|
|
const showHeaderForFirstTimeUsers = getTrailStore().recent.length < 2; |
|
|
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
return ( |
|
|
|
<div className={styles.container}> |
|
|
|
<Page navId="explore/metrics" pageNav={{ text: getMetricName(metric) }} layout={PageLayoutType.Custom}> |
|
|
|
{showHeaderForFirstTimeUsers && <MetricsHeader />} |
|
|
|
<div className={styles.container}> |
|
|
|
<history.Component model={history} /> |
|
|
|
{showHeaderForFirstTimeUsers && <MetricsHeader />} |
|
|
|
{controls && ( |
|
|
|
<history.Component model={history} /> |
|
|
|
<div className={styles.controls}> |
|
|
|
{controls && ( |
|
|
|
{controls.map((control) => ( |
|
|
|
<div className={styles.controls}> |
|
|
|
<control.Component key={control.state.key} model={control} /> |
|
|
|
{controls.map((control) => ( |
|
|
|
))} |
|
|
|
<control.Component key={control.state.key} model={control} /> |
|
|
|
<settings.Component model={settings} /> |
|
|
|
))} |
|
|
|
</div> |
|
|
|
<settings.Component model={settings} /> |
|
|
|
)} |
|
|
|
</div> |
|
|
|
<div className={styles.body}>{topScene && <topScene.Component model={topScene} />}</div> |
|
|
|
)} |
|
|
|
</div> |
|
|
|
<div className={styles.body}>{topScene && <topScene.Component model={topScene} />}</div> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
</Page> |
|
|
|
); |
|
|
|
); |
|
|
|
}; |
|
|
|
}; |
|
|
|
} |
|
|
|
} |
|
|
@ -288,6 +266,8 @@ function getStyles(theme: GrafanaTheme2) { |
|
|
|
gap: theme.spacing(1), |
|
|
|
gap: theme.spacing(1), |
|
|
|
minHeight: '100%', |
|
|
|
minHeight: '100%', |
|
|
|
flexDirection: 'column', |
|
|
|
flexDirection: 'column', |
|
|
|
|
|
|
|
background: theme.isLight ? theme.colors.background.primary : theme.colors.background.canvas, |
|
|
|
|
|
|
|
padding: theme.spacing(2, 3, 2, 3), |
|
|
|
}), |
|
|
|
}), |
|
|
|
body: css({ |
|
|
|
body: css({ |
|
|
|
flexGrow: 1, |
|
|
|
flexGrow: 1, |
|
|
|