diff --git a/.deps/dev.md b/.deps/dev.md index 4e698a163..8aa9c1e16 100644 --- a/.deps/dev.md +++ b/.deps/dev.md @@ -47,7 +47,6 @@ | [`@csstools/css-tokenizer@2.2.1`](https://github.com/csstools/postcss-plugins.git) | MIT | clearlydefined | | [`@csstools/media-query-list-parser@2.1.5`](https://github.com/csstools/postcss-plugins.git) | MIT | clearlydefined | | [`@csstools/selector-specificity@3.0.0`](https://github.com/csstools/postcss-plugins.git) | MIT-0 | transitive dependency | -| [`@devfile/api@2.2.2-1700686170`](https://github.com/GIT_USER_ID/GIT_REPO_ID.git) | Apache-2.0 | N/A | | [`@discoveryjs/json-ext@0.5.7`](https://github.com/discoveryjs/json-ext.git) | MIT | clearlydefined | | `@eclipse-che/api@7.80.0` | EPL-2.0 | ecd.che | | [`@eslint-community/eslint-utils@4.4.0`](https://github.com/eslint-community/eslint-utils) | MIT | #8032 | @@ -172,10 +171,11 @@ | [`@types/minimist@1.2.4`](https://github.com/DefinitelyTyped/DefinitelyTyped.git) | MIT | #10839 | | [`@types/normalize-package-data@2.4.3`](https://github.com/DefinitelyTyped/DefinitelyTyped.git) | MIT | #10792 | | [`@types/parse-json@4.0.1`](https://github.com/DefinitelyTyped/DefinitelyTyped.git) | MIT | clearlydefined | -| [`@types/qs@6.9.9`](https://github.com/DefinitelyTyped/DefinitelyTyped.git) | MIT | clearlydefined | +| [`@types/qs@6.9.9`](https://github.com/DefinitelyTyped/DefinitelyTyped.git) | MIT | #13991 | | [`@types/react-copy-to-clipboard@4.3.0`](https://github.com/DefinitelyTyped/DefinitelyTyped.git) | MIT | clearlydefined | | [`@types/react-test-renderer@18.0.5`](https://github.com/DefinitelyTyped/DefinitelyTyped.git) | MIT | clearlydefined | | [`@types/redux-mock-store@1.0.5`](https://github.com/DefinitelyTyped/DefinitelyTyped.git) | MIT | clearlydefined | +| [`@types/request@2.48.12`](https://github.com/DefinitelyTyped/DefinitelyTyped.git) | MIT | clearlydefined | | [`@types/sanitize-html@2.9.3`](https://github.com/DefinitelyTyped/DefinitelyTyped.git) | MIT | clearlydefined | | [`@types/semver@7.5.4`](https://github.com/DefinitelyTyped/DefinitelyTyped.git) | MIT | #10842 | | [`@types/stack-utils@2.0.2`](https://github.com/DefinitelyTyped/DefinitelyTyped.git) | MIT | clearlydefined | @@ -265,7 +265,6 @@ | [`bl@4.1.0`](https://github.com/rvagg/bl.git) | MIT | clearlydefined | | [`boolbase@1.0.0`](https://github.com/fb55/boolbase) | ISC | clearlydefined | | [`bplist-parser@0.2.0`](https://github.com/nearinfinity/node-bplist-parser.git) | MIT | clearlydefined | -| [`brace-expansion@2.0.1`](git://github.com/juliangruber/brace-expansion.git) | MIT | clearlydefined | | [`braces@3.0.2`](https://github.com/micromatch/braces.git) | MIT | clearlydefined | | [`browserslist@4.22.1`](https://github.com/browserslist/browserslist.git) | MIT | #10780 | | [`bs-logger@0.2.6`](git+https://github.com/huafu/bs-logger.git) | MIT | clearlydefined | @@ -388,7 +387,7 @@ | [`err-code@2.0.3`](git://github.com/IndigoUnited/js-err-code.git) | MIT | clearlydefined | | [`error-ex@1.3.2`](https://github.com/qix-/node-error-ex.git) | MIT | clearlydefined | | [`es-abstract@1.22.3`](git://github.com/ljharb/es-abstract.git) | MIT | #9656 | -| [`es-iterator-helpers@1.0.15`](git+https://github.com/es-shims/iterator-helpers.git) | MIT | clearlydefined | +| [`es-iterator-helpers@1.0.15`](git+https://github.com/es-shims/iterator-helpers.git) | MIT | #13907 | | [`es-module-lexer@1.3.1`](git+https://github.com/guybedford/es-module-lexer.git) | MIT | #8964 | | [`es-set-tostringtag@2.0.2`](git+https://github.com/es-shims/es-set-tostringtag.git) | MIT | #6218 | | [`es-shim-unscopables@1.0.2`](git+https://github.com/ljharb/es-shim-unscopables.git) | MIT | clearlydefined | @@ -411,6 +410,7 @@ | [`esquery@1.5.0`](https://github.com/estools/esquery.git) | BSD-3-Clause | #7469 | | [`esrecurse@4.3.0`](https://github.com/estools/esrecurse.git) | BSD-2-Clause | clearlydefined | | [`estraverse@5.3.0`](http://github.com/estools/estraverse.git) | BSD-2-Clause | #1557 | +| [`esutils@2.0.3`](http://github.com/estools/esutils.git) | BSD-2-Clause | #120 | | [`eventemitter3@4.0.7`](git://github.com/primus/eventemitter3.git) | MIT | clearlydefined | | [`execa@5.1.1`](https://github.com/sindresorhus/execa.git) | MIT | clearlydefined | | [`exit@0.1.2`](git://github.com/cowboy/node-exit.git) | MIT | clearlydefined | @@ -644,6 +644,7 @@ | [`mimic-fn@2.1.0`](https://github.com/sindresorhus/mimic-fn.git) | MIT | clearlydefined | | [`min-indent@1.0.1`](https://github.com/thejameskyle/min-indent) | MIT | clearlydefined | | [`mini-css-extract-plugin@2.7.6`](https://github.com/webpack-contrib/mini-css-extract-plugin.git) | MIT | #5004 | +| [`minimatch@3.1.2`](git://github.com/isaacs/minimatch.git) | ISC | clearlydefined | | [`minimist-options@4.1.0`](https://github.com/vadimdemedes/minimist-options.git) | MIT | clearlydefined | | `minipass-collect@1.0.2` | ISC | clearlydefined | | [`minipass-fetch@3.0.4`](https://github.com/npm/minipass-fetch.git) | MIT | #5764 | @@ -696,6 +697,7 @@ | [`opener@1.5.2`](https://github.com/domenic/opener.git) | (WTFPL OR MIT) | #11619 | | [`optionator@0.9.3`](git://github.com/gkz/optionator.git) | MIT | #9208 | | [`ora@5.4.1`](https://github.com/sindresorhus/ora.git) | MIT | clearlydefined | +| [`os-tmpdir@1.0.2`](https://github.com/sindresorhus/os-tmpdir.git) | MIT | clearlydefined | | [`p-finally@1.0.0`](https://github.com/sindresorhus/p-finally.git) | MIT | clearlydefined | | [`p-locate@4.1.0`](https://github.com/sindresorhus/p-locate.git) | MIT | clearlydefined | | [`p-map-series@2.1.0`](https://github.com/sindresorhus/p-map-series.git) | MIT | clearlydefined | @@ -791,7 +793,7 @@ | [`rechoir@0.8.0`](https://github.com/gulpjs/rechoir.git) | MIT | clearlydefined | | [`redent@3.0.0`](https://github.com/sindresorhus/redent.git) | MIT | clearlydefined | | [`redux-mock-store@1.5.4`](git+https://github.com/arnaudbenard/redux-mock-store.git) | MIT | clearlydefined | -| [`reflect.getprototypeof@1.0.4`](git+https://github.com/es-shims/Reflect.getPrototypeOf.git) | MIT | clearlydefined | +| [`reflect.getprototypeof@1.0.4`](git+https://github.com/es-shims/Reflect.getPrototypeOf.git) | MIT | #13910 | | [`regexp.prototype.flags@1.5.1`](git://github.com/es-shims/RegExp.prototype.flags.git) | MIT | #8199 | | [`relateurl@0.2.7`](git://github.com/stevenvachon/relateurl.git) | MIT | clearlydefined | | [`renderkid@3.0.0`](https://github.com/AriaMinaei/RenderKid.git) | MIT | clearlydefined | diff --git a/.deps/prod.md b/.deps/prod.md index 5c1069999..6e0fb8658 100644 --- a/.deps/prod.md +++ b/.deps/prod.md @@ -3,13 +3,11 @@ | Packages | License | Resolved CQs | | --- | --- | --- | | [`@babel/runtime@7.23.2`](https://github.com/babel/babel.git) | MIT | #10718 | -| [`@devfile/api@2.2.0-alpha-1637255314`](https://github.com/devfile/api.git) | EPL-2.0 | clearlydefined | -| `@eclipse-che/api@7.76.0` | EPL-2.0 | ecd.che | +| [`@devfile/api@2.2.2-1700686170`](https://github.com/GIT_USER_ID/GIT_REPO_ID.git) | Apache-2.0 | clearlydefined | | [`@eclipse-che/che-devworkspace-generator@7.79.0-next-1427c19`](git+https://github.com/eclipse-che/che-devfile-registry.git) | EPL-2.0 | ecd.che | -| [`@eclipse-che/common@7.83.0-next`](https://github.com/eclipse-che/che-dashboard) | EPL-2.0 | ecd.che | -| [`@eclipse-che/dashboard-backend@7.83.0-next`](https://github.com/eclipse-che/che-dashboard) | EPL-2.0 | ecd.che | -| [`@eclipse-che/dashboard-frontend@7.83.0-next`](git://github.com/eclipse/che-dashboard.git) | EPL-2.0 | ecd.che | -| [`@eclipse-che/devfile-converter@0.0.1-0751ad2`](git+https://github.com/che-incubator/devfile-converter.git) | EPL-2.0 | ecd.che | +| [`@eclipse-che/common@7.84.0-next`](https://github.com/eclipse-che/che-dashboard) | EPL-2.0 | ecd.che | +| [`@eclipse-che/dashboard-backend@7.84.0-next`](https://github.com/eclipse-che/che-dashboard) | EPL-2.0 | ecd.che | +| [`@eclipse-che/dashboard-frontend@7.84.0-next`](git://github.com/eclipse/che-dashboard.git) | EPL-2.0 | ecd.che | | [`@fastify/accept-negotiator@1.1.0`](git+https://github.com/fastify/accept-negotiator.git) | MIT | clearlydefined | | [`@fastify/ajv-compiler@3.5.0`](git+https://github.com/fastify/ajv-compiler.git) | MIT | clearlydefined | | [`@fastify/busboy@2.0.0`](https://github.com/fastify/busboy.git) | MIT | clearlydefined | @@ -41,7 +39,6 @@ | [`@sideway/address@4.1.4`](git://github.com/sideway/address) | BSD-3-Clause | #3098 | | [`@sideway/formula@3.0.1`](git://github.com/sideway/formula) | BSD-3-Clause | clearlydefined | | [`@sideway/pinpoint@2.0.0`](git://github.com/sideway/pinpoint) | BSD-3-Clause | clearlydefined | -| [`@types/bluebird@3.5.21`](https://github.com/DefinitelyTyped/DefinitelyTyped.git) | MIT | clearlydefined | | [`@types/caseless@0.12.4`](https://github.com/DefinitelyTyped/DefinitelyTyped.git) | MIT | clearlydefined | | [`@types/hoist-non-react-statics@3.3.4`](https://github.com/DefinitelyTyped/DefinitelyTyped.git) | MIT | clearlydefined | | [`@types/js-yaml@4.0.8`](https://github.com/DefinitelyTyped/DefinitelyTyped.git) | MIT | clearlydefined | @@ -58,7 +55,6 @@ | [`abstract-logging@2.0.1`](git+https://github.com/jsumners/abstract-logging.git) | MIT | clearlydefined | | [`ajv-formats@2.1.1`](git+https://github.com/ajv-validator/ajv-formats.git) | MIT | clearlydefined | | [`ajv@8.12.0`](https://github.com/ajv-validator/ajv.git) | MIT | #6025 | -| [`ansi-regex@2.1.1`](https://github.com/chalk/ansi-regex.git) | MIT | #5896 | | [`ansi-styles@3.2.1`](https://github.com/chalk/ansi-styles.git) | MIT | clearlydefined | | [`archy@1.0.0`](http://github.com/substack/node-archy.git) | MIT | clearlydefined | | [`argparse@2.0.1`](https://github.com/nodeca/argparse.git) | Python-2.0 | [CQ22954](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=22954) | @@ -73,25 +69,12 @@ | [`aws-sign2@0.7.0`](https://github.com/mikeal/aws-sign) | Apache-2.0 | clearlydefined | | [`aws4@1.12.0`](https://github.com/mhart/aws4.git) | MIT | #6221 | | [`axios@1.6.2`](https://github.com/axios/axios.git) | MIT | #11338 | -| [`babel-code-frame@6.26.0`](https://github.com/babel/babel/tree/master/packages/babel-code-frame) | MIT | clearlydefined | -| [`babel-core@6.26.3`](https://github.com/babel/babel/tree/master/packages/babel-core) | MIT | clearlydefined | -| [`babel-generator@6.26.1`](https://github.com/babel/babel/tree/master/packages/babel-generator) | MIT | clearlydefined | -| [`babel-helpers@6.24.1`](https://github.com/babel/babel/tree/master/packages/babel-helpers) | MIT | clearlydefined | -| [`babel-messages@6.23.0`](https://github.com/babel/babel/tree/master/packages/babel-messages) | MIT | clearlydefined | -| [`babel-plugin-transform-es2015-block-scoping@6.26.0`](https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-es2015-block-scoping) | MIT | clearlydefined | -| [`babel-register@6.26.0`](https://github.com/babel/babel/tree/master/packages/babel-register) | MIT | clearlydefined | -| [`babel-runtime@6.26.0`](https://github.com/babel/babel/tree/master/packages/babel-runtime) | MIT | #943 | -| [`babel-template@6.26.0`](https://github.com/babel/babel/tree/master/packages/babel-template) | MIT | clearlydefined | -| [`babel-traverse@6.26.0`](https://github.com/babel/babel/tree/master/packages/babel-traverse) | MIT | clearlydefined | -| [`babel-types@6.26.0`](https://github.com/babel/babel/tree/master/packages/babel-types) | MIT | clearlydefined | -| [`babylon@6.18.0`](https://github.com/babel/babylon) | MIT | #1052 | | [`balanced-match@1.0.2`](git://github.com/juliangruber/balanced-match.git) | MIT | clearlydefined | | [`base64-js@1.5.1`](git://github.com/beatgammit/base64-js.git) | MIT | clearlydefined | | [`bcrypt-pbkdf@1.0.2`](git://github.com/joyent/node-bcrypt-pbkdf.git) | BSD-3-Clause | #2725 | -| [`bluebird@3.7.2`](git://github.com/petkaantonov/bluebird.git) | MIT | clearlydefined | | [`blueimp-md5@2.19.0`](git://github.com/blueimp/JavaScript-MD5.git) | MIT | [clearlydefined](https://clearlydefined.io/definitions/npm/npmjs/-/blueimp-md5/2.19.0) | | [`bn.js@4.12.0`](git@github.com:indutny/bn.js) | MIT | clearlydefined | -| [`brace-expansion@1.1.11`](git://github.com/juliangruber/brace-expansion.git) | MIT | clearlydefined | +| [`brace-expansion@2.0.1`](git://github.com/juliangruber/brace-expansion.git) | MIT | clearlydefined | | [`brorand@1.1.0`](git@github.com:indutny/brorand) | MIT | clearlydefined | | [`browserify-aes@1.2.0`](git://github.com/crypto-browserify/browserify-aes.git) | MIT | clearlydefined | | [`browserify-cipher@1.0.1`](git@github.com:crypto-browserify/browserify-cipher.git) | MIT | clearlydefined | @@ -115,7 +98,6 @@ | [`concat-map@0.0.1`](git://github.com/substack/node-concat-map.git) | MIT | clearlydefined | | [`connected-react-router@6.9.3`](https://github.com/supasate/connected-react-router.git) | MIT | clearlydefined | | [`content-disposition@0.5.4`](https://github.com/jshttp/content-disposition.git) | MIT | clearlydefined | -| [`convert-source-map@1.9.0`](git://github.com/thlorenz/convert-source-map.git) | MIT | clearlydefined | | [`cookie@0.5.0`](https://github.com/jshttp/cookie.git) | MIT | clearlydefined | | [`copy-to-clipboard@3.3.3`](git+https://github.com/sudodoki/copy-to-clipboard) | MIT | clearlydefined | | [`core-js@2.6.12`](https://github.com/zloirock/core-js.git) | MIT | #2912 | @@ -135,7 +117,6 @@ | [`depd@2.0.0`](https://github.com/dougwilson/nodejs-depd.git) | MIT | clearlydefined | | [`des.js@1.1.0`](git+ssh://git@github.com/indutny/des.js.git) | MIT | clearlydefined | | [`detect-browser@5.3.0`](https://github.com/DamonOehlman/detect-browser.git) | MIT | clearlydefined | -| [`detect-indent@4.0.0`](https://github.com/sindresorhus/detect-indent.git) | MIT | clearlydefined | | [`diffie-hellman@5.0.3`](https://github.com/crypto-browserify/diffie-hellman.git) | MIT | clearlydefined | | [`dom-serializer@2.0.0`](git://github.com/cheeriojs/dom-serializer.git) | MIT | clearlydefined | | [`domelementtype@2.3.0`](git://github.com/fb55/domelementtype.git) | BSD-2-Clause | clearlydefined | @@ -147,8 +128,7 @@ | [`entities@4.5.0`](git://github.com/fb55/entities.git) | BSD-2-Clause | #7910 | | [`es6-promise@4.2.8`](git://github.com/stefanpenner/es6-promise.git) | MIT | #2898 | | [`escape-html@1.0.3`](https://github.com/component/escape-html.git) | MIT | clearlydefined | -| [`escape-string-regexp@1.0.5`](https://github.com/sindresorhus/escape-string-regexp.git) | MIT | clearlydefined | -| [`esutils@2.0.3`](http://github.com/estools/esutils.git) | BSD-2-Clause | #120 | +| [`escape-string-regexp@4.0.0`](https://github.com/sindresorhus/escape-string-regexp.git) | MIT | clearlydefined | | [`event-target-shim@5.0.1`](https://github.com/mysticatea/event-target-shim.git) | MIT | #7578 | | [`events@3.3.0`](git://github.com/Gozala/events.git) | MIT | clearlydefined | | [`evp_bytestokey@1.0.3`](https://github.com/crypto-browserify/EVP_BytesToKey.git) | MIT | clearlydefined | @@ -181,13 +161,11 @@ | [`get-intrinsic@1.2.2`](git+https://github.com/ljharb/get-intrinsic.git) | MIT | #8453 | | [`getpass@0.1.7`](https://github.com/arekinath/node-getpass.git) | MIT | clearlydefined | | [`glob@8.1.0`](git://github.com/isaacs/node-glob.git) | ISC | #7145 | -| [`globals@9.18.0`](https://github.com/sindresorhus/globals.git) | MIT | clearlydefined | | [`gopd@1.0.1`](git+https://github.com/ljharb/gopd.git) | MIT | #4863 | | [`graceful-fs@4.2.11`](https://github.com/isaacs/node-graceful-fs) | ISC | #7413 | | [`gravatar-url@4.0.1`](https://github.com/sindresorhus/gravatar-url.git) | MIT | clearlydefined | | [`har-schema@2.0.0`](https://github.com/ahmadnassri/har-schema.git) | ISC | clearlydefined | | [`har-validator@5.1.5`](https://github.com/ahmadnassri/node-har-validator.git) | MIT | clearlydefined | -| [`has-ansi@2.0.0`](https://github.com/sindresorhus/has-ansi.git) | MIT | clearlydefined | | [`has-flag@3.0.0`](https://github.com/sindresorhus/has-flag.git) | MIT | clearlydefined | | [`has-property-descriptors@1.0.1`](git+https://github.com/inspect-js/has-property-descriptors.git) | MIT | #11098 | | [`has-proto@1.0.1`](git+https://github.com/inspect-js/has-proto.git) | MIT | #6175 | @@ -199,7 +177,6 @@ | [`history@4.10.1`](https://github.com/ReactTraining/history.git) | MIT | clearlydefined | | [`hmac-drbg@1.0.1`](git+ssh://git@github.com/indutny/hmac-drbg.git) | MIT | clearlydefined | | [`hoist-non-react-statics@3.3.2`](git://github.com/mridgway/hoist-non-react-statics.git) | BSD-3-Clause | clearlydefined | -| [`home-or-tmp@2.0.0`](https://github.com/sindresorhus/home-or-tmp.git) | MIT | clearlydefined | | [`htmlparser2@8.0.2`](git://github.com/fb55/htmlparser2.git) | MIT | clearlydefined | | [`http-errors@2.0.0`](https://github.com/jshttp/http-errors.git) | MIT | clearlydefined | | [`http-signature@1.2.0`](git://github.com/joyent/node-http-signature.git) | MIT | #2732 | @@ -208,12 +185,10 @@ | [`immutable@4.3.4`](git://github.com/immutable-js/immutable-js.git) | MIT | #7353 | | [`inflight@1.0.6`](https://github.com/npm/inflight.git) | ISC | clearlydefined | | [`inherits@2.0.4`](git://github.com/isaacs/inherits) | ISC | clearlydefined | -| [`invariant@2.2.4`](https://github.com/zertosh/invariant) | MIT | #1034 | | [`inversify-inject-decorators@3.1.0`](git+https://github.com/inversify/inversify-inject-decorators.git) | MIT | clearlydefined | | [`inversify-react@1.1.0`](https://github.com/Kukkimonsuta/inversify-react.git) | Apache-2.0 | clearlydefined | | [`inversify@6.0.2`](https://github.com/inversify/InversifyJS.git) | MIT | clearlydefined | | [`ipaddr.js@1.9.1`](git://github.com/whitequark/ipaddr.js) | MIT | clearlydefined | -| [`is-finite@1.1.0`](https://github.com/sindresorhus/is-finite.git) | MIT | clearlydefined | | [`is-plain-object@5.0.0`](https://github.com/jonschlinkert/is-plain-object.git) | MIT | clearlydefined | | [`is-typedarray@1.0.0`](git://github.com/hughsk/is-typedarray.git) | MIT | #2531 | | [`isarray@0.0.1`](git://github.com/juliangruber/isarray.git) | MIT | clearlydefined | @@ -225,13 +200,11 @@ | [`js-tokens@4.0.0`](https://github.com/lydell/js-tokens.git) | MIT | #2401 | | [`js-yaml@4.1.0`](https://github.com/nodeca/js-yaml.git) | MIT | clearlydefined | | [`jsbn@0.1.1`](https://github.com/andyperlitch/jsbn.git) | MIT | clearlydefined | -| [`jsesc@1.3.0`](https://github.com/mathiasbynens/jsesc.git) | MIT | clearlydefined | | [`json-schema-ref-resolver@1.0.1`](git+https://github.com/fastify/json-schema-ref-resolver.git) | MIT | clearlydefined | | [`json-schema-resolver@2.0.0`](git+https://github.com/Eomm/json-schema-resolver.git) | MIT | clearlydefined | | [`json-schema-traverse@1.0.0`](git+https://github.com/epoberezkin/json-schema-traverse.git) | MIT | clearlydefined | | [`json-schema@0.4.0`](http://github.com/kriszyp/json-schema) | (AFL-2.1 OR BSD-3-Clause) | #2410 | | [`json-stringify-safe@5.0.1`](git://github.com/isaacs/json-stringify-safe) | ISC | clearlydefined | -| [`json5@0.5.1`](https://github.com/aseemk/json5.git) | MIT | #1040 | | [`jsonc-parser@3.2.0`](https://github.com/microsoft/node-jsonc-parser) | MIT | #12891 | | [`jsonfile@6.1.0`](git@github.com:jprichardson/node-jsonfile.git) | MIT | clearlydefined | | [`jsonpath-plus@7.2.0`](git://github.com/s3u/JSONPath.git) | MIT | clearlydefined | @@ -251,7 +224,7 @@ | [`mime@3.0.0`](https://github.com/broofa/mime) | MIT | clearlydefined | | [`minimalistic-assert@1.0.1`](https://github.com/calvinmetcalf/minimalistic-assert.git) | ISC | clearlydefined | | [`minimalistic-crypto-utils@1.0.1`](git+ssh://git@github.com/indutny/minimalistic-crypto-utils.git) | MIT | clearlydefined | -| [`minimatch@3.1.2`](git://github.com/isaacs/minimatch.git) | ISC | clearlydefined | +| [`minimatch@5.1.6`](git://github.com/isaacs/minimatch.git) | ISC | #5952 | | [`minimist@1.2.8`](git://github.com/minimistjs/minimist.git) | MIT | #5886 | | [`minipass@3.3.6`](git+https://github.com/isaacs/minipass.git) | ISC | clearlydefined | | [`minizlib@2.1.2`](git+https://github.com/isaacs/minizlib.git) | MIT | clearlydefined | @@ -272,8 +245,6 @@ | [`once@1.4.0`](git://github.com/isaacs/once) | ISC | clearlydefined | | [`openapi-types@12.1.3`](https://github.com/kogosoftwarellc/open-api/tree/master/packages/openapi-types) | MIT | clearlydefined | | [`openid-client@5.6.1`](https://github.com/panva/node-openid-client.git) | MIT | clearlydefined | -| [`os-homedir@1.0.2`](https://github.com/sindresorhus/os-homedir.git) | MIT | clearlydefined | -| [`os-tmpdir@1.0.2`](https://github.com/sindresorhus/os-tmpdir.git) | MIT | clearlydefined | | [`p-limit@3.1.0`](https://github.com/sindresorhus/p-limit.git) | MIT | clearlydefined | | [`parse-asn1@5.1.6`](git://github.com/crypto-browserify/parse-asn1.git) | ISC | clearlydefined | | [`parse-srcset@1.0.2`](git+https://github.com/albell/parse-srcset.git) | MIT | clearlydefined | @@ -288,7 +259,6 @@ | [`pino@8.16.1`](git+https://github.com/pinojs/pino.git) | MIT | clearlydefined | | [`popper.js@1.16.1`](git+https://github.com/FezVrasta/popper.js.git) | MIT | [CQ22353](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=22353) | | [`postcss@8.4.31`](https://github.com/postcss/postcss.git) | MIT | #3545 | -| [`private@0.1.8`](git://github.com/benjamn/private.git) | MIT | clearlydefined | | [`process-warning@2.3.0`](git+https://github.com/fastify/process-warning.git) | MIT | clearlydefined | | [`process@0.11.10`](git://github.com/shtylman/node-process.git) | MIT | [CQ23452](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=23452) | | [`prop-types-extra@1.1.1`](git+https://github.com/react-bootstrap/prop-types-extra.git) | MIT | [CQ22354](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=22354) | @@ -325,7 +295,6 @@ | [`redux@4.2.1`](https://github.com/reduxjs/redux.git) | MIT | #7046 | | [`reflect-metadata@0.1.13`](https://github.com/rbuckton/reflect-metadata.git) | Apache-2.0 | clearlydefined | | [`regenerator-runtime@0.14.0`](https://github.com/facebook/regenerator/tree/main/packages/runtime) | MIT | #9897 | -| [`repeating@2.0.1`](https://github.com/sindresorhus/repeating.git) | MIT | clearlydefined | | [`request@2.88.2`](https://github.com/request/request.git) | Apache-2.0 | #997 | | [`require-from-string@2.0.2`](https://github.com/floatdrop/require-from-string.git) | MIT | clearlydefined | | [`requires-port@1.0.0`](https://github.com/unshiftio/requires-port) | MIT | clearlydefined | @@ -333,7 +302,6 @@ | [`resolve-pathname@3.0.0`](https://github.com/mjackson/resolve-pathname.git) | MIT | clearlydefined | | [`ret@0.2.2`](git://github.com/fent/ret.js.git) | MIT | clearlydefined | | [`reusify@1.0.4`](git+https://github.com/mcollina/reusify.git) | MIT | clearlydefined | -| [`rewire@3.0.2`](git://github.com/jhnns/rewire.git) | MIT | clearlydefined | | [`rfc4648@1.5.3`](git@github.com:swansontec/rfc4648.js.git) | MIT | clearlydefined | | [`rfdc@1.3.0`](git+https://github.com/davidmarkclements/rfdc.git) | MIT | clearlydefined | | [`rimraf@3.0.2`](git://github.com/isaacs/rimraf.git) | ISC | clearlydefined | @@ -353,18 +321,14 @@ | [`sha.js@2.4.11`](git://github.com/crypto-browserify/sha.js.git) | (MIT AND BSD-3-Clause) | #1031 | | [`side-channel@1.0.4`](git+https://github.com/ljharb/side-channel.git) | MIT | clearlydefined | | [`simple-oauth2@5.0.0`](https://github.com/lelylan/simple-oauth2) | Apache-2.0 | clearlydefined | -| [`slash@1.0.0`](https://github.com/sindresorhus/slash.git) | MIT | clearlydefined | | [`sonic-boom@3.7.0`](git+https://github.com/pinojs/sonic-boom.git) | MIT | clearlydefined | | [`source-map-js@1.0.2`](https://github.com/7rulnik/source-map-js.git) | BSD-3-Clause | #2412 | -| [`source-map-support@0.4.18`](https://github.com/evanw/node-source-map-support) | MIT | clearlydefined | -| [`source-map@0.5.7`](http://github.com/mozilla/source-map.git) | BSD-3-Clause | #2400 | | [`split2@4.2.0`](https://github.com/mcollina/split2.git) | ISC | clearlydefined | | [`sshpk@1.18.0`](git+https://github.com/joyent/node-sshpk.git) | MIT | clearlydefined | | [`statuses@2.0.1`](https://github.com/jshttp/statuses.git) | MIT | clearlydefined | | [`stream-browserify@3.0.0`](git://github.com/browserify/stream-browserify.git) | MIT | clearlydefined | | [`stream-buffers@3.0.2`](https://github.com/samcday/node-stream-buffer.git) | Unlicense | clearlydefined | | [`string_decoder@1.3.0`](git://github.com/nodejs/string_decoder.git) | MIT | clearlydefined | -| [`strip-ansi@3.0.1`](https://github.com/chalk/strip-ansi.git) | MIT | clearlydefined | | [`strip-json-comments@3.1.1`](https://github.com/sindresorhus/strip-json-comments.git) | MIT | clearlydefined | | [`supports-color@5.5.0`](https://github.com/chalk/supports-color.git) | MIT | clearlydefined | | [`tabbable@5.3.3`](git+https://github.com/focus-trap/tabbable.git) | MIT | clearlydefined | @@ -376,13 +340,11 @@ | [`tippy.js@5.1.2`](git+https://github.com/atomiks/tippyjs.git) | MIT | clearlydefined | | [`tmp-promise@3.0.3`](git://github.com/benjamingr/tmp-promise.git) | MIT | clearlydefined | | [`tmp@0.2.1`](https://github.com/raszi/node-tmp.git) | MIT | clearlydefined | -| [`to-fast-properties@1.0.3`](https://github.com/sindresorhus/to-fast-properties.git) | MIT | clearlydefined | | [`toad-cache@3.3.0`](git://github.com/kibertoad/toad-cache.git) | MIT | clearlydefined | | [`toggle-selection@1.0.6`](git+https://github.com/sudodoki/toggle-selection) | MIT | clearlydefined | | [`toidentifier@1.0.1`](https://github.com/component/toidentifier.git) | MIT | clearlydefined | | [`tough-cookie@2.5.0`](git://github.com/salesforce/tough-cookie.git) | BSD-3-Clause | clearlydefined | | [`tr46@0.0.3`](git+https://github.com/Sebmaster/tr46.js.git) | MIT | clearlydefined | -| [`trim-right@1.0.1`](https://github.com/sindresorhus/trim-right.git) | MIT | clearlydefined | | [`tslib@2.6.2`](https://github.com/Microsoft/tslib.git) | 0BSD | #9189 | | [`tunnel-agent@0.6.0`](https://github.com/mikeal/tunnel-agent) | Apache-2.0 | clearlydefined | | [`tweetnacl@0.14.5`](https://github.com/dchest/tweetnacl-js.git) | Unlicense | #1035 | diff --git a/packages/dashboard-frontend/jest.config.js b/packages/dashboard-frontend/jest.config.js index 2c2429eaf..c1e014616 100644 --- a/packages/dashboard-frontend/jest.config.js +++ b/packages/dashboard-frontend/jest.config.js @@ -50,10 +50,10 @@ module.exports = { ], coverageThreshold: { global: { - statements: 89, - branches: 86, - functions: 83, - lines: 89, + statements: 90, + branches: 87, + functions: 84, + lines: 90, }, }, }; diff --git a/packages/dashboard-frontend/package.json b/packages/dashboard-frontend/package.json index 2acbd2bde..504a497c5 100644 --- a/packages/dashboard-frontend/package.json +++ b/packages/dashboard-frontend/package.json @@ -32,7 +32,6 @@ "test:watch": "yarn test --watch" }, "dependencies": { - "@eclipse-che/devfile-converter": "0.0.1-0751ad2", "@patternfly/react-core": "^4.276.11", "@patternfly/react-icons": "^4.93.7", "@patternfly/react-table": "^4.113.3", diff --git a/packages/dashboard-frontend/src/__tests__/const.ts b/packages/dashboard-frontend/src/__tests__/const.ts index e09c47e21..e15e77e07 100644 --- a/packages/dashboard-frontend/src/__tests__/const.ts +++ b/packages/dashboard-frontend/src/__tests__/const.ts @@ -14,7 +14,6 @@ import { dump } from 'js-yaml'; import devfileApi from '@/services/devfileApi'; import { FactoryResolver } from '@/services/helpers/types'; -import normalizeDevfileV2 from '@/store/FactoryResolver/normalizeDevfileV2'; export const FACTORY_RESOLVER_DELAY = 600; export const DEVWORKSPACE_RESOURSES_DELAY = 600; @@ -54,14 +53,6 @@ export const factoryResolver: FactoryResolver = { devfile: devfile, links: [], }; -export const devfileV2 = normalizeDevfileV2( - devfile as devfileApi.DevfileLike, - factoryResolver, - 'https://github.com/eclipse-che/che-dashboard', - [], - namespace.name, - { factoryUrl: url }, -); const sampleResourceUrl = 'http://localhost/plugin-registry/v3/plugins/che-incubator/che-code/insiders/devfile.yaml'; export const plugins = { diff --git a/packages/dashboard-frontend/src/__tests__/workspaceCreationTimeCheck.check.tsx b/packages/dashboard-frontend/src/__tests__/workspaceCreationTimeCheck.check.tsx index 6678c3044..38e48e997 100644 --- a/packages/dashboard-frontend/src/__tests__/workspaceCreationTimeCheck.check.tsx +++ b/packages/dashboard-frontend/src/__tests__/workspaceCreationTimeCheck.check.tsx @@ -25,7 +25,6 @@ import { ThunkDispatch } from 'redux-thunk'; import { CREATE_DEVWORKSPACE_DELAY, CREATE_DEVWORKSPACETEMPLATE_DELAY, - devfileV2, DEVWORKSPACE_RESOURSES_DELAY, devworkspaceResources, FACTORY_RESOLVER_DELAY, @@ -43,7 +42,7 @@ import Routes from '@/Routes'; import devfileApi from '@/services/devfileApi'; import { AppState } from '@/store'; import { FakeStoreBuilder } from '@/store/__mocks__/storeBuilder'; -import { ConvertedState, ResolverState } from '@/store/FactoryResolver'; +import { FactoryResolverStateResolver } from '@/store/FactoryResolver'; // mute the outputs console.error = jest.fn(); @@ -172,13 +171,11 @@ describe('Workspace creation time', () => { .withInfrastructureNamespace([namespace]) .withFactoryResolver({ resolver: Object.assign( - { location: 'https://github.com/eclipse-che/che-dashboard' } as ResolverState, + { + location: 'https://github.com/eclipse-che/che-dashboard', + } as FactoryResolverStateResolver, factoryResolver, ), - converted: { - isConverted: false, - devfileV2: devfileV2, - } as ConvertedState, }) .withDwServerConfig({ defaults: { diff --git a/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/Apply/Devfile/__tests__/index.spec.tsx b/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/Apply/Devfile/__tests__/index.spec.tsx index 02f611030..aeaa9a262 100644 --- a/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/Apply/Devfile/__tests__/index.spec.tsx +++ b/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/Apply/Devfile/__tests__/index.spec.tsx @@ -202,7 +202,7 @@ describe('Creating steps, applying a devfile', () => { ]; const store = getStoreBuilder() - .withFactoryResolver({ resolver: undefined, converted: undefined }) + .withFactoryResolver({ resolver: undefined }) .withDevfileRegistries({ registries: { [registryUrl]: { @@ -281,9 +281,7 @@ describe('Creating steps, applying a devfile', () => { resolver: { location: factoryUrl, source: 'repo', - }, - converted: { - devfileV2: devfile, + devfile, }, }) .withDevfileRegistries({ @@ -360,7 +358,7 @@ describe('Creating steps, applying a devfile', () => { ]; const store = getStoreBuilder() - .withFactoryResolver({ resolver: undefined, converted: undefined }) + .withFactoryResolver({ resolver: undefined }) .withDevfileRegistries({ registries: { [registryUrl]: { @@ -431,9 +429,8 @@ describe('Creating steps, applying a devfile', () => { const store = getStoreBuilder() .withFactoryResolver({ - resolver: {}, - converted: { - devfileV2: devfile, + resolver: { + devfile, }, }) .withDevfileRegistries({ @@ -486,9 +483,8 @@ describe('Creating steps, applying a devfile', () => { workspaces: [new DevWorkspaceBuilder().withName(devfileName).build()], }) .withFactoryResolver({ - resolver: {}, - converted: { - devfileV2: devfile, + resolver: { + devfile, }, }) .build(); @@ -507,9 +503,8 @@ describe('Creating steps, applying a devfile', () => { workspaces: [new DevWorkspaceBuilder().withName('unique-name').build()], }) .withFactoryResolver({ - resolver: {}, - converted: { - devfileV2: devfile, + resolver: { + devfile, }, }) .build(); @@ -531,9 +526,8 @@ describe('Creating steps, applying a devfile', () => { workspaces: [new DevWorkspaceBuilder().withName('unique-name').build()], }) .withFactoryResolver({ - resolver: {}, - converted: { - devfileV2: devfile, + resolver: { + devfile: devfile, }, }) .build(); @@ -576,9 +570,8 @@ describe('Creating steps, applying a devfile', () => { workspaces: [new DevWorkspaceBuilder().withName('unique-name').build()], }) .withFactoryResolver({ - resolver: {}, - converted: { - devfileV2: devfile, + resolver: { + devfile, }, }) .withDevfileRegistries({ @@ -711,9 +704,8 @@ describe('Creating steps, applying a devfile', () => { test('creation timeout expired, alert notification', async () => { const store = getStoreBuilder() .withFactoryResolver({ - resolver: {}, - converted: { - devfileV2: devfile, + resolver: { + devfile, }, }) .build(); @@ -760,9 +752,8 @@ describe('Creating steps, applying a devfile', () => { test('the new workspace created successfully', async () => { const store = getStoreBuilder() .withFactoryResolver({ - resolver: {}, - converted: { - devfileV2: devfile, + resolver: { + devfile, }, }) .build(); @@ -782,9 +773,8 @@ describe('Creating steps, applying a devfile', () => { // build next store const nextStore = getStoreBuilder() .withFactoryResolver({ - resolver: {}, - converted: { - devfileV2: devfile, + resolver: { + devfile, }, }) .withDevWorkspaces({ @@ -813,9 +803,8 @@ describe('Creating steps, applying a devfile', () => { const store = getStoreBuilder() .withFactoryResolver({ - resolver: {}, - converted: { - devfileV2: devfile, + resolver: { + devfile, }, }) .withDevWorkspaces({ diff --git a/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/Apply/Devfile/index.tsx b/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/Apply/Devfile/index.tsx index bdf49348d..f7bb6c337 100644 --- a/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/Apply/Devfile/index.tsx +++ b/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/Apply/Devfile/index.tsx @@ -42,10 +42,7 @@ import { AlertItem } from '@/services/helpers/types'; import { Workspace } from '@/services/workspace-adapter'; import { AppState } from '@/store'; import { selectDefaultDevfile } from '@/store/DevfileRegistries/selectors'; -import { - selectFactoryResolver, - selectFactoryResolverConverted, -} from '@/store/FactoryResolver/selectors'; +import { selectFactoryResolver } from '@/store/FactoryResolver/selectors'; import { selectDefaultNamespace } from '@/store/InfrastructureNamespaces/selectors'; import * as WorkspacesStore from '@/store/Workspaces'; import { selectDevWorkspaceWarnings } from '@/store/Workspaces/devWorkspaces/selectors'; @@ -227,7 +224,7 @@ class CreatingStepApplyDevfile extends ProgressStep { } protected async runStep(): Promise { - const { factoryResolverConverted, factoryResolver, defaultDevfile } = this.props; + const { factoryResolver, defaultDevfile } = this.props; const { shouldCreate, devfile, warning, continueWithDefaultDevfile } = this.state; if (warning) { @@ -285,8 +282,8 @@ class CreatingStepApplyDevfile extends ProgressStep { if (!_devfile.attributes) { _devfile.attributes = {}; } - if (factoryResolverConverted?.devfileV2 !== undefined) { - const { metadata, projects } = factoryResolverConverted.devfileV2; + if (factoryResolver?.devfile !== undefined) { + const { metadata, projects } = factoryResolver.devfile; _devfile.projects = projects; _devfile.metadata.name = metadata.name; _devfile.metadata.generateName = metadata.generateName; @@ -308,7 +305,7 @@ class CreatingStepApplyDevfile extends ProgressStep { // proceed with the user devfile if (devfile === undefined) { - const resolvedDevfile = factoryResolverConverted?.devfileV2; + const resolvedDevfile = factoryResolver?.devfile; if (resolvedDevfile === undefined) { throw new Error('Failed to resolve the devfile.'); } @@ -458,7 +455,6 @@ const mapStateToProps = (state: AppState) => ({ allWorkspaces: selectAllWorkspaces(state), defaultNamespace: selectDefaultNamespace(state), factoryResolver: selectFactoryResolver(state), - factoryResolverConverted: selectFactoryResolverConverted(state), defaultDevfile: selectDefaultDevfile(state), devWorkspaceWarnings: selectDevWorkspaceWarnings(state), }); diff --git a/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/Apply/Devfile/prepareDevfile.ts b/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/Apply/Devfile/prepareDevfile.ts index 04bf7d3db..b21ae5180 100644 --- a/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/Apply/Devfile/prepareDevfile.ts +++ b/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/Apply/Devfile/prepareDevfile.ts @@ -33,7 +33,7 @@ export function prepareDevfile( appendSuffix: boolean, ): devfileApi.Devfile { const devfile = cloneDeep(_devfile); - const attributes = DevfileAdapter.getAttributesFromDevfileV2(devfile); + const attributes = DevfileAdapter.getAttributes(devfile); if ( !attributes[DEVWORKSPACE_METADATA_ANNOTATION] || typeof attributes[DEVWORKSPACE_METADATA_ANNOTATION] !== 'object' diff --git a/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/Apply/Resources/index.tsx b/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/Apply/Resources/index.tsx index 3e5a00c29..b21ca5437 100644 --- a/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/Apply/Resources/index.tsx +++ b/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/Apply/Resources/index.tsx @@ -37,11 +37,8 @@ import { AppState } from '@/store'; import * as DevfileRegistriesStore from '@/store/DevfileRegistries'; import { DevWorkspaceResources } from '@/store/DevfileRegistries'; import { selectDevWorkspaceResources } from '@/store/DevfileRegistries/selectors'; -import * as FactoryResolverStore from '@/store/FactoryResolver'; -import { - selectFactoryResolver, - selectFactoryResolverConverted, -} from '@/store/FactoryResolver/selectors'; +import { factoryResolverActionCreators } from '@/store/FactoryResolver'; +import { selectFactoryResolver } from '@/store/FactoryResolver/selectors'; import { selectDefaultNamespace } from '@/store/InfrastructureNamespaces/selectors'; import * as WorkspacesStore from '@/store/Workspaces'; import * as DevWorkspacesStore from '@/store/Workspaces/devWorkspaces'; @@ -288,7 +285,6 @@ const mapStateToProps = (state: AppState) => ({ allWorkspaces: selectAllWorkspaces(state), defaultNamespace: selectDefaultNamespace(state), factoryResolver: selectFactoryResolver(state), - factoryResolverConverted: selectFactoryResolverConverted(state), devWorkspaceResources: selectDevWorkspaceResources(state), devWorkspaceWarnings: selectDevWorkspaceWarnings(state), }); @@ -297,7 +293,7 @@ const connector = connect( mapStateToProps, { ...DevfileRegistriesStore.actionCreators, - ...FactoryResolverStore.actionCreators, + ...factoryResolverActionCreators, ...WorkspacesStore.actionCreators, createWorkspaceFromResources: DevWorkspacesStore.actionCreators.createWorkspaceFromResources, }, diff --git a/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/CheckExistingWorkspaces/__tests__/index.spec.tsx b/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/CheckExistingWorkspaces/__tests__/index.spec.tsx index 8b6df235e..df015ea9b 100644 --- a/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/CheckExistingWorkspaces/__tests__/index.spec.tsx +++ b/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/CheckExistingWorkspaces/__tests__/index.spec.tsx @@ -282,9 +282,7 @@ describe('Creating steps, checking existing workspaces', () => { .withFactoryResolver({ resolver: { location: factoryUrl, - }, - converted: { - devfileV2: { + devfile: { schemaVersion: '2.1.0', metadata: { name: workspaceName, diff --git a/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/CheckExistingWorkspaces/index.tsx b/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/CheckExistingWorkspaces/index.tsx index f83becf73..df5077079 100644 --- a/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/CheckExistingWorkspaces/index.tsx +++ b/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/CheckExistingWorkspaces/index.tsx @@ -31,10 +31,7 @@ import { AlertItem } from '@/services/helpers/types'; import { Workspace } from '@/services/workspace-adapter'; import { AppState } from '@/store'; import { selectDevWorkspaceResources } from '@/store/DevfileRegistries/selectors'; -import { - selectFactoryResolver, - selectFactoryResolverConverted, -} from '@/store/FactoryResolver/selectors'; +import { selectFactoryResolver } from '@/store/FactoryResolver/selectors'; import { selectAllWorkspaces } from '@/store/Workspaces/selectors'; export type Props = MappedProps & @@ -134,7 +131,7 @@ class CreatingStepCheckExistingWorkspaces extends ProgressStep { } protected async runStep(): Promise { - const { devWorkspaceResources, factoryResolver, factoryResolverConverted } = this.props; + const { devWorkspaceResources, factoryResolver } = this.props; const { factoryParams, shouldCreate } = this.state; if (shouldCreate) { @@ -160,13 +157,13 @@ class CreatingStepCheckExistingWorkspaces extends ProgressStep { if ( factoryResolver === undefined || factoryResolver.location !== factoryParams.sourceUrl || - factoryResolverConverted?.devfileV2 === undefined + factoryResolver?.devfile === undefined ) { // going to use the default devfile in the next step return true; } - const devfile = factoryResolverConverted.devfileV2; + const devfile = factoryResolver.devfile; newWorkspaceName = devfile.metadata.name; } @@ -234,7 +231,6 @@ const mapStateToProps = (state: AppState) => ({ allWorkspaces: selectAllWorkspaces(state), devWorkspaceResources: selectDevWorkspaceResources(state), factoryResolver: selectFactoryResolver(state), - factoryResolverConverted: selectFactoryResolverConverted(state), }); const connector = connect(mapStateToProps, null, null, { diff --git a/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/Fetch/Devfile/__tests__/buildStepName.spec.tsx b/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/Fetch/Devfile/__tests__/buildStepName.spec.tsx index d563fd6ae..2de88aaec 100644 --- a/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/Fetch/Devfile/__tests__/buildStepName.spec.tsx +++ b/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/Fetch/Devfile/__tests__/buildStepName.spec.tsx @@ -24,8 +24,17 @@ const factoryUrl = 'https://factory-url'; describe('Factory flow: step Fetch Devfile', () => { let searchParams: URLSearchParams; + let devfile: devfileApi.Devfile; beforeEach(() => { + devfile = { + schemaVersion: '2.2.2', + metadata: { + name: 'my-project', + namespace: 'user-che', + generateName: 'my-project-', + }, + }; searchParams = new URLSearchParams({ [FACTORY_URL_ATTR]: factoryUrl, }); @@ -36,19 +45,10 @@ describe('Factory flow: step Fetch Devfile', () => { const store = new FakeStoreBuilder() .withFactoryResolver({ resolver: { - devfile: {} as devfileApi.Devfile, + devfile, location: factoryUrl, source: undefined, // <- }, - converted: { - isConverted: false, - devfileV2: { - metadata: { - name: 'my-project', - generateName: 'my-project-', - }, - } as devfileApi.Devfile, - }, }) .build(); const factoryParams = buildFactoryParams(searchParams); @@ -56,7 +56,6 @@ describe('Factory flow: step Fetch Devfile', () => { const newTitle = buildStepName( factoryParams.sourceUrl, store.getState().factoryResolver.resolver!, - store.getState().factoryResolver.converted!, ); expect(newTitle).toEqual('Devfile found with name "my-project".'); @@ -66,19 +65,10 @@ describe('Factory flow: step Fetch Devfile', () => { const store = new FakeStoreBuilder() .withFactoryResolver({ resolver: { - devfile: {} as devfileApi.Devfile, + devfile, location: factoryUrl, source: 'repo', // <- }, - converted: { - isConverted: false, - devfileV2: { - metadata: { - name: 'my-project', - generateName: 'my-project-', - }, - } as devfileApi.Devfile, - }, }) .build(); const factoryParams = buildFactoryParams(searchParams); @@ -86,7 +76,6 @@ describe('Factory flow: step Fetch Devfile', () => { const newTitle = buildStepName( factoryParams.sourceUrl, store.getState().factoryResolver.resolver!, - store.getState().factoryResolver.converted!, ); expect(newTitle).toEqual( @@ -98,19 +87,10 @@ describe('Factory flow: step Fetch Devfile', () => { const store = new FakeStoreBuilder() .withFactoryResolver({ resolver: { - devfile: {} as devfileApi.Devfile, + devfile, location: factoryUrl, source: 'devfile.yaml', // <- }, - converted: { - isConverted: false, - devfileV2: { - metadata: { - name: 'my-project', - generateName: 'my-project-', - }, - } as devfileApi.Devfile, - }, }) .build(); const factoryParams = buildFactoryParams(searchParams); @@ -118,43 +98,9 @@ describe('Factory flow: step Fetch Devfile', () => { const newTitle = buildStepName( factoryParams.sourceUrl, store.getState().factoryResolver.resolver!, - store.getState().factoryResolver.converted!, ); expect(newTitle).toEqual('Devfile found with name "my-project".'); }); - - test('devfile converted', async () => { - const store = new FakeStoreBuilder() - .withFactoryResolver({ - resolver: { - devfile: {} as devfileApi.Devfile, - location: factoryUrl, - source: 'devfile.yaml', - }, - converted: { - isConverted: true, // <- - devfileV2: { - schemaVersion: '2.1.0', - metadata: { - name: 'my-project', - generateName: 'my-project-', - }, - } as devfileApi.Devfile, - }, - }) - .build(); - const factoryParams = buildFactoryParams(searchParams); - - const newTitle = buildStepName( - factoryParams.sourceUrl, - store.getState().factoryResolver.resolver!, - store.getState().factoryResolver.converted!, - ); - - expect(newTitle).toEqual( - 'Devfile found with name "my-project". Devfile version 1 found, converting it to devfile version 2.', - ); - }); }); }); diff --git a/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/Fetch/Devfile/__tests__/index.spec.tsx b/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/Fetch/Devfile/__tests__/index.spec.tsx index 69ea2a417..1fbca4f4a 100644 --- a/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/Fetch/Devfile/__tests__/index.spec.tsx +++ b/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/Fetch/Devfile/__tests__/index.spec.tsx @@ -32,26 +32,38 @@ import { REMOTES_ATTR, } from '@/services/helpers/factoryFlow/buildFactoryParams'; import { AlertItem } from '@/services/helpers/types'; -import OAuthService from '@/services/oauth'; import { AppThunk } from '@/store'; import { FakeStoreBuilder } from '@/store/__mocks__/storeBuilder'; -import { ActionCreators, OAuthResponse } from '@/store/FactoryResolver'; +import { OAuthResponse } from '@/store/FactoryResolver'; +import { FactoryResolverActionCreators } from '@/store/FactoryResolver'; jest.mock('@/components/WorkspaceProgress/TimeLimit'); const mockRequestFactoryResolver = jest.fn(); -const mockIsOAuthResponse = jest.fn(); -jest.mock('@/store/FactoryResolver', () => { +jest.mock('@/store/FactoryResolver/actions', () => { return { + ...jest.requireActual('@/store/FactoryResolver'), actionCreators: { requestFactoryResolver: ( - ...args: Parameters + ...args: Parameters ): AppThunk> => async (): Promise => mockRequestFactoryResolver(...args), - } as ActionCreators, - isOAuthResponse: (_args: unknown[]) => mockIsOAuthResponse(_args), + } as FactoryResolverActionCreators, + }; +}); + +const mockIsOAuthResponse = jest.fn().mockReturnValue(false); +const mockOpenOAuthPage = jest.fn(); +jest.mock('@/services/oauth', () => { + return { + __esModule: true, + OAuthService: { + openOAuthPage: (..._args: unknown[]) => mockOpenOAuthPage(..._args), + refreshTokenIfNeeded: () => jest.fn().mockResolvedValue(undefined), + }, + isOAuthResponse: (..._args: unknown[]) => mockIsOAuthResponse(..._args), }; }); @@ -67,22 +79,23 @@ const factoryUrl = 'https://factory-url'; describe('Creating steps, fetching a devfile', () => { let searchParams: URLSearchParams; let store: Store; + let devfile: devfileApi.Devfile; beforeEach(() => { + devfile = { + schemaVersion: '2.2.2', + metadata: { + name: 'my-project', + namespace: 'user-che', + generateName: 'my-project-', + }, + }; store = new FakeStoreBuilder() .withFactoryResolver({ resolver: { - devfile: {} as devfileApi.Devfile, + devfile, location: factoryUrl, }, - converted: { - devfileV2: { - metadata: { - name: 'my-project', - generateName: 'my-project-', - }, - } as devfileApi.Devfile, - }, }) .build(); @@ -96,7 +109,6 @@ describe('Creating steps, fetching a devfile', () => { afterEach(() => { jest.clearAllMocks(); jest.clearAllTimers(); - jest.useRealTimers(); }); test('factory should not resolve the SSH location', async () => { @@ -463,7 +475,6 @@ describe('Creating steps, fetching a devfile', () => { describe('public repo', () => { beforeEach(() => { mockRequestFactoryResolver.mockResolvedValueOnce(undefined); - mockIsOAuthResponse.mockReturnValueOnce(false); }); test('request factory resolver', async () => { @@ -517,14 +528,13 @@ describe('Creating steps, fetching a devfile', () => { .withFactoryResolver({ resolver: { location: factoryUrl, - }, - converted: { - devfileV2: { + devfile: { + schemaVersion: '2.2.2', metadata: { name: 'my-project', - generateName: 'my-project-', + namespace: 'user-che', }, - } as devfileApi.Devfile, + }, }, }) .build(); @@ -542,7 +552,6 @@ describe('Creating steps, fetching a devfile', () => { const host = 'che-host'; const protocol = 'http://'; let spyWindowLocation: jest.SpyInstance; - let spyOpenOAuthPage: jest.SpyInstance; let history: MemoryHistory; beforeEach(() => { @@ -555,9 +564,6 @@ describe('Creating steps, fetching a devfile', () => { } as OAuthResponse); spyWindowLocation = createWindowLocationSpy(host, protocol); - spyOpenOAuthPage = jest - .spyOn(OAuthService, 'openOAuthPage') - .mockImplementation(() => jest.fn()); history = createMemoryHistory({ initialEntries: [ @@ -571,7 +577,6 @@ describe('Creating steps, fetching a devfile', () => { afterEach(() => { sessionStorage.clear(); spyWindowLocation.mockClear(); - spyOpenOAuthPage.mockClear(); }); test('redirect to an authentication URL', async () => { @@ -586,7 +591,7 @@ describe('Creating steps, fetching a devfile', () => { )}`; await waitFor(() => - expect(spyOpenOAuthPage).toHaveBeenCalledWith(oauthAuthenticationUrl, expectedRedirectUrl), + expect(mockOpenOAuthPage).toHaveBeenCalledWith(oauthAuthenticationUrl, expectedRedirectUrl), ); expect(mockOnError).not.toHaveBeenCalled(); @@ -605,7 +610,7 @@ describe('Creating steps, fetching a devfile', () => { )}`; await waitFor(() => - expect(spyOpenOAuthPage).toHaveBeenCalledWith(oauthAuthenticationUrl, expectedRedirectUrl), + expect(mockOpenOAuthPage).toHaveBeenCalledWith(oauthAuthenticationUrl, expectedRedirectUrl), ); // cleanup previous render @@ -617,7 +622,7 @@ describe('Creating steps, fetching a devfile', () => { await jest.advanceTimersByTimeAsync(MIN_STEP_DURATION_MS); await waitFor(() => - expect(spyOpenOAuthPage).toHaveBeenCalledWith(oauthAuthenticationUrl, expectedRedirectUrl), + expect(mockOpenOAuthPage).toHaveBeenCalledWith(oauthAuthenticationUrl, expectedRedirectUrl), ); await waitFor(() => expect(mockOnError).not.toHaveBeenCalled()); @@ -631,7 +636,7 @@ describe('Creating steps, fetching a devfile', () => { await jest.advanceTimersByTimeAsync(MIN_STEP_DURATION_MS); await waitFor(() => - expect(spyOpenOAuthPage).toHaveBeenCalledWith(oauthAuthenticationUrl, expectedRedirectUrl), + expect(mockOpenOAuthPage).toHaveBeenCalledWith(oauthAuthenticationUrl, expectedRedirectUrl), ); const expectAlertItem = expect.objectContaining({ @@ -681,9 +686,7 @@ describe('Creating steps, fetching a devfile', () => { .withFactoryResolver({ resolver: { location: factoryUrl, - }, - converted: { - devfileV2: { + devfile: { metadata: { name: 'my-project', generateName: 'my-project-', @@ -707,7 +710,6 @@ describe('Creating steps, fetching a devfile', () => { const factoryUrl = 'git@github.com:user/repository-name.git'; let spyWindowLocation: jest.SpyInstance; - let spyOpenOAuthPage: jest.SpyInstance; let history: MemoryHistory; beforeEach(() => { @@ -717,13 +719,9 @@ describe('Creating steps, fetching a devfile', () => { [FACTORY_URL_ATTR]: factoryUrl, }); - mockIsOAuthResponse.mockReturnValue(false); mockRequestFactoryResolver.mockRejectedValue('Could not reach devfile'); spyWindowLocation = createWindowLocationSpy(host, protocol); - spyOpenOAuthPage = jest - .spyOn(OAuthService, 'openOAuthPage') - .mockImplementation(() => jest.fn()); history = createMemoryHistory({ initialEntries: [ @@ -737,7 +735,6 @@ describe('Creating steps, fetching a devfile', () => { afterEach(() => { sessionStorage.clear(); spyWindowLocation.mockClear(); - spyOpenOAuthPage.mockClear(); }); it('should go to next step', async () => { @@ -749,7 +746,7 @@ describe('Creating steps, fetching a devfile', () => { await waitFor(() => expect(mockOnNextStep).toHaveBeenCalled()); - expect(spyOpenOAuthPage).not.toHaveBeenCalled(); + expect(mockOpenOAuthPage).not.toHaveBeenCalled(); expect(mockOnError).not.toHaveBeenCalled(); }); }); diff --git a/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/Fetch/Devfile/buildStepName.ts b/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/Fetch/Devfile/buildStepName.ts index 35728cf5f..924dc550e 100644 --- a/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/Fetch/Devfile/buildStepName.ts +++ b/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/Fetch/Devfile/buildStepName.ts @@ -10,24 +10,22 @@ * Red Hat, Inc. - initial API and implementation */ -import * as FactoryResolverStore from '@/store/FactoryResolver'; +import { FactoryResolverStateResolver } from '@/store/FactoryResolver'; export function buildStepName( sourceUrl: string, - factoryResolver: FactoryResolverStore.ResolverState, - factoryResolverConverted: FactoryResolverStore.ConvertedState, + factoryResolver: FactoryResolverStateResolver, ): string { // source tells where devfile comes from // - no source: the url to raw content is used // - repo: means no devfile is found and default is generated // - any other - devfile is found in repository as filename from the value - const { source } = factoryResolver; - const { devfileV2 } = factoryResolverConverted; + const { devfile, source } = factoryResolver; const devfileName = - devfileV2.metadata.name !== undefined - ? `name "${devfileV2.metadata.name}"` - : `generateName "${devfileV2.metadata.generateName}"`; + devfile.metadata.name !== undefined + ? `name "${devfile.metadata.name}"` + : `generateName "${devfile.metadata.generateName}"`; let newTitle = ''; if (!source) { @@ -36,9 +34,6 @@ export function buildStepName( newTitle = `Devfile could not be found in ${sourceUrl}. Applying the default configuration.`; } else { newTitle = `Devfile found with ${devfileName}.`; - if (factoryResolverConverted.isConverted) { - newTitle += ` Devfile version 1 found, converting it to devfile version 2.`; - } } return newTitle; } diff --git a/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/Fetch/Devfile/index.tsx b/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/Fetch/Devfile/index.tsx index a34179df1..bfe941983 100644 --- a/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/Fetch/Devfile/index.tsx +++ b/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/Fetch/Devfile/index.tsx @@ -33,14 +33,10 @@ import { USE_DEFAULT_DEVFILE, } from '@/services/helpers/factoryFlow/buildFactoryParams'; import { AlertItem } from '@/services/helpers/types'; -import OAuthService, { isOAuthResponse } from '@/services/oauth'; +import { isOAuthResponse, OAuthService } from '@/services/oauth'; import SessionStorageService, { SessionStorageKey } from '@/services/session-storage'; import { AppState } from '@/store'; -import * as FactoryResolverStore from '@/store/FactoryResolver'; -import { - selectFactoryResolver, - selectFactoryResolverConverted, -} from '@/store/FactoryResolver/selectors'; +import { factoryResolverActionCreators, selectFactoryResolver } from '@/store/FactoryResolver'; import { selectAllWorkspaces } from '@/store/Workspaces/selectors'; export class ApplyingDevfileError extends Error { @@ -195,15 +191,12 @@ class CreatingStepFetchDevfile extends ProgressStep { protected async runStep(): Promise { const { factoryParams, shouldResolve, useDefaultDevfile } = this.state; - const { factoryResolver, factoryResolverConverted } = this.props; + const { factoryResolver } = this.props; const { sourceUrl } = factoryParams; - if ( - factoryResolver?.location === sourceUrl && - factoryResolverConverted?.devfileV2 !== undefined - ) { + if (factoryResolver?.location === sourceUrl && factoryResolver.devfile !== undefined) { // the devfile resolved successfully - const newName = buildStepName(sourceUrl, factoryResolver, factoryResolverConverted); + const newName = buildStepName(sourceUrl, factoryResolver); this.setState({ name: newName, }); @@ -433,19 +426,11 @@ class CreatingStepFetchDevfile extends ProgressStep { const mapStateToProps = (state: AppState) => ({ allWorkspaces: selectAllWorkspaces(state), factoryResolver: selectFactoryResolver(state), - factoryResolverConverted: selectFactoryResolverConverted(state), }); -const connector = connect( - mapStateToProps, - { - ...FactoryResolverStore.actionCreators, - }, - null, - { - // forwardRef is mandatory for using `@react-mock/state` in unit tests - forwardRef: true, - }, -); +const connector = connect(mapStateToProps, factoryResolverActionCreators, null, { + // forwardRef is mandatory for using `@react-mock/state` in unit tests + forwardRef: true, +}); type MappedProps = ConnectedProps; export default connector(CreatingStepFetchDevfile); diff --git a/packages/dashboard-frontend/src/pages/WorkspaceDetails/DevfileEditorTab/index.tsx b/packages/dashboard-frontend/src/pages/WorkspaceDetails/DevfileEditorTab/index.tsx index 40bdfffb1..2f19c4cb1 100644 --- a/packages/dashboard-frontend/src/pages/WorkspaceDetails/DevfileEditorTab/index.tsx +++ b/packages/dashboard-frontend/src/pages/WorkspaceDetails/DevfileEditorTab/index.tsx @@ -78,7 +78,7 @@ export function prepareDevfile(workspace: Workspace): devfileApi.Devfile { const devfileStr = workspace.ref.metadata?.annotations?.[DEVWORKSPACE_DEVFILE]; const devfile = devfileStr ? (load(devfileStr) as devfileApi.Devfile) : workspace.devfile; - const attrs = DevfileAdapter.getAttributesFromDevfileV2(devfile); + const attrs = DevfileAdapter.getAttributes(devfile); if (attrs?.[DEVWORKSPACE_METADATA_ANNOTATION]) { delete attrs[DEVWORKSPACE_METADATA_ANNOTATION]; } diff --git a/packages/dashboard-frontend/src/services/devfile/__tests__/devfileAdapter.spec.ts b/packages/dashboard-frontend/src/services/devfile/__tests__/devfileAdapter.spec.ts index 42f6db64a..91066ceef 100644 --- a/packages/dashboard-frontend/src/services/devfile/__tests__/devfileAdapter.spec.ts +++ b/packages/dashboard-frontend/src/services/devfile/__tests__/devfileAdapter.spec.ts @@ -11,112 +11,49 @@ */ import { DevfileAdapter } from '@/services/devfile/adapter'; -import { convertDevfileV1toDevfileV2 } from '@/services/devfile/converters'; import devfileApi from '@/services/devfileApi'; -import { DEVWORKSPACE_STORAGE_TYPE_ATTR } from '@/services/devfileApi/devWorkspace/spec/template'; -import { che } from '@/services/models'; -import { DevfileBuilder } from '@/store/__mocks__/devfile'; describe('DevfileAdapter Service', () => { describe('getAttributesFromDevfileV2', () => { - it('should returns attributes from the devfile v2.0.0', async () => { - const devfileV2 = { + it('should return attributes from the devfile v2.0.0', async () => { + const devfile = { schemaVersion: '2.0.0', metadata: { name: 'wksp-test', }, } as devfileApi.Devfile; - const attributes = DevfileAdapter.getAttributesFromDevfileV2(devfileV2); - expect(attributes === devfileV2.metadata.attributes).toBeTruthy(); - expect(attributes === devfileV2.attributes).toBeFalsy(); + const adapter = new DevfileAdapter(devfile); + + expect(adapter.attributes).toStrictEqual(devfile.metadata.attributes); + expect(adapter.attributes).not.toStrictEqual(devfile.attributes); }); - it('should returns attributes from the devfile v2.1.0', async () => { - const devfileV2 = { + it('should return attributes from the devfile v2.1.0', async () => { + const devfile = { schemaVersion: '2.1.0', metadata: { name: 'wksp-test', }, } as devfileApi.Devfile; - const attributes = DevfileAdapter.getAttributesFromDevfileV2(devfileV2); - expect(attributes === devfileV2.metadata.attributes).toBeFalsy(); - expect(attributes === devfileV2.attributes).toBeTruthy(); + const adapter = new DevfileAdapter(devfile); + + expect(adapter.attributes).not.toStrictEqual(devfile.metadata.attributes); + expect(adapter.attributes).toStrictEqual(devfile.attributes); }); it('should returns attributes from the devfile v2.2.0', async () => { - const devfileV2 = { + const devfile = { schemaVersion: '2.2.0', metadata: { name: 'wksp-test', }, } as devfileApi.Devfile; - const attributes = DevfileAdapter.getAttributesFromDevfileV2(devfileV2); - - expect(attributes === devfileV2.metadata.attributes).toBeFalsy(); - expect(attributes === devfileV2.attributes).toBeTruthy(); - }); - }); - describe('update storageType', () => { - describe('devfile V2', () => { - describe('setting the "ephemeral" storage', () => { - it('should correctly update a devfile with "ephemeral" storage', async () => { - const devfileV2 = await convertDevfileV1toDevfileV2(getDevfileWithPersistentStorage()); - const devfileAdapter = new DevfileAdapter(devfileV2); - - expect(devfileAdapter.storageType).toEqual('persistent'); - expect(devfileAdapter.devfile.attributes).not.toEqual( - expect.objectContaining({ [DEVWORKSPACE_STORAGE_TYPE_ATTR]: 'ephemeral' }), - ); - - devfileAdapter.storageType = 'ephemeral'; - - expect(devfileAdapter.devfile.attributes).toEqual( - expect.objectContaining({ - [DEVWORKSPACE_STORAGE_TYPE_ATTR]: 'ephemeral', - 'che-theia.eclipse.org/sidecar-policy': 'mergeImage', - }), - ); - expect(devfileAdapter.storageType).toEqual('ephemeral'); - }); + const adapter = new DevfileAdapter(devfile); - it('should correctly update a devfile with "ephemeral" storage', async () => { - const devfileV2 = await convertDevfileV1toDevfileV2(getDevfileWithEphemeralStorage()); - - const devfileAdapter = new DevfileAdapter(devfileV2); - - expect(devfileAdapter.storageType).toEqual('ephemeral'); - expect(devfileAdapter.devfile.attributes).toEqual( - expect.objectContaining({ - [DEVWORKSPACE_STORAGE_TYPE_ATTR]: 'ephemeral', - }), - ); - - devfileAdapter.storageType = 'per-workspace'; - - expect(devfileAdapter.devfile.attributes).not.toEqual( - expect.objectContaining({ - [DEVWORKSPACE_STORAGE_TYPE_ATTR]: 'ephemeral', - }), - ); - expect(devfileAdapter.storageType).toEqual('per-workspace'); - }); - }); + expect(adapter.attributes).not.toStrictEqual(devfile.metadata.attributes); + expect(adapter.attributes).toStrictEqual(devfile.attributes); }); }); }); - -function getDevfileWithPersistentStorage(): che.api.workspace.devfile.Devfile { - const devfileV1 = new DevfileBuilder().withAttributes({ - persistVolumes: 'true', - }); - return devfileV1.build(); -} - -function getDevfileWithEphemeralStorage(): che.api.workspace.devfile.Devfile { - const devfileV1 = new DevfileBuilder().withAttributes({ - persistVolumes: 'false', - }); - return devfileV1.build(); -} diff --git a/packages/dashboard-frontend/src/services/devfile/adapter.ts b/packages/dashboard-frontend/src/services/devfile/adapter.ts index 30ee24953..8f5696c8c 100644 --- a/packages/dashboard-frontend/src/services/devfile/adapter.ts +++ b/packages/dashboard-frontend/src/services/devfile/adapter.ts @@ -10,107 +10,31 @@ * Red Hat, Inc. - initial API and implementation */ -import devfileApi, { isDevfileV2 } from '@/services/devfileApi'; -import { DEVWORKSPACE_STORAGE_TYPE_ATTR } from '@/services/devfileApi/devWorkspace/spec/template'; -import { che } from '@/services/models'; -import { attributesToType } from '@/services/storageTypes'; - -export type Devfile = che.api.workspace.devfile.Devfile | devfileApi.Devfile; +import devfileApi from '@/services/devfileApi'; export class DevfileAdapter { - private _devfile: Devfile; + private _devfile: devfileApi.Devfile; - constructor(devfile: Devfile) { + constructor(devfile: devfileApi.Devfile) { this._devfile = devfile; } - public static getAttributesFromDevfileV2(devfile: devfileApi.Devfile) { - let attributes = {}; + public static getAttributes(devfile: devfileApi.Devfile) { + const attributes = {}; if (devfile.schemaVersion?.startsWith('2.0')) { if (!devfile.metadata.attributes) { devfile.metadata.attributes = attributes; - } else { - attributes = devfile.metadata.attributes; } + return devfile.metadata.attributes; } else { if (!devfile.attributes) { devfile.attributes = attributes; - } else { - attributes = devfile.attributes; } + return devfile.attributes; } - - return attributes; - } - - get devfile(): Devfile { - return this._devfile; } - set storageType(type: che.WorkspaceStorageType) { - if (isDevfileV2(this._devfile)) { - const attributes = DevfileAdapter.getAttributesFromDevfileV2(this._devfile); - if (type && type !== 'persistent') { - attributes[DEVWORKSPACE_STORAGE_TYPE_ATTR] = type; - } else { - if (attributes[DEVWORKSPACE_STORAGE_TYPE_ATTR]) { - delete attributes[DEVWORKSPACE_STORAGE_TYPE_ATTR]; - } - if (Object.keys(attributes).length === 0) { - if (this._devfile.attributes === attributes) { - delete this._devfile.attributes; - } else if (this._devfile.metadata.attributes === attributes) { - delete this._devfile.metadata.attributes; - } - } - } - } else { - const attributes = this._devfile.attributes; - switch (type) { - case 'persistent': - if (attributes) { - delete attributes.persistVolumes; - delete attributes.asyncPersist; - if (Object.keys(attributes).length === 0) { - delete this._devfile.attributes; - } - } - break; - case 'ephemeral': - if (!attributes) { - this._devfile.attributes = { persistVolumes: 'false' }; - } else { - attributes.persistVolumes = 'false'; - delete attributes.asyncPersist; - } - break; - case 'async': - if (!attributes) { - this._devfile.attributes = { - persistVolumes: 'false', - asyncPersist: 'true', - }; - } else { - attributes.persistVolumes = 'false'; - attributes.asyncPersist = 'true'; - } - break; - } - } - } - - get storageType(): che.WorkspaceStorageType { - if (isDevfileV2(this._devfile)) { - let type = this._devfile.metadata.attributes?.[DEVWORKSPACE_STORAGE_TYPE_ATTR]; - if (type) { - return type; - } - type = this._devfile.attributes?.[DEVWORKSPACE_STORAGE_TYPE_ATTR]; - if (type) { - return type; - } - return 'persistent'; - } - return attributesToType(this._devfile.attributes); + get attributes() { + return DevfileAdapter.getAttributes(this._devfile); } } diff --git a/packages/dashboard-frontend/src/services/devfile/converters.ts b/packages/dashboard-frontend/src/services/devfile/converters.ts deleted file mode 100644 index bd94699a3..000000000 --- a/packages/dashboard-frontend/src/services/devfile/converters.ts +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2018-2024 Red Hat, Inc. - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Red Hat, Inc. - initial API and implementation - */ - -import * as devfileConverter from '@eclipse-che/devfile-converter'; - -import devfileApi from '@/services/devfileApi'; -import { che } from '@/services/models'; - -export async function convertDevfileV1toDevfileV2( - devfile: che.api.workspace.devfile.Devfile, -): Promise { - const converted = (await devfileConverter.v1ToV2(devfile)) as devfileApi.Devfile; - - if (converted.components?.some(component => component.container?.image)) { - return converted; - } - - // if no user component found - // use `mergeImage` sidecar policy - const sidecarPolicyKey = 'che-theia.eclipse.org/sidecar-policy'; - const sidecarPolicy = 'mergeImage'; - if (converted.attributes === undefined) { - converted.attributes = {}; - } - if (converted.attributes?.[sidecarPolicyKey] === undefined) { - converted.attributes[sidecarPolicyKey] = sidecarPolicy; - } - - return converted; -} diff --git a/packages/dashboard-frontend/src/services/helpers/editor.ts b/packages/dashboard-frontend/src/services/helpers/editor.ts index 6a7befd2b..7d131e79a 100644 --- a/packages/dashboard-frontend/src/services/helpers/editor.ts +++ b/packages/dashboard-frontend/src/services/helpers/editor.ts @@ -13,10 +13,8 @@ import { dump } from 'js-yaml'; import devfileApi from '@/services/devfileApi'; -import { che } from '@/services/models'; -const sortOrder: Array = [ - 'apiVersion', +const sortOrder: Array = [ 'schemaVersion', 'metadata', 'attributes', @@ -28,8 +26,8 @@ const sortOrder: Array { - devfile: che.api.workspace.devfile.Devfile | devfileApi.Devfile; + devfile?: che.api.workspace.devfile.Devfile | devfileApi.Devfile; location?: string; scm_info?: FactoryResolverScmInfo; } diff --git a/packages/dashboard-frontend/src/services/oauth/__tests__/index.spec.ts b/packages/dashboard-frontend/src/services/oauth/__tests__/index.spec.ts index 1b44b26de..85bbc3cd0 100644 --- a/packages/dashboard-frontend/src/services/oauth/__tests__/index.spec.ts +++ b/packages/dashboard-frontend/src/services/oauth/__tests__/index.spec.ts @@ -14,10 +14,9 @@ import common from '@eclipse-che/common'; import { AxiosError } from 'axios'; import * as factoryApi from '@/services/backend-client/factoryApi'; +import { OAuthService } from '@/services/oauth'; import { DevWorkspaceBuilder } from '@/store/__mocks__/devWorkspaceBuilder'; -import OAuthService from '..'; - const refreshFactoryOauthTokenSpy = jest.spyOn(factoryApi, 'refreshFactoryOauthToken'); const mockOpenOAuthPage = jest.fn().mockImplementation(); diff --git a/packages/dashboard-frontend/src/services/oauth/index.ts b/packages/dashboard-frontend/src/services/oauth/index.ts index 60bfd4cb3..f382d5c41 100644 --- a/packages/dashboard-frontend/src/services/oauth/index.ts +++ b/packages/dashboard-frontend/src/services/oauth/index.ts @@ -16,7 +16,7 @@ import { refreshFactoryOauthToken } from '@/services/backend-client/factoryApi'; import devfileApi from '@/services/devfileApi'; import { OAuthResponse } from '@/store/FactoryResolver'; -export default class OAuthService { +export class OAuthService { static openOAuthPage(authenticationUrl: string, redirectUrl: string): void { try { const oauthUrlTmp = new window.URL(authenticationUrl); @@ -70,10 +70,11 @@ export default class OAuthService { } } -export function isOAuthResponse(responseData: any): responseData is OAuthResponse { +export function isOAuthResponse(responseData: unknown): responseData is OAuthResponse { if ( - responseData?.attributes?.oauth_provider && - responseData?.attributes?.oauth_authentication_url + responseData && + (responseData as Partial).attributes?.oauth_provider && + (responseData as Partial).attributes?.oauth_authentication_url ) { return true; } diff --git a/packages/dashboard-frontend/src/services/workspace-adapter/index.ts b/packages/dashboard-frontend/src/services/workspace-adapter/index.ts index 37c25212f..cb245d52e 100644 --- a/packages/dashboard-frontend/src/services/workspace-adapter/index.ts +++ b/packages/dashboard-frontend/src/services/workspace-adapter/index.ts @@ -274,7 +274,3 @@ export class WorkspaceAdapter implements Work export function constructWorkspace(workspace: T): Workspace { return new WorkspaceAdapter(workspace); } - -export function isCheDevfile(devfile: unknown): devfile is che.api.workspace.devfile.Devfile { - return !isDevfileV2(devfile); -} diff --git a/packages/dashboard-frontend/src/store/FactoryResolver/__tests__/actions.spec.ts b/packages/dashboard-frontend/src/store/FactoryResolver/__tests__/actions.spec.ts new file mode 100644 index 000000000..6da383eda --- /dev/null +++ b/packages/dashboard-frontend/src/store/FactoryResolver/__tests__/actions.spec.ts @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2018-2024 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ + +import { AxiosError } from 'axios'; +import { MockStoreEnhanced } from 'redux-mock-store'; +import { ThunkDispatch } from 'redux-thunk'; + +import * as factoryResolver from '@/services/backend-client/factoryApi'; +import * as yamlResolver from '@/services/backend-client/yamlResolverApi'; +import devfileApi from '@/services/devfileApi'; +import { AppState } from '@/store'; +import { FakeStoreBuilder } from '@/store/__mocks__/storeBuilder'; +import { actionCreators } from '@/store/FactoryResolver/actions'; +import { normalizeDevfile } from '@/store/FactoryResolver/helpers'; +import { KnownAction, Resolver, Type } from '@/store/FactoryResolver/types'; +import { AUTHORIZED } from '@/store/sanityCheckMiddleware'; + +const mockGrabLink = jest.fn().mockResolvedValue(undefined); +const mockIsDevfileRegistryLocation = jest.fn().mockReturnValue(false); +const mockNormalizeDevfile = jest + .fn() + .mockImplementation((...args: Parameters) => args[0].devfile); +jest.mock('@/store/FactoryResolver/helpers.ts', () => { + return { + grabLink: (...args: unknown[]) => mockGrabLink(...args), + isDevfileRegistryLocation: (...args: unknown[]) => mockIsDevfileRegistryLocation(...args), + normalizeDevfile: (...args: unknown[]) => mockNormalizeDevfile(...args), + }; +}); + +jest.mock('@/services/devfileApi'); +jest.mock('@/services/devfileApi/typeguards', () => { + return { + ...jest.requireActual('@/services/devfileApi/typeguards'), + isDevfileV2: (devfile: unknown): boolean => { + return (devfile as devfileApi.Devfile).schemaVersion !== undefined; + }, + }; +}); + +const getFactoryResolverSpy = jest.spyOn(factoryResolver, 'getFactoryResolver'); +const getYamlResolverSpy = jest.spyOn(yamlResolver, 'getYamlResolver'); + +describe('FactoryResolver store, actions', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + + let store: MockStoreEnhanced>; + + beforeEach(() => { + store = new FakeStoreBuilder().build(); + }); + + it('should create REQUEST_FACTORY_RESOLVER and RECEIVE_FACTORY_RESOLVER_ERROR if factory resolver fails', async () => { + getFactoryResolverSpy.mockRejectedValueOnce({ + isAxiosError: true, + code: '500', + response: { + data: { + message: 'Something unexpected happened.', + }, + }, + } as AxiosError); + + const location = 'http://factory-link'; + await expect( + store.dispatch(actionCreators.requestFactoryResolver(location, {})), + ).rejects.toEqual( + 'Unexpected error. Check DevTools console and network tabs for more information.', + ); + + const actions = store.getActions(); + const expectedActions: KnownAction[] = [ + { + type: Type.REQUEST_FACTORY_RESOLVER, + check: AUTHORIZED, + }, + { + type: Type.RECEIVE_FACTORY_RESOLVER_ERROR, + error: expect.stringContaining('Unexpected error'), + }, + ]; + + expect(actions).toEqual(expectedActions); + }); + + it('should create REQUEST_FACTORY_RESOLVER and RECEIVE_FACTORY_RESOLVER_ERROR if resolver returns no devfile', async () => { + getFactoryResolverSpy.mockResolvedValueOnce({ + devfile: undefined, + }); + + const location = 'http://factory-link'; + await expect( + store.dispatch(actionCreators.requestFactoryResolver(location, {})), + ).rejects.toEqual('The specified link does not contain any Devfile.'); + + const actions = store.getActions(); + const expectedActions: KnownAction[] = [ + { + type: Type.REQUEST_FACTORY_RESOLVER, + check: AUTHORIZED, + }, + { + error: 'The specified link does not contain any Devfile.', + type: Type.RECEIVE_FACTORY_RESOLVER_ERROR, + }, + ]; + + expect(actions).toEqual(expectedActions); + }); + + it('should create REQUEST_FACTORY_RESOLVER if authentication is needed', async () => { + getFactoryResolverSpy.mockRejectedValueOnce({ + isAxiosError: true, + code: '401', + response: { + headers: {}, + status: 401, + statusText: 'Unauthorized', + config: {}, + data: { + attributes: { + oauth_provider: 'oauth_provider', + oauth_authentication_url: 'oauth_authentication_url', + }, + }, + }, + } as AxiosError); + + const location = 'http://factory-link'; + await expect( + store.dispatch(actionCreators.requestFactoryResolver(location, {})), + ).rejects.toStrictEqual({ + attributes: { + oauth_provider: 'oauth_provider', + oauth_authentication_url: 'oauth_authentication_url', + }, + }); + + const actions = store.getActions(); + const expectedActions: KnownAction[] = [ + { + type: Type.REQUEST_FACTORY_RESOLVER, + check: AUTHORIZED, + }, + ]; + + expect(actions).toEqual(expectedActions); + }); + + it('should create REQUEST_FACTORY_RESOLVER and RECEIVE_FACTORY_RESOLVER', async () => { + const devfile = { + schemaVersion: '2.0.0', + } as devfileApi.Devfile; + getFactoryResolverSpy.mockResolvedValueOnce({ + devfile, + }); + + const location = 'http://factory-link'; + await expect( + store.dispatch(actionCreators.requestFactoryResolver(location, {})), + ).resolves.toBeUndefined(); + + const actions = store.getActions(); + const expectedActions: KnownAction[] = [ + { + type: Type.REQUEST_FACTORY_RESOLVER, + check: AUTHORIZED, + }, + { + resolver: { + devfile, + location, + optionalFilesContent: {}, + }, + type: Type.RECEIVE_FACTORY_RESOLVER, + }, + ]; + + expect(actions).toEqual(expectedActions); + }); + + describe('check resolver types', () => { + const resolver = { + devfile: { + schemaVersion: '2.0.0', + } as devfileApi.Devfile, + } as Resolver; + + beforeEach(() => { + getFactoryResolverSpy.mockResolvedValueOnce(resolver); + getYamlResolverSpy.mockResolvedValueOnce(resolver); + }); + + it('should call the yaml resolver for a devfile registry', async () => { + const location = 'http://registry/devfile.yaml'; + + mockIsDevfileRegistryLocation.mockReturnValueOnce(true); + + await expect( + store.dispatch(actionCreators.requestFactoryResolver(location, {})), + ).resolves.toBeUndefined(); + + expect(getYamlResolverSpy).toHaveBeenCalledWith(location); + expect(getFactoryResolverSpy).not.toHaveBeenCalled(); + }); + + it('should call the factory resolver for non-registry devfiles', async () => { + const location = 'https://github.com/eclipse-che/che-dashboard.git'; + + mockIsDevfileRegistryLocation.mockReturnValueOnce(false); + + await expect( + store.dispatch(actionCreators.requestFactoryResolver(location, {})), + ).resolves.toBeUndefined(); + + expect(getYamlResolverSpy).not.toHaveBeenCalledWith(); + expect(getFactoryResolverSpy).toHaveBeenCalledWith(location, { + error_code: undefined, + }); + }); + }); +}); diff --git a/packages/dashboard-frontend/src/store/FactoryResolver/__tests__/helper.isDevfileRegistryLocation.spec.ts b/packages/dashboard-frontend/src/store/FactoryResolver/__tests__/helper.isDevfileRegistryLocation.spec.ts new file mode 100644 index 000000000..312dae040 --- /dev/null +++ b/packages/dashboard-frontend/src/store/FactoryResolver/__tests__/helper.isDevfileRegistryLocation.spec.ts @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2018-2024 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ + +import { IServerConfig } from '@eclipse-che/common/lib/dto/api'; + +import { DEFAULT_REGISTRY } from '@/store/DevfileRegistries'; +import { isDevfileRegistryLocation } from '@/store/FactoryResolver/helpers'; + +describe('isDevfileRegistryLocation', () => { + const devfileRegistryURL = 'https://devfile-registry.dev'; + const externalDevfileRegistryURL = 'https://external-devfile-registry.dev'; + const config = { + devfileRegistryURL, + devfileRegistry: { + externalDevfileRegistries: [ + { + url: externalDevfileRegistryURL, + }, + ], + }, + } as unknown as IServerConfig; + + test('default registry', () => { + const location = `${window.location.origin}${DEFAULT_REGISTRY}devfiles/devfile.yaml`; + expect(isDevfileRegistryLocation(location, config)).toBe(true); + }); + + test('devfile registry', () => { + const location = `${devfileRegistryURL}/devfiles/devfile.yaml`; + expect(isDevfileRegistryLocation(location, config)).toBe(true); + }); + + test('external registry', () => { + const location = `${externalDevfileRegistryURL}/devfiles/devfile.yaml`; + expect(isDevfileRegistryLocation(location, config)).toBe(true); + }); + + test('non-registry devfile', () => { + const location = 'https://my-host.dev/devfiles/devfile.yaml'; + expect(isDevfileRegistryLocation(location, config)).toBe(false); + }); +}); diff --git a/packages/dashboard-frontend/src/store/FactoryResolver/__tests__/helpers.grabLink.spec.ts b/packages/dashboard-frontend/src/store/FactoryResolver/__tests__/helpers.grabLink.spec.ts new file mode 100644 index 000000000..a5dcf17a5 --- /dev/null +++ b/packages/dashboard-frontend/src/store/FactoryResolver/__tests__/helpers.grabLink.spec.ts @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2018-2024 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ + +import mockAxios, { AxiosResponse } from 'axios'; + +import { grabLink } from '@/store/FactoryResolver/helpers'; + +const mockGet = mockAxios.get as jest.Mock; + +describe('grabLink', () => { + beforeEach(() => { + mockGet.mockResolvedValue({ + data: 'inline:\n schemaVersion: 2.1.0\n metadata:\n name: che-code\n displayName: VS Code - Open Source', + }); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + test('list of links is empty', async () => { + const links = []; + const link = await grabLink(links, 'self'); + + expect(link).toBeUndefined(); + }); + + test('link is not found', async () => { + const links = getLinks(); + const link = await grabLink(links, '.che/my-editor.yaml'); + + expect(link).toBeUndefined(); + }); + + test('link is found', async () => { + const links = getLinks(); + const link = await grabLink(links, '.che/che-editor.yaml'); + + expect(link).toEqual( + 'inline:\n schemaVersion: 2.1.0\n metadata:\n name: che-code\n displayName: VS Code - Open Source', + ); + }); + + test('link is found but devfile is not found', async () => { + mockGet.mockRejectedValueOnce({ + response: { + headers: {}, + config: {}, + status: 404, + statusText: 'Not Found', + data: {}, + } as AxiosResponse, + }); + + const links = getLinks(); + await expect(grabLink(links, '.che/che-editor.yaml')).resolves.toBeUndefined(); + }); + + test('link is found but request fails', async () => { + const response = { + headers: {}, + config: {}, + status: 500, + statusText: 'Internal Server Error', + data: {}, + } as AxiosResponse; + mockGet.mockRejectedValueOnce({ + response, + }); + + const links = getLinks(); + await expect(grabLink(links, '.che/che-editor.yaml')).rejects.toEqual({ response }); + }); + + test('query parameters are encoded', async () => { + const links = getLinks(); + await grabLink(links, '.che/che-editor.yaml'); + + expect(mockAxios.get).toHaveBeenCalledWith( + 'https://che-host/api/scm/resolve?repository=https%3A%2F%2Fgithub.com%2Fusername%2Fweb-nodejs-sample%2Ftree%2Fubi9-devspaces-editor&file=.che%2Fche-editor.yaml', + expect.anything(), + ); + }); +}); + +function getLinks() { + return [ + { + href: 'https://che-host/api/scm/resolve?repository=https://github.com/username/repo&file=devfile.yaml', + rel: 'devfile.yaml content', + method: 'GET', + }, + { + href: 'https://che-host/api/scm/resolve?repository=https://github.com/username/web-nodejs-sample/tree/ubi9-devspaces-editor&file=.che/che-editor.yaml', + rel: '.che/che-editor.yaml content', + method: 'GET', + }, + { + href: 'https://che-host/api/scm/resolve?repository=https://github.com/username/web-nodejs-sample/tree/ubi9-devspaces-editor&file=.che/che-theia-plugins.yaml', + rel: '.che/che-theia-plugins.yaml content', + method: 'GET', + }, + { + href: 'https://che-host/api/scm/resolve?repository=https://github.com/username/web-nodejs-sample/tree/ubi9-devspaces-editor&file=.vscode/extensions.json', + rel: '.vscode/extensions.json content', + method: 'GET', + }, + ]; +} diff --git a/packages/dashboard-frontend/src/store/FactoryResolver/__tests__/normalizeDevfileV2.spec.ts b/packages/dashboard-frontend/src/store/FactoryResolver/__tests__/helpers.normalizeDevfileV2.spec.ts similarity index 63% rename from packages/dashboard-frontend/src/store/FactoryResolver/__tests__/normalizeDevfileV2.spec.ts rename to packages/dashboard-frontend/src/store/FactoryResolver/__tests__/helpers.normalizeDevfileV2.spec.ts index 1b7f61a7d..51287395a 100644 --- a/packages/dashboard-frontend/src/store/FactoryResolver/__tests__/normalizeDevfileV2.spec.ts +++ b/packages/dashboard-frontend/src/store/FactoryResolver/__tests__/helpers.normalizeDevfileV2.spec.ts @@ -10,11 +10,61 @@ * Red Hat, Inc. - initial API and implementation */ -import { V222DevfileComponents } from '@devfile/api'; +import { V222Devfile, V222DevfileComponents } from '@devfile/api'; -import devfileApi from '@/services/devfileApi'; import { FactoryResolver } from '@/services/helpers/types'; -import normalizeDevfileV2 from '@/store/FactoryResolver/normalizeDevfileV2'; +import { che } from '@/services/models'; +import { buildDevfileV2, normalizeDevfile } from '@/store/FactoryResolver/helpers'; + +describe('buildDevfileV2', () => { + let devfileV1: che.api.workspace.devfile.Devfile; + + beforeEach(() => { + devfileV1 = { + apiVersion: '1.0.0', + metadata: { + generateName: 'empty', + }, + projects: [ + { + name: 'my-project', + source: { + location: 'https://github.com/my/project.git', + type: 'github', + }, + }, + ], + }; + }); + + it('should return a devfile with the correct schemaVersion', () => { + const devfile = buildDevfileV2(devfileV1); + + expect(devfile.schemaVersion).toEqual('2.2.2'); + }); + + it('should return a devfile with the correct metadata', () => { + const devfile = buildDevfileV2(devfileV1); + + expect(devfile.metadata).toStrictEqual(devfile.metadata); + }); + + it('should return a devfile with the correct projects', () => { + const devfile = buildDevfileV2(devfileV1); + + expect(devfile.projects).toStrictEqual([ + { + attributes: {}, + git: { + remotes: { + origin: 'https://github.com/my/project.git', + }, + }, + name: 'my-project', + }, + ]); + }); +}); describe('Normalize Devfile V2', () => { let defaultComponents: V222DevfileComponents[]; @@ -31,8 +81,8 @@ describe('Normalize Devfile V2', () => { }); it('should not apply defaultComponents if components exist', () => { - const devfileLike = { - schemaVersion: '2.1.0', + const devfile = { + schemaVersion: '2.2.2', metadata: { generateName: 'empty', }, @@ -44,11 +94,12 @@ describe('Normalize Devfile V2', () => { name: 'custom-image', }, ], - } as devfileApi.DevfileLike; + } as V222Devfile; - const targetDevfile = normalizeDevfileV2( - devfileLike, - {} as FactoryResolver, + const targetDevfile = normalizeDevfile( + { + devfile, + } as FactoryResolver, 'http://dummy-registry/devfiles/empty.yaml', defaultComponents, 'che', @@ -62,14 +113,14 @@ describe('Normalize Devfile V2', () => { ); expect(targetDevfile).toEqual( expect.objectContaining({ - components: devfileLike.components, + components: devfile.components, }), ); }); it('should not apply defaultComponents if parent exist', () => { - const devfileLike = { - schemaVersion: '2.1.0', + const devfile = { + schemaVersion: '2.2.2', metadata: { generateName: 'empty', }, @@ -79,11 +130,12 @@ describe('Normalize Devfile V2', () => { version: '1.2.0', }, components: [], - } as devfileApi.DevfileLike; + } as V222Devfile; - const targetDevfile = normalizeDevfileV2( - devfileLike, - {} as FactoryResolver, + const targetDevfile = normalizeDevfile( + { + devfile, + } as FactoryResolver, 'http://dummy-registry/devfiles/empty.yaml', defaultComponents, 'che', @@ -97,19 +149,20 @@ describe('Normalize Devfile V2', () => { ); expect(targetDevfile).toEqual( expect.objectContaining({ - components: devfileLike.components, + components: devfile.components, }), ); }); it('should apply metadata name and namespace', () => { - const devfileLike = { - schemaVersion: '2.1.0', - } as devfileApi.DevfileLike; + const devfile = { + schemaVersion: '2.2.2', + } as V222Devfile; - const targetDevfile = normalizeDevfileV2( - devfileLike, - {} as FactoryResolver, + const targetDevfile = normalizeDevfile( + { + devfile, + } as FactoryResolver, 'http://dummy-registry/devfiles/empty.yaml', [], 'che', @@ -121,17 +174,18 @@ describe('Normalize Devfile V2', () => { }); it('should apply defaultComponents', () => { - const devfileLike = { - schemaVersion: '2.1.0', + const devfile = { + schemaVersion: '2.2.2', metadata: { generateName: 'empty', }, components: [], - } as devfileApi.DevfileLike; + } as V222Devfile; - const targetDevfile = normalizeDevfileV2( - devfileLike, - {} as FactoryResolver, + const targetDevfile = normalizeDevfile( + { + devfile, + } as FactoryResolver, 'http://dummy-registry/devfiles/empty.yaml', defaultComponents, 'che', @@ -140,7 +194,7 @@ describe('Normalize Devfile V2', () => { expect(targetDevfile).not.toEqual( expect.objectContaining({ - components: devfileLike.components, + components: devfile.components, }), ); expect(targetDevfile).toEqual( @@ -151,8 +205,8 @@ describe('Normalize Devfile V2', () => { }); it('should apply the custom image from factory params', () => { - const devfileLike = { - schemaVersion: '2.1.0', + const devfile = { + schemaVersion: '2.2.2', metadata: { generateName: 'empty', }, @@ -164,14 +218,15 @@ describe('Normalize Devfile V2', () => { name: 'developer-image', }, ], - } as devfileApi.DevfileLike; + } as V222Devfile; const factoryParams = { image: 'quay.io/devfile/universal-developer-image:test', }; - const targetDevfile = normalizeDevfileV2( - devfileLike, - {} as FactoryResolver, + const targetDevfile = normalizeDevfile( + { + devfile, + } as FactoryResolver, 'http://dummy-registry/devfiles/empty.yaml', defaultComponents, 'che', @@ -193,19 +248,20 @@ describe('Normalize Devfile V2', () => { }); it('should apply defaultComponents and then the custom image from factory params', () => { - const devfileLike = { - schemaVersion: '2.1.0', + const devfile = { + schemaVersion: '2.2.2', metadata: { generateName: 'empty', }, - } as devfileApi.DevfileLike; + } as V222Devfile; const factoryParams = { image: 'quay.io/devfile/universal-developer-image:test', }; - const targetDevfile = normalizeDevfileV2( - devfileLike, - {} as FactoryResolver, + const targetDevfile = normalizeDevfile( + { + devfile, + } as FactoryResolver, 'http://dummy-registry/devfiles/empty.yaml', defaultComponents, 'che', diff --git a/packages/dashboard-frontend/src/store/FactoryResolver/__tests__/index.spec.ts b/packages/dashboard-frontend/src/store/FactoryResolver/__tests__/index.spec.ts deleted file mode 100644 index 40ce417d2..000000000 --- a/packages/dashboard-frontend/src/store/FactoryResolver/__tests__/index.spec.ts +++ /dev/null @@ -1,439 +0,0 @@ -/* - * Copyright (c) 2018-2024 Red Hat, Inc. - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Red Hat, Inc. - initial API and implementation - */ - -import common from '@eclipse-che/common'; -import { AxiosError } from 'axios'; -import { MockStoreEnhanced } from 'redux-mock-store'; -import { ThunkDispatch } from 'redux-thunk'; - -import * as factoryResolver from '@/services/backend-client/factoryApi'; -import * as yamlResolver from '@/services/backend-client/yamlResolverApi'; -import { convertDevfileV1toDevfileV2 } from '@/services/devfile/converters'; -import devfileApi from '@/services/devfileApi'; -import { FactoryResolver } from '@/services/helpers/types'; -import { che } from '@/services/models'; -import { AppState } from '@/store'; -import { FakeStoreBuilder } from '@/store/__mocks__/storeBuilder'; -import normalizeDevfileV1 from '@/store/FactoryResolver/normalizeDevfileV1'; -import normalizeDevfileV2 from '@/store/FactoryResolver/normalizeDevfileV2'; -import { AUTHORIZED } from '@/store/sanityCheckMiddleware'; - -import * as factoryResolverStore from '..'; - -jest.mock('../normalizeDevfileV1.ts'); -(normalizeDevfileV1 as jest.Mock).mockImplementation(devfile => { - return devfile; -}); -jest.mock('../normalizeDevfileV2.ts'); -(normalizeDevfileV2 as jest.Mock).mockImplementation(devfile => { - return devfile; -}); - -jest.mock('@/services/devfile/converters'); -(convertDevfileV1toDevfileV2 as jest.Mock).mockImplementation(async () => { - return { - schemaVersion: '2.0.0', - } as devfileApi.Devfile; -}); - -jest.mock('@/services/devfileApi'); -jest.mock('@/services/devfileApi/typeguards.ts', () => { - return { - // eslint-disable-next-line @typescript-eslint/ban-types - ...(jest.requireActual('@/services/devfileApi/typeguards.ts') as Object), - isDevfileV2: (devfile: unknown): boolean => { - return (devfile as devfileApi.Devfile).schemaVersion !== undefined; - }, - }; -}); - -// mute the error outputs -console.error = jest.fn(); - -const getFactoryResolverSpy = jest.spyOn(factoryResolver, 'getFactoryResolver'); -const getYamlResolverSpy = jest.spyOn(yamlResolver, 'getYamlResolver'); - -describe('FactoryResolver store', () => { - describe('requestFactoryResolver action', () => { - it('should convert resolved devfile v1 with devworkspace mode ENABLED', async () => { - const resolver = { - devfile: { - apiVersion: '1.0.0', - } as che.api.workspace.devfile.Devfile, - } as FactoryResolver; - - getFactoryResolverSpy.mockResolvedValueOnce(resolver); - - const store = new FakeStoreBuilder().build() as MockStoreEnhanced< - AppState, - ThunkDispatch - >; - - const location = 'http://factory-link'; - await store.dispatch( - factoryResolverStore.actionCreators.requestFactoryResolver(location, {}), - ); - - const actions = store.getActions(); - expect(actions).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - type: 'RECEIVE_FACTORY_RESOLVER', - converted: expect.objectContaining({ - isConverted: true, - }), - }), - ]), - ); - }); - - it('should NOT convert resolved devfile v2.x.x with devworkspace mode ENABLED', async () => { - const resolver = { - devfile: { - schemaVersion: '2.0.0', - } as devfileApi.Devfile, - } as factoryResolverStore.ResolverState; - - getFactoryResolverSpy.mockResolvedValueOnce(resolver); - - const store = new FakeStoreBuilder().build() as MockStoreEnhanced< - AppState, - ThunkDispatch - >; - - const location = 'http://factory-link'; - await store.dispatch( - factoryResolverStore.actionCreators.requestFactoryResolver(location, {}), - ); - - const actions = store.getActions(); - expect(actions).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - type: 'RECEIVE_FACTORY_RESOLVER', - converted: expect.objectContaining({ - isConverted: false, - }), - }), - ]), - ); - }); - }); - - describe('actions', () => { - it('should create REQUEST_FACTORY_RESOLVER and RECEIVE_FACTORY_RESOLVER_ERROR', async () => { - getFactoryResolverSpy.mockRejectedValueOnce({ - isAxiosError: true, - code: '500', - response: { - data: { - message: 'Something unexpected happened.', - }, - }, - } as AxiosError); - - const store = new FakeStoreBuilder().build() as MockStoreEnhanced< - AppState, - ThunkDispatch - >; - - const actions = store.getActions(); - const expectedActions: factoryResolverStore.KnownAction[] = [ - { - type: 'REQUEST_FACTORY_RESOLVER', - check: AUTHORIZED, - }, - { - type: 'RECEIVE_FACTORY_RESOLVER_ERROR', - error: expect.stringContaining('Unexpected error'), - }, - ]; - - const isAxiosErrorMock = jest - .spyOn(common.helpers.errors, 'isAxiosError') - .mockImplementation(() => true); - const isAxiosResponseMock = jest - .spyOn(common.helpers.errors, 'isAxiosResponse') - .mockImplementation(() => true); - - const location = 'http://factory-link'; - await expect( - store.dispatch(factoryResolverStore.actionCreators.requestFactoryResolver(location, {})), - ).rejects.toMatch('Unexpected error'); - expect(actions).toEqual(expectedActions); - - isAxiosErrorMock.mockRestore(); - isAxiosResponseMock.mockRestore(); - }); - - it('should throw if it resolves no devfile', async () => { - const resolver = {} as factoryResolverStore.ResolverState; - - getFactoryResolverSpy.mockResolvedValueOnce(resolver); - - const store = new FakeStoreBuilder().build() as MockStoreEnhanced< - AppState, - ThunkDispatch - >; - - const actions = store.getActions(); - const expectedActions: factoryResolverStore.KnownAction[] = [ - { - type: 'REQUEST_FACTORY_RESOLVER', - check: AUTHORIZED, - }, - { - type: 'RECEIVE_FACTORY_RESOLVER_ERROR', - error: expect.stringContaining('The specified link does not contain a valid Devfile.'), - }, - ]; - - const location = 'http://factory-link'; - await expect( - store.dispatch(factoryResolverStore.actionCreators.requestFactoryResolver(location, {})), - ).rejects.toMatch('The specified link does not contain a valid Devfile.'); - expect(actions).toEqual(expectedActions); - }); - - it('should reject if authentication is needed', async () => { - getFactoryResolverSpy.mockRejectedValueOnce({ - isAxiosError: true, - code: '401', - response: { - headers: {}, - status: 401, - statusText: 'Unauthorized', - config: {}, - data: { - attributes: { - oauth_provider: 'oauth_provider', - oauth_authentication_url: 'oauth_authentication_url', - }, - }, - }, - } as AxiosError); - - const store = new FakeStoreBuilder().build() as MockStoreEnhanced< - AppState, - ThunkDispatch - >; - - const isAxiosErrorMock = jest - .spyOn(common.helpers.errors, 'isAxiosError') - .mockReturnValue(true); - const isAxiosResponseMock = jest - .spyOn(common.helpers.errors, 'isAxiosResponse') - .mockReturnValue(true); - - const location = 'http://factory-link'; - await expect( - store.dispatch(factoryResolverStore.actionCreators.requestFactoryResolver(location, {})), - ).rejects.toEqual({ - attributes: { - oauth_provider: 'oauth_provider', - oauth_authentication_url: 'oauth_authentication_url', - }, - }); - - isAxiosErrorMock.mockRestore(); - isAxiosResponseMock.mockRestore(); - }); - }); - - describe('reducers', () => { - it('should return initial state', () => { - const incomingAction: factoryResolverStore.KnownAction = { - type: 'REQUEST_FACTORY_RESOLVER', - check: AUTHORIZED, - }; - - const initialState = factoryResolverStore.reducer(undefined, incomingAction); - const expectedState: factoryResolverStore.State = { - isLoading: false, - }; - - expect(initialState).toEqual(expectedState); - }); - - it('should return state if action is not matched', () => { - const initialState: factoryResolverStore.State = { - isLoading: true, - }; - const incomingAction = { - type: 'OTHER_ACTION', - }; - - const newState = factoryResolverStore.reducer(initialState, incomingAction); - const expectedState: factoryResolverStore.State = { - isLoading: true, - }; - - expect(newState).toEqual(expectedState); - }); - - it('should handle REQUEST_FACTORY_RESOLVER', () => { - const initialState: factoryResolverStore.State = { - isLoading: false, - }; - const incomingAction: factoryResolverStore.KnownAction = { - type: 'REQUEST_FACTORY_RESOLVER', - check: AUTHORIZED, - }; - - const newState = factoryResolverStore.reducer(initialState, incomingAction); - const expectedState: factoryResolverStore.State = { - isLoading: true, - }; - - expect(newState).toEqual(expectedState); - }); - - it('should handle RECEIVE_FACTORY_RESOLVER', () => { - const initialState: factoryResolverStore.State = { - isLoading: true, - }; - const resolver = { - devfile: { - schemaVersion: '2.0.0', - } as devfileApi.Devfile, - } as factoryResolverStore.ResolverState; - const converted: factoryResolverStore.ConvertedState = { - isConverted: false, - } as any; - const incomingAction: factoryResolverStore.KnownAction = { - type: 'RECEIVE_FACTORY_RESOLVER', - resolver, - converted, - }; - - const newState = factoryResolverStore.reducer(initialState, incomingAction); - const expectedState: factoryResolverStore.State = { - isLoading: false, - resolver, - converted, - }; - - expect(newState).toEqual(expectedState); - }); - - it('should handle RECEIVE_FACTORY_RESOLVER_ERROR', () => { - const initialState: factoryResolverStore.State = { - isLoading: true, - }; - const incomingAction: factoryResolverStore.KnownAction = { - type: 'RECEIVE_FACTORY_RESOLVER_ERROR', - error: 'Unexpected error', - }; - - const newState = factoryResolverStore.reducer(initialState, incomingAction); - const expectedState: factoryResolverStore.State = { - isLoading: false, - error: 'Unexpected error', - }; - - expect(newState).toEqual(expectedState); - }); - }); - - describe('check resolver types', () => { - const resolver = { - devfile: { - schemaVersion: '2.0.0', - } as devfileApi.Devfile, - } as factoryResolverStore.ResolverState; - - let store: MockStoreEnhanced< - AppState, - ThunkDispatch - >; - - beforeEach(() => { - delete (window as any).location; - (window.location as any) = { protocol: 'http:', host: 'localhost:8080' }; - - store = new FakeStoreBuilder() - .withInfrastructureNamespace([ - { - attributes: { phase: 'Active' }, - name: 'user-che', - }, - ]) - .withDwServerConfig({ - devfileRegistry: { - disableInternalRegistry: false, - externalDevfileRegistries: [{ url: 'https://registry.devfile.io/' }], - }, - devfileRegistryURL: 'http://localhost:8080/devfile-registry/', - }) - .build(); - - getFactoryResolverSpy.mockResolvedValueOnce(resolver); - getYamlResolverSpy.mockResolvedValueOnce(resolver); - }); - - afterEach(() => { - jest.clearAllMocks(); - }); - - it('should call the yaml resolver for a builtin devfile registry', async () => { - const location = 'http://localhost:8080/devfile-registry/devfiles/empty.yaml'; - - await store.dispatch( - factoryResolverStore.actionCreators.requestFactoryResolver(location, {}), - ); - - expect(getYamlResolverSpy).toHaveBeenCalledWith(location); - expect(getFactoryResolverSpy).not.toHaveBeenCalledWith(location, { - error_code: undefined, - }); - }); - - it('should call the yaml resolver for an external devfile registry', async () => { - const location = 'https://registry.devfile.io/devfiles/nodejs/2.1.1'; - - await store.dispatch( - factoryResolverStore.actionCreators.requestFactoryResolver(location, {}), - ); - - expect(getYamlResolverSpy).toHaveBeenCalledWith(location); - expect(getFactoryResolverSpy).not.toHaveBeenCalledWith(location, { - error_code: undefined, - }); - }); - - it('should call the yaml resolver for the default devfile registry', async () => { - const location = 'http://localhost:8080/dashboard/devfile-registry/devfiles/empty.yaml'; - - await store.dispatch( - factoryResolverStore.actionCreators.requestFactoryResolver(location, {}), - ); - - expect(getYamlResolverSpy).toHaveBeenCalledWith(location); - expect(getFactoryResolverSpy).not.toHaveBeenCalledWith(location, { - error_code: undefined, - }); - }); - - it('should call the factory resolver by default', async () => { - const location = 'https://github.com/eclipse-che/che-dashboard.git'; - - await store.dispatch( - factoryResolverStore.actionCreators.requestFactoryResolver(location, {}), - ); - - expect(getYamlResolverSpy).not.toHaveBeenCalledWith(location); - expect(getFactoryResolverSpy).toHaveBeenCalledWith(location, { - error_code: undefined, - }); - }); - }); -}); diff --git a/packages/dashboard-frontend/src/store/FactoryResolver/__tests__/normalizeDevfileV1.spec.ts b/packages/dashboard-frontend/src/store/FactoryResolver/__tests__/normalizeDevfileV1.spec.ts deleted file mode 100644 index cd0dae0db..000000000 --- a/packages/dashboard-frontend/src/store/FactoryResolver/__tests__/normalizeDevfileV1.spec.ts +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2018-2024 Red Hat, Inc. - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Red Hat, Inc. - initial API and implementation - */ - -import { che } from '@eclipse-che/api'; - -import getRandomString from '@/services/helpers/random'; -import normalizeDevfileV1 from '@/store/FactoryResolver/normalizeDevfileV1'; - -describe('Normalize Devfile V1', () => { - it('should not change valid values (generateName, name and project name)', () => { - const prefix = 'prefix'; - const generateName = prefix + getRandomString(50).toLowerCase(); - const name = prefix + getRandomString(50).toLowerCase(); - const projectName = prefix + getRandomString(50).toLowerCase(); - - const devfileLike = { - apiVersion: '1.0.0', - metadata: { - generateName: generateName, - name: name, - }, - projects: [ - { - name: projectName, - source: { - location: 'https://github.com/eclipse-che/che-theia.git', - type: 'github', - }, - }, - ], - } as che.workspace.devfile.Devfile; - - const targetDevfile = normalizeDevfileV1(devfileLike, 'ephemeral'); - - expect(generateName).toEqual(targetDevfile.metadata?.generateName); - - expect(name).toEqual(targetDevfile.metadata?.name); - - expect(projectName).toEqual(targetDevfile.projects?.[0].name); - }); - - it('should fix invalid values (generateName, name and project name)', () => { - const prefix = 'prefix'; - const generateName = prefix.toUpperCase() + getRandomString(128); - const name = prefix.toUpperCase() + getRandomString(128); - const projectName = prefix.toUpperCase() + getRandomString(128); - - const devfileLike = { - apiVersion: '1.0.0', - metadata: { - generateName: generateName, - name: name, - }, - projects: [ - { - name: projectName, - source: { - location: 'https://github.com/eclipse-che/che-theia.git', - type: 'github', - }, - }, - ], - } as che.workspace.devfile.Devfile; - - const targetDevfile = normalizeDevfileV1(devfileLike, 'ephemeral'); - - expect(generateName.startsWith('PREFIX')).toBeTruthy(); - expect(generateName).not.toEqual(targetDevfile.metadata?.generateName); - - expect(targetDevfile.metadata?.generateName?.startsWith('prefix')).toBeTruthy(); - expect(targetDevfile.metadata?.generateName?.length).toBeLessThan(63); - - expect(name.startsWith('PREFIX')).toBeTruthy(); - expect(name).not.toEqual(targetDevfile.metadata?.name); - - expect(targetDevfile.metadata?.name?.startsWith('prefix')).toBeTruthy(); - expect(targetDevfile.metadata?.name?.length).toBeLessThan(63); - - expect(projectName.startsWith('PREFIX')).toBeTruthy(); - expect(projectName).not.toEqual(targetDevfile.projects?.[0].name); - - expect(targetDevfile.projects?.[0].name?.startsWith('prefix')).toBeTruthy(); - expect(targetDevfile.projects?.[0].name?.length).toBeLessThan(63); - }); -}); diff --git a/packages/dashboard-frontend/src/store/FactoryResolver/__tests__/reducer.spec.ts b/packages/dashboard-frontend/src/store/FactoryResolver/__tests__/reducer.spec.ts new file mode 100644 index 000000000..1d59d6d61 --- /dev/null +++ b/packages/dashboard-frontend/src/store/FactoryResolver/__tests__/reducer.spec.ts @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2018-2024 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ + +import devfileApi from '@/services/devfileApi'; +import { reducer } from '@/store/FactoryResolver/reducer'; +import { KnownAction, Resolver, State, Type } from '@/store/FactoryResolver/types'; +import { AUTHORIZED } from '@/store/sanityCheckMiddleware'; + +describe('FactoryResolver store, reducers', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should return initial state', () => { + const incomingAction: KnownAction = { + type: Type.REQUEST_FACTORY_RESOLVER, + check: AUTHORIZED, + }; + + const initialState = reducer(undefined, incomingAction); + const expectedState: State = { + isLoading: false, + }; + + expect(initialState).toEqual(expectedState); + }); + + it('should return state if action is not matched', () => { + const initialState: State = { + isLoading: true, + }; + const incomingAction = { + type: 'OTHER_ACTION', + }; + + const newState = reducer(initialState, incomingAction); + const expectedState: State = { + isLoading: true, + }; + + expect(newState).toEqual(expectedState); + }); + + it('should handle REQUEST_FACTORY_RESOLVER', () => { + const initialState: State = { + isLoading: false, + }; + const incomingAction: KnownAction = { + type: Type.REQUEST_FACTORY_RESOLVER, + check: AUTHORIZED, + }; + + const newState = reducer(initialState, incomingAction); + const expectedState: State = { + isLoading: true, + }; + + expect(newState).toEqual(expectedState); + }); + + it('should handle RECEIVE_FACTORY_RESOLVER', () => { + const initialState: State = { + isLoading: true, + }; + const resolver = { + devfile: { + schemaVersion: '2.0.0', + } as devfileApi.Devfile, + } as Resolver; + const incomingAction: KnownAction = { + type: Type.RECEIVE_FACTORY_RESOLVER, + resolver, + }; + + const newState = reducer(initialState, incomingAction); + const expectedState: State = { + isLoading: false, + resolver, + }; + + expect(newState).toEqual(expectedState); + }); + + it('should handle RECEIVE_FACTORY_RESOLVER_ERROR', () => { + const initialState: State = { + isLoading: true, + }; + const incomingAction: KnownAction = { + type: Type.RECEIVE_FACTORY_RESOLVER_ERROR, + error: 'Unexpected error', + }; + + const newState = reducer(initialState, incomingAction); + const expectedState: State = { + isLoading: false, + error: 'Unexpected error', + }; + + expect(newState).toEqual(expectedState); + }); +}); diff --git a/packages/dashboard-frontend/src/store/FactoryResolver/__tests__/selectors.spec.ts b/packages/dashboard-frontend/src/store/FactoryResolver/__tests__/selectors.spec.ts new file mode 100644 index 000000000..cfbd68aba --- /dev/null +++ b/packages/dashboard-frontend/src/store/FactoryResolver/__tests__/selectors.spec.ts @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2018-2024 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ + +import devfileApi from '@/services/devfileApi'; +import { AppState } from '@/store'; +import { + selectFactoryResolver, + selectFactoryResolverError, +} from '@/store/FactoryResolver/selectors'; +import { State } from '@/store/FactoryResolver/types'; + +describe('FactoryResolver, selectors', () => { + test('selectFactoryResolver', () => { + const state = { + resolver: { + devfile: { + schemaVersion: '2.2.2', + } as devfileApi.Devfile, + }, + isLoading: false, + } as State; + + const resolver = selectFactoryResolver({ factoryResolver: state } as AppState); + + expect(resolver).toEqual(state.resolver); + }); + + test('selectFactoryResolverError', () => { + const state = { + error: 'error', + isLoading: false, + } as State; + + const error = selectFactoryResolverError({ factoryResolver: state } as AppState); + + expect(error).toEqual(state.error); + }); +}); diff --git a/packages/dashboard-frontend/src/store/FactoryResolver/actions.ts b/packages/dashboard-frontend/src/store/FactoryResolver/actions.ts new file mode 100644 index 000000000..17236e9aa --- /dev/null +++ b/packages/dashboard-frontend/src/store/FactoryResolver/actions.ts @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2018-2024 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ + +import common from '@eclipse-che/common'; + +import { getFactoryResolver } from '@/services/backend-client/factoryApi'; +import { getYamlResolver } from '@/services/backend-client/yamlResolverApi'; +import { FactoryParams } from '@/services/helpers/factoryFlow/buildFactoryParams'; +import { FactoryResolver } from '@/services/helpers/types'; +import { isOAuthResponse } from '@/services/oauth'; +import { CHE_EDITOR_YAML_PATH } from '@/services/workspace-client/helpers'; +import { + grabLink, + isDevfileRegistryLocation, + normalizeDevfile, +} from '@/store/FactoryResolver/helpers'; +import { ActionCreators, KnownAction, Type } from '@/store/FactoryResolver/types'; +import { AppThunk } from '@/store/index'; +import { selectDefaultNamespace } from '@/store/InfrastructureNamespaces/selectors'; +import { selectAsyncIsAuthorized, selectSanityCheckError } from '@/store/SanityCheck/selectors'; +import { AUTHORIZED } from '@/store/sanityCheckMiddleware'; +import { selectDefaultComponents } from '@/store/ServerConfig/selectors'; + +export const actionCreators: ActionCreators = { + requestFactoryResolver: + ( + location: string, + factoryParams: Partial = {}, + ): AppThunk> => + async (dispatch, getState): Promise => { + const state = getState(); + const namespace = selectDefaultNamespace(state).name; + const optionalFilesContent = {}; + + const overrideParams = factoryParams + ? Object.assign({}, factoryParams.overrides, { + error_code: factoryParams?.errorCode, + }) + : undefined; + + try { + await dispatch({ + type: Type.REQUEST_FACTORY_RESOLVER, + check: AUTHORIZED, + }); + if (!(await selectAsyncIsAuthorized(getState()))) { + const error = selectSanityCheckError(getState()); + throw new Error(error); + } + let data: FactoryResolver; + + if (isDevfileRegistryLocation(location, state.dwServerConfig.config)) { + data = await getYamlResolver(location); + } else { + data = await getFactoryResolver(location, overrideParams); + const cheEditor = await grabLink(data.links || [], CHE_EDITOR_YAML_PATH); + if (cheEditor) { + optionalFilesContent[CHE_EDITOR_YAML_PATH] = cheEditor; + } + } + + if (!data.devfile) { + throw new Error('The specified link does not contain any Devfile.'); + } + + const defaultComponents = selectDefaultComponents(state); + const devfile = normalizeDevfile( + data, + location, + defaultComponents, + namespace, + factoryParams, + ); + + const resolver = { + ...data, + devfile: devfile, + location, + optionalFilesContent, + }; + + dispatch({ + type: Type.RECEIVE_FACTORY_RESOLVER, + resolver, + }); + return; + } catch (e) { + if (common.helpers.errors.includesAxiosResponse(e)) { + const response = e.response; + if (response.status === 401 && isOAuthResponse(response.data)) { + throw response.data; + } + } + const errorMessage = common.helpers.errors.getMessage(e); + dispatch({ + type: Type.RECEIVE_FACTORY_RESOLVER_ERROR, + error: errorMessage, + }); + throw errorMessage; + } + }, +}; diff --git a/packages/dashboard-frontend/src/store/FactoryResolver/helpers.ts b/packages/dashboard-frontend/src/store/FactoryResolver/helpers.ts new file mode 100644 index 000000000..2830bb632 --- /dev/null +++ b/packages/dashboard-frontend/src/store/FactoryResolver/helpers.ts @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2018-2024 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ + +import { V222DevfileComponents, V222DevfileProjects } from '@devfile/api'; +import common, { api } from '@eclipse-che/common'; +import axios from 'axios'; +import { dump } from 'js-yaml'; +import { cloneDeep } from 'lodash'; + +import { DevfileAdapter } from '@/services/devfile/adapter'; +import devfileApi, { isDevfileV2 } from '@/services/devfileApi'; +import { FactoryParams } from '@/services/helpers/factoryFlow/buildFactoryParams'; +import { generateWorkspaceName } from '@/services/helpers/generateName'; +import { getProjectName } from '@/services/helpers/getProjectName'; +import { DevfileV2ProjectSource, FactoryResolver } from '@/services/helpers/types'; +import { che } from '@/services/models'; +import { + DEVWORKSPACE_DEVFILE_SOURCE, + DEVWORKSPACE_METADATA_ANNOTATION, +} from '@/services/workspace-client/devworkspace/devWorkspaceClient'; +import { DEFAULT_REGISTRY } from '@/store/DevfileRegistries'; + +/** + * Grabs an editor devfile from the provided links. + */ +export async function grabLink( + links: che.api.core.rest.Link[], + filename: string, +): Promise { + // handle servers not yet providing links + if (links.length === 0) { + return undefined; + } + // grab the one matching + const foundLink = links.find(link => link.href?.includes(`file=${filename}`)); + if (!foundLink || !foundLink.href) { + return undefined; + } + + const url = new URL(foundLink.href); + url.searchParams.forEach((value, key) => url.searchParams.set(key, encodeURI(value))); + + try { + // load it in raw format + // see https://github.com/axios/axios/issues/907 + const response = await axios.get(url.href, { + responseType: 'text', + transformResponse: [ + data => { + return data; + }, + ], + }); + return response.data; + } catch (error) { + // content may not be there + if (common.helpers.errors.includesAxiosResponse(error) && error.response?.status == 404) { + return undefined; + } + throw error; + } +} + +/** + * Checks if the location is a devfile registry location. + */ +export function isDevfileRegistryLocation(location: string, config: api.IServerConfig): boolean { + const devfileRegistries = [`${window.location.origin}${DEFAULT_REGISTRY}`]; + + if (config.devfileRegistryURL) { + devfileRegistries.push(config.devfileRegistryURL); + } + + const externalDevfileRegistries = config.devfileRegistry.externalDevfileRegistries.map( + externalDevfileRegistry => externalDevfileRegistry.url, + ); + if (externalDevfileRegistries.length) { + devfileRegistries.push(...externalDevfileRegistries); + } + + return devfileRegistries.some(registry => location.startsWith(registry)); +} + +/** + * Returns `true` if the devfile was resolved successfully. + */ +/* c8 ignore next 3 */ +export function isDevfileFoundInRepo(data: FactoryResolver): boolean { + return data.source !== 'repo'; +} + +/** + * Builds a Devfile V2 from a default Devfile V1 returned by che-server. + */ +export function buildDevfileV2( + devfileV1: che.api.workspace.devfile.Devfile | undefined, +): devfileApi.DevfileLike { + const devfile = { + schemaVersion: '2.2.2', + } as devfileApi.DevfileLike; + + const metadataV1 = devfileV1?.metadata; + if (metadataV1 !== undefined) { + devfile.metadata = metadataV1; + } + + const projectV1 = devfileV1?.projects?.[0]; + if (projectV1 !== undefined) { + const projectName = (projectV1.name || metadataV1?.name || metadataV1?.generateName || '') + // the name can't have spaces + // replace space by dash and then remove all special characters + .replace(/\s+/g, '-') + // names should not use _ + .replace(/_/g, '-') + // names should not use . + .replace(/\./g, '-') + // trim '-' character from start or end + .replace(/^-+|-+$/g, '') + .toLowerCase(); + + const devfileV2Project: V222DevfileProjects = { + attributes: {}, + name: projectName, + }; + if (projectV1.clonePath) { + devfileV2Project.clonePath = projectV1.clonePath; + } + + if (projectV1.source) { + const source = projectV1.source; + if (source.type === 'git' || source.type === 'github' || source.type === 'bitbucket') { + const remotes = { origin: source.location! }; + devfileV2Project.git = { + remotes, + }; + } else if (source.type === 'zip') { + devfileV2Project.zip = { + location: source.location, + }; + } + } + devfile.projects = [devfileV2Project]; + } + return devfile; +} + +/** + * Returns a devfile from the FactoryResolver object. + * @param data a FactoryResolver object. + * @param location a source location. + * @param defaultComponents Default components. These default components + * are meant to be used when a Devfile does not contain any components. + * @param namespace the namespace where the pod lives. + * @param factoryParams a Partial object. + */ + +export function normalizeDevfile( + data: FactoryResolver, + location: string, + defaultComponents: V222DevfileComponents[], + namespace: string, + factoryParams: Partial, +): devfileApi.Devfile { + /* Validate object */ + + let _devfile: unknown = data.devfile; + if (isDevfileFoundInRepo(data) === true) { + _devfile = data.devfile; + } else if (!isDevfileV2(data.devfile)) { + _devfile = buildDevfileV2(data.devfile); + } + if (!isDevfileV2(_devfile)) { + throw new Error('Received object is not a Devfile V2.'); + } + + const scmInfo = data['scm_info']; + const devfile = cloneDeep(_devfile); + + /* Devfile Metadata */ + + const projectName = getProjectName(scmInfo?.clone_url || location); + const namePrefix = devfile.metadata?.generateName ? devfile.metadata?.generateName : projectName; + const name = devfile.metadata?.name || generateWorkspaceName(namePrefix); + + const metadata: devfileApi.DevfileMetadata = { + name, + namespace, + }; + + devfile.metadata = Object.assign({}, metadata, devfile.metadata); + delete devfile.metadata.generateName; + + /* Devfile Components */ + + // propagate default components + if (!devfile.parent && (!devfile.components || devfile.components.length === 0)) { + devfile.components = cloneDeep(defaultComponents); + } + + if (devfile.components && devfile.components.length > 0) { + // apply the custom image from factory params + if (factoryParams.image && devfile.components[0].container?.image) { + devfile.components[0].container.image = factoryParams.image; + } + + // temporary solution for fix che-server serialization bug with empty volume + devfile.components.forEach(component => { + if (Object.keys(component).length === 1 && component.name) { + component.volume = {}; + } + }); + } + + /* Devfile Projects */ + + // add a default project + const projects: DevfileV2ProjectSource[] = []; + if (!devfile.projects?.length && scmInfo) { + const origin = scmInfo.clone_url; + const projectName = getProjectName(origin); + const revision = scmInfo.branch; + const project: DevfileV2ProjectSource = { name: projectName, git: { remotes: { origin } } }; + if (revision) { + project.git.checkoutFrom = { revision }; + } + projects.push(project); + devfile.projects = projects; + } + + // provide metadata about the origin of the devfile with DevWorkspace + let devfileSource = ''; + if (data.source && scmInfo) { + if (scmInfo.branch) { + devfileSource = dump({ + scm: { + repo: scmInfo['clone_url'], + revision: scmInfo.branch, + fileName: data.source, + }, + }); + } else { + devfileSource = dump({ + scm: { + repo: scmInfo['clone_url'], + fileName: data.source, + }, + }); + } + } else if (location) { + devfileSource = dump({ url: { location } }); + } + + /* Devfile Attributes */ + + const attributes = DevfileAdapter.getAttributes(devfile); + + if (!attributes[DEVWORKSPACE_METADATA_ANNOTATION]) { + attributes[DEVWORKSPACE_METADATA_ANNOTATION] = {}; + } + attributes[DEVWORKSPACE_METADATA_ANNOTATION][DEVWORKSPACE_DEVFILE_SOURCE] = devfileSource; + + return devfile; +} diff --git a/packages/dashboard-frontend/src/store/FactoryResolver/index.ts b/packages/dashboard-frontend/src/store/FactoryResolver/index.ts index deb49f31f..170db81cf 100644 --- a/packages/dashboard-frontend/src/store/FactoryResolver/index.ts +++ b/packages/dashboard-frontend/src/store/FactoryResolver/index.ts @@ -10,274 +10,12 @@ * Red Hat, Inc. - initial API and implementation */ -import common from '@eclipse-che/common'; -import axios from 'axios'; -import { Action, Reducer } from 'redux'; - -import { getFactoryResolver } from '@/services/backend-client/factoryApi'; -import { getYamlResolver } from '@/services/backend-client/yamlResolverApi'; -import { convertDevfileV1toDevfileV2 } from '@/services/devfile/converters'; -import devfileApi, { isDevfileV2 } from '@/services/devfileApi'; -import { FactoryParams } from '@/services/helpers/factoryFlow/buildFactoryParams'; -import { FactoryResolver } from '@/services/helpers/types'; -import { che } from '@/services/models'; -import { isOAuthResponse } from '@/services/oauth'; -import { CHE_EDITOR_YAML_PATH } from '@/services/workspace-client/helpers'; -import { DEFAULT_REGISTRY } from '@/store/DevfileRegistries'; -import normalizeDevfileV1 from '@/store/FactoryResolver/normalizeDevfileV1'; -import normalizeDevfileV2 from '@/store/FactoryResolver/normalizeDevfileV2'; -import { createObject } from '@/store/helpers'; -import { AppThunk } from '@/store/index'; -import { selectDefaultNamespace } from '@/store/InfrastructureNamespaces/selectors'; -import { selectAsyncIsAuthorized, selectSanityCheckError } from '@/store/SanityCheck/selectors'; -import { AUTHORIZED, SanityCheckAction } from '@/store/sanityCheckMiddleware'; -import { selectDefaultComponents, selectPvcStrategy } from '@/store/ServerConfig/selectors'; - -export type OAuthResponse = { - attributes: { - oauth_provider: string; - oauth_version: string; - oauth_authentication_url: string; - }; - errorCode: number; - message: string | undefined; -}; - -export interface ResolverState extends FactoryResolver { - devfile: devfileApi.Devfile; - optionalFilesContent?: { - [fileName: string]: string; - }; -} - -export interface ConvertedState { - resolvedDevfile: devfileApi.Devfile | che.api.workspace.devfile.Devfile; - devfileV2: devfileApi.Devfile; - isConverted: boolean; -} - -export interface State { - isLoading: boolean; - resolver?: ResolverState; - converted?: ConvertedState; - error?: string; -} - -interface RequestFactoryResolverAction extends Action, SanityCheckAction { - type: 'REQUEST_FACTORY_RESOLVER'; -} - -interface ReceiveFactoryResolverAction { - type: 'RECEIVE_FACTORY_RESOLVER'; - resolver: ResolverState; - converted: ConvertedState; -} - -interface ReceiveFactoryResolverErrorAction { - type: 'RECEIVE_FACTORY_RESOLVER_ERROR'; - error: string | undefined; -} - -export type KnownAction = - | RequestFactoryResolverAction - | ReceiveFactoryResolverAction - | ReceiveFactoryResolverErrorAction; - -export type ActionCreators = { - requestFactoryResolver: ( - location: string, - factoryParams: Partial, - ) => AppThunk>; -}; - -export async function grabLink( - links: che.api.core.rest.Link[], - filename: string, -): Promise { - // handle servers not yet providing links - if (!links || links.length === 0) { - return undefined; - } - // grab the one matching - const foundLink = links.find(link => link.href?.includes(`file=${filename}`)); - if (!foundLink || !foundLink.href) { - return undefined; - } - - const url = new URL(foundLink.href); - let search = '?'; - url.searchParams.forEach((value, key) => { - search += `${key}=${encodeURIComponent(encodeURI(value))}&`; - }); - search = search.slice(0, -1); - - try { - // load it in raw format - // see https://github.com/axios/axios/issues/907 - const response = await axios.get(`${url.pathname}${search}`, { - responseType: 'text', - transformResponse: [ - data => { - return data; - }, - ], - }); - return response.data; - } catch (error) { - // content may not be there - if (common.helpers.errors.isAxiosError(error) && error.response?.status == 404) { - return undefined; - } - throw error; - } -} - -export const actionCreators: ActionCreators = { - requestFactoryResolver: - ( - location: string, - factoryParams: Partial = {}, - ): AppThunk> => - async (dispatch, getState): Promise => { - const state = getState(); - const namespace = selectDefaultNamespace(state).name; - const optionalFilesContent = {}; - - const overrideParams = factoryParams - ? Object.assign({}, factoryParams.overrides, { - error_code: factoryParams?.errorCode, - }) - : undefined; - const isDevfileRegistryLocation = (location: string): boolean => { - const devfileRegistries = [ - `${window.location.protocol}//${window.location.host}${DEFAULT_REGISTRY}`, - ]; - if (state.dwServerConfig.config.devfileRegistryURL) { - devfileRegistries.push(state.dwServerConfig.config.devfileRegistryURL); - } - const externalDevfileRegistries = - state.dwServerConfig.config.devfileRegistry.externalDevfileRegistries.map( - externalDevfileRegistry => externalDevfileRegistry.url, - ); - if (externalDevfileRegistries.length) { - devfileRegistries.push(...externalDevfileRegistries); - } - return devfileRegistries.some(registry => location.startsWith(registry)); - }; - - try { - await dispatch({ type: 'REQUEST_FACTORY_RESOLVER', check: AUTHORIZED }); - if (!(await selectAsyncIsAuthorized(getState()))) { - const error = selectSanityCheckError(getState()); - throw new Error(error); - } - let data: FactoryResolver; - if (isDevfileRegistryLocation(location)) { - data = await getYamlResolver(location); - } else { - data = await getFactoryResolver(location, overrideParams); - const cheEditor = await grabLink(data.links || [], CHE_EDITOR_YAML_PATH); - if (cheEditor) { - optionalFilesContent[CHE_EDITOR_YAML_PATH] = cheEditor; - } - } - if (!data.devfile) { - throw new Error('The specified link does not contain a valid Devfile.'); - } - const preferredStorageType = selectPvcStrategy(state) as che.WorkspaceStorageType; - const isResolvedDevfileV2 = isDevfileV2(data.devfile); - let devfileV2: devfileApi.Devfile; - const defaultComponents = selectDefaultComponents(state); - if (isDevfileV2(data.devfile)) { - devfileV2 = normalizeDevfileV2( - data.devfile as devfileApi.DevfileLike, - data, - location, - defaultComponents, - namespace, - factoryParams, - ); - } else { - const devfileV1 = normalizeDevfileV1( - data.devfile as che.api.workspace.devfile.Devfile, - preferredStorageType, - ); - devfileV2 = normalizeDevfileV2( - await convertDevfileV1toDevfileV2(devfileV1), - data, - location, - defaultComponents, - namespace, - factoryParams, - ); - } - const converted: ConvertedState = { - resolvedDevfile: data.devfile, - isConverted: !isResolvedDevfileV2, - devfileV2, - }; - - const resolver = { - ...data, - devfile: devfileV2, - location, - optionalFilesContent, - }; - - dispatch({ - type: 'RECEIVE_FACTORY_RESOLVER', - resolver, - converted, - }); - return; - } catch (e) { - if (common.helpers.errors.includesAxiosResponse(e)) { - const response = e.response; - if (response.status === 401 && isOAuthResponse(response.data)) { - throw response.data; - } - } - const errorMessage = common.helpers.errors.getMessage(e); - dispatch({ - type: 'RECEIVE_FACTORY_RESOLVER_ERROR', - error: errorMessage, - }); - throw errorMessage; - } - }, -}; - -const unloadedState: State = { - isLoading: false, -}; - -export const reducer: Reducer = ( - state: State | undefined, - incomingAction: Action, -): State => { - if (state === undefined) { - return unloadedState; - } - - const action = incomingAction as KnownAction; - switch (action.type) { - case 'REQUEST_FACTORY_RESOLVER': - return createObject(state, { - isLoading: true, - error: undefined, - }); - case 'RECEIVE_FACTORY_RESOLVER': - return createObject(state, { - isLoading: false, - resolver: action.resolver, - converted: action.converted, - }); - case 'RECEIVE_FACTORY_RESOLVER_ERROR': - return createObject(state, { - isLoading: false, - error: action.error, - }); - default: - return state; - } -}; +export { actionCreators as factoryResolverActionCreators } from '@/store/FactoryResolver/actions'; +export { reducer as factoryResolverReducer } from '@/store/FactoryResolver/reducer'; +export * from '@/store/FactoryResolver/selectors'; +export { + ActionCreators as FactoryResolverActionCreators, + State as FactoryResolverState, + Resolver as FactoryResolverStateResolver, + OAuthResponse, +} from '@/store/FactoryResolver/types'; diff --git a/packages/dashboard-frontend/src/store/FactoryResolver/normalizeDevfileV1.ts b/packages/dashboard-frontend/src/store/FactoryResolver/normalizeDevfileV1.ts deleted file mode 100644 index 2166d34b3..000000000 --- a/packages/dashboard-frontend/src/store/FactoryResolver/normalizeDevfileV1.ts +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2018-2024 Red Hat, Inc. - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Red Hat, Inc. - initial API and implementation - */ - -import { cloneDeep } from 'lodash'; - -import { DevfileAdapter } from '@/services/devfile/adapter'; -import { che } from '@/services/models'; - -const MAX_LENGTH = 63; - -function getNormalizeValue(value: string): string { - value = value.toLowerCase(); - - if (value.length > MAX_LENGTH) { - return value.substring(0, MAX_LENGTH - 1); - } - - return value; -} - -export default function normalizeDevfileV1( - devfile: che.api.workspace.devfile.Devfile, - preferredStorageType: che.WorkspaceStorageType, -): che.api.workspace.devfile.Devfile { - const newDevfile = cloneDeep(devfile); - if (newDevfile.metadata?.generateName) { - newDevfile.metadata.generateName = getNormalizeValue(newDevfile.metadata.generateName); - } - if (newDevfile.metadata?.name) { - newDevfile.metadata.name = getNormalizeValue(newDevfile.metadata.name); - } - if (newDevfile.projects?.length) { - newDevfile.projects.forEach(project => { - if (project.name) { - project.name = getNormalizeValue(project.name); - } - }); - } - const devfileAdapter = new DevfileAdapter(newDevfile); - devfileAdapter.storageType = preferredStorageType; - - return devfileAdapter.devfile as che.api.workspace.devfile.Devfile; -} diff --git a/packages/dashboard-frontend/src/store/FactoryResolver/normalizeDevfileV2.ts b/packages/dashboard-frontend/src/store/FactoryResolver/normalizeDevfileV2.ts deleted file mode 100644 index 984ebec51..000000000 --- a/packages/dashboard-frontend/src/store/FactoryResolver/normalizeDevfileV2.ts +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (c) 2018-2024 Red Hat, Inc. - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Red Hat, Inc. - initial API and implementation - */ - -import { V222DevfileComponents } from '@devfile/api'; -import { dump } from 'js-yaml'; -import { cloneDeep } from 'lodash'; - -import { DevfileAdapter } from '@/services/devfile/adapter'; -import devfileApi from '@/services/devfileApi'; -import { FactoryParams } from '@/services/helpers/factoryFlow/buildFactoryParams'; -import { generateWorkspaceName } from '@/services/helpers/generateName'; -import { getProjectName } from '@/services/helpers/getProjectName'; -import { DevfileV2ProjectSource, FactoryResolver } from '@/services/helpers/types'; -import { - DEVWORKSPACE_DEVFILE_SOURCE, - DEVWORKSPACE_METADATA_ANNOTATION, -} from '@/services/workspace-client/devworkspace/devWorkspaceClient'; - -/** - * Returns a devfile from the FactoryResolver object. - * @param devfileLike a Devfile. - * @param data a FactoryResolver object. - * @param location a source location. - * @param defaultComponents Default components. These default components - * are meant to be used when a Devfile does not contain any components. - * @param namespace the namespace where the pod lives. - * @param factoryParams a Partial object. - */ -export default function normalizeDevfileV2( - devfileLike: devfileApi.DevfileLike, - data: FactoryResolver, - location: string, - defaultComponents: V222DevfileComponents[], - namespace: string, - factoryParams: Partial, -): devfileApi.Devfile { - const scmInfo = data['scm_info']; - - const projectName = getProjectName(scmInfo?.clone_url || location); - if (!devfileLike.metadata) { - devfileLike.metadata = {}; - } - const prefix = devfileLike.metadata.generateName - ? devfileLike.metadata.generateName - : projectName; - const name = devfileLike.metadata.name || generateWorkspaceName(prefix); - - // set mandatory fields - const devfile = cloneDeep(devfileLike) as devfileApi.Devfile; - devfile.metadata.name = name; - if (devfile.metadata.generateName) { - delete devfile.metadata.generateName; - } - devfile.metadata.namespace = namespace; - - // propagate default components - if (!devfile.parent && (!devfile.components || devfile.components.length === 0)) { - devfile.components = cloneDeep(defaultComponents); - } - - if (devfile.components && devfile.components.length > 0) { - // apply the custom image from factory params - if (factoryParams.image && devfile.components[0].container?.image) { - devfile.components[0].container.image = factoryParams.image; - } - - // temporary solution for fix che-server serialization bug with empty volume - devfile.components.forEach(component => { - if (Object.keys(component).length === 1 && component.name) { - component.volume = {}; - } - }); - } - - // add a default project - const projects: DevfileV2ProjectSource[] = []; - if (!devfile.projects?.length && scmInfo) { - const origin = scmInfo.clone_url; - const projectName = getProjectName(origin); - const revision = scmInfo.branch; - const project: DevfileV2ProjectSource = { name: projectName, git: { remotes: { origin } } }; - if (revision) { - project.git.checkoutFrom = { revision }; - } - projects.push(project); - devfile.projects = projects; - } - - // provide metadata about the origin of the devfile with DevWorkspace - let devfileSource = ''; - if (data.source && scmInfo) { - if (scmInfo.branch) { - devfileSource = dump({ - scm: { - repo: scmInfo['clone_url'], - revision: scmInfo.branch, - fileName: data.source, - }, - }); - } else { - devfileSource = dump({ - scm: { - repo: scmInfo['clone_url'], - fileName: data.source, - }, - }); - } - } else if (location) { - devfileSource = dump({ url: { location } }); - } - - const attributes = DevfileAdapter.getAttributesFromDevfileV2(devfile); - - if (!attributes[DEVWORKSPACE_METADATA_ANNOTATION]) { - attributes[DEVWORKSPACE_METADATA_ANNOTATION] = {}; - } - attributes[DEVWORKSPACE_METADATA_ANNOTATION][DEVWORKSPACE_DEVFILE_SOURCE] = devfileSource; - - return devfile; -} diff --git a/packages/dashboard-frontend/src/store/FactoryResolver/reducer.ts b/packages/dashboard-frontend/src/store/FactoryResolver/reducer.ts new file mode 100644 index 000000000..3e52c0d4c --- /dev/null +++ b/packages/dashboard-frontend/src/store/FactoryResolver/reducer.ts @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2018-2024 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ + +import { Action, Reducer } from 'redux'; + +import { KnownAction, State } from '@/store/FactoryResolver/types'; +import { createObject } from '@/store/helpers'; + +const unloadedState: State = { + isLoading: false, +}; + +export const reducer: Reducer = ( + state: State | undefined, + incomingAction: Action, +): State => { + if (state === undefined) { + return unloadedState; + } + + const action = incomingAction as KnownAction; + switch (action.type) { + case 'REQUEST_FACTORY_RESOLVER': + return createObject(state, { + isLoading: true, + error: undefined, + }); + case 'RECEIVE_FACTORY_RESOLVER': + return createObject(state, { + isLoading: false, + resolver: action.resolver, + }); + case 'RECEIVE_FACTORY_RESOLVER_ERROR': + return createObject(state, { + isLoading: false, + error: action.error, + }); + default: + return state; + } +}; diff --git a/packages/dashboard-frontend/src/store/FactoryResolver/selectors.ts b/packages/dashboard-frontend/src/store/FactoryResolver/selectors.ts index 3bd46574b..3b590936c 100644 --- a/packages/dashboard-frontend/src/store/FactoryResolver/selectors.ts +++ b/packages/dashboard-frontend/src/store/FactoryResolver/selectors.ts @@ -18,6 +18,4 @@ const selectState = (state: AppState) => state.factoryResolver; export const selectFactoryResolver = createSelector(selectState, state => state.resolver); -export const selectFactoryResolverConverted = createSelector(selectState, state => state.converted); - export const selectFactoryResolverError = createSelector(selectState, state => state.error); diff --git a/packages/dashboard-frontend/src/store/FactoryResolver/types.ts b/packages/dashboard-frontend/src/store/FactoryResolver/types.ts new file mode 100644 index 000000000..dbc62f0a2 --- /dev/null +++ b/packages/dashboard-frontend/src/store/FactoryResolver/types.ts @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2018-2024 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ + +import { Action } from 'redux'; + +import devfileApi from '@/services/devfileApi'; +import { FactoryParams } from '@/services/helpers/factoryFlow/buildFactoryParams'; +import { FactoryResolver } from '@/services/helpers/types'; +import { AppThunk } from '@/store'; +import { SanityCheckAction } from '@/store/sanityCheckMiddleware'; + +export interface Resolver extends FactoryResolver { + devfile: devfileApi.Devfile; + optionalFilesContent?: { + [fileName: string]: string; + }; +} + +export interface State { + isLoading: boolean; + resolver?: Resolver; + error?: string; +} + +export type OAuthResponse = { + attributes: { + oauth_provider: string; + oauth_version: string; + oauth_authentication_url: string; + }; + errorCode: number; + message: string | undefined; +}; + +export enum Type { + REQUEST_FACTORY_RESOLVER = 'REQUEST_FACTORY_RESOLVER', + RECEIVE_FACTORY_RESOLVER = 'RECEIVE_FACTORY_RESOLVER', + RECEIVE_FACTORY_RESOLVER_ERROR = 'RECEIVE_FACTORY_RESOLVER_ERROR', +} + +interface RequestFactoryResolverAction extends Action, SanityCheckAction { + type: Type.REQUEST_FACTORY_RESOLVER; +} +interface ReceiveFactoryResolverAction { + type: Type.RECEIVE_FACTORY_RESOLVER; + resolver: Resolver; +} +interface ReceiveFactoryResolverErrorAction { + type: Type.RECEIVE_FACTORY_RESOLVER_ERROR; + error: string | undefined; +} + +export type KnownAction = + | RequestFactoryResolverAction + | ReceiveFactoryResolverAction + | ReceiveFactoryResolverErrorAction; + +export type ActionCreators = { + requestFactoryResolver: ( + location: string, + factoryParams: Partial, + ) => AppThunk>; +}; diff --git a/packages/dashboard-frontend/src/store/Workspaces/devWorkspaces/index.ts b/packages/dashboard-frontend/src/store/Workspaces/devWorkspaces/index.ts index dd148c746..c42b43e8a 100644 --- a/packages/dashboard-frontend/src/store/Workspaces/devWorkspaces/index.ts +++ b/packages/dashboard-frontend/src/store/Workspaces/devWorkspaces/index.ts @@ -33,7 +33,7 @@ import { DisposableCollection } from '@/services/helpers/disposable'; import { FactoryParams } from '@/services/helpers/factoryFlow/buildFactoryParams'; import { getNewerResourceVersion } from '@/services/helpers/resourceVersion'; import { DevWorkspaceStatus } from '@/services/helpers/types'; -import OAuthService, { isOAuthResponse } from '@/services/oauth'; +import { isOAuthResponse, OAuthService } from '@/services/oauth'; import { loadResourcesContent } from '@/services/registry/resources'; import { WorkspaceAdapter } from '@/services/workspace-adapter'; import { diff --git a/packages/dashboard-frontend/src/store/__mocks__/devfile.ts b/packages/dashboard-frontend/src/store/__mocks__/devfile.ts deleted file mode 100644 index 6a114a5e2..000000000 --- a/packages/dashboard-frontend/src/store/__mocks__/devfile.ts +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2018-2024 Red Hat, Inc. - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Red Hat, Inc. - initial API and implementation - */ - -import { che } from '@/services/models'; - -export class DevfileBuilder { - private devfile: che.api.workspace.devfile.Devfile = { - apiVersion: '1.0.0', - metadata: { - generateName: 'stub-devfile-', - }, - } as che.api.workspace.devfile.Devfile; - - public withName(name: string): DevfileBuilder { - this.devfile.metadata!.name = name; - delete this.devfile.metadata!.generateName; - return this; - } - - public withComponents(components: Array): DevfileBuilder { - this.devfile.components = Object.assign([], components); - return this; - } - - public withProjects(projects: Array): DevfileBuilder { - this.devfile.projects = Object.assign([], projects); - return this; - } - - public withCommands(commands: Array): DevfileBuilder { - this.devfile.commands = Object.assign([], commands); - return this; - } - - public withAttributes(attributes: che.WorkspaceDevfileAttributes): DevfileBuilder { - this.devfile.attributes = Object.assign({}, attributes); - return this; - } - - public build(): che.api.workspace.devfile.Devfile { - return this.devfile; - } -} diff --git a/packages/dashboard-frontend/src/store/__mocks__/factoryResolverBuilder.ts b/packages/dashboard-frontend/src/store/__mocks__/factoryResolverBuilder.ts deleted file mode 100644 index b0d614f48..000000000 --- a/packages/dashboard-frontend/src/store/__mocks__/factoryResolverBuilder.ts +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2018-2024 Red Hat, Inc. - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Red Hat, Inc. - initial API and implementation - */ - -import { FactoryResolver, FactoryResolverScmInfo } from '@/services/helpers/types'; -import { che } from '@/services/models'; - -export class FactoryResolverBuilder { - private factoryResolver = { - v: '4.0', - } as FactoryResolver; - - withDevfile(devfile: che.api.workspace.devfile.Devfile): FactoryResolverBuilder { - this.factoryResolver.devfile = devfile; - return this; - } - - withSource(source: string): FactoryResolverBuilder { - this.factoryResolver.source = source; - return this; - } - - withScmInfo(scmInfo: FactoryResolverScmInfo): FactoryResolverBuilder { - this.factoryResolver['scm_info'] = scmInfo; - return this; - } - - build(): FactoryResolver { - return this.factoryResolver; - } -} diff --git a/packages/dashboard-frontend/src/store/__mocks__/storeBuilder.ts b/packages/dashboard-frontend/src/store/__mocks__/storeBuilder.ts index f36c8e294..30cc11829 100644 --- a/packages/dashboard-frontend/src/store/__mocks__/storeBuilder.ts +++ b/packages/dashboard-frontend/src/store/__mocks__/storeBuilder.ts @@ -23,11 +23,7 @@ import mockThunk from '@/store/__mocks__/thunk'; import { State as BrandingState } from '@/store/Branding'; import { DevWorkspaceResources, State as DevfileRegistriesState } from '@/store/DevfileRegistries'; import { RegistryEntry } from '@/store/DockerConfig/types'; -import { - ConvertedState, - ResolverState, - State as FactoryResolverState, -} from '@/store/FactoryResolver'; +import { FactoryResolverState, FactoryResolverStateResolver } from '@/store/FactoryResolver'; import { IGitOauth } from '@/store/GitOauthConfig/types'; import { State as InfrastructureNamespaceState } from '@/store/InfrastructureNamespaces'; import { State as PluginsState } from '@/store/Plugins/chePlugins'; @@ -262,21 +258,18 @@ export class FakeStoreBuilder { public withFactoryResolver( options: { - resolver?: Partial; - converted?: Partial; + resolver?: Partial; }, isLoading = false, ): FakeStoreBuilder { if (options.resolver) { - this.state.factoryResolver.resolver = Object.assign({}, options.resolver as ResolverState); + this.state.factoryResolver.resolver = Object.assign( + {}, + options.resolver as FactoryResolverStateResolver, + ); } else { delete this.state.factoryResolver.resolver; } - if (options.converted) { - this.state.factoryResolver.converted = Object.assign({}, options.converted as ConvertedState); - } else { - delete this.state.factoryResolver.converted; - } this.state.factoryResolver.isLoading = isLoading; return this; } diff --git a/packages/dashboard-frontend/src/store/index.ts b/packages/dashboard-frontend/src/store/index.ts index 180a3b099..bd293c17e 100644 --- a/packages/dashboard-frontend/src/store/index.ts +++ b/packages/dashboard-frontend/src/store/index.ts @@ -20,7 +20,7 @@ import * as ClusterInfo from '@/store/ClusterInfo'; import * as DevfileRegistriesStore from '@/store/DevfileRegistries'; import * as DockerConfigStore from '@/store/DockerConfig'; import * as EventsStore from '@/store/Events'; -import * as FactoryResolverStore from '@/store/FactoryResolver'; +import { factoryResolverReducer, FactoryResolverState } from '@/store/FactoryResolver'; import * as GitConfigStore from '@/store/GitConfig'; import * as GitOauthConfigStore from '@/store/GitOauthConfig'; import * as InfrastructureNamespacesStore from '@/store/InfrastructureNamespaces'; @@ -49,7 +49,7 @@ export interface AppState { dwPlugins: DwPluginsStore.State; dwServerConfig: DwServerConfigStore.State; events: EventsStore.State; - factoryResolver: FactoryResolverStore.State; + factoryResolver: FactoryResolverState; gitConfig: GitConfigStore.State; gitOauthConfig: GitOauthConfigStore.State; infrastructureNamespaces: InfrastructureNamespacesStore.State; @@ -75,7 +75,7 @@ export const reducers = { dwPlugins: DwPluginsStore.reducer, dwServerConfig: DwServerConfigStore.reducer, events: EventsStore.reducer, - factoryResolver: FactoryResolverStore.reducer, + factoryResolver: factoryResolverReducer, gitConfig: GitConfigStore.reducer, gitOauthConfig: GitOauthConfigStore.reducer, infrastructureNamespaces: InfrastructureNamespacesStore.reducer, diff --git a/yarn.lock b/yarn.lock index c79888525..b6022c60f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -342,17 +342,6 @@ resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-3.0.0.tgz#798622546b63847e82389e473fd67f2707d82247" integrity sha512-hBI9tfBtuPIi885ZsZ32IMEU/5nlZH/KOVYJCOh7gyMxaVLGmLedYqFN6Ui1LXkI8JlC8IsuC0rF0btcRZKd5g== -"@devfile/api@2.2.0-alpha-1637255314": - version "2.2.0-alpha-1637255314" - resolved "https://registry.yarnpkg.com/@devfile/api/-/api-2.2.0-alpha-1637255314.tgz#f2c628a61f18aecef3c0bcdc01e88faf4c4b287c" - integrity sha512-wlSk0iKbWXO6JAl5GIy6dpy91OoE/aHohzqUPXXbWaOsvWgjvQrWF8jcZl9UUnRKkhReMlaQOydMj6vkBu2Dyw== - dependencies: - "@types/bluebird" "3.5.21" - "@types/request" "*" - bluebird "^3.5.0" - request "^2.81.0" - rewire "^3.0.2" - "@devfile/api@2.2.2-1700686170": version "2.2.2-1700686170" resolved "https://registry.yarnpkg.com/@devfile/api/-/api-2.2.2-1700686170.tgz#faf3627f1f9d5df60705813add60b349eb3166bb" @@ -370,11 +359,6 @@ resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== -"@eclipse-che/api@^7.39.2": - version "7.76.0" - resolved "https://registry.yarnpkg.com/@eclipse-che/api/-/api-7.76.0.tgz#4e51015b566df5a9843d32d4de040875da78e368" - integrity sha512-V7egXY0x5Ce9DJGLrjXEeBkA/0854C9oz+KhxzCT/mXYbVVj4+YbNFjiuufNRnuGOBOOVCOLhhe69ebODjCiQQ== - "@eclipse-che/api@^7.80.0": version "7.80.0" resolved "https://registry.yarnpkg.com/@eclipse-che/api/-/api-7.80.0.tgz#3e62755ebe6598391fd0b77436ef0092fd9e7e20" @@ -394,18 +378,6 @@ jsonschema "^1.4.1" reflect-metadata "^0.1.13" -"@eclipse-che/devfile-converter@0.0.1-0751ad2": - version "0.0.1-0751ad2" - resolved "https://registry.yarnpkg.com/@eclipse-che/devfile-converter/-/devfile-converter-0.0.1-0751ad2.tgz#729fe29b2c952a84f1d79970953370e7b9c79f4d" - integrity sha512-zMLXc/o9QnXcuAs1x4OD9n1pX4yCz7ZQvQ4DcfWyKYn5e5dtxipAwHNOE8ClqM3us4/8Be0HhDrwE91yUDU5ig== - dependencies: - "@devfile/api" "2.2.0-alpha-1637255314" - "@eclipse-che/api" "^7.39.2" - inversify "^6.0.0" - js-yaml "^4.0.0" - jsonc-parser "^3.0.0" - reflect-metadata "^0.1.13" - "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" @@ -1694,11 +1666,6 @@ dependencies: "@babel/types" "^7.20.7" -"@types/bluebird@3.5.21": - version "3.5.21" - resolved "https://registry.yarnpkg.com/@types/bluebird/-/bluebird-3.5.21.tgz#567615589cc913e84a28ecf9edb031732bdf2634" - integrity sha512-6UNEwyw+6SGMC/WMI0ld0PS4st7Qq51qgguFrFizOSpGvZiqe9iswztFSdZvwJBEhLOy2JaxNE6VC7yMAlbfyQ== - "@types/caseless@*": version "0.12.4" resolved "https://registry.yarnpkg.com/@types/caseless/-/caseless-0.12.4.tgz#1326429a519cc077028150343fd502b04686bd6f" @@ -1908,7 +1875,7 @@ dependencies: redux "^4.0.5" -"@types/request@*", "@types/request@^2.47.1": +"@types/request@^2.47.1": version "2.48.11" resolved "https://registry.yarnpkg.com/@types/request/-/request-2.48.11.tgz#04b597ea308418422f7901c9a52b24967a2c4ed2" integrity sha512-HuihY1+Vss5RS9ZHzRyTGIzwPTdrJBkCm/mAeLRYrOQu/MGqyezKXWOK1VhCnR+SDbp9G2mRUP+OVEqCrzpcfA== @@ -2394,11 +2361,6 @@ ansi-escapes@^4.2.1: dependencies: type-fest "^0.21.3" -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - integrity sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA== - ansi-regex@^5.0.0, ansi-regex@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" @@ -2409,11 +2371,6 @@ ansi-regex@^6.0.1: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== -ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - integrity sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA== - ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" @@ -2708,62 +2665,6 @@ axios@^1.6.0: form-data "^4.0.0" proxy-from-env "^1.1.0" -babel-code-frame@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" - integrity sha512-XqYMR2dfdGMW+hd0IUZ2PwK+fGeFkOxZJ0wY+JaQAHzt1Zx8LcvpiZD2NiGkEG8qx0CfkAOr5xt76d1e8vG90g== - dependencies: - chalk "^1.1.3" - esutils "^2.0.2" - js-tokens "^3.0.2" - -babel-core@^6.26.0: - version "6.26.3" - resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.3.tgz#b2e2f09e342d0f0c88e2f02e067794125e75c207" - integrity sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA== - dependencies: - babel-code-frame "^6.26.0" - babel-generator "^6.26.0" - babel-helpers "^6.24.1" - babel-messages "^6.23.0" - babel-register "^6.26.0" - babel-runtime "^6.26.0" - babel-template "^6.26.0" - babel-traverse "^6.26.0" - babel-types "^6.26.0" - babylon "^6.18.0" - convert-source-map "^1.5.1" - debug "^2.6.9" - json5 "^0.5.1" - lodash "^4.17.4" - minimatch "^3.0.4" - path-is-absolute "^1.0.1" - private "^0.1.8" - slash "^1.0.0" - source-map "^0.5.7" - -babel-generator@^6.26.0: - version "6.26.1" - resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" - integrity sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA== - dependencies: - babel-messages "^6.23.0" - babel-runtime "^6.26.0" - babel-types "^6.26.0" - detect-indent "^4.0.0" - jsesc "^1.3.0" - lodash "^4.17.4" - source-map "^0.5.7" - trim-right "^1.0.1" - -babel-helpers@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" - integrity sha512-n7pFrqQm44TCYvrCDb0MqabAF+JUBq+ijBvNMUxpkLjJaAu32faIexewMumrH5KLLJ1HDyT0PTEqRyAe/GwwuQ== - dependencies: - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-jest@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5" @@ -2777,13 +2678,6 @@ babel-jest@^29.7.0: graceful-fs "^4.2.9" slash "^3.0.0" -babel-messages@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" - integrity sha512-Bl3ZiA+LjqaMtNYopA9TYE9HP1tQ+E5dLxE0XrAzcIJeK2UqF0/EaqXwBn9esd4UmTfEab+P+UYQ1GnioFIb/w== - dependencies: - babel-runtime "^6.22.0" - babel-plugin-istanbul@^6.1.1: version "6.1.1" resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" @@ -2805,17 +2699,6 @@ babel-plugin-jest-hoist@^29.6.3: "@types/babel__core" "^7.1.14" "@types/babel__traverse" "^7.0.6" -babel-plugin-transform-es2015-block-scoping@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f" - integrity sha512-YiN6sFAQ5lML8JjCmr7uerS5Yc/EMbgg9G8ZNmk2E3nYX4ckHR01wrkeeMijEf5WHNK5TW0Sl0Uu3pv3EdOJWw== - dependencies: - babel-runtime "^6.26.0" - babel-template "^6.26.0" - babel-traverse "^6.26.0" - babel-types "^6.26.0" - lodash "^4.17.4" - babel-preset-current-node-syntax@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" @@ -2842,68 +2725,6 @@ babel-preset-jest@^29.6.3: babel-plugin-jest-hoist "^29.6.3" babel-preset-current-node-syntax "^1.0.0" -babel-register@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" - integrity sha512-veliHlHX06wjaeY8xNITbveXSiI+ASFnOqvne/LaIJIqOWi2Ogmj91KOugEz/hoh/fwMhXNBJPCv8Xaz5CyM4A== - dependencies: - babel-core "^6.26.0" - babel-runtime "^6.26.0" - core-js "^2.5.0" - home-or-tmp "^2.0.0" - lodash "^4.17.4" - mkdirp "^0.5.1" - source-map-support "^0.4.15" - -babel-runtime@^6.22.0, babel-runtime@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" - integrity sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g== - dependencies: - core-js "^2.4.0" - regenerator-runtime "^0.11.0" - -babel-template@^6.24.1, babel-template@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" - integrity sha512-PCOcLFW7/eazGUKIoqH97sO9A2UYMahsn/yRQ7uOk37iutwjq7ODtcTNF+iFDSHNfkctqsLRjLP7URnOx0T1fg== - dependencies: - babel-runtime "^6.26.0" - babel-traverse "^6.26.0" - babel-types "^6.26.0" - babylon "^6.18.0" - lodash "^4.17.4" - -babel-traverse@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" - integrity sha512-iSxeXx7apsjCHe9c7n8VtRXGzI2Bk1rBSOJgCCjfyXb6v1aCqE1KSEpq/8SXuVN8Ka/Rh1WDTF0MDzkvTA4MIA== - dependencies: - babel-code-frame "^6.26.0" - babel-messages "^6.23.0" - babel-runtime "^6.26.0" - babel-types "^6.26.0" - babylon "^6.18.0" - debug "^2.6.8" - globals "^9.18.0" - invariant "^2.2.2" - lodash "^4.17.4" - -babel-types@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" - integrity sha512-zhe3V/26rCWsEZK8kZN+HaQj5yQ1CilTObixFzKW1UWjqG7618Twz6YEsCnjfg5gBcJh02DrpCkS9h98ZqDY+g== - dependencies: - babel-runtime "^6.26.0" - esutils "^2.0.2" - lodash "^4.17.4" - to-fast-properties "^1.0.3" - -babylon@^6.18.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" - integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ== - balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" @@ -2965,11 +2786,6 @@ bl@^4.0.3, bl@^4.1.0: inherits "^2.0.4" readable-stream "^3.4.0" -bluebird@^3.5.0: - version "3.7.2" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" - integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== - blueimp-md5@^2.18.0: version "2.19.0" resolved "https://registry.yarnpkg.com/blueimp-md5/-/blueimp-md5-2.19.0.tgz#b53feea5498dcb53dc6ec4b823adb84b729c4af0" @@ -3292,17 +3108,6 @@ chalk@4.1.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - integrity sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A== - dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" - chalk@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" @@ -3695,11 +3500,6 @@ conventional-recommended-bump@6.1.0: meow "^8.0.0" q "^1.5.1" -convert-source-map@^1.5.1: - version "1.9.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" - integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== - convert-source-map@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" @@ -3734,7 +3534,7 @@ core-js-pure@^3.30.2: resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.33.2.tgz#644830db2507ef84d068a70980ccd99c275f5fa6" integrity sha512-a8zeCdyVk7uF2elKIGz67AjcXOxjRbwOLz8SbklEso1V+2DoW4OkAMZN9S9GBgvZIaqQi/OemFX4OiSoQEmg1Q== -core-js@^2.4.0, core-js@^2.5.0: +core-js@^2.5.0: version "2.6.12" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== @@ -4056,13 +3856,6 @@ debug@4, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.3, d dependencies: ms "2.1.2" -debug@^2.6.8, debug@^2.6.9: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - debug@^3.2.7: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" @@ -4218,13 +4011,6 @@ detect-browser@^5.3.0: resolved "https://registry.yarnpkg.com/detect-browser/-/detect-browser-5.3.0.tgz#9705ef2bddf46072d0f7265a1fe300e36fe7ceca" integrity sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w== -detect-indent@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" - integrity sha512-BDKtmHlOzwI7iRuEkhzsnPoi5ypEhWAJB5RvHWe1kMr06js3uK5B3734i3ui5Yd+wOJV1cpE4JnivPD283GU/A== - dependencies: - repeating "^2.0.0" - detect-indent@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-5.0.0.tgz#3871cc0a6a002e8c3e5b3cf7f336264675f06b9d" @@ -4605,7 +4391,7 @@ escape-html@~1.0.3: resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== -escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: +escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== @@ -5573,11 +5359,6 @@ globals@^13.19.0: dependencies: type-fest "^0.20.2" -globals@^9.18.0: - version "9.18.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" - integrity sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ== - globalthis@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf" @@ -5704,13 +5485,6 @@ harmony-reflect@^1.4.6: resolved "https://registry.yarnpkg.com/harmony-reflect/-/harmony-reflect-1.6.2.tgz#31ecbd32e648a34d030d86adb67d4d47547fe710" integrity sha512-HIp/n38R9kQjDEziXyDTuW3vvoxxyxjxFzXLrBr18uB47GnSt+G9D29fqrpM5ZkspMcPICud3XsBJQ4Y2URg8g== -has-ansi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - integrity sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg== - dependencies: - ansi-regex "^2.0.0" - has-bigints@^1.0.1, has-bigints@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" @@ -5820,14 +5594,6 @@ hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0, hoist-non-react- dependencies: react-is "^16.7.0" -home-or-tmp@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" - integrity sha512-ycURW7oUxE2sNiPVw1HVEFsW+ecOpJ5zaj7eC0RlwhibhRBod20muUN8qu/gzx956YrLolVvs1MTXwKgC2rVEg== - dependencies: - os-homedir "^1.0.0" - os-tmpdir "^1.0.1" - hosted-git-info@^2.1.4: version "2.8.9" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" @@ -6174,13 +5940,6 @@ interpret@^3.1.1: resolved "https://registry.yarnpkg.com/interpret/-/interpret-3.1.1.tgz#5be0ceed67ca79c6c4bc5cf0d7ee843dcea110c4" integrity sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ== -invariant@^2.2.2: - version "2.2.4" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" - integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== - dependencies: - loose-envify "^1.0.0" - inversify-inject-decorators@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/inversify-inject-decorators/-/inversify-inject-decorators-3.1.0.tgz#d9941080bad77cec8a65ee29d905e4d5d73e1e95" @@ -6196,7 +5955,7 @@ inversify@^5.0.1: resolved "https://registry.yarnpkg.com/inversify/-/inversify-5.1.1.tgz#6fbd668c591337404e005a1946bfe0d802c08730" integrity sha512-j8grHGDzv1v+8T1sAQ+3boTCntFPfvxLCkNcxB1J8qA0lUN+fAlSyYd+RXKvaPRL4AGyPxViutBEJHNXOyUdFQ== -inversify@^6.0.0, inversify@^6.0.1: +inversify@^6.0.1: version "6.0.2" resolved "https://registry.yarnpkg.com/inversify/-/inversify-6.0.2.tgz#dc7fa0348213d789d35ffb719dea9685570989c7" integrity sha512-i9m8j/7YIv4mDuYXUAcrpKPSaju/CIly9AHK5jvCBeoiM/2KEsuCQTTP+rzSWWpLYWRukdXFSl6ZTk2/uumbiA== @@ -6307,11 +6066,6 @@ is-finalizationregistry@^1.0.2: dependencies: call-bind "^1.0.2" -is-finite@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.1.0.tgz#904135c77fb42c0641d6aa1bcdbc4daa8da082f3" - integrity sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w== - is-fullwidth-code-point@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" @@ -7052,11 +6806,6 @@ joycon@^3.1.1: resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== -js-tokens@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" - integrity sha512-RjTcuD4xjtthQkaWH7dFlH85L+QaVtSoOyGdZ3g6HFhS9dFNDfLyqgm2NFe2X6cQpeFmt0452FJjFG5UameExg== - js-yaml@4.1.0, js-yaml@^4.0.0, js-yaml@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" @@ -7109,11 +6858,6 @@ jsdom@^20.0.0: ws "^8.11.0" xml-name-validator "^4.0.0" -jsesc@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" - integrity sha512-Mke0DA0QjUWuJlhsE0ZPPhYiJkRap642SmI/4ztCFaUs6V2AiH1sfecc+57NgaryfAA2VR3v6O+CSjC1jZJKOA== - jsesc@^2.5.1: version "2.5.2" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" @@ -7185,11 +6929,6 @@ json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== -json5@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" - integrity sha512-4xrs1aW+6N5DalkqSVA8fxh458CXvR99WU8WLKmq4v8eWAL86Xo3BVqyd3SkA9wEVjCMqyvvRRkshAdOnBp5rw== - json5@^2.1.2, json5@^2.2.2, json5@^2.2.3: version "2.2.3" resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" @@ -7558,7 +7297,7 @@ lodash.uniqby@^4.7.0: resolved "https://registry.yarnpkg.com/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz#d99c07a669e9e6d24e1362dfe266c67616af1302" integrity sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww== -lodash@^4.0.0, lodash@^4.15.0, lodash@^4.17.11, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.4: +lodash@^4.0.0, lodash@^4.15.0, lodash@^4.17.11, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -8046,11 +7785,6 @@ mrmime@^1.0.0: resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-1.0.1.tgz#5f90c825fad4bdd41dc914eff5d1a8cfdaf24f27" integrity sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw== -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== - ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" @@ -8651,12 +8385,7 @@ ora@^5.4.1: strip-ansi "^6.0.0" wcwidth "^1.0.1" -os-homedir@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" - integrity sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ== - -os-tmpdir@^1.0.1, os-tmpdir@~1.0.2: +os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== @@ -8914,7 +8643,7 @@ path-exists@^4.0.0: resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== -path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: +path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== @@ -9395,11 +9124,6 @@ pretty-format@^29.0.0, pretty-format@^29.7.0: ansi-styles "^5.0.0" react-is "^18.0.0" -private@^0.1.8: - version "0.1.8" - resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" - integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg== - proc-log@^2.0.0, proc-log@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/proc-log/-/proc-log-2.0.1.tgz#8f3f69a1f608de27878f91f5c688b225391cb685" @@ -9967,11 +9691,6 @@ reflect.getprototypeof@^1.0.4: globalthis "^1.0.3" which-builtin-type "^1.1.3" -regenerator-runtime@^0.11.0: - version "0.11.1" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" - integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== - regenerator-runtime@^0.14.0: version "0.14.0" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz#5e19d68eb12d486f797e15a3c6a918f7cec5eb45" @@ -10002,14 +9721,7 @@ renderkid@^3.0.0: lodash "^4.17.21" strip-ansi "^6.0.1" -repeating@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" - integrity sha512-ZqtSMuVybkISo2OWvqvm7iHSWngvdaW3IpsT9/uP8v4gMi591LY6h35wdOfvQdWCKFWZWm2Y1Opp4kV7vQKT6A== - dependencies: - is-finite "^1.0.0" - -request@^2.81.0, request@^2.88.0: +request@^2.88.0: version "2.88.2" resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== @@ -10123,14 +9835,6 @@ reusify@^1.0.4: resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -rewire@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rewire/-/rewire-3.0.2.tgz#25e5413c4f1676eb3247d1884198b3a265408bbd" - integrity sha512-ejkkt3qYnsQ38ifc9llAAzuHiGM7kR8N5/mL3aHWgmWwet0OMFcmJB8aTsMV2PBHCWxNVTLCeRfBpEa8X2+1fw== - dependencies: - babel-core "^6.26.0" - babel-plugin-transform-es2015-block-scoping "^6.26.0" - rfc4648@^1.3.0: version "1.5.3" resolved "https://registry.yarnpkg.com/rfc4648/-/rfc4648-1.5.3.tgz#e62b81736c10361ca614efe618a566e93d0b41c0" @@ -10463,11 +10167,6 @@ slash@3.0.0, slash@^3.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== -slash@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" - integrity sha512-3TYDR7xWt4dIqV2JauJr+EJeW356RXijHeUlO+8djJ+uBXPn8/2dpzBc8yQhh583sVvc9CvFAeQVgijsH+PNNg== - slash@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-4.0.0.tgz#2422372176c4c6c5addb5e2ada885af984b396a7" @@ -10545,13 +10244,6 @@ source-map-support@0.5.13: buffer-from "^1.0.0" source-map "^0.6.0" -source-map-support@^0.4.15: - version "0.4.18" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" - integrity sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA== - dependencies: - source-map "^0.5.6" - source-map-support@~0.5.20: version "0.5.21" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" @@ -10560,11 +10252,6 @@ source-map-support@~0.5.20: buffer-from "^1.0.0" source-map "^0.6.0" -source-map@^0.5.6, source-map@^0.5.7: - version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== - source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" @@ -10784,13 +10471,6 @@ string_decoder@~1.1.1: dependencies: ansi-regex "^5.0.1" -strip-ansi@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - integrity sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg== - dependencies: - ansi-regex "^2.0.0" - strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" @@ -10955,11 +10635,6 @@ stylelint@^15.10.2: table "^6.8.1" write-file-atomic "^5.0.1" -supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - integrity sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g== - supports-color@^5.3.0, supports-color@^5.5.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" @@ -11226,11 +10901,6 @@ tmpl@1.0.5: resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== -to-fast-properties@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" - integrity sha512-lxrWP8ejsq+7E3nNjwYmUBMAgjMTZoTI+sdBOpvNyijeDLa29LUn9QaoXAHv4+Z578hbmHHJKZknzxVtvo77og== - to-fast-properties@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" @@ -11315,11 +10985,6 @@ trim-newlines@^4.0.2: resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-4.1.1.tgz#28c88deb50ed10c7ba6dc2474421904a00139125" integrity sha512-jRKj0n0jXWo6kh62nA5TEh3+4igKDXLvzBJcPpiizP7oOolUrYIxmVBG9TOtHYFHoddUk6YvAkGeGoSVTXfQXQ== -trim-right@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" - integrity sha512-WZGXGstmCWgeevgTL54hrCuw1dyMQIzWy7ZfqRJfSmJZBwklI15egmQytFP6bPidmw3M8d5yEowl1niq4vmqZw== - ts-api-utils@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.0.3.tgz#f12c1c781d04427313dbac808f453f050e54a331"