Scene: Small refactorings and name changes (#51866)

* Rename onMount and onUnmount and some other small refactorings

* More refactorings fixing typescript issues
pull/52052/head
Torkel Ödegaard 3 years ago committed by GitHub
parent 6447e08809
commit 849134b5dd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      .betterer.results
  2. 10
      public/app/features/scenes/components/Scene.tsx
  3. 4
      public/app/features/scenes/components/ScenePanelRepeater.tsx
  4. 32
      public/app/features/scenes/core/SceneComponentWrapper.tsx
  5. 4
      public/app/features/scenes/core/SceneObjectBase.test.ts
  6. 42
      public/app/features/scenes/core/SceneObjectBase.tsx
  7. 11
      public/app/features/scenes/core/types.ts
  8. 25
      public/app/features/scenes/editor/SceneComponentEditWrapper.tsx
  9. 13
      public/app/features/scenes/querying/SceneQueryRunner.ts

@ -5726,11 +5726,9 @@ exports[`better eslint`] = {
"public/app/features/scenes/components/SceneFlexLayout.tsx:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"]
],
"public/app/features/scenes/core/SceneComponentEditWrapper.tsx:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
[0, 0, 0, "Do not use any type assertions.", "1"],
[0, 0, 0, "Unexpected any. Specify a different type.", "2"],
[0, 0, 0, "Unexpected any. Specify a different type.", "3"]
"public/app/features/scenes/core/SceneComponentWrapper.tsx:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"],
[0, 0, 0, "Unexpected any. Specify a different type.", "1"]
],
"public/app/features/scenes/core/SceneObjectBase.tsx:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],

@ -17,13 +17,13 @@ export class Scene extends SceneObjectBase<SceneState> {
static Component = SceneRenderer;
urlSyncManager?: UrlSyncManager;
onMount() {
super.onMount();
activate() {
super.activate();
this.urlSyncManager = new UrlSyncManager(this);
}
onUnmount() {
super.onUnmount();
deactivate() {
super.deactivate();
this.urlSyncManager!.cleanUp();
}
}
@ -31,8 +31,6 @@ export class Scene extends SceneObjectBase<SceneState> {
function SceneRenderer({ model }: SceneComponentProps<Scene>) {
const { title, layout, actions = [], isEditing, $editor } = model.useState();
console.log('render scene');
return (
<div style={{ height: '100%', display: 'flex', flexDirection: 'column', flex: '1 1 0', minHeight: 0 }}>
<PageToolbar title={title}>

@ -11,8 +11,8 @@ interface RepeatOptions extends SceneObjectState {
}
export class ScenePanelRepeater extends SceneObjectBase<RepeatOptions> {
onMount() {
super.onMount();
activate(): void {
super.activate();
this.subs.add(
this.getData().subscribe({

@ -0,0 +1,32 @@
import React, { useEffect } from 'react';
import { SceneComponentEditingWrapper } from '../editor/SceneComponentEditWrapper';
import { SceneComponentProps, SceneObject } from './types';
export function SceneComponentWrapper<T extends SceneObject>({ model, isEditing }: SceneComponentProps<T>) {
const Component = (model as any).constructor['Component'] ?? EmptyRenderer;
const inner = <Component model={model} isEditing={isEditing} />;
// Handle component activation state state
useEffect(() => {
if (!model.isActive) {
model.activate();
}
return () => {
if (model.isActive) {
model.deactivate();
}
};
}, [model]);
if (!isEditing) {
return inner;
}
return <SceneComponentEditingWrapper model={model}>{inner}</SceneComponentEditingWrapper>;
}
function EmptyRenderer<T>(_: SceneComponentProps<T>): React.ReactElement | null {
return null;
}

@ -23,12 +23,12 @@ describe('SceneObject', () => {
],
});
scene.state.nested?.onMount();
scene.state.nested?.activate();
const clone = scene.clone();
expect(clone).not.toBe(scene);
expect(clone.state.nested).not.toBe(scene.state.nested);
expect(clone.state.nested?.isMounted).toBe(undefined);
expect(clone.state.nested?.isActive).toBe(undefined);
expect(clone.state.children![0]).not.toBe(scene.state.children![0]);
});

@ -1,11 +1,10 @@
import { useEffect } from 'react';
import { useObservable } from 'react-use';
import { Observer, Subject, Subscription } from 'rxjs';
import { v4 as uuidv4 } from 'uuid';
import { EventBusSrv } from '@grafana/data';
import { SceneComponentEditWrapper } from './SceneComponentEditWrapper';
import { SceneComponentWrapper } from './SceneComponentWrapper';
import { SceneObjectStateChangedEvent } from './events';
import {
SceneDataState,
@ -23,7 +22,7 @@ export abstract class SceneObjectBase<TState extends SceneObjectState = {}> impl
state: TState;
parent?: SceneObjectBase<any>;
subs = new Subscription();
isMounted?: boolean;
isActive?: boolean;
events = new EventBusSrv();
constructor(state: TState) {
@ -41,7 +40,7 @@ export abstract class SceneObjectBase<TState extends SceneObjectState = {}> impl
* Wraps the component in an EditWrapper that handles edit mode
*/
get Component(): SceneComponent<this> {
return SceneComponentEditWrapper;
return SceneComponentWrapper;
}
/**
@ -96,46 +95,27 @@ export abstract class SceneObjectBase<TState extends SceneObjectState = {}> impl
return !this.parent ? this : this.parent.getRoot();
}
onMount() {
this.isMounted = true;
activate() {
this.isActive = true;
const { $data } = this.state;
if ($data && !$data.isMounted) {
$data.onMount();
if ($data && !$data.isActive) {
$data.activate();
}
}
onUnmount() {
this.isMounted = false;
deactivate(): void {
this.isActive = false;
const { $data } = this.state;
if ($data && $data.isMounted) {
$data.onUnmount();
if ($data && $data.isActive) {
$data.deactivate();
}
this.subs.unsubscribe();
this.subs = new Subscription();
}
/**
* The scene object needs to know when the react component is mounted to trigger query and other lazy actions
*/
useMount() {
// eslint-disable-next-line react-hooks/rules-of-hooks
useEffect(() => {
if (!this.isMounted) {
this.onMount();
}
return () => {
if (this.isMounted) {
this.onUnmount();
}
};
}, []);
return this;
}
useState() {
// eslint-disable-next-line react-hooks/rules-of-hooks
return useObservable(this.subject, this.state);

@ -41,7 +41,7 @@ export interface SceneObject<TState extends SceneObjectState = SceneObjectState>
state: TState;
/** True when there is a React component mounted for this Object */
isMounted?: boolean;
isActive?: boolean;
/** SceneObject parent */
parent?: SceneObject;
@ -55,14 +55,11 @@ export interface SceneObject<TState extends SceneObjectState = SceneObjectState>
/** How to modify state */
setState(state: Partial<TState>): void;
/** Utility hook for main component so that object knows when it's mounted */
useMount(): this;
/** Called when component mounts. A place to register event listeners add subscribe to state changes */
onMount(): void;
/** Called when the Component is mounted. A place to register event listeners add subscribe to state changes */
activate(): void;
/** Called when component unmounts. Unsubscribe to events */
onUnmount(): void;
deactivate(): void;
/** Get the scene editor */
getSceneEditor(): SceneEditor;

@ -4,26 +4,9 @@ import React, { CSSProperties } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
import { SceneObjectBase } from './SceneObjectBase';
import { SceneComponentProps } from './types';
import { SceneObject } from '../core/types';
export function SceneComponentEditWrapper<T extends SceneObjectBase<any>>({
model,
isEditing,
}: SceneComponentProps<T>) {
const Component = (model as any).constructor['Component'] ?? EmptyRenderer;
const inner = <Component model={model} isEditing={isEditing} />;
model.useMount();
if (!isEditing) {
return inner;
}
return <SceneComponentEditingWrapper model={model}>{inner}</SceneComponentEditingWrapper>;
}
export function SceneComponentEditingWrapper<T extends SceneObjectBase<any>>({
export function SceneComponentEditingWrapper<T extends SceneObject>({
model,
children,
}: {
@ -76,7 +59,3 @@ const getStyles = (theme: GrafanaTheme2) => {
}),
};
};
function EmptyRenderer<T>(_: SceneComponentProps<T>): React.ReactElement | null {
return null;
}

@ -31,8 +31,8 @@ export interface DataQueryExtended extends DataQuery {
export class SceneQueryRunner extends SceneObjectBase<QueryRunnerState> {
private querySub?: Unsubscribable;
onMount() {
super.onMount();
activate() {
super.activate();
const timeRange = this.getTimeRange();
@ -49,12 +49,9 @@ export class SceneQueryRunner extends SceneObjectBase<QueryRunnerState> {
}
}
onUnmount() {
super.onUnmount();
this.cleanUp();
}
deactivate(): void {
super.deactivate();
cleanUp() {
if (this.querySub) {
this.querySub.unsubscribe();
this.querySub = undefined;
@ -108,8 +105,6 @@ export class SceneQueryRunner extends SceneObjectBase<QueryRunnerState> {
request.interval = norm.interval;
request.intervalMs = norm.intervalMs;
console.log('Query runner run');
this.querySub = runRequest(ds, request).subscribe({
next: (data) => {
console.log('set data', data, data.state);

Loading…
Cancel
Save