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.
- {girder-5.0.15.dev18/girder.egg-info → girder-5.0.16.dev4}/PKG-INFO +1 -1
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/api/v1/group.py +6 -0
- girder-5.0.16.dev4/girder/web/tests/spec/collectionBaseClass.spec.ts +427 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/tests/spec/plugin_slicer_cli_web.spec.ts +3 -1
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/tests/spec/plugin_terms.spec.ts +3 -1
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/tests/spec/plugin_thumbnails.spec.ts +3 -1
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/tests/spec/plugin_user_quota.spec.ts +3 -1
- {girder-5.0.15.dev18 → girder-5.0.16.dev4/girder.egg-info}/PKG-INFO +1 -1
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder.egg-info/SOURCES.txt +1 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder.egg-info/scm_file_list.json +1 -0
- girder-5.0.16.dev4/girder.egg-info/scm_version.json +8 -0
- girder-5.0.15.dev18/girder.egg-info/scm_version.json +0 -8
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/.circleci/Dockerfile +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/.circleci/build_plugins.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/.circleci/config.yml +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/.circleci/generatePyEnvChecksum.sh +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/.circleci/publish_npm.sh +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/.circleci/publish_pypi.sh +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/.circleci/rabbitmq.conf +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/.codecov.yml +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/.dockerignore +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/.editorconfig +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/.git-blame-ignore-revs +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/.github/workflows/codespell.yml +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/.gitignore +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/.pre-commit-config.yaml +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/.readthedocs.yml +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/CHANGELOG.rst +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/CMakeLists.txt +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/CONTRIBUTING.rst +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/Dockerfile +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/LICENSE +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/MANIFEST.in +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/README.rst +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/clients/python/README.rst +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/clients/python/girder_client/__init__.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/clients/python/girder_client/_jsonemitter.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/clients/python/girder_client/cli.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/clients/python/pyproject.toml +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/clients/python/setup.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docker-compose.yml +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/admin-docs.rst +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/api-docs.rst +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/build-docs.rst +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/conf.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/configuration.rst +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/dependencies.rst +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/deployment.rst +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/dev-installation.rst +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/developer-cookbook.rst +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/developer-docs.rst +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/development.rst +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/favicon.ico +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/images/dicom-viewer.png +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/index.rst +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/license.png +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/list_env_settings.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/list_env_settings.yaml +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/migration-guide.rst +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/mount.rst +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/plugin-development.rst +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/plugins.rst +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/python-client.rst +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/requirements-docs.txt +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/security.rst +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/sftp.rst +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/static/custom.css +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/user-docs.rst +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/docs/user-guide.rst +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/__init__.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/api/__init__.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/api/access.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/api/api_docs.mako +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/api/api_main.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/api/describe.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/api/docs.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/api/filter_logging.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/api/rest.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/api/sftp.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/api/v1/__init__.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/api/v1/api_key.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/api/v1/assetstore.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/api/v1/collection.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/api/v1/file.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/api/v1/folder.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/api/v1/item.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/api/v1/resource.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/api/v1/system.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/api/v1/token.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/api/v1/user.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/asgi.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/cli/__init__.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/cli/mount.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/cli/serve.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/cli/sftpd.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/cli/shell.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/constants.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/events.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/exceptions.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/mail_templates/_footer.mako +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/mail_templates/_header.mako +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/mail_templates/accountApproval.mako +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/mail_templates/accountApproved.mako +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/mail_templates/emailVerification.mako +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/mail_templates/groupInvite.mako +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/mail_templates/temporaryAccess.mako +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/models/__init__.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/models/api_key.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/models/assetstore.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/models/collection.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/models/file.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/models/folder.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/models/group.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/models/item.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/models/model_base.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/models/setting.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/models/token.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/models/upload.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/models/user.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/notification.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/plugin.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/settings.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/tasks.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/utility/__init__.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/utility/_cache.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/utility/_hash_state.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/utility/abstract_assetstore_adapter.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/utility/acl_mixin.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/utility/assetstore_utilities.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/utility/config.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/utility/error.mako +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/utility/filesystem_assetstore_adapter.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/utility/mail_utils.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/utility/model_importer.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/utility/path.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/utility/progress.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/utility/s3_assetstore_adapter.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/utility/search.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/utility/server.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/utility/setting_utilities.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/utility/system.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/utility/webroot.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/utility/ziputil.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/.env.development +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/.gitignore +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/.prettierrc.json +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/README.rst +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/Girder_Favicon.png +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/Girder_Mark.png +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/fontello-3xN5GmYC.woff +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/fontello-BGLM866c.svg +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/fontello-BM99wLny.ttf +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/fontello-Cf9aKW7e.woff2 +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/fontello-DzekhRz_.eot +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/glyphicons-halflings-regular-BKjkU69z.woff +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/glyphicons-halflings-regular-BUJKDMgK.eot +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/glyphicons-halflings-regular-CSehLiBc.svg +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/glyphicons-halflings-regular-DrwTMapi.ttf +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/glyphicons-halflings-regular-DzqM6ju8.woff2 +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/index-Dj5Hkfi2.js +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/index-Dj5Hkfi2.js.map +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/index-gzLH-yPG.css +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/jsoneditor-icons-CIlYC0TY.svg +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/open-sans-latin-300-B6tDWRxp.woff2 +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/open-sans-latin-300-DZbNTRe6.woff +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/open-sans-latin-300italic-DLsXqxhU.woff2 +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/open-sans-latin-300italic-Dfz31Up5.woff +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/open-sans-latin-400-D5zbb_EN.woff +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/open-sans-latin-400-DLgeRt71.woff2 +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/open-sans-latin-400italic-DpGQ6Ktj.woff2 +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/open-sans-latin-400italic-UJbezL8h.woff +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/open-sans-latin-600-CCvT4JHQ.woff2 +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/open-sans-latin-600-DHWfDY-G.woff +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/open-sans-latin-600italic-X8kCjSq_.woff +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/open-sans-latin-600italic-slqXzGub.woff2 +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/open-sans-latin-700-CsbQbrjx.woff2 +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/open-sans-latin-700-DNl7WOH5.woff +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/open-sans-latin-700italic-BtE7VvhE.woff2 +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/open-sans-latin-700italic-hc2P_kZo.woff +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/open-sans-latin-800-CbJOM4_m.woff2 +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/open-sans-latin-800-XaYTAPrv.woff +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/open-sans-latin-800italic-DqvYew-K.woff +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/assets/open-sans-latin-800italic-JIGkTxpX.woff2 +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/index.html +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/src/src/auth.js +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/src/src/constants.js +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/src/src/dialog.js +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/src/src/events.js +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/src/src/index.ts +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/src/src/main.ts +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/src/src/misc.js +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/src/src/pluginUtils.js +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/src/src/rest.js +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/src/src/router.js +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/src/src/routes.js +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/src/src/version.js +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/dist/src/src/vite-env.d.ts +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/env.d.ts +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/playwright.config.ts +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/tests/coverage.ts +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/tests/playwright-setup.ts +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/tests/playwright-teardown.ts +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/tests/server.ts +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/tests/spec/admin.spec.ts +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/tests/spec/browser.spec.ts +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/tests/spec/data/README.md +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/tests/spec/data/nomime.dat +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/tests/spec/data/slicer_cli_web_test.xml +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/tests/spec/data/ten_byte_file.txt +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/tests/spec/file_upload.spec.ts +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/tests/spec/plugin_authorized_upload.spec.ts +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/tests/spec/plugin_hashsum_download.spec.ts +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/tests/spec/plugin_homepage.spec.ts +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/tests/spec/plugin_item_licenses.spec.ts +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/tests/spec/plugin_readme.spec.ts +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/tests/util.ts +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/worker_plugin.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/wsgi.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder.egg-info/dependency_links.txt +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder.egg-info/entry_points.txt +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder.egg-info/not-zip-safe +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder.egg-info/requires.txt +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder.egg-info/top_level.txt +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/jsdoc.json +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/package-lock.json +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/package.json +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/pyproject.toml +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/pytest_girder/LICENSE +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/pytest_girder/MANIFEST.in +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/pytest_girder/pyproject.toml +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/pytest_girder/pytest_girder/__init__.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/pytest_girder/pytest_girder/assertions.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/pytest_girder/pytest_girder/fixtures.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/pytest_girder/pytest_girder/plugin.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/pytest_girder/pytest_girder/plugin_registry.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/pytest_girder/pytest_girder/utils.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/pytest_girder/pytest_girder/web_client.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/pytest_girder/setup.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/requirements-dev.txt +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/scripts/midas/README.rst +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/scripts/midas/migrate.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/scripts/midas/requirements.txt +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/scripts/midas/walk_girder.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/scripts/midas/walk_midas.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/scripts/publicNames.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/scripts/publicNames.txt +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/scripts/test_names.sh +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/setup.cfg +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/setup.py +0 -0
- {girder-5.0.15.dev18 → girder-5.0.16.dev4}/tox.ini +0 -0
|
@@ -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
|
+
});
|
{girder-5.0.15.dev18 → girder-5.0.16.dev4}/girder/web/tests/spec/plugin_slicer_cli_web.spec.ts
RENAMED
|
@@ -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
|
|
|
@@ -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",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|