girder 5.0.15.dev18__tar.gz → 5.0.16.dev4__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 (250) hide show
  1. {girder-5.0.15.dev18/girder.egg-info → girder-5.0.16.dev4}/PKG-INFO +1 -1
  2. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/api/v1/group.py +6 -0
  3. girder-5.0.16.dev4/girder/web/tests/spec/collectionBaseClass.spec.ts +427 -0
  4. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/tests/spec/plugin_slicer_cli_web.spec.ts +3 -1
  5. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/tests/spec/plugin_terms.spec.ts +3 -1
  6. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/tests/spec/plugin_thumbnails.spec.ts +3 -1
  7. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/tests/spec/plugin_user_quota.spec.ts +3 -1
  8. {girder-5.0.15.dev18 → girder-5.0.16.dev4/girder.egg-info}/PKG-INFO +1 -1
  9. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder.egg-info/SOURCES.txt +1 -0
  10. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder.egg-info/scm_file_list.json +1 -0
  11. girder-5.0.16.dev4/girder.egg-info/scm_version.json +8 -0
  12. girder-5.0.15.dev18/girder.egg-info/scm_version.json +0 -8
  13. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/.circleci/Dockerfile +0 -0
  14. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/.circleci/build_plugins.py +0 -0
  15. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/.circleci/config.yml +0 -0
  16. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/.circleci/generatePyEnvChecksum.sh +0 -0
  17. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/.circleci/publish_npm.sh +0 -0
  18. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/.circleci/publish_pypi.sh +0 -0
  19. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/.circleci/rabbitmq.conf +0 -0
  20. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/.codecov.yml +0 -0
  21. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/.dockerignore +0 -0
  22. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/.editorconfig +0 -0
  23. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/.git-blame-ignore-revs +0 -0
  24. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/.github/workflows/codespell.yml +0 -0
  25. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/.gitignore +0 -0
  26. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/.pre-commit-config.yaml +0 -0
  27. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/.readthedocs.yml +0 -0
  28. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/CHANGELOG.rst +0 -0
  29. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/CMakeLists.txt +0 -0
  30. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/CONTRIBUTING.rst +0 -0
  31. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/Dockerfile +0 -0
  32. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/LICENSE +0 -0
  33. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/MANIFEST.in +0 -0
  34. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/README.rst +0 -0
  35. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/clients/python/README.rst +0 -0
  36. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/clients/python/girder_client/__init__.py +0 -0
  37. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/clients/python/girder_client/_jsonemitter.py +0 -0
  38. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/clients/python/girder_client/cli.py +0 -0
  39. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/clients/python/pyproject.toml +0 -0
  40. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/clients/python/setup.py +0 -0
  41. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docker-compose.yml +0 -0
  42. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/admin-docs.rst +0 -0
  43. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/api-docs.rst +0 -0
  44. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/build-docs.rst +0 -0
  45. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/conf.py +0 -0
  46. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/configuration.rst +0 -0
  47. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/dependencies.rst +0 -0
  48. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/deployment.rst +0 -0
  49. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/dev-installation.rst +0 -0
  50. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/developer-cookbook.rst +0 -0
  51. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/developer-docs.rst +0 -0
  52. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/development.rst +0 -0
  53. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/favicon.ico +0 -0
  54. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/images/dicom-viewer.png +0 -0
  55. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/index.rst +0 -0
  56. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/license.png +0 -0
  57. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/list_env_settings.py +0 -0
  58. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/list_env_settings.yaml +0 -0
  59. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/migration-guide.rst +0 -0
  60. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/mount.rst +0 -0
  61. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/plugin-development.rst +0 -0
  62. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/plugins.rst +0 -0
  63. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/python-client.rst +0 -0
  64. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/requirements-docs.txt +0 -0
  65. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/security.rst +0 -0
  66. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/sftp.rst +0 -0
  67. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/static/custom.css +0 -0
  68. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/user-docs.rst +0 -0
  69. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/user-guide.rst +0 -0
  70. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/__init__.py +0 -0
  71. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/api/__init__.py +0 -0
  72. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/api/access.py +0 -0
  73. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/api/api_docs.mako +0 -0
  74. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/api/api_main.py +0 -0
  75. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/api/describe.py +0 -0
  76. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/api/docs.py +0 -0
  77. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/api/filter_logging.py +0 -0
  78. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/api/rest.py +0 -0
  79. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/api/sftp.py +0 -0
  80. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/api/v1/__init__.py +0 -0
  81. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/api/v1/api_key.py +0 -0
  82. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/api/v1/assetstore.py +0 -0
  83. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/api/v1/collection.py +0 -0
  84. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/api/v1/file.py +0 -0
  85. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/api/v1/folder.py +0 -0
  86. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/api/v1/item.py +0 -0
  87. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/api/v1/resource.py +0 -0
  88. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/api/v1/system.py +0 -0
  89. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/api/v1/token.py +0 -0
  90. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/api/v1/user.py +0 -0
  91. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/asgi.py +0 -0
  92. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/cli/__init__.py +0 -0
  93. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/cli/mount.py +0 -0
  94. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/cli/serve.py +0 -0
  95. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/cli/sftpd.py +0 -0
  96. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/cli/shell.py +0 -0
  97. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/constants.py +0 -0
  98. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/events.py +0 -0
  99. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/exceptions.py +0 -0
  100. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/mail_templates/_footer.mako +0 -0
  101. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/mail_templates/_header.mako +0 -0
  102. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/mail_templates/accountApproval.mako +0 -0
  103. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/mail_templates/accountApproved.mako +0 -0
  104. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/mail_templates/emailVerification.mako +0 -0
  105. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/mail_templates/groupInvite.mako +0 -0
  106. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/mail_templates/temporaryAccess.mako +0 -0
  107. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/models/__init__.py +0 -0
  108. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/models/api_key.py +0 -0
  109. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/models/assetstore.py +0 -0
  110. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/models/collection.py +0 -0
  111. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/models/file.py +0 -0
  112. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/models/folder.py +0 -0
  113. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/models/group.py +0 -0
  114. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/models/item.py +0 -0
  115. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/models/model_base.py +0 -0
  116. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/models/setting.py +0 -0
  117. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/models/token.py +0 -0
  118. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/models/upload.py +0 -0
  119. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/models/user.py +0 -0
  120. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/notification.py +0 -0
  121. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/plugin.py +0 -0
  122. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/settings.py +0 -0
  123. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/tasks.py +0 -0
  124. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/utility/__init__.py +0 -0
  125. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/utility/_cache.py +0 -0
  126. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/utility/_hash_state.py +0 -0
  127. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/utility/abstract_assetstore_adapter.py +0 -0
  128. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/utility/acl_mixin.py +0 -0
  129. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/utility/assetstore_utilities.py +0 -0
  130. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/utility/config.py +0 -0
  131. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/utility/error.mako +0 -0
  132. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/utility/filesystem_assetstore_adapter.py +0 -0
  133. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/utility/mail_utils.py +0 -0
  134. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/utility/model_importer.py +0 -0
  135. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/utility/path.py +0 -0
  136. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/utility/progress.py +0 -0
  137. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/utility/s3_assetstore_adapter.py +0 -0
  138. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/utility/search.py +0 -0
  139. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/utility/server.py +0 -0
  140. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/utility/setting_utilities.py +0 -0
  141. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/utility/system.py +0 -0
  142. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/utility/webroot.py +0 -0
  143. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/utility/ziputil.py +0 -0
  144. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/.env.development +0 -0
  145. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/.gitignore +0 -0
  146. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/.prettierrc.json +0 -0
  147. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/README.rst +0 -0
  148. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/Girder_Favicon.png +0 -0
  149. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/Girder_Mark.png +0 -0
  150. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/fontello-3xN5GmYC.woff +0 -0
  151. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/fontello-BGLM866c.svg +0 -0
  152. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/fontello-BM99wLny.ttf +0 -0
  153. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/fontello-Cf9aKW7e.woff2 +0 -0
  154. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/fontello-DzekhRz_.eot +0 -0
  155. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/glyphicons-halflings-regular-BKjkU69z.woff +0 -0
  156. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/glyphicons-halflings-regular-BUJKDMgK.eot +0 -0
  157. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/glyphicons-halflings-regular-CSehLiBc.svg +0 -0
  158. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/glyphicons-halflings-regular-DrwTMapi.ttf +0 -0
  159. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/glyphicons-halflings-regular-DzqM6ju8.woff2 +0 -0
  160. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/index-Dj5Hkfi2.js +0 -0
  161. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/index-Dj5Hkfi2.js.map +0 -0
  162. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/index-gzLH-yPG.css +0 -0
  163. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/jsoneditor-icons-CIlYC0TY.svg +0 -0
  164. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/open-sans-latin-300-B6tDWRxp.woff2 +0 -0
  165. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/open-sans-latin-300-DZbNTRe6.woff +0 -0
  166. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/open-sans-latin-300italic-DLsXqxhU.woff2 +0 -0
  167. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/open-sans-latin-300italic-Dfz31Up5.woff +0 -0
  168. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/open-sans-latin-400-D5zbb_EN.woff +0 -0
  169. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/open-sans-latin-400-DLgeRt71.woff2 +0 -0
  170. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/open-sans-latin-400italic-DpGQ6Ktj.woff2 +0 -0
  171. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/open-sans-latin-400italic-UJbezL8h.woff +0 -0
  172. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/open-sans-latin-600-CCvT4JHQ.woff2 +0 -0
  173. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/open-sans-latin-600-DHWfDY-G.woff +0 -0
  174. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/open-sans-latin-600italic-X8kCjSq_.woff +0 -0
  175. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/open-sans-latin-600italic-slqXzGub.woff2 +0 -0
  176. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/open-sans-latin-700-CsbQbrjx.woff2 +0 -0
  177. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/open-sans-latin-700-DNl7WOH5.woff +0 -0
  178. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/open-sans-latin-700italic-BtE7VvhE.woff2 +0 -0
  179. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/open-sans-latin-700italic-hc2P_kZo.woff +0 -0
  180. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/open-sans-latin-800-CbJOM4_m.woff2 +0 -0
  181. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/open-sans-latin-800-XaYTAPrv.woff +0 -0
  182. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/open-sans-latin-800italic-DqvYew-K.woff +0 -0
  183. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/open-sans-latin-800italic-JIGkTxpX.woff2 +0 -0
  184. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/index.html +0 -0
  185. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/src/src/auth.js +0 -0
  186. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/src/src/constants.js +0 -0
  187. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/src/src/dialog.js +0 -0
  188. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/src/src/events.js +0 -0
  189. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/src/src/index.ts +0 -0
  190. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/src/src/main.ts +0 -0
  191. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/src/src/misc.js +0 -0
  192. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/src/src/pluginUtils.js +0 -0
  193. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/src/src/rest.js +0 -0
  194. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/src/src/router.js +0 -0
  195. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/src/src/routes.js +0 -0
  196. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/src/src/version.js +0 -0
  197. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/src/src/vite-env.d.ts +0 -0
  198. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/env.d.ts +0 -0
  199. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/playwright.config.ts +0 -0
  200. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/tests/coverage.ts +0 -0
  201. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/tests/playwright-setup.ts +0 -0
  202. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/tests/playwright-teardown.ts +0 -0
  203. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/tests/server.ts +0 -0
  204. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/tests/spec/admin.spec.ts +0 -0
  205. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/tests/spec/browser.spec.ts +0 -0
  206. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/tests/spec/data/README.md +0 -0
  207. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/tests/spec/data/nomime.dat +0 -0
  208. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/tests/spec/data/slicer_cli_web_test.xml +0 -0
  209. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/tests/spec/data/ten_byte_file.txt +0 -0
  210. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/tests/spec/file_upload.spec.ts +0 -0
  211. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/tests/spec/plugin_authorized_upload.spec.ts +0 -0
  212. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/tests/spec/plugin_hashsum_download.spec.ts +0 -0
  213. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/tests/spec/plugin_homepage.spec.ts +0 -0
  214. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/tests/spec/plugin_item_licenses.spec.ts +0 -0
  215. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/tests/spec/plugin_readme.spec.ts +0 -0
  216. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/tests/util.ts +0 -0
  217. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/worker_plugin.py +0 -0
  218. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/wsgi.py +0 -0
  219. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder.egg-info/dependency_links.txt +0 -0
  220. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder.egg-info/entry_points.txt +0 -0
  221. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder.egg-info/not-zip-safe +0 -0
  222. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder.egg-info/requires.txt +0 -0
  223. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder.egg-info/top_level.txt +0 -0
  224. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/jsdoc.json +0 -0
  225. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/package-lock.json +0 -0
  226. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/package.json +0 -0
  227. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/pyproject.toml +0 -0
  228. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/pytest_girder/LICENSE +0 -0
  229. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/pytest_girder/MANIFEST.in +0 -0
  230. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/pytest_girder/pyproject.toml +0 -0
  231. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/pytest_girder/pytest_girder/__init__.py +0 -0
  232. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/pytest_girder/pytest_girder/assertions.py +0 -0
  233. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/pytest_girder/pytest_girder/fixtures.py +0 -0
  234. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/pytest_girder/pytest_girder/plugin.py +0 -0
  235. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/pytest_girder/pytest_girder/plugin_registry.py +0 -0
  236. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/pytest_girder/pytest_girder/utils.py +0 -0
  237. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/pytest_girder/pytest_girder/web_client.py +0 -0
  238. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/pytest_girder/setup.py +0 -0
  239. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/requirements-dev.txt +0 -0
  240. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/scripts/midas/README.rst +0 -0
  241. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/scripts/midas/migrate.py +0 -0
  242. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/scripts/midas/requirements.txt +0 -0
  243. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/scripts/midas/walk_girder.py +0 -0
  244. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/scripts/midas/walk_midas.py +0 -0
  245. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/scripts/publicNames.py +0 -0
  246. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/scripts/publicNames.txt +0 -0
  247. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/scripts/test_names.sh +0 -0
  248. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/setup.cfg +0 -0
  249. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/setup.py +0 -0
  250. {girder-5.0.15.dev18 → girder-5.0.16.dev4}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: girder
3
- Version: 5.0.15.dev18
3
+ Version: 5.0.16.dev4
4
4
  Summary: Web-based data management platform
5
5
  Home-page: https://girder.readthedocs.org
6
6
  Author: Kitware, Inc.
@@ -222,6 +222,12 @@ class Group(Resource):
222
222
  mustBeAdmin = False
223
223
  if mustBeAdmin:
224
224
  self.requireAdmin(user)
225
+ if not user['admin']:
226
+ # A non-site-admin may only grant an access level that they
227
+ # themselves hold. Without this clamp, a moderator (WRITE)
228
+ # could promote an arbitrary user to ADMIN via the force path,
229
+ # bypassing the level check that the non-force branch applies.
230
+ groupModel.requireAccess(group, user, level)
225
231
  groupModel.addUser(group, userToInvite, level=level)
226
232
  else:
227
233
  # Can only invite into access levels that you yourself have
@@ -0,0 +1,427 @@
1
+ import { Page, expect, test } from '@playwright/test';
2
+
3
+ import { createUser, waitForIdlePage } from '../util';
4
+ import { setupServer } from '../server';
5
+
6
+ /**
7
+ * Helper to make a REST request from the page context (in the browser)
8
+ */
9
+ async function asyncRestRequest(page: Page, opts: Record<string, unknown>) {
10
+ return await page.evaluate((opts) => {
11
+ return new Promise((resolve, reject) => {
12
+ // @ts-ignore - window.girder is available at runtime
13
+ window.girder.rest.restRequest(opts).done((resp) => {
14
+ resolve(resp);
15
+ }).fail((resp) => {
16
+ reject(resp);
17
+ });
18
+ });
19
+ }, opts);
20
+ }
21
+
22
+ /**
23
+ * Helper to create an API key via REST API.
24
+ */
25
+ async function createApiKey(page: Page, name: string) {
26
+ const resp = await asyncRestRequest(page, {
27
+ url: '/api_key',
28
+ method: 'POST',
29
+ data: { name },
30
+ });
31
+
32
+ return resp as Record<string, unknown>;
33
+ }
34
+
35
+ /**
36
+ * Ported from 3.x-maintenance: girder/web_client/test/spec/collectionBaseClassSpec.js
37
+ *
38
+ * The original test "Test normal collection operation" had three separate tests:
39
+ * 1. create several dummy api keys
40
+ * 2. ensure collection fetch fires backbone "reset" event with expected options
41
+ * 3. ensure collections can go backwards and forwards
42
+ *
43
+ * Ported to Playwright testing.
44
+ */
45
+ test.describe('Test normal collection operation', () => {
46
+ setupServer();
47
+
48
+ test('create API keys, verify reset event, and test pagination all in one test (combined from original)', async ({ page }) => {
49
+ // Login as admin first (first user becomes admin)
50
+ await createUser(page, 'admin');
51
+
52
+ // === Part 1: Create several dummy api keys using Backbone models (as in original test) ===
53
+ const keysCreated = await page.evaluate(() => {
54
+ return new Promise<number>((resolve, reject) => {
55
+ // @ts-ignore - window.girder is available at runtime
56
+ const savePromises: Promise<Record<string, unknown>>[] = [];
57
+ for (let i = 0; i < 10; i++) {
58
+ savePromises.push(new (window.girder.models.ApiKeyModel)({ name: `test${i}` }).save());
59
+ }
60
+ Promise.all(savePromises).then((results) => resolve(results.length)).catch(reject);
61
+ });
62
+ });
63
+
64
+ expect(keysCreated).toBe(10);
65
+ await waitForIdlePage(page);
66
+
67
+ // === Part 2: Test collection fetch fires "reset" event with expected options ===
68
+ const resetResult = await page.evaluate(() => {
69
+ return new Promise<Record<string, unknown>>((resolve, reject) => {
70
+ // @ts-ignore - window.girder is available at runtime
71
+ const collection = new (window.girder.collections.ApiKeyCollection)();
72
+ let previousModels: unknown[] | null = null;
73
+
74
+ collection.once('reset', (_collection: any, options: { previousModels?: unknown[] }) => {
75
+ previousModels = options.previousModels;
76
+ });
77
+
78
+ collection.fetch()
79
+ .done(() => {
80
+ resolve({
81
+ length: collection.length,
82
+ hasPreviousModels: Array.isArray(previousModels),
83
+ previousModelsLength: previousModels ? previousModels.length : -1,
84
+ });
85
+ })
86
+ .fail(reject);
87
+ });
88
+ });
89
+
90
+ expect(resetResult.length).toBeGreaterThanOrEqual(10);
91
+ expect(resetResult.hasPreviousModels).toBe(true);
92
+ expect(resetResult.previousModelsLength).toBe(0);
93
+
94
+ // === Part 3: Create new keys for pagination testing and test forward/backward ===
95
+ const keyIds: string[] = [];
96
+ for (let i = 0; i < 10; i++) {
97
+ const resp = await createApiKey(page, `navTest${i}`);
98
+ keyIds.push((resp as Record<string, string>).id || '');
99
+ }
100
+ await waitForIdlePage(page);
101
+
102
+ // Verify we have the keys from REST API
103
+ const allKeys = await asyncRestRequest(page, { url: '/api_key', data: { limit: 100 } });
104
+ expect((allKeys as unknown[]).length).toBeGreaterThanOrEqual(10);
105
+
106
+ // Now test pagination with fetchNextPage/fetchPreviousPage
107
+ const paginationResult = await page.evaluate(async () => {
108
+ // @ts-ignore - window.girder is available at runtime
109
+ const collection = new (window.girder.collections.ApiKeyCollection)();
110
+ collection.pageLimit = 2;
111
+ // @ts-ignore - append is a property on collections
112
+ collection.append = false;
113
+
114
+ await new Promise<void>((resolve, reject) => {
115
+ collection.fetch().done(resolve).fail(reject);
116
+ });
117
+
118
+ const results: Record<string, unknown>[] = [];
119
+ try {
120
+ // Initial state
121
+ results.push({
122
+ length: collection.length,
123
+ hasNext: collection.hasNextPage(),
124
+ hasPrev: collection.hasPreviousPage(),
125
+ offset: collection.offset,
126
+ pageNum: collection.pageNum(),
127
+ });
128
+
129
+ // Navigate forward 5 times
130
+ for (let i = 0; i < 5; i++) {
131
+ await new Promise<void>((resolve, reject) => {
132
+ collection.fetchNextPage().done(resolve).fail(reject);
133
+ });
134
+ results.push({
135
+ length: collection.length,
136
+ hasNext: collection.hasNextPage(),
137
+ hasPrev: collection.hasPreviousPage(),
138
+ offset: collection.offset,
139
+ pageNum: collection.pageNum(),
140
+ });
141
+ }
142
+
143
+ // Navigate back 5 times
144
+ for (let i = 0; i < 5; i++) {
145
+ await new Promise<void>((resolve, reject) => {
146
+ collection.fetchPreviousPage().done(resolve).fail(reject);
147
+ });
148
+ results.push({
149
+ length: collection.length,
150
+ hasNext: collection.hasNextPage(),
151
+ hasPrev: collection.hasPreviousPage(),
152
+ offset: collection.offset,
153
+ pageNum: collection.pageNum(),
154
+ });
155
+ }
156
+
157
+ } catch (error) {
158
+ return { error: String(error), results: [] };
159
+ }
160
+
161
+ return { error: null as string | null, steps: results.length, result: results };
162
+ });
163
+
164
+ expect(paginationResult.error).toBe(null);
165
+ if ((paginationResult.result as Record<string, unknown>[]).length > 0) {
166
+ const results = paginationResult.result as Record<string, unknown>[];
167
+ expect(results.length).toBeGreaterThanOrEqual(1);
168
+ // At least some collection items should have been fetched
169
+ expect((results[0].length as number)).toBeGreaterThan(0);
170
+ }
171
+
172
+ // Clean up test keys from this step
173
+ for (const id of keyIds) {
174
+ if (id) {
175
+ await asyncRestRequest(page, { url: `/api_key/${id}`, method: 'DELETE' }).catch(() => {});
176
+ }
177
+ }
178
+ });
179
+ });
180
+
181
+
182
+ /**
183
+ * Ported from 3.x-maintenance: girder/web_client/test/spec/collectionBaseClassSpec.js
184
+ *
185
+ * The original "Test collection filtering" had four separate tests that relied on shared
186
+ * pre-created data (filterTest0-9). In Playwright each describe block gets its own fresh
187
+ * MongoDB via setupServer(). To avoid cross-test state contamination we use separate
188
+ * describe blocks so each test has complete isolation.
189
+ */
190
+
191
+ test.describe('Test collection filtering: collect all', () => {
192
+ setupServer();
193
+
194
+ test('create several dummy api keys then fetch with collect-all filterFunc', async ({ page }) => {
195
+ await createUser(page, 'admin');
196
+ for (let i = 0; i < 10; i++) {
197
+ await createApiKey(page, `filterTest${i}`);
198
+ }
199
+ // Wait for all API key creations to complete before fetching
200
+ await waitForIdlePage(page);
201
+
202
+ const result = await page.evaluate(() => {
203
+ return new Promise<Record<string, unknown>>((resolve, reject) => {
204
+ // @ts-ignore - window.girder is available at runtime
205
+ const collection = new (window.girder.collections.ApiKeyCollection)();
206
+ const reFiltered = /filterTest(\d+)/;
207
+
208
+ collection.filterFunc = function (apiKey: { name?: string }) {
209
+ return apiKey.name && apiKey.name.match(reFiltered);
210
+ };
211
+
212
+ collection.fetch()
213
+ .done(() => {
214
+ const names: string[] = [];
215
+ for (let i = 0; i < collection.length; i++) {
216
+ // @ts-ignore - Backbone model at() returns a model instance
217
+ names.push(collection.at(i).get('name'));
218
+ }
219
+ resolve({ length: collection.length, names });
220
+ })
221
+ .fail(reject);
222
+ });
223
+ });
224
+
225
+ expect(result.length).toBe(10);
226
+ expect((result.names as string[])).toEqual([
227
+ 'filterTest0', 'filterTest1', 'filterTest2', 'filterTest3',
228
+ 'filterTest4', 'filterTest5', 'filterTest6', 'filterTest7',
229
+ 'filterTest8', 'filterTest9',
230
+ ]);
231
+ });
232
+ });
233
+
234
+ test.describe('Test collection filtering: even index only', () => {
235
+ setupServer();
236
+
237
+ test('select only dummy api keys with even index', async ({ page }) => {
238
+ await createUser(page, 'admin');
239
+ for (let i = 0; i < 10; i++) {
240
+ await createApiKey(page, `filterTest${i}`);
241
+ }
242
+ // Wait for all API key creations to complete before fetching
243
+ await waitForIdlePage(page);
244
+
245
+ const result = await page.evaluate(() => {
246
+ return new Promise<Record<string, unknown>>((resolve, reject) => {
247
+ // @ts-ignore - window.girder is available at runtime
248
+ const reFiltered = /filterTest(\d+)/;
249
+ const collection = new (window.girder.collections.ApiKeyCollection)();
250
+
251
+ collection.filterFunc = function (apiKey: { name?: string }) {
252
+ const match = apiKey.name?.match(reFiltered);
253
+ if (match) {
254
+ const index = parseInt(match[1], 10);
255
+ return index % 2 === 0;
256
+ }
257
+ return false;
258
+ };
259
+
260
+ collection.fetch()
261
+ .done(() => {
262
+ const names: string[] = [];
263
+ for (let i = 0; i < collection.length; i++) {
264
+ // @ts-ignore - Backbone model at() returns a model instance
265
+ names.push(collection.at(i).get('name'));
266
+ }
267
+ resolve({ length: collection.length, names });
268
+ })
269
+ .fail(reject);
270
+ });
271
+ });
272
+
273
+ expect(result.length).toBe(5);
274
+ expect((result.names as string[])).toEqual([
275
+ 'filterTest0', 'filterTest2', 'filterTest4', 'filterTest6', 'filterTest8',
276
+ ]);
277
+ });
278
+ });
279
+
280
+ test.describe('Test collection filtering: outside range', () => {
281
+ setupServer();
282
+
283
+ test('select only dummy api keys outside a given range (index < 3 || index > 6)', async ({ page }) => {
284
+ await createUser(page, 'admin');
285
+ for (let i = 0; i < 10; i++) {
286
+ await createApiKey(page, `filterTest${i}`);
287
+ }
288
+ // Wait for all API key creations to complete before fetching
289
+ await waitForIdlePage(page);
290
+
291
+ const result = await page.evaluate(() => {
292
+ return new Promise<Record<string, unknown>>((resolve, reject) => {
293
+ // @ts-ignore - window.girder is available at runtime
294
+ const reFiltered = /filterTest(\d+)/;
295
+ const collection = new (window.girder.collections.ApiKeyCollection)();
296
+
297
+ collection.filterFunc = function (apiKey: { name?: string }) {
298
+ const match = apiKey.name?.match(reFiltered);
299
+ let result = false;
300
+ if (match) {
301
+ const index = parseInt(match[1], 10);
302
+ result = index < 3 || index > 6;
303
+ }
304
+ return result;
305
+ };
306
+
307
+ collection.pageLimit = 5;
308
+
309
+ collection.fetch()
310
+ .done(() => {
311
+ const names: string[] = [];
312
+ for (let i = 0; i < collection.length; i++) {
313
+ // @ts-ignore - Backbone model at() returns a model instance
314
+ names.push(collection.at(i).get('name'));
315
+ }
316
+ resolve({ length: collection.length, names });
317
+ })
318
+ .fail(reject);
319
+ });
320
+ });
321
+
322
+ expect(result.length).toBe(5);
323
+ expect((result.names as string[])).toEqual([
324
+ 'filterTest0', 'filterTest1', 'filterTest2', 'filterTest7', 'filterTest8',
325
+ ]);
326
+ });
327
+ });
328
+
329
+ test.describe('Test collection filtering: navigation', () => {
330
+ setupServer();
331
+
332
+ test('ensure filtered collections can go backwards and forwards', async ({ page }) => {
333
+ await createUser(page, 'admin');
334
+ for (let i = 0; i < 10; i++) {
335
+ await createApiKey(page, `filterTest${i}`);
336
+ }
337
+ // Wait for all API key creations to complete before fetching
338
+ await waitForIdlePage(page);
339
+
340
+ const steps: Record<string, unknown>[] = await page.evaluate(async () => {
341
+ // @ts-ignore - window.girder is available at runtime
342
+ const reFiltered = /filterTest(\d+)/;
343
+ const collection = new (window.girder.collections.ApiKeyCollection)();
344
+
345
+ collection.filterFunc = function (apiKey: { name?: string }) {
346
+ const match = apiKey.name?.match(reFiltered);
347
+ let result = false;
348
+ if (match) {
349
+ const index = parseInt(match[1], 10);
350
+ result = index < 3 || index > 6;
351
+ }
352
+ return result;
353
+ };
354
+
355
+ collection.pageLimit = 2;
356
+ // @ts-ignore - append is a property on collections
357
+ collection.append = false;
358
+
359
+ function pageResult(col: any): Record<string, unknown> {
360
+ try {
361
+ return {
362
+ length: col.length,
363
+ at0: col.at(0).get('name'),
364
+ at1: col.at(1) ? col.at(1).get('name') : null,
365
+ hasNextPage: col.hasNextPage(),
366
+ hasPreviousPage: col.hasPreviousPage(),
367
+ offset: col.offset,
368
+ };
369
+ } catch {
370
+ return {};
371
+ }
372
+ }
373
+
374
+ const step0 = new Promise<void>((resolve, reject) => {
375
+ collection.fetchNextPage().done(resolve).fail(reject);
376
+ });
377
+ const step1 = step0.then(() =>
378
+ new Promise<void>((resolve, reject) => {
379
+ collection.fetchNextPage().done(resolve).fail(reject);
380
+ })
381
+ );
382
+ const step2 = step1.then(() =>
383
+ new Promise<void>((resolve, reject) => {
384
+ collection.fetchPreviousPage().done(resolve).fail(reject);
385
+ })
386
+ );
387
+ const step3 = step2.then(() =>
388
+ new Promise<void>((resolve, reject) => {
389
+ collection.fetchPreviousPage().done(resolve).fail(reject);
390
+ })
391
+ );
392
+
393
+ await step0;
394
+ const results: Record<string, unknown>[] = [];
395
+ results.push(pageResult(collection));
396
+ await step1;
397
+ results.push(pageResult(collection));
398
+ await step2;
399
+ results.push(pageResult(collection));
400
+ await step3;
401
+ results.push(pageResult(collection));
402
+
403
+ return results;
404
+ });
405
+
406
+ expect(steps.length).toBe(4);
407
+
408
+ const s0 = steps[0] as Record<string, unknown>;
409
+ const s1 = steps[1] as Record<string, unknown>;
410
+ const s3 = steps[3] as Record<string, unknown>;
411
+
412
+ // Step 0: first page with 2 matches (filterTest0, filterTest1)
413
+ expect(s0.length).toBe(2);
414
+ expect((s0.at0 as string)).toBe('filterTest0');
415
+ expect((s0.at1 as string)).toBe('filterTest1');
416
+ expect((s0.hasNextPage as boolean)).toBe(true);
417
+
418
+ // Step 1: second page with next two matches (filterTest2, filterTest7)
419
+ expect(s1.length).toBe(2);
420
+ expect((s1.at0 as string)).toBe('filterTest2');
421
+ expect((s1.at1 as string)).toBe('filterTest7');
422
+
423
+ // Step 3: navigate back twice should return to step 0 state
424
+ expect((s3.at0 as string)).toBe('filterTest0');
425
+ expect((s3.at1 as string)).toBe('filterTest1');
426
+ });
427
+ });
@@ -5,7 +5,7 @@ import { fileURLToPath } from 'url';
5
5
  import { expect, test } from '@playwright/test';
6
6
 
7
7
  import { setupServer } from '../server';
8
- import { createUser } from '../util';
8
+ import { createUser, waitForIdlePage } from '../util';
9
9
 
10
10
  const __filename = fileURLToPath(import.meta.url);
11
11
  const __dirname = path.dirname(__filename);
@@ -54,6 +54,8 @@ test.describe('Test Slicer CLI web', () => {
54
54
  test('create a CLI item', async ({ page }) => {
55
55
  await createUser(page, 'admin');
56
56
  await createCliItem(page);
57
+ // Wait for all REST requests from CLI creation to complete before navigating
58
+ await waitForIdlePage(page);
57
59
 
58
60
  await page.locator('#g-app-header-container').getByText('admin').click();
59
61
  await page.locator('a.g-my-folders').click();
@@ -1,7 +1,7 @@
1
1
  import { expect, test } from '@playwright/test';
2
2
 
3
3
  import { setupServer } from '../server';
4
- import { createUser, logout } from '../util';
4
+ import { createUser, logout, waitForIdlePage } from '../util';
5
5
 
6
6
  test.describe('Test the terms front-end', () => {
7
7
  setupServer();
@@ -17,6 +17,8 @@ test.describe('Test the terms front-end', () => {
17
17
  await page.getByRole('button', { name: ' Create', exact: true }).click();
18
18
 
19
19
  await expect(page.locator('#g-dialog-container')).toBeHidden();
20
+ // Wait for REST requests to complete before further actions
21
+ await waitForIdlePage(page);
20
22
 
21
23
  await page.getByRole('button', { name: '' }).click();
22
24
  await page.getByLabel('Public — Anyone can view this collection').check();
@@ -4,7 +4,7 @@ import { fileURLToPath } from 'url';
4
4
  import { expect, test } from '@playwright/test';
5
5
 
6
6
  import { setupServer } from '../server';
7
- import { createUser, upload } from '../util';
7
+ import { createUser, upload, waitForIdlePage } from '../util';
8
8
 
9
9
  const __filename = fileURLToPath(import.meta.url);
10
10
  const __dirname = path.dirname(__filename);
@@ -26,6 +26,8 @@ test.describe('Test the thumbnails front-end', () => {
26
26
  await page.getByPlaceholder('width').press('Tab');
27
27
  await page.getByPlaceholder('height').fill('50');
28
28
  await page.getByRole('button', { name: ' Create' }).click();
29
+ // Wait for thumbnail creation task to complete
30
+ await waitForIdlePage(page);
29
31
 
30
32
  await expect(page.locator('.g-thumbnail')).toBeVisible();
31
33
 
@@ -4,7 +4,7 @@ import { fileURLToPath } from 'url';
4
4
  import { expect, test } from '@playwright/test';
5
5
 
6
6
  import { setupServer } from '../server';
7
- import { createUser, upload } from '../util';
7
+ import { createUser, upload, waitForIdlePage } from '../util';
8
8
 
9
9
  const __filename = fileURLToPath(import.meta.url);
10
10
  const __dirname = path.dirname(__filename);
@@ -23,6 +23,8 @@ test.describe('Test the quota front-end', () => {
23
23
  await page.getByPlaceholder('Maximum allowed size of all files, or blank for no limit').fill('15');
24
24
  await page.getByRole('button', { name: ' Save' }).click();
25
25
  await expect(page.locator('#g-dialog-container')).toBeHidden();
26
+ // Wait for quota setting to be saved via REST before proceeding
27
+ await waitForIdlePage(page);
26
28
 
27
29
  await page.getByRole('link', { name: ' Private ' }).click();
28
30
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: girder
3
- Version: 5.0.15.dev18
3
+ Version: 5.0.16.dev4
4
4
  Summary: Web-based data management platform
5
5
  Home-page: https://girder.readthedocs.org
6
6
  Author: Kitware, Inc.
@@ -212,6 +212,7 @@ girder/web/tests/server.ts
212
212
  girder/web/tests/util.ts
213
213
  girder/web/tests/spec/admin.spec.ts
214
214
  girder/web/tests/spec/browser.spec.ts
215
+ girder/web/tests/spec/collectionBaseClass.spec.ts
215
216
  girder/web/tests/spec/file_upload.spec.ts
216
217
  girder/web/tests/spec/plugin_authorized_upload.spec.ts
217
218
  girder/web/tests/spec/plugin_hashsum_download.spec.ts
@@ -385,6 +385,7 @@
385
385
  "girder/web/tests/server.ts",
386
386
  "girder/web/tests/spec/admin.spec.ts",
387
387
  "girder/web/tests/spec/browser.spec.ts",
388
+ "girder/web/tests/spec/collectionBaseClass.spec.ts",
388
389
  "girder/web/tests/spec/data/README.md",
389
390
  "girder/web/tests/spec/data/nomime.dat",
390
391
  "girder/web/tests/spec/data/slicer_cli_web_test.xml",
@@ -0,0 +1,8 @@
1
+ {
2
+ "tag": "5.0.15",
3
+ "distance": 4,
4
+ "node": "gb1a26bfee3a7bf12a9524b0194492ee747da57eb",
5
+ "dirty": false,
6
+ "branch": "master",
7
+ "node_date": "2026-08-14"
8
+ }
@@ -1,8 +0,0 @@
1
- {
2
- "tag": "5.0.14",
3
- "distance": 18,
4
- "node": "ga4151d04f75943588c31eb977f836c0c4b22050f",
5
- "dirty": false,
6
- "branch": "master",
7
- "node_date": "2026-08-11"
8
- }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes