diff --git a/.deps/dev.md b/.deps/dev.md index 62124037a..a10aa6d5f 100644 --- a/.deps/dev.md +++ b/.deps/dev.md @@ -143,19 +143,19 @@ | [`@npmcli/package-json@2.0.0`](https://github.com/npm/package-json.git) | ISC | clearlydefined | | [`@npmcli/promise-spawn@3.0.0`](https://github.com/npm/promise-spawn.git) | ISC | clearlydefined | | [`@npmcli/run-script@3.0.3`](https://github.com/npm/run-script.git) | ISC | clearlydefined | -| [`@octokit/auth-token@2.5.0`](https://github.com/octokit/auth-token.js.git) | MIT | clearlydefined | -| [`@octokit/core@3.6.0`](https://github.com/octokit/core.js.git) | MIT | clearlydefined | -| [`@octokit/endpoint@6.0.12`](https://github.com/octokit/endpoint.js.git) | MIT | #891 | -| [`@octokit/graphql@4.8.0`](https://github.com/octokit/graphql.js.git) | MIT | clearlydefined | -| [`@octokit/openapi-types@11.2.0`](https://github.com/octokit/openapi-types.ts.git) | MIT | clearlydefined | +| [`@octokit/auth-token@2.5.0`](https://github.com/octokit/auth-token.js.git) | MIT | ecd.jkube | +| [`@octokit/core@3.6.0`](https://github.com/octokit/core.js.git) | MIT | ecd.jkube | +| [`@octokit/endpoint@6.0.12`](https://github.com/octokit/endpoint.js.git) | MIT | ecd.jkube | +| [`@octokit/graphql@4.8.0`](https://github.com/octokit/graphql.js.git) | MIT | ecd.jkube | +| [`@octokit/openapi-types@11.2.0`](https://github.com/octokit/openapi-types.ts.git) | MIT | ecd.jkube | | [`@octokit/plugin-enterprise-rest@6.0.1`](https://github.com/octokit/plugin-enterprise-rest.js.git) | MIT | clearlydefined | -| [`@octokit/plugin-paginate-rest@2.17.0`](https://github.com/octokit/plugin-paginate-rest.js.git) | MIT | #1552 | -| [`@octokit/plugin-request-log@1.0.4`](https://github.com/octokit/plugin-request-log.js.git) | MIT | #1837 | -| [`@octokit/plugin-rest-endpoint-methods@5.13.0`](https://github.com/octokit/plugin-rest-endpoint-methods.js.git) | MIT | #1556 | -| [`@octokit/request-error@2.1.0`](https://github.com/octokit/request-error.js.git) | MIT | clearlydefined | -| [`@octokit/request@5.6.3`](https://github.com/octokit/request.js.git) | MIT | clearlydefined | -| [`@octokit/rest@18.12.0`](https://github.com/octokit/rest.js.git) | MIT | clearlydefined | -| [`@octokit/types@6.34.0`](https://github.com/octokit/types.ts.git) | MIT | #1554 | +| [`@octokit/plugin-paginate-rest@2.17.0`](https://github.com/octokit/plugin-paginate-rest.js.git) | MIT | ecd.jkube | +| [`@octokit/plugin-request-log@1.0.4`](https://github.com/octokit/plugin-request-log.js.git) | MIT | ecd.jkube | +| [`@octokit/plugin-rest-endpoint-methods@5.13.0`](https://github.com/octokit/plugin-rest-endpoint-methods.js.git) | MIT | ecd.jkube | +| [`@octokit/request-error@2.1.0`](https://github.com/octokit/request-error.js.git) | MIT | ecd.jkube | +| [`@octokit/request@5.6.3`](https://github.com/octokit/request.js.git) | MIT | ecd.jkube | +| [`@octokit/rest@18.12.0`](https://github.com/octokit/rest.js.git) | MIT | ecd.jkube | +| [`@octokit/types@6.34.0`](https://github.com/octokit/types.ts.git) | MIT | ecd.jkube | | [`@react-mock/state@0.1.8`](https://github.com/skidding/react-mock) | MIT | clearlydefined | | [`@sinonjs/commons@1.8.3`](git+https://github.com/sinonjs/commons.git) | BSD-3-Clause | #4340 | | [`@sinonjs/fake-timers@6.0.1`](http://github.com/sinonjs/fake-timers.git) | BSD-3-Clause | #1348 | @@ -181,7 +181,7 @@ | [`@types/eslint@8.4.2`](https://github.com/DefinitelyTyped/DefinitelyTyped.git) | MIT | #2429 | | [`@types/estree@0.0.51`](https://github.com/DefinitelyTyped/DefinitelyTyped.git) | MIT | clearlydefined | | [`@types/express-serve-static-core@4.17.28`](https://github.com/DefinitelyTyped/DefinitelyTyped.git) | MIT | clearlydefined | -| [`@types/express@4.17.13`](https://github.com/DefinitelyTyped/DefinitelyTyped.git) | MIT | clearlydefined | +| [`@types/express@4.17.13`](https://github.com/DefinitelyTyped/DefinitelyTyped.git) | MIT | #5760 | | [`@types/fs-extra@9.0.13`](https://github.com/DefinitelyTyped/DefinitelyTyped.git) | MIT | clearlydefined | | [`@types/graceful-fs@4.1.5`](https://github.com/DefinitelyTyped/DefinitelyTyped.git) | MIT | clearlydefined | | [`@types/history@4.7.11`](https://github.com/DefinitelyTyped/DefinitelyTyped.git) | MIT | clearlydefined | @@ -396,7 +396,7 @@ | [`decamelize-keys@1.1.0`](https://github.com/dsblv/decamelize-keys.git) | MIT | #4601 | | [`decamelize@1.2.0`](https://github.com/sindresorhus/decamelize.git) | MIT | clearlydefined | | [`decimal.js@10.3.1`](https://github.com/MikeMcl/decimal.js.git) | MIT | clearlydefined | -| [`decode-uri-component@0.2.0`](https://github.com/SamVerschueren/decode-uri-component.git) | MIT | clearlydefined | +| [`decode-uri-component@0.2.0`](https://github.com/SamVerschueren/decode-uri-component.git) | MIT | #5322 | | [`dedent@0.7.0`](git://github.com/dmnd/dedent.git) | MIT | clearlydefined | | [`deep-is@0.1.4`](http://github.com/thlorenz/deep-is.git) | MIT | #2130 | | [`default-gateway@6.0.3`](https://github.com/silverwind/default-gateway.git) | BSD-2-Clause | [clearlydefined](https://clearlydefined.io/definitions/npm/npmjs/-/default-gateway/6.0.3) | @@ -469,7 +469,7 @@ | [`fast-levenshtein@2.0.6`](https://github.com/hiddentao/fast-levenshtein.git) | MIT | #2428 | | [`fastest-levenshtein@1.0.12`](git+https://github.com/ka-weihe/fastest-levenshtein.git) | MIT | clearlydefined | | [`faye-websocket@0.11.4`](git://github.com/faye/faye-websocket-node.git) | Apache-2.0 | clearlydefined | -| [`fb-watchman@2.0.1`](git@github.com:facebook/watchman.git) | Apache-2.0 | clearlydefined | +| [`fb-watchman@2.0.1`](git@github.com:facebook/watchman.git) | Apache-2.0 | #5379 | | [`figures@3.2.0`](https://github.com/sindresorhus/figures.git) | MIT | clearlydefined | | [`file-entry-cache@6.0.1`](https://github.com/royriojas/file-entry-cache.git) | MIT | clearlydefined | | [`file-loader@6.2.0`](https://github.com/webpack-contrib/file-loader.git) | MIT | clearlydefined | @@ -544,7 +544,7 @@ | [`identity-obj-proxy@3.0.0`](git+https://github.com/keyanzhang/identity-obj-proxy.git) | MIT | clearlydefined | | [`ignore-by-default@1.0.1`](git+https://github.com/novemberborn/ignore-by-default.git) | ISC | clearlydefined | | [`ignore-walk@3.0.4`](git+https://github.com/isaacs/ignore-walk.git) | ISC | clearlydefined | -| [`ignore@5.2.0`](git@github.com:kaelzhang/node-ignore.git) | MIT | clearlydefined | +| [`ignore@5.2.0`](git@github.com:kaelzhang/node-ignore.git) | MIT | #5907 | | [`import-fresh@3.3.0`](https://github.com/sindresorhus/import-fresh.git) | MIT | clearlydefined | | [`import-lazy@4.0.0`](https://github.com/sindresorhus/import-lazy.git) | MIT | clearlydefined | | [`import-local@3.1.0`](https://github.com/sindresorhus/import-local.git) | MIT | clearlydefined | @@ -684,7 +684,7 @@ | [`mixin-deep@1.3.2`](https://github.com/jonschlinkert/mixin-deep.git) | MIT | clearlydefined | | [`mkdirp-infer-owner@2.0.0`](git+https://github.com/isaacs/mkdirp-infer-owner) | ISC | clearlydefined | | [`modify-values@1.0.1`](https://github.com/sindresorhus/modify-values.git) | MIT | clearlydefined | -| [`ms@2.1.3`](https://github.com/vercel/ms.git) | MIT | clearlydefined | +| [`ms@2.1.3`](https://github.com/vercel/ms.git) | MIT | #5895 | | [`multicast-dns@7.2.5`](https://github.com/mafintosh/multicast-dns.git) | MIT | clearlydefined | | [`multimatch@5.0.0`](https://github.com/sindresorhus/multimatch.git) | MIT | clearlydefined | | [`mute-stream@0.0.8`](git://github.com/isaacs/mute-stream) | ISC | clearlydefined | @@ -835,7 +835,7 @@ | [`serialize-javascript@6.0.0`](git+https://github.com/yahoo/serialize-javascript.git) | BSD-3-Clause | clearlydefined | | [`serve-index@1.9.1`](https://github.com/expressjs/serve-index.git) | MIT | clearlydefined | | [`serve-static@1.15.0`](https://github.com/expressjs/serve-static.git) | MIT | clearlydefined | -| [`set-blocking@2.0.0`](git+https://github.com/yargs/set-blocking.git) | ISC | clearlydefined | +| [`set-blocking@2.0.0`](git+https://github.com/yargs/set-blocking.git) | ISC | #5899 | | [`set-value@2.0.1`](https://github.com/jonschlinkert/set-value.git) | MIT | clearlydefined | | [`shallow-clone@3.0.1`](https://github.com/jonschlinkert/shallow-clone.git) | MIT | clearlydefined | | [`shellwords@0.1.1`](git://github.com/jimmycuadra/shellwords.git) | MIT | clearlydefined | @@ -919,6 +919,7 @@ | [`type-detect@4.0.8`](git+ssh://git@github.com/chaijs/type-detect.git) | MIT | clearlydefined | | [`type-fest@0.18.1`](https://github.com/sindresorhus/type-fest.git) | (MIT OR CC0-1.0) | clearlydefined | | [`type-is@1.6.18`](https://github.com/jshttp/type-is.git) | MIT | clearlydefined | +| [`typedarray-to-buffer@3.1.5`](git://github.com/feross/typedarray-to-buffer.git) | MIT | clearlydefined | | [`typedarray@0.0.6`](git://github.com/substack/typedarray.git) | MIT | clearlydefined | | [`typescript@4.4.4`](https://github.com/Microsoft/TypeScript.git) | Apache-2.0 | #1524 | | [`uglify-js@3.15.3`](https://github.com/mishoo/UglifyJS.git) | BSD-2-Clause | #1958 | diff --git a/.deps/prod.md b/.deps/prod.md index ebd5c975a..af2182565 100644 --- a/.deps/prod.md +++ b/.deps/prod.md @@ -7,11 +7,11 @@ | `@eclipse-che/api@7.44.0` | EPL-2.0 | ecd.che | | [`@eclipse-che/che-code-devworkspace-handler@1.74.0-dev-e701cae`](git+https://github.com/che-incubator/che-code.git) | EPL-2.0 | ecd.che | | [`@eclipse-che/che-theia-devworkspace-handler@0.0.1-1667484092`](git+https://github.com/eclipse-che/che-theia.git) | EPL-2.0 | ecd.che | -| [`@eclipse-che/common@7.58.0-next`](https://github.com/eclipse-che/che-dashboard) | EPL-2.0 | ecd.che | -| [`@eclipse-che/dashboard-backend@7.58.0-next`](https://github.com/eclipse-che/che-dashboard) | EPL-2.0 | ecd.che | -| [`@eclipse-che/dashboard-frontend@7.58.0-next`](git://github.com/eclipse/che-dashboard.git) | EPL-2.0 | ecd.che | +| [`@eclipse-che/common@7.59.0-next`](https://github.com/eclipse-che/che-dashboard) | EPL-2.0 | ecd.che | +| [`@eclipse-che/dashboard-backend@7.59.0-next`](https://github.com/eclipse-che/che-dashboard) | EPL-2.0 | ecd.che | +| [`@eclipse-che/dashboard-frontend@7.59.0-next`](git://github.com/eclipse/che-dashboard.git) | EPL-2.0 | ecd.che | | [`@eclipse-che/devfile-converter@0.0.1-d624e3e`](git+https://github.com/che-incubator/devfile-converter.git) | EPL-2.0 | ecd.che | -| [`@eclipse-che/workspace-client@0.0.1-1663851810`](https://github.com/eclipse/che-workspace-client) | EPL-2.0 | ecd.che | +| [`@eclipse-che/workspace-client@0.0.1-1671793076`](https://github.com/eclipse/che-workspace-client) | EPL-2.0 | ecd.che | | [`@fastify/ajv-compiler@1.1.0`](git+https://github.com/fastify/ajv-compiler.git) | MIT | clearlydefined | | [`@fastify/cors@7.0.0`](git+https://github.com/fastify/fastify-cors.git) | MIT | clearlydefined | | [`@fastify/error@3.0.0`](git+https://github.com/fastify/fastify-error.git) | MIT | clearlydefined | @@ -64,7 +64,7 @@ | [`agent-base@4.3.0`](git://github.com/TooTallNate/node-agent-base.git) | MIT | clearlydefined | | [`aggregate-error@3.1.0`](https://github.com/sindresorhus/aggregate-error.git) | MIT | clearlydefined | | [`ajv@6.12.6`](https://github.com/ajv-validator/ajv.git) | MIT | #979 | -| [`ansi-regex@2.1.1`](https://github.com/chalk/ansi-regex.git) | MIT | clearlydefined | +| [`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) | @@ -131,7 +131,7 @@ | [`cookie@0.5.0`](https://github.com/jshttp/cookie.git) | MIT | clearlydefined | | [`copy-to-clipboard@3.3.1`](git+https://github.com/sudodoki/copy-to-clipboard) | MIT | clearlydefined | | [`core-js@2.6.12`](https://github.com/zloirock/core-js.git) | MIT | #2912 | -| [`core-util-is@1.0.2`](git://github.com/isaacs/core-util-is) | MIT | clearlydefined | +| [`core-util-is@1.0.2`](git://github.com/isaacs/core-util-is) | MIT | #5898 | | [`create-ecdh@4.0.4`](https://github.com/crypto-browserify/createECDH.git) | MIT | clearlydefined | | [`create-hash@1.2.0`](git@github.com:crypto-browserify/createHash.git) | MIT | clearlydefined | | [`create-hmac@1.1.7`](https://github.com/crypto-browserify/createHmac.git) | MIT | clearlydefined | @@ -284,7 +284,7 @@ | [`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 | -| [`minimist@1.2.6`](git://github.com/substack/minimist.git) | MIT | clearlydefined | +| [`minimist@1.2.6`](git://github.com/substack/minimist.git) | MIT | #5886 | | [`minipass@3.1.6`](git+https://github.com/isaacs/minipass.git) | ISC | clearlydefined | | [`minizlib@2.1.2`](git+https://github.com/isaacs/minizlib.git) | MIT | clearlydefined | | [`mkdirp@1.0.4`](https://github.com/isaacs/node-mkdirp.git) | MIT | clearlydefined | @@ -293,7 +293,6 @@ | [`monaco-languages@1.10.0`](https://github.com/Microsoft/monaco-languages) | MIT | clearlydefined | | [`mri@1.1.4`](https://github.com/lukeed/mri.git) | MIT | clearlydefined | | [`ms@2.0.0`](https://github.com/zeit/ms.git) | MIT | clearlydefined | -| [`nan@2.15.0`](git://github.com/nodejs/nan.git) | MIT | #986 | | [`nanoid@3.3.4`](https://github.com/ai/nanoid.git) | MIT | clearlydefined | | [`node-fetch@2.6.7`](https://github.com/bitinn/node-fetch.git) | MIT | clearlydefined | | [`normalize-url@6.1.0`](https://github.com/sindresorhus/normalize-url.git) | MIT | clearlydefined | @@ -399,7 +398,7 @@ | [`shebang-regex@3.0.0`](https://github.com/sindresorhus/shebang-regex.git) | MIT | clearlydefined | | [`shelljs@0.8.5`](git://github.com/shelljs/shelljs.git) | BSD-3-Clause | #1126 | | [`side-channel@1.0.4`](git+https://github.com/ljharb/side-channel.git) | MIT | clearlydefined | -| [`signal-exit@3.0.7`](https://github.com/tapjs/signal-exit.git) | ISC | clearlydefined | +| [`signal-exit@3.0.7`](https://github.com/tapjs/signal-exit.git) | ISC | #5892 | | [`simple-oauth2@3.4.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@1.4.1`](git+https://github.com/mcollina/sonic-boom.git) | MIT | clearlydefined | @@ -436,13 +435,12 @@ | [`tunnel@0.0.6`](https://github.com/koichik/node-tunnel.git) | MIT | clearlydefined | | [`tweetnacl@0.14.5`](https://github.com/dchest/tweetnacl-js.git) | Unlicense | #1035 | | [`type-fest@0.8.1`](https://github.com/sindresorhus/type-fest.git) | (MIT OR CC0-1.0) | clearlydefined | -| [`typedarray-to-buffer@3.1.5`](git://github.com/feross/typedarray-to-buffer.git) | MIT | clearlydefined | | [`umd-compat-loader@2.1.2`](http://github.com/matt-gadd/umd-compat-loader.git) | Apache-2.0 | clearlydefined | | [`underscore@1.13.2`](git://github.com/jashkenas/underscore.git) | MIT | clearlydefined | | [`undici@5.9.1`](git+https://github.com/nodejs/undici.git) | MIT | clearlydefined | | [`universalify@2.0.0`](git+https://github.com/RyanZim/universalify.git) | MIT | clearlydefined | | [`uri-js@4.4.1`](http://github.com/garycourt/uri-js) | BSD-2-Clause | #1086 | -| [`util-deprecate@1.0.2`](git://github.com/TooTallNate/util-deprecate.git) | MIT | clearlydefined | +| [`util-deprecate@1.0.2`](git://github.com/TooTallNate/util-deprecate.git) | MIT | #5885 | | [`uuid@3.4.0`](https://github.com/uuidjs/uuid.git) | MIT | #2733 | | [`value-equal@1.0.1`](https://github.com/mjackson/value-equal.git) | MIT | clearlydefined | | [`vary@1.1.2`](https://github.com/jshttp/vary.git) | MIT | clearlydefined | @@ -458,12 +456,10 @@ | [`vscode-uri@2.1.2`](git+https://github.com/Microsoft/vscode-uri.git) | MIT | clearlydefined | | [`warning@4.0.3`](https://github.com/BerkeleyTrue/warning.git) | MIT | [CQ22359](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=22359) | | [`webidl-conversions@3.0.1`](https://github.com/jsdom/webidl-conversions.git) | BSD-2-Clause | clearlydefined | -| [`websocket@1.0.23`](https://github.com/theturtle32/WebSocket-Node.git) | Apache-2.0 | [CQ22360](https://dev.eclipse.org/ipzilla/show_bug.cgi?id=22360) | | [`whatwg-url@5.0.0`](https://github.com/jsdom/whatwg-url.git) | MIT | clearlydefined | | [`which@2.0.2`](git://github.com/isaacs/node-which.git) | ISC | clearlydefined | | [`wrappy@1.0.2`](https://github.com/npm/wrappy) | ISC | clearlydefined | | [`ws@8.7.0`](https://github.com/websockets/ws.git) | MIT | clearlydefined | -| [`yaeti@0.0.4`](https://github.com/ibc/yaeti.git) | MIT | clearlydefined | | [`yallist@4.0.0`](git+https://github.com/isaacs/yallist.git) | ISC | clearlydefined | | [`yaml-language-server-parser@0.1.1`](https://github.com/redhat-developer/yaml-ast-parser.git) | Apache-2.0 | clearlydefined | | [`yaml-language-server@0.13.0`](https://github.com/redhat-developer/yaml-language-server.git) | MIT | clearlydefined | diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 91159e646..82081941d 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -128,4 +128,4 @@ jobs: script: | const { issue: { number: issue_number }, repo: { owner, repo } } = context; const dashboardImage = '${{ env.ORGANIZATION }}/che-dashboard:${{ env.IMAGE_VERSION }}'; - github.issues.createComment({ issue_number, owner, repo, body: 'Docker image build succeeded: **' + dashboardImage + '**' }); + github.rest.issues.createComment({ issue_number, owner, repo, body: 'Docker image build succeeded: **' + dashboardImage + '**' }); diff --git a/packages/dashboard-backend/src/devfileSchemas/1.0.0/devfile.json b/packages/dashboard-backend/src/devfileSchemas/1.0.0/devfile.json deleted file mode 100644 index e616ea565..000000000 --- a/packages/dashboard-backend/src/devfileSchemas/1.0.0/devfile.json +++ /dev/null @@ -1,871 +0,0 @@ -{ - "meta:license": [ - " Copyright (c) 2012-2019 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" - ], - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "title": "Devfile object", - "description": "This schema describes the structure of the devfile object", - "definitions": { - "attributes": { - "type": "object", - "additionalProperties": { - "type": "string" - } - }, - "selector": { - "type": "object", - "additionalProperties": { - "type": "string" - } - } - }, - "required": [ - "apiVersion", - "metadata" - ], - "additionalProperties": false, - "properties": { - "apiVersion": { - "const": "1.0.0", - "title": "Devfile API Version" - }, - "metadata": { - "type": "object", - "properties": { - "name": { - "type": "string", - "minLength": 1, - "title": "Devfile Name", - "description": "The name of the devfile. Workspaces created from devfile, will inherit this name", - "examples": [ - "petclinic-dev-environment" - ] - }, - "generateName": { - "type": "string", - "minLength": 1, - "title": "Devfile Generate Name", - "description": "Workspaces created from devfile, will use it as base and append random suffix. It's used when name is not defined.", - "examples": [ - "petclinic-" - ] - } - }, - "additionalProperties": false, - "anyOf": [ - { - "required": [ - "name" - ] - }, - { - "required": [ - "generateName" - ] - } - ] - }, - "projects": { - "type": "array", - "title": "The Projects List", - "description": "Description of the projects, containing names and sources locations", - "items": { - "type": "object", - "required": [ - "name", - "source" - ], - "additionalProperties": false, - "properties": { - "name": { - "type": "string", - "title": "The Project Name", - "examples": [ - "petclinic" - ] - }, - "source": { - "type": "object", - "title": "The Project Source object", - "description": "Describes the project's source - type and location", - "required": [ - "type", - "location" - ], - "properties": { - "type": { - "type": "string", - "description": "Project's source type.", - "examples": [ - "git", - "github", - "zip" - ] - }, - "location": { - "type": "string", - "description": "Project's source location address. Should be URL for git and github located projects, or file:// for zip.", - "examples": [ - "git@github.com:spring-projects/spring-petclinic.git" - ] - }, - "branch": { - "type": "string", - "description": "The name of the of the branch to check out after obtaining the source from the location. The branch has to already exist in the source otherwise the default branch is used. In case of git, this is also the name of the remote branch to push to.", - "examples": [ - "master", - "feature-42" - ] - }, - "startPoint": { - "type": "string", - "description": "The tag or commit id to reset the checked out branch to.", - "examples": [ - "release/4.2", - "349d3ad", - "v4.2.0" - ] - }, - "tag": { - "type": "string", - "description": "The name of the tag to reset the checked out branch to. Note that this is equivalent to 'startPoint' and provided for convenience.", - "examples": [ - "v4.2.0" - ] - }, - "commitId": { - "type": "string", - "description": "The id of the commit to reset the checked out branch to. Note that this is equivalent to 'startPoint' and provided for convenience.", - "examples": [ - "349d3ad" - ] - }, - "sparseCheckoutDir": { - "type": "string", - "description": "Part of project to populate in the working directory.", - "examples": [ - "/core/", - "core/", - "core", - "/wsmaster/che-core-api-workspace/", - "/d*" - ] - } - } - }, - "clonePath": { - "type": "string", - "description": "The path relative to the root of the projects to which this project should be cloned into. This is a unix-style relative path (i.e. uses forward slashes). The path is invalid if it is absolute or tries to escape the project root through the usage of '..'. If not specified, defaults to the project name." - } - } - } - }, - "components": { - "type": "array", - "title": "The Components List", - "description": "Description of the workspace components, such as editor and plugins", - "items": { - "type": "object", - "required": [ - "type" - ], - "if": { - "properties": { - "type": { - "type": "string" - } - }, - "required": [ - "type" - ] - }, - "then": { - "allOf": [ - { - "if": { - "properties": { - "type": { - "enum": [ - "cheEditor", - "chePlugin" - ] - } - } - }, - "then": { - "oneOf": [ - { - "required": [ - "id" - ], - "not": { - "required": [ - "reference" - ] - } - }, - { - "required": [ - "reference" - ], - "not": { - "required": [ - "id" - ] - } - } - ], - "properties": { - "type": {}, - "alias": {}, - "id": { - "type": "string", - "description": "Describes the component id. It has the following format: {plugin/editor PUBLISHER}/{plugin/editor NAME}/{plugin/editor VERSION}", - "pattern": "[a-z0-9_\\-.]+/[a-z0-9_\\-.]+/[a-z0-9_\\-.]+$", - "examples": [ - "eclipse/maven-jdk8/1.0.0" - ] - }, - "reference": { - "description": "Describes raw location of plugin yaml file.", - "type": "string", - "examples": [ - "https://pastebin.com/raw/kYprWiNB" - ] - }, - "registryUrl": { - "description": "Describes URL of custom plugin registry.", - "type": "string", - "pattern": "^(https?://)[a-zA-Z0-9_\\-./]+", - "examples": [ - "https://che-plugin-registry.openshift.io/v3/" - ] - } - } - } - }, - { - "if": { - "properties": { - "type": { - "enum": [ - "cheEditor" - ] - } - } - }, - "then": { - "additionalProperties": false, - "properties": { - "type": {}, - "alias": {}, - "id": {}, - "env": {}, - "endpoints": {}, - "volumes": {}, - "reference": {}, - "registryUrl": {}, - "memoryLimit": {}, - "memoryRequest": {}, - "automountWorkspaceSecrets": {}, - "cpuLimit": {}, - "cpuRequest": {} - } - } - }, - { - "if": { - "properties": { - "type": { - "enum": [ - "chePlugin" - ] - } - } - }, - "then": { - "additionalProperties": false, - "properties": { - "type": {}, - "alias": {}, - "id": {}, - "env": {}, - "endpoints": {}, - "volumes": {}, - "memoryLimit": {}, - "memoryRequest": {}, - "automountWorkspaceSecrets": {}, - "cpuLimit": {}, - "cpuRequest": {}, - "reference": {}, - "registryUrl": {}, - "preferences": { - "type": "object", - "description": "Additional plugin preferences", - "examples": [ - "{\"java.home\": \"/home/user/jdk11\", \"java.jdt.ls.vmargs\": \"-Xmx1G\"}" - ], - "additionalProperties": { - "anyOf": [ - { - "type": [ - "boolean", - "string", - "number" - ] - }, - { - "type": "array", - "items": { - "type": [ - "boolean", - "string", - "number" - ] - } - } - ] - } - } - } - } - }, - { - "if": { - "properties": { - "type": { - "enum": [ - "kubernetes", - "openshift" - ] - } - } - }, - "then": { - "anyOf": [ - { - "required": [ - "reference" - ], - "additionalProperties": true - }, - { - "required": [ - "referenceContent" - ], - "additionalProperties": true - } - ], - "additionalProperties": false, - "properties": { - "type": {}, - "alias": {}, - "mountSources": {}, - "automountWorkspaceSecrets": {}, - "volumes": {}, - "env": {}, - "endpoints": {}, - "reference": { - "description": "Describes absolute or devfile-relative location of Kubernetes list yaml file. Applicable only for 'kubernetes' and 'openshift' type components", - "type": "string", - "examples": [ - "petclinic-app.yaml" - ] - }, - "referenceContent": { - "description": "Inlined content of a file specified in field 'reference'", - "type": "string", - "examples": [ - "{\"kind\":\"List\",\"items\":[{\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"name\":\"ws\"},\"spec\":{\"containers\":[{\"image\":\"quay.io/eclipse/che-dev:nightly\"}]}}]}" - ] - }, - "selector": { - "$ref": "#/definitions/selector", - "description": "Describes the objects selector for the recipe type components. Allows to pick-up only selected items from k8s/openshift list", - "examples": [ - "{\n \"app.kubernetes.io/name\" : \"mysql\", \n \"app.kubernetes.io/component\" : \"database\", \n \"app.kubernetes.io/part-of\" : \"petclinic\" \n}" - ] - }, - "entrypoints": { - "type": "array", - "items": { - "type": "object", - "properties": { - "parentName": { - "type": "string", - "description": "The name of the top level object in the referenced object list in which to search for containers. If not specified, the objects to search through can have any name." - }, - "containerName": { - "type": "string", - "description": "The name of the container to apply the entrypoint to. If not specified, the entrypoint is modified on all matching containers." - }, - "parentSelector": { - "$ref": "#/definitions/selector", - "description": "The selector on labels of the top level objects in the referenced list in which to search for containers. If not specified, the objects to search through can have any labels." - }, - "command": { - "type": "array", - "items": { - "type": "string" - }, - "default": null, - "description": "The command to run in the component instead of the default one provided in the image of the container. Defaults to null, meaning use whatever is defined in the image.", - "examples": [ - "['/bin/sh', '-c']" - ] - }, - "args": { - "type": "array", - "items": { - "type": "string" - }, - "default": null, - "description": "The arguments to supply to the command running the component. The arguments are supplied either to the default command provided in the image of the container or to the overridden command. Defaults to null, meaning use whatever is defined in the image.", - "examples": [ - "['-R', '-f']" - ] - } - } - } - } - } - } - }, - { - "if": { - "properties": { - "type": { - "enum": [ - "dockerimage" - ] - } - } - }, - "then": { - "required": [ - "image", - "memoryLimit" - ], - "additionalProperties": false, - "properties": { - "type": {}, - "alias": {}, - "mountSources": {}, - "env": {}, - "cpuLimit": {}, - "cpuRequest": {}, - "automountWorkspaceSecrets": {}, - "volumes": {}, - "endpoints": {}, - "memoryLimit": {}, - "memoryRequest": {}, - "image": { - "type": "string", - "description": "Specifies the docker image that should be used for component", - "examples": [ - "eclipse/maven-jdk8:1.0.0" - ] - }, - "command": { - "type": "array", - "items": { - "type": "string" - }, - "default": null, - "description": "The command to run in the dockerimage component instead of the default one provided in the image. Defaults to null, meaning use whatever is defined in the image.", - "examples": [ - "['/bin/sh', '-c']" - ] - }, - "args": { - "type": "array", - "items": { - "type": "string" - }, - "default": null, - "description": "The arguments to supply to the command running the dockerimage component. The arguments are supplied either to the default command provided in the image or to the overridden command. Defaults to null, meaning use whatever is defined in the image.", - "examples": [ - "['-R', '-f']" - ] - } - } - } - } - ] - }, - "properties": { - "alias": { - "description": "The name using which other places of this devfile (like commands) can refer to this component. This attribute is optional but must be unique in the devfile if specified.", - "type": "string", - "examples": [ - "mvn-stack" - ] - }, - "type": { - "description": "Describes type of the component, e.g. whether it is an plugin or editor or other type", - "enum": [ - "cheEditor", - "chePlugin", - "kubernetes", - "openshift", - "dockerimage" - ], - "examples": [ - "chePlugin", - "cheEditor", - "kubernetes", - "openshift", - "dockerimage" - ] - }, - "mountSources": { - "type": "boolean", - "description": "Describes whether projects sources should be mount to the component. `CHE_PROJECTS_ROOT` environment variable should contains a path where projects sources are mount", - "default": "false" - }, - "memoryLimit": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "integer", - "exclusiveMinimum": 0 - } - ], - "description": "Describes memory limit for the component. You can express memory as a plain integer or as a fixed-point integer using one of these suffixes: E, P, T, G, M, K. You can also use the power-of-two equivalents: Ei, Pi, Ti, Gi, Mi, Ki", - "examples": [ - "128974848", - "129e6", - "129M", - "123Mi" - ] - }, - "memoryRequest": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "integer", - "exclusiveMinimum": 0 - } - ], - "description": "Describes memory request for the component. You can express memory as a plain integer or as a fixed-point integer using one of these suffixes: E, P, T, G, M, K. You can also use the power-of-two equivalents: Ei, Pi, Ti, Gi, Mi, Ki", - "examples": [ - "128974848", - "129e6", - "129M", - "123Mi" - ] - }, - "cpuLimit": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number", - "exclusiveMinimum": 0 - } - ], - "description": "Describes CPU limit for the component. You can express CPU limit as a float-point cores or as a fixed-point integer millicores using 'm' suffix", - "examples": [ - "2", - "0.235", - "100m", - "1230m" - ] - }, - "cpuRequest": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number", - "exclusiveMinimum": 0 - } - ], - "description": "Describes CPU request for the component. You can express CPU request as a float-point cores or as a fixed-point integer millicores using 'm' suffix", - "examples": [ - "2", - "0.235", - "100m", - "1230m" - ] - }, - "automountWorkspaceSecrets": { - "type": "boolean", - "description": "Describes whether namespace secrets should be mount to the component." - }, - "volumes": { - "type": "array", - "description": "Describes volumes which should be mount to component", - "items": { - "type": "object", - "description": "Describe volume that should be mount to component", - "required": [ - "name", - "containerPath" - ], - "properties": { - "name": { - "type": "string", - "title": "The Volume Name", - "description": "The volume name. If several components mount the same volume then they will reuse the volume and will be able to access to the same files", - "examples": [ - "my-data" - ] - }, - "containerPath": { - "type": "string", - "title": "The path where volume should be mount to container", - "examples": [ - "/home/user/data" - ] - } - } - } - }, - "env": { - "type": "array", - "description": "The environment variables list that should be set to docker container", - "items": { - "type": "object", - "description": "Describes environment variable", - "required": [ - "name", - "value" - ], - "properties": { - "name": { - "type": "string", - "title": "The Environment Variable Name", - "description": "The environment variable name" - }, - "value": { - "type": "string", - "title": "The Environment Variable Value", - "description": "The environment variable value" - } - } - } - }, - "endpoints": { - "type": "array", - "description": "Describes dockerimage component endpoints", - "items": { - "name": "object", - "description": "Describes dockerimage component endpoint", - "required": [ - "name", - "port" - ], - "properties": { - "name": { - "type": "string", - "title": "The Endpoint Name", - "description": "The Endpoint name" - }, - "port": { - "type": "integer", - "title": "The Endpoint Port", - "description": "The container port that should be used as endpoint" - }, - "attributes": { - "type": "object", - "public": { - "type": "boolean", - "description": "Identifies endpoint as workspace internally or externally accessible.", - "default": "true" - }, - "secure": { - "type": "boolean", - "description": "Identifies server as secure or non-secure. Requests to secure servers will be authenticated and must contain machine token", - "default": "false" - }, - "discoverable": { - "type": "boolean", - "description": "Identifies endpoint as accessible by its name.", - "default": "false" - }, - "protocol": { - "type": "boolean", - "description": "Defines protocol that should be used for communication with endpoint. Is used for endpoint URL evaluation" - }, - "additionalProperties": { - "type": "string" - }, - "javaType": "java.util.Map" - } - } - } - } - }, - "additionalProperties": true - } - }, - "commands": { - "type": "array", - "title": "The Commands List", - "description": "Description of the predefined commands to be available in workspace", - "items": { - "type": "object", - "additionalProperties": false, - "required": [ - "name", - "actions" - ], - "properties": { - "name": { - "description": "Describes the name of the command. Should be unique per commands set.", - "type": "string", - "examples": [ - "build" - ] - }, - "attributes": { - "description": "Additional command attributes", - "$ref": "#/definitions/attributes" - }, - "actions": { - "type": "array", - "description": "List of the actions of given command. Now the only one command must be specified in list but there are plans to implement supporting multiple actions commands.", - "title": "The Command Actions List", - "minItems": 1, - "maxItems": 1, - "items": { - "oneOf": [ - { - "properties": { - "type": {}, - "component": {}, - "command": {}, - "workdir": {} - }, - "required": [ - "type", - "component", - "command" - ], - "additionalProperties": false - }, - { - "properties": { - "type": {}, - "reference": {}, - "referenceContent": {} - }, - "anyOf": [ - { - "required": [ - "type", - "reference" - ], - "additionalProperties": true - }, - { - "required": [ - "type", - "referenceContent" - ], - "additionalProperties": true - } - ], - "additionalProperties": false - } - ], - "type": "object", - "properties": { - "type": { - "description": "Describes action type", - "type": "string", - "examples": [ - "exec", - "vscode-task", - "vscode-launch" - ] - }, - "component": { - "type": "string", - "description": "Describes component to which given action relates", - "examples": [ - "mvn-stack" - ] - }, - "command": { - "type": "string", - "description": "The actual action command-line string", - "examples": [ - "mvn package" - ] - }, - "workdir": { - "type": "string", - "description": "Working directory where the command should be executed", - "examples": [ - "/projects/spring-petclinic" - ] - }, - "reference": { - "type": "string", - "description": "the path relative to the location of the devfile to the configuration file defining one or more actions in the editor-specific format", - "examples": [ - "../ide-config/launch.json" - ] - }, - "referenceContent": { - "type": "string", - "description": "The content of the referenced configuration file that defines one or more actions in the editor-specific format", - "examples": [ - "{\"version\": \"2.0.0\",\n \"tasks\": [\n {\n \"type\": \"typescript\",\n \"tsconfig\": \"tsconfig.json\",\n \"problemMatcher\": [\n \"$tsc\"\n ],\n \"group\": {\n \"kind\": \"build\",\n \"isDefault\": true\n }\n }\n ]}" - ] - } - } - } - }, - "previewUrl": { - "type": "object", - "required": [ - "port" - ], - "properties": { - "port": { - "type": "number", - "minimum": 0, - "maximum": 65535 - }, - "path": { - "type": "string" - } - } - } - } - } - }, - "attributes": { - "type": "object", - "editorFree": { - "type": "boolean", - "description": "Defines that no editor is needed and default one should not be provisioned. Defaults to `false`.", - "default": "false" - }, - "persistVolumes": { - "type": "boolean", - "description": "Defines whether volumes should be stored or not. Defaults to `true`. In case of `false` workspace volumes will be created as `emptyDir`. The data in the `emptyDir` volume is deleted forever when a workspace Pod is removed for any reason(pod is crashed, workspace is restarted).", - "default": "true" - }, - "additionalProperties": { - "type": "string" - } - } - } -} diff --git a/packages/dashboard-backend/src/devfileSchemas/2.0.0/devfile.json b/packages/dashboard-backend/src/devfileSchemas/2.0.0/devfile.json index 726f05fea..3f62b9569 100644 --- a/packages/dashboard-backend/src/devfileSchemas/2.0.0/devfile.json +++ b/packages/dashboard-backend/src/devfileSchemas/2.0.0/devfile.json @@ -2,52 +2,36 @@ "description": "Devfile describes the structure of a cloud-native workspace and development environment.", "type": "object", "title": "Devfile schema - Version 2.0.0", - "required": [ - "schemaVersion" - ], + "required": ["schemaVersion"], "properties": { "commands": { "description": "Predefined, ready-to-use, workspace-related commands", "type": "array", "items": { "type": "object", - "required": [ - "id" - ], + "required": ["id"], "oneOf": [ { - "required": [ - "exec" - ] + "required": ["exec"] }, { - "required": [ - "apply" - ] + "required": ["apply"] }, { - "required": [ - "vscodeTask" - ] + "required": ["vscodeTask"] }, { - "required": [ - "vscodeLaunch" - ] + "required": ["vscodeLaunch"] }, { - "required": [ - "composite" - ] + "required": ["composite"] } ], "properties": { "apply": { "description": "Command that consists in applying a given component definition, typically bound to a workspace event.\n\nFor example, when an `apply` command is bound to a `preStart` event, and references a `container` component, it will start the container as a K8S initContainer in the workspace POD, unless the component has its `dedicatedPod` field set to `true`.\n\nWhen no `apply` command exist for a given component, it is assumed the component will be applied at workspace start by default.", "type": "object", - "required": [ - "component" - ], + "required": ["component"], "properties": { "component": { "description": "Describes component that will be applied", @@ -56,9 +40,7 @@ "group": { "description": "Defines the group this command is part of", "type": "object", - "required": [ - "kind" - ], + "required": ["kind"], "properties": { "isDefault": { "description": "Identifies the default command for a given group kind", @@ -67,12 +49,7 @@ "kind": { "description": "Kind of group the command is part of", "type": "string", - "enum": [ - "build", - "run", - "test", - "debug" - ] + "enum": ["build", "run", "test", "debug"] } }, "additionalProperties": false @@ -103,9 +80,7 @@ "group": { "description": "Defines the group this command is part of", "type": "object", - "required": [ - "kind" - ], + "required": ["kind"], "properties": { "isDefault": { "description": "Identifies the default command for a given group kind", @@ -114,12 +89,7 @@ "kind": { "description": "Kind of group the command is part of", "type": "string", - "enum": [ - "build", - "run", - "test", - "debug" - ] + "enum": ["build", "run", "test", "debug"] } }, "additionalProperties": false @@ -138,10 +108,7 @@ "exec": { "description": "CLI Command executed in an existing component container", "type": "object", - "required": [ - "commandLine", - "component" - ], + "required": ["commandLine", "component"], "properties": { "commandLine": { "description": "The actual command-line string\n\nSpecial variables that can be used:\n\n - `$PROJECTS_ROOT`: A path where projects sources are mounted as defined by container component's sourceMapping.\n\n - `$PROJECT_SOURCE`: A path to a project source ($PROJECTS_ROOT/\u003cproject-name\u003e). If there are multiple projects, this will point to the directory of the first one.", @@ -156,10 +123,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name", - "value" - ], + "required": ["name", "value"], "properties": { "name": { "type": "string" @@ -174,9 +138,7 @@ "group": { "description": "Defines the group this command is part of", "type": "object", - "required": [ - "kind" - ], + "required": ["kind"], "properties": { "isDefault": { "description": "Identifies the default command for a given group kind", @@ -185,12 +147,7 @@ "kind": { "description": "Kind of group the command is part of", "type": "string", - "enum": [ - "build", - "run", - "test", - "debug" - ] + "enum": ["build", "run", "test", "debug"] } }, "additionalProperties": false @@ -221,23 +178,17 @@ "type": "object", "oneOf": [ { - "required": [ - "uri" - ] + "required": ["uri"] }, { - "required": [ - "inlined" - ] + "required": ["inlined"] } ], "properties": { "group": { "description": "Defines the group this command is part of", "type": "object", - "required": [ - "kind" - ], + "required": ["kind"], "properties": { "isDefault": { "description": "Identifies the default command for a given group kind", @@ -246,12 +197,7 @@ "kind": { "description": "Kind of group the command is part of", "type": "string", - "enum": [ - "build", - "run", - "test", - "debug" - ] + "enum": ["build", "run", "test", "debug"] } }, "additionalProperties": false @@ -272,23 +218,17 @@ "type": "object", "oneOf": [ { - "required": [ - "uri" - ] + "required": ["uri"] }, { - "required": [ - "inlined" - ] + "required": ["inlined"] } ], "properties": { "group": { "description": "Defines the group this command is part of", "type": "object", - "required": [ - "kind" - ], + "required": ["kind"], "properties": { "isDefault": { "description": "Identifies the default command for a given group kind", @@ -297,12 +237,7 @@ "kind": { "description": "Kind of group the command is part of", "type": "string", - "enum": [ - "build", - "run", - "test", - "debug" - ] + "enum": ["build", "run", "test", "debug"] } }, "additionalProperties": false @@ -327,34 +262,22 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "oneOf": [ { - "required": [ - "container" - ] + "required": ["container"] }, { - "required": [ - "kubernetes" - ] + "required": ["kubernetes"] }, { - "required": [ - "openshift" - ] + "required": ["openshift"] }, { - "required": [ - "volume" - ] + "required": ["volume"] }, { - "required": [ - "plugin" - ] + "required": ["plugin"] } ], "properties": { @@ -366,9 +289,7 @@ "container": { "description": "Allows adding and configuring workspace-related containers", "type": "object", - "required": [ - "image" - ], + "required": ["image"], "properties": { "args": { "description": "The arguments to supply to the command running the dockerimage component. The arguments are supplied either to the default command provided in the image or to the overridden command.\n\nDefaults to an empty array, meaning use whatever is defined in the image.", @@ -392,10 +313,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name", - "targetPort" - ], + "required": ["name", "targetPort"], "properties": { "attributes": { "description": "Map of implementation-dependant string-based free-form attributes.\n\nExamples of Che-specific attributes:\n- cookiesAuthEnabled: \"true\" / \"false\",\n- type: \"terminal\" / \"ide\" / \"ide-dev\",", @@ -406,11 +324,7 @@ "description": "Describes how the endpoint should be exposed on the network.\n- `public` means that the endpoint will be exposed on the public network, typically through a K8S ingress or an OpenShift route.\n- `internal` means that the endpoint will be exposed internally outside of the main workspace POD, typically by K8S services, to be consumed by other elements running on the same cloud internal network.\n- `none` means that the endpoint will not be exposed and will only be accessible inside the main workspace POD, on a local address.\n\nDefault value is `public`", "type": "string", "default": "public", - "enum": [ - "public", - "internal", - "none" - ] + "enum": ["public", "internal", "none"] }, "name": { "type": "string", @@ -425,14 +339,7 @@ "description": "Describes the application and transport protocols of the traffic that will go through this endpoint.\n- `http`: Endpoint will have `http` traffic, typically on a TCP connection. It will be automaticaly promoted to `https` when the `secure` field is set to `true`.\n- `https`: Endpoint will have `https` traffic, typically on a TCP connection.\n- `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. It will be automaticaly promoted to `wss` when the `secure` field is set to `true`.\n- `wss`: Endpoint will have `wss` traffic, typically on a TCP connection.\n- `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol.\n- `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol.\n\nDefault value is `http`", "type": "string", "default": "http", - "enum": [ - "http", - "https", - "ws", - "wss", - "tcp", - "udp" - ] + "enum": ["http", "https", "ws", "wss", "tcp", "udp"] }, "secure": { "description": "Describes whether the endpoint should be secured and protected by some authentication process. This requires a protocol of `https` or `wss`.", @@ -450,10 +357,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name", - "value" - ], + "required": ["name", "value"], "properties": { "name": { "type": "string" @@ -486,9 +390,7 @@ "items": { "description": "Volume that should be mounted to a component container", "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "name": { "description": "The volume mount name is the name of an existing `Volume` component. If several containers mount the same volume name then they will reuse the same volume and will be able to access to the same files.", @@ -512,14 +414,10 @@ "type": "object", "oneOf": [ { - "required": [ - "uri" - ] + "required": ["uri"] }, { - "required": [ - "inlined" - ] + "required": ["inlined"] } ], "properties": { @@ -527,10 +425,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name", - "targetPort" - ], + "required": ["name", "targetPort"], "properties": { "attributes": { "description": "Map of implementation-dependant string-based free-form attributes.\n\nExamples of Che-specific attributes:\n- cookiesAuthEnabled: \"true\" / \"false\",\n- type: \"terminal\" / \"ide\" / \"ide-dev\",", @@ -541,11 +436,7 @@ "description": "Describes how the endpoint should be exposed on the network.\n- `public` means that the endpoint will be exposed on the public network, typically through a K8S ingress or an OpenShift route.\n- `internal` means that the endpoint will be exposed internally outside of the main workspace POD, typically by K8S services, to be consumed by other elements running on the same cloud internal network.\n- `none` means that the endpoint will not be exposed and will only be accessible inside the main workspace POD, on a local address.\n\nDefault value is `public`", "type": "string", "default": "public", - "enum": [ - "public", - "internal", - "none" - ] + "enum": ["public", "internal", "none"] }, "name": { "type": "string", @@ -560,14 +451,7 @@ "description": "Describes the application and transport protocols of the traffic that will go through this endpoint.\n- `http`: Endpoint will have `http` traffic, typically on a TCP connection. It will be automaticaly promoted to `https` when the `secure` field is set to `true`.\n- `https`: Endpoint will have `https` traffic, typically on a TCP connection.\n- `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. It will be automaticaly promoted to `wss` when the `secure` field is set to `true`.\n- `wss`: Endpoint will have `wss` traffic, typically on a TCP connection.\n- `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol.\n- `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol.\n\nDefault value is `http`", "type": "string", "default": "http", - "enum": [ - "http", - "https", - "ws", - "wss", - "tcp", - "udp" - ] + "enum": ["http", "https", "ws", "wss", "tcp", "udp"] }, "secure": { "description": "Describes whether the endpoint should be secured and protected by some authentication process. This requires a protocol of `https` or `wss`.", @@ -602,14 +486,10 @@ "type": "object", "oneOf": [ { - "required": [ - "uri" - ] + "required": ["uri"] }, { - "required": [ - "inlined" - ] + "required": ["inlined"] } ], "properties": { @@ -617,10 +497,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name", - "targetPort" - ], + "required": ["name", "targetPort"], "properties": { "attributes": { "description": "Map of implementation-dependant string-based free-form attributes.\n\nExamples of Che-specific attributes:\n- cookiesAuthEnabled: \"true\" / \"false\",\n- type: \"terminal\" / \"ide\" / \"ide-dev\",", @@ -631,11 +508,7 @@ "description": "Describes how the endpoint should be exposed on the network.\n- `public` means that the endpoint will be exposed on the public network, typically through a K8S ingress or an OpenShift route.\n- `internal` means that the endpoint will be exposed internally outside of the main workspace POD, typically by K8S services, to be consumed by other elements running on the same cloud internal network.\n- `none` means that the endpoint will not be exposed and will only be accessible inside the main workspace POD, on a local address.\n\nDefault value is `public`", "type": "string", "default": "public", - "enum": [ - "public", - "internal", - "none" - ] + "enum": ["public", "internal", "none"] }, "name": { "type": "string", @@ -650,14 +523,7 @@ "description": "Describes the application and transport protocols of the traffic that will go through this endpoint.\n- `http`: Endpoint will have `http` traffic, typically on a TCP connection. It will be automaticaly promoted to `https` when the `secure` field is set to `true`.\n- `https`: Endpoint will have `https` traffic, typically on a TCP connection.\n- `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. It will be automaticaly promoted to `wss` when the `secure` field is set to `true`.\n- `wss`: Endpoint will have `wss` traffic, typically on a TCP connection.\n- `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol.\n- `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol.\n\nDefault value is `http`", "type": "string", "default": "http", - "enum": [ - "http", - "https", - "ws", - "wss", - "tcp", - "udp" - ] + "enum": ["http", "https", "ws", "wss", "tcp", "udp"] }, "secure": { "description": "Describes whether the endpoint should be secured and protected by some authentication process. This requires a protocol of `https` or `wss`.", @@ -686,19 +552,13 @@ "type": "object", "oneOf": [ { - "required": [ - "uri" - ] + "required": ["uri"] }, { - "required": [ - "id" - ] + "required": ["id"] }, { - "required": [ - "kubernetes" - ] + "required": ["kubernetes"] } ], "properties": { @@ -707,34 +567,22 @@ "type": "array", "items": { "type": "object", - "required": [ - "id" - ], + "required": ["id"], "oneOf": [ { - "required": [ - "exec" - ] + "required": ["exec"] }, { - "required": [ - "apply" - ] + "required": ["apply"] }, { - "required": [ - "vscodeTask" - ] + "required": ["vscodeTask"] }, { - "required": [ - "vscodeLaunch" - ] + "required": ["vscodeLaunch"] }, { - "required": [ - "composite" - ] + "required": ["composite"] } ], "properties": { @@ -757,12 +605,7 @@ "kind": { "description": "Kind of group the command is part of", "type": "string", - "enum": [ - "build", - "run", - "test", - "debug" - ] + "enum": ["build", "run", "test", "debug"] } }, "additionalProperties": false @@ -801,12 +644,7 @@ "kind": { "description": "Kind of group the command is part of", "type": "string", - "enum": [ - "build", - "run", - "test", - "debug" - ] + "enum": ["build", "run", "test", "debug"] } }, "additionalProperties": false @@ -839,9 +677,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "name": { "type": "string" @@ -864,12 +700,7 @@ "kind": { "description": "Kind of group the command is part of", "type": "string", - "enum": [ - "build", - "run", - "test", - "debug" - ] + "enum": ["build", "run", "test", "debug"] } }, "additionalProperties": false @@ -900,14 +731,10 @@ "type": "object", "oneOf": [ { - "required": [ - "uri" - ] + "required": ["uri"] }, { - "required": [ - "inlined" - ] + "required": ["inlined"] } ], "properties": { @@ -922,12 +749,7 @@ "kind": { "description": "Kind of group the command is part of", "type": "string", - "enum": [ - "build", - "run", - "test", - "debug" - ] + "enum": ["build", "run", "test", "debug"] } }, "additionalProperties": false @@ -948,14 +770,10 @@ "type": "object", "oneOf": [ { - "required": [ - "uri" - ] + "required": ["uri"] }, { - "required": [ - "inlined" - ] + "required": ["inlined"] } ], "properties": { @@ -970,12 +788,7 @@ "kind": { "description": "Kind of group the command is part of", "type": "string", - "enum": [ - "build", - "run", - "test", - "debug" - ] + "enum": ["build", "run", "test", "debug"] } }, "additionalProperties": false @@ -1000,29 +813,19 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "oneOf": [ { - "required": [ - "container" - ] + "required": ["container"] }, { - "required": [ - "kubernetes" - ] + "required": ["kubernetes"] }, { - "required": [ - "openshift" - ] + "required": ["openshift"] }, { - "required": [ - "volume" - ] + "required": ["volume"] } ], "properties": { @@ -1057,9 +860,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "attributes": { "description": "Map of implementation-dependant string-based free-form attributes.\n\nExamples of Che-specific attributes:\n- cookiesAuthEnabled: \"true\" / \"false\",\n- type: \"terminal\" / \"ide\" / \"ide-dev\",", @@ -1069,11 +870,7 @@ "exposure": { "description": "Describes how the endpoint should be exposed on the network.\n- `public` means that the endpoint will be exposed on the public network, typically through a K8S ingress or an OpenShift route.\n- `internal` means that the endpoint will be exposed internally outside of the main workspace POD, typically by K8S services, to be consumed by other elements running on the same cloud internal network.\n- `none` means that the endpoint will not be exposed and will only be accessible inside the main workspace POD, on a local address.\n\nDefault value is `public`", "type": "string", - "enum": [ - "public", - "internal", - "none" - ] + "enum": ["public", "internal", "none"] }, "name": { "type": "string", @@ -1087,14 +884,7 @@ "protocol": { "description": "Describes the application and transport protocols of the traffic that will go through this endpoint.\n- `http`: Endpoint will have `http` traffic, typically on a TCP connection. It will be automaticaly promoted to `https` when the `secure` field is set to `true`.\n- `https`: Endpoint will have `https` traffic, typically on a TCP connection.\n- `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. It will be automaticaly promoted to `wss` when the `secure` field is set to `true`.\n- `wss`: Endpoint will have `wss` traffic, typically on a TCP connection.\n- `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol.\n- `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol.\n\nDefault value is `http`", "type": "string", - "enum": [ - "http", - "https", - "ws", - "wss", - "tcp", - "udp" - ] + "enum": ["http", "https", "ws", "wss", "tcp", "udp"] }, "secure": { "description": "Describes whether the endpoint should be secured and protected by some authentication process. This requires a protocol of `https` or `wss`.", @@ -1112,9 +902,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "name": { "type": "string" @@ -1146,9 +934,7 @@ "items": { "description": "Volume that should be mounted to a component container", "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "name": { "description": "The volume mount name is the name of an existing `Volume` component. If several containers mount the same volume name then they will reuse the same volume and will be able to access to the same files.", @@ -1172,14 +958,10 @@ "type": "object", "oneOf": [ { - "required": [ - "uri" - ] + "required": ["uri"] }, { - "required": [ - "inlined" - ] + "required": ["inlined"] } ], "properties": { @@ -1187,9 +969,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "attributes": { "description": "Map of implementation-dependant string-based free-form attributes.\n\nExamples of Che-specific attributes:\n- cookiesAuthEnabled: \"true\" / \"false\",\n- type: \"terminal\" / \"ide\" / \"ide-dev\",", @@ -1199,11 +979,7 @@ "exposure": { "description": "Describes how the endpoint should be exposed on the network.\n- `public` means that the endpoint will be exposed on the public network, typically through a K8S ingress or an OpenShift route.\n- `internal` means that the endpoint will be exposed internally outside of the main workspace POD, typically by K8S services, to be consumed by other elements running on the same cloud internal network.\n- `none` means that the endpoint will not be exposed and will only be accessible inside the main workspace POD, on a local address.\n\nDefault value is `public`", "type": "string", - "enum": [ - "public", - "internal", - "none" - ] + "enum": ["public", "internal", "none"] }, "name": { "type": "string", @@ -1217,14 +993,7 @@ "protocol": { "description": "Describes the application and transport protocols of the traffic that will go through this endpoint.\n- `http`: Endpoint will have `http` traffic, typically on a TCP connection. It will be automaticaly promoted to `https` when the `secure` field is set to `true`.\n- `https`: Endpoint will have `https` traffic, typically on a TCP connection.\n- `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. It will be automaticaly promoted to `wss` when the `secure` field is set to `true`.\n- `wss`: Endpoint will have `wss` traffic, typically on a TCP connection.\n- `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol.\n- `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol.\n\nDefault value is `http`", "type": "string", - "enum": [ - "http", - "https", - "ws", - "wss", - "tcp", - "udp" - ] + "enum": ["http", "https", "ws", "wss", "tcp", "udp"] }, "secure": { "description": "Describes whether the endpoint should be secured and protected by some authentication process. This requires a protocol of `https` or `wss`.", @@ -1259,14 +1028,10 @@ "type": "object", "oneOf": [ { - "required": [ - "uri" - ] + "required": ["uri"] }, { - "required": [ - "inlined" - ] + "required": ["inlined"] } ], "properties": { @@ -1274,9 +1039,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "attributes": { "description": "Map of implementation-dependant string-based free-form attributes.\n\nExamples of Che-specific attributes:\n- cookiesAuthEnabled: \"true\" / \"false\",\n- type: \"terminal\" / \"ide\" / \"ide-dev\",", @@ -1286,11 +1049,7 @@ "exposure": { "description": "Describes how the endpoint should be exposed on the network.\n- `public` means that the endpoint will be exposed on the public network, typically through a K8S ingress or an OpenShift route.\n- `internal` means that the endpoint will be exposed internally outside of the main workspace POD, typically by K8S services, to be consumed by other elements running on the same cloud internal network.\n- `none` means that the endpoint will not be exposed and will only be accessible inside the main workspace POD, on a local address.\n\nDefault value is `public`", "type": "string", - "enum": [ - "public", - "internal", - "none" - ] + "enum": ["public", "internal", "none"] }, "name": { "type": "string", @@ -1304,14 +1063,7 @@ "protocol": { "description": "Describes the application and transport protocols of the traffic that will go through this endpoint.\n- `http`: Endpoint will have `http` traffic, typically on a TCP connection. It will be automaticaly promoted to `https` when the `secure` field is set to `true`.\n- `https`: Endpoint will have `https` traffic, typically on a TCP connection.\n- `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. It will be automaticaly promoted to `wss` when the `secure` field is set to `true`.\n- `wss`: Endpoint will have `wss` traffic, typically on a TCP connection.\n- `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol.\n- `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol.\n\nDefault value is `http`", "type": "string", - "enum": [ - "http", - "https", - "ws", - "wss", - "tcp", - "udp" - ] + "enum": ["http", "https", "ws", "wss", "tcp", "udp"] }, "secure": { "description": "Describes whether the endpoint should be secured and protected by some authentication process. This requires a protocol of `https` or `wss`.", @@ -1357,9 +1109,7 @@ "kubernetes": { "description": "Reference to a Kubernetes CRD of type DevWorkspaceTemplate", "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "name": { "type": "string" @@ -1479,19 +1229,13 @@ "type": "object", "oneOf": [ { - "required": [ - "uri" - ] + "required": ["uri"] }, { - "required": [ - "id" - ] + "required": ["id"] }, { - "required": [ - "kubernetes" - ] + "required": ["kubernetes"] } ], "properties": { @@ -1500,34 +1244,22 @@ "type": "array", "items": { "type": "object", - "required": [ - "id" - ], + "required": ["id"], "oneOf": [ { - "required": [ - "exec" - ] + "required": ["exec"] }, { - "required": [ - "apply" - ] + "required": ["apply"] }, { - "required": [ - "vscodeTask" - ] + "required": ["vscodeTask"] }, { - "required": [ - "vscodeLaunch" - ] + "required": ["vscodeLaunch"] }, { - "required": [ - "composite" - ] + "required": ["composite"] } ], "properties": { @@ -1550,12 +1282,7 @@ "kind": { "description": "Kind of group the command is part of", "type": "string", - "enum": [ - "build", - "run", - "test", - "debug" - ] + "enum": ["build", "run", "test", "debug"] } }, "additionalProperties": false @@ -1594,12 +1321,7 @@ "kind": { "description": "Kind of group the command is part of", "type": "string", - "enum": [ - "build", - "run", - "test", - "debug" - ] + "enum": ["build", "run", "test", "debug"] } }, "additionalProperties": false @@ -1632,9 +1354,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "name": { "type": "string" @@ -1657,12 +1377,7 @@ "kind": { "description": "Kind of group the command is part of", "type": "string", - "enum": [ - "build", - "run", - "test", - "debug" - ] + "enum": ["build", "run", "test", "debug"] } }, "additionalProperties": false @@ -1693,14 +1408,10 @@ "type": "object", "oneOf": [ { - "required": [ - "uri" - ] + "required": ["uri"] }, { - "required": [ - "inlined" - ] + "required": ["inlined"] } ], "properties": { @@ -1715,12 +1426,7 @@ "kind": { "description": "Kind of group the command is part of", "type": "string", - "enum": [ - "build", - "run", - "test", - "debug" - ] + "enum": ["build", "run", "test", "debug"] } }, "additionalProperties": false @@ -1741,14 +1447,10 @@ "type": "object", "oneOf": [ { - "required": [ - "uri" - ] + "required": ["uri"] }, { - "required": [ - "inlined" - ] + "required": ["inlined"] } ], "properties": { @@ -1763,12 +1465,7 @@ "kind": { "description": "Kind of group the command is part of", "type": "string", - "enum": [ - "build", - "run", - "test", - "debug" - ] + "enum": ["build", "run", "test", "debug"] } }, "additionalProperties": false @@ -1793,34 +1490,22 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "oneOf": [ { - "required": [ - "container" - ] + "required": ["container"] }, { - "required": [ - "kubernetes" - ] + "required": ["kubernetes"] }, { - "required": [ - "openshift" - ] + "required": ["openshift"] }, { - "required": [ - "volume" - ] + "required": ["volume"] }, { - "required": [ - "plugin" - ] + "required": ["plugin"] } ], "properties": { @@ -1855,9 +1540,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "attributes": { "description": "Map of implementation-dependant string-based free-form attributes.\n\nExamples of Che-specific attributes:\n- cookiesAuthEnabled: \"true\" / \"false\",\n- type: \"terminal\" / \"ide\" / \"ide-dev\",", @@ -1867,11 +1550,7 @@ "exposure": { "description": "Describes how the endpoint should be exposed on the network.\n- `public` means that the endpoint will be exposed on the public network, typically through a K8S ingress or an OpenShift route.\n- `internal` means that the endpoint will be exposed internally outside of the main workspace POD, typically by K8S services, to be consumed by other elements running on the same cloud internal network.\n- `none` means that the endpoint will not be exposed and will only be accessible inside the main workspace POD, on a local address.\n\nDefault value is `public`", "type": "string", - "enum": [ - "public", - "internal", - "none" - ] + "enum": ["public", "internal", "none"] }, "name": { "type": "string", @@ -1885,14 +1564,7 @@ "protocol": { "description": "Describes the application and transport protocols of the traffic that will go through this endpoint.\n- `http`: Endpoint will have `http` traffic, typically on a TCP connection. It will be automaticaly promoted to `https` when the `secure` field is set to `true`.\n- `https`: Endpoint will have `https` traffic, typically on a TCP connection.\n- `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. It will be automaticaly promoted to `wss` when the `secure` field is set to `true`.\n- `wss`: Endpoint will have `wss` traffic, typically on a TCP connection.\n- `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol.\n- `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol.\n\nDefault value is `http`", "type": "string", - "enum": [ - "http", - "https", - "ws", - "wss", - "tcp", - "udp" - ] + "enum": ["http", "https", "ws", "wss", "tcp", "udp"] }, "secure": { "description": "Describes whether the endpoint should be secured and protected by some authentication process. This requires a protocol of `https` or `wss`.", @@ -1910,9 +1582,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "name": { "type": "string" @@ -1944,9 +1614,7 @@ "items": { "description": "Volume that should be mounted to a component container", "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "name": { "description": "The volume mount name is the name of an existing `Volume` component. If several containers mount the same volume name then they will reuse the same volume and will be able to access to the same files.", @@ -1970,14 +1638,10 @@ "type": "object", "oneOf": [ { - "required": [ - "uri" - ] + "required": ["uri"] }, { - "required": [ - "inlined" - ] + "required": ["inlined"] } ], "properties": { @@ -1985,9 +1649,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "attributes": { "description": "Map of implementation-dependant string-based free-form attributes.\n\nExamples of Che-specific attributes:\n- cookiesAuthEnabled: \"true\" / \"false\",\n- type: \"terminal\" / \"ide\" / \"ide-dev\",", @@ -1997,11 +1659,7 @@ "exposure": { "description": "Describes how the endpoint should be exposed on the network.\n- `public` means that the endpoint will be exposed on the public network, typically through a K8S ingress or an OpenShift route.\n- `internal` means that the endpoint will be exposed internally outside of the main workspace POD, typically by K8S services, to be consumed by other elements running on the same cloud internal network.\n- `none` means that the endpoint will not be exposed and will only be accessible inside the main workspace POD, on a local address.\n\nDefault value is `public`", "type": "string", - "enum": [ - "public", - "internal", - "none" - ] + "enum": ["public", "internal", "none"] }, "name": { "type": "string", @@ -2015,14 +1673,7 @@ "protocol": { "description": "Describes the application and transport protocols of the traffic that will go through this endpoint.\n- `http`: Endpoint will have `http` traffic, typically on a TCP connection. It will be automaticaly promoted to `https` when the `secure` field is set to `true`.\n- `https`: Endpoint will have `https` traffic, typically on a TCP connection.\n- `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. It will be automaticaly promoted to `wss` when the `secure` field is set to `true`.\n- `wss`: Endpoint will have `wss` traffic, typically on a TCP connection.\n- `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol.\n- `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol.\n\nDefault value is `http`", "type": "string", - "enum": [ - "http", - "https", - "ws", - "wss", - "tcp", - "udp" - ] + "enum": ["http", "https", "ws", "wss", "tcp", "udp"] }, "secure": { "description": "Describes whether the endpoint should be secured and protected by some authentication process. This requires a protocol of `https` or `wss`.", @@ -2057,14 +1708,10 @@ "type": "object", "oneOf": [ { - "required": [ - "uri" - ] + "required": ["uri"] }, { - "required": [ - "inlined" - ] + "required": ["inlined"] } ], "properties": { @@ -2072,9 +1719,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "attributes": { "description": "Map of implementation-dependant string-based free-form attributes.\n\nExamples of Che-specific attributes:\n- cookiesAuthEnabled: \"true\" / \"false\",\n- type: \"terminal\" / \"ide\" / \"ide-dev\",", @@ -2084,11 +1729,7 @@ "exposure": { "description": "Describes how the endpoint should be exposed on the network.\n- `public` means that the endpoint will be exposed on the public network, typically through a K8S ingress or an OpenShift route.\n- `internal` means that the endpoint will be exposed internally outside of the main workspace POD, typically by K8S services, to be consumed by other elements running on the same cloud internal network.\n- `none` means that the endpoint will not be exposed and will only be accessible inside the main workspace POD, on a local address.\n\nDefault value is `public`", "type": "string", - "enum": [ - "public", - "internal", - "none" - ] + "enum": ["public", "internal", "none"] }, "name": { "type": "string", @@ -2102,14 +1743,7 @@ "protocol": { "description": "Describes the application and transport protocols of the traffic that will go through this endpoint.\n- `http`: Endpoint will have `http` traffic, typically on a TCP connection. It will be automaticaly promoted to `https` when the `secure` field is set to `true`.\n- `https`: Endpoint will have `https` traffic, typically on a TCP connection.\n- `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. It will be automaticaly promoted to `wss` when the `secure` field is set to `true`.\n- `wss`: Endpoint will have `wss` traffic, typically on a TCP connection.\n- `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol.\n- `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol.\n\nDefault value is `http`", "type": "string", - "enum": [ - "http", - "https", - "ws", - "wss", - "tcp", - "udp" - ] + "enum": ["http", "https", "ws", "wss", "tcp", "udp"] }, "secure": { "description": "Describes whether the endpoint should be secured and protected by some authentication process. This requires a protocol of `https` or `wss`.", @@ -2138,19 +1772,13 @@ "type": "object", "oneOf": [ { - "required": [ - "uri" - ] + "required": ["uri"] }, { - "required": [ - "id" - ] + "required": ["id"] }, { - "required": [ - "kubernetes" - ] + "required": ["kubernetes"] } ], "properties": { @@ -2159,34 +1787,22 @@ "type": "array", "items": { "type": "object", - "required": [ - "id" - ], + "required": ["id"], "oneOf": [ { - "required": [ - "exec" - ] + "required": ["exec"] }, { - "required": [ - "apply" - ] + "required": ["apply"] }, { - "required": [ - "vscodeTask" - ] + "required": ["vscodeTask"] }, { - "required": [ - "vscodeLaunch" - ] + "required": ["vscodeLaunch"] }, { - "required": [ - "composite" - ] + "required": ["composite"] } ], "properties": { @@ -2209,12 +1825,7 @@ "kind": { "description": "Kind of group the command is part of", "type": "string", - "enum": [ - "build", - "run", - "test", - "debug" - ] + "enum": ["build", "run", "test", "debug"] } }, "additionalProperties": false @@ -2253,12 +1864,7 @@ "kind": { "description": "Kind of group the command is part of", "type": "string", - "enum": [ - "build", - "run", - "test", - "debug" - ] + "enum": ["build", "run", "test", "debug"] } }, "additionalProperties": false @@ -2291,9 +1897,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "name": { "type": "string" @@ -2316,12 +1920,7 @@ "kind": { "description": "Kind of group the command is part of", "type": "string", - "enum": [ - "build", - "run", - "test", - "debug" - ] + "enum": ["build", "run", "test", "debug"] } }, "additionalProperties": false @@ -2352,14 +1951,10 @@ "type": "object", "oneOf": [ { - "required": [ - "uri" - ] + "required": ["uri"] }, { - "required": [ - "inlined" - ] + "required": ["inlined"] } ], "properties": { @@ -2374,12 +1969,7 @@ "kind": { "description": "Kind of group the command is part of", "type": "string", - "enum": [ - "build", - "run", - "test", - "debug" - ] + "enum": ["build", "run", "test", "debug"] } }, "additionalProperties": false @@ -2400,14 +1990,10 @@ "type": "object", "oneOf": [ { - "required": [ - "uri" - ] + "required": ["uri"] }, { - "required": [ - "inlined" - ] + "required": ["inlined"] } ], "properties": { @@ -2422,12 +2008,7 @@ "kind": { "description": "Kind of group the command is part of", "type": "string", - "enum": [ - "build", - "run", - "test", - "debug" - ] + "enum": ["build", "run", "test", "debug"] } }, "additionalProperties": false @@ -2452,29 +2033,19 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "oneOf": [ { - "required": [ - "container" - ] + "required": ["container"] }, { - "required": [ - "kubernetes" - ] + "required": ["kubernetes"] }, { - "required": [ - "openshift" - ] + "required": ["openshift"] }, { - "required": [ - "volume" - ] + "required": ["volume"] } ], "properties": { @@ -2509,9 +2080,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "attributes": { "description": "Map of implementation-dependant string-based free-form attributes.\n\nExamples of Che-specific attributes:\n- cookiesAuthEnabled: \"true\" / \"false\",\n- type: \"terminal\" / \"ide\" / \"ide-dev\",", @@ -2521,11 +2090,7 @@ "exposure": { "description": "Describes how the endpoint should be exposed on the network.\n- `public` means that the endpoint will be exposed on the public network, typically through a K8S ingress or an OpenShift route.\n- `internal` means that the endpoint will be exposed internally outside of the main workspace POD, typically by K8S services, to be consumed by other elements running on the same cloud internal network.\n- `none` means that the endpoint will not be exposed and will only be accessible inside the main workspace POD, on a local address.\n\nDefault value is `public`", "type": "string", - "enum": [ - "public", - "internal", - "none" - ] + "enum": ["public", "internal", "none"] }, "name": { "type": "string", @@ -2539,14 +2104,7 @@ "protocol": { "description": "Describes the application and transport protocols of the traffic that will go through this endpoint.\n- `http`: Endpoint will have `http` traffic, typically on a TCP connection. It will be automaticaly promoted to `https` when the `secure` field is set to `true`.\n- `https`: Endpoint will have `https` traffic, typically on a TCP connection.\n- `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. It will be automaticaly promoted to `wss` when the `secure` field is set to `true`.\n- `wss`: Endpoint will have `wss` traffic, typically on a TCP connection.\n- `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol.\n- `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol.\n\nDefault value is `http`", "type": "string", - "enum": [ - "http", - "https", - "ws", - "wss", - "tcp", - "udp" - ] + "enum": ["http", "https", "ws", "wss", "tcp", "udp"] }, "secure": { "description": "Describes whether the endpoint should be secured and protected by some authentication process. This requires a protocol of `https` or `wss`.", @@ -2564,9 +2122,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "name": { "type": "string" @@ -2598,9 +2154,7 @@ "items": { "description": "Volume that should be mounted to a component container", "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "name": { "description": "The volume mount name is the name of an existing `Volume` component. If several containers mount the same volume name then they will reuse the same volume and will be able to access to the same files.", @@ -2624,14 +2178,10 @@ "type": "object", "oneOf": [ { - "required": [ - "uri" - ] + "required": ["uri"] }, { - "required": [ - "inlined" - ] + "required": ["inlined"] } ], "properties": { @@ -2639,9 +2189,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "attributes": { "description": "Map of implementation-dependant string-based free-form attributes.\n\nExamples of Che-specific attributes:\n- cookiesAuthEnabled: \"true\" / \"false\",\n- type: \"terminal\" / \"ide\" / \"ide-dev\",", @@ -2651,11 +2199,7 @@ "exposure": { "description": "Describes how the endpoint should be exposed on the network.\n- `public` means that the endpoint will be exposed on the public network, typically through a K8S ingress or an OpenShift route.\n- `internal` means that the endpoint will be exposed internally outside of the main workspace POD, typically by K8S services, to be consumed by other elements running on the same cloud internal network.\n- `none` means that the endpoint will not be exposed and will only be accessible inside the main workspace POD, on a local address.\n\nDefault value is `public`", "type": "string", - "enum": [ - "public", - "internal", - "none" - ] + "enum": ["public", "internal", "none"] }, "name": { "type": "string", @@ -2669,14 +2213,7 @@ "protocol": { "description": "Describes the application and transport protocols of the traffic that will go through this endpoint.\n- `http`: Endpoint will have `http` traffic, typically on a TCP connection. It will be automaticaly promoted to `https` when the `secure` field is set to `true`.\n- `https`: Endpoint will have `https` traffic, typically on a TCP connection.\n- `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. It will be automaticaly promoted to `wss` when the `secure` field is set to `true`.\n- `wss`: Endpoint will have `wss` traffic, typically on a TCP connection.\n- `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol.\n- `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol.\n\nDefault value is `http`", "type": "string", - "enum": [ - "http", - "https", - "ws", - "wss", - "tcp", - "udp" - ] + "enum": ["http", "https", "ws", "wss", "tcp", "udp"] }, "secure": { "description": "Describes whether the endpoint should be secured and protected by some authentication process. This requires a protocol of `https` or `wss`.", @@ -2711,14 +2248,10 @@ "type": "object", "oneOf": [ { - "required": [ - "uri" - ] + "required": ["uri"] }, { - "required": [ - "inlined" - ] + "required": ["inlined"] } ], "properties": { @@ -2726,9 +2259,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "attributes": { "description": "Map of implementation-dependant string-based free-form attributes.\n\nExamples of Che-specific attributes:\n- cookiesAuthEnabled: \"true\" / \"false\",\n- type: \"terminal\" / \"ide\" / \"ide-dev\",", @@ -2738,11 +2269,7 @@ "exposure": { "description": "Describes how the endpoint should be exposed on the network.\n- `public` means that the endpoint will be exposed on the public network, typically through a K8S ingress or an OpenShift route.\n- `internal` means that the endpoint will be exposed internally outside of the main workspace POD, typically by K8S services, to be consumed by other elements running on the same cloud internal network.\n- `none` means that the endpoint will not be exposed and will only be accessible inside the main workspace POD, on a local address.\n\nDefault value is `public`", "type": "string", - "enum": [ - "public", - "internal", - "none" - ] + "enum": ["public", "internal", "none"] }, "name": { "type": "string", @@ -2756,14 +2283,7 @@ "protocol": { "description": "Describes the application and transport protocols of the traffic that will go through this endpoint.\n- `http`: Endpoint will have `http` traffic, typically on a TCP connection. It will be automaticaly promoted to `https` when the `secure` field is set to `true`.\n- `https`: Endpoint will have `https` traffic, typically on a TCP connection.\n- `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. It will be automaticaly promoted to `wss` when the `secure` field is set to `true`.\n- `wss`: Endpoint will have `wss` traffic, typically on a TCP connection.\n- `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol.\n- `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol.\n\nDefault value is `http`", "type": "string", - "enum": [ - "http", - "https", - "ws", - "wss", - "tcp", - "udp" - ] + "enum": ["http", "https", "ws", "wss", "tcp", "udp"] }, "secure": { "description": "Describes whether the endpoint should be secured and protected by some authentication process. This requires a protocol of `https` or `wss`.", @@ -2851,9 +2371,7 @@ "kubernetes": { "description": "Reference to a Kubernetes CRD of type DevWorkspaceTemplate", "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "name": { "type": "string" @@ -2869,24 +2387,16 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "oneOf": [ { - "required": [ - "git" - ] + "required": ["git"] }, { - "required": [ - "github" - ] + "required": ["github"] }, { - "required": [ - "zip" - ] + "required": ["zip"] } ], "properties": { @@ -2993,24 +2503,16 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "oneOf": [ { - "required": [ - "git" - ] + "required": ["git"] }, { - "required": [ - "github" - ] + "required": ["github"] }, { - "required": [ - "zip" - ] + "required": ["zip"] } ], "properties": { @@ -3118,24 +2620,16 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "oneOf": [ { - "required": [ - "git" - ] + "required": ["git"] }, { - "required": [ - "github" - ] + "required": ["github"] }, { - "required": [ - "zip" - ] + "required": ["zip"] } ], "properties": { @@ -3151,9 +2645,7 @@ "git": { "description": "Project's Git source", "type": "object", - "required": [ - "remotes" - ], + "required": ["remotes"], "properties": { "checkoutFrom": { "description": "Defines from what the project should be checked out. Required if there are more than one remote configured", @@ -3183,9 +2675,7 @@ "github": { "description": "Project's GitHub source", "type": "object", - "required": [ - "remotes" - ], + "required": ["remotes"], "properties": { "checkoutFrom": { "description": "Defines from what the project should be checked out. Required if there are more than one remote configured", @@ -3250,24 +2740,16 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "oneOf": [ { - "required": [ - "git" - ] + "required": ["git"] }, { - "required": [ - "github" - ] + "required": ["github"] }, { - "required": [ - "zip" - ] + "required": ["zip"] } ], "properties": { @@ -3283,9 +2765,7 @@ "git": { "description": "Project's Git source", "type": "object", - "required": [ - "remotes" - ], + "required": ["remotes"], "properties": { "checkoutFrom": { "description": "Defines from what the project should be checked out. Required if there are more than one remote configured", @@ -3315,9 +2795,7 @@ "github": { "description": "Project's GitHub source", "type": "object", - "required": [ - "remotes" - ], + "required": ["remotes"], "properties": { "checkoutFrom": { "description": "Defines from what the project should be checked out. Required if there are more than one remote configured", @@ -3371,4 +2849,4 @@ } }, "additionalProperties": false -} \ No newline at end of file +} diff --git a/packages/dashboard-backend/src/devfileSchemas/2.1.0/devfile.json b/packages/dashboard-backend/src/devfileSchemas/2.1.0/devfile.json index 9c7c8beac..bc55619d3 100644 --- a/packages/dashboard-backend/src/devfileSchemas/2.1.0/devfile.json +++ b/packages/dashboard-backend/src/devfileSchemas/2.1.0/devfile.json @@ -2,9 +2,7 @@ "description": "Devfile describes the structure of a cloud-native devworkspace and development environment.", "type": "object", "title": "Devfile schema - Version 2.1.0", - "required": [ - "schemaVersion" - ], + "required": ["schemaVersion"], "properties": { "attributes": { "description": "Map of implementation-dependant free-form YAML attributes.", @@ -16,33 +14,23 @@ "type": "array", "items": { "type": "object", - "required": [ - "id" - ], + "required": ["id"], "oneOf": [ { - "required": [ - "exec" - ] + "required": ["exec"] }, { - "required": [ - "apply" - ] + "required": ["apply"] }, { - "required": [ - "composite" - ] + "required": ["composite"] } ], "properties": { "apply": { "description": "Command that consists in applying a given component definition, typically bound to a devworkspace event.\n\nFor example, when an `apply` command is bound to a `preStart` event, and references a `container` component, it will start the container as a K8S initContainer in the devworkspace POD, unless the component has its `dedicatedPod` field set to `true`.\n\nWhen no `apply` command exist for a given component, it is assumed the component will be applied at devworkspace start by default.", "type": "object", - "required": [ - "component" - ], + "required": ["component"], "properties": { "component": { "description": "Describes component that will be applied", @@ -51,9 +39,7 @@ "group": { "description": "Defines the group this command is part of", "type": "object", - "required": [ - "kind" - ], + "required": ["kind"], "properties": { "isDefault": { "description": "Identifies the default command for a given group kind", @@ -62,12 +48,7 @@ "kind": { "description": "Kind of group the command is part of", "type": "string", - "enum": [ - "build", - "run", - "test", - "debug" - ] + "enum": ["build", "run", "test", "debug"] } }, "additionalProperties": false @@ -98,9 +79,7 @@ "group": { "description": "Defines the group this command is part of", "type": "object", - "required": [ - "kind" - ], + "required": ["kind"], "properties": { "isDefault": { "description": "Identifies the default command for a given group kind", @@ -109,12 +88,7 @@ "kind": { "description": "Kind of group the command is part of", "type": "string", - "enum": [ - "build", - "run", - "test", - "debug" - ] + "enum": ["build", "run", "test", "debug"] } }, "additionalProperties": false @@ -133,10 +107,7 @@ "exec": { "description": "CLI Command executed in an existing component container", "type": "object", - "required": [ - "commandLine", - "component" - ], + "required": ["commandLine", "component"], "properties": { "commandLine": { "description": "The actual command-line string\n\nSpecial variables that can be used:\n\n - `$PROJECTS_ROOT`: A path where projects sources are mounted as defined by container component's sourceMapping.\n\n - `$PROJECT_SOURCE`: A path to a project source ($PROJECTS_ROOT/\u003cproject-name\u003e). If there are multiple projects, this will point to the directory of the first one.", @@ -151,10 +122,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name", - "value" - ], + "required": ["name", "value"], "properties": { "name": { "type": "string" @@ -169,9 +137,7 @@ "group": { "description": "Defines the group this command is part of", "type": "object", - "required": [ - "kind" - ], + "required": ["kind"], "properties": { "isDefault": { "description": "Identifies the default command for a given group kind", @@ -180,12 +146,7 @@ "kind": { "description": "Kind of group the command is part of", "type": "string", - "enum": [ - "build", - "run", - "test", - "debug" - ] + "enum": ["build", "run", "test", "debug"] } }, "additionalProperties": false @@ -220,29 +181,19 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "oneOf": [ { - "required": [ - "container" - ] + "required": ["container"] }, { - "required": [ - "kubernetes" - ] + "required": ["kubernetes"] }, { - "required": [ - "openshift" - ] + "required": ["openshift"] }, { - "required": [ - "volume" - ] + "required": ["volume"] } ], "properties": { @@ -254,9 +205,7 @@ "container": { "description": "Allows adding and configuring devworkspace-related containers", "type": "object", - "required": [ - "image" - ], + "required": ["image"], "properties": { "args": { "description": "The arguments to supply to the command running the dockerimage component. The arguments are supplied either to the default command provided in the image or to the overridden command.\n\nDefaults to an empty array, meaning use whatever is defined in the image.", @@ -286,10 +235,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name", - "targetPort" - ], + "required": ["name", "targetPort"], "properties": { "attributes": { "description": "Map of implementation-dependant string-based free-form attributes.\n\nExamples of Che-specific attributes:\n- cookiesAuthEnabled: \"true\" / \"false\",\n- type: \"terminal\" / \"ide\" / \"ide-dev\",", @@ -300,11 +246,7 @@ "description": "Describes how the endpoint should be exposed on the network.\n- `public` means that the endpoint will be exposed on the public network, typically through a K8S ingress or an OpenShift route.\n- `internal` means that the endpoint will be exposed internally outside of the main devworkspace POD, typically by K8S services, to be consumed by other elements running on the same cloud internal network.\n- `none` means that the endpoint will not be exposed and will only be accessible inside the main devworkspace POD, on a local address.\n\nDefault value is `public`", "type": "string", "default": "public", - "enum": [ - "public", - "internal", - "none" - ] + "enum": ["public", "internal", "none"] }, "name": { "type": "string", @@ -319,14 +261,7 @@ "description": "Describes the application and transport protocols of the traffic that will go through this endpoint.\n- `http`: Endpoint will have `http` traffic, typically on a TCP connection. It will be automaticaly promoted to `https` when the `secure` field is set to `true`.\n- `https`: Endpoint will have `https` traffic, typically on a TCP connection.\n- `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. It will be automaticaly promoted to `wss` when the `secure` field is set to `true`.\n- `wss`: Endpoint will have `wss` traffic, typically on a TCP connection.\n- `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol.\n- `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol.\n\nDefault value is `http`", "type": "string", "default": "http", - "enum": [ - "http", - "https", - "ws", - "wss", - "tcp", - "udp" - ] + "enum": ["http", "https", "ws", "wss", "tcp", "udp"] }, "secure": { "description": "Describes whether the endpoint should be secured and protected by some authentication process. This requires a protocol of `https` or `wss`.", @@ -344,10 +279,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name", - "value" - ], + "required": ["name", "value"], "properties": { "name": { "type": "string" @@ -383,9 +315,7 @@ "items": { "description": "Volume that should be mounted to a component container", "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "name": { "description": "The volume mount name is the name of an existing `Volume` component. If several containers mount the same volume name then they will reuse the same volume and will be able to access to the same files.", @@ -409,14 +339,10 @@ "type": "object", "oneOf": [ { - "required": [ - "uri" - ] + "required": ["uri"] }, { - "required": [ - "inlined" - ] + "required": ["inlined"] } ], "properties": { @@ -424,10 +350,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name", - "targetPort" - ], + "required": ["name", "targetPort"], "properties": { "attributes": { "description": "Map of implementation-dependant string-based free-form attributes.\n\nExamples of Che-specific attributes:\n- cookiesAuthEnabled: \"true\" / \"false\",\n- type: \"terminal\" / \"ide\" / \"ide-dev\",", @@ -438,11 +361,7 @@ "description": "Describes how the endpoint should be exposed on the network.\n- `public` means that the endpoint will be exposed on the public network, typically through a K8S ingress or an OpenShift route.\n- `internal` means that the endpoint will be exposed internally outside of the main devworkspace POD, typically by K8S services, to be consumed by other elements running on the same cloud internal network.\n- `none` means that the endpoint will not be exposed and will only be accessible inside the main devworkspace POD, on a local address.\n\nDefault value is `public`", "type": "string", "default": "public", - "enum": [ - "public", - "internal", - "none" - ] + "enum": ["public", "internal", "none"] }, "name": { "type": "string", @@ -457,14 +376,7 @@ "description": "Describes the application and transport protocols of the traffic that will go through this endpoint.\n- `http`: Endpoint will have `http` traffic, typically on a TCP connection. It will be automaticaly promoted to `https` when the `secure` field is set to `true`.\n- `https`: Endpoint will have `https` traffic, typically on a TCP connection.\n- `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. It will be automaticaly promoted to `wss` when the `secure` field is set to `true`.\n- `wss`: Endpoint will have `wss` traffic, typically on a TCP connection.\n- `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol.\n- `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol.\n\nDefault value is `http`", "type": "string", "default": "http", - "enum": [ - "http", - "https", - "ws", - "wss", - "tcp", - "udp" - ] + "enum": ["http", "https", "ws", "wss", "tcp", "udp"] }, "secure": { "description": "Describes whether the endpoint should be secured and protected by some authentication process. This requires a protocol of `https` or `wss`.", @@ -499,14 +411,10 @@ "type": "object", "oneOf": [ { - "required": [ - "uri" - ] + "required": ["uri"] }, { - "required": [ - "inlined" - ] + "required": ["inlined"] } ], "properties": { @@ -514,10 +422,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name", - "targetPort" - ], + "required": ["name", "targetPort"], "properties": { "attributes": { "description": "Map of implementation-dependant string-based free-form attributes.\n\nExamples of Che-specific attributes:\n- cookiesAuthEnabled: \"true\" / \"false\",\n- type: \"terminal\" / \"ide\" / \"ide-dev\",", @@ -528,11 +433,7 @@ "description": "Describes how the endpoint should be exposed on the network.\n- `public` means that the endpoint will be exposed on the public network, typically through a K8S ingress or an OpenShift route.\n- `internal` means that the endpoint will be exposed internally outside of the main devworkspace POD, typically by K8S services, to be consumed by other elements running on the same cloud internal network.\n- `none` means that the endpoint will not be exposed and will only be accessible inside the main devworkspace POD, on a local address.\n\nDefault value is `public`", "type": "string", "default": "public", - "enum": [ - "public", - "internal", - "none" - ] + "enum": ["public", "internal", "none"] }, "name": { "type": "string", @@ -547,14 +448,7 @@ "description": "Describes the application and transport protocols of the traffic that will go through this endpoint.\n- `http`: Endpoint will have `http` traffic, typically on a TCP connection. It will be automaticaly promoted to `https` when the `secure` field is set to `true`.\n- `https`: Endpoint will have `https` traffic, typically on a TCP connection.\n- `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. It will be automaticaly promoted to `wss` when the `secure` field is set to `true`.\n- `wss`: Endpoint will have `wss` traffic, typically on a TCP connection.\n- `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol.\n- `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol.\n\nDefault value is `http`", "type": "string", "default": "http", - "enum": [ - "http", - "https", - "ws", - "wss", - "tcp", - "udp" - ] + "enum": ["http", "https", "ws", "wss", "tcp", "udp"] }, "secure": { "description": "Describes whether the endpoint should be secured and protected by some authentication process. This requires a protocol of `https` or `wss`.", @@ -693,19 +587,13 @@ "type": "object", "oneOf": [ { - "required": [ - "uri" - ] + "required": ["uri"] }, { - "required": [ - "id" - ] + "required": ["id"] }, { - "required": [ - "kubernetes" - ] + "required": ["kubernetes"] } ], "properties": { @@ -719,24 +607,16 @@ "type": "array", "items": { "type": "object", - "required": [ - "id" - ], + "required": ["id"], "oneOf": [ { - "required": [ - "exec" - ] + "required": ["exec"] }, { - "required": [ - "apply" - ] + "required": ["apply"] }, { - "required": [ - "composite" - ] + "required": ["composite"] } ], "properties": { @@ -759,12 +639,7 @@ "kind": { "description": "Kind of group the command is part of", "type": "string", - "enum": [ - "build", - "run", - "test", - "debug" - ] + "enum": ["build", "run", "test", "debug"] } }, "additionalProperties": false @@ -803,12 +678,7 @@ "kind": { "description": "Kind of group the command is part of", "type": "string", - "enum": [ - "build", - "run", - "test", - "debug" - ] + "enum": ["build", "run", "test", "debug"] } }, "additionalProperties": false @@ -841,9 +711,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "name": { "type": "string" @@ -866,12 +734,7 @@ "kind": { "description": "Kind of group the command is part of", "type": "string", - "enum": [ - "build", - "run", - "test", - "debug" - ] + "enum": ["build", "run", "test", "debug"] } }, "additionalProperties": false @@ -906,29 +769,19 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "oneOf": [ { - "required": [ - "container" - ] + "required": ["container"] }, { - "required": [ - "kubernetes" - ] + "required": ["kubernetes"] }, { - "required": [ - "openshift" - ] + "required": ["openshift"] }, { - "required": [ - "volume" - ] + "required": ["volume"] } ], "properties": { @@ -969,9 +822,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "attributes": { "description": "Map of implementation-dependant string-based free-form attributes.\n\nExamples of Che-specific attributes:\n- cookiesAuthEnabled: \"true\" / \"false\",\n- type: \"terminal\" / \"ide\" / \"ide-dev\",", @@ -981,11 +832,7 @@ "exposure": { "description": "Describes how the endpoint should be exposed on the network.\n- `public` means that the endpoint will be exposed on the public network, typically through a K8S ingress or an OpenShift route.\n- `internal` means that the endpoint will be exposed internally outside of the main devworkspace POD, typically by K8S services, to be consumed by other elements running on the same cloud internal network.\n- `none` means that the endpoint will not be exposed and will only be accessible inside the main devworkspace POD, on a local address.\n\nDefault value is `public`", "type": "string", - "enum": [ - "public", - "internal", - "none" - ] + "enum": ["public", "internal", "none"] }, "name": { "type": "string", @@ -999,14 +846,7 @@ "protocol": { "description": "Describes the application and transport protocols of the traffic that will go through this endpoint.\n- `http`: Endpoint will have `http` traffic, typically on a TCP connection. It will be automaticaly promoted to `https` when the `secure` field is set to `true`.\n- `https`: Endpoint will have `https` traffic, typically on a TCP connection.\n- `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. It will be automaticaly promoted to `wss` when the `secure` field is set to `true`.\n- `wss`: Endpoint will have `wss` traffic, typically on a TCP connection.\n- `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol.\n- `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol.\n\nDefault value is `http`", "type": "string", - "enum": [ - "http", - "https", - "ws", - "wss", - "tcp", - "udp" - ] + "enum": ["http", "https", "ws", "wss", "tcp", "udp"] }, "secure": { "description": "Describes whether the endpoint should be secured and protected by some authentication process. This requires a protocol of `https` or `wss`.", @@ -1024,9 +864,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "name": { "type": "string" @@ -1061,9 +899,7 @@ "items": { "description": "Volume that should be mounted to a component container", "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "name": { "description": "The volume mount name is the name of an existing `Volume` component. If several containers mount the same volume name then they will reuse the same volume and will be able to access to the same files.", @@ -1087,14 +923,10 @@ "type": "object", "oneOf": [ { - "required": [ - "uri" - ] + "required": ["uri"] }, { - "required": [ - "inlined" - ] + "required": ["inlined"] } ], "properties": { @@ -1102,9 +934,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "attributes": { "description": "Map of implementation-dependant string-based free-form attributes.\n\nExamples of Che-specific attributes:\n- cookiesAuthEnabled: \"true\" / \"false\",\n- type: \"terminal\" / \"ide\" / \"ide-dev\",", @@ -1114,11 +944,7 @@ "exposure": { "description": "Describes how the endpoint should be exposed on the network.\n- `public` means that the endpoint will be exposed on the public network, typically through a K8S ingress or an OpenShift route.\n- `internal` means that the endpoint will be exposed internally outside of the main devworkspace POD, typically by K8S services, to be consumed by other elements running on the same cloud internal network.\n- `none` means that the endpoint will not be exposed and will only be accessible inside the main devworkspace POD, on a local address.\n\nDefault value is `public`", "type": "string", - "enum": [ - "public", - "internal", - "none" - ] + "enum": ["public", "internal", "none"] }, "name": { "type": "string", @@ -1132,14 +958,7 @@ "protocol": { "description": "Describes the application and transport protocols of the traffic that will go through this endpoint.\n- `http`: Endpoint will have `http` traffic, typically on a TCP connection. It will be automaticaly promoted to `https` when the `secure` field is set to `true`.\n- `https`: Endpoint will have `https` traffic, typically on a TCP connection.\n- `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. It will be automaticaly promoted to `wss` when the `secure` field is set to `true`.\n- `wss`: Endpoint will have `wss` traffic, typically on a TCP connection.\n- `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol.\n- `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol.\n\nDefault value is `http`", "type": "string", - "enum": [ - "http", - "https", - "ws", - "wss", - "tcp", - "udp" - ] + "enum": ["http", "https", "ws", "wss", "tcp", "udp"] }, "secure": { "description": "Describes whether the endpoint should be secured and protected by some authentication process. This requires a protocol of `https` or `wss`.", @@ -1174,14 +993,10 @@ "type": "object", "oneOf": [ { - "required": [ - "uri" - ] + "required": ["uri"] }, { - "required": [ - "inlined" - ] + "required": ["inlined"] } ], "properties": { @@ -1189,9 +1004,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "attributes": { "description": "Map of implementation-dependant string-based free-form attributes.\n\nExamples of Che-specific attributes:\n- cookiesAuthEnabled: \"true\" / \"false\",\n- type: \"terminal\" / \"ide\" / \"ide-dev\",", @@ -1201,11 +1014,7 @@ "exposure": { "description": "Describes how the endpoint should be exposed on the network.\n- `public` means that the endpoint will be exposed on the public network, typically through a K8S ingress or an OpenShift route.\n- `internal` means that the endpoint will be exposed internally outside of the main devworkspace POD, typically by K8S services, to be consumed by other elements running on the same cloud internal network.\n- `none` means that the endpoint will not be exposed and will only be accessible inside the main devworkspace POD, on a local address.\n\nDefault value is `public`", "type": "string", - "enum": [ - "public", - "internal", - "none" - ] + "enum": ["public", "internal", "none"] }, "name": { "type": "string", @@ -1219,14 +1028,7 @@ "protocol": { "description": "Describes the application and transport protocols of the traffic that will go through this endpoint.\n- `http`: Endpoint will have `http` traffic, typically on a TCP connection. It will be automaticaly promoted to `https` when the `secure` field is set to `true`.\n- `https`: Endpoint will have `https` traffic, typically on a TCP connection.\n- `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. It will be automaticaly promoted to `wss` when the `secure` field is set to `true`.\n- `wss`: Endpoint will have `wss` traffic, typically on a TCP connection.\n- `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol.\n- `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol.\n\nDefault value is `http`", "type": "string", - "enum": [ - "http", - "https", - "ws", - "wss", - "tcp", - "udp" - ] + "enum": ["http", "https", "ws", "wss", "tcp", "udp"] }, "secure": { "description": "Describes whether the endpoint should be secured and protected by some authentication process. This requires a protocol of `https` or `wss`.", @@ -1276,9 +1078,7 @@ "kubernetes": { "description": "Reference to a Kubernetes CRD of type DevWorkspaceTemplate", "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "name": { "type": "string" @@ -1294,19 +1094,13 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "oneOf": [ { - "required": [ - "git" - ] + "required": ["git"] }, { - "required": [ - "zip" - ] + "required": ["zip"] } ], "properties": { @@ -1378,19 +1172,13 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "oneOf": [ { - "required": [ - "git" - ] + "required": ["git"] }, { - "required": [ - "zip" - ] + "required": ["zip"] } ], "properties": { @@ -1476,19 +1264,13 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "oneOf": [ { - "required": [ - "git" - ] + "required": ["git"] }, { - "required": [ - "zip" - ] + "required": ["zip"] } ], "properties": { @@ -1504,9 +1286,7 @@ "git": { "description": "Project's Git source", "type": "object", - "required": [ - "remotes" - ], + "required": ["remotes"], "properties": { "checkoutFrom": { "description": "Defines from what the project should be checked out. Required if there are more than one remote configured", @@ -1564,19 +1344,13 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "oneOf": [ { - "required": [ - "git" - ] + "required": ["git"] }, { - "required": [ - "zip" - ] + "required": ["zip"] } ], "properties": { @@ -1592,9 +1366,7 @@ "git": { "description": "Project's Git source", "type": "object", - "required": [ - "remotes" - ], + "required": ["remotes"], "properties": { "checkoutFrom": { "description": "Defines from what the project should be checked out. Required if there are more than one remote configured", diff --git a/packages/dashboard-backend/src/devfileSchemas/2.2.0/devfile.json b/packages/dashboard-backend/src/devfileSchemas/2.2.0/devfile.json index 4c6f35411..ed4afd332 100644 --- a/packages/dashboard-backend/src/devfileSchemas/2.2.0/devfile.json +++ b/packages/dashboard-backend/src/devfileSchemas/2.2.0/devfile.json @@ -2,9 +2,7 @@ "description": "Devfile describes the structure of a cloud-native devworkspace and development environment.\n\nIDE-targeted variants of the schemas provide the following difference compared to the main schemas:\n- They contain additional non-standard `markdownDescription` attributes that are used by IDEs such a VSCode\nto provide markdown-rendered documentation hovers. \n- They don't contain `default` attributes, since this triggers unwanted addition of defaulted fields during completion in IDEs.", "type": "object", "title": "Devfile schema - Version 2.2.0 - IDE-targeted variant", - "required": [ - "schemaVersion" - ], + "required": ["schemaVersion"], "properties": { "attributes": { "description": "Map of implementation-dependant free-form YAML attributes.", @@ -17,33 +15,23 @@ "type": "array", "items": { "type": "object", - "required": [ - "id" - ], + "required": ["id"], "oneOf": [ { - "required": [ - "exec" - ] + "required": ["exec"] }, { - "required": [ - "apply" - ] + "required": ["apply"] }, { - "required": [ - "composite" - ] + "required": ["composite"] } ], "properties": { "apply": { "description": "Command that consists in applying a given component definition, typically bound to a devworkspace event.\n\nFor example, when an `apply` command is bound to a `preStart` event, and references a `container` component, it will start the container as a K8S initContainer in the devworkspace POD, unless the component has its `dedicatedPod` field set to `true`.\n\nWhen no `apply` command exist for a given component, it is assumed the component will be applied at devworkspace start by default, unless `deployByDefault` for that component is set to false.", "type": "object", - "required": [ - "component" - ], + "required": ["component"], "properties": { "component": { "description": "Describes component that will be applied", @@ -53,9 +41,7 @@ "group": { "description": "Defines the group this command is part of", "type": "object", - "required": [ - "kind" - ], + "required": ["kind"], "properties": { "isDefault": { "description": "Identifies the default command for a given group kind", @@ -65,13 +51,7 @@ "kind": { "description": "Kind of group the command is part of", "type": "string", - "enum": [ - "build", - "run", - "test", - "debug", - "deploy" - ], + "enum": ["build", "run", "test", "debug", "deploy"], "markdownDescription": "Kind of group the command is part of" } }, @@ -108,9 +88,7 @@ "group": { "description": "Defines the group this command is part of", "type": "object", - "required": [ - "kind" - ], + "required": ["kind"], "properties": { "isDefault": { "description": "Identifies the default command for a given group kind", @@ -120,13 +98,7 @@ "kind": { "description": "Kind of group the command is part of", "type": "string", - "enum": [ - "build", - "run", - "test", - "debug", - "deploy" - ], + "enum": ["build", "run", "test", "debug", "deploy"], "markdownDescription": "Kind of group the command is part of" } }, @@ -150,10 +122,7 @@ "exec": { "description": "CLI Command executed in an existing component container", "type": "object", - "required": [ - "commandLine", - "component" - ], + "required": ["commandLine", "component"], "properties": { "commandLine": { "description": "The actual command-line string\n\nSpecial variables that can be used:\n\n - `$PROJECTS_ROOT`: A path where projects sources are mounted as defined by container component's sourceMapping.\n\n - `$PROJECT_SOURCE`: A path to a project source ($PROJECTS_ROOT/\u003cproject-name\u003e). If there are multiple projects, this will point to the directory of the first one.", @@ -170,10 +139,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name", - "value" - ], + "required": ["name", "value"], "properties": { "name": { "type": "string" @@ -189,9 +155,7 @@ "group": { "description": "Defines the group this command is part of", "type": "object", - "required": [ - "kind" - ], + "required": ["kind"], "properties": { "isDefault": { "description": "Identifies the default command for a given group kind", @@ -201,13 +165,7 @@ "kind": { "description": "Kind of group the command is part of", "type": "string", - "enum": [ - "build", - "run", - "test", - "debug", - "deploy" - ], + "enum": ["build", "run", "test", "debug", "deploy"], "markdownDescription": "Kind of group the command is part of" } }, @@ -250,34 +208,22 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "oneOf": [ { - "required": [ - "container" - ] + "required": ["container"] }, { - "required": [ - "kubernetes" - ] + "required": ["kubernetes"] }, { - "required": [ - "openshift" - ] + "required": ["openshift"] }, { - "required": [ - "volume" - ] + "required": ["volume"] }, { - "required": [ - "image" - ] + "required": ["image"] } ], "properties": { @@ -290,9 +236,7 @@ "container": { "description": "Allows adding and configuring devworkspace-related containers", "type": "object", - "required": [ - "image" - ], + "required": ["image"], "properties": { "annotation": { "description": "Annotations that should be added to specific resources for this container", @@ -349,10 +293,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name", - "targetPort" - ], + "required": ["name", "targetPort"], "properties": { "annotation": { "description": "Annotations to be added to Kubernetes Ingress or Openshift Route", @@ -371,11 +312,7 @@ "exposure": { "description": "Describes how the endpoint should be exposed on the network.\n- `public` means that the endpoint will be exposed on the public network, typically through a K8S ingress or an OpenShift route.\n- `internal` means that the endpoint will be exposed internally outside of the main devworkspace POD, typically by K8S services, to be consumed by other elements running on the same cloud internal network.\n- `none` means that the endpoint will not be exposed and will only be accessible inside the main devworkspace POD, on a local address.\n\nDefault value is `public`", "type": "string", - "enum": [ - "public", - "internal", - "none" - ], + "enum": ["public", "internal", "none"], "markdownDescription": "Describes how the endpoint should be exposed on the network.\n- `public` means that the endpoint will be exposed on the public network, typically through a K8S ingress or an OpenShift route.\n- `internal` means that the endpoint will be exposed internally outside of the main devworkspace POD, typically by K8S services, to be consumed by other elements running on the same cloud internal network.\n- `none` means that the endpoint will not be exposed and will only be accessible inside the main devworkspace POD, on a local address.\n\nDefault value is `public`" }, "name": { @@ -391,14 +328,7 @@ "protocol": { "description": "Describes the application and transport protocols of the traffic that will go through this endpoint.\n- `http`: Endpoint will have `http` traffic, typically on a TCP connection. It will be automaticaly promoted to `https` when the `secure` field is set to `true`.\n- `https`: Endpoint will have `https` traffic, typically on a TCP connection.\n- `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. It will be automaticaly promoted to `wss` when the `secure` field is set to `true`.\n- `wss`: Endpoint will have `wss` traffic, typically on a TCP connection.\n- `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol.\n- `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol.\n\nDefault value is `http`", "type": "string", - "enum": [ - "http", - "https", - "ws", - "wss", - "tcp", - "udp" - ], + "enum": ["http", "https", "ws", "wss", "tcp", "udp"], "markdownDescription": "Describes the application and transport protocols of the traffic that will go through this endpoint.\n- `http`: Endpoint will have `http` traffic, typically on a TCP connection. It will be automaticaly promoted to `https` when the `secure` field is set to `true`.\n- `https`: Endpoint will have `https` traffic, typically on a TCP connection.\n- `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. It will be automaticaly promoted to `wss` when the `secure` field is set to `true`.\n- `wss`: Endpoint will have `wss` traffic, typically on a TCP connection.\n- `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol.\n- `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol.\n\nDefault value is `http`" }, "secure": { @@ -420,10 +350,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name", - "value" - ], + "required": ["name", "value"], "properties": { "name": { "type": "string" @@ -461,9 +388,7 @@ "items": { "description": "Volume that should be mounted to a component container", "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "name": { "description": "The volume mount name is the name of an existing `Volume` component. If several containers mount the same volume name then they will reuse the same volume and will be able to access to the same files.", @@ -490,14 +415,10 @@ "image": { "description": "Allows specifying the definition of an image for outer loop builds", "type": "object", - "required": [ - "imageName" - ], + "required": ["imageName"], "oneOf": [ { - "required": [ - "dockerfile" - ] + "required": ["dockerfile"] } ], "properties": { @@ -511,19 +432,13 @@ "type": "object", "oneOf": [ { - "required": [ - "uri" - ] + "required": ["uri"] }, { - "required": [ - "devfileRegistry" - ] + "required": ["devfileRegistry"] }, { - "required": [ - "git" - ] + "required": ["git"] } ], "properties": { @@ -543,9 +458,7 @@ "devfileRegistry": { "description": "Dockerfile's Devfile Registry source", "type": "object", - "required": [ - "id" - ], + "required": ["id"], "properties": { "id": { "description": "Id in a devfile registry that contains a Dockerfile. The src in the OCI registry required for the Dockerfile build will be downloaded for building the image.", @@ -564,9 +477,7 @@ "git": { "description": "Dockerfile's Git source", "type": "object", - "required": [ - "remotes" - ], + "required": ["remotes"], "properties": { "checkoutFrom": { "description": "Defines from what the project should be checked out. Required if there are more than one remote configured", @@ -631,14 +542,10 @@ "type": "object", "oneOf": [ { - "required": [ - "uri" - ] + "required": ["uri"] }, { - "required": [ - "inlined" - ] + "required": ["inlined"] } ], "properties": { @@ -651,10 +558,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name", - "targetPort" - ], + "required": ["name", "targetPort"], "properties": { "annotation": { "description": "Annotations to be added to Kubernetes Ingress or Openshift Route", @@ -673,11 +577,7 @@ "exposure": { "description": "Describes how the endpoint should be exposed on the network.\n- `public` means that the endpoint will be exposed on the public network, typically through a K8S ingress or an OpenShift route.\n- `internal` means that the endpoint will be exposed internally outside of the main devworkspace POD, typically by K8S services, to be consumed by other elements running on the same cloud internal network.\n- `none` means that the endpoint will not be exposed and will only be accessible inside the main devworkspace POD, on a local address.\n\nDefault value is `public`", "type": "string", - "enum": [ - "public", - "internal", - "none" - ], + "enum": ["public", "internal", "none"], "markdownDescription": "Describes how the endpoint should be exposed on the network.\n- `public` means that the endpoint will be exposed on the public network, typically through a K8S ingress or an OpenShift route.\n- `internal` means that the endpoint will be exposed internally outside of the main devworkspace POD, typically by K8S services, to be consumed by other elements running on the same cloud internal network.\n- `none` means that the endpoint will not be exposed and will only be accessible inside the main devworkspace POD, on a local address.\n\nDefault value is `public`" }, "name": { @@ -693,14 +593,7 @@ "protocol": { "description": "Describes the application and transport protocols of the traffic that will go through this endpoint.\n- `http`: Endpoint will have `http` traffic, typically on a TCP connection. It will be automaticaly promoted to `https` when the `secure` field is set to `true`.\n- `https`: Endpoint will have `https` traffic, typically on a TCP connection.\n- `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. It will be automaticaly promoted to `wss` when the `secure` field is set to `true`.\n- `wss`: Endpoint will have `wss` traffic, typically on a TCP connection.\n- `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol.\n- `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol.\n\nDefault value is `http`", "type": "string", - "enum": [ - "http", - "https", - "ws", - "wss", - "tcp", - "udp" - ], + "enum": ["http", "https", "ws", "wss", "tcp", "udp"], "markdownDescription": "Describes the application and transport protocols of the traffic that will go through this endpoint.\n- `http`: Endpoint will have `http` traffic, typically on a TCP connection. It will be automaticaly promoted to `https` when the `secure` field is set to `true`.\n- `https`: Endpoint will have `https` traffic, typically on a TCP connection.\n- `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. It will be automaticaly promoted to `wss` when the `secure` field is set to `true`.\n- `wss`: Endpoint will have `wss` traffic, typically on a TCP connection.\n- `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol.\n- `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol.\n\nDefault value is `http`" }, "secure": { @@ -743,14 +636,10 @@ "type": "object", "oneOf": [ { - "required": [ - "uri" - ] + "required": ["uri"] }, { - "required": [ - "inlined" - ] + "required": ["inlined"] } ], "properties": { @@ -763,10 +652,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name", - "targetPort" - ], + "required": ["name", "targetPort"], "properties": { "annotation": { "description": "Annotations to be added to Kubernetes Ingress or Openshift Route", @@ -785,11 +671,7 @@ "exposure": { "description": "Describes how the endpoint should be exposed on the network.\n- `public` means that the endpoint will be exposed on the public network, typically through a K8S ingress or an OpenShift route.\n- `internal` means that the endpoint will be exposed internally outside of the main devworkspace POD, typically by K8S services, to be consumed by other elements running on the same cloud internal network.\n- `none` means that the endpoint will not be exposed and will only be accessible inside the main devworkspace POD, on a local address.\n\nDefault value is `public`", "type": "string", - "enum": [ - "public", - "internal", - "none" - ], + "enum": ["public", "internal", "none"], "markdownDescription": "Describes how the endpoint should be exposed on the network.\n- `public` means that the endpoint will be exposed on the public network, typically through a K8S ingress or an OpenShift route.\n- `internal` means that the endpoint will be exposed internally outside of the main devworkspace POD, typically by K8S services, to be consumed by other elements running on the same cloud internal network.\n- `none` means that the endpoint will not be exposed and will only be accessible inside the main devworkspace POD, on a local address.\n\nDefault value is `public`" }, "name": { @@ -805,14 +687,7 @@ "protocol": { "description": "Describes the application and transport protocols of the traffic that will go through this endpoint.\n- `http`: Endpoint will have `http` traffic, typically on a TCP connection. It will be automaticaly promoted to `https` when the `secure` field is set to `true`.\n- `https`: Endpoint will have `https` traffic, typically on a TCP connection.\n- `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. It will be automaticaly promoted to `wss` when the `secure` field is set to `true`.\n- `wss`: Endpoint will have `wss` traffic, typically on a TCP connection.\n- `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol.\n- `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol.\n\nDefault value is `http`", "type": "string", - "enum": [ - "http", - "https", - "ws", - "wss", - "tcp", - "udp" - ], + "enum": ["http", "https", "ws", "wss", "tcp", "udp"], "markdownDescription": "Describes the application and transport protocols of the traffic that will go through this endpoint.\n- `http`: Endpoint will have `http` traffic, typically on a TCP connection. It will be automaticaly promoted to `https` when the `secure` field is set to `true`.\n- `https`: Endpoint will have `https` traffic, typically on a TCP connection.\n- `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. It will be automaticaly promoted to `wss` when the `secure` field is set to `true`.\n- `wss`: Endpoint will have `wss` traffic, typically on a TCP connection.\n- `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol.\n- `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol.\n\nDefault value is `http`" }, "secure": { @@ -917,12 +792,7 @@ "items": { "description": "Architecture describes the architecture type", "type": "string", - "enum": [ - "amd64", - "arm64", - "ppc64le", - "s390x" - ], + "enum": ["amd64", "arm64", "ppc64le", "s390x"], "markdownDescription": "Architecture describes the architecture type" }, "markdownDescription": "Optional list of processor architectures that the devfile supports, empty list suggests that the devfile can be used on any architecture" @@ -1006,19 +876,13 @@ "type": "object", "oneOf": [ { - "required": [ - "uri" - ] + "required": ["uri"] }, { - "required": [ - "id" - ] + "required": ["id"] }, { - "required": [ - "kubernetes" - ] + "required": ["kubernetes"] } ], "properties": { @@ -1033,24 +897,16 @@ "type": "array", "items": { "type": "object", - "required": [ - "id" - ], + "required": ["id"], "oneOf": [ { - "required": [ - "exec" - ] + "required": ["exec"] }, { - "required": [ - "apply" - ] + "required": ["apply"] }, { - "required": [ - "composite" - ] + "required": ["composite"] } ], "properties": { @@ -1075,13 +931,7 @@ "kind": { "description": "Kind of group the command is part of", "type": "string", - "enum": [ - "build", - "run", - "test", - "debug", - "deploy" - ], + "enum": ["build", "run", "test", "debug", "deploy"], "markdownDescription": "Kind of group the command is part of" } }, @@ -1127,13 +977,7 @@ "kind": { "description": "Kind of group the command is part of", "type": "string", - "enum": [ - "build", - "run", - "test", - "debug", - "deploy" - ], + "enum": ["build", "run", "test", "debug", "deploy"], "markdownDescription": "Kind of group the command is part of" } }, @@ -1173,9 +1017,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "name": { "type": "string" @@ -1200,13 +1042,7 @@ "kind": { "description": "Kind of group the command is part of", "type": "string", - "enum": [ - "build", - "run", - "test", - "debug", - "deploy" - ], + "enum": ["build", "run", "test", "debug", "deploy"], "markdownDescription": "Kind of group the command is part of" } }, @@ -1249,34 +1085,22 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "oneOf": [ { - "required": [ - "container" - ] + "required": ["container"] }, { - "required": [ - "kubernetes" - ] + "required": ["kubernetes"] }, { - "required": [ - "openshift" - ] + "required": ["openshift"] }, { - "required": [ - "volume" - ] + "required": ["volume"] }, { - "required": [ - "image" - ] + "required": ["image"] } ], "properties": { @@ -1345,9 +1169,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "annotation": { "description": "Annotations to be added to Kubernetes Ingress or Openshift Route", @@ -1366,11 +1188,7 @@ "exposure": { "description": "Describes how the endpoint should be exposed on the network.\n- `public` means that the endpoint will be exposed on the public network, typically through a K8S ingress or an OpenShift route.\n- `internal` means that the endpoint will be exposed internally outside of the main devworkspace POD, typically by K8S services, to be consumed by other elements running on the same cloud internal network.\n- `none` means that the endpoint will not be exposed and will only be accessible inside the main devworkspace POD, on a local address.\n\nDefault value is `public`", "type": "string", - "enum": [ - "public", - "internal", - "none" - ], + "enum": ["public", "internal", "none"], "markdownDescription": "Describes how the endpoint should be exposed on the network.\n- `public` means that the endpoint will be exposed on the public network, typically through a K8S ingress or an OpenShift route.\n- `internal` means that the endpoint will be exposed internally outside of the main devworkspace POD, typically by K8S services, to be consumed by other elements running on the same cloud internal network.\n- `none` means that the endpoint will not be exposed and will only be accessible inside the main devworkspace POD, on a local address.\n\nDefault value is `public`" }, "name": { @@ -1386,14 +1204,7 @@ "protocol": { "description": "Describes the application and transport protocols of the traffic that will go through this endpoint.\n- `http`: Endpoint will have `http` traffic, typically on a TCP connection. It will be automaticaly promoted to `https` when the `secure` field is set to `true`.\n- `https`: Endpoint will have `https` traffic, typically on a TCP connection.\n- `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. It will be automaticaly promoted to `wss` when the `secure` field is set to `true`.\n- `wss`: Endpoint will have `wss` traffic, typically on a TCP connection.\n- `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol.\n- `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol.\n\nDefault value is `http`", "type": "string", - "enum": [ - "http", - "https", - "ws", - "wss", - "tcp", - "udp" - ], + "enum": ["http", "https", "ws", "wss", "tcp", "udp"], "markdownDescription": "Describes the application and transport protocols of the traffic that will go through this endpoint.\n- `http`: Endpoint will have `http` traffic, typically on a TCP connection. It will be automaticaly promoted to `https` when the `secure` field is set to `true`.\n- `https`: Endpoint will have `https` traffic, typically on a TCP connection.\n- `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. It will be automaticaly promoted to `wss` when the `secure` field is set to `true`.\n- `wss`: Endpoint will have `wss` traffic, typically on a TCP connection.\n- `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol.\n- `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol.\n\nDefault value is `http`" }, "secure": { @@ -1415,9 +1226,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "name": { "type": "string" @@ -1455,9 +1264,7 @@ "items": { "description": "Volume that should be mounted to a component container", "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "name": { "description": "The volume mount name is the name of an existing `Volume` component. If several containers mount the same volume name then they will reuse the same volume and will be able to access to the same files.", @@ -1486,14 +1293,10 @@ "type": "object", "oneOf": [ { - "required": [ - "dockerfile" - ] + "required": ["dockerfile"] }, { - "required": [ - "autoBuild" - ] + "required": ["autoBuild"] } ], "properties": { @@ -1507,19 +1310,13 @@ "type": "object", "oneOf": [ { - "required": [ - "uri" - ] + "required": ["uri"] }, { - "required": [ - "devfileRegistry" - ] + "required": ["devfileRegistry"] }, { - "required": [ - "git" - ] + "required": ["git"] } ], "properties": { @@ -1621,14 +1418,10 @@ "type": "object", "oneOf": [ { - "required": [ - "uri" - ] + "required": ["uri"] }, { - "required": [ - "inlined" - ] + "required": ["inlined"] } ], "properties": { @@ -1641,9 +1434,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "annotation": { "description": "Annotations to be added to Kubernetes Ingress or Openshift Route", @@ -1662,11 +1453,7 @@ "exposure": { "description": "Describes how the endpoint should be exposed on the network.\n- `public` means that the endpoint will be exposed on the public network, typically through a K8S ingress or an OpenShift route.\n- `internal` means that the endpoint will be exposed internally outside of the main devworkspace POD, typically by K8S services, to be consumed by other elements running on the same cloud internal network.\n- `none` means that the endpoint will not be exposed and will only be accessible inside the main devworkspace POD, on a local address.\n\nDefault value is `public`", "type": "string", - "enum": [ - "public", - "internal", - "none" - ], + "enum": ["public", "internal", "none"], "markdownDescription": "Describes how the endpoint should be exposed on the network.\n- `public` means that the endpoint will be exposed on the public network, typically through a K8S ingress or an OpenShift route.\n- `internal` means that the endpoint will be exposed internally outside of the main devworkspace POD, typically by K8S services, to be consumed by other elements running on the same cloud internal network.\n- `none` means that the endpoint will not be exposed and will only be accessible inside the main devworkspace POD, on a local address.\n\nDefault value is `public`" }, "name": { @@ -1682,14 +1469,7 @@ "protocol": { "description": "Describes the application and transport protocols of the traffic that will go through this endpoint.\n- `http`: Endpoint will have `http` traffic, typically on a TCP connection. It will be automaticaly promoted to `https` when the `secure` field is set to `true`.\n- `https`: Endpoint will have `https` traffic, typically on a TCP connection.\n- `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. It will be automaticaly promoted to `wss` when the `secure` field is set to `true`.\n- `wss`: Endpoint will have `wss` traffic, typically on a TCP connection.\n- `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol.\n- `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol.\n\nDefault value is `http`", "type": "string", - "enum": [ - "http", - "https", - "ws", - "wss", - "tcp", - "udp" - ], + "enum": ["http", "https", "ws", "wss", "tcp", "udp"], "markdownDescription": "Describes the application and transport protocols of the traffic that will go through this endpoint.\n- `http`: Endpoint will have `http` traffic, typically on a TCP connection. It will be automaticaly promoted to `https` when the `secure` field is set to `true`.\n- `https`: Endpoint will have `https` traffic, typically on a TCP connection.\n- `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. It will be automaticaly promoted to `wss` when the `secure` field is set to `true`.\n- `wss`: Endpoint will have `wss` traffic, typically on a TCP connection.\n- `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol.\n- `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol.\n\nDefault value is `http`" }, "secure": { @@ -1732,14 +1512,10 @@ "type": "object", "oneOf": [ { - "required": [ - "uri" - ] + "required": ["uri"] }, { - "required": [ - "inlined" - ] + "required": ["inlined"] } ], "properties": { @@ -1752,9 +1528,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "annotation": { "description": "Annotations to be added to Kubernetes Ingress or Openshift Route", @@ -1773,11 +1547,7 @@ "exposure": { "description": "Describes how the endpoint should be exposed on the network.\n- `public` means that the endpoint will be exposed on the public network, typically through a K8S ingress or an OpenShift route.\n- `internal` means that the endpoint will be exposed internally outside of the main devworkspace POD, typically by K8S services, to be consumed by other elements running on the same cloud internal network.\n- `none` means that the endpoint will not be exposed and will only be accessible inside the main devworkspace POD, on a local address.\n\nDefault value is `public`", "type": "string", - "enum": [ - "public", - "internal", - "none" - ], + "enum": ["public", "internal", "none"], "markdownDescription": "Describes how the endpoint should be exposed on the network.\n- `public` means that the endpoint will be exposed on the public network, typically through a K8S ingress or an OpenShift route.\n- `internal` means that the endpoint will be exposed internally outside of the main devworkspace POD, typically by K8S services, to be consumed by other elements running on the same cloud internal network.\n- `none` means that the endpoint will not be exposed and will only be accessible inside the main devworkspace POD, on a local address.\n\nDefault value is `public`" }, "name": { @@ -1793,14 +1563,7 @@ "protocol": { "description": "Describes the application and transport protocols of the traffic that will go through this endpoint.\n- `http`: Endpoint will have `http` traffic, typically on a TCP connection. It will be automaticaly promoted to `https` when the `secure` field is set to `true`.\n- `https`: Endpoint will have `https` traffic, typically on a TCP connection.\n- `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. It will be automaticaly promoted to `wss` when the `secure` field is set to `true`.\n- `wss`: Endpoint will have `wss` traffic, typically on a TCP connection.\n- `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol.\n- `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol.\n\nDefault value is `http`", "type": "string", - "enum": [ - "http", - "https", - "ws", - "wss", - "tcp", - "udp" - ], + "enum": ["http", "https", "ws", "wss", "tcp", "udp"], "markdownDescription": "Describes the application and transport protocols of the traffic that will go through this endpoint.\n- `http`: Endpoint will have `http` traffic, typically on a TCP connection. It will be automaticaly promoted to `https` when the `secure` field is set to `true`.\n- `https`: Endpoint will have `https` traffic, typically on a TCP connection.\n- `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. It will be automaticaly promoted to `wss` when the `secure` field is set to `true`.\n- `wss`: Endpoint will have `wss` traffic, typically on a TCP connection.\n- `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol.\n- `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol.\n\nDefault value is `http`" }, "secure": { @@ -1862,9 +1625,7 @@ "kubernetes": { "description": "Reference to a Kubernetes CRD of type DevWorkspaceTemplate", "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "name": { "type": "string" @@ -1881,19 +1642,13 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "oneOf": [ { - "required": [ - "git" - ] + "required": ["git"] }, { - "required": [ - "zip" - ] + "required": ["zip"] } ], "properties": { @@ -1977,19 +1732,13 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "oneOf": [ { - "required": [ - "git" - ] + "required": ["git"] }, { - "required": [ - "zip" - ] + "required": ["zip"] } ], "properties": { @@ -2096,19 +1845,13 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "oneOf": [ { - "required": [ - "git" - ] + "required": ["git"] }, { - "required": [ - "zip" - ] + "required": ["zip"] } ], "properties": { @@ -2126,9 +1869,7 @@ "git": { "description": "Project's Git source", "type": "object", - "required": [ - "remotes" - ], + "required": ["remotes"], "properties": { "checkoutFrom": { "description": "Defines from what the project should be checked out. Required if there are more than one remote configured", @@ -2196,19 +1937,13 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "oneOf": [ { - "required": [ - "git" - ] + "required": ["git"] }, { - "required": [ - "zip" - ] + "required": ["zip"] } ], "properties": { @@ -2226,9 +1961,7 @@ "git": { "description": "Project's Git source", "type": "object", - "required": [ - "remotes" - ], + "required": ["remotes"], "properties": { "checkoutFrom": { "description": "Defines from what the project should be checked out. Required if there are more than one remote configured", diff --git a/packages/dashboard-backend/src/devfileSchemas/2.2.1-alpha/devfile.json b/packages/dashboard-backend/src/devfileSchemas/2.2.1-alpha/devfile.json index 9158d7dbb..79c983ab4 100644 --- a/packages/dashboard-backend/src/devfileSchemas/2.2.1-alpha/devfile.json +++ b/packages/dashboard-backend/src/devfileSchemas/2.2.1-alpha/devfile.json @@ -2,9 +2,7 @@ "description": "Devfile describes the structure of a cloud-native devworkspace and development environment.\n\nIDE-targeted variants of the schemas provide the following difference compared to the main schemas:\n- They contain additional non-standard `markdownDescription` attributes that are used by IDEs such a VSCode\nto provide markdown-rendered documentation hovers.\n- They don't contain `default` attributes, since this triggers unwanted addition of defaulted fields during completion in IDEs.", "type": "object", "title": "Devfile schema - Version 2.2.1-alpha - IDE-targeted variant", - "required": [ - "schemaVersion" - ], + "required": ["schemaVersion"], "properties": { "attributes": { "description": "Map of implementation-dependant free-form YAML attributes.", @@ -17,33 +15,23 @@ "type": "array", "items": { "type": "object", - "required": [ - "id" - ], + "required": ["id"], "oneOf": [ { - "required": [ - "exec" - ] + "required": ["exec"] }, { - "required": [ - "apply" - ] + "required": ["apply"] }, { - "required": [ - "composite" - ] + "required": ["composite"] } ], "properties": { "apply": { "description": "Command that consists in applying a given component definition, typically bound to a devworkspace event.\n\nFor example, when an `apply` command is bound to a `preStart` event, and references a `container` component, it will start the container as a K8S initContainer in the devworkspace POD, unless the component has its `dedicatedPod` field set to `true`.\n\nWhen no `apply` command exist for a given component, it is assumed the component will be applied at devworkspace start by default, unless `deployByDefault` for that component is set to false.", "type": "object", - "required": [ - "component" - ], + "required": ["component"], "properties": { "component": { "description": "Describes component that will be applied", @@ -53,9 +41,7 @@ "group": { "description": "Defines the group this command is part of", "type": "object", - "required": [ - "kind" - ], + "required": ["kind"], "properties": { "isDefault": { "description": "Identifies the default command for a given group kind", @@ -65,13 +51,7 @@ "kind": { "description": "Kind of group the command is part of", "type": "string", - "enum": [ - "build", - "run", - "test", - "debug", - "deploy" - ], + "enum": ["build", "run", "test", "debug", "deploy"], "markdownDescription": "Kind of group the command is part of" } }, @@ -108,9 +88,7 @@ "group": { "description": "Defines the group this command is part of", "type": "object", - "required": [ - "kind" - ], + "required": ["kind"], "properties": { "isDefault": { "description": "Identifies the default command for a given group kind", @@ -120,13 +98,7 @@ "kind": { "description": "Kind of group the command is part of", "type": "string", - "enum": [ - "build", - "run", - "test", - "debug", - "deploy" - ], + "enum": ["build", "run", "test", "debug", "deploy"], "markdownDescription": "Kind of group the command is part of" } }, @@ -150,10 +122,7 @@ "exec": { "description": "CLI Command executed in an existing component container", "type": "object", - "required": [ - "commandLine", - "component" - ], + "required": ["commandLine", "component"], "properties": { "commandLine": { "description": "The actual command-line string\n\nSpecial variables that can be used:\n\n - `$PROJECTS_ROOT`: A path where projects sources are mounted as defined by container component's sourceMapping.\n\n - `$PROJECT_SOURCE`: A path to a project source ($PROJECTS_ROOT/\u003cproject-name\u003e). If there are multiple projects, this will point to the directory of the first one.", @@ -170,10 +139,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name", - "value" - ], + "required": ["name", "value"], "properties": { "name": { "type": "string" @@ -189,9 +155,7 @@ "group": { "description": "Defines the group this command is part of", "type": "object", - "required": [ - "kind" - ], + "required": ["kind"], "properties": { "isDefault": { "description": "Identifies the default command for a given group kind", @@ -201,13 +165,7 @@ "kind": { "description": "Kind of group the command is part of", "type": "string", - "enum": [ - "build", - "run", - "test", - "debug", - "deploy" - ], + "enum": ["build", "run", "test", "debug", "deploy"], "markdownDescription": "Kind of group the command is part of" } }, @@ -250,34 +208,22 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "oneOf": [ { - "required": [ - "container" - ] + "required": ["container"] }, { - "required": [ - "kubernetes" - ] + "required": ["kubernetes"] }, { - "required": [ - "openshift" - ] + "required": ["openshift"] }, { - "required": [ - "volume" - ] + "required": ["volume"] }, { - "required": [ - "image" - ] + "required": ["image"] } ], "properties": { @@ -290,9 +236,7 @@ "container": { "description": "Allows adding and configuring devworkspace-related containers", "type": "object", - "required": [ - "image" - ], + "required": ["image"], "properties": { "annotation": { "description": "Annotations that should be added to specific resources for this container", @@ -349,10 +293,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name", - "targetPort" - ], + "required": ["name", "targetPort"], "properties": { "annotation": { "description": "Annotations to be added to Kubernetes Ingress or Openshift Route", @@ -371,11 +312,7 @@ "exposure": { "description": "Describes how the endpoint should be exposed on the network.\n- `public` means that the endpoint will be exposed on the public network, typically through a K8S ingress or an OpenShift route.\n- `internal` means that the endpoint will be exposed internally outside of the main devworkspace POD, typically by K8S services, to be consumed by other elements running on the same cloud internal network.\n- `none` means that the endpoint will not be exposed and will only be accessible inside the main devworkspace POD, on a local address.\n\nDefault value is `public`", "type": "string", - "enum": [ - "public", - "internal", - "none" - ], + "enum": ["public", "internal", "none"], "markdownDescription": "Describes how the endpoint should be exposed on the network.\n- `public` means that the endpoint will be exposed on the public network, typically through a K8S ingress or an OpenShift route.\n- `internal` means that the endpoint will be exposed internally outside of the main devworkspace POD, typically by K8S services, to be consumed by other elements running on the same cloud internal network.\n- `none` means that the endpoint will not be exposed and will only be accessible inside the main devworkspace POD, on a local address.\n\nDefault value is `public`" }, "name": { @@ -391,14 +328,7 @@ "protocol": { "description": "Describes the application and transport protocols of the traffic that will go through this endpoint.\n- `http`: Endpoint will have `http` traffic, typically on a TCP connection. It will be automaticaly promoted to `https` when the `secure` field is set to `true`.\n- `https`: Endpoint will have `https` traffic, typically on a TCP connection.\n- `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. It will be automaticaly promoted to `wss` when the `secure` field is set to `true`.\n- `wss`: Endpoint will have `wss` traffic, typically on a TCP connection.\n- `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol.\n- `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol.\n\nDefault value is `http`", "type": "string", - "enum": [ - "http", - "https", - "ws", - "wss", - "tcp", - "udp" - ], + "enum": ["http", "https", "ws", "wss", "tcp", "udp"], "markdownDescription": "Describes the application and transport protocols of the traffic that will go through this endpoint.\n- `http`: Endpoint will have `http` traffic, typically on a TCP connection. It will be automaticaly promoted to `https` when the `secure` field is set to `true`.\n- `https`: Endpoint will have `https` traffic, typically on a TCP connection.\n- `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. It will be automaticaly promoted to `wss` when the `secure` field is set to `true`.\n- `wss`: Endpoint will have `wss` traffic, typically on a TCP connection.\n- `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol.\n- `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol.\n\nDefault value is `http`" }, "secure": { @@ -420,10 +350,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name", - "value" - ], + "required": ["name", "value"], "properties": { "name": { "type": "string" @@ -461,9 +388,7 @@ "items": { "description": "Volume that should be mounted to a component container", "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "name": { "description": "The volume mount name is the name of an existing `Volume` component. If several containers mount the same volume name then they will reuse the same volume and will be able to access to the same files.", @@ -490,14 +415,10 @@ "image": { "description": "Allows specifying the definition of an image for outer loop builds", "type": "object", - "required": [ - "imageName" - ], + "required": ["imageName"], "oneOf": [ { - "required": [ - "dockerfile" - ] + "required": ["dockerfile"] } ], "properties": { @@ -511,19 +432,13 @@ "type": "object", "oneOf": [ { - "required": [ - "uri" - ] + "required": ["uri"] }, { - "required": [ - "devfileRegistry" - ] + "required": ["devfileRegistry"] }, { - "required": [ - "git" - ] + "required": ["git"] } ], "properties": { @@ -543,9 +458,7 @@ "devfileRegistry": { "description": "Dockerfile's Devfile Registry source", "type": "object", - "required": [ - "id" - ], + "required": ["id"], "properties": { "id": { "description": "Id in a devfile registry that contains a Dockerfile. The src in the OCI registry required for the Dockerfile build will be downloaded for building the image.", @@ -564,9 +477,7 @@ "git": { "description": "Dockerfile's Git source", "type": "object", - "required": [ - "remotes" - ], + "required": ["remotes"], "properties": { "checkoutFrom": { "description": "Defines from what the project should be checked out. Required if there are more than one remote configured", @@ -631,14 +542,10 @@ "type": "object", "oneOf": [ { - "required": [ - "uri" - ] + "required": ["uri"] }, { - "required": [ - "inlined" - ] + "required": ["inlined"] } ], "properties": { @@ -651,10 +558,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name", - "targetPort" - ], + "required": ["name", "targetPort"], "properties": { "annotation": { "description": "Annotations to be added to Kubernetes Ingress or Openshift Route", @@ -673,11 +577,7 @@ "exposure": { "description": "Describes how the endpoint should be exposed on the network.\n- `public` means that the endpoint will be exposed on the public network, typically through a K8S ingress or an OpenShift route.\n- `internal` means that the endpoint will be exposed internally outside of the main devworkspace POD, typically by K8S services, to be consumed by other elements running on the same cloud internal network.\n- `none` means that the endpoint will not be exposed and will only be accessible inside the main devworkspace POD, on a local address.\n\nDefault value is `public`", "type": "string", - "enum": [ - "public", - "internal", - "none" - ], + "enum": ["public", "internal", "none"], "markdownDescription": "Describes how the endpoint should be exposed on the network.\n- `public` means that the endpoint will be exposed on the public network, typically through a K8S ingress or an OpenShift route.\n- `internal` means that the endpoint will be exposed internally outside of the main devworkspace POD, typically by K8S services, to be consumed by other elements running on the same cloud internal network.\n- `none` means that the endpoint will not be exposed and will only be accessible inside the main devworkspace POD, on a local address.\n\nDefault value is `public`" }, "name": { @@ -693,14 +593,7 @@ "protocol": { "description": "Describes the application and transport protocols of the traffic that will go through this endpoint.\n- `http`: Endpoint will have `http` traffic, typically on a TCP connection. It will be automaticaly promoted to `https` when the `secure` field is set to `true`.\n- `https`: Endpoint will have `https` traffic, typically on a TCP connection.\n- `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. It will be automaticaly promoted to `wss` when the `secure` field is set to `true`.\n- `wss`: Endpoint will have `wss` traffic, typically on a TCP connection.\n- `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol.\n- `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol.\n\nDefault value is `http`", "type": "string", - "enum": [ - "http", - "https", - "ws", - "wss", - "tcp", - "udp" - ], + "enum": ["http", "https", "ws", "wss", "tcp", "udp"], "markdownDescription": "Describes the application and transport protocols of the traffic that will go through this endpoint.\n- `http`: Endpoint will have `http` traffic, typically on a TCP connection. It will be automaticaly promoted to `https` when the `secure` field is set to `true`.\n- `https`: Endpoint will have `https` traffic, typically on a TCP connection.\n- `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. It will be automaticaly promoted to `wss` when the `secure` field is set to `true`.\n- `wss`: Endpoint will have `wss` traffic, typically on a TCP connection.\n- `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol.\n- `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol.\n\nDefault value is `http`" }, "secure": { @@ -743,14 +636,10 @@ "type": "object", "oneOf": [ { - "required": [ - "uri" - ] + "required": ["uri"] }, { - "required": [ - "inlined" - ] + "required": ["inlined"] } ], "properties": { @@ -763,10 +652,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name", - "targetPort" - ], + "required": ["name", "targetPort"], "properties": { "annotation": { "description": "Annotations to be added to Kubernetes Ingress or Openshift Route", @@ -785,11 +671,7 @@ "exposure": { "description": "Describes how the endpoint should be exposed on the network.\n- `public` means that the endpoint will be exposed on the public network, typically through a K8S ingress or an OpenShift route.\n- `internal` means that the endpoint will be exposed internally outside of the main devworkspace POD, typically by K8S services, to be consumed by other elements running on the same cloud internal network.\n- `none` means that the endpoint will not be exposed and will only be accessible inside the main devworkspace POD, on a local address.\n\nDefault value is `public`", "type": "string", - "enum": [ - "public", - "internal", - "none" - ], + "enum": ["public", "internal", "none"], "markdownDescription": "Describes how the endpoint should be exposed on the network.\n- `public` means that the endpoint will be exposed on the public network, typically through a K8S ingress or an OpenShift route.\n- `internal` means that the endpoint will be exposed internally outside of the main devworkspace POD, typically by K8S services, to be consumed by other elements running on the same cloud internal network.\n- `none` means that the endpoint will not be exposed and will only be accessible inside the main devworkspace POD, on a local address.\n\nDefault value is `public`" }, "name": { @@ -805,14 +687,7 @@ "protocol": { "description": "Describes the application and transport protocols of the traffic that will go through this endpoint.\n- `http`: Endpoint will have `http` traffic, typically on a TCP connection. It will be automaticaly promoted to `https` when the `secure` field is set to `true`.\n- `https`: Endpoint will have `https` traffic, typically on a TCP connection.\n- `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. It will be automaticaly promoted to `wss` when the `secure` field is set to `true`.\n- `wss`: Endpoint will have `wss` traffic, typically on a TCP connection.\n- `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol.\n- `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol.\n\nDefault value is `http`", "type": "string", - "enum": [ - "http", - "https", - "ws", - "wss", - "tcp", - "udp" - ], + "enum": ["http", "https", "ws", "wss", "tcp", "udp"], "markdownDescription": "Describes the application and transport protocols of the traffic that will go through this endpoint.\n- `http`: Endpoint will have `http` traffic, typically on a TCP connection. It will be automaticaly promoted to `https` when the `secure` field is set to `true`.\n- `https`: Endpoint will have `https` traffic, typically on a TCP connection.\n- `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. It will be automaticaly promoted to `wss` when the `secure` field is set to `true`.\n- `wss`: Endpoint will have `wss` traffic, typically on a TCP connection.\n- `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol.\n- `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol.\n\nDefault value is `http`" }, "secure": { @@ -917,12 +792,7 @@ "items": { "description": "Architecture describes the architecture type", "type": "string", - "enum": [ - "amd64", - "arm64", - "ppc64le", - "s390x" - ], + "enum": ["amd64", "arm64", "ppc64le", "s390x"], "markdownDescription": "Architecture describes the architecture type" }, "markdownDescription": "Optional list of processor architectures that the devfile supports, empty list suggests that the devfile can be used on any architecture" @@ -1006,19 +876,13 @@ "type": "object", "oneOf": [ { - "required": [ - "uri" - ] + "required": ["uri"] }, { - "required": [ - "id" - ] + "required": ["id"] }, { - "required": [ - "kubernetes" - ] + "required": ["kubernetes"] } ], "properties": { @@ -1033,24 +897,16 @@ "type": "array", "items": { "type": "object", - "required": [ - "id" - ], + "required": ["id"], "oneOf": [ { - "required": [ - "exec" - ] + "required": ["exec"] }, { - "required": [ - "apply" - ] + "required": ["apply"] }, { - "required": [ - "composite" - ] + "required": ["composite"] } ], "properties": { @@ -1075,13 +931,7 @@ "kind": { "description": "Kind of group the command is part of", "type": "string", - "enum": [ - "build", - "run", - "test", - "debug", - "deploy" - ], + "enum": ["build", "run", "test", "debug", "deploy"], "markdownDescription": "Kind of group the command is part of" } }, @@ -1127,13 +977,7 @@ "kind": { "description": "Kind of group the command is part of", "type": "string", - "enum": [ - "build", - "run", - "test", - "debug", - "deploy" - ], + "enum": ["build", "run", "test", "debug", "deploy"], "markdownDescription": "Kind of group the command is part of" } }, @@ -1173,9 +1017,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "name": { "type": "string" @@ -1200,13 +1042,7 @@ "kind": { "description": "Kind of group the command is part of", "type": "string", - "enum": [ - "build", - "run", - "test", - "debug", - "deploy" - ], + "enum": ["build", "run", "test", "debug", "deploy"], "markdownDescription": "Kind of group the command is part of" } }, @@ -1249,34 +1085,22 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "oneOf": [ { - "required": [ - "container" - ] + "required": ["container"] }, { - "required": [ - "kubernetes" - ] + "required": ["kubernetes"] }, { - "required": [ - "openshift" - ] + "required": ["openshift"] }, { - "required": [ - "volume" - ] + "required": ["volume"] }, { - "required": [ - "image" - ] + "required": ["image"] } ], "properties": { @@ -1345,9 +1169,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "annotation": { "description": "Annotations to be added to Kubernetes Ingress or Openshift Route", @@ -1366,11 +1188,7 @@ "exposure": { "description": "Describes how the endpoint should be exposed on the network.\n- `public` means that the endpoint will be exposed on the public network, typically through a K8S ingress or an OpenShift route.\n- `internal` means that the endpoint will be exposed internally outside of the main devworkspace POD, typically by K8S services, to be consumed by other elements running on the same cloud internal network.\n- `none` means that the endpoint will not be exposed and will only be accessible inside the main devworkspace POD, on a local address.\n\nDefault value is `public`", "type": "string", - "enum": [ - "public", - "internal", - "none" - ], + "enum": ["public", "internal", "none"], "markdownDescription": "Describes how the endpoint should be exposed on the network.\n- `public` means that the endpoint will be exposed on the public network, typically through a K8S ingress or an OpenShift route.\n- `internal` means that the endpoint will be exposed internally outside of the main devworkspace POD, typically by K8S services, to be consumed by other elements running on the same cloud internal network.\n- `none` means that the endpoint will not be exposed and will only be accessible inside the main devworkspace POD, on a local address.\n\nDefault value is `public`" }, "name": { @@ -1386,14 +1204,7 @@ "protocol": { "description": "Describes the application and transport protocols of the traffic that will go through this endpoint.\n- `http`: Endpoint will have `http` traffic, typically on a TCP connection. It will be automaticaly promoted to `https` when the `secure` field is set to `true`.\n- `https`: Endpoint will have `https` traffic, typically on a TCP connection.\n- `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. It will be automaticaly promoted to `wss` when the `secure` field is set to `true`.\n- `wss`: Endpoint will have `wss` traffic, typically on a TCP connection.\n- `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol.\n- `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol.\n\nDefault value is `http`", "type": "string", - "enum": [ - "http", - "https", - "ws", - "wss", - "tcp", - "udp" - ], + "enum": ["http", "https", "ws", "wss", "tcp", "udp"], "markdownDescription": "Describes the application and transport protocols of the traffic that will go through this endpoint.\n- `http`: Endpoint will have `http` traffic, typically on a TCP connection. It will be automaticaly promoted to `https` when the `secure` field is set to `true`.\n- `https`: Endpoint will have `https` traffic, typically on a TCP connection.\n- `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. It will be automaticaly promoted to `wss` when the `secure` field is set to `true`.\n- `wss`: Endpoint will have `wss` traffic, typically on a TCP connection.\n- `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol.\n- `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol.\n\nDefault value is `http`" }, "secure": { @@ -1415,9 +1226,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "name": { "type": "string" @@ -1455,9 +1264,7 @@ "items": { "description": "Volume that should be mounted to a component container", "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "name": { "description": "The volume mount name is the name of an existing `Volume` component. If several containers mount the same volume name then they will reuse the same volume and will be able to access to the same files.", @@ -1486,14 +1293,10 @@ "type": "object", "oneOf": [ { - "required": [ - "dockerfile" - ] + "required": ["dockerfile"] }, { - "required": [ - "autoBuild" - ] + "required": ["autoBuild"] } ], "properties": { @@ -1507,19 +1310,13 @@ "type": "object", "oneOf": [ { - "required": [ - "uri" - ] + "required": ["uri"] }, { - "required": [ - "devfileRegistry" - ] + "required": ["devfileRegistry"] }, { - "required": [ - "git" - ] + "required": ["git"] } ], "properties": { @@ -1621,14 +1418,10 @@ "type": "object", "oneOf": [ { - "required": [ - "uri" - ] + "required": ["uri"] }, { - "required": [ - "inlined" - ] + "required": ["inlined"] } ], "properties": { @@ -1641,9 +1434,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "annotation": { "description": "Annotations to be added to Kubernetes Ingress or Openshift Route", @@ -1662,11 +1453,7 @@ "exposure": { "description": "Describes how the endpoint should be exposed on the network.\n- `public` means that the endpoint will be exposed on the public network, typically through a K8S ingress or an OpenShift route.\n- `internal` means that the endpoint will be exposed internally outside of the main devworkspace POD, typically by K8S services, to be consumed by other elements running on the same cloud internal network.\n- `none` means that the endpoint will not be exposed and will only be accessible inside the main devworkspace POD, on a local address.\n\nDefault value is `public`", "type": "string", - "enum": [ - "public", - "internal", - "none" - ], + "enum": ["public", "internal", "none"], "markdownDescription": "Describes how the endpoint should be exposed on the network.\n- `public` means that the endpoint will be exposed on the public network, typically through a K8S ingress or an OpenShift route.\n- `internal` means that the endpoint will be exposed internally outside of the main devworkspace POD, typically by K8S services, to be consumed by other elements running on the same cloud internal network.\n- `none` means that the endpoint will not be exposed and will only be accessible inside the main devworkspace POD, on a local address.\n\nDefault value is `public`" }, "name": { @@ -1682,14 +1469,7 @@ "protocol": { "description": "Describes the application and transport protocols of the traffic that will go through this endpoint.\n- `http`: Endpoint will have `http` traffic, typically on a TCP connection. It will be automaticaly promoted to `https` when the `secure` field is set to `true`.\n- `https`: Endpoint will have `https` traffic, typically on a TCP connection.\n- `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. It will be automaticaly promoted to `wss` when the `secure` field is set to `true`.\n- `wss`: Endpoint will have `wss` traffic, typically on a TCP connection.\n- `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol.\n- `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol.\n\nDefault value is `http`", "type": "string", - "enum": [ - "http", - "https", - "ws", - "wss", - "tcp", - "udp" - ], + "enum": ["http", "https", "ws", "wss", "tcp", "udp"], "markdownDescription": "Describes the application and transport protocols of the traffic that will go through this endpoint.\n- `http`: Endpoint will have `http` traffic, typically on a TCP connection. It will be automaticaly promoted to `https` when the `secure` field is set to `true`.\n- `https`: Endpoint will have `https` traffic, typically on a TCP connection.\n- `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. It will be automaticaly promoted to `wss` when the `secure` field is set to `true`.\n- `wss`: Endpoint will have `wss` traffic, typically on a TCP connection.\n- `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol.\n- `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol.\n\nDefault value is `http`" }, "secure": { @@ -1732,14 +1512,10 @@ "type": "object", "oneOf": [ { - "required": [ - "uri" - ] + "required": ["uri"] }, { - "required": [ - "inlined" - ] + "required": ["inlined"] } ], "properties": { @@ -1752,9 +1528,7 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "annotation": { "description": "Annotations to be added to Kubernetes Ingress or Openshift Route", @@ -1773,11 +1547,7 @@ "exposure": { "description": "Describes how the endpoint should be exposed on the network.\n- `public` means that the endpoint will be exposed on the public network, typically through a K8S ingress or an OpenShift route.\n- `internal` means that the endpoint will be exposed internally outside of the main devworkspace POD, typically by K8S services, to be consumed by other elements running on the same cloud internal network.\n- `none` means that the endpoint will not be exposed and will only be accessible inside the main devworkspace POD, on a local address.\n\nDefault value is `public`", "type": "string", - "enum": [ - "public", - "internal", - "none" - ], + "enum": ["public", "internal", "none"], "markdownDescription": "Describes how the endpoint should be exposed on the network.\n- `public` means that the endpoint will be exposed on the public network, typically through a K8S ingress or an OpenShift route.\n- `internal` means that the endpoint will be exposed internally outside of the main devworkspace POD, typically by K8S services, to be consumed by other elements running on the same cloud internal network.\n- `none` means that the endpoint will not be exposed and will only be accessible inside the main devworkspace POD, on a local address.\n\nDefault value is `public`" }, "name": { @@ -1793,14 +1563,7 @@ "protocol": { "description": "Describes the application and transport protocols of the traffic that will go through this endpoint.\n- `http`: Endpoint will have `http` traffic, typically on a TCP connection. It will be automaticaly promoted to `https` when the `secure` field is set to `true`.\n- `https`: Endpoint will have `https` traffic, typically on a TCP connection.\n- `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. It will be automaticaly promoted to `wss` when the `secure` field is set to `true`.\n- `wss`: Endpoint will have `wss` traffic, typically on a TCP connection.\n- `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol.\n- `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol.\n\nDefault value is `http`", "type": "string", - "enum": [ - "http", - "https", - "ws", - "wss", - "tcp", - "udp" - ], + "enum": ["http", "https", "ws", "wss", "tcp", "udp"], "markdownDescription": "Describes the application and transport protocols of the traffic that will go through this endpoint.\n- `http`: Endpoint will have `http` traffic, typically on a TCP connection. It will be automaticaly promoted to `https` when the `secure` field is set to `true`.\n- `https`: Endpoint will have `https` traffic, typically on a TCP connection.\n- `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. It will be automaticaly promoted to `wss` when the `secure` field is set to `true`.\n- `wss`: Endpoint will have `wss` traffic, typically on a TCP connection.\n- `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol.\n- `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol.\n\nDefault value is `http`" }, "secure": { @@ -1862,9 +1625,7 @@ "kubernetes": { "description": "Reference to a Kubernetes CRD of type DevWorkspaceTemplate", "type": "object", - "required": [ - "name" - ], + "required": ["name"], "properties": { "name": { "type": "string" @@ -1881,19 +1642,13 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "oneOf": [ { - "required": [ - "git" - ] + "required": ["git"] }, { - "required": [ - "zip" - ] + "required": ["zip"] } ], "properties": { @@ -1977,19 +1732,13 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "oneOf": [ { - "required": [ - "git" - ] + "required": ["git"] }, { - "required": [ - "zip" - ] + "required": ["zip"] } ], "properties": { @@ -2096,19 +1845,13 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "oneOf": [ { - "required": [ - "git" - ] + "required": ["git"] }, { - "required": [ - "zip" - ] + "required": ["zip"] } ], "properties": { @@ -2126,9 +1869,7 @@ "git": { "description": "Project's Git source", "type": "object", - "required": [ - "remotes" - ], + "required": ["remotes"], "properties": { "checkoutFrom": { "description": "Defines from what the project should be checked out. Required if there are more than one remote configured", @@ -2196,19 +1937,13 @@ "type": "array", "items": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "oneOf": [ { - "required": [ - "git" - ] + "required": ["git"] }, { - "required": [ - "zip" - ] + "required": ["zip"] } ], "properties": { @@ -2226,9 +1961,7 @@ "git": { "description": "Project's Git source", "type": "object", - "required": [ - "remotes" - ], + "required": ["remotes"], "properties": { "checkoutFrom": { "description": "Defines from what the project should be checked out. Required if there are more than one remote configured", @@ -2301,4 +2034,4 @@ }, "additionalProperties": false, "markdownDescription": "Devfile describes the structure of a cloud-native devworkspace and development environment.\n\nIDE-targeted variants of the schemas provide the following difference compared to the main schemas:\n- They contain additional non-standard `markdownDescription` attributes that are used by IDEs such a VSCode\nto provide markdown-rendered documentation hovers.\n- They don't contain `default` attributes, since this triggers unwanted addition of defaulted fields during completion in IDEs." -} \ No newline at end of file +} diff --git a/packages/dashboard-backend/src/routes/api/devfileSchema.ts b/packages/dashboard-backend/src/routes/api/devfileSchema.ts index 69d7c2edc..c4c148ffa 100644 --- a/packages/dashboard-backend/src/routes/api/devfileSchema.ts +++ b/packages/dashboard-backend/src/routes/api/devfileSchema.ts @@ -15,7 +15,6 @@ import { baseApiPath } from '../../constants/config'; import { getSchema } from '../../services/helpers'; import { devfileVersionSchema } from '../../constants/schemas'; import { restParams } from '../../typings/models'; -import * as devfileSchemaV100 from '../../devfileSchemas/1.0.0/devfile.json'; import * as devfileSchemaV200 from '../../devfileSchemas/2.0.0/devfile.json'; import * as devfileSchemaV210 from '../../devfileSchemas/2.1.0/devfile.json'; import * as devfileSchemaV220 from '../../devfileSchemas/2.2.0/devfile.json'; @@ -36,8 +35,6 @@ export function registerDevfileSchemaRoute(server: FastifyInstance) { ): Promise { const { version } = request.query as restParams.IDevfileVersionParams; switch (version) { - case '1.0.0': - return devfileSchemaV100; case '2.0.0': return devfileSchemaV200; case '2.1.0': diff --git a/packages/dashboard-frontend/package.json b/packages/dashboard-frontend/package.json index ab01c6a21..64bd1a3f3 100644 --- a/packages/dashboard-frontend/package.json +++ b/packages/dashboard-frontend/package.json @@ -36,7 +36,7 @@ "@eclipse-che/che-code-devworkspace-handler": "1.74.0-dev-e701cae", "@eclipse-che/che-theia-devworkspace-handler": "0.0.1-1667484092", "@eclipse-che/devfile-converter": "0.0.1-d624e3e", - "@eclipse-che/workspace-client": "0.0.1-1663851810", + "@eclipse-che/workspace-client": "0.0.1-1671793076", "@patternfly/react-core": "4.120.0", "@patternfly/react-icons": "^4.3.5", "@patternfly/react-table": "^4.5.7", diff --git a/packages/dashboard-frontend/src/Layout/Navigation/MainList.tsx b/packages/dashboard-frontend/src/Layout/Navigation/MainList.tsx index bbc79398c..1ea86357b 100644 --- a/packages/dashboard-frontend/src/Layout/Navigation/MainList.tsx +++ b/packages/dashboard-frontend/src/Layout/Navigation/MainList.tsx @@ -27,12 +27,7 @@ export class NavigationMainList extends React.PureComponent { private get items(): NavigationItemObject[] { const { allWorkspaces } = this.props; - const allWorkspacesNumber = allWorkspaces.filter(workspace => { - if (workspace.isDevWorkspace) { - return true; - } - return (workspace.ref as che.Workspace).attributes?.convertedId === undefined; - }).length; + const allWorkspacesNumber = allWorkspaces.length; return [ { to: ROUTE.GET_STARTED, label: 'Create Workspace' }, diff --git a/packages/dashboard-frontend/src/Layout/Navigation/__tests__/MainItem.spec.tsx b/packages/dashboard-frontend/src/Layout/Navigation/__tests__/MainItem.spec.tsx index 4ccb128f1..094173ba3 100644 --- a/packages/dashboard-frontend/src/Layout/Navigation/__tests__/MainItem.spec.tsx +++ b/packages/dashboard-frontend/src/Layout/Navigation/__tests__/MainItem.spec.tsx @@ -19,6 +19,7 @@ import NavigationMainItem from '../MainItem'; import { NavigationItemObject } from '..'; import { FakeStoreBuilder } from '../../../store/__mocks__/storeBuilder'; import { Provider } from 'react-redux'; +import devfileApi from '../../../services/devfileApi'; describe('Navigation Item', () => { let activeItem = ''; @@ -28,8 +29,8 @@ describe('Navigation Item', () => { to: '/home', }; - function renderComponent(workspaces: che.Workspace[] = []): RenderResult { - const store = new FakeStoreBuilder().withCheWorkspaces({ workspaces }).build(); + function renderComponent(workspaces: devfileApi.DevWorkspace[] = []): RenderResult { + const store = new FakeStoreBuilder().withDevWorkspaces({ workspaces }).build(); return render( diff --git a/packages/dashboard-frontend/src/Layout/Navigation/__tests__/MainList.spec.tsx b/packages/dashboard-frontend/src/Layout/Navigation/__tests__/MainList.spec.tsx index 829413c29..89593a696 100644 --- a/packages/dashboard-frontend/src/Layout/Navigation/__tests__/MainList.spec.tsx +++ b/packages/dashboard-frontend/src/Layout/Navigation/__tests__/MainList.spec.tsx @@ -14,14 +14,11 @@ import React from 'react'; import { render, RenderResult, screen } from '@testing-library/react'; import { MemoryRouter } from 'react-router'; import { Nav } from '@patternfly/react-core'; - import NavigationMainList from '../MainList'; import { FakeStoreBuilder } from '../../../store/__mocks__/storeBuilder'; import { Provider } from 'react-redux'; import { DevWorkspaceBuilder } from '../../../store/__mocks__/devWorkspaceBuilder'; import { Store } from 'redux'; -import { CheWorkspaceBuilder } from '../../../store/__mocks__/cheWorkspaceBuilder'; -import { WorkspaceAdapter } from '../../../services/workspace-adapter'; describe('Navigation Main List', () => { it('should have correct number of main navigation items', () => { @@ -65,34 +62,6 @@ describe('Navigation Main List', () => { expect(screen.queryByRole('link', { name: 'Workspaces (3)' })).toBeInTheDocument(); }); - - describe('with deprecated workspaces', () => { - it('should count all workspaces but converted', () => { - const devworkspaces = [0, 1].map(i => - new DevWorkspaceBuilder() - .withId('devwksp-' + i) - .withName('wksp-' + i) - .build(), - ); - const cheworkspaces = [ - new CheWorkspaceBuilder().withId('wksp-1').withName('wksp-1').build(), - new CheWorkspaceBuilder() - .withId('wksp-2') - .withName('wksp-2') - .withAttributes({ - convertedId: WorkspaceAdapter.getId(devworkspaces[0]), - } as che.WorkspaceAttributes) - .build(), - ]; - const store = new FakeStoreBuilder() - .withCheWorkspaces({ workspaces: cheworkspaces }) - .withDevWorkspaces({ workspaces: devworkspaces }) - .build(); - renderComponent(store); - - expect(screen.queryByRole('link', { name: 'Workspaces (3)' })).toBeInTheDocument(); - }); - }); }); function renderComponent(store: Store): RenderResult { diff --git a/packages/dashboard-frontend/src/Layout/Navigation/__tests__/RecentList.spec.tsx b/packages/dashboard-frontend/src/Layout/Navigation/__tests__/RecentList.spec.tsx index 184ed3f63..c43a55e0c 100644 --- a/packages/dashboard-frontend/src/Layout/Navigation/__tests__/RecentList.spec.tsx +++ b/packages/dashboard-frontend/src/Layout/Navigation/__tests__/RecentList.spec.tsx @@ -16,12 +16,12 @@ import { Nav } from '@patternfly/react-core'; import { Provider } from 'react-redux'; import { RenderResult, render, screen } from '@testing-library/react'; import { Store } from 'redux'; - +import devfileApi from '../../../services/devfileApi'; import NavigationRecentList from '../RecentList'; import { constructWorkspace, Workspace } from '../../../services/workspace-adapter'; import { FakeStoreBuilder } from '../../../store/__mocks__/storeBuilder'; import { createHashHistory } from 'history'; -import { CheWorkspaceBuilder } from '../../../store/__mocks__/cheWorkspaceBuilder'; +import { DevWorkspaceBuilder } from '../../../store/__mocks__/devWorkspaceBuilder'; jest.mock('react-tooltip', () => { return function DummyTooltip(): React.ReactElement { @@ -29,18 +29,18 @@ jest.mock('react-tooltip', () => { }; }); -let cheWorkspaces: che.Workspace[]; +let devWorkspaces: devfileApi.DevWorkspace[]; let workspaces: Workspace[]; describe('Navigation Recent List', () => { beforeEach(() => { - cheWorkspaces = [1, 2, 3].map(i => - new CheWorkspaceBuilder() + devWorkspaces = [1, 2, 3].map(i => + new DevWorkspaceBuilder() .withId('wksp-' + i) .withName('wksp-' + i) .build(), ); - workspaces = cheWorkspaces.map(workspace => constructWorkspace(workspace)); + workspaces = devWorkspaces.map(workspace => constructWorkspace(workspace)); }); function renderComponent(store: Store, workspaces: Workspace[]): RenderResult { @@ -101,5 +101,5 @@ describe('Navigation Recent List', () => { }); function createFakeStore(): Store { - return new FakeStoreBuilder().withCheWorkspaces({ workspaces: cheWorkspaces }).build(); + return new FakeStoreBuilder().withDevWorkspaces({ workspaces: devWorkspaces }).build(); } diff --git a/packages/dashboard-frontend/src/components/DevfileEditor/__tests__/DevfileEditor.spec.tsx b/packages/dashboard-frontend/src/components/DevfileEditor/__tests__/DevfileEditor.spec.tsx index 67f8f1cdd..8966d8507 100644 --- a/packages/dashboard-frontend/src/components/DevfileEditor/__tests__/DevfileEditor.spec.tsx +++ b/packages/dashboard-frontend/src/components/DevfileEditor/__tests__/DevfileEditor.spec.tsx @@ -16,7 +16,8 @@ import { Provider } from 'react-redux'; import DevfileEditor from '..'; import { BrandingData } from '../../../services/bootstrap/branding.constant'; import { FakeStoreBuilder } from '../../../store/__mocks__/storeBuilder'; -import { createFakeCheWorkspace } from '../../../store/__mocks__/workspace'; +import { DevWorkspaceBuilder } from '../../../store/__mocks__/devWorkspaceBuilder'; +import { devWorkspaceToDevfile } from '../../../services/workspace-client/devworkspace/converters'; jest.mock('monaco-editor-core', () => { return { @@ -67,9 +68,9 @@ function renderComponent( decorationPattern: string, onChange: (newValue: string, isValid: boolean) => void, ): ReactTestRenderer { - const workspace = createFakeCheWorkspace(workspaceId, workspaceName); + const workspace = new DevWorkspaceBuilder().withId(workspaceId).withName(workspaceName).build(); const store = new FakeStoreBuilder() - .withCheWorkspaces({ + .withDevWorkspaces({ workspaces: [workspace], }) .withBranding({ @@ -78,13 +79,11 @@ function renderComponent( }, } as BrandingData) .build(); + const devfile = devWorkspaceToDevfile(workspace); + return renderer.create( - + , ); } diff --git a/packages/dashboard-frontend/src/components/EditorTools/index.tsx b/packages/dashboard-frontend/src/components/EditorTools/index.tsx index 17b1ea24b..e74e2c332 100644 --- a/packages/dashboard-frontend/src/components/EditorTools/index.tsx +++ b/packages/dashboard-frontend/src/components/EditorTools/index.tsx @@ -24,7 +24,7 @@ import { helpers } from '@eclipse-che/common'; import { ToggleBarsContext } from '../../contexts/ToggleBars'; type Props = { - content: che.Workspace | devfileApi.DevWorkspace | che.WorkspaceDevfile | devfileApi.Devfile; + content: devfileApi.DevWorkspace | devfileApi.Devfile; handleExpand: (isExpand: boolean) => void; }; @@ -112,30 +112,19 @@ class EditorTools extends React.PureComponent { } } - private getName( - content: che.Workspace | devfileApi.DevWorkspace | che.WorkspaceDevfile | devfileApi.Devfile, - ): string | undefined { + private getName(content: devfileApi.DevWorkspace | devfileApi.Devfile): string | undefined { if ((content as devfileApi.DevWorkspace)?.kind === 'DevWorkspace') { return (content as devfileApi.DevWorkspace).metadata.name; - } else if ((content as che.Workspace)?.devfile) { - return (content as che.Workspace).devfile.metadata.name; - } else if ((content as che.WorkspaceDevfile).apiVersion) { - return (content as che.WorkspaceDevfile).metadata.name; - } else if ((content as devfileApi.Devfile).schemaVersion) { + } else { return (content as devfileApi.Devfile).metadata.name; } return undefined; } - private isWorkspace( - content: che.Workspace | devfileApi.DevWorkspace | che.WorkspaceDevfile | devfileApi.Devfile, - ): boolean { + private isWorkspace(content: devfileApi.DevWorkspace | devfileApi.Devfile): boolean { if ((content as devfileApi.DevWorkspace)?.kind === 'DevWorkspace') { return true; } - if ((content as che.Workspace)?.devfile) { - return true; - } return false; } diff --git a/packages/dashboard-frontend/src/components/WorkspaceEditor/index.tsx b/packages/dashboard-frontend/src/components/WorkspaceEditor/index.tsx index 38794d326..62ef31896 100644 --- a/packages/dashboard-frontend/src/components/WorkspaceEditor/index.tsx +++ b/packages/dashboard-frontend/src/components/WorkspaceEditor/index.tsx @@ -36,7 +36,7 @@ const MONACO_CONFIG: editor.IStandaloneEditorConstructionOptions = { }; type Props = { - workspace: che.Workspace | devfileApi.DevWorkspace; + workspace: devfileApi.DevWorkspace; isActive: boolean; }; @@ -80,7 +80,7 @@ export class WorkspaceEditor extends React.PureComponent { } } - private updateContent(workspace: che.Workspace | devfileApi.DevWorkspace): void { + private updateContent(workspace: devfileApi.DevWorkspace): void { if (!this.editor) { return; } diff --git a/packages/dashboard-frontend/src/components/WorkspaceLogs/__tests__/__snapshots__/index.spec.tsx.snap b/packages/dashboard-frontend/src/components/WorkspaceLogs/__tests__/__snapshots__/index.spec.tsx.snap index 2010f9a25..d50cbfffd 100644 --- a/packages/dashboard-frontend/src/components/WorkspaceLogs/__tests__/__snapshots__/index.spec.tsx.snap +++ b/packages/dashboard-frontend/src/components/WorkspaceLogs/__tests__/__snapshots__/index.spec.tsx.snap @@ -46,218 +46,91 @@ exports[`The LogsTab component should render empty state widget correctly 1`] = `; exports[`The LogsTab component should render workspace-logs widget with logs inside correctly 1`] = ` -
- + + +

+ No Logs to display +

-
- 4 - lines -
-
-        

- Pulling image "quay.io/eclipse/che-theia-endpoint-runtime-binary:next" -

-

- Successfully pulled image "quay.io/eclipse/che-theia-endpoint-runtime-binary:next" -

-

- Created container remote-runtime-injectorvpj -

-

- Started container remote-runtime-injectorvpj -

-
+ Logs will be displayed in a running workspace.
-
+ `; exports[`The LogsTab component should render workspace-logs widget without logs correctly 1`] = ` -
- + + +

+ No Logs to display +

-
- 0 - lines -
-
+      Logs will be displayed in a running workspace.
     
-
+ `; diff --git a/packages/dashboard-frontend/src/components/WorkspaceLogs/__tests__/index.spec.tsx b/packages/dashboard-frontend/src/components/WorkspaceLogs/__tests__/index.spec.tsx index 6e272b45b..194fb8e78 100644 --- a/packages/dashboard-frontend/src/components/WorkspaceLogs/__tests__/index.spec.tsx +++ b/packages/dashboard-frontend/src/components/WorkspaceLogs/__tests__/index.spec.tsx @@ -16,11 +16,9 @@ import renderer, { ReactTestRenderer } from 'react-test-renderer'; import { Store } from 'redux'; import WorkspaceLogs from '..'; import { FakeStoreBuilder } from '../../../store/__mocks__/storeBuilder'; -import { - createFakeCheWorkspace, - createFakeWorkspaceLogs, -} from '../../../store/__mocks__/workspace'; +import { createFakeWorkspaceLogs } from '../../../store/__mocks__/workspace'; import { WorkspaceStatus } from '../../../services/helpers/types'; +import { DevWorkspaceBuilder } from '../../../store/__mocks__/devWorkspaceBuilder'; jest.mock('../../../services/helpers/tools', () => { return { @@ -33,16 +31,15 @@ describe('The LogsTab component', () => { const workspaceId = 'workspace-test-id'; const workspaceName = 'workspace-test-name'; const status = WorkspaceStatus.RUNNING; - const runtime: che.WorkspaceRuntime = { - machines: {}, - status: WorkspaceStatus.RUNNING, - activeEnv: 'default', - }; it('should render empty state widget correctly', () => { - const workspace = createFakeCheWorkspace(workspaceId, workspaceName); + const workspace = new DevWorkspaceBuilder() + .withUID(workspaceId) + .withName(workspaceName) + .withNamespace(namespace) + .build(); const store = new FakeStoreBuilder() - .withCheWorkspaces({ + .withDevWorkspaces({ workspaces: [workspace], }) .build(); @@ -53,16 +50,15 @@ describe('The LogsTab component', () => { }); it('should render workspace-logs widget without logs correctly', () => { - const workspace = createFakeCheWorkspace( - workspaceId, - workspaceName, - namespace, - status, - runtime, - ); + const workspace = new DevWorkspaceBuilder() + .withId(workspaceId) + .withName(workspaceName) + .withStatus({ phase: status }) + .withNamespace(namespace) + .build(); const store = new FakeStoreBuilder() - .withCheWorkspaces({ + .withDevWorkspaces({ workspaces: [workspace], }) .build(); @@ -73,13 +69,12 @@ describe('The LogsTab component', () => { }); it('should render workspace-logs widget with logs inside correctly', () => { - const workspace = createFakeCheWorkspace( - workspaceId, - workspaceName, - namespace, - status, - runtime, - ); + const workspace = new DevWorkspaceBuilder() + .withId(workspaceId) + .withName(workspaceName) + .withStatus({ phase: status }) + .withNamespace(namespace) + .build(); const workspacesLogs = createFakeWorkspaceLogs(workspaceId, [ 'Pulling image "quay.io/eclipse/che-theia-endpoint-runtime-binary:next"', 'Successfully pulled image "quay.io/eclipse/che-theia-endpoint-runtime-binary:next"', @@ -87,7 +82,7 @@ describe('The LogsTab component', () => { 'Started container remote-runtime-injectorvpj', ]); const store = new FakeStoreBuilder() - .withCheWorkspaces({ + .withDevWorkspaces({ workspaces: [workspace], workspacesLogs: workspacesLogs, }) diff --git a/packages/dashboard-frontend/src/containers/Loader/Factory/Steps/Apply/Devfile/index.tsx b/packages/dashboard-frontend/src/containers/Loader/Factory/Steps/Apply/Devfile/index.tsx index e4793d3fa..072180848 100644 --- a/packages/dashboard-frontend/src/containers/Loader/Factory/Steps/Apply/Devfile/index.tsx +++ b/packages/dashboard-frontend/src/containers/Loader/Factory/Steps/Apply/Devfile/index.tsx @@ -237,15 +237,8 @@ class StepApplyDevfile extends AbstractLoaderStep { private async createWorkspaceFromDevfile(devfile: devfileApi.Devfile): Promise { const params = Object.fromEntries(this.props.searchParams); - const infrastructureNamespace = this.props.defaultNamespace.name; const optionalFilesContent = this.props.factoryResolver?.optionalFilesContent || {}; - await this.props.createWorkspaceFromDevfile( - devfile, - undefined, - infrastructureNamespace, - params, - optionalFilesContent, - ); + await this.props.createWorkspaceFromDevfile(devfile, params, optionalFilesContent); } private handleCreateWorkspaceError(): void { diff --git a/packages/dashboard-frontend/src/containers/Loader/Workspace/Steps/Initialize/__tests__/index.spec.tsx b/packages/dashboard-frontend/src/containers/Loader/Workspace/Steps/Initialize/__tests__/index.spec.tsx index 74370d4bb..26517e130 100644 --- a/packages/dashboard-frontend/src/containers/Loader/Workspace/Steps/Initialize/__tests__/index.spec.tsx +++ b/packages/dashboard-frontend/src/containers/Loader/Workspace/Steps/Initialize/__tests__/index.spec.tsx @@ -19,8 +19,6 @@ import { screen, waitFor, within } from '@testing-library/react'; import { WorkspaceParams } from '../../../../../../Routes/routes'; import { FakeStoreBuilder } from '../../../../../../store/__mocks__/storeBuilder'; import { DevWorkspaceBuilder } from '../../../../../../store/__mocks__/devWorkspaceBuilder'; -import { CheWorkspaceBuilder } from '../../../../../../store/__mocks__/cheWorkspaceBuilder'; -import { WorkspaceAdapter } from '../../../../../../services/workspace-adapter'; import { List, LoaderStep, LoadingStep } from '../../../../../../components/Loader/Step'; import { MIN_STEP_DURATION_MS, TIMEOUT_TO_STOP_SEC } from '../../../../const'; import { @@ -101,46 +99,6 @@ describe('Workspace Loader, step INITIALIZE', () => { expect(mockOnNextStep).not.toHaveBeenCalled(); }); - test('deprecated workspace', async () => { - const deprecatedId = 'che-wksp-id'; - WorkspaceAdapter.setDeprecatedUIDs([deprecatedId]); - const store = new FakeStoreBuilder() - .withCheWorkspaces({ - workspaces: [ - new CheWorkspaceBuilder() - .withId(deprecatedId) - .withName(workspaceName) - .withNamespace(namespace) - .build(), - ], - }) - .withWorkspacesSettings({ - 'che.devworkspaces.enabled': 'true', - }) - .build(); - - renderComponent(store, loaderSteps); - - jest.advanceTimersByTime(MIN_STEP_DURATION_MS); - - const currentStepId = screen.getByTestId('current-step-id'); - await waitFor(() => expect(currentStepId.textContent).toEqual(stepId)); - - const currentStep = screen.getByTestId(stepId); - const hasError = within(currentStep).getByTestId('hasError'); - expect(hasError.textContent).toEqual('true'); - - const alertTitle = screen.getByTestId('alert-title'); - expect(alertTitle.textContent).toEqual('Failed to open the workspace'); - - const alertBody = screen.getByTestId('alert-body'); - expect(alertBody.textContent).toEqual( - 'The workspace is deprecated. Convert the workspace and try again.', - ); - - expect(mockOnNextStep).not.toHaveBeenCalled(); - }); - test('workspace is STOPPING more than TIMEOUT_TO_STOP_SEC seconds', async () => { const store = new FakeStoreBuilder() .withDevWorkspaces({ diff --git a/packages/dashboard-frontend/src/containers/WorkspaceDetails/__tests__/index.conversion.spec.tsx b/packages/dashboard-frontend/src/containers/WorkspaceDetails/__tests__/index.conversion.spec.tsx deleted file mode 100644 index 070d5302a..000000000 --- a/packages/dashboard-frontend/src/containers/WorkspaceDetails/__tests__/index.conversion.spec.tsx +++ /dev/null @@ -1,332 +0,0 @@ -/* - * Copyright (c) 2018-2021 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 React from 'react'; -import { RouteComponentProps } from 'react-router'; -import { render, screen, waitFor } from '@testing-library/react'; -import { Provider } from 'react-redux'; -import WorkspaceDetailsContainer from '..'; -import { getMockRouterProps } from '../../../services/__mocks__/router'; -import { ROUTE } from '../../../Routes/routes'; -import { FakeStoreBuilder } from '../../../store/__mocks__/storeBuilder'; -import { - ActionCreators, - actionCreators as workspacesActionCreators, -} from '../../../store/Workspaces'; -import { DevWorkspaceBuilder } from '../../../store/__mocks__/devWorkspaceBuilder'; -import { CheWorkspaceBuilder } from '../../../store/__mocks__/cheWorkspaceBuilder'; -import { DEVWORKSPACE_ID_OVERRIDE_ANNOTATION } from '../../../services/devfileApi/devWorkspace/metadata'; -import userEvent from '@testing-library/user-event'; -import devfileApi from '../../../services/devfileApi'; -import { DEVWORKSPACE_METADATA_ANNOTATION } from '../../../services/workspace-client/devworkspace/devWorkspaceClient'; - -const mockUpdateWorkspace = jest.fn(); -const mockCreateWorkspaceFromDevfile = jest.fn(); - -jest.mock('../../../store/Workspaces'); -(workspacesActionCreators.requestWorkspaces as jest.Mock).mockImplementation(() => async () => { - // no-op -}); -(workspacesActionCreators.createWorkspaceFromDevfile as jest.Mock).mockImplementation( - (...args) => - async () => - mockCreateWorkspaceFromDevfile(...args), -); -(workspacesActionCreators.updateWorkspace as jest.Mock).mockImplementation( - (...args) => - async () => - mockUpdateWorkspace(...args), -); - -jest.mock('../../../pages/WorkspaceDetails'); - -describe('Workspace Details container', () => { - // beforeEach(() => {}); - afterEach(() => { - jest.clearAllMocks(); - }); - - describe('devfile v1->v2 conversion', () => { - const workspaceName = 'wksp'; - const cheWorkspaceId = 'che-wksp-id'; - const devWorkspaceId = 'che-wksp-id'; - const devWorkspaceUID = 'uid-1234'; - const cheNamespace = 'user-che'; - const devNamespace = 'user-dev'; - - type Props = { - namespace: string; - workspaceName: string; - }; - - let cheWorkspaceBuilder: CheWorkspaceBuilder; - let devWorkspaceBuilder: DevWorkspaceBuilder; - let fakeStoreBuilder: FakeStoreBuilder; - - beforeEach(() => { - cheWorkspaceBuilder = new CheWorkspaceBuilder() - .withId(cheWorkspaceId) - .withName(workspaceName) - .withNamespace(cheNamespace); - devWorkspaceBuilder = new DevWorkspaceBuilder() - .withId(devWorkspaceId) - .withUID(devWorkspaceUID) - .withName(workspaceName) - .withNamespace(devNamespace); - fakeStoreBuilder = new FakeStoreBuilder() - .withWorkspacesSettings({ 'che.devworkspaces.enabled': 'true' } as che.WorkspaceSettings) - .withInfrastructureNamespace( - [{ name: devNamespace, attributes: { phase: 'Active' } }], - false, - ); - }); - - describe('DevWorkspace', () => { - let routeProps: RouteComponentProps; - - beforeEach(() => { - routeProps = getMockRouterProps(ROUTE.WORKSPACE_DETAILS, { - namespace: devNamespace, - workspaceName, - }); - }); - - it('should not show the Convert button', () => { - const devWorkspace = devWorkspaceBuilder.build(); - const store = fakeStoreBuilder.withDevWorkspaces({ workspaces: [devWorkspace] }).build(); - - render( - - - , - ); - - const showConvertButton = screen.getByTestId('props-show-convert-button'); - expect(showConvertButton).toHaveTextContent('false'); - }); - - it('should not show an old workspace link - without annotation', () => { - const cheWorkspace = cheWorkspaceBuilder - .withAttributes({ - convertedId: devWorkspaceId, - } as che.WorkspaceAttributes) - .build(); - const devWorkspace = devWorkspaceBuilder.build(); - const store = fakeStoreBuilder - .withCheWorkspaces({ workspaces: [cheWorkspace] }) - .withDevWorkspaces({ workspaces: [devWorkspace] }) - .build(); - - render( - - - , - ); - - const oldWorkspacePath = screen.getByTestId('props-old-workspace-path'); - expect(oldWorkspacePath).toHaveTextContent(''); - }); - - it('should not show any old workspace link - with annotation', () => { - const devWorkspace = devWorkspaceBuilder - .withMetadata({ - annotations: { - [DEVWORKSPACE_ID_OVERRIDE_ANNOTATION]: cheWorkspaceId, - }, - }) - .build(); - const store = fakeStoreBuilder.withDevWorkspaces({ workspaces: [devWorkspace] }).build(); - - render( - - - , - ); - - const oldWorkspacePath = screen.getByTestId('props-old-workspace-path'); - expect(oldWorkspacePath).toHaveTextContent(''); - }); - - it('should show the old workspace link', async () => { - const cheWorkspace = cheWorkspaceBuilder - .withAttributes({ - convertedId: devWorkspaceId, - } as che.WorkspaceAttributes) - .build(); - const devWorkspace = devWorkspaceBuilder - .withMetadata({ - annotations: { - [DEVWORKSPACE_ID_OVERRIDE_ANNOTATION]: cheWorkspaceId, - }, - }) - .build(); - const store = fakeStoreBuilder - .withCheWorkspaces({ workspaces: [cheWorkspace] }) - .withDevWorkspaces({ workspaces: [devWorkspace] }) - .build(); - - render( - - - , - ); - - const oldWorkspacePath = screen.getByTestId('props-old-workspace-path'); - const expectedPath = `workspace/${cheNamespace}/${workspaceName}`; - expect(oldWorkspacePath).toHaveTextContent(expectedPath); - }); - }); - - describe('Che workspace', () => { - let routeProps: RouteComponentProps; - - beforeEach(() => { - routeProps = getMockRouterProps(ROUTE.WORKSPACE_DETAILS, { - namespace: cheNamespace, - workspaceName, - }); - }); - - it('should not show the old workspace link', () => { - const cheWorkspace = cheWorkspaceBuilder.build(); - const store = fakeStoreBuilder.withCheWorkspaces({ workspaces: [cheWorkspace] }).build(); - - render( - - - , - ); - - const oldWorkspacePath = screen.getByTestId('props-old-workspace-path'); - expect(oldWorkspacePath).toHaveTextContent(''); - }); - - it('should not show the Convert button - if the converted workspace exists', () => { - const cheWorkspace = cheWorkspaceBuilder - .withAttributes({ - convertedId: devWorkspaceId, - } as che.WorkspaceAttributes) - .build(); - const devWorkspace = devWorkspaceBuilder.build(); - const store = fakeStoreBuilder - .withCheWorkspaces({ workspaces: [cheWorkspace] }) - .withDevWorkspaces({ workspaces: [devWorkspace] }) - .build(); - - render( - - - , - ); - - const showConvertButton = screen.queryByTestId('props-show-convert-button'); - expect(showConvertButton).toHaveTextContent('false'); - }); - - it('should show the Convert button - without attribute', () => { - const cheWorkspace = cheWorkspaceBuilder.build(); - const store = fakeStoreBuilder.withCheWorkspaces({ workspaces: [cheWorkspace] }).build(); - - render( - - - , - ); - - const showConvertButton = screen.queryByTestId('props-show-convert-button'); - expect(showConvertButton).toHaveTextContent('true'); - }); - - it('should show the Convert button - with attribute', async () => { - const cheWorkspace = cheWorkspaceBuilder - .withAttributes({ - convertedId: devWorkspaceUID, - } as che.WorkspaceAttributes) - .build(); - const store = new FakeStoreBuilder() - .withCheWorkspaces({ workspaces: [cheWorkspace] }) - .build(); - - render( - - - , - ); - - const showConvertButton = screen.queryByTestId('props-show-convert-button'); - expect(showConvertButton).toHaveTextContent('true'); - }); - - it('should convert devfile and create a new DevWorkspace', async () => { - const cheWorkspace = cheWorkspaceBuilder.build(); - const devWorkspace = devWorkspaceBuilder - .withMetadata({ - annotations: { - [DEVWORKSPACE_ID_OVERRIDE_ANNOTATION]: cheWorkspaceId, - }, - }) - .build(); - const store = fakeStoreBuilder - .withCheWorkspaces({ workspaces: [cheWorkspace] }) - .withDevWorkspaces({ workspaces: [devWorkspace] }) - .build(); - - const spyHistoryReplace = jest.spyOn(routeProps.history, 'replace'); - - render( - - - , - ); - - const convertButton = screen.getByRole('button', { name: 'Convert' }); - userEvent.click(convertButton); - - await waitFor(() => - expect(spyHistoryReplace).toHaveBeenCalledWith( - expect.objectContaining({ pathname: `/workspace/${devNamespace}/${workspaceName}` }), - ), - ); - - expect(mockCreateWorkspaceFromDevfile).toHaveBeenCalledWith< - Parameters - >( - expect.objectContaining({ - metadata: expect.objectContaining({ - attributes: expect.objectContaining({ - [DEVWORKSPACE_METADATA_ANNOTATION]: { - [DEVWORKSPACE_ID_OVERRIDE_ANNOTATION]: cheWorkspaceId, - }, - }), - }), - } as devfileApi.DevfileLike), - undefined, - devNamespace, - {}, - {}, - ); - - expect(mockUpdateWorkspace).toHaveBeenCalledWith< - Parameters - >( - expect.objectContaining({ - ref: expect.objectContaining({ - attributes: expect.objectContaining({ - convertedId: devWorkspaceUID, - }), - }), - }), - ); - }); - }); - }); -}); diff --git a/packages/dashboard-frontend/src/containers/WorkspaceDetails/__tests__/index.spec.tsx b/packages/dashboard-frontend/src/containers/WorkspaceDetails/__tests__/index.spec.tsx index bb9b41fc2..879b978b1 100644 --- a/packages/dashboard-frontend/src/containers/WorkspaceDetails/__tests__/index.spec.tsx +++ b/packages/dashboard-frontend/src/containers/WorkspaceDetails/__tests__/index.spec.tsx @@ -77,12 +77,14 @@ describe('Workspace Details container', () => { .withId(nextWorkspaceId) .withName(nextWorkspaceName) .withNamespace(namespace); - prevStoreBuilder = new FakeStoreBuilder() - .withWorkspacesSettings({ 'che.devworkspaces.enabled': 'true' } as che.WorkspaceSettings) - .withInfrastructureNamespace([{ name: namespace, attributes: { phase: 'Active' } }], false); - nextStoreBuilder = new FakeStoreBuilder() - .withWorkspacesSettings({ 'che.devworkspaces.enabled': 'true' } as che.WorkspaceSettings) - .withInfrastructureNamespace([{ name: namespace, attributes: { phase: 'Active' } }], false); + prevStoreBuilder = new FakeStoreBuilder().withInfrastructureNamespace( + [{ name: namespace, attributes: { phase: 'Active' } }], + false, + ); + nextStoreBuilder = new FakeStoreBuilder().withInfrastructureNamespace( + [{ name: namespace, attributes: { phase: 'Active' } }], + false, + ); }); afterEach(() => { @@ -222,7 +224,6 @@ describe('Workspace Details container', () => { .build(); const prevStore = new FakeStoreBuilder() - .withWorkspacesSettings({ 'che.devworkspaces.enabled': 'true' } as che.WorkspaceSettings) .withInfrastructureNamespace([{ name: namespace, attributes: { phase: 'Active' } }], false) .withDevWorkspaces({ workspaces: [workspace1, workspace2] }) .build(); @@ -240,7 +241,6 @@ describe('Workspace Details container', () => { // remove workspace1 from store const nextStore = new FakeStoreBuilder() - .withWorkspacesSettings({ 'che.devworkspaces.enabled': 'true' } as che.WorkspaceSettings) .withInfrastructureNamespace([{ name: namespace, attributes: { phase: 'Active' } }], false) .withDevWorkspaces({ workspaces: [workspace2] }) .build(); diff --git a/packages/dashboard-frontend/src/containers/WorkspaceDetails/index.tsx b/packages/dashboard-frontend/src/containers/WorkspaceDetails/index.tsx index c6b24558c..49979b51f 100644 --- a/packages/dashboard-frontend/src/containers/WorkspaceDetails/index.tsx +++ b/packages/dashboard-frontend/src/containers/WorkspaceDetails/index.tsx @@ -27,8 +27,6 @@ import * as WorkspacesStore from '../../store/Workspaces'; import { selectAllWorkspaces, selectIsLoading } from '../../store/Workspaces/selectors'; import { isDevWorkspace } from '../../services/devfileApi'; import { DEVWORKSPACE_ID_OVERRIDE_ANNOTATION } from '../../services/devfileApi/devWorkspace/metadata'; -import { convertDevfileV1toDevfileV2 } from '../../services/devfile/converters'; -import { DEVWORKSPACE_METADATA_ANNOTATION } from '../../services/workspace-client/devworkspace/devWorkspaceClient'; import { selectDefaultNamespace } from '../../store/InfrastructureNamespaces/selectors'; import { isEqual } from 'lodash'; @@ -102,19 +100,6 @@ class WorkspaceDetailsContainer extends React.Component { return buildDetailsLocation(che7Workspace, WorkspaceDetailsTab.DEVFILE); } - private getShowConvertButton(workspace?: Workspace): boolean { - if (!workspace || isDevWorkspace(workspace.ref)) { - return false; - } - const cheWorkspace = workspace.ref; - if (!cheWorkspace.attributes?.convertedId) { - return true; - } else { - const devWorkspaceUID = cheWorkspace.attributes.convertedId; - return this.props.allWorkspaces.every(workspace => workspace.uid !== devWorkspaceUID); - } - } - public componentDidMount(): void { this.init(); } @@ -140,17 +125,14 @@ class WorkspaceDetailsContainer extends React.Component { const { workspace } = this.state; const oldWorkspaceLocation = this.getOldWorkspaceLocation(workspace); - const showConvertButton = this.getShowConvertButton(workspace); return ( await this.handleConversion(workspace)} onSave={async (workspace: Workspace) => await this.onSave(workspace)} /> ); @@ -159,51 +141,6 @@ class WorkspaceDetailsContainer extends React.Component { async onSave(changedWorkspace: Workspace): Promise { await this.props.updateWorkspace(changedWorkspace); } - - private async handleConversion(oldWorkspace: Workspace): Promise { - if (isDevWorkspace(oldWorkspace.ref)) { - throw new Error('This workspace cannot be converted to DevWorkspaces.'); - } - - const devfileV1 = oldWorkspace.devfile as che.WorkspaceDevfile; - const devfileV2 = await convertDevfileV1toDevfileV2(devfileV1); - if (devfileV2.metadata.attributes === undefined) { - devfileV2.metadata.attributes = {}; - } - if (devfileV2.metadata.attributes[DEVWORKSPACE_METADATA_ANNOTATION] === undefined) { - devfileV2.metadata.attributes[DEVWORKSPACE_METADATA_ANNOTATION] = {}; - } - devfileV2.metadata.attributes[DEVWORKSPACE_METADATA_ANNOTATION][ - DEVWORKSPACE_ID_OVERRIDE_ANNOTATION - ] = oldWorkspace.uid; - const defaultNamespace = this.props.defaultNamespace.name; - // create a new workspace - await this.props.createWorkspaceFromDevfile(devfileV2, undefined, defaultNamespace, {}, {}); - - const newWorkspace = this.props.allWorkspaces.find(workspace => { - if (isDevWorkspace(workspace.ref)) { - return ( - workspace.ref.metadata.annotations?.[DEVWORKSPACE_ID_OVERRIDE_ANNOTATION] === - oldWorkspace.uid - ); - } - return false; - }); - - if (!newWorkspace) { - throw new Error('The new DevWorkspace has been created but cannot be obtained.'); - } - - // add 'converted' attribute to the old workspace - // to be able to hide it on the Workspaces page - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - oldWorkspace.ref.attributes!.convertedId = newWorkspace.uid; - await this.props.updateWorkspace(oldWorkspace); - - // return the new workspace page location - const nextLocation = buildDetailsLocation(newWorkspace, WorkspaceDetailsTab.DEVFILE); - this.props.history.replace(nextLocation); - } } const mapStateToProps = (state: AppState) => ({ diff --git a/packages/dashboard-frontend/src/containers/WorkspacesList.tsx b/packages/dashboard-frontend/src/containers/WorkspacesList.tsx index ad98b3279..4731c3c87 100644 --- a/packages/dashboard-frontend/src/containers/WorkspacesList.tsx +++ b/packages/dashboard-frontend/src/containers/WorkspacesList.tsx @@ -23,7 +23,6 @@ import { WorkspaceActionsConsumer } from '../contexts/WorkspaceActions'; import { lazyInject } from '../inversify.config'; import { AppAlerts } from '../services/alerts/appAlerts'; import { selectBranding } from '../store/Branding/selectors'; -import { isDevWorkspace } from '../services/devfileApi'; type Props = MappedProps & { history: History }; @@ -45,21 +44,6 @@ export class WorkspacesListContainer extends React.PureComponent { return Fallback; } - const UIDs = allWorkspaces.map(workspace => workspace.uid); - const filteredWorkspaces = allWorkspaces.filter(workspace => { - if (isDevWorkspace(workspace.ref)) { - return true; - } - if (workspace.isDeprecated === false) { - return true; - } - const convertedUID = workspace.ref.attributes?.convertedId; - if (convertedUID === undefined) { - return true; - } - return UIDs.includes(convertedUID) === false; - }); - return ( @@ -67,7 +51,7 @@ export class WorkspacesListContainer extends React.PureComponent { context.handleAction(action, uid)} showConfirmation={wantDelete => context.showConfirmation(wantDelete)} toDelete={context.toDelete} diff --git a/packages/dashboard-frontend/src/containers/__tests__/WorkspacesList.spec.tsx b/packages/dashboard-frontend/src/containers/__tests__/WorkspacesList.spec.tsx index 8e400fb17..2a63d126e 100644 --- a/packages/dashboard-frontend/src/containers/__tests__/WorkspacesList.spec.tsx +++ b/packages/dashboard-frontend/src/containers/__tests__/WorkspacesList.spec.tsx @@ -20,9 +20,8 @@ import { Action, Store } from 'redux'; import { ActionCreators } from '../../store/Workspaces'; import WorkspacesList from '../WorkspacesList'; import { FakeStoreBuilder } from '../../store/__mocks__/storeBuilder'; -import { CheWorkspaceBuilder } from '../../store/__mocks__/cheWorkspaceBuilder'; import { DevWorkspaceBuilder } from '../../store/__mocks__/devWorkspaceBuilder'; -import { Workspace, WorkspaceAdapter } from '../../services/workspace-adapter'; +import { Workspace } from '../../services/workspace-adapter'; jest.mock('../../store/Workspaces/index', () => { return { @@ -86,91 +85,6 @@ describe('Workspaces List Container', () => { expect(screen.queryByText('Fallback Spinner')).toBeTruthy(); }); }); - - describe('workspaces filter', () => { - describe('in che-server mode', () => { - it('should pass all workspaces', () => { - const devWorkspaceId = 'dev-wksp-0'; - const devWorkspaces = [ - new DevWorkspaceBuilder() - .withId(devWorkspaceId) - .withName('dev-wksp-0') - .withNamespace('user-dev') - .build(), - ]; - const cheWorkspaces = [ - new CheWorkspaceBuilder() - .withId('che-wksp-0') - .withName('che-wksp-0') - .withAttributes({ - created: new Date().toISOString(), - convertedId: devWorkspaceId, - infrastructureNamespace: 'user', - }) - .build(), - new CheWorkspaceBuilder().withId('che-wksp-1').withName('che-wksp-1').build(), - ]; - const store = new FakeStoreBuilder() - .withDevWorkspaces({ workspaces: devWorkspaces }) - .withCheWorkspaces({ workspaces: cheWorkspaces }) - .withWorkspaces({}) - .withWorkspacesSettings({ - 'che.devworkspaces.enabled': 'false', - }) - .build(); - renderComponent(store); - - const workspaces = screen.getAllByTestId('workspace'); - expect(workspaces.length).toEqual(3); - }); - }); - - describe('in devworkspace mode', () => { - it('should pass workspaces but not converted che-server based workspaces', () => { - const deprecated = ['che-wksp-0', 'che-wksp-1', 'che-wksp-2']; - WorkspaceAdapter.setDeprecatedUIDs(deprecated); - const devWorkspaces = [0, 1, 2, 4].map(i => - new DevWorkspaceBuilder() - .withId('dev-wksp-' + i) - .withName('dev-wksp-' + i) - .build(), - ); - const cheWorkspaces = [ - new CheWorkspaceBuilder() - .withId(deprecated[0]) - .withName(deprecated[0]) - .withAttributes({ - created: new Date().toISOString(), - convertedId: WorkspaceAdapter.getUID(devWorkspaces[0]), - infrastructureNamespace: 'user', - }) - .build(), - new CheWorkspaceBuilder() - .withId(deprecated[0]) - .withName(deprecated[0]) - .withAttributes({ - created: new Date().toISOString(), - convertedId: 'deleted-wksp-id', - infrastructureNamespace: 'user', - }) - .build(), - new CheWorkspaceBuilder().withId(deprecated[2]).withName(deprecated[2]).build(), - ]; - const store = new FakeStoreBuilder() - .withCheWorkspaces({ workspaces: cheWorkspaces }) - .withDevWorkspaces({ workspaces: devWorkspaces }) - .withWorkspaces({}) - .withWorkspacesSettings({ - 'che.devworkspaces.enabled': 'true', - }) - .build(); - renderComponent(store); - - const workspaces = screen.getAllByTestId('workspace'); - expect(workspaces.length).toEqual(6); - }); - }); - }); }); function renderComponent(store: Store): RenderResult { diff --git a/packages/dashboard-frontend/src/contexts/WorkspaceActions/Provider.tsx b/packages/dashboard-frontend/src/contexts/WorkspaceActions/Provider.tsx index d8e89da15..7534e7a0a 100644 --- a/packages/dashboard-frontend/src/contexts/WorkspaceActions/Provider.tsx +++ b/packages/dashboard-frontend/src/contexts/WorkspaceActions/Provider.tsx @@ -34,7 +34,7 @@ import { AppState } from '../../store'; import { selectAllWorkspaces } from '../../store/Workspaces/selectors'; import * as WorkspacesStore from '../../store/Workspaces'; import { WorkspaceActionsContext } from '.'; -import { isCheWorkspace, Workspace } from '../../services/workspace-adapter'; +import { Workspace } from '../../services/workspace-adapter'; type Deferred = { resolve: () => void; @@ -71,22 +71,14 @@ export class WorkspaceActionsProvider extends React.Component { * open the action in a new tab for DevWorkspaces */ private async handleLocation(location: Location, workspace: Workspace): Promise { - if (workspace.isDevWorkspace) { - const link = toHref(this.props.history, location); - window.open(link, workspace.uid); - } else { - return location; - } + const link = toHref(this.props.history, location); + window.open(link, workspace.uid); } private async deleteWorkspace( action: WorkspaceAction, workspace: Workspace, ): Promise { - if (isCheWorkspace(workspace.ref) && !(workspace.isStopped || workspace.hasError)) { - throw new Error('Only STOPPED workspaces can be deleted.'); - } - this.deleting.add(workspace.uid); this.setState({ toDelete: Array.from(this.deleting), diff --git a/packages/dashboard-frontend/src/contexts/WorkspaceActions/__tests__/index.spec.tsx b/packages/dashboard-frontend/src/contexts/WorkspaceActions/__tests__/index.spec.tsx index 6a14e1543..dca7c39b8 100644 --- a/packages/dashboard-frontend/src/contexts/WorkspaceActions/__tests__/index.spec.tsx +++ b/packages/dashboard-frontend/src/contexts/WorkspaceActions/__tests__/index.spec.tsx @@ -19,11 +19,11 @@ import WorkspaceActionsProvider from '../Provider'; import { WorkspaceAction } from '../../../services/helpers/types'; import { ActionContextType, WorkspaceActionsConsumer } from '..'; import { FakeStoreBuilder } from '../../../store/__mocks__/storeBuilder'; -import { createFakeCheWorkspace } from '../../../store/__mocks__/workspace'; import { ActionCreators } from '../../../store/Workspaces'; import { AppThunk } from '../../../store'; import { Workspace } from '../../../services/workspace-adapter'; import { createHashHistory } from 'history'; +import { DevWorkspaceBuilder } from '../../../store/__mocks__/devWorkspaceBuilder'; jest.mock('../../../store/Workspaces/index', () => { /* eslint-disable @typescript-eslint/no-unused-vars */ @@ -277,10 +277,13 @@ describe('Workspace Actions', () => { function createFakeStore(): Store { const workspaces = [0, 1, 2, 3, 4].map(i => - createFakeCheWorkspace('workspace-' + i, 'workspace-' + i), + new DevWorkspaceBuilder() + .withUID('workspace-' + i) + .withName('workspace-' + i) + .build(), ); return new FakeStoreBuilder() - .withCheWorkspaces({ + .withDevWorkspaces({ workspaces, }) .build(); diff --git a/packages/dashboard-frontend/src/pages/GetStarted/GetStartedTab/ImportFromGit/index.tsx b/packages/dashboard-frontend/src/pages/GetStarted/GetStartedTab/ImportFromGit/index.tsx index 2598561e0..334e2e13f 100644 --- a/packages/dashboard-frontend/src/pages/GetStarted/GetStartedTab/ImportFromGit/index.tsx +++ b/packages/dashboard-frontend/src/pages/GetStarted/GetStartedTab/ImportFromGit/index.tsx @@ -12,33 +12,18 @@ import React from 'react'; import { connect, ConnectedProps } from 'react-redux'; -import { - Alert, - AlertActionCloseButton, - AlertGroup, - AlertVariant, - Flex, - FlexItem, - FormGroup, - Text, - TextContent, - TextVariants, -} from '@patternfly/react-core'; -import common from '@eclipse-che/common'; +import { Flex, FlexItem, FormGroup, Text, TextContent, TextVariants } from '@patternfly/react-core'; import { AppState } from '../../../../store'; import * as DevfileRegistriesStore from '../../../../store/DevfileRegistries'; import * as FactoryResolverStore from '../../../../store/FactoryResolver'; import { GitRepoLocationInput } from './GitRepoLocationInput'; -import { AlertItem } from '../../../../services/helpers/types'; import { selectWorkspacesSettings } from '../../../../store/Workspaces/Settings/selectors'; -import { isDevworkspacesEnabled } from '../../../../services/helpers/devworkspace'; type Props = MappedProps & { onDevfileResolve: (resolverState: FactoryResolverStore.ResolverState, location: string) => void; }; type State = { isLoading: boolean; - alerts: AlertItem[]; }; export class ImportFromGit extends React.PureComponent { @@ -50,7 +35,6 @@ export class ImportFromGit extends React.PureComponent { this.state = { isLoading: false, - alerts: [], }; this.devfileLocationRef = React.createRef(); } @@ -60,59 +44,16 @@ export class ImportFromGit extends React.PureComponent { } private async handleLocationChange(location: string): Promise { - // if devWorkspace is enabled - // use factory workflow to load the git location - const cheDevworkspaceEnabled = isDevworkspacesEnabled(this.props.workspacesSettings); - if (cheDevworkspaceEnabled) { - const factoryUrl = `${window.location.origin}/#${location}`; - // open a new page to handle that - window.open(factoryUrl, '_blank'); - return; - } - - try { - this.setState({ isLoading: true }); - await this.props.requestFactoryResolver(location); - // at this point the resolver object is defined - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const resolver = this.factoryResolver.resolver!; - this.props.onDevfileResolve(resolver, location); - this.setState({ isLoading: false }); - } catch (e) { - this.setState({ isLoading: false }); - this.devfileLocationRef.current?.invalidateInput(); - this.showAlert({ - key: 'load-devfile-resolver-failed', - title: common.helpers.errors.getMessage(e), - variant: AlertVariant.danger, - }); - } - } - - private showAlert(alert: AlertItem): void { - const alerts = [...this.state.alerts, alert]; - this.setState({ alerts }); - } - - private removeAlert(key: string): void { - this.setState({ alerts: [...this.state.alerts.filter(al => al.key !== key)] }); + const factoryUrl = `${window.location.origin}/#${location}`; + // open a new page to handle that + window.open(factoryUrl, '_blank'); } public render(): React.ReactNode { - const { alerts, isLoading } = this.state; + const { isLoading } = this.state; return ( <> - - {alerts.map(({ title, variant, key }) => ( - this.removeAlert(key)} />} - /> - ))} - ({ const connector = connect(mapStateToProps, { ...DevfileRegistriesStore.actionCreators, - ...FactoryResolverStore.actionCreators, }); type MappedProps = ConnectedProps; diff --git a/packages/dashboard-frontend/src/pages/GetStarted/GetStartedTab/SamplesListGallery.tsx b/packages/dashboard-frontend/src/pages/GetStarted/GetStartedTab/SamplesListGallery.tsx index 398c77a50..ed41366e6 100644 --- a/packages/dashboard-frontend/src/pages/GetStarted/GetStartedTab/SamplesListGallery.tsx +++ b/packages/dashboard-frontend/src/pages/GetStarted/GetStartedTab/SamplesListGallery.tsx @@ -37,7 +37,6 @@ import { } from '../../../store/DevfileRegistries/selectors'; import { selectWorkspacesSettings } from '../../../store/Workspaces/Settings/selectors'; import * as FactoryResolverStore from '../../../store/FactoryResolver'; -import { isDevworkspacesEnabled } from '../../../services/helpers/devworkspace'; import { selectDefaultEditor } from '../../../store/Plugins/devWorkspacePlugins/selectors'; import { selectEditors } from '../../../store/Plugins/chePlugins/selectors'; @@ -157,8 +156,7 @@ export class SamplesListGallery extends React.PureComponent { } this.isLoading = true; try { - const cheDevworkspaceEnabled = isDevworkspacesEnabled(this.props.workspacesSettings); - if (cheDevworkspaceEnabled && meta.links.v2) { + if (meta.links.v2) { const link = encodeURIComponent(meta.links.v2); let devWorkspace = ''; if (!editor && this.props.defaultEditor) { @@ -178,18 +176,17 @@ export class SamplesListGallery extends React.PureComponent { } // open a new page to handle that window.open(factoryUrl, '_blank'); - this.isLoading = false; - return; + } else if (meta.links.self) { + const devfileContent = (await this.props.requestDevfile(meta.links.self)) as string; + this.props.onCardClick(devfileContent, meta.displayName); } - const devfileContent = (await this.props.requestDevfile(meta.links.self)) as string; - this.props.onCardClick(devfileContent, meta.displayName); } catch (e) { console.warn('Failed to load devfile.', e); - + const key = meta.links.self ? meta.links.self : meta.links.v2 || meta.displayName; const alerts = [ ...this.state.alerts, { - key: meta.links.self, + key, title: `Failed to load devfile "${meta.displayName}"`, variant: AlertVariant.warning, }, @@ -218,7 +215,7 @@ export class SamplesListGallery extends React.PureComponent { .sort(SamplesListGallery.sortByDisplayName) .sort(SamplesListGallery.sortByVisibleTag) .sort(SamplesListGallery.sortByEmptyWorkspaceTag) - .map(meta => ( + .map((meta: che.DevfileMetaData) => ( { const FakeSamplesListGallery = (props: { @@ -71,10 +71,7 @@ describe('Samples list tab', () => { pvcStrategy: preferredStorageType, }, } as dashboardBackendApi.IServerConfig) - .withWorkspacesSettings({ - 'che.workspace.storage.preferred_type': preferredStorageType, - } as che.WorkspaceSettings) - .withCheWorkspaces({ + .withDevWorkspaces({ workspaces: [], }) .withBranding(brandingData) @@ -118,12 +115,7 @@ describe('Samples list tab', () => { sampleItem.click(); expect(onDevfileMock).toBeCalledTimes(1); expect(onDevfileMock).toHaveBeenCalledWith( - expect.not.stringContaining('persistVolumes:'), - testStackName, - undefined, - ); - expect(onDevfileMock).toHaveBeenCalledWith( - expect.not.stringContaining('asyncPersist:'), + expect.not.stringContaining('controller.devfile.io/storage-type:'), testStackName, undefined, ); @@ -142,12 +134,7 @@ describe('Samples list tab', () => { sampleItem.click(); expect(onDevfileMock).toHaveBeenCalledWith( - expect.not.stringContaining('persistVolumes:'), - testStackName, - undefined, - ); - expect(onDevfileMock).toHaveBeenCalledWith( - expect.not.stringContaining('asyncPersist:'), + expect.not.stringContaining('controller.devfile.io/storage-type:'), testStackName, undefined, ); @@ -168,7 +155,7 @@ describe('Samples list tab', () => { sampleItem.click(); expect(onDevfileMock).toHaveBeenCalledWith( - expect.stringContaining("persistVolumes: 'false'"), + expect.stringContaining('controller.devfile.io/storage-type: ephemeral'), testStackName, undefined, ); @@ -186,18 +173,13 @@ describe('Samples list tab', () => { sampleItem.click(); expect(onDevfileMock).toHaveBeenCalledWith( - expect.stringContaining("persistVolumes: 'false'"), - testStackName, - undefined, - ); - expect(onDevfileMock).toHaveBeenCalledWith( - expect.stringContaining("asyncPersist: 'true'"), + expect.stringContaining('controller.devfile.io/storage-type: async'), testStackName, undefined, ); }); - it('should correctly apply the storage type "async"', () => { + it('should correctly apply the storage type "ephemeral"', () => { const preferredStorageType = 'persistent'; renderComponent(preferredStorageType); @@ -212,7 +194,7 @@ describe('Samples list tab', () => { sampleItem.click(); expect(onDevfileMock).toHaveBeenCalledWith( - expect.stringContaining("persistVolumes: 'false'"), + expect.stringContaining('controller.devfile.io/storage-type: ephemeral'), testStackName, undefined, ); @@ -233,12 +215,7 @@ describe('Samples list tab', () => { sampleItem.click(); expect(onDevfileMock).toHaveBeenCalledWith( - expect.not.stringContaining('persistVolumes:'), - testStackName, - undefined, - ); - expect(onDevfileMock).toHaveBeenCalledWith( - expect.not.stringContaining('asyncPersist:'), + expect.not.stringContaining('controller.devfile.io/storage-type:'), testStackName, undefined, ); diff --git a/packages/dashboard-frontend/src/pages/GetStarted/GetStartedTab/__tests__/SamplesListGallery.spec.tsx b/packages/dashboard-frontend/src/pages/GetStarted/GetStartedTab/__tests__/SamplesListGallery.spec.tsx index 0ad3722d2..ec648f9f7 100644 --- a/packages/dashboard-frontend/src/pages/GetStarted/GetStartedTab/__tests__/SamplesListGallery.spec.tsx +++ b/packages/dashboard-frontend/src/pages/GetStarted/GetStartedTab/__tests__/SamplesListGallery.spec.tsx @@ -19,8 +19,8 @@ import { Provider } from 'react-redux'; import mockMetadata from '../../__tests__/devfileMetadata.json'; import { FakeStoreBuilder } from '../../../../store/__mocks__/storeBuilder'; import { BrandingData } from '../../../../services/bootstrap/branding.constant'; -import { Devfile } from '../../../../services/workspace-adapter'; import { ConvertedState } from '../../../../store/FactoryResolver'; +import devfileApi from '../../../../services/devfileApi'; const requestFactoryResolverMock = jest.fn().mockResolvedValue(undefined); @@ -66,45 +66,14 @@ describe('Samples List Gallery', () => { ); } - it('should render cards with metadata', () => { - // eslint-disable-next-line - const store = createFakeStoreWithMetadata(); - renderGallery(store); - - const cards = screen.getAllByRole('article'); - expect(cards.length).toEqual(26); - }); - it('should render cards with v2 metadata only', () => { // eslint-disable-next-line - const store = createFakeStoreWithMetadata(true); + const store = createFakeStoreWithMetadata(); renderGallery(store); const cards = screen.getAllByRole('article'); // only one link is with devfile v2 format - expect(cards.length).toEqual(1); - }); - - it('should handle "onCardClick" event', async () => { - let resolveFn: { - (value?: unknown): void; - }; - const onCardClickedPromise = new Promise(resolve => (resolveFn = resolve)); - const onCardClicked = jest.fn(() => resolveFn()); - - // eslint-disable-next-line - const store = createFakeStoreWithMetadata(); - renderGallery(store, onCardClicked); - - (mockAxios.get as any).mockResolvedValueOnce({ - data: {}, - }); - - const cardHeader = screen.getByText('Go'); - fireEvent.click(cardHeader); - - await onCardClickedPromise; - expect(onCardClicked).toHaveBeenCalled(); + expect(cards.length).toEqual(18); }); it('should handle "onCardClick" event for v2 metadata', async () => { @@ -114,18 +83,18 @@ describe('Samples List Gallery', () => { const onCardClicked = jest.fn(() => resolveFn()); // eslint-disable-next-line - const store = createFakeStoreWithMetadata(true); + const store = createFakeStoreWithMetadata(); renderGallery(store, onCardClicked); (mockAxios.get as any).mockResolvedValueOnce({ data: {}, }); const windowSpy = spyOn(window, 'open'); - const cardHeader = screen.getByText('Java with Spring Boot and MySQL'); + const cardHeader = screen.getByText('Java with Spring Boot and MongoDB'); fireEvent.click(cardHeader); jest.runOnlyPendingTimers(); expect(windowSpy).toBeCalledWith( - 'http://localhost/#/load-factory?url=http%3A%2F%2Fmy-fake-repository.com%2F', + 'http://localhost/#/load-factory?url=https%3A%2F%2Fgithub.com%2Fche-samples%2Fjava-guestbook%2Ftree%2Fdevfilev2', '_blank', ); }); @@ -140,7 +109,7 @@ describe('Samples List Gallery', () => { }); }); -function createFakeStore(metadata?: che.DevfileMetaData[], devWorkspaceEnabled?: boolean): Store { +function createFakeStore(metadata?: che.DevfileMetaData[]): Store { const registries = {} as { [location: string]: { metadata?: che.DevfileMetaData[]; @@ -152,21 +121,16 @@ function createFakeStore(metadata?: che.DevfileMetaData[], devWorkspaceEnabled?: metadata, }; } - const workspaceSettings = {} as che.WorkspaceSettings; - if (devWorkspaceEnabled) { - workspaceSettings['che.devworkspaces.enabled'] = 'true'; - } return new FakeStoreBuilder() .withBranding({ docs: { storageTypes: 'https://docs.location', }, } as BrandingData) - .withWorkspacesSettings(workspaceSettings) .withFactoryResolver({ resolver: { source: 'devfile.yaml', - devfile: {} as Devfile, + devfile: {} as devfileApi.Devfile, location: 'http://fake-location', scm_info: { clone_url: 'http://github.com/clone-url', @@ -186,6 +150,6 @@ function createFakeStoreWithoutMetadata(): Store { return createFakeStore(); } -function createFakeStoreWithMetadata(devWorkspaceEnabled?: boolean): Store { - return createFakeStore(mockMetadata, devWorkspaceEnabled); +function createFakeStoreWithMetadata(): Store { + return createFakeStore(mockMetadata); } diff --git a/packages/dashboard-frontend/src/pages/GetStarted/__tests__/GetStarted.spec.tsx b/packages/dashboard-frontend/src/pages/GetStarted/__tests__/GetStarted.spec.tsx index edf0e98d5..79b97e827 100644 --- a/packages/dashboard-frontend/src/pages/GetStarted/__tests__/GetStarted.spec.tsx +++ b/packages/dashboard-frontend/src/pages/GetStarted/__tests__/GetStarted.spec.tsx @@ -18,8 +18,10 @@ import React from 'react'; import GetStarted from '..'; import { FakeStoreBuilder } from '../../../store/__mocks__/storeBuilder'; import { BrandingData } from '../../../services/bootstrap/branding.constant'; -import { constructWorkspace, Devfile, Workspace } from '../../../services/workspace-adapter'; -import { CheWorkspaceBuilder } from '../../../store/__mocks__/cheWorkspaceBuilder'; +import { constructWorkspace, Workspace } from '../../../services/workspace-adapter'; +import { DevWorkspaceBuilder } from '../../../store/__mocks__/devWorkspaceBuilder'; +import { devfileToDevWorkspace } from '../../../services/workspace-client/devworkspace/converters'; +import devfileApi from '../../../services/devfileApi'; const setWorkspaceQualifiedName = jest.fn(); const createWorkspaceFromDevfileMock = jest.fn().mockResolvedValue(undefined); @@ -28,32 +30,25 @@ const startWorkspaceMock = jest.fn().mockResolvedValue(undefined); const namespace = 'che'; const workspaceName = 'wksp-test'; const dummyDevfile = { - apiVersion: '1.0.0', + schemaVersion: '2.2.0', metadata: { name: workspaceName, + namespace, }, -} as Devfile; -const workspace = new CheWorkspaceBuilder() - .withDevfile(dummyDevfile as che.WorkspaceDevfile) +} as devfileApi.Devfile; +const workspace = new DevWorkspaceBuilder() + .withName(workspaceName) .withNamespace(namespace) .build(); jest.mock('../../../store/Workspaces/index', () => { return { actionCreators: { - createWorkspaceFromDevfile: - (devfile, namespace, infrastructureNamespace, attributes) => - async (): Promise => { - createWorkspaceFromDevfileMock(devfile, namespace, infrastructureNamespace, attributes); - return constructWorkspace({ - id: 'id-wksp-test', - attributes, - namespace, - devfile: dummyDevfile as che.WorkspaceDevfile, - temporary: false, - status: 'STOPPED', - }); - }, + createWorkspaceFromDevfile: (devfile, attributes) => async (): Promise => { + createWorkspaceFromDevfileMock(devfile, attributes); + const devWorkspace = devfileToDevWorkspace(devfile, 'che', false); + return constructWorkspace(devWorkspace); + }, startWorkspace: workspace => async (): Promise => { startWorkspaceMock(workspace); }, @@ -93,15 +88,13 @@ describe('Quick Add page', () => { await waitFor(() => expect(screen.getByRole('button', { name: 'Dummy Devfile' })).toBeTruthy()); - const devfileButton = screen.getByRole('button', { name: 'Dummy Devfile' }); + const devfileButton = await screen.findByRole('button', { name: 'Dummy Devfile' }); + expect(devfileButton).toBeTruthy(); devfileButton.click(); - expect(createWorkspaceFromDevfileMock).toHaveBeenCalledWith( - dummyDevfile, - undefined, - namespace, - { stackName: 'dummyStackName' }, - ); + expect(createWorkspaceFromDevfileMock).toHaveBeenCalledWith(dummyDevfile, { + stackName: 'dummyStackName', + }); }); it('should have correct masthead when Quick Add tab is active', () => { @@ -130,13 +123,12 @@ function createFakeStore(): Store { .withBranding({ name: 'test', } as BrandingData) - .withCheWorkspaces({ + .withDevWorkspaces({ workspaces: [workspace], }) .withWorkspaces({ - workspaceUID: workspace.id, - namespace: namespace, - workspaceName: workspace.devfile.metadata.name, + namespace: workspace.metadata.namespace, + workspaceName: workspace.metadata.name, }) .withInfrastructureNamespace([{ name: namespace, attributes: { phase: 'Active' } }], false) .build(); diff --git a/packages/dashboard-frontend/src/pages/GetStarted/__tests__/devfileMetadata.json b/packages/dashboard-frontend/src/pages/GetStarted/__tests__/devfileMetadata.json index ecb385669..ab266018c 100644 --- a/packages/dashboard-frontend/src/pages/GetStarted/__tests__/devfileMetadata.json +++ b/packages/dashboard-frontend/src/pages/GetStarted/__tests__/devfileMetadata.json @@ -1,237 +1,273 @@ [ - { - "displayName": "NodeJS Angular Web Application", - "description": "Stack for developing NodeJS Angular Web Application", - "tags": ["NodeJS", "Angular", "Alpine"], - "icon": "/images/angular.svg", - "globalMemoryLimit": "2686Mi", - "links": { - "self": "/devfiles/angular/devfile.yaml" - } - }, - { - "displayName": "Apache Camel K", - "description": "Stack with tooling ready to develop Integration projects with Apache Camel K", - "tags": ["Apache Camel K", "Red Hat Fuse", "Integration"], - "icon": "/images/camelk.svg", - "globalMemoryLimit": "2850Mi", - "links": { - "self": "/devfiles/apache-camel-k/devfile.yaml" - } - }, { "displayName": "Apache Camel based on Spring Boot", "description": "Stack with environment ready to develop Integration projects with Apache Camel based on Spring Boot.", - "tags": ["Java", "OpenJDK", "Maven", "Debian", "Apache Camel", "Red Hat Fuse", "Spring Boot"], + "tags": [ + "Community", + "Java", + "OpenJDK", + "Maven", + "Debian", + "Apache Camel", + "Red Hat Fuse", + "Spring Boot" + ], "icon": "/images/camelk.svg", - "globalMemoryLimit": "2930Mi", "links": { - "self": "/devfiles/apache-camel-springboot/devfile.yaml" + "v2": "https://github.com/che-samples/fuse-rest-http-booster/tree/devfilev2" } }, { - "displayName": "Mainframe Basic Stack", - "description": "Che4z Mainframe Basic Stack is an all-in-one extension pack for developers working with z/OS applications, suitable for all levels of mainframe experience, even beginners.", + "displayName": "Java with Spring Boot and MongoDB", + "description": "Java stack with OpenJDK 8, MongoDB and Spring Boot Guestbook demo application", "tags": [ - "Che4z", - "Zowe", - "mainframe", - "Endevor", - "explorer", - "dataset", - "COBOL", - "JCL", - "zOS", - "USS", - "HLASM", - "InterTest", - "debug" + "Community", + "Java", + "OpenJDK", + "Maven", + "Spring Boot", + "MongoDB" ], - "icon": "/images/che4z.svg", - "globalMemoryLimit": "3Gi", + "icon": "/images/java.svg", "links": { - "self": "/devfiles/che4z/devfile.yaml" + "v2": "https://github.com/che-samples/java-guestbook/tree/devfilev2" } }, { - "displayName": "C/C++", - "description": "Stack with C/C++ and Clang 8", - "tags": ["C/C++", "clang", "g++", "gdb"], - "icon": "/images/cpp.svg", - "globalMemoryLimit": "1686Mi", + "displayName": "Java Lombok", + "description": "Java Stack with Lombok 1.18.18, OpenJDK 11 and Maven 3.6.0", + "tags": [ + "Community", + "Java", + "OpenJDK", + "Maven", + "Debian", + "Lombok" + ], + "icon": "/images/lombok.svg", "links": { - "self": "/devfiles/cpp/devfile.yaml" + "v2": "https://github.com/che-samples/lombok-project-sample/tree/devfilev2" } }, { - "displayName": ".NET Core", - "description": "Stack with .Net 2.2", - "tags": ["Debian", "Dotnet", "C#"], - "icon": "/images/dotnetcore.svg", - "globalMemoryLimit": "2710Mi", + "displayName": "Scala", + "description": "Scala Stack with OpenJDK 11 and sbt 1.x", + "tags": [ + "Community", + "Scala", + "OpenJDK", + "sbt", + "Debian" + ], + "icon": "/images/scala.svg", "links": { - "self": "/devfiles/dotnet/devfile.yaml" + "v2": "https://github.com/che-samples/scala-sbt/tree/devfilev2" } }, { "displayName": "ASP.NET Core Web Application", "description": "Stack for developing ASP.NET Core Web Application", - "tags": ["Debian", "Dotnet", "C#", "ASP.NET"], + "tags": [ + "Community", + "Debian", + "Dotnet", + "C#", + "ASP.NET" + ], "icon": "/images/dotnetcore.svg", - "globalMemoryLimit": "2710Mi", - "links": { - "self": "/devfiles/dotnet-asp.net/devfile.yaml" - } - }, - { - "displayName": "Go", - "description": "Stack with Go 1.12.10", - "tags": ["Debian", "Go"], - "icon": "/images/go.svg", - "globalMemoryLimit": "1686Mi", "links": { - "self": "/devfiles/go/devfile.yaml" + "v2": "https://github.com/che-samples/aspnetcore-realworld-example-app/tree/devfilev2" } }, { - "displayName": "Java Gradle", - "description": "Java Stack with OpenJDK 11 and Gradle 6.2.1", - "tags": ["Java", "OpenJDK", "Gradle", "Ubuntu"], - "icon": "/images/java.svg", - "globalMemoryLimit": "2674Mi", - "links": { - "self": "/devfiles/java-gradle/devfile.yaml" - } - }, - { - "displayName": "Java Maven", - "description": "Java Stack with OpenJDK 11 and Maven 3.6.0", - "tags": ["Java", "OpenJDK", "Maven", "Debian"], - "icon": "/images/java.svg", - "globalMemoryLimit": "2674Mi", + "displayName": "Node.js React Web Application", + "description": "Stack for developing Node.js React Web Application", + "tags": [ + "Community", + "Node.js", + "React", + "Redux", + "RealWorld" + ], + "icon": "/images/nodejs.svg", "links": { - "self": "/devfiles/java-maven/devfile.yaml" + "v2": "https://github.com/che-samples/nodejs-react-redux/tree/devfilev2" } }, { - "displayName": "Java with Spring Boot and MongoDB", - "description": "Java stack with OpenJDK 8, MongoDB and Spring Boot Guestbook demo application", - "tags": ["Java", "OpenJDK", "Maven", "Spring Boot", "MongoDB"], - "icon": "/images/java.svg", - "globalMemoryLimit": "2884Mi", + "displayName": "Node.js Angular Web Application", + "description": "Stack for developing Node.js Angular Web Application", + "tags": [ + "Community", + "Node.js", + "Angular", + "Alpine" + ], + "icon": "/images/angular.svg", "links": { - "self": "/devfiles/java-mongo/devfile.yaml" + "v2": "https://github.com/che-samples/nodejs-angular/tree/devfilev2" } }, { - "displayName": "Java with Spring Boot and MySQL", - "description": "Java stack with OpenJDK 8, MySQL and Spring Boot Petclinic demo application", - "tags": ["Java", "OpenJDK", "Maven", "Spring Boot", "MySQL"], - "icon": "/images/springboot.svg", - "globalMemoryLimit": "3372Mi", + "displayName": "PHP Symfony", + "description": "PHP Stack with Symfony Demo Application https://symfony.com/", + "tags": [ + "Community", + "PHP", + "Apache", + "MySQL", + "Symfony", + "Debian", + "Centos" + ], + "icon": "/images/php.svg", "links": { - "self": "/devfiles/java-mysql/devfile.yaml", - "v2": "http://my-fake-repository.com/" + "v2": "https://github.com/che-samples/php-symfony/tree/devfilev2" } }, { - "displayName": "Java Spring Boot", - "description": "Java stack with OpenJDK 8 and Spring Boot Petclinic demo application", - "tags": ["Java", "OpenJDK", "Maven", "Spring Boot"], - "icon": "/images/springboot.svg", - "globalMemoryLimit": "3072Mi", + "displayName": "Quarkus REST API", + "description": "Quarkus stack with a default REST endpoint application sample", + "tags": [ + "Community", + "Java", + "Quarkus", + "OpenJDK", + "Maven", + "Debian" + ], + "icon": "/images/quarkus.svg", "links": { - "self": "/devfiles/java-web-spring/devfile.yaml" + "v2": "https://github.com/che-samples/quarkus-quickstarts/tree/devfilev2" } }, { - "displayName": "Java Vert.x", - "description": "Java stack with OpenJDK 8 and Vert.x demo application", - "tags": ["Java", "OpenJDK", "Maven", "Vertx"], - "icon": "/images/vertx.svg", - "globalMemoryLimit": "2674Mi", + "displayName": "Apache Camel K", + "description": "Stack with tooling ready to develop Integration projects with Apache Camel K", + "tags": [ + "Community", + "Apache Camel K", + "Red Hat Fuse", + "Integration" + ], + "icon": "/images/camelk.svg", "links": { - "self": "/devfiles/java-web-vertx/devfile.yaml" + "v2": "https://github.com/che-samples/apache-camel-k/tree/devfilev2" } }, { - "displayName": "NodeJS Express Web Application", - "description": "Stack with NodeJS 10", - "tags": ["NodeJS", "Express", "ubi8"], + "displayName": "Node.js Express Web Application", + "description": "Stack with Node.js 10", + "tags": [ + "Community", + "Node.js", + "Express", + "ubi8" + ], "icon": "/images/nodejs.svg", - "globalMemoryLimit": "1686Mi", "links": { - "self": "/devfiles/nodejs/devfile.yaml" + "v2": "https://github.com/che-samples/web-nodejs-sample/tree/devfilev2" } }, { - "displayName": "NodeJS MongoDB Web Application", - "description": "Stack with NodeJS 10 and MongoDB 3.4", - "tags": ["NodeJS", "Express", "MongoDB", "RealWorld", "ubi8", "Centos"], + "displayName": "Node.js Web Application based on Yarn", + "description": "Stack for developing Node.js Web Application based on Yarn", + "tags": [ + "Community", + "Node.js", + "Alpine", + "Yarn", + "React" + ], "icon": "/images/nodejs.svg", - "globalMemoryLimit": "1686Mi", "links": { - "self": "/devfiles/nodejs-mongo/devfile.yaml" + "v2": "https://github.com/che-samples/react-web-app/tree/devfilev2" } }, { - "displayName": "NodeJS React Web Application", - "description": "Stack for developing NodeJS React Web Application", - "tags": ["NodeJS", "React", "Redux", "RealWorld"], - "icon": "/images/nodejs.svg", - "globalMemoryLimit": "1686Mi", + "displayName": "Bash", + "description": "Stack with environment ready to develop bash scripts.", + "tags": [ + "Community", + "Bash", + "Shell" + ], + "icon": "/images/che.svg", "links": { - "self": "/devfiles/nodejs-react/devfile.yaml" + "v2": "https://github.com/che-samples/bash/tree/devfilev2" } }, { - "displayName": "NodeJS Web Application based on Yarn", - "description": "Stack for developing NodeJS Web Application based on Yarn", - "tags": ["NodeJS", "Alpine", "Yarn", "React"], - "icon": "/images/nodejs.svg", - "globalMemoryLimit": "2198Mi", + "displayName": "Python Django", + "description": "Python Stack with Python 3.8 and Django application", + "tags": [ + "Community", + "Centos", + "Python", + "pip" + ], + "icon": "/images/python.svg", "links": { - "self": "/devfiles/nodejs-yarn/devfile.yaml" + "v2": "https://github.com/che-samples/django-realworld-example-app/tree/devfile2" } }, { - "displayName": "PHP Laravel with MySQL", - "description": "PHP Stack with Laravel and MySQL real world application", - "tags": ["PHP", "Apache", "MySQL", "Centos", "Debian"], - "icon": "/images/php.svg", - "globalMemoryLimit": "2686Mi", + "displayName": "C/C++", + "description": "Stack with C/C++ and Clang 8", + "tags": [ + "Community", + "C/C++", + "Clang", + "g++", + "GDB" + ], + "icon": "/images/cpp.svg", "links": { - "self": "/devfiles/php-laravel/devfile.yaml" + "v2": "https://github.com/che-samples/cpp-hello-world/tree/devfilev2" } }, { - "displayName": "PHP with MySQL", - "description": "PHP Stack with MySQL and simple database application", - "tags": ["PHP", "Apache", "MySQL", "Debian", "Centos"], - "icon": "/images/php.svg", - "globalMemoryLimit": "2686Mi", + "displayName": "Node.js MongoDB Web Application", + "description": "Stack with NodeJS 10 and MongoDB 3.4", + "tags": [ + "Community", + "Node.js", + "Express", + "MongoDB", + "RealWorld", + "ubi8", + "Centos" + ], + "icon": "/images/nodejs.svg", "links": { - "self": "/devfiles/php-mysql/devfile.yaml" + "v2": "https://github.com/che-samples/nodejs-mongodb-sample/tree/devfilev2" } }, { - "displayName": "PHP Symfony", - "description": "PHP Stack with Symfony Demo Application https://symfony.com/", - "tags": ["PHP", "Apache", "MySQL", "Symfony", "Debian", "Centos"], - "icon": "/images/php.svg", - "globalMemoryLimit": "2686Mi", + "displayName": "Rust", + "description": "Rust Stack with Rust 1.57", + "tags": [ + "Community", + "Rust" + ], + "icon": "/images/rust.svg", "links": { - "self": "/devfiles/php-symfony/devfile.yaml" + "v2": "https://github.com/che-samples/helloworld-rust/tree/devfilev2" } }, { - "displayName": "PHP Simple", - "description": "PHP Stack with PHP 7.1 and simple web application", - "tags": ["PHP", "Apache", "Debian"], - "icon": "/images/php.svg", - "globalMemoryLimit": "2430Mi", + "displayName": "Java Spring Boot", + "description": "Java stack with OpenJDK 11 and Spring Boot Petclinic demo application", + "tags": [ + "Community", + "Java", + "OpenJDK", + "Maven", + "Spring Boot" + ], + "icon": "/images/springboot.svg", "links": { - "self": "/devfiles/php-web-simple/devfile.yaml" + "v2": "https://github.com/che-samples/java-spring-petclinic/tree/devfilev2" } }, { @@ -244,26 +280,6 @@ "self": "/devfiles/python/devfile.yaml" } }, - { - "displayName": "Python Django", - "description": "Python Stack with Python 3.7 and Django application", - "tags": ["Centos", "Python", "pip"], - "icon": "/images/python.svg", - "globalMemoryLimit": "1686Mi", - "links": { - "self": "/devfiles/python-django/devfile.yaml" - } - }, - { - "displayName": "Quarkus Tools", - "description": "Quarkus Tools with OpenJDK 8 and Maven 3.6.3", - "tags": ["Java", "Quarkus", "OpenJDK", "Maven", "Debian"], - "icon": "/images/quarkus.svg", - "globalMemoryLimit": "2674Mi", - "links": { - "self": "/devfiles/quarkus/devfile.yaml" - } - }, { "displayName": "Rust", "description": "Rust Stack with Rust 1.39", diff --git a/packages/dashboard-frontend/src/pages/GetStarted/index.tsx b/packages/dashboard-frontend/src/pages/GetStarted/index.tsx index b6fb68ed4..f6613fcea 100644 --- a/packages/dashboard-frontend/src/pages/GetStarted/index.tsx +++ b/packages/dashboard-frontend/src/pages/GetStarted/index.tsx @@ -31,13 +31,12 @@ import * as WorkspaceStore from '../../store/Workspaces'; import { AppState } from '../../store'; import { AlertItem, CreateWorkspaceTab } from '../../services/helpers/types'; import { ROUTE } from '../../Routes/routes'; -import { Workspace, Devfile, isCheDevfile } from '../../services/workspace-adapter'; -import { selectBranding } from '../../store/Branding/selectors'; +import { Workspace, isCheDevfile } from '../../services/workspace-adapter'; import { selectRegistriesErrors } from '../../store/DevfileRegistries/selectors'; import { selectWorkspaceByQualifiedName } from '../../store/Workspaces/selectors'; import { selectDefaultNamespace } from '../../store/InfrastructureNamespaces/selectors'; import getRandomString from '../../services/helpers/random'; -import { selectWorkspacesSettings } from '../../store/Workspaces/Settings/selectors'; +import devfileApi from '../../services/devfileApi'; const SamplesListTab = React.lazy(() => import('./GetStartedTab')); @@ -110,7 +109,7 @@ export class GetStarted extends React.PureComponent { } private async createWorkspace( - devfile: Devfile, + devfile: devfileApi.Devfile, stackName: string | undefined, infrastructureNamespace: string | undefined, optionalFilesContent?: { @@ -131,13 +130,7 @@ export class GetStarted extends React.PureComponent { : this.props.defaultNamespace.name; let workspace: Workspace | undefined; try { - await this.props.createWorkspaceFromDevfile( - devfile, - undefined, - namespace, - attr, - optionalFilesContent, - ); + await this.props.createWorkspaceFromDevfile(devfile, attr, optionalFilesContent); this.props.setWorkspaceQualifiedName(namespace, devfile.metadata.name as string); workspace = this.props.activeWorkspace; } catch (e) { @@ -252,11 +245,9 @@ export class GetStarted extends React.PureComponent { } const mapStateToProps = (state: AppState) => ({ - branding: selectBranding(state), registriesErrors: selectRegistriesErrors(state), activeWorkspace: selectWorkspaceByQualifiedName(state), defaultNamespace: selectDefaultNamespace(state), - workspacesSettings: selectWorkspacesSettings(state), }); const connector = connect(mapStateToProps, WorkspaceStore.actionCreators); diff --git a/packages/dashboard-frontend/src/pages/UserPreferences/ContainerRegistriesTab/__tests__/index.spec.tsx b/packages/dashboard-frontend/src/pages/UserPreferences/ContainerRegistriesTab/__tests__/index.spec.tsx index 728f60f30..eff990b86 100644 --- a/packages/dashboard-frontend/src/pages/UserPreferences/ContainerRegistriesTab/__tests__/index.spec.tsx +++ b/packages/dashboard-frontend/src/pages/UserPreferences/ContainerRegistriesTab/__tests__/index.spec.tsx @@ -64,7 +64,7 @@ describe('ContainerRegistries', () => { it('should correctly render the component which contains two registries', () => { const component = getComponent( new FakeStoreBuilder() - .withCheDockerConfig([ + .withDockerConfig([ new FakeRegistryBuilder().withUrl('http://test.reg').withPassword('qwerty').build(), new FakeRegistryBuilder().withUrl('https://tstreg.com').withPassword('123').build(), ]) @@ -111,7 +111,7 @@ describe('ContainerRegistries', () => { it('should delete a registry', () => { const component = getComponent( new FakeStoreBuilder() - .withCheDockerConfig([ + .withDockerConfig([ new FakeRegistryBuilder().withUrl('http://test.reg').withPassword('qwerty').build(), ]) .build(), diff --git a/packages/dashboard-frontend/src/pages/WorkspaceDetails/DevfileEditorTab/index.tsx b/packages/dashboard-frontend/src/pages/WorkspaceDetails/DevfileEditorTab/index.tsx index d8973496f..db867a39b 100644 --- a/packages/dashboard-frontend/src/pages/WorkspaceDetails/DevfileEditorTab/index.tsx +++ b/packages/dashboard-frontend/src/pages/WorkspaceDetails/DevfileEditorTab/index.tsx @@ -29,7 +29,7 @@ import { safeLoad } from 'js-yaml'; import common from '@eclipse-che/common'; import DevfileEditor, { DevfileEditor as Editor } from '../../../components/DevfileEditor'; import EditorTools from '../../../components/EditorTools'; -import { constructWorkspace, isCheWorkspace, Workspace } from '../../../services/workspace-adapter'; +import { constructWorkspace, Workspace } from '../../../services/workspace-adapter'; import devfileApi, { isDevfileV2, isDevWorkspace } from '../../../services/devfileApi'; import { DEVWORKSPACE_NEXT_START_ANNOTATION, @@ -49,7 +49,7 @@ export type Props = { }; export type State = { - devfile: che.WorkspaceDevfile | devfileApi.Devfile; + devfile: devfileApi.Devfile; hasChanges: boolean; hasRequestErrors: boolean; currentRequestError: string; @@ -61,7 +61,7 @@ export type State = { }; export class DevfileEditorTab extends React.PureComponent { - private originDevfile: che.WorkspaceDevfile | devfileApi.Devfile | undefined; + private originDevfile: devfileApi.Devfile | undefined; private readonly devfileEditorRef: React.RefObject; private devworkspaceClient: DevWorkspaceClient; @@ -71,7 +71,7 @@ export class DevfileEditorTab extends React.PureComponent { super(props); this.devworkspaceClient = container.get(DevWorkspaceClient); - const devfile = Object.assign({}, this.props.workspace.devfile); + const devfile = this.props.workspace.devfile; const additionSchema = this.getAdditionSchema(devfile); this.state = { @@ -93,9 +93,7 @@ export class DevfileEditorTab extends React.PureComponent { this.devfileEditorRef = React.createRef(); } - private getAdditionSchema( - devfile: che.WorkspaceDevfile | devfileApi.Devfile, - ): { [key: string]: any } | undefined { + private getAdditionSchema(devfile: devfileApi.Devfile): { [key: string]: any } | undefined { return isDevfileV2(devfile) ? { properties: { @@ -297,14 +295,14 @@ export class DevfileEditorTab extends React.PureComponent { this.setState({ hasChanges: false }); return; } - let devfile: che.WorkspaceDevfile; + let devfile: devfileApi.Devfile; try { - devfile = safeLoad(newValue) as che.WorkspaceDevfile; + devfile = safeLoad(newValue) as devfileApi.Devfile; } catch (e) { console.error('Devfile parse error', e); return; } - if (this.areEqual(this.props.workspace.devfile as che.WorkspaceDevfile, devfile)) { + if (this.areEqual(this.props.workspace.devfile, devfile)) { this.setState({ hasChanges: false }); return; } @@ -316,7 +314,7 @@ export class DevfileEditorTab extends React.PureComponent { } private async onSave(): Promise { - if (!this.props.workspace.isRunning || isCheWorkspace(this.props.workspace.ref)) { + if (!this.props.workspace.isRunning) { await this.saveDevfile(); } else { this.setState({ @@ -361,9 +359,6 @@ export class DevfileEditorTab extends React.PureComponent { } const workspaceCopy = constructWorkspace(this.props.workspace.ref); - if (!devfile.metadata) { - devfile.metadata = {}; - } if (!devfile.metadata.name) { devfile.metadata.name = workspaceCopy.name; } @@ -397,25 +392,17 @@ export class DevfileEditorTab extends React.PureComponent { }); } - private sortKeysInObject( - obj: che.WorkspaceDevfile | devfileApi.Devfile, - ): che.WorkspaceDevfile | devfileApi.Devfile { + private sortKeysInObject(obj: devfileApi.Devfile): devfileApi.Devfile { return Object.keys(obj) .sort() - .reduce((result: che.WorkspaceDevfile | devfileApi.Devfile, key: string) => { + .reduce((result: devfileApi.Devfile, key: string) => { result[key] = obj[key]; return result; - }, {} as che.WorkspaceDevfile | devfileApi.Devfile); + }, {} as devfileApi.Devfile); } - private areEqual( - a: che.WorkspaceDevfile | devfileApi.Devfile, - b: che.WorkspaceDevfile | devfileApi.Devfile, - ): boolean { - return ( - JSON.stringify(this.sortKeysInObject(a)) == - JSON.stringify(this.sortKeysInObject(b as che.WorkspaceDevfile)) - ); + private areEqual(a: devfileApi.Devfile, b: devfileApi.Devfile): boolean { + return JSON.stringify(this.sortKeysInObject(a)) == JSON.stringify(this.sortKeysInObject(b)); } } diff --git a/packages/dashboard-frontend/src/pages/WorkspaceDetails/Header/Actions/__tests__/index.spec.tsx b/packages/dashboard-frontend/src/pages/WorkspaceDetails/Header/Actions/__tests__/index.spec.tsx index 5d4a0ca50..e83ad7788 100644 --- a/packages/dashboard-frontend/src/pages/WorkspaceDetails/Header/Actions/__tests__/index.spec.tsx +++ b/packages/dashboard-frontend/src/pages/WorkspaceDetails/Header/Actions/__tests__/index.spec.tsx @@ -24,8 +24,9 @@ import { Workspace } from '../../../../../services/workspace-adapter'; import { AppThunk } from '../../../../../store'; import { ActionCreators, ResourceQueryParams } from '../../../../../store/Workspaces'; import { FakeStoreBuilder } from '../../../../../store/__mocks__/storeBuilder'; -import { CheWorkspaceBuilder } from '../../../../../store/__mocks__/cheWorkspaceBuilder'; +import { DevWorkspaceBuilder } from '../../../../../store/__mocks__/devWorkspaceBuilder'; import { Store } from 'redux'; +import devfileApi from '../../../../../services/devfileApi'; /* eslint-disable @typescript-eslint/no-unused-vars */ jest.mock('../../../../../store/Workspaces/index', () => { @@ -50,23 +51,17 @@ const namespace = 'che'; const workspaceName = 'test-workspace-name'; const workspaceUID = 'test-workspace-id'; -let cheWorkspace: che.Workspace; +let devWorkspace: devfileApi.DevWorkspace; let store: Store; describe('Workspace WorkspaceAction widget', () => { + global.open = jest.fn(); + beforeEach(() => { - cheWorkspace = new CheWorkspaceBuilder() - .withId(workspaceUID) + devWorkspace = new DevWorkspaceBuilder() + .withUID(workspaceUID) .withName(workspaceName) .withNamespace(namespace) - .withStatus(WorkspaceStatus.STOPPED) - .withDevfile({ - apiVersion: 'v1', - components: [], - metadata: { - name: workspaceName, - }, - }) .build(); store = new FakeStoreBuilder() .withWorkspaces({ @@ -74,8 +69,8 @@ describe('Workspace WorkspaceAction widget', () => { workspaceName, }) .withInfrastructureNamespace([{ name: namespace, attributes: { phase: 'Active' } }], false) - .withCheWorkspaces({ - workspaces: [cheWorkspace], + .withDevWorkspaces({ + workspaces: [devWorkspace], }) .build(); }); @@ -103,19 +98,6 @@ describe('Workspace WorkspaceAction widget', () => { expect(actionButton).toBeTruthy(); }); - it('should not not show actions nor button', () => { - const history = createHashHistory(); - const component = createComponent(history, 'Deprecated', false); - - renderComponent(component); - - const actionButton = screen.queryByRole('button', { name: /delete/i }); - expect(actionButton).toBe(null); - - const actionDropdown = screen.queryByTestId(`${workspaceUID}-action-dropdown`); - expect(actionDropdown).toBe(null); - }); - it('should call the callback with OPEN action', async () => { const action = WorkspaceAction.OPEN_IDE; const history = createHashHistory(); @@ -132,7 +114,7 @@ describe('Workspace WorkspaceAction widget', () => { targetAction.click(); await waitFor(() => - expect(history.location.pathname).toBe(`/ide/${namespace}/test-workspace-name`), + expect(window.open).toBeCalledWith(`#/ide/${namespace}/test-workspace-name`, workspaceUID), ); }); @@ -152,7 +134,7 @@ describe('Workspace WorkspaceAction widget', () => { targetAction.click(); await waitFor(() => - expect(history.location.pathname).toBe(`/ide/${namespace}/test-workspace-name`), + expect(window.open).toBeCalledWith(`#/ide/${namespace}/test-workspace-name`, workspaceUID), ); }); @@ -211,13 +193,11 @@ describe('Workspace WorkspaceAction widget', () => { function createComponent( history: History, status: WorkspaceStatus | DeprecatedWorkspaceStatus = WorkspaceStatus.STOPPED, - canDelete = true, ): React.ReactElement { return ( diff --git a/packages/dashboard-frontend/src/pages/WorkspaceDetails/Header/Actions/index.tsx b/packages/dashboard-frontend/src/pages/WorkspaceDetails/Header/Actions/index.tsx index 1f6c41388..5bae588c6 100644 --- a/packages/dashboard-frontend/src/pages/WorkspaceDetails/Header/Actions/index.tsx +++ b/packages/dashboard-frontend/src/pages/WorkspaceDetails/Header/Actions/index.tsx @@ -31,7 +31,6 @@ import ButtonAction from './Button'; type Props = { workspaceUID: string; workspaceName: string; - canDelete: boolean; status: WorkspaceStatus | DevWorkspaceStatus | DeprecatedWorkspaceStatus; history: History; }; @@ -77,23 +76,19 @@ export class HeaderActionSelect extends React.PureComponent { } render(): React.ReactNode { - const { canDelete, history, status } = this.props; + const { history, status } = this.props; return ( {context => { if (status === 'Deprecated') { - if (canDelete) { - return ( - this.handleSelectedAction(action, context)} - /> - ); - } else { - return <>; - } + return ( + this.handleSelectedAction(action, context)} + /> + ); } const { ...props } = this.props; return ( diff --git a/packages/dashboard-frontend/src/pages/WorkspaceDetails/InlineAlerts/__tests__/index.spec.tsx b/packages/dashboard-frontend/src/pages/WorkspaceDetails/InlineAlerts/__tests__/index.spec.tsx deleted file mode 100644 index 6e8aa4546..000000000 --- a/packages/dashboard-frontend/src/pages/WorkspaceDetails/InlineAlerts/__tests__/index.spec.tsx +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright (c) 2018-2021 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 React from 'react'; -import { render, RenderResult, screen } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; -import { WorkspaceInlineAlerts } from '..'; -import { - constructWorkspace, - Workspace, - WorkspaceAdapter, -} from '../../../../services/workspace-adapter'; -import { DevWorkspaceBuilder } from '../../../../store/__mocks__/devWorkspaceBuilder'; -import { CheWorkspaceBuilder } from '../../../../store/__mocks__/cheWorkspaceBuilder'; - -const mockOnCloseConversionError = jest.fn(); -const mockOnCloseRestartAlert = jest.fn(); - -describe('Inline alerts', () => { - afterEach(() => { - jest.resetAllMocks(); - }); - - it('should render empty alert group', () => { - const workspace = constructWorkspace( - new DevWorkspaceBuilder().withName('wksp').withNamespace('user').build(), - ); - renderComponent({ workspace }); - - const alertHeadings = screen.queryAllByRole('heading'); - expect(alertHeadings.length).toEqual(0); - }); - - it('should render the deprecation warning', () => { - const deprecatedId = 'wksp-id'; - WorkspaceAdapter.setDeprecatedUIDs([deprecatedId]); - const workspace = constructWorkspace( - new CheWorkspaceBuilder().withId(deprecatedId).withName('wksp').withNamespace('user').build(), - ); - renderComponent({ workspace }); - - const alertHeading = screen.queryByRole('heading'); - expect(alertHeading).toBeTruthy(); - expect(alertHeading).toBeInTheDocument(); - expect(alertHeading).toHaveTextContent('This workspace is deprecated.'); - }); - - it('should render the conversion error', () => { - const deprecatedId = 'wksp-id'; - WorkspaceAdapter.setDeprecatedUIDs([deprecatedId]); - const workspace = constructWorkspace( - new CheWorkspaceBuilder().withId(deprecatedId).withName('wksp').withNamespace('user').build(), - ); - const conversionError = 'An error happened during devfiles conversion.'; - renderComponent({ workspace, conversionError }); - - const alertHeading = screen.queryByRole('heading', { - name: /workspace conversion failed/i, - }); - expect(alertHeading).toBeTruthy(); - expect(alertHeading).toBeInTheDocument(); - expect(screen.queryByText(conversionError)).toBeTruthy(); - expect(screen.queryByText(/instructions for converting/i)).toBeTruthy(); - }); - - it('should render the restart warning', () => { - const workspace = constructWorkspace( - new DevWorkspaceBuilder().withName('wksp').withNamespace('user').build(), - ); - renderComponent({ workspace, restartWarning: true }); - - const alertHeading = screen.queryByRole('heading'); - expect(alertHeading).toBeTruthy(); - expect(alertHeading).toBeInTheDocument(); - expect(alertHeading).toHaveTextContent(/should be restarted to apply changes/i); - }); - - describe('workspace failures', () => { - it('should render no alerts if status message was not set', () => { - const workspace = constructWorkspace( - new DevWorkspaceBuilder() - .withName('wksp') - .withNamespace('user') - .withStatus({ phase: 'FAILED' }) - .build(), - ); - renderComponent({ workspace }); - - const alertHeading = screen.queryByRole('heading'); - expect(alertHeading).toBeFalsy(); - }); - - it('should initially render a failure error', () => { - const failureMessage = 'The workspace failed to start.'; - const workspace = constructWorkspace( - new DevWorkspaceBuilder() - .withName('wksp') - .withNamespace('user') - .withStatus({ phase: 'FAILED', message: failureMessage }) - .build(), - ); - renderComponent({ workspace }); - - const alertHeading = screen.queryByRole('heading'); - expect(alertHeading).toBeTruthy(); - expect(alertHeading).toBeInTheDocument(); - expect(alertHeading).toHaveTextContent(failureMessage); - }); - - it('should re-render a failure error', () => { - const failureMessage = 'The workspace failed to start.'; - const initWorkspace = constructWorkspace( - new DevWorkspaceBuilder() - .withName('wksp') - .withNamespace('user') - .withStatus({ phase: 'FAILED' }) - .build(), - ); - const { rerender } = renderComponent({ workspace: initWorkspace }); - - const prevAlertHeading = screen.queryByRole('heading'); - expect(prevAlertHeading).toBeFalsy(); - - const nextWorkspace = constructWorkspace( - new DevWorkspaceBuilder() - .withName('wksp') - .withNamespace('user') - .withStatus({ phase: 'FAILED', message: failureMessage }) - .build(), - ); - reRenderComponent({ workspace: nextWorkspace }, rerender); - - const nextAlertHeading = screen.queryByRole('heading'); - expect(nextAlertHeading).toBeTruthy(); - expect(nextAlertHeading).toBeInTheDocument(); - expect(nextAlertHeading).toHaveTextContent(failureMessage); - }); - - // the alert should remain closed if until the workspace status is changed - it('should close a failure error', () => { - const failureMessage = 'The workspace failed to start.'; - const devworkspace = new DevWorkspaceBuilder() - .withName('wksp') - .withNamespace('user') - .withStatus({ phase: 'FAILED', message: failureMessage }) - .build(); - const prevWorkspace = constructWorkspace(devworkspace); - const { rerender } = renderComponent({ workspace: prevWorkspace }); - - // alert visible - let prevAlertHeading = screen.queryByRole('heading'); - expect(prevAlertHeading).toBeTruthy(); - - const closeButton = screen.getByRole('button', { - name: /workspace failed/i, - }); - userEvent.click(closeButton); - - // alert closed - prevAlertHeading = screen.queryByRole('heading'); - expect(prevAlertHeading).toBeFalsy(); - - const nextWorkspace = constructWorkspace(devworkspace); - reRenderComponent({ workspace: nextWorkspace }, rerender); - - // alert remains closed - const nextAlertHeading = screen.queryByRole('heading'); - expect(nextAlertHeading).toBeFalsy(); - }); - - // the alert should be reopened if the workspace status is changed - it('should reopen a failure error alert', () => { - const failureMessage = 'The workspace failed to start.'; - const failedWorkspace = constructWorkspace( - new DevWorkspaceBuilder() - .withName('wksp') - .withNamespace('user') - .withStatus({ phase: 'FAILED', message: failureMessage }) - .build(), - ); - const startingWorkspace = constructWorkspace( - new DevWorkspaceBuilder() - .withName('wksp') - .withNamespace('user') - .withStatus({ phase: 'STARTING' }) - .build(), - ); - - const { rerender } = renderComponent({ workspace: failedWorkspace }); - - // alert visible - let prevAlertHeading = screen.queryByRole('heading'); - expect(prevAlertHeading).toBeTruthy(); - - const closeButton = screen.getByRole('button', { - name: /workspace failed/i, - }); - userEvent.click(closeButton); - - // alert closed - prevAlertHeading = screen.queryByRole('heading'); - expect(prevAlertHeading).toBeFalsy(); - - // render the workspace in 'starting' phase - reRenderComponent({ workspace: startingWorkspace }, rerender); - - // render the workspace in 'failed' phase again - reRenderComponent({ workspace: failedWorkspace }, rerender); - - // alert should be visible - const nextAlertHeading = screen.queryByRole('heading'); - expect(nextAlertHeading).toBeTruthy(); - }); - }); -}); - -function renderComponent(options: { - workspace: Workspace; - canConvert?: boolean; - conversionError?: string; - restartWarning?: boolean; -}): RenderResult { - options.canConvert = !!options.canConvert; - options.restartWarning = !!options.restartWarning; - - return render( - , - ); -} -function reRenderComponent( - options: { - workspace: Workspace; - canConvert?: boolean; - conversionError?: string; - restartWarning?: boolean; - }, - rerender: (ui: React.ReactElement) => void, -): void { - options.canConvert = !!options.canConvert; - options.restartWarning = !!options.restartWarning; - - rerender( - , - ); -} diff --git a/packages/dashboard-frontend/src/pages/WorkspaceDetails/InlineAlerts/index.tsx b/packages/dashboard-frontend/src/pages/WorkspaceDetails/InlineAlerts/index.tsx deleted file mode 100644 index 8f5aeb0b8..000000000 --- a/packages/dashboard-frontend/src/pages/WorkspaceDetails/InlineAlerts/index.tsx +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright (c) 2018-2021 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 React from 'react'; -import { - AlertGroup, - Alert, - AlertVariant, - AlertActionCloseButton, - Text, - TextContent, - TextVariants, -} from '@patternfly/react-core'; -import spacing from '@patternfly/react-styles/css/utilities/Spacing/spacing'; -import devfileApi from '../../../services/devfileApi'; -import { DevWorkspaceStatus } from '../../../services/helpers/types'; -import { Workspace } from '../../../services/workspace-adapter'; - -const migratingDocs = 'https://devfile.io/docs/2.2.0-alpha/migrating-to-devfile-v2'; - -type Props = { - workspace: Workspace; - canConvert: boolean; - conversionError: string | undefined; - onCloseConversionAlert: () => void; - showRestartWarning: boolean; - onCloseRestartAlert: () => void; -}; - -type State = { - showFailureAlert: boolean; -}; - -export class WorkspaceInlineAlerts extends React.PureComponent { - constructor(props: Props) { - super(props); - - this.state = { - showFailureAlert: true, - }; - } - - private buildDeprecationAlert(): React.ReactElement { - const title = this.props.canConvert - ? "This workspace is deprecated. Use the 'Convert' button for making it devfile v2 compatible." - : 'This workspace is deprecated.'; - return ( - - - FAQ / Known Issues - - - ); - } - - private buildConversionAlert(): React.ReactElement { - const { conversionError } = this.props; - return ( - this.props.onCloseConversionAlert()} />} - > - - {conversionError} - - Find manual instructions for converting devfile v1 to devfile v2 in the{' '} - - documentation - - . - - - - ); - } - - private buildRestartAlert(): React.ReactElement { - const { workspace } = this.props; - return ( - - The workspace {workspace.name}  should be restarted to apply changes. - - } - actionClose={ this.props.onCloseRestartAlert()} />} - /> - ); - } - - private buildFailureAlert(): React.ReactElement { - const { workspace } = this.props; - if (!workspace.isDevWorkspace) { - return <>; - } - const { status } = workspace.ref as devfileApi.DevWorkspace; - if (!status) { - return <>; - } - const title = status.message; - if (!title) { - return <>; - } - - return ( - this.handleCloseFailureAlert()} />} - /> - ); - } - - private handleCloseFailureAlert(): void { - this.setState({ - showFailureAlert: false, - }); - } - - public componentDidUpdate(prevProps: Props): void { - if (this.state.showFailureAlert === false) { - const showFailureAlert = this.props.workspace.status !== prevProps.workspace.status; - this.setState({ - showFailureAlert, - }); - } - } - - render(): React.ReactElement { - const { workspace, conversionError, showRestartWarning: restartWarning } = this.props; - const { showFailureAlert } = this.state; - - return ( - - {workspace.isDeprecated && this.buildDeprecationAlert()} - {conversionError && this.buildConversionAlert()} - {restartWarning && this.buildRestartAlert()} - {showFailureAlert && - workspace.status === DevWorkspaceStatus.FAILED && - this.buildFailureAlert()} - - ); - } -} diff --git a/packages/dashboard-frontend/src/pages/WorkspaceDetails/OverviewTab/StorageType/index.tsx b/packages/dashboard-frontend/src/pages/WorkspaceDetails/OverviewTab/StorageType/index.tsx index 4930d894b..f7911f9aa 100644 --- a/packages/dashboard-frontend/src/pages/WorkspaceDetails/OverviewTab/StorageType/index.tsx +++ b/packages/dashboard-frontend/src/pages/WorkspaceDetails/OverviewTab/StorageType/index.tsx @@ -26,13 +26,13 @@ import { import { AppState } from '../../../../store'; import { connect, ConnectedProps } from 'react-redux'; import { OutlinedQuestionCircleIcon, PencilAltIcon } from '@patternfly/react-icons'; -import { selectAvailableStorageTypes } from '../../../../store/Workspaces/Settings/selectors'; import * as storageTypeService from '../../../../services/storageTypes'; import { selectBranding } from '../../../../store/Branding/selectors'; import overviewStyles from '../index.module.css'; import styles from './index.module.css'; import { selectPvcStrategy } from '../../../../store/ServerConfig/selectors'; +import * as storageTypesService from '../../../../services/storageTypes'; export type Props = MappedProps & { readonly: boolean; @@ -58,7 +58,7 @@ export class StorageTypeFormGroup extends React.PureComponent { isInfoOpen: false, }; - const availableTypes = this.props.availableStorageTypes; + const availableTypes = storageTypesService.getAvailable(); if (Array.isArray(availableTypes)) { this.storageTypes = availableTypes; @@ -358,7 +358,6 @@ export class StorageTypeFormGroup extends React.PureComponent { const mapStateToProps = (state: AppState) => ({ branding: selectBranding(state), - availableStorageTypes: selectAvailableStorageTypes(state), preferredStorageType: selectPvcStrategy(state), }); diff --git a/packages/dashboard-frontend/src/pages/WorkspaceDetails/__mocks__/index.tsx b/packages/dashboard-frontend/src/pages/WorkspaceDetails/__mocks__/index.tsx index f3565ddc3..95291c22a 100644 --- a/packages/dashboard-frontend/src/pages/WorkspaceDetails/__mocks__/index.tsx +++ b/packages/dashboard-frontend/src/pages/WorkspaceDetails/__mocks__/index.tsx @@ -27,14 +27,10 @@ export class WorkspaceDetails extends React.PureComponent {
{this.props.oldWorkspaceLocation?.pathname}
-
- {this.props.showConvertButton === true ? 'true' : 'false'} -
{this.props.workspace.id}
{this.props.workspace.name}
{this.props.workspacesLink}
- ); } diff --git a/packages/dashboard-frontend/src/pages/WorkspaceDetails/__tests__/index.spec.tsx b/packages/dashboard-frontend/src/pages/WorkspaceDetails/__tests__/index.spec.tsx index c2ce3866d..8456fee75 100644 --- a/packages/dashboard-frontend/src/pages/WorkspaceDetails/__tests__/index.spec.tsx +++ b/packages/dashboard-frontend/src/pages/WorkspaceDetails/__tests__/index.spec.tsx @@ -18,12 +18,10 @@ import { Provider } from 'react-redux'; import { Router } from 'react-router'; import { WorkspaceDetails, Props } from '..'; import { DevWorkspaceBuilder } from '../../../store/__mocks__/devWorkspaceBuilder'; -import { CheWorkspaceBuilder } from '../../../store/__mocks__/cheWorkspaceBuilder'; import { FakeStoreBuilder } from '../../../store/__mocks__/storeBuilder'; import { constructWorkspace } from '../../../services/workspace-adapter'; import devfileApi from '../../../services/devfileApi'; -const mockOnConvert = jest.fn(); const mockOnSave = jest.fn(); jest.mock('../DevfileEditorTab'); @@ -36,15 +34,11 @@ jest.mock('../DevworkspaceEditorTab', () => { let history: History; describe('Workspace Details page', () => { - let cheWorkspaceBuilder: CheWorkspaceBuilder; let devWorkspaceBuilder: DevWorkspaceBuilder; const workspaceName = 'wksp'; beforeEach(() => { history = createHashHistory(); - cheWorkspaceBuilder = new CheWorkspaceBuilder() - .withName(workspaceName) - .withNamespace('user-dev'); devWorkspaceBuilder = new DevWorkspaceBuilder() .withName(workspaceName) .withNamespace('user-che'); @@ -124,93 +118,6 @@ describe('Workspace Details page', () => { }); }); - describe('Convert button', () => { - it('should NOT show the button', () => { - const workspace = constructWorkspace(cheWorkspaceBuilder.build()); - renderComponent({ - workspace, - }); - expect(screen.queryByRole('button', { name: 'Convert' })).toBeFalsy(); - }); - - it('should show the button', () => { - const workspace = constructWorkspace(cheWorkspaceBuilder.build()); - renderComponent({ - workspace, - showConvertButton: true, - }); - expect(screen.queryByRole('button', { name: 'Convert' })).toBeTruthy(); - }); - }); - - describe('Conversion', () => { - it('should NOT show alert', async () => { - const workspace = constructWorkspace(cheWorkspaceBuilder.build()); - - renderComponent({ - workspace, - showConvertButton: true, - }); - - const convertButton = screen.getByRole('button', { name: 'Convert' }); - userEvent.click(convertButton); - - await waitFor(() => expect(mockOnConvert).toHaveBeenCalled()); - - const closeButton = screen.queryByRole('button', { name: /workspace conversion failed/i }); - expect(closeButton).toBeFalsy(); - - const alertHeading = screen.queryByRole('heading', { name: /workspace conversion failed/i }); - expect(alertHeading).toBeFalsy(); - }); - - it('should show alert', async () => { - const workspace = constructWorkspace(cheWorkspaceBuilder.build()); - - mockOnConvert.mockImplementationOnce(() => { - throw new Error('Failed.'); - }); - renderComponent({ - workspace, - showConvertButton: true, - }); - - const convertButton = screen.getByRole('button', { name: 'Convert' }); - userEvent.click(convertButton); - - await waitFor(() => expect(mockOnConvert).toHaveBeenCalled()); - - const closeButton = screen.queryByRole('button', { name: /workspace conversion failed/i }); - expect(closeButton).toBeTruthy(); - - const alertHeading = screen.queryByRole('heading', { name: /workspace conversion failed/i }); - expect(alertHeading).toBeTruthy(); - }); - - it('should close conversion alert', async () => { - const workspace = constructWorkspace(cheWorkspaceBuilder.build()); - - mockOnConvert.mockImplementationOnce(() => { - throw new Error('Failed.'); - }); - renderComponent({ - workspace, - showConvertButton: true, - }); - - const convertButton = screen.getByRole('button', { name: 'Convert' }); - userEvent.click(convertButton); - - await waitFor(() => expect(mockOnConvert).toHaveBeenCalled()); - - const closeButton = screen.getByRole('button', { name: /workspace conversion failed/i }); - userEvent.click(closeButton); - - const alertHeading = screen.queryByRole('headiing', { name: /workspace conversion failed/i }); - expect(alertHeading).toBeFalsy(); - }); - }); - describe('Saving changes', () => { test('successfully saved changes', async () => { const workspace = constructWorkspace(devWorkspaceBuilder.build()); @@ -272,10 +179,8 @@ function renderComponent(props?: Partial): void { history={history} isLoading={props?.isLoading || false} oldWorkspaceLocation={props?.oldWorkspaceLocation} - showConvertButton={props?.showConvertButton || false} workspace={props?.workspace} workspacesLink={props?.workspacesLink || '/workspaces'} - onConvert={mockOnConvert} onSave={mockOnSave} />
diff --git a/packages/dashboard-frontend/src/pages/WorkspaceDetails/index.tsx b/packages/dashboard-frontend/src/pages/WorkspaceDetails/index.tsx index 19bb50564..7c005d950 100644 --- a/packages/dashboard-frontend/src/pages/WorkspaceDetails/index.tsx +++ b/packages/dashboard-frontend/src/pages/WorkspaceDetails/index.tsx @@ -22,7 +22,7 @@ import { } from '@patternfly/react-core'; import common from '@eclipse-che/common'; import Head from '../../components/Head'; -import { WorkspaceDetailsTab, WorkspaceStatus } from '../../services/helpers/types'; +import { WorkspaceDetailsTab } from '../../services/helpers/types'; import Header from './Header'; import ProgressIndicator from '../../components/Progress'; import { HeaderActionSelect } from './Header/Actions'; @@ -32,10 +32,8 @@ import OverviewTab, { OverviewTab as Overview } from './OverviewTab'; import DevfileEditorTab, { DevfileEditorTab as Editor } from './DevfileEditorTab'; import DevworkspaceEditorTab from './DevworkspaceEditorTab'; import { History, UnregisterCallback, Location } from 'history'; -import { isCheWorkspace, Workspace } from '../../services/workspace-adapter'; +import { Workspace } from '../../services/workspace-adapter'; import UnsavedChangesModal from '../../components/UnsavedChangesModal'; -import WorkspaceConversionButton from './ConversionButton'; -import { WorkspaceInlineAlerts } from './InlineAlerts'; import { buildDetailsLocation } from '../../services/helpers/location'; import styles from './index.module.css'; @@ -46,10 +44,8 @@ export type Props = { history: History; isLoading: boolean; oldWorkspaceLocation?: Location; - showConvertButton: boolean; workspace: Workspace | undefined; workspacesLink: string; - onConvert: (workspace: Workspace) => Promise; onSave: (workspace: Workspace) => Promise; }; @@ -111,16 +107,6 @@ export class WorkspaceDetails extends React.PureComponent { }; } - private async handleConversion(workspace: Workspace): Promise { - this.closeConversionAlert(); - try { - await this.props.onConvert(workspace); - } catch (e) { - const errorMessage = common.helpers.errors.getMessage(e); - this.showConversionAlert(errorMessage); - } - } - private showConversionAlert(errorMessage: string): void { this.setState({ inlineAlertConversionError: errorMessage, @@ -213,18 +199,13 @@ export class WorkspaceDetails extends React.PureComponent { } public render(): React.ReactElement { - const { history, oldWorkspaceLocation, showConvertButton, workspace, workspacesLink } = - this.props; + const { history, oldWorkspaceLocation, workspace, workspacesLink } = this.props; if (!workspace) { return
Workspace not found.
; } const workspaceName = workspace.name; - const { inlineAlertConversionError, showInlineAlertRestartWarning } = this.state; - - // show the Delete button for a deprecated workspace until it's converted - const canDelete = showConvertButton; return ( @@ -242,26 +223,14 @@ export class WorkspaceDetails extends React.PureComponent { Show Original Devfile )} - {showConvertButton && ( - this.handleConversion(workspace)} /> - )} - this.closeConversionAlert()} - onCloseRestartAlert={() => this.handleCloseRestartWarning()} - /> @@ -300,13 +269,6 @@ export class WorkspaceDetails extends React.PureComponent { } private async handleOnSave(workspace: Workspace): Promise { - if ( - this.props.workspace && - isCheWorkspace((this.props.workspace as Workspace).ref) && - this.props.workspace.status !== WorkspaceStatus.STOPPED - ) { - this.handleRestartWarning(); - } try { await this.props.onSave(workspace); this.showAlert(AlertVariant.success, 'Workspace has been updated'); diff --git a/packages/dashboard-frontend/src/pages/WorkspacesList/Rows.tsx b/packages/dashboard-frontend/src/pages/WorkspacesList/Rows.tsx index f72e153f8..a357d2e85 100644 --- a/packages/dashboard-frontend/src/pages/WorkspacesList/Rows.tsx +++ b/packages/dashboard-frontend/src/pages/WorkspacesList/Rows.tsx @@ -18,7 +18,7 @@ import { Button } from '@patternfly/react-core'; import WorkspaceIndicator from '../../components/Workspace/Indicator'; import { formatDate, formatRelativeDate } from '../../services/helpers/date'; import { buildDetailsLocation, buildIdeLoaderLocation } from '../../services/helpers/location'; -import { isCheWorkspace, Workspace } from '../../services/workspace-adapter'; +import { Workspace } from '../../services/workspace-adapter'; import devfileApi from '../../services/devfileApi'; import { DevWorkspaceStatus, WorkspaceDetailsTab } from '../../services/helpers/types'; @@ -130,21 +130,14 @@ export function buildRow( /* projects list */ const projects: string[] = []; - if (isCheWorkspace(workspace.ref)) { - const workspaceProjects = (workspace.devfile as che.WorkspaceDevfile).projects; - (workspaceProjects || []) - .map(project => project.name || project.source?.location) - .filter((projectName?: string) => projectName) - .forEach((projectName: string) => projects.push(projectName)); - } else { - const workspaceProjects = (workspace.ref as devfileApi.DevWorkspace).spec.template.projects; - (workspaceProjects || []) - .map(project => project.name || project.git?.remotes?.origin) - .filter((projectName?: string): projectName is string => { - return typeof projectName === 'string' && projectName !== ''; - }) - .forEach((projectName: string) => projects.push(projectName)); - } + const workspaceProjects = (workspace.ref as devfileApi.DevWorkspace).spec.template.projects; + (workspaceProjects || []) + .map(project => project.name || project.git?.remotes?.origin) + .filter((projectName?: string): projectName is string => { + return typeof projectName === 'string' && projectName !== ''; + }) + .forEach((projectName: string) => projects.push(projectName)); + const projectsList = projects.join(', \n') || '-'; let action: React.ReactElement | string; diff --git a/packages/dashboard-frontend/src/pages/WorkspacesList/Toolbar/__tests__/index.spec.tsx b/packages/dashboard-frontend/src/pages/WorkspacesList/Toolbar/__tests__/index.spec.tsx index 1f6946902..7feb2e7d8 100644 --- a/packages/dashboard-frontend/src/pages/WorkspacesList/Toolbar/__tests__/index.spec.tsx +++ b/packages/dashboard-frontend/src/pages/WorkspacesList/Toolbar/__tests__/index.spec.tsx @@ -16,8 +16,8 @@ import React from 'react'; import { render, screen, RenderResult, fireEvent } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import WorkspacesListToolbar from '..'; -import { createFakeCheWorkspace } from '../../../../store/__mocks__/workspace'; import { constructWorkspace, Workspace } from '../../../../services/workspace-adapter'; +import { DevWorkspaceBuilder } from '../../../../store/__mocks__/devWorkspaceBuilder'; let workspaces: Workspace[]; let isSelectedAll: boolean; @@ -44,7 +44,12 @@ describe('Workspaces List Toolbar', () => { beforeEach(() => { workspaces = [0, 1, 2, 3, 4] - .map(i => createFakeCheWorkspace('workspace-' + i, 'workspace-' + i)) + .map(i => + new DevWorkspaceBuilder() + .withUID('workspace-' + i) + .withName('workspace-' + i) + .build(), + ) .map(workspace => constructWorkspace(workspace)); isSelectedAll = false; isEnabledDelete = false; diff --git a/packages/dashboard-frontend/src/pages/WorkspacesList/__tests__/index.spec.tsx b/packages/dashboard-frontend/src/pages/WorkspacesList/__tests__/index.spec.tsx index cdc4578b6..a421d4097 100644 --- a/packages/dashboard-frontend/src/pages/WorkspacesList/__tests__/index.spec.tsx +++ b/packages/dashboard-frontend/src/pages/WorkspacesList/__tests__/index.spec.tsx @@ -19,13 +19,9 @@ import { Router } from 'react-router'; import userEvent from '@testing-library/user-event'; import WorkspacesList from '..'; import { BrandingData } from '../../../services/bootstrap/branding.constant'; -import { WorkspaceAction, WorkspaceStatus } from '../../../services/helpers/types'; -import { - constructWorkspace, - Workspace, - WorkspaceAdapter, -} from '../../../services/workspace-adapter'; -import { CheWorkspaceBuilder } from '../../../store/__mocks__/cheWorkspaceBuilder'; +import { WorkspaceAction } from '../../../services/helpers/types'; +import { constructWorkspace, Workspace } from '../../../services/workspace-adapter'; +import { DevWorkspaceBuilder } from '../../../store/__mocks__/devWorkspaceBuilder'; jest.mock('../../../components/Head', () => { const FakeHead = () => { @@ -60,9 +56,10 @@ describe('Workspaces List Page', () => { beforeEach(() => { workspaces = [0, 1, 2, 3, 4] .map(i => - new CheWorkspaceBuilder() - .withId('workspace-' + i) + new DevWorkspaceBuilder() + .withUID('workspace-' + i) .withName('workspace-' + i) + .withNamespace('che') .build(), ) .map(workspace => constructWorkspace(workspace)); @@ -357,17 +354,12 @@ describe('Workspaces List Page', () => { }); it('should handle "Stop Workspace" action', () => { - const runtime: che.WorkspaceRuntime = { - machines: {}, - status: WorkspaceStatus.RUNNING, - activeEnv: 'default', - }; workspaces[0] = constructWorkspace( - new CheWorkspaceBuilder() - .withId('workspace-0') + new DevWorkspaceBuilder() + .withUID('workspace-0') .withName('workspace-0') - .withStatus('RUNNING') - .withRuntime(runtime) + .withNamespace('user') + .withStatus({ phase: 'RUNNING' }) .build(), ); @@ -400,76 +392,6 @@ describe('Workspaces List Page', () => { workspaces[0].uid, ); }); - - describe('with deprecated workspaces', () => { - test('actions', () => { - const deprecatedWorkspaceId = 'deprecated-workspace-id'; - WorkspaceAdapter.setDeprecatedUIDs([deprecatedWorkspaceId]); - const workspaces: Workspace[] = [ - new CheWorkspaceBuilder() - .withId(deprecatedWorkspaceId) - .withName('workspace-name') - .build(), - ].map(constructWorkspace); - renderComponent(workspaces); - - // no menu items at all initially - let menuItems = screen.queryAllByRole('menuitem'); - expect(menuItems.length).toEqual(0); - - const actionButtons = screen.getAllByRole('button', { name: /actions/i }); - // click the kebab button on the first workspace row - userEvent.click(actionButtons[0]); - expect(actionButtons[0]).toBeEnabled(); - - // check number of menu items shown - menuItems = screen.getAllByRole('menuitem'); - expect(menuItems.length).toEqual(1); - - const deleteAction = screen.queryByRole('button', { name: /delete workspace/i }); - expect(deleteAction).not.toBeNull(); - expect(deleteAction).toBeEnabled(); - }); - - test('status icon', () => { - const deprecatedWorkspaceId = 'deprecated-workspace-id'; - // mark the workspace as deprecated - WorkspaceAdapter.setDeprecatedUIDs([deprecatedWorkspaceId]); - const workspaces: Workspace[] = [ - new CheWorkspaceBuilder() - .withId(deprecatedWorkspaceId) - .withName('workspace-name') - .build(), - ].map(constructWorkspace); - renderComponent(workspaces); - - const rows = screen.getAllByRole('row'); - - // skip headings row, take the workspace row and get the workspace status indicator - const statusIcon = rows[1].querySelector('[data-testid="workspace-status-indicator"]'); - expect(statusIcon).not.toBeNull(); - expect(statusIcon!.getAttribute('data-tip')).toEqual('Deprecated workspace'); - }); - - test('Convert action link should redirect to the workspace page', () => { - const deprecatedWorkspaceId = 'deprecated-workspace-id'; - // mark the workspace as deprecated - WorkspaceAdapter.setDeprecatedUIDs([deprecatedWorkspaceId]); - const workspaces: Workspace[] = [ - new CheWorkspaceBuilder() - .withId(deprecatedWorkspaceId) - .withName('workspace-name') - .withNamespace('user') - .build(), - ].map(constructWorkspace); - renderComponent(workspaces); - - const convertActions = screen.getAllByRole('link', { name: 'Convert' }); - - userEvent.click(convertActions[0]); - expect(window.location.href).toMatch(/user\/workspace-name/); - }); - }); }); describe('Empty State', () => { diff --git a/packages/dashboard-frontend/src/pages/WorkspacesList/index.tsx b/packages/dashboard-frontend/src/pages/WorkspacesList/index.tsx index 0d757794f..041534853 100644 --- a/packages/dashboard-frontend/src/pages/WorkspacesList/index.tsx +++ b/packages/dashboard-frontend/src/pages/WorkspacesList/index.tsx @@ -47,7 +47,7 @@ import { lazyInject } from '../../inversify.config'; import NoWorkspacesEmptyState from './EmptyState/NoWorkspaces'; import NothingFoundEmptyState from './EmptyState/NothingFound'; import { buildRows, RowData } from './Rows'; -import { isCheWorkspace, Workspace } from '../../services/workspace-adapter'; +import { Workspace } from '../../services/workspace-adapter'; import styles from './index.module.css'; @@ -251,15 +251,11 @@ export default class WorkspacesList extends React.PureComponent { private async handleBulkDelete(): Promise { const { selected } = this.state; const { workspaces } = this.props; - let hasCheWorkspaces = false; // show confirmation window try { const wantDelete = selected.map(uid => { const workspace = workspaces.find(workspace => uid === workspace.uid); - if (!hasCheWorkspaces && workspace) { - hasCheWorkspaces = isCheWorkspace(workspace.ref); - } return workspace?.name || uid; }); await this.props.showConfirmation(wantDelete); @@ -273,10 +269,9 @@ export default class WorkspacesList extends React.PureComponent { return uid; } catch (e) { const workspace = this.props.workspaces.find(workspace => uid === workspace.uid); - const action = workspace && isCheWorkspace(workspace.ref) ? 'delete' : 'terminate'; const workspaceName = workspace?.name ? `workspace "${workspace.name}"` : 'workspace'; const message = - `Unable to ${action} ${workspaceName}. ` + + `Unable to terminate ${workspaceName}. ` + common.helpers.errors.getMessage(e).replace('Error: ', ''); this.showAlert(message); console.warn(message); @@ -308,10 +303,8 @@ export default class WorkspacesList extends React.PureComponent { if (!rejected) { const message = promises.length === 1 - ? `The workspace was ${hasCheWorkspaces ? 'deleted' : 'terminated'} successfully` - : `${promises.length} workspaces were ${ - hasCheWorkspaces ? 'deleted' : 'terminated' - } successfully.`; + ? `The workspace was terminated successfully` + : `${promises.length} workspaces were terminated successfully.`; this.showAlert(message, AlertVariant.success); } else if (rejected === promises.length) { const message = 'No workspaces were deleted.'; @@ -319,12 +312,8 @@ export default class WorkspacesList extends React.PureComponent { } else { const message = fulfilled === 1 - ? `${fulfilled} of ${promises.length} workspaces was ${ - hasCheWorkspaces ? 'deleted' : 'terminated' - }.` - : `${fulfilled} of ${promises.length} workspaces were ${ - hasCheWorkspaces ? 'deleted' : 'terminated' - }. `; + ? `${fulfilled} of ${promises.length} workspaces was terminated.` + : `${fulfilled} of ${promises.length} workspaces were terminated.`; this.showAlert(message, AlertVariant.warning); } } catch (e) { diff --git a/packages/dashboard-frontend/src/preload/index.html b/packages/dashboard-frontend/src/preload/index.html index 36b3748e4..8db558610 100644 --- a/packages/dashboard-frontend/src/preload/index.html +++ b/packages/dashboard-frontend/src/preload/index.html @@ -13,8 +13,8 @@ --> - - - - + + + + diff --git a/packages/dashboard-frontend/src/services/bootstrap/index.ts b/packages/dashboard-frontend/src/services/bootstrap/index.ts index 2488e0768..e1e76ad63 100644 --- a/packages/dashboard-frontend/src/services/bootstrap/index.ts +++ b/packages/dashboard-frontend/src/services/bootstrap/index.ts @@ -30,7 +30,6 @@ import * as DevWorkspacesStore from '../../store/Workspaces/devWorkspaces'; import * as WorkspacesSettingsStore from '../../store/Workspaces/Settings'; import { ResourceFetcherService } from '../resource-fetcher'; import { IssuesReporterService, IssueType, WorkspaceData } from './issuesReporter'; -import { CheWorkspaceClient } from '../workspace-client/cheworkspace/cheWorkspaceClient'; import { DevWorkspaceClient } from '../workspace-client/devworkspace/devWorkspaceClient'; import { selectDwEditorsPluginsList } from '../../store/Plugins/devWorkspacePlugins/selectors'; import devfileApi from '../devfileApi'; @@ -50,9 +49,6 @@ export default class Bootstrap { @lazyInject(IssuesReporterService) private readonly issuesReporterService: IssuesReporterService; - @lazyInject(CheWorkspaceClient) - private readonly cheWorkspaceClient: CheWorkspaceClient; - @lazyInject(DevWorkspaceClient) private readonly devWorkspaceClient: DevWorkspaceClient; diff --git a/packages/dashboard-frontend/src/services/helpers/devworkspace.ts b/packages/dashboard-frontend/src/services/helpers/devworkspace.ts index c48e59e8c..3948058a7 100644 --- a/packages/dashboard-frontend/src/services/helpers/devworkspace.ts +++ b/packages/dashboard-frontend/src/services/helpers/devworkspace.ts @@ -10,17 +10,13 @@ * Red Hat, Inc. - initial API and implementation */ +import * as devfileApi from '../devfileApi/devfileApi'; + /** * Check to see if the workspace is a web terminal - * @param workspaceOrDevfile The workspace or devfile you want to check + * @param workspace The workspace you want to check */ -export function isWebTerminal( - workspaceOrDevfile: che.Workspace | api.che.workspace.devfile.Devfile, -): boolean { - const labels = workspaceOrDevfile?.metadata?.labels; - return !!labels && !!labels['console.openshift.io/terminal']; -} - -export function isDevworkspacesEnabled(settings: che.WorkspaceSettings): boolean { - return settings['che.devworkspaces.enabled'] === 'true'; +export function isWebTerminal(workspace: devfileApi.DevWorkspace): boolean { + const labels = workspace?.metadata?.labels; + return labels?.['console.openshift.io/terminal'] !== undefined; } diff --git a/packages/dashboard-frontend/src/services/helpers/editor.ts b/packages/dashboard-frontend/src/services/helpers/editor.ts index 7a83c7261..1a60c445c 100644 --- a/packages/dashboard-frontend/src/services/helpers/editor.ts +++ b/packages/dashboard-frontend/src/services/helpers/editor.ts @@ -54,7 +54,7 @@ function sortKeys(key1: keyof che.WorkspaceDevfile, key2: keyof che.WorkspaceDev * Provides a devfile stringify function. */ export default function stringify( - obj: che.WorkspaceDevfile | che.Workspace | devfileApi.Devfile | devfileApi.DevWorkspace, + obj: che.WorkspaceDevfile | devfileApi.Devfile | devfileApi.DevWorkspace, ): string { if (!obj) { return ''; diff --git a/packages/dashboard-frontend/src/services/helpers/types.ts b/packages/dashboard-frontend/src/services/helpers/types.ts index 9baac97fd..433260ea4 100644 --- a/packages/dashboard-frontend/src/services/helpers/types.ts +++ b/packages/dashboard-frontend/src/services/helpers/types.ts @@ -12,7 +12,7 @@ import { AlertVariant } from '@patternfly/react-core'; import * as React from 'react'; -import { Devfile } from '../workspace-adapter'; +import devfileApi from '../devfileApi'; export type ActionCallback = { title: string; @@ -32,7 +32,7 @@ export interface AlertItem { export interface FactoryResolver { v: string; source?: string; - devfile: Devfile; + devfile: devfileApi.Devfile | che.WorkspaceDevfile; location?: string; scm_info?: FactoryResolverScmInfo; links: api.che.core.rest.Link[]; diff --git a/packages/dashboard-frontend/src/services/storageTypes.ts b/packages/dashboard-frontend/src/services/storageTypes.ts index 2b6a6748d..935a5012d 100644 --- a/packages/dashboard-frontend/src/services/storageTypes.ts +++ b/packages/dashboard-frontend/src/services/storageTypes.ts @@ -10,9 +10,6 @@ * Red Hat, Inc. - initial API and implementation */ -import { getEnvironment, isDevEnvironment } from './helpers/environment'; -import { isDevworkspacesEnabled } from './helpers/devworkspace'; - export enum StorageTypeTitle { async = 'Asynchronous', ephemeral = 'Ephemeral', @@ -29,38 +26,8 @@ export function toTitle(type: che.WorkspaceStorageType): string { return StorageTypeTitle[type]; } -export function getAvailable(settings: che.WorkspaceSettings): che.WorkspaceStorageType[] { - if (isDevworkspacesEnabled(settings)) { - return ['per-user', 'per-workspace', 'ephemeral']; - } - if (!settings['che.workspace.storage.available_types']) { - const env = getEnvironment(); - if (isDevEnvironment(env)) { - // running Dashboard in Che in dev mode needs for storage types to be stubbed - return ['persistent']; - } - throw new Error('Unable to get available storage types'); - } - const availableTypes = settings['che.workspace.storage.available_types']; - return availableTypes.split(',') as che.WorkspaceStorageType[]; -} - -export function typeToAttributes( - type: che.WorkspaceStorageType, -): che.WorkspaceDevfileAttributes | undefined { - switch (type) { - case 'persistent': - return; - case 'ephemeral': - return { - persistVolumes: 'false', - }; - case 'async': - return { - asyncPersist: 'true', - persistVolumes: 'false', - }; - } +export function getAvailable(): che.WorkspaceStorageType[] { + return ['per-user', 'per-workspace', 'ephemeral']; } export function attributesToType( diff --git a/packages/dashboard-frontend/src/services/workspace-adapter/__tests__/index.spec.ts b/packages/dashboard-frontend/src/services/workspace-adapter/__tests__/index.spec.ts index 0ed8c802d..ad12b8c75 100644 --- a/packages/dashboard-frontend/src/services/workspace-adapter/__tests__/index.spec.ts +++ b/packages/dashboard-frontend/src/services/workspace-adapter/__tests__/index.spec.ts @@ -10,13 +10,7 @@ * Red Hat, Inc. - initial API and implementation */ -import { cloneDeep } from 'lodash'; import { constructWorkspace } from '..'; -import { - CheWorkspaceBuilder, - CHE_DEVFILE_STUB, - CHE_RUNTIME_STUB, -} from '../../../store/__mocks__/cheWorkspaceBuilder'; import { DevWorkspaceBuilder } from '../../../store/__mocks__/devWorkspaceBuilder'; import { DEVWORKSPACE_UPDATING_TIMESTAMP_ANNOTATION } from '../../devfileApi/devWorkspace/metadata'; import { DEVWORKSPACE_STORAGE_TYPE_ATTR } from '../../devfileApi/devWorkspace/spec/template'; @@ -26,394 +20,213 @@ import { StorageTypeTitle } from '../../storageTypes'; /** * @jest-environment node */ -describe('Workspace adapter', () => { - let cheDevfile: che.WorkspaceDevfile; +describe('for Dev workspace', () => { + it('should set "ephemeral" storage type', () => { + const devWorkspace = new DevWorkspaceBuilder().build(); + devWorkspace.spec.template.attributes = { + [DEVWORKSPACE_STORAGE_TYPE_ATTR]: 'per-workspace', + }; + const workspace = constructWorkspace(devWorkspace); - beforeEach(() => { - cheDevfile = cloneDeep(CHE_DEVFILE_STUB); - }); - - afterEach(() => { - jest.clearAllMocks(); - }); - - describe('converting workspaces', () => { - it('should not throw when convert Che workspace', () => { - const cheWorkspace = new CheWorkspaceBuilder().build(); - expect(() => { - constructWorkspace(cheWorkspace); - }).not.toThrow(); - }); - - it('should not throw when convert Dev workspace', () => { - const devWorkspace = new DevWorkspaceBuilder().build(); - expect(() => { - constructWorkspace(devWorkspace); - }).not.toThrow(); + expect(workspace.storageType).toEqual('per-workspace'); + expect(workspace.devfile.attributes).toEqual({ + [DEVWORKSPACE_STORAGE_TYPE_ATTR]: 'per-workspace', }); - it('should throw when convert not Che nor Dev workspace', () => { - console.error = jest.fn(); + workspace.storageType = 'ephemeral'; - const obj = { - field: 'value', - } as any; - expect(() => { - constructWorkspace(obj); - }).toThrow(); + expect(workspace.storageType).toEqual('ephemeral'); + expect(workspace.devfile.attributes).toEqual({ + [DEVWORKSPACE_STORAGE_TYPE_ATTR]: 'ephemeral', }); }); - describe('for Che workspace', () => { - it('should return reference to the workspace', () => { - const cheWorkspace = new CheWorkspaceBuilder().build(); - const workspace = constructWorkspace(cheWorkspace); - expect(workspace.ref).toMatchObject(cheWorkspace); - }); - - it('should return ID', () => { - const id = 'workspace1234asdf'; - const cheWorkspace = new CheWorkspaceBuilder().withId(id).build(); - const workspace = constructWorkspace(cheWorkspace); - expect(workspace.id).toEqual(id); - }); - - it('should return UID', () => { - const id = 'workspace1234asdf'; - const cheWorkspace = new CheWorkspaceBuilder().withId(id).build(); - const workspace = constructWorkspace(cheWorkspace); - expect(workspace.uid).toEqual(id); - }); - - it('should return name', () => { - const name = 'wksp-1234'; - const cheWorkspace = new CheWorkspaceBuilder().withName(name).build(); - const workspace = constructWorkspace(cheWorkspace); - expect(workspace.name).toEqual(name); - }); - - it('should return namespace', () => { - const namespace = 'test-namespace'; - const cheWorkspace = new CheWorkspaceBuilder().withNamespace(namespace).build(); - const workspace = constructWorkspace(cheWorkspace); - expect(workspace.namespace).toEqual(namespace); - }); + it('should set "per-workspace" storage type', () => { + const devWorkspace = new DevWorkspaceBuilder().build(); + devWorkspace.spec.template.attributes = { + [DEVWORKSPACE_STORAGE_TYPE_ATTR]: 'ephemeral', + }; + const workspace = constructWorkspace(devWorkspace); - it('should return infrastructure namespace', () => { - const infrastructureNamespace = 'infrastructure-namespace'; - const cheWorkspace = new CheWorkspaceBuilder() - .withAttributes({ - infrastructureNamespace, - } as che.WorkspaceAttributes) - .build(); - const workspace = constructWorkspace(cheWorkspace); - expect(workspace.infrastructureNamespace).toEqual(infrastructureNamespace); + expect(workspace.storageType).toEqual('ephemeral'); + expect(workspace.devfile.attributes).toEqual({ + [DEVWORKSPACE_STORAGE_TYPE_ATTR]: 'ephemeral', }); - it('should return timestamp of creating', () => { - const created = '1111111'; - const cheWorkspace = new CheWorkspaceBuilder() - .withAttributes({ - created, - } as che.WorkspaceAttributes) - .build(); - const workspace = constructWorkspace(cheWorkspace); - expect(workspace.created.toString()).toEqual(created); - }); - - it('should return timestamp of updating', () => { - const updated = '2222222'; - const cheWorkspace = new CheWorkspaceBuilder() - .withAttributes({ - updated, - } as che.WorkspaceAttributes) - .build(); - const workspace = constructWorkspace(cheWorkspace); - expect(workspace.updated.toString()).toEqual(updated); - }); - - it('should return status', () => { - const status = 'STARTING'; - const cheWorkspace = new CheWorkspaceBuilder().withStatus(status).build(); - const workspace = constructWorkspace(cheWorkspace); - expect(workspace.status).toEqual(status); - }); + workspace.storageType = 'per-workspace'; - it('should return ideUrl', () => { - const ideUrl = 'my/ide/url'; - const runtime = CHE_RUNTIME_STUB; - runtime.machines['theia-ide'].servers.theia.url = ideUrl; - const cheWorkspace = new CheWorkspaceBuilder().withRuntime(runtime).build(); - const workspace = constructWorkspace(cheWorkspace); - expect(workspace.ideUrl).toEqual(ideUrl); - }); - - it('should return storage type', () => { - cheDevfile.attributes = { - persistVolumes: 'false', - asyncPersist: 'false', - }; - const cheWorkspace = new CheWorkspaceBuilder().withDevfile(cheDevfile).build(); - const workspace = constructWorkspace(cheWorkspace); - expect(workspace.storageType).toEqual(StorageTypeTitle.ephemeral.toLowerCase()); - }); - - it('should return devfile', () => { - cheDevfile.attributes = { - persistVolumes: 'true', - asyncPersist: 'false', - }; - const cheWorkspace = new CheWorkspaceBuilder().withDevfile(cheDevfile).build(); - const workspace = constructWorkspace(cheWorkspace); - expect(workspace.devfile).toMatchObject(cheDevfile); - }); - - it('should return list of project names', () => { - const projects = [ - { - name: 'My first project', - source: { - type: 'git', - location: 'first/project/location', - }, - }, - { - name: 'My second project', - source: { - type: 'git', - location: 'second/project/location', - }, - }, - ]; - const cheWorkspace = new CheWorkspaceBuilder().withProjects(projects).build(); - const workspace = constructWorkspace(cheWorkspace); - expect(workspace.projects).toEqual([projects[0].name, projects[1].name]); - }); - - it('should set "ephemeral" storage type', () => { - const cheWorkspace = new CheWorkspaceBuilder().withDevfile(cheDevfile).build(); - const workspace = constructWorkspace(cheWorkspace); - - expect(workspace.storageType).toEqual('persistent'); - expect((workspace.devfile as che.WorkspaceDevfile).attributes).toEqual(undefined); - - workspace.storageType = 'ephemeral'; - - expect(workspace.storageType).toEqual('ephemeral'); - expect((workspace.devfile as che.WorkspaceDevfile).attributes).toEqual({ - persistVolumes: 'false', - }); + expect(workspace.storageType).toEqual('per-workspace'); + expect(workspace.devfile.attributes).toEqual({ + [DEVWORKSPACE_STORAGE_TYPE_ATTR]: 'per-workspace', }); }); - describe('for Dev workspace', () => { - it('should set "ephemeral" storage type', () => { - const devWorkspace = new DevWorkspaceBuilder().build(); - devWorkspace.spec.template.attributes = { - [DEVWORKSPACE_STORAGE_TYPE_ATTR]: 'per-workspace', - }; - const workspace = constructWorkspace(devWorkspace); + it('should set "per-user" storage type', () => { + const devWorkspace = new DevWorkspaceBuilder().build(); + devWorkspace.spec.template.attributes = { + [DEVWORKSPACE_STORAGE_TYPE_ATTR]: 'per-workspace', + }; + const workspace = constructWorkspace(devWorkspace); - expect(workspace.storageType).toEqual('per-workspace'); - expect(workspace.devfile.attributes).toEqual({ - [DEVWORKSPACE_STORAGE_TYPE_ATTR]: 'per-workspace', - }); - - workspace.storageType = 'ephemeral'; - - expect(workspace.storageType).toEqual('ephemeral'); - expect(workspace.devfile.attributes).toEqual({ - [DEVWORKSPACE_STORAGE_TYPE_ATTR]: 'ephemeral', - }); + expect(workspace.storageType).toEqual('per-workspace'); + expect(workspace.devfile.attributes).toEqual({ + [DEVWORKSPACE_STORAGE_TYPE_ATTR]: 'per-workspace', }); - it('should set "per-workspace" storage type', () => { - const devWorkspace = new DevWorkspaceBuilder().build(); - devWorkspace.spec.template.attributes = { - [DEVWORKSPACE_STORAGE_TYPE_ATTR]: 'ephemeral', - }; - const workspace = constructWorkspace(devWorkspace); - - expect(workspace.storageType).toEqual('ephemeral'); - expect(workspace.devfile.attributes).toEqual({ - [DEVWORKSPACE_STORAGE_TYPE_ATTR]: 'ephemeral', - }); - - workspace.storageType = 'per-workspace'; + workspace.storageType = 'per-user'; - expect(workspace.storageType).toEqual('per-workspace'); - expect(workspace.devfile.attributes).toEqual({ - [DEVWORKSPACE_STORAGE_TYPE_ATTR]: 'per-workspace', - }); - }); - - it('should set "per-user" storage type', () => { - const devWorkspace = new DevWorkspaceBuilder().build(); - devWorkspace.spec.template.attributes = { - [DEVWORKSPACE_STORAGE_TYPE_ATTR]: 'per-workspace', - }; - const workspace = constructWorkspace(devWorkspace); - - expect(workspace.storageType).toEqual('per-workspace'); - expect(workspace.devfile.attributes).toEqual({ - [DEVWORKSPACE_STORAGE_TYPE_ATTR]: 'per-workspace', - }); - - workspace.storageType = 'per-user'; - - expect(workspace.storageType).toEqual('per-user'); - expect(workspace.devfile.attributes).toEqual({ - [DEVWORKSPACE_STORAGE_TYPE_ATTR]: 'per-user', - }); + expect(workspace.storageType).toEqual('per-user'); + expect(workspace.devfile.attributes).toEqual({ + [DEVWORKSPACE_STORAGE_TYPE_ATTR]: 'per-user', }); + }); - it('should return reference to the workspace', () => { - const devWorkspace = new DevWorkspaceBuilder().build(); - const workspace = constructWorkspace(devWorkspace); - expect(workspace.ref).toMatchObject(devWorkspace); - }); + it('should return reference to the workspace', () => { + const devWorkspace = new DevWorkspaceBuilder().build(); + const workspace = constructWorkspace(devWorkspace); + expect(workspace.ref).toMatchObject(devWorkspace); + }); - it('should return ID', () => { - const id = '1234asdf'; - const devWorkspace = new DevWorkspaceBuilder().withId(id).build(); - const workspace = constructWorkspace(devWorkspace); - expect(workspace.id).toEqual(id); - }); + it('should return ID', () => { + const id = '1234asdf'; + const devWorkspace = new DevWorkspaceBuilder().withId(id).build(); + const workspace = constructWorkspace(devWorkspace); + expect(workspace.id).toEqual(id); + }); - it('should return UID', () => { - const id = '1234asdf'; - const devWorkspace = new DevWorkspaceBuilder().withId(id).build(); - const workspace = constructWorkspace(devWorkspace); - expect(workspace.uid).not.toEqual(id); - expect(workspace.uid).toMatch(/^uid-/); - }); + it('should return UID', () => { + const id = '1234asdf'; + const devWorkspace = new DevWorkspaceBuilder().withId(id).build(); + const workspace = constructWorkspace(devWorkspace); + expect(workspace.uid).not.toEqual(id); + expect(workspace.uid).toMatch(/^uid-/); + }); - it('should return name', () => { - const name = 'wksp-1234'; - const devWorkspace = new DevWorkspaceBuilder().withName(name).build(); - const workspace = constructWorkspace(devWorkspace); - expect(workspace.name).toEqual(name); - }); + it('should return name', () => { + const name = 'wksp-1234'; + const devWorkspace = new DevWorkspaceBuilder().withName(name).build(); + const workspace = constructWorkspace(devWorkspace); + expect(workspace.name).toEqual(name); + }); - it('should return namespace', () => { - const namespace = 'test-namespace'; - const devWorkspace = new DevWorkspaceBuilder().withNamespace(namespace).build(); - const workspace = constructWorkspace(devWorkspace); - expect(workspace.namespace).toEqual(namespace); - }); + it('should return namespace', () => { + const namespace = 'test-namespace'; + const devWorkspace = new DevWorkspaceBuilder().withNamespace(namespace).build(); + const workspace = constructWorkspace(devWorkspace); + expect(workspace.namespace).toEqual(namespace); + }); - it('should return infrastructure namespace', () => { - const infrastructureNamespace = 'infrastructure-namespace'; - const devWorkspace = new DevWorkspaceBuilder().withNamespace(infrastructureNamespace).build(); - const workspace = constructWorkspace(devWorkspace); - expect(workspace.infrastructureNamespace).toEqual(infrastructureNamespace); - }); + it('should return infrastructure namespace', () => { + const infrastructureNamespace = 'infrastructure-namespace'; + const devWorkspace = new DevWorkspaceBuilder().withNamespace(infrastructureNamespace).build(); + const workspace = constructWorkspace(devWorkspace); + expect(workspace.infrastructureNamespace).toEqual(infrastructureNamespace); + }); - it('should return timestamp of creating', () => { - const timestamp = 1111111; - const created = new Date(timestamp); - const devWorkspace = new DevWorkspaceBuilder().build(); - devWorkspace.metadata.creationTimestamp = created; - const workspace = constructWorkspace(devWorkspace); - expect(workspace.created).toEqual(timestamp); - }); + it('should return timestamp of creating', () => { + const timestamp = 1111111; + const created = new Date(timestamp); + const devWorkspace = new DevWorkspaceBuilder().build(); + devWorkspace.metadata.creationTimestamp = created; + const workspace = constructWorkspace(devWorkspace); + expect(workspace.created).toEqual(timestamp); + }); - it('should return timestamp of updating', () => { - const timestamp = 22222222; - const updated = new Date(timestamp).toISOString(); - const devWorkspace = new DevWorkspaceBuilder().build(); - devWorkspace.metadata.annotations = { - [DEVWORKSPACE_UPDATING_TIMESTAMP_ANNOTATION]: updated, - }; - const workspace = constructWorkspace(devWorkspace); - expect(workspace.updated).toEqual(timestamp); - }); + it('should return timestamp of updating', () => { + const timestamp = 22222222; + const updated = new Date(timestamp).toISOString(); + const devWorkspace = new DevWorkspaceBuilder().build(); + devWorkspace.metadata.annotations = { + [DEVWORKSPACE_UPDATING_TIMESTAMP_ANNOTATION]: updated, + }; + const workspace = constructWorkspace(devWorkspace); + expect(workspace.updated).toEqual(timestamp); + }); - it('should return status', () => { - const status = 'STARTING'; - const devWorkspace = new DevWorkspaceBuilder().withStatus({ phase: status }).build(); - const workspace = constructWorkspace(devWorkspace); - expect(workspace.status).toEqual(DevWorkspaceStatus[status]); - }); + it('should return status', () => { + const status = 'STARTING'; + const devWorkspace = new DevWorkspaceBuilder().withStatus({ phase: status }).build(); + const workspace = constructWorkspace(devWorkspace); + expect(workspace.status).toEqual(DevWorkspaceStatus[status]); + }); - it('should return ideUrl', () => { - const ideUrl = 'my/ide/url'; - const devWorkspace = new DevWorkspaceBuilder().withIdeUrl(ideUrl).build(); - const workspace = constructWorkspace(devWorkspace); - expect(workspace.ideUrl).toEqual(ideUrl); - }); + it('should return ideUrl', () => { + const ideUrl = 'my/ide/url'; + const devWorkspace = new DevWorkspaceBuilder().withIdeUrl(ideUrl).build(); + const workspace = constructWorkspace(devWorkspace); + expect(workspace.ideUrl).toEqual(ideUrl); + }); - it('should return Not Defined storage type', () => { - const devWorkspace = new DevWorkspaceBuilder().build(); - const workspace = constructWorkspace(devWorkspace); - expect(StorageTypeTitle[workspace.storageType as '']).toEqual('Not defined'); - }); + it('should return Not Defined storage type', () => { + const devWorkspace = new DevWorkspaceBuilder().build(); + const workspace = constructWorkspace(devWorkspace); + expect(StorageTypeTitle[workspace.storageType as '']).toEqual('Not defined'); + }); - it('should return Ephemeral storage type', () => { - const devWorkspace = new DevWorkspaceBuilder().build(); - devWorkspace.spec.template.attributes = { - [DEVWORKSPACE_STORAGE_TYPE_ATTR]: 'ephemeral', - }; - const workspace = constructWorkspace(devWorkspace); - expect(StorageTypeTitle[workspace.storageType as 'ephemeral']).toEqual('Ephemeral'); - }); + it('should return Ephemeral storage type', () => { + const devWorkspace = new DevWorkspaceBuilder().build(); + devWorkspace.spec.template.attributes = { + [DEVWORKSPACE_STORAGE_TYPE_ATTR]: 'ephemeral', + }; + const workspace = constructWorkspace(devWorkspace); + expect(StorageTypeTitle[workspace.storageType as 'ephemeral']).toEqual('Ephemeral'); + }); - it('should return Per-user storage type', () => { - const devWorkspace = new DevWorkspaceBuilder().build(); - devWorkspace.spec.template.attributes = { - [DEVWORKSPACE_STORAGE_TYPE_ATTR]: 'per-user', - }; - const workspace = constructWorkspace(devWorkspace); - expect(StorageTypeTitle[workspace.storageType as 'per-user']).toEqual('Per-user'); - }); + it('should return Per-user storage type', () => { + const devWorkspace = new DevWorkspaceBuilder().build(); + devWorkspace.spec.template.attributes = { + [DEVWORKSPACE_STORAGE_TYPE_ATTR]: 'per-user', + }; + const workspace = constructWorkspace(devWorkspace); + expect(StorageTypeTitle[workspace.storageType as 'per-user']).toEqual('Per-user'); + }); - it('should return Per-workspace storage type', () => { - const devWorkspace = new DevWorkspaceBuilder().build(); - devWorkspace.spec.template.attributes = { - [DEVWORKSPACE_STORAGE_TYPE_ATTR]: 'per-workspace', - }; - const workspace = constructWorkspace(devWorkspace); - expect(StorageTypeTitle[workspace.storageType as 'per-workspace']).toEqual('Per-workspace'); - }); + it('should return Per-workspace storage type', () => { + const devWorkspace = new DevWorkspaceBuilder().build(); + devWorkspace.spec.template.attributes = { + [DEVWORKSPACE_STORAGE_TYPE_ATTR]: 'per-workspace', + }; + const workspace = constructWorkspace(devWorkspace); + expect(StorageTypeTitle[workspace.storageType as 'per-workspace']).toEqual('Per-workspace'); + }); - it('should return devfile', () => { - const devfile = { - schemaVersion: '2.1.0', - metadata: { - name: 'my-wksp', - namespace: 'my-namespace', - }, - }; - const devWorkspace = new DevWorkspaceBuilder() - .withName('my-wksp') - .withNamespace('my-namespace') - .build(); - const workspace = constructWorkspace(devWorkspace); - expect(workspace.devfile).toMatchObject(devfile); - }); + it('should return devfile', () => { + const devfile = { + schemaVersion: '2.1.0', + metadata: { + name: 'my-wksp', + namespace: 'my-namespace', + }, + }; + const devWorkspace = new DevWorkspaceBuilder() + .withName('my-wksp') + .withNamespace('my-namespace') + .build(); + const workspace = constructWorkspace(devWorkspace); + expect(workspace.devfile).toMatchObject(devfile); + }); - it('should return list of project names', () => { - const projects = [ - { - name: 'My first project', - git: { - remotes: { - origin: 'first/project/location', - }, + it('should return list of project names', () => { + const projects = [ + { + name: 'My first project', + git: { + remotes: { + origin: 'first/project/location', }, }, - { - name: 'My second project', - git: { - remotes: { - origin: 'second/project/location', - }, + }, + { + name: 'My second project', + git: { + remotes: { + origin: 'second/project/location', }, }, - ]; - const devWorkspace = new DevWorkspaceBuilder().withProjects(projects).build(); - const workspace = constructWorkspace(devWorkspace); - expect(workspace.projects).toEqual([projects[0].name, projects[1].name]); - }); + }, + ]; + const devWorkspace = new DevWorkspaceBuilder().withProjects(projects).build(); + const workspace = constructWorkspace(devWorkspace); + expect(workspace.projects).toEqual([projects[0].name, projects[1].name]); }); }); diff --git a/packages/dashboard-frontend/src/services/workspace-adapter/index.ts b/packages/dashboard-frontend/src/services/workspace-adapter/index.ts index fb5e51554..a0810315e 100644 --- a/packages/dashboard-frontend/src/services/workspace-adapter/index.ts +++ b/packages/dashboard-frontend/src/services/workspace-adapter/index.ts @@ -11,21 +11,17 @@ */ import devfileApi, { isDevfileV2, isDevWorkspace } from '../devfileApi'; -import { devWorkspaceKind } from '../devfileApi/devWorkspace'; import { DEVWORKSPACE_UPDATING_TIMESTAMP_ANNOTATION } from '../devfileApi/devWorkspace/metadata'; import { DEVWORKSPACE_STORAGE_TYPE_ATTR } from '../devfileApi/devWorkspace/spec/template'; import { DeprecatedWorkspaceStatus, DevWorkspaceStatus, WorkspaceStatus } from '../helpers/types'; -import { attributesToType, typeToAttributes } from '../storageTypes'; import { devfileToDevWorkspace, devWorkspaceToDevfile, } from '../workspace-client/devworkspace/converters'; import { DEVWORKSPACE_NEXT_START_ANNOTATION } from '../workspace-client/devworkspace/devWorkspaceClient'; -export type Devfile = che.WorkspaceDevfile | devfileApi.Devfile; - export interface Workspace { - readonly ref: che.Workspace | devfileApi.DevWorkspace; + readonly ref: devfileApi.DevWorkspace; readonly id: string; readonly uid: string; @@ -36,7 +32,7 @@ export interface Workspace { readonly updated: number; status: WorkspaceStatus | DevWorkspaceStatus | DeprecatedWorkspaceStatus; readonly ideUrl?: string; - devfile: Devfile; + devfile: devfileApi.Devfile; storageType: che.WorkspaceStorageType; readonly projects: string[]; readonly isStarting: boolean; @@ -48,14 +44,12 @@ export interface Workspace { readonly isDeprecated: boolean; } -export class WorkspaceAdapter - implements Workspace -{ +export class WorkspaceAdapter implements Workspace { private static deprecatedUIDs: string[] = []; - private workspace: T; + private readonly workspace: T; constructor(workspace: T) { - if (isCheWorkspace(workspace) || isDevWorkspace(workspace)) { + if (isDevWorkspace(workspace)) { this.workspace = workspace; } else { console.error('Unexpected workspace object shape:', workspace); @@ -67,54 +61,43 @@ export class WorkspaceAdapter WorkspaceAdapter.deprecatedUIDs = UIDs; } - static isDeprecated(workspace: che.Workspace | devfileApi.DevWorkspace): boolean { + static isDeprecated(workspace: devfileApi.DevWorkspace): boolean { if (isDevWorkspace(workspace)) { return false; + } else { + return true; } - return WorkspaceAdapter.deprecatedUIDs.indexOf(WorkspaceAdapter.getId(workspace)) !== -1; } /** * Returns a workspace ID. * Note that IDs may intersect for Che7 workspaces and DevWorkspaces. */ - static getId(workspace: che.Workspace | devfileApi.DevWorkspace): string { - if (isCheWorkspace(workspace)) { - return workspace.id; - } else { - if (workspace.status?.devworkspaceId) { - return workspace.status.devworkspaceId; - } - return 'workspace' + workspace.metadata.uid.split('-').splice(0, 3).join(''); + static getId(workspace: devfileApi.DevWorkspace): string { + if (workspace.status?.devworkspaceId) { + return workspace.status.devworkspaceId; } + return 'workspace' + workspace.metadata.uid.split('-').splice(0, 3).join(''); } /** * Returns a unique workspace ID. */ - static getUID(workspace: che.Workspace | devfileApi.DevWorkspace): string { - if (isCheWorkspace(workspace)) { - return workspace.id; - } else { - return workspace.metadata.uid; - } + static getUID(workspace: devfileApi.DevWorkspace): string { + return workspace.metadata.uid; } static getStatus( - workspace: che.Workspace | devfileApi.DevWorkspace, - ): WorkspaceStatus | DevWorkspaceStatus | DeprecatedWorkspaceStatus { + workspace: devfileApi.DevWorkspace, + ): DevWorkspaceStatus | DeprecatedWorkspaceStatus { if (WorkspaceAdapter.isDeprecated(workspace)) { return 'Deprecated'; } - if (isCheWorkspace(workspace)) { - return workspace.status as WorkspaceStatus; - } else { - if (!workspace.status?.phase) { - return workspace.spec.started ? DevWorkspaceStatus.STARTING : DevWorkspaceStatus.STOPPED; - } - - return workspace.status.phase as DevWorkspaceStatus; + if (!workspace.status?.phase) { + return workspace.spec.started ? DevWorkspaceStatus.STARTING : DevWorkspaceStatus.STOPPED; } + + return workspace.status.phase as DevWorkspaceStatus; } get ref(): T { @@ -130,27 +113,15 @@ export class WorkspaceAdapter } get name(): string { - if (isCheWorkspace(this.workspace)) { - return this.workspace.devfile.metadata.name || ''; - } else { - return this.workspace.metadata.name; - } + return this.workspace.metadata.name; } set name(name: string) { - if (isCheWorkspace(this.workspace)) { - this.workspace.devfile.metadata.name = name; - } else { - console.error('Not implemented: set name of the devworkspace.'); - } + console.error('Not implemented: set name of the devworkspace.'); } get namespace(): string { - if (isCheWorkspace(this.workspace)) { - return this.workspace.namespace || ''; - } else { - return this.workspace.metadata.namespace; - } + return this.workspace.metadata.namespace; } get isDevWorkspace(): boolean { @@ -158,27 +129,16 @@ export class WorkspaceAdapter } get infrastructureNamespace(): string { - if (isCheWorkspace(this.workspace)) { - return this.workspace.attributes?.infrastructureNamespace || ''; - } else { - return this.workspace.metadata.namespace; - } + return this.workspace.metadata.namespace; } /** * Returns a workspace creation time in ms */ get created(): number { - if (isCheWorkspace(this.workspace)) { - if (this.workspace.attributes?.created) { - // `created` is a Unix timestamp String - return new Date(parseInt(this.workspace.attributes.created, 10)).getTime(); - } - } else { - if (this.workspace.metadata.creationTimestamp) { - // `creationTimestamp` is a date time String - return new Date(this.workspace.metadata.creationTimestamp).getTime(); - } + if (this.workspace.metadata.creationTimestamp) { + // `creationTimestamp` is a date time String + return new Date(this.workspace.metadata.creationTimestamp).getTime(); } return new Date().getTime(); } @@ -187,16 +147,10 @@ export class WorkspaceAdapter * Returns a workspace last updated time in ms */ get updated(): number { - if (isCheWorkspace(this.workspace)) { - if (this.workspace.attributes?.updated) { - return new Date(parseInt(this.workspace.attributes.updated, 10)).getTime(); - } - } else { - const updated = - this.workspace.metadata.annotations?.[DEVWORKSPACE_UPDATING_TIMESTAMP_ANNOTATION]; - if (updated) { - return new Date(updated).getTime(); - } + const updated = + this.workspace.metadata.annotations?.[DEVWORKSPACE_UPDATING_TIMESTAMP_ANNOTATION]; + if (updated) { + return new Date(updated).getTime(); } return new Date().getTime(); } @@ -210,197 +164,93 @@ export class WorkspaceAdapter } get isStarting(): boolean { - if (isCheWorkspace(this.workspace)) { - return (this.workspace.status as WorkspaceStatus) === WorkspaceStatus.STARTING; - } else { - return ( - (WorkspaceAdapter.getStatus(this.workspace) as DevWorkspaceStatus) === - DevWorkspaceStatus.STARTING - ); - } + return WorkspaceAdapter.getStatus(this.workspace) === DevWorkspaceStatus.STARTING; } get isStopped(): boolean { - if (isCheWorkspace(this.workspace)) { - return (this.workspace.status as WorkspaceStatus) === WorkspaceStatus.STOPPED; - } else { - return ( - (WorkspaceAdapter.getStatus(this.workspace) as DevWorkspaceStatus) === - DevWorkspaceStatus.STOPPED - ); - } + return WorkspaceAdapter.getStatus(this.workspace) === DevWorkspaceStatus.STOPPED; } get isStopping(): boolean { - if (isCheWorkspace(this.workspace)) { - return (this.workspace.status as WorkspaceStatus) === WorkspaceStatus.STOPPING; - } else { - return ( - (WorkspaceAdapter.getStatus(this.workspace) as DevWorkspaceStatus) === - DevWorkspaceStatus.STOPPING - ); - } + return WorkspaceAdapter.getStatus(this.workspace) === DevWorkspaceStatus.STOPPING; } get isRunning(): boolean { - if (isCheWorkspace(this.workspace)) { - return (this.workspace.status as WorkspaceStatus) === WorkspaceStatus.RUNNING; - } else { - return ( - (WorkspaceAdapter.getStatus(this.workspace) as DevWorkspaceStatus) === - DevWorkspaceStatus.RUNNING - ); - } + return WorkspaceAdapter.getStatus(this.workspace) === DevWorkspaceStatus.RUNNING; } get hasError(): boolean { - if (isCheWorkspace(this.workspace)) { - return (this.workspace.status as WorkspaceStatus) === WorkspaceStatus.ERROR; - } else { - const devWorkspaceStatus = WorkspaceAdapter.getStatus(this.workspace) as DevWorkspaceStatus; - return ( - devWorkspaceStatus === DevWorkspaceStatus.FAILED || - devWorkspaceStatus === DevWorkspaceStatus.FAILING - ); - } + const devWorkspaceStatus = WorkspaceAdapter.getStatus(this.workspace); + return ( + devWorkspaceStatus === DevWorkspaceStatus.FAILED || + devWorkspaceStatus === DevWorkspaceStatus.FAILING + ); } get ideUrl(): string | undefined { - if (isCheWorkspace(this.workspace)) { - const runtime = this.workspace.runtime; - if (!runtime || !runtime.machines) { - return; - } - for (const machineName of Object.keys(runtime.machines)) { - const servers = runtime.machines[machineName].servers || {}; - for (const serverId of Object.keys(servers)) { - const attributes = (servers[serverId] as any).attributes; - if (attributes && attributes['type'] === 'ide') { - return servers[serverId].url; - } - } - } - } else { - return this.workspace.status?.mainUrl; - } + return this.workspace.status?.mainUrl; } get storageType(): che.WorkspaceStorageType { - if (isCheWorkspace(this.workspace)) { - return attributesToType(this.workspace.devfile.attributes); - } else { - return (this.workspace.spec.template?.attributes?.[DEVWORKSPACE_STORAGE_TYPE_ATTR] || - '') as che.WorkspaceStorageType; - } + return (this.workspace.spec.template?.attributes?.[DEVWORKSPACE_STORAGE_TYPE_ATTR] || + '') as che.WorkspaceStorageType; } set storageType(type: che.WorkspaceStorageType) { - if (isCheWorkspace(this.workspace)) { - const attributes = typeToAttributes(type); - if (!this.workspace.devfile.attributes) { - this.workspace.devfile.attributes = {}; - } else { - delete this.workspace.devfile.attributes.asyncPersist; - delete this.workspace.devfile.attributes.persistVolumes; - } - if (attributes) { - Object.assign(this.workspace.devfile.attributes, attributes); - } - if (Object.keys(this.workspace.devfile.attributes).length === 0) { - delete this.workspace.devfile.attributes; + if (type) { + if (!this.workspace.spec.template.attributes) { + this.workspace.spec.template.attributes = {}; } + this.workspace.spec.template.attributes[DEVWORKSPACE_STORAGE_TYPE_ATTR] = type; } else { - if (type) { - if (!this.workspace.spec.template.attributes) { - this.workspace.spec.template.attributes = {}; - } - this.workspace.spec.template.attributes[DEVWORKSPACE_STORAGE_TYPE_ATTR] = type; - } else { - if (this.workspace.spec.template.attributes?.[DEVWORKSPACE_STORAGE_TYPE_ATTR]) { - delete this.workspace.spec.template.attributes[DEVWORKSPACE_STORAGE_TYPE_ATTR]; - if (Object.keys(this.workspace.spec.template.attributes).length === 0) { - delete this.workspace.spec.template.attributes; - } + if (this.workspace.spec.template.attributes?.[DEVWORKSPACE_STORAGE_TYPE_ATTR]) { + delete this.workspace.spec.template.attributes[DEVWORKSPACE_STORAGE_TYPE_ATTR]; + if (Object.keys(this.workspace.spec.template.attributes).length === 0) { + delete this.workspace.spec.template.attributes; } } } } - get devfile(): che.WorkspaceDevfile | devfileApi.Devfile { - if (isCheWorkspace(this.workspace)) { - return this.workspace.devfile as T extends che.Workspace - ? che.WorkspaceDevfile - : devfileApi.Devfile; - } else { - if ( - this.workspace.metadata.annotations && - this.workspace.metadata.annotations[DEVWORKSPACE_NEXT_START_ANNOTATION] - ) { - const devfile = devWorkspaceToDevfile( - JSON.parse(this.workspace.metadata.annotations[DEVWORKSPACE_NEXT_START_ANNOTATION]), - ); - if (isDevfileV2(devfile)) { - return devfile; - } + get devfile(): devfileApi.Devfile { + if ( + this.workspace.metadata.annotations && + this.workspace.metadata.annotations[DEVWORKSPACE_NEXT_START_ANNOTATION] + ) { + const devfile = devWorkspaceToDevfile( + JSON.parse(this.workspace.metadata.annotations[DEVWORKSPACE_NEXT_START_ANNOTATION]), + ); + if (isDevfileV2(devfile)) { + return devfile; } - return devWorkspaceToDevfile(this.workspace) as devfileApi.Devfile; } + return devWorkspaceToDevfile(this.workspace) as devfileApi.Devfile; } - set devfile(devfile: che.WorkspaceDevfile | devfileApi.Devfile) { - if (isCheWorkspace(this.workspace)) { - this.workspace.devfile = devfile as che.WorkspaceDevfile; - } else { - const plugins = this.workspace.spec.contributions || []; - const converted = devfileToDevWorkspace( - devfile as devfileApi.Devfile, - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - this.workspace.spec.routingClass!, - this.workspace.spec.started, - ); - if (isDevWorkspace(converted)) { - if (converted.spec.contributions === undefined) { - converted.spec.contributions = []; - } - converted.spec.contributions.push(...plugins); - (this.workspace as devfileApi.DevWorkspace) = converted; - } else { - console.error( - `WorkspaceAdapter: the received devworkspace either has wrong "kind" (not ${devWorkspaceKind}) or lacks some of mandatory fields: `, - converted, - ); - throw new Error( - 'Unexpected error happened. Please check the Console tab of Developer tools.', - ); - } + set devfile(devfile: devfileApi.Devfile) { + const plugins = this.workspace.spec.contributions || []; + const converted = devfileToDevWorkspace( + devfile as devfileApi.Devfile, + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + this.workspace.spec.routingClass!, + this.workspace.spec.started, + ); + if (converted.spec.contributions === undefined) { + converted.spec.contributions = []; } + converted.spec.contributions.push(...plugins); + (this.workspace as devfileApi.DevWorkspace) = converted; } get projects(): string[] { - if (isCheWorkspace(this.workspace)) { - return (this.workspace.devfile.projects || []).map(project => project.name); - } else { - return (this.workspace.spec.template.projects || []).map(project => project.name); - } + return (this.workspace.spec.template.projects || []).map(project => project.name); } } -export function constructWorkspace( - workspace: T, -): Workspace { +export function constructWorkspace(workspace: T): Workspace { return new WorkspaceAdapter(workspace); } -export function isCheWorkspace( - workspace: che.Workspace | devfileApi.DevWorkspace, -): workspace is che.Workspace { - return ( - (workspace as che.Workspace).id !== undefined && - (workspace as che.Workspace).devfile !== undefined && - (workspace as che.Workspace).status !== undefined - ); -} - -export function isCheDevfile(devfile: Devfile): devfile is che.WorkspaceDevfile { +export function isCheDevfile(devfile: unknown): devfile is che.WorkspaceDevfile { return !isDevfileV2(devfile); } diff --git a/packages/dashboard-frontend/src/store/DevfileRegistries/__tests__/index.spec.ts b/packages/dashboard-frontend/src/store/DevfileRegistries/__tests__/index.spec.ts index 65ba576a5..5a80f66f0 100644 --- a/packages/dashboard-frontend/src/store/DevfileRegistries/__tests__/index.spec.ts +++ b/packages/dashboard-frontend/src/store/DevfileRegistries/__tests__/index.spec.ts @@ -170,39 +170,6 @@ describe('Devfile registries', () => { expect(actions).toEqual(expectedActions); }); - it('should create REQUEST_SCHEMA and RECEIVE_SCHEMA when fetching the devfile v1 schema', async () => { - const schemaV1 = getSchemaV1(); - (mockAxios.get as jest.Mock).mockResolvedValueOnce({ - data: schemaV1, - }); - - const store = new FakeStoreBuilder() - .withWorkspacesSettings({ - 'che.devworkspaces.enabled': 'false', - } as che.WorkspaceSettings) - .build() as MockStoreEnhanced< - AppState, - ThunkDispatch - >; - - await store.dispatch(devfileRegistriesStore.actionCreators.requestJsonSchema()); - - const actions = store.getActions(); - - const expectedActions: devfileRegistriesStore.KnownAction[] = [ - { - type: devfileRegistriesStore.Type.REQUEST_SCHEMA, - check: AUTHORIZED, - }, - { - type: devfileRegistriesStore.Type.RECEIVE_SCHEMA, - schema: schemaV1, - }, - ]; - - expect(actions).toEqual(expectedActions); - }); - it('should create REQUEST_SCHEMA and RECEIVE_SCHEMA when fetching all devfile schemas', async () => { const schemaV1 = getSchemaV1(); const schemaV200 = getSchemaV200(); @@ -225,11 +192,7 @@ describe('Devfile registries', () => { data: schemav221alpha, }); - const store = new FakeStoreBuilder() - .withWorkspacesSettings({ - 'che.devworkspaces.enabled': 'true', - } as che.WorkspaceSettings) - .build() as MockStoreEnhanced< + const store = new FakeStoreBuilder().build() as MockStoreEnhanced< AppState, ThunkDispatch >; @@ -246,52 +209,13 @@ describe('Devfile registries', () => { { type: devfileRegistriesStore.Type.RECEIVE_SCHEMA, schema: { - oneOf: expect.arrayContaining([ - schemaV1, - schemaV200, - schemaV210, - schemaV220, - schemav221alpha, - ]), + oneOf: expect.arrayContaining([schemaV200, schemaV210, schemaV220]), }, }, ]; expect(actions).toEqual(expectedActions); }); - - it('should create REQUEST_SCHEMA and RECEIVE_SCHEMA_ERROR when failed to fetch devfile schemas', async () => { - const errorMessage = 'error message'; - (mockAxios.get as jest.Mock).mockRejectedValueOnce(errorMessage); - - const store = new FakeStoreBuilder() - .withWorkspacesSettings({ - 'che.devworkspaces.enabled': 'false', - } as che.WorkspaceSettings) - .build() as MockStoreEnhanced< - AppState, - ThunkDispatch - >; - - await expect( - store.dispatch(devfileRegistriesStore.actionCreators.requestJsonSchema()), - ).rejects.toMatch('Failed to request devfile JSON schema'); - - const actions = store.getActions(); - - const expectedActions: devfileRegistriesStore.KnownAction[] = [ - { - type: devfileRegistriesStore.Type.REQUEST_SCHEMA, - check: AUTHORIZED, - }, - { - type: devfileRegistriesStore.Type.RECEIVE_SCHEMA_ERROR, - error: expect.stringContaining(errorMessage), - }, - ]; - - expect(actions).toEqual(expectedActions); - }); }); describe('reducer', () => { diff --git a/packages/dashboard-frontend/src/store/DevfileRegistries/index.ts b/packages/dashboard-frontend/src/store/DevfileRegistries/index.ts index dda481e71..cdcf99d19 100644 --- a/packages/dashboard-frontend/src/store/DevfileRegistries/index.ts +++ b/packages/dashboard-frontend/src/store/DevfileRegistries/index.ts @@ -15,14 +15,11 @@ import common from '@eclipse-che/common'; import { AppThunk } from '..'; import { fetchRegistryMetadata, fetchDevfile } from '../../services/registry/devfiles'; import { createObject } from '../helpers'; -import { selectPlugins } from '../Plugins/chePlugins/selectors'; -import { isDevworkspacesEnabled } from '../../services/helpers/devworkspace'; import fetchAndUpdateDevfileSchema from './fetchAndUpdateDevfileSchema'; import devfileApi from '../../services/devfileApi'; import { fetchResources, loadResourcesContent } from '../../services/registry/resources'; import updateDevWorkspacePlugins from './updateDevWorkspacePlugins'; import { AUTHORIZED, SanityCheckAction } from '../sanityCheckMiddleware'; -import { getDevfileSchema } from '../../services/dashboard-backend-client/devWorkspaceApi'; export const DEFAULT_REGISTRY = '/dashboard/devfile-registry/'; @@ -267,71 +264,17 @@ export const actionCreators: ActionCreators = { requestJsonSchema: (): AppThunk => - async (dispatch, getState): Promise => { + async (dispatch): Promise => { await dispatch({ type: Type.REQUEST_SCHEMA, check: AUTHORIZED }); try { - const state = getState(); - const schemav1 = (await getDevfileSchema('1.0.0')) as { - [key: string]: any; - }; - const items = selectPlugins(state); - const components = schemav1?.properties?.components; - if (components) { - const mountSources = components.items.properties.mountSources; - // mount sources is specific only for some of component types but always appears - // patch schema and remove default value for boolean mount sources to avoid their appearing during the completion - if (mountSources && mountSources.default === 'false') { - delete mountSources.default; - } - schemav1.additionalProperties = true; - if (!components.defaultSnippets) { - components.defaultSnippets = []; - } - const pluginsId: string[] = []; - items.forEach((item: che.Plugin) => { - const id = `${item.publisher}/${item.name}/latest`; - if (pluginsId.indexOf(id) === -1 && item.type !== 'Che Editor') { - pluginsId.push(id); - components.defaultSnippets.push({ - label: item.displayName, - description: item.description, - body: { id: id, type: 'chePlugin' }, - }); - } else { - pluginsId.push(item.id); - } - }); - if (components.items && components.items.properties) { - if (!components.items.properties.id) { - components.items.properties.id = { - type: 'string', - description: 'Plugin/Editor id.', - }; - } - components.items.properties.id.examples = pluginsId; - } - } + const schemav200 = await fetchAndUpdateDevfileSchema('2.0.0'); + const schemav210 = await fetchAndUpdateDevfileSchema('2.1.0'); + const schemav220 = await fetchAndUpdateDevfileSchema('2.2.0'); + const schemav221alpha = await fetchAndUpdateDevfileSchema('2.2.1-alpha'); - let schema = schemav1; - - const cheDevworkspaceEnabled = isDevworkspacesEnabled(state.workspacesSettings.settings); - if (cheDevworkspaceEnabled) { - // This makes $ref resolve against the first schema, otherwise the yaml language server will report errors - const patchedJSONString = JSON.stringify(schemav1).replace( - /#\/definitions/g, - '#/oneOf/0/definitions', - ); - const parsedSchemaV1 = JSON.parse(patchedJSONString); - - const schemav200 = await fetchAndUpdateDevfileSchema('2.0.0'); - const schemav210 = await fetchAndUpdateDevfileSchema('2.1.0'); - const schemav220 = await fetchAndUpdateDevfileSchema('2.2.0'); - const schemav221alpha = await fetchAndUpdateDevfileSchema('2.2.1-alpha'); - - schema = { - oneOf: [parsedSchemaV1, schemav200, schemav210, schemav220, schemav221alpha], - }; - } + const schema = { + oneOf: [schemav200, schemav210, schemav220, schemav221alpha], + }; dispatch({ type: Type.RECEIVE_SCHEMA, diff --git a/packages/dashboard-frontend/src/store/DevfileRegistries/selectors.ts b/packages/dashboard-frontend/src/store/DevfileRegistries/selectors.ts index f01db2b9c..0d581626e 100644 --- a/packages/dashboard-frontend/src/store/DevfileRegistries/selectors.ts +++ b/packages/dashboard-frontend/src/store/DevfileRegistries/selectors.ts @@ -13,8 +13,6 @@ import { createSelector } from 'reselect'; import { AppState } from '..'; import match from '../../services/helpers/filter'; -import { selectWorkspacesSettingsState } from '../Workspaces/Settings/selectors'; -import { isDevworkspacesEnabled } from '../../services/helpers/devworkspace'; import { load } from 'js-yaml'; import devfileApi from '../../services/devfileApi'; import { selectDefaultComponents } from '../ServerConfig/selectors'; @@ -23,23 +21,14 @@ export const EMPTY_WORKSPACE_TAG = 'Empty'; const selectState = (state: AppState) => state.devfileRegistries; -export const selectRegistriesMetadata = createSelector( - selectState, - selectWorkspacesSettingsState, - (devfileRegistriesState, workspacesSettingsState) => { - const registriesMetadata = Object.keys(devfileRegistriesState.registries).map(registry => { - const metadata = devfileRegistriesState.registries[registry].metadata || []; - return metadata.map(meta => Object.assign({ registry }, meta)); - }); - const metadata = mergeRegistriesMetadata(registriesMetadata); - const cheDevworkspaceEnabled = isDevworkspacesEnabled(workspacesSettingsState.settings); - if (cheDevworkspaceEnabled) { - return filterDevfileV2Metadata(metadata); - } else { - return metadata; - } - }, -); +export const selectRegistriesMetadata = createSelector(selectState, devfileRegistriesState => { + const registriesMetadata = Object.keys(devfileRegistriesState.registries).map(registry => { + const metadata = devfileRegistriesState.registries[registry].metadata || []; + return metadata.map(meta => Object.assign({ registry }, meta)); + }); + const metadata = mergeRegistriesMetadata(registriesMetadata); + return filterDevfileV2Metadata(metadata); +}); export const selectRegistriesErrors = createSelector(selectState, state => { const errors: Array<{ url: string; errorMessage: string }> = []; diff --git a/packages/dashboard-frontend/src/store/DockerConfig/dw/__tests__/index.spec.ts b/packages/dashboard-frontend/src/store/DockerConfig/__tests__/index.spec.ts similarity index 96% rename from packages/dashboard-frontend/src/store/DockerConfig/dw/__tests__/index.spec.ts rename to packages/dashboard-frontend/src/store/DockerConfig/__tests__/index.spec.ts index 9a0170440..d65ca22cf 100644 --- a/packages/dashboard-frontend/src/store/DockerConfig/dw/__tests__/index.spec.ts +++ b/packages/dashboard-frontend/src/store/DockerConfig/__tests__/index.spec.ts @@ -13,17 +13,15 @@ import mockAxios from 'axios'; import { MockStoreEnhanced } from 'redux-mock-store'; import { ThunkDispatch } from 'redux-thunk'; -import { FakeStoreBuilder } from '../../../__mocks__/storeBuilder'; +import { FakeStoreBuilder } from '../../__mocks__/storeBuilder'; import * as dwDockerConfigStore from '..'; -import { AppState } from '../../..'; +import { AppState } from '../..'; import { AnyAction } from 'redux'; -import { AUTHORIZED } from '../../../sanityCheckMiddleware'; +import { AUTHORIZED } from '../../sanityCheckMiddleware'; // mute the outputs console.error = jest.fn(); -const namespace = 'admin-che'; - describe('dwDockerConfig store', () => { afterEach(() => { jest.clearAllMocks(); @@ -44,7 +42,7 @@ describe('dwDockerConfig store', () => { ThunkDispatch >; - await store.dispatch(dwDockerConfigStore.actionCreators.requestCredentials(namespace)); + await store.dispatch(dwDockerConfigStore.actionCreators.requestCredentials()); const actions = store.getActions(); @@ -82,7 +80,7 @@ describe('dwDockerConfig store', () => { >; await store.dispatch( - dwDockerConfigStore.actionCreators.updateCredentials(namespace, [ + dwDockerConfigStore.actionCreators.updateCredentials([ { password: 'YYYYYYYYYYYY', url: 'dummy.io', diff --git a/packages/dashboard-frontend/src/store/DockerConfig/__tests__/selectors.spec.ts b/packages/dashboard-frontend/src/store/DockerConfig/__tests__/selectors.spec.ts index 3945b319a..ecfbbad14 100644 --- a/packages/dashboard-frontend/src/store/DockerConfig/__tests__/selectors.spec.ts +++ b/packages/dashboard-frontend/src/store/DockerConfig/__tests__/selectors.spec.ts @@ -34,13 +34,7 @@ describe('dockerConfig selectors', () => { describe('devworkspaces enabled', () => { it('should return all registries', () => { const fakeStore = new FakeStoreBuilder() - .withDwDockerConfig(registries, false) - .withWorkspacesSettings( - { - ['che.devworkspaces.enabled']: 'true', - }, - false, - ) + .withDockerConfig(registries, false) .build() as MockStoreEnhanced>; const state = fakeStore.getState(); @@ -51,13 +45,7 @@ describe('dockerConfig selectors', () => { it('should return isLoading status', () => { const fakeStore = new FakeStoreBuilder() - .withDwDockerConfig([], true) - .withWorkspacesSettings( - { - ['che.devworkspaces.enabled']: 'true', - }, - false, - ) + .withDockerConfig([], true) .build() as MockStoreEnhanced>; const state = fakeStore.getState(); @@ -68,13 +56,7 @@ describe('dockerConfig selectors', () => { it('should return an error related to default editor fetching', () => { const fakeStore = new FakeStoreBuilder() - .withDwDockerConfig(registries, false, 'default editor fetching error') - .withWorkspacesSettings( - { - ['che.devworkspaces.enabled']: 'true', - }, - false, - ) + .withDockerConfig(registries, false, 'default editor fetching error') .build() as MockStoreEnhanced>; const state = fakeStore.getState(); @@ -86,7 +68,7 @@ describe('dockerConfig selectors', () => { describe('devworkspaces disabled', () => { it('should return all registries', () => { const fakeStore = new FakeStoreBuilder() - .withCheDockerConfig(registries, false) + .withDockerConfig(registries, false) .build() as MockStoreEnhanced>; const state = fakeStore.getState(); @@ -97,7 +79,7 @@ describe('dockerConfig selectors', () => { it('should return isLoading status', () => { const fakeStore = new FakeStoreBuilder() - .withCheDockerConfig([], true) + .withDockerConfig([], true) .build() as MockStoreEnhanced>; const state = fakeStore.getState(); @@ -108,7 +90,7 @@ describe('dockerConfig selectors', () => { it('should return an error related to default editor fetching', () => { const fakeStore = new FakeStoreBuilder() - .withCheDockerConfig(registries, false, 'default editor fetching error') + .withDockerConfig(registries, false, 'default editor fetching error') .build() as MockStoreEnhanced>; const state = fakeStore.getState(); diff --git a/packages/dashboard-frontend/src/store/DockerConfig/che/__tests__/index.spec.ts b/packages/dashboard-frontend/src/store/DockerConfig/che/__tests__/index.spec.ts deleted file mode 100644 index 922dc9a12..000000000 --- a/packages/dashboard-frontend/src/store/DockerConfig/che/__tests__/index.spec.ts +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Copyright (c) 2018-2021 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 { MockStoreEnhanced } from 'redux-mock-store'; -import { ThunkDispatch } from 'redux-thunk'; -import { FakeStoreBuilder } from '../../../__mocks__/storeBuilder'; -import * as cheDockerConfigStore from '..'; -import { AppState } from '../../..'; -import { AnyAction } from 'redux'; -import { AUTHORIZED } from '../../../sanityCheckMiddleware'; - -jest.mock('../../../UserPreferences', () => { - return { - actionCreators: { - requestUserPreferences: () => (): Promise => Promise.resolve(), - replaceUserPreferences: () => (): Promise => Promise.resolve(), - }, - }; -}); - -// mute the outputs -console.error = jest.fn(); - -describe('cheDockerConfig store', () => { - afterEach(() => { - jest.clearAllMocks(); - }); - - describe('actions', () => { - it('should create REQUEST_CHEWORKSPACE_CREDENTIALS and SET_CHEWORKSPACE_CREDENTIALS when requestCredentials', async () => { - const store = new FakeStoreBuilder() - .withUserPreferences({ - dockerCredentials: - 'eyJkdW1teS5pbyI6eyJwYXNzd29yZCI6IlhYWFhYWFhYWFhYWFhYWCIsInVzZXJuYW1lIjoidGVzdG5hbWUifX0=', - }) - .build() as MockStoreEnhanced< - AppState, - ThunkDispatch - >; - - await store.dispatch(cheDockerConfigStore.actionCreators.requestCredentials()); - - const actions = store.getActions(); - - const expectedActions: cheDockerConfigStore.KnownAction[] = [ - { - type: 'REQUEST_CHEWORKSPACE_CREDENTIALS', - check: AUTHORIZED, - }, - { - type: 'SET_CHEWORKSPACE_CREDENTIALS', - registries: [ - { - password: 'XXXXXXXXXXXXXXX', - url: 'dummy.io', - username: 'testname', - }, - ], - }, - ]; - - expect(actions).toEqual(expectedActions); - }); - - it('should create REQUEST_CHEWORKSPACE_CREDENTIALS and SET_CHEWORKSPACE_CREDENTIALS when updateCredentials', async () => { - const store = new FakeStoreBuilder() - .withUserPreferences({ - dockerCredentials: - 'eyJkdW1teS5pbyI6eyJwYXNzd29yZCI6IlhYWFhYWFhYWFhYWFhYWCIsInVzZXJuYW1lIjoidGVzdG5hbWUifX0=', - }) - .build() as MockStoreEnhanced< - AppState, - ThunkDispatch - >; - - await store.dispatch( - cheDockerConfigStore.actionCreators.updateCredentials([ - { - password: 'YYYYYYYYYYYY', - url: 'dummy.io', - username: 'testname2', - }, - ]), - ); - - const actions = store.getActions(); - - const expectedActions: cheDockerConfigStore.KnownAction[] = [ - { - type: 'REQUEST_CHEWORKSPACE_CREDENTIALS', - check: AUTHORIZED, - }, - { - type: 'SET_CHEWORKSPACE_CREDENTIALS', - registries: [ - { - password: 'YYYYYYYYYYYY', - url: 'dummy.io', - username: 'testname2', - }, - ], - }, - ]; - - expect(actions).toEqual(expectedActions); - }); - - describe('reducers', () => { - it('should return initial state', () => { - const incomingAction: cheDockerConfigStore.RequestCredentialsAction = { - type: 'REQUEST_CHEWORKSPACE_CREDENTIALS', - check: AUTHORIZED, - }; - const initialState = cheDockerConfigStore.reducer(undefined, incomingAction); - - const expectedState: cheDockerConfigStore.State = { - isLoading: false, - registries: [], - error: undefined, - }; - - expect(initialState).toEqual(expectedState); - }); - - it('should return state if action type is not matched', () => { - const initialState: cheDockerConfigStore.State = { - isLoading: false, - registries: [ - { - password: 'YYYYYYYYYYYY', - url: 'dummy.io', - username: 'testname3', - }, - ], - error: undefined, - } as cheDockerConfigStore.State; - const incomingAction = { - type: 'OTHER_ACTION', - isLoading: true, - registries: [], - } as AnyAction; - const newState = cheDockerConfigStore.reducer(initialState, incomingAction); - - const expectedState: cheDockerConfigStore.State = { - isLoading: false, - registries: [ - { - password: 'YYYYYYYYYYYY', - url: 'dummy.io', - username: 'testname3', - }, - ], - error: undefined, - }; - expect(newState).toEqual(expectedState); - }); - - it('should handle REQUEST_CHEWORKSPACE_CREDENTIALS', () => { - const initialState: cheDockerConfigStore.State = { - isLoading: false, - registries: [ - { - password: '********', - url: 'dummy.io', - username: 'testname4', - }, - ], - error: undefined, - }; - const incomingAction: cheDockerConfigStore.RequestCredentialsAction = { - type: 'REQUEST_CHEWORKSPACE_CREDENTIALS', - check: AUTHORIZED, - }; - - const newState = cheDockerConfigStore.reducer(initialState, incomingAction); - - const expectedState: cheDockerConfigStore.State = { - isLoading: true, - registries: [ - { - password: '********', - url: 'dummy.io', - username: 'testname4', - }, - ], - error: undefined, - }; - - expect(newState).toEqual(expectedState); - }); - - it('should handle SET_CHEWORKSPACE_CREDENTIALS', () => { - const initialState: cheDockerConfigStore.State = { - isLoading: true, - registries: [ - { - password: '********', - url: 'dummy.io', - username: 'testname4', - }, - ], - error: undefined, - }; - const incomingAction: cheDockerConfigStore.SetCredentialsAction = { - type: 'SET_CHEWORKSPACE_CREDENTIALS', - registries: [], - }; - - const newState = cheDockerConfigStore.reducer(initialState, incomingAction); - - const expectedState: cheDockerConfigStore.State = { - isLoading: false, - registries: [], - error: undefined, - }; - - expect(newState).toEqual(expectedState); - }); - - it('should handle RECEIVE_CHEWORKSPACE_CREDENTIALS_ERROR', () => { - const initialState: cheDockerConfigStore.State = { - isLoading: true, - registries: [], - resourceVersion: undefined, - error: undefined, - }; - const incomingAction: cheDockerConfigStore.ReceiveErrorAction = { - type: 'RECEIVE_CHEWORKSPACE_CREDENTIALS_ERROR', - error: 'unexpected error', - }; - - const newState = cheDockerConfigStore.reducer(initialState, incomingAction); - - const expectedState: cheDockerConfigStore.State = { - isLoading: false, - registries: [], - resourceVersion: undefined, - error: 'unexpected error', - }; - - expect(newState).toEqual(expectedState); - }); - }); - }); -}); diff --git a/packages/dashboard-frontend/src/store/DockerConfig/che/index.ts b/packages/dashboard-frontend/src/store/DockerConfig/che/index.ts deleted file mode 100644 index 7af3fa967..000000000 --- a/packages/dashboard-frontend/src/store/DockerConfig/che/index.ts +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (c) 2018-2021 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 { helpers } from '@eclipse-che/common'; -import { AppThunk } from '../..'; -import { createObject } from '../../helpers'; -import { ContainerCredentials, RegistryEntry } from '../types'; -import { State } from '../dockerConfigState'; -import * as UserPreferences from '../../UserPreferences'; -import { AUTHORIZED, SanityCheckAction } from '../../sanityCheckMiddleware'; -export * from '../dockerConfigState'; - -export interface RequestCredentialsAction extends Action, SanityCheckAction { - type: 'REQUEST_CHEWORKSPACE_CREDENTIALS'; -} - -export interface SetCredentialsAction extends Action { - type: 'SET_CHEWORKSPACE_CREDENTIALS'; - registries: RegistryEntry[]; -} - -export interface ReceiveErrorAction extends Action { - type: 'RECEIVE_CHEWORKSPACE_CREDENTIALS_ERROR'; - error: string; -} - -export type KnownAction = RequestCredentialsAction | SetCredentialsAction | ReceiveErrorAction; - -export type ActionCreators = { - requestCredentials: () => AppThunk>; - updateCredentials: (registries: RegistryEntry[]) => AppThunk>; -}; - -export const actionCreators: ActionCreators = { - requestCredentials: - (): AppThunk> => - async (dispatch, getState): Promise => { - await dispatch({ type: 'REQUEST_CHEWORKSPACE_CREDENTIALS', check: AUTHORIZED }); - const { - userPreferences: { preferences }, - } = getState(); - try { - await dispatch(UserPreferences.actionCreators.requestUserPreferences(undefined)); - const registries: RegistryEntry[] = []; - if (preferences.dockerCredentials) { - const containerCredentials: ContainerCredentials = JSON.parse( - window.atob(preferences.dockerCredentials), - ); - for (const [url, value] of Object.entries(containerCredentials)) { - const { username, password } = value || {}; - registries.push({ url, username, password }); - } - } - dispatch({ - type: 'SET_CHEWORKSPACE_CREDENTIALS', - registries, - }); - } catch (e) { - const errorMessage = - 'Failed to request the docker config. Reason: ' + helpers.errors.getMessage(e); - dispatch({ - type: 'RECEIVE_CHEWORKSPACE_CREDENTIALS_ERROR', - error: errorMessage, - }); - throw errorMessage; - } - }, - - updateCredentials: - (registries: RegistryEntry[]): AppThunk> => - async (dispatch, getState): Promise => { - await dispatch({ type: 'REQUEST_CHEWORKSPACE_CREDENTIALS', check: AUTHORIZED }); - const { - userPreferences: { preferences }, - } = getState(); - const newContainerCredentials: ContainerCredentials = {}; - registries.forEach(item => { - const { url, username, password } = item; - newContainerCredentials[url] = { username, password }; - }); - const dockerCredentials = window.btoa(JSON.stringify(newContainerCredentials)); - const prefUpdate = Object.assign({}, preferences, { - dockerCredentials, - }) as che.UserPreferences; - try { - await dispatch(UserPreferences.actionCreators.replaceUserPreferences(prefUpdate)); - dispatch({ - type: 'SET_CHEWORKSPACE_CREDENTIALS', - registries, - }); - } catch (e) { - const errorMessage = - 'Failed to update the docker cofig. Reason: ' + helpers.errors.getMessage(e); - dispatch({ - type: 'RECEIVE_CHEWORKSPACE_CREDENTIALS_ERROR', - error: errorMessage, - }); - throw errorMessage; - } - }, -}; - -const unloadedState: State = { - isLoading: false, - registries: [], - error: undefined, -}; - -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_CHEWORKSPACE_CREDENTIALS': - return createObject(state, { - isLoading: true, - error: undefined, - }); - case 'SET_CHEWORKSPACE_CREDENTIALS': - return createObject(state, { - isLoading: false, - registries: action.registries, - }); - case 'RECEIVE_CHEWORKSPACE_CREDENTIALS_ERROR': - return createObject(state, { - isLoading: false, - error: action.error, - }); - default: - return state; - } -}; diff --git a/packages/dashboard-frontend/src/store/DockerConfig/dw/index.ts b/packages/dashboard-frontend/src/store/DockerConfig/dw/index.ts deleted file mode 100644 index 850c96ecd..000000000 --- a/packages/dashboard-frontend/src/store/DockerConfig/dw/index.ts +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright (c) 2018-2021 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 { api, helpers } from '@eclipse-che/common'; -import { AppThunk } from '../..'; -import { createObject } from '../../helpers'; -import * as DwApi from '../../../services/dashboard-backend-client/devWorkspaceApi'; -import { RegistryEntry } from '../types'; -import { State } from '../dockerConfigState'; -import { AUTHORIZED, SanityCheckAction } from '../../sanityCheckMiddleware'; -export * from '../dockerConfigState'; - -export interface RequestCredentialsAction extends Action, SanityCheckAction { - type: 'REQUEST_DEVWORKSPACE_CREDENTIALS'; -} - -export interface SetCredentialsAction extends Action { - type: 'SET_DEVWORKSPACE_CREDENTIALS'; - registries: RegistryEntry[]; - resourceVersion: string | undefined; -} - -export interface ReceiveErrorAction extends Action { - type: 'RECEIVE_DEVWORKSPACE_CREDENTIALS_ERROR'; - error: string; -} - -export type KnownAction = RequestCredentialsAction | SetCredentialsAction | ReceiveErrorAction; - -export type ActionCreators = { - requestCredentials: (namespace: string) => AppThunk>; - updateCredentials: ( - namespace: string, - registries: RegistryEntry[], - ) => AppThunk>; -}; - -export const actionCreators: ActionCreators = { - requestCredentials: - (namespace: string): AppThunk> => - async (dispatch): Promise => { - await dispatch({ type: 'REQUEST_DEVWORKSPACE_CREDENTIALS', check: AUTHORIZED }); - try { - const { registries, resourceVersion } = await getDockerConfig(namespace); - dispatch({ - type: 'SET_DEVWORKSPACE_CREDENTIALS', - registries, - resourceVersion, - }); - } catch (e) { - const errorMessage = helpers.errors.getMessage(e); - dispatch({ - type: 'RECEIVE_DEVWORKSPACE_CREDENTIALS_ERROR', - error: errorMessage, - }); - throw errorMessage; - } - }, - - updateCredentials: - (namespace: string, registries: RegistryEntry[]): AppThunk> => - async (dispatch, getState): Promise => { - await dispatch({ type: 'REQUEST_DEVWORKSPACE_CREDENTIALS', check: AUTHORIZED }); - const { dwDockerConfig } = getState(); - try { - const { resourceVersion } = await putDockerConfig( - namespace, - registries, - dwDockerConfig?.resourceVersion, - ); - dispatch({ - type: 'SET_DEVWORKSPACE_CREDENTIALS', - registries, - resourceVersion, - }); - } catch (e) { - const errorMessage = helpers.errors.getMessage(e); - dispatch({ - type: 'RECEIVE_DEVWORKSPACE_CREDENTIALS_ERROR', - error: errorMessage, - }); - throw errorMessage; - } - }, -}; - -async function getDockerConfig( - namespace: string, -): Promise<{ registries: RegistryEntry[]; resourceVersion?: string }> { - let dockerconfig, resourceVersion: string | undefined; - try { - const resp = await DwApi.getDockerConfig(namespace); - dockerconfig = resp.dockerconfig; - resourceVersion = resp.resourceVersion; - } catch (e) { - throw 'Failed to request the docker config. Reason: ' + helpers.errors.getMessage(e); - } - const registries: RegistryEntry[] = []; - if (dockerconfig) { - try { - const auths = JSON.parse(window.atob(dockerconfig))['auths']; - Object.keys(auths).forEach(key => { - const [username, password] = window.atob(auths[key]['auth']).split(':'); - registries.push({ url: key, username, password }); - }); - } catch (e) { - throw 'Unable to decode and parse data. Reason: ' + helpers.errors.getMessage(e); - } - } - return { registries, resourceVersion }; -} - -function putDockerConfig( - namespace: string, - registries: RegistryEntry[], - resourceVersion?: string, -): Promise { - const config: api.IDockerConfig = { dockerconfig: '' }; - try { - const authInfo = { auths: {} }; - registries.forEach(item => { - const { url, username, password } = item; - authInfo.auths[url] = { username, password }; - authInfo.auths[url].auth = window.btoa(username + ':' + password); - }); - config.dockerconfig = window.btoa(JSON.stringify(authInfo)); - if (resourceVersion) { - config.resourceVersion = resourceVersion; - } - try { - return DwApi.putDockerConfig(namespace, config); - } catch (err) { - throw 'Failed to update the docker cofig. Reason: ' + helpers.errors.getMessage(err); - } - } catch (e) { - throw 'Unable to parse and code data. Reason: ' + helpers.errors.getMessage(e); - } -} - -const unloadedState: State = { - isLoading: false, - registries: [], - resourceVersion: undefined, - error: undefined, -}; - -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_DEVWORKSPACE_CREDENTIALS': - return createObject(state, { - isLoading: true, - error: undefined, - }); - case 'SET_DEVWORKSPACE_CREDENTIALS': - return createObject(state, { - isLoading: false, - registries: action.registries, - resourceVersion: action.resourceVersion, - }); - case 'RECEIVE_DEVWORKSPACE_CREDENTIALS_ERROR': - return createObject(state, { - isLoading: false, - error: action.error, - }); - default: - return state; - } -}; diff --git a/packages/dashboard-frontend/src/store/DockerConfig/index.ts b/packages/dashboard-frontend/src/store/DockerConfig/index.ts index e951f5356..46dbd4c07 100644 --- a/packages/dashboard-frontend/src/store/DockerConfig/index.ts +++ b/packages/dashboard-frontend/src/store/DockerConfig/index.ts @@ -10,41 +10,178 @@ * Red Hat, Inc. - initial API and implementation */ -import { Action } from 'redux'; +import { Action, Reducer } from 'redux'; +import { api, helpers } from '@eclipse-che/common'; import { AppThunk } from '..'; -import * as CheWorkspacesStore from './che'; -import * as DevWorkspacesStore from './dw'; +import { createObject } from '../helpers'; +import * as DwApi from '../../services/dashboard-backend-client/devWorkspaceApi'; import { RegistryEntry } from './types'; +import { State } from './dockerConfigState'; +import { AUTHORIZED, SanityCheckAction } from '../sanityCheckMiddleware'; import { selectDefaultNamespace } from '../InfrastructureNamespaces/selectors'; -import { selectDevworkspacesEnabled } from '../Workspaces/Settings/selectors'; +export * from './dockerConfigState'; + +export interface RequestCredentialsAction extends Action, SanityCheckAction { + type: 'REQUEST_DEVWORKSPACE_CREDENTIALS'; +} + +export interface SetCredentialsAction extends Action { + type: 'SET_DEVWORKSPACE_CREDENTIALS'; + registries: RegistryEntry[]; + resourceVersion: string | undefined; +} + +export interface ReceiveErrorAction extends Action { + type: 'RECEIVE_DEVWORKSPACE_CREDENTIALS_ERROR'; + error: string; +} + +export type KnownAction = RequestCredentialsAction | SetCredentialsAction | ReceiveErrorAction; export type ActionCreators = { - requestCredentials: () => AppThunk>; - updateCredentials: (registries: RegistryEntry[]) => AppThunk>; + requestCredentials: () => AppThunk>; + updateCredentials: (registries: RegistryEntry[]) => AppThunk>; }; export const actionCreators: ActionCreators = { requestCredentials: - (): AppThunk> => + (): AppThunk> => async (dispatch, getState): Promise => { const state = getState(); - if (selectDevworkspacesEnabled(state)) { - const namespace = selectDefaultNamespace(state).name; - await dispatch(DevWorkspacesStore.actionCreators.requestCredentials(namespace)); - } else { - await dispatch(CheWorkspacesStore.actionCreators.requestCredentials()); + const namespace = selectDefaultNamespace(state).name; + await dispatch({ type: 'REQUEST_DEVWORKSPACE_CREDENTIALS', check: AUTHORIZED }); + try { + const { registries, resourceVersion } = await getDockerConfig(namespace); + dispatch({ + type: 'SET_DEVWORKSPACE_CREDENTIALS', + registries, + resourceVersion, + }); + } catch (e) { + const errorMessage = helpers.errors.getMessage(e); + dispatch({ + type: 'RECEIVE_DEVWORKSPACE_CREDENTIALS_ERROR', + error: errorMessage, + }); + throw e; } }, updateCredentials: - (registries: RegistryEntry[]): AppThunk> => + (registries: RegistryEntry[]): AppThunk> => async (dispatch, getState): Promise => { + await dispatch({ type: 'REQUEST_DEVWORKSPACE_CREDENTIALS', check: AUTHORIZED }); const state = getState(); - if (selectDevworkspacesEnabled(state)) { - const namespace = selectDefaultNamespace(state).name; - await dispatch(DevWorkspacesStore.actionCreators.updateCredentials(namespace, registries)); - } else { - await dispatch(CheWorkspacesStore.actionCreators.updateCredentials(registries)); + const namespace = selectDefaultNamespace(state).name; + try { + const { resourceVersion } = await putDockerConfig( + namespace, + registries, + state.dockerConfig?.resourceVersion, + ); + dispatch({ + type: 'SET_DEVWORKSPACE_CREDENTIALS', + registries, + resourceVersion, + }); + } catch (e) { + const errorMessage = helpers.errors.getMessage(e); + dispatch({ + type: 'RECEIVE_DEVWORKSPACE_CREDENTIALS_ERROR', + error: errorMessage, + }); + throw e; } }, }; + +async function getDockerConfig( + namespace: string, +): Promise<{ registries: RegistryEntry[]; resourceVersion?: string }> { + let dockerconfig, resourceVersion: string | undefined; + try { + const resp = await DwApi.getDockerConfig(namespace); + dockerconfig = resp.dockerconfig; + resourceVersion = resp.resourceVersion; + } catch (e) { + throw 'Failed to request the docker config. Reason: ' + helpers.errors.getMessage(e); + } + const registries: RegistryEntry[] = []; + if (dockerconfig) { + try { + const auths = JSON.parse(window.atob(dockerconfig))['auths']; + Object.keys(auths).forEach(key => { + const [username, password] = window.atob(auths[key]['auth']).split(':'); + registries.push({ url: key, username, password }); + }); + } catch (e) { + throw 'Unable to decode and parse data. Reason: ' + helpers.errors.getMessage(e); + } + } + return { registries, resourceVersion }; +} + +function putDockerConfig( + namespace: string, + registries: RegistryEntry[], + resourceVersion?: string, +): Promise { + const config: api.IDockerConfig = { dockerconfig: '' }; + try { + const authInfo = { auths: {} }; + registries.forEach(item => { + const { url, username, password } = item; + authInfo.auths[url] = { username, password }; + authInfo.auths[url].auth = window.btoa(username + ':' + password); + }); + config.dockerconfig = window.btoa(JSON.stringify(authInfo)); + if (resourceVersion) { + config.resourceVersion = resourceVersion; + } + try { + return DwApi.putDockerConfig(namespace, config); + } catch (err) { + throw 'Failed to update the docker cofig. Reason: ' + helpers.errors.getMessage(err); + } + } catch (e) { + throw 'Unable to parse and code data. Reason: ' + helpers.errors.getMessage(e); + } +} + +const unloadedState: State = { + isLoading: false, + registries: [], + resourceVersion: undefined, + error: undefined, +}; + +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_DEVWORKSPACE_CREDENTIALS': + return createObject(state, { + isLoading: true, + error: undefined, + }); + case 'SET_DEVWORKSPACE_CREDENTIALS': + return createObject(state, { + isLoading: false, + registries: action.registries, + resourceVersion: action.resourceVersion, + }); + case 'RECEIVE_DEVWORKSPACE_CREDENTIALS_ERROR': + return createObject(state, { + isLoading: false, + error: action.error, + }); + default: + return state; + } +}; diff --git a/packages/dashboard-frontend/src/store/DockerConfig/selectors.ts b/packages/dashboard-frontend/src/store/DockerConfig/selectors.ts index ce11374e9..3cdb22eb9 100644 --- a/packages/dashboard-frontend/src/store/DockerConfig/selectors.ts +++ b/packages/dashboard-frontend/src/store/DockerConfig/selectors.ts @@ -12,24 +12,9 @@ import { createSelector } from 'reselect'; import { AppState } from '..'; -import { selectDevworkspacesEnabled } from '../Workspaces/Settings/selectors'; import { State } from './dockerConfigState'; -const selectCheDockerConfigState = (state: AppState) => state.cheDockerConfig; -const selectDwDockerConfigState = (state: AppState) => state.dwDockerConfig; - -const selectState = createSelector( - selectDevworkspacesEnabled, - selectCheDockerConfigState, - selectDwDockerConfigState, - (devworkspaceEnabled, cheDockerConfigState, dwDockerConfigState) => { - if (devworkspaceEnabled) { - return dwDockerConfigState; - } else { - return cheDockerConfigState; - } - }, -); +const selectState = (state: AppState) => state.dockerConfig; export const selectIsLoading = createSelector(selectState, state => { return state.isLoading; diff --git a/packages/dashboard-frontend/src/store/FactoryResolver/__tests__/index.spec.ts b/packages/dashboard-frontend/src/store/FactoryResolver/__tests__/index.spec.ts index cf5228880..4ad781497 100644 --- a/packages/dashboard-frontend/src/store/FactoryResolver/__tests__/index.spec.ts +++ b/packages/dashboard-frontend/src/store/FactoryResolver/__tests__/index.spec.ts @@ -84,7 +84,6 @@ describe('FactoryResolver store', () => { const store = new FakeStoreBuilder() .withWorkspacesSettings({ - 'che.devworkspaces.enabled': 'true', 'che.workspace.storage.preferred_type': 'ephemeral', }) .build() as MockStoreEnhanced< @@ -117,12 +116,7 @@ describe('FactoryResolver store', () => { getFactoryResolverSpy.mockResolvedValueOnce(resolver); - const store = new FakeStoreBuilder() - .withWorkspacesSettings({ - 'che.devworkspaces.enabled': 'true', - 'che.workspace.storage.preferred_type': 'ephemeral', - }) - .build() as MockStoreEnhanced< + const store = new FakeStoreBuilder().build() as MockStoreEnhanced< AppState, ThunkDispatch >; diff --git a/packages/dashboard-frontend/src/store/FactoryResolver/index.ts b/packages/dashboard-frontend/src/store/FactoryResolver/index.ts index 512cfb939..258776b8a 100644 --- a/packages/dashboard-frontend/src/store/FactoryResolver/index.ts +++ b/packages/dashboard-frontend/src/store/FactoryResolver/index.ts @@ -19,7 +19,6 @@ import { CheWorkspaceClient } from '../../services/workspace-client/cheworkspace import { AppThunk } from '../index'; import { createObject } from '../helpers'; import { selectDefaultComponents, selectPvcStrategy } from '../ServerConfig/selectors'; -import { Devfile } from '../../services/workspace-adapter'; import devfileApi, { isDevfileV2 } from '../../services/devfileApi'; import { convertDevfileV1toDevfileV2 } from '../../services/devfile/converters'; import normalizeDevfileV2 from './normalizeDevfileV2'; @@ -49,7 +48,7 @@ export interface ResolverState extends FactoryResolver { } export interface ConvertedState { - resolvedDevfile: Devfile; + resolvedDevfile: devfileApi.Devfile | che.WorkspaceDevfile; devfileV2: devfileApi.Devfile; isConverted: boolean; } diff --git a/packages/dashboard-frontend/src/store/ServerConfig/selectors.ts b/packages/dashboard-frontend/src/store/ServerConfig/selectors.ts index e22b3e34a..5b3d65e88 100644 --- a/packages/dashboard-frontend/src/store/ServerConfig/selectors.ts +++ b/packages/dashboard-frontend/src/store/ServerConfig/selectors.ts @@ -38,7 +38,7 @@ export const selectPvcStrategy = createSelector( export const selectStartTimeout = createSelector( selectState, - state => state.config.timeouts.startTimeout, + state => (state.config.timeouts as any)?.startTimeout, ); export const selectServerConfigError = createSelector(selectState, state => state.error); diff --git a/packages/dashboard-frontend/src/store/UserPreferences/index.ts b/packages/dashboard-frontend/src/store/UserPreferences/index.ts deleted file mode 100644 index 4350c1483..000000000 --- a/packages/dashboard-frontend/src/store/UserPreferences/index.ts +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2018-2021 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 - */ - -// This state defines the type of data maintained in the Redux store. - -import { Action, Reducer } from 'redux'; -import common from '@eclipse-che/common'; -import { createObject } from '../helpers'; -import { AppThunk } from '..'; -import { container } from '../../inversify.config'; -import { CheWorkspaceClient } from '../../services/workspace-client/cheworkspace/cheWorkspaceClient'; -import { AUTHORIZED, SanityCheckAction } from '../sanityCheckMiddleware'; - -const WorkspaceClient = container.get(CheWorkspaceClient); - -export interface State { - preferences: che.UserPreferences; - isLoading: boolean; -} - -interface RequestUserPreferencesAction extends Action, SanityCheckAction { - type: 'REQUEST_USER_PREFERENCES'; -} - -interface ReceiveUserPreferencesAction { - type: 'RECEIVE_USER_PREFERENCES'; - preferences: che.UserPreferences; -} - -type KnownAction = RequestUserPreferencesAction | ReceiveUserPreferencesAction; - -export type ActionCreators = { - requestUserPreferences: (filter: string | undefined) => AppThunk>; - replaceUserPreferences: ( - preferences: che.UserPreferences, - ) => AppThunk>; -}; - -export const actionCreators: ActionCreators = { - requestUserPreferences: - (filter: string | undefined): AppThunk> => - async (dispatch): Promise => { - await dispatch({ type: 'REQUEST_USER_PREFERENCES', check: AUTHORIZED }); - - try { - const data = await WorkspaceClient.restApiClient.getUserPreferences(filter); - dispatch({ type: 'RECEIVE_USER_PREFERENCES', preferences: data }); - return; - } catch (e) { - const errorMessage = - 'Failed to request user preferences, reason: ' + common.helpers.errors.getMessage(e); - throw new Error(errorMessage); - } - }, - replaceUserPreferences: - (preferences: che.UserPreferences): AppThunk> => - async (dispatch): Promise => { - await dispatch({ type: 'REQUEST_USER_PREFERENCES', check: AUTHORIZED }); - - try { - await WorkspaceClient.restApiClient.replaceUserPreferences(preferences); - dispatch({ type: 'RECEIVE_USER_PREFERENCES', preferences }); - return; - } catch (e) { - const errorMessage = - 'Failed to update user preferences, reason: ' + common.helpers.errors.getMessage(e); - throw new Error(errorMessage); - } - }, -}; - -const unloadedState: State = { - preferences: {}, - 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_USER_PREFERENCES': - return createObject(state, { - isLoading: true, - }); - case 'RECEIVE_USER_PREFERENCES': - return createObject(state, { - isLoading: false, - preferences: action.preferences, - }); - default: - return state; - } -}; diff --git a/packages/dashboard-frontend/src/store/UserPreferences/selectors.ts b/packages/dashboard-frontend/src/store/UserPreferences/selectors.ts deleted file mode 100644 index 2efb9feb0..000000000 --- a/packages/dashboard-frontend/src/store/UserPreferences/selectors.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2018-2021 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 { createSelector } from 'reselect'; -import { AppState } from '..'; - -const selectState = (state: AppState) => state.userPreferences; - -export const selectIsLoading = createSelector(selectState, state => state.isLoading); - -export const selectPreferences = createSelector(selectState, state => state.preferences); diff --git a/packages/dashboard-frontend/src/store/Workspaces/Settings/selectors.ts b/packages/dashboard-frontend/src/store/Workspaces/Settings/selectors.ts index 86fbed6d6..2a629db83 100644 --- a/packages/dashboard-frontend/src/store/Workspaces/Settings/selectors.ts +++ b/packages/dashboard-frontend/src/store/Workspaces/Settings/selectors.ts @@ -12,20 +12,10 @@ import { createSelector } from 'reselect'; import { AppState } from '../..'; -import * as storageTypesService from '../../../services/storageTypes'; -import { isDevworkspacesEnabled } from '../../../services/helpers/devworkspace'; const selectState = (state: AppState) => state.workspacesSettings; export const selectWorkspacesSettingsState = selectState; export const selectWorkspacesSettings = createSelector(selectState, state => state.settings); -export const selectAvailableStorageTypes = createSelector(selectWorkspacesSettings, settings => - storageTypesService.getAvailable(settings), -); - export const selectWorkspacesSettingsError = createSelector(selectState, state => state.error); - -export const selectDevworkspacesEnabled = createSelector(selectState, state => - isDevworkspacesEnabled(state?.settings || {}), -); diff --git a/packages/dashboard-frontend/src/store/Workspaces/cheWorkspaces/index.ts b/packages/dashboard-frontend/src/store/Workspaces/cheWorkspaces/index.ts deleted file mode 100644 index bd822563e..000000000 --- a/packages/dashboard-frontend/src/store/Workspaces/cheWorkspaces/index.ts +++ /dev/null @@ -1,508 +0,0 @@ -/* - * Copyright (c) 2018-2021 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 * as api from '@eclipse-che/api'; -import { ThunkDispatch } from 'redux-thunk'; -import common from '@eclipse-che/common'; -import { AppThunk } from '../..'; -import { container } from '../../../inversify.config'; -import { CheWorkspaceClient } from '../../../services/workspace-client/cheworkspace/cheWorkspaceClient'; -import { WorkspacesLogs, WorkspaceStatus } from '../../../services/helpers/types'; -import { createObject } from '../../helpers'; -import { deleteLogs, mergeLogs } from '../logs'; -import { getDefer, IDeferred } from '../../../services/helpers/deferred'; -import { DisposableCollection } from '../../../services/helpers/disposable'; -import { WorkspaceAdapter } from '../../../services/workspace-adapter'; -import { selectDevworkspacesEnabled } from '../Settings/selectors'; -import { AUTHORIZED, SanityCheckAction } from '../../sanityCheckMiddleware'; - -const cheWorkspaceClient = container.get(CheWorkspaceClient); - -export interface State { - isLoading: boolean; - workspaces: che.Workspace[]; - error?: string; - // runtime logs - workspacesLogs: WorkspacesLogs; -} - -interface RequestWorkspacesAction extends Action, SanityCheckAction { - type: 'CHE_REQUEST_WORKSPACES'; -} - -interface ReceiveErrorAction { - type: 'CHE_RECEIVE_ERROR'; - error: string; -} - -interface ReceiveWorkspacesAction { - type: 'CHE_RECEIVE_WORKSPACES'; - workspaces: che.Workspace[]; -} - -interface UpdateWorkspaceAction { - type: 'CHE_UPDATE_WORKSPACE'; - workspace: che.Workspace; -} - -interface UpdateWorkspaceStatusAction extends Action { - type: 'CHE_UPDATE_WORKSPACE_STATUS'; - workspaceId: string; - status: string; -} - -interface UpdateWorkspacesLogsAction extends Action { - type: 'CHE_UPDATE_WORKSPACES_LOGS'; - workspacesLogs: WorkspacesLogs; -} - -interface DeleteWorkspaceLogsAction { - type: 'CHE_DELETE_WORKSPACE_LOGS'; - workspaceId: string; -} - -interface DeleteWorkspaceAction { - type: 'CHE_DELETE_WORKSPACE'; - workspaceId: string; -} - -interface AddWorkspaceAction { - type: 'CHE_ADD_WORKSPACE'; - workspace: che.Workspace; -} - -type KnownAction = - | RequestWorkspacesAction - | ReceiveErrorAction - | ReceiveWorkspacesAction - | UpdateWorkspaceAction - | DeleteWorkspaceAction - | AddWorkspaceAction - | UpdateWorkspaceStatusAction - | UpdateWorkspacesLogsAction - | DeleteWorkspaceLogsAction; - -export type ResourceQueryParams = { - 'debug-workspace-start': boolean; - [propName: string]: string | boolean | undefined; -}; -export type ActionCreators = { - requestWorkspaces: () => AppThunk>; - requestWorkspace: (workspace: che.Workspace) => AppThunk>; - startWorkspace: ( - workspace: che.Workspace, - params?: ResourceQueryParams, - ) => AppThunk>; - stopWorkspace: (workspace: che.Workspace) => AppThunk>; - restartWorkspace: (workspace: che.Workspace) => AppThunk>; - deleteWorkspace: (workspace: che.Workspace) => AppThunk>; - updateWorkspace: (workspace: che.Workspace) => AppThunk>; - createWorkspaceFromDevfile: ( - devfile: che.WorkspaceDevfile, - namespace: string | undefined, - infrastructureNamespace: string | undefined, - attributes: { [key: string]: string }, - ) => AppThunk>; - deleteWorkspaceLogs: (workspaceId: string) => AppThunk; -}; - -type WorkspaceStatusMessageHandler = ( - message: api.che.workspace.event.WorkspaceStatusEvent, -) => void; -type EnvironmentOutputMessageHandler = (message: api.che.workspace.event.RuntimeLogEvent) => void; -const subscribedWorkspaceStatusCallbacks = new Map(); -const subscribedEnvironmentOutputCallbacks = new Map(); -const onStatusChangeCallbacks = new Map void>(); - -async function onStatusUpdateReceived( - workspace: che.Workspace, - dispatch: ThunkDispatch< - State, - undefined, - UpdateWorkspaceStatusAction | UpdateWorkspacesLogsAction | DeleteWorkspaceLogsAction - >, - message: any, -) { - let status: string; - if (message.error) { - const workspacesLogs = new Map(); - workspacesLogs.set(workspace.id, [`Error: Failed to run the workspace: "${message.error}"`]); - dispatch({ - type: 'CHE_UPDATE_WORKSPACES_LOGS', - workspacesLogs, - }); - // ignore an error if start interrupted by owner - const re = - /^Runtime start for identity 'workspace: (?:[\d\w]+), environment: (?:[\w\d]+), ownerId: (?:[-\d\w]+)' is interrupted$/; - status = re.test(message.error) ? message.status : WorkspaceStatus.ERROR; - } else { - status = message.status; - } - if (WorkspaceStatus[status]) { - dispatch({ - type: 'CHE_UPDATE_WORKSPACE_STATUS', - workspaceId: workspace.id, - status, - }); - const onStatusChangeCallback = onStatusChangeCallbacks.get(workspace.id); - if (onStatusChangeCallback) { - onStatusChangeCallback(status); - } - } -} - -function subscribeToStatusChange( - workspace: che.Workspace, - dispatch: ThunkDispatch< - State, - undefined, - UpdateWorkspaceStatusAction | UpdateWorkspacesLogsAction | DeleteWorkspaceLogsAction - >, -): void { - if (subscribedWorkspaceStatusCallbacks.has(workspace.id)) { - return; - } - const callback = (message: any) => onStatusUpdateReceived(workspace, dispatch, message); - subscribedWorkspaceStatusCallbacks.set(workspace.id, callback); -} - -function subscribeToEnvironmentOutput( - workspaceId: string, - dispatch: ThunkDispatch, -): void { - if (subscribedEnvironmentOutputCallbacks.has(workspaceId)) { - return; - } - const callback: EnvironmentOutputMessageHandler = message => { - if (message.runtimeId?.workspaceId === workspaceId && message.text) { - const workspacesLogs = new Map(); - workspacesLogs.set(workspaceId, message.text.split(new RegExp('\\r\\n|\\r|\\n'))); - dispatch({ - type: 'CHE_UPDATE_WORKSPACES_LOGS', - workspacesLogs, - }); - } - }; - dispatch({ - type: 'CHE_DELETE_WORKSPACE_LOGS', - workspaceId, - }); - subscribedEnvironmentOutputCallbacks.set(workspaceId, callback); -} - -export const actionCreators: ActionCreators = { - requestWorkspaces: - (): AppThunk> => - async (dispatch, getState): Promise => { - await dispatch({ type: 'CHE_REQUEST_WORKSPACES', check: AUTHORIZED }); - const state = getState(); - - try { - const workspaces = await cheWorkspaceClient.restApiClient.getAll(); - - if (selectDevworkspacesEnabled(state)) { - // deprecate Che7 workspaces - const deprecated = new Set(); - state.cheWorkspaces.workspaces.forEach(w => deprecated.add(WorkspaceAdapter.getUID(w))); - workspaces.forEach(w => deprecated.add(WorkspaceAdapter.getUID(w))); - WorkspaceAdapter.setDeprecatedUIDs(Array.from(deprecated)); - } - - dispatch({ - type: 'CHE_RECEIVE_WORKSPACES', - workspaces, - }); - - // Subscribe - workspaces.forEach(workspace => { - subscribeToStatusChange(workspace, dispatch); - - if (WorkspaceStatus.STARTING === workspace.status) { - subscribeToEnvironmentOutput(workspace.id, dispatch); - } - }); - } catch (e) { - const errorMessage = - 'Failed to fetch available workspaces, reason: ' + common.helpers.errors.getMessage(e); - dispatch({ - type: 'CHE_RECEIVE_ERROR', - error: errorMessage, - }); - throw errorMessage; - } - }, - - requestWorkspace: - (workspace: che.Workspace): AppThunk> => - async (dispatch): Promise => { - await dispatch({ type: 'CHE_REQUEST_WORKSPACES', check: AUTHORIZED }); - - try { - const update = await cheWorkspaceClient.restApiClient.getById(workspace.id); - - if (!subscribedWorkspaceStatusCallbacks.has(update.id)) { - subscribeToStatusChange(update, dispatch); - } - if (update.status === WorkspaceStatus.STARTING) { - subscribeToEnvironmentOutput(workspace.id, dispatch); - } - dispatch({ - type: 'CHE_UPDATE_WORKSPACE', - workspace: update, - }); - } catch (e) { - const errorMessage = - `Failed to fetch the workspace ${workspace.devfile.metadata.name}, reason: ` + - common.helpers.errors.getMessage(e); - dispatch({ - type: 'CHE_RECEIVE_ERROR', - error: errorMessage, - }); - throw errorMessage; - } - }, - - startWorkspace: - ( - /* eslint-disable @typescript-eslint/no-unused-vars */ - workspace: che.Workspace, - params?: ResourceQueryParams, - /* eslint-enable @typescript-eslint/no-unused-vars */ - ): AppThunk> => - async (): Promise => { - throw new Error('Running Che7 workspaces is not supported.'); - }, - - stopWorkspace: - (workspace: che.Workspace): AppThunk> => - async (dispatch): Promise => { - try { - await cheWorkspaceClient.restApiClient.stop(workspace.id); - } catch (e) { - const errorMessage = - `Failed to stop the workspace ${workspace.devfile.metadata.name}, reason: ` + - common.helpers.errors.getMessage(e); - dispatch({ - type: 'CHE_RECEIVE_ERROR', - error: errorMessage, - }); - throw errorMessage; - } - }, - - restartWorkspace: - (workspace: che.Workspace): AppThunk> => - async (dispatch): Promise => { - const defer: IDeferred = getDefer(); - const toDispose = new DisposableCollection(); - const onStatusChangeCallback = (status: string) => { - if (status === WorkspaceStatus.STOPPED || status === WorkspaceStatus.ERROR) { - toDispose.dispose(); - dispatch(actionCreators.startWorkspace(workspace)) - .then(() => { - defer.resolve(); - }) - .catch(e => { - defer.reject( - `Failed to restart the workspace ${workspace.devfile.metadata.name}. ${e}`, - ); - }); - } - }; - if ( - workspace.status === WorkspaceStatus.STOPPED || - workspace.status === WorkspaceStatus.ERROR - ) { - onStatusChangeCallback(workspace.status); - } else { - const workspaceId = workspace.id; - onStatusChangeCallbacks.set(workspaceId, onStatusChangeCallback); - toDispose.push({ - dispose: () => onStatusChangeCallbacks.delete(workspaceId), - }); - if ( - workspace.status === WorkspaceStatus.RUNNING || - workspace.status === WorkspaceStatus.STARTING - ) { - try { - await dispatch(actionCreators.stopWorkspace(workspace)); - } catch (e) { - defer.reject( - `Failed to restart the workspace ${workspace.devfile.metadata.name}. ${e}`, - ); - } - } - } - return defer.promise; - }, - - deleteWorkspace: - (workspace: che.Workspace): AppThunk> => - async (dispatch): Promise => { - try { - await cheWorkspaceClient.restApiClient.delete(workspace.id); - dispatch({ - type: 'CHE_DELETE_WORKSPACE_LOGS', - workspaceId: workspace.id, - }); - dispatch({ - type: 'CHE_DELETE_WORKSPACE', - workspaceId: workspace.id, - }); - } catch (e) { - const errorMessage = - `Failed to delete the workspace ${workspace.devfile.metadata.name}, reason: ` + - common.helpers.errors.getMessage(e); - dispatch({ - type: 'CHE_RECEIVE_ERROR', - error: errorMessage, - }); - throw errorMessage; - } - }, - - updateWorkspace: - (workspace: che.Workspace): AppThunk> => - async (dispatch): Promise => { - await dispatch({ type: 'CHE_REQUEST_WORKSPACES', check: AUTHORIZED }); - - try { - const updatedWorkspace = await cheWorkspaceClient.restApiClient.update( - workspace.id, - workspace as api.che.workspace.Workspace, - ); - dispatch({ - type: 'CHE_UPDATE_WORKSPACE', - workspace: updatedWorkspace, - }); - } catch (e) { - const errorMessage = - `Failed to update the workspace ${workspace.devfile.metadata.name}, reason: ` + - common.helpers.errors.getMessage(e); - dispatch({ - type: 'CHE_RECEIVE_ERROR', - error: errorMessage, - }); - throw errorMessage; - } - }, - - createWorkspaceFromDevfile: - ( - devfile: che.WorkspaceDevfile, - namespace: string | undefined, - infrastructureNamespace: string | undefined, - attributes: { [key: string]: string } = {}, - ): AppThunk> => - async (dispatch): Promise => { - await dispatch({ type: 'CHE_REQUEST_WORKSPACES', check: AUTHORIZED }); - try { - const param = { attributes, namespace, infrastructureNamespace }; - const workspace = await cheWorkspaceClient.restApiClient.create( - devfile, - param, - ); - - // Subscribe - subscribeToStatusChange(workspace, dispatch); - - dispatch({ - type: 'CHE_ADD_WORKSPACE', - workspace, - }); - } catch (e) { - const errorMessage = common.helpers.errors.getMessage(e); - dispatch({ - type: 'CHE_RECEIVE_ERROR', - error: errorMessage, - }); - throw errorMessage; - } - }, - - deleteWorkspaceLogs: - (workspaceId: string): AppThunk => - (dispatch): void => { - dispatch({ type: 'CHE_DELETE_WORKSPACE_LOGS', workspaceId }); - }, -}; - -const unloadedState: State = { - workspaces: [], - isLoading: false, - - workspacesLogs: new Map(), -}; - -export const reducer: Reducer = ( - state: State | undefined, - incomingAction: Action, -): State => { - if (state === undefined) { - return unloadedState; - } - - const action = incomingAction as KnownAction; - switch (action.type) { - case 'CHE_REQUEST_WORKSPACES': - return createObject(state, { - isLoading: true, - error: undefined, - }); - case 'CHE_RECEIVE_WORKSPACES': - return createObject(state, { - isLoading: false, - workspaces: action.workspaces, - }); - case 'CHE_RECEIVE_ERROR': - return createObject(state, { - isLoading: false, - error: action.error, - }); - case 'CHE_UPDATE_WORKSPACE': - return createObject(state, { - isLoading: false, - workspaces: state.workspaces.map(workspace => - workspace.id === action.workspace.id ? action.workspace : workspace, - ), - }); - case 'CHE_UPDATE_WORKSPACE_STATUS': - return createObject(state, { - workspaces: state.workspaces.map(workspace => { - if (workspace.id === action.workspaceId) { - workspace.status = action.status; - } - return workspace; - }), - }); - case 'CHE_ADD_WORKSPACE': - return createObject(state, { - workspaces: state.workspaces.concat([action.workspace]), - }); - case 'CHE_DELETE_WORKSPACE': - return createObject(state, { - isLoading: false, - workspaces: state.workspaces.filter(workspace => workspace.id !== action.workspaceId), - }); - case 'CHE_UPDATE_WORKSPACES_LOGS': - return createObject(state, { - workspacesLogs: mergeLogs(state.workspacesLogs, action.workspacesLogs), - }); - case 'CHE_DELETE_WORKSPACE_LOGS': - return createObject(state, { - workspacesLogs: deleteLogs(state.workspacesLogs, action.workspaceId), - }); - default: - return state; - } -}; diff --git a/packages/dashboard-frontend/src/store/Workspaces/cheWorkspaces/selectors.ts b/packages/dashboard-frontend/src/store/Workspaces/cheWorkspaces/selectors.ts deleted file mode 100644 index e075e10d4..000000000 --- a/packages/dashboard-frontend/src/store/Workspaces/cheWorkspaces/selectors.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2018-2021 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 { createSelector } from 'reselect'; -import { AppState } from '../..'; - -const selectState = (state: AppState) => state.cheWorkspaces; -export const selectCheWorkspacesState = selectState; - -export const selectAllCheWorkspaces = createSelector(selectState, state => { - return state.workspaces; -}); - -export const selectCheWorkspacesError = createSelector(selectState, state => state.error); diff --git a/packages/dashboard-frontend/src/store/Workspaces/index.ts b/packages/dashboard-frontend/src/store/Workspaces/index.ts index 9486b889f..df3cf05ba 100644 --- a/packages/dashboard-frontend/src/store/Workspaces/index.ts +++ b/packages/dashboard-frontend/src/store/Workspaces/index.ts @@ -13,11 +13,9 @@ import { Reducer } from 'redux'; import { AppThunk } from '..'; import { createObject } from '../helpers'; -import devfileApi, { isDevfileV2, isDevWorkspace } from '../../services/devfileApi'; -import { isCheWorkspace, Workspace } from '../../services/workspace-adapter'; -import * as CheWorkspacesStore from './cheWorkspaces'; +import devfileApi from '../../services/devfileApi'; +import { Workspace } from '../../services/workspace-adapter'; import * as DevWorkspacesStore from './devWorkspaces'; -import { isDevworkspacesEnabled } from '../../services/helpers/devworkspace'; import common from '@eclipse-che/common'; import OAuthService, { isOAuthResponse } from '../../services/oauth'; @@ -110,9 +108,7 @@ export type ActionCreators = { deleteWorkspace: (workspace: Workspace) => AppThunk>; updateWorkspace: (workspace: Workspace) => AppThunk>; createWorkspaceFromDevfile: ( - devfile: che.WorkspaceDevfile | devfileApi.Devfile, - namespace: string | undefined, - infrastructureNamespace: string | undefined, + devfile: devfileApi.Devfile, attributes: { [key: string]: string }, optionalFilesContent?: { [fileName: string]: string; @@ -135,12 +131,7 @@ export const actionCreators: ActionCreators = { async (dispatch): Promise => { dispatch({ type: 'REQUEST_WORKSPACES' }); try { - const promises: Promise[] = [ - dispatch(DevWorkspacesStore.actionCreators.requestWorkspaces()), - dispatch(CheWorkspacesStore.actionCreators.requestWorkspaces()), - ]; - - await Promise.allSettled(promises); + await dispatch(DevWorkspacesStore.actionCreators.requestWorkspaces()); dispatch({ type: 'RECEIVE_WORKSPACES' }); } catch (e) { @@ -151,19 +142,10 @@ export const actionCreators: ActionCreators = { requestWorkspace: (workspace: Workspace): AppThunk> => - async (dispatch, getState): Promise => { + async (dispatch): Promise => { dispatch({ type: 'REQUEST_WORKSPACES' }); try { - const state = getState(); - const cheDevworkspaceEnabled = isDevworkspacesEnabled(state.workspacesSettings.settings); - - if (cheDevworkspaceEnabled && isDevWorkspace(workspace.ref)) { - await dispatch(DevWorkspacesStore.actionCreators.requestWorkspace(workspace.ref)); - } else { - await dispatch( - CheWorkspacesStore.actionCreators.requestWorkspace(workspace.ref as che.Workspace), - ); - } + await dispatch(DevWorkspacesStore.actionCreators.requestWorkspace(workspace.ref)); dispatch({ type: 'UPDATE_WORKSPACE' }); } catch (e) { dispatch({ type: 'RECEIVE_ERROR' }); @@ -173,26 +155,15 @@ export const actionCreators: ActionCreators = { startWorkspace: (workspace: Workspace, params?: ResourceQueryParams): AppThunk> => - async (dispatch, getState): Promise => { + async (dispatch): Promise => { dispatch({ type: 'REQUEST_WORKSPACES' }); try { - const state = getState(); - const cheDevworkspaceEnabled = isDevworkspacesEnabled(state.workspacesSettings.settings); await OAuthService.refreshTokenIfNeeded(workspace); - if (cheDevworkspaceEnabled && isDevWorkspace(workspace.ref)) { - const debugWorkspace = params && params['debug-workspace-start']; - await dispatch( - DevWorkspacesStore.actionCreators.startWorkspace(workspace.ref, debugWorkspace), - ); - } else { - await dispatch( - CheWorkspacesStore.actionCreators.startWorkspace( - workspace.ref as che.Workspace, - params, - ), - ); - } + const debugWorkspace = params && params['debug-workspace-start']; + await dispatch( + DevWorkspacesStore.actionCreators.startWorkspace(workspace.ref, debugWorkspace), + ); dispatch({ type: 'UPDATE_WORKSPACE' }); } catch (e) { if (common.helpers.errors.includesAxiosResponse(e)) { @@ -221,17 +192,9 @@ export const actionCreators: ActionCreators = { restartWorkspace: (workspace: Workspace): AppThunk> => - async (dispatch, getState): Promise => { + async (dispatch): Promise => { try { - const state = getState(); - const cheDevworkspaceEnabled = isDevworkspacesEnabled(state.workspacesSettings.settings); - if (cheDevworkspaceEnabled && isDevWorkspace(workspace.ref)) { - await dispatch(DevWorkspacesStore.actionCreators.restartWorkspace(workspace.ref)); - } else { - await dispatch( - CheWorkspacesStore.actionCreators.restartWorkspace(workspace.ref as che.Workspace), - ); - } + await dispatch(DevWorkspacesStore.actionCreators.restartWorkspace(workspace.ref)); } catch (e) { dispatch({ type: 'RECEIVE_ERROR' }); throw e; @@ -240,17 +203,9 @@ export const actionCreators: ActionCreators = { stopWorkspace: (workspace: Workspace): AppThunk> => - async (dispatch, getState): Promise => { + async (dispatch): Promise => { try { - const state = getState(); - const cheDevworkspaceEnabled = isDevworkspacesEnabled(state.workspacesSettings.settings); - if (cheDevworkspaceEnabled && isDevWorkspace(workspace.ref)) { - await dispatch(DevWorkspacesStore.actionCreators.stopWorkspace(workspace.ref)); - } else { - await dispatch( - CheWorkspacesStore.actionCreators.stopWorkspace(workspace.ref as che.Workspace), - ); - } + await dispatch(DevWorkspacesStore.actionCreators.stopWorkspace(workspace.ref)); } catch (e) { dispatch({ type: 'RECEIVE_ERROR' }); throw e; @@ -259,17 +214,9 @@ export const actionCreators: ActionCreators = { deleteWorkspace: (workspace: Workspace): AppThunk> => - async (dispatch, getState): Promise => { + async (dispatch): Promise => { try { - const state = getState(); - const cheDevworkspaceEnabled = isDevworkspacesEnabled(state.workspacesSettings.settings); - if (cheDevworkspaceEnabled && isDevWorkspace(workspace.ref)) { - await dispatch(DevWorkspacesStore.actionCreators.terminateWorkspace(workspace.ref)); - } else { - await dispatch( - CheWorkspacesStore.actionCreators.deleteWorkspace(workspace.ref as che.Workspace), - ); - } + await dispatch(DevWorkspacesStore.actionCreators.terminateWorkspace(workspace.ref)); } catch (e) { dispatch({ type: 'RECEIVE_ERROR' }); throw e; @@ -281,17 +228,11 @@ export const actionCreators: ActionCreators = { async (dispatch): Promise => { dispatch({ type: 'REQUEST_WORKSPACES' }); try { - if (isCheWorkspace(workspace.ref)) { - await dispatch( - CheWorkspacesStore.actionCreators.updateWorkspace(workspace.ref as che.Workspace), - ); - } else { - await dispatch( - DevWorkspacesStore.actionCreators.updateWorkspace( - workspace.ref as devfileApi.DevWorkspace, - ), - ); - } + await dispatch( + DevWorkspacesStore.actionCreators.updateWorkspace( + workspace.ref as devfileApi.DevWorkspace, + ), + ); dispatch({ type: 'UPDATE_WORKSPACE' }); } catch (e) { dispatch({ type: 'RECEIVE_ERROR' }); @@ -301,9 +242,7 @@ export const actionCreators: ActionCreators = { createWorkspaceFromDevfile: ( - devfile: che.WorkspaceDevfile | devfileApi.Devfile, - namespace: string | undefined, - infrastructureNamespace: string | undefined, + devfile: devfileApi.Devfile, attributes: { [key: string]: string }, optionalFilesContent?: { [fileName: string]: string; @@ -313,36 +252,20 @@ export const actionCreators: ActionCreators = { dispatch({ type: 'REQUEST_WORKSPACES' }); try { const state = getState(); - - const cheDevworkspaceEnabled = isDevworkspacesEnabled(state.workspacesSettings.settings); - if (cheDevworkspaceEnabled && isDevfileV2(devfile)) { - const pluginRegistryUrl = - state.workspacesSettings.settings['cheWorkspacePluginRegistryUrl']; - const pluginRegistryInternalUrl = - state.workspacesSettings.settings['cheWorkspacePluginRegistryInternalUrl']; - await dispatch( - DevWorkspacesStore.actionCreators.createWorkspaceFromDevfile( - devfile, - optionalFilesContent || {}, - pluginRegistryUrl, - pluginRegistryInternalUrl, - attributes, - ), - ); - dispatch({ type: 'ADD_WORKSPACE' }); - } else { - await dispatch( - CheWorkspacesStore.actionCreators.createWorkspaceFromDevfile( - devfile as che.WorkspaceDevfile, - namespace, - infrastructureNamespace, - attributes, - ), - ); - dispatch({ - type: 'ADD_WORKSPACE', - }); - } + const pluginRegistryUrl = + state.workspacesSettings.settings['cheWorkspacePluginRegistryUrl']; + const pluginRegistryInternalUrl = + state.workspacesSettings.settings['cheWorkspacePluginRegistryInternalUrl']; + await dispatch( + DevWorkspacesStore.actionCreators.createWorkspaceFromDevfile( + devfile, + optionalFilesContent || {}, + pluginRegistryUrl, + pluginRegistryInternalUrl, + attributes, + ), + ); + dispatch({ type: 'ADD_WORKSPACE' }); } catch (e) { dispatch({ type: 'RECEIVE_ERROR' }); throw e; @@ -378,14 +301,8 @@ export const actionCreators: ActionCreators = { deleteWorkspaceLogs: (workspace: Workspace): AppThunk => - (dispatch, getState): void => { - const state = getState(); - const cheDevworkspaceEnabled = isDevworkspacesEnabled(state.workspacesSettings.settings); - if (cheDevworkspaceEnabled) { - dispatch(DevWorkspacesStore.actionCreators.deleteWorkspaceLogs(workspace.uid)); - } else { - dispatch(CheWorkspacesStore.actionCreators.deleteWorkspaceLogs(workspace.uid)); - } + (dispatch): void => { + dispatch(DevWorkspacesStore.actionCreators.deleteWorkspaceLogs(workspace.uid)); }, }; diff --git a/packages/dashboard-frontend/src/store/Workspaces/selectors.ts b/packages/dashboard-frontend/src/store/Workspaces/selectors.ts index 0f505dcc3..d9bf58dba 100644 --- a/packages/dashboard-frontend/src/store/Workspaces/selectors.ts +++ b/packages/dashboard-frontend/src/store/Workspaces/selectors.ts @@ -12,45 +12,23 @@ import { createSelector } from 'reselect'; import { AppState } from '..'; -import { constructWorkspace, Workspace, WorkspaceAdapter } from '../../services/workspace-adapter'; -import { selectCheWorkspacesError } from './cheWorkspaces/selectors'; -import { selectDevWorkspacesError, selectRunningDevWorkspaces } from './devWorkspaces/selectors'; +import { constructWorkspace, Workspace } from '../../services/workspace-adapter'; +import { selectRunningDevWorkspaces, selectDevWorkspacesError } from './devWorkspaces/selectors'; const selectState = (state: AppState) => state.workspaces; -const selectCheWorkspacesState = (state: AppState) => state.cheWorkspaces; const selectDevWorkspacesState = (state: AppState) => state.devWorkspaces; export const selectIsLoading = createSelector(selectDevWorkspacesState, devWorkspacesState => { return devWorkspacesState.isLoading; }); -export const selectLogs = createSelector( - selectCheWorkspacesState, - selectDevWorkspacesState, - (cheWorkspacesState, devWorkspacesState) => { - return new Map([...cheWorkspacesState.workspacesLogs, ...devWorkspacesState.workspacesLogs]); - }, -); - -/** - * Returns array of UIDs of deprecated workspaces - */ -export const selectDeprecatedWorkspacesUIDs = createSelector( - selectCheWorkspacesState, - cheWorkspacesState => { - return cheWorkspacesState.workspaces.map(workspace => WorkspaceAdapter.getUID(workspace)); - }, -); +export const selectLogs = createSelector(selectDevWorkspacesState, devWorkspacesState => { + return new Map([...devWorkspacesState.workspacesLogs]); +}); -export const selectAllWorkspaces = createSelector( - selectCheWorkspacesState, - selectDevWorkspacesState, - (cheWorkspacesState, devWorkspacesState) => { - return [...cheWorkspacesState.workspaces, ...devWorkspacesState.workspaces].map(workspace => - constructWorkspace(workspace), - ); - }, -); +export const selectAllWorkspaces = createSelector(selectDevWorkspacesState, devWorkspacesState => { + return devWorkspacesState.workspaces.map(workspace => constructWorkspace(workspace)); +}); export const selectWorkspaceByQualifiedName = createSelector( selectState, @@ -116,23 +94,12 @@ const selectRecentNumber = createSelector(selectState, state => state.recentNumb export const selectRecentWorkspaces = createSelector( selectRecentNumber, selectAllWorkspaces, - selectDeprecatedWorkspacesUIDs, - (recentNumber, allWorkspaces, deprecatedWorkspacesUIDs) => - allWorkspaces - .filter(workspace => deprecatedWorkspacesUIDs.indexOf(workspace.uid) === -1) - .sort(sortByUpdatedTimeFn) - .slice(0, recentNumber), + (recentNumber, allWorkspaces) => allWorkspaces.sort(sortByUpdatedTimeFn).slice(0, recentNumber), ); export const selectWorkspacesError = createSelector( - selectCheWorkspacesError, selectDevWorkspacesError, - (cheWorkspacesError, devWorkspacesError) => { - if (devWorkspacesError) { - return devWorkspacesError; - } - return cheWorkspacesError; - }, + devWorkspacesError => devWorkspacesError, ); export const selectRunningWorkspaces = createSelector( diff --git a/packages/dashboard-frontend/src/store/__mocks__/cheWorkspaceBuilder.ts b/packages/dashboard-frontend/src/store/__mocks__/cheWorkspaceBuilder.ts deleted file mode 100644 index 7e30a9d53..000000000 --- a/packages/dashboard-frontend/src/store/__mocks__/cheWorkspaceBuilder.ts +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2018-2021 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 getRandomString from '../../services/helpers/random'; -import { WorkspaceStatus } from '../../services/helpers/types'; -import { cloneDeep } from 'lodash'; - -export const CHE_DEVFILE_STUB: che.WorkspaceDevfile = { - apiVersion: '1.0.0', - metadata: { - name: 'wksp-' + getRandomString(4), - }, -} as che.WorkspaceDevfile; - -export const CHE_RUNTIME_STUB: che.WorkspaceRuntime = { - machines: { - 'theia-ide': { - attributes: { - source: 'tool', - }, - servers: { - theia: { - status: WorkspaceStatus.RUNNING, - attributes: { - type: 'ide', - }, - url: 'url/ide/' + getRandomString(4), - }, - }, - status: WorkspaceStatus.RUNNING, - }, - }, - status: WorkspaceStatus.RUNNING, - activeEnv: 'default', -}; - -export class CheWorkspaceBuilder { - private workspace: che.Workspace = { - id: getRandomString(4), - attributes: { - infrastructureNamespace: 'che', - } as che.WorkspaceAttributes, - status: WorkspaceStatus.STOPPED, - namespace: 'admin', - devfile: cloneDeep(CHE_DEVFILE_STUB), - }; - - withId(id: string): CheWorkspaceBuilder { - this.workspace.id = id; - return this; - } - - withName(name: string): CheWorkspaceBuilder { - this.workspace.devfile.metadata.name = name; - return this; - } - - withAttributes(attributes: che.WorkspaceAttributes): CheWorkspaceBuilder { - this.workspace.attributes = Object.assign({}, this.workspace.attributes, attributes); - return this; - } - - withDevfile(devfile: che.WorkspaceDevfile): CheWorkspaceBuilder { - this.workspace.devfile = cloneDeep(devfile); - return this; - } - - withProjects(projects: any[]): CheWorkspaceBuilder { - this.workspace.devfile.projects = cloneDeep(projects); - return this; - } - - withStatus(status: keyof typeof WorkspaceStatus): CheWorkspaceBuilder { - this.workspace.status = status; - return this; - } - - withNamespace(namespace: string): CheWorkspaceBuilder { - this.workspace.namespace = namespace; - if (!this.workspace.attributes) { - this.workspace.attributes = {} as che.WorkspaceAttributes; - } - this.workspace.attributes.infrastructureNamespace = namespace; - return this; - } - - withRuntime(runtime: che.WorkspaceRuntime): CheWorkspaceBuilder { - this.workspace.runtime = cloneDeep(runtime); - this.workspace.status = WorkspaceStatus.RUNNING; - return this; - } - - build(): che.Workspace { - return this.workspace; - } -} diff --git a/packages/dashboard-frontend/src/store/__mocks__/storeBuilder.ts b/packages/dashboard-frontend/src/store/__mocks__/storeBuilder.ts index fe9cc62f1..776eabf51 100644 --- a/packages/dashboard-frontend/src/store/__mocks__/storeBuilder.ts +++ b/packages/dashboard-frontend/src/store/__mocks__/storeBuilder.ts @@ -84,11 +84,6 @@ export class FakeStoreBuilder { workspaceUID: '', recentNumber: 5, } as WorkspacesState, - cheWorkspaces: { - isLoading: false, - workspaces: [], - workspacesLogs: new Map(), - }, devWorkspaces: { isLoading: false, workspaces: [], @@ -118,22 +113,13 @@ export class FakeStoreBuilder { isLoading: false, namespaces: [], } as InfrastructureNamespaceState, - userPreferences: { - isLoading: false, - preferences: {}, - }, dwPlugins: { isLoading: false, editors: {}, plugins: {}, defaultPlugins: {}, }, - dwDockerConfig: { - isLoading: false, - registries: [], - error: undefined, - }, - cheDockerConfig: { + dockerConfig: { isLoading: false, registries: [], error: undefined, @@ -153,34 +139,14 @@ export class FakeStoreBuilder { return this; } - public withDwDockerConfig( + public withDockerConfig( registries: RegistryEntry[], isLoading = false, error?: string, ): FakeStoreBuilder { - this.state.dwDockerConfig.registries = registries; - this.state.dwDockerConfig.isLoading = isLoading; - this.state.dwDockerConfig.error = error; - return this; - } - - public withCheDockerConfig( - registries: RegistryEntry[], - isLoading = false, - error?: string, - ): FakeStoreBuilder { - this.state.cheDockerConfig.registries = registries; - this.state.cheDockerConfig.isLoading = isLoading; - this.state.cheDockerConfig.error = error; - return this; - } - - public withUserPreferences( - preferences: che.UserPreferences, - isLoading = false, - ): FakeStoreBuilder { - this.state.userPreferences.preferences = preferences; - this.state.userPreferences.isLoading = isLoading; + this.state.dockerConfig.registries = registries; + this.state.dockerConfig.isLoading = isLoading; + this.state.dockerConfig.error = error; return this; } @@ -297,25 +263,6 @@ export class FakeStoreBuilder { return this; } - public withCheWorkspaces( - options: { - workspaces?: che.Workspace[]; - workspacesLogs?: WorkspacesLogs; - }, - isLoading = false, - error?: string, - ): FakeStoreBuilder { - if (options.workspaces) { - this.state.cheWorkspaces.workspaces = Object.assign([], options.workspaces); - } - if (options.workspacesLogs) { - this.state.cheWorkspaces.workspacesLogs = new Map(options.workspacesLogs); - } - this.state.cheWorkspaces.isLoading = isLoading; - this.state.cheWorkspaces.error = error; - return this; - } - public withDevWorkspaces( options: { workspaces?: devfileApi.DevWorkspace[]; diff --git a/packages/dashboard-frontend/src/store/__mocks__/workspace.ts b/packages/dashboard-frontend/src/store/__mocks__/workspace.ts index 56aac8b1d..63e461418 100644 --- a/packages/dashboard-frontend/src/store/__mocks__/workspace.ts +++ b/packages/dashboard-frontend/src/store/__mocks__/workspace.ts @@ -10,39 +10,7 @@ * Red Hat, Inc. - initial API and implementation */ -import { WorkspacesLogs, WorkspaceStatus } from '../../services/helpers/types'; - -/** - * @deprecated use CheWorkspaceBuilder instead - */ -export const createFakeCheWorkspace = ( - workspaceId: string, - workspaceName: string, - namespace = 'admin', - status = WorkspaceStatus.STOPPED, - runtime?: che.WorkspaceRuntime, -): che.Workspace => { - if (runtime && status === WorkspaceStatus.STOPPED) { - throw new Error( - 'Failed creating a stub workspace. Workspace runtime object is only combined with "RUNNING" status', - ); - } - return { - id: workspaceId, - attributes: { - infrastructureNamespace: 'che', - }, - status, - devfile: { - apiVersion: '1.0.0', - metadata: { - name: workspaceName, - }, - }, - namespace, - runtime: runtime, - } as che.Workspace; -}; +import { WorkspacesLogs } from '../../services/helpers/types'; export const createFakeWorkspaceLogs = ( workspaceId: string, diff --git a/packages/dashboard-frontend/src/store/index.ts b/packages/dashboard-frontend/src/store/index.ts index 817e7188b..49f7ca82f 100644 --- a/packages/dashboard-frontend/src/store/index.ts +++ b/packages/dashboard-frontend/src/store/index.ts @@ -17,18 +17,15 @@ import * as BrandingStore from './Branding'; import * as ClusterConfig from './ClusterConfig'; import * as ClusterInfo from './ClusterInfo'; import * as DevfileRegistriesStore from './DevfileRegistries'; -import * as CheDockerConfigStore from './DockerConfig/che'; -import * as DwDockerConfigStore from './DockerConfig/dw'; +import * as DockerConfigStore from './DockerConfig'; import * as FactoryResolverStore from './FactoryResolver'; import * as InfrastructureNamespacesStore from './InfrastructureNamespaces'; import * as PluginsStore from './Plugins/chePlugins'; import * as SanityCheckStore from './SanityCheck'; import * as DwPluginsStore from './Plugins/devWorkspacePlugins'; import * as DwServerConfigStore from './ServerConfig'; -import * as UserPreferences from './UserPreferences'; import * as UserProfileStore from './UserProfile'; import * as WorkspacesStore from './Workspaces'; -import * as CheWorkspacesStore from './Workspaces/cheWorkspaces'; import * as DevWorkspacesStore from './Workspaces/devWorkspaces'; import * as WorkspacesSettingsStore from './Workspaces/Settings'; @@ -36,20 +33,17 @@ import * as WorkspacesSettingsStore from './Workspaces/Settings'; export interface AppState { bannerAlert: BannerAlertStore.State; branding: BrandingStore.State; - cheDockerConfig: CheDockerConfigStore.State; - cheWorkspaces: CheWorkspacesStore.State; clusterConfig: ClusterConfig.State; clusterInfo: ClusterInfo.State; devWorkspaces: DevWorkspacesStore.State; devfileRegistries: DevfileRegistriesStore.State; - dwDockerConfig: DwDockerConfigStore.State; + dockerConfig: DockerConfigStore.State; dwPlugins: DwPluginsStore.State; dwServerConfig: DwServerConfigStore.State; factoryResolver: FactoryResolverStore.State; infrastructureNamespaces: InfrastructureNamespacesStore.State; plugins: PluginsStore.State; sanityCheck: SanityCheckStore.State; - userPreferences: UserPreferences.State; userProfile: UserProfileStore.State; workspaces: WorkspacesStore.State; workspacesSettings: WorkspacesSettingsStore.State; @@ -58,20 +52,17 @@ export interface AppState { export const reducers = { bannerAlert: BannerAlertStore.reducer, branding: BrandingStore.reducer, - cheDockerConfig: CheDockerConfigStore.reducer, - cheWorkspaces: CheWorkspacesStore.reducer, clusterConfig: ClusterConfig.reducer, clusterInfo: ClusterInfo.reducer, devWorkspaces: DevWorkspacesStore.reducer, devfileRegistries: DevfileRegistriesStore.reducer, - dwDockerConfig: DwDockerConfigStore.reducer, + dockerConfig: DockerConfigStore.reducer, dwPlugins: DwPluginsStore.reducer, dwServerConfig: DwServerConfigStore.reducer, factoryResolver: FactoryResolverStore.reducer, infrastructureNamespaces: InfrastructureNamespacesStore.reducer, plugins: PluginsStore.reducer, sanityCheck: SanityCheckStore.reducer, - userPreferences: UserPreferences.reducer, userProfile: UserProfileStore.reducer, workspaces: WorkspacesStore.reducer, workspacesSettings: WorkspacesSettingsStore.reducer, diff --git a/packages/dashboard-frontend/src/typings/che.d.ts b/packages/dashboard-frontend/src/typings/che.d.ts index ac8015c25..9303da10d 100755 --- a/packages/dashboard-frontend/src/typings/che.d.ts +++ b/packages/dashboard-frontend/src/typings/che.d.ts @@ -11,23 +11,6 @@ */ declare namespace che { - export interface Workspace { - id: string; - projects?: any; - links?: { - ide?: string; - [rel: string]: string | undefined; - }; - temporary?: boolean; - status: string; - namespace?: string; - attributes?: WorkspaceAttributes; - devfile: WorkspaceDevfile; - runtime?: WorkspaceRuntime; - isLocked?: boolean; - usedResources?: string; - } - export type WorkspaceStorageType = | 'async' | 'ephemeral' @@ -97,46 +80,6 @@ declare namespace che { }; } - export interface WorkspaceRuntime { - activeEnv: string; - status: string; - machines: { - [machineName: string]: WorkspaceRuntimeMachine; - }; - machineToken?: string; - } - - export interface WorkspaceWarning { - code?: number; - message: string; - } - - export interface WorkspaceRuntimeMachine { - attributes: { [propName: string]: string }; - servers: { [serverName: string]: WorkspaceRuntimeMachineServer }; - status: string; - } - - export interface WorkspaceRuntimeMachineServer { - status: string; - url: string; - attributes: { [propName: string]: string }; - } - - export interface ProfileAttributes { - firstName?: string; - lastName?: string; - - [propName: string]: string | number | undefined; - } - - export interface Profile { - attributes?: ProfileAttributes; - email: string; - links?: Array; - userId: string; - } - export interface User { links: any[]; attributes?: { @@ -153,10 +96,6 @@ declare namespace che { sub?: string; } - export interface UserPreferences { - [key: string]: string; - } - export interface DevfileMetaData { displayName: string; description?: string; @@ -168,7 +107,7 @@ declare namespace che { devWorkspaces?: { [editorId: string]: string; }; - self: string; + self?: string; [key: string]: any; }; tags: Array; diff --git a/yarn.lock b/yarn.lock index 3ee466e91..5395a591a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -381,16 +381,15 @@ jsonc-parser "^3.0.0" reflect-metadata "^0.1.13" -"@eclipse-che/workspace-client@0.0.1-1663851810": - version "0.0.1-1663851810" - resolved "https://registry.yarnpkg.com/@eclipse-che/workspace-client/-/workspace-client-0.0.1-1663851810.tgz#575c6e9c359a536ec3b1f359d7142bcd6b59d735" - integrity sha512-oV+zTmsrMcV+SvnZBuHWbrwYimqUqWil2BHGjQYpK1TroEMHiOgfs0Xjh7FxdrgcYUc05Rnb7yvwe4QSjw7iTQ== +"@eclipse-che/workspace-client@0.0.1-1671793076": + version "0.0.1-1671793076" + resolved "https://registry.yarnpkg.com/@eclipse-che/workspace-client/-/workspace-client-0.0.1-1671793076.tgz#87bd373048762b12ce2353306cd1e4b357857d00" + integrity sha512-zmX5m0RcP15Z+kArofjAUKODbWWHK7M7CDMZ3Vadj2zD8P0K26doT3IJZRiJGsMxOB8Y6onGypnCGJrtJEiJTA== dependencies: "@eclipse-che/api" "^7.0.0-beta-4.0" - axios "^0.21.1" + axios "^0.21.4" qs "^6.9.4" tunnel "0.0.6" - websocket "1.0.23" "@eslint/eslintrc@^0.4.3": version "0.4.3" @@ -8854,11 +8853,6 @@ mute-stream@0.0.8, mute-stream@~0.0.4: resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz" integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== -nan@^2.3.3: - version "2.15.0" - resolved "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz" - integrity sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ== - nanoid@^3.3.4: version "3.3.4" resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz" @@ -12138,7 +12132,7 @@ type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" -typedarray-to-buffer@^3.1.2, typedarray-to-buffer@^3.1.5: +typedarray-to-buffer@^3.1.5: version "3.1.5" resolved "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz" integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== @@ -12674,16 +12668,6 @@ websocket-extensions@>=0.1.1: resolved "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz" integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== -websocket@1.0.23: - version "1.0.23" - resolved "https://registry.npmjs.org/websocket/-/websocket-1.0.23.tgz" - integrity sha1-IN6OxKcSawlGVXjNXbspqcKWqsY= - dependencies: - debug "^2.2.0" - nan "^2.3.3" - typedarray-to-buffer "^3.1.2" - yaeti "^0.0.4" - whatwg-encoding@^1.0.5: version "1.0.5" resolved "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz" @@ -12900,11 +12884,6 @@ y18n@^5.0.5: resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== -yaeti@^0.0.4: - version "0.0.4" - resolved "https://registry.npmjs.org/yaeti/-/yaeti-0.0.4.tgz" - integrity sha1-if5znEWsRJECiXMZMmKoN2k6ZrY= - yallist@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz"