+
+ {conditionalRenderingOverlay}
))}
>
@@ -38,14 +38,9 @@ export function AutoGridItemRenderer({ model }: SceneComponentProps
{isDragged && }
-
+
+ {conditionalRenderingOverlay}
);
diff --git a/public/app/features/dashboard-scene/scene/layout-rows/RowItemRenderer.tsx b/public/app/features/dashboard-scene/scene/layout-rows/RowItemRenderer.tsx
index 62510d2ab65..ff61f974d0d 100644
--- a/public/app/features/dashboard-scene/scene/layout-rows/RowItemRenderer.tsx
+++ b/public/app/features/dashboard-scene/scene/layout-rows/RowItemRenderer.tsx
@@ -8,8 +8,9 @@ import { SceneComponentProps } from '@grafana/scenes';
import { clearButtonStyles, Icon, Tooltip, useElementSelection, usePointerDistance, useStyles2 } from '@grafana/ui';
import { t } from 'app/core/internationalization';
+import { useIsConditionallyHidden } from '../../conditional-rendering/useIsConditionallyHidden';
import { useIsClone } from '../../utils/clone';
-import { useDashboardState, useInterpolatedTitle, useIsConditionallyHidden } from '../../utils/utils';
+import { useDashboardState, useInterpolatedTitle } from '../../utils/utils';
import { DashboardScene } from '../DashboardScene';
import { RowItem } from './RowItem';
@@ -18,7 +19,8 @@ export function RowItemRenderer({ model }: SceneComponentProps) {
const { layout, collapse: isCollapsed, fillScreen, hideHeader: isHeaderHidden, isDropTarget, key } = model.useState();
const isClone = useIsClone(model);
const { isEditing } = useDashboardState(model);
- const isConditionallyHidden = useIsConditionallyHidden(model);
+ const [isConditionallyHidden, conditionalRenderingClass, conditionalRenderingOverlay] =
+ useIsConditionallyHidden(model);
const { isSelected, onSelect, isSelectable } = useElementSelection(key);
const title = useInterpolatedTitle(model);
const { rows } = model.getParentLayout().useState();
@@ -54,12 +56,13 @@ export function RowItemRenderer({ model }: SceneComponentProps) {
data-dashboard-drop-target-key={model.state.key}
className={cx(
styles.wrapper,
+ !isCollapsed && styles.wrapperNotCollapsed,
dragSnapshot.isDragging && styles.dragging,
isEditing && !isCollapsed && styles.wrapperEditing,
isEditing && isCollapsed && styles.wrapperEditingCollapsed,
isCollapsed && styles.wrapperCollapsed,
shouldGrow && styles.wrapperGrow,
- isConditionallyHidden && 'dashboard-visible-hidden-element',
+ conditionalRenderingClass,
!isClone && isSelected && 'dashboard-selected-element',
!isClone && !isSelected && selectableHighlight && 'dashboard-selectable-element',
isDropTarget && 'dashboard-drop-target'
@@ -86,11 +89,7 @@ export function RowItemRenderer({ model }: SceneComponentProps) {
>
{(!isHeaderHidden || isEditing) && (
) {
)}
{!isCollapsed && }
+ {conditionalRenderingOverlay}
)}
@@ -170,6 +170,11 @@ function getStyles(theme: GrafanaTheme2) {
}),
rowTitleHidden: css({
textDecoration: 'line-through',
+ opacity: 0.6,
+
+ '&:hover': css({
+ opacity: 1,
+ }),
}),
rowTitleNested: css({
fontSize: theme.typography.body.fontSize,
@@ -183,9 +188,12 @@ function getStyles(theme: GrafanaTheme2) {
flexDirection: 'column',
width: '100%',
minHeight: '100px',
+ }),
+ wrapperNotCollapsed: css({
'> div:nth-child(2)': {
marginLeft: theme.spacing(3),
position: 'relative',
+
'&:before': {
content: '""',
position: 'absolute',
diff --git a/public/app/features/dashboard-scene/scene/layout-tabs/TabItem.tsx b/public/app/features/dashboard-scene/scene/layout-tabs/TabItem.tsx
index 2a014f48433..afa22d1792a 100644
--- a/public/app/features/dashboard-scene/scene/layout-tabs/TabItem.tsx
+++ b/public/app/features/dashboard-scene/scene/layout-tabs/TabItem.tsx
@@ -15,6 +15,7 @@ import store from 'app/core/store';
import kbn from 'app/core/utils/kbn';
import { OptionsPaneCategoryDescriptor } from 'app/features/dashboard/components/PanelEditor/OptionsPaneCategoryDescriptor';
+import { ConditionalRendering } from '../../conditional-rendering/ConditionalRendering';
import { serializeTab } from '../../serialization/layoutSerializers/TabsLayoutSerializer';
import { getElements } from '../../serialization/layoutSerializers/utils';
import { getDashboardSceneFor, getDefaultVizPanel } from '../../utils/utils';
@@ -41,6 +42,7 @@ export interface TabItemState extends SceneObjectState {
*/
isNew?: boolean;
isDropTarget?: boolean;
+ conditionalRendering?: ConditionalRendering;
}
export class TabItem
@@ -64,7 +66,20 @@ export class TabItem
...state,
title: state?.title ?? t('dashboard.tabs-layout.tab.new', 'New tab'),
layout: state?.layout ?? AutoGridLayoutManager.createEmpty(),
+ conditionalRendering: state?.conditionalRendering ?? ConditionalRendering.createEmpty(),
});
+
+ this.addActivationHandler(() => this._activationHandler());
+ }
+
+ private _activationHandler() {
+ const deactivate = this.state.conditionalRendering?.activate();
+
+ return () => {
+ if (deactivate) {
+ deactivate();
+ }
+ };
}
public getEditableElementInfo(): EditableDashboardElementInfo {
diff --git a/public/app/features/dashboard-scene/scene/layout-tabs/TabItemEditor.tsx b/public/app/features/dashboard-scene/scene/layout-tabs/TabItemEditor.tsx
index 8d4528022c6..9b2ff27e38c 100644
--- a/public/app/features/dashboard-scene/scene/layout-tabs/TabItemEditor.tsx
+++ b/public/app/features/dashboard-scene/scene/layout-tabs/TabItemEditor.tsx
@@ -5,6 +5,7 @@ import { t } from 'app/core/internationalization';
import { OptionsPaneCategoryDescriptor } from 'app/features/dashboard/components/PanelEditor/OptionsPaneCategoryDescriptor';
import { OptionsPaneItemDescriptor } from 'app/features/dashboard/components/PanelEditor/OptionsPaneItemDescriptor';
+import { useConditionalRenderingEditor } from '../../conditional-rendering/ConditionalRenderingEditor';
import { useLayoutCategory } from '../layouts-shared/DashboardLayoutSelector';
import { useEditPaneInputAutoFocus } from '../layouts-shared/utils';
@@ -26,7 +27,18 @@ export function getEditOptions(model: TabItem): OptionsPaneCategoryDescriptor[]
const layoutCategory = useLayoutCategory(layout);
- return [tabCategory, layoutCategory];
+ const editOptions = [tabCategory, layoutCategory];
+
+ const conditionalRenderingCategory = useMemo(
+ () => useConditionalRenderingEditor(model.state.conditionalRendering),
+ [model]
+ );
+
+ if (conditionalRenderingCategory) {
+ editOptions.push(conditionalRenderingCategory);
+ }
+
+ return editOptions;
}
function TabTitleInput({ tab }: { tab: TabItem }) {
diff --git a/public/app/features/dashboard-scene/scene/layout-tabs/TabItemRenderer.tsx b/public/app/features/dashboard-scene/scene/layout-tabs/TabItemRenderer.tsx
index 748b8c92e10..7f44fb2f0c3 100644
--- a/public/app/features/dashboard-scene/scene/layout-tabs/TabItemRenderer.tsx
+++ b/public/app/features/dashboard-scene/scene/layout-tabs/TabItemRenderer.tsx
@@ -6,6 +6,7 @@ import { locationUtil, textUtil } from '@grafana/data';
import { SceneComponentProps, sceneGraph } from '@grafana/scenes';
import { Tab, useElementSelection, usePointerDistance, useStyles2 } from '@grafana/ui';
+import { useIsConditionallyHidden } from '../../conditional-rendering/useIsConditionallyHidden';
import { useDashboardState } from '../../utils/utils';
import { TabItem } from './TabItem';
@@ -25,6 +26,11 @@ export function TabItemRenderer({ model }: SceneComponentProps