plexora 0.0.8__tar.gz → 0.0.10__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {plexora-0.0.8/plexora.egg-info → plexora-0.0.10}/PKG-INFO +1 -1
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/main.js +141 -8
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/remoteGlobe.js +58 -2
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/remoteState.js +49 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/resourceRouting.js +47 -4
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/templates/base.html +3 -3
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/templates/index.html +1 -1
- {plexora-0.0.8 → plexora-0.0.10}/plexora/connect.py +146 -129
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/models/remote_sessions.py +65 -7
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/node/app.py +18 -1
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/routes/settings_routes.py +24 -3
- {plexora-0.0.8 → plexora-0.0.10/plexora.egg-info}/PKG-INFO +1 -1
- {plexora-0.0.8 → plexora-0.0.10}/pyproject.toml +1 -1
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_connect.py +68 -50
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_node_warm_and_cache.py +28 -10
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_remote_connect.py +165 -6
- {plexora-0.0.8 → plexora-0.0.10}/LICENSE +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/MANIFEST.in +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/README.md +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/__init__.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/__main__.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/_resources.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/_url.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/api/__init__.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/api/dataset.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/api/http.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/api/plugin.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/api/store.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/askpass.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/cli.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/dist/354_bundle.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/dist/354_bundle.js.LICENSE.txt +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/dist/418_bundle.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/dist/418_bundle.js.LICENSE.txt +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/dist/693b935cb1f907814be9c6199a68c217.svg +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/dist/713c134ff47cd328a5b711526f151082.svg +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/dist/770_bundle.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/dist/ff743f408972e0e96ca9153ed5ae4c83.svg +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/dist/vendor_bundle.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/dist/vendor_bundle.js.LICENSE.txt +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/LICENSE.txt +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/canvas-overlay-hd.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/changelog.txt +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/.gitattributes +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/LICENSE.txt +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/Photoshop/Toolbar.png +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/Photoshop/fullpage.psd +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/Photoshop/home.psd +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/Photoshop/next.psd +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/Photoshop/previous.psd +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/Photoshop/rotateleft.psd +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/Photoshop/rotateright.psd +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/Photoshop/zoom.psd +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/README.md +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/fullpage_grouphover.png +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/fullpage_hover.png +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/fullpage_pressed.png +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/fullpage_rest.png +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/home_grouphover.png +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/home_hover.png +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/home_pressed.png +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/home_rest.png +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/next_grouphover.png +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/next_hover.png +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/next_pressed.png +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/next_rest.png +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/previous_grouphover.png +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/previous_hover.png +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/previous_pressed.png +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/previous_rest.png +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/rotateleft_grouphover.png +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/rotateleft_hover.png +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/rotateleft_pressed.png +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/rotateleft_rest.png +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/rotateright_grouphover.png +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/rotateright_hover.png +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/rotateright_pressed.png +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/rotateright_rest.png +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/zoomin_grouphover.png +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/zoomin_hover.png +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/zoomin_pressed.png +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/zoomin_rest.png +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/zoomout_grouphover.png +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/zoomout_hover.png +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/zoomout_pressed.png +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/zoomout_rest.png +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-scalebar.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/css/import.css +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/css/main.css +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/css/openProject.css +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/css/quickView.css +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/css/settings.css +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/css/tokens.css +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/css/viewer.css +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/img/apple-touch-icon.png +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/img/favicon.ico +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/img/logo.ai +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/img/logo.svg +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/img/logo_with_text.ai +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/img/logo_with_text.svg +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/pluginRegistry.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/appRouter.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/appStatus.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/browsePicker.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/connectionModal.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/dataLayer.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/dataLocation.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/datasetContext.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/fileLocation.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/glRenderer.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/importFormValidation.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/keyboardShortcuts.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/logTerminal.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/numericData.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/pageBoot.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/passVariablesToFrontend.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/pathPicker.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/placePicker.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/resourceStatus.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/sessionExpiry.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/simpleEventHandler.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/vendor.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/channelList.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/channelNamesUpload.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/colorSwatchPicker.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/columnClassifier.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/coordinateField.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/dataSourceField.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/imageViewer.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/miniMap.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/navbarControls.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/openProjectPage.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/popoverPortal.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/projectEdit.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/quickViewLanding.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/rainbow.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/requirementsModal.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/rgbImageViewer.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/searchableSelect.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/segmentationProgress.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/segmentationWait.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/settingsPage.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/toolLoader.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/viewerControls.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/viewerManager.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/viewerSidebar.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/workers/tileDecoder.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/shaders/frag.glsl +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/shaders/vert.glsl +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/templates/_fragment.html +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/templates/open_project.html +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/templates/project_columns.html +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/templates/project_edit.html +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/templates/settings.html +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/client/templates/upload.html +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/datasource.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/jupyter.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/nodes.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/notebook_env.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/paths.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/__init__.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/cell_explorer/__init__.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/cell_explorer/server/__init__.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/cell_explorer/server/routes.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/cell_explorer/server/state.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/cell_explorer/server/values.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/cell_explorer/server/variables.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/cell_explorer/static/cellExplorerApi.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/cell_explorer/static/cellExplorerColors.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/cell_explorer/static/cellExplorerContinuous.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/cell_explorer/static/cellExplorerFigureBridge.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/cell_explorer/static/cellExplorerLegend.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/cell_explorer/static/cellExplorerRoiBridge.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/cell_explorer/static/cellExplorerSidebarController.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/cell_explorer/static/cellExplorerState.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/cell_explorer/static/cell_explorer.css +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/cell_explorer/templates/cell_explorer/panel.html +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/__init__.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/server/__init__.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/server/compose.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/server/export.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/server/export_jobs.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/server/operations.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/server/pixels.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/server/provenance.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/server/render.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/server/repository.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/server/routes.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/server/schema.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/server/shapegeom.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/server/sources.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/server/strokegeom.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/server/textmetrics.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureActions.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureBuilderApi.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureCanvas.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureCaptureBoxes.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureCaptureDock.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureCaptureTool.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureChoiceField.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureColorField.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureConfirm.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureContextBar.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureContextMenu.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureDocumentState.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureExportUi.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureImagePanel.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureLibrary.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureLineDefs.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureLinePanel.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figurePanelCompositor.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figurePointEditor.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureQuickEdit.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureRichText.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureSceneSnapshot.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureSchema.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureShapeDefs.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureShapeDrawing.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureShapeGeometry.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureShapePanel.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureSidebarController.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureStrokeGeometry.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureTextEditor.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureTextPanel.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureViewOptions.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureWorkspace.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figure_builder.css +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/templates/figure_builder/library.html +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/templates/figure_builder/workspace.html +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/templates/figure_builder/workspace_body.html +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/gating/__init__.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/gating/server/__init__.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/gating/server/anndata_gates.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/gating/server/database.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/gating/server/model.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/gating/server/routes.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/gating/server/tableops.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/gating/static/csvGatingList.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/gating/static/gating.css +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/gating/static/gatingApi.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/gating/static/gatingSidebarController.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/gating/templates/gating/legacy.html +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/gating/templates/gating/panel.html +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/roi/__init__.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/roi/server/__init__.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/roi/server/adapters.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/roi/server/geojson.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/roi/server/geometry.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/roi/server/mapping.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/roi/server/operations.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/roi/server/repository.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/roi/server/routes.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/roi/server/schema.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/roi/server/tableops.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/roi/static/roi.css +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/roi/static/roiApi.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/roi/static/roiFigureBridge.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/roi/static/roiGeometry.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/roi/static/roiRenderer.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/roi/static/roiSidebarController.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/roi/static/roiState.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/roi/static/roiTools.js +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/roi/templates/roi/panel.html +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/proxy.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/models/adapters/__init__.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/models/adapters/anndata_adapter.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/models/adapters/base.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/models/adapters/classify.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/models/adapters/csv_adapter.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/models/adapters/inspection.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/models/adapters/spatialdata_adapter.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/models/centroid_tiles.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/models/data_migration.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/models/data_model.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/models/database_model.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/models/nodes.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/models/project.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/models/recipes.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/models/remotes.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/models/secret_store.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/node/api.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/node/resources.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/plugins.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/providers/__init__.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/providers/base.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/providers/http.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/providers/local.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/providers/node.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/providers/operations.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/providers/wire.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/routes/browse_routes.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/routes/data_routes.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/routes/import_routes.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/routes/page_routes.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/routes/project_routes.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/routes/quick_view_routes.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/routes/system_routes.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/routes/tool_routes.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/routes/transfer_routes.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/utils/addHEColumns.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/utils/channel_file.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/utils/dir_listing.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/utils/fast_png.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/utils/file_transfer.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/utils/fullConversion.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/utils/native_dialog.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/utils/pre_normalization.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/utils/segmentation_pyramid.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/utils/smallestenclosingcircle.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server/utils/tiffsurgeon.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/server_cli.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora/test.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora.egg-info/SOURCES.txt +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora.egg-info/dependency_links.txt +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora.egg-info/entry_points.txt +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora.egg-info/requires.txt +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/plexora.egg-info/top_level.txt +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/setup.cfg +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_anndata_adapter.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_api_dataset.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_api_store.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_app_router.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_app_shell.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_auth_token.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_browse_routes.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_cell_color_layer.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_cell_mode_control.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_centroid_tiles.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_channel_names_modal.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_channel_names_upload.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_channel_overview.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_channel_rename_state.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_classify_columns.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_cli.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_column_classifier_css.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_config_store.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_connection_modal.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_csv_adapter.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_data_location.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_database_model.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_datalayer_requests.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_derive_anndata_channel_names.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_detect_data_type.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_file_location.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_file_transfer_node.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_hd_slider_domain.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_icon_names.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_jupyter_viewer.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_label_outlines.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_label_tile_lifecycle.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_marker_split.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_mask_without_table.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_metadata_columns.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_mini_map.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_nav_shortcuts.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_node_direct_routing.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_node_disconnect.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_node_dynamic.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_node_image.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_node_reconnect.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_node_routes.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_node_table.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_notebook_env.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_notebook_mode.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_optional_segmentation.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_page_assets.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_page_routes.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_path_picker.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_paths.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_plugin_boundary.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_plugin_css_boundary.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_plugins.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_popover_portal.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_project_edit_routes.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_project_record.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_quick_view_routes.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_recipes.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_reconnect.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_refresh_dataset.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_register_anndata_datasource.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_register_image_datasource.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_remote_globe.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_remote_health.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_remote_state.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_rename_channels.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_requirements_routes.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_resource_status_banner.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_segmentation_mapping.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_segmentation_mode_routes.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_segmentation_pyramid.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_segmentation_wait.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_session_expiry.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_session_walltime.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_settings_page.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_settings_remotes_page.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_shared_roots.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_spatialdata_adapter.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_tile_url.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_tool_assets.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_tool_cards.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_tool_coexistence.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_tool_switching.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_transfer_routes.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_unreachable_node.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_url_helpers.py +0 -0
- {plexora-0.0.8 → plexora-0.0.10}/tests/test_view_menu.py +0 -0
|
@@ -60,10 +60,9 @@ async function init(config) {
|
|
|
60
60
|
// to "everything is on this server" without a single probe, and the rewrite
|
|
61
61
|
// below is exactly what it has always been. For a project reading from a
|
|
62
62
|
// data node it decides, once per tab, whether this browser can reach that
|
|
63
|
-
// node directly -- see services/resourceRouting.js.
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
const segRoute = PlexoraRouting.tileSource(routing, "segmentation");
|
|
63
|
+
// node directly -- see services/resourceRouting.js. `let`, because a
|
|
64
|
+
// reconnect mid-session replaces it -- see repairRouting below.
|
|
65
|
+
let routing = await PlexoraRouting.load(datasource);
|
|
67
66
|
|
|
68
67
|
// A layer that could not be loaded at all is already absent from `config`
|
|
69
68
|
// by this point, so nothing below would ever mention it. Not awaited: the
|
|
@@ -74,21 +73,49 @@ async function init(config) {
|
|
|
74
73
|
}
|
|
75
74
|
|
|
76
75
|
if (Array.isArray(config.imageData)) {
|
|
77
|
-
config.imageData.forEach(function (channel
|
|
76
|
+
config.imageData.forEach(function (channel) {
|
|
78
77
|
if (channel.src && channel.src.startsWith("/")) {
|
|
79
78
|
channel.src = plexoraUrl(channel.src);
|
|
80
79
|
}
|
|
80
|
+
// The address THIS server serves the layer at, kept apart from the
|
|
81
|
+
// routed rewrite below so routing can be applied again later. A
|
|
82
|
+
// reconnect changes a node's port and token, and re-deriving the
|
|
83
|
+
// direct address from the previous direct address would strand the
|
|
84
|
+
// one case that has to work: a route that has fallen back to the
|
|
85
|
+
// proxy and later becomes direct again.
|
|
86
|
+
channel.origSrc = channel.src;
|
|
87
|
+
});
|
|
88
|
+
applyRouting(routing);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Point every layer's tile address at what `routing` says, from scratch.
|
|
93
|
+
*
|
|
94
|
+
* Idempotent over `origSrc`, so it can run again when the answer changes
|
|
95
|
+
* -- at boot, and on every repair after a node reconnects or goes away.
|
|
96
|
+
*/
|
|
97
|
+
function applyRouting(resolved) {
|
|
98
|
+
const imageRoute = PlexoraRouting.tileSource(resolved, "image");
|
|
99
|
+
const segRoute = PlexoraRouting.tileSource(resolved, "segmentation");
|
|
100
|
+
(config.imageData || []).forEach(function (channel, index) {
|
|
101
|
+
if (!channel.origSrc) return;
|
|
81
102
|
// imageData[0] is the label layer when, and only when, the project
|
|
82
103
|
// has a mask -- the same rule ViewerManager.raiseLabelLayer applies
|
|
83
104
|
// and for the same reason, so the two cannot disagree about which
|
|
84
105
|
// entry is which.
|
|
85
106
|
const isLabel = index === 0 && Boolean(config.segmentation);
|
|
86
107
|
const route = isLabel ? segRoute : imageRoute;
|
|
87
|
-
if (!route)
|
|
108
|
+
if (!route) {
|
|
109
|
+
// This server's own address: the proxy path, which is also the
|
|
110
|
+
// only path for a local layer.
|
|
111
|
+
channel.src = channel.origSrc;
|
|
112
|
+
channel.srcQuery = "";
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
88
115
|
// An image names which channel in the path; a mask has one plane
|
|
89
116
|
// and names nothing. The key is the last segment of the address
|
|
90
|
-
// this
|
|
91
|
-
const key = channel.
|
|
117
|
+
// this server would serve the entry at.
|
|
118
|
+
const key = channel.origSrc.replace(/\/+$/, "").split("/").pop();
|
|
92
119
|
channel.src = route.appendKey ? route.base + key + "/" : route.base;
|
|
93
120
|
// Carried apart from `src` rather than appended to it, because
|
|
94
121
|
// `channel_add` reads the key back out of `src` by position and a
|
|
@@ -163,6 +190,112 @@ async function init(config) {
|
|
|
163
190
|
__plexora.dataset = PlexoraDataset.build(config, imageChannels, dd);
|
|
164
191
|
channelList.init(dd);
|
|
165
192
|
|
|
193
|
+
/**
|
|
194
|
+
* Rebuild every tiled image off the addresses `config` now holds.
|
|
195
|
+
*
|
|
196
|
+
* The same remove-and-re-add the HD toggle uses, and for the same reason
|
|
197
|
+
* (see ViewerManager.setHdMode): invalidating tiles in place leaves stale
|
|
198
|
+
* canvases on screen. `currentChannels` still holds each layer's OLD url,
|
|
199
|
+
* which is exactly what channel_remove matches world items against -- so
|
|
200
|
+
* the order is fixed: applyRouting first, this second.
|
|
201
|
+
*/
|
|
202
|
+
function rebuildTileLayers() {
|
|
203
|
+
const world = seaDragonViewer.viewer && seaDragonViewer.viewer.world;
|
|
204
|
+
if (!world) return;
|
|
205
|
+
Object.keys(channelList.currentChannels).map(Number).forEach((srcIdx) => {
|
|
206
|
+
viewerManager.channel_remove(srcIdx);
|
|
207
|
+
viewerManager.channel_add(srcIdx);
|
|
208
|
+
});
|
|
209
|
+
if (config.segmentation) {
|
|
210
|
+
for (let i = world.getItemCount() - 1; i >= 0; i -= 1) {
|
|
211
|
+
const item = world.getItemAt(i);
|
|
212
|
+
if (item && item.source && item.source.tileFormat === 32) {
|
|
213
|
+
world.removeItem(item);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
// Both guards exist to make lazy loading happen once; this is the
|
|
217
|
+
// one caller that means "again" -- the same resets
|
|
218
|
+
// adoptSegmentation makes when a mask arrives mid-session.
|
|
219
|
+
// `noLabel` is set by the error callback when the label layer
|
|
220
|
+
// failed to load, which during an outage it did.
|
|
221
|
+
seaDragonViewer.noLabel = false;
|
|
222
|
+
viewerManager.labelLayerRequested = false;
|
|
223
|
+
viewerManager.load_label_image();
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Say again what is missing, now that the answer may have changed.
|
|
229
|
+
*
|
|
230
|
+
* One banner at a time: whatever strip is up is about the addresses that
|
|
231
|
+
* were just replaced, and report() draws a fresh one when there is still
|
|
232
|
+
* something to say (and clears its own per-tab memories when there is not).
|
|
233
|
+
*/
|
|
234
|
+
function rereportResources(resolved) {
|
|
235
|
+
if (!window.PlexoraResourceStatus) return;
|
|
236
|
+
document.querySelectorAll(".resource-status-banner")
|
|
237
|
+
.forEach((strip) => strip.remove());
|
|
238
|
+
PlexoraResourceStatus.report(datasource, resolved);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
//: The in-flight repair, shared: a burst of failing tiles and a reconnect
|
|
242
|
+
//: event landing together is one re-resolution, not several racing ones.
|
|
243
|
+
let repairing = null;
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Re-resolve where tiles come from, and take the answer on in place.
|
|
247
|
+
*
|
|
248
|
+
* What a reconnect used to require a page reload for: the node comes back
|
|
249
|
+
* on a new port with a new token, the server's own providers re-resolve on
|
|
250
|
+
* their next call (nodes.address_generation), and this is the browser-side
|
|
251
|
+
* counterpart -- without it every direct tile URL on the page kept the
|
|
252
|
+
* dead address, which made each reconnect look like it had done nothing.
|
|
253
|
+
*/
|
|
254
|
+
function repairRouting() {
|
|
255
|
+
if (!window.PlexoraRouting) return Promise.resolve(null);
|
|
256
|
+
if (repairing) return repairing;
|
|
257
|
+
repairing = (async () => {
|
|
258
|
+
const before = JSON.stringify(routing && routing.routes || {});
|
|
259
|
+
const fresh = await PlexoraRouting.refresh(datasource);
|
|
260
|
+
routing = fresh;
|
|
261
|
+
rereportResources(fresh);
|
|
262
|
+
if (JSON.stringify(fresh.routes || {}) === before) return null;
|
|
263
|
+
applyRouting(fresh);
|
|
264
|
+
rebuildTileLayers();
|
|
265
|
+
return fresh;
|
|
266
|
+
})().finally(() => { repairing = null; });
|
|
267
|
+
return repairing;
|
|
268
|
+
}
|
|
269
|
+
__plexora.repairRouting = repairRouting;
|
|
270
|
+
|
|
271
|
+
// A data node connecting or going away is the moment tile addresses can
|
|
272
|
+
// change. remoteState announces the transition (it is already watching
|
|
273
|
+
// whenever one can happen in this tab); repairing on it is what lets a
|
|
274
|
+
// reconnect heal an open viewer instead of needing a reload nobody was
|
|
275
|
+
// told about.
|
|
276
|
+
window.addEventListener("plexora:remote-nodes-changed", () => {
|
|
277
|
+
repairRouting();
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
//: How often failing tiles may trigger a repair attempt. A dead node fails
|
|
281
|
+
//: tiles for as long as it is dead; asking the server once per window is
|
|
282
|
+
//: what keeps that from becoming a poll.
|
|
283
|
+
const TILE_FAILURE_REPAIR_MS = 30000;
|
|
284
|
+
let lastTileRepair = 0;
|
|
285
|
+
// A burst of failing tiles is how a moved or dead node actually presents
|
|
286
|
+
// mid-session -- nothing else on the page is watching when no dialog is
|
|
287
|
+
// open. Repairing answers both cases: an address that changed is taken on
|
|
288
|
+
// in place, and a node that is gone from the map gets the resource-status
|
|
289
|
+
// report (the modal with the Connect button) instead of silent timeouts.
|
|
290
|
+
if (seaDragonViewer.viewer && seaDragonViewer.viewer.addHandler) {
|
|
291
|
+
seaDragonViewer.viewer.addHandler("tile-load-failed", () => {
|
|
292
|
+
const now = Date.now();
|
|
293
|
+
if (now - lastTileRepair < TILE_FAILURE_REPAIR_MS) return;
|
|
294
|
+
lastTileRepair = now;
|
|
295
|
+
repairRouting();
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
|
|
166
299
|
/**
|
|
167
300
|
* Re-fetch what the server says this project's numbers are.
|
|
168
301
|
*
|
|
@@ -85,7 +85,7 @@ window.PlexoraRemoteGlobe = (function () {
|
|
|
85
85
|
* Collapsing them loses the case that matters -- a session that still
|
|
86
86
|
* reads connected against a node that has stopped answering.
|
|
87
87
|
*/
|
|
88
|
-
function healthOf(entry, health) {
|
|
88
|
+
function healthOf(entry, health, stale) {
|
|
89
89
|
//: The probe first, and the session only as a fallback. A data node
|
|
90
90
|
//: outlives the process that started it, so after a restart there is
|
|
91
91
|
//: no session and the registry still holds the node -- asking the
|
|
@@ -101,6 +101,18 @@ window.PlexoraRemoteGlobe = (function () {
|
|
|
101
101
|
cls: "is-checking", ms: null, detail: "" };
|
|
102
102
|
}
|
|
103
103
|
if (probe.state === "healthy") {
|
|
104
|
+
//: The BROWSER's own version of the server's "stale" below, and it
|
|
105
|
+
//: outlasts it: the server's held address heals itself on its next
|
|
106
|
+
//: proxied call, while the page's direct tile URLs stay wherever
|
|
107
|
+
//: the tiles on screen were fetched from. Checked here, on top of
|
|
108
|
+
//: a healthy probe, because both claims are true at once -- the
|
|
109
|
+
//: machine IS well, and this page is not reading from it.
|
|
110
|
+
if (stale && stale[nodeNameOf(entry)]) {
|
|
111
|
+
return { word: "Reconnected", glyph: "arrows-rotate",
|
|
112
|
+
cls: "is-degraded", ms: null,
|
|
113
|
+
detail: "That machine is answering at a new address; "
|
|
114
|
+
+ "this page is being repointed at it now." };
|
|
115
|
+
}
|
|
104
116
|
return { word: "Healthy", glyph: "circle-check", cls: "is-healthy",
|
|
105
117
|
ms: probe.ms, detail: "" };
|
|
106
118
|
}
|
|
@@ -120,6 +132,33 @@ window.PlexoraRemoteGlobe = (function () {
|
|
|
120
132
|
};
|
|
121
133
|
}
|
|
122
134
|
|
|
135
|
+
/**
|
|
136
|
+
* Which nodes the open page is still addressing at a retired location.
|
|
137
|
+
*
|
|
138
|
+
* Compares what this page's tiles were actually built from
|
|
139
|
+
* (`PlexoraRouting.held`) with what `/resource_routing` answers NOW. Only
|
|
140
|
+
* a direct route can be stale in the browser -- a proxied layer goes
|
|
141
|
+
* through this server, whose providers re-resolve on their own -- and a
|
|
142
|
+
* node that has left the map entirely is not stale, it is gone, which the
|
|
143
|
+
* probe already says in its own words. Empty on every page that never
|
|
144
|
+
* resolved routing, which is every page but the viewer.
|
|
145
|
+
*/
|
|
146
|
+
function staleNodes(datasource, candidates) {
|
|
147
|
+
const held = window.PlexoraRouting && PlexoraRouting.held
|
|
148
|
+
? PlexoraRouting.held(datasource) : null;
|
|
149
|
+
const routes = (held && held.routes) || {};
|
|
150
|
+
const stale = {};
|
|
151
|
+
Object.keys(routes).forEach((kind) => {
|
|
152
|
+
const mine = routes[kind];
|
|
153
|
+
const now = candidates[kind];
|
|
154
|
+
if (!mine || mine.mode !== "direct" || !now) return;
|
|
155
|
+
if (mine.base !== now.tile_base || mine.query !== now.query) {
|
|
156
|
+
stale[mine.node] = true;
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
return stale;
|
|
160
|
+
}
|
|
161
|
+
|
|
123
162
|
//: The one mount there will ever be. This icon lives in the NAVBAR, which
|
|
124
163
|
//: the router does not swap -- only the page below it is replaced -- so
|
|
125
164
|
//: `PlexoraPage.register` runs again on every internal navigation against
|
|
@@ -158,6 +197,10 @@ window.PlexoraRemoteGlobe = (function () {
|
|
|
158
197
|
//: and a different one from "we have not asked".
|
|
159
198
|
let imageNode = null;
|
|
160
199
|
let routingRead = false;
|
|
200
|
+
//: Node names whose registry address no longer matches what this
|
|
201
|
+
//: page's tiles were built from -- see staleNodes. Computed with the
|
|
202
|
+
//: routing read, drawn over a healthy probe as "Reconnected".
|
|
203
|
+
let pageStale = {};
|
|
161
204
|
//: What `/remote_health` last said, by profile name, and which set of
|
|
162
205
|
//: connected machines that answer was about -- so becoming connected
|
|
163
206
|
//: while the panel is open re-asks, and a poll that changed nothing
|
|
@@ -234,6 +277,7 @@ window.PlexoraRemoteGlobe = (function () {
|
|
|
234
277
|
|
|
235
278
|
imageNode = null;
|
|
236
279
|
routingRead = false;
|
|
280
|
+
pageStale = {};
|
|
237
281
|
health = {};
|
|
238
282
|
healthFor = null;
|
|
239
283
|
readRouting();
|
|
@@ -295,6 +339,18 @@ window.PlexoraRemoteGlobe = (function () {
|
|
|
295
339
|
const routes = (payload && payload.routes) || {};
|
|
296
340
|
imageNode = (routes.image && routes.image.node) || null;
|
|
297
341
|
routingRead = true;
|
|
342
|
+
pageStale = staleNodes(datasource, routes);
|
|
343
|
+
if (Object.keys(pageStale).length) {
|
|
344
|
+
// Saying so is this panel's job; fixing it is the
|
|
345
|
+
// viewer's. The same event a watched reconnect fires,
|
|
346
|
+
// so there is one repair path -- this is the backstop
|
|
347
|
+
// for a reconnect made from another tab, which no poll
|
|
348
|
+
// in this one was awake to see.
|
|
349
|
+
window.dispatchEvent(new CustomEvent(
|
|
350
|
+
"plexora:remote-nodes-changed",
|
|
351
|
+
{ detail: { changed: Object.keys(pageStale).map(
|
|
352
|
+
(node) => ({ name: null, node: node, up: true })) } }));
|
|
353
|
+
}
|
|
298
354
|
if (panel) draw(Remotes().snapshot());
|
|
299
355
|
})
|
|
300
356
|
.catch(() => {});
|
|
@@ -430,7 +486,7 @@ window.PlexoraRemoteGlobe = (function () {
|
|
|
430
486
|
item.append(top);
|
|
431
487
|
|
|
432
488
|
const bottom = el("div", "remote-conn-bottom");
|
|
433
|
-
const state = healthOf(entry, health);
|
|
489
|
+
const state = healthOf(entry, health, pageStale);
|
|
434
490
|
const well = el("span", "remote-conn-health " + state.cls);
|
|
435
491
|
well.append(icon(state.glyph));
|
|
436
492
|
well.append(el("span", null, state.word));
|
|
@@ -299,7 +299,52 @@ window.PlexoraRemotes = (function () {
|
|
|
299
299
|
timer = window.setTimeout(() => { refresh(); }, POLL_MS);
|
|
300
300
|
}
|
|
301
301
|
|
|
302
|
+
/**
|
|
303
|
+
* Which profiles' data nodes changed condition between two snapshots.
|
|
304
|
+
*
|
|
305
|
+
* The one thing a snapshot difference can say that no subscriber can:
|
|
306
|
+
* a node session coming up or going away changes which ADDRESS the open
|
|
307
|
+
* project's tiles should be fetched from, and the page holding those tile
|
|
308
|
+
* URLs (main.js) is not a subscriber -- it resolved routing once at boot.
|
|
309
|
+
* The event is what lets it repair itself instead of failing against a
|
|
310
|
+
* port that has gone until somebody thinks to reload.
|
|
311
|
+
*
|
|
312
|
+
* Only real transitions: a profile present in both snapshots whose node
|
|
313
|
+
* half changed being-up, map name, or registry name. The first snapshot
|
|
314
|
+
* has nothing to differ from, and a failed poll republishes the same
|
|
315
|
+
* entries object, so neither fires anything.
|
|
316
|
+
*/
|
|
317
|
+
function nodeChanges(previous, next) {
|
|
318
|
+
if (!previous.loaded || !next.loaded) return [];
|
|
319
|
+
if (previous.entries === next.entries) return [];
|
|
320
|
+
const before = new Map();
|
|
321
|
+
(previous.entries || []).forEach((entry) => {
|
|
322
|
+
before.set(entry.name, entry.node);
|
|
323
|
+
});
|
|
324
|
+
const changed = [];
|
|
325
|
+
(next.entries || []).forEach((entry) => {
|
|
326
|
+
const was = before.get(entry.name);
|
|
327
|
+
if (!was) return;
|
|
328
|
+
const wasUp = was.state === "connected" || Boolean(was.node);
|
|
329
|
+
const isUp = entry.node.state === "connected"
|
|
330
|
+
|| Boolean(entry.node.node);
|
|
331
|
+
if (wasUp !== isUp
|
|
332
|
+
|| (was.node || null) !== (entry.node.node || null)
|
|
333
|
+
|| (was.registered || null)
|
|
334
|
+
!== (entry.node.registered || null)) {
|
|
335
|
+
changed.push({
|
|
336
|
+
name: entry.name,
|
|
337
|
+
node: entry.node.node || entry.node.registered
|
|
338
|
+
|| was.node || was.registered || null,
|
|
339
|
+
up: isUp,
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
return changed;
|
|
344
|
+
}
|
|
345
|
+
|
|
302
346
|
function publish(next) {
|
|
347
|
+
const changed = nodeChanges(current, next);
|
|
303
348
|
current = next;
|
|
304
349
|
subscribers.forEach((sub) => {
|
|
305
350
|
try {
|
|
@@ -311,6 +356,10 @@ window.PlexoraRemotes = (function () {
|
|
|
311
356
|
if (window.console) console.error("remote state subscriber", e);
|
|
312
357
|
}
|
|
313
358
|
});
|
|
359
|
+
if (changed.length) {
|
|
360
|
+
window.dispatchEvent(new CustomEvent("plexora:remote-nodes-changed",
|
|
361
|
+
{ detail: { changed } }));
|
|
362
|
+
}
|
|
314
363
|
}
|
|
315
364
|
|
|
316
365
|
/**
|
|
@@ -48,6 +48,14 @@ window.PlexoraRouting = (function () {
|
|
|
48
48
|
//: wait on the same probe rather than starting their own.
|
|
49
49
|
const pending = new Map();
|
|
50
50
|
|
|
51
|
+
//: datasource -> the last fully-resolved table this page handed out: what
|
|
52
|
+
//: the page is ACTUALLY using, kept for anything that compares it against
|
|
53
|
+
//: the registry's current answer (the globe's stale check). Overwritten
|
|
54
|
+
//: when a re-resolution lands, never cleared by `forget` -- while a fresh
|
|
55
|
+
//: probe is in flight the old table is still the truthful account of what
|
|
56
|
+
//: the tiles on screen were built from.
|
|
57
|
+
const settled = new Map();
|
|
58
|
+
|
|
51
59
|
//: The answer for a project with nothing on a node. Frozen and shared:
|
|
52
60
|
//: every lookup against it returns "local", which is what every call site
|
|
53
61
|
//: already assumed.
|
|
@@ -119,7 +127,11 @@ window.PlexoraRouting = (function () {
|
|
|
119
127
|
+ "?datasource=" + encodeURIComponent(datasource))
|
|
120
128
|
.then((response) => (response.ok ? response.json() : { routes: {} }))
|
|
121
129
|
.then((body) => decide(datasource, body.routes || {}))
|
|
122
|
-
.catch(() => NOTHING_REMOTE)
|
|
130
|
+
.catch(() => NOTHING_REMOTE)
|
|
131
|
+
.then((resolved) => {
|
|
132
|
+
settled.set(datasource, resolved);
|
|
133
|
+
return resolved;
|
|
134
|
+
});
|
|
123
135
|
|
|
124
136
|
pending.set(datasource, promise);
|
|
125
137
|
return promise;
|
|
@@ -142,8 +154,14 @@ window.PlexoraRouting = (function () {
|
|
|
142
154
|
});
|
|
143
155
|
|
|
144
156
|
const asked = Array.from(byNode.entries()).map(([node, route]) => {
|
|
145
|
-
|
|
146
|
-
|
|
157
|
+
// Only a remembered YES is reused. A remembered "unreachable" was
|
|
158
|
+
// true of a moment -- a node mid-restart, a tunnel not yet up --
|
|
159
|
+
// and reusing it pinned the whole tab to the proxy hop for as long
|
|
160
|
+
// as it stayed open, silently, after the node came back. Probing
|
|
161
|
+
// again costs this one load at most PROBE_TIMEOUT_MS; being wrong
|
|
162
|
+
// the other way cost every tile an extra hop for the afternoon.
|
|
163
|
+
if (known[node] === true) {
|
|
164
|
+
verdicts[node] = true;
|
|
147
165
|
return Promise.resolve();
|
|
148
166
|
}
|
|
149
167
|
return probe(route).then((reachable) => { verdicts[node] = reachable; });
|
|
@@ -202,5 +220,30 @@ window.PlexoraRouting = (function () {
|
|
|
202
220
|
pending.delete(datasource);
|
|
203
221
|
}
|
|
204
222
|
|
|
205
|
-
|
|
223
|
+
/**
|
|
224
|
+
* The routing table this page is currently using, or null.
|
|
225
|
+
*
|
|
226
|
+
* Synchronous and never resolving anything: it answers "what were the
|
|
227
|
+
* tiles on screen built from", which is a fact about the past. The globe
|
|
228
|
+
* compares it against `/resource_routing`'s current answer to tell whether
|
|
229
|
+
* the open project is still addressed to where a node was before it was
|
|
230
|
+
* reconnected.
|
|
231
|
+
*/
|
|
232
|
+
function held(datasource) {
|
|
233
|
+
return settled.get(datasource) || null;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Ask again from scratch: drop the memoised table AND the remembered
|
|
238
|
+
* verdicts, then resolve anew. What a reconnect calls -- the node came
|
|
239
|
+
* back on a new port with a new token, so both halves of what this tab
|
|
240
|
+
* remembers are about an address that has gone.
|
|
241
|
+
*/
|
|
242
|
+
function refresh(datasource) {
|
|
243
|
+
forget(datasource);
|
|
244
|
+
return load(datasource);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return { load, tileSource, unreachable, forget, held, refresh,
|
|
248
|
+
PROBE_TIMEOUT_MS };
|
|
206
249
|
})();
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
awaits it before it builds a single tile source, and every page that
|
|
35
35
|
can open a viewer loads it. Costs one request that answers "{}" for a
|
|
36
36
|
project with nothing on a node. -->
|
|
37
|
-
<script src="{{ data.base_url }}/client/src/js/services/resourceRouting.js?v=
|
|
37
|
+
<script src="{{ data.base_url }}/client/src/js/services/resourceRouting.js?v=20260830_reconnect_repair" type="text/javascript"></script>
|
|
38
38
|
<!-- Why a layer is missing, when one is. Asks /resource_status once per
|
|
39
39
|
project load and says nothing at all for a project with everything on
|
|
40
40
|
this machine, which is every ordinary one. -->
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
the one poll that four surfaces used to run three of. It costs nothing
|
|
88
88
|
on a page that never subscribes -- there is no timer until somebody
|
|
89
89
|
does. #}
|
|
90
|
-
<script src="{{ data.base_url }}/client/src/js/services/remoteState.js?v=
|
|
90
|
+
<script src="{{ data.base_url }}/client/src/js/services/remoteState.js?v=20260830_reconnect_repair" defer></script>
|
|
91
91
|
{# The connection log, shared by the modal and the Settings page's cards.
|
|
92
92
|
Before both of them: they call into it as they build. #}
|
|
93
93
|
<script src="{{ data.base_url }}/client/src/js/services/logTerminal.js?v=20260829_terminal" defer></script>
|
|
@@ -97,7 +97,7 @@
|
|
|
97
97
|
it after pageBoot.js below (a normal script beats every deferred one),
|
|
98
98
|
so PlexoraPage.register exists by the time this file's last line runs.
|
|
99
99
|
It needs popoverPortal.js, loaded above with the other widgets. #}
|
|
100
|
-
<script src="{{ data.base_url }}/client/src/js/services/remoteGlobe.js?v=
|
|
100
|
+
<script src="{{ data.base_url }}/client/src/js/services/remoteGlobe.js?v=20260830_reconnect_repair" defer></script>
|
|
101
101
|
{# Says so before a scheduled job ends, from whichever page the user is on.
|
|
102
102
|
After connectionModal.js, which its one button opens; passive, so it
|
|
103
103
|
costs nothing while a connection sits settled. #}
|
|
@@ -244,7 +244,7 @@
|
|
|
244
244
|
by the time the user clicks the sidebar's upload icon, so deferred is ample.
|
|
245
245
|
#}
|
|
246
246
|
<script src="{{ data.base_url }}/client/src/js/views/channelNamesUpload.js?v=20260829_channel_names_switch" defer></script>
|
|
247
|
-
<script src="{{ data.base_url }}/client/src/js/main.js?v=
|
|
247
|
+
<script src="{{ data.base_url }}/client/src/js/main.js?v=20260830_reconnect_repair" defer></script>
|
|
248
248
|
{% else %}
|
|
249
249
|
<div id="quick_view_landing" class="quick-view-landing">
|
|
250
250
|
<div class="quick-view-card">
|