From 81decc88ec0ee165b62a58fe3026fff6f4f434c2 Mon Sep 17 00:00:00 2001 From: Ruben Thoms Date: Mon, 9 Oct 2023 20:01:56 +0200 Subject: [PATCH] First implementation --- frontend/src/framework/ModuleContext.ts | 21 +++++++- frontend/src/framework/ModuleInstance.ts | 48 +++++++++++++++++++ .../ViewWrapper/private-components/header.tsx | 30 +++++++++++- .../src/modules/DistributionPlot/view.tsx | 2 + 4 files changed, 99 insertions(+), 2 deletions(-) diff --git a/frontend/src/framework/ModuleContext.ts b/frontend/src/framework/ModuleContext.ts index ef519a82d..75b99becf 100644 --- a/frontend/src/framework/ModuleContext.ts +++ b/frontend/src/framework/ModuleContext.ts @@ -1,10 +1,17 @@ import React from "react"; import { BroadcastChannel } from "./Broadcaster"; -import { ModuleInstance } from "./ModuleInstance"; +import { ModuleInstance, ModuleInstanceLogEntryType } from "./ModuleInstance"; import { StateBaseType, StateStore, useSetStoreValue, useStoreState, useStoreValue } from "./StateStore"; import { SyncSettingKey } from "./SyncSettings"; +export enum ModuleInstanceState { + LOADING, + READY, + ERROR, + WARNING, +} + export class ModuleContext { private _moduleInstance: ModuleInstance; private _stateStore: StateStore; @@ -56,4 +63,16 @@ export class ModuleContext { setInstanceTitle(title: string): void { this._moduleInstance.setTitle(title); } + + setLoading(isLoading: boolean): void { + this._moduleInstance.setLoading(isLoading); + } + + log(message: string, type: ModuleInstanceLogEntryType = ModuleInstanceLogEntryType.INFO): void { + this._moduleInstance.log(message, type); + } + + clearLog(): void { + this._moduleInstance.clearLog(); + } } diff --git a/frontend/src/framework/ModuleInstance.ts b/frontend/src/framework/ModuleInstance.ts index 79a154263..97d68e905 100644 --- a/frontend/src/framework/ModuleInstance.ts +++ b/frontend/src/framework/ModuleInstance.ts @@ -17,6 +17,18 @@ export enum ModuleInstanceState { RESETTING, } +export enum ModuleInstanceLogEntryType { + INFO, + WARNING, + ERROR, +} + +export type ModuleInstanceLogEntry = { + message: string; + timestamp: number; + type: ModuleInstanceLogEntryType; +}; + export class ModuleInstance { private _id: string; private _title: string; @@ -35,6 +47,8 @@ export class ModuleInstance { private _cachedDefaultState: StateType | null; private _cachedStateStoreOptions?: StateOptions; private _initialSettings: InitialSettings | null; + private _contentIsLoading: boolean; + private _logEntries: ModuleInstanceLogEntry[]; constructor( module: Module, @@ -57,6 +71,8 @@ export class ModuleInstance { this._fatalError = null; this._cachedDefaultState = null; this._initialSettings = null; + this._contentIsLoading = false; + this._logEntries = []; this._broadcastChannels = {} as Record; @@ -161,6 +177,38 @@ export class ModuleInstance { this.notifySubscribersAboutTitleChange(); } + setLoading(isLoading: boolean): void { + this._contentIsLoading = isLoading; + } + + isLoading(): boolean { + return this._contentIsLoading; + } + + log(message: string, type: ModuleInstanceLogEntryType = ModuleInstanceLogEntryType.INFO): void { + this._logEntries.push({ + message, + timestamp: Date.now(), + type, + }); + } + + getLogEntries(): ModuleInstanceLogEntry[] { + return this._logEntries; + } + + clearLog(): void { + this._logEntries = []; + } + + hasLoggedErrors(): boolean { + return this._logEntries.some((entry) => entry.type === ModuleInstanceLogEntryType.ERROR); + } + + hasLoggedWarnings(): boolean { + return this._logEntries.some((entry) => entry.type === ModuleInstanceLogEntryType.WARNING); + } + subscribeToTitleChange(cb: (title: string) => void): () => void { this._titleChangeSubscribers.add(cb); return () => { diff --git a/frontend/src/framework/internal/components/Content/private-components/ViewWrapper/private-components/header.tsx b/frontend/src/framework/internal/components/Content/private-components/ViewWrapper/private-components/header.tsx index eb0f42009..7093038a3 100644 --- a/frontend/src/framework/internal/components/Content/private-components/ViewWrapper/private-components/header.tsx +++ b/frontend/src/framework/internal/components/Content/private-components/ViewWrapper/private-components/header.tsx @@ -2,8 +2,9 @@ import React from "react"; import { ModuleInstance } from "@framework/ModuleInstance"; import { SyncSettingKey, SyncSettingsMeta } from "@framework/SyncSettings"; +import { CircularProgress } from "@lib/components/CircularProgress"; import { isDevMode } from "@lib/utils/devMode"; -import { Close } from "@mui/icons-material"; +import { Close, Error, Warning } from "@mui/icons-material"; export type HeaderProps = { moduleInstance: ModuleInstance; @@ -42,6 +43,32 @@ export const Header: React.FC = (props) => { e.stopPropagation(); } + function makeStateIndicator() { + if (props.moduleInstance.isLoading()) { + return ( +
+ +
+ ); + } + + if (props.moduleInstance.hasLoggedErrors()) { + return ( +
+ +
+ ); + } + + if (props.moduleInstance.hasLoggedWarnings()) { + return ( +
+ +
+ ); + } + } + return (
= (props) => { onPointerDown={props.onPointerDown} >
+ {makeStateIndicator()} {title} diff --git a/frontend/src/modules/DistributionPlot/view.tsx b/frontend/src/modules/DistributionPlot/view.tsx index aaf1f8f8d..6c1edf2bf 100644 --- a/frontend/src/modules/DistributionPlot/view.tsx +++ b/frontend/src/modules/DistributionPlot/view.tsx @@ -40,6 +40,8 @@ export const view = ({ moduleContext, workbenchServices, workbenchSettings }: Mo const numBins = moduleContext.useStoreValue("numBins"); const orientation = moduleContext.useStoreValue("orientation"); + moduleContext.setLoading(true); + const [highlightedKey, setHighlightedKey] = React.useState(null); const [dataX, setDataX] = React.useState(null); const [dataY, setDataY] = React.useState(null);