From 843ea75372072af803d10c24c0a10525d8e97f5c Mon Sep 17 00:00:00 2001 From: ddelpiano Date: Fri, 5 Sep 2025 11:56:48 +0200 Subject: [PATCH 1/4] small fixes with loader and double requests --- .../src/components/StackViewerComponent.jsx | 15 ++++++++- .../frontend/src/reducers/InstancesReducer.js | 32 +++++++++++++++++-- .../src/reducers/actions/instances.js | 9 ++++++ .../actions/types/getInstancesTypes.js | 4 ++- .../middleware/urlUpdaterMiddleware.js | 14 ++++++-- .../src/reducers/middleware/vfbMiddleware.js | 2 -- .../frontend/src/shared/subHeader/index.jsx | 20 ++++++++++-- 7 files changed, 84 insertions(+), 12 deletions(-) diff --git a/applications/virtual-fly-brain/frontend/src/components/StackViewerComponent.jsx b/applications/virtual-fly-brain/frontend/src/components/StackViewerComponent.jsx index 7508be84..989d4e19 100644 --- a/applications/virtual-fly-brain/frontend/src/components/StackViewerComponent.jsx +++ b/applications/virtual-fly-brain/frontend/src/components/StackViewerComponent.jsx @@ -491,6 +491,12 @@ const rgbToHex = (color) => { }, callObjects: function () { + // Prevent duplicate calls within 100ms + const now = Date.now(); + if (this._lastCallObjectsTime && (now - this._lastCallObjectsTime) < 100) { + return; + } + this._lastCallObjectsTime = now; var j, result; var that = this; @@ -1289,13 +1295,20 @@ const rgbToHex = (color) => { this.props.setExtent({ stackX: this.stack.position.x, stackY: this.stack.position.y }); this.createImages(); this.state.buffer[-1].text = ''; + + // Set flag to prevent duplicate click event + this._justFinishedDrag = true; + setTimeout(() => { + this._justFinishedDrag = false; + }, 10); } this.state.dragging = false; }, onStackClick: function (event) { // Backup click handler for when drag doesn't register as a click - if (!this.state.dragging) { + // But prevent duplicate calls if we just finished a drag operation + if (!this.state.dragging && !this._justFinishedDrag) { var clickPosition; if (event.data && typeof event.data.getLocalPosition === "function") { clickPosition = event.data.getLocalPosition(this.stack); diff --git a/applications/virtual-fly-brain/frontend/src/reducers/InstancesReducer.js b/applications/virtual-fly-brain/frontend/src/reducers/InstancesReducer.js index 7a691459..c18e42f3 100644 --- a/applications/virtual-fly-brain/frontend/src/reducers/InstancesReducer.js +++ b/applications/virtual-fly-brain/frontend/src/reducers/InstancesReducer.js @@ -24,6 +24,8 @@ export const initialStateInstancesReducer = { selectedInstancesCount: 1, loadingInstances: 0, finishedLoadedInstances: 0, + bulkLoadingCount: 0, + isBulkLoading: false, }; const getMappedCanvasData = (loadedInstances) => { @@ -120,6 +122,9 @@ const InstancesReducer = (state = initialStateInstancesReducer, response) => { }); } + const newFinishedCount = state.finishedLoadedInstances + 1; + const isAllBulkInstancesLoaded = state.isBulkLoading && newFinishedCount >= state.bulkLoadingCount; + return Object.assign({}, state, { allLoadedInstances: loadedInstances, launchTemplate: launchTemplate, @@ -130,10 +135,13 @@ const InstancesReducer = (state = initialStateInstancesReducer, response) => { id: response.payload.Id, trigger: Date.now(), }, - isLoading: false, + isLoading: state.isBulkLoading ? !isAllBulkInstancesLoaded : false, error: false, errorMessage: undefined, - finishedLoadedInstances: state.finishedLoadedInstances + 1, + finishedLoadedInstances: newFinishedCount, + // Reset bulk loading state when all instances are loaded + isBulkLoading: state.isBulkLoading && !isAllBulkInstancesLoaded, + bulkLoadingCount: isAllBulkInstancesLoaded ? 0 : state.bulkLoadingCount, }); } case getInstancesTypes.GET_INSTANCES_FAILURE: { @@ -143,6 +151,9 @@ const InstancesReducer = (state = initialStateInstancesReducer, response) => { loadingInstances: 0, finishedLoadedInstances: 0, isLoading: false, + // Reset bulk loading state on failure + isBulkLoading: false, + bulkLoadingCount: 0, }); } case getInstancesTypes.REMOVE_INSTANCES_SUCCESS: { @@ -727,6 +738,23 @@ const InstancesReducer = (state = initialStateInstancesReducer, response) => { errorMessage: undefined, }); } + case getInstancesTypes.SET_BULK_LOADING_COUNT: { + return Object.assign({}, state, { + bulkLoadingCount: response.payload.count, + isBulkLoading: true, + loadingInstances: 0, + finishedLoadedInstances: 0, + }); + } + case getInstancesTypes.RESET_BULK_LOADING: { + return Object.assign({}, state, { + bulkLoadingCount: 0, + isBulkLoading: false, + loadingInstances: 0, + finishedLoadedInstances: 0, + isLoading: false, + }); + } default: return state; } diff --git a/applications/virtual-fly-brain/frontend/src/reducers/actions/instances.js b/applications/virtual-fly-brain/frontend/src/reducers/actions/instances.js index a06b4c8a..ea5d42b5 100644 --- a/applications/virtual-fly-brain/frontend/src/reducers/actions/instances.js +++ b/applications/virtual-fly-brain/frontend/src/reducers/actions/instances.js @@ -170,6 +170,15 @@ export const resetLoadingState = () => ({ type: getInstancesTypes.RESET_LOADING_STATE }); +export const setBulkLoadingCount = (count) => ({ + type: getInstancesTypes.SET_BULK_LOADING_COUNT, + payload: { count } +}); + +export const resetBulkLoading = () => ({ + type: getInstancesTypes.RESET_BULK_LOADING +}); + export const triggerInstanceFailure = (error) => { store.dispatch(getInstancesFailure(error)); return; diff --git a/applications/virtual-fly-brain/frontend/src/reducers/actions/types/getInstancesTypes.js b/applications/virtual-fly-brain/frontend/src/reducers/actions/types/getInstancesTypes.js index 951647bf..d738fd09 100644 --- a/applications/virtual-fly-brain/frontend/src/reducers/actions/types/getInstancesTypes.js +++ b/applications/virtual-fly-brain/frontend/src/reducers/actions/types/getInstancesTypes.js @@ -28,5 +28,7 @@ export const getInstancesTypes = Object.freeze({ UPDATE_SKELETON : "UPDATE_SKELETON", LAUNCH_TEMPLATE : "LAUNCH_TEMPLATE", UPDATE_INSTANCES : "UPDATE_INSTANCES", - RESET_LOADING_STATE : "RESET_LOADING_STATE" + RESET_LOADING_STATE : "RESET_LOADING_STATE", + SET_BULK_LOADING_COUNT : "SET_BULK_LOADING_COUNT", + RESET_BULK_LOADING : "RESET_BULK_LOADING" }) diff --git a/applications/virtual-fly-brain/frontend/src/reducers/middleware/urlUpdaterMiddleware.js b/applications/virtual-fly-brain/frontend/src/reducers/middleware/urlUpdaterMiddleware.js index 9630369f..65f04484 100644 --- a/applications/virtual-fly-brain/frontend/src/reducers/middleware/urlUpdaterMiddleware.js +++ b/applications/virtual-fly-brain/frontend/src/reducers/middleware/urlUpdaterMiddleware.js @@ -3,7 +3,7 @@ import { getQueriesFailure } from '../actions/queries'; import { getQueriesTypes } from '../actions/types/getQueriesTypes'; import { getInstancesTypes } from '../actions/types/getInstancesTypes'; import { setFirstIDLoaded, setAlignTemplates, setTemplateID } from '../actions/globals'; -import { getInstanceByID, get3DMesh, triggerInstanceFailure } from '../actions/instances'; +import { getInstanceByID, get3DMesh, triggerInstanceFailure, setBulkLoadingCount } from '../actions/instances'; import * as GeppettoActions from '@metacell/geppetto-meta-client/common/actions'; function updateUrlParameterWithCurrentUrl(param, value, reset) { @@ -43,7 +43,7 @@ function updateUrlWithInstancesAndSelectedId(selectedId) { const DEFAULT_ID = "VFB_00101567"; const APP_LOADED_FLAG_KEY = "CURRENT_LOADED_URL"; -const isFirstTimeLoad = (allLoadedInstances) => { +const isFirstTimeLoad = (allLoadedInstances, store) => { const appLoadedUrl = localStorage.getItem(APP_LOADED_FLAG_KEY); const currentUrl = window.location.href; if (currentUrl != appLoadedUrl) { @@ -71,6 +71,14 @@ const isFirstTimeLoad = (allLoadedInstances) => { idToUpdate.push(DEFAULT_ID); } + // Filter out instances that are already loaded to get the actual count we need to load + const instancesToLoad = idToUpdate.filter(id => !allLoadedInstances?.find(i => i.metadata?.Id === id)); + + // If we have instances to load, set up bulk loading + if (instancesToLoad.length > 0) { + store.dispatch(setBulkLoadingCount(instancesToLoad.length)); + } + idToUpdate?.forEach( id => { // if it's the last ID in the list, we need to focus it if (id === idToUpdate[idToUpdate.length - 1]) { @@ -101,7 +109,7 @@ export const urlUpdaterMiddleware = store => next => (action) => { // Only call isFirstTimeLoad if we haven't loaded the first ID yet if (!firstIDLoaded) { - isFirstTimeLoad(allLoadedInstances); + isFirstTimeLoad(allLoadedInstances, store); } switch (action.type) { diff --git a/applications/virtual-fly-brain/frontend/src/reducers/middleware/vfbMiddleware.js b/applications/virtual-fly-brain/frontend/src/reducers/middleware/vfbMiddleware.js index f4669615..ce1ef63d 100644 --- a/applications/virtual-fly-brain/frontend/src/reducers/middleware/vfbMiddleware.js +++ b/applications/virtual-fly-brain/frontend/src/reducers/middleware/vfbMiddleware.js @@ -43,7 +43,6 @@ const vfbMiddleware = store => next => (action) => { break; } case getGlobalTypes.SHOW_SLICE_DISPLAY : { - let matchInstance = store.getState().instances.allLoadedInstances.find( i => i.metadata?.Id === action.payload.id ); let objectFound = null; for (let child of store.getState().instances.threeDObjects) { if ( action.payload.data?.id === child.material?.name ) { @@ -66,7 +65,6 @@ const vfbMiddleware = store => next => (action) => { break; } case getGlobalTypes.MODIFY_SLICE_DISPLAY : { - let matchInstance = store.getState().instances.allLoadedInstances.find( i => i.metadata?.Id === action.payload.id ); let objectFound = null; for (let child of store.getState().instances.threeDObjects) { if ( action.payload.data?.id === child.material?.name ) { diff --git a/applications/virtual-fly-brain/frontend/src/shared/subHeader/index.jsx b/applications/virtual-fly-brain/frontend/src/shared/subHeader/index.jsx index e5a0c5fd..685f8272 100644 --- a/applications/virtual-fly-brain/frontend/src/shared/subHeader/index.jsx +++ b/applications/virtual-fly-brain/frontend/src/shared/subHeader/index.jsx @@ -80,6 +80,12 @@ const SubHeader = ({ setBottomNav, bottomNav }) => { const finishedLoadedInstances = useSelector( (state) => state.instances.finishedLoadedInstances ); + const isBulkLoading = useSelector( + (state) => state.instances.isBulkLoading + ); + const bulkLoadingCount = useSelector( + (state) => state.instances.bulkLoadingCount + ); const dispatch = useDispatch(); const classes = { root: { @@ -103,7 +109,13 @@ const SubHeader = ({ setBottomNav, bottomNav }) => { }; useEffect(() => { - if (loadingInstances > 0 && loadingInstances === finishedLoadedInstances) { + // For bulk loading, check if all instances are loaded using bulk count + // For individual loading, use the original logic + const allLoaded = isBulkLoading + ? finishedLoadedInstances >= bulkLoadingCount + : loadingInstances > 0 && loadingInstances === finishedLoadedInstances; + + if (allLoaded) { // Add a small delay to show the final loading state before resetting const timer = setTimeout(() => { dispatch(resetLoadingState()); @@ -111,7 +123,7 @@ const SubHeader = ({ setBottomNav, bottomNav }) => { return () => clearTimeout(timer); } - }, [loadingInstances, finishedLoadedInstances]); + }, [loadingInstances, finishedLoadedInstances, isBulkLoading, bulkLoadingCount, dispatch]); return ( { Loading{" "} - {loadingInstances > 0 && finishedLoadedInstances > 0 + {isBulkLoading && bulkLoadingCount > 0 + ? `instance ${finishedLoadedInstances} of ${bulkLoadingCount}` + : loadingInstances > 0 && finishedLoadedInstances > 0 ? `instance ${finishedLoadedInstances} of ${loadingInstances}` : " ..."} From 60ca00e0a821f4d7089bd3914b3c507bc2fd53a0 Mon Sep 17 00:00:00 2001 From: ddelpiano Date: Fri, 5 Sep 2025 12:01:18 +0200 Subject: [PATCH 2/4] nginx configuration timeout --- applications/virtual-fly-brain/deploy/values-dev.yaml | 5 +++++ applications/virtual-fly-brain/deploy/values-local.yaml | 5 +++++ applications/virtual-fly-brain/deploy/values.yaml | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/applications/virtual-fly-brain/deploy/values-dev.yaml b/applications/virtual-fly-brain/deploy/values-dev.yaml index d048e646..19228034 100644 --- a/applications/virtual-fly-brain/deploy/values-dev.yaml +++ b/applications/virtual-fly-brain/deploy/values-dev.yaml @@ -18,3 +18,8 @@ harness: build: - cloudharness-base-debian - cloudharness-flask + ingress: + annotations: + nginx.ingress.kubernetes.io/proxy-read-timeout: "300" + nginx.ingress.kubernetes.io/proxy-connect-timeout: "300" + nginx.ingress.kubernetes.io/proxy-send-timeout: "300" diff --git a/applications/virtual-fly-brain/deploy/values-local.yaml b/applications/virtual-fly-brain/deploy/values-local.yaml index d2020baf..89280f67 100644 --- a/applications/virtual-fly-brain/deploy/values-local.yaml +++ b/applications/virtual-fly-brain/deploy/values-local.yaml @@ -1,3 +1,8 @@ harness: database: size: 10Gi + ingress: + annotations: + nginx.ingress.kubernetes.io/proxy-read-timeout: "300" + nginx.ingress.kubernetes.io/proxy-connect-timeout: "300" + nginx.ingress.kubernetes.io/proxy-send-timeout: "300" diff --git a/applications/virtual-fly-brain/deploy/values.yaml b/applications/virtual-fly-brain/deploy/values.yaml index d048e646..19228034 100644 --- a/applications/virtual-fly-brain/deploy/values.yaml +++ b/applications/virtual-fly-brain/deploy/values.yaml @@ -18,3 +18,8 @@ harness: build: - cloudharness-base-debian - cloudharness-flask + ingress: + annotations: + nginx.ingress.kubernetes.io/proxy-read-timeout: "300" + nginx.ingress.kubernetes.io/proxy-connect-timeout: "300" + nginx.ingress.kubernetes.io/proxy-send-timeout: "300" From 80c1013e082f9fbf0eab316e3fbf8483e56ec716 Mon Sep 17 00:00:00 2001 From: ddelpiano Date: Fri, 5 Sep 2025 12:07:39 +0200 Subject: [PATCH 3/4] fixing zindex across the app --- .../virtual-fly-brain/frontend/src/shared/sidebar/index.jsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/applications/virtual-fly-brain/frontend/src/shared/sidebar/index.jsx b/applications/virtual-fly-brain/frontend/src/shared/sidebar/index.jsx index be2e3b54..5a609df7 100644 --- a/applications/virtual-fly-brain/frontend/src/shared/sidebar/index.jsx +++ b/applications/virtual-fly-brain/frontend/src/shared/sidebar/index.jsx @@ -36,7 +36,7 @@ const CustomTableContainer = styled(TableContainer)( content: ''; position: absolute; top: 0; - z-index: 999; + z-index: 5; display: block; height: 100%; width: 100%; @@ -53,7 +53,7 @@ const CustomBox = styled(Box)( content: ''; position: absolute; right: 0; - z-index: 999; + z-index: 5; width: 100%; height: 100%; display: block; @@ -639,4 +639,4 @@ const SideBar = ({ open, setOpen }) => { ) }; -export default SideBar; \ No newline at end of file +export default SideBar; From ac7262e6127ebd419b656e69d6ad797c11715d31 Mon Sep 17 00:00:00 2001 From: ddelpiano Date: Fri, 5 Sep 2025 12:09:59 +0200 Subject: [PATCH 4/4] increasing gunicorn worker timeout --- applications/virtual-fly-brain/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/virtual-fly-brain/Dockerfile b/applications/virtual-fly-brain/Dockerfile index e74a404b..eadab005 100644 --- a/applications/virtual-fly-brain/Dockerfile +++ b/applications/virtual-fly-brain/Dockerfile @@ -72,4 +72,4 @@ RUN mkdir -p /var/log && touch /var/log/vfb_cache_cleanup.log WORKDIR /usr/src/app/virtual_fly_brain EXPOSE 8080 -ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh", "gunicorn", "--log-level=info", "--preload", "--bind=0.0.0.0:8080", "--timeout=120", "--graceful-timeout=30", "--keep-alive=5", "virtual_fly_brain.__main__:app"] +ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh", "gunicorn", "--log-level=info", "--preload", "--bind=0.0.0.0:8080", "--timeout=240", "--graceful-timeout=30", "--keep-alive=5", "virtual_fly_brain.__main__:app"]