diff --git a/CHANGELOG.md b/CHANGELOG.md index 429f274b7..847a88e80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,37 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [3.2.1] - 2023-10-05: Search and Target Path fixes + +### Fixed +WP-297: Fix site search for public and community data (#870) +WP-306: Fix target path regression (#871) + +## [3.2.0] - 2023-10-02: V3 integration improvements; bug fixes + +### Added + +- WP-211: App Form updates to allow target path (#857) +- WP-272: Include username in Onboarding Admin user listing (#861) + +### Changed + +- WP-189 Handle timeout exit code for interactive app jobs (#851) +- WP-163 Compress Archive Path Fix (#846) +- WP-105: create common utils function (#850) +- WP-172: Minimize unit test warnings (#855) +- WP-62: Changed upload function to use TAPIS file insert api (#859) + +### Fixed +- WP-249 Shared Workspace Copy Bug Fix (#858) +- WP-262 Workspace file operations bug fixes (#862) +- WP-276: Fixed Data Files Add button dropdown off-centered UI (#863) +- Quick: handle missing default system; enable work as default system locally (#867) +- WP-52 Jobs View Infinite Scroll Fix (#865) +- WP-228: Fixed sorting for system list (#860) +- WP-209: fix deprecated warnings (part II) (#852) + + ## [3.1.2] - 2023-08-22: Secure user search endpoint ### Fixed @@ -928,7 +959,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [1.0.0] - 2020-02-28 v1.0.0 Production release as of Feb 28, 2020. -[unreleased]: https://github.com/TACC/Core-Portal/compare/v3.1.2...HEAD +[unreleased]: https://github.com/TACC/Core-Portal/compare/v3.2.1...HEAD +[3.2.1]: https://github.com/TACC/Core-Portal/releases/tag/v3.2.1 +[3.2.0]: https://github.com/TACC/Core-Portal/releases/tag/v3.2.0 [3.1.2]: https://github.com/TACC/Core-Portal/releases/tag/v3.1.2 [3.1.1]: https://github.com/TACC/Core-Portal/releases/tag/v3.1.1 [3.1.0]: https://github.com/TACC/Core-Portal/releases/tag/v3.1.0 diff --git a/client/package-lock.json b/client/package-lock.json index f000bf735..98a48ba2e 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -76,6 +76,7 @@ "stylelint": "^14.4.0", "stylelint-config-recommended": "^7.0.0", "stylelint-config-standard": "^25.0.0", + "timekeeper": "^2.3.1", "typescript": "^4.4.3", "vite": "^2.9.16", "weak-key": "^1.0.1" @@ -133,12 +134,13 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "dev": true, "dependencies": { - "@babel/highlight": "^7.18.6" + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" }, "engines": { "node": ">=6.9.0" @@ -184,13 +186,14 @@ } }, "node_modules/@babel/generator": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.0.tgz", - "integrity": "sha512-S1ahxf1gZ2dpoiFgA+ohK9DIpz50bJ0CWs7Zlzb54Z4sG8qmdIrGrVqmy1sAtTVRb+9CU6U8VqT9L0Zj7hxHVg==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", "dev": true, "dependencies": { - "@babel/types": "^7.19.0", + "@babel/types": "^7.23.0", "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" }, "engines": { @@ -297,9 +300,9 @@ } }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "dev": true, "engines": { "node": ">=6.9.0" @@ -318,25 +321,25 @@ } }, "node_modules/@babel/helper-function-name": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", - "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dev": true, "dependencies": { - "@babel/template": "^7.18.10", - "@babel/types": "^7.19.0" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "dev": true, "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -461,30 +464,30 @@ } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "dev": true, "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz", - "integrity": "sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", - "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "dev": true, "engines": { "node": ">=6.9.0" @@ -529,13 +532,13 @@ } }, "node_modules/@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, "engines": { @@ -543,9 +546,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.0.tgz", - "integrity": "sha512-74bEXKX2h+8rrfQUfsBfuZZHzsEs6Eql4pqy/T4Nn6Y9wNPggQOqD6z6pn5Bl8ZfysKouFZT/UXEH94ummEeQw==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -1926,33 +1929,33 @@ } }, "node_modules/@babel/template": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", - "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.18.10", - "@babel/types": "^7.18.10" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.0.tgz", - "integrity": "sha512-4pKpFRDh+utd2mbRC8JLnlsMUii3PMHjpL6a0SZ4NMZy7YFP9aXORxEhdMVOc9CpWtDF09IkciQLEhK7Ml7gRA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.0", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.19.0", - "@babel/types": "^7.19.0", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -1961,13 +1964,13 @@ } }, "node_modules/@babel/types": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.0.tgz", - "integrity": "sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.18.10", - "@babel/helper-validator-identifier": "^7.18.6", + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" }, "engines": { @@ -3082,9 +3085,9 @@ } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", - "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", "dev": true, "engines": { "node": ">=6.0.0" @@ -3100,19 +3103,19 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.11", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", - "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==", + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.15", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz", - "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==", + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", "dev": true, "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "node_modules/@material-ui/core": { @@ -14617,6 +14620,12 @@ "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", "dev": true }, + "node_modules/timekeeper": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/timekeeper/-/timekeeper-2.3.1.tgz", + "integrity": "sha512-LeQRS7/4JcC0PgdSFnfUiStQEdiuySlCj/5SJ18D+T1n9BoY7PxKFfCwLulpHXoLUFr67HxBddQdEX47lDGx1g==", + "dev": true + }, "node_modules/tiny-invariant": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.2.0.tgz", @@ -15354,12 +15363,13 @@ } }, "@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "dev": true, "requires": { - "@babel/highlight": "^7.18.6" + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" } }, "@babel/compat-data": { @@ -15392,13 +15402,14 @@ } }, "@babel/generator": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.0.tgz", - "integrity": "sha512-S1ahxf1gZ2dpoiFgA+ohK9DIpz50bJ0CWs7Zlzb54Z4sG8qmdIrGrVqmy1sAtTVRb+9CU6U8VqT9L0Zj7hxHVg==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", "dev": true, "requires": { - "@babel/types": "^7.19.0", + "@babel/types": "^7.23.0", "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" } }, @@ -15475,9 +15486,9 @@ } }, "@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "dev": true }, "@babel/helper-explode-assignable-expression": { @@ -15490,22 +15501,22 @@ } }, "@babel/helper-function-name": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", - "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dev": true, "requires": { - "@babel/template": "^7.18.10", - "@babel/types": "^7.19.0" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" } }, "@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "dev": true, "requires": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" } }, "@babel/helper-member-expression-to-functions": { @@ -15600,24 +15611,24 @@ } }, "@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "dev": true, "requires": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" } }, "@babel/helper-string-parser": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz", - "integrity": "sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", "dev": true }, "@babel/helper-validator-identifier": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", - "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "dev": true }, "@babel/helper-validator-option": { @@ -15650,20 +15661,20 @@ } }, "@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" } }, "@babel/parser": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.0.tgz", - "integrity": "sha512-74bEXKX2h+8rrfQUfsBfuZZHzsEs6Eql4pqy/T4Nn6Y9wNPggQOqD6z6pn5Bl8ZfysKouFZT/UXEH94ummEeQw==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", "dev": true }, "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { @@ -16587,42 +16598,42 @@ } }, "@babel/template": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", - "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "dev": true, "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.18.10", - "@babel/types": "^7.18.10" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" } }, "@babel/traverse": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.0.tgz", - "integrity": "sha512-4pKpFRDh+utd2mbRC8JLnlsMUii3PMHjpL6a0SZ4NMZy7YFP9aXORxEhdMVOc9CpWtDF09IkciQLEhK7Ml7gRA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.0", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.19.0", - "@babel/types": "^7.19.0", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", "debug": "^4.1.0", "globals": "^11.1.0" } }, "@babel/types": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.0.tgz", - "integrity": "sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", "dev": true, "requires": { - "@babel/helper-string-parser": "^7.18.10", - "@babel/helper-validator-identifier": "^7.18.6", + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" } }, @@ -17394,9 +17405,9 @@ } }, "@jridgewell/resolve-uri": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", - "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", "dev": true }, "@jridgewell/set-array": { @@ -17406,19 +17417,19 @@ "dev": true }, "@jridgewell/sourcemap-codec": { - "version": "1.4.11", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", - "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==", + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", "dev": true }, "@jridgewell/trace-mapping": { - "version": "0.3.15", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz", - "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==", + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", "dev": true, "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "@material-ui/core": { @@ -25859,6 +25870,12 @@ "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", "dev": true }, + "timekeeper": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/timekeeper/-/timekeeper-2.3.1.tgz", + "integrity": "sha512-LeQRS7/4JcC0PgdSFnfUiStQEdiuySlCj/5SJ18D+T1n9BoY7PxKFfCwLulpHXoLUFr67HxBddQdEX47lDGx1g==", + "dev": true + }, "tiny-invariant": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.2.0.tgz", diff --git a/client/package.json b/client/package.json index db805dab0..8313ccab5 100644 --- a/client/package.json +++ b/client/package.json @@ -98,6 +98,7 @@ "stylelint": "^14.4.0", "stylelint-config-recommended": "^7.0.0", "stylelint-config-standard": "^25.0.0", + "timekeeper": "^2.3.1", "typescript": "^4.4.3", "vite": "^2.9.16", "weak-key": "^1.0.1" diff --git a/client/src/components/Applications/AppForm/AppForm.jsx b/client/src/components/Applications/AppForm/AppForm.jsx index 4cb3cfbf9..f197be6cd 100644 --- a/client/src/components/Applications/AppForm/AppForm.jsx +++ b/client/src/components/Applications/AppForm/AppForm.jsx @@ -19,10 +19,14 @@ import { Link } from 'react-router-dom'; import { getSystemName } from 'utils/systems'; import FormSchema from './AppFormSchema'; import { + isTargetPathEmpty, + isTargetPathField, + getInputFieldFromTargetPathField, getQueueMaxMinutes, getMaxMinutesValidation, getNodeCountValidation, getCoresPerNodeValidation, + getTargetPathFieldName, updateValuesForQueue, } from './AppFormUtils'; import DataFilesSelectModal from '../../DataFiles/DataFilesModals/DataFilesSelectModal'; @@ -201,7 +205,7 @@ export const AppSchemaForm = ({ app }) => { const hasCorral = configuration.length && ['corral.tacc.utexas.edu', 'data.tacc.utexas.edu'].some((s) => - defaultHost.endsWith(s) + defaultHost?.endsWith(s) ); return { allocations: matchingExecutionHost @@ -459,17 +463,53 @@ export const AppSchemaForm = ({ app }) => { onSubmit={(values, { setSubmitting, resetForm }) => { const job = cloneDeep(values); - job.fileInputs = Object.entries(job.fileInputs) - .map(([k, v]) => { - // filter out read only inputs. 'FIXED' inputs are tracked as readOnly - if ( - Object.hasOwn(appFields.fileInputs, k) && - appFields.fileInputs[k].readOnly - ) - return; - return { name: k, sourceUrl: v }; - }) - .filter((fileInput) => fileInput && fileInput.sourceUrl); // filter out any empty values + // Transform input field values into format that jobs service wants. + // File Input structure will have 2 fields if target path is required by the app. + // field 1 - has source url + // field 2 - has target path for the source url. + // tapis wants only 1 field with 2 properties - source url and target path. + // The logic below handles that scenario by merging the related fields into 1 field. + job.fileInputs = Object.values( + Object.entries(job.fileInputs) + .map(([k, v]) => { + // filter out read only inputs. 'FIXED' inputs are tracked as readOnly + if ( + Object.hasOwn(appFields.fileInputs, k) && + appFields.fileInputs[k].readOnly + ) + return; + return { + name: k, + sourceUrl: !isTargetPathField(k) ? v : null, + targetDir: isTargetPathField(k) ? v : null, + }; + }) + .filter((v) => v) //filter nulls + .reduce((acc, entry) => { + // merge input field and targetPath fields into one. + const key = getInputFieldFromTargetPathField(entry.name); + if (!acc[key]) { + acc[key] = {}; + } + acc[key]['name'] = key; + acc[key]['sourceUrl'] = + acc[key]['sourceUrl'] ?? entry.sourceUrl; + acc[key]['targetPath'] = + acc[key]['targetPath'] ?? entry.targetDir; + return acc; + }, {}) + ) + .flat() + .filter((fileInput) => fileInput.sourceUrl) // filter out any empty values + .map((fileInput) => { + if (isTargetPathEmpty(fileInput.targetPath)) { + return { + name: fileInput.name, + sourceUrl: fileInput.sourceUrl, + }; + } + return fileInput; + }); job.parameterSet = Object.assign( {}, @@ -559,8 +599,15 @@ export const AppSchemaForm = ({ app }) => { {Object.entries(appFields.fileInputs).map( ([name, field]) => { - // TODOv3 handle fileInputArrays https://jira.tacc.utexas.edu/browse/TV3-81 - return ( + // TODOv3 handle fileInputArrays https://jira.tacc.utexas.edu/browse/WP-81 + return isTargetPathField(name) ? ( + + ) : ( { ) .map((q) => q.name) .sort() - .map((queueName) => ( - - )) + .map((queueName) => + app.definition.notes.queueFilter ? ( + app.definition.notes.queueFilter.includes( + queueName + ) && ( + + ) + ) : ( + + ) + ) .sort()} )} diff --git a/client/src/components/Applications/AppForm/AppForm.test.js b/client/src/components/Applications/AppForm/AppForm.test.js index d09920342..2a6b119df 100644 --- a/client/src/components/Applications/AppForm/AppForm.test.js +++ b/client/src/components/Applications/AppForm/AppForm.test.js @@ -1,5 +1,6 @@ import React from 'react'; -import { render, waitFor } from '@testing-library/react'; +import { fireEvent, render, waitFor } from '@testing-library/react'; +import '@testing-library/jest-dom/extend-expect'; import { Provider } from 'react-redux'; import configureStore from 'redux-mock-store'; import { BrowserRouter } from 'react-router-dom'; @@ -15,11 +16,16 @@ import { appTrayExpectedFixture, } from '../../../redux/sagas/fixtures/apptray.fixture'; import { initialAppState } from '../../../redux/reducers/apps.reducers'; -import { helloWorldAppFixture } from './fixtures/AppForm.app.fixture'; +import { + helloWorldAppFixture, + helloWorldAppSubmissionPayloadFixture, +} from './fixtures/AppForm.app.fixture'; import systemsFixture from '../../DataFiles/fixtures/DataFiles.systems.fixture'; import { projectsFixture } from '../../../redux/sagas/fixtures/projects.fixture'; import '@testing-library/jest-dom/extend-expect'; +import timekeeper from 'timekeeper'; +const frozenDate = '2023-10-01'; const mockStore = configureStore(); const initialMockState = { allocations: allocationsFixture, @@ -56,6 +62,11 @@ function renderAppSchemaFormComponent(store, app) { } describe('AppSchemaForm', () => { + beforeAll(() => { + // Lock Time + timekeeper.freeze(new Date(frozenDate)); + }); + it('renders the AppSchemaForm', async () => { const store = mockStore({ ...initialMockState, @@ -257,6 +268,162 @@ describe('AppSchemaForm', () => { expect(getByText(/Activate your Application Name license/)).toBeDefined(); }); }); + + it('job submission with file input mode FIXED', async () => { + const store = mockStore({ + ...initialMockState, + }); + + const { getByText, container } = renderAppSchemaFormComponent(store, { + ...helloWorldAppFixture, + definition: { + ...helloWorldAppFixture.definition, + jobAttributes: { + ...helloWorldAppFixture.definition.jobAttributes, + fileInputs: [ + { + name: 'File to copy', + description: 'A fixed file used by the app', + inputMode: 'FIXED', + autoMountLocal: true, + sourceUrl: + 'tapis://corral-tacc/tacc/aci/secure-test/rallyGolf.jpg', + targetPath: 'rallyGolf.jpg', + }, + ], + }, + }, + }); + const hiddenFileInput = container.querySelector( + 'input[name="fileInputs.File to copy"]' + ); + // FIXED fields are still shown in UI but not submitted. + expect(hiddenFileInput).toBeInTheDocument(); + + const submitButton = getByText(/Submit/); + fireEvent.click(submitButton); + const payload = { + ...helloWorldAppSubmissionPayloadFixture, + job: { + ...helloWorldAppSubmissionPayloadFixture.job, + name: 'hello-world-0.0.1_' + frozenDate + 'T00:00:00', + }, + }; + + await waitFor(() => { + expect(store.getActions()).toEqual([ + { type: 'GET_SYSTEM_MONITOR' }, + { type: 'SUBMIT_JOB', payload: payload }, + ]); + }); + }); + + it('job submission with file input hidden', async () => { + const store = mockStore({ + ...initialMockState, + }); + + const { getByText, container } = renderAppSchemaFormComponent(store, { + ...helloWorldAppFixture, + definition: { + ...helloWorldAppFixture.definition, + jobAttributes: { + ...helloWorldAppFixture.definition.jobAttributes, + fileInputs: [ + { + name: 'File to copy', + description: 'A fixed file used by the app', + inputMode: 'REQUIRED', + autoMountLocal: true, + sourceUrl: + 'tapis://corral-tacc/tacc/aci/secure-test/rallyGolf.jpg', + targetPath: 'rallyGolf.jpg', + notes: { + isHidden: true, + }, + }, + ], + }, + }, + }); + + const hiddenFileInput = container.querySelector( + 'input[name="fileInputs.File to copy"]' + ); + expect(hiddenFileInput).not.toBeInTheDocument(); + + const submitButton = getByText(/Submit/); + fireEvent.click(submitButton); + const payload = { + ...helloWorldAppSubmissionPayloadFixture, + job: { + ...helloWorldAppSubmissionPayloadFixture.job, + name: 'hello-world-0.0.1_' + frozenDate + 'T00:00:00', + }, + }; + + await waitFor(() => { + expect(store.getActions()).toEqual([ + { type: 'GET_SYSTEM_MONITOR' }, + { type: 'SUBMIT_JOB', payload: payload }, + ]); + }); + }); + + it('job submission with custom target path', async () => { + const store = mockStore({ + ...initialMockState, + }); + const { getByText, container } = renderAppSchemaFormComponent(store, { + ...helloWorldAppFixture, + definition: { + ...helloWorldAppFixture.definition, + notes: { + ...helloWorldAppFixture.definition.notes, + showTargetPath: true, + }, + }, + }); + + const fileInput = container.querySelector( + 'input[name="fileInputs.File to modify"]' + ); + const file = 'tapis://foo/bar.txt'; + const targetPathForFile = 'baz.txt'; + fireEvent.change(fileInput, { target: { value: file } }); + const targetPathInput = container.querySelector( + 'input[name="fileInputs._TargetPath_File to modify"]' + ); + fireEvent.change(targetPathInput, { target: { value: targetPathForFile } }); + + const submitButton = getByText(/Submit/); + fireEvent.click(submitButton); + const payload = { + ...helloWorldAppSubmissionPayloadFixture, + job: { + ...helloWorldAppSubmissionPayloadFixture.job, + fileInputs: [ + { + name: 'File to modify', + sourceUrl: file, + targetPath: targetPathForFile, + }, + ], + name: 'hello-world-0.0.1_' + frozenDate + 'T00:00:00', + }, + }; + + await waitFor(() => { + expect(store.getActions()).toEqual([ + { type: 'GET_SYSTEM_MONITOR' }, + { type: 'SUBMIT_JOB', payload: payload }, + ]); + }); + }); + + afterAll(() => { + timekeeper.reset(); + }); }); describe('AppDetail', () => { @@ -275,3 +442,58 @@ describe('AppDetail', () => { ).toBeDefined(); }); }); + +const mockAppWithQueueFilter = { + ...helloWorldAppFixture, + definition: { + ...helloWorldAppFixture.definition, + notes: { + ...helloWorldAppFixture.definition.notes, + queueFilter: ['rtx', 'small'], + }, + }, +}; + +const mockAppWithoutQueueFilter = { + ...helloWorldAppFixture, + definition: { + ...helloWorldAppFixture.definition, + notes: { + ...helloWorldAppFixture.definition.notes, + queueFilter: null, + }, + }, +}; + +describe('AppSchemaForm queueFilter tests', () => { + it('renders only the queues specified in the queueFilter', () => { + const { container } = renderAppSchemaFormComponent( + mockStore(initialMockState), + mockAppWithQueueFilter + ); + + const targetDropdown = container.querySelector( + 'select[name="execSystemLogicalQueue"]' + ); + const options = Array.from(targetDropdown.querySelectorAll('option')); + expect(options).toHaveLength(2); + expect(options[0].textContent).toBe('rtx'); + expect(options[1].textContent).toBe('small'); + }); + + it('renders all queues when no queueFilter is present', () => { + const { container } = renderAppSchemaFormComponent( + mockStore(initialMockState), + mockAppWithoutQueueFilter + ); + + const targetDropdown = container.querySelector( + 'select[name="execSystemLogicalQueue"]' + ); + const options = Array.from(targetDropdown.querySelectorAll('option')); + expect(options).toHaveLength(3); + expect(options[0].textContent).toBe('development'); + expect(options[1].textContent).toBe('rtx'); + expect(options[2].textContent).toBe('small'); + }); +}); diff --git a/client/src/components/Applications/AppForm/AppFormSchema.js b/client/src/components/Applications/AppForm/AppFormSchema.js index ab9a98d09..b3f26ba09 100644 --- a/client/src/components/Applications/AppForm/AppFormSchema.js +++ b/client/src/components/Applications/AppForm/AppFormSchema.js @@ -1,4 +1,8 @@ import * as Yup from 'yup'; +import { + checkAndSetDefaultTargetPath, + getTargetPathFieldName, +} from './AppFormUtils'; const FormSchema = (app) => { const appFields = { @@ -97,13 +101,15 @@ const FormSchema = (app) => { } ); + // The default is to not show target path for file inputs. + const showTargetPathForFileInputs = + app.definition.notes.showTargetPath ?? false; (app.definition.jobAttributes.fileInputs || []).forEach((i) => { const input = i; - /* TODOv3 consider hidden file inputs https://jira.tacc.utexas.edu/browse/WP-102 - if (input.name.startsWith('_') || !input.value.visible) { // TODOv3 visible or hidden - return; - } - */ + if (input.notes?.isHidden) { + return; + } + const field = { label: input.name, description: input.description, @@ -131,6 +137,33 @@ const FormSchema = (app) => { input.sourceUrl === null || typeof input.sourceUrl === 'undefined' ? '' : input.sourceUrl; + + // Add targetDir for all sourceUrl + if (!showTargetPathForFileInputs) { + return; + } + const targetPathName = getTargetPathFieldName(input.name); + appFields.schema.fileInputs[targetPathName] = Yup.string(); + appFields.schema.fileInputs[targetPathName] = appFields.schema.fileInputs[ + targetPathName + ].matches( + /^tapis:\/\//g, + "Input file Target Directory must be a valid Tapis URI, starting with 'tapis://'" + ); + + appFields.schema.fileInputs[targetPathName] = false; + appFields.fileInputs[targetPathName] = { + label: 'Target Path for ' + input.name, + description: + 'The name of the ' + + input.name + + ' after it is copied to the target system, but before the job is run. Leave this value blank to just use the name of the input file.', + required: false, + readOnly: field.readOnly, + type: 'text', + }; + appFields.defaults.fileInputs[targetPathName] = + checkAndSetDefaultTargetPath(input.targetPath); }); return appFields; }; diff --git a/client/src/components/Applications/AppForm/AppFormUtils.js b/client/src/components/Applications/AppForm/AppFormUtils.js index 812fe3379..fcaa7910c 100644 --- a/client/src/components/Applications/AppForm/AppFormUtils.js +++ b/client/src/components/Applications/AppForm/AppFormUtils.js @@ -1,6 +1,8 @@ import * as Yup from 'yup'; import { getSystemName } from 'utils/systems'; +export const TARGET_PATH_FIELD_PREFIX = '_TargetPath_'; + export const getQueueMaxMinutes = (app, queueName) => { return app.exec_sys.batchLogicalQueues.find((q) => q.name === queueName) .maxMinutes; @@ -165,3 +167,72 @@ export const updateValuesForQueue = (app, values) => { return updatedValues; }; + +/** + * Get the field name used for target path in AppForm + * + * @function + * @param {String} inputFieldName + * @returns {String} field Name prefixed with target path + */ +export const getTargetPathFieldName = (inputFieldName) => { + return TARGET_PATH_FIELD_PREFIX + inputFieldName; +}; + +/** + * Whether a field name is a system defined field for Target Path + * + * @function + * @param {String} inputFieldName + * @returns {String} field Name suffixed with target path + */ +export const isTargetPathField = (inputFieldName) => { + return inputFieldName && inputFieldName.startsWith(TARGET_PATH_FIELD_PREFIX); +}; + +/** + * From target path field name, derive the original input field name. + * + * @function + * @param {String} targetPathFieldName + * @returns {String} actual field name + */ +export const getInputFieldFromTargetPathField = (targetPathFieldName) => { + return targetPathFieldName.replace(TARGET_PATH_FIELD_PREFIX, ''); +}; + +/** + * Check if targetPath is empty on input field + * + * @function + * @param {String} targetPathFieldValue + * @returns {boolean} if target path is empty + */ +export const isTargetPathEmpty = (targetPathFieldValue) => { + if (targetPathFieldValue === null || targetPathFieldValue === undefined) { + return true; + } + + targetPathFieldValue = targetPathFieldValue.trim(); + + if (targetPathFieldValue.trim() === '') { + return true; + } + + return false; +}; + +/** + * Sets the default value if target path is not set. + * + * @function + * @param {String} targetPathFieldValue + * @returns {String} target path value + */ +export const checkAndSetDefaultTargetPath = (targetPathFieldValue) => { + if (isTargetPathEmpty(targetPathFieldValue)) { + return '*'; + } + + return targetPathFieldValue; +}; diff --git a/client/src/components/Applications/AppForm/fixtures/AppForm.app.fixture.js b/client/src/components/Applications/AppForm/fixtures/AppForm.app.fixture.js index 5aa718ba4..1458448ea 100644 --- a/client/src/components/Applications/AppForm/fixtures/AppForm.app.fixture.js +++ b/client/src/components/Applications/AppForm/fixtures/AppForm.app.fixture.js @@ -237,3 +237,49 @@ export const helloWorldAppFixture = { type: null, }, }; + +export const helloWorldAppSubmissionPayloadFixture = { + job: { + fileInputs: [], + parameterSet: { + appArgs: [ + { + name: 'Greeting', + arg: 'hello', + }, + { + name: 'Target', + arg: 'world', + }, + { + name: 'Sleep Time', + arg: '30', + }, + ], + containerArgs: [], + schedulerOptions: [ + { + name: 'TACC Allocation', + description: 'The TACC allocation associated with this job execution', + include: true, + arg: '-A TACC-ACI', + }, + ], + envVariables: [], + }, + name: 'hello-world-0.0.1', + nodeCount: 1, + coresPerNode: 1, + maxMinutes: 10, + archiveSystemId: 'frontera', + archiveSystemDir: + 'HOST_EVAL($HOME)/tapis-jobs-archive/${JobCreateDate}/${JobName}-${JobUUID}', + archiveOnAppError: true, + appId: 'hello-world', + appVersion: '0.0.1', + execSystemId: 'frontera', + execSystemLogicalQueue: 'development', + }, + licenseType: null, + isInteractive: false, +}; diff --git a/client/src/components/DataFiles/DataFilesModals/DataFilesCopyModal.jsx b/client/src/components/DataFiles/DataFilesModals/DataFilesCopyModal.jsx index bebffdf3f..c4cd26d68 100644 --- a/client/src/components/DataFiles/DataFilesModals/DataFilesCopyModal.jsx +++ b/client/src/components/DataFiles/DataFilesModals/DataFilesCopyModal.jsx @@ -142,7 +142,7 @@ const DataFilesCopyModal = React.memo(() => { Destination { const onOpened = () => { fetchListing({ - api: 'tapis', - scheme: 'private', - system: selectedSystem.system, - path: `${selectedSystem.homeDir || ''}`, + ...params, }); }; @@ -68,7 +65,7 @@ const DataFilesMoveModal = React.memo(() => { setDisabled(true); move({ destSystem: system, - destPath: path, + destPath: path || '/', callback: reloadPage, }); }, diff --git a/client/src/components/DataFiles/DataFilesModals/DataFilesSelectModal.jsx b/client/src/components/DataFiles/DataFilesModals/DataFilesSelectModal.jsx index eaa7d8168..f019d8fdd 100644 --- a/client/src/components/DataFiles/DataFilesModals/DataFilesSelectModal.jsx +++ b/client/src/components/DataFiles/DataFilesModals/DataFilesSelectModal.jsx @@ -72,7 +72,7 @@ const DataFilesSelectModal = ({ isOpen, toggle, onSelect }) => { Select Input { payload: { operation: 'upload', props: {} }, }); }; - const err = useSelector((state) => state.files.error.FilesListing); + const hasError = useSelector((state) => state.files.error.FilesListing); const { api, scheme } = useSelector( (state) => state.files.params.FilesListing ); @@ -60,7 +60,7 @@ const DataFilesAddButton = ({ readOnly }) => { const disabled = readOnly || - err !== false || + hasError !== false || api !== 'tapis' || (scheme !== 'private' && scheme !== 'projects'); diff --git a/client/src/components/DataFiles/DataFilesSidebar/DataFilesSidebar.scss b/client/src/components/DataFiles/DataFilesSidebar/DataFilesSidebar.scss index b343e4381..3b5cd538b 100644 --- a/client/src/components/DataFiles/DataFilesSidebar/DataFilesSidebar.scss +++ b/client/src/components/DataFiles/DataFilesSidebar/DataFilesSidebar.scss @@ -12,7 +12,7 @@ padding-left: var(--horizontal-buffer); } #data-files-add { - width: 140px; + width: 174px; } .data-files-nav { @@ -24,27 +24,28 @@ .dropdown-menu { border-color: var(--global-color-accent--normal); border-radius: 0; - margin-top: 11px; - padding: 0; + margin: 11px 3px 0; width: 200px; vertical-align: top; } .dropdown-menu::before { position: absolute; top: -10px; - left: 65px; + left: 67px; border-right: 10px solid transparent; border-bottom: 10px solid var(--global-color-accent--normal); border-left: 10px solid transparent; + margin-left: 20px; content: ''; } .dropdown-menu::after { position: absolute; top: -9px; - left: 66px; + left: 68px; border-right: 9px solid transparent; border-bottom: 9px solid #ffffff; border-left: 9px solid transparent; + margin-left: 20px; content: ''; } diff --git a/client/src/components/DataFiles/DataFilesStatus/DataFilesStatus.jsx b/client/src/components/DataFiles/DataFilesStatus/DataFilesStatus.jsx index f7756c7bf..5a747c3e0 100644 --- a/client/src/components/DataFiles/DataFilesStatus/DataFilesStatus.jsx +++ b/client/src/components/DataFiles/DataFilesStatus/DataFilesStatus.jsx @@ -38,17 +38,18 @@ const OPERATION_MAP = { case 'upload': case 'move': case 'copy': { - const destPath = response.path.split('/').slice(0, -1).join('/'); - const projectName = findProjectTitle(projectList, response.systemId); + const { path, systemId, source } = response; + const destPath = path.split('/').slice(0, -1).join('/'); + const projectName = findProjectTitle(projectList, systemId); let op = mappedOp; if (mappedOp === 'copied') { const srcSystem = - response.source.split('/')[0] === 'https:' - ? response.source.split('/')[7] - : response.source.split('/')[2]; - const destSystem = response.systemId; + source.split('/')[0] === 'https:' + ? source.split('/')[7] + : source.split('/')[2]; + const destSystem = systemId; if (srcSystem !== destSystem) { op = 'started copying'; } @@ -62,7 +63,7 @@ const OPERATION_MAP = { } else { dest = destPath === '/' || destPath === '' - ? `${findSystemDisplayName(systemList, response.systemId)}/` + ? `${findSystemDisplayName(systemList, systemId)}/` : destPath; } diff --git a/client/src/components/DataFiles/DataFilesSystemSelector/DataFilesSystemSelector.jsx b/client/src/components/DataFiles/DataFilesSystemSelector/DataFilesSystemSelector.jsx index 4c1fc721a..55a477207 100644 --- a/client/src/components/DataFiles/DataFilesSystemSelector/DataFilesSystemSelector.jsx +++ b/client/src/components/DataFiles/DataFilesSystemSelector/DataFilesSystemSelector.jsx @@ -5,7 +5,7 @@ import { DropdownSelector } from '_common'; import styles from './DataFilesSystemSelector.module.scss'; const DataFilesSystemSelector = ({ - systemId, + systemAndHomeDirId, section, disabled, operation, @@ -17,11 +17,12 @@ const DataFilesSystemSelector = ({ (state) => state.systems.storage.configuration ); const modalProps = useSelector((state) => state.files.modalProps[operation]); - const findSystem = (id) => + const findSystem = (systemAndHomeDirPath) => systemList.find( - (system) => `${system.system}${system.homeDir || ''}` === id + (system) => + `${system.system}${system.homeDir || ''}` === systemAndHomeDirPath ); - const [selectedSystem, setSelectedSystem] = useState(systemId); + const [selectedSystem, setSelectedSystem] = useState(systemAndHomeDirId); const openSystem = useCallback( (event) => { @@ -69,7 +70,7 @@ const DataFilesSystemSelector = ({ }; useEffect(() => { - setSelectedSystem(systemId); + setSelectedSystem(systemAndHomeDirId); }, []); const dropdownSystems = systemList.filter( @@ -111,7 +112,7 @@ const DataFilesSystemSelector = ({ }; DataFilesSystemSelector.propTypes = { - systemId: PropTypes.string, + systemAndHomeDirId: PropTypes.string, section: PropTypes.string.isRequired, disabled: PropTypes.bool, operation: PropTypes.string.isRequired, @@ -120,7 +121,7 @@ DataFilesSystemSelector.propTypes = { }; DataFilesSystemSelector.defaultProps = { - systemId: '', + systemAndHomeDirId: '', disabled: false, showProjects: false, excludedSystems: [], diff --git a/client/src/components/Jobs/Jobs.jsx b/client/src/components/Jobs/Jobs.jsx index bbef04a96..1945d1bf7 100644 --- a/client/src/components/Jobs/Jobs.jsx +++ b/client/src/components/Jobs/Jobs.jsx @@ -75,11 +75,14 @@ function JobsView({ const infiniteScrollCallback = useCallback(() => { // TODOv3: dropV2Jobs const dispatchType = version === 'v3' ? 'GET_JOBS' : 'GET_V2_JOBS'; - dispatch({ - type: dispatchType, - params: { offset: jobs.length, queryString: query.query_string || '' }, - }); - }, [dispatch, jobs, query.query_string]); + + if (!isJobLoading) { + dispatch({ + type: dispatchType, + params: { offset: jobs.length, queryString: query.query_string || '' }, + }); + } + }, [dispatch, jobs, query.query_string, isJobLoading]); const jobDetailLink = useCallback( ({ @@ -217,22 +220,20 @@ function JobsView({ disabled={isJobLoading || isNotificationLoading} /> )} -
- - {noDataText} - - } - getRowProps={rowProps} - columnMemoProps={[version]} /* TODOv3: dropV2Jobs. */ - /> -
+ + {noDataText} + + } + getRowProps={rowProps} + columnMemoProps={[version]} /* TODOv3: dropV2Jobs. */ + /> ); } diff --git a/client/src/components/Jobs/Jobs.test.js b/client/src/components/Jobs/Jobs.test.js index ea30d1934..05dcb53f6 100644 --- a/client/src/components/Jobs/Jobs.test.js +++ b/client/src/components/Jobs/Jobs.test.js @@ -1,5 +1,5 @@ import React from 'react'; -import { render } from '@testing-library/react'; +import { fireEvent, render, waitFor } from '@testing-library/react'; import Jobs from './Jobs'; import { createMemoryHistory } from 'history'; import { default as jobsList } from './Jobs.fixture'; @@ -135,4 +135,35 @@ describe('Jobs View', () => { const { getByText } = renderJobsComponent(store, history); expect(getByText(/unable to retrieve your jobs/)).toBeDefined(); }); + + it('should dispatch another get jobs event on scroll with proper offset', async () => { + const store = mockStore({ + notifications, + jobs: { ...jobs, list: jobsList }, + workbench: { ...workbench, config: { hideDataFiles: false } }, + apps: { + appIcons: {}, + }, + }); + + const { container } = render( + + + + + + ); + + const scrollContainer = container.querySelector('.table-container'); + + fireEvent.scroll(scrollContainer, { target: { scrollTop: 1 } }); + + expect(store.getActions()).toEqual([ + { type: 'GET_JOBS', params: { offset: 0, queryString: '' } }, + { + type: 'GET_JOBS', + params: { offset: jobsList.length, queryString: '' }, + }, + ]); + }); }); diff --git a/client/src/components/Jobs/JobsSessionModal/JobsSessionModal.jsx b/client/src/components/Jobs/JobsSessionModal/JobsSessionModal.jsx index bb0827877..9fbd2e06f 100644 --- a/client/src/components/Jobs/JobsSessionModal/JobsSessionModal.jsx +++ b/client/src/components/Jobs/JobsSessionModal/JobsSessionModal.jsx @@ -4,7 +4,12 @@ import { bool, func, string } from 'prop-types'; import './JobsSessionModal.global.scss'; import styles from './JobsSessionModal.module.scss'; -const JobsSessionModal = ({ isOpen, toggle, interactiveSessionLink }) => { +const JobsSessionModal = ({ + isOpen, + toggle, + interactiveSessionLink, + message, +}) => { return ( { Click the button below to connect to the interactive session. + {message && {message}} To end the job, quit the application within the session. Files may take some time to appear in the output location after the diff --git a/client/src/components/Jobs/JobsStatus/JobsStatus.jsx b/client/src/components/Jobs/JobsStatus/JobsStatus.jsx index e162a3a77..4f5ec2291 100644 --- a/client/src/components/Jobs/JobsStatus/JobsStatus.jsx +++ b/client/src/components/Jobs/JobsStatus/JobsStatus.jsx @@ -72,6 +72,7 @@ function JobsStatus({ status, fancy, jobUuid }) { const notifs = useSelector((state) => state.notifications.list.notifs); let interactiveSessionLink; + let message; const jobConcluded = isTerminalState(status) || status === 'ARCHIVING'; @@ -85,6 +86,7 @@ function JobsStatus({ status, fancy, jobUuid }) { ); const notif = interactiveNotifs.find((n) => n.extra.uuid === jobUuid); interactiveSessionLink = notif ? notif.action_link : null; + message = notif ? notif.message : null; } return ( @@ -109,6 +111,7 @@ function JobsStatus({ status, fancy, jobUuid }) { toggle={toggleModal} isOpen={modal} interactiveSessionLink={interactiveSessionLink} + message={message} /> )} diff --git a/client/src/components/ManageAccount/ManageAccountTables.jsx b/client/src/components/ManageAccount/ManageAccountTables.jsx index 8ad1abbd4..ad360f725 100644 --- a/client/src/components/ManageAccount/ManageAccountTables.jsx +++ b/client/src/components/ManageAccount/ManageAccountTables.jsx @@ -65,8 +65,6 @@ export const ProfileInformation = () => { { Header: 'Institution', accessor: 'institution' }, { Header: 'Country of Residence', accessor: 'country' }, { Header: 'Country of Citizenship', accessor: 'citizenship' }, - { Header: 'Ethnicity', accessor: 'ethnicity' }, - { Header: 'Gender', accessor: 'gender' }, ], [] ); diff --git a/client/src/components/ManageAccount/tests/ManageAccountTables.test.js b/client/src/components/ManageAccount/tests/ManageAccountTables.test.js index 3a655aaae..e10515297 100644 --- a/client/src/components/ManageAccount/tests/ManageAccountTables.test.js +++ b/client/src/components/ManageAccount/tests/ManageAccountTables.test.js @@ -21,12 +21,6 @@ const dummyState = { }, data: { demographics: { - ethnicity: 'Asian', - gender: 'Male', - bio: '', - website: 'http://owais.io', - orcid_id: 'test', - professional_level: 'Staff (support, administration, etc)', username: 'ojamil', email: 'ojamil@tacc.utexas.edu', firstName: 'Owais', @@ -77,8 +71,6 @@ describe('Profile Information Component', () => { 'Institution', 'Country of Residence', 'Country of Citizenship', - 'Ethnicity', - 'Gender', ]; headings.forEach((heading) => { expect(getByText(heading)).toBeInTheDocument(); diff --git a/client/src/components/Onboarding/OnboardingAdmin.jsx b/client/src/components/Onboarding/OnboardingAdmin.jsx index e5397b93c..73f8508e7 100644 --- a/client/src/components/Onboarding/OnboardingAdmin.jsx +++ b/client/src/components/Onboarding/OnboardingAdmin.jsx @@ -120,6 +120,8 @@ const OnboardingAdminListUser = ({ user, viewLogCallback }) => { {index === 0 && ( {`${user.firstName} ${user.lastName}`} +
+ {user.username} )} diff --git a/client/src/components/Onboarding/OnboardingAdmin.module.scss b/client/src/components/Onboarding/OnboardingAdmin.module.scss index ad4358e4a..3b7515b4c 100644 --- a/client/src/components/Onboarding/OnboardingAdmin.module.scss +++ b/client/src/components/Onboarding/OnboardingAdmin.module.scss @@ -87,6 +87,12 @@ background-color: #c6c6c61a; } +.username { + display: inline-block; /* needed to make margin-top work with span */ + margin-top: 5px; /* adjust value as needed to create more space between fullname and username */ + font-weight: bold; +} + /* HACK: This selector has knowledge of sibling component's internal markup */ /* FAQ: Because we cannot pass `className`to via */ /* FAQ: Because has a superfluous root element */ diff --git a/client/src/components/Onboarding/OnboardingAdmin.test.js b/client/src/components/Onboarding/OnboardingAdmin.test.js index 644b3a3c5..7222104c5 100644 --- a/client/src/components/Onboarding/OnboardingAdmin.test.js +++ b/client/src/components/Onboarding/OnboardingAdmin.test.js @@ -29,5 +29,6 @@ describe('Onboarding Admin View', () => { const { getByText } = renderOnboardingAdminComponent(store); expect(getByText(/First Last/)).toBeDefined(); + expect(getByText(/username/)).toBeDefined(); }); }); diff --git a/client/src/components/_common/InfiniteScrollTable/InfiniteScrollTable.jsx b/client/src/components/_common/InfiniteScrollTable/InfiniteScrollTable.jsx index f8496eeb8..a3bbe85e5 100644 --- a/client/src/components/_common/InfiniteScrollTable/InfiniteScrollTable.jsx +++ b/client/src/components/_common/InfiniteScrollTable/InfiniteScrollTable.jsx @@ -62,51 +62,60 @@ const InfiniteScrollTable = ({ useTable({ columns, data }); const onScroll = ({ target }) => { - const bottom = - target.scrollHeight - target.scrollTop === target.clientHeight; + const scrollbarHeight = target.offsetHeight - target.clientHeight; + const clientRectHeight = target.getBoundingClientRect().height; + const clientCalcHeight = clientRectHeight - scrollbarHeight; + const difference = Math.floor(target.scrollHeight - target.scrollTop); + + const bottom = difference <= clientCalcHeight; + if (bottom && target.scrollTop > 0) { onInfiniteScroll(tableData.length); } }; return ( - - - {headerGroups.map((headerGroup) => ( - - {headerGroup.headers.map((column) => ( - - ))} - - ))} - - - {rows.map((row) => { - prepareRow(row); - return ( - - {row.cells.map((cell) => { - return ( - - ); - })} +
+
{column.render('Header')}
- {cell.render('Cell')} -
+ + {headerGroups.map((headerGroup) => ( + + {headerGroup.headers.map((column) => ( + + ))} - ); - })} - - - -
{column.render('Header')}
+ ))} + + + {rows.map((row) => { + prepareRow(row); + return ( + + {row.cells.map((cell) => { + return ( + + {cell.render('Cell')} + + ); + })} + + ); + })} + + + + + ); }; diff --git a/client/src/components/_common/InfiniteScrollTable/InfiniteScrollTable.scss b/client/src/components/_common/InfiniteScrollTable/InfiniteScrollTable.scss index 55b98d918..4361f7586 100644 --- a/client/src/components/_common/InfiniteScrollTable/InfiniteScrollTable.scss +++ b/client/src/components/_common/InfiniteScrollTable/InfiniteScrollTable.scss @@ -79,3 +79,8 @@ width: 100%; } } + +.table-container { + height: 100%; + overflow: scroll; +} diff --git a/client/src/redux/sagas/datafiles.sagas.js b/client/src/redux/sagas/datafiles.sagas.js index 730a63c44..2ef66a565 100644 --- a/client/src/redux/sagas/datafiles.sagas.js +++ b/client/src/redux/sagas/datafiles.sagas.js @@ -254,7 +254,7 @@ export function* renameFile(action) { action.payload.api, action.payload.scheme, file.system, - file.path, + '/' + file.path, action.payload.newName ); yield put({ diff --git a/client/src/redux/sagas/systemMonitor.sagas.js b/client/src/redux/sagas/systemMonitor.sagas.js index f5ee638d0..f29c29bb6 100644 --- a/client/src/redux/sagas/systemMonitor.sagas.js +++ b/client/src/redux/sagas/systemMonitor.sagas.js @@ -7,6 +7,9 @@ function* getSystemMonitor(action) { const result = yield call(fetchUtil, { url: '/api/system-monitor/', }); + + result.sort((a, b) => a.display_name.localeCompare(b.display_name)); + yield put({ type: 'SYSTEM_MONITOR_SUCCESS', payload: result }); } catch (error) { yield put({ diff --git a/server/conftest.py b/server/conftest.py index 361e77367..c27ca68ca 100644 --- a/server/conftest.py +++ b/server/conftest.py @@ -117,7 +117,7 @@ def agave_storage_system_mock(): @pytest.fixture -def agave_file_mock(): +def tapis_file_mock(): with open(os.path.join(settings.BASE_DIR, 'fixtures/agave/files/file.json')) as f: yield json.load(f) diff --git a/server/poetry.lock b/server/poetry.lock index 5f746b1be..aaf7d1064 100644 --- a/server/poetry.lock +++ b/server/poetry.lock @@ -787,78 +787,65 @@ pyflakes = ">=3.0.0,<3.1.0" [[package]] name = "gevent" -version = "22.10.2" +version = "23.9.1" description = "Coroutine-based network library" optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5" -files = [ - {file = "gevent-22.10.2-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:97cd42382421779f5d82ec5007199e8a84aa288114975429e4fd0a98f2290f10"}, - {file = "gevent-22.10.2-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:1e1286a76f15b5e15f1e898731d50529e249529095a032453f2c101af3fde71c"}, - {file = "gevent-22.10.2-cp27-cp27m-win32.whl", hash = "sha256:59b47e81b399d49a5622f0f503c59f1ce57b7705306ea0196818951dfc2f36c8"}, - {file = "gevent-22.10.2-cp27-cp27m-win_amd64.whl", hash = "sha256:1d543c9407a1e4bca11a8932916988cfb16de00366de5bf7bc9e7a3f61e60b18"}, - {file = "gevent-22.10.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:4e2f008c82dc54ec94f4de12ca6feea60e419babb48ec145456907ae61625aa4"}, - {file = "gevent-22.10.2-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:990d7069f14dc40674e0d5cb43c68fd3bad8337048613b9bb94a0c4180ffc176"}, - {file = "gevent-22.10.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f23d0997149a816a2a9045af29c66f67f405a221745b34cefeac5769ed451db8"}, - {file = "gevent-22.10.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b43d500d7d3c0e03070dee813335bb5315215aa1cf6a04c61093dfdd718640b3"}, - {file = "gevent-22.10.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b68f4c9e20e47ad49fe797f37f91d5bbeace8765ce2707f979a8d4ec197e4d"}, - {file = "gevent-22.10.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1f001cac0ba8da76abfeb392a3057f81fab3d67cc916c7df8ea977a44a2cc989"}, - {file = "gevent-22.10.2-cp310-cp310-win_amd64.whl", hash = "sha256:3b7eae8a0653ba95a224faaddf629a913ace408edb67384d3117acf42d7dcf89"}, - {file = "gevent-22.10.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8f2477e7b0a903a01485c55bacf2089110e5f767014967ba4b287ff390ae2638"}, - {file = "gevent-22.10.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ddaa3e310a8f1a45b5c42cf50b54c31003a3028e7d4e085059090ea0e7a5fddd"}, - {file = "gevent-22.10.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:98bc510e80f45486ef5b806a1c305e0e89f0430688c14984b0dbdec03331f48b"}, - {file = "gevent-22.10.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:877abdb3a669576b1d51ce6a49b7260b2a96f6b2424eb93287e779a3219d20ba"}, - {file = "gevent-22.10.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d21ad79cca234cdbfa249e727500b0ddcbc7adfff6614a96e6eaa49faca3e4f2"}, - {file = "gevent-22.10.2-cp311-cp311-win_amd64.whl", hash = "sha256:1e955238f59b2947631c9782a713280dd75884e40e455313b5b6bbc20b92ff73"}, - {file = "gevent-22.10.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:5aa99e4882a9e909b4756ee799c6fa0f79eb0542779fad4cc60efa23ec1b2aa8"}, - {file = "gevent-22.10.2-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:d82081656a5b9a94d37c718c8646c757e1617e389cdc533ea5e6a6f0b8b78545"}, - {file = "gevent-22.10.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54f4bfd74c178351a4a05c5c7df6f8a0a279ff6f392b57608ce0e83c768207f9"}, - {file = "gevent-22.10.2-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ff3796692dff50fec2f381b9152438b221335f557c4f9b811f7ded51b7a25a1"}, - {file = "gevent-22.10.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f01c9adbcb605364694b11dcd0542ec468a29ac7aba2fb5665dc6caf17ba4d7e"}, - {file = "gevent-22.10.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:9d85574eb729f981fea9a78998725a06292d90a3ed50ddca74530c3148c0be41"}, - {file = "gevent-22.10.2-cp36-cp36m-win32.whl", hash = "sha256:8c192d2073e558e241f0b592c1e2b34127a4481a5be240cad4796533b88b1a98"}, - {file = "gevent-22.10.2-cp36-cp36m-win_amd64.whl", hash = "sha256:a2237451c721a0f874ef89dbb4af4fdc172b76a964befaa69deb15b8fff10f49"}, - {file = "gevent-22.10.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:53ee7f170ed42c7561fe8aff5d381dc9a4124694e70580d0c02fba6aafc0ea37"}, - {file = "gevent-22.10.2-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:96c56c280e3c43cfd075efd10b250350ed5ffd3c1514ec99a080b1b92d7c8374"}, - {file = "gevent-22.10.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b6c144e08dfad4106effc043a026e5d0c0eff6ad031904c70bf5090c63f3a6a7"}, - {file = "gevent-22.10.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:018f93de7d5318d2fb440f846839a4464738468c3476d5c9cf7da45bb71c18bd"}, - {file = "gevent-22.10.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7ed2346eb9dc4344f9cb0d7963ce5b74fe16fdd031a2809bb6c2b6eba7ebcd5"}, - {file = "gevent-22.10.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:84c517e33ed604fa06b7d756dc0171169cc12f7fdd68eb7b17708a62eebf4516"}, - {file = "gevent-22.10.2-cp37-cp37m-win32.whl", hash = "sha256:4114f0f439f0b547bb6f1d474fee99ddb46736944ad2207cef3771828f6aa358"}, - {file = "gevent-22.10.2-cp37-cp37m-win_amd64.whl", hash = "sha256:0d581f22a5be6281b11ad6309b38b18f0638cf896931223cbaa5adb904826ef6"}, - {file = "gevent-22.10.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2929377c8ebfb6f4d868d161cd8de2ea6b9f6c7a5fcd4f78bcd537319c16190b"}, - {file = "gevent-22.10.2-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:efc003b6c1481165af61f0aeac248e0a9ac8d880bb3acbe469b448674b2d5281"}, - {file = "gevent-22.10.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db562a8519838bddad0c439a2b12246bab539dd50e299ea7ff3644274a33b6a5"}, - {file = "gevent-22.10.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1472012493ca1fac103f700d309cb6ef7964dcdb9c788d1768266e77712f5e49"}, - {file = "gevent-22.10.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c04ee32c11e9fcee47c1b431834878dc987a7a2cc4fe126ddcae3bad723ce89"}, - {file = "gevent-22.10.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8729129edef2637a8084258cb9ec4e4d5ca45d97ac77aa7a6ff19ccb530ab731"}, - {file = "gevent-22.10.2-cp38-cp38-win32.whl", hash = "sha256:ae90226074a6089371a95f20288431cd4b3f6b0b096856afd862e4ac9510cddd"}, - {file = "gevent-22.10.2-cp38-cp38-win_amd64.whl", hash = "sha256:494c7f29e94df9a1c3157d67bb7edfa32a46eed786e04d9ee68d39f375e30001"}, - {file = "gevent-22.10.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:58898dbabb5b11e4d0192aae165ad286dc6742c543e1be9d30dc82753547c508"}, - {file = "gevent-22.10.2-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:4197d423e198265eef39a0dea286ef389da9148e070310f34455ecee8172c391"}, - {file = "gevent-22.10.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da4183f0b9d9a1e25e1758099220d32c51cc2c6340ee0dea3fd236b2b37598e4"}, - {file = "gevent-22.10.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a5488eba6a568b4d23c072113da4fc0feb1b5f5ede7381656dc913e0d82204e2"}, - {file = "gevent-22.10.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:319d8b1699b7b8134de66d656cd739b308ab9c45ace14d60ae44de7775b456c9"}, - {file = "gevent-22.10.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f3329bedbba4d3146ae58c667e0f9ac1e6f1e1e6340c7593976cdc60aa7d1a47"}, - {file = "gevent-22.10.2-cp39-cp39-win32.whl", hash = "sha256:172caa66273315f283e90a315921902cb6549762bdcb0587fd60cb712a9d6263"}, - {file = "gevent-22.10.2-cp39-cp39-win_amd64.whl", hash = "sha256:323b207b281ba0405fea042067fa1a61662e5ac0d574ede4ebbda03efd20c350"}, - {file = "gevent-22.10.2-pp27-pypy_73-win_amd64.whl", hash = "sha256:ed7f16613eebf892a6a744d7a4a8f345bc6f066a0ff3b413e2479f9c0a180193"}, - {file = "gevent-22.10.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:a47a4e77e2bc668856aad92a0b8de7ee10768258d93cd03968e6c7ba2e832f76"}, - {file = "gevent-22.10.2.tar.gz", hash = "sha256:1ca01da176ee37b3527a2702f7d40dbc9ffb8cfc7be5a03bfa4f9eec45e55c46"}, +python-versions = ">=3.8" +files = [ + {file = "gevent-23.9.1-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:a3c5e9b1f766a7a64833334a18539a362fb563f6c4682f9634dea72cbe24f771"}, + {file = "gevent-23.9.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b101086f109168b23fa3586fccd1133494bdb97f86920a24dc0b23984dc30b69"}, + {file = "gevent-23.9.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:36a549d632c14684bcbbd3014a6ce2666c5f2a500f34d58d32df6c9ea38b6535"}, + {file = "gevent-23.9.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:272cffdf535978d59c38ed837916dfd2b5d193be1e9e5dcc60a5f4d5025dd98a"}, + {file = "gevent-23.9.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcb8612787a7f4626aa881ff15ff25439561a429f5b303048f0fca8a1c781c39"}, + {file = "gevent-23.9.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:d57737860bfc332b9b5aa438963986afe90f49645f6e053140cfa0fa1bdae1ae"}, + {file = "gevent-23.9.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5f3c781c84794926d853d6fb58554dc0dcc800ba25c41d42f6959c344b4db5a6"}, + {file = "gevent-23.9.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:dbb22a9bbd6a13e925815ce70b940d1578dbe5d4013f20d23e8a11eddf8d14a7"}, + {file = "gevent-23.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:707904027d7130ff3e59ea387dddceedb133cc742b00b3ffe696d567147a9c9e"}, + {file = "gevent-23.9.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:45792c45d60f6ce3d19651d7fde0bc13e01b56bb4db60d3f32ab7d9ec467374c"}, + {file = "gevent-23.9.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e24c2af9638d6c989caffc691a039d7c7022a31c0363da367c0d32ceb4a0648"}, + {file = "gevent-23.9.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e1ead6863e596a8cc2a03e26a7a0981f84b6b3e956101135ff6d02df4d9a6b07"}, + {file = "gevent-23.9.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65883ac026731ac112184680d1f0f1e39fa6f4389fd1fc0bf46cc1388e2599f9"}, + {file = "gevent-23.9.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf7af500da05363e66f122896012acb6e101a552682f2352b618e541c941a011"}, + {file = "gevent-23.9.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:c3e5d2fa532e4d3450595244de8ccf51f5721a05088813c1abd93ad274fe15e7"}, + {file = "gevent-23.9.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c84d34256c243b0a53d4335ef0bc76c735873986d478c53073861a92566a8d71"}, + {file = "gevent-23.9.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ada07076b380918829250201df1d016bdafb3acf352f35e5693b59dceee8dd2e"}, + {file = "gevent-23.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:921dda1c0b84e3d3b1778efa362d61ed29e2b215b90f81d498eb4d8eafcd0b7a"}, + {file = "gevent-23.9.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:ed7a048d3e526a5c1d55c44cb3bc06cfdc1947d06d45006cc4cf60dedc628904"}, + {file = "gevent-23.9.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c1abc6f25f475adc33e5fc2dbcc26a732608ac5375d0d306228738a9ae14d3b"}, + {file = "gevent-23.9.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4368f341a5f51611411ec3fc62426f52ac3d6d42eaee9ed0f9eebe715c80184e"}, + {file = "gevent-23.9.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:52b4abf28e837f1865a9bdeef58ff6afd07d1d888b70b6804557e7908032e599"}, + {file = "gevent-23.9.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:52e9f12cd1cda96603ce6b113d934f1aafb873e2c13182cf8e86d2c5c41982ea"}, + {file = "gevent-23.9.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:de350fde10efa87ea60d742901e1053eb2127ebd8b59a7d3b90597eb4e586599"}, + {file = "gevent-23.9.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:fde6402c5432b835fbb7698f1c7f2809c8d6b2bd9d047ac1f5a7c1d5aa569303"}, + {file = "gevent-23.9.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:dd6c32ab977ecf7c7b8c2611ed95fa4aaebd69b74bf08f4b4960ad516861517d"}, + {file = "gevent-23.9.1-cp312-cp312-win_amd64.whl", hash = "sha256:455e5ee8103f722b503fa45dedb04f3ffdec978c1524647f8ba72b4f08490af1"}, + {file = "gevent-23.9.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:7ccf0fd378257cb77d91c116e15c99e533374a8153632c48a3ecae7f7f4f09fe"}, + {file = "gevent-23.9.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d163d59f1be5a4c4efcdd13c2177baaf24aadf721fdf2e1af9ee54a998d160f5"}, + {file = "gevent-23.9.1-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:7532c17bc6c1cbac265e751b95000961715adef35a25d2b0b1813aa7263fb397"}, + {file = "gevent-23.9.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:78eebaf5e73ff91d34df48f4e35581ab4c84e22dd5338ef32714264063c57507"}, + {file = "gevent-23.9.1-cp38-cp38-win32.whl", hash = "sha256:f632487c87866094546a74eefbca2c74c1d03638b715b6feb12e80120960185a"}, + {file = "gevent-23.9.1-cp38-cp38-win_amd64.whl", hash = "sha256:62d121344f7465e3739989ad6b91f53a6ca9110518231553fe5846dbe1b4518f"}, + {file = "gevent-23.9.1-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:bf456bd6b992eb0e1e869e2fd0caf817f0253e55ca7977fd0e72d0336a8c1c6a"}, + {file = "gevent-23.9.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:43daf68496c03a35287b8b617f9f91e0e7c0d042aebcc060cadc3f049aadd653"}, + {file = "gevent-23.9.1-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:7c28e38dcde327c217fdafb9d5d17d3e772f636f35df15ffae2d933a5587addd"}, + {file = "gevent-23.9.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:fae8d5b5b8fa2a8f63b39f5447168b02db10c888a3e387ed7af2bd1b8612e543"}, + {file = "gevent-23.9.1-cp39-cp39-win32.whl", hash = "sha256:2c7b5c9912378e5f5ccf180d1fdb1e83f42b71823483066eddbe10ef1a2fcaa2"}, + {file = "gevent-23.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:a2898b7048771917d85a1d548fd378e8a7b2ca963db8e17c6d90c76b495e0e2b"}, + {file = "gevent-23.9.1.tar.gz", hash = "sha256:72c002235390d46f94938a96920d8856d4ffd9ddf62a303a0d7c118894097e34"}, ] [package.dependencies] cffi = {version = ">=1.12.2", markers = "platform_python_implementation == \"CPython\" and sys_platform == \"win32\""} -greenlet = {version = ">=2.0.0", markers = "platform_python_implementation == \"CPython\""} -setuptools = "*" +greenlet = {version = ">=3.0rc3", markers = "platform_python_implementation == \"CPython\" and python_version >= \"3.11\""} "zope.event" = "*" "zope.interface" = "*" [package.extras] dnspython = ["dnspython (>=1.16.0,<2.0)", "idna"] -docs = ["repoze.sphinx.autointerface", "sphinxcontrib-programoutput", "zope.schema"] +docs = ["furo", "repoze.sphinx.autointerface", "sphinx", "sphinxcontrib-programoutput", "zope.schema"] monitor = ["psutil (>=5.7.0)"] -recommended = ["backports.socketpair", "cffi (>=1.12.2)", "dnspython (>=1.16.0,<2.0)", "idna", "psutil (>=5.7.0)", "selectors2"] -test = ["backports.socketpair", "cffi (>=1.12.2)", "contextvars (==2.4)", "coverage (>=5.0)", "coveralls (>=1.7.0)", "dnspython (>=1.16.0,<2.0)", "futures", "idna", "mock", "objgraph", "psutil (>=5.7.0)", "requests", "selectors2"] +recommended = ["cffi (>=1.12.2)", "dnspython (>=1.16.0,<2.0)", "idna", "psutil (>=5.7.0)"] +test = ["cffi (>=1.12.2)", "coverage (>=5.0)", "dnspython (>=1.16.0,<2.0)", "idna", "objgraph", "psutil (>=5.7.0)", "requests", "setuptools"] [[package]] name = "google-api-core" @@ -977,79 +964,73 @@ grpc = ["grpcio (>=1.44.0,<2.0.0dev)"] [[package]] name = "greenlet" -version = "2.0.2" +version = "3.0.0rc3" description = "Lightweight in-process concurrent programming" optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" -files = [ - {file = "greenlet-2.0.2-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:bdfea8c661e80d3c1c99ad7c3ff74e6e87184895bbaca6ee8cc61209f8b9b85d"}, - {file = "greenlet-2.0.2-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:9d14b83fab60d5e8abe587d51c75b252bcc21683f24699ada8fb275d7712f5a9"}, - {file = "greenlet-2.0.2-cp27-cp27m-win32.whl", hash = "sha256:6c3acb79b0bfd4fe733dff8bc62695283b57949ebcca05ae5c129eb606ff2d74"}, - {file = "greenlet-2.0.2-cp27-cp27m-win_amd64.whl", hash = "sha256:283737e0da3f08bd637b5ad058507e578dd462db259f7f6e4c5c365ba4ee9343"}, - {file = "greenlet-2.0.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:d27ec7509b9c18b6d73f2f5ede2622441de812e7b1a80bbd446cb0633bd3d5ae"}, - {file = "greenlet-2.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d967650d3f56af314b72df7089d96cda1083a7fc2da05b375d2bc48c82ab3f3c"}, - {file = "greenlet-2.0.2-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:30bcf80dda7f15ac77ba5af2b961bdd9dbc77fd4ac6105cee85b0d0a5fcf74df"}, - {file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26fbfce90728d82bc9e6c38ea4d038cba20b7faf8a0ca53a9c07b67318d46088"}, - {file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9190f09060ea4debddd24665d6804b995a9c122ef5917ab26e1566dcc712ceeb"}, - {file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d75209eed723105f9596807495d58d10b3470fa6732dd6756595e89925ce2470"}, - {file = "greenlet-2.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3a51c9751078733d88e013587b108f1b7a1fb106d402fb390740f002b6f6551a"}, - {file = "greenlet-2.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:76ae285c8104046b3a7f06b42f29c7b73f77683df18c49ab5af7983994c2dd91"}, - {file = "greenlet-2.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:2d4686f195e32d36b4d7cf2d166857dbd0ee9f3d20ae349b6bf8afc8485b3645"}, - {file = "greenlet-2.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c4302695ad8027363e96311df24ee28978162cdcdd2006476c43970b384a244c"}, - {file = "greenlet-2.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d4606a527e30548153be1a9f155f4e283d109ffba663a15856089fb55f933e47"}, - {file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c48f54ef8e05f04d6eff74b8233f6063cb1ed960243eacc474ee73a2ea8573ca"}, - {file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a1846f1b999e78e13837c93c778dcfc3365902cfb8d1bdb7dd73ead37059f0d0"}, - {file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a06ad5312349fec0ab944664b01d26f8d1f05009566339ac6f63f56589bc1a2"}, - {file = "greenlet-2.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:eff4eb9b7eb3e4d0cae3d28c283dc16d9bed6b193c2e1ace3ed86ce48ea8df19"}, - {file = "greenlet-2.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5454276c07d27a740c5892f4907c86327b632127dd9abec42ee62e12427ff7e3"}, - {file = "greenlet-2.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:7cafd1208fdbe93b67c7086876f061f660cfddc44f404279c1585bbf3cdc64c5"}, - {file = "greenlet-2.0.2-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:910841381caba4f744a44bf81bfd573c94e10b3045ee00de0cbf436fe50673a6"}, - {file = "greenlet-2.0.2-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:18a7f18b82b52ee85322d7a7874e676f34ab319b9f8cce5de06067384aa8ff43"}, - {file = "greenlet-2.0.2-cp35-cp35m-win32.whl", hash = "sha256:03a8f4f3430c3b3ff8d10a2a86028c660355ab637cee9333d63d66b56f09d52a"}, - {file = "greenlet-2.0.2-cp35-cp35m-win_amd64.whl", hash = "sha256:4b58adb399c4d61d912c4c331984d60eb66565175cdf4a34792cd9600f21b394"}, - {file = "greenlet-2.0.2-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:703f18f3fda276b9a916f0934d2fb6d989bf0b4fb5a64825260eb9bfd52d78f0"}, - {file = "greenlet-2.0.2-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:32e5b64b148966d9cccc2c8d35a671409e45f195864560829f395a54226408d3"}, - {file = "greenlet-2.0.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2dd11f291565a81d71dab10b7033395b7a3a5456e637cf997a6f33ebdf06f8db"}, - {file = "greenlet-2.0.2-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e0f72c9ddb8cd28532185f54cc1453f2c16fb417a08b53a855c4e6a418edd099"}, - {file = "greenlet-2.0.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd021c754b162c0fb55ad5d6b9d960db667faad0fa2ff25bb6e1301b0b6e6a75"}, - {file = "greenlet-2.0.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:3c9b12575734155d0c09d6c3e10dbd81665d5c18e1a7c6597df72fd05990c8cf"}, - {file = "greenlet-2.0.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:b9ec052b06a0524f0e35bd8790686a1da006bd911dd1ef7d50b77bfbad74e292"}, - {file = "greenlet-2.0.2-cp36-cp36m-win32.whl", hash = "sha256:dbfcfc0218093a19c252ca8eb9aee3d29cfdcb586df21049b9d777fd32c14fd9"}, - {file = "greenlet-2.0.2-cp36-cp36m-win_amd64.whl", hash = "sha256:9f35ec95538f50292f6d8f2c9c9f8a3c6540bbfec21c9e5b4b751e0a7c20864f"}, - {file = "greenlet-2.0.2-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:d5508f0b173e6aa47273bdc0a0b5ba055b59662ba7c7ee5119528f466585526b"}, - {file = "greenlet-2.0.2-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:f82d4d717d8ef19188687aa32b8363e96062911e63ba22a0cff7802a8e58e5f1"}, - {file = "greenlet-2.0.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9c59a2120b55788e800d82dfa99b9e156ff8f2227f07c5e3012a45a399620b7"}, - {file = "greenlet-2.0.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2780572ec463d44c1d3ae850239508dbeb9fed38e294c68d19a24d925d9223ca"}, - {file = "greenlet-2.0.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:937e9020b514ceedb9c830c55d5c9872abc90f4b5862f89c0887033ae33c6f73"}, - {file = "greenlet-2.0.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:36abbf031e1c0f79dd5d596bfaf8e921c41df2bdf54ee1eed921ce1f52999a86"}, - {file = "greenlet-2.0.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:18e98fb3de7dba1c0a852731c3070cf022d14f0d68b4c87a19cc1016f3bb8b33"}, - {file = "greenlet-2.0.2-cp37-cp37m-win32.whl", hash = "sha256:3f6ea9bd35eb450837a3d80e77b517ea5bc56b4647f5502cd28de13675ee12f7"}, - {file = "greenlet-2.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:7492e2b7bd7c9b9916388d9df23fa49d9b88ac0640db0a5b4ecc2b653bf451e3"}, - {file = "greenlet-2.0.2-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:b864ba53912b6c3ab6bcb2beb19f19edd01a6bfcbdfe1f37ddd1778abfe75a30"}, - {file = "greenlet-2.0.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1087300cf9700bbf455b1b97e24db18f2f77b55302a68272c56209d5587c12d1"}, - {file = "greenlet-2.0.2-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:ba2956617f1c42598a308a84c6cf021a90ff3862eddafd20c3333d50f0edb45b"}, - {file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc3a569657468b6f3fb60587e48356fe512c1754ca05a564f11366ac9e306526"}, - {file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8eab883b3b2a38cc1e050819ef06a7e6344d4a990d24d45bc6f2cf959045a45b"}, - {file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:acd2162a36d3de67ee896c43effcd5ee3de247eb00354db411feb025aa319857"}, - {file = "greenlet-2.0.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0bf60faf0bc2468089bdc5edd10555bab6e85152191df713e2ab1fcc86382b5a"}, - {file = "greenlet-2.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b0ef99cdbe2b682b9ccbb964743a6aca37905fda5e0452e5ee239b1654d37f2a"}, - {file = "greenlet-2.0.2-cp38-cp38-win32.whl", hash = "sha256:b80f600eddddce72320dbbc8e3784d16bd3fb7b517e82476d8da921f27d4b249"}, - {file = "greenlet-2.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:4d2e11331fc0c02b6e84b0d28ece3a36e0548ee1a1ce9ddde03752d9b79bba40"}, - {file = "greenlet-2.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8512a0c38cfd4e66a858ddd1b17705587900dd760c6003998e9472b77b56d417"}, - {file = "greenlet-2.0.2-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:88d9ab96491d38a5ab7c56dd7a3cc37d83336ecc564e4e8816dbed12e5aaefc8"}, - {file = "greenlet-2.0.2-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:561091a7be172ab497a3527602d467e2b3fbe75f9e783d8b8ce403fa414f71a6"}, - {file = "greenlet-2.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:971ce5e14dc5e73715755d0ca2975ac88cfdaefcaab078a284fea6cfabf866df"}, - {file = "greenlet-2.0.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be4ed120b52ae4d974aa40215fcdfde9194d63541c7ded40ee12eb4dda57b76b"}, - {file = "greenlet-2.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94c817e84245513926588caf1152e3b559ff794d505555211ca041f032abbb6b"}, - {file = "greenlet-2.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1a819eef4b0e0b96bb0d98d797bef17dc1b4a10e8d7446be32d1da33e095dbb8"}, - {file = "greenlet-2.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7efde645ca1cc441d6dc4b48c0f7101e8d86b54c8530141b09fd31cef5149ec9"}, - {file = "greenlet-2.0.2-cp39-cp39-win32.whl", hash = "sha256:ea9872c80c132f4663822dd2a08d404073a5a9b5ba6155bea72fb2a79d1093b5"}, - {file = "greenlet-2.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:db1a39669102a1d8d12b57de2bb7e2ec9066a6f2b3da35ae511ff93b01b5d564"}, - {file = "greenlet-2.0.2.tar.gz", hash = "sha256:e7c8dc13af7db097bed64a051d2dd49e9f0af495c26995c00a9ee842690d34c0"}, -] - -[package.extras] -docs = ["Sphinx", "docutils (<0.18)"] +python-versions = ">=3.7" +files = [ + {file = "greenlet-3.0.0rc3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a2affddff9b2f846f40799673e41b29f0500582415c860fca8f146858e9de1a"}, + {file = "greenlet-3.0.0rc3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dd00046dfd00767fce18f9933658d126652a500caf7af9dbfbd43818e4b484c2"}, + {file = "greenlet-3.0.0rc3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e787b00002cef3b98c7cf700fb85c2c01b0d202b1c6731706e5baa4b3325aa1e"}, + {file = "greenlet-3.0.0rc3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38ffc7538bc66766a8b551888903d415773481c4bd13560a4fb24887222e3cc9"}, + {file = "greenlet-3.0.0rc3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dde5deb355b34bbf44b15789e27c56862f51f417207be49eedc58fce34681fe6"}, + {file = "greenlet-3.0.0rc3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:1fb703a102a02361a0cc6a3d9a7958e1584fdeb536bd37ca9aca529d3356bedd"}, + {file = "greenlet-3.0.0rc3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f8661d14d3e07f2ceeb850e4cbcc7114bdf90a8dc82d63d37b08a50bb6955a77"}, + {file = "greenlet-3.0.0rc3-cp310-cp310-win_amd64.whl", hash = "sha256:997456b74efee91ceeb39d63818909da5dbb712a07f7742f4378986ac3473463"}, + {file = "greenlet-3.0.0rc3-cp310-universal2-macosx_11_0_x86_64.whl", hash = "sha256:d3cd3957af8cec1fcfd87d92ca71b7d434d798036e14ae878f9ab1e07d99da0d"}, + {file = "greenlet-3.0.0rc3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:895b689fc52a5bc402f8d624705110df5c265b1410ffe8e0769a66db9d2e7851"}, + {file = "greenlet-3.0.0rc3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a84a88422b5a0360fae57ad6b3b20fc17c9462880929810b0a26ee43aa05982e"}, + {file = "greenlet-3.0.0rc3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d79cf299ba1996d8a4f133b317e709a0a3ce87181308280e40664e12cb512c54"}, + {file = "greenlet-3.0.0rc3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef9789aea735004eba559c7919a73a3b475d0c28e2c1e9de464c6bc761bf69f4"}, + {file = "greenlet-3.0.0rc3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:66790e1537382e53bce64de3a695d1b12a04b00104df45f7ef472a10561936c2"}, + {file = "greenlet-3.0.0rc3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:68349987bf2ce274953f9f9b28458869bd8770a0c5461e1ef91d8107b1bae361"}, + {file = "greenlet-3.0.0rc3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:30ffaa6c020a615c8f4be3abfc6029982fda026a3bf9a6dc7205afb033251506"}, + {file = "greenlet-3.0.0rc3-cp311-cp311-win_amd64.whl", hash = "sha256:864619b058f573058cd77f6944cf63d7f42157fe30be494798721bd8ac256d7b"}, + {file = "greenlet-3.0.0rc3-cp311-universal2-macosx_10_9_universal2.whl", hash = "sha256:7c887ecb55374d585d71ff8f9d07c137637694e88fa2b5d5b1450a05ece62ae9"}, + {file = "greenlet-3.0.0rc3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:686821157368c1c4ef53aa68e6801280010da92ab0e4265dad37003341fca6a1"}, + {file = "greenlet-3.0.0rc3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:242d56d2d5f6859f0f086ce62555a2c692c8053c89721d41fead5e1e8dffdb36"}, + {file = "greenlet-3.0.0rc3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81d653ae6c64b85ce4c7bccbea7b630de8799da751b73e55b4c68875b6eb19d6"}, + {file = "greenlet-3.0.0rc3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:beeb5cfbd8f3792c37db4e3c5665aa750d78bbdabe758161a34e7dfe27075e69"}, + {file = "greenlet-3.0.0rc3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:30daee988fc83078b016fa95a7a1f78a7c86534a44238748b9748675814eb1dc"}, + {file = "greenlet-3.0.0rc3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:977898b8c24159467c66ed1a8f62aacd33f3d85f852cf413d0d2e2a87a6b3091"}, + {file = "greenlet-3.0.0rc3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:097a2f75c79c3fa76fea2e5d48a637233722fe72a5ebb1213c55f0a0898f481c"}, + {file = "greenlet-3.0.0rc3-cp312-cp312-win_amd64.whl", hash = "sha256:5770d43b08dfa10f4460c1bd51f8c80e6f2c47611054e9fb80d4d7976d07e560"}, + {file = "greenlet-3.0.0rc3-cp312-universal2-macosx_10_9_universal2.whl", hash = "sha256:f33e7ff85775cb0ec6abb0950ffc631960bae5a203da38166fc3dfde826e0d0a"}, + {file = "greenlet-3.0.0rc3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:07f6d1ce31a1db5102a42b4afa609af330edfd8a81d10faba3e47ae33a07cbdf"}, + {file = "greenlet-3.0.0rc3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86e651fa59263f7ff1d4657b086c48cfe7e26db2a36e2d74069f3b5aeab478e6"}, + {file = "greenlet-3.0.0rc3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ef7c6e49a9a020d56349c6a769352709bfbe35d3ee7f98bd5efcac6cedbdc162"}, + {file = "greenlet-3.0.0rc3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5585bf8d1d2d3712010ee74988c2ed85c54b127b97f2778fbdcc5b3ea8e801a2"}, + {file = "greenlet-3.0.0rc3-cp37-cp37m-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c706041cd92e1b9d2b602eaa31e94aad14453bdbf186ce77530f25167c173a0e"}, + {file = "greenlet-3.0.0rc3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:37213e72058d2e6231d18417adc63c698c040fbb47dc59a3fd633973214ab1ab"}, + {file = "greenlet-3.0.0rc3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:95bc6ec8dd73f8f36e9dfc61a7fa5a2819d1cd52d0bfdb70a43434d6b2aeb239"}, + {file = "greenlet-3.0.0rc3-cp37-cp37m-win32.whl", hash = "sha256:e83c4c7a0814dcfd7e2fe4b74a371f3ce489b62ff02e81d0c5cacc8ba4750395"}, + {file = "greenlet-3.0.0rc3-cp37-cp37m-win_amd64.whl", hash = "sha256:4c35608918f331256be199d3712552fa8a1d12f87ac171a86a31488c60d298f5"}, + {file = "greenlet-3.0.0rc3-cp37-universal2-macosx_11_0_x86_64.whl", hash = "sha256:215bdb33e85fd89fe55f9984dc6f0a96b5774bace663e1a6d051e65d66170ef8"}, + {file = "greenlet-3.0.0rc3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69db00f775ed9d233f53ef67c66ea40a7add0c0929eb528f633982e27595dd37"}, + {file = "greenlet-3.0.0rc3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5fcc7162944c2fedfb2253ca2171267e016a3b065c73369d0d4a27f601e7f162"}, + {file = "greenlet-3.0.0rc3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3c0082d7b83312c59127811367089f812f8f1386fad7e8cf321fd732b4a6ace6"}, + {file = "greenlet-3.0.0rc3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66f1131c17dba115ea7cb3b257b6751b3c4cfd324f2121447e2483f57abbbf3c"}, + {file = "greenlet-3.0.0rc3-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f0c5508582339090b99e2863a157fc2708ab9c8b5cd21619bdcb04edcdc6c28d"}, + {file = "greenlet-3.0.0rc3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f1c9ad8d6500f7b142a94054281d9628bc8652a14b0923d02e0dfd87392fbc74"}, + {file = "greenlet-3.0.0rc3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bd586284bbf18ca3068e1fcc67ef54538e1bb74cb605ebdac9e62048237839f5"}, + {file = "greenlet-3.0.0rc3-cp38-cp38-win32.whl", hash = "sha256:1c16f1bbaf9c75dfac3e52bb778d2fd6099fd5aa59fafa678eca5853eedd99ec"}, + {file = "greenlet-3.0.0rc3-cp38-cp38-win_amd64.whl", hash = "sha256:e388ceb55b8f3f388afea4d4a17a64b619040f0e8e9fa3e17e7c34f4d0fbe103"}, + {file = "greenlet-3.0.0rc3-cp38-universal2-macosx_11_0_x86_64.whl", hash = "sha256:68bd35ad9f99df0ef18836fd0fb34278dca6b3350bdcf1e8809822fc4f57a82e"}, + {file = "greenlet-3.0.0rc3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:256b748fc1e6c97012f217e0a403116cb0dd369bf1cff51c07a9c52899d4a8a8"}, + {file = "greenlet-3.0.0rc3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4936e6e051932848c4b237a874da8dbb47bfbb5ae5104497fb78c4f4cf184989"}, + {file = "greenlet-3.0.0rc3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a31b3a4bd10c540a7eb7d4b43d16779813ca4c79b615ed6d4ebf0e5a782d9fa0"}, + {file = "greenlet-3.0.0rc3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b6f8253fdb00e74b928ab5d04f88ddbc8beb0cc26aa978bb4a12c1513166d481"}, + {file = "greenlet-3.0.0rc3-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2a7831d04a0f8a14645c010e3fb3fa36b8d2df304dd837948427ccfec2524ddf"}, + {file = "greenlet-3.0.0rc3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ae84d2f2658990f29df4ea753061b25c337bd70f805128af328098e5b8afc454"}, + {file = "greenlet-3.0.0rc3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:cd51cc2528a2985f3bc0564c1b1ce5b2e6fa4ee9924503010428256fa95b0e3c"}, + {file = "greenlet-3.0.0rc3-cp39-cp39-win32.whl", hash = "sha256:e8698f341e78dd0f149511929e92d1507cc26647f047db13987169d244db10fb"}, + {file = "greenlet-3.0.0rc3-cp39-cp39-win_amd64.whl", hash = "sha256:f059457db4e2ae4a4fdae455453c5e5765aa08efcb804e2a106c69c31bd438ba"}, + {file = "greenlet-3.0.0rc3-cp39-universal2-macosx_11_0_x86_64.whl", hash = "sha256:c80cac2776df3dd08f27b7338f467a62ee6cb29668a8f4f408b8da1f981aae9e"}, + {file = "greenlet-3.0.0rc3.tar.gz", hash = "sha256:0df5c2ad154f457fd372e39723493b3df519330a4c1bff3ca901be66130f379b"}, +] + +[package.extras] +docs = ["Sphinx"] test = ["objgraph", "psutil"] [[package]] @@ -2638,17 +2619,17 @@ files = [ [[package]] name = "urllib3" -version = "1.26.13" +version = "1.26.18" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" files = [ - {file = "urllib3-1.26.13-py2.py3-none-any.whl", hash = "sha256:47cc05d99aaa09c9e72ed5809b60e7ba354e64b59c9c173ac3018642d8bb41fc"}, - {file = "urllib3-1.26.13.tar.gz", hash = "sha256:c083dd0dce68dbfbe1129d5271cb90f9447dea7d52097c6e0126120c521ddea8"}, + {file = "urllib3-1.26.18-py2.py3-none-any.whl", hash = "sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07"}, + {file = "urllib3-1.26.18.tar.gz", hash = "sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0"}, ] [package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] +brotli = ["brotli (==1.0.9)", "brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] @@ -2785,4 +2766,4 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "c40d55ad3a597c47d889feb6d959fa7f75622025eeb7670fffe10dfd01e9b559" +content-hash = "049b0a377342fc90a595807282f8e9591fadff7220753d48f4cc241f34124449" diff --git a/server/portal/apps/accounts/migrations/0006_auto_20231018_1927.py b/server/portal/apps/accounts/migrations/0006_auto_20231018_1927.py new file mode 100644 index 000000000..183c3ebd7 --- /dev/null +++ b/server/portal/apps/accounts/migrations/0006_auto_20231018_1927.py @@ -0,0 +1,37 @@ +# Generated by Django 3.2.20 on 2023-10-18 19:27 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('accounts', '0005_auto_20210316_1950'), + ] + + operations = [ + migrations.RemoveField( + model_name='portalprofile', + name='bio', + ), + migrations.RemoveField( + model_name='portalprofile', + name='ethnicity', + ), + migrations.RemoveField( + model_name='portalprofile', + name='gender', + ), + migrations.RemoveField( + model_name='portalprofile', + name='orcid_id', + ), + migrations.RemoveField( + model_name='portalprofile', + name='professional_level', + ), + migrations.RemoveField( + model_name='portalprofile', + name='website', + ), + ] diff --git a/server/portal/apps/accounts/models.py b/server/portal/apps/accounts/models.py index 4f18ff8a1..482c363f3 100644 --- a/server/portal/apps/accounts/models.py +++ b/server/portal/apps/accounts/models.py @@ -26,13 +26,6 @@ class PortalProfile(models.Model): related_name='profile', on_delete=models.CASCADE ) - ethnicity = models.CharField(max_length=255) - gender = models.CharField(max_length=255) - bio = models.CharField(max_length=4096, default=None, null=True, blank=True) - website = models.CharField(max_length=256, default=None, null=True, blank=True) - orcid_id = models.CharField(max_length=256, default=None, null=True, blank=True) - professional_level = models.CharField(max_length=256, default=None, null=True) - # Default to False. If PORTAL_USER_ACCOUNT_SETUP_STEPS is empty, # setup_complete will be set to True on first login setup_complete = models.BooleanField(default=False) diff --git a/server/portal/apps/datafiles/views.py b/server/portal/apps/datafiles/views.py index e85d42069..8f0e769cd 100644 --- a/server/portal/apps/datafiles/views.py +++ b/server/portal/apps/datafiles/views.py @@ -48,7 +48,7 @@ def get(self, request): if 'homeDir' in system else system for system in portal_systems ] - default_system = settings.PORTAL_DATAFILES_DEFAULT_STORAGE_SYSTEM + default_system = settings.PORTAL_DATAFILES_DEFAULT_STORAGE_SYSTEM or settings.PORTAL_DATAFILES_STORAGE_SYSTEMS[0] if default_system: system_id = default_system.get('system') system_def = request.user.tapis_oauth.client.systems.getSystem(systemId=system_id, select='host') diff --git a/server/portal/apps/datafiles/views_unit_test.py b/server/portal/apps/datafiles/views_unit_test.py index d16cd5cd6..af10bc4f7 100644 --- a/server/portal/apps/datafiles/views_unit_test.py +++ b/server/portal/apps/datafiles/views_unit_test.py @@ -224,17 +224,15 @@ def test_tapis_file_view_put_is_logged_for_metrics(mock_indexer, client, authent @patch('portal.libs.agave.operations.tapis_indexer') def test_tapis_file_view_post_is_logged_for_metrics(mock_indexer, client, authenticated_user, mock_tapis_client, logging_metric_mock, - agave_file_mock, requests_mock, text_file_fixture): + tapis_file_mock, requests_mock, text_file_fixture): - mock_tapis_client.access_token.access_token = "my_access_token" - requests_mock.post(f'{settings.TAPIS_TENANT_BASEURL}/v3/files/ops/frontera.home.username/text_file.txt', - json=agave_file_mock) + mock_tapis_client.files.insert.return_value = tapis_file_mock response = client.post("/api/datafiles/tapis/upload/private/frontera.home.username/", data={"uploaded_file": text_file_fixture}) assert response.status_code == 200 - assert response.json() == {"data": agave_file_mock} + assert response.json() == {"data": tapis_file_mock} # Ensure metric-related logging is being performed logging_metric_mock.assert_called_with( diff --git a/server/portal/apps/projects/views.py b/server/portal/apps/projects/views.py index 8baf098d3..ca03a8479 100644 --- a/server/portal/apps/projects/views.py +++ b/server/portal/apps/projects/views.py @@ -17,7 +17,9 @@ list_projects, get_project, create_shared_workspace,\ update_project, get_workspace_role, change_user_role, add_user_to_workspace,\ remove_user, transfer_ownership - +from portal.apps.search.tasks import tapis_project_listing_indexer +from portal.libs.elasticsearch.indexes import IndexedProject +from elasticsearch_dsl import Q LOGGER = logging.getLogger(__name__) @@ -63,12 +65,35 @@ def get(self, request): } ``` """ - # TODOv3: Support Elasticsearch queries for V3 projects https://jira.tacc.utexas.edu/browse/TV3-160 - # query_string = request.GET.get('query_string') - # offset = int(request.GET.get('offset', 0)) - # limit = int(request.GET.get('limit', 100)) - client = request.user.tapis_oauth.client - listing = list_projects(client) + + query_string = request.GET.get('query_string') + offset = int(request.GET.get('offset', 0)) + limit = int(request.GET.get('limit', 100)) + + listing = [] + + if query_string: + search = IndexedProject.search() + + ngram_query = Q("query_string", query=query_string, + fields=["title", "id"], + minimum_should_match='100%', + default_operator='or') + + wildcard_query = Q("wildcard", title=f'*{query_string}*') | Q("wildcard", id=f'*{query_string}*') + + search = search.query(ngram_query | wildcard_query) + search = search.extra(from_=int(offset), size=int(limit)) + + res = search.execute() + hits = [hit.to_dict() for hit in res] + listing = hits + else: + client = request.user.tapis_oauth.client + listing = list_projects(client) + + tapis_project_listing_indexer.delay(listing) + return JsonResponse({"status": 200, "response": listing}) def post(self, request): # pylint: disable=no-self-use diff --git a/server/portal/apps/projects/workspace_operations/shared_workspace_migration.py b/server/portal/apps/projects/workspace_operations/shared_workspace_migration.py index 6bf6d4ec8..58cd57e3f 100644 --- a/server/portal/apps/projects/workspace_operations/shared_workspace_migration.py +++ b/server/portal/apps/projects/workspace_operations/shared_workspace_migration.py @@ -62,7 +62,11 @@ def migrate_project(project_id): for co_pi in v2_project.co_pis.all(): v2_role = get_role(project_id, co_pi.username) - v3_role = ROLE_MAP[v2_role] + try: + v3_role = ROLE_MAP[v2_role] + except KeyError: + print(f'ERROR: No role found for: {v2_role}') + v3_role = "reader" try: add_user_to_workspace(client, project_id, co_pi.username, v3_role) except NotFoundError: @@ -71,7 +75,11 @@ def migrate_project(project_id): for team_member in v2_project.team_members.all(): v2_role = get_role(project_id, team_member.username) - v3_role = ROLE_MAP[v2_role] + try: + v3_role = ROLE_MAP[v2_role] + except KeyError: + print(f'ERROR: No role found for: {v2_role}') + v3_role = "reader" try: add_user_to_workspace(client, project_id, team_member.username, v3_role) except NotFoundError: diff --git a/server/portal/apps/search/tasks.py b/server/portal/apps/search/tasks.py index 6dabd8725..61bf00a2e 100644 --- a/server/portal/apps/search/tasks.py +++ b/server/portal/apps/search/tasks.py @@ -3,7 +3,7 @@ from django.conf import settings from celery import shared_task from portal.libs.agave.utils import user_account, service_account -from portal.libs.elasticsearch.utils import index_listing +from portal.libs.elasticsearch.utils import index_listing, index_project_listing from portal.apps.users.utils import get_tas_allocations from portal.apps.projects.models.metadata import ProjectMetadata from portal.libs.elasticsearch.docs.base import (IndexedAllocation, @@ -78,3 +78,8 @@ def index_project(self, project_id): project_doc = IndexedProject(**project_dict) project_doc.meta.id = project_id project_doc.save() + + +@shared_task(bind=True, max_retries=3, queue='default') +def tapis_project_listing_indexer(self, projects): + index_project_listing(projects) diff --git a/server/portal/apps/signals/signals.py b/server/portal/apps/signals/signals.py index 5b605e70f..0993e637f 100644 --- a/server/portal/apps/signals/signals.py +++ b/server/portal/apps/signals/signals.py @@ -1,4 +1,3 @@ from django.dispatch import Signal -# Generic event signal. Not in use as of 6.29.20 -portal_event = Signal(providing_args=['event_type', 'event_data', 'event_users']) +portal_event = Signal() diff --git a/server/portal/apps/site_search/api/unit_test.py b/server/portal/apps/site_search/api/unit_test.py index 6f5f09668..b871a3e70 100644 --- a/server/portal/apps/site_search/api/unit_test.py +++ b/server/portal/apps/site_search/api/unit_test.py @@ -20,6 +20,11 @@ def mock_cms_search(mocker): yield mocked_fn +@pytest.fixture +def mock_service_account(mocker): + yield mocker.patch('portal.apps.site_search.api.views.service_account', autospec=True) + + @pytest.fixture def mock_files_search(mocker): mocked_fn = mocker.patch('portal.apps.site_search.api.views.files_search') @@ -76,7 +81,7 @@ def test_search_with_auth(regular_user, client, mock_cms_search, 'include': True}} -def test_search_no_auth(client, mock_cms_search, mock_files_search): +def test_search_no_auth(client, mock_cms_search, mock_files_search, mock_service_account): response = client.get('/api/site-search/?page=0&query_string=test') assert response.json() == { @@ -93,7 +98,7 @@ def test_search_no_auth(client, mock_cms_search, mock_files_search): def test_search_public(client, configure_public, mock_cms_search, - mock_files_search): + mock_files_search, mock_service_account): response = client.get('/api/site-search/?page=0&query_string=test') assert response.json() == { @@ -132,15 +137,16 @@ def test_cms_search_util(mock_dsl_search): 'highlight': {'body': ['highlight 1']}}]) -def test_file_search_util(mock_file_search): +def test_file_search_util(mock_file_search, regular_user): from portal.apps.site_search.api.views import files_search mock_file_search.return_value = {'count': 1, 'listing': [{'name': 'testfile', 'path': '/path/to/testfile'}]} - res = files_search('test_query', 'test_system') + client = regular_user.tapis_oauth.client + res = files_search(client, 'test_query', 'test_system') - mock_file_search.assert_called_with(None, 'test_system', '/', + mock_file_search.assert_called_with(client, 'test_system', '/', query_string='test_query', filter=None, offset=0, diff --git a/server/portal/apps/site_search/api/views.py b/server/portal/apps/site_search/api/views.py index 061e71db4..7203e15e2 100644 --- a/server/portal/apps/site_search/api/views.py +++ b/server/portal/apps/site_search/api/views.py @@ -3,6 +3,7 @@ from portal.libs.agave.operations import search as search_operation from portal.views.base import BaseApiView from django.conf import settings +from portal.libs.agave.utils import service_account import logging logger = logging.getLogger(__name__) @@ -35,8 +36,8 @@ def cms_search(query_string, offset=0, limit=10): return total, results -def files_search(query_string, system, filter=None, offset=0, limit=10): - res = search_operation(None, system, '/', offset=offset, limit=limit, +def files_search(client, query_string, system, filter=None, offset=0, limit=10): + res = search_operation(client, system, '/', offset=offset, limit=limit, query_string=query_string, filter=filter) return (res['count'], res['listing']) @@ -62,8 +63,9 @@ def get(self, request, *args, **kwargs): in settings.PORTAL_DATAFILES_STORAGE_SYSTEMS if conf['scheme'] == 'public' and ('siteSearchPriority' in conf and conf['siteSearchPriority'] is not None)) + client = request.user.tapis_oauth.client if (request.user.is_authenticated and request.user.profile.setup_complete) else service_account() (public_total, public_results) = \ - files_search(qs, public_conf['system'], filter=filter, + files_search(client, qs, public_conf['system'], filter=filter, offset=offset, limit=limit) response['public'] = {'count': public_total, 'listing': public_results, @@ -80,8 +82,9 @@ def get(self, request, *args, **kwargs): in settings.PORTAL_DATAFILES_STORAGE_SYSTEMS if conf['scheme'] == 'community' and ('siteSearchPriority' in conf and conf['siteSearchPriority'] is not None)) + client = request.user.tapis_oauth.client (community_total, community_results) = \ - files_search(qs, community_conf['system'], filter=filter, + files_search(client, qs, community_conf['system'], filter=filter, offset=offset, limit=limit) response['community'] = {'count': community_total, diff --git a/server/portal/apps/tickets/rtUtil.py b/server/portal/apps/tickets/rtUtil.py index 42c1bd7cd..bd848e585 100644 --- a/server/portal/apps/tickets/rtUtil.py +++ b/server/portal/apps/tickets/rtUtil.py @@ -47,7 +47,7 @@ def create_ticket(self, attachments, subject, problem_description, requestor, cc files=attachments, Subject=subject, Text=problem_description, - Requestors=requestor, + Requestor=requestor, Cc=cc, CF_resource=settings.RT_TAG) diff --git a/server/portal/apps/webhooks/views.py b/server/portal/apps/webhooks/views.py index 54544b23d..f38430c1b 100644 --- a/server/portal/apps/webhooks/views.py +++ b/server/portal/apps/webhooks/views.py @@ -161,6 +161,7 @@ def post(self, request, *args, **kwargs): job_uuid = request.POST.get('job_uuid', None) job_owner = request.POST.get('owner', None) address = request.POST.get('address', None) + message = request.POST.get('message', None) if not address: msg = "Missing required interactive webhook parameter: address" @@ -174,6 +175,9 @@ def post(self, request, *args, **kwargs): Notification.ACTION_LINK: address } + if message: + event_data[Notification.MESSAGE] = message + # confirm that there is a corresponding running tapis job before sending notification try: valid_state = validate_tapis_job(job_uuid, job_owner, TERMINAL_JOB_STATES) diff --git a/server/portal/apps/workspace/api/views.py b/server/portal/apps/workspace/api/views.py index 9a94db829..f76b36402 100644 --- a/server/portal/apps/workspace/api/views.py +++ b/server/portal/apps/workspace/api/views.py @@ -179,7 +179,7 @@ def listing(self, client, request): data = client.jobs.getJobSearchList( limit=limit, - startAfter=offset, + skip=offset, orderBy='lastUpdated(desc),name(asc)', _tapis_query_parameters={'tags.contains': f'portalName: {portal_name}'}, select='allAttributes' diff --git a/server/portal/fixtures/accounts.json b/server/portal/fixtures/accounts.json index cf850fd7b..fdd870d93 100644 --- a/server/portal/fixtures/accounts.json +++ b/server/portal/fixtures/accounts.json @@ -3,27 +3,21 @@ "model": "accounts.portalprofile", "pk": 1, "fields": { - "user": 1, - "ethnicity": "", - "gender": "" + "user": 1 } }, { "model": "accounts.portalprofile", "pk": 2, "fields": { - "user": 2, - "ethnicity": "", - "gender": "" + "user": 2 } }, { "model": "accounts.portalprofile", "pk": 3, "fields": { - "user": 3, - "ethnicity": "", - "gender": "" + "user": 3 } }, { diff --git a/server/portal/fixtures/users.json b/server/portal/fixtures/users.json index baca595ba..a5410e9ad 100644 --- a/server/portal/fixtures/users.json +++ b/server/portal/fixtures/users.json @@ -58,12 +58,6 @@ "pk": 1, "fields": { "user": 1, - "ethnicity": "", - "gender": "", - "bio": null, - "website": null, - "orcid_id": null, - "professional_level": null, "setup_complete": true } } diff --git a/server/portal/libs/agave/operations.py b/server/portal/libs/agave/operations.py index 1603039ee..83264a1a8 100644 --- a/server/portal/libs/agave/operations.py +++ b/server/portal/libs/agave/operations.py @@ -10,7 +10,6 @@ from portal.libs.agave.filter_mapping import filter_mapping from pathlib import Path from tapipy.errors import BaseTapyException -import requests as r logger = logging.getLogger(__name__) @@ -21,7 +20,7 @@ def listing(client, system, path, offset=0, limit=100, *args, **kwargs): Params ------ - client: agavepy.agave.Agave + client: tapipy.tapis.Tapis Tapis client to use for the listing. system: str Tapis system ID. @@ -93,7 +92,8 @@ def search(client, system, path='', offset=0, limit=100, query_string='', filter Params ------ - client: NoneType + client: tapipy.tapis.Tapis + Tapis client to use for the listing. system: str Tapis system ID to filter on. path: NoneType @@ -139,7 +139,7 @@ def search(client, system, path='', offset=0, limit=100, query_string='', filter if filter: search = search.filter(filter_query) - search = search.filter('prefix', **{'path._exact': path}) + search = search.filter('prefix', **{'path._exact': path.strip('/')}) search = search.filter('term', **{'system._exact': system}) search = search.extra(from_=int(offset), size=int(limit)) res = search.execute() @@ -448,20 +448,8 @@ def upload(client, system, path, uploaded_file): file_listing = client.files.listFiles(systemId=system, path=path) uploaded_file.name = increment_file_name(listing=file_listing, file_name=uploaded_file.name) - base_url = settings.TAPIS_TENANT_BASEURL - token = client.access_token.access_token - systemId = system dest_path = os.path.join(path.strip('/'), uploaded_file.name) - - res = r.post( - url=f'{base_url}/v3/files/ops/{systemId}/{dest_path}', - files={"file": uploaded_file.file}, - headers={"X-Tapis-Token": token}) - - res.raise_for_status() - - response_json = res.json() - + response_json = client.files.insert(systemId=system, path=dest_path, file=uploaded_file) tapis_indexer.apply_async(kwargs={'access_token': client.access_token.access_token, 'systemId': system, 'filePath': path, diff --git a/server/portal/libs/agave/operations_unit_test.py b/server/portal/libs/agave/operations_unit_test.py index 269826025..81ddfaa85 100644 --- a/server/portal/libs/agave/operations_unit_test.py +++ b/server/portal/libs/agave/operations_unit_test.py @@ -74,7 +74,7 @@ def test_search(self, mock_search, mock_listing): "name._exact, name._pattern"], default_operator='and')) - mock_search().query().filter.assert_called_with('prefix', **{'path._exact': '/path'}) + mock_search().query().filter.assert_called_with('prefix', **{'path._exact': 'path'}) mock_search().query().filter().filter.assert_called_with('term', **{'system._exact': 'test.system'}) mock_search().query().filter().filter().extra.assert_called_with(from_=int(0), size=int(100)) self.assertEqual(search_res, {'listing': diff --git a/server/portal/libs/elasticsearch/docs/base.py b/server/portal/libs/elasticsearch/docs/base.py index 9d17e3315..c52b36be7 100644 --- a/server/portal/libs/elasticsearch/docs/base.py +++ b/server/portal/libs/elasticsearch/docs/base.py @@ -17,37 +17,21 @@ class IndexedProject(Document): + id = Keyword(fields={'_exact': Keyword()}) title = Text(fields={'_exact': Keyword()}) description = Text() - created = Date() - lastModified = Date() - projectId = Keyword() + path = Text() + name = Text() + host = Text() owner = Object( - properties={ - 'username': Keyword(), - 'fullName': Text() - } - ) - pi = Object( - properties={ - 'username': Keyword(), - 'fullName': Text() - } - ) - coPIs = Object( - multi=True, - properties={ - 'username': Keyword(), - 'fullName': Text() - } - ) - teamMembers = Object( - multi=True, - properties={ - 'username': Keyword(), - 'fullName': Text() - } + properties={ + 'username': Keyword(), + 'firstName': Text(), + 'lastName': Text(), + 'email': Text() + } ) + updated = Date() @classmethod def from_id(cls, projectId): diff --git a/server/portal/libs/elasticsearch/utils.py b/server/portal/libs/elasticsearch/utils.py index cd2c2cc75..90666209f 100644 --- a/server/portal/libs/elasticsearch/utils.py +++ b/server/portal/libs/elasticsearch/utils.py @@ -219,3 +219,25 @@ def index_listing(files): }) bulk(client, ops) + + +def index_project_listing(projects): + from portal.libs.elasticsearch.docs.base import IndexedProject + + idx = IndexedProject.Index.name + client = get_connection('default') + ops = [] + + for _project in projects: + project_dict = dict(_project) + project_dict['updated'] = current_time() + project_uuid = get_sha256_hash(project_dict['id']) + ops.append({ + '_index': idx, + '_id': project_uuid, + 'doc': project_dict, + '_op_type': 'update', + 'doc_as_upsert': True + }) + + bulk(client, ops) diff --git a/server/portal/settings/settings.py b/server/portal/settings/settings.py index e2e82770f..d4c6ae458 100644 --- a/server/portal/settings/settings.py +++ b/server/portal/settings/settings.py @@ -512,7 +512,7 @@ PORTAL_DATAFILES_STORAGE_SYSTEMS = getattr( settings_custom, '_PORTAL_DATAFILES_STORAGE_SYSTEMS', [] ) -PORTAL_DATAFILES_DEFAULT_STORAGE_SYSTEM = next((sys for sys in PORTAL_DATAFILES_STORAGE_SYSTEMS if sys['default'] is True), None) +PORTAL_DATAFILES_DEFAULT_STORAGE_SYSTEM = next((sys for sys in PORTAL_DATAFILES_STORAGE_SYSTEMS if sys.get('default')), None) PORTAL_SEARCH_MANAGERS = { 'my-data': 'portal.apps.search.api.managers.private_data_search.PrivateDataSearchManager', diff --git a/server/portal/settings/settings_default.py b/server/portal/settings/settings_default.py index 433b52d3b..443520033 100644 --- a/server/portal/settings/settings_default.py +++ b/server/portal/settings/settings_default.py @@ -59,22 +59,21 @@ _PORTAL_DATAFILES_STORAGE_SYSTEMS = [ { - 'name': 'My Data (Corral)', - 'system': 'cloud.data', + 'name': 'My Data (Work)', + 'system': 'frontera', 'scheme': 'private', 'api': 'tapis', - 'homeDir': '/home/{username}', + 'homeDir': '/work/{tasdir}', 'icon': None, - 'keyservice': True, 'default': True }, { - 'name': 'My Data (Work)', + 'name': 'My Data (Scratch)', 'system': 'frontera', 'scheme': 'private', 'api': 'tapis', - 'homeDir': '/work/{tasdir}', - 'icon': None, + 'homeDir': '/scratch1/{tasdir}', + 'icon': None }, { 'name': 'My Data (Frontera)', diff --git a/server/pyproject.toml b/server/pyproject.toml index 798b9a066..af2cdcad9 100644 --- a/server/pyproject.toml +++ b/server/pyproject.toml @@ -37,7 +37,7 @@ python-magic = "^0.4.18" zeep = "^4.1.0" tapipy = "^1.3" pyopenssl = "^23.1.1" -gevent = "^22.10.2" +gevent = "^23.9.1" pymemcache = "^4.0.0" [tool.poetry.group.dev.dependencies] diff --git a/server/pytest.ini b/server/pytest.ini index 7f9c0a6d5..2e8f63f32 100644 --- a/server/pytest.ini +++ b/server/pytest.ini @@ -1,3 +1,17 @@ [pytest] DJANGO_SETTINGS_MODULE = portal.settings.unit_test_settings python_files = tests.py *unit_test.py + +filterwarnings = + ignore::DeprecationWarning:django.*: + ignore::DeprecationWarning:openapi_schema_validator.*: + ignore::DeprecationWarning:openapi_spec_validator.*: + ignore::DeprecationWarning:openapi_core.*: + ignore::DeprecationWarning:kombu.*: + ignore::DeprecationWarning:pkg_resources.*: + ignore:.*Django now detects this configuration.*:django.utils.deprecation.RemovedInDjango41Warning + +markers = + asyncio: mark a test as asyncio. + +# refer to WP-271 for follow up on Deprecation Warnings