Scopes: Replace scopes bridge with scopes variable (#105399)
This commit is contained in:
+2
-2
@@ -284,8 +284,8 @@
|
||||
"@grafana/plugin-ui": "0.10.5",
|
||||
"@grafana/prometheus": "workspace:*",
|
||||
"@grafana/runtime": "workspace:*",
|
||||
"@grafana/scenes": "6.10.4",
|
||||
"@grafana/scenes-react": "6.10.4",
|
||||
"@grafana/scenes": "^6.12.0",
|
||||
"@grafana/scenes-react": "^6.12.0",
|
||||
"@grafana/schema": "workspace:*",
|
||||
"@grafana/sql": "workspace:*",
|
||||
"@grafana/ui": "workspace:*",
|
||||
|
||||
+3
@@ -144,6 +144,9 @@ const dashboard = {
|
||||
to: 'now',
|
||||
},
|
||||
timepicker: { refresh_intervals: ['5s', '30s', '1m'] },
|
||||
templating: {
|
||||
list: [],
|
||||
},
|
||||
meta: {
|
||||
canSave: true,
|
||||
folderId: 1,
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
sceneGraph,
|
||||
SceneObjectBase,
|
||||
SceneObjectState,
|
||||
SceneScopesBridge,
|
||||
SceneTimeRangeLike,
|
||||
VariableDependencyConfig,
|
||||
} from '@grafana/scenes';
|
||||
@@ -22,7 +21,6 @@ export interface DashboardReloadBehaviorState extends SceneObjectState {
|
||||
|
||||
export class DashboardReloadBehavior extends SceneObjectBase<DashboardReloadBehaviorState> {
|
||||
private _timeRange: SceneTimeRangeLike | undefined;
|
||||
private _scopesBridge: SceneScopesBridge | undefined;
|
||||
private _dashboardScene: DashboardScene | undefined;
|
||||
|
||||
constructor(state: DashboardReloadBehaviorState) {
|
||||
@@ -40,17 +38,11 @@ export class DashboardReloadBehavior extends SceneObjectBase<DashboardReloadBeha
|
||||
}
|
||||
|
||||
this._timeRange = sceneGraph.getTimeRange(this);
|
||||
this._scopesBridge = sceneGraph.getScopesBridge(this);
|
||||
this._dashboardScene = sceneGraph.getAncestor(this, DashboardScene);
|
||||
|
||||
this._variableDependency = new VariableDependencyConfig(this, {
|
||||
onAnyVariableChanged: this.reloadDashboard,
|
||||
});
|
||||
|
||||
this._scopesBridge?.subscribeToValue(() => {
|
||||
if (shouldReload) {
|
||||
this.reloadDashboard();
|
||||
}
|
||||
dependsOnScopes: true,
|
||||
});
|
||||
|
||||
this._subs.add(
|
||||
@@ -82,9 +74,11 @@ export class DashboardReloadBehavior extends SceneObjectBase<DashboardReloadBeha
|
||||
|
||||
// This is wrapped in setTimeout in order to allow variables and scopes to be set in the URL before actually reloading the dashboard
|
||||
setTimeout(() => {
|
||||
const scopes = sceneGraph.getScopes(this) ?? [];
|
||||
|
||||
getDashboardScenePageStateManager().reloadDashboard({
|
||||
version: this.state.version!,
|
||||
scopes: this._scopesBridge?.getValue().map((scope) => scope.metadata.name) ?? [],
|
||||
scopes: scopes.map((scope) => scope.metadata.name),
|
||||
// We're not using the getUrlState from timeRange since it makes more sense to pass the absolute timestamps as opposed to relative time
|
||||
timeRange: {
|
||||
from: this._timeRange!.state.value.from.toISOString(),
|
||||
|
||||
@@ -8,7 +8,6 @@ import {
|
||||
SceneObjectBase,
|
||||
SceneObjectRef,
|
||||
SceneObjectState,
|
||||
SceneScopesBridge,
|
||||
SceneTimeRange,
|
||||
sceneUtils,
|
||||
SceneVariable,
|
||||
@@ -142,7 +141,6 @@ export interface DashboardSceneState extends SceneObjectState {
|
||||
panelsPerRow?: number;
|
||||
/** options pane */
|
||||
editPane: DashboardEditPane;
|
||||
scopesBridge: SceneScopesBridge | undefined;
|
||||
/** Manages dragging/dropping of layout items */
|
||||
layoutOrchestrator?: DashboardLayoutOrchestrator;
|
||||
}
|
||||
@@ -199,7 +197,6 @@ export class DashboardScene extends SceneObjectBase<DashboardSceneState> impleme
|
||||
links: state.links ?? [],
|
||||
...state,
|
||||
editPane: new DashboardEditPane(),
|
||||
scopesBridge: config.featureToggles.scopeFilters ? new SceneScopesBridge({}) : undefined,
|
||||
layoutOrchestrator: new DashboardLayoutOrchestrator(),
|
||||
});
|
||||
|
||||
@@ -212,8 +209,6 @@ export class DashboardScene extends SceneObjectBase<DashboardSceneState> impleme
|
||||
}
|
||||
|
||||
private _activationHandler() {
|
||||
this.state.scopesBridge?.setEnabled(true);
|
||||
|
||||
let prevSceneContext = window.__grafanaSceneContext;
|
||||
const isNew = locationService.getLocation().pathname === '/dashboard/new';
|
||||
|
||||
@@ -222,7 +217,6 @@ export class DashboardScene extends SceneObjectBase<DashboardSceneState> impleme
|
||||
this._initializePanelSearch();
|
||||
|
||||
if (this.state.isEditing) {
|
||||
this.state.scopesBridge?.setReadOnly(true);
|
||||
this._initialUrlState = locationService.getLocation();
|
||||
this._changeTracker.startTrackingChanges();
|
||||
}
|
||||
@@ -247,8 +241,6 @@ export class DashboardScene extends SceneObjectBase<DashboardSceneState> impleme
|
||||
|
||||
// Deactivation logic
|
||||
return () => {
|
||||
this.state.scopesBridge?.setReadOnly(false);
|
||||
this.state.scopesBridge?.setEnabled(false);
|
||||
window.__grafanaSceneContext = prevSceneContext;
|
||||
clearKeyBindings();
|
||||
this._changeTracker.terminate();
|
||||
@@ -281,9 +273,6 @@ export class DashboardScene extends SceneObjectBase<DashboardSceneState> impleme
|
||||
// Propagate change edit mode change to children
|
||||
this.state.body.editModeChanged?.(true);
|
||||
|
||||
// Propagate edit mode to scopes
|
||||
this.state.scopesBridge?.setReadOnly(true);
|
||||
|
||||
this._changeTracker.startTrackingChanges();
|
||||
};
|
||||
|
||||
@@ -324,7 +313,6 @@ export class DashboardScene extends SceneObjectBase<DashboardSceneState> impleme
|
||||
|
||||
if (!this.state.isDirty || skipConfirm) {
|
||||
this.exitEditModeConfirmed(restoreInitialState || this.state.isDirty);
|
||||
this.state.scopesBridge?.setReadOnly(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -336,7 +324,6 @@ export class DashboardScene extends SceneObjectBase<DashboardSceneState> impleme
|
||||
yesText: 'Discard',
|
||||
onConfirm: () => {
|
||||
this.exitEditModeConfirmed();
|
||||
this.state.scopesBridge?.setReadOnly(false);
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import { useContext, useEffect, useMemo } from 'react';
|
||||
import { useLocation, useParams } from 'react-router-dom-v5-compat';
|
||||
|
||||
import { PageLayoutType } from '@grafana/data';
|
||||
import { ScopesContext } from '@grafana/runtime';
|
||||
import { SceneComponentProps } from '@grafana/scenes';
|
||||
import { Page } from 'app/core/components/Page/Page';
|
||||
import { getNavModel } from 'app/core/selectors/navModel';
|
||||
@@ -22,11 +23,11 @@ export function DashboardSceneRenderer({ model }: SceneComponentProps<DashboardS
|
||||
panelSearch,
|
||||
panelsPerRow,
|
||||
isEditing,
|
||||
scopesBridge,
|
||||
layoutOrchestrator,
|
||||
} = model.useState();
|
||||
const { type } = useParams();
|
||||
const location = useLocation();
|
||||
const scopesContext = useContext(ScopesContext);
|
||||
const navIndex = useSelector((state) => state.navIndex);
|
||||
const pageNav = model.getPageNav(location, navIndex);
|
||||
const bodyToRender = model.getBodyToRender();
|
||||
@@ -47,10 +48,21 @@ export function DashboardSceneRenderer({ model }: SceneComponentProps<DashboardS
|
||||
}
|
||||
}, [isSettingsOpen, editPanel, viewPanelScene, model]);
|
||||
|
||||
useEffect(() => {
|
||||
if (scopesContext && isEditing) {
|
||||
scopesContext.setReadOnly(true);
|
||||
|
||||
return () => {
|
||||
scopesContext.setReadOnly(false);
|
||||
};
|
||||
}
|
||||
|
||||
return;
|
||||
}, [scopesContext, isEditing]);
|
||||
|
||||
if (editview) {
|
||||
return (
|
||||
<>
|
||||
{scopesBridge && <scopesBridge.Component model={scopesBridge} />}
|
||||
<editview.Component model={editview} />
|
||||
{overlay && <overlay.Component model={overlay} />}
|
||||
</>
|
||||
@@ -69,7 +81,6 @@ export function DashboardSceneRenderer({ model }: SceneComponentProps<DashboardS
|
||||
<>
|
||||
{layoutOrchestrator && <layoutOrchestrator.Component model={layoutOrchestrator} />}
|
||||
<Page navModel={navModel} pageNav={pageNav} layout={PageLayoutType.Custom}>
|
||||
{scopesBridge && <scopesBridge.Component model={scopesBridge} />}
|
||||
{editPanel && <editPanel.Component model={editPanel} />}
|
||||
{!editPanel && (
|
||||
<DashboardEditPaneSplitter
|
||||
|
||||
@@ -141,8 +141,6 @@ export class DashboardSceneUrlSync implements SceneObjectUrlSyncHandler {
|
||||
this._scene.onEnterEditMode();
|
||||
}
|
||||
|
||||
this._scene.state.scopesBridge?.setReadOnly(true);
|
||||
|
||||
const libPanelBehavior = getLibraryPanelBehavior(panel);
|
||||
if (libPanelBehavior && !libPanelBehavior?.state.isLoaded) {
|
||||
this._waitForLibPanelToLoadBeforeEnteringPanelEdit(panel, libPanelBehavior);
|
||||
|
||||
@@ -29,6 +29,10 @@ export function VariableValueSelectWrapper({ variable }: VariableSelectProps) {
|
||||
const styles = useStyles2(getStyles);
|
||||
|
||||
if (state.hide === VariableHide.hideVariable) {
|
||||
if (variable.UNSAFE_renderAsHidden) {
|
||||
return <variable.Component model={variable} />;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
MultiValueVariable,
|
||||
SceneVariables,
|
||||
sceneUtils,
|
||||
SceneVariable,
|
||||
} from '@grafana/scenes';
|
||||
import {
|
||||
VariableModel,
|
||||
@@ -47,6 +48,7 @@ import {
|
||||
|
||||
export function sceneVariablesSetToVariables(set: SceneVariables, keepQueryOptions?: boolean) {
|
||||
const variables: VariableModel[] = [];
|
||||
|
||||
for (const variable of set.state.variables) {
|
||||
const commonProperties = {
|
||||
name: variable.state.name,
|
||||
@@ -191,6 +193,8 @@ export function sceneVariablesSetToVariables(set: SceneVariables, keepQueryOptio
|
||||
filters: validateFiltersOrigin(variable.state.filters),
|
||||
defaultKeys: variable.state.defaultKeys,
|
||||
});
|
||||
} else if (variable.state.type === 'system') {
|
||||
// Not persisted
|
||||
} else {
|
||||
throw new Error('Unsupported variable type');
|
||||
}
|
||||
@@ -435,6 +439,8 @@ export function sceneVariablesSetToSchemaV2Variables(
|
||||
},
|
||||
};
|
||||
variables.push(adhocVariable);
|
||||
} else if (variable.state.type === 'system') {
|
||||
// Do nothing
|
||||
} else {
|
||||
throw new Error('Unsupported variable type: ' + variable.state.type);
|
||||
}
|
||||
@@ -459,3 +465,7 @@ function validateFiltersOrigin(filters?: SceneAdHocFilterWithLabels[]): AdHocFil
|
||||
}) || []
|
||||
);
|
||||
}
|
||||
|
||||
export function isVariableEditable(variable: SceneVariable) {
|
||||
return variable.state.type !== 'system';
|
||||
}
|
||||
|
||||
+8
-10
@@ -15,6 +15,7 @@ import {
|
||||
SceneTimeRange,
|
||||
SceneVariable,
|
||||
SceneVariableSet,
|
||||
ScopesVariable,
|
||||
TextBoxVariable,
|
||||
} from '@grafana/scenes';
|
||||
import {
|
||||
@@ -227,17 +228,10 @@ export function transformSaveModelSchemaV2ToScene(dto: DashboardWithAccessInfo<D
|
||||
function getVariables(dashboard: DashboardV2Spec, isSnapshot: boolean): SceneVariableSet | undefined {
|
||||
let variables: SceneVariableSet | undefined;
|
||||
|
||||
if (dashboard.variables.length) {
|
||||
if (isSnapshot) {
|
||||
variables = createVariablesForSnapshot(dashboard);
|
||||
} else {
|
||||
variables = createVariablesForDashboard(dashboard);
|
||||
}
|
||||
if (isSnapshot) {
|
||||
variables = createVariablesForSnapshot(dashboard);
|
||||
} else {
|
||||
// Create empty variable set
|
||||
variables = new SceneVariableSet({
|
||||
variables: [],
|
||||
});
|
||||
variables = createVariablesForDashboard(dashboard);
|
||||
}
|
||||
|
||||
return variables;
|
||||
@@ -257,6 +251,10 @@ function createVariablesForDashboard(dashboard: DashboardV2Spec) {
|
||||
// Added temporarily to allow skipping non-compatible variables
|
||||
.filter((v): v is SceneVariable => Boolean(v));
|
||||
|
||||
if (config.featureToggles.scopeFilters) {
|
||||
variableObjects.push(new ScopesVariable({ enable: true }));
|
||||
}
|
||||
|
||||
return new SceneVariableSet({
|
||||
variables: variableObjects,
|
||||
});
|
||||
|
||||
@@ -181,17 +181,10 @@ export function createDashboardSceneFromDashboardModel(oldModel: DashboardModel,
|
||||
const uid = oldModel.uid;
|
||||
const serializerVersion = config.featureToggles.dashboardNewLayouts ? 'v2' : 'v1';
|
||||
|
||||
if (oldModel.templating?.list?.length) {
|
||||
if (oldModel.meta.isSnapshot) {
|
||||
variables = createVariablesForSnapshot(oldModel);
|
||||
} else {
|
||||
variables = createVariablesForDashboard(oldModel);
|
||||
}
|
||||
if (oldModel.meta.isSnapshot) {
|
||||
variables = createVariablesForSnapshot(oldModel);
|
||||
} else {
|
||||
// Create empty variable set
|
||||
variables = new SceneVariableSet({
|
||||
variables: [],
|
||||
});
|
||||
variables = createVariablesForDashboard(oldModel);
|
||||
}
|
||||
|
||||
if (oldModel.annotations?.list?.length && !oldModel.isSnapshot()) {
|
||||
|
||||
@@ -9,6 +9,7 @@ import { reportInteraction } from '@grafana/runtime';
|
||||
import { SceneVariable, SceneVariableState } from '@grafana/scenes';
|
||||
import { useStyles2, Stack, Button, EmptyState, TextLink } from '@grafana/ui';
|
||||
|
||||
import { isVariableEditable } from '../../serialization/sceneVariablesSetToVariables';
|
||||
import { VariablesDependenciesButton } from '../../variables/VariablesDependenciesButton';
|
||||
import { UsagesToNetwork, VariableUsageTree } from '../../variables/utils';
|
||||
|
||||
@@ -46,7 +47,9 @@ export function VariableEditorList({
|
||||
onChangeOrder(result.source.index, result.destination.index);
|
||||
};
|
||||
|
||||
return variables.length <= 0 ? (
|
||||
const editableVariables = variables.filter(isVariableEditable);
|
||||
|
||||
return editableVariables.length <= 0 ? (
|
||||
<EmptyVariablesList onAdd={onAdd} />
|
||||
) : (
|
||||
<Stack direction="column" gap={3}>
|
||||
@@ -71,6 +74,10 @@ export function VariableEditorList({
|
||||
{(provided) => (
|
||||
<tbody ref={provided.innerRef} {...provided.droppableProps}>
|
||||
{variables.map((variableScene, index) => {
|
||||
if (!isVariableEditable(variableScene)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const variableState = variableScene.state;
|
||||
return (
|
||||
<VariableEditorListRow
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
QueryVariable,
|
||||
SceneVariable,
|
||||
SceneVariableSet,
|
||||
ScopesVariable,
|
||||
TextBoxVariable,
|
||||
} from '@grafana/scenes';
|
||||
import { DashboardModel } from 'app/features/dashboard/state/DashboardModel';
|
||||
@@ -34,6 +35,10 @@ export function createVariablesForDashboard(oldModel: DashboardModel) {
|
||||
// Added temporarily to allow skipping non-compatible variables
|
||||
.filter((v): v is SceneVariable => Boolean(v));
|
||||
|
||||
if (config.featureToggles.scopeFilters) {
|
||||
variableObjects.push(new ScopesVariable({ enable: true }));
|
||||
}
|
||||
|
||||
return new SceneVariableSet({
|
||||
variables: variableObjects,
|
||||
});
|
||||
|
||||
@@ -197,7 +197,7 @@ export async function renderDashboard(
|
||||
</KBarProvider>
|
||||
);
|
||||
|
||||
await waitFor(() => expect(sceneGraph.getScopesBridge(scene)).toBeDefined());
|
||||
await waitFor(() => expect(sceneGraph.getScopes(scene)).toBeDefined());
|
||||
|
||||
return {
|
||||
scene,
|
||||
|
||||
@@ -3474,11 +3474,11 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@grafana/scenes-react@npm:6.10.4":
|
||||
version: 6.10.4
|
||||
resolution: "@grafana/scenes-react@npm:6.10.4"
|
||||
"@grafana/scenes-react@npm:^6.12.0":
|
||||
version: 6.12.0
|
||||
resolution: "@grafana/scenes-react@npm:6.12.0"
|
||||
dependencies:
|
||||
"@grafana/scenes": "npm:6.10.4"
|
||||
"@grafana/scenes": "npm:6.12.0"
|
||||
lru-cache: "npm:^10.2.2"
|
||||
react-use: "npm:^17.4.0"
|
||||
peerDependencies:
|
||||
@@ -3490,13 +3490,13 @@ __metadata:
|
||||
react: ^18.0.0
|
||||
react-dom: ^18.0.0
|
||||
react-router-dom: ^6.28.0
|
||||
checksum: 10/73aee4eca47a27e1fbb7a8f09ddf6a365b121cb361b01c7daabf698677f192c188de0dd64a424db4195139f625660f40371619abbb95a999e14c94e313e25755
|
||||
checksum: 10/56113394d169c96537a46ca5dc4c62eda54c6addd348c9e3321a122a6d01c19a14c57b04945ee3d836638f3dc1c1941f7647fa649495226432664e0ff8bd0af0
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@grafana/scenes@npm:6.10.4":
|
||||
version: 6.10.4
|
||||
resolution: "@grafana/scenes@npm:6.10.4"
|
||||
"@grafana/scenes@npm:6.12.0, @grafana/scenes@npm:^6.12.0":
|
||||
version: 6.12.0
|
||||
resolution: "@grafana/scenes@npm:6.12.0"
|
||||
dependencies:
|
||||
"@floating-ui/react": "npm:^0.26.16"
|
||||
"@leeoniya/ufuzzy": "npm:^1.0.16"
|
||||
@@ -3514,7 +3514,7 @@ __metadata:
|
||||
react: ^18.0.0
|
||||
react-dom: ^18.0.0
|
||||
react-router-dom: ^6.28.0
|
||||
checksum: 10/ffd51ad71fe3b89c3cd16bfaa0f11e003bf11e4a4fb7513c5c55fdc5e569f51dcf9fb70cb125e63b5b2269d68e86a961769e07a8078cad70163de2c2ed779ef7
|
||||
checksum: 10/1bcddada8bf626d552aaa29ae4f916a50968bb36761285b0517500f50d8f52314148a8ed73419f381f8e5b901308cdf2450f0b82754691af512a2cff9f52b6bb
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -17717,8 +17717,8 @@ __metadata:
|
||||
"@grafana/plugin-ui": "npm:0.10.5"
|
||||
"@grafana/prometheus": "workspace:*"
|
||||
"@grafana/runtime": "workspace:*"
|
||||
"@grafana/scenes": "npm:6.10.4"
|
||||
"@grafana/scenes-react": "npm:6.10.4"
|
||||
"@grafana/scenes": "npm:^6.12.0"
|
||||
"@grafana/scenes-react": "npm:^6.12.0"
|
||||
"@grafana/schema": "workspace:*"
|
||||
"@grafana/sql": "workspace:*"
|
||||
"@grafana/test-utils": "workspace:*"
|
||||
|
||||
Reference in New Issue
Block a user