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.
Files changed (406) hide show
  1. {plexora-0.0.8/plexora.egg-info → plexora-0.0.10}/PKG-INFO +1 -1
  2. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/main.js +141 -8
  3. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/remoteGlobe.js +58 -2
  4. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/remoteState.js +49 -0
  5. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/resourceRouting.js +47 -4
  6. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/templates/base.html +3 -3
  7. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/templates/index.html +1 -1
  8. {plexora-0.0.8 → plexora-0.0.10}/plexora/connect.py +146 -129
  9. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/models/remote_sessions.py +65 -7
  10. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/node/app.py +18 -1
  11. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/routes/settings_routes.py +24 -3
  12. {plexora-0.0.8 → plexora-0.0.10/plexora.egg-info}/PKG-INFO +1 -1
  13. {plexora-0.0.8 → plexora-0.0.10}/pyproject.toml +1 -1
  14. {plexora-0.0.8 → plexora-0.0.10}/tests/test_connect.py +68 -50
  15. {plexora-0.0.8 → plexora-0.0.10}/tests/test_node_warm_and_cache.py +28 -10
  16. {plexora-0.0.8 → plexora-0.0.10}/tests/test_remote_connect.py +165 -6
  17. {plexora-0.0.8 → plexora-0.0.10}/LICENSE +0 -0
  18. {plexora-0.0.8 → plexora-0.0.10}/MANIFEST.in +0 -0
  19. {plexora-0.0.8 → plexora-0.0.10}/README.md +0 -0
  20. {plexora-0.0.8 → plexora-0.0.10}/plexora/__init__.py +0 -0
  21. {plexora-0.0.8 → plexora-0.0.10}/plexora/__main__.py +0 -0
  22. {plexora-0.0.8 → plexora-0.0.10}/plexora/_resources.py +0 -0
  23. {plexora-0.0.8 → plexora-0.0.10}/plexora/_url.py +0 -0
  24. {plexora-0.0.8 → plexora-0.0.10}/plexora/api/__init__.py +0 -0
  25. {plexora-0.0.8 → plexora-0.0.10}/plexora/api/dataset.py +0 -0
  26. {plexora-0.0.8 → plexora-0.0.10}/plexora/api/http.py +0 -0
  27. {plexora-0.0.8 → plexora-0.0.10}/plexora/api/plugin.py +0 -0
  28. {plexora-0.0.8 → plexora-0.0.10}/plexora/api/store.py +0 -0
  29. {plexora-0.0.8 → plexora-0.0.10}/plexora/askpass.py +0 -0
  30. {plexora-0.0.8 → plexora-0.0.10}/plexora/cli.py +0 -0
  31. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/dist/354_bundle.js +0 -0
  32. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/dist/354_bundle.js.LICENSE.txt +0 -0
  33. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/dist/418_bundle.js +0 -0
  34. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/dist/418_bundle.js.LICENSE.txt +0 -0
  35. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/dist/693b935cb1f907814be9c6199a68c217.svg +0 -0
  36. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/dist/713c134ff47cd328a5b711526f151082.svg +0 -0
  37. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/dist/770_bundle.js +0 -0
  38. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/dist/ff743f408972e0e96ca9153ed5ae4c83.svg +0 -0
  39. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/dist/vendor_bundle.js +0 -0
  40. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/dist/vendor_bundle.js.LICENSE.txt +0 -0
  41. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/LICENSE.txt +0 -0
  42. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/canvas-overlay-hd.js +0 -0
  43. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/changelog.txt +0 -0
  44. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/.gitattributes +0 -0
  45. {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
  46. {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
  47. {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
  48. {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
  49. {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
  50. {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
  51. {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
  52. {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
  53. {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
  54. {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
  55. {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
  56. {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
  57. {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
  58. {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
  59. {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
  60. {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
  61. {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
  62. {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
  63. {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
  64. {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
  65. {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
  66. {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
  67. {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
  68. {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
  69. {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
  70. {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
  71. {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
  72. {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
  73. {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
  74. {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
  75. {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
  76. {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
  77. {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
  78. {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
  79. {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
  80. {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
  81. {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
  82. {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
  83. {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
  84. {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
  85. {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
  86. {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
  87. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/external/openseadragon-bin-2.4.0/openseadragon-scalebar.js +0 -0
  88. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/css/import.css +0 -0
  89. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/css/main.css +0 -0
  90. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/css/openProject.css +0 -0
  91. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/css/quickView.css +0 -0
  92. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/css/settings.css +0 -0
  93. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/css/tokens.css +0 -0
  94. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/css/viewer.css +0 -0
  95. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/img/apple-touch-icon.png +0 -0
  96. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/img/favicon.ico +0 -0
  97. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/img/logo.ai +0 -0
  98. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/img/logo.svg +0 -0
  99. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/img/logo_with_text.ai +0 -0
  100. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/img/logo_with_text.svg +0 -0
  101. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/pluginRegistry.js +0 -0
  102. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/appRouter.js +0 -0
  103. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/appStatus.js +0 -0
  104. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/browsePicker.js +0 -0
  105. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/connectionModal.js +0 -0
  106. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/dataLayer.js +0 -0
  107. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/dataLocation.js +0 -0
  108. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/datasetContext.js +0 -0
  109. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/fileLocation.js +0 -0
  110. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/glRenderer.js +0 -0
  111. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/importFormValidation.js +0 -0
  112. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/keyboardShortcuts.js +0 -0
  113. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/logTerminal.js +0 -0
  114. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/numericData.js +0 -0
  115. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/pageBoot.js +0 -0
  116. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/passVariablesToFrontend.js +0 -0
  117. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/pathPicker.js +0 -0
  118. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/placePicker.js +0 -0
  119. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/resourceStatus.js +0 -0
  120. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/sessionExpiry.js +0 -0
  121. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/services/simpleEventHandler.js +0 -0
  122. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/vendor.js +0 -0
  123. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/channelList.js +0 -0
  124. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/channelNamesUpload.js +0 -0
  125. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/colorSwatchPicker.js +0 -0
  126. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/columnClassifier.js +0 -0
  127. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/coordinateField.js +0 -0
  128. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/dataSourceField.js +0 -0
  129. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/imageViewer.js +0 -0
  130. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/miniMap.js +0 -0
  131. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/navbarControls.js +0 -0
  132. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/openProjectPage.js +0 -0
  133. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/popoverPortal.js +0 -0
  134. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/projectEdit.js +0 -0
  135. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/quickViewLanding.js +0 -0
  136. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/rainbow.js +0 -0
  137. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/requirementsModal.js +0 -0
  138. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/rgbImageViewer.js +0 -0
  139. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/searchableSelect.js +0 -0
  140. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/segmentationProgress.js +0 -0
  141. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/segmentationWait.js +0 -0
  142. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/settingsPage.js +0 -0
  143. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/toolLoader.js +0 -0
  144. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/viewerControls.js +0 -0
  145. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/viewerManager.js +0 -0
  146. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/views/viewerSidebar.js +0 -0
  147. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/js/workers/tileDecoder.js +0 -0
  148. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/shaders/frag.glsl +0 -0
  149. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/src/shaders/vert.glsl +0 -0
  150. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/templates/_fragment.html +0 -0
  151. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/templates/open_project.html +0 -0
  152. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/templates/project_columns.html +0 -0
  153. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/templates/project_edit.html +0 -0
  154. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/templates/settings.html +0 -0
  155. {plexora-0.0.8 → plexora-0.0.10}/plexora/client/templates/upload.html +0 -0
  156. {plexora-0.0.8 → plexora-0.0.10}/plexora/datasource.py +0 -0
  157. {plexora-0.0.8 → plexora-0.0.10}/plexora/jupyter.py +0 -0
  158. {plexora-0.0.8 → plexora-0.0.10}/plexora/nodes.py +0 -0
  159. {plexora-0.0.8 → plexora-0.0.10}/plexora/notebook_env.py +0 -0
  160. {plexora-0.0.8 → plexora-0.0.10}/plexora/paths.py +0 -0
  161. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/__init__.py +0 -0
  162. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/cell_explorer/__init__.py +0 -0
  163. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/cell_explorer/server/__init__.py +0 -0
  164. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/cell_explorer/server/routes.py +0 -0
  165. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/cell_explorer/server/state.py +0 -0
  166. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/cell_explorer/server/values.py +0 -0
  167. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/cell_explorer/server/variables.py +0 -0
  168. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/cell_explorer/static/cellExplorerApi.js +0 -0
  169. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/cell_explorer/static/cellExplorerColors.js +0 -0
  170. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/cell_explorer/static/cellExplorerContinuous.js +0 -0
  171. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/cell_explorer/static/cellExplorerFigureBridge.js +0 -0
  172. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/cell_explorer/static/cellExplorerLegend.js +0 -0
  173. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/cell_explorer/static/cellExplorerRoiBridge.js +0 -0
  174. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/cell_explorer/static/cellExplorerSidebarController.js +0 -0
  175. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/cell_explorer/static/cellExplorerState.js +0 -0
  176. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/cell_explorer/static/cell_explorer.css +0 -0
  177. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/cell_explorer/templates/cell_explorer/panel.html +0 -0
  178. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/__init__.py +0 -0
  179. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/server/__init__.py +0 -0
  180. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/server/compose.py +0 -0
  181. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/server/export.py +0 -0
  182. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/server/export_jobs.py +0 -0
  183. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/server/operations.py +0 -0
  184. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/server/pixels.py +0 -0
  185. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/server/provenance.py +0 -0
  186. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/server/render.py +0 -0
  187. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/server/repository.py +0 -0
  188. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/server/routes.py +0 -0
  189. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/server/schema.py +0 -0
  190. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/server/shapegeom.py +0 -0
  191. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/server/sources.py +0 -0
  192. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/server/strokegeom.py +0 -0
  193. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/server/textmetrics.py +0 -0
  194. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureActions.js +0 -0
  195. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureBuilderApi.js +0 -0
  196. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureCanvas.js +0 -0
  197. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureCaptureBoxes.js +0 -0
  198. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureCaptureDock.js +0 -0
  199. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureCaptureTool.js +0 -0
  200. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureChoiceField.js +0 -0
  201. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureColorField.js +0 -0
  202. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureConfirm.js +0 -0
  203. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureContextBar.js +0 -0
  204. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureContextMenu.js +0 -0
  205. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureDocumentState.js +0 -0
  206. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureExportUi.js +0 -0
  207. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureImagePanel.js +0 -0
  208. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureLibrary.js +0 -0
  209. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureLineDefs.js +0 -0
  210. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureLinePanel.js +0 -0
  211. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figurePanelCompositor.js +0 -0
  212. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figurePointEditor.js +0 -0
  213. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureQuickEdit.js +0 -0
  214. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureRichText.js +0 -0
  215. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureSceneSnapshot.js +0 -0
  216. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureSchema.js +0 -0
  217. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureShapeDefs.js +0 -0
  218. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureShapeDrawing.js +0 -0
  219. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureShapeGeometry.js +0 -0
  220. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureShapePanel.js +0 -0
  221. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureSidebarController.js +0 -0
  222. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureStrokeGeometry.js +0 -0
  223. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureTextEditor.js +0 -0
  224. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureTextPanel.js +0 -0
  225. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureViewOptions.js +0 -0
  226. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figureWorkspace.js +0 -0
  227. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/static/figure_builder.css +0 -0
  228. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/templates/figure_builder/library.html +0 -0
  229. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/templates/figure_builder/workspace.html +0 -0
  230. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/figure_builder/templates/figure_builder/workspace_body.html +0 -0
  231. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/gating/__init__.py +0 -0
  232. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/gating/server/__init__.py +0 -0
  233. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/gating/server/anndata_gates.py +0 -0
  234. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/gating/server/database.py +0 -0
  235. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/gating/server/model.py +0 -0
  236. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/gating/server/routes.py +0 -0
  237. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/gating/server/tableops.py +0 -0
  238. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/gating/static/csvGatingList.js +0 -0
  239. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/gating/static/gating.css +0 -0
  240. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/gating/static/gatingApi.js +0 -0
  241. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/gating/static/gatingSidebarController.js +0 -0
  242. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/gating/templates/gating/legacy.html +0 -0
  243. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/gating/templates/gating/panel.html +0 -0
  244. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/roi/__init__.py +0 -0
  245. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/roi/server/__init__.py +0 -0
  246. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/roi/server/adapters.py +0 -0
  247. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/roi/server/geojson.py +0 -0
  248. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/roi/server/geometry.py +0 -0
  249. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/roi/server/mapping.py +0 -0
  250. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/roi/server/operations.py +0 -0
  251. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/roi/server/repository.py +0 -0
  252. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/roi/server/routes.py +0 -0
  253. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/roi/server/schema.py +0 -0
  254. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/roi/server/tableops.py +0 -0
  255. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/roi/static/roi.css +0 -0
  256. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/roi/static/roiApi.js +0 -0
  257. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/roi/static/roiFigureBridge.js +0 -0
  258. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/roi/static/roiGeometry.js +0 -0
  259. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/roi/static/roiRenderer.js +0 -0
  260. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/roi/static/roiSidebarController.js +0 -0
  261. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/roi/static/roiState.js +0 -0
  262. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/roi/static/roiTools.js +0 -0
  263. {plexora-0.0.8 → plexora-0.0.10}/plexora/plugins/roi/templates/roi/panel.html +0 -0
  264. {plexora-0.0.8 → plexora-0.0.10}/plexora/proxy.py +0 -0
  265. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/models/adapters/__init__.py +0 -0
  266. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/models/adapters/anndata_adapter.py +0 -0
  267. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/models/adapters/base.py +0 -0
  268. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/models/adapters/classify.py +0 -0
  269. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/models/adapters/csv_adapter.py +0 -0
  270. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/models/adapters/inspection.py +0 -0
  271. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/models/adapters/spatialdata_adapter.py +0 -0
  272. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/models/centroid_tiles.py +0 -0
  273. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/models/data_migration.py +0 -0
  274. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/models/data_model.py +0 -0
  275. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/models/database_model.py +0 -0
  276. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/models/nodes.py +0 -0
  277. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/models/project.py +0 -0
  278. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/models/recipes.py +0 -0
  279. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/models/remotes.py +0 -0
  280. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/models/secret_store.py +0 -0
  281. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/node/api.py +0 -0
  282. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/node/resources.py +0 -0
  283. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/plugins.py +0 -0
  284. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/providers/__init__.py +0 -0
  285. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/providers/base.py +0 -0
  286. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/providers/http.py +0 -0
  287. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/providers/local.py +0 -0
  288. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/providers/node.py +0 -0
  289. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/providers/operations.py +0 -0
  290. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/providers/wire.py +0 -0
  291. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/routes/browse_routes.py +0 -0
  292. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/routes/data_routes.py +0 -0
  293. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/routes/import_routes.py +0 -0
  294. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/routes/page_routes.py +0 -0
  295. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/routes/project_routes.py +0 -0
  296. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/routes/quick_view_routes.py +0 -0
  297. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/routes/system_routes.py +0 -0
  298. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/routes/tool_routes.py +0 -0
  299. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/routes/transfer_routes.py +0 -0
  300. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/utils/addHEColumns.py +0 -0
  301. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/utils/channel_file.py +0 -0
  302. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/utils/dir_listing.py +0 -0
  303. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/utils/fast_png.py +0 -0
  304. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/utils/file_transfer.py +0 -0
  305. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/utils/fullConversion.py +0 -0
  306. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/utils/native_dialog.py +0 -0
  307. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/utils/pre_normalization.py +0 -0
  308. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/utils/segmentation_pyramid.py +0 -0
  309. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/utils/smallestenclosingcircle.py +0 -0
  310. {plexora-0.0.8 → plexora-0.0.10}/plexora/server/utils/tiffsurgeon.py +0 -0
  311. {plexora-0.0.8 → plexora-0.0.10}/plexora/server_cli.py +0 -0
  312. {plexora-0.0.8 → plexora-0.0.10}/plexora/test.py +0 -0
  313. {plexora-0.0.8 → plexora-0.0.10}/plexora.egg-info/SOURCES.txt +0 -0
  314. {plexora-0.0.8 → plexora-0.0.10}/plexora.egg-info/dependency_links.txt +0 -0
  315. {plexora-0.0.8 → plexora-0.0.10}/plexora.egg-info/entry_points.txt +0 -0
  316. {plexora-0.0.8 → plexora-0.0.10}/plexora.egg-info/requires.txt +0 -0
  317. {plexora-0.0.8 → plexora-0.0.10}/plexora.egg-info/top_level.txt +0 -0
  318. {plexora-0.0.8 → plexora-0.0.10}/setup.cfg +0 -0
  319. {plexora-0.0.8 → plexora-0.0.10}/tests/test_anndata_adapter.py +0 -0
  320. {plexora-0.0.8 → plexora-0.0.10}/tests/test_api_dataset.py +0 -0
  321. {plexora-0.0.8 → plexora-0.0.10}/tests/test_api_store.py +0 -0
  322. {plexora-0.0.8 → plexora-0.0.10}/tests/test_app_router.py +0 -0
  323. {plexora-0.0.8 → plexora-0.0.10}/tests/test_app_shell.py +0 -0
  324. {plexora-0.0.8 → plexora-0.0.10}/tests/test_auth_token.py +0 -0
  325. {plexora-0.0.8 → plexora-0.0.10}/tests/test_browse_routes.py +0 -0
  326. {plexora-0.0.8 → plexora-0.0.10}/tests/test_cell_color_layer.py +0 -0
  327. {plexora-0.0.8 → plexora-0.0.10}/tests/test_cell_mode_control.py +0 -0
  328. {plexora-0.0.8 → plexora-0.0.10}/tests/test_centroid_tiles.py +0 -0
  329. {plexora-0.0.8 → plexora-0.0.10}/tests/test_channel_names_modal.py +0 -0
  330. {plexora-0.0.8 → plexora-0.0.10}/tests/test_channel_names_upload.py +0 -0
  331. {plexora-0.0.8 → plexora-0.0.10}/tests/test_channel_overview.py +0 -0
  332. {plexora-0.0.8 → plexora-0.0.10}/tests/test_channel_rename_state.py +0 -0
  333. {plexora-0.0.8 → plexora-0.0.10}/tests/test_classify_columns.py +0 -0
  334. {plexora-0.0.8 → plexora-0.0.10}/tests/test_cli.py +0 -0
  335. {plexora-0.0.8 → plexora-0.0.10}/tests/test_column_classifier_css.py +0 -0
  336. {plexora-0.0.8 → plexora-0.0.10}/tests/test_config_store.py +0 -0
  337. {plexora-0.0.8 → plexora-0.0.10}/tests/test_connection_modal.py +0 -0
  338. {plexora-0.0.8 → plexora-0.0.10}/tests/test_csv_adapter.py +0 -0
  339. {plexora-0.0.8 → plexora-0.0.10}/tests/test_data_location.py +0 -0
  340. {plexora-0.0.8 → plexora-0.0.10}/tests/test_database_model.py +0 -0
  341. {plexora-0.0.8 → plexora-0.0.10}/tests/test_datalayer_requests.py +0 -0
  342. {plexora-0.0.8 → plexora-0.0.10}/tests/test_derive_anndata_channel_names.py +0 -0
  343. {plexora-0.0.8 → plexora-0.0.10}/tests/test_detect_data_type.py +0 -0
  344. {plexora-0.0.8 → plexora-0.0.10}/tests/test_file_location.py +0 -0
  345. {plexora-0.0.8 → plexora-0.0.10}/tests/test_file_transfer_node.py +0 -0
  346. {plexora-0.0.8 → plexora-0.0.10}/tests/test_hd_slider_domain.py +0 -0
  347. {plexora-0.0.8 → plexora-0.0.10}/tests/test_icon_names.py +0 -0
  348. {plexora-0.0.8 → plexora-0.0.10}/tests/test_jupyter_viewer.py +0 -0
  349. {plexora-0.0.8 → plexora-0.0.10}/tests/test_label_outlines.py +0 -0
  350. {plexora-0.0.8 → plexora-0.0.10}/tests/test_label_tile_lifecycle.py +0 -0
  351. {plexora-0.0.8 → plexora-0.0.10}/tests/test_marker_split.py +0 -0
  352. {plexora-0.0.8 → plexora-0.0.10}/tests/test_mask_without_table.py +0 -0
  353. {plexora-0.0.8 → plexora-0.0.10}/tests/test_metadata_columns.py +0 -0
  354. {plexora-0.0.8 → plexora-0.0.10}/tests/test_mini_map.py +0 -0
  355. {plexora-0.0.8 → plexora-0.0.10}/tests/test_nav_shortcuts.py +0 -0
  356. {plexora-0.0.8 → plexora-0.0.10}/tests/test_node_direct_routing.py +0 -0
  357. {plexora-0.0.8 → plexora-0.0.10}/tests/test_node_disconnect.py +0 -0
  358. {plexora-0.0.8 → plexora-0.0.10}/tests/test_node_dynamic.py +0 -0
  359. {plexora-0.0.8 → plexora-0.0.10}/tests/test_node_image.py +0 -0
  360. {plexora-0.0.8 → plexora-0.0.10}/tests/test_node_reconnect.py +0 -0
  361. {plexora-0.0.8 → plexora-0.0.10}/tests/test_node_routes.py +0 -0
  362. {plexora-0.0.8 → plexora-0.0.10}/tests/test_node_table.py +0 -0
  363. {plexora-0.0.8 → plexora-0.0.10}/tests/test_notebook_env.py +0 -0
  364. {plexora-0.0.8 → plexora-0.0.10}/tests/test_notebook_mode.py +0 -0
  365. {plexora-0.0.8 → plexora-0.0.10}/tests/test_optional_segmentation.py +0 -0
  366. {plexora-0.0.8 → plexora-0.0.10}/tests/test_page_assets.py +0 -0
  367. {plexora-0.0.8 → plexora-0.0.10}/tests/test_page_routes.py +0 -0
  368. {plexora-0.0.8 → plexora-0.0.10}/tests/test_path_picker.py +0 -0
  369. {plexora-0.0.8 → plexora-0.0.10}/tests/test_paths.py +0 -0
  370. {plexora-0.0.8 → plexora-0.0.10}/tests/test_plugin_boundary.py +0 -0
  371. {plexora-0.0.8 → plexora-0.0.10}/tests/test_plugin_css_boundary.py +0 -0
  372. {plexora-0.0.8 → plexora-0.0.10}/tests/test_plugins.py +0 -0
  373. {plexora-0.0.8 → plexora-0.0.10}/tests/test_popover_portal.py +0 -0
  374. {plexora-0.0.8 → plexora-0.0.10}/tests/test_project_edit_routes.py +0 -0
  375. {plexora-0.0.8 → plexora-0.0.10}/tests/test_project_record.py +0 -0
  376. {plexora-0.0.8 → plexora-0.0.10}/tests/test_quick_view_routes.py +0 -0
  377. {plexora-0.0.8 → plexora-0.0.10}/tests/test_recipes.py +0 -0
  378. {plexora-0.0.8 → plexora-0.0.10}/tests/test_reconnect.py +0 -0
  379. {plexora-0.0.8 → plexora-0.0.10}/tests/test_refresh_dataset.py +0 -0
  380. {plexora-0.0.8 → plexora-0.0.10}/tests/test_register_anndata_datasource.py +0 -0
  381. {plexora-0.0.8 → plexora-0.0.10}/tests/test_register_image_datasource.py +0 -0
  382. {plexora-0.0.8 → plexora-0.0.10}/tests/test_remote_globe.py +0 -0
  383. {plexora-0.0.8 → plexora-0.0.10}/tests/test_remote_health.py +0 -0
  384. {plexora-0.0.8 → plexora-0.0.10}/tests/test_remote_state.py +0 -0
  385. {plexora-0.0.8 → plexora-0.0.10}/tests/test_rename_channels.py +0 -0
  386. {plexora-0.0.8 → plexora-0.0.10}/tests/test_requirements_routes.py +0 -0
  387. {plexora-0.0.8 → plexora-0.0.10}/tests/test_resource_status_banner.py +0 -0
  388. {plexora-0.0.8 → plexora-0.0.10}/tests/test_segmentation_mapping.py +0 -0
  389. {plexora-0.0.8 → plexora-0.0.10}/tests/test_segmentation_mode_routes.py +0 -0
  390. {plexora-0.0.8 → plexora-0.0.10}/tests/test_segmentation_pyramid.py +0 -0
  391. {plexora-0.0.8 → plexora-0.0.10}/tests/test_segmentation_wait.py +0 -0
  392. {plexora-0.0.8 → plexora-0.0.10}/tests/test_session_expiry.py +0 -0
  393. {plexora-0.0.8 → plexora-0.0.10}/tests/test_session_walltime.py +0 -0
  394. {plexora-0.0.8 → plexora-0.0.10}/tests/test_settings_page.py +0 -0
  395. {plexora-0.0.8 → plexora-0.0.10}/tests/test_settings_remotes_page.py +0 -0
  396. {plexora-0.0.8 → plexora-0.0.10}/tests/test_shared_roots.py +0 -0
  397. {plexora-0.0.8 → plexora-0.0.10}/tests/test_spatialdata_adapter.py +0 -0
  398. {plexora-0.0.8 → plexora-0.0.10}/tests/test_tile_url.py +0 -0
  399. {plexora-0.0.8 → plexora-0.0.10}/tests/test_tool_assets.py +0 -0
  400. {plexora-0.0.8 → plexora-0.0.10}/tests/test_tool_cards.py +0 -0
  401. {plexora-0.0.8 → plexora-0.0.10}/tests/test_tool_coexistence.py +0 -0
  402. {plexora-0.0.8 → plexora-0.0.10}/tests/test_tool_switching.py +0 -0
  403. {plexora-0.0.8 → plexora-0.0.10}/tests/test_transfer_routes.py +0 -0
  404. {plexora-0.0.8 → plexora-0.0.10}/tests/test_unreachable_node.py +0 -0
  405. {plexora-0.0.8 → plexora-0.0.10}/tests/test_url_helpers.py +0 -0
  406. {plexora-0.0.8 → plexora-0.0.10}/tests/test_view_menu.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plexora
3
- Version: 0.0.8
3
+ Version: 0.0.10
4
4
  Summary: OpenSeadragon-based cellular image viewing and analysis tool.
5
5
  License-Expression: LicenseRef-Plexora-Academic-1.0
6
6
  Requires-Python: <3.14,>=3.12
@@ -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
- const routing = await PlexoraRouting.load(datasource);
65
- const imageRoute = PlexoraRouting.tileSource(routing, "image");
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, index) {
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) return;
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 entry already had, whichever server it pointed at.
91
- const key = channel.src.replace(/\/+$/, "").split("/").pop();
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
- if (Object.prototype.hasOwnProperty.call(known, node)) {
146
- verdicts[node] = known[node];
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
- return { load, tileSource, unreachable, forget, PROBE_TIMEOUT_MS };
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=20260826_direct_routing" type="text/javascript"></script>
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=20260830_install_plexora" defer></script>
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=20260830_node_reconnect" defer></script>
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=20260826_direct_routing" defer></script>
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">