diff --git a/apps/sim-core/packages/core/src/components/Analysis/OutputMetricsGrid.spec.tsx b/apps/sim-core/packages/core/src/components/Analysis/OutputMetricsGrid.spec.tsx
index d48339b1..665b5764 100644
--- a/apps/sim-core/packages/core/src/components/Analysis/OutputMetricsGrid.spec.tsx
+++ b/apps/sim-core/packages/core/src/components/Analysis/OutputMetricsGrid.spec.tsx
@@ -1,14 +1,10 @@
import React from "react";
-import ReactDOM from "react-dom";
-import { Provider } from "react-redux";
+import { render } from "@testing-library/react";
import { ModalProvider } from "react-modal-hook";
import { ComparisonTypes, Operation, OperationTypes } from "./types";
import { ErrorBoundary } from "../ErrorBoundary";
import { OutputMetricsGrid } from "./OutputMetricsGrid";
-import { mockProject } from "../../features/project/mocks";
-import { setProjectWithMeta } from "../../features/actions";
-import { store } from "../../features/store";
const noop = () => {};
const operations: Operation[] = [
@@ -23,24 +19,15 @@ const operations: Operation[] = [
const metrics = { metricName: operations };
it("renders without crashing", () => {
- const div = document.createElement("div");
-
- //@ts-expect-error Redux types need to be repaired.
- store.dispatch(setProjectWithMeta(mockProject));
-
- ReactDOM.render(
-
-
-
-
-
-
- ,
- div,
+ render(
+
+
+
+
+ ,
);
- ReactDOM.unmountComponentAtNode(div);
});
diff --git a/apps/sim-core/packages/core/src/components/Analysis/OutputMetricsGrid.tsx b/apps/sim-core/packages/core/src/components/Analysis/OutputMetricsGrid.tsx
index 77d706bd..f92b12f6 100644
--- a/apps/sim-core/packages/core/src/components/Analysis/OutputMetricsGrid.tsx
+++ b/apps/sim-core/packages/core/src/components/Analysis/OutputMetricsGrid.tsx
@@ -1,7 +1,7 @@
import React, { FC, useReducer } from "react";
import { useModal } from "react-modal-hook";
import classNames from "classnames";
-import { omit } from "lodash";
+import { omit } from "lodash-es";
import { IconAddDatapoint } from "../Icon/AddDatapoint";
import { IconContentDuplicate } from "../Icon/ContentDuplicate";
diff --git a/apps/sim-core/packages/core/src/components/Analysis/PlotsTab.tsx b/apps/sim-core/packages/core/src/components/Analysis/PlotsTab.tsx
index dc950d90..a8bf1efa 100644
--- a/apps/sim-core/packages/core/src/components/Analysis/PlotsTab.tsx
+++ b/apps/sim-core/packages/core/src/components/Analysis/PlotsTab.tsx
@@ -1,5 +1,4 @@
import React, { FC } from "react";
-import { useSelector } from "react-redux";
import { AnalysisViewerPlotsTabProps } from "./types";
import { ButtonCallToAction } from "./ButtonCallToAction";
@@ -7,7 +6,7 @@ import { HelpParagraph } from "./HelpParagraph";
import { IconCreatePlot } from "../Icon/CreatePlot";
import { PlotViewer } from "../PlotViewer/PlotViewer";
import { Scope, useScopes } from "../../features/scopes";
-import { selectEmbedded } from "../../features/viewer/selectors";
+import { useViewer } from "../../features/viewer/ViewerContext";
export const PlotsTab: FC
= ({
analysisPlotsDataAvailable,
@@ -21,7 +20,7 @@ export const PlotsTab: FC = ({
readonly,
}) => {
const { canEdit, canLogin } = useScopes(Scope.edit, Scope.login);
- const embedded = useSelector(selectEmbedded);
+ const { embedded } = useViewer();
if (!analysisMode) {
return embedded ? null : (
diff --git a/apps/sim-core/packages/core/src/components/Analysis/TabListActionButtons.scss b/apps/sim-core/packages/core/src/components/Analysis/TabListActionButtons.scss
index cc063943..679fd2d2 100644
--- a/apps/sim-core/packages/core/src/components/Analysis/TabListActionButtons.scss
+++ b/apps/sim-core/packages/core/src/components/Analysis/TabListActionButtons.scss
@@ -2,7 +2,8 @@
max-width: calc(
(var(--analysis-tab-container-width) - 10px) - var(
--AnalysisViewer__ActionButtons__Tooltip--index
- ) * 38px
+ ) *
+ 38px
);
min-width: 0;
--clip-y-below: -50px;
diff --git a/apps/sim-core/packages/core/src/components/Analysis/modals.ts b/apps/sim-core/packages/core/src/components/Analysis/modals.ts
index 2cd69757..c36537ba 100644
--- a/apps/sim-core/packages/core/src/components/Analysis/modals.ts
+++ b/apps/sim-core/packages/core/src/components/Analysis/modals.ts
@@ -1,4 +1,5 @@
-import { omit } from "lodash";
+import { PlotDefinition } from "@hashintel/engine-web";
+import { omit } from "lodash-es";
import { ChartTypes, Operation, Plot, YAxisItemType } from "./types";
import { ParsedAnalysis } from "../../features/files/types";
@@ -7,17 +8,17 @@ import { updateFile } from "../../features/files/slice";
export const MAGIC_STEPS_KEY = "Use steps on the X Axis";
-interface ModalsBaseProps {
+type ModalsBaseProps = {
dispatch: Function;
setAnalysis: Function;
analysis: any;
analysisString?: string;
-}
+};
-interface OutputMetricsModalSubmitType {
+type OutputMetricsModalSubmitType = {
title: string;
operations: Operation[];
-}
+};
type OnOutputMetricsModalSaveInputType = ModalsBaseProps & {
data: OutputMetricsModalSubmitType;
@@ -36,51 +37,51 @@ type OnPlotsModalDeleteType = ModalsBaseProps & {
indexToDelete: number;
};
-interface PlotsModalChartTypeOption {
+type PlotsModalChartTypeOption = {
value: string;
label: string;
-}
+};
-interface PlotsModalYAxisItemType {
+type PlotsModalYAxisItemType = {
name: string;
metric: string;
-}
+};
-interface PlotsModalXAxisItemType {
+type PlotsModalXAxisItemType = {
name: string;
metric: string;
-}
+};
-interface PlotsModalLayoutType {
+type PlotsModalLayoutType = {
width: string;
height: string;
-}
+};
-interface PlotsModalPositionType {
+type PlotsModalPositionType = {
x: string;
y: string;
-}
+};
-interface PlotsModalSubmitType {
+type PlotsModalSubmitType = {
title: string;
chartType: PlotsModalChartTypeOption;
yitems?: PlotsModalYAxisItemType[];
xitems?: PlotsModalXAxisItemType[];
layout: PlotsModalLayoutType;
position: PlotsModalPositionType;
-}
+};
type OnPlotsModalSaveType = ModalsBaseProps & {
data: PlotsModalSubmitType;
plotIndex?: number;
};
-interface saveToAnalysisFile {
+type saveToAnalysisFile = {
dispatch: Function;
setAnalysis: Function;
analysisString?: string;
newValues: any;
-}
+};
const saveToAnalysisFile = ({
dispatch,
@@ -159,8 +160,8 @@ export const onDuplicateMetric = ({
// Reads the data definition and transforms it to a format understood
// by the Plots modal
export const getYAxisItemsFromDataDefinition = (
- input: any,
-): YAxisItemType[] => {
+ input: PlotDefinition & any,
+): Array => {
if (!input.type && input[ChartTypes.timeseries]) {
return input.timeseries.map((metric: any) => ({
name: metric,
@@ -195,8 +196,8 @@ export const getYAxisItemsFromDataDefinition = (
// Reads the data definition and transforms it to a format understood
// by the Plots modal
export const getXAxisItemsFromDataDefinition = (
- input: any,
-): YAxisItemType[] => {
+ input: PlotDefinition & any,
+): Array => {
if (!input.type) {
return input.data;
}
@@ -210,13 +211,16 @@ export const getXAxisItemsFromDataDefinition = (
);
};
-export const getPlotTypeFromDataDefinition = (input: any): string =>
- input.type ?? ChartTypes.timeseries;
+export const getPlotTypeFromDataDefinition = (
+ input: PlotDefinition & any,
+): string => input.type ?? ChartTypes.timeseries;
const chartItemLabel = (item: { name?: string; metric?: string }) =>
item.name ?? item.metric;
-export const transformPlotDataBasedOnChartType = (input: any) => {
+export const transformPlotDataBasedOnChartType = (
+ input: PlotDefinition & any,
+) => {
const result = Object.assign({}, input);
switch (input.type) {
// http://localhost:8080/@hash/city-infection-model/6.1.1
@@ -261,12 +265,12 @@ export const transformPlotDataBasedOnChartType = (input: any) => {
break;
case ChartTypes.line:
- case ChartTypes.scatter: {
+ case ChartTypes.scatter:
// this assumes we have both X and Y OR we have only Y and X=steps
const hasMagicStepsKey =
input.data?.xitems.length === 1 &&
input.data.xitems[0].metric === MAGIC_STEPS_KEY;
- const hasYItems = input.data?.yitems.length > 0 ?? false;
+ const hasYItems = (input.data?.yitems.length ?? 0) > 0;
const hasXItems = hasMagicStepsKey
? false
: input.data?.xitems.length > 0;
@@ -290,7 +294,7 @@ export const transformPlotDataBasedOnChartType = (input: any) => {
}
break;
- }
+
case ChartTypes.bar:
default:
result.data = input.data?.yitems?.map((item: any) => ({
diff --git a/apps/sim-core/packages/core/src/components/Analysis/types.ts b/apps/sim-core/packages/core/src/components/Analysis/types.ts
index 984f020d..04482f88 100644
--- a/apps/sim-core/packages/core/src/components/Analysis/types.ts
+++ b/apps/sim-core/packages/core/src/components/Analysis/types.ts
@@ -1,27 +1,27 @@
import { MouseEvent } from "react";
-import { PlotParams } from "react-plotly.js";
+import type { PlotParams } from "react-plotly.js";
import { AnalysisMode } from "../../features/simulator/simulate/enum";
import { ReactSelectOption } from "../Dropdown/types";
-export interface AnalysisProps {
+export type AnalysisProps = {
currentStep: number;
visible?: boolean;
-}
+};
-export interface AnalysisViewerPlotsTabProps {
+export type AnalysisViewerPlotsTabProps = {
analysisPlotsDataAvailable: boolean;
analysisOutputMetricsDataAvailable: boolean;
currentStep: number;
- outputs: Record;
+ outputs: { [index: string]: any[] };
analysisMode?: AnalysisMode | null;
onPlotsModalSaveHandler: Function;
onPlotsModalDeleteHandler: Function;
showPlotsModal: (event: MouseEvent) => void;
readonly: boolean;
-}
+};
-export interface AnalysisViewerOutputMetricsTabProps {
+export type AnalysisViewerOutputMetricsTabProps = {
analysisOutputMetricsDataAvailable: boolean;
showOutputMetricsModal: (event: MouseEvent) => void;
analysis: any;
@@ -29,7 +29,7 @@ export interface AnalysisViewerOutputMetricsTabProps {
onOutputMetricsModalDeleteHandler: Function;
onDuplicateMetricHandler: Function;
readonly: boolean;
-}
+};
export type OutputPlotProps = PlotParams & {
key: string;
@@ -42,12 +42,12 @@ export enum ButtonCallToActionType {
PLOTS = "PLOTS",
}
-export interface ButtonCallToActionProps {
+export type ButtonCallToActionProps = {
children: JSX.Element | JSX.Element[];
onClick?: (event: MouseEvent) => void;
-}
+};
-export interface AnalysisViewerActionButtonsProps {
+export type AnalysisViewerActionButtonsProps = {
canCreateNewPlot?: boolean;
showOutputMetricsModal: (event: MouseEvent) => void;
showPlotsModal: (event: MouseEvent) => void;
@@ -57,7 +57,7 @@ export interface AnalysisViewerActionButtonsProps {
* it
*/
canEdit: true;
-}
+};
export enum ComparisonTypes {
eq = "eq",
@@ -78,7 +78,7 @@ export enum OperationTypes {
mean = "mean",
}
-export interface OperationItemProps {
+export type OperationItemProps = {
operation: Operation;
index: number;
onDelete: (event: MouseEvent) => void;
@@ -86,33 +86,33 @@ export interface OperationItemProps {
permittedOperations: ReactSelectOption[]; // the operations that preceed this one.
hideDelete?: boolean;
behaviorKeysOptions?: ReactSelectOption[]; // used for "field"
-}
+};
-export interface Operation {
+export type Operation = {
op: OperationTypes;
field?: string;
comparison?: ComparisonTypes;
value?: any;
-}
+};
-export interface OutputMetricsGridProps {
+export type OutputMetricsGridProps = {
onOutputMetricsModalSave: Function;
- metrics?: Record;
+ metrics?: { [index: string]: Operation[] };
onOutputMetricsModalDelete?: Function;
onDuplicateMetric?: Function;
sizeClassname?: string;
readonly: boolean;
-}
+};
-interface PlotLayout {
+type PlotLayout = {
width: string;
height: string;
-}
+};
-interface PlotPosition {
+type PlotPosition = {
x: string;
y: string;
-}
+};
enum PlotType {
timeseries,
@@ -121,39 +121,39 @@ enum PlotType {
line,
}
-interface PlotData {
+type PlotData = {
y: string;
name: string;
-}
+};
-export interface Plot {
+export type Plot = {
title: string;
layout: PlotLayout;
position: PlotPosition;
type?: PlotType;
data?: PlotData[];
timeseries?: string[];
-}
+};
-export interface AnalysisObject {
- outputs: Record;
+export type AnalysisObject = {
+ outputs: { [index: string]: Operation[] };
plots: Plot[];
-}
+};
-export interface AnalysisState {
+export type AnalysisState = {
lastAnalysisString?: any;
analysis?: AnalysisObject;
error: any;
-}
+};
-export interface OnOutputMetricsModalSaveType {
+export type OnOutputMetricsModalSaveType = {
title: string;
operations: Operation[];
-}
+};
-export interface OnOutputMetricsModalSaveProps {
+export type OnOutputMetricsModalSaveProps = {
data: OnOutputMetricsModalSaveType;
-}
+};
export enum ChartTypes {
area = "area",
@@ -171,18 +171,18 @@ export enum ChartTypes {
// scatter3d = "scatter3d",
}
-interface AxisItemType {
+type AxisItemType = {
name: string;
metric: string;
-}
+};
export type YAxisItemType = AxisItemType;
export type XAxisItemType = AxisItemType;
-export interface YAxisItemProps {
+export type YAxisItemProps = {
item: YAxisItemType;
index: number;
metricKeysOptions: ReactSelectOption[];
onDelete: (event: MouseEvent) => void;
onChange: Function;
hideDelete: boolean;
-}
+};
diff --git a/apps/sim-core/packages/core/src/components/App/App.tsx b/apps/sim-core/packages/core/src/components/App/App.tsx
index 1132412e..c6d98311 100644
--- a/apps/sim-core/packages/core/src/components/App/App.tsx
+++ b/apps/sim-core/packages/core/src/components/App/App.tsx
@@ -1,34 +1,56 @@
-import React, { FC } from "react";
-import { Provider } from "react-redux";
+import React, { FC, PropsWithChildren } from "react";
import { ModalProvider } from "react-modal-hook";
-import { Store } from "@reduxjs/toolkit";
-import { RecoilRoot } from "recoil";
import { ErrorBoundary } from "../ErrorBoundary";
+import { ExamplesProvider } from "../../features/examples/ExamplesContext";
+import { FilesProvider } from "../../features/files/FilesContext";
import { FontsPreloader } from "../FontsPreloader";
+import { ProjectProvider } from "../../features/project/ProjectContext";
import { MonacoContainerProvider } from "../TabbedEditor/hooks";
+import { SceneProvider } from "../AgentScene/state/SceneContext";
+import { SearchProvider } from "../../features/search/SearchContext";
import { SimulatorProvider } from "../../features/simulator/context";
+import { MonacoModelSync } from "../../features/monaco/MonacoModelSync";
+import { StoreSync } from "../../features/simulator/simulate/StoreSync";
+import { ToastProvider } from "../../features/toast/ToastContext";
+import { UserProvider } from "../../features/user/UserContext";
+import { ViewerProvider } from "../../features/viewer/ViewerContext";
import "./App.css";
-interface AppProps {
- store: Store;
-}
-
-export const App: FC = ({ store, children }) => (
-
-
-
-
-
-
-
- {children}
-
-
-
-
-
-
-
+/**
+ * Provider ordering: ProjectProvider is below Viewer, Toast, Files so it can
+ * coordinate setProjectWithMeta across those contexts. The simulator keeps
+ * its own Redux store for performance; StoreSync bridges app contexts to it.
+ */
+export const App: FC = ({ children }) => (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {children}
+
+
+
+
+
+
+
+
+
+
+
+
+
);
diff --git a/apps/sim-core/packages/core/src/components/BehaviorKeys/BehaviorKeysFieldForm.tsx b/apps/sim-core/packages/core/src/components/BehaviorKeys/BehaviorKeysFieldForm.tsx
index 0031f946..4967c7ce 100644
--- a/apps/sim-core/packages/core/src/components/BehaviorKeys/BehaviorKeysFieldForm.tsx
+++ b/apps/sim-core/packages/core/src/components/BehaviorKeys/BehaviorKeysFieldForm.tsx
@@ -1,7 +1,6 @@
import React, { FC, useState } from "react";
-import { batch } from "react-redux";
import classNames from "classnames";
-import { debounce } from "lodash";
+import { debounce } from "lodash-es";
import {
BehaviorKeysField,
@@ -76,10 +75,8 @@ export const BehaviorKeysFieldForm: FC = ({
value={fieldName}
onChange={(evt) => {
const value = evt.target.value;
- batch(() => {
- setIsErrorOpen(false);
- onNameChange(value);
- });
+ setIsErrorOpen(false);
+ onNameChange(value);
}}
onBlur={() => {
onNameCommit();
diff --git a/apps/sim-core/packages/core/src/components/BehaviorKeys/BehaviorKeysForm.tsx b/apps/sim-core/packages/core/src/components/BehaviorKeys/BehaviorKeysForm.tsx
index 1e7a4967..470aa92a 100644
--- a/apps/sim-core/packages/core/src/components/BehaviorKeys/BehaviorKeysForm.tsx
+++ b/apps/sim-core/packages/core/src/components/BehaviorKeys/BehaviorKeysForm.tsx
@@ -1,6 +1,5 @@
import React, { FC, useEffect, useRef, useState } from "react";
-import { batch, useDispatch, useSelector } from "react-redux";
-import produce, { Draft } from "immer";
+import { produce, Draft } from "immer";
import {
BehaviorKeysDraftField,
@@ -18,15 +17,8 @@ import { Projection } from "./types";
import { ScrollFadeShadow } from "../ScrollFade/ScrollFadeShadow";
import { SimpleTooltip } from "../SimpleTooltip";
import { addField } from "./utils";
-import {
- parseAndShowBehaviorKeys,
- updateBehaviorKeysDynamicAccess,
-} from "../../features/files/slice";
-import {
- selectBehaviorKeysDynamicAccess,
- selectSharedBehaviorKeyFieldNames,
-} from "../../features/files/selectors";
-import { useAbortingDispatch } from "../../hooks/useAbortingDispatch";
+import { selectSharedBehaviorKeyFieldNames } from "../../features/files/selectors";
+import { useFiles, useFilesSelector } from "../../features/files/FilesContext";
import { useScrollState } from "../../hooks/useScrollState";
import "./BehaviorKeysForm.scss";
@@ -67,10 +59,14 @@ export const BehaviorKeysForm: FC<{
const onDataChangeRef = useRef(onDataChange);
const clashes = calculateRowClashes(data.rows);
- const dispatch = useDispatch();
- const dynamicAccess = useSelector(selectBehaviorKeysDynamicAccess);
+ const {
+ updateBehaviorKeysDynamicAccess,
+ behaviorKeysDynamicAccess: dynamicAccess,
+ } = useFiles();
- const sharedBehaviorKeyNames = useSelector(selectSharedBehaviorKeyFieldNames);
+ const sharedBehaviorKeyNames = useFilesSelector(
+ selectSharedBehaviorKeyFieldNames,
+ );
const lockedNames = projection.length === 0 ? sharedBehaviorKeyNames : [];
const formDisabled =
projection.length === 0
@@ -96,8 +92,20 @@ export const BehaviorKeysForm: FC<{
const listRef = useRef(null);
const [scrollStateRef, contentRemaining] = useScrollState();
- const [dispatchParseAndShowBehaviorKeys, isParsingDisabled] =
- useAbortingDispatch(parseAndShowBehaviorKeys, [autosuggest]);
+ const { handleParseAndShowBehaviorKeys } = useFiles();
+ const [isParsingDisabled, setIsParsingDisabled] = useState(false);
+ const dispatchParseAndShowBehaviorKeys = async ({
+ fileId,
+ }: {
+ fileId: string;
+ }) => {
+ setIsParsingDisabled(true);
+ try {
+ await handleParseAndShowBehaviorKeys(fileId);
+ } finally {
+ setIsParsingDisabled(false);
+ }
+ };
const focusLast = () => {
const fields =
@@ -112,7 +120,7 @@ export const BehaviorKeysForm: FC<{
const onAddField = () => {
setData((draft) => addField(draft, projection.length === 0));
- setTimeout(() => {
+ setImmediate(() => {
if (listRef.current) {
scrollToEnd(listRef.current);
focusLast();
@@ -131,12 +139,7 @@ export const BehaviorKeysForm: FC<{
disabled={disabled}
id="dynamicAccessCheckbox"
onChange={(evt) => {
- dispatch(
- updateBehaviorKeysDynamicAccess({
- fileId,
- dynamicAccess: evt.target.checked,
- }),
- );
+ updateBehaviorKeysDynamicAccess(fileId, evt.target.checked);
}}
/>
Access all fields defined in other behaviors
@@ -242,10 +245,8 @@ export const BehaviorKeysForm: FC<{
}}
onNameCommit={() => {
if (draftData) {
- batch(() => {
- onDataChangeRef.current(draftData.draft.rows);
- setDraftData(null);
- });
+ onDataChangeRef.current(draftData.draft.rows);
+ setDraftData(null);
}
}}
disabled={disabled || formDisabled}
diff --git a/apps/sim-core/packages/core/src/components/BehaviorKeys/BehaviorKeysRow.tsx b/apps/sim-core/packages/core/src/components/BehaviorKeys/BehaviorKeysRow.tsx
index 583b2654..f6677345 100644
--- a/apps/sim-core/packages/core/src/components/BehaviorKeys/BehaviorKeysRow.tsx
+++ b/apps/sim-core/packages/core/src/components/BehaviorKeys/BehaviorKeysRow.tsx
@@ -1,6 +1,6 @@
import React, { FC, HTMLProps } from "react";
import classNames from "classnames";
-import omit from "lodash/omit";
+import omit from "lodash-es/omit";
import "./BehaviorKeysRow.scss";
diff --git a/apps/sim-core/packages/core/src/components/BehaviorKeys/project.ts b/apps/sim-core/packages/core/src/components/BehaviorKeys/project.ts
index 2945ed7f..12f313c8 100644
--- a/apps/sim-core/packages/core/src/components/BehaviorKeys/project.ts
+++ b/apps/sim-core/packages/core/src/components/BehaviorKeys/project.ts
@@ -1,4 +1,4 @@
-import produce from "immer";
+import { produce } from "immer";
import {
BehaviorKeysDraftFieldWithRows,
diff --git a/apps/sim-core/packages/core/src/components/BehaviorKeys/types.ts b/apps/sim-core/packages/core/src/components/BehaviorKeys/types.ts
index 7620c708..bc48eda7 100644
--- a/apps/sim-core/packages/core/src/components/BehaviorKeys/types.ts
+++ b/apps/sim-core/packages/core/src/components/BehaviorKeys/types.ts
@@ -2,14 +2,14 @@ import { Draft } from "immer";
import { BehaviorKeysDraftField } from "../../features/files/behaviorKeys";
-export interface ProjectionItem {
+export type ProjectionItem = {
label: string;
idx: number;
-}
+};
export type Projection = ProjectionItem[];
-export interface BehaviorKeysFieldFormProps {
+export type BehaviorKeysFieldFormProps = {
fieldName: string;
clash: boolean;
projection: ProjectionItem[];
@@ -29,4 +29,4 @@ export interface BehaviorKeysFieldFormProps {
disabled: boolean;
typeDisabled: boolean;
emptyName: boolean;
-}
+};
diff --git a/apps/sim-core/packages/core/src/components/DataLoader/DataLoader.tsx b/apps/sim-core/packages/core/src/components/DataLoader/DataLoader.tsx
index c6383b14..37dcb031 100644
--- a/apps/sim-core/packages/core/src/components/DataLoader/DataLoader.tsx
+++ b/apps/sim-core/packages/core/src/components/DataLoader/DataLoader.tsx
@@ -25,14 +25,14 @@ const paginationPx = 26;
const rowHeightRem = 1.2;
const rowBorderPx = 1;
-interface DataLoaderProps {
+type DataLoaderProps = {
url: string;
editorInstance: EditorInstance | undefined;
manifestId: string | null;
file: HcDatasetFile;
setDidFallback: Dispatch>;
containerHeight?: number;
-}
+};
export const DataLoader: FC = ({
url,
diff --git a/apps/sim-core/packages/core/src/components/DataLoader/hooks/useDataLoaderParser.ts b/apps/sim-core/packages/core/src/components/DataLoader/hooks/useDataLoaderParser.ts
index 772d7354..27bc1aff 100644
--- a/apps/sim-core/packages/core/src/components/DataLoader/hooks/useDataLoaderParser.ts
+++ b/apps/sim-core/packages/core/src/components/DataLoader/hooks/useDataLoaderParser.ts
@@ -9,7 +9,6 @@ import {
import type { DataLoaderParserReducer, DataLoaderParserState } from "../types";
import { HcDatasetFile } from "../../../features/files/types";
import { jsonToRows } from "../utils";
-import { getErrorMessage } from "../../../features/utils";
export const loadingMessage = "Loading...";
export const successMessage = "Success!";
@@ -83,10 +82,10 @@ export const useDataLoaderParser = (
}
({ pathname, format } = result);
- } catch (error) {
+ } catch (error: any) {
dispatch({
type: "invalidUrl",
- payload: { url, errorMessage: getErrorMessage(error) },
+ payload: { url, errorMessage: error.message },
});
return;
}
diff --git a/apps/sim-core/packages/core/src/components/DataLoader/types.ts b/apps/sim-core/packages/core/src/components/DataLoader/types.ts
index dfaa9890..159a7b38 100644
--- a/apps/sim-core/packages/core/src/components/DataLoader/types.ts
+++ b/apps/sim-core/packages/core/src/components/DataLoader/types.ts
@@ -1,42 +1,42 @@
import { Reducer } from "react";
-interface DataLoaderParserMessage {
+type DataLoaderParserMessage = {
message: string;
-}
+};
-interface DataLoaderParserData {
+type DataLoaderParserData = {
headings?: string[];
records?: any[][];
contents?: string;
-}
+};
export type DataLoaderParserState = DataLoaderParserData &
DataLoaderParserMessage;
-interface DataLoaderParserActionSuccess {
+type DataLoaderParserActionSuccess = {
type: "success";
payload: DataLoaderParserData;
-}
+};
-interface DataLoaderParserActionInvalidUrl {
+type DataLoaderParserActionInvalidUrl = {
type: "invalidUrl";
payload: { url: string; errorMessage: string };
-}
+};
-interface DataLoaderParserActionUnparseableValue {
+type DataLoaderParserActionUnparseableValue = {
type: "unparseableValue";
payload: { pathname: string; errorMessage: string };
-}
+};
-interface DataLoaderParserActionUnsupportedExtension {
+type DataLoaderParserActionUnsupportedExtension = {
type: "unsupportedExtension";
payload: { pathname: string; ext: string };
-}
+};
-interface DataLoaderParserActionLoadingError {
+type DataLoaderParserActionLoadingError = {
type: "loadingError";
payload: { pathname: string; errorMessage: string };
-}
+};
type DataLoaderParserAction =
| DataLoaderParserActionSuccess
diff --git a/apps/sim-core/packages/core/src/components/DataTable/Body/DataTableBody.spec.tsx b/apps/sim-core/packages/core/src/components/DataTable/Body/DataTableBody.spec.tsx
index 37b83993..5ed7cf6f 100644
--- a/apps/sim-core/packages/core/src/components/DataTable/Body/DataTableBody.spec.tsx
+++ b/apps/sim-core/packages/core/src/components/DataTable/Body/DataTableBody.spec.tsx
@@ -1,10 +1,12 @@
import React from "react";
-import ReactDOM from "react-dom";
+import { render } from "@testing-library/react";
import { DataTableBody } from "./DataTableBody";
it("renders without crashing", () => {
- const table = document.createElement("table");
- ReactDOM.render(, table);
- ReactDOM.unmountComponentAtNode(table);
+ render(
+ ,
+ );
});
diff --git a/apps/sim-core/packages/core/src/components/DataTable/Body/DataTableBody.tsx b/apps/sim-core/packages/core/src/components/DataTable/Body/DataTableBody.tsx
index b21c0bcc..07bd2a35 100644
--- a/apps/sim-core/packages/core/src/components/DataTable/Body/DataTableBody.tsx
+++ b/apps/sim-core/packages/core/src/components/DataTable/Body/DataTableBody.tsx
@@ -4,10 +4,10 @@ import { DataTableRow } from "..";
import "./DataTableBody.css";
-interface DataTableBodyProps {
+type DataTableBodyProps = {
beginIndex: number;
records: any[][];
-}
+};
export const DataTableBody: FC = memo(
({ beginIndex, records }) => (
diff --git a/apps/sim-core/packages/core/src/components/DataTable/Cell/DataTableCell.spec.tsx b/apps/sim-core/packages/core/src/components/DataTable/Cell/DataTableCell.spec.tsx
index 930915bf..a3858e3b 100644
--- a/apps/sim-core/packages/core/src/components/DataTable/Cell/DataTableCell.spec.tsx
+++ b/apps/sim-core/packages/core/src/components/DataTable/Cell/DataTableCell.spec.tsx
@@ -1,10 +1,16 @@
import React from "react";
-import ReactDOM from "react-dom";
+import { render } from "@testing-library/react";
import { DataTableCell } from "./DataTableCell";
it("renders without crashing", () => {
- const tr = document.createElement("tr");
- ReactDOM.render(, tr);
- ReactDOM.unmountComponentAtNode(tr);
+ render(
+ ,
+ );
});
diff --git a/apps/sim-core/packages/core/src/components/DataTable/Cell/DataTableCell.tsx b/apps/sim-core/packages/core/src/components/DataTable/Cell/DataTableCell.tsx
index 7e9d0a0a..380bd358 100644
--- a/apps/sim-core/packages/core/src/components/DataTable/Cell/DataTableCell.tsx
+++ b/apps/sim-core/packages/core/src/components/DataTable/Cell/DataTableCell.tsx
@@ -5,9 +5,9 @@ import { IconCheck, IconClose } from "../../Icon";
import "./DataTableCell.css";
-interface DataTableCellProps {
+type DataTableCellProps = {
cellValue: any;
-}
+};
enum TypeOf {
Undefined = "undefined",
diff --git a/apps/sim-core/packages/core/src/components/DataTable/DataTable.spec.tsx b/apps/sim-core/packages/core/src/components/DataTable/DataTable.spec.tsx
index 7831bf13..09cdc5c7 100644
--- a/apps/sim-core/packages/core/src/components/DataTable/DataTable.spec.tsx
+++ b/apps/sim-core/packages/core/src/components/DataTable/DataTable.spec.tsx
@@ -1,10 +1,8 @@
import React from "react";
-import ReactDOM from "react-dom";
+import { render } from "@testing-library/react";
import { DataTable } from "./DataTable";
it("renders without crashing", () => {
- const div = document.createElement("div");
- ReactDOM.render(, div);
- ReactDOM.unmountComponentAtNode(div);
+ render();
});
diff --git a/apps/sim-core/packages/core/src/components/DataTable/DataTable.tsx b/apps/sim-core/packages/core/src/components/DataTable/DataTable.tsx
index bbc209b5..d11fe63f 100644
--- a/apps/sim-core/packages/core/src/components/DataTable/DataTable.tsx
+++ b/apps/sim-core/packages/core/src/components/DataTable/DataTable.tsx
@@ -4,11 +4,11 @@ import { DataTableBody, DataTableHead, DataTablePagination } from ".";
import "./DataTable.css";
-interface DataTableProps {
+type DataTableProps = {
headings: string[];
records: any[][];
recordsPerPage?: number;
-}
+};
export const DataTable: FC = memo(
({ headings, records, recordsPerPage = 50 }) => {
diff --git a/apps/sim-core/packages/core/src/components/DataTable/Head/DataTableHead.spec.tsx b/apps/sim-core/packages/core/src/components/DataTable/Head/DataTableHead.spec.tsx
index a4697778..620734fb 100644
--- a/apps/sim-core/packages/core/src/components/DataTable/Head/DataTableHead.spec.tsx
+++ b/apps/sim-core/packages/core/src/components/DataTable/Head/DataTableHead.spec.tsx
@@ -1,10 +1,12 @@
import React from "react";
-import ReactDOM from "react-dom";
+import { render } from "@testing-library/react";
import { DataTableHead } from "./DataTableHead";
it("renders without crashing", () => {
- const table = document.createElement("table");
- ReactDOM.render(, table);
- ReactDOM.unmountComponentAtNode(table);
+ render(
+ ,
+ );
});
diff --git a/apps/sim-core/packages/core/src/components/DataTable/Head/DataTableHead.tsx b/apps/sim-core/packages/core/src/components/DataTable/Head/DataTableHead.tsx
index c0730ed3..d71aba1b 100644
--- a/apps/sim-core/packages/core/src/components/DataTable/Head/DataTableHead.tsx
+++ b/apps/sim-core/packages/core/src/components/DataTable/Head/DataTableHead.tsx
@@ -1,11 +1,11 @@
import React, { FC, memo } from "react";
-import { kebabCase } from "lodash";
+import { kebabCase } from "lodash-es";
import "./DataTableHead.css";
-interface DataTableHeadProps {
+type DataTableHeadProps = {
headings: string[];
-}
+};
export const DataTableHead: FC = memo(({ headings }) => (
<>
diff --git a/apps/sim-core/packages/core/src/components/DataTable/Pagination/DataTablePagination.spec.tsx b/apps/sim-core/packages/core/src/components/DataTable/Pagination/DataTablePagination.spec.tsx
index 3af3ef96..1a9c32d3 100644
--- a/apps/sim-core/packages/core/src/components/DataTable/Pagination/DataTablePagination.spec.tsx
+++ b/apps/sim-core/packages/core/src/components/DataTable/Pagination/DataTablePagination.spec.tsx
@@ -1,17 +1,14 @@
import React from "react";
-import ReactDOM from "react-dom";
+import { render } from "@testing-library/react";
import { DataTablePagination } from "./DataTablePagination";
it("renders without crashing", () => {
- const div = document.createElement("div");
- ReactDOM.render(
+ render(
{}}
totalPages={1}
/>,
- div,
);
- ReactDOM.unmountComponentAtNode(div);
});
diff --git a/apps/sim-core/packages/core/src/components/DataTable/Pagination/DataTablePagination.tsx b/apps/sim-core/packages/core/src/components/DataTable/Pagination/DataTablePagination.tsx
index ad7ffc97..e7b66b3b 100644
--- a/apps/sim-core/packages/core/src/components/DataTable/Pagination/DataTablePagination.tsx
+++ b/apps/sim-core/packages/core/src/components/DataTable/Pagination/DataTablePagination.tsx
@@ -4,11 +4,11 @@ import { FancyButton } from "../../Fancy";
import "./DataTablePagination.css";
-interface DataTablePaginationProps {
+type DataTablePaginationProps = {
currentPage: number;
setCurrentPage: Dispatch>;
totalPages: number;
-}
+};
export const DataTablePagination: FC = memo(
({ currentPage, setCurrentPage, totalPages }) => (
diff --git a/apps/sim-core/packages/core/src/components/DataTable/Row/DataTableRow.spec.tsx b/apps/sim-core/packages/core/src/components/DataTable/Row/DataTableRow.spec.tsx
index 2de326b9..41b25cd7 100644
--- a/apps/sim-core/packages/core/src/components/DataTable/Row/DataTableRow.spec.tsx
+++ b/apps/sim-core/packages/core/src/components/DataTable/Row/DataTableRow.spec.tsx
@@ -1,10 +1,14 @@
import React from "react";
-import ReactDOM from "react-dom";
+import { render } from "@testing-library/react";
import { DataTableRow } from "./DataTableRow";
it("renders without crashing", () => {
- const tbody = document.createElement("tbody");
- ReactDOM.render(, tbody);
- ReactDOM.unmountComponentAtNode(tbody);
+ render(
+ ,
+ );
});
diff --git a/apps/sim-core/packages/core/src/components/DataTable/Row/DataTableRow.tsx b/apps/sim-core/packages/core/src/components/DataTable/Row/DataTableRow.tsx
index 940cf147..f6b9d705 100644
--- a/apps/sim-core/packages/core/src/components/DataTable/Row/DataTableRow.tsx
+++ b/apps/sim-core/packages/core/src/components/DataTable/Row/DataTableRow.tsx
@@ -2,10 +2,10 @@ import React, { FC, memo } from "react";
import { DataTableCell } from "../Cell";
-interface DataTableRowProps {
+type DataTableRowProps = {
rowIndex: number;
record: any[];
-}
+};
export const DataTableRow: FC = memo(
({ rowIndex, record }) => (
diff --git a/apps/sim-core/packages/core/src/components/Dropdown/Dropdown.spec.tsx b/apps/sim-core/packages/core/src/components/Dropdown/Dropdown.spec.tsx
index 68d9095c..a737eacc 100644
--- a/apps/sim-core/packages/core/src/components/Dropdown/Dropdown.spec.tsx
+++ b/apps/sim-core/packages/core/src/components/Dropdown/Dropdown.spec.tsx
@@ -1,13 +1,10 @@
import React from "react";
-import ReactDOM from "react-dom";
+import { render } from "@testing-library/react";
import { Dropdown } from "./Dropdown";
it("renders without crashing", () => {
- const div = document.createElement("div");
- ReactDOM.render(
+ render(
{}} />,
- div,
);
- ReactDOM.unmountComponentAtNode(div);
});
diff --git a/apps/sim-core/packages/core/src/components/Dropdown/MenuList/DropdownMenuList.spec.tsx b/apps/sim-core/packages/core/src/components/Dropdown/MenuList/DropdownMenuList.spec.tsx
index 744fe0d3..41763dc7 100644
--- a/apps/sim-core/packages/core/src/components/Dropdown/MenuList/DropdownMenuList.spec.tsx
+++ b/apps/sim-core/packages/core/src/components/Dropdown/MenuList/DropdownMenuList.spec.tsx
@@ -1,10 +1,8 @@
import React from "react";
-import ReactDOM from "react-dom";
+import { render } from "@testing-library/react";
import { DropdownMenuList } from "./DropdownMenuList";
it("renders without crashing", () => {
- const div = document.createElement("div");
- ReactDOM.render({[]}, div);
- ReactDOM.unmountComponentAtNode(div);
+ render();
});
diff --git a/apps/sim-core/packages/core/src/components/Dropdown/MenuList/DropdownMenuList.tsx b/apps/sim-core/packages/core/src/components/Dropdown/MenuList/DropdownMenuList.tsx
index e8aa0c5d..94808af9 100644
--- a/apps/sim-core/packages/core/src/components/Dropdown/MenuList/DropdownMenuList.tsx
+++ b/apps/sim-core/packages/core/src/components/Dropdown/MenuList/DropdownMenuList.tsx
@@ -1,11 +1,17 @@
-import React, { FC, useRef, useEffect, Children } from "react";
+import React, {
+ FC,
+ PropsWithChildren,
+ useRef,
+ useEffect,
+ Children,
+} from "react";
import { VariableSizeList } from "react-window";
import type { ReactSelectOption } from "../types";
-interface DropdownMenuListProps {
+type DropdownMenuListProps = {
options: ReactSelectOption[];
-}
+};
/**
* these numbers are kinda magic numbers, it's known and tolerated for
@@ -20,7 +26,7 @@ const SUB_LABEL_AVG_SIZE = 46;
const SUB_LABEL_MAX_SIZE = 60;
const LIST_HEIGHT = 200;
-export const DropdownMenuList: FC = ({
+export const DropdownMenuList: FC> = ({
options,
children,
}) => {
diff --git a/apps/sim-core/packages/core/src/components/Dropdown/types.ts b/apps/sim-core/packages/core/src/components/Dropdown/types.ts
index a3a5093c..6365ba04 100644
--- a/apps/sim-core/packages/core/src/components/Dropdown/types.ts
+++ b/apps/sim-core/packages/core/src/components/Dropdown/types.ts
@@ -1,12 +1,12 @@
import { SelectComponents } from "react-select/src/components";
-export interface ReactSelectOption {
+export type ReactSelectOption = {
label: string;
subLabel?: string;
value: string;
-}
+};
-export interface DropdownProps {
+export type DropdownProps = {
options: ReactSelectOption[];
value: ReactSelectOption | ReactSelectOption[] | undefined;
onChange: (option: any) => void;
@@ -28,4 +28,4 @@ export interface DropdownProps {
largeList?: boolean;
className?: string;
creatableIsCaseInsensitive?: boolean;
-}
+};
diff --git a/apps/sim-core/packages/core/src/components/EmbedApp/EmbedApp.tsx b/apps/sim-core/packages/core/src/components/EmbedApp/EmbedApp.tsx
index 899cb6fa..5d92f719 100644
--- a/apps/sim-core/packages/core/src/components/EmbedApp/EmbedApp.tsx
+++ b/apps/sim-core/packages/core/src/components/EmbedApp/EmbedApp.tsx
@@ -1,18 +1,13 @@
import React, { FC } from "react";
-import { useSelector } from "react-redux";
import { HashCoreAccessGate } from "../HashCore/AccessGate/HashCoreAccessGate";
import { HashCoreSection } from "../HashCore/Section/HashCoreSection";
-import {
- selectAccessGate,
- selectProjectLoaded,
-} from "../../features/project/selectors";
+import { useProject } from "../../features/project/ProjectContext";
import "./EmbedApp.scss";
export const EmbedApp: FC = () => {
- const projectLoaded = useSelector(selectProjectLoaded);
- const accessGate = useSelector(selectAccessGate);
+ const { projectLoaded, accessGate } = useProject();
if (accessGate) {
return ;
diff --git a/apps/sim-core/packages/core/src/components/EmbedApp/bootEmbed.tsx b/apps/sim-core/packages/core/src/components/EmbedApp/bootEmbed.tsx
index 757fcf54..9c9f6d16 100644
--- a/apps/sim-core/packages/core/src/components/EmbedApp/bootEmbed.tsx
+++ b/apps/sim-core/packages/core/src/components/EmbedApp/bootEmbed.tsx
@@ -10,54 +10,72 @@ import "../../util/api";
*/
import "../OpenInCore/OpenInCore";
-import React from "react";
-import { render } from "react-dom";
+import React, { FC, useEffect, useRef } from "react";
+import { createRoot } from "react-dom/client";
import { App } from "../App";
import { BasicUser } from "../../util/api/types";
import { EmbedApp } from "./EmbedApp";
import { RemoteSimulationProject } from "../../features/project/types";
import { ValidatedEmbedParams } from "../../util/getEmbedParams";
-import { activateEmbedded } from "../../features/viewer/slice";
import { boot } from "../../boot";
-import { fetchProject } from "../../features/project/slice";
import { getUiQueryParams } from "../../hooks/useParameterisedUi";
-import { setBasicUser } from "../../features/user/slice";
-import { store } from "../../features/store";
+import { useProject } from "../../features/project/ProjectContext";
+import { useUser } from "../../features/user/UserContext";
+import { useViewer } from "../../features/viewer/ViewerContext";
-// @todo error handling
-export const bootEmbed = async (
- params: ValidatedEmbedParams,
- prefetchedProjectPromise: Promise,
- basicUserPromise: Promise,
-) => {
- await boot(false);
+interface EmbedBootstrapProps {
+ params: ValidatedEmbedParams;
+ basicUserPromise: Promise;
+}
+
+/**
+ * Inner component that initializes embed state via context hooks on mount.
+ * This replaces the old pattern of dispatching Redux actions before render.
+ */
+const EmbedBootstrap: FC = ({
+ params,
+ basicUserPromise,
+}) => {
+ const { activateEmbedded } = useViewer();
+ const { fetchProject } = useProject();
+ const { setBasicUser } = useUser();
+ const initialized = useRef(false);
+
+ useEffect(() => {
+ if (initialized.current) return;
+ initialized.current = true;
- const { tabs, view } = getUiQueryParams();
+ const { tabs, view } = getUiQueryParams();
+ activateEmbedded({ tabs, tab: view });
- store.dispatch(activateEmbedded({ tabs, tab: view }));
+ fetchProject({
+ project: { pathWithNamespace: params.project, ref: params.ref },
+ redirect: false,
+ });
- await Promise.all([
- store.dispatch(
- //@ts-expect-error redux problems
- fetchProject({
- project: { pathWithNamespace: params.project, ref: params.ref },
- prefetchedRemoteProject: prefetchedProjectPromise,
- redirect: false,
- access: params.access,
- }),
- ),
basicUserPromise.then((basicUser) => {
if (basicUser) {
- return store.dispatch(setBasicUser(basicUser));
+ setBasicUser(basicUser);
}
- }),
- ]);
+ });
+ }, [activateEmbedded, fetchProject, setBasicUser, params, basicUserPromise]);
+
+ return ;
+};
+
+// @todo error handling
+export const bootEmbed = async (
+ params: ValidatedEmbedParams,
+ _prefetchedProjectPromise: Promise,
+ basicUserPromise: Promise,
+) => {
+ await boot(false);
- render(
-
-
+ const root = createRoot(document.getElementById("root")!);
+ root.render(
+
+
,
- document.getElementById("root"),
);
};
diff --git a/apps/sim-core/packages/core/src/components/ErrorBoundary/ErrorBoundary.spec.tsx b/apps/sim-core/packages/core/src/components/ErrorBoundary/ErrorBoundary.spec.tsx
index 27b08b02..f7f56e6a 100644
--- a/apps/sim-core/packages/core/src/components/ErrorBoundary/ErrorBoundary.spec.tsx
+++ b/apps/sim-core/packages/core/src/components/ErrorBoundary/ErrorBoundary.spec.tsx
@@ -1,10 +1,8 @@
import React from "react";
-import ReactDOM from "react-dom";
+import { render } from "@testing-library/react";
import { ErrorBoundary } from "./ErrorBoundary";
it("renders without crashing", () => {
- const div = document.createElement("div");
- ReactDOM.render({null}, div);
- ReactDOM.unmountComponentAtNode(div);
+ render({null});
});
diff --git a/apps/sim-core/packages/core/src/components/ErrorBoundary/ErrorBoundary.tsx b/apps/sim-core/packages/core/src/components/ErrorBoundary/ErrorBoundary.tsx
index d014e1e7..246b2ef2 100644
--- a/apps/sim-core/packages/core/src/components/ErrorBoundary/ErrorBoundary.tsx
+++ b/apps/sim-core/packages/core/src/components/ErrorBoundary/ErrorBoundary.tsx
@@ -1,14 +1,15 @@
import React, {
Component,
createContext,
+ ErrorInfo,
FC,
+ PropsWithChildren,
useContext,
useMemo,
useState,
} from "react";
import { customAlphabet } from "nanoid";
-import { BasicDiscordWidget } from "../DiscordWidget/DiscordWidget";
import { BigModal } from "../Modal";
import { ErrorDetails } from "../ErrorDetails";
import { FancyButton } from "../Fancy";
@@ -41,17 +42,15 @@ const quotableId = (() => {
.padStart(2, "0")}${generateHashEventId()}`;
})();
-// eslint-disable-next-line @typescript-eslint/no-empty-interface
-interface ErrorBoundaryProps {}
-interface ErrorBoundaryState {
+type ErrorBoundaryProps = {};
+type ErrorBoundaryState = {
didError: boolean;
errorName?: string;
errorMessage?: string;
errorStack?: string;
- eventId: string | null;
detailsHidden: boolean;
hashEventId: string | null;
-}
+};
type TErrorBoundaryContext = {
handlePromiseRejection: (promise: Promise) => void;
@@ -78,7 +77,7 @@ export const useFatalError = () => useContext(ErrorBoundaryContext)!.fatalError;
*
* @see https://github.com/facebook/react/issues/14981#issuecomment-468460187
*/
-const ErrorBoundaryContextProvider: FC = ({ children }) => {
+const ErrorBoundaryContextProvider: FC = ({ children }) => {
const [, catchError] = useState();
const contextValue = useMemo(() => {
const fatalError = (err: any) => {
@@ -125,11 +124,14 @@ export class ErrorBoundary extends Component<
errorName: undefined,
errorMessage: undefined,
errorStack: undefined,
- eventId: null,
detailsHidden: true,
hashEventId: null,
};
+ componentDidCatch(_error: Error, _errorInfo: ErrorInfo) {
+ // Error captured and displayed to user
+ }
+
render() {
const {
didError,
@@ -161,7 +163,6 @@ export class ErrorBoundary extends Component<
troubleshooting guide
@@ -194,7 +195,6 @@ export class ErrorBoundary extends Component<
REFRESH PAGE
-
) : (
diff --git a/apps/sim-core/packages/core/src/components/ErrorDetails/ErrorDetails.spec.tsx b/apps/sim-core/packages/core/src/components/ErrorDetails/ErrorDetails.spec.tsx
index e3517de6..f7391168 100644
--- a/apps/sim-core/packages/core/src/components/ErrorDetails/ErrorDetails.spec.tsx
+++ b/apps/sim-core/packages/core/src/components/ErrorDetails/ErrorDetails.spec.tsx
@@ -1,18 +1,15 @@
import React from "react";
-import ReactDOM from "react-dom";
+import { render } from "@testing-library/react";
import { ErrorDetails } from "./ErrorDetails";
it("renders without crashing", () => {
- const div = document.createElement("div");
- ReactDOM.render(
+ render(