@grafana/scenes 0.0.19 → 0.0.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -10
- package/dist/esm/components/EmbeddedScene.js +10 -9
- package/dist/esm/components/EmbeddedScene.js.map +1 -1
- package/dist/esm/components/SceneApp/SceneApp.js +3 -145
- package/dist/esm/components/SceneApp/SceneApp.js.map +1 -1
- package/dist/esm/components/SceneApp/SceneAppPage.js +151 -0
- package/dist/esm/components/SceneApp/SceneAppPage.js.map +1 -0
- package/dist/esm/components/SceneByFrameRepeater.js +8 -8
- package/dist/esm/components/SceneByFrameRepeater.js.map +1 -1
- package/dist/esm/components/SceneReactObject.js +34 -0
- package/dist/esm/components/SceneReactObject.js.map +1 -0
- package/dist/esm/components/SceneRefreshPicker.js +8 -9
- package/dist/esm/components/SceneRefreshPicker.js.map +1 -1
- package/dist/esm/components/VizPanel/VizPanel.js.map +1 -1
- package/dist/esm/components/VizPanel/VizPanelMenu.js +42 -0
- package/dist/esm/components/VizPanel/VizPanelMenu.js.map +1 -0
- package/dist/esm/components/VizPanel/VizPanelRenderer.js +11 -3
- package/dist/esm/components/VizPanel/VizPanelRenderer.js.map +1 -1
- package/dist/esm/components/layout/SceneFlexLayout.js +2 -1
- package/dist/esm/components/layout/SceneFlexLayout.js.map +1 -1
- package/dist/esm/core/SceneObjectBase.js +21 -9
- package/dist/esm/core/SceneObjectBase.js.map +1 -1
- package/dist/esm/core/types.js.map +1 -1
- package/dist/esm/index.js +4 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/querying/SceneDataTransformer.js +10 -9
- package/dist/esm/querying/SceneDataTransformer.js.map +1 -1
- package/dist/esm/querying/SceneQueryRunner.js +34 -18
- package/dist/esm/querying/SceneQueryRunner.js.map +1 -1
- package/dist/esm/variables/interpolation/formatRegistry.js.map +1 -1
- package/dist/esm/variables/sets/SceneVariableSet.js +29 -29
- package/dist/esm/variables/sets/SceneVariableSet.js.map +1 -1
- package/dist/esm/variables/variants/query/QueryVariable.js +10 -12
- package/dist/esm/variables/variants/query/QueryVariable.js.map +1 -1
- package/dist/index.d.ts +112 -43
- package/dist/index.js +472 -366
- package/dist/index.js.map +1 -1
- package/package.json +21 -25
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
<img
|
|
3
|
-
src="
|
|
3
|
+
src="https://raw.githubusercontent.com/grafana/scenes/main/docs/img/grafana_icon.svg"
|
|
4
4
|
alt="Grafana Logo"
|
|
5
5
|
width="100px"
|
|
6
6
|
padding="40px"
|
|
@@ -9,27 +9,37 @@
|
|
|
9
9
|
<p>Create dashboard-like experiences in Grafana app plugins</p>
|
|
10
10
|
</div>
|
|
11
11
|
|
|
12
|
-
##
|
|
12
|
+
## About @grafana/scenes
|
|
13
13
|
|
|
14
|
-
@grafana/scenes
|
|
14
|
+
@grafana/scenes provides a framework to build dashboard-like experiences within Grafana's app plugins. It comes with the following features:
|
|
15
|
+
|
|
16
|
+
- Versatile layout options.
|
|
17
|
+
- Grafana panels rendering.
|
|
18
|
+
- Querying & transformations support
|
|
19
|
+
- Multiple time ranges support.
|
|
20
|
+
- Template variables support.
|
|
21
|
+
- URL sync.
|
|
22
|
+
- ... and more.
|
|
15
23
|
|
|
16
24
|
## Development
|
|
17
25
|
|
|
18
|
-
|
|
26
|
+
To work on @grafana/scenes SDK, please follow the guides below.
|
|
27
|
+
|
|
28
|
+
### Setting up local version of @grafana/scenes with local Grafana instance
|
|
19
29
|
|
|
20
|
-
|
|
30
|
+
It is currently possible to run Scene demos using Grafana. To do that, the following setup is required.
|
|
21
31
|
|
|
22
|
-
1. Clone
|
|
32
|
+
1. Clone [Grafana Scenes repository](https://github.com/grafana/grafana/).
|
|
23
33
|
1. Clone [Grafana](https://github.com/grafana/grafana/) repository and follow [Development guide](https://github.com/grafana/grafana/blob/main/contribute/developer-guide.md#developer-guide).
|
|
24
34
|
1. Setup env variable `GRAFANA_PATH` to point to your Grafana repository directory, `export GRAFANA_PATH=<path-to-grafana-directory>`
|
|
25
|
-
1. From
|
|
35
|
+
1. From Grafana Scenes root directory run `./scripts/dev.sh`. This will compile @grafana/scenes with watch mode enabled and link it to your Grafana.
|
|
26
36
|
1. From Grafana directory run `yarn install`.
|
|
27
37
|
1. Start Grafana with `scenes` [feature toggle enabled](https://grafana.com/docs/grafana/latest/setup-grafana/configure-grafana/#feature_toggles)
|
|
28
38
|
1. Navigate to `http://localhost:3000/scenes` to explore demo scenes.
|
|
29
39
|
|
|
30
|
-
###
|
|
40
|
+
### Setting up local version of @grafana/scenes with app plugin
|
|
31
41
|
|
|
32
|
-
1. Run `YARN_IGNORE_PATH=1 yarn link` from
|
|
33
|
-
1. Run `yarn dev` from
|
|
42
|
+
1. Run `YARN_IGNORE_PATH=1 yarn link` from `packages/scenes` directory.
|
|
43
|
+
1. Run `yarn dev` from `packages/scenes` directory.
|
|
34
44
|
1. Run `yarn link @grafana/scenes` from app plugin directory.
|
|
35
45
|
1. Start app plugin development server.
|
|
@@ -5,19 +5,20 @@ import { SceneObjectBase } from '../core/SceneObjectBase.js';
|
|
|
5
5
|
import { UrlSyncManager } from '../services/UrlSyncManager.js';
|
|
6
6
|
|
|
7
7
|
class EmbeddedScene extends SceneObjectBase {
|
|
8
|
+
constructor(state) {
|
|
9
|
+
super(state);
|
|
10
|
+
this.addActivationHandler(() => {
|
|
11
|
+
return () => {
|
|
12
|
+
if (this.urlSyncManager) {
|
|
13
|
+
this.urlSyncManager.cleanUp();
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
});
|
|
17
|
+
}
|
|
8
18
|
initUrlSync() {
|
|
9
19
|
this.urlSyncManager = new UrlSyncManager(this);
|
|
10
20
|
this.urlSyncManager.initSync();
|
|
11
21
|
}
|
|
12
|
-
activate() {
|
|
13
|
-
super.activate();
|
|
14
|
-
}
|
|
15
|
-
deactivate() {
|
|
16
|
-
super.deactivate();
|
|
17
|
-
if (this.urlSyncManager) {
|
|
18
|
-
this.urlSyncManager.cleanUp();
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
22
|
}
|
|
22
23
|
EmbeddedScene.Component = EmbeddedSceneRenderer;
|
|
23
24
|
function EmbeddedSceneRenderer({ model }) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EmbeddedScene.js","sources":["../../../src/components/EmbeddedScene.tsx"],"sourcesContent":["import { css } from '@emotion/css';\nimport { GrafanaTheme2 } from '@grafana/data';\nimport { useStyles2 } from '@grafana/ui';\nimport React from 'react';\n\nimport { SceneObjectBase } from '../core/SceneObjectBase';\nimport { SceneComponentProps, SceneObjectStatePlain, SceneObject } from '../core/types';\nimport { UrlSyncManager } from '../services/UrlSyncManager';\n\nexport interface EmbeddedSceneState extends SceneObjectStatePlain {\n /**\n * The main content of the scene (usually a SceneFlexLayout)\n */\n body: SceneObject;\n /**\n * Top row of variable selectors, filters, time pickers and custom actions.\n */\n controls?: SceneObject[];\n}\n\nexport class EmbeddedScene extends SceneObjectBase<EmbeddedSceneState> {\n public static Component = EmbeddedSceneRenderer;\n\n private urlSyncManager?: UrlSyncManager;\n\n /**\n * initUrlSync should be called before the scene is rendered to ensure that objects are in sync\n * before they get activated. This saves some unnecessary re-renders and makes sure variables\n * queries are issued as needed.\n */\n public initUrlSync() {\n this.urlSyncManager = new UrlSyncManager(this);\n this.urlSyncManager.initSync();\n }\n
|
|
1
|
+
{"version":3,"file":"EmbeddedScene.js","sources":["../../../src/components/EmbeddedScene.tsx"],"sourcesContent":["import { css } from '@emotion/css';\nimport { GrafanaTheme2 } from '@grafana/data';\nimport { useStyles2 } from '@grafana/ui';\nimport React from 'react';\n\nimport { SceneObjectBase } from '../core/SceneObjectBase';\nimport { SceneComponentProps, SceneObjectStatePlain, SceneObject } from '../core/types';\nimport { UrlSyncManager } from '../services/UrlSyncManager';\n\nexport interface EmbeddedSceneState extends SceneObjectStatePlain {\n /**\n * The main content of the scene (usually a SceneFlexLayout)\n */\n body: SceneObject;\n /**\n * Top row of variable selectors, filters, time pickers and custom actions.\n */\n controls?: SceneObject[];\n}\n\nexport class EmbeddedScene extends SceneObjectBase<EmbeddedSceneState> {\n public static Component = EmbeddedSceneRenderer;\n\n private urlSyncManager?: UrlSyncManager;\n\n public constructor(state: EmbeddedSceneState) {\n super(state);\n\n this.addActivationHandler(() => {\n // Clean up url sync when the scene is deactivated\n return () => {\n if (this.urlSyncManager) {\n this.urlSyncManager!.cleanUp();\n }\n };\n });\n }\n\n /**\n * initUrlSync should be called before the scene is rendered to ensure that objects are in sync\n * before they get activated. This saves some unnecessary re-renders and makes sure variables\n * queries are issued as needed.\n */\n public initUrlSync() {\n this.urlSyncManager = new UrlSyncManager(this);\n this.urlSyncManager.initSync();\n }\n}\n\nfunction EmbeddedSceneRenderer({ model }: SceneComponentProps<EmbeddedScene>) {\n const { body, controls } = model.useState();\n const styles = useStyles2(getStyles);\n\n return (\n <div className={styles.container}>\n {controls && (\n <div className={styles.controls}>\n {controls.map((control) => (\n <control.Component key={control.state.key} model={control} />\n ))}\n </div>\n )}\n <div className={styles.body}>\n <body.Component model={body} />\n </div>\n </div>\n );\n}\n\nfunction getStyles(theme: GrafanaTheme2) {\n return {\n container: css({\n flexGrow: 1,\n display: 'flex',\n gap: theme.spacing(2),\n minHeight: '100%',\n flexDirection: 'column',\n }),\n body: css({\n flexGrow: 1,\n display: 'flex',\n gap: '8px',\n }),\n controls: css({\n display: 'flex',\n gap: theme.spacing(1),\n alignItems: 'center',\n flexWrap: 'wrap',\n }),\n };\n}\n"],"names":[],"mappings":";;;;;;AAoBO,MAAM,sBAAsB,eAAoC,CAAA;AAAA,EAK9D,YAAY,KAA2B,EAAA;AAC5C,IAAA,KAAA,CAAM,KAAK,CAAA,CAAA;AAEX,IAAA,IAAA,CAAK,qBAAqB,MAAM;AAE9B,MAAA,OAAO,MAAM;AACX,QAAA,IAAI,KAAK,cAAgB,EAAA;AACvB,UAAA,IAAA,CAAK,eAAgB,OAAQ,EAAA,CAAA;AAAA,SAC/B;AAAA,OACF,CAAA;AAAA,KACD,CAAA,CAAA;AAAA,GACH;AAAA,EAOO,WAAc,GAAA;AACnB,IAAK,IAAA,CAAA,cAAA,GAAiB,IAAI,cAAA,CAAe,IAAI,CAAA,CAAA;AAC7C,IAAA,IAAA,CAAK,eAAe,QAAS,EAAA,CAAA;AAAA,GAC/B;AACF,CAAA;AA3Ba,aAAA,CACG,SAAY,GAAA,qBAAA,CAAA;AA4B5B,SAAS,qBAAA,CAAsB,EAAE,KAAA,EAA6C,EAAA;AAC5E,EAAA,MAAM,EAAE,IAAA,EAAM,QAAS,EAAA,GAAI,MAAM,QAAS,EAAA,CAAA;AAC1C,EAAM,MAAA,MAAA,GAAS,WAAW,SAAS,CAAA,CAAA;AAEnC,EAAA,uBACG,KAAA,CAAA,aAAA,CAAA,KAAA,EAAA;AAAA,IAAI,WAAW,MAAO,CAAA,SAAA;AAAA,GAAA,EACpB,4BACE,KAAA,CAAA,aAAA,CAAA,KAAA,EAAA;AAAA,IAAI,WAAW,MAAO,CAAA,QAAA;AAAA,GAAA,EACpB,SAAS,GAAI,CAAA,CAAC,OACb,qBAAA,KAAA,CAAA,aAAA,CAAC,QAAQ,SAAR,EAAA;AAAA,IAAkB,GAAA,EAAK,QAAQ,KAAM,CAAA,GAAA;AAAA,IAAK,KAAO,EAAA,OAAA;AAAA,GAAS,CAC5D,CACH,CAAA,kBAED,KAAA,CAAA,aAAA,CAAA,KAAA,EAAA;AAAA,IAAI,WAAW,MAAO,CAAA,IAAA;AAAA,GACrB,kBAAA,KAAA,CAAA,aAAA,CAAC,KAAK,SAAL,EAAA;AAAA,IAAe,KAAO,EAAA,IAAA;AAAA,GAAM,CAC/B,CACF,CAAA,CAAA;AAEJ,CAAA;AAEA,SAAS,UAAU,KAAsB,EAAA;AACvC,EAAO,OAAA;AAAA,IACL,WAAW,GAAI,CAAA;AAAA,MACb,QAAU,EAAA,CAAA;AAAA,MACV,OAAS,EAAA,MAAA;AAAA,MACT,GAAA,EAAK,KAAM,CAAA,OAAA,CAAQ,CAAC,CAAA;AAAA,MACpB,SAAW,EAAA,MAAA;AAAA,MACX,aAAe,EAAA,QAAA;AAAA,KAChB,CAAA;AAAA,IACD,MAAM,GAAI,CAAA;AAAA,MACR,QAAU,EAAA,CAAA;AAAA,MACV,OAAS,EAAA,MAAA;AAAA,MACT,GAAK,EAAA,KAAA;AAAA,KACN,CAAA;AAAA,IACD,UAAU,GAAI,CAAA;AAAA,MACZ,OAAS,EAAA,MAAA;AAAA,MACT,GAAA,EAAK,KAAM,CAAA,OAAA,CAAQ,CAAC,CAAA;AAAA,MACpB,UAAY,EAAA,QAAA;AAAA,MACZ,QAAU,EAAA,MAAA;AAAA,KACX,CAAA;AAAA,GACH,CAAA;AACF;;;;"}
|
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
import React
|
|
2
|
-
import { Switch, Route
|
|
3
|
-
import { PluginPage } from '@grafana/runtime';
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Switch, Route } from 'react-router-dom';
|
|
4
3
|
import { SceneObjectBase } from '../../core/SceneObjectBase.js';
|
|
5
|
-
import { useAppQueryParams, getLinkUrlWithAppUrlState } from './utils.js';
|
|
6
4
|
|
|
7
|
-
const sceneCache = /* @__PURE__ */ new Map();
|
|
8
5
|
class SceneApp extends SceneObjectBase {
|
|
9
6
|
}
|
|
10
7
|
SceneApp.Component = ({ model }) => {
|
|
@@ -20,145 +17,6 @@ SceneApp.Component = ({ model }) => {
|
|
|
20
17
|
}
|
|
21
18
|
})));
|
|
22
19
|
};
|
|
23
|
-
class SceneAppPage extends SceneObjectBase {
|
|
24
|
-
}
|
|
25
|
-
SceneAppPage.Component = SceneAppPageRenderer;
|
|
26
|
-
function SceneAppPageRenderer({ model }) {
|
|
27
|
-
var _a;
|
|
28
|
-
const { tabs, drilldowns, url, routePath } = model.state;
|
|
29
|
-
const routes = [];
|
|
30
|
-
if (tabs) {
|
|
31
|
-
for (const page2 of tabs) {
|
|
32
|
-
routes.push(
|
|
33
|
-
/* @__PURE__ */ React.createElement(Route, {
|
|
34
|
-
exact: true,
|
|
35
|
-
key: page2.state.url,
|
|
36
|
-
path: (_a = page2.state.routePath) != null ? _a : page2.state.url,
|
|
37
|
-
render: () => {
|
|
38
|
-
return /* @__PURE__ */ React.createElement(page2.Component, {
|
|
39
|
-
model: page2
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
})
|
|
43
|
-
);
|
|
44
|
-
if (page2.state.drilldowns) {
|
|
45
|
-
for (const drilldown of page2.state.drilldowns) {
|
|
46
|
-
routes.push(
|
|
47
|
-
/* @__PURE__ */ React.createElement(Route, {
|
|
48
|
-
exact: false,
|
|
49
|
-
key: drilldown.routePath,
|
|
50
|
-
path: drilldown.routePath,
|
|
51
|
-
render: () => {
|
|
52
|
-
return /* @__PURE__ */ React.createElement(SceneAppDrilldownViewRender, {
|
|
53
|
-
drilldown,
|
|
54
|
-
parent: page2
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
})
|
|
58
|
-
);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
return /* @__PURE__ */ React.createElement(Switch, null, routes);
|
|
63
|
-
}
|
|
64
|
-
if (drilldowns) {
|
|
65
|
-
for (const drilldown of drilldowns) {
|
|
66
|
-
routes.push(
|
|
67
|
-
/* @__PURE__ */ React.createElement(Route, {
|
|
68
|
-
key: drilldown.routePath,
|
|
69
|
-
exact: false,
|
|
70
|
-
path: drilldown.routePath,
|
|
71
|
-
render: () => {
|
|
72
|
-
return /* @__PURE__ */ React.createElement(SceneAppDrilldownViewRender, {
|
|
73
|
-
drilldown,
|
|
74
|
-
parent: model
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
})
|
|
78
|
-
);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
let page = /* @__PURE__ */ React.createElement(ScenePageRenderer, {
|
|
82
|
-
page: model
|
|
83
|
-
});
|
|
84
|
-
if (model.parent instanceof SceneAppPage) {
|
|
85
|
-
page = /* @__PURE__ */ React.createElement(ScenePageRenderer, {
|
|
86
|
-
page: model.parent,
|
|
87
|
-
activeTab: model,
|
|
88
|
-
tabs: model.parent.state.tabs
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
return /* @__PURE__ */ React.createElement(Switch, null, /* @__PURE__ */ React.createElement(Route, {
|
|
92
|
-
key: url,
|
|
93
|
-
exact: true,
|
|
94
|
-
path: routePath != null ? routePath : url,
|
|
95
|
-
render: () => {
|
|
96
|
-
return page;
|
|
97
|
-
}
|
|
98
|
-
}), routes);
|
|
99
|
-
}
|
|
100
|
-
function ScenePageRenderer({ page, tabs, activeTab }) {
|
|
101
|
-
const [isInitialized, setIsInitialized] = useState(false);
|
|
102
|
-
const params = useAppQueryParams();
|
|
103
|
-
const routeMatch = useRouteMatch();
|
|
104
|
-
let scene = sceneCache.get(routeMatch.url);
|
|
105
|
-
if (!scene) {
|
|
106
|
-
scene = activeTab ? activeTab.state.getScene(routeMatch) : page.state.getScene(routeMatch);
|
|
107
|
-
sceneCache.set(routeMatch.url, scene);
|
|
108
|
-
}
|
|
109
|
-
useEffect(() => {
|
|
110
|
-
if (!isInitialized && scene) {
|
|
111
|
-
scene.initUrlSync();
|
|
112
|
-
setIsInitialized(true);
|
|
113
|
-
}
|
|
114
|
-
}, [isInitialized, scene]);
|
|
115
|
-
if (!isInitialized) {
|
|
116
|
-
return null;
|
|
117
|
-
}
|
|
118
|
-
const pageNav = {
|
|
119
|
-
text: page.state.title,
|
|
120
|
-
subTitle: page.state.subTitle,
|
|
121
|
-
url: getLinkUrlWithAppUrlState(page.state.url, params, page.state.preserveUrlKeys),
|
|
122
|
-
hideFromBreadcrumbs: page.state.hideFromBreadcrumbs,
|
|
123
|
-
parentItem: getParentBreadcrumbs(page.state.getParentPage ? page.state.getParentPage() : page.parent, params)
|
|
124
|
-
};
|
|
125
|
-
if (tabs) {
|
|
126
|
-
pageNav.children = tabs.map((tab) => {
|
|
127
|
-
return {
|
|
128
|
-
text: tab.state.title,
|
|
129
|
-
active: activeTab === tab,
|
|
130
|
-
url: getLinkUrlWithAppUrlState(tab.state.url, params, tab.state.preserveUrlKeys),
|
|
131
|
-
parentItem: pageNav
|
|
132
|
-
};
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
return /* @__PURE__ */ React.createElement(PluginPage, {
|
|
136
|
-
pageNav
|
|
137
|
-
}, /* @__PURE__ */ React.createElement(scene.Component, {
|
|
138
|
-
model: scene
|
|
139
|
-
}));
|
|
140
|
-
}
|
|
141
|
-
function SceneAppDrilldownViewRender(props) {
|
|
142
|
-
const routeMatch = useRouteMatch();
|
|
143
|
-
const scene = props.drilldown.getPage(routeMatch, props.parent);
|
|
144
|
-
return /* @__PURE__ */ React.createElement(scene.Component, {
|
|
145
|
-
model: scene
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
function getParentBreadcrumbs(parent, params) {
|
|
149
|
-
if (parent instanceof SceneAppPage) {
|
|
150
|
-
return {
|
|
151
|
-
text: parent.state.title,
|
|
152
|
-
url: getLinkUrlWithAppUrlState(parent.state.url, params, parent.state.preserveUrlKeys),
|
|
153
|
-
hideFromBreadcrumbs: parent.state.hideFromBreadcrumbs,
|
|
154
|
-
parentItem: getParentBreadcrumbs(
|
|
155
|
-
parent.state.getParentPage ? parent.state.getParentPage() : parent.parent,
|
|
156
|
-
params
|
|
157
|
-
)
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
return void 0;
|
|
161
|
-
}
|
|
162
20
|
|
|
163
|
-
export { SceneApp
|
|
21
|
+
export { SceneApp };
|
|
164
22
|
//# sourceMappingURL=SceneApp.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SceneApp.js","sources":["../../../../src/components/SceneApp/SceneApp.tsx"],"sourcesContent":["import React, { useEffect, useState } from 'react';\nimport { Route, Switch, useRouteMatch } from 'react-router-dom';\n\nimport { NavModelItem, UrlQueryMap } from '@grafana/data';\nimport { PluginPage } from '@grafana/runtime';\n\nimport { SceneComponentProps, SceneObject, SceneObjectStatePlain } from '../../core/types';\nimport { SceneObjectBase } from '../../core/SceneObjectBase';\nimport { getLinkUrlWithAppUrlState, useAppQueryParams } from './utils';\nimport { EmbeddedScene } from '../EmbeddedScene';\n\nconst sceneCache = new Map<string, EmbeddedScene>();\n\nexport interface SceneAppState extends SceneObjectStatePlain {\n // Array of SceneAppPage objects that are considered app's top level pages\n pages: SceneAppPage[];\n}\n\nexport interface SceneRouteMatch<Params extends { [K in keyof Params]?: string } = {}> {\n params: Params;\n isExact: boolean;\n path: string;\n url: string;\n}\n\nexport interface SceneAppRoute {\n path: string;\n page?: SceneAppPage;\n drilldown?: SceneAppDrilldownView;\n}\n\n/**\n * Responsible for top level pages routing\n */\nexport class SceneApp extends SceneObjectBase<SceneAppState> {\n public static Component = ({ model }: SceneComponentProps<SceneApp>) => {\n const { pages } = model.useState();\n\n return (\n <Switch>\n {pages.map((page) => (\n <Route\n key={page.state.url}\n exact={false}\n path={page.state.url}\n render={() => {\n return page && <page.Component model={page} />;\n }}\n ></Route>\n ))}\n </Switch>\n );\n };\n}\n\nexport interface SceneAppPageState extends SceneObjectStatePlain {\n title: string;\n subTitle?: string;\n // Use to provide page absolute URL, i.e. /app/overview\n url: string;\n // Use to provide parametrized page URL, i.e. /app/overview/:clusterId\n routePath?: string;\n // Whether or not page should be visible in the breadcrumbs path\n hideFromBreadcrumbs?: boolean;\n // Array of SceneAppPage objects that are used as page tabs displayed on top of the page\n tabs?: SceneAppPage[];\n // Function that returns a scene object for the page\n getScene: (routeMatch: SceneRouteMatch) => EmbeddedScene;\n // Array of scenes used for drilldown views\n drilldowns?: SceneAppDrilldownView[];\n // Function that returns a parent page object, used to create breadcrumbs structure\n getParentPage?: () => SceneAppPage;\n // Array of query params that will be preserved in breadcrumb and page tab links, i.e. ['from', 'to', 'var-datacenter',...]\n preserveUrlKeys?: string[];\n}\n\n/**\n * Responsible for page's drilldown & tabs routing\n */\nexport class SceneAppPage extends SceneObjectBase<SceneAppPageState> {\n public static Component = SceneAppPageRenderer;\n}\n\nfunction SceneAppPageRenderer({ model }: SceneComponentProps<SceneAppPage>) {\n const { tabs, drilldowns, url, routePath } = model.state;\n const routes: React.ReactNode[] = [];\n\n if (tabs) {\n for (const page of tabs) {\n routes.push(\n <Route\n exact={true}\n key={page.state.url}\n path={page.state.routePath ?? page.state.url}\n render={() => {\n return <page.Component model={page} />;\n }}\n ></Route>\n );\n\n if (page.state.drilldowns) {\n for (const drilldown of page.state.drilldowns) {\n routes.push(\n <Route\n exact={false}\n key={drilldown.routePath}\n path={drilldown.routePath}\n render={() => {\n return <SceneAppDrilldownViewRender drilldown={drilldown} parent={page} />;\n }}\n ></Route>\n );\n }\n }\n }\n\n return <Switch>{routes}</Switch>;\n }\n\n if (drilldowns) {\n for (const drilldown of drilldowns) {\n routes.push(\n <Route\n key={drilldown.routePath}\n exact={false}\n path={drilldown.routePath}\n render={() => {\n return <SceneAppDrilldownViewRender drilldown={drilldown} parent={model} />;\n }}\n ></Route>\n );\n }\n }\n\n let page = <ScenePageRenderer page={model} />;\n\n // if parent is a SceneAppPage we are a tab\n if (model.parent instanceof SceneAppPage) {\n page = <ScenePageRenderer page={model.parent} activeTab={model} tabs={model.parent.state.tabs} />;\n }\n\n return (\n <Switch>\n {/* page route */}\n <Route\n key={url}\n exact={true}\n path={routePath ?? url}\n render={() => {\n return page;\n }}\n ></Route>\n\n {/* drilldown routes */}\n {routes}\n </Switch>\n );\n}\n\ninterface ScenePageRenderProps {\n page: SceneAppPage;\n tabs?: SceneAppPage[];\n activeTab?: SceneAppPage;\n}\n\nfunction ScenePageRenderer({ page, tabs, activeTab }: ScenePageRenderProps) {\n /**\n * We use this flag to make sure the URL sync is enabled before the scene is actually rendered.\n */\n const [isInitialized, setIsInitialized] = useState(false);\n const params = useAppQueryParams();\n const routeMatch = useRouteMatch();\n\n let scene = sceneCache.get(routeMatch!.url);\n if (!scene) {\n // If we are rendering a tab, we need to get the scene f rom the tab, otherwise, use page's scene\n scene = activeTab ? activeTab.state.getScene(routeMatch) : page.state.getScene(routeMatch);\n sceneCache.set(routeMatch!.url, scene);\n }\n\n useEffect(() => {\n // Before rendering scene components, we are making sure the URL sync is enabled for.\n if (!isInitialized && scene) {\n scene.initUrlSync();\n setIsInitialized(true);\n }\n }, [isInitialized, scene]);\n\n if (!isInitialized) {\n return null;\n }\n\n const pageNav: NavModelItem = {\n text: page.state.title,\n subTitle: page.state.subTitle,\n url: getLinkUrlWithAppUrlState(page.state.url, params, page.state.preserveUrlKeys),\n hideFromBreadcrumbs: page.state.hideFromBreadcrumbs,\n parentItem: getParentBreadcrumbs(page.state.getParentPage ? page.state.getParentPage() : page.parent, params),\n };\n\n if (tabs) {\n pageNav.children = tabs.map((tab) => {\n return {\n text: tab.state.title,\n active: activeTab === tab,\n url: getLinkUrlWithAppUrlState(tab.state.url, params, tab.state.preserveUrlKeys),\n parentItem: pageNav,\n };\n });\n }\n\n return (\n <PluginPage pageNav={pageNav} /*hideFooter={true}*/>\n <scene.Component model={scene} />\n </PluginPage>\n );\n}\n\nexport interface SceneAppDrilldownView {\n // Use to provide parametrized drilldown URL, i.e. /app/clusters/:clusterId\n routePath: string;\n // Function that returns a page object for a given drilldown route match. Use parent to configure drilldown view parent SceneAppPage via getParentPage method.\n getPage: (routeMatch: SceneRouteMatch<any>, parent: SceneAppPage) => SceneAppPage;\n}\n\nexport function SceneAppDrilldownViewRender(props: { drilldown: SceneAppDrilldownView; parent: SceneAppPage }) {\n const routeMatch = useRouteMatch();\n const scene = props.drilldown.getPage(routeMatch, props.parent);\n return <scene.Component model={scene} />;\n}\n\nfunction getParentBreadcrumbs(parent: SceneObject | undefined, params: UrlQueryMap): NavModelItem | undefined {\n if (parent instanceof SceneAppPage) {\n return {\n text: parent.state.title,\n url: getLinkUrlWithAppUrlState(parent.state.url, params, parent.state.preserveUrlKeys),\n hideFromBreadcrumbs: parent.state.hideFromBreadcrumbs,\n parentItem: getParentBreadcrumbs(\n parent.state.getParentPage ? parent.state.getParentPage() : parent.parent,\n params\n ),\n };\n }\n\n return undefined;\n}\n"],"names":["page"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SceneApp.js","sources":["../../../../src/components/SceneApp/SceneApp.tsx"],"sourcesContent":["import React from 'react';\nimport { Route, Switch } from 'react-router-dom';\n\nimport { SceneComponentProps } from '../../core/types';\nimport { SceneObjectBase } from '../../core/SceneObjectBase';\nimport { SceneAppState } from './types';\n\n/**\n * Responsible for top level pages routing\n */\nexport class SceneApp extends SceneObjectBase<SceneAppState> {\n public static Component = ({ model }: SceneComponentProps<SceneApp>) => {\n const { pages } = model.useState();\n\n return (\n <Switch>\n {pages.map((page) => (\n <Route\n key={page.state.url}\n exact={false}\n path={page.state.url}\n render={() => {\n return page && <page.Component model={page} />;\n }}\n ></Route>\n ))}\n </Switch>\n );\n };\n}\n"],"names":[],"mappings":";;;;AAUO,MAAM,iBAAiB,eAA+B,CAAA;AAmB7D,CAAA;AAnBa,QAAA,CACG,SAAY,GAAA,CAAC,EAAE,KAAA,EAA2C,KAAA;AACtE,EAAA,MAAM,EAAE,KAAA,EAAU,GAAA,KAAA,CAAM,QAAS,EAAA,CAAA;AAEjC,EAAA,2CACG,MACE,EAAA,IAAA,EAAA,KAAA,CAAM,GAAI,CAAA,CAAC,yBACT,KAAA,CAAA,aAAA,CAAA,KAAA,EAAA;AAAA,IACC,GAAA,EAAK,KAAK,KAAM,CAAA,GAAA;AAAA,IAChB,KAAO,EAAA,KAAA;AAAA,IACP,IAAA,EAAM,KAAK,KAAM,CAAA,GAAA;AAAA,IACjB,QAAQ,MAAM;AACZ,MAAO,OAAA,IAAA,oBAAS,KAAA,CAAA,aAAA,CAAA,IAAA,CAAK,SAAL,EAAA;AAAA,QAAe,KAAO,EAAA,IAAA;AAAA,OAAM,CAAA,CAAA;AAAA,KAC9C;AAAA,GACD,CACF,CACH,CAAA,CAAA;AAEJ,CAAA;;;;"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
|
2
|
+
import { PluginPage } from '@grafana/runtime';
|
|
3
|
+
import { Route, Switch, useRouteMatch } from 'react-router-dom';
|
|
4
|
+
import { SceneObjectBase } from '../../core/SceneObjectBase.js';
|
|
5
|
+
import { useAppQueryParams, getLinkUrlWithAppUrlState } from './utils.js';
|
|
6
|
+
|
|
7
|
+
const sceneCache = /* @__PURE__ */ new Map();
|
|
8
|
+
class SceneAppPage extends SceneObjectBase {
|
|
9
|
+
}
|
|
10
|
+
SceneAppPage.Component = SceneAppPageRenderer;
|
|
11
|
+
function SceneAppPageRenderer({ model }) {
|
|
12
|
+
var _a;
|
|
13
|
+
const { tabs, drilldowns, url, routePath } = model.state;
|
|
14
|
+
const routes = [];
|
|
15
|
+
if (tabs) {
|
|
16
|
+
for (const page2 of tabs) {
|
|
17
|
+
routes.push(
|
|
18
|
+
/* @__PURE__ */ React.createElement(Route, {
|
|
19
|
+
exact: true,
|
|
20
|
+
key: page2.state.url,
|
|
21
|
+
path: (_a = page2.state.routePath) != null ? _a : page2.state.url,
|
|
22
|
+
render: () => {
|
|
23
|
+
return /* @__PURE__ */ React.createElement(page2.Component, {
|
|
24
|
+
model: page2
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
})
|
|
28
|
+
);
|
|
29
|
+
if (page2.state.drilldowns) {
|
|
30
|
+
for (const drilldown of page2.state.drilldowns) {
|
|
31
|
+
routes.push(
|
|
32
|
+
/* @__PURE__ */ React.createElement(Route, {
|
|
33
|
+
exact: false,
|
|
34
|
+
key: drilldown.routePath,
|
|
35
|
+
path: drilldown.routePath,
|
|
36
|
+
render: () => {
|
|
37
|
+
return /* @__PURE__ */ React.createElement(SceneAppDrilldownViewRender, {
|
|
38
|
+
drilldown,
|
|
39
|
+
parent: page2
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return /* @__PURE__ */ React.createElement(Switch, null, routes);
|
|
48
|
+
}
|
|
49
|
+
if (drilldowns) {
|
|
50
|
+
for (const drilldown of drilldowns) {
|
|
51
|
+
routes.push(
|
|
52
|
+
/* @__PURE__ */ React.createElement(Route, {
|
|
53
|
+
key: drilldown.routePath,
|
|
54
|
+
exact: false,
|
|
55
|
+
path: drilldown.routePath,
|
|
56
|
+
render: () => {
|
|
57
|
+
return /* @__PURE__ */ React.createElement(SceneAppDrilldownViewRender, {
|
|
58
|
+
drilldown,
|
|
59
|
+
parent: model
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
})
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
let page = /* @__PURE__ */ React.createElement(ScenePageRenderer, {
|
|
67
|
+
page: model
|
|
68
|
+
});
|
|
69
|
+
if (model.parent instanceof SceneAppPage) {
|
|
70
|
+
page = /* @__PURE__ */ React.createElement(ScenePageRenderer, {
|
|
71
|
+
page: model.parent,
|
|
72
|
+
activeTab: model,
|
|
73
|
+
tabs: model.parent.state.tabs
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
return /* @__PURE__ */ React.createElement(Switch, null, /* @__PURE__ */ React.createElement(Route, {
|
|
77
|
+
key: url,
|
|
78
|
+
exact: true,
|
|
79
|
+
path: routePath != null ? routePath : url,
|
|
80
|
+
render: () => {
|
|
81
|
+
return page;
|
|
82
|
+
}
|
|
83
|
+
}), routes);
|
|
84
|
+
}
|
|
85
|
+
function ScenePageRenderer({ page, tabs, activeTab }) {
|
|
86
|
+
const [isInitialized, setIsInitialized] = useState(false);
|
|
87
|
+
const params = useAppQueryParams();
|
|
88
|
+
const routeMatch = useRouteMatch();
|
|
89
|
+
let scene = sceneCache.get(routeMatch.url);
|
|
90
|
+
if (!scene) {
|
|
91
|
+
scene = activeTab ? activeTab.state.getScene(routeMatch) : page.state.getScene(routeMatch);
|
|
92
|
+
sceneCache.set(routeMatch.url, scene);
|
|
93
|
+
}
|
|
94
|
+
useEffect(() => {
|
|
95
|
+
if (!isInitialized && scene) {
|
|
96
|
+
scene.initUrlSync();
|
|
97
|
+
setIsInitialized(true);
|
|
98
|
+
}
|
|
99
|
+
}, [isInitialized, scene]);
|
|
100
|
+
if (!isInitialized) {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
const pageNav = {
|
|
104
|
+
text: page.state.title,
|
|
105
|
+
subTitle: page.state.subTitle,
|
|
106
|
+
img: page.state.titleImg,
|
|
107
|
+
icon: page.state.titleIcon,
|
|
108
|
+
url: getLinkUrlWithAppUrlState(page.state.url, params, page.state.preserveUrlKeys),
|
|
109
|
+
hideFromBreadcrumbs: page.state.hideFromBreadcrumbs,
|
|
110
|
+
parentItem: getParentBreadcrumbs(page.state.getParentPage ? page.state.getParentPage() : page.parent, params)
|
|
111
|
+
};
|
|
112
|
+
if (tabs) {
|
|
113
|
+
pageNav.children = tabs.map((tab) => {
|
|
114
|
+
return {
|
|
115
|
+
text: tab.state.title,
|
|
116
|
+
active: activeTab === tab,
|
|
117
|
+
url: getLinkUrlWithAppUrlState(tab.state.url, params, tab.state.preserveUrlKeys),
|
|
118
|
+
parentItem: pageNav
|
|
119
|
+
};
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
return /* @__PURE__ */ React.createElement(PluginPage, {
|
|
123
|
+
pageNav
|
|
124
|
+
}, /* @__PURE__ */ React.createElement(scene.Component, {
|
|
125
|
+
model: scene
|
|
126
|
+
}));
|
|
127
|
+
}
|
|
128
|
+
function SceneAppDrilldownViewRender(props) {
|
|
129
|
+
const routeMatch = useRouteMatch();
|
|
130
|
+
const scene = props.drilldown.getPage(routeMatch, props.parent);
|
|
131
|
+
return /* @__PURE__ */ React.createElement(scene.Component, {
|
|
132
|
+
model: scene
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
function getParentBreadcrumbs(parent, params) {
|
|
136
|
+
if (parent instanceof SceneAppPage) {
|
|
137
|
+
return {
|
|
138
|
+
text: parent.state.title,
|
|
139
|
+
url: getLinkUrlWithAppUrlState(parent.state.url, params, parent.state.preserveUrlKeys),
|
|
140
|
+
hideFromBreadcrumbs: parent.state.hideFromBreadcrumbs,
|
|
141
|
+
parentItem: getParentBreadcrumbs(
|
|
142
|
+
parent.state.getParentPage ? parent.state.getParentPage() : parent.parent,
|
|
143
|
+
params
|
|
144
|
+
)
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
return void 0;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export { SceneAppPage };
|
|
151
|
+
//# sourceMappingURL=SceneAppPage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SceneAppPage.js","sources":["../../../../src/components/SceneApp/SceneAppPage.tsx"],"sourcesContent":["import React, { useState, useEffect } from 'react';\nimport { NavModelItem, UrlQueryMap } from '@grafana/data';\nimport { PluginPage } from '@grafana/runtime';\nimport { Route, Switch, useRouteMatch } from 'react-router-dom';\nimport { SceneObjectBase } from '../../core/SceneObjectBase';\nimport { SceneComponentProps, SceneObject } from '../../core/types';\nimport { EmbeddedScene } from '../EmbeddedScene';\nimport { SceneAppDrilldownView, SceneAppPageLike, SceneAppPageState } from './types';\nimport { getLinkUrlWithAppUrlState, useAppQueryParams } from './utils';\n\nconst sceneCache = new Map<string, EmbeddedScene>();\n\n/**\n * Responsible for page's drilldown & tabs routing\n */\nexport class SceneAppPage extends SceneObjectBase<SceneAppPageState> {\n public static Component = SceneAppPageRenderer;\n}\n\nfunction SceneAppPageRenderer({ model }: SceneComponentProps<SceneAppPage>) {\n const { tabs, drilldowns, url, routePath } = model.state;\n const routes: React.ReactNode[] = [];\n\n if (tabs) {\n for (const page of tabs) {\n routes.push(\n <Route\n exact={true}\n key={page.state.url}\n path={page.state.routePath ?? page.state.url}\n render={() => {\n return <page.Component model={page} />;\n }}\n ></Route>\n );\n\n if (page.state.drilldowns) {\n for (const drilldown of page.state.drilldowns) {\n routes.push(\n <Route\n exact={false}\n key={drilldown.routePath}\n path={drilldown.routePath}\n render={() => {\n return <SceneAppDrilldownViewRender drilldown={drilldown} parent={page} />;\n }}\n ></Route>\n );\n }\n }\n }\n\n return <Switch>{routes}</Switch>;\n }\n\n if (drilldowns) {\n for (const drilldown of drilldowns) {\n routes.push(\n <Route\n key={drilldown.routePath}\n exact={false}\n path={drilldown.routePath}\n render={() => {\n return <SceneAppDrilldownViewRender drilldown={drilldown} parent={model} />;\n }}\n ></Route>\n );\n }\n }\n\n let page = <ScenePageRenderer page={model} />;\n\n // if parent is a SceneAppPage we are a tab\n if (model.parent instanceof SceneAppPage) {\n page = <ScenePageRenderer page={model.parent} activeTab={model} tabs={model.parent.state.tabs} />;\n }\n\n return (\n <Switch>\n {/* page route */}\n <Route\n key={url}\n exact={true}\n path={routePath ?? url}\n render={() => {\n return page;\n }}\n ></Route>\n\n {/* drilldown routes */}\n {routes}\n </Switch>\n );\n}\n\ninterface ScenePageRenderProps {\n page: SceneAppPageLike;\n tabs?: SceneAppPageLike[];\n activeTab?: SceneAppPage;\n}\n\nfunction ScenePageRenderer({ page, tabs, activeTab }: ScenePageRenderProps) {\n /**\n * We use this flag to make sure the URL sync is enabled before the scene is actually rendered.\n */\n const [isInitialized, setIsInitialized] = useState(false);\n const params = useAppQueryParams();\n const routeMatch = useRouteMatch();\n\n let scene = sceneCache.get(routeMatch!.url);\n if (!scene) {\n // If we are rendering a tab, we need to get the scene f rom the tab, otherwise, use page's scene\n scene = activeTab ? activeTab.state.getScene(routeMatch) : page.state.getScene(routeMatch);\n sceneCache.set(routeMatch!.url, scene);\n }\n\n useEffect(() => {\n // Before rendering scene components, we are making sure the URL sync is enabled for.\n if (!isInitialized && scene) {\n scene.initUrlSync();\n setIsInitialized(true);\n }\n }, [isInitialized, scene]);\n\n if (!isInitialized) {\n return null;\n }\n\n const pageNav: NavModelItem = {\n text: page.state.title,\n subTitle: page.state.subTitle,\n img: page.state.titleImg,\n icon: page.state.titleIcon,\n url: getLinkUrlWithAppUrlState(page.state.url, params, page.state.preserveUrlKeys),\n hideFromBreadcrumbs: page.state.hideFromBreadcrumbs,\n parentItem: getParentBreadcrumbs(page.state.getParentPage ? page.state.getParentPage() : page.parent, params),\n };\n\n if (tabs) {\n pageNav.children = tabs.map((tab) => {\n return {\n text: tab.state.title,\n active: activeTab === tab,\n url: getLinkUrlWithAppUrlState(tab.state.url, params, tab.state.preserveUrlKeys),\n parentItem: pageNav,\n };\n });\n }\n\n return (\n <PluginPage pageNav={pageNav}>\n <scene.Component model={scene} />\n </PluginPage>\n );\n}\n\nfunction SceneAppDrilldownViewRender(props: { drilldown: SceneAppDrilldownView; parent: SceneAppPageLike }) {\n const routeMatch = useRouteMatch();\n const scene = props.drilldown.getPage(routeMatch, props.parent);\n return <scene.Component model={scene} />;\n}\n\nfunction getParentBreadcrumbs(parent: SceneObject | undefined, params: UrlQueryMap): NavModelItem | undefined {\n if (parent instanceof SceneAppPage) {\n return {\n text: parent.state.title,\n url: getLinkUrlWithAppUrlState(parent.state.url, params, parent.state.preserveUrlKeys),\n hideFromBreadcrumbs: parent.state.hideFromBreadcrumbs,\n parentItem: getParentBreadcrumbs(\n parent.state.getParentPage ? parent.state.getParentPage() : parent.parent,\n params\n ),\n };\n }\n\n return undefined;\n}\n"],"names":["page"],"mappings":"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"}
|
|
@@ -4,18 +4,18 @@ import { SceneObjectBase } from '../core/SceneObjectBase.js';
|
|
|
4
4
|
import { sceneGraph } from '../core/sceneGraph.js';
|
|
5
5
|
|
|
6
6
|
class SceneByFrameRepeater extends SceneObjectBase {
|
|
7
|
-
|
|
8
|
-
super
|
|
9
|
-
this.
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
constructor(state) {
|
|
8
|
+
super(state);
|
|
9
|
+
this.addActivationHandler(() => {
|
|
10
|
+
this._subs.add(
|
|
11
|
+
sceneGraph.getData(this).subscribeToState((data) => {
|
|
12
12
|
var _a;
|
|
13
13
|
if (((_a = data.data) == null ? void 0 : _a.state) === LoadingState.Done) {
|
|
14
14
|
this.performRepeat(data.data);
|
|
15
15
|
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
);
|
|
16
|
+
})
|
|
17
|
+
);
|
|
18
|
+
});
|
|
19
19
|
}
|
|
20
20
|
performRepeat(data) {
|
|
21
21
|
const newChildren = [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SceneByFrameRepeater.js","sources":["../../../src/components/SceneByFrameRepeater.tsx"],"sourcesContent":["import React from 'react';\n\nimport { LoadingState, PanelData, DataFrame } from '@grafana/data';\n\nimport { SceneObjectBase } from '../core/SceneObjectBase';\nimport { sceneGraph } from '../core/sceneGraph';\nimport {\n SceneComponentProps,\n SceneObject,\n SceneObjectStatePlain,\n SceneLayoutState,\n SceneLayoutChild,\n} from '../core/types';\n\ninterface
|
|
1
|
+
{"version":3,"file":"SceneByFrameRepeater.js","sources":["../../../src/components/SceneByFrameRepeater.tsx"],"sourcesContent":["import React from 'react';\n\nimport { LoadingState, PanelData, DataFrame } from '@grafana/data';\n\nimport { SceneObjectBase } from '../core/SceneObjectBase';\nimport { sceneGraph } from '../core/sceneGraph';\nimport {\n SceneComponentProps,\n SceneObject,\n SceneObjectStatePlain,\n SceneLayoutState,\n SceneLayoutChild,\n} from '../core/types';\n\ninterface SceneByFrameRepeaterState extends SceneObjectStatePlain {\n body: SceneObject<SceneLayoutState>;\n getLayoutChild(data: PanelData, frame: DataFrame, frameIndex: number): SceneLayoutChild;\n}\n\nexport class SceneByFrameRepeater extends SceneObjectBase<SceneByFrameRepeaterState> {\n public constructor(state: SceneByFrameRepeaterState) {\n super(state);\n\n this.addActivationHandler(() => {\n this._subs.add(\n sceneGraph.getData(this).subscribeToState((data) => {\n if (data.data?.state === LoadingState.Done) {\n this.performRepeat(data.data);\n }\n })\n );\n });\n }\n\n private performRepeat(data: PanelData) {\n const newChildren: SceneLayoutChild[] = [];\n\n for (let seriesIndex = 0; seriesIndex < data.series.length; seriesIndex++) {\n const layoutChild = this.state.getLayoutChild(data, data.series[seriesIndex], seriesIndex);\n newChildren.push(layoutChild);\n }\n\n this.state.body.setState({ children: newChildren });\n }\n\n public static Component = ({ model, isEditing }: SceneComponentProps<SceneByFrameRepeater>) => {\n const { body } = model.useState();\n return <body.Component model={body} isEditing={isEditing} />;\n };\n}\n"],"names":[],"mappings":";;;;;AAmBO,MAAM,6BAA6B,eAA2C,CAAA;AAAA,EAC5E,YAAY,KAAkC,EAAA;AACnD,IAAA,KAAA,CAAM,KAAK,CAAA,CAAA;AAEX,IAAA,IAAA,CAAK,qBAAqB,MAAM;AAC9B,MAAA,IAAA,CAAK,KAAM,CAAA,GAAA;AAAA,QACT,WAAW,OAAQ,CAAA,IAAI,CAAE,CAAA,gBAAA,CAAiB,CAAC,IAAS,KAAA;AAzB5D,UAAA,IAAA,EAAA,CAAA;AA0BU,UAAA,IAAA,CAAA,CAAI,EAAK,GAAA,IAAA,CAAA,IAAA,KAAL,IAAW,GAAA,KAAA,CAAA,GAAA,EAAA,CAAA,KAAA,MAAU,aAAa,IAAM,EAAA;AAC1C,YAAK,IAAA,CAAA,aAAA,CAAc,KAAK,IAAI,CAAA,CAAA;AAAA,WAC9B;AAAA,SACD,CAAA;AAAA,OACH,CAAA;AAAA,KACD,CAAA,CAAA;AAAA,GACH;AAAA,EAEQ,cAAc,IAAiB,EAAA;AACrC,IAAA,MAAM,cAAkC,EAAC,CAAA;AAEzC,IAAA,KAAA,IAAS,cAAc,CAAG,EAAA,WAAA,GAAc,IAAK,CAAA,MAAA,CAAO,QAAQ,WAAe,EAAA,EAAA;AACzE,MAAM,MAAA,WAAA,GAAc,KAAK,KAAM,CAAA,cAAA,CAAe,MAAM,IAAK,CAAA,MAAA,CAAO,cAAc,WAAW,CAAA,CAAA;AACzF,MAAA,WAAA,CAAY,KAAK,WAAW,CAAA,CAAA;AAAA,KAC9B;AAEA,IAAA,IAAA,CAAK,MAAM,IAAK,CAAA,QAAA,CAAS,EAAE,QAAA,EAAU,aAAa,CAAA,CAAA;AAAA,GACpD;AAMF,CAAA;AA9Ba,oBAAA,CA0BG,SAAY,GAAA,CAAC,EAAE,KAAA,EAAO,WAA2D,KAAA;AAC7F,EAAA,MAAM,EAAE,IAAA,EAAS,GAAA,KAAA,CAAM,QAAS,EAAA,CAAA;AAChC,EAAO,uBAAA,KAAA,CAAA,aAAA,CAAC,KAAK,SAAL,EAAA;AAAA,IAAe,KAAO,EAAA,IAAA;AAAA,IAAM,SAAA;AAAA,GAAsB,CAAA,CAAA;AAC5D,CAAA;;;;"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { SceneObjectBase } from '../core/SceneObjectBase.js';
|
|
3
|
+
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
8
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
9
|
+
var __spreadValues = (a, b) => {
|
|
10
|
+
for (var prop in b || (b = {}))
|
|
11
|
+
if (__hasOwnProp.call(b, prop))
|
|
12
|
+
__defNormalProp(a, prop, b[prop]);
|
|
13
|
+
if (__getOwnPropSymbols)
|
|
14
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
15
|
+
if (__propIsEnum.call(b, prop))
|
|
16
|
+
__defNormalProp(a, prop, b[prop]);
|
|
17
|
+
}
|
|
18
|
+
return a;
|
|
19
|
+
};
|
|
20
|
+
class SceneReactObject extends SceneObjectBase {
|
|
21
|
+
}
|
|
22
|
+
SceneReactObject.Component = ({ model }) => {
|
|
23
|
+
const { component: Component, props, reactNode } = model.useState();
|
|
24
|
+
if (Component) {
|
|
25
|
+
return /* @__PURE__ */ React.createElement(Component, __spreadValues({}, props));
|
|
26
|
+
}
|
|
27
|
+
if (reactNode) {
|
|
28
|
+
return reactNode;
|
|
29
|
+
}
|
|
30
|
+
return null;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export { SceneReactObject };
|
|
34
|
+
//# sourceMappingURL=SceneReactObject.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SceneReactObject.js","sources":["../../../src/components/SceneReactObject.tsx"],"sourcesContent":["import React from 'react';\n\nimport { SceneObjectBase } from '../core/SceneObjectBase';\nimport { SceneComponentProps, SceneLayoutChildState } from '../core/types';\n\nexport interface SceneReactObjectState<TProps = {}> extends SceneLayoutChildState {\n /**\n * React component to render\n */\n component?: React.ComponentType<TProps>;\n /**\n * Props to pass to the component\n */\n props?: TProps;\n /**\n * Alternative to component and props is just to pass a React node\n */\n reactNode?: React.ReactNode;\n}\n\n/**\n * A utility object that can be used to render any React component or ReactNode\n */\nexport class SceneReactObject extends SceneObjectBase<SceneReactObjectState> {\n public static Component = ({ model }: SceneComponentProps<SceneReactObject>) => {\n const { component: Component, props, reactNode } = model.useState();\n\n if (Component) {\n return <Component {...props} />;\n }\n\n if (reactNode) {\n return reactNode;\n }\n\n return null;\n };\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;AAuBO,MAAM,yBAAyB,eAAuC,CAAA;AAc7E,CAAA;AAda,gBAAA,CACG,SAAY,GAAA,CAAC,EAAE,KAAA,EAAmD,KAAA;AAC9E,EAAA,MAAM,EAAE,SAAW,EAAA,SAAA,EAAW,OAAO,SAAU,EAAA,GAAI,MAAM,QAAS,EAAA,CAAA;AAElE,EAAA,IAAI,SAAW,EAAA;AACb,IAAO,uBAAA,KAAA,CAAA,aAAA,CAAC,8BAAc,KAAO,CAAA,CAAA,CAAA;AAAA,GAC/B;AAEA,EAAA,IAAI,SAAW,EAAA;AACb,IAAO,OAAA,SAAA,CAAA;AAAA,GACT;AAEA,EAAO,OAAA,IAAA,CAAA;AACT,CAAA;;;;"}
|
|
@@ -63,15 +63,14 @@ class SceneRefreshPicker extends SceneObjectBase {
|
|
|
63
63
|
timeRange.onRefresh();
|
|
64
64
|
}, intervalMs);
|
|
65
65
|
};
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}
|
|
66
|
+
this.addActivationHandler(() => {
|
|
67
|
+
this.setupIntervalTimer();
|
|
68
|
+
return () => {
|
|
69
|
+
if (this._intervalTimer) {
|
|
70
|
+
clearInterval(this._intervalTimer);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
});
|
|
75
74
|
}
|
|
76
75
|
getUrlState() {
|
|
77
76
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SceneRefreshPicker.js","sources":["../../../src/components/SceneRefreshPicker.tsx"],"sourcesContent":["import React from 'react';\n\nimport { rangeUtil } from '@grafana/data';\nimport { RefreshPicker } from '@grafana/ui';\n\nimport { SceneObjectBase } from '../core/SceneObjectBase';\nimport { sceneGraph } from '../core/sceneGraph';\nimport { SceneComponentProps, SceneObjectStatePlain, SceneObjectUrlValues } from '../core/types';\nimport { SceneObjectUrlSyncConfig } from '../services/SceneObjectUrlSyncConfig';\n\nexport const DEFAULT_INTERVALS = ['5s', '10s', '30s', '1m', '5m', '15m', '30m', '1h', '2h', '1d'];\n\nexport interface SceneRefreshPickerState extends SceneObjectStatePlain {\n // Refresh interval, e.g. 5s, 1m, 2h\n refresh: string;\n // List of allowed refresh intervals, e.g. ['5s', '1m']\n intervals?: string[];\n isOnCanvas?: boolean;\n}\n\nexport class SceneRefreshPicker extends SceneObjectBase<SceneRefreshPickerState> {\n public static Component = SceneRefreshPickerRenderer;\n protected _urlSync = new SceneObjectUrlSyncConfig(this, { keys: ['refresh'] });\n\n private _intervalTimer: ReturnType<typeof setInterval> | undefined;\n\n public constructor(state: Partial<SceneRefreshPickerState>) {\n super({\n refresh: '',\n ...state,\n intervals: state.intervals ?? DEFAULT_INTERVALS,\n });\n
|
|
1
|
+
{"version":3,"file":"SceneRefreshPicker.js","sources":["../../../src/components/SceneRefreshPicker.tsx"],"sourcesContent":["import React from 'react';\n\nimport { rangeUtil } from '@grafana/data';\nimport { RefreshPicker } from '@grafana/ui';\n\nimport { SceneObjectBase } from '../core/SceneObjectBase';\nimport { sceneGraph } from '../core/sceneGraph';\nimport { SceneComponentProps, SceneObjectStatePlain, SceneObjectUrlValues } from '../core/types';\nimport { SceneObjectUrlSyncConfig } from '../services/SceneObjectUrlSyncConfig';\n\nexport const DEFAULT_INTERVALS = ['5s', '10s', '30s', '1m', '5m', '15m', '30m', '1h', '2h', '1d'];\n\nexport interface SceneRefreshPickerState extends SceneObjectStatePlain {\n // Refresh interval, e.g. 5s, 1m, 2h\n refresh: string;\n // List of allowed refresh intervals, e.g. ['5s', '1m']\n intervals?: string[];\n isOnCanvas?: boolean;\n}\n\nexport class SceneRefreshPicker extends SceneObjectBase<SceneRefreshPickerState> {\n public static Component = SceneRefreshPickerRenderer;\n protected _urlSync = new SceneObjectUrlSyncConfig(this, { keys: ['refresh'] });\n\n private _intervalTimer: ReturnType<typeof setInterval> | undefined;\n\n public constructor(state: Partial<SceneRefreshPickerState>) {\n super({\n refresh: '',\n ...state,\n intervals: state.intervals ?? DEFAULT_INTERVALS,\n });\n\n this.addActivationHandler(() => {\n this.setupIntervalTimer();\n\n return () => {\n if (this._intervalTimer) {\n clearInterval(this._intervalTimer);\n }\n };\n });\n }\n\n public onRefresh = () => {\n const timeRange = sceneGraph.getTimeRange(this);\n\n if (this._intervalTimer) {\n clearInterval(this._intervalTimer);\n }\n\n timeRange.onRefresh();\n this.setupIntervalTimer();\n };\n\n public onIntervalChanged = (interval: string) => {\n this.setState({ refresh: interval });\n this.setupIntervalTimer();\n };\n\n public getUrlState() {\n return {\n refresh: this.state.refresh,\n };\n }\n\n public updateFromUrl(values: SceneObjectUrlValues) {\n const refresh = values.refresh;\n\n if (refresh && typeof refresh === 'string') {\n this.setState({\n refresh,\n });\n }\n }\n\n private setupIntervalTimer = () => {\n const timeRange = sceneGraph.getTimeRange(this);\n const { refresh, intervals } = this.state;\n\n if (this._intervalTimer || refresh === '') {\n clearInterval(this._intervalTimer);\n }\n\n if (refresh === '') {\n return;\n }\n\n // When the provided interval is not allowed\n if (intervals && !intervals.includes(refresh)) {\n return;\n }\n\n const intervalMs = rangeUtil.intervalToMs(refresh);\n\n this._intervalTimer = setInterval(() => {\n timeRange.onRefresh();\n }, intervalMs);\n };\n}\n\nexport function SceneRefreshPickerRenderer({ model }: SceneComponentProps<SceneRefreshPicker>) {\n const { refresh, intervals, isOnCanvas } = model.useState();\n\n return (\n <RefreshPicker\n value={refresh}\n intervals={intervals}\n onRefresh={model.onRefresh}\n onIntervalChanged={model.onIntervalChanged}\n isOnCanvas={isOnCanvas}\n />\n );\n}\n"],"names":[],"mappings":"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"}
|