From aad65543c98f07a719fb227de911250b53477c30 Mon Sep 17 00:00:00 2001 From: yuhsuan Date: Thu, 24 Oct 2024 17:01:39 +0800 Subject: [PATCH 01/14] upgrade react and patch golden-layout --- package-lock.json | 33 +++++++++++++++++++------------ package.json | 8 ++++---- patches/golden-layout+1.5.9.patch | 24 ++++++++++++++++++++++ src/index.tsx | 9 ++++++--- 4 files changed, 54 insertions(+), 20 deletions(-) create mode 100644 patches/golden-layout+1.5.9.patch diff --git a/package-lock.json b/package-lock.json index 5c251c53d1..8534d3a9ba 100644 --- a/package-lock.json +++ b/package-lock.json @@ -67,10 +67,10 @@ "protobufjs": "^7.3.2", "protobufjs-cli": "1.1.2", "raw-loader": "^4.0.2", - "react": "^17.0.2", + "react": "^18.3.1", "react-chartjs-2": "^5.2.0", "react-color": "^2.17.3", - "react-dom": "^17.0.2", + "react-dom": "^18.3.1", "react-iframe": "^1.8.5", "react-konva": "^17.0.2-6", "react-plotly.js": "^2.6.0", @@ -16061,12 +16061,11 @@ } }, "node_modules/react": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", - "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" + "loose-envify": "^1.1.0" }, "engines": { "node": ">=0.10.0" @@ -16241,17 +16240,25 @@ } }, "node_modules/react-dom": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", - "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "dev": true, "dependencies": { "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "scheduler": "^0.20.2" + "scheduler": "^0.23.2" }, "peerDependencies": { - "react": "17.0.2" + "react": "^18.3.1" + } + }, + "node_modules/react-dom/node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "dev": true, + "dependencies": { + "loose-envify": "^1.1.0" } }, "node_modules/react-draggable": { diff --git a/package.json b/package.json index a9a3dc8489..c3b908fa42 100644 --- a/package.json +++ b/package.json @@ -58,10 +58,10 @@ "protobufjs": "^7.3.2", "protobufjs-cli": "1.1.2", "raw-loader": "^4.0.2", - "react": "^17.0.2", + "react": "^18.3.1", "react-chartjs-2": "^5.2.0", "react-color": "^2.17.3", - "react-dom": "^17.0.2", + "react-dom": "^18.3.1", "react-iframe": "^1.8.5", "react-konva": "^17.0.2-6", "react-plotly.js": "^2.6.0", @@ -204,8 +204,8 @@ "usehooks-ts": "^3.1.0" }, "overrides": { - "react": "^17.0.2", - "react-dom": "^17.0.2", + "react": "^18.3.1", + "react-dom": "^18.3.1", "typescript": "^5.5.4", "fork-ts-checker-webpack-plugin": "^6.5.3", "@typescript-eslint/typescript-estree": "^7.15.0", diff --git a/patches/golden-layout+1.5.9.patch b/patches/golden-layout+1.5.9.patch new file mode 100644 index 0000000000..46112b1008 --- /dev/null +++ b/patches/golden-layout+1.5.9.patch @@ -0,0 +1,24 @@ +diff --git a/node_modules/golden-layout/dist/goldenlayout.js b/node_modules/golden-layout/dist/goldenlayout.js +index 736f9ec..9c59284 100644 +--- a/node_modules/golden-layout/dist/goldenlayout.js ++++ b/node_modules/golden-layout/dist/goldenlayout.js +@@ -5265,7 +5265,9 @@ lm.utils.copy( lm.utils.ReactComponentHandler.prototype, { + * @returns {void} + */ + _render: function() { +- this._reactComponent = ReactDOM.render( this._getReactComponent(), this._container.getElement()[ 0 ] ); ++ this._reactRoot = createRoot( this._container.getElement()[ 0 ] ); ++ this._reactRoot.render( this._getReactComponent() ); ++ this._reactComponent = this._getReactComponent(); + this._originalComponentWillUpdate = this._reactComponent.componentWillUpdate || function() { + }; + this._reactComponent.componentWillUpdate = this._onUpdate.bind( this ); +@@ -5281,7 +5283,7 @@ lm.utils.copy( lm.utils.ReactComponentHandler.prototype, { + * @returns {void} + */ + _destroy: function() { +- ReactDOM.unmountComponentAtNode( this._container.getElement()[ 0 ] ); ++ this._reactRoot.unmount(); + this._container.off( 'open', this._render, this ); + this._container.off( 'destroy', this._destroy, this ); + }, diff --git a/src/index.tsx b/src/index.tsx index e33773374e..8c67ad01bf 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,5 +1,6 @@ import * as React from "react"; import * as ReactDOM from "react-dom"; +import {createRoot} from "react-dom/client"; import {FocusStyleManager, OverlaysProvider} from "@blueprintjs/core"; import axios from "axios"; @@ -27,6 +28,7 @@ FocusStyleManager.onlyShowFocusOnTabs(); // GoldenLayout requires these in the global namespace window["React"] = React; // tslint:disable-line window["ReactDOM"] = ReactDOM; // tslint:disable-line +window["createRoot"] = createRoot; // tslint:disable-line async function fetchConfig() { const baseUrl = window.location.href.replace(window.location.search, "").replace("index.html", ""); @@ -39,11 +41,12 @@ async function fetchConfig() { ApiService.SetRuntimeConfig({}); } - ReactDOM.render( + const container = document.getElementById("root") as HTMLElement; + const root = createRoot(container); + root.render( - , - document.getElementById("root") as HTMLElement + ); } From a998e7f03f9a90f2f44fcdca65d1ef9c6e375922 Mon Sep 17 00:00:00 2001 From: yuhsuan Date: Fri, 25 Oct 2024 12:05:38 +0800 Subject: [PATCH 02/14] migrate dialog workaround to react 18 --- .../Dialogs/DraggableDialog/DraggableDialogComponent.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/components/Dialogs/DraggableDialog/DraggableDialogComponent.tsx b/src/components/Dialogs/DraggableDialog/DraggableDialogComponent.tsx index 40b63dc879..c8e8bb4547 100644 --- a/src/components/Dialogs/DraggableDialog/DraggableDialogComponent.tsx +++ b/src/components/Dialogs/DraggableDialog/DraggableDialogComponent.tsx @@ -1,6 +1,6 @@ // Based on code from https://github.com/palantir/blueprint/issues/336 import * as React from "react"; -import * as ReactDOM from "react-dom"; +import {createRoot} from "react-dom/client"; import {ResizeEnable, Rnd} from "react-rnd"; import {Button, Classes, Dialog, DialogProps} from "@blueprintjs/core"; import {observer} from "mobx-react"; @@ -41,7 +41,10 @@ export class DraggableDialogComponent extends React.Component; const helpButtonDiv = document.createElement("div") as HTMLDivElement; helpButtonDiv.setAttribute("class", "help-button"); - ReactDOM.render(helpButton, helpButtonDiv); + + const root = createRoot(helpButtonDiv); + root.render(helpButton); + const closeButton = this.dd.current.getElementsByClassName(Classes.DIALOG_CLOSE_BUTTON); if (closeButton.length > 0) { closeButton[0].before(helpButtonDiv); From 49f5c437aa7bf1d63ad2e7b3da8ff36f7e71f43d Mon Sep 17 00:00:00 2001 From: yuhsuan Date: Fri, 25 Oct 2024 14:11:38 +0800 Subject: [PATCH 03/14] migrate blueprint toaster to react 18 --- .../CodeSnippetDialogComponent.tsx | 2 +- .../FileBrowserDialogComponent.tsx | 8 +-- .../PreferenceDialogComponent.tsx | 2 +- .../ShareWorkspaceDialogComponent.tsx | 2 +- .../WorkspaceDialogComponent.tsx | 6 +- src/components/Menu/RootMenuComponent.tsx | 4 +- src/components/Shared/toaster.ts | 16 +++-- src/services/ApiService.ts | 6 +- src/services/CatalogApiService.ts | 14 ++-- src/stores/AppStore/AppStore.ts | 72 +++++++++---------- .../FileBrowserStore/FileBrowserStore.ts | 2 +- .../ImageFittingStore/ImageFittingStore.ts | 2 +- src/stores/LayoutStore/LayoutStore.ts | 12 ++-- src/stores/Snippet/SnippetStore.ts | 4 +- 14 files changed, 79 insertions(+), 73 deletions(-) diff --git a/src/components/Dialogs/CodeSnippetDialog/CodeSnippetDialogComponent.tsx b/src/components/Dialogs/CodeSnippetDialog/CodeSnippetDialogComponent.tsx index 5f43f2204b..d2360726c2 100644 --- a/src/components/Dialogs/CodeSnippetDialog/CodeSnippetDialogComponent.tsx +++ b/src/components/Dialogs/CodeSnippetDialog/CodeSnippetDialogComponent.tsx @@ -78,7 +78,7 @@ export class CodeSnippetDialogComponent extends React.Component { if (snippetStore.validInput && !snippetStore.isExecuting) { const success = await snippetStore.executeCurrentSnippet(); if (!success) { - AppToaster.show(WarningToast("Error encountered while executing snippet. See JavaScript console for details.")); + (await AppToaster).show(WarningToast("Error encountered while executing snippet. See JavaScript console for details.")); } } this.tryRefocusEditor(); diff --git a/src/components/Dialogs/FileBrowser/FileBrowserDialogComponent.tsx b/src/components/Dialogs/FileBrowser/FileBrowserDialogComponent.tsx index 610d2db56c..f543609728 100644 --- a/src/components/Dialogs/FileBrowser/FileBrowserDialogComponent.tsx +++ b/src/components/Dialogs/FileBrowser/FileBrowserDialogComponent.tsx @@ -199,7 +199,7 @@ export class FileBrowserDialogComponent extends React.Component { this.overwriteExistingFileAlertVisible = true; } else { console.error(err.message); - AppToaster.show({icon: "warning-sign", message: err.message, intent: "danger", timeout: 3000}); + (await AppToaster).show({icon: "warning-sign", message: err.message, intent: "danger", timeout: 3000}); } } }; @@ -219,7 +219,7 @@ export class FileBrowserDialogComponent extends React.Component { this.overwriteExistingFileAlertVisible = true; } else { console.error(err.message); - AppToaster.show(ErrorToast(err.message)); + (await AppToaster).show(ErrorToast(err.message)); } } }; @@ -245,14 +245,14 @@ export class FileBrowserDialogComponent extends React.Component { await this.exportRegion(fileBrowserStore.fileList.directory, filename, true); } catch (err) { console.error(err.message); - AppToaster.show(ErrorToast(err.message)); + (await AppToaster).show(ErrorToast(err.message)); } } else if (fileBrowserStore.browserMode === BrowserMode.SaveFile) { try { await this.handleSaveFile(true); } catch (err) { console.error(err.message); - AppToaster.show({icon: "warning-sign", message: err.message, intent: "danger", timeout: 3000}); + (await AppToaster).show({icon: "warning-sign", message: err.message, intent: "danger", timeout: 3000}); } } }; diff --git a/src/components/Dialogs/PreferenceDialog/PreferenceDialogComponent.tsx b/src/components/Dialogs/PreferenceDialog/PreferenceDialogComponent.tsx index c196a4ff87..7488806f7a 100644 --- a/src/components/Dialogs/PreferenceDialog/PreferenceDialogComponent.tsx +++ b/src/components/Dialogs/PreferenceDialog/PreferenceDialogComponent.tsx @@ -148,7 +148,7 @@ export class PreferenceDialogComponent extends React.Component { const appStore = AppStore.Instance; try { await copyToClipboard(appStore.telemetryService.decodedUserId); - AppToaster.show(SuccessToast("clipboard", "Copied user ID to clipboard.")); + (await AppToaster).show(SuccessToast("clipboard", "Copied user ID to clipboard.")); } catch (err) { console.log(err); } diff --git a/src/components/Dialogs/ShareWorkspaceDialog/ShareWorkspaceDialogComponent.tsx b/src/components/Dialogs/ShareWorkspaceDialog/ShareWorkspaceDialogComponent.tsx index b65212cd6f..f3cc12b461 100644 --- a/src/components/Dialogs/ShareWorkspaceDialog/ShareWorkspaceDialogComponent.tsx +++ b/src/components/Dialogs/ShareWorkspaceDialog/ShareWorkspaceDialogComponent.tsx @@ -51,7 +51,7 @@ export const ShareWorkspaceDialogComponent = observer(() => { setShareKey(shareKey); } catch (err) { console.log(err); - AppToaster.show(WarningToast("Could not generate a sharing link.")); + (await AppToaster).show(WarningToast("Could not generate a sharing link.")); } }; diff --git a/src/components/Dialogs/WorkspaceDialog/WorkspaceDialogComponent.tsx b/src/components/Dialogs/WorkspaceDialog/WorkspaceDialogComponent.tsx index 0298ba1d2a..1751dd5373 100644 --- a/src/components/Dialogs/WorkspaceDialog/WorkspaceDialogComponent.tsx +++ b/src/components/Dialogs/WorkspaceDialog/WorkspaceDialogComponent.tsx @@ -71,14 +71,14 @@ export const WorkspaceDialogComponent = observer(() => { try { const res = await appStore.saveWorkspace(name); if (res) { - AppToaster.show(SuccessToast("floppy-disk", "Workspace saved")); + (await AppToaster).show(SuccessToast("floppy-disk", "Workspace saved")); handleCloseClicked(); return; } } catch (err) { console.log(err); } - AppToaster.show(ErrorToast("Error saving workspace")); + (await AppToaster).show(ErrorToast("Error saving workspace")); setIsFetching(false); }, [appStore, handleCloseClicked] @@ -94,7 +94,7 @@ export const WorkspaceDialogComponent = observer(() => { try { const res = await appStore.loadWorkspace(name); if (res) { - AppToaster.show(SuccessToast("floppy-disk", "Workspace loaded")); + (await AppToaster).show(SuccessToast("floppy-disk", "Workspace loaded")); handleCloseClicked(); return; } diff --git a/src/components/Menu/RootMenuComponent.tsx b/src/components/Menu/RootMenuComponent.tsx index 79913eeb24..e9b0b5097f 100644 --- a/src/components/Menu/RootMenuComponent.tsx +++ b/src/components/Menu/RootMenuComponent.tsx @@ -189,7 +189,7 @@ export class RootMenuComponent extends React.Component { onClick={async () => { try { await copyToClipboard(appStore.backendService.sessionId.toString()); - AppToaster.show(SuccessToast("clipboard", "Session ID copied!")); + (await AppToaster).show(SuccessToast("clipboard", "Session ID copied!")); } catch (err) { console.log(err); } @@ -212,7 +212,7 @@ export class RootMenuComponent extends React.Component { } else { await copyToClipboard(document.URL); } - AppToaster.show(SuccessToast("clipboard", "Session URL copied!")); + (await AppToaster).show(SuccessToast("clipboard", "Session URL copied!")); } catch (err) { console.log(err); } diff --git a/src/components/Shared/toaster.ts b/src/components/Shared/toaster.ts index 2874f1f867..b2e3e471f0 100644 --- a/src/components/Shared/toaster.ts +++ b/src/components/Shared/toaster.ts @@ -1,11 +1,17 @@ -import {IconName, Position, Toaster, ToastProps} from "@blueprintjs/core"; +import {createRoot} from "react-dom/client"; +import {IconName, OverlayToaster, Position, ToastProps} from "@blueprintjs/core"; import {copyToClipboard} from "utilities"; -export const AppToaster = Toaster.create({ - className: "app-toaster", - position: Position.BOTTOM -}); +export const AppToaster = OverlayToaster.createAsync( + { + className: "app-toaster", + position: Position.BOTTOM + }, + { + domRenderer: (toaster, containerElement) => createRoot(containerElement).render(toaster) + } +); export function SuccessToast(icon: IconName, message: string, timeout?: number): ToastProps { return { diff --git a/src/services/ApiService.ts b/src/services/ApiService.ts index 563ee59b89..71f14ebc3c 100644 --- a/src/services/ApiService.ts +++ b/src/services/ApiService.ts @@ -111,14 +111,14 @@ export class ApiService { } }; - private handleAuthLost = () => { + private handleAuthLost = async () => { if (ApiService.RuntimeConfig.dashboardAddress) { this.clearToken(); const redirectParams = btoa(window.location.search); window.open(`${ApiService.RuntimeConfig.dashboardAddress}?redirectParams=${redirectParams}`, "_self"); } else { this.clearToken(); - AppToaster.show({icon: "warning-sign", message: "Could not authenticate with server", intent: "danger", timeout: 3000}); + (await AppToaster).show({icon: "warning-sign", message: "Could not authenticate with server", intent: "danger", timeout: 3000}); } }; @@ -156,7 +156,7 @@ export class ApiService { const url = `${ApiService.RuntimeConfig.apiAddress}/server/stop`; await this.axiosInstance.post(url); } catch (err) { - AppToaster.show({icon: "warning-sign", message: "Could not stop CARTA server", intent: "danger", timeout: 3000}); + (await AppToaster).show({icon: "warning-sign", message: "Could not stop CARTA server", intent: "danger", timeout: 3000}); console.log(err); } } diff --git a/src/services/CatalogApiService.ts b/src/services/CatalogApiService.ts index 907974f993..bdc3b9afa2 100644 --- a/src/services/CatalogApiService.ts +++ b/src/services/CatalogApiService.ts @@ -79,11 +79,11 @@ export class CatalogApiService { } catch (error) { if (axios.isCancel(error)) { if (error?.message) { - AppToaster.show(WarningToast(error?.message)); + (await AppToaster).show(WarningToast(error?.message)); } CatalogApiService.Instance.resetCancelTokenSource(CatalogDatabase.VIZIER); } else if (error?.message) { - AppToaster.show(ErrorToast(error.message)); + (await AppToaster).show(ErrorToast(error.message)); } else { console.log("Vizier Resource Error: " + error); } @@ -110,11 +110,11 @@ export class CatalogApiService { } catch (error) { if (axios.isCancel(error)) { if (error?.message) { - AppToaster.show(WarningToast(error?.message)); + (await AppToaster).show(WarningToast(error?.message)); } CatalogApiService.Instance.resetCancelTokenSource(CatalogDatabase.VIZIER); } else if (error?.message) { - AppToaster.show(ErrorToast(error.message)); + (await AppToaster).show(ErrorToast(error.message)); } else { console.log("VizieR Table Error: " + error); } @@ -174,7 +174,7 @@ export class CatalogApiService { const appStore = AppStore.Instance; const frame = appStore.activeFrame; if (!frame) { - AppToaster.show(ErrorToast("Please load the image file")); + (await AppToaster).show(ErrorToast("Please load the image file")); throw new Error("No image file"); } @@ -207,11 +207,11 @@ export class CatalogApiService { } catch (error) { if (axios.isCancel(error)) { if (error?.message) { - AppToaster.show(WarningToast(error?.message)); + (await AppToaster).show(WarningToast(error?.message)); } CatalogApiService.Instance.resetCancelTokenSource(CatalogDatabase.SIMBAD); } else if (error?.message) { - AppToaster.show(ErrorToast(error.message)); + (await AppToaster).show(ErrorToast(error.message)); } else { console.log("Append Simbad Error: " + error); } diff --git a/src/stores/AppStore/AppStore.ts b/src/stores/AppStore/AppStore.ts index ab3eda6ec7..81fe9afd6f 100644 --- a/src/stores/AppStore/AppStore.ts +++ b/src/stores/AppStore/AppStore.ts @@ -681,7 +681,7 @@ export class AppStore { const ack = yield this.backendService.loadFile(path, filename, hdu, this.fileCounter, imageArithmetic); this.fileCounter++; if (!this.addFrame(ack, path, imageArithmetic, hdu, false, setAsActive, updateStartingDirectory)) { - AppToaster.show({icon: "warning-sign", message: "Load file failed.", intent: "danger", timeout: 3000}); + (yield AppToaster).show({icon: "warning-sign", message: "Load file failed.", intent: "danger", timeout: 3000}); } this.endFileLoading(); this.fileBrowserStore.hideFileBrowser(); @@ -710,10 +710,10 @@ export class AppStore { this.fileCounter++; const ack: CARTA.IRemoteFileResponse = yield this.backendService.requestRemoteFile(remoteRequest); if (!ack.success || !ack.openFileAck) { - AppToaster.show({icon: "warning-sign", message: `HiPS data query failed: ${ack.message}`, intent: "danger", timeout: 3000}); + (yield AppToaster).show({icon: "warning-sign", message: `HiPS data query failed: ${ack.message}`, intent: "danger", timeout: 3000}); } if (!this.addFrame(ack.openFileAck, "", false, "", true, true, false)) { - AppToaster.show({icon: "warning-sign", message: "HiPS data query failed: Load file failed.", intent: "danger", timeout: 3000}); + (yield AppToaster).show({icon: "warning-sign", message: "HiPS data query failed: Load file failed.", intent: "danger", timeout: 3000}); } this.dialogStore.hideDialog(DialogId.OnlineDataQuery); WidgetsStore.ResetWidgetPlotXYBounds(this.widgetsStore.spatialProfileWidgets); @@ -734,7 +734,7 @@ export class AppStore { const ack = await this.backendService.loadStokeFiles(stokesFiles, this.fileCounter, CARTA.RenderMode.RASTER); this.fileCounter++; if (!this.addFrame(ack.openFileAck, directory, false, hdu)) { - AppToaster.show({icon: "warning-sign", message: "Load file failed.", intent: "danger", timeout: 3000}); + (await AppToaster).show({icon: "warning-sign", message: "Load file failed.", intent: "danger", timeout: 3000}); } this.endFileLoading(); this.fileBrowserStore.hideFileBrowser(); @@ -814,7 +814,7 @@ export class AppStore { const fileId = this.activeFrame.frameInfo.fileId; try { const ack = yield this.backendService.saveFile(fileId, directory, filename, fileType, regionId, channels, stokes, !shouldDropDegenerateAxes, restFreq, overwrite); - AppToaster.show({icon: "saved", message: `${filename} saved.`, intent: "success", timeout: 3000}); + (yield AppToaster).show({icon: "saved", message: `${filename} saved.`, intent: "success", timeout: 3000}); this.fileBrowserStore.hideFileBrowser(); this.endFileSaving(); return ack.fileId; @@ -1098,11 +1098,11 @@ export class AppStore { @flow.bound *appendCatalog(directory: string, file: string, previewDataSize: number, type: CARTA.CatalogFileType) { if (!this.activeFrame) { - AppToaster.show(ErrorToast("Please load the image file")); + (yield AppToaster).show(ErrorToast("Please load the image file")); throw new Error("No image file"); } if (!(type === CARTA.CatalogFileType.VOTable)) { - AppToaster.show(ErrorToast("Catalog type not supported")); + (yield AppToaster).show(ErrorToast("Catalog type not supported")); throw new Error("Catalog type not supported"); } this.startFileLoading(); @@ -1219,7 +1219,7 @@ export class AppStore { @flow.bound *importRegion(directory: string, file: string, type: CARTA.FileType | CARTA.CatalogFileType, targetFrame?: FrameStore) { if (!(type === CARTA.FileType.CRTF || type === CARTA.FileType.DS9_REG)) { - AppToaster.show(ErrorToast("Region type not supported")); + (yield AppToaster).show(ErrorToast("Region type not supported")); return; } @@ -1231,7 +1231,7 @@ export class AppStore { } if (!frame) { - AppToaster.show(ErrorToast("No image file")); + (yield AppToaster).show(ErrorToast("No image file")); return; } @@ -1254,7 +1254,7 @@ export class AppStore { console.error(err); this.fileBrowserStore.setImportingRegions(false); this.fileBrowserStore.resetLoadingStates(); - AppToaster.show(ErrorToast(err)); + (yield AppToaster).show(ErrorToast(err)); } } @@ -1334,7 +1334,7 @@ export class AppStore { try { yield this.backendService.exportRegion(directory, file, fileType, coordType, frame.frameInfo.fileId, regionStyles, overwrite); - AppToaster.show(SuccessToast("saved", `Exported regions for ${frame.filename} using ${coordType === CARTA.CoordinateType.WORLD ? "world" : "pixel"} coordinates`)); + (yield AppToaster).show(SuccessToast("saved", `Exported regions for ${frame.filename} using ${coordType === CARTA.CoordinateType.WORLD ? "world" : "pixel"} coordinates`)); this.fileBrowserStore.hideFileBrowser(); } catch (err) { throw err; @@ -1344,13 +1344,13 @@ export class AppStore { /** * Deletes all regions including annotations. */ - @action deleteAllRegions = () => { + @action deleteAllRegions = async () => { this.activeFrame.regionSet.regionMap.forEach(x => { if (x.regionId !== CURSOR_REGION_ID) { this.deleteRegion(x); } }); - AppToaster.show(SuccessToast("console", `Regions deleted successfully.`, 3000)); + (await AppToaster).show(SuccessToast("console", `Regions deleted successfully.`, 3000)); }; /** @@ -1421,7 +1421,7 @@ export class AppStore { newMomentImage.setSpatialReference(this.spatialReference); } } else { - AppToaster.show({icon: "warning-sign", message: "Load file failed.", intent: "danger", timeout: 3000}); + (yield AppToaster).show({icon: "warning-sign", message: "Load file failed.", intent: "danger", timeout: 3000}); } } } @@ -1465,7 +1465,7 @@ export class AppStore { this.fileCounter++; frame.addPvImage(this.frames.find(f => f.frameInfo.fileId === ack.openFileAck.fileId)); } else { - AppToaster.show({icon: "warning-sign", message: "Load file failed.", intent: "danger", timeout: 3000}); + (yield AppToaster).show({icon: "warning-sign", message: "Load file failed.", intent: "danger", timeout: 3000}); } } frame.resetPvRequestState(); @@ -1476,7 +1476,7 @@ export class AppStore { frame.setIsRequestPVCancelling(false); this.endFileLoading(); console.error(err); - AppToaster.show(ErrorToast(err)); + (yield AppToaster).show(ErrorToast(err)); } } @@ -1501,7 +1501,7 @@ export class AppStore { WidgetsStore.Instance.createFloatingSettingsWidget("PV Preview Viewer", id, PvGeneratorComponent.WIDGET_CONFIG.type); } } else { - AppToaster.show({icon: "warning-sign", message: "Load preview failed.", intent: "danger", timeout: 3000}); + (yield AppToaster).show({icon: "warning-sign", message: "Load preview failed.", intent: "danger", timeout: 3000}); } frame.resetPvRequestState(); frame.setIsRequestPVCancelling(false); @@ -1511,7 +1511,7 @@ export class AppStore { frame.resetPvRequestState(); frame.setIsRequestPVCancelling(false); this.endFileLoading(); - AppToaster.show(ErrorToast(err)); + (yield AppToaster).show(ErrorToast(err)); } } @@ -1564,7 +1564,7 @@ export class AppStore { this.fileCounter++; frame?.addFittingModelImage(this.getFrame(ack.modelImage.fileId)); } else { - AppToaster.show({icon: "warning-sign", message: "Load model image failed.", intent: "danger", timeout: 3000}); + (yield AppToaster).show({icon: "warning-sign", message: "Load model image failed.", intent: "danger", timeout: 3000}); } } if (ack.residualImage) { @@ -1572,15 +1572,15 @@ export class AppStore { this.fileCounter++; frame?.addFittingResidualImage(this.getFrame(ack.residualImage.fileId)); } else { - AppToaster.show({icon: "warning-sign", message: "Load residual image failed.", intent: "danger", timeout: 3000}); + (yield AppToaster).show({icon: "warning-sign", message: "Load residual image failed.", intent: "danger", timeout: 3000}); } } } if (ack.message) { - AppToaster.show(WarningToast(`Image fitting: ${ack.message}.`)); + (yield AppToaster).show(WarningToast(`Image fitting: ${ack.message}.`)); } } catch (err) { - AppToaster.show(ErrorToast(`Image fitting failed: ${err}.`)); + (yield AppToaster).show(ErrorToast(`Image fitting failed: ${err}.`)); } this.setActiveImageByFileId(message.fileId); @@ -1916,21 +1916,21 @@ export class AppStore { }); // Display toasts when connection status changes - autorun(() => { + autorun(async () => { const newConnectionStatus = this.backendService.connectionStatus; const userString = this.username ? ` as ${this.username}` : ""; switch (newConnectionStatus) { case ConnectionStatus.ACTIVE: - AppToaster.clear(); + (await AppToaster).clear(); if (this.backendService.connectionDropped) { - AppToaster.show(WarningToast(`Reconnected to server${userString}. Some errors may occur`)); + (await AppToaster).show(WarningToast(`Reconnected to server${userString}. Some errors may occur`)); } else { - AppToaster.show(SuccessToast("swap-vertical", `Connected to CARTA server${userString}`)); + (await AppToaster).show(SuccessToast("swap-vertical", `Connected to CARTA server${userString}`)); } break; case ConnectionStatus.CLOSED: if (this.previousConnectionStatus === ConnectionStatus.ACTIVE || this.previousConnectionStatus === ConnectionStatus.PENDING) { - AppToaster.show(ErrorToast("Disconnected from server")); + (await AppToaster).show(ErrorToast("Disconnected from server")); this.alertStore .showRetryAlert( "You have been disconnected from the server. Do you want to reconnect? Please note that temporary images such as moment images, PV images, or fitting model/residual images generated via the GUI will be unloaded.", @@ -2496,7 +2496,7 @@ export class AppStore { const workspace: Workspace = yield this.apiService.getWorkspace(name, isKey); if (!workspace) { this.loadingWorkspace = false; - AppToaster.show({icon: "warning-sign", message: `Could not load workspace "${name}"`, intent: "danger", timeout: 3000}); + (yield AppToaster).show({icon: "warning-sign", message: `Could not load workspace "${name}"`, intent: "danger", timeout: 3000}); return false; } @@ -2638,7 +2638,7 @@ export class AppStore { return true; } catch (err) { console.error(err); - AppToaster.show({icon: "warning-sign", message: `Could not load workspace "${name}"`, intent: "danger", timeout: 3000}); + (yield AppToaster).show({icon: "warning-sign", message: `Could not load workspace "${name}"`, intent: "danger", timeout: 3000}); this.loadingWorkspace = false; return false; } @@ -2765,7 +2765,7 @@ export class AppStore { } if (hasTemporaryFiles) { - AppToaster.show(WarningToast("The workspace contains generated files. These will not be preserved when reloading.")); + (yield AppToaster).show(WarningToast("The workspace contains generated files. These will not be preserved when reloading.")); } if (this.activeFrame) { workspace.selectedFile = this.activeFrameFileId; @@ -2782,7 +2782,7 @@ export class AppStore { try { const success = await this.apiService.clearWorkspace(name); if (success) { - AppToaster.show(SuccessToast("console", `Workspace ${name} deleted successfully.`, SnippetStore.ToasterTimeout)); + (await AppToaster).show(SuccessToast("console", `Workspace ${name} deleted successfully.`, SnippetStore.ToasterTimeout)); return; } } catch (err) { @@ -3039,7 +3039,7 @@ export class AppStore { if (val) { if (!frame.setSpatialReference(this.spatialReference)) { - AppToaster.show(WarningToast(`Could not enable spatial matching of ${frame.filename} to reference image ${this.spatialReference.filename}. No valid transform was found.`)); + (yield AppToaster).show(WarningToast(`Could not enable spatial matching of ${frame.filename} to reference image ${this.spatialReference.filename}. No valid transform was found.`)); } } else { const confirmed = yield this.confirmColorBlendingRemoval(frame); @@ -3109,14 +3109,14 @@ export class AppStore { } }; - @action setSpectralMatchingEnabled = (frame: FrameStore, val: boolean) => { + @action setSpectralMatchingEnabled = async (frame: FrameStore, val: boolean) => { if (!frame || frame === this.spectralReference) { return; } if (val) { if (!frame.setSpectralReference(this.spectralReference)) { - AppToaster.show(WarningToast(`Could not enable spectral matching (velocity system) of ${frame.filename} to reference image ${this.spectralReference.filename}. No valid transform was found`)); + (await AppToaster).show(WarningToast(`Could not enable spectral matching (velocity system) of ${frame.filename} to reference image ${this.spectralReference.filename}. No valid transform was found`)); } } else { frame.clearSpectralReference(); @@ -3240,9 +3240,9 @@ export class AppStore { } }; - decreaseImageRatio = () => { + decreaseImageRatio = async () => { if (this.imageRatio !== 1 && this.isExportingImage === true) { - AppToaster.show(WarningToast(`Exceeded the maximum canvas size; exporting image with ${this.imageRatio - 1}00% resolution instead.`)); + (await AppToaster).show(WarningToast(`Exceeded the maximum canvas size; exporting image with ${this.imageRatio - 1}00% resolution instead.`)); this.setImageRatio(this.imageRatio - 1); } }; diff --git a/src/stores/FileBrowserStore/FileBrowserStore.ts b/src/stores/FileBrowserStore/FileBrowserStore.ts index 6c54d563c4..66b2c3809d 100644 --- a/src/stores/FileBrowserStore/FileBrowserStore.ts +++ b/src/stores/FileBrowserStore/FileBrowserStore.ts @@ -218,7 +218,7 @@ export class FileBrowserStore { } } catch (err) { console.log(err); - AppToaster.show(ErrorToast(`Error loading file list for directory ${directory}`)); + (yield AppToaster).show(ErrorToast(`Error loading file list for directory ${directory}`)); } this.loadingList = false; this.resetLoadingStates(); diff --git a/src/stores/ImageFittingStore/ImageFittingStore.ts b/src/stores/ImageFittingStore/ImageFittingStore.ts index 311be6eb4a..bb90d2547c 100644 --- a/src/stores/ImageFittingStore/ImageFittingStore.ts +++ b/src/stores/ImageFittingStore/ImageFittingStore.ts @@ -367,7 +367,7 @@ export class ImageFittingStore { }) ); newRegions?.forEach(r => r?.setDashLength(2)); - AppToaster.show(SuccessToast("tick", `Created ${params?.length} ellipse regions.`)); + (await AppToaster).show(SuccessToast("tick", `Created ${params?.length} ellipse regions.`)); } catch (err) { console.log(err); } diff --git a/src/stores/LayoutStore/LayoutStore.ts b/src/stores/LayoutStore/LayoutStore.ts index 264d5b01e1..613fa9a012 100644 --- a/src/stores/LayoutStore/LayoutStore.ts +++ b/src/stores/LayoutStore/LayoutStore.ts @@ -188,9 +188,9 @@ export class LayoutStore { } } - private handleSaveResult = (success: boolean) => { + private handleSaveResult = async (success: boolean) => { if (success) { - AppToaster.show(SuccessToast("layout-grid", `Layout ${this.layoutNameToBeSaved} saved successfully.`, LayoutStore.ToasterTimeout)); + (await AppToaster).show(SuccessToast("layout-grid", `Layout ${this.layoutNameToBeSaved} saved successfully.`, LayoutStore.ToasterTimeout)); this.currentLayoutName = this.layoutNameToBeSaved; } else { delete this.layouts[this.layoutNameToBeSaved]; @@ -243,9 +243,9 @@ export class LayoutStore { } } - private handleRenameResult = (oldName: string, newName: string, success: boolean) => { + private handleRenameResult = async (oldName: string, newName: string, success: boolean) => { if (success) { - AppToaster.show(SuccessToast("layout-grid", `Layout ${oldName} renamed to ${newName} successfully.`, LayoutStore.ToasterTimeout)); + (await AppToaster).show(SuccessToast("layout-grid", `Layout ${oldName} renamed to ${newName} successfully.`, LayoutStore.ToasterTimeout)); if (oldName === this.currentLayoutName) { this.currentLayoutName = newName; } @@ -273,9 +273,9 @@ export class LayoutStore { } } - private handleDeleteResult = (layoutName: string, success: boolean) => { + private handleDeleteResult = async (layoutName: string, success: boolean) => { if (success) { - AppToaster.show(SuccessToast("layout-grid", `Layout ${layoutName} deleted successfully.`, LayoutStore.ToasterTimeout)); + (await AppToaster).show(SuccessToast("layout-grid", `Layout ${layoutName} deleted successfully.`, LayoutStore.ToasterTimeout)); if (layoutName === this.currentLayoutName) { this.currentLayoutName = ""; } diff --git a/src/stores/Snippet/SnippetStore.ts b/src/stores/Snippet/SnippetStore.ts index 5b81da6f2d..8e3ba1ab82 100644 --- a/src/stores/Snippet/SnippetStore.ts +++ b/src/stores/Snippet/SnippetStore.ts @@ -139,7 +139,7 @@ export class SnippetStore { if (success) { // Silently exit on success if silent flag is set if (!silent) { - AppToaster.show(SuccessToast("console", `Snippet ${name} saved successfully.`, SnippetStore.ToasterTimeout)); + (yield AppToaster).show(SuccessToast("console", `Snippet ${name} saved successfully.`, SnippetStore.ToasterTimeout)); } return true; } else { @@ -159,7 +159,7 @@ export class SnippetStore { if (success) { // Silently exit on success if silent flag is set if (!silent) { - AppToaster.show(SuccessToast("console", `Snippet ${name} deleted successfully.`, SnippetStore.ToasterTimeout)); + (yield AppToaster).show(SuccessToast("console", `Snippet ${name} deleted successfully.`, SnippetStore.ToasterTimeout)); } return true; } else { From 60129c3e846c944141078c4164ec0e3ab6685412 Mon Sep 17 00:00:00 2001 From: yuhsuan Date: Fri, 25 Oct 2024 14:49:05 +0800 Subject: [PATCH 04/14] upgrade react type definition; remove react-color type def; patch react-split-pane type def --- package-lock.json | 46 +++++++-------------------- package.json | 7 ++-- patches/react-split-pane+0.1.92.patch | 20 ++++++++++++ 3 files changed, 35 insertions(+), 38 deletions(-) create mode 100644 patches/react-split-pane+0.1.92.patch diff --git a/package-lock.json b/package-lock.json index 8534d3a9ba..4d084e54b7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,9 +27,8 @@ "@types/node": "^20.14.13", "@types/plotly.js": "^2.33.3", "@types/prismjs": "^1.26.4", - "@types/react": "^17.0.80", - "@types/react-color": "^3.0.12", - "@types/react-dom": "^17.0.25", + "@types/react": "^18.3.12", + "@types/react-dom": "^18.3.1", "@types/react-plotly.js": "^2.6.3", "@types/react-virtualized-auto-sizer": "^1.0.4", "@types/react-window": "^1.8.8", @@ -4338,33 +4337,22 @@ "license": "MIT" }, "node_modules/@types/react": { - "version": "17.0.80", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.80.tgz", - "integrity": "sha512-LrgHIu2lEtIo8M7d1FcI3BdwXWoRQwMoXOZ7+dPTW0lYREjmlHl3P0U1VD0i/9tppOuv8/sam7sOjx34TxSFbA==", + "version": "18.3.12", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.12.tgz", + "integrity": "sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==", "dev": true, "dependencies": { "@types/prop-types": "*", - "@types/scheduler": "^0.16", "csstype": "^3.0.2" } }, - "node_modules/@types/react-color": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/@types/react-color/-/react-color-3.0.12.tgz", - "integrity": "sha512-pr3uKE3lSvf7GFo1Rn2K3QktiZQFFrSgSGJ/3iMvSOYWt2pPAJ97rVdVfhWxYJZ8prAEXzoP2XX//3qGSQgu7Q==", - "dev": true, - "dependencies": { - "@types/react": "*", - "@types/reactcss": "*" - } - }, "node_modules/@types/react-dom": { - "version": "17.0.25", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.25.tgz", - "integrity": "sha512-urx7A7UxkZQmThYA4So0NelOVjx3V4rNFVJwp0WZlbIK5eM4rNJDiN3R/E9ix0MBh6kAEojk/9YL+Te6D9zHNA==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==", "dev": true, "dependencies": { - "@types/react": "^17" + "@types/react": "*" } }, "node_modules/@types/react-plotly.js": { @@ -4404,14 +4392,6 @@ "@types/react": "*" } }, - "node_modules/@types/reactcss": { - "version": "1.2.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/react": "*" - } - }, "node_modules/@types/resolve": { "version": "1.17.1", "license": "MIT", @@ -4423,11 +4403,6 @@ "version": "0.12.0", "license": "MIT" }, - "node_modules/@types/scheduler": { - "version": "0.16.2", - "dev": true, - "license": "MIT" - }, "node_modules/@types/semver": { "version": "7.3.13", "license": "MIT" @@ -16106,8 +16081,9 @@ }, "node_modules/react-color": { "version": "2.19.3", + "resolved": "https://registry.npmjs.org/react-color/-/react-color-2.19.3.tgz", + "integrity": "sha512-LEeGE/ZzNLIsFWa1TMe8y5VYqr7bibneWmvJwm1pCn/eNmrabWDh659JSPn9BuaMpEfU83WTOJfnCcjDZwNQTA==", "dev": true, - "license": "MIT", "dependencies": { "@icons/material": "^0.2.4", "lodash": "^4.17.15", diff --git a/package.json b/package.json index c3b908fa42..974985da0f 100644 --- a/package.json +++ b/package.json @@ -18,9 +18,8 @@ "@types/node": "^20.14.13", "@types/plotly.js": "^2.33.3", "@types/prismjs": "^1.26.4", - "@types/react": "^17.0.80", - "@types/react-color": "^3.0.12", - "@types/react-dom": "^17.0.25", + "@types/react": "^18.3.12", + "@types/react-dom": "^18.3.1", "@types/react-plotly.js": "^2.6.3", "@types/react-virtualized-auto-sizer": "^1.0.4", "@types/react-window": "^1.8.8", @@ -204,6 +203,8 @@ "usehooks-ts": "^3.1.0" }, "overrides": { + "@types/react": "^18.3.12", + "@types/react-dom": "^18.3.1", "react": "^18.3.1", "react-dom": "^18.3.1", "typescript": "^5.5.4", diff --git a/patches/react-split-pane+0.1.92.patch b/patches/react-split-pane+0.1.92.patch new file mode 100644 index 0000000000..7d4b6daeb1 --- /dev/null +++ b/patches/react-split-pane+0.1.92.patch @@ -0,0 +1,20 @@ +diff --git a/node_modules/react-split-pane/index.d.ts b/node_modules/react-split-pane/index.d.ts +index d116f54..54452b7 100644 +--- a/node_modules/react-split-pane/index.d.ts ++++ b/node_modules/react-split-pane/index.d.ts +@@ -5,6 +5,7 @@ export type Size = string | number; + export type Split = 'vertical' | 'horizontal'; + + export type SplitPaneProps = { ++ children: React.ReactNode[]; + allowResize?: boolean; + className?: string; + primary?: 'first' | 'second'; +@@ -59,6 +60,7 @@ declare class SplitPane extends React.Component< + export default SplitPane; + + export type PaneProps = { ++ children: React.ReactNode; + className?: string; + size?: Size; + split?: Split; From 3e3822affd163cdee0e6c495f2ff5d981a68d829 Mon Sep 17 00:00:00 2001 From: yuhsuan Date: Fri, 25 Oct 2024 15:20:48 +0800 Subject: [PATCH 05/14] fix type --- .../CatalogOverlayPlotSettingsPanelComponent.tsx | 2 +- .../Dialogs/DraggableDialog/DraggableDialogComponent.tsx | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/CatalogOverlay/CatalogOverlayPlotSettingsPanelComponent/CatalogOverlayPlotSettingsPanelComponent.tsx b/src/components/CatalogOverlay/CatalogOverlayPlotSettingsPanelComponent/CatalogOverlayPlotSettingsPanelComponent.tsx index c5d2a8f914..bafa1182b9 100644 --- a/src/components/CatalogOverlay/CatalogOverlayPlotSettingsPanelComponent/CatalogOverlayPlotSettingsPanelComponent.tsx +++ b/src/components/CatalogOverlay/CatalogOverlayPlotSettingsPanelComponent/CatalogOverlayPlotSettingsPanelComponent.tsx @@ -15,7 +15,7 @@ import {getColorForTheme, SWATCH_COLORS} from "utilities"; import "./CatalogOverlayPlotSettingsPanelComponent.scss"; -const IconWrapper = (path: React.SVGProps, color: string, fill: boolean, strokeWidth = 2, viewboxDefault = 16) => { +const IconWrapper = (path: React.ReactNode, color: string, fill: boolean, strokeWidth = 2, viewboxDefault = 16) => { let fillColor = color; if (!fill) { fillColor = "none"; diff --git a/src/components/Dialogs/DraggableDialog/DraggableDialogComponent.tsx b/src/components/Dialogs/DraggableDialog/DraggableDialogComponent.tsx index c8e8bb4547..62743d3a67 100644 --- a/src/components/Dialogs/DraggableDialog/DraggableDialogComponent.tsx +++ b/src/components/Dialogs/DraggableDialog/DraggableDialogComponent.tsx @@ -19,6 +19,7 @@ export class ResizableDialogComponentProps { helpType?: HelpType; onResizeStop?: (newWidth: number, newHeight: number) => void; dialogId: string; + children?: React.ReactNode; } @observer From 53d0c035307a96e3bb24b638a44c83e7205dad64 Mon Sep 17 00:00:00 2001 From: yuhsuan Date: Fri, 25 Oct 2024 15:27:30 +0800 Subject: [PATCH 06/14] upgrade react-konva; fix types --- package-lock.json | 67 ++++++++++--------- package.json | 2 +- .../PointShapeSelectComponent.tsx | 2 +- .../PopoverSettingsComponent.tsx | 1 + 4 files changed, 38 insertions(+), 34 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4d084e54b7..a35781facc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -71,7 +71,7 @@ "react-color": "^2.17.3", "react-dom": "^18.3.1", "react-iframe": "^1.8.5", - "react-konva": "^17.0.2-6", + "react-konva": "^18.2.10", "react-plotly.js": "^2.6.0", "react-resize-detector": "^9.1.1", "react-rnd": "^10.4.11", @@ -4366,9 +4366,9 @@ } }, "node_modules/@types/react-reconciler": { - "version": "0.26.7", - "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.26.7.tgz", - "integrity": "sha512-mBDYl8x+oyPX/VBb3E638N0B7xG+SPk/EAMcVPeexqus/5aTpTphQi0curhhshOqRrc9t6OPoJfEUkbymse/lQ==", + "version": "0.28.8", + "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.28.8.tgz", + "integrity": "sha512-SN9c4kxXZonFhbX4hJrZy37yw9e7EIxcpHCxQv5JUS18wDE5ovkQKlqQEkufdJCCMfuI9BnjUJvhYeJ9x5Ra7g==", "dev": true, "dependencies": { "@types/react": "*" @@ -11190,6 +11190,18 @@ "node": ">=8" } }, + "node_modules/its-fine": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/its-fine/-/its-fine-1.2.5.tgz", + "integrity": "sha512-fXtDA0X0t0eBYAGLVM5YsgJGsJ5jEmqZEPrGbzdf5awjv0xE7nqv3TVnvtUF060Tkes15DbDAKW/I48vsb6SyA==", + "dev": true, + "dependencies": { + "@types/react-reconciler": "^0.28.0" + }, + "peerDependencies": { + "react": ">=18.0" + } + }, "node_modules/jake": { "version": "10.8.2", "license": "Apache-2.0", @@ -16228,15 +16240,6 @@ "react": "^18.3.1" } }, - "node_modules/react-dom/node_modules/scheduler": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", - "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", - "dev": true, - "dependencies": { - "loose-envify": "^1.1.0" - } - }, "node_modules/react-draggable": { "version": "4.4.6", "resolved": "https://registry.npmjs.org/react-draggable/-/react-draggable-4.4.6.tgz", @@ -16303,9 +16306,9 @@ "license": "MIT" }, "node_modules/react-konva": { - "version": "17.0.2-6", - "resolved": "https://registry.npmjs.org/react-konva/-/react-konva-17.0.2-6.tgz", - "integrity": "sha512-cfRsBKxqAQ6gTBmyrKptKRWhHD+C068dvyqcZ4h8qzKbAacTXQtfLMSpOI+d+ptxSMvayIbbCdbsBmk3bWiClQ==", + "version": "18.2.10", + "resolved": "https://registry.npmjs.org/react-konva/-/react-konva-18.2.10.tgz", + "integrity": "sha512-ohcX1BJINL43m4ynjZ24MxFI1syjBdrXhqVxYVDw2rKgr3yuS0x/6m1Y2Z4sl4T/gKhfreBx8KHisd0XC6OT1g==", "dev": true, "funding": [ { @@ -16322,14 +16325,15 @@ } ], "dependencies": { - "@types/react-reconciler": "~0.26.2", - "react-reconciler": "~0.26.2", - "scheduler": "^0.20.2" + "@types/react-reconciler": "^0.28.2", + "its-fine": "^1.1.1", + "react-reconciler": "~0.29.0", + "scheduler": "^0.23.0" }, "peerDependencies": { - "konva": "^8.0.1 || ^7.2.5", - "react": ">=16.8.0", - "react-dom": ">=16.8.0" + "konva": "^8.0.1 || ^7.2.5 || ^9.0.0", + "react": ">=18.0.0", + "react-dom": ">=18.0.0" } }, "node_modules/react-lifecycles-compat": { @@ -16380,20 +16384,19 @@ } }, "node_modules/react-reconciler": { - "version": "0.26.2", - "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.26.2.tgz", - "integrity": "sha512-nK6kgY28HwrMNwDnMui3dvm3rCFjZrcGiuwLc5COUipBK5hWHLOxMJhSnSomirqWwjPBJKV1QcbkI0VJr7Gl1Q==", + "version": "0.29.2", + "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.29.2.tgz", + "integrity": "sha512-zZQqIiYgDCTP/f1N/mAR10nJGrPD2ZR+jDSEsKWJHYC7Cm2wodlwbR3upZRdC3cjIjSlTLNVyO7Iu0Yy7t2AYg==", "dev": true, "dependencies": { "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "scheduler": "^0.20.2" + "scheduler": "^0.23.2" }, "engines": { "node": ">=0.10.0" }, "peerDependencies": { - "react": "^17.0.2" + "react": "^18.3.1" } }, "node_modules/react-refresh": { @@ -17290,12 +17293,12 @@ } }, "node_modules/scheduler": { - "version": "0.20.2", + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", "dev": true, - "license": "MIT", "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" + "loose-envify": "^1.1.0" } }, "node_modules/schema-utils": { diff --git a/package.json b/package.json index 974985da0f..6d39cc86fc 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "react-color": "^2.17.3", "react-dom": "^18.3.1", "react-iframe": "^1.8.5", - "react-konva": "^17.0.2-6", + "react-konva": "^18.2.10", "react-plotly.js": "^2.6.0", "react-resize-detector": "^9.1.1", "react-rnd": "^10.4.11", diff --git a/src/components/Shared/PointShapeSelectComponent/PointShapeSelectComponent.tsx b/src/components/Shared/PointShapeSelectComponent/PointShapeSelectComponent.tsx index 16075d7c4e..901aa52e48 100644 --- a/src/components/Shared/PointShapeSelectComponent/PointShapeSelectComponent.tsx +++ b/src/components/Shared/PointShapeSelectComponent/PointShapeSelectComponent.tsx @@ -10,7 +10,7 @@ export const PointShapeSelectComponent = observer((props: {handleChange: (pointS const appStore = AppStore.Instance; const preference = appStore.preferenceStore; - const iconWrapper = (path: React.SVGProps, color: string, fill: boolean, strokeWidth = 2, viewboxDefault = 16) => { + const iconWrapper = (path: React.ReactNode, color: string, fill: boolean, strokeWidth = 2, viewboxDefault = 16) => { let fillColor = color; if (!fill) { fillColor = "none"; diff --git a/src/components/Shared/PopoverSettings/PopoverSettingsComponent.tsx b/src/components/Shared/PopoverSettings/PopoverSettingsComponent.tsx index c4914386ae..6fb72eb1e2 100644 --- a/src/components/Shared/PopoverSettings/PopoverSettingsComponent.tsx +++ b/src/components/Shared/PopoverSettings/PopoverSettingsComponent.tsx @@ -8,6 +8,7 @@ export interface PopoverSettingsComponentProps { contentWidth: number; onShowClicked?: () => void; onHideClicked?: () => void; + children?: React.ReactNode; } export class PopoverSettingsComponent extends React.Component { From 49d41b39dd775e844b877f4f92a85510a85b8075 Mon Sep 17 00:00:00 2001 From: yuhsuan Date: Fri, 25 Oct 2024 15:41:30 +0800 Subject: [PATCH 07/14] fix key related warnings --- .../ImageView/RegionView/RegionViewComponent.tsx | 11 +++++------ .../SpectralSettings/SpectralSettingsComponent.tsx | 6 +++--- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/components/ImageView/RegionView/RegionViewComponent.tsx b/src/components/ImageView/RegionView/RegionViewComponent.tsx index 6d9d59c680..02dfb7b0e2 100644 --- a/src/components/ImageView/RegionView/RegionViewComponent.tsx +++ b/src/components/ImageView/RegionView/RegionViewComponent.tsx @@ -758,7 +758,6 @@ class RegionComponents extends React.Component<{frame: FrameStore; regions: Regi const regionSet = this.props.frame?.regionSet; return regions.map(r => { const commonProps = { - key: r.regionId, region: r, frame: this.props.frame, layerWidth: this.props.width, @@ -770,11 +769,11 @@ class RegionComponents extends React.Component<{frame: FrameStore; regions: Regi }; if (r.regionType === CARTA.RegionType.POINT || r.regionType === CARTA.RegionType.ANNPOINT) { - return ; + return ; } else if (r.regionType === CARTA.RegionType.ANNCOMPASS) { - return ; + return ; } else if (r.regionType === CARTA.RegionType.ANNRULER) { - return ; + return ; } else { const allProps = { ...commonProps, @@ -788,9 +787,9 @@ class RegionComponents extends React.Component<{frame: FrameStore; regions: Regi r.regionType === CARTA.RegionType.ANNLINE || r.regionType === CARTA.RegionType.ANNVECTOR || r.regionType === CARTA.RegionType.ANNPOLYLINE ? ( - + ) : ( - + ); } }); diff --git a/src/components/Shared/SpectralSettings/SpectralSettingsComponent.tsx b/src/components/Shared/SpectralSettings/SpectralSettingsComponent.tsx index 3d195f4ea3..a039ade54d 100644 --- a/src/components/Shared/SpectralSettings/SpectralSettingsComponent.tsx +++ b/src/components/Shared/SpectralSettings/SpectralSettingsComponent.tsx @@ -23,14 +23,14 @@ export class SpectralSettingsComponent extends React.Component<{ const filteredSpectralTypes = this.props.disableChannelOption ? spectralTypes.filter(type => type !== "Channel") : spectralTypes; const spectralCoordinateOptions: OptionProps[] = filteredSpectralTypes.map((coord: string) => { if (coord === SPECTRAL_TYPE_STRING.get(SpectralType.NATIVE)) { - return {value: coord, label: nativeSpectralCoordinate + " (Native WCS)"}; + return {value: coord, label: nativeSpectralCoordinate + " (Native WCS)", key: coord}; } - return {value: coord, label: coord === nativeSpectralCoordinate ? coord + " (Native WCS)" : coord}; + return {value: coord, label: coord === nativeSpectralCoordinate ? coord + " (Native WCS)" : coord, key: coord}; }); const spectralSystemOptions: OptionProps[] = frame?.spectralSystemsSupported?.length > 0 ? frame.spectralSystemsSupported.map(system => { - return {value: system, label: system}; + return {value: system, label: system, key: system}; }) : [{value: frame?.spectralAxis?.specsys, label: frame?.spectralAxis?.specsys}]; const hasFrameCoordinateSetting = frame?.isSpectralChannel; From 8bf1f37d423be4f769969377d026a1a967acf56f Mon Sep 17 00:00:00 2001 From: yuhsuan Date: Mon, 28 Oct 2024 15:49:07 +0800 Subject: [PATCH 08/14] remove unused property --- src/index.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/index.tsx b/src/index.tsx index 8c67ad01bf..c9b59fc519 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,5 +1,4 @@ import * as React from "react"; -import * as ReactDOM from "react-dom"; import {createRoot} from "react-dom/client"; import {FocusStyleManager, OverlaysProvider} from "@blueprintjs/core"; import axios from "axios"; @@ -27,7 +26,6 @@ FocusStyleManager.onlyShowFocusOnTabs(); // GoldenLayout requires these in the global namespace window["React"] = React; // tslint:disable-line -window["ReactDOM"] = ReactDOM; // tslint:disable-line window["createRoot"] = createRoot; // tslint:disable-line async function fetchConfig() { From e99bcb1c69352bc79a4c7f41c16d58949b67c7d4 Mon Sep 17 00:00:00 2001 From: yuhsuan Date: Mon, 28 Oct 2024 15:52:32 +0800 Subject: [PATCH 09/14] remove overrides --- package-lock.json | 26 ++++++++++++++++++++++++++ package.json | 2 -- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index a35781facc..bfb3309e1f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3856,6 +3856,26 @@ "react-dom": "<18.0.0" } }, + "node_modules/@testing-library/react/node_modules/@types/react": { + "version": "17.0.83", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.83.tgz", + "integrity": "sha512-l0m4ArKJvmFtR4e8UmKrj1pB4tUgOhJITf+mADyF/p69Ts1YAR/E+G9XEM0mHXKVRa1dQNHseyyDNzeuAXfXQw==", + "dev": true, + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "^0.16", + "csstype": "^3.0.2" + } + }, + "node_modules/@testing-library/react/node_modules/@types/react-dom": { + "version": "17.0.25", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.25.tgz", + "integrity": "sha512-urx7A7UxkZQmThYA4So0NelOVjx3V4rNFVJwp0WZlbIK5eM4rNJDiN3R/E9ix0MBh6kAEojk/9YL+Te6D9zHNA==", + "dev": true, + "dependencies": { + "@types/react": "^17" + } + }, "node_modules/@testing-library/user-event": { "version": "14.5.2", "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.5.2.tgz", @@ -4403,6 +4423,12 @@ "version": "0.12.0", "license": "MIT" }, + "node_modules/@types/scheduler": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", + "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==", + "dev": true + }, "node_modules/@types/semver": { "version": "7.3.13", "license": "MIT" diff --git a/package.json b/package.json index 6d39cc86fc..e11811fc22 100644 --- a/package.json +++ b/package.json @@ -203,8 +203,6 @@ "usehooks-ts": "^3.1.0" }, "overrides": { - "@types/react": "^18.3.12", - "@types/react-dom": "^18.3.1", "react": "^18.3.1", "react-dom": "^18.3.1", "typescript": "^5.5.4", From 9ca659ea67abee0b702ee1f9941104cd4c462bc3 Mon Sep 17 00:00:00 2001 From: yuhsuan Date: Wed, 30 Oct 2024 14:35:24 +0800 Subject: [PATCH 10/14] Revert "migrate blueprint toaster to react 18" This reverts commit 49f5c437aa7bf1d63ad2e7b3da8ff36f7e71f43d. --- .../CodeSnippetDialogComponent.tsx | 2 +- .../FileBrowserDialogComponent.tsx | 8 +-- .../PreferenceDialogComponent.tsx | 2 +- .../ShareWorkspaceDialogComponent.tsx | 2 +- .../WorkspaceDialogComponent.tsx | 6 +- src/components/Menu/RootMenuComponent.tsx | 4 +- src/components/Shared/toaster.ts | 16 ++--- src/services/ApiService.ts | 6 +- src/services/CatalogApiService.ts | 14 ++-- src/stores/AppStore/AppStore.ts | 72 +++++++++---------- .../FileBrowserStore/FileBrowserStore.ts | 2 +- .../ImageFittingStore/ImageFittingStore.ts | 2 +- src/stores/LayoutStore/LayoutStore.ts | 12 ++-- src/stores/Snippet/SnippetStore.ts | 4 +- 14 files changed, 73 insertions(+), 79 deletions(-) diff --git a/src/components/Dialogs/CodeSnippetDialog/CodeSnippetDialogComponent.tsx b/src/components/Dialogs/CodeSnippetDialog/CodeSnippetDialogComponent.tsx index d2360726c2..5f43f2204b 100644 --- a/src/components/Dialogs/CodeSnippetDialog/CodeSnippetDialogComponent.tsx +++ b/src/components/Dialogs/CodeSnippetDialog/CodeSnippetDialogComponent.tsx @@ -78,7 +78,7 @@ export class CodeSnippetDialogComponent extends React.Component { if (snippetStore.validInput && !snippetStore.isExecuting) { const success = await snippetStore.executeCurrentSnippet(); if (!success) { - (await AppToaster).show(WarningToast("Error encountered while executing snippet. See JavaScript console for details.")); + AppToaster.show(WarningToast("Error encountered while executing snippet. See JavaScript console for details.")); } } this.tryRefocusEditor(); diff --git a/src/components/Dialogs/FileBrowser/FileBrowserDialogComponent.tsx b/src/components/Dialogs/FileBrowser/FileBrowserDialogComponent.tsx index f543609728..610d2db56c 100644 --- a/src/components/Dialogs/FileBrowser/FileBrowserDialogComponent.tsx +++ b/src/components/Dialogs/FileBrowser/FileBrowserDialogComponent.tsx @@ -199,7 +199,7 @@ export class FileBrowserDialogComponent extends React.Component { this.overwriteExistingFileAlertVisible = true; } else { console.error(err.message); - (await AppToaster).show({icon: "warning-sign", message: err.message, intent: "danger", timeout: 3000}); + AppToaster.show({icon: "warning-sign", message: err.message, intent: "danger", timeout: 3000}); } } }; @@ -219,7 +219,7 @@ export class FileBrowserDialogComponent extends React.Component { this.overwriteExistingFileAlertVisible = true; } else { console.error(err.message); - (await AppToaster).show(ErrorToast(err.message)); + AppToaster.show(ErrorToast(err.message)); } } }; @@ -245,14 +245,14 @@ export class FileBrowserDialogComponent extends React.Component { await this.exportRegion(fileBrowserStore.fileList.directory, filename, true); } catch (err) { console.error(err.message); - (await AppToaster).show(ErrorToast(err.message)); + AppToaster.show(ErrorToast(err.message)); } } else if (fileBrowserStore.browserMode === BrowserMode.SaveFile) { try { await this.handleSaveFile(true); } catch (err) { console.error(err.message); - (await AppToaster).show({icon: "warning-sign", message: err.message, intent: "danger", timeout: 3000}); + AppToaster.show({icon: "warning-sign", message: err.message, intent: "danger", timeout: 3000}); } } }; diff --git a/src/components/Dialogs/PreferenceDialog/PreferenceDialogComponent.tsx b/src/components/Dialogs/PreferenceDialog/PreferenceDialogComponent.tsx index 7488806f7a..c196a4ff87 100644 --- a/src/components/Dialogs/PreferenceDialog/PreferenceDialogComponent.tsx +++ b/src/components/Dialogs/PreferenceDialog/PreferenceDialogComponent.tsx @@ -148,7 +148,7 @@ export class PreferenceDialogComponent extends React.Component { const appStore = AppStore.Instance; try { await copyToClipboard(appStore.telemetryService.decodedUserId); - (await AppToaster).show(SuccessToast("clipboard", "Copied user ID to clipboard.")); + AppToaster.show(SuccessToast("clipboard", "Copied user ID to clipboard.")); } catch (err) { console.log(err); } diff --git a/src/components/Dialogs/ShareWorkspaceDialog/ShareWorkspaceDialogComponent.tsx b/src/components/Dialogs/ShareWorkspaceDialog/ShareWorkspaceDialogComponent.tsx index f3cc12b461..b65212cd6f 100644 --- a/src/components/Dialogs/ShareWorkspaceDialog/ShareWorkspaceDialogComponent.tsx +++ b/src/components/Dialogs/ShareWorkspaceDialog/ShareWorkspaceDialogComponent.tsx @@ -51,7 +51,7 @@ export const ShareWorkspaceDialogComponent = observer(() => { setShareKey(shareKey); } catch (err) { console.log(err); - (await AppToaster).show(WarningToast("Could not generate a sharing link.")); + AppToaster.show(WarningToast("Could not generate a sharing link.")); } }; diff --git a/src/components/Dialogs/WorkspaceDialog/WorkspaceDialogComponent.tsx b/src/components/Dialogs/WorkspaceDialog/WorkspaceDialogComponent.tsx index 1751dd5373..0298ba1d2a 100644 --- a/src/components/Dialogs/WorkspaceDialog/WorkspaceDialogComponent.tsx +++ b/src/components/Dialogs/WorkspaceDialog/WorkspaceDialogComponent.tsx @@ -71,14 +71,14 @@ export const WorkspaceDialogComponent = observer(() => { try { const res = await appStore.saveWorkspace(name); if (res) { - (await AppToaster).show(SuccessToast("floppy-disk", "Workspace saved")); + AppToaster.show(SuccessToast("floppy-disk", "Workspace saved")); handleCloseClicked(); return; } } catch (err) { console.log(err); } - (await AppToaster).show(ErrorToast("Error saving workspace")); + AppToaster.show(ErrorToast("Error saving workspace")); setIsFetching(false); }, [appStore, handleCloseClicked] @@ -94,7 +94,7 @@ export const WorkspaceDialogComponent = observer(() => { try { const res = await appStore.loadWorkspace(name); if (res) { - (await AppToaster).show(SuccessToast("floppy-disk", "Workspace loaded")); + AppToaster.show(SuccessToast("floppy-disk", "Workspace loaded")); handleCloseClicked(); return; } diff --git a/src/components/Menu/RootMenuComponent.tsx b/src/components/Menu/RootMenuComponent.tsx index e9b0b5097f..79913eeb24 100644 --- a/src/components/Menu/RootMenuComponent.tsx +++ b/src/components/Menu/RootMenuComponent.tsx @@ -189,7 +189,7 @@ export class RootMenuComponent extends React.Component { onClick={async () => { try { await copyToClipboard(appStore.backendService.sessionId.toString()); - (await AppToaster).show(SuccessToast("clipboard", "Session ID copied!")); + AppToaster.show(SuccessToast("clipboard", "Session ID copied!")); } catch (err) { console.log(err); } @@ -212,7 +212,7 @@ export class RootMenuComponent extends React.Component { } else { await copyToClipboard(document.URL); } - (await AppToaster).show(SuccessToast("clipboard", "Session URL copied!")); + AppToaster.show(SuccessToast("clipboard", "Session URL copied!")); } catch (err) { console.log(err); } diff --git a/src/components/Shared/toaster.ts b/src/components/Shared/toaster.ts index b2e3e471f0..2874f1f867 100644 --- a/src/components/Shared/toaster.ts +++ b/src/components/Shared/toaster.ts @@ -1,17 +1,11 @@ -import {createRoot} from "react-dom/client"; -import {IconName, OverlayToaster, Position, ToastProps} from "@blueprintjs/core"; +import {IconName, Position, Toaster, ToastProps} from "@blueprintjs/core"; import {copyToClipboard} from "utilities"; -export const AppToaster = OverlayToaster.createAsync( - { - className: "app-toaster", - position: Position.BOTTOM - }, - { - domRenderer: (toaster, containerElement) => createRoot(containerElement).render(toaster) - } -); +export const AppToaster = Toaster.create({ + className: "app-toaster", + position: Position.BOTTOM +}); export function SuccessToast(icon: IconName, message: string, timeout?: number): ToastProps { return { diff --git a/src/services/ApiService.ts b/src/services/ApiService.ts index 71f14ebc3c..563ee59b89 100644 --- a/src/services/ApiService.ts +++ b/src/services/ApiService.ts @@ -111,14 +111,14 @@ export class ApiService { } }; - private handleAuthLost = async () => { + private handleAuthLost = () => { if (ApiService.RuntimeConfig.dashboardAddress) { this.clearToken(); const redirectParams = btoa(window.location.search); window.open(`${ApiService.RuntimeConfig.dashboardAddress}?redirectParams=${redirectParams}`, "_self"); } else { this.clearToken(); - (await AppToaster).show({icon: "warning-sign", message: "Could not authenticate with server", intent: "danger", timeout: 3000}); + AppToaster.show({icon: "warning-sign", message: "Could not authenticate with server", intent: "danger", timeout: 3000}); } }; @@ -156,7 +156,7 @@ export class ApiService { const url = `${ApiService.RuntimeConfig.apiAddress}/server/stop`; await this.axiosInstance.post(url); } catch (err) { - (await AppToaster).show({icon: "warning-sign", message: "Could not stop CARTA server", intent: "danger", timeout: 3000}); + AppToaster.show({icon: "warning-sign", message: "Could not stop CARTA server", intent: "danger", timeout: 3000}); console.log(err); } } diff --git a/src/services/CatalogApiService.ts b/src/services/CatalogApiService.ts index bdc3b9afa2..907974f993 100644 --- a/src/services/CatalogApiService.ts +++ b/src/services/CatalogApiService.ts @@ -79,11 +79,11 @@ export class CatalogApiService { } catch (error) { if (axios.isCancel(error)) { if (error?.message) { - (await AppToaster).show(WarningToast(error?.message)); + AppToaster.show(WarningToast(error?.message)); } CatalogApiService.Instance.resetCancelTokenSource(CatalogDatabase.VIZIER); } else if (error?.message) { - (await AppToaster).show(ErrorToast(error.message)); + AppToaster.show(ErrorToast(error.message)); } else { console.log("Vizier Resource Error: " + error); } @@ -110,11 +110,11 @@ export class CatalogApiService { } catch (error) { if (axios.isCancel(error)) { if (error?.message) { - (await AppToaster).show(WarningToast(error?.message)); + AppToaster.show(WarningToast(error?.message)); } CatalogApiService.Instance.resetCancelTokenSource(CatalogDatabase.VIZIER); } else if (error?.message) { - (await AppToaster).show(ErrorToast(error.message)); + AppToaster.show(ErrorToast(error.message)); } else { console.log("VizieR Table Error: " + error); } @@ -174,7 +174,7 @@ export class CatalogApiService { const appStore = AppStore.Instance; const frame = appStore.activeFrame; if (!frame) { - (await AppToaster).show(ErrorToast("Please load the image file")); + AppToaster.show(ErrorToast("Please load the image file")); throw new Error("No image file"); } @@ -207,11 +207,11 @@ export class CatalogApiService { } catch (error) { if (axios.isCancel(error)) { if (error?.message) { - (await AppToaster).show(WarningToast(error?.message)); + AppToaster.show(WarningToast(error?.message)); } CatalogApiService.Instance.resetCancelTokenSource(CatalogDatabase.SIMBAD); } else if (error?.message) { - (await AppToaster).show(ErrorToast(error.message)); + AppToaster.show(ErrorToast(error.message)); } else { console.log("Append Simbad Error: " + error); } diff --git a/src/stores/AppStore/AppStore.ts b/src/stores/AppStore/AppStore.ts index 81fe9afd6f..ab3eda6ec7 100644 --- a/src/stores/AppStore/AppStore.ts +++ b/src/stores/AppStore/AppStore.ts @@ -681,7 +681,7 @@ export class AppStore { const ack = yield this.backendService.loadFile(path, filename, hdu, this.fileCounter, imageArithmetic); this.fileCounter++; if (!this.addFrame(ack, path, imageArithmetic, hdu, false, setAsActive, updateStartingDirectory)) { - (yield AppToaster).show({icon: "warning-sign", message: "Load file failed.", intent: "danger", timeout: 3000}); + AppToaster.show({icon: "warning-sign", message: "Load file failed.", intent: "danger", timeout: 3000}); } this.endFileLoading(); this.fileBrowserStore.hideFileBrowser(); @@ -710,10 +710,10 @@ export class AppStore { this.fileCounter++; const ack: CARTA.IRemoteFileResponse = yield this.backendService.requestRemoteFile(remoteRequest); if (!ack.success || !ack.openFileAck) { - (yield AppToaster).show({icon: "warning-sign", message: `HiPS data query failed: ${ack.message}`, intent: "danger", timeout: 3000}); + AppToaster.show({icon: "warning-sign", message: `HiPS data query failed: ${ack.message}`, intent: "danger", timeout: 3000}); } if (!this.addFrame(ack.openFileAck, "", false, "", true, true, false)) { - (yield AppToaster).show({icon: "warning-sign", message: "HiPS data query failed: Load file failed.", intent: "danger", timeout: 3000}); + AppToaster.show({icon: "warning-sign", message: "HiPS data query failed: Load file failed.", intent: "danger", timeout: 3000}); } this.dialogStore.hideDialog(DialogId.OnlineDataQuery); WidgetsStore.ResetWidgetPlotXYBounds(this.widgetsStore.spatialProfileWidgets); @@ -734,7 +734,7 @@ export class AppStore { const ack = await this.backendService.loadStokeFiles(stokesFiles, this.fileCounter, CARTA.RenderMode.RASTER); this.fileCounter++; if (!this.addFrame(ack.openFileAck, directory, false, hdu)) { - (await AppToaster).show({icon: "warning-sign", message: "Load file failed.", intent: "danger", timeout: 3000}); + AppToaster.show({icon: "warning-sign", message: "Load file failed.", intent: "danger", timeout: 3000}); } this.endFileLoading(); this.fileBrowserStore.hideFileBrowser(); @@ -814,7 +814,7 @@ export class AppStore { const fileId = this.activeFrame.frameInfo.fileId; try { const ack = yield this.backendService.saveFile(fileId, directory, filename, fileType, regionId, channels, stokes, !shouldDropDegenerateAxes, restFreq, overwrite); - (yield AppToaster).show({icon: "saved", message: `${filename} saved.`, intent: "success", timeout: 3000}); + AppToaster.show({icon: "saved", message: `${filename} saved.`, intent: "success", timeout: 3000}); this.fileBrowserStore.hideFileBrowser(); this.endFileSaving(); return ack.fileId; @@ -1098,11 +1098,11 @@ export class AppStore { @flow.bound *appendCatalog(directory: string, file: string, previewDataSize: number, type: CARTA.CatalogFileType) { if (!this.activeFrame) { - (yield AppToaster).show(ErrorToast("Please load the image file")); + AppToaster.show(ErrorToast("Please load the image file")); throw new Error("No image file"); } if (!(type === CARTA.CatalogFileType.VOTable)) { - (yield AppToaster).show(ErrorToast("Catalog type not supported")); + AppToaster.show(ErrorToast("Catalog type not supported")); throw new Error("Catalog type not supported"); } this.startFileLoading(); @@ -1219,7 +1219,7 @@ export class AppStore { @flow.bound *importRegion(directory: string, file: string, type: CARTA.FileType | CARTA.CatalogFileType, targetFrame?: FrameStore) { if (!(type === CARTA.FileType.CRTF || type === CARTA.FileType.DS9_REG)) { - (yield AppToaster).show(ErrorToast("Region type not supported")); + AppToaster.show(ErrorToast("Region type not supported")); return; } @@ -1231,7 +1231,7 @@ export class AppStore { } if (!frame) { - (yield AppToaster).show(ErrorToast("No image file")); + AppToaster.show(ErrorToast("No image file")); return; } @@ -1254,7 +1254,7 @@ export class AppStore { console.error(err); this.fileBrowserStore.setImportingRegions(false); this.fileBrowserStore.resetLoadingStates(); - (yield AppToaster).show(ErrorToast(err)); + AppToaster.show(ErrorToast(err)); } } @@ -1334,7 +1334,7 @@ export class AppStore { try { yield this.backendService.exportRegion(directory, file, fileType, coordType, frame.frameInfo.fileId, regionStyles, overwrite); - (yield AppToaster).show(SuccessToast("saved", `Exported regions for ${frame.filename} using ${coordType === CARTA.CoordinateType.WORLD ? "world" : "pixel"} coordinates`)); + AppToaster.show(SuccessToast("saved", `Exported regions for ${frame.filename} using ${coordType === CARTA.CoordinateType.WORLD ? "world" : "pixel"} coordinates`)); this.fileBrowserStore.hideFileBrowser(); } catch (err) { throw err; @@ -1344,13 +1344,13 @@ export class AppStore { /** * Deletes all regions including annotations. */ - @action deleteAllRegions = async () => { + @action deleteAllRegions = () => { this.activeFrame.regionSet.regionMap.forEach(x => { if (x.regionId !== CURSOR_REGION_ID) { this.deleteRegion(x); } }); - (await AppToaster).show(SuccessToast("console", `Regions deleted successfully.`, 3000)); + AppToaster.show(SuccessToast("console", `Regions deleted successfully.`, 3000)); }; /** @@ -1421,7 +1421,7 @@ export class AppStore { newMomentImage.setSpatialReference(this.spatialReference); } } else { - (yield AppToaster).show({icon: "warning-sign", message: "Load file failed.", intent: "danger", timeout: 3000}); + AppToaster.show({icon: "warning-sign", message: "Load file failed.", intent: "danger", timeout: 3000}); } } } @@ -1465,7 +1465,7 @@ export class AppStore { this.fileCounter++; frame.addPvImage(this.frames.find(f => f.frameInfo.fileId === ack.openFileAck.fileId)); } else { - (yield AppToaster).show({icon: "warning-sign", message: "Load file failed.", intent: "danger", timeout: 3000}); + AppToaster.show({icon: "warning-sign", message: "Load file failed.", intent: "danger", timeout: 3000}); } } frame.resetPvRequestState(); @@ -1476,7 +1476,7 @@ export class AppStore { frame.setIsRequestPVCancelling(false); this.endFileLoading(); console.error(err); - (yield AppToaster).show(ErrorToast(err)); + AppToaster.show(ErrorToast(err)); } } @@ -1501,7 +1501,7 @@ export class AppStore { WidgetsStore.Instance.createFloatingSettingsWidget("PV Preview Viewer", id, PvGeneratorComponent.WIDGET_CONFIG.type); } } else { - (yield AppToaster).show({icon: "warning-sign", message: "Load preview failed.", intent: "danger", timeout: 3000}); + AppToaster.show({icon: "warning-sign", message: "Load preview failed.", intent: "danger", timeout: 3000}); } frame.resetPvRequestState(); frame.setIsRequestPVCancelling(false); @@ -1511,7 +1511,7 @@ export class AppStore { frame.resetPvRequestState(); frame.setIsRequestPVCancelling(false); this.endFileLoading(); - (yield AppToaster).show(ErrorToast(err)); + AppToaster.show(ErrorToast(err)); } } @@ -1564,7 +1564,7 @@ export class AppStore { this.fileCounter++; frame?.addFittingModelImage(this.getFrame(ack.modelImage.fileId)); } else { - (yield AppToaster).show({icon: "warning-sign", message: "Load model image failed.", intent: "danger", timeout: 3000}); + AppToaster.show({icon: "warning-sign", message: "Load model image failed.", intent: "danger", timeout: 3000}); } } if (ack.residualImage) { @@ -1572,15 +1572,15 @@ export class AppStore { this.fileCounter++; frame?.addFittingResidualImage(this.getFrame(ack.residualImage.fileId)); } else { - (yield AppToaster).show({icon: "warning-sign", message: "Load residual image failed.", intent: "danger", timeout: 3000}); + AppToaster.show({icon: "warning-sign", message: "Load residual image failed.", intent: "danger", timeout: 3000}); } } } if (ack.message) { - (yield AppToaster).show(WarningToast(`Image fitting: ${ack.message}.`)); + AppToaster.show(WarningToast(`Image fitting: ${ack.message}.`)); } } catch (err) { - (yield AppToaster).show(ErrorToast(`Image fitting failed: ${err}.`)); + AppToaster.show(ErrorToast(`Image fitting failed: ${err}.`)); } this.setActiveImageByFileId(message.fileId); @@ -1916,21 +1916,21 @@ export class AppStore { }); // Display toasts when connection status changes - autorun(async () => { + autorun(() => { const newConnectionStatus = this.backendService.connectionStatus; const userString = this.username ? ` as ${this.username}` : ""; switch (newConnectionStatus) { case ConnectionStatus.ACTIVE: - (await AppToaster).clear(); + AppToaster.clear(); if (this.backendService.connectionDropped) { - (await AppToaster).show(WarningToast(`Reconnected to server${userString}. Some errors may occur`)); + AppToaster.show(WarningToast(`Reconnected to server${userString}. Some errors may occur`)); } else { - (await AppToaster).show(SuccessToast("swap-vertical", `Connected to CARTA server${userString}`)); + AppToaster.show(SuccessToast("swap-vertical", `Connected to CARTA server${userString}`)); } break; case ConnectionStatus.CLOSED: if (this.previousConnectionStatus === ConnectionStatus.ACTIVE || this.previousConnectionStatus === ConnectionStatus.PENDING) { - (await AppToaster).show(ErrorToast("Disconnected from server")); + AppToaster.show(ErrorToast("Disconnected from server")); this.alertStore .showRetryAlert( "You have been disconnected from the server. Do you want to reconnect? Please note that temporary images such as moment images, PV images, or fitting model/residual images generated via the GUI will be unloaded.", @@ -2496,7 +2496,7 @@ export class AppStore { const workspace: Workspace = yield this.apiService.getWorkspace(name, isKey); if (!workspace) { this.loadingWorkspace = false; - (yield AppToaster).show({icon: "warning-sign", message: `Could not load workspace "${name}"`, intent: "danger", timeout: 3000}); + AppToaster.show({icon: "warning-sign", message: `Could not load workspace "${name}"`, intent: "danger", timeout: 3000}); return false; } @@ -2638,7 +2638,7 @@ export class AppStore { return true; } catch (err) { console.error(err); - (yield AppToaster).show({icon: "warning-sign", message: `Could not load workspace "${name}"`, intent: "danger", timeout: 3000}); + AppToaster.show({icon: "warning-sign", message: `Could not load workspace "${name}"`, intent: "danger", timeout: 3000}); this.loadingWorkspace = false; return false; } @@ -2765,7 +2765,7 @@ export class AppStore { } if (hasTemporaryFiles) { - (yield AppToaster).show(WarningToast("The workspace contains generated files. These will not be preserved when reloading.")); + AppToaster.show(WarningToast("The workspace contains generated files. These will not be preserved when reloading.")); } if (this.activeFrame) { workspace.selectedFile = this.activeFrameFileId; @@ -2782,7 +2782,7 @@ export class AppStore { try { const success = await this.apiService.clearWorkspace(name); if (success) { - (await AppToaster).show(SuccessToast("console", `Workspace ${name} deleted successfully.`, SnippetStore.ToasterTimeout)); + AppToaster.show(SuccessToast("console", `Workspace ${name} deleted successfully.`, SnippetStore.ToasterTimeout)); return; } } catch (err) { @@ -3039,7 +3039,7 @@ export class AppStore { if (val) { if (!frame.setSpatialReference(this.spatialReference)) { - (yield AppToaster).show(WarningToast(`Could not enable spatial matching of ${frame.filename} to reference image ${this.spatialReference.filename}. No valid transform was found.`)); + AppToaster.show(WarningToast(`Could not enable spatial matching of ${frame.filename} to reference image ${this.spatialReference.filename}. No valid transform was found.`)); } } else { const confirmed = yield this.confirmColorBlendingRemoval(frame); @@ -3109,14 +3109,14 @@ export class AppStore { } }; - @action setSpectralMatchingEnabled = async (frame: FrameStore, val: boolean) => { + @action setSpectralMatchingEnabled = (frame: FrameStore, val: boolean) => { if (!frame || frame === this.spectralReference) { return; } if (val) { if (!frame.setSpectralReference(this.spectralReference)) { - (await AppToaster).show(WarningToast(`Could not enable spectral matching (velocity system) of ${frame.filename} to reference image ${this.spectralReference.filename}. No valid transform was found`)); + AppToaster.show(WarningToast(`Could not enable spectral matching (velocity system) of ${frame.filename} to reference image ${this.spectralReference.filename}. No valid transform was found`)); } } else { frame.clearSpectralReference(); @@ -3240,9 +3240,9 @@ export class AppStore { } }; - decreaseImageRatio = async () => { + decreaseImageRatio = () => { if (this.imageRatio !== 1 && this.isExportingImage === true) { - (await AppToaster).show(WarningToast(`Exceeded the maximum canvas size; exporting image with ${this.imageRatio - 1}00% resolution instead.`)); + AppToaster.show(WarningToast(`Exceeded the maximum canvas size; exporting image with ${this.imageRatio - 1}00% resolution instead.`)); this.setImageRatio(this.imageRatio - 1); } }; diff --git a/src/stores/FileBrowserStore/FileBrowserStore.ts b/src/stores/FileBrowserStore/FileBrowserStore.ts index 66b2c3809d..6c54d563c4 100644 --- a/src/stores/FileBrowserStore/FileBrowserStore.ts +++ b/src/stores/FileBrowserStore/FileBrowserStore.ts @@ -218,7 +218,7 @@ export class FileBrowserStore { } } catch (err) { console.log(err); - (yield AppToaster).show(ErrorToast(`Error loading file list for directory ${directory}`)); + AppToaster.show(ErrorToast(`Error loading file list for directory ${directory}`)); } this.loadingList = false; this.resetLoadingStates(); diff --git a/src/stores/ImageFittingStore/ImageFittingStore.ts b/src/stores/ImageFittingStore/ImageFittingStore.ts index bb90d2547c..311be6eb4a 100644 --- a/src/stores/ImageFittingStore/ImageFittingStore.ts +++ b/src/stores/ImageFittingStore/ImageFittingStore.ts @@ -367,7 +367,7 @@ export class ImageFittingStore { }) ); newRegions?.forEach(r => r?.setDashLength(2)); - (await AppToaster).show(SuccessToast("tick", `Created ${params?.length} ellipse regions.`)); + AppToaster.show(SuccessToast("tick", `Created ${params?.length} ellipse regions.`)); } catch (err) { console.log(err); } diff --git a/src/stores/LayoutStore/LayoutStore.ts b/src/stores/LayoutStore/LayoutStore.ts index 613fa9a012..264d5b01e1 100644 --- a/src/stores/LayoutStore/LayoutStore.ts +++ b/src/stores/LayoutStore/LayoutStore.ts @@ -188,9 +188,9 @@ export class LayoutStore { } } - private handleSaveResult = async (success: boolean) => { + private handleSaveResult = (success: boolean) => { if (success) { - (await AppToaster).show(SuccessToast("layout-grid", `Layout ${this.layoutNameToBeSaved} saved successfully.`, LayoutStore.ToasterTimeout)); + AppToaster.show(SuccessToast("layout-grid", `Layout ${this.layoutNameToBeSaved} saved successfully.`, LayoutStore.ToasterTimeout)); this.currentLayoutName = this.layoutNameToBeSaved; } else { delete this.layouts[this.layoutNameToBeSaved]; @@ -243,9 +243,9 @@ export class LayoutStore { } } - private handleRenameResult = async (oldName: string, newName: string, success: boolean) => { + private handleRenameResult = (oldName: string, newName: string, success: boolean) => { if (success) { - (await AppToaster).show(SuccessToast("layout-grid", `Layout ${oldName} renamed to ${newName} successfully.`, LayoutStore.ToasterTimeout)); + AppToaster.show(SuccessToast("layout-grid", `Layout ${oldName} renamed to ${newName} successfully.`, LayoutStore.ToasterTimeout)); if (oldName === this.currentLayoutName) { this.currentLayoutName = newName; } @@ -273,9 +273,9 @@ export class LayoutStore { } } - private handleDeleteResult = async (layoutName: string, success: boolean) => { + private handleDeleteResult = (layoutName: string, success: boolean) => { if (success) { - (await AppToaster).show(SuccessToast("layout-grid", `Layout ${layoutName} deleted successfully.`, LayoutStore.ToasterTimeout)); + AppToaster.show(SuccessToast("layout-grid", `Layout ${layoutName} deleted successfully.`, LayoutStore.ToasterTimeout)); if (layoutName === this.currentLayoutName) { this.currentLayoutName = ""; } diff --git a/src/stores/Snippet/SnippetStore.ts b/src/stores/Snippet/SnippetStore.ts index 8e3ba1ab82..5b81da6f2d 100644 --- a/src/stores/Snippet/SnippetStore.ts +++ b/src/stores/Snippet/SnippetStore.ts @@ -139,7 +139,7 @@ export class SnippetStore { if (success) { // Silently exit on success if silent flag is set if (!silent) { - (yield AppToaster).show(SuccessToast("console", `Snippet ${name} saved successfully.`, SnippetStore.ToasterTimeout)); + AppToaster.show(SuccessToast("console", `Snippet ${name} saved successfully.`, SnippetStore.ToasterTimeout)); } return true; } else { @@ -159,7 +159,7 @@ export class SnippetStore { if (success) { // Silently exit on success if silent flag is set if (!silent) { - (yield AppToaster).show(SuccessToast("console", `Snippet ${name} deleted successfully.`, SnippetStore.ToasterTimeout)); + AppToaster.show(SuccessToast("console", `Snippet ${name} deleted successfully.`, SnippetStore.ToasterTimeout)); } return true; } else { From 26e15af5c61b06251134abfc87f98de96288bf5a Mon Sep 17 00:00:00 2001 From: yuhsuan Date: Wed, 30 Oct 2024 15:35:23 +0800 Subject: [PATCH 11/14] migrate blueprint toaster to react 18 --- src/components/Shared/toaster.ts | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/components/Shared/toaster.ts b/src/components/Shared/toaster.ts index 2874f1f867..0de069e75f 100644 --- a/src/components/Shared/toaster.ts +++ b/src/components/Shared/toaster.ts @@ -1,11 +1,26 @@ -import {IconName, Position, Toaster, ToastProps} from "@blueprintjs/core"; +import {createRoot} from "react-dom/client"; +import {IconName, OverlayToaster, Position, ToastProps} from "@blueprintjs/core"; import {copyToClipboard} from "utilities"; -export const AppToaster = Toaster.create({ - className: "app-toaster", - position: Position.BOTTOM -}); +const toaster = OverlayToaster.createAsync( + { + className: "app-toaster", + position: Position.BOTTOM + }, + { + domRenderer: (toaster, containerElement) => createRoot(containerElement).render(toaster) + } +); + +export const AppToaster = { + show: async (toast: ToastProps) => { + (await toaster).show(toast); + }, + clear: async () => { + (await toaster).clear(); + } +}; export function SuccessToast(icon: IconName, message: string, timeout?: number): ToastProps { return { From 80d67ccf86aeaa7e34d05e9b01f5ccc0e8fac74b Mon Sep 17 00:00:00 2001 From: yuhsuan Date: Mon, 4 Nov 2024 15:01:40 +0800 Subject: [PATCH 12/14] upgrade konva --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index bfb3309e1f..fcf2ccd754 100644 --- a/package-lock.json +++ b/package-lock.json @@ -50,7 +50,7 @@ "idb": "^8.0.0", "jest-canvas-mock": "^2.5.2", "jwt-decode": "^4.0.0", - "konva": "^8.4.3", + "konva": "^9.3.16", "lodash": "^4.17.15", "mnemonist": "^0.39.8", "mobx": "^6.13.1", @@ -12613,9 +12613,9 @@ } }, "node_modules/konva": { - "version": "8.4.3", - "resolved": "https://registry.npmjs.org/konva/-/konva-8.4.3.tgz", - "integrity": "sha512-ARqdgAbdNIougRlOKvkQwHlGhXPRBV4KvhCP+qoPpGoVQwwiJe4Hkdu4HHdRPb9rGUp04jDTAxBzEwBsE272pg==", + "version": "9.3.16", + "resolved": "https://registry.npmjs.org/konva/-/konva-9.3.16.tgz", + "integrity": "sha512-qa47cefGDDHzkToGRGDsy24f/Njrz7EHP56jQ8mlDcjAPO7vkfTDeoBDIfmF7PZtpfzDdooafQmEUJMDU2F7FQ==", "dev": true, "funding": [ { diff --git a/package.json b/package.json index e11811fc22..c4b7c84af3 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "idb": "^8.0.0", "jest-canvas-mock": "^2.5.2", "jwt-decode": "^4.0.0", - "konva": "^8.4.3", + "konva": "^9.3.16", "lodash": "^4.17.15", "mnemonist": "^0.39.8", "mobx": "^6.13.1", From 90b25d8de209d3e96369e7a5564993d5ec878467 Mon Sep 17 00:00:00 2001 From: yuhsuan Date: Mon, 4 Nov 2024 15:06:21 +0800 Subject: [PATCH 13/14] upgrade react testing library --- package-lock.json | 83 ++++++++++++++++++----------------------------- package.json | 2 +- 2 files changed, 32 insertions(+), 53 deletions(-) diff --git a/package-lock.json b/package-lock.json index fcf2ccd754..bac32a51c8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,7 @@ "@blueprintjs/select": "^5.2.2", "@blueprintjs/table": "^5.1.8", "@testing-library/jest-dom": "^6.4.8", - "@testing-library/react": "^12.1.5", + "@testing-library/react": "^16.0.1", "@testing-library/user-event": "^14.5.2", "@types/jest": "^29.5.12", "@types/jquery": "^3.5.30", @@ -3768,31 +3768,23 @@ } }, "node_modules/@testing-library/dom": { - "version": "8.20.1", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.20.1.tgz", - "integrity": "sha512-/DiOQ5xBxgdYRC8LNk7U+RWat0S3qRLeIw3ZIkMQ9kkVlRmwD/Eg8k8CqIpD6GW7u20JIUOfMKbxtiLutpjQ4g==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", + "integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==", "dev": true, + "peer": true, "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", "@types/aria-query": "^5.0.1", - "aria-query": "5.1.3", + "aria-query": "5.3.0", "chalk": "^4.1.0", "dom-accessibility-api": "^0.5.9", "lz-string": "^1.5.0", "pretty-format": "^27.0.2" }, "engines": { - "node": ">=12" - } - }, - "node_modules/@testing-library/dom/node_modules/aria-query": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", - "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", - "dev": true, - "dependencies": { - "deep-equal": "^2.0.5" + "node": ">=18" } }, "node_modules/@testing-library/dom/node_modules/chalk": { @@ -3800,6 +3792,7 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "peer": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -3815,7 +3808,8 @@ "version": "0.5.16", "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", - "dev": true + "dev": true, + "peer": true }, "node_modules/@testing-library/jest-dom": { "version": "6.4.8", @@ -3839,41 +3833,30 @@ } }, "node_modules/@testing-library/react": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-12.1.5.tgz", - "integrity": "sha512-OfTXCJUFgjd/digLUuPxa0+/3ZxsQmE7ub9kcbW/wi96Bh3o/p5vrETcBGfP17NWPGqeYYl5LTRpwyGoMC4ysg==", + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.0.1.tgz", + "integrity": "sha512-dSmwJVtJXmku+iocRhWOUFbrERC76TX2Mnf0ATODz8brzAZrMBbzLwQixlBSanZxR6LddK3eiwpSFZgDET1URg==", "dev": true, "dependencies": { - "@babel/runtime": "^7.12.5", - "@testing-library/dom": "^8.0.0", - "@types/react-dom": "<18.0.0" + "@babel/runtime": "^7.12.5" }, "engines": { - "node": ">=12" + "node": ">=18" }, "peerDependencies": { - "react": "<18.0.0", - "react-dom": "<18.0.0" - } - }, - "node_modules/@testing-library/react/node_modules/@types/react": { - "version": "17.0.83", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.83.tgz", - "integrity": "sha512-l0m4ArKJvmFtR4e8UmKrj1pB4tUgOhJITf+mADyF/p69Ts1YAR/E+G9XEM0mHXKVRa1dQNHseyyDNzeuAXfXQw==", - "dev": true, - "dependencies": { - "@types/prop-types": "*", - "@types/scheduler": "^0.16", - "csstype": "^3.0.2" - } - }, - "node_modules/@testing-library/react/node_modules/@types/react-dom": { - "version": "17.0.25", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.25.tgz", - "integrity": "sha512-urx7A7UxkZQmThYA4So0NelOVjx3V4rNFVJwp0WZlbIK5eM4rNJDiN3R/E9ix0MBh6kAEojk/9YL+Te6D9zHNA==", - "dev": true, - "dependencies": { - "@types/react": "^17" + "@testing-library/dom": "^10.0.0", + "@types/react": "^18.0.0", + "@types/react-dom": "^18.0.0", + "react": "^18.0.0", + "react-dom": "^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, "node_modules/@testing-library/user-event": { @@ -3947,7 +3930,8 @@ "version": "5.0.4", "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", - "dev": true + "dev": true, + "peer": true }, "node_modules/@types/babel__core": { "version": "7.20.0", @@ -4423,12 +4407,6 @@ "version": "0.12.0", "license": "MIT" }, - "node_modules/@types/scheduler": { - "version": "0.16.8", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", - "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==", - "dev": true - }, "node_modules/@types/semver": { "version": "7.3.13", "license": "MIT" @@ -12815,6 +12793,7 @@ "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", "dev": true, + "peer": true, "bin": { "lz-string": "bin/bin.js" } diff --git a/package.json b/package.json index c4b7c84af3..3a196fcc98 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "@blueprintjs/select": "^5.2.2", "@blueprintjs/table": "^5.1.8", "@testing-library/jest-dom": "^6.4.8", - "@testing-library/react": "^12.1.5", + "@testing-library/react": "^16.0.1", "@testing-library/user-event": "^14.5.2", "@types/jest": "^29.5.12", "@types/jquery": "^3.5.30", From 582d34cf9eb535172fb01b6b7df7e5c5f345af0b Mon Sep 17 00:00:00 2001 From: yuhsuan Date: Wed, 20 Nov 2024 17:32:18 +0800 Subject: [PATCH 14/14] fix auto scroll not being triggered --- src/components/Shared/Tables/FilterableTableComponent.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Shared/Tables/FilterableTableComponent.tsx b/src/components/Shared/Tables/FilterableTableComponent.tsx index 9c0615f14e..508757f1ce 100644 --- a/src/components/Shared/Tables/FilterableTableComponent.tsx +++ b/src/components/Shared/Tables/FilterableTableComponent.tsx @@ -353,7 +353,7 @@ export class FilterableTableComponent extends React.Component table.updateTableRef(ref) : null} + ref={table.updateTableRef ?? null} numRows={table.numVisibleRows} renderMode={RenderMode.BATCH} enableRowReordering={false}