diff --git a/frontend/src/framework/internal/components/Content/private-components/ViewWrapper/private-components/viewContent.tsx b/frontend/src/framework/internal/components/Content/private-components/ViewWrapper/private-components/viewContent.tsx index 0bf5835bc..f082fe1cb 100644 --- a/frontend/src/framework/internal/components/Content/private-components/ViewWrapper/private-components/viewContent.tsx +++ b/frontend/src/framework/internal/components/Content/private-components/ViewWrapper/private-components/viewContent.tsx @@ -3,6 +3,7 @@ import React from "react"; import { ImportState } from "@framework/Module"; import { ModuleInstance, ModuleInstanceState } from "@framework/ModuleInstance"; import { Workbench } from "@framework/Workbench"; +import { DebugProfiler } from "@framework/internal/components/DebugProfiler"; import { ErrorBoundary } from "@framework/internal/components/ErrorBoundary"; import { CircularProgress } from "@lib/components/CircularProgress"; @@ -114,13 +115,15 @@ export const ViewContent = React.memo((props: ViewContentProps) => { return (
- + + +
); diff --git a/frontend/src/framework/internal/components/DebugProfiler/debugProfiler.tsx b/frontend/src/framework/internal/components/DebugProfiler/debugProfiler.tsx new file mode 100644 index 000000000..3a17ab602 --- /dev/null +++ b/frontend/src/framework/internal/components/DebugProfiler/debugProfiler.tsx @@ -0,0 +1,137 @@ +import React from "react"; + +import { isDevMode } from "@lib/utils/devMode"; + +type DebugProfilerRenderInfoProps = { + children: React.ReactNode | React.ReactNode[]; + title: string; +}; + +const DebugProfilerRenderInfo: React.FC = (props) => { + return ( + + {props.children} + + ); +}; + +DebugProfilerRenderInfo.displayName = "DebugProfilerRenderInfo"; + +type DebugProfilerWrapperProps = { + id: string; + children: React.ReactNode; + onRender: React.ProfilerOnRenderCallback; +}; + +const DebugProfilerWrapper = React.memo((props: DebugProfilerWrapperProps) => { + return ( + + {props.children} + + ); +}); + +DebugProfilerWrapper.displayName = "DebugProfilerWrapper"; + +export type DebugProfilerProps = { + id: string; + children: React.ReactNode; +}; + +type RenderInfo = { + phase: "mount" | "update"; + actualDuration: number; + baseDuration: number; + startTime: number; + commitTime: number; + interactions: Set; + renderCount: number; + minTime: number; + maxTime: number; + totalTime: number; + avgTime: number; +}; + +export const DebugProfiler: React.FC = (props) => { + const [renderInfo, setRenderInfo] = React.useState(null); + + const handleRender = React.useCallback( + ( + _: string, + phase: "mount" | "update", + actualDuration: number, + baseDuration: number, + startTime: number, + commitTime: number, + interactions: Set + ) => { + setRenderInfo((prev) => ({ + phase, + actualDuration, + baseDuration, + startTime, + commitTime, + interactions, + renderCount: (prev?.renderCount ?? 0) + 1, + minTime: Math.min(prev?.minTime ?? actualDuration, actualDuration), + maxTime: Math.max(prev?.maxTime ?? actualDuration, actualDuration), + totalTime: (prev?.totalTime ?? 0) + actualDuration, + avgTime: ((prev?.totalTime ?? 0) + actualDuration) / ((prev?.renderCount ?? 0) + 1), + })); + }, + [] + ); + + if (isDevMode()) { + return ( + <> + + {props.children} + +
+ {renderInfo && ( + <> + + RC: {renderInfo.renderCount} + + P: {renderInfo.phase} + + AD: {renderInfo.actualDuration.toFixed(2)}ms + + + BD: {renderInfo.baseDuration.toFixed(2)}ms + + + MIN: {renderInfo.minTime.toFixed(2)}ms + + + MAX: {renderInfo.maxTime.toFixed(2)}ms + + + AVG: {renderInfo.avgTime.toFixed(2)}ms + + + )} +
+ + ); + } + + return <>{props.children}; +}; + +DebugProfiler.displayName = "DebugProfiler"; diff --git a/frontend/src/framework/internal/components/DebugProfiler/index.ts b/frontend/src/framework/internal/components/DebugProfiler/index.ts new file mode 100644 index 000000000..daaa2e7eb --- /dev/null +++ b/frontend/src/framework/internal/components/DebugProfiler/index.ts @@ -0,0 +1 @@ +export { DebugProfiler } from "./debugProfiler"; diff --git a/frontend/src/framework/internal/components/Settings/private-components/setting.tsx b/frontend/src/framework/internal/components/Settings/private-components/setting.tsx index 1fe3f9530..c589cb01b 100644 --- a/frontend/src/framework/internal/components/Settings/private-components/setting.tsx +++ b/frontend/src/framework/internal/components/Settings/private-components/setting.tsx @@ -9,6 +9,8 @@ import { Cog6ToothIcon } from "@heroicons/react/20/solid"; import { CircularProgress } from "@lib/components/CircularProgress"; import { resolveClassNames } from "@lib/utils/resolveClassNames"; +import { DebugProfiler } from "../../DebugProfiler"; + type SettingProps = { moduleInstance: ModuleInstance; activeModuleId: string; @@ -74,7 +76,7 @@ export const Setting: React.FC = (props) => { key={props.moduleInstance.getId()} className={resolveClassNames( props.activeModuleId === props.moduleInstance.getId() ? "flex" : "hidden", - "flex-col h-full w-full" + "flex-col h-full w-full relative" )} > @@ -89,13 +91,15 @@ export const Setting: React.FC = (props) => {
- + + +