Skip to content

Commit

Permalink
Fix build:dev (styled err) (#7248)
Browse files Browse the repository at this point in the history
* Reapply "Implement a global lazyLoading error handling (#7227)" (#7242)

This reverts commit fc42926.

* put the global context inside the globalStyleProvider

* GlobalErrorDialog without custom components

* dev logging

* Revert "dev logging"

This reverts commit 172b67a.

* update emotion package, fix imports, serve:dev script
  • Loading branch information
bobbykolev authored Nov 25, 2024
1 parent fc42926 commit 14c64ed
Show file tree
Hide file tree
Showing 19 changed files with 1,725 additions and 296 deletions.
1,652 changes: 1,440 additions & 212 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"lint": "tsc --noEmit && eslint src/**/*.ts{,x}",
"lint:fix": "tsc --noEmit && eslint src/**/*.ts{,x} --fix",
"lint:prod": "tsc --noEmit && cross-env NODE_ENV=production eslint src/**/*.ts{,x}",
"serve:dev": "serve -s build -l 3001",
"start": "cross-env NODE_ENV=development node buildConfiguration && vite --host",
"test": "vitest",
"test:coverage": "cross-env NODE_ENV=test node buildConfiguration && vitest run --coverage.enabled --coverage.provider=istanbul --coverage.all --coverage.reporter=lcov",
Expand Down Expand Up @@ -79,8 +80,8 @@
"@apollo/client": "^3.10.8",
"@elastic/apm-rum": "^5.12.0",
"@elastic/apm-rum-react": "^1.4.2",
"@emotion/react": "^11.5.0",
"@emotion/styled": "^11.3.0",
"@emotion/react": "^11.13.5",
"@emotion/styled": "^11.13.5",
"@mui/base": "^5.0.0-beta.23",
"@mui/icons-material": "^5.15.10",
"@mui/lab": "^5.0.0-alpha.56",
Expand Down Expand Up @@ -192,6 +193,7 @@
"husky": "^4.3.7",
"lint-staged": "^13.0.3",
"prettier": "^2.5.1",
"serve": "^14.2.4",
"source-map-explorer": "^2.5.3",
"vite": "^5.3.4",
"vite-plugin-svgr": "^4.2.0",
Expand Down
4 changes: 4 additions & 0 deletions src/core/i18n/en/translation.en.json
Original file line number Diff line number Diff line change
Expand Up @@ -2557,6 +2557,10 @@
"line3": "If the error persists please contact support.",
"buttons": {
"reload": "Reload"
},
"errors": {
"LazyLoadError": "Network error occurred. Please try reloading the page.",
"unknown": "An unknown error occurred. Please try reloading the page."
}
},
"four-ou-four": {
Expand Down
38 changes: 38 additions & 0 deletions src/core/lazyLoading/GlobalErrorContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React, { createContext, useContext, useState, ReactNode } from 'react';

type GlobalErrorContextType = {
error: Error | null;
setError: (error: Error | null) => void;
};

// Global function to set error (to be initialized by provider)
let setGlobalError: ((error: Error | null) => void) | null = null;

export const useGlobalError = (): GlobalErrorContextType => {
const context = useContext(GlobalErrorContext);
if (!context) {
throw new Error('useGlobalError must be used within a GlobalErrorProvider');
}
return context;
};

const GlobalErrorContext = createContext<GlobalErrorContextType | undefined>(undefined);

// GlobalErrorProvider but used only for LazyLoading ATM
// see SentryErrorBoundary for global error handling
export const GlobalErrorProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
const [error, setError] = useState<Error | null>(null);

// Set the global error function during initialization
setGlobalError = setError;

return <GlobalErrorContext.Provider value={{ error, setError }}>{children}</GlobalErrorContext.Provider>;
};

// the global error setter
export const getGlobalErrorSetter = (): ((error: Error | null) => void) => {
if (!setGlobalError) {
throw new Error('GlobalErrorProvider is not initialized.');
}
return setGlobalError;
};
52 changes: 52 additions & 0 deletions src/core/lazyLoading/GlobalErrorDialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import React from 'react';
import { Trans, useTranslation } from 'react-i18next';
import { Box, Button, Dialog, DialogContent, DialogTitle } from '@mui/material';
import { useGlobalError } from './GlobalErrorContext';
import { LazyLoadError } from './lazyWithGlobalErrorHandler';
import TranslationKey from '@/core/i18n/utils/TranslationKey';

const ErrorTranslationMappings = (error: Error): TranslationKey => {
if (error instanceof LazyLoadError) {
return 'pages.error.errors.LazyLoadError';
}
return 'pages.error.errors.unknown';
};

export const GlobalErrorDialog: React.FC = () => {
const { t } = useTranslation();
const { error, setError } = useGlobalError();

if (!error) return null;

return (
<Dialog open={!!error} aria-labelledby="global-error-dialog" onClose={() => setError(null)}>
<DialogTitle sx={{ m: 0, p: 2 }} id="customized-dialog-title">
{t('pages.error.title')}
</DialogTitle>
<DialogContent>
<Box>
<Trans
i18nKey="pages.error.line1"
values={{
message: t(ErrorTranslationMappings(error)),
}}
components={{
italic: <i />,
}}
/>
</Box>
<Box sx={{ display: 'flex', justifyContent: 'flex-end', marginTop: '20px' }}>
<Button
variant="contained"
onClick={() => {
setError(null);
window.location.reload();
}}
>
{t('pages.error.buttons.reload')}
</Button>
</Box>
</DialogContent>
</Dialog>
);
};
49 changes: 49 additions & 0 deletions src/core/lazyLoading/lazyWithGlobalErrorHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import React from 'react';
import { getGlobalErrorSetter } from './GlobalErrorContext';

type ImportFunc<T> = () => Promise<{ default: React.ComponentType<T> }>;

export class LazyLoadError extends Error {
constructor(originalError: Error) {
super(originalError.message);
this.name = 'LazyLoadError';
Object.setPrototypeOf(this, LazyLoadError.prototype);
}
}

export const lazyWithGlobalErrorHandler = <T>(
importFunc: ImportFunc<T>
): React.LazyExoticComponent<React.ComponentType<T>> => {
return React.lazy(async () => {
try {
return await importFunc();
} catch (error) {
const setError = getGlobalErrorSetter();
const originalError: Error =
error instanceof Error ? error : error?.['message'] ? new Error(error['message']) : new Error('Unknown error');

setError(new LazyLoadError(originalError));

// it looks like this error is already logged by the useErrorLoggerLink (network error)

// Instead of throwing, return a fallback component to prevent
// catching it in the ErrorBoundary
return {
default: () => null,
};
}
});
};

export const lazyImportWithErrorHandler = async <T>(importFunc: () => Promise<T>): Promise<T> => {
try {
return await importFunc();
} catch (error) {
const setError = getGlobalErrorSetter();
const originalError: Error =
error instanceof Error ? error : error?.['message'] ? new Error(error['message']) : new Error('Unknown error');

setError(new LazyLoadError(originalError));
throw new LazyLoadError(originalError);
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ import useWhiteboardFilesManager from '@/domain/common/whiteboard/excalidraw/use
import { WhiteboardTemplateContent } from '@/domain/templates/models/WhiteboardTemplate';
import { WhiteboardDetails } from './WhiteboardDialog';
import { Identifiable } from '@/core/utils/Identifiable';
import type { serializeAsJSON as ExcalidrawSerializeAsJSON } from '@alkemio/excalidraw';
import { lazyImportWithErrorHandler } from '@/core/lazyLoading/lazyWithGlobalErrorHandler';

type ExcalidrawUtils = {
serializeAsJSON: typeof ExcalidrawSerializeAsJSON;
};

export interface WhiteboardWithContent extends WhiteboardDetails {
content: string;
Expand Down Expand Up @@ -116,8 +122,7 @@ const SingleUserWhiteboardDialog = ({ entities, actions, options, state }: Singl
if (!state) {
return;
}

const { serializeAsJSON } = await import('@alkemio/excalidraw');
const { serializeAsJSON } = await lazyImportWithErrorHandler<ExcalidrawUtils>(() => import('@alkemio/excalidraw'));

const { appState, elements, files } = await filesManager.convertLocalFilesToRemoteInWhiteboard(state);

Expand Down Expand Up @@ -153,7 +158,9 @@ const SingleUserWhiteboardDialog = ({ entities, actions, options, state }: Singl

const onClose = async (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
if (excalidrawAPI && options.canEdit) {
const { serializeAsJSON } = await import('@alkemio/excalidraw');
const { serializeAsJSON } = await lazyImportWithErrorHandler<ExcalidrawUtils>(
() => import('@alkemio/excalidraw')
);

const elements = excalidrawAPI.getSceneElements();
const appState = excalidrawAPI.getAppState();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,15 @@ import getWhiteboardPreviewDimensions from './getWhiteboardPreviewDimensions';
import { VisualType } from '@/core/apollo/generated/graphql-schema';
import { useUploadVisualMutation } from '@/core/apollo/generated/apollo-hooks';
import { BannerDimensions, BannerNarrowDimensions } from './WhiteboardDimensions';
import type { exportToBlob as ExcalidrawExportToBlob } from '@alkemio/excalidraw';
import { lazyImportWithErrorHandler } from '@/core/lazyLoading/lazyWithGlobalErrorHandler';

type RelevantExcalidrawState = Pick<ExportedDataState, 'appState' | 'elements' | 'files'>;

type ExcalidrawUtils = {
exportToBlob: typeof ExcalidrawExportToBlob;
};

export interface PreviewImageDimensions {
maxWidth: number;
maxHeight: number;
Expand Down Expand Up @@ -43,7 +49,7 @@ export const generateWhiteboardPreviewImages = async <Whiteboard extends Whitebo

const previewImages: WhiteboardPreviewImage[] = [];

const { exportToBlob } = await import('@alkemio/excalidraw');
const { exportToBlob } = await lazyImportWithErrorHandler<ExcalidrawUtils>(() => import('@alkemio/excalidraw'));

previewImages.push({
visualType: VisualType.Banner,
Expand Down
19 changes: 14 additions & 5 deletions src/domain/collaboration/whiteboard/utils/mergeWhiteboard.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
import type { ExcalidrawElement } from '@alkemio/excalidraw/dist/excalidraw/element/types';
import type { BinaryFileData, ExcalidrawImperativeAPI } from '@alkemio/excalidraw/dist/excalidraw/types';
import { v4 as uuidv4 } from 'uuid';
import { StoreAction } from '@alkemio/excalidraw';
import type {
StoreAction as ExcalidrawStoreAction,
getSceneVersion as ExcalidrawGetSceneVersion,
} from '@alkemio/excalidraw';
import { lazyImportWithErrorHandler } from '@/core/lazyLoading/lazyWithGlobalErrorHandler';

const ANIMATION_SPEED = 2000;
const ANIMATION_ZOOM_FACTOR = 0.75;

type ExcalidrawElementWithContainerId = ExcalidrawElement & { containerId: string | null };
type ExcalidrawUtils = {
StoreAction: typeof ExcalidrawStoreAction;
getSceneVersion: typeof ExcalidrawGetSceneVersion;
};

class WhiteboardMergeError extends Error {}

interface WhiteboardLike {
Expand Down Expand Up @@ -122,9 +131,9 @@ const displaceElements = (displacement: { x: number; y: number }) => (element: E
});

const mergeWhiteboard = async (whiteboardApi: ExcalidrawImperativeAPI, whiteboardContent: string) => {
const excalidrawUtils: {
getSceneVersion: (elements: readonly ExcalidrawElement[]) => number;
} = await import('@alkemio/excalidraw');
const { getSceneVersion, StoreAction } = await lazyImportWithErrorHandler<ExcalidrawUtils>(
() => import('@alkemio/excalidraw')
);

let parsedWhiteboard: unknown;
try {
Expand All @@ -147,7 +156,7 @@ const mergeWhiteboard = async (whiteboardApi: ExcalidrawImperativeAPI, whiteboar
}

const currentElements = whiteboardApi.getSceneElementsIncludingDeleted();
const sceneVersion = excalidrawUtils.getSceneVersion(whiteboardApi.getSceneElementsIncludingDeleted());
const sceneVersion = getSceneVersion(whiteboardApi.getSceneElementsIncludingDeleted());

const currentElementsBBox = getBoundingBox(currentElements);
const insertedWhiteboardBBox = getBoundingBox(parsedWhiteboard.elements);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,12 @@ import { useTick } from '@/core/utils/time/tick';
import useWhiteboardDefaults from './useWhiteboardDefaults';
import Loading from '@/core/ui/loading/Loading';
import { Identifiable } from '@/core/utils/Identifiable';
import { lazyWithGlobalErrorHandler } from '@/core/lazyLoading/lazyWithGlobalErrorHandler';

const FILE_IMPORT_ENABLED = true;
const SAVE_FILE_TO_DISK = true;

const Excalidraw = React.lazy(async () => {
const Excalidraw = lazyWithGlobalErrorHandler(async () => {
const { Excalidraw } = await import('@alkemio/excalidraw');
await import('@alkemio/excalidraw/index.css');
return { default: Excalidraw };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import EmptyWhiteboard from '../EmptyWhiteboard';
import { WhiteboardFilesManager } from './useWhiteboardFilesManager';
import useWhiteboardDefaults from './useWhiteboardDefaults';
import Loading from '@/core/ui/loading/Loading';
import { lazyWithGlobalErrorHandler } from '@/core/lazyLoading/lazyWithGlobalErrorHandler';

const useActorWhiteboardStyles = makeStyles(theme => ({
container: {
Expand Down Expand Up @@ -55,7 +56,7 @@ type RefreshWhiteboardStateParam = Parameters<ExcalidrawImperativeAPI['updateSce

const WINDOW_SCROLL_HANDLER_DEBOUNCE_INTERVAL = 100;

const Excalidraw = React.lazy(async () => {
const Excalidraw = lazyWithGlobalErrorHandler(async () => {
const { Excalidraw } = await import('@alkemio/excalidraw');
await import('@alkemio/excalidraw/index.css');
return { default: Excalidraw };
Expand Down
Loading

0 comments on commit 14c64ed

Please sign in to comment.