grafana/public/app/features/scenes/components/SceneFlexLayout.tsx
Torkel Ödegaard 935334cbda
Scene: POC for a future dashboard model and runtime (#50980)
* Playing around

* This is getting interesting

* Updates

* Updated

* Observable experiments

* This is tricky

* VizPanel panel renderer

* New model progress

* Maybe this could be something

* Updated

* Rename

* updates

* Updated

* Query runners? not sure

* Updated

* updates

* flex box layout starting to work

* Testing

* Tested an action

* Parent context sort of working

* Progress

* Progress

* Updated

* Starting to work

* Things are working

* Scene list, nested scene demo

* Progress on repeats

* Moving things

* Pretty big progress

* More things working

* Great progress

* Progress

* Name changing

* Minor tweaks

* Simplified sizing

* Move toggleDirection to SceneFlexLayout

* add feature flag (#50990)

* removed new useObservable hook

* Rename folder and feature toggle to scenes

* Caching scenes so you can go back to another scene without having to re-query data

* Fix issue with subs on re-mount

* Fixing test

* Added SceneCanvasText to play around with layout elements with size based on content

* Scene: Edit mode and component edit wrapper that handles selection  (#51078)

* First step for scene variables

* Started playing around with a scene edit mode

* Better way to set component

* Progress on edit mode

* Update

* Progress on edit mode

* Progress on editor

* Progress on editor

* Updates

* More working

* Progress

* Minor update

* removed unnessary file

* Moving things around

* Updated

* Making time range separate from time picker

* minor rename of methods

* The most basic variable start

* Minor renames

* Fixed interpolate issue if not found at closest level

* An embryo of event model and url sync handling

* Update url sync types

* Removed unnessary any type arg

Co-authored-by: Ryan McKinley <ryantxu@gmail.com>
Co-authored-by: Dominik Prokop <dominik.prokop@grafana.com>
2022-07-07 08:53:02 +02:00

111 lines
2.8 KiB
TypeScript

import React, { CSSProperties } from 'react';
import { Field, RadioButtonGroup } from '@grafana/ui';
import { SceneObjectBase } from '../core/SceneObjectBase';
import { SceneObject, SceneObjectSize, SceneObjectState, SceneLayoutState, SceneComponentProps } from '../core/types';
export type FlexLayoutDirection = 'column' | 'row';
interface SceneFlexLayoutState extends SceneObjectState, SceneLayoutState {
direction?: FlexLayoutDirection;
}
export class SceneFlexLayout extends SceneObjectBase<SceneFlexLayoutState> {
static Component = FlexLayoutRenderer;
static Editor = FlexLayoutEditor;
toggleDirection() {
this.setState({
direction: this.state.direction === 'row' ? 'column' : 'row',
});
}
}
function FlexLayoutRenderer({ model, isEditing }: SceneComponentProps<SceneFlexLayout>) {
const { direction = 'row', children } = model.useState();
return (
<div style={{ flexGrow: 1, flexDirection: direction, display: 'flex', gap: '8px' }}>
{children.map((item) => (
<FlexLayoutChildComponent key={item.state.key} item={item} direction={direction} isEditing={isEditing} />
))}
</div>
);
}
function FlexLayoutChildComponent({
item,
direction,
isEditing,
}: {
item: SceneObject<SceneObjectState>;
direction: FlexLayoutDirection;
isEditing?: boolean;
}) {
const { size } = item.useState();
return (
<div style={getItemStyles(direction, size)}>
<item.Component model={item} isEditing={isEditing} />
</div>
);
}
function getItemStyles(direction: FlexLayoutDirection, sizing: SceneObjectSize = {}) {
const { xSizing = 'fill', ySizing = 'fill' } = sizing;
const style: CSSProperties = {
display: 'flex',
flexDirection: direction,
minWidth: sizing.minWidth,
minHeight: sizing.minHeight,
};
if (direction === 'column') {
if (sizing.height) {
style.height = sizing.height;
} else {
style.flexGrow = ySizing === 'fill' ? 1 : 0;
}
if (sizing.width) {
style.width = sizing.width;
} else {
style.alignSelf = xSizing === 'fill' ? 'stretch' : 'flex-start';
}
} else {
if (sizing.height) {
style.height = sizing.height;
} else {
style.alignSelf = ySizing === 'fill' ? 'stretch' : 'flex-start';
}
if (sizing.width) {
style.width = sizing.width;
} else {
style.flexGrow = xSizing === 'fill' ? 1 : 0;
}
}
return style;
}
function FlexLayoutEditor({ model }: SceneComponentProps<SceneFlexLayout>) {
const { direction = 'row' } = model.useState();
const options = [
{ icon: 'arrow-right', value: 'row' },
{ icon: 'arrow-down', value: 'column' },
];
return (
<Field label="Direction">
<RadioButtonGroup
options={options}
value={direction}
onChange={(value) => model.setState({ direction: value as FlexLayoutDirection })}
/>
</Field>
);
}