mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Scenes: Remove old scenes stuff (#79760)
* Scenes: Remove old scenes stuff * Fixes * Fixes * update
This commit is contained in:
parent
692e8958a3
commit
f0c38611a2
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
@ -413,7 +413,6 @@ cypress.config.js @grafana/grafana-frontend-platform
|
||||
/public/app/features/runtime/ @ryantxu
|
||||
/public/app/features/query/ @grafana/dashboards-squad
|
||||
/public/app/features/sandbox/ @grafana/grafana-frontend-platform
|
||||
/public/app/features/scenes/ @grafana/dashboards-squad
|
||||
/public/app/features/browse-dashboards/ @grafana/grafana-frontend-platform
|
||||
/public/app/features/search/ @grafana/grafana-frontend-platform
|
||||
/public/app/features/serviceaccounts/ @grafana/identity-access-team
|
||||
|
@ -368,15 +368,6 @@ func (s *ServiceImpl) buildDashboardNavLinks(c *contextmodel.ReqContext) []*navt
|
||||
}
|
||||
}
|
||||
|
||||
if s.features.IsEnabled(c.Req.Context(), featuremgmt.FlagScenes) {
|
||||
dashboardChildNavs = append(dashboardChildNavs, &navtree.NavLink{
|
||||
Text: "Scenes",
|
||||
Id: "scenes",
|
||||
Url: s.cfg.AppSubURL + "/scenes",
|
||||
Icon: "apps",
|
||||
})
|
||||
}
|
||||
|
||||
if s.features.IsEnabled(c.Req.Context(), featuremgmt.FlagDatatrails) {
|
||||
dashboardChildNavs = append(dashboardChildNavs, &navtree.NavLink{
|
||||
Text: "Data trails",
|
||||
|
@ -121,7 +121,6 @@ export class PanelEditor extends SceneObjectBase<PanelEditorState> {
|
||||
getDashboardUrl({
|
||||
uid: this.state.dashboardRef.resolve().state.uid,
|
||||
currentQueryParams: locationService.getLocation().search,
|
||||
useExperimentalURL: true,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ import * as H from 'history';
|
||||
import { Unsubscribable } from 'rxjs';
|
||||
|
||||
import { CoreApp, DataQueryRequest, NavIndex, NavModelItem } from '@grafana/data';
|
||||
import { config, locationService } from '@grafana/runtime';
|
||||
import { locationService } from '@grafana/runtime';
|
||||
import {
|
||||
getUrlSyncManager,
|
||||
SceneFlexLayout,
|
||||
@ -195,7 +195,6 @@ export class DashboardScene extends SceneObjectBase<DashboardSceneState> {
|
||||
uid: this.state.uid,
|
||||
currentQueryParams: location.search,
|
||||
updateQuery: { viewPanel: null, inspect: null, editview: null },
|
||||
useExperimentalURL: Boolean(config.featureToggles.dashboardSceneForViewers && meta.canEdit),
|
||||
}),
|
||||
};
|
||||
|
||||
|
@ -54,7 +54,7 @@ describe('panelMenuBehavior', () => {
|
||||
});
|
||||
|
||||
beforeAll(() => {
|
||||
locationService.push('/scenes/dashboard/dash-1?from=now-5m&to=now');
|
||||
locationService.push('/d/dash-1?from=now-5m&to=now');
|
||||
});
|
||||
|
||||
it('Given standard panel', async () => {
|
||||
@ -71,9 +71,9 @@ describe('panelMenuBehavior', () => {
|
||||
|
||||
expect(menu.state.items?.length).toBe(6);
|
||||
// verify view panel url keeps url params and adds viewPanel=<panel-key>
|
||||
expect(menu.state.items?.[0].href).toBe('/scenes/dashboard/dash-1?from=now-5m&to=now&viewPanel=panel-12');
|
||||
expect(menu.state.items?.[0].href).toBe('/d/dash-1?from=now-5m&to=now&viewPanel=panel-12');
|
||||
// verify edit url keeps url time range
|
||||
expect(menu.state.items?.[1].href).toBe('/scenes/dashboard/dash-1/panel-edit/12?from=now-5m&to=now');
|
||||
expect(menu.state.items?.[1].href).toBe('/d/dash-1/panel-edit/12?from=now-5m&to=now');
|
||||
// verify share
|
||||
expect(menu.state.items?.[2].text).toBe('Share');
|
||||
// verify explore url
|
||||
@ -86,7 +86,7 @@ describe('panelMenuBehavior', () => {
|
||||
expect(getExploreArgs.scopedVars?.__sceneObject?.value).toBe(panel);
|
||||
|
||||
// verify inspect url keeps url params and adds inspect=<panel-key>
|
||||
expect(menu.state.items?.[4].href).toBe('/scenes/dashboard/dash-1?from=now-5m&to=now&inspect=panel-12');
|
||||
expect(menu.state.items?.[4].href).toBe('/d/dash-1?from=now-5m&to=now&inspect=panel-12');
|
||||
expect(menu.state.items?.[4].subMenu).toBeDefined();
|
||||
|
||||
expect(menu.state.items?.[4].subMenu?.length).toBe(3);
|
||||
|
@ -71,7 +71,6 @@ export function panelMenuBehavior(menu: VizPanelMenu) {
|
||||
uid: dashboard.state.uid,
|
||||
subPath: `/panel-edit/${panelId}`,
|
||||
currentQueryParams: location.search,
|
||||
useExperimentalURL: true,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ describe('ShareLinkTab', () => {
|
||||
config.rendererAvailable = true;
|
||||
config.bootData.user.orgId = 1;
|
||||
config.featureToggles.dashboardSceneForViewers = true;
|
||||
locationService.push('/scenes/dashboard/dash-1?from=now-6h&to=now');
|
||||
locationService.push('/d/dash-1?from=now-6h&to=now');
|
||||
});
|
||||
|
||||
describe('with locked time range (absolute) range', () => {
|
||||
@ -38,7 +38,7 @@ describe('ShareLinkTab', () => {
|
||||
buildAndRenderScenario({});
|
||||
|
||||
expect(await screen.findByRole('textbox', { name: 'Link URL' })).toHaveValue(
|
||||
'http://dashboards.grafana.com/grafana/scenes/dashboard/dash-1?from=2019-02-11T13:00:00.000Z&to=2019-02-11T19:00:00.000Z&viewPanel=panel-12'
|
||||
'http://dashboards.grafana.com/grafana/d/dash-1?from=2019-02-11T13:00:00.000Z&to=2019-02-11T19:00:00.000Z&viewPanel=panel-12'
|
||||
);
|
||||
});
|
||||
});
|
||||
@ -49,7 +49,7 @@ describe('ShareLinkTab', () => {
|
||||
act(() => tab.onToggleLockedTime());
|
||||
|
||||
expect(await screen.findByRole('textbox', { name: 'Link URL' })).toHaveValue(
|
||||
'http://dashboards.grafana.com/grafana/scenes/dashboard/dash-1?from=now-6h&to=now&viewPanel=panel-12'
|
||||
'http://dashboards.grafana.com/grafana/d/dash-1?from=now-6h&to=now&viewPanel=panel-12'
|
||||
);
|
||||
});
|
||||
});
|
||||
@ -59,7 +59,7 @@ describe('ShareLinkTab', () => {
|
||||
act(() => tab.onThemeChange('light'));
|
||||
|
||||
expect(await screen.findByRole('textbox', { name: 'Link URL' })).toHaveValue(
|
||||
'http://dashboards.grafana.com/grafana/scenes/dashboard/dash-1?from=2019-02-11T13:00:00.000Z&to=2019-02-11T19:00:00.000Z&viewPanel=panel-12&theme=light'
|
||||
'http://dashboards.grafana.com/grafana/d/dash-1?from=2019-02-11T13:00:00.000Z&to=2019-02-11T19:00:00.000Z&viewPanel=panel-12&theme=light'
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -76,7 +76,6 @@ export class ShareLinkTab extends SceneObjectBase<ShareLinkTabState> {
|
||||
currentQueryParams: location.search,
|
||||
updateQuery: urlParamsUpdate,
|
||||
absolute: true,
|
||||
useExperimentalURL: Boolean(config.featureToggles.dashboardSceneForViewers && dashboard.state.meta.canEdit),
|
||||
});
|
||||
|
||||
if (useShortUrl) {
|
||||
|
@ -2,9 +2,9 @@ import { getDashboardUrl } from './urlBuilders';
|
||||
|
||||
describe('dashboard utils', () => {
|
||||
it('Can getUrl', () => {
|
||||
const url = getDashboardUrl({ uid: 'dash-1', currentQueryParams: '?orgId=1&filter=A', useExperimentalURL: true });
|
||||
const url = getDashboardUrl({ uid: 'dash-1', currentQueryParams: '?orgId=1&filter=A' });
|
||||
|
||||
expect(url).toBe('/scenes/dashboard/dash-1?orgId=1&filter=A');
|
||||
expect(url).toBe('/d/dash-1?orgId=1&filter=A');
|
||||
});
|
||||
|
||||
it('Can getUrl with subpath', () => {
|
||||
@ -12,10 +12,9 @@ describe('dashboard utils', () => {
|
||||
uid: 'dash-1',
|
||||
subPath: '/panel-edit/2',
|
||||
currentQueryParams: '?orgId=1&filter=A',
|
||||
useExperimentalURL: true,
|
||||
});
|
||||
|
||||
expect(url).toBe('/scenes/dashboard/dash-1/panel-edit/2?orgId=1&filter=A');
|
||||
expect(url).toBe('/d/dash-1/panel-edit/2?orgId=1&filter=A');
|
||||
});
|
||||
|
||||
it('Can getUrl with params removed and addded', () => {
|
||||
@ -23,9 +22,8 @@ describe('dashboard utils', () => {
|
||||
uid: 'dash-1',
|
||||
currentQueryParams: '?orgId=1&filter=A',
|
||||
updateQuery: { filter: null, new: 'A' },
|
||||
useExperimentalURL: true,
|
||||
});
|
||||
|
||||
expect(url).toBe('/scenes/dashboard/dash-1?orgId=1&new=A');
|
||||
expect(url).toBe('/d/dash-1?orgId=1&new=A');
|
||||
});
|
||||
});
|
||||
|
@ -21,15 +21,10 @@ export interface DashboardUrlOptions {
|
||||
absolute?: boolean;
|
||||
// Add tz to query params
|
||||
timeZone?: string;
|
||||
|
||||
// Add tz to query params
|
||||
useExperimentalURL?: boolean;
|
||||
}
|
||||
|
||||
export function getDashboardUrl(options: DashboardUrlOptions) {
|
||||
let path = options.useExperimentalURL
|
||||
? `/scenes/dashboard/${options.uid}${options.subPath ?? ''}`
|
||||
: `/d/${options.uid}${options.subPath ?? ''}`;
|
||||
let path = `/d/${options.uid}${options.subPath ?? ''}`;
|
||||
|
||||
if (options.soloRoute) {
|
||||
path = `/d-solo/${options.uid}${options.subPath ?? ''}`;
|
||||
|
@ -203,8 +203,7 @@ export const DashNav = React.memo<Props>((props) => {
|
||||
tooltip={'View as Scene'}
|
||||
icon="apps"
|
||||
onClick={() => {
|
||||
const location = locationService.getLocation();
|
||||
locationService.push(`/scenes/dashboard/${dashboard.uid}${location.search}`);
|
||||
locationService.partial({ scenes: true });
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
@ -18,7 +18,7 @@ export type DashboardPageProxyProps = GrafanaRouteComponentProps<
|
||||
// This proxy component is used for Dashboard -> Scenes migration.
|
||||
// It will render DashboardScenePage if the user is only allowed to view the dashboard.
|
||||
function DashboardPageProxy(props: DashboardPageProxyProps) {
|
||||
if (config.featureToggles.dashboardScene) {
|
||||
if (config.featureToggles.dashboardScene || props.queryParams.scenes) {
|
||||
return <DashboardScenePage {...props} />;
|
||||
}
|
||||
|
||||
|
@ -18,4 +18,5 @@ export type DashboardPageRouteSearchParams = {
|
||||
to?: string;
|
||||
refresh?: string;
|
||||
kiosk?: string | true;
|
||||
scenes?: boolean;
|
||||
};
|
||||
|
@ -1,57 +0,0 @@
|
||||
// Libraries
|
||||
import React from 'react';
|
||||
import { useAsync } from 'react-use';
|
||||
|
||||
import { Card, Stack } from '@grafana/ui';
|
||||
import { Page } from 'app/core/components/Page/Page';
|
||||
|
||||
// Types
|
||||
import { getGrafanaSearcher } from '../search/service';
|
||||
|
||||
import { getScenes } from './scenes';
|
||||
|
||||
export interface Props {}
|
||||
|
||||
export const SceneListPage = ({}: Props) => {
|
||||
const scenes = getScenes();
|
||||
const results = useAsync(() => {
|
||||
return getGrafanaSearcher().starred({ starred: true });
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Page navId="scenes" subTitle="Experimental new runtime and state model for dashboards">
|
||||
<Page.Contents>
|
||||
<Stack direction="column" gap={1}>
|
||||
<h5>Apps</h5>
|
||||
<Stack direction="column" gap={0}>
|
||||
<Card href={`/scenes/grafana-monitoring`}>
|
||||
<Card.Heading>Grafana monitoring</Card.Heading>
|
||||
</Card>
|
||||
</Stack>
|
||||
<h5>Test scenes</h5>
|
||||
<Stack direction="column" gap={0}>
|
||||
{scenes.map((scene) => (
|
||||
<Card key={scene.title} href={`/scenes/${scene.title}`}>
|
||||
<Card.Heading>{scene.title}</Card.Heading>
|
||||
</Card>
|
||||
))}
|
||||
</Stack>
|
||||
{results.value && (
|
||||
<>
|
||||
<h5>Starred dashboards</h5>
|
||||
<Stack direction="column" gap={0}>
|
||||
{results.value!.view.map((dash) => (
|
||||
<Card href={`/scenes/dashboard/${dash.uid}`} key={dash.uid}>
|
||||
<Card.Heading>{dash.name}</Card.Heading>
|
||||
</Card>
|
||||
))}
|
||||
</Stack>
|
||||
</>
|
||||
)}
|
||||
</Stack>
|
||||
</Page.Contents>
|
||||
</Page>
|
||||
);
|
||||
};
|
||||
|
||||
export default SceneListPage;
|
@ -1,33 +0,0 @@
|
||||
// Libraries
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
import { getUrlSyncManager } from '@grafana/scenes';
|
||||
import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
|
||||
|
||||
import { getSceneByTitle } from './scenes';
|
||||
|
||||
export interface Props extends GrafanaRouteComponentProps<{ name: string }> {}
|
||||
|
||||
export const ScenePage = (props: Props) => {
|
||||
const scene = getSceneByTitle(props.match.params.name);
|
||||
const [isInitialized, setInitialized] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (scene && !isInitialized) {
|
||||
getUrlSyncManager().initSync(scene);
|
||||
setInitialized(true);
|
||||
}
|
||||
}, [isInitialized, scene]);
|
||||
|
||||
if (!scene) {
|
||||
return <h2>Scene not found</h2>;
|
||||
}
|
||||
|
||||
if (!isInitialized) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return <scene.Component model={scene} />;
|
||||
};
|
||||
|
||||
export default ScenePage;
|
@ -1,110 +0,0 @@
|
||||
// Libraries
|
||||
import React, { useMemo, useState } from 'react';
|
||||
|
||||
import { SceneApp, SceneAppPage, SceneRouteMatch, SceneAppPageLike } from '@grafana/scenes';
|
||||
import { usePageNav } from 'app/core/components/Page/usePageNav';
|
||||
import { PluginPageContext, PluginPageContextType } from 'app/features/plugins/components/PluginPageContext';
|
||||
|
||||
import {
|
||||
getOverviewScene,
|
||||
getHttpHandlerListScene,
|
||||
getOverviewLogsScene,
|
||||
getHandlerDetailsScene,
|
||||
getHandlerLogsScene,
|
||||
} from './scenes';
|
||||
import { getTrafficScene } from './traffic';
|
||||
|
||||
export function GrafanaMonitoringApp() {
|
||||
const appScene = useMemo(
|
||||
() =>
|
||||
new SceneApp({
|
||||
pages: [getMainPageScene()],
|
||||
}),
|
||||
[]
|
||||
);
|
||||
|
||||
const sectionNav = usePageNav('scenes')!;
|
||||
const [pluginContext] = useState<PluginPageContextType>({ sectionNav });
|
||||
|
||||
return (
|
||||
<PluginPageContext.Provider value={pluginContext}>
|
||||
<appScene.Component model={appScene} />
|
||||
</PluginPageContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function getMainPageScene() {
|
||||
return new SceneAppPage({
|
||||
title: 'Grafana Monitoring',
|
||||
subTitle: 'A custom app with embedded scenes to monitor your Grafana server',
|
||||
url: '/scenes/grafana-monitoring',
|
||||
hideFromBreadcrumbs: false,
|
||||
getScene: getOverviewScene,
|
||||
tabs: [
|
||||
new SceneAppPage({
|
||||
title: 'Overview',
|
||||
url: '/scenes/grafana-monitoring',
|
||||
getScene: getOverviewScene,
|
||||
preserveUrlKeys: ['from', 'to', 'var-instance'],
|
||||
}),
|
||||
new SceneAppPage({
|
||||
title: 'HTTP handlers',
|
||||
url: '/scenes/grafana-monitoring/handlers',
|
||||
getScene: getHttpHandlerListScene,
|
||||
preserveUrlKeys: ['from', 'to', 'var-instance'],
|
||||
drilldowns: [
|
||||
{
|
||||
routePath: '/scenes/grafana-monitoring/handlers/:handler',
|
||||
getPage: getHandlerDrilldownPage,
|
||||
},
|
||||
],
|
||||
}),
|
||||
new SceneAppPage({
|
||||
title: 'Traffic',
|
||||
url: '/scenes/grafana-monitoring/traffic',
|
||||
getScene: getTrafficScene,
|
||||
preserveUrlKeys: ['from', 'to', 'var-instance'],
|
||||
}),
|
||||
new SceneAppPage({
|
||||
title: 'Logs',
|
||||
url: '/scenes/grafana-monitoring/logs',
|
||||
getScene: getOverviewLogsScene,
|
||||
preserveUrlKeys: ['from', 'to', 'var-instance'],
|
||||
}),
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
export function getHandlerDrilldownPage(
|
||||
match: SceneRouteMatch<{ handler: string; tab?: string }>,
|
||||
parent: SceneAppPageLike
|
||||
) {
|
||||
const handler = decodeURIComponent(match.params.handler);
|
||||
const baseUrl = `/scenes/grafana-monitoring/handlers/${encodeURIComponent(handler)}`;
|
||||
|
||||
return new SceneAppPage({
|
||||
title: handler,
|
||||
subTitle: 'A grafana http handler is responsible for service a specific API request',
|
||||
url: baseUrl,
|
||||
getParentPage: () => parent,
|
||||
getScene: () => getHandlerDetailsScene(handler),
|
||||
tabs: [
|
||||
new SceneAppPage({
|
||||
title: 'Metrics',
|
||||
url: baseUrl,
|
||||
routePath: '/scenes/grafana-monitoring/handlers/:handler',
|
||||
getScene: () => getHandlerDetailsScene(handler),
|
||||
preserveUrlKeys: ['from', 'to', 'var-instance'],
|
||||
}),
|
||||
new SceneAppPage({
|
||||
title: 'Logs',
|
||||
url: baseUrl + '/logs',
|
||||
routePath: '/scenes/grafana-monitoring/handlers/:handler/logs',
|
||||
getScene: () => getHandlerLogsScene(handler),
|
||||
preserveUrlKeys: ['from', 'to', 'var-instance'],
|
||||
}),
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
export default GrafanaMonitoringApp;
|
@ -1,24 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import { SceneComponentProps, SceneObjectBase, SceneObjectState } from '@grafana/scenes';
|
||||
import { RadioButtonGroup } from '@grafana/ui';
|
||||
|
||||
export interface SceneRadioToggleState extends SceneObjectState {
|
||||
options: Array<SelectableValue<string>>;
|
||||
value: string;
|
||||
onChange: (value: string) => void;
|
||||
}
|
||||
|
||||
export class SceneRadioToggle extends SceneObjectBase<SceneRadioToggleState> {
|
||||
onChange = (value: string) => {
|
||||
this.setState({ value });
|
||||
this.state.onChange(value);
|
||||
};
|
||||
|
||||
static Component = ({ model }: SceneComponentProps<SceneRadioToggle>) => {
|
||||
const { options, value } = model.useState();
|
||||
|
||||
return <RadioButtonGroup options={options} value={value} onChange={model.onChange} />;
|
||||
};
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
import { SceneComponentProps, SceneObjectState, SceneObjectBase } from '@grafana/scenes';
|
||||
import { Input } from '@grafana/ui';
|
||||
|
||||
export interface SceneSearchBoxState extends SceneObjectState {
|
||||
value: string;
|
||||
}
|
||||
|
||||
export class SceneSearchBox extends SceneObjectBase<SceneSearchBoxState> {
|
||||
onChange = (evt: React.FormEvent<HTMLInputElement>) => {
|
||||
this.setState({ value: evt.currentTarget.value });
|
||||
};
|
||||
|
||||
static Component = ({ model }: SceneComponentProps<SceneSearchBox>) => {
|
||||
const { value } = model.useState();
|
||||
|
||||
return <Input width={25} placeholder="Search..." value={value} onChange={model.onChange} />;
|
||||
};
|
||||
}
|
@ -1,428 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
import { FieldColorModeId, getFrameDisplayName } from '@grafana/data';
|
||||
import { locationService } from '@grafana/runtime';
|
||||
import {
|
||||
SceneFlexLayout,
|
||||
SceneByFrameRepeater,
|
||||
SceneTimePicker,
|
||||
EmbeddedScene,
|
||||
SceneDataNode,
|
||||
SceneTimeRange,
|
||||
VariableValueSelectors,
|
||||
SceneQueryRunner,
|
||||
SceneControlsSpacer,
|
||||
SceneDataTransformer,
|
||||
SceneRefreshPicker,
|
||||
SceneFlexItem,
|
||||
PanelBuilders,
|
||||
} from '@grafana/scenes';
|
||||
import { BigValueGraphMode, BigValueTextMode, LogsDedupStrategy, LogsSortOrder } from '@grafana/schema';
|
||||
import { LinkButton } from '@grafana/ui';
|
||||
|
||||
import { SceneRadioToggle } from './SceneRadioToggle';
|
||||
import { SceneSearchBox } from './SceneSearchBox';
|
||||
import { getTableFilterTransform, getTimeSeriesFilterTransform } from './transforms';
|
||||
import { getInstantQuery, getLinkUrlWithAppUrlState, getTimeSeriesQuery, getVariablesDefinitions } from './utils';
|
||||
|
||||
export function getHttpHandlerListScene(): EmbeddedScene {
|
||||
const searchBox = new SceneSearchBox({ value: '' });
|
||||
|
||||
const httpHandlerQueries = getInstantQuery({
|
||||
expr: 'sort_desc(avg without(job, instance) (rate(grafana_http_request_duration_seconds_sum[$__rate_interval]) * 1e3)) ',
|
||||
});
|
||||
|
||||
const httpHandlerQueriesFiltered = new SceneDataTransformer({
|
||||
$data: httpHandlerQueries,
|
||||
transformations: [getTableFilterTransform('')],
|
||||
});
|
||||
|
||||
httpHandlerQueriesFiltered.addActivationHandler(() => {
|
||||
const sub = searchBox.subscribeToState((state) => {
|
||||
// Update transform and re-process them
|
||||
httpHandlerQueriesFiltered.setState({ transformations: [getTableFilterTransform(state.value)] });
|
||||
httpHandlerQueriesFiltered.reprocessTransformations();
|
||||
});
|
||||
|
||||
return () => sub.unsubscribe();
|
||||
});
|
||||
|
||||
const httpHandlersTable = PanelBuilders.table()
|
||||
.setTitle('Handlers')
|
||||
.setData(httpHandlerQueriesFiltered)
|
||||
.setOption('footer', {
|
||||
enablePagination: true,
|
||||
})
|
||||
.setOverrides((b) =>
|
||||
b
|
||||
.matchFieldsWithNameByRegex('.*')
|
||||
.overrideFilterable(false)
|
||||
.matchFieldsWithName('Time')
|
||||
.overrideCustomFieldConfig('hidden', true)
|
||||
.matchFieldsWithName('Value')
|
||||
.overrideDisplayName('Duration (Avg)')
|
||||
.matchFieldsWithName('handler')
|
||||
.overrideLinks([
|
||||
{
|
||||
title: 'Go to handler drilldown view',
|
||||
url: '',
|
||||
onBuildUrl: () => {
|
||||
const params = locationService.getSearchObject();
|
||||
return getLinkUrlWithAppUrlState(
|
||||
'/scenes/grafana-monitoring/handlers/${__value.text:percentencode}',
|
||||
params
|
||||
);
|
||||
},
|
||||
},
|
||||
])
|
||||
)
|
||||
.build();
|
||||
|
||||
const reqDurationTimeSeries = new SceneQueryRunner({
|
||||
datasource: { uid: 'gdev-prometheus' },
|
||||
queries: [
|
||||
{
|
||||
refId: 'A',
|
||||
//expr: ``,
|
||||
expr: 'topk(20, avg without(job, instance) (rate(grafana_http_request_duration_seconds_sum[$__rate_interval])) * 1e3)',
|
||||
range: true,
|
||||
format: 'time_series',
|
||||
legendFormat: '{{method}} {{handler}} (status = {{status_code}})',
|
||||
maxDataPoints: 500,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const reqDurationTimeSeriesFiltered = new SceneDataTransformer({
|
||||
$data: reqDurationTimeSeries,
|
||||
transformations: [getTimeSeriesFilterTransform('')],
|
||||
});
|
||||
|
||||
reqDurationTimeSeriesFiltered.addActivationHandler(() => {
|
||||
const sub = searchBox.subscribeToState((state) => {
|
||||
// Update transform and re-process them
|
||||
reqDurationTimeSeriesFiltered.setState({ transformations: [getTimeSeriesFilterTransform(state.value)] });
|
||||
reqDurationTimeSeriesFiltered.reprocessTransformations();
|
||||
});
|
||||
|
||||
return () => sub.unsubscribe();
|
||||
});
|
||||
|
||||
const graphsScene = new SceneByFrameRepeater({
|
||||
$data: reqDurationTimeSeriesFiltered,
|
||||
body: new SceneFlexLayout({
|
||||
direction: 'column',
|
||||
children: [],
|
||||
}),
|
||||
getLayoutChild: (data, frame, frameIndex) => {
|
||||
return new SceneFlexItem({
|
||||
key: `panel-${frameIndex}`,
|
||||
minHeight: 200,
|
||||
$data: new SceneDataNode({
|
||||
data: {
|
||||
...data,
|
||||
series: [frame],
|
||||
},
|
||||
}),
|
||||
body: new SceneFlexLayout({
|
||||
direction: 'row',
|
||||
key: `row-${frameIndex}`,
|
||||
children: [
|
||||
new SceneFlexItem({
|
||||
key: `flex1-${frameIndex}`,
|
||||
body: PanelBuilders.timeseries()
|
||||
.setTitle(getFrameDisplayName(frame))
|
||||
.setOption('legend', { showLegend: false })
|
||||
.setHeaderActions(
|
||||
<LinkButton
|
||||
fill="text"
|
||||
size="sm"
|
||||
icon="arrow-right"
|
||||
href={getHandlerDrilldownUrl(frame.fields[1]!.labels!.handler)}
|
||||
>
|
||||
Details
|
||||
</LinkButton>
|
||||
)
|
||||
.build(),
|
||||
}),
|
||||
|
||||
new SceneFlexItem({
|
||||
key: `flex2-${frameIndex}`,
|
||||
width: 200,
|
||||
body: PanelBuilders.stat()
|
||||
.setTitle('Last')
|
||||
.setOption('graphMode', BigValueGraphMode.None)
|
||||
.setOption('textMode', BigValueTextMode.Value)
|
||||
.setDisplayName('Last')
|
||||
.build(),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const layout = new SceneFlexLayout({
|
||||
children: [new SceneFlexItem({ body: httpHandlersTable })],
|
||||
});
|
||||
|
||||
const sceneToggle = new SceneRadioToggle({
|
||||
options: [
|
||||
{ value: 'table', label: 'Table' },
|
||||
{ value: 'graphs', label: 'Graphs' },
|
||||
],
|
||||
value: 'table',
|
||||
onChange: (value) => {
|
||||
if (value === 'table') {
|
||||
layout.setState({ children: [new SceneFlexItem({ body: httpHandlersTable })] });
|
||||
} else {
|
||||
layout.setState({ children: [graphsScene] });
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const scene = new EmbeddedScene({
|
||||
$variables: getVariablesDefinitions(),
|
||||
$data: httpHandlerQueries,
|
||||
$timeRange: new SceneTimeRange({ from: 'now-1h', to: 'now' }),
|
||||
controls: [
|
||||
new VariableValueSelectors({}),
|
||||
searchBox,
|
||||
new SceneControlsSpacer(),
|
||||
sceneToggle,
|
||||
new SceneTimePicker({ isOnCanvas: true }),
|
||||
new SceneRefreshPicker({ isOnCanvas: true }),
|
||||
],
|
||||
body: layout,
|
||||
});
|
||||
|
||||
return scene;
|
||||
}
|
||||
|
||||
function getHandlerDrilldownUrl(handler: string) {
|
||||
const params = locationService.getSearchObject();
|
||||
return getLinkUrlWithAppUrlState(`/scenes/grafana-monitoring/handlers/${encodeURIComponent(handler)}`, params);
|
||||
}
|
||||
|
||||
export function getHandlerDetailsScene(handler: string): EmbeddedScene {
|
||||
const reqDurationTimeSeries = getTimeSeriesQuery({
|
||||
expr: `avg without(job, instance) (rate(grafana_http_request_duration_seconds_sum{handler="${handler}"}[$__rate_interval])) * 1e3`,
|
||||
legendFormat: '{{method}} {{handler}} (status = {{status_code}})',
|
||||
});
|
||||
|
||||
const reqCountTimeSeries = getTimeSeriesQuery({
|
||||
expr: `sum without(job, instance) (rate(grafana_http_request_duration_seconds_count{handler="${handler}"}[$__rate_interval])) `,
|
||||
legendFormat: '{{method}} {{handler}} (status = {{status_code}})',
|
||||
});
|
||||
|
||||
const scene = new EmbeddedScene({
|
||||
$variables: getVariablesDefinitions(),
|
||||
$timeRange: new SceneTimeRange({ from: 'now-1h', to: 'now' }),
|
||||
controls: [
|
||||
new VariableValueSelectors({}),
|
||||
new SceneControlsSpacer(),
|
||||
new SceneTimePicker({ isOnCanvas: true }),
|
||||
new SceneRefreshPicker({ isOnCanvas: true }),
|
||||
],
|
||||
body: new SceneFlexLayout({
|
||||
direction: 'column',
|
||||
children: [
|
||||
new SceneFlexItem({
|
||||
body: PanelBuilders.timeseries().setData(reqDurationTimeSeries).setTitle('Request duration avg (ms)').build(),
|
||||
}),
|
||||
new SceneFlexItem({
|
||||
body: PanelBuilders.timeseries().setData(reqCountTimeSeries).setTitle('Request count/s').build(),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
});
|
||||
|
||||
return scene;
|
||||
}
|
||||
|
||||
export function getOverviewScene(): EmbeddedScene {
|
||||
const scene = new EmbeddedScene({
|
||||
$variables: getVariablesDefinitions(),
|
||||
$timeRange: new SceneTimeRange({ from: 'now-1h', to: 'now' }),
|
||||
controls: [
|
||||
new VariableValueSelectors({}),
|
||||
new SceneControlsSpacer(),
|
||||
new SceneTimePicker({ isOnCanvas: true }),
|
||||
new SceneRefreshPicker({ isOnCanvas: true }),
|
||||
],
|
||||
body: new SceneFlexLayout({
|
||||
direction: 'column',
|
||||
children: [
|
||||
new SceneFlexItem({
|
||||
height: 150,
|
||||
body: new SceneFlexLayout({
|
||||
children: [
|
||||
new SceneFlexItem({
|
||||
body: getInstantStatPanel('grafana_stat_totals_dashboard', 'Dashboards'),
|
||||
}),
|
||||
new SceneFlexItem({
|
||||
body: getInstantStatPanel('grafana_stat_total_users', 'Users'),
|
||||
}),
|
||||
new SceneFlexItem({
|
||||
body: getInstantStatPanel('sum(grafana_stat_totals_datasource)', 'Data sources'),
|
||||
}),
|
||||
new SceneFlexItem({
|
||||
body: getInstantStatPanel('grafana_stat_total_service_account_tokens', 'Service account tokens'),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
}),
|
||||
|
||||
new SceneFlexItem({
|
||||
body: PanelBuilders.timeseries()
|
||||
.setData(
|
||||
new SceneQueryRunner({
|
||||
datasource: { uid: 'gdev-prometheus' },
|
||||
queries: [
|
||||
{
|
||||
refId: 'A',
|
||||
expr: `sum(process_resident_memory_bytes{job="grafana", instance=~"$instance"})`,
|
||||
range: true,
|
||||
format: 'time_series',
|
||||
maxDataPoints: 500,
|
||||
},
|
||||
],
|
||||
})
|
||||
)
|
||||
.setTitle('Memory usage')
|
||||
.setOption('legend', { showLegend: false })
|
||||
.setUnit('bytes')
|
||||
.setMin(0)
|
||||
.setCustomFieldConfig('lineWidth', 2)
|
||||
.setCustomFieldConfig('fillOpacity', 6)
|
||||
.build(),
|
||||
}),
|
||||
new SceneFlexItem({
|
||||
body: PanelBuilders.timeseries()
|
||||
.setData(
|
||||
new SceneQueryRunner({
|
||||
datasource: { uid: 'gdev-prometheus' },
|
||||
queries: [
|
||||
{
|
||||
refId: 'A',
|
||||
expr: `sum(go_goroutines{job="grafana", instance=~"$instance"})`,
|
||||
range: true,
|
||||
format: 'time_series',
|
||||
maxDataPoints: 500,
|
||||
},
|
||||
],
|
||||
})
|
||||
)
|
||||
.setOption('legend', { showLegend: false })
|
||||
.setMin(0)
|
||||
.setCustomFieldConfig('lineWidth', 2)
|
||||
.setCustomFieldConfig('fillOpacity', 6)
|
||||
.setTitle('Go routines')
|
||||
.build(),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
});
|
||||
|
||||
return scene;
|
||||
}
|
||||
|
||||
function getInstantStatPanel(query: string, title: string) {
|
||||
return PanelBuilders.stat()
|
||||
.setData(getInstantQuery({ expr: query }))
|
||||
.setTitle(title)
|
||||
.setColor({ fixedColor: 'text', mode: FieldColorModeId.Fixed })
|
||||
.build();
|
||||
}
|
||||
|
||||
export function getHandlerLogsScene(handler: string): EmbeddedScene {
|
||||
const logsQuery = new SceneQueryRunner({
|
||||
datasource: { uid: 'gdev-loki' },
|
||||
queries: [
|
||||
{
|
||||
refId: 'A',
|
||||
expr: `{job="grafana"} | logfmt | handler=\`${handler}\` | __error__=\`\``,
|
||||
queryType: 'range',
|
||||
maxDataPoints: 5000,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const scene = new EmbeddedScene({
|
||||
$variables: getVariablesDefinitions(),
|
||||
$timeRange: new SceneTimeRange({ from: 'now-1h', to: 'now' }),
|
||||
controls: [
|
||||
new VariableValueSelectors({}),
|
||||
new SceneControlsSpacer(),
|
||||
new SceneTimePicker({ isOnCanvas: true }),
|
||||
new SceneRefreshPicker({ isOnCanvas: true }),
|
||||
],
|
||||
body: new SceneFlexLayout({
|
||||
direction: 'column',
|
||||
children: [
|
||||
new SceneFlexItem({
|
||||
body: PanelBuilders.logs()
|
||||
.setData(logsQuery)
|
||||
.setTitle('')
|
||||
.setOption('showTime', true)
|
||||
.setOption('showLabels', false)
|
||||
.setOption('showCommonLabels', false)
|
||||
.setOption('wrapLogMessage', true)
|
||||
.setOption('prettifyLogMessage', false)
|
||||
.setOption('enableLogDetails', true)
|
||||
.setOption('dedupStrategy', LogsDedupStrategy.none)
|
||||
.setOption('sortOrder', LogsSortOrder.Descending)
|
||||
.build(),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
});
|
||||
|
||||
return scene;
|
||||
}
|
||||
|
||||
export function getOverviewLogsScene(): EmbeddedScene {
|
||||
const logsQuery = new SceneQueryRunner({
|
||||
datasource: { uid: 'gdev-loki' },
|
||||
queries: [
|
||||
{
|
||||
refId: 'A',
|
||||
expr: `{job="grafana"} | logfmt | __error__=\`\``,
|
||||
queryType: 'range',
|
||||
maxDataPoints: 5000,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const scene = new EmbeddedScene({
|
||||
$variables: getVariablesDefinitions(),
|
||||
$timeRange: new SceneTimeRange({ from: 'now-1h', to: 'now' }),
|
||||
controls: [
|
||||
new VariableValueSelectors({}),
|
||||
new SceneControlsSpacer(),
|
||||
new SceneTimePicker({ isOnCanvas: true }),
|
||||
new SceneRefreshPicker({ isOnCanvas: true }),
|
||||
],
|
||||
body: new SceneFlexLayout({
|
||||
direction: 'column',
|
||||
children: [
|
||||
new SceneFlexItem({
|
||||
body: PanelBuilders.logs()
|
||||
.setTitle('')
|
||||
.setData(logsQuery)
|
||||
.setOption('showTime', true)
|
||||
.setOption('showLabels', false)
|
||||
.setOption('showCommonLabels', false)
|
||||
.setOption('wrapLogMessage', true)
|
||||
.setOption('prettifyLogMessage', false)
|
||||
.setOption('enableLogDetails', true)
|
||||
.setOption('dedupStrategy', LogsDedupStrategy.none)
|
||||
.setOption('sortOrder', LogsSortOrder.Descending)
|
||||
.build(),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
});
|
||||
|
||||
return scene;
|
||||
}
|
@ -1,127 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
import {
|
||||
SceneFlexLayout,
|
||||
SceneTimePicker,
|
||||
EmbeddedScene,
|
||||
SceneTimeRange,
|
||||
VariableValueSelectors,
|
||||
SceneControlsSpacer,
|
||||
SceneRefreshPicker,
|
||||
SceneFlexItem,
|
||||
SceneObjectState,
|
||||
SceneObjectBase,
|
||||
SceneObjectUrlSyncConfig,
|
||||
SceneObjectUrlValues,
|
||||
PanelBuilders,
|
||||
} from '@grafana/scenes';
|
||||
import { Button } from '@grafana/ui';
|
||||
|
||||
import { getInstantQuery, getTimeSeriesQuery, getVariablesDefinitions } from './utils';
|
||||
|
||||
export function getTrafficScene(): EmbeddedScene {
|
||||
const httpHandlersTable = PanelBuilders.table()
|
||||
.setData(
|
||||
getInstantQuery({
|
||||
expr: 'sort_desc(avg without(job, instance) (rate(grafana_http_request_duration_seconds_sum[$__rate_interval]) * 1e3)) ',
|
||||
})
|
||||
)
|
||||
.setTitle('Handlers')
|
||||
.setOption('footer', { enablePagination: true })
|
||||
.setOverrides((b) =>
|
||||
b
|
||||
.matchFieldsWithNameByRegex('.*')
|
||||
.overrideFilterable(false)
|
||||
.matchFieldsWithName('Time')
|
||||
.overrideCustomFieldConfig('hidden', true)
|
||||
.matchFieldsWithName('Value')
|
||||
.overrideDisplayName('Duration (Avg)')
|
||||
.matchFieldsWithName('handler')
|
||||
.overrideLinks([
|
||||
{
|
||||
title: 'Go to handler drilldown view',
|
||||
url: '/scenes/grafana-monitoring/traffic?handler=${__value.text:percentencode}',
|
||||
},
|
||||
])
|
||||
)
|
||||
.build();
|
||||
|
||||
const scene = new EmbeddedScene({
|
||||
$variables: getVariablesDefinitions(),
|
||||
$timeRange: new SceneTimeRange({ from: 'now-1h', to: 'now' }),
|
||||
controls: [
|
||||
new VariableValueSelectors({}),
|
||||
new SceneControlsSpacer(),
|
||||
new SceneTimePicker({ isOnCanvas: true }),
|
||||
new SceneRefreshPicker({ isOnCanvas: true }),
|
||||
],
|
||||
body: new SceneFlexLayout({
|
||||
$behaviors: [new HandlerDrilldownViewBehavior()],
|
||||
children: [new SceneFlexItem({ body: httpHandlersTable })],
|
||||
}),
|
||||
});
|
||||
|
||||
return scene;
|
||||
}
|
||||
|
||||
export interface HandlerDrilldownViewBehaviorState extends SceneObjectState {
|
||||
handler?: string;
|
||||
}
|
||||
|
||||
export class HandlerDrilldownViewBehavior extends SceneObjectBase<HandlerDrilldownViewBehaviorState> {
|
||||
protected _urlSync = new SceneObjectUrlSyncConfig(this, { keys: ['handler'] });
|
||||
|
||||
constructor() {
|
||||
super({});
|
||||
|
||||
this.addActivationHandler(() => {
|
||||
this._subs.add(this.subscribeToState((state) => this.onHandlerChanged(state.handler)));
|
||||
this.onHandlerChanged(this.state.handler);
|
||||
});
|
||||
}
|
||||
|
||||
private onHandlerChanged(handler: string | undefined) {
|
||||
const layout = this.getLayout();
|
||||
|
||||
if (handler == null) {
|
||||
layout.setState({ children: layout.state.children.slice(0, 1) });
|
||||
} else {
|
||||
layout.setState({ children: [layout.state.children[0], this.getDrilldownView(handler)] });
|
||||
}
|
||||
}
|
||||
|
||||
private getDrilldownView(handler: string): SceneFlexItem {
|
||||
return new SceneFlexItem({
|
||||
key: 'drilldown-flex',
|
||||
body: PanelBuilders.timeseries()
|
||||
.setData(
|
||||
getTimeSeriesQuery({
|
||||
expr: `rate(grafana_http_request_duration_seconds_sum{handler="${handler}"}[$__rate_interval]) * 1e3`,
|
||||
})
|
||||
)
|
||||
.setTitle(`Handler: ${handler} details`)
|
||||
.setHeaderActions(
|
||||
<Button size="sm" variant="secondary" icon="times" onClick={() => this.setState({ handler: undefined })} />
|
||||
)
|
||||
.build(),
|
||||
});
|
||||
}
|
||||
|
||||
getUrlState() {
|
||||
return { handler: this.state.handler };
|
||||
}
|
||||
|
||||
updateFromUrl(values: SceneObjectUrlValues) {
|
||||
if (typeof values.handler === 'string' || values.handler === undefined) {
|
||||
this.setState({ handler: values.handler });
|
||||
}
|
||||
}
|
||||
|
||||
private getLayout() {
|
||||
if (this.parent instanceof SceneFlexLayout) {
|
||||
return this.parent;
|
||||
}
|
||||
|
||||
throw new Error('Invalid parent');
|
||||
}
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
import { map } from 'rxjs';
|
||||
|
||||
import {
|
||||
BasicValueMatcherOptions,
|
||||
CustomTransformOperator,
|
||||
DataTransformerID,
|
||||
getFrameDisplayName,
|
||||
ValueMatcherID,
|
||||
} from '@grafana/data';
|
||||
import { FilterByValueMatch, FilterByValueType } from '@grafana/data/src/transformations/transformers/filterByValue';
|
||||
import { DataTransformerConfig, MatcherConfig } from '@grafana/schema';
|
||||
|
||||
export function getTableFilterTransform(query: string): DataTransformerConfig {
|
||||
const regex: MatcherConfig<BasicValueMatcherOptions<string>> = {
|
||||
id: ValueMatcherID.regex,
|
||||
options: { value: query },
|
||||
};
|
||||
|
||||
return {
|
||||
id: DataTransformerID.filterByValue,
|
||||
options: {
|
||||
type: FilterByValueType.include,
|
||||
match: FilterByValueMatch.all,
|
||||
filters: [
|
||||
{
|
||||
fieldName: 'handler',
|
||||
config: regex,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function getTimeSeriesFilterTransform(query: string): CustomTransformOperator {
|
||||
return () => (source) => {
|
||||
return source.pipe(
|
||||
map((data) => {
|
||||
return data.filter((frame) => getFrameDisplayName(frame).toLowerCase().includes(query.toLowerCase()));
|
||||
})
|
||||
);
|
||||
};
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
import { useLocation } from 'react-router-dom';
|
||||
|
||||
import { UrlQueryMap, urlUtil } from '@grafana/data';
|
||||
import { locationSearchToObject } from '@grafana/runtime';
|
||||
import { QueryVariable, SceneQueryRunner, SceneVariableSet } from '@grafana/scenes';
|
||||
import { PromQuery } from 'app/plugins/datasource/prometheus/types';
|
||||
|
||||
export function useAppQueryParams() {
|
||||
const location = useLocation();
|
||||
return locationSearchToObject(location.search || '');
|
||||
}
|
||||
|
||||
export function getLinkUrlWithAppUrlState(path: string, params: UrlQueryMap): string {
|
||||
return urlUtil.renderUrl(path, params);
|
||||
}
|
||||
|
||||
export function getInstantQuery(query: Partial<PromQuery>): SceneQueryRunner {
|
||||
return new SceneQueryRunner({
|
||||
datasource: { uid: 'gdev-prometheus' },
|
||||
queries: [
|
||||
{
|
||||
refId: 'A',
|
||||
instant: true,
|
||||
format: 'table',
|
||||
maxDataPoints: 500,
|
||||
...query,
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
export function getTimeSeriesQuery(query: Partial<PromQuery>): SceneQueryRunner {
|
||||
return new SceneQueryRunner({
|
||||
datasource: { uid: 'gdev-prometheus' },
|
||||
queries: [
|
||||
{
|
||||
refId: 'A',
|
||||
range: true,
|
||||
format: 'time_series',
|
||||
maxDataPoints: 500,
|
||||
...query,
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
export function getVariablesDefinitions() {
|
||||
return new SceneVariableSet({
|
||||
variables: [
|
||||
new QueryVariable({
|
||||
name: 'instance',
|
||||
datasource: { uid: 'gdev-prometheus' },
|
||||
query: { query: 'label_values(grafana_http_request_duration_seconds_sum, instance)', refId: 'A' },
|
||||
}),
|
||||
],
|
||||
});
|
||||
}
|
@ -1,73 +0,0 @@
|
||||
import {
|
||||
SceneGridRow,
|
||||
SceneTimePicker,
|
||||
SceneGridLayout,
|
||||
SceneTimeRange,
|
||||
SceneRefreshPicker,
|
||||
SceneGridItem,
|
||||
PanelBuilders,
|
||||
} from '@grafana/scenes';
|
||||
import { TestDataQueryType } from '@grafana-plugins/grafana-testdata-datasource/dataquery.gen';
|
||||
|
||||
import { DashboardScene } from '../../dashboard-scene/scene/DashboardScene';
|
||||
|
||||
import { getQueryRunnerWithRandomWalkQuery } from './queries';
|
||||
|
||||
export function getGridWithMultipleTimeRanges(): DashboardScene {
|
||||
const globalTimeRange = new SceneTimeRange();
|
||||
const row1TimeRange = new SceneTimeRange({
|
||||
from: 'now-1y',
|
||||
to: 'now',
|
||||
});
|
||||
|
||||
return new DashboardScene({
|
||||
title: 'Grid with rows and different queries and time ranges',
|
||||
body: new SceneGridLayout({
|
||||
children: [
|
||||
new SceneGridRow({
|
||||
$timeRange: row1TimeRange,
|
||||
$data: getQueryRunnerWithRandomWalkQuery({ scenarioId: TestDataQueryType.RandomWalkTable }),
|
||||
title: 'Row A - has its own query, last year time range',
|
||||
key: 'Row A',
|
||||
isCollapsed: true,
|
||||
y: 0,
|
||||
children: [
|
||||
new SceneGridItem({
|
||||
x: 0,
|
||||
y: 1,
|
||||
width: 12,
|
||||
height: 5,
|
||||
isResizable: true,
|
||||
isDraggable: true,
|
||||
body: PanelBuilders.timeseries().setTitle('Row A Child1').build(),
|
||||
}),
|
||||
new SceneGridItem({
|
||||
x: 0,
|
||||
y: 5,
|
||||
width: 6,
|
||||
height: 5,
|
||||
isResizable: true,
|
||||
isDraggable: true,
|
||||
body: PanelBuilders.timeseries().setTitle('Row A Child2').build(),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
new SceneGridItem({
|
||||
x: 0,
|
||||
y: 12,
|
||||
width: 6,
|
||||
height: 10,
|
||||
isResizable: true,
|
||||
isDraggable: true,
|
||||
body: PanelBuilders.timeseries()
|
||||
.setTitle('Outsider, has its own query')
|
||||
.setData(getQueryRunnerWithRandomWalkQuery())
|
||||
.build(),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
$timeRange: globalTimeRange,
|
||||
$data: getQueryRunnerWithRandomWalkQuery(),
|
||||
actions: [new SceneTimePicker({}), new SceneRefreshPicker({})],
|
||||
});
|
||||
}
|
@ -1,117 +0,0 @@
|
||||
import {
|
||||
SceneTimePicker,
|
||||
SceneFlexLayout,
|
||||
SceneGridLayout,
|
||||
SceneTimeRange,
|
||||
SceneRefreshPicker,
|
||||
SceneGridItem,
|
||||
SceneFlexItem,
|
||||
PanelBuilders,
|
||||
} from '@grafana/scenes';
|
||||
|
||||
import { DashboardScene } from '../../dashboard-scene/scene/DashboardScene';
|
||||
|
||||
import { getQueryRunnerWithRandomWalkQuery } from './queries';
|
||||
|
||||
export function getMultipleGridLayoutTest(): DashboardScene {
|
||||
return new DashboardScene({
|
||||
title: 'Multiple grid layouts test',
|
||||
body: new SceneFlexLayout({
|
||||
children: [
|
||||
new SceneFlexItem({
|
||||
body: new SceneGridLayout({
|
||||
children: [
|
||||
new SceneGridItem({
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 12,
|
||||
height: 10,
|
||||
isDraggable: true,
|
||||
isResizable: true,
|
||||
body: PanelBuilders.timeseries().setTitle('Dragabble and resizable').build(),
|
||||
}),
|
||||
new SceneGridItem({
|
||||
x: 12,
|
||||
y: 0,
|
||||
width: 12,
|
||||
height: 10,
|
||||
isResizable: false,
|
||||
isDraggable: true,
|
||||
body: PanelBuilders.timeseries().setTitle('Draggable only').build(),
|
||||
}),
|
||||
new SceneGridItem({
|
||||
x: 6,
|
||||
y: 11,
|
||||
width: 12,
|
||||
height: 10,
|
||||
isResizable: false,
|
||||
isDraggable: true,
|
||||
body: new SceneFlexLayout({
|
||||
direction: 'column',
|
||||
children: [
|
||||
new SceneFlexItem({
|
||||
ySizing: 'fill',
|
||||
body: PanelBuilders.timeseries().setTitle('Fill height').build(),
|
||||
}),
|
||||
new SceneFlexItem({
|
||||
ySizing: 'fill',
|
||||
body: PanelBuilders.timeseries().setTitle('Fill height').build(),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
}),
|
||||
new SceneFlexItem({
|
||||
body: new SceneGridLayout({
|
||||
children: [
|
||||
new SceneGridItem({
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 12,
|
||||
height: 10,
|
||||
isDraggable: true,
|
||||
isResizable: true,
|
||||
body: PanelBuilders.timeseries().setTitle('Dragabble and resizable').build(),
|
||||
}),
|
||||
new SceneGridItem({
|
||||
x: 12,
|
||||
y: 0,
|
||||
width: 12,
|
||||
height: 10,
|
||||
isResizable: false,
|
||||
isDraggable: true,
|
||||
body: PanelBuilders.timeseries().setTitle('Draggable only').build(),
|
||||
}),
|
||||
new SceneGridItem({
|
||||
x: 6,
|
||||
y: 11,
|
||||
width: 12,
|
||||
height: 10,
|
||||
isResizable: false,
|
||||
isDraggable: true,
|
||||
body: new SceneFlexLayout({
|
||||
direction: 'column',
|
||||
children: [
|
||||
new SceneFlexItem({
|
||||
ySizing: 'fill',
|
||||
body: PanelBuilders.timeseries().setTitle('Fill height').build(),
|
||||
}),
|
||||
new SceneFlexItem({
|
||||
ySizing: 'fill',
|
||||
body: PanelBuilders.timeseries().setTitle('Fill height').build(),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
$timeRange: new SceneTimeRange(),
|
||||
$data: getQueryRunnerWithRandomWalkQuery(),
|
||||
actions: [new SceneTimePicker({}), new SceneRefreshPicker({})],
|
||||
});
|
||||
}
|
@ -1,105 +0,0 @@
|
||||
import {
|
||||
SceneGridRow,
|
||||
SceneTimePicker,
|
||||
SceneGridLayout,
|
||||
SceneTimeRange,
|
||||
SceneRefreshPicker,
|
||||
SceneGridItem,
|
||||
PanelBuilders,
|
||||
} from '@grafana/scenes';
|
||||
import { TestDataQueryType } from '@grafana-plugins/grafana-testdata-datasource/dataquery.gen';
|
||||
|
||||
import { DashboardScene } from '../../dashboard-scene/scene/DashboardScene';
|
||||
|
||||
import { getQueryRunnerWithRandomWalkQuery } from './queries';
|
||||
|
||||
export function getGridWithMultipleData(): DashboardScene {
|
||||
return new DashboardScene({
|
||||
title: 'Grid with rows and different queries',
|
||||
body: new SceneGridLayout({
|
||||
children: [
|
||||
new SceneGridRow({
|
||||
$timeRange: new SceneTimeRange(),
|
||||
$data: getQueryRunnerWithRandomWalkQuery({ scenarioId: TestDataQueryType.RandomWalkTable }),
|
||||
title: 'Row A - has its own query',
|
||||
key: 'Row A',
|
||||
isCollapsed: true,
|
||||
y: 0,
|
||||
children: [
|
||||
new SceneGridItem({
|
||||
x: 0,
|
||||
y: 1,
|
||||
width: 12,
|
||||
height: 5,
|
||||
isResizable: true,
|
||||
isDraggable: true,
|
||||
body: PanelBuilders.timeseries().setTitle('Row A Child1').build(),
|
||||
}),
|
||||
new SceneGridItem({
|
||||
x: 0,
|
||||
y: 5,
|
||||
width: 6,
|
||||
height: 5,
|
||||
isResizable: true,
|
||||
isDraggable: true,
|
||||
body: PanelBuilders.timeseries().setTitle('Row A Child2').build(),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
new SceneGridRow({
|
||||
title: 'Row B - uses global query',
|
||||
key: 'Row B',
|
||||
isCollapsed: true,
|
||||
y: 1,
|
||||
children: [
|
||||
new SceneGridItem({
|
||||
x: 0,
|
||||
y: 2,
|
||||
width: 12,
|
||||
height: 5,
|
||||
isResizable: false,
|
||||
isDraggable: true,
|
||||
body: PanelBuilders.timeseries().setTitle('Row B Child1').build(),
|
||||
}),
|
||||
new SceneGridItem({
|
||||
x: 0,
|
||||
y: 7,
|
||||
width: 6,
|
||||
height: 5,
|
||||
isResizable: false,
|
||||
isDraggable: true,
|
||||
body: PanelBuilders.timeseries()
|
||||
.setTitle('Row B Child2 with data')
|
||||
.setData(getQueryRunnerWithRandomWalkQuery({ seriesCount: 10 }))
|
||||
.build(),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
new SceneGridItem({
|
||||
x: 0,
|
||||
y: 12,
|
||||
width: 6,
|
||||
height: 10,
|
||||
isResizable: true,
|
||||
isDraggable: true,
|
||||
body: PanelBuilders.timeseries()
|
||||
.setTitle('Outsider, has its own query')
|
||||
.setData(getQueryRunnerWithRandomWalkQuery({ seriesCount: 10 }))
|
||||
.build(),
|
||||
}),
|
||||
new SceneGridItem({
|
||||
x: 6,
|
||||
y: 12,
|
||||
width: 12,
|
||||
height: 10,
|
||||
isResizable: true,
|
||||
isDraggable: true,
|
||||
body: PanelBuilders.timeseries().setTitle('Outsider, uses global query').build(),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
$timeRange: new SceneTimeRange(),
|
||||
$data: getQueryRunnerWithRandomWalkQuery(),
|
||||
actions: [new SceneTimePicker({}), new SceneRefreshPicker({})],
|
||||
});
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
import { DashboardScene } from '../../dashboard-scene/scene/DashboardScene';
|
||||
|
||||
import { getGridWithMultipleTimeRanges } from './gridMultiTimeRange';
|
||||
import { getMultipleGridLayoutTest } from './gridMultiple';
|
||||
import { getGridWithMultipleData } from './gridWithMultipleData';
|
||||
import { getQueryVariableDemo } from './queryVariableDemo';
|
||||
import { getRepeatingPanelsDemo, getRepeatingRowsDemo } from './repeatingPanels';
|
||||
import { getSceneWithRows } from './sceneWithRows';
|
||||
import { getTransformationsDemo } from './transformations';
|
||||
import { getVariablesDemo, getVariablesDemoWithAll } from './variablesDemo';
|
||||
|
||||
interface SceneDef {
|
||||
title: string;
|
||||
getScene: () => DashboardScene;
|
||||
}
|
||||
export function getScenes(): SceneDef[] {
|
||||
return [
|
||||
{ title: 'Scene with rows', getScene: getSceneWithRows },
|
||||
{ title: 'Grid with rows and different queries', getScene: getGridWithMultipleData },
|
||||
{ title: 'Grid with rows and different queries and time ranges', getScene: getGridWithMultipleTimeRanges },
|
||||
{ title: 'Multiple grid layouts test', getScene: getMultipleGridLayoutTest },
|
||||
{ title: 'Variables', getScene: getVariablesDemo },
|
||||
{ title: 'Variables with All values', getScene: getVariablesDemoWithAll },
|
||||
{ title: 'Variables - Repeating panels', getScene: getRepeatingPanelsDemo },
|
||||
{ title: 'Variables - Repeating rows', getScene: getRepeatingRowsDemo },
|
||||
{ title: 'Query variable', getScene: getQueryVariableDemo },
|
||||
{ title: 'Transformations demo', getScene: getTransformationsDemo },
|
||||
];
|
||||
}
|
||||
|
||||
const cache: Record<string, DashboardScene> = {};
|
||||
|
||||
export function getSceneByTitle(title: string) {
|
||||
if (cache[title]) {
|
||||
return cache[title];
|
||||
}
|
||||
|
||||
const scene = getScenes().find((x) => x.title === title);
|
||||
|
||||
if (scene) {
|
||||
cache[title] = scene.getScene();
|
||||
}
|
||||
|
||||
return cache[title];
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
import { QueryRunnerState, SceneQueryRunner } from '@grafana/scenes';
|
||||
import { TestData } from '@grafana-plugins/grafana-testdata-datasource/dataquery.gen';
|
||||
|
||||
export function getQueryRunnerWithRandomWalkQuery(
|
||||
overrides?: Partial<TestData>,
|
||||
queryRunnerOverrides?: Partial<QueryRunnerState>
|
||||
) {
|
||||
return new SceneQueryRunner({
|
||||
queries: [
|
||||
{
|
||||
refId: 'A',
|
||||
datasource: {
|
||||
uid: 'gdev-testdata',
|
||||
type: 'testdata',
|
||||
},
|
||||
scenarioId: 'random_walk',
|
||||
...overrides,
|
||||
},
|
||||
],
|
||||
...queryRunnerOverrides,
|
||||
});
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
import { VariableRefresh } from '@grafana/data';
|
||||
import {
|
||||
SceneCanvasText,
|
||||
SceneTimePicker,
|
||||
SceneFlexLayout,
|
||||
SceneTimeRange,
|
||||
VariableValueSelectors,
|
||||
SceneVariableSet,
|
||||
CustomVariable,
|
||||
DataSourceVariable,
|
||||
QueryVariable,
|
||||
SceneRefreshPicker,
|
||||
SceneFlexItem,
|
||||
} from '@grafana/scenes';
|
||||
|
||||
import { DashboardScene } from '../../dashboard-scene/scene/DashboardScene';
|
||||
|
||||
export function getQueryVariableDemo(): DashboardScene {
|
||||
return new DashboardScene({
|
||||
title: 'Query variable',
|
||||
$variables: new SceneVariableSet({
|
||||
variables: [
|
||||
new CustomVariable({
|
||||
name: 'metric',
|
||||
query: 'job : job, instance : instance',
|
||||
}),
|
||||
new DataSourceVariable({
|
||||
name: 'datasource',
|
||||
pluginId: 'prometheus',
|
||||
}),
|
||||
new QueryVariable({
|
||||
name: 'instance (using datasource variable)',
|
||||
refresh: VariableRefresh.onTimeRangeChanged,
|
||||
query: { query: 'label_values(go_gc_duration_seconds, ${metric})', refId: 'A' },
|
||||
datasource: { uid: '${datasource}' },
|
||||
}),
|
||||
new QueryVariable({
|
||||
name: 'label values (on time range refresh)',
|
||||
refresh: VariableRefresh.onTimeRangeChanged,
|
||||
query: { query: 'label_values(go_gc_duration_seconds, ${metric})', refId: 'B' },
|
||||
datasource: { uid: 'gdev-prometheus', type: 'prometheus' },
|
||||
}),
|
||||
new QueryVariable({
|
||||
name: 'legacy (graphite)',
|
||||
refresh: VariableRefresh.onTimeRangeChanged,
|
||||
query: { queryType: 'Default', target: 'stats.response.*', refId: 'C' },
|
||||
datasource: { uid: 'gdev-graphite', type: 'graphite' },
|
||||
}),
|
||||
],
|
||||
}),
|
||||
body: new SceneFlexLayout({
|
||||
direction: 'row',
|
||||
children: [
|
||||
new SceneFlexItem({
|
||||
width: '40%',
|
||||
body: new SceneCanvasText({
|
||||
text: 'metric: ${metric}',
|
||||
fontSize: 20,
|
||||
align: 'center',
|
||||
}),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
$timeRange: new SceneTimeRange(),
|
||||
actions: [new SceneTimePicker({}), new SceneRefreshPicker({})],
|
||||
controls: [new VariableValueSelectors({})],
|
||||
});
|
||||
}
|
@ -1,189 +0,0 @@
|
||||
import {
|
||||
SceneTimePicker,
|
||||
SceneTimeRange,
|
||||
VariableValueSelectors,
|
||||
SceneVariableSet,
|
||||
TestVariable,
|
||||
SceneRefreshPicker,
|
||||
PanelBuilders,
|
||||
SceneGridLayout,
|
||||
SceneControlsSpacer,
|
||||
SceneGridRow,
|
||||
} from '@grafana/scenes';
|
||||
import { VariableRefresh } from '@grafana/schema';
|
||||
import { PanelRepeaterGridItem } from 'app/features/dashboard-scene/scene/PanelRepeaterGridItem';
|
||||
import { RowRepeaterBehavior } from 'app/features/dashboard-scene/scene/RowRepeaterBehavior';
|
||||
|
||||
import { DashboardScene } from '../../dashboard-scene/scene/DashboardScene';
|
||||
|
||||
import { getQueryRunnerWithRandomWalkQuery } from './queries';
|
||||
|
||||
/**
|
||||
* Repeat panels by variable that changes with time refresh. This tries to setup a very specific scenario
|
||||
* where a variable that is slow (2s) and constantly changing it's result is used to repeat panels. This
|
||||
* can be used to verify that when the time range change the repeated panels with locally scoped variable value
|
||||
* still wait for the top level variable to finish loading and the repeat process to complete.
|
||||
*/
|
||||
export function getRepeatingPanelsDemo(): DashboardScene {
|
||||
return new DashboardScene({
|
||||
title: 'Variables - Repeating panels',
|
||||
$variables: new SceneVariableSet({
|
||||
variables: [
|
||||
new TestVariable({
|
||||
name: 'server',
|
||||
query: 'AB',
|
||||
value: 'server',
|
||||
text: '',
|
||||
delayMs: 2000,
|
||||
isMulti: true,
|
||||
includeAll: true,
|
||||
refresh: VariableRefresh.onTimeRangeChanged,
|
||||
optionsToReturn: [
|
||||
{ label: 'A', value: 'A' },
|
||||
{ label: 'B', value: 'B' },
|
||||
],
|
||||
options: [],
|
||||
$behaviors: [changeVariable],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
body: new SceneGridLayout({
|
||||
isDraggable: true,
|
||||
isResizable: true,
|
||||
children: [
|
||||
new PanelRepeaterGridItem({
|
||||
variableName: 'server',
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 24,
|
||||
height: 8,
|
||||
itemHeight: 8,
|
||||
source: PanelBuilders.timeseries()
|
||||
.setTitle('server = $server')
|
||||
.setData(getQueryRunnerWithRandomWalkQuery({ alias: 'server = $server' }))
|
||||
.build(),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
$timeRange: new SceneTimeRange(),
|
||||
actions: [],
|
||||
controls: [
|
||||
new VariableValueSelectors({}),
|
||||
new SceneControlsSpacer(),
|
||||
new SceneTimePicker({}),
|
||||
new SceneRefreshPicker({}),
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
function changeVariable(variable: TestVariable) {
|
||||
const sub = variable.subscribeToState((state, old) => {
|
||||
if (!state.loading && old.loading) {
|
||||
if (variable.state.optionsToReturn?.length === 2) {
|
||||
variable.setState({
|
||||
query: 'ABC',
|
||||
optionsToReturn: [
|
||||
{ label: 'A', value: 'A' },
|
||||
{ label: 'B', value: 'B' },
|
||||
{ label: 'C', value: 'C' },
|
||||
],
|
||||
});
|
||||
} else {
|
||||
variable.setState({
|
||||
query: 'AB',
|
||||
optionsToReturn: [
|
||||
{ label: 'A', value: 'A' },
|
||||
{ label: 'B', value: 'B' },
|
||||
],
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
sub.unsubscribe();
|
||||
};
|
||||
}
|
||||
|
||||
export function getRepeatingRowsDemo(): DashboardScene {
|
||||
return new DashboardScene({
|
||||
title: 'Variables - Repeating rows',
|
||||
$variables: new SceneVariableSet({
|
||||
variables: [
|
||||
new TestVariable({
|
||||
name: 'server',
|
||||
query: 'AB',
|
||||
value: ['A', 'B', 'C'],
|
||||
text: ['A', 'B', 'C'],
|
||||
delayMs: 2000,
|
||||
isMulti: true,
|
||||
includeAll: true,
|
||||
refresh: VariableRefresh.onTimeRangeChanged,
|
||||
optionsToReturn: [
|
||||
{ label: 'A', value: 'A' },
|
||||
{ label: 'B', value: 'B' },
|
||||
{ label: 'C', value: 'C' },
|
||||
],
|
||||
options: [],
|
||||
//$behaviors: [changeVariable],
|
||||
}),
|
||||
new TestVariable({
|
||||
name: 'pod',
|
||||
query: 'AB',
|
||||
value: ['Mu', 'Ma', 'Mi'],
|
||||
text: ['Mu', 'Ma', 'Mi'],
|
||||
delayMs: 2000,
|
||||
isMulti: true,
|
||||
includeAll: true,
|
||||
refresh: VariableRefresh.onTimeRangeChanged,
|
||||
optionsToReturn: [
|
||||
{ label: 'Mu', value: 'Mu' },
|
||||
{ label: 'Ma', value: 'Ma' },
|
||||
{ label: 'Mi', value: 'Mi' },
|
||||
],
|
||||
options: [],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
body: new SceneGridLayout({
|
||||
isDraggable: true,
|
||||
isResizable: true,
|
||||
children: [
|
||||
new SceneGridRow({
|
||||
title: 'Row $server',
|
||||
key: 'Row A',
|
||||
isCollapsed: false,
|
||||
y: 0,
|
||||
x: 0,
|
||||
$behaviors: [
|
||||
new RowRepeaterBehavior({
|
||||
variableName: 'server',
|
||||
sources: [
|
||||
new PanelRepeaterGridItem({
|
||||
variableName: 'pod',
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 24,
|
||||
height: 5,
|
||||
itemHeight: 5,
|
||||
source: PanelBuilders.timeseries()
|
||||
.setTitle('server = $server, pod = $pod')
|
||||
.setData(getQueryRunnerWithRandomWalkQuery({ alias: 'server = $server, pod = $pod' }))
|
||||
.build(),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
$timeRange: new SceneTimeRange(),
|
||||
actions: [],
|
||||
controls: [
|
||||
new VariableValueSelectors({}),
|
||||
new SceneControlsSpacer(),
|
||||
new SceneTimePicker({}),
|
||||
new SceneRefreshPicker({}),
|
||||
],
|
||||
});
|
||||
}
|
@ -1,58 +0,0 @@
|
||||
import {
|
||||
NestedScene,
|
||||
SceneTimePicker,
|
||||
SceneFlexLayout,
|
||||
SceneTimeRange,
|
||||
SceneRefreshPicker,
|
||||
SceneFlexItem,
|
||||
PanelBuilders,
|
||||
} from '@grafana/scenes';
|
||||
|
||||
import { DashboardScene } from '../../dashboard-scene/scene/DashboardScene';
|
||||
|
||||
import { getQueryRunnerWithRandomWalkQuery } from './queries';
|
||||
|
||||
export function getSceneWithRows(): DashboardScene {
|
||||
return new DashboardScene({
|
||||
title: 'Scene with rows',
|
||||
body: new SceneFlexLayout({
|
||||
direction: 'column',
|
||||
children: [
|
||||
new NestedScene({
|
||||
title: 'Overview',
|
||||
canCollapse: true,
|
||||
body: new SceneFlexLayout({
|
||||
direction: 'row',
|
||||
children: [
|
||||
new SceneFlexItem({
|
||||
body: PanelBuilders.timeseries().setTitle('Fill height').build(),
|
||||
}),
|
||||
|
||||
new SceneFlexItem({
|
||||
body: PanelBuilders.timeseries().setTitle('Fill height').build(),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
}),
|
||||
new NestedScene({
|
||||
title: 'More server details',
|
||||
canCollapse: true,
|
||||
body: new SceneFlexLayout({
|
||||
direction: 'row',
|
||||
children: [
|
||||
new SceneFlexItem({
|
||||
body: PanelBuilders.timeseries().setTitle('Fill height').build(),
|
||||
}),
|
||||
new SceneFlexItem({
|
||||
body: PanelBuilders.timeseries().setTitle('Fill height').build(),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
$timeRange: new SceneTimeRange(),
|
||||
$data: getQueryRunnerWithRandomWalkQuery(),
|
||||
actions: [new SceneTimePicker({}), new SceneRefreshPicker({})],
|
||||
});
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
import {
|
||||
SceneTimePicker,
|
||||
SceneFlexLayout,
|
||||
SceneDataTransformer,
|
||||
SceneTimeRange,
|
||||
SceneRefreshPicker,
|
||||
SceneFlexItem,
|
||||
PanelBuilders,
|
||||
} from '@grafana/scenes';
|
||||
|
||||
import { DashboardScene } from '../../dashboard-scene/scene/DashboardScene';
|
||||
|
||||
import { getQueryRunnerWithRandomWalkQuery } from './queries';
|
||||
|
||||
export function getTransformationsDemo(): DashboardScene {
|
||||
return new DashboardScene({
|
||||
title: 'Transformations demo',
|
||||
body: new SceneFlexLayout({
|
||||
direction: 'row',
|
||||
children: [
|
||||
new SceneFlexItem({
|
||||
body: new SceneFlexLayout({
|
||||
direction: 'column',
|
||||
children: [
|
||||
new SceneFlexItem({
|
||||
body: new SceneFlexLayout({
|
||||
direction: 'row',
|
||||
children: [
|
||||
new SceneFlexItem({
|
||||
body: PanelBuilders.timeseries().setTitle('Source data (global query)').build(),
|
||||
}),
|
||||
new SceneFlexItem({
|
||||
body: PanelBuilders.stat()
|
||||
.setTitle('Transformed data')
|
||||
.setData(
|
||||
new SceneDataTransformer({
|
||||
transformations: [
|
||||
{
|
||||
id: 'reduce',
|
||||
options: {
|
||||
reducers: ['last', 'mean'],
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
)
|
||||
.build(),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
}),
|
||||
new SceneFlexItem({
|
||||
body: PanelBuilders.stat()
|
||||
.setTitle('Query with predefined transformations')
|
||||
.setData(
|
||||
new SceneDataTransformer({
|
||||
$data: getQueryRunnerWithRandomWalkQuery(),
|
||||
transformations: [
|
||||
{
|
||||
id: 'reduce',
|
||||
options: {
|
||||
reducers: ['mean'],
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
)
|
||||
.build(),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
$timeRange: new SceneTimeRange(),
|
||||
$data: getQueryRunnerWithRandomWalkQuery(),
|
||||
actions: [new SceneTimePicker({}), new SceneRefreshPicker({})],
|
||||
});
|
||||
}
|
@ -1,203 +0,0 @@
|
||||
import {
|
||||
SceneCanvasText,
|
||||
SceneTimePicker,
|
||||
SceneFlexLayout,
|
||||
SceneTimeRange,
|
||||
VariableValueSelectors,
|
||||
SceneVariableSet,
|
||||
CustomVariable,
|
||||
DataSourceVariable,
|
||||
TestVariable,
|
||||
NestedScene,
|
||||
SceneRefreshPicker,
|
||||
TextBoxVariable,
|
||||
SceneFlexItem,
|
||||
PanelBuilders,
|
||||
} from '@grafana/scenes';
|
||||
|
||||
import { DashboardScene } from '../../dashboard-scene/scene/DashboardScene';
|
||||
|
||||
import { getQueryRunnerWithRandomWalkQuery } from './queries';
|
||||
|
||||
export function getVariablesDemo(): DashboardScene {
|
||||
return new DashboardScene({
|
||||
title: 'Variables',
|
||||
$variables: new SceneVariableSet({
|
||||
variables: [
|
||||
new TestVariable({
|
||||
name: 'server',
|
||||
query: 'A.*',
|
||||
value: 'server',
|
||||
text: '',
|
||||
delayMs: 1000,
|
||||
options: [],
|
||||
}),
|
||||
new TestVariable({
|
||||
name: 'pod',
|
||||
query: 'A.$server.*',
|
||||
value: 'pod',
|
||||
delayMs: 1000,
|
||||
isMulti: true,
|
||||
text: '',
|
||||
options: [],
|
||||
}),
|
||||
new TestVariable({
|
||||
name: 'handler',
|
||||
query: 'A.$server.$pod.*',
|
||||
value: 'handler',
|
||||
delayMs: 1000,
|
||||
//isMulti: true,
|
||||
text: '',
|
||||
options: [],
|
||||
}),
|
||||
new CustomVariable({
|
||||
name: 'custom',
|
||||
query: 'A : 10,B : 20',
|
||||
}),
|
||||
new DataSourceVariable({
|
||||
name: 'ds',
|
||||
pluginId: 'testdata',
|
||||
}),
|
||||
new TextBoxVariable({
|
||||
name: 'textbox',
|
||||
value: 'default value',
|
||||
}),
|
||||
],
|
||||
}),
|
||||
body: new SceneFlexLayout({
|
||||
direction: 'row',
|
||||
children: [
|
||||
new SceneFlexItem({
|
||||
body: new SceneFlexLayout({
|
||||
direction: 'column',
|
||||
children: [
|
||||
new SceneFlexItem({
|
||||
body: new SceneFlexLayout({
|
||||
children: [
|
||||
new SceneFlexItem({
|
||||
body: PanelBuilders.timeseries()
|
||||
.setTitle('handler: $handler')
|
||||
.setData(
|
||||
getQueryRunnerWithRandomWalkQuery({
|
||||
alias: 'handler: $handler',
|
||||
})
|
||||
)
|
||||
.build(),
|
||||
}),
|
||||
new SceneFlexItem({
|
||||
body: new SceneCanvasText({
|
||||
text: 'Text: ${textbox}',
|
||||
fontSize: 20,
|
||||
align: 'center',
|
||||
}),
|
||||
}),
|
||||
new SceneFlexItem({
|
||||
width: '40%',
|
||||
body: new SceneCanvasText({
|
||||
text: 'server: ${server} pod:${pod}',
|
||||
fontSize: 20,
|
||||
align: 'center',
|
||||
}),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
}),
|
||||
new SceneFlexItem({
|
||||
body: new NestedScene({
|
||||
title: 'Collapsable inner scene',
|
||||
canCollapse: true,
|
||||
body: new SceneFlexLayout({
|
||||
direction: 'row',
|
||||
children: [
|
||||
new SceneFlexItem({
|
||||
body: PanelBuilders.timeseries()
|
||||
.setTitle('handler: $handler')
|
||||
.setData(
|
||||
getQueryRunnerWithRandomWalkQuery({
|
||||
alias: 'handler: $handler',
|
||||
})
|
||||
)
|
||||
.build(),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
$timeRange: new SceneTimeRange(),
|
||||
actions: [new SceneTimePicker({}), new SceneRefreshPicker({})],
|
||||
controls: [new VariableValueSelectors({})],
|
||||
});
|
||||
}
|
||||
|
||||
export function getVariablesDemoWithAll(): DashboardScene {
|
||||
return new DashboardScene({
|
||||
title: 'Variables with All values',
|
||||
$variables: new SceneVariableSet({
|
||||
variables: [
|
||||
new TestVariable({
|
||||
name: 'server',
|
||||
query: 'A.*',
|
||||
value: 'AA',
|
||||
text: 'AA',
|
||||
includeAll: true,
|
||||
defaultToAll: true,
|
||||
delayMs: 1000,
|
||||
options: [],
|
||||
}),
|
||||
new TestVariable({
|
||||
name: 'pod',
|
||||
query: 'A.$server.*',
|
||||
value: [],
|
||||
delayMs: 1000,
|
||||
isMulti: true,
|
||||
includeAll: true,
|
||||
defaultToAll: true,
|
||||
text: '',
|
||||
options: [],
|
||||
}),
|
||||
new TestVariable({
|
||||
name: 'handler',
|
||||
query: 'A.$server.$pod.*',
|
||||
value: [],
|
||||
delayMs: 1000,
|
||||
includeAll: true,
|
||||
defaultToAll: false,
|
||||
isMulti: true,
|
||||
text: '',
|
||||
options: [],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
body: new SceneFlexLayout({
|
||||
direction: 'row',
|
||||
children: [
|
||||
new SceneFlexItem({
|
||||
body: PanelBuilders.timeseries()
|
||||
.setTitle('handler: $handler')
|
||||
.setData(
|
||||
getQueryRunnerWithRandomWalkQuery({
|
||||
alias: 'handler: $handler',
|
||||
})
|
||||
)
|
||||
.build(),
|
||||
}),
|
||||
new SceneFlexItem({
|
||||
width: '40%',
|
||||
body: new SceneCanvasText({
|
||||
text: 'server: ${server} pod:${pod}',
|
||||
fontSize: 20,
|
||||
align: 'center',
|
||||
}),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
$timeRange: new SceneTimeRange(),
|
||||
actions: [new SceneTimePicker({}), new SceneRefreshPicker({})],
|
||||
controls: [new VariableValueSelectors({})],
|
||||
});
|
||||
}
|
@ -38,6 +38,12 @@ export function getAppRoutes(): RouteDescriptor[] {
|
||||
() => import(/* webpackChunkName: "DashboardPageProxy" */ '../features/dashboard/containers/DashboardPageProxy')
|
||||
),
|
||||
},
|
||||
{
|
||||
path: '/d/:uid/panel-edit/:panelId',
|
||||
component: SafeDynamicImport(
|
||||
() => import(/* webpackChunkName: "scenes"*/ 'app/features/dashboard-scene/pages/PanelEditPage')
|
||||
),
|
||||
},
|
||||
{
|
||||
path: '/d/:uid/:slug?',
|
||||
pageClass: 'page-dashboard',
|
||||
@ -488,7 +494,6 @@ export function getAppRoutes(): RouteDescriptor[] {
|
||||
() => import(/* webpackChunkName: "DataTrailsPage"*/ 'app/features/trails/DataTrailsPage')
|
||||
),
|
||||
},
|
||||
...getDynamicDashboardRoutes(),
|
||||
...getPluginCatalogRoutes(),
|
||||
...getSupportBundleRoutes(),
|
||||
...getAlertingRoutes(),
|
||||
@ -523,38 +528,3 @@ export function getSupportBundleRoutes(cfg = config): RouteDescriptor[] {
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export function getDynamicDashboardRoutes(cfg = config): RouteDescriptor[] {
|
||||
if (!cfg.featureToggles.scenes) {
|
||||
return [];
|
||||
}
|
||||
return [
|
||||
{
|
||||
path: '/scenes',
|
||||
component: SafeDynamicImport(() => import(/* webpackChunkName: "scenes"*/ 'app/features/scenes/SceneListPage')),
|
||||
},
|
||||
{
|
||||
path: '/scenes/dashboard/:uid',
|
||||
component: SafeDynamicImport(
|
||||
() => import(/* webpackChunkName: "scenes"*/ 'app/features/dashboard-scene/pages/DashboardScenePage')
|
||||
),
|
||||
},
|
||||
{
|
||||
path: '/scenes/dashboard/:uid/panel-edit/:panelId',
|
||||
component: SafeDynamicImport(
|
||||
() => import(/* webpackChunkName: "scenes"*/ 'app/features/dashboard-scene/pages/PanelEditPage')
|
||||
),
|
||||
},
|
||||
{
|
||||
path: '/scenes/grafana-monitoring',
|
||||
exact: false,
|
||||
component: SafeDynamicImport(
|
||||
() => import(/* webpackChunkName: "scenes"*/ 'app/features/scenes/apps/GrafanaMonitoringApp')
|
||||
),
|
||||
},
|
||||
{
|
||||
path: '/scenes/:name',
|
||||
component: SafeDynamicImport(() => import(/* webpackChunkName: "scenes"*/ 'app/features/scenes/ScenePage')),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user