@grafana/scenes 0.3.0 → 0.4.0
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/CHANGELOG.md +51 -5
- package/README.md +1 -1
- package/dist/esm/components/EmbeddedScene.js +8 -5
- package/dist/esm/components/EmbeddedScene.js.map +1 -1
- package/dist/esm/components/NestedScene.js.map +1 -1
- package/dist/esm/components/SceneApp/SceneApp.js +2 -5
- package/dist/esm/components/SceneApp/SceneApp.js.map +1 -1
- package/dist/esm/components/SceneApp/SceneAppPage.js +122 -104
- package/dist/esm/components/SceneApp/SceneAppPage.js.map +1 -1
- package/dist/esm/components/SceneApp/SceneAppPageView.js +82 -0
- package/dist/esm/components/SceneApp/SceneAppPageView.js.map +1 -0
- package/dist/esm/components/SceneApp/utils.js +5 -1
- package/dist/esm/components/SceneApp/utils.js.map +1 -1
- package/dist/esm/components/layout/SceneFlexLayout.js +40 -19
- package/dist/esm/components/layout/SceneFlexLayout.js.map +1 -1
- package/dist/esm/components/layout/grid/LazyLoader.js +87 -0
- package/dist/esm/components/layout/grid/LazyLoader.js.map +1 -0
- package/dist/esm/components/layout/grid/SceneGridLayout.js +2 -50
- package/dist/esm/components/layout/grid/SceneGridLayout.js.map +1 -1
- package/dist/esm/components/layout/grid/SceneGridLayoutRenderer.js +70 -0
- package/dist/esm/components/layout/grid/SceneGridLayoutRenderer.js.map +1 -0
- package/dist/esm/core/SceneComponentWrapper.js +8 -1
- package/dist/esm/core/SceneComponentWrapper.js.map +1 -1
- package/dist/esm/core/SceneObjectBase.js +16 -2
- package/dist/esm/core/SceneObjectBase.js.map +1 -1
- package/dist/esm/core/sceneGraph.js +49 -30
- package/dist/esm/core/sceneGraph.js.map +1 -1
- package/dist/esm/core/types.js.map +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/querying/SceneQueryRunner.js +11 -14
- package/dist/esm/querying/SceneQueryRunner.js.map +1 -1
- package/dist/esm/services/UrlSyncManager.js +52 -17
- package/dist/esm/services/UrlSyncManager.js.map +1 -1
- package/dist/esm/utils/getDataSource.js.map +1 -1
- package/dist/esm/variables/interpolation/ScopedVarsVariable.js +4 -13
- package/dist/esm/variables/interpolation/ScopedVarsVariable.js.map +1 -1
- package/dist/esm/variables/interpolation/fieldAccessorCache.js +13 -0
- package/dist/esm/variables/interpolation/fieldAccessorCache.js.map +1 -0
- package/dist/esm/variables/macros/dataMacros.js +134 -0
- package/dist/esm/variables/macros/dataMacros.js.map +1 -0
- package/dist/esm/variables/macros/index.js +5 -2
- package/dist/esm/variables/macros/index.js.map +1 -1
- package/dist/esm/variables/macros/templateProxies.js +51 -0
- package/dist/esm/variables/macros/templateProxies.js.map +1 -0
- package/dist/esm/variables/sets/SceneVariableSet.js +17 -1
- package/dist/esm/variables/sets/SceneVariableSet.js.map +1 -1
- package/dist/esm/variables/variants/TestVariable.js +3 -1
- package/dist/esm/variables/variants/TestVariable.js.map +1 -1
- package/dist/esm/variables/variants/query/QueryVariable.js +1 -17
- package/dist/esm/variables/variants/query/QueryVariable.js.map +1 -1
- package/dist/index.d.ts +84 -32
- package/dist/index.js +986 -585
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/dist/esm/variables/macros/DataValueMacro.js +0 -60
- package/dist/esm/variables/macros/DataValueMacro.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,47 @@
|
|
|
1
|
+
# v0.4.0 (Tue Apr 18 2023)
|
|
2
|
+
|
|
3
|
+
### Release Notes
|
|
4
|
+
|
|
5
|
+
#### Behaviors: Add state and runtime behavior to any scene object ([#119](https://github.com/grafana/scenes/pull/119))
|
|
6
|
+
|
|
7
|
+
You can now augment any scene object with runtime state & behavior using the new `$behaviors` state key. Behaviors are implemented as SceneObjects that are activated when their parent is activated or as pure functions that get called when the SceneObject they are attached to get's activated.
|
|
8
|
+
|
|
9
|
+
With behaviors you can easily implement conditional display of panels using the new `isHidden` property on SceneFlexItem. and other dynamic layout behaviors. View the [behaviors demo](https://github.com/grafana/scenes/blob/main/packages/scenes-app/src/demos/behaviorsDemo.tsx) for some examples.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
#### 🚀 Enhancement
|
|
14
|
+
|
|
15
|
+
- Behaviors: Add state and runtime behavior to any scene object [#119](https://github.com/grafana/scenes/pull/119) ([@torkelo](https://github.com/torkelo))
|
|
16
|
+
- SceneObjectBase: Activate parents before children [#148](https://github.com/grafana/scenes/pull/148) ([@torkelo](https://github.com/torkelo))
|
|
17
|
+
|
|
18
|
+
#### 🐛 Bug Fix
|
|
19
|
+
|
|
20
|
+
- SceneQueryRunner: Return after setting empty state [#145](https://github.com/grafana/scenes/pull/145) ([@torkelo](https://github.com/torkelo))
|
|
21
|
+
- SceneGridLayout: Support lazy rendering of items out of view [#129](https://github.com/grafana/scenes/pull/129) ([@kaydelaney](https://github.com/kaydelaney) [@torkelo](https://github.com/torkelo))
|
|
22
|
+
- UrlSync: Makes url sync work on SceneAppPage level [#143](https://github.com/grafana/scenes/pull/143) ([@torkelo](https://github.com/torkelo))
|
|
23
|
+
- SceneAppPage: Refactorings and adding default fallback routes [#142](https://github.com/grafana/scenes/pull/142) ([@torkelo](https://github.com/torkelo))
|
|
24
|
+
- Flex layout item parent direction [#141](https://github.com/grafana/scenes/pull/141) ([@dprokop](https://github.com/dprokop) [@torkelo](https://github.com/torkelo))
|
|
25
|
+
- SceneApp: Correctly build demo pages with getParentPage [#137](https://github.com/grafana/scenes/pull/137) ([@torkelo](https://github.com/torkelo))
|
|
26
|
+
- Templating: Add macros for __data, __field and __series [#131](https://github.com/grafana/scenes/pull/131) ([@torkelo](https://github.com/torkelo))
|
|
27
|
+
- FlexLayout: Allow SceneFlexLayout to be child of another flex layout [#135](https://github.com/grafana/scenes/pull/135) ([@dprokop](https://github.com/dprokop))
|
|
28
|
+
- FindObject: Fixes search logic so that it does not get stuck in infine loops [#140](https://github.com/grafana/scenes/pull/140) ([@torkelo](https://github.com/torkelo))
|
|
29
|
+
- sceneGraph: findObject [#127](https://github.com/grafana/scenes/pull/127) ([@torkelo](https://github.com/torkelo))
|
|
30
|
+
- SceneAppPage: Support dynamic pages (changing tabs, title, controls) [#71](https://github.com/grafana/scenes/pull/71) ([@torkelo](https://github.com/torkelo))
|
|
31
|
+
- scene-app: Refactor to use SceneAppPage for demos [#125](https://github.com/grafana/scenes/pull/125) ([@torkelo](https://github.com/torkelo) [@dprokop](https://github.com/dprokop))
|
|
32
|
+
- Packages: Update grafana/* to latest [#130](https://github.com/grafana/scenes/pull/130) ([@torkelo](https://github.com/torkelo))
|
|
33
|
+
- QueryEditor: Adds inline query editor scene object [#43](https://github.com/grafana/scenes/pull/43) ([@kaydelaney](https://github.com/kaydelaney) [@dprokop](https://github.com/dprokop))
|
|
34
|
+
- SceneVariableSet: Refresh variables that depend on time range [#124](https://github.com/grafana/scenes/pull/124) ([@dprokop](https://github.com/dprokop))
|
|
35
|
+
- ValueMacro: Fixes so __value works for rowIndex 0 [#123](https://github.com/grafana/scenes/pull/123) ([@torkelo](https://github.com/torkelo))
|
|
36
|
+
|
|
37
|
+
#### Authors: 3
|
|
38
|
+
|
|
39
|
+
- Dominik Prokop ([@dprokop](https://github.com/dprokop))
|
|
40
|
+
- kay delaney ([@kaydelaney](https://github.com/kaydelaney))
|
|
41
|
+
- Torkel Ödegaard ([@torkelo](https://github.com/torkelo))
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
1
45
|
# v0.3.0 (Mon Apr 03 2023)
|
|
2
46
|
|
|
3
47
|
### Release Notes
|
|
@@ -18,7 +62,7 @@
|
|
|
18
62
|
#### 🐛 Bug Fix
|
|
19
63
|
|
|
20
64
|
- LayoutTypes: Cleanup old types that are no longer needed [#120](https://github.com/grafana/scenes/pull/120) ([@torkelo](https://github.com/torkelo))
|
|
21
|
-
- Interpolation: Add support for
|
|
65
|
+
- Interpolation: Add support for \_\_value.\* macro that uses new scopedVar data context [#103](https://github.com/grafana/scenes/pull/103) ([@torkelo](https://github.com/torkelo))
|
|
22
66
|
|
|
23
67
|
#### ⚠️ Pushed to `main`
|
|
24
68
|
|
|
@@ -39,12 +83,14 @@
|
|
|
39
83
|
#### Layout: Create atomic, layout specific objects ([#97](https://github.com/grafana/scenes/pull/97))
|
|
40
84
|
|
|
41
85
|
The interface of `SceneFlexLayout` and `SceneGridLayout` has changed. These scene objects now accept only dedicated layout item objects as children:
|
|
86
|
+
|
|
42
87
|
- `SceneFlexItem` for `SceneFlexLayout`
|
|
43
88
|
- `SceneGridItem` and `SceneGridRow` for `SceneGridLayout`
|
|
44
89
|
|
|
45
|
-
`placement` property has been replaced by those layout-specific objects.
|
|
90
|
+
`placement` property has been replaced by those layout-specific objects.
|
|
46
91
|
|
|
47
92
|
Example
|
|
93
|
+
|
|
48
94
|
```tsx
|
|
49
95
|
// BEFORE
|
|
50
96
|
const layout = new SceneFlexLayout({
|
|
@@ -65,8 +111,8 @@ const layout = new SceneFlexLayout({
|
|
|
65
111
|
// AFTER
|
|
66
112
|
const layout = new SceneFlexLayout({
|
|
67
113
|
direction: 'column',
|
|
68
|
-
children: [
|
|
69
|
-
new SceneFlexItem({
|
|
114
|
+
children: [
|
|
115
|
+
new SceneFlexItem({
|
|
70
116
|
width: '50%',
|
|
71
117
|
height: '400',
|
|
72
118
|
body: new VizPanel({ ... }),
|
|
@@ -98,7 +144,7 @@ const layout = new SceneFlexLayout({
|
|
|
98
144
|
|
|
99
145
|
#### UrlSync: Simplify url sync interface ([#100](https://github.com/grafana/scenes/pull/100))
|
|
100
146
|
|
|
101
|
-
The
|
|
147
|
+
The SceneObjectUrlSyncHandler interface has changed. The function `getUrlState` no longer takes state as parameter. The implementation needs to use the current scene object state instead.
|
|
102
148
|
|
|
103
149
|
---
|
|
104
150
|
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
<img
|
|
3
|
-
src="https://raw.githubusercontent.com/grafana/scenes/main/
|
|
3
|
+
src="https://raw.githubusercontent.com/grafana/scenes/main/docusaurus/website/static/img/logo.svg"
|
|
4
4
|
alt="Grafana Logo"
|
|
5
5
|
width="100px"
|
|
6
6
|
padding="40px"
|
|
@@ -2,14 +2,17 @@ import { css } from '@emotion/css';
|
|
|
2
2
|
import { useStyles2 } from '@grafana/ui';
|
|
3
3
|
import React from 'react';
|
|
4
4
|
import { SceneObjectBase } from '../core/SceneObjectBase.js';
|
|
5
|
-
import {
|
|
5
|
+
import { getUrlSyncManager } from '../services/UrlSyncManager.js';
|
|
6
6
|
|
|
7
7
|
class EmbeddedScene extends SceneObjectBase {
|
|
8
|
+
constructor(state) {
|
|
9
|
+
super(state);
|
|
10
|
+
this.addActivationHandler(() => {
|
|
11
|
+
return () => getUrlSyncManager().cleanUp(this);
|
|
12
|
+
});
|
|
13
|
+
}
|
|
8
14
|
initUrlSync() {
|
|
9
|
-
|
|
10
|
-
this.urlSyncManager = new UrlSyncManager(this);
|
|
11
|
-
}
|
|
12
|
-
this.urlSyncManager.initSync();
|
|
15
|
+
getUrlSyncManager().initSync(this);
|
|
13
16
|
}
|
|
14
17
|
}
|
|
15
18
|
EmbeddedScene.Component = EmbeddedSceneRenderer;
|
|
@@ -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, SceneObjectState, SceneObject } from '../core/types';\nimport {
|
|
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, SceneObjectState, SceneObject } from '../core/types';\nimport { getUrlSyncManager } from '../services/UrlSyncManager';\n\nexport interface EmbeddedSceneState extends SceneObjectState {\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 public constructor(state: EmbeddedSceneState) {\n super(state);\n\n this.addActivationHandler(() => {\n return () => getUrlSyncManager().cleanUp(this);\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. If your using SceneAppPage you will not need to call this as\n * url sync is handled on the SceneAppPage level not this level.\n */\n public initUrlSync() {\n getUrlSyncManager().initSync(this);\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,EAG9D,YAAY,KAA2B,EAAA;AAC5C,IAAA,KAAA,CAAM,KAAK,CAAA,CAAA;AAEX,IAAA,IAAA,CAAK,qBAAqB,MAAM;AAC9B,MAAA,OAAO,MAAM,iBAAA,EAAoB,CAAA,OAAA,CAAQ,IAAI,CAAA,CAAA;AAAA,KAC9C,CAAA,CAAA;AAAA,GACH;AAAA,EAQO,WAAc,GAAA;AACnB,IAAkB,iBAAA,EAAA,CAAE,SAAS,IAAI,CAAA,CAAA;AAAA,GACnC;AACF,CAAA;AApBa,aAAA,CACG,SAAY,GAAA,qBAAA,CAAA;AAqB5B,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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NestedScene.js","sources":["../../../src/components/NestedScene.tsx"],"sourcesContent":["import { css } from '@emotion/css';\nimport React from 'react';\n\nimport { GrafanaTheme2 } from '@grafana/data';\nimport { Stack } from '@grafana/experimental';\nimport { Button, ToolbarButton, useStyles2 } from '@grafana/ui';\n\nimport { SceneObjectBase } from '../core/SceneObjectBase';\nimport { SceneObject, SceneComponentProps, SceneLayout,
|
|
1
|
+
{"version":3,"file":"NestedScene.js","sources":["../../../src/components/NestedScene.tsx"],"sourcesContent":["import { css } from '@emotion/css';\nimport React from 'react';\n\nimport { GrafanaTheme2 } from '@grafana/data';\nimport { Stack } from '@grafana/experimental';\nimport { Button, ToolbarButton, useStyles2 } from '@grafana/ui';\n\nimport { SceneObjectBase } from '../core/SceneObjectBase';\nimport { SceneObject, SceneComponentProps, SceneLayout, SceneObjectState } from '../core/types';\n\ninterface NestedSceneState extends SceneObjectState {\n title: string;\n isCollapsed?: boolean;\n canCollapse?: boolean;\n canRemove?: boolean;\n body: SceneLayout;\n actions?: SceneObject[];\n}\n\n/**\n * @internal\n * POC status, don't use this yet\n */\nexport class NestedScene extends SceneObjectBase<NestedSceneState> {\n public static Component = NestedSceneRenderer;\n\n public onToggle = () => {\n this.setState({\n isCollapsed: !this.state.isCollapsed,\n });\n };\n\n /** Removes itself from its parent's children array */\n public onRemove = () => {\n const parent = this.parent!;\n\n if (isSceneLayoutItem(parent)) {\n parent.setState({\n body: undefined,\n });\n }\n };\n}\n\nexport function NestedSceneRenderer({ model }: SceneComponentProps<NestedScene>) {\n const { title, isCollapsed, canCollapse, canRemove, body, actions } = model.useState();\n const styles = useStyles2(getStyles);\n\n const toolbarActions = (actions ?? []).map((action) => <action.Component key={action.state.key} model={action} />);\n\n if (canRemove) {\n toolbarActions.push(\n <ToolbarButton\n icon=\"times\"\n variant={'default'}\n onClick={model.onRemove}\n key=\"remove-button\"\n aria-label=\"Remove scene\"\n />\n );\n }\n\n return (\n <div className={styles.row}>\n <div className={styles.rowHeader}>\n <Stack gap={0}>\n <div className={styles.title} role=\"heading\" aria-level={1}>\n {title}\n </div>\n {canCollapse && (\n <div className={styles.toggle}>\n <Button\n size=\"sm\"\n icon={isCollapsed ? 'angle-down' : 'angle-up'}\n fill=\"text\"\n variant=\"secondary\"\n aria-label={isCollapsed ? 'Expand scene' : 'Collapse scene'}\n onClick={model.onToggle}\n />\n </div>\n )}\n </Stack>\n <div className={styles.actions}>{toolbarActions}</div>\n </div>\n {!isCollapsed && <body.Component model={body} />}\n </div>\n );\n}\n\nconst getStyles = (theme: GrafanaTheme2) => ({\n row: css({\n display: 'flex',\n flexDirection: 'column',\n flexGrow: 1,\n gap: theme.spacing(1),\n cursor: 'pointer',\n }),\n toggle: css({}),\n title: css({\n fontSize: theme.typography.h5.fontSize,\n }),\n rowHeader: css({\n display: 'flex',\n alignItems: 'center',\n gap: theme.spacing(2),\n }),\n actions: css({\n display: 'flex',\n alignItems: 'center',\n gap: theme.spacing(1),\n justifyContent: 'flex-end',\n flexGrow: 1,\n }),\n});\n\nfunction isSceneLayoutItem(x: SceneObject): x is SceneObject<SceneObjectState & { body: SceneObject | undefined }> {\n return 'body' in x.state;\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Switch, Route } from 'react-router-dom';
|
|
3
3
|
import { SceneObjectBase } from '../../core/SceneObjectBase.js';
|
|
4
|
+
import { renderSceneComponentWithRouteProps } from './utils.js';
|
|
4
5
|
|
|
5
6
|
class SceneApp extends SceneObjectBase {
|
|
6
7
|
}
|
|
@@ -10,11 +11,7 @@ SceneApp.Component = ({ model }) => {
|
|
|
10
11
|
key: page.state.url,
|
|
11
12
|
exact: false,
|
|
12
13
|
path: page.state.url,
|
|
13
|
-
render: () =>
|
|
14
|
-
return page && /* @__PURE__ */ React.createElement(page.Component, {
|
|
15
|
-
model: page
|
|
16
|
-
});
|
|
17
|
-
}
|
|
14
|
+
render: (props) => renderSceneComponentWithRouteProps(page, props)
|
|
18
15
|
})));
|
|
19
16
|
};
|
|
20
17
|
|
|
@@ -1 +1 @@
|
|
|
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={() =>
|
|
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';\nimport { renderSceneComponentWithRouteProps } from './utils';\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={(props) => renderSceneComponentWithRouteProps(page, props)}\n ></Route>\n ))}\n </Switch>\n );\n };\n}\n"],"names":[],"mappings":";;;;;AAWO,MAAM,iBAAiB,eAA+B,CAAA;AAiB7D,CAAA;AAjBa,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,MAAQ,EAAA,CAAC,KAAU,KAAA,kCAAA,CAAmC,MAAM,KAAK,CAAA;AAAA,GAClE,CACF,CACH,CAAA,CAAA;AAEJ,CAAA;;;;"}
|
|
@@ -1,49 +1,92 @@
|
|
|
1
|
-
import React
|
|
2
|
-
import {
|
|
3
|
-
import { Route, Switch, useRouteMatch } from 'react-router-dom';
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Route, Switch } from 'react-router-dom';
|
|
4
3
|
import { SceneObjectBase } from '../../core/SceneObjectBase.js';
|
|
5
|
-
import {
|
|
4
|
+
import { getUrlSyncManager } from '../../services/UrlSyncManager.js';
|
|
5
|
+
import { EmbeddedScene } from '../EmbeddedScene.js';
|
|
6
|
+
import { SceneFlexLayout, SceneFlexItem } from '../layout/SceneFlexLayout.js';
|
|
7
|
+
import { SceneReactObject } from '../SceneReactObject.js';
|
|
8
|
+
import { SceneAppDrilldownViewRender, SceneAppPageView } from './SceneAppPageView.js';
|
|
9
|
+
import { renderSceneComponentWithRouteProps } from './utils.js';
|
|
6
10
|
|
|
7
|
-
const sceneCache = /* @__PURE__ */ new Map();
|
|
8
11
|
class SceneAppPage extends SceneObjectBase {
|
|
12
|
+
constructor(state) {
|
|
13
|
+
super(state);
|
|
14
|
+
this._sceneCache = /* @__PURE__ */ new Map();
|
|
15
|
+
this._drilldownCache = /* @__PURE__ */ new Map();
|
|
16
|
+
this.addActivationHandler(() => {
|
|
17
|
+
return () => getUrlSyncManager().cleanUp(this);
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
initializeScene(scene) {
|
|
21
|
+
this.setState({ initializedScene: scene });
|
|
22
|
+
getUrlSyncManager().initSync(this);
|
|
23
|
+
}
|
|
24
|
+
getScene(routeMatch) {
|
|
25
|
+
let scene = this._sceneCache.get(routeMatch.url);
|
|
26
|
+
if (scene) {
|
|
27
|
+
return scene;
|
|
28
|
+
}
|
|
29
|
+
if (!this.state.getScene) {
|
|
30
|
+
throw new Error("Missing getScene on SceneAppPage " + this.state.title);
|
|
31
|
+
}
|
|
32
|
+
scene = this.state.getScene(routeMatch);
|
|
33
|
+
this._sceneCache.set(routeMatch.url, scene);
|
|
34
|
+
return scene;
|
|
35
|
+
}
|
|
36
|
+
getDrilldownPage(drilldown, routeMatch) {
|
|
37
|
+
let page = this._drilldownCache.get(routeMatch.url);
|
|
38
|
+
if (page) {
|
|
39
|
+
return page;
|
|
40
|
+
}
|
|
41
|
+
page = drilldown.getPage(routeMatch, this);
|
|
42
|
+
this._drilldownCache.set(routeMatch.url, page);
|
|
43
|
+
return page;
|
|
44
|
+
}
|
|
9
45
|
}
|
|
10
46
|
SceneAppPage.Component = SceneAppPageRenderer;
|
|
11
|
-
function SceneAppPageRenderer({ model }) {
|
|
12
|
-
var _a;
|
|
13
|
-
const { tabs, drilldowns
|
|
47
|
+
function SceneAppPageRenderer({ model, routeProps }) {
|
|
48
|
+
var _a, _b;
|
|
49
|
+
const { tabs, drilldowns } = model.useState();
|
|
14
50
|
const routes = [];
|
|
15
|
-
if (tabs) {
|
|
16
|
-
for (
|
|
51
|
+
if (tabs && tabs.length > 0) {
|
|
52
|
+
for (let tabIndex = 0; tabIndex < tabs.length; tabIndex++) {
|
|
53
|
+
const tab = tabs[tabIndex];
|
|
54
|
+
if (tabIndex === 0) {
|
|
55
|
+
routes.push(
|
|
56
|
+
/* @__PURE__ */ React.createElement(Route, {
|
|
57
|
+
exact: true,
|
|
58
|
+
key: model.state.url,
|
|
59
|
+
path: (_a = model.state.routePath) != null ? _a : model.state.url,
|
|
60
|
+
render: (props) => renderSceneComponentWithRouteProps(tab, props)
|
|
61
|
+
})
|
|
62
|
+
);
|
|
63
|
+
}
|
|
17
64
|
routes.push(
|
|
18
65
|
/* @__PURE__ */ React.createElement(Route, {
|
|
19
66
|
exact: true,
|
|
20
|
-
key:
|
|
21
|
-
path: (
|
|
22
|
-
render: () =>
|
|
23
|
-
return /* @__PURE__ */ React.createElement(page2.Component, {
|
|
24
|
-
model: page2
|
|
25
|
-
});
|
|
26
|
-
}
|
|
67
|
+
key: tab.state.url,
|
|
68
|
+
path: (_b = tab.state.routePath) != null ? _b : tab.state.url,
|
|
69
|
+
render: (props) => renderSceneComponentWithRouteProps(tab, props)
|
|
27
70
|
})
|
|
28
71
|
);
|
|
29
|
-
if (
|
|
30
|
-
for (const drilldown of
|
|
72
|
+
if (tab.state.drilldowns) {
|
|
73
|
+
for (const drilldown of tab.state.drilldowns) {
|
|
31
74
|
routes.push(
|
|
32
75
|
/* @__PURE__ */ React.createElement(Route, {
|
|
33
76
|
exact: false,
|
|
34
77
|
key: drilldown.routePath,
|
|
35
78
|
path: drilldown.routePath,
|
|
36
|
-
render: () => {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
79
|
+
render: (props) => /* @__PURE__ */ React.createElement(SceneAppDrilldownViewRender, {
|
|
80
|
+
drilldown,
|
|
81
|
+
parent: tab,
|
|
82
|
+
routeProps: props
|
|
83
|
+
})
|
|
42
84
|
})
|
|
43
85
|
);
|
|
44
86
|
}
|
|
45
87
|
}
|
|
46
88
|
}
|
|
89
|
+
routes.push(getFallbackRoute(model, routeProps));
|
|
47
90
|
return /* @__PURE__ */ React.createElement(Switch, null, routes);
|
|
48
91
|
}
|
|
49
92
|
if (drilldowns) {
|
|
@@ -53,99 +96,74 @@ function SceneAppPageRenderer({ model }) {
|
|
|
53
96
|
key: drilldown.routePath,
|
|
54
97
|
exact: false,
|
|
55
98
|
path: drilldown.routePath,
|
|
56
|
-
render: () => {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
99
|
+
render: (props) => /* @__PURE__ */ React.createElement(SceneAppDrilldownViewRender, {
|
|
100
|
+
drilldown,
|
|
101
|
+
parent: model,
|
|
102
|
+
routeProps: props
|
|
103
|
+
})
|
|
62
104
|
})
|
|
63
105
|
);
|
|
64
106
|
}
|
|
65
107
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
page = /* @__PURE__ */ React.createElement(ScenePageRenderer, {
|
|
71
|
-
page: model.parent,
|
|
72
|
-
activeTab: model,
|
|
73
|
-
tabs: model.parent.state.tabs
|
|
108
|
+
if (isCurrentPageRouteMatch(model, routeProps.match)) {
|
|
109
|
+
return /* @__PURE__ */ React.createElement(SceneAppPageView, {
|
|
110
|
+
page: model,
|
|
111
|
+
routeProps
|
|
74
112
|
});
|
|
75
113
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
114
|
+
routes.push(getFallbackRoute(model, routeProps));
|
|
115
|
+
return /* @__PURE__ */ React.createElement(Switch, null, routes);
|
|
116
|
+
}
|
|
117
|
+
function getFallbackRoute(page, routeProps) {
|
|
118
|
+
return /* @__PURE__ */ React.createElement(Route, {
|
|
119
|
+
key: "fallback route",
|
|
120
|
+
render: (props) => {
|
|
121
|
+
const fallbackPage = getDefaultFallbackPage();
|
|
122
|
+
return /* @__PURE__ */ React.createElement(SceneAppPageView, {
|
|
123
|
+
page: fallbackPage,
|
|
124
|
+
routeProps
|
|
125
|
+
});
|
|
82
126
|
}
|
|
83
|
-
})
|
|
127
|
+
});
|
|
84
128
|
}
|
|
85
|
-
function
|
|
86
|
-
|
|
87
|
-
|
|
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);
|
|
129
|
+
function isCurrentPageRouteMatch(page, match) {
|
|
130
|
+
if (!match.isExact) {
|
|
131
|
+
return false;
|
|
93
132
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
scene.initUrlSync();
|
|
97
|
-
setIsInitialized(true);
|
|
98
|
-
}
|
|
99
|
-
}, [isInitialized, scene]);
|
|
100
|
-
if (!isInitialized) {
|
|
101
|
-
return null;
|
|
133
|
+
if (match.url === page.state.url) {
|
|
134
|
+
return true;
|
|
102
135
|
}
|
|
103
|
-
|
|
104
|
-
|
|
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
|
-
});
|
|
136
|
+
if (page.parent instanceof SceneAppPage && page.parent.state.tabs[0] === page && page.parent.state.url === match.url) {
|
|
137
|
+
return true;
|
|
121
138
|
}
|
|
122
|
-
return
|
|
123
|
-
pageNav
|
|
124
|
-
}, /* @__PURE__ */ React.createElement(scene.Component, {
|
|
125
|
-
model: scene
|
|
126
|
-
}));
|
|
139
|
+
return false;
|
|
127
140
|
}
|
|
128
|
-
function
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
141
|
+
function getDefaultFallbackPage() {
|
|
142
|
+
return new SceneAppPage({
|
|
143
|
+
url: "",
|
|
144
|
+
title: "Not found",
|
|
145
|
+
subTitle: "The url did not match any page",
|
|
146
|
+
getScene: () => {
|
|
147
|
+
return new EmbeddedScene({
|
|
148
|
+
body: new SceneFlexLayout({
|
|
149
|
+
direction: "column",
|
|
150
|
+
children: [
|
|
151
|
+
new SceneFlexItem({
|
|
152
|
+
flexGrow: 1,
|
|
153
|
+
body: new SceneReactObject({
|
|
154
|
+
component: () => {
|
|
155
|
+
return /* @__PURE__ */ React.createElement("div", {
|
|
156
|
+
"data-testid": "default-fallback-content"
|
|
157
|
+
}, "If you found your way here using a link then there might be a bug in this application.");
|
|
158
|
+
}
|
|
159
|
+
})
|
|
160
|
+
})
|
|
161
|
+
]
|
|
162
|
+
})
|
|
163
|
+
});
|
|
164
|
+
}
|
|
133
165
|
});
|
|
134
166
|
}
|
|
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
167
|
|
|
150
168
|
export { SceneAppPage };
|
|
151
169
|
//# sourceMappingURL=SceneAppPage.js.map
|
|
@@ -1 +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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"}
|
|
1
|
+
{"version":3,"file":"SceneAppPage.js","sources":["../../../../src/components/SceneApp/SceneAppPage.tsx"],"sourcesContent":["import React from 'react';\nimport { Route, RouteComponentProps, Switch } from 'react-router-dom';\nimport { SceneObjectBase } from '../../core/SceneObjectBase';\nimport { SceneComponentProps } from '../../core/types';\nimport { getUrlSyncManager } from '../../services/UrlSyncManager';\nimport { EmbeddedScene } from '../EmbeddedScene';\nimport { SceneFlexItem, SceneFlexLayout } from '../layout/SceneFlexLayout';\nimport { SceneReactObject } from '../SceneReactObject';\nimport { SceneAppDrilldownViewRender, SceneAppPageView } from './SceneAppPageView';\nimport { SceneAppDrilldownView, SceneAppPageLike, SceneAppPageState, SceneRouteMatch } from './types';\nimport { renderSceneComponentWithRouteProps } from './utils';\n\n/**\n * Responsible for page's drilldown & tabs routing\n */\nexport class SceneAppPage extends SceneObjectBase<SceneAppPageState> implements SceneAppPageLike {\n public static Component = SceneAppPageRenderer;\n private _sceneCache = new Map<string, EmbeddedScene>();\n private _drilldownCache = new Map<string, SceneAppPageLike>();\n\n public constructor(state: SceneAppPageState) {\n super(state);\n\n this.addActivationHandler(() => {\n return () => getUrlSyncManager().cleanUp(this);\n });\n }\n\n public initializeScene(scene: EmbeddedScene) {\n this.setState({ initializedScene: scene });\n getUrlSyncManager().initSync(this);\n }\n\n public getScene(routeMatch: SceneRouteMatch): EmbeddedScene {\n let scene = this._sceneCache.get(routeMatch.url);\n\n if (scene) {\n return scene;\n }\n\n if (!this.state.getScene) {\n throw new Error('Missing getScene on SceneAppPage ' + this.state.title);\n }\n\n scene = this.state.getScene(routeMatch);\n this._sceneCache.set(routeMatch.url, scene);\n\n return scene;\n }\n\n public getDrilldownPage(drilldown: SceneAppDrilldownView, routeMatch: SceneRouteMatch<{}>): SceneAppPageLike {\n let page = this._drilldownCache.get(routeMatch!.url);\n if (page) {\n return page;\n }\n\n page = drilldown.getPage(routeMatch, this);\n this._drilldownCache.set(routeMatch!.url, page);\n\n return page;\n }\n}\n\nexport interface SceneAppPageRendererProps extends SceneComponentProps<SceneAppPage> {\n routeProps: RouteComponentProps;\n}\n\nfunction SceneAppPageRenderer({ model, routeProps }: SceneAppPageRendererProps) {\n const { tabs, drilldowns } = model.useState();\n const routes: React.ReactNode[] = [];\n\n if (tabs && tabs.length > 0) {\n for (let tabIndex = 0; tabIndex < tabs.length; tabIndex++) {\n const tab = tabs[tabIndex];\n\n // Add first tab as a default route, this makes it possible for the first tab to render with the url of the parent page\n if (tabIndex === 0) {\n routes.push(\n <Route\n exact={true}\n key={model.state.url}\n path={model.state.routePath ?? model.state.url}\n render={(props) => renderSceneComponentWithRouteProps(tab, props)}\n ></Route>\n );\n }\n\n routes.push(\n <Route\n exact={true}\n key={tab.state.url}\n path={tab.state.routePath ?? tab.state.url}\n render={(props) => renderSceneComponentWithRouteProps(tab, props)}\n ></Route>\n );\n\n if (tab.state.drilldowns) {\n for (const drilldown of tab.state.drilldowns) {\n routes.push(\n <Route\n exact={false}\n key={drilldown.routePath}\n path={drilldown.routePath}\n render={(props) => <SceneAppDrilldownViewRender drilldown={drilldown} parent={tab} routeProps={props} />}\n ></Route>\n );\n }\n }\n }\n\n routes.push(getFallbackRoute(model, routeProps));\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={(props) => <SceneAppDrilldownViewRender drilldown={drilldown} parent={model} routeProps={props} />}\n ></Route>\n );\n }\n }\n\n if (isCurrentPageRouteMatch(model, routeProps.match)) {\n return <SceneAppPageView page={model} routeProps={routeProps} />;\n }\n\n routes.push(getFallbackRoute(model, routeProps));\n\n return <Switch>{routes}</Switch>;\n}\n\nfunction getFallbackRoute(page: SceneAppPage, routeProps: RouteComponentProps) {\n return (\n <Route\n key={'fallback route'}\n render={(props) => {\n const fallbackPage = getDefaultFallbackPage();\n return <SceneAppPageView page={fallbackPage} routeProps={routeProps} />;\n }}\n ></Route>\n );\n}\n\nfunction isCurrentPageRouteMatch(page: SceneAppPage, match: SceneRouteMatch) {\n if (!match.isExact) {\n return false;\n }\n\n // current page matches the route url\n if (match.url === page.state.url) {\n return true;\n }\n\n // check if we are a tab and the first tab, then we should also render on the parent url\n if (\n page.parent instanceof SceneAppPage &&\n page.parent.state.tabs![0] === page &&\n page.parent.state.url === match.url\n ) {\n return true;\n }\n\n return false;\n}\n\nfunction getDefaultFallbackPage() {\n return new SceneAppPage({\n url: '',\n title: 'Not found',\n subTitle: 'The url did not match any page',\n getScene: () => {\n return new EmbeddedScene({\n body: new SceneFlexLayout({\n direction: 'column',\n children: [\n new SceneFlexItem({\n flexGrow: 1,\n body: new SceneReactObject({\n component: () => {\n return (\n <div data-testid=\"default-fallback-content\">\n If you found your way here using a link then there might be a bug in this application.\n </div>\n );\n },\n }),\n }),\n ],\n }),\n });\n },\n });\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { PluginPage } from '@grafana/runtime';
|
|
2
|
+
import React, { useState, useLayoutEffect } from 'react';
|
|
3
|
+
import { SceneAppPage } from './SceneAppPage.js';
|
|
4
|
+
import { useAppQueryParams, getLinkUrlWithAppUrlState, renderSceneComponentWithRouteProps } from './utils.js';
|
|
5
|
+
|
|
6
|
+
function SceneAppPageView({ page, routeProps }) {
|
|
7
|
+
const containerPage = getParentPageIfTab(page);
|
|
8
|
+
const containerState = containerPage.useState();
|
|
9
|
+
const params = useAppQueryParams();
|
|
10
|
+
const scene = page.getScene(routeProps.match);
|
|
11
|
+
const [initialized, setInitialized] = useState(false);
|
|
12
|
+
useLayoutEffect(() => {
|
|
13
|
+
if (!initialized) {
|
|
14
|
+
containerPage.initializeScene(scene);
|
|
15
|
+
setInitialized(true);
|
|
16
|
+
}
|
|
17
|
+
}, [initialized, scene, containerPage]);
|
|
18
|
+
if (!initialized) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
const pageNav = {
|
|
22
|
+
text: containerState.title,
|
|
23
|
+
subTitle: containerState.subTitle,
|
|
24
|
+
img: containerState.titleImg,
|
|
25
|
+
icon: containerState.titleIcon,
|
|
26
|
+
url: getLinkUrlWithAppUrlState(containerState.url, params, containerState.preserveUrlKeys),
|
|
27
|
+
hideFromBreadcrumbs: containerState.hideFromBreadcrumbs,
|
|
28
|
+
parentItem: getParentBreadcrumbs(
|
|
29
|
+
containerState.getParentPage ? containerState.getParentPage() : page.parent,
|
|
30
|
+
params
|
|
31
|
+
)
|
|
32
|
+
};
|
|
33
|
+
if (containerState.tabs) {
|
|
34
|
+
pageNav.children = containerState.tabs.map((tab) => {
|
|
35
|
+
return {
|
|
36
|
+
text: tab.state.title,
|
|
37
|
+
active: page === tab,
|
|
38
|
+
url: getLinkUrlWithAppUrlState(tab.state.url, params, tab.state.preserveUrlKeys),
|
|
39
|
+
parentItem: pageNav
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
let pageActions = void 0;
|
|
44
|
+
if (containerState.controls) {
|
|
45
|
+
pageActions = containerState.controls.map((control) => /* @__PURE__ */ React.createElement(control.Component, {
|
|
46
|
+
model: control,
|
|
47
|
+
key: control.state.key
|
|
48
|
+
}));
|
|
49
|
+
}
|
|
50
|
+
return /* @__PURE__ */ React.createElement(PluginPage, {
|
|
51
|
+
pageNav,
|
|
52
|
+
actions: pageActions
|
|
53
|
+
}, /* @__PURE__ */ React.createElement(scene.Component, {
|
|
54
|
+
model: scene
|
|
55
|
+
}));
|
|
56
|
+
}
|
|
57
|
+
function getParentPageIfTab(page) {
|
|
58
|
+
if (page.parent instanceof SceneAppPage) {
|
|
59
|
+
return page.parent;
|
|
60
|
+
}
|
|
61
|
+
return page;
|
|
62
|
+
}
|
|
63
|
+
function getParentBreadcrumbs(parent, params) {
|
|
64
|
+
if (parent instanceof SceneAppPage) {
|
|
65
|
+
return {
|
|
66
|
+
text: parent.state.title,
|
|
67
|
+
url: getLinkUrlWithAppUrlState(parent.state.url, params, parent.state.preserveUrlKeys),
|
|
68
|
+
hideFromBreadcrumbs: parent.state.hideFromBreadcrumbs,
|
|
69
|
+
parentItem: getParentBreadcrumbs(
|
|
70
|
+
parent.state.getParentPage ? parent.state.getParentPage() : parent.parent,
|
|
71
|
+
params
|
|
72
|
+
)
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
return void 0;
|
|
76
|
+
}
|
|
77
|
+
function SceneAppDrilldownViewRender({ drilldown, parent, routeProps }) {
|
|
78
|
+
return renderSceneComponentWithRouteProps(parent.getDrilldownPage(drilldown, routeProps.match), routeProps);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export { SceneAppDrilldownViewRender, SceneAppPageView };
|
|
82
|
+
//# sourceMappingURL=SceneAppPageView.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SceneAppPageView.js","sources":["../../../../src/components/SceneApp/SceneAppPageView.tsx"],"sourcesContent":["import { NavModelItem, UrlQueryMap } from '@grafana/data';\nimport { PluginPage } from '@grafana/runtime';\nimport React, { useLayoutEffect, useState } from 'react';\n\nimport { RouteComponentProps } from 'react-router-dom';\nimport { SceneObject } from '../../core/types';\nimport { SceneAppPage } from './SceneAppPage';\nimport { SceneAppDrilldownView, SceneAppPageLike } from './types';\nimport { getLinkUrlWithAppUrlState, renderSceneComponentWithRouteProps, useAppQueryParams } from './utils';\n\nexport interface Props {\n page: SceneAppPageLike;\n // activeTab?: SceneAppPageLike;\n routeProps: RouteComponentProps;\n}\n\nexport function SceneAppPageView({ page, routeProps }: Props) {\n const containerPage = getParentPageIfTab(page);\n const containerState = containerPage.useState();\n const params = useAppQueryParams();\n const scene = page.getScene(routeProps.match);\n const [initialized, setInitialized] = useState(false);\n\n useLayoutEffect(() => {\n // Before rendering scene components, we are making sure the URL sync is enabled for.\n if (!initialized) {\n containerPage.initializeScene(scene);\n setInitialized(true);\n }\n }, [initialized, scene, containerPage]);\n\n if (!initialized) {\n return null;\n }\n\n const pageNav: NavModelItem = {\n text: containerState.title,\n subTitle: containerState.subTitle,\n img: containerState.titleImg,\n icon: containerState.titleIcon,\n url: getLinkUrlWithAppUrlState(containerState.url, params, containerState.preserveUrlKeys),\n hideFromBreadcrumbs: containerState.hideFromBreadcrumbs,\n parentItem: getParentBreadcrumbs(\n containerState.getParentPage ? containerState.getParentPage() : page.parent,\n params\n ),\n };\n\n if (containerState.tabs) {\n pageNav.children = containerState.tabs.map((tab) => {\n return {\n text: tab.state.title,\n active: page === tab,\n url: getLinkUrlWithAppUrlState(tab.state.url, params, tab.state.preserveUrlKeys),\n parentItem: pageNav,\n };\n });\n }\n\n let pageActions: React.ReactNode = undefined;\n if (containerState.controls) {\n pageActions = containerState.controls.map((control) => (\n <control.Component model={control} key={control.state.key} />\n ));\n }\n\n return (\n <PluginPage pageNav={pageNav} actions={pageActions}>\n <scene.Component model={scene} />\n </PluginPage>\n );\n}\n\n/**\n * For pages that are \"tabs\" this will return the parent page\n */\nfunction getParentPageIfTab(page: SceneAppPageLike) {\n if (page.parent instanceof SceneAppPage) {\n return page.parent;\n }\n\n return page;\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\nexport interface SceneAppDrilldownViewRenderProps {\n drilldown: SceneAppDrilldownView;\n parent: SceneAppPageLike;\n routeProps: RouteComponentProps;\n}\n\nexport function SceneAppDrilldownViewRender({ drilldown, parent, routeProps }: SceneAppDrilldownViewRenderProps) {\n return renderSceneComponentWithRouteProps(parent.getDrilldownPage(drilldown, routeProps.match), routeProps);\n}\n"],"names":[],"mappings":"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"}
|