diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 50109dda..7218bf97 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -10,4 +10,5 @@ /workspaces/marketplace @christoph-jerolimov @debsmita1 @divyanshiGupta /workspaces/openshift-image-registry @christoph-jerolimov @debsmita1 @divyanshiGupta /workspaces/theme @christoph-jerolimov @ciiay @debsmita1 -/workspaces/lightspeed @karthikjeeyar @yangcao77 @rohitkrai03 \ No newline at end of file +/workspaces/lightspeed @karthikjeeyar @yangcao77 @rohitkrai03 +/workspaces/orchestrator @batzionb @mareklibra @gciavarrini \ No newline at end of file diff --git a/.github/workflows/automate_changeset_feedback.yml b/.github/workflows/automate_changeset_feedback.yml new file mode 100644 index 00000000..703b6f7c --- /dev/null +++ b/.github/workflows/automate_changeset_feedback.yml @@ -0,0 +1,48 @@ +name: Automate changeset feedback +on: + pull_request_target: + branches: ['main'] + +permissions: + pull-requests: write + actions: none + checks: none + contents: none + deployments: none + issues: none + packages: none + pages: none + repository-projects: none + security-events: none + statuses: none + +jobs: + changeset-feedback: + name: Generate Changeset Feedback + # prevent running towards forks and version packages + if: github.repository == 'redhat-developer/rhdh-plugins' && github.event.pull_request.user.login != 'rhdh-bot' + runs-on: ubuntu-latest + steps: + - name: Harden Runner + uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + with: + egress-policy: audit + + - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + with: + # Fetch the commit that's merged into the base rather than the target ref + # This will let us diff only the contents of the PR, without fetching more history + ref: 'refs/pull/${{ github.event.pull_request.number }}/merge' + - name: fetch base + run: git fetch --depth 1 origin ${{ github.base_ref }} + + - uses: backstage/actions/changeset-feedback@v0.6.10 + name: Generate feedback + with: + diff-ref: 'origin/main' + marker: + issue-number: ${{ github.event.pull_request.number }} + app-id: ${{ secrets.RHDH_GH_APP_ID }} + private-key: ${{ secrets.RHDH_GH_APP_PRIVATE_KEY }} + installation-id: ${{ secrets.RHDH_GH_APP_INSTALLATION_ID }} + multiple-workspaces: true \ No newline at end of file diff --git a/workspaces/bulk-import/plugins/bulk-import-backend/.lintstagedrc.json b/workspaces/bulk-import/plugins/bulk-import-backend/.lintstagedrc.json deleted file mode 100644 index 14b2263d..00000000 --- a/workspaces/bulk-import/plugins/bulk-import-backend/.lintstagedrc.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "*": "prettier --ignore-unknown --write", - "*.{js,jsx,ts,tsx,mjs,cjs}": "backstage-cli package lint --fix" -} diff --git a/workspaces/bulk-import/plugins/bulk-import-backend/.versionhistory.md b/workspaces/bulk-import/plugins/bulk-import-backend/.versionhistory.md deleted file mode 100644 index 2e864bc0..00000000 --- a/workspaces/bulk-import/plugins/bulk-import-backend/.versionhistory.md +++ /dev/null @@ -1 +0,0 @@ -- Bumped to 1.6.0 in main branch for next release 1.3.0 diff --git a/workspaces/bulk-import/plugins/bulk-import-backend/tsconfig.json b/workspaces/bulk-import/plugins/bulk-import-backend/tsconfig.json deleted file mode 100644 index 7f3f9317..00000000 --- a/workspaces/bulk-import/plugins/bulk-import-backend/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "@backstage/cli/config/tsconfig.json", - "include": ["src", "dev", "migrations"], - "exclude": ["node_modules"], - "compilerOptions": { - "outDir": "../../dist-types/plugins/bulk-import-backend", - "rootDir": "." - } -} diff --git a/workspaces/bulk-import/plugins/bulk-import-backend/turbo.json b/workspaces/bulk-import/plugins/bulk-import-backend/turbo.json deleted file mode 100644 index 34c7e369..00000000 --- a/workspaces/bulk-import/plugins/bulk-import-backend/turbo.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "extends": ["//"], - "tasks": { - "start": { - "dependsOn": ["openapi"] - }, - "tsc": { - "outputs": ["../../dist-types/plugins/bulk-import-backend/**"], - "dependsOn": ["^tsc", "openapi"] - }, - "openapi": { - "outputs": [ - "src/generated/openapi.d.ts", - "src/generated/openapidocument.ts", - "api-docs/**" - ] - }, - "test": { - "dependsOn": ["openapi"] - } - } -} diff --git a/workspaces/bulk-import/plugins/bulk-import-common/.lintstagedrc.json b/workspaces/bulk-import/plugins/bulk-import-common/.lintstagedrc.json deleted file mode 100644 index 14b2263d..00000000 --- a/workspaces/bulk-import/plugins/bulk-import-common/.lintstagedrc.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "*": "prettier --ignore-unknown --write", - "*.{js,jsx,ts,tsx,mjs,cjs}": "backstage-cli package lint --fix" -} diff --git a/workspaces/bulk-import/plugins/bulk-import-common/.versionhistory.md b/workspaces/bulk-import/plugins/bulk-import-common/.versionhistory.md deleted file mode 100644 index b17e6983..00000000 --- a/workspaces/bulk-import/plugins/bulk-import-common/.versionhistory.md +++ /dev/null @@ -1 +0,0 @@ -- Bumped to 1.1.0 in main branch for next release 1.3.0 diff --git a/workspaces/bulk-import/plugins/bulk-import-common/tsconfig.json b/workspaces/bulk-import/plugins/bulk-import-common/tsconfig.json deleted file mode 100644 index 8ca0750f..00000000 --- a/workspaces/bulk-import/plugins/bulk-import-common/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "@backstage/cli/config/tsconfig.json", - "include": ["src"], - "exclude": ["node_modules"], - "compilerOptions": { - "outDir": "../../dist-types/plugins/bulk-import-common", - "rootDir": "." - } -} diff --git a/workspaces/bulk-import/plugins/bulk-import-common/turbo.json b/workspaces/bulk-import/plugins/bulk-import-common/turbo.json deleted file mode 100644 index 4cb9b5aa..00000000 --- a/workspaces/bulk-import/plugins/bulk-import-common/turbo.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": ["//"], - "tasks": { - "tsc": { - "outputs": ["../../dist-types/plugins/bulk-import-common/**"] - } - } -} diff --git a/workspaces/bulk-import/plugins/bulk-import/.lintstagedrc.json b/workspaces/bulk-import/plugins/bulk-import/.lintstagedrc.json deleted file mode 100644 index 14b2263d..00000000 --- a/workspaces/bulk-import/plugins/bulk-import/.lintstagedrc.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "*": "prettier --ignore-unknown --write", - "*.{js,jsx,ts,tsx,mjs,cjs}": "backstage-cli package lint --fix" -} diff --git a/workspaces/bulk-import/plugins/bulk-import/.versionhistory.md b/workspaces/bulk-import/plugins/bulk-import/.versionhistory.md deleted file mode 100644 index 40f0aa1c..00000000 --- a/workspaces/bulk-import/plugins/bulk-import/.versionhistory.md +++ /dev/null @@ -1 +0,0 @@ -- Bumped to 1.5.0 in main branch for next release 1.3.0 diff --git a/workspaces/bulk-import/plugins/bulk-import/tsconfig.json b/workspaces/bulk-import/plugins/bulk-import/tsconfig.json deleted file mode 100644 index 72923847..00000000 --- a/workspaces/bulk-import/plugins/bulk-import/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "@backstage/cli/config/tsconfig.json", - "include": ["src", "dev", "migrations"], - "exclude": ["node_modules"], - "compilerOptions": { - "outDir": "../../dist-types/plugins/bulk-import", - "rootDir": "." - } -} diff --git a/workspaces/bulk-import/plugins/bulk-import/turbo.json b/workspaces/bulk-import/plugins/bulk-import/turbo.json deleted file mode 100644 index 62ec9034..00000000 --- a/workspaces/bulk-import/plugins/bulk-import/turbo.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": ["//"], - "tasks": { - "tsc": { - "outputs": ["../../dist-types/plugins/bulk-import/**"] - } - } -} diff --git a/workspaces/homepage/plugins/dynamic-home-page/CHANGELOG.md b/workspaces/homepage/plugins/dynamic-home-page/CHANGELOG.md index bc960d6b..fbc1a98d 100644 --- a/workspaces/homepage/plugins/dynamic-home-page/CHANGELOG.md +++ b/workspaces/homepage/plugins/dynamic-home-page/CHANGELOG.md @@ -1,5 +1,11 @@ # @red-hat-developer-hub/backstage-plugin-dynamic-home-page +## 1.0.1 + +### Patch Changes + +- 849e0c7: Update dependencies (@scalprum/react-core from 0.8 to 0.9 and tss-react) + ## 1.0.0 ### Major Changes diff --git a/workspaces/homepage/plugins/dynamic-home-page/package.json b/workspaces/homepage/plugins/dynamic-home-page/package.json index 6ae74324..775c2736 100644 --- a/workspaces/homepage/plugins/dynamic-home-page/package.json +++ b/workspaces/homepage/plugins/dynamic-home-page/package.json @@ -1,6 +1,6 @@ { "name": "@red-hat-developer-hub/backstage-plugin-dynamic-home-page", - "version": "1.0.0", + "version": "1.0.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -41,10 +41,10 @@ "@backstage/theme": "0.6.0", "@mui/material": "5.16.7", "@mui/styles": "5.16.7", - "@scalprum/react-core": "0.8.0", + "@scalprum/react-core": "0.9.3", "react-grid-layout": "1.4.4", "react-use": "17.5.1", - "tss-react": "4.9.12" + "tss-react": "4.9.13" }, "peerDependencies": { "react": "16.13.1 || ^17.0.0 || ^18.2.0", diff --git a/workspaces/homepage/yarn.lock b/workspaces/homepage/yarn.lock index 999fbe65..9dba4cb4 100644 --- a/workspaces/homepage/yarn.lock +++ b/workspaces/homepage/yarn.lock @@ -10079,7 +10079,7 @@ __metadata: "@mui/styles": 5.16.7 "@openshift/dynamic-plugin-sdk": 5.0.1 "@redhat-developer/red-hat-developer-hub-theme": 0.4.0 - "@scalprum/react-core": 0.8.0 + "@scalprum/react-core": 0.9.3 "@testing-library/jest-dom": 6.6.3 "@testing-library/react": 14.3.1 "@testing-library/user-event": 14.5.2 @@ -10088,7 +10088,7 @@ __metadata: react: ^16.13.1 || ^17.0.0 || ^18.0.0 react-grid-layout: 1.4.4 react-use: 17.5.1 - tss-react: 4.9.12 + tss-react: 4.9.13 peerDependencies: react: 16.13.1 || ^17.0.0 || ^18.2.0 react-router-dom: 6.26.2 @@ -10483,27 +10483,27 @@ __metadata: languageName: node linkType: hard -"@scalprum/core@npm:^0.7.0": - version: 0.7.0 - resolution: "@scalprum/core@npm:0.7.0" +"@scalprum/core@npm:^0.8.1": + version: 0.8.1 + resolution: "@scalprum/core@npm:0.8.1" dependencies: "@openshift/dynamic-plugin-sdk": ^5.0.1 tslib: ^2.6.2 - checksum: 0698e2520a9a9a7c220b5067792e81f267659ae0e9c0e117d9dc5aa24f28be2b8c72d5c79aedf3a68fc803e47c1f473ff25945299c03b978ea5360d766975fc2 + checksum: 581631848bda2081dfe797c4c4326b442ce086d69117cc1eb74c18d345124825d87f570d09e8edaaa132d32a7720db0e728971834f1509aca9349aff21246a52 languageName: node linkType: hard -"@scalprum/react-core@npm:0.8.0": - version: 0.8.0 - resolution: "@scalprum/react-core@npm:0.8.0" +"@scalprum/react-core@npm:0.9.3": + version: 0.9.3 + resolution: "@scalprum/react-core@npm:0.9.3" dependencies: "@openshift/dynamic-plugin-sdk": ^5.0.1 - "@scalprum/core": ^0.7.0 + "@scalprum/core": ^0.8.1 lodash: ^4.17.0 peerDependencies: react: ">=16.8.0 || >=17.0.0 || ^18.0.0" react-dom: ">=16.8.0 || >=17.0.0 || ^18.0.0" - checksum: 1eff07a1efa4cded62bc3602ef5745e2ff39f8291af1af4486bc6fa703b59f5e94fc6c76929f5653c15d5a5e70dd85d41c145982f605042d4ec2eb983b531031 + checksum: 19c29a54e25c8025b668a96291741ce4b68dc0c87684cc39c260fc29aa2e0fc0d3e01266e0b5f64a290607e3df8d766539b619d23b756e2d09534b37034c313c languageName: node linkType: hard @@ -31938,9 +31938,9 @@ __metadata: languageName: node linkType: hard -"tss-react@npm:4.9.12": - version: 4.9.12 - resolution: "tss-react@npm:4.9.12" +"tss-react@npm:4.9.13": + version: 4.9.13 + resolution: "tss-react@npm:4.9.13" dependencies: "@emotion/cache": "*" "@emotion/serialize": "*" @@ -31948,14 +31948,14 @@ __metadata: peerDependencies: "@emotion/react": ^11.4.1 "@emotion/server": ^11.4.0 - "@mui/material": ^5.0.0 + "@mui/material": ^5.0.0 || ^6.0.0 react: ^16.8.0 || ^17.0.2 || ^18.0.0 peerDependenciesMeta: "@emotion/server": optional: true "@mui/material": optional: true - checksum: b1bec7c6d80b93d325ceca040ff5629b8a898b9f86a6d3260f2614943b64873afacd1f56d65a7850090a01869ea4fdac045da77ec96b80fbf157d475bcbd7187 + checksum: 9327cef392007237020df5d388b4aeabbf7cc06f6d5ac32e2781367244c2de34688922a345878408f45a38890324d67d9a0f7b48cf6b1c968d66d52b3e14e28f languageName: node linkType: hard diff --git a/workspaces/lightspeed/plugins/lightspeed-backend/.lintstagedrc.json b/workspaces/lightspeed/plugins/lightspeed-backend/.lintstagedrc.json deleted file mode 100644 index 14b2263d..00000000 --- a/workspaces/lightspeed/plugins/lightspeed-backend/.lintstagedrc.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "*": "prettier --ignore-unknown --write", - "*.{js,jsx,ts,tsx,mjs,cjs}": "backstage-cli package lint --fix" -} diff --git a/workspaces/lightspeed/plugins/lightspeed-backend/tsconfig.json b/workspaces/lightspeed/plugins/lightspeed-backend/tsconfig.json deleted file mode 100644 index 5b53ff6f..00000000 --- a/workspaces/lightspeed/plugins/lightspeed-backend/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "@backstage/cli/config/tsconfig.json", - "include": ["src", "dev", "migrations"], - "exclude": ["node_modules"], - "compilerOptions": { - "outDir": "../../dist-types/plugins/lightspeed-backend", - "rootDir": "." - } -} diff --git a/workspaces/lightspeed/plugins/lightspeed-backend/turbo.json b/workspaces/lightspeed/plugins/lightspeed-backend/turbo.json deleted file mode 100644 index bcc47a18..00000000 --- a/workspaces/lightspeed/plugins/lightspeed-backend/turbo.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": ["//"], - "tasks": { - "tsc": { - "outputs": ["../../dist-types/plugins/lightspeed/**"] - } - } -} diff --git a/workspaces/lightspeed/plugins/lightspeed/.lintstagedrc.json b/workspaces/lightspeed/plugins/lightspeed/.lintstagedrc.json deleted file mode 100644 index 14b2263d..00000000 --- a/workspaces/lightspeed/plugins/lightspeed/.lintstagedrc.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "*": "prettier --ignore-unknown --write", - "*.{js,jsx,ts,tsx,mjs,cjs}": "backstage-cli package lint --fix" -} diff --git a/workspaces/lightspeed/plugins/lightspeed/tsconfig.json b/workspaces/lightspeed/plugins/lightspeed/tsconfig.json deleted file mode 100644 index fc57735d..00000000 --- a/workspaces/lightspeed/plugins/lightspeed/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "@backstage/cli/config/tsconfig.json", - "include": ["src", "dev"], - "exclude": ["node_modules"], - "compilerOptions": { - "outDir": "../../dist-types/plugins/lightspeed", - "rootDir": "." - } -} diff --git a/workspaces/lightspeed/plugins/lightspeed/turbo.json b/workspaces/lightspeed/plugins/lightspeed/turbo.json deleted file mode 100644 index bcc47a18..00000000 --- a/workspaces/lightspeed/plugins/lightspeed/turbo.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": ["//"], - "tasks": { - "tsc": { - "outputs": ["../../dist-types/plugins/lightspeed/**"] - } - } -} diff --git a/workspaces/openshift-image-registry/plugins/openshift-image-registry/.lintstagedrc.json b/workspaces/openshift-image-registry/plugins/openshift-image-registry/.lintstagedrc.json deleted file mode 100644 index 14b2263d..00000000 --- a/workspaces/openshift-image-registry/plugins/openshift-image-registry/.lintstagedrc.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "*": "prettier --ignore-unknown --write", - "*.{js,jsx,ts,tsx,mjs,cjs}": "backstage-cli package lint --fix" -} diff --git a/workspaces/openshift-image-registry/plugins/openshift-image-registry/.versionhistory.md b/workspaces/openshift-image-registry/plugins/openshift-image-registry/.versionhistory.md deleted file mode 100644 index 89bdf9ea..00000000 --- a/workspaces/openshift-image-registry/plugins/openshift-image-registry/.versionhistory.md +++ /dev/null @@ -1,2 +0,0 @@ -- Bumped to 1.4.0 in main branch for next release 1.2.0 -- Bumped to 1.9.0 in main branch for next release 1.3.0 diff --git a/workspaces/openshift-image-registry/plugins/openshift-image-registry/tsconfig.json b/workspaces/openshift-image-registry/plugins/openshift-image-registry/tsconfig.json deleted file mode 100644 index 25242c70..00000000 --- a/workspaces/openshift-image-registry/plugins/openshift-image-registry/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "@backstage/cli/config/tsconfig.json", - "include": ["src", "dev", "migrations"], - "exclude": ["node_modules"], - "compilerOptions": { - "outDir": "../../dist-types/plugins/openshift-image-registry", - "rootDir": "." - } -} diff --git a/workspaces/openshift-image-registry/plugins/openshift-image-registry/turbo.json b/workspaces/openshift-image-registry/plugins/openshift-image-registry/turbo.json deleted file mode 100644 index eb48d0d0..00000000 --- a/workspaces/openshift-image-registry/plugins/openshift-image-registry/turbo.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": ["//"], - "tasks": { - "tsc": { - "outputs": ["../../dist-types/plugins/openshift-image-registry/**"] - } - } -} diff --git a/workspaces/orchestrator/.changeset/README.md b/workspaces/orchestrator/.changeset/README.md new file mode 100644 index 00000000..e5b6d8d6 --- /dev/null +++ b/workspaces/orchestrator/.changeset/README.md @@ -0,0 +1,8 @@ +# Changesets + +Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works +with multi-package repos, or single-package repos to help you version and publish your code. You can +find the full documentation for it [in our repository](https://github.com/changesets/changesets) + +We have a quick list of common questions to get you started engaging with this project in +[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) diff --git a/workspaces/orchestrator/.changeset/config.json b/workspaces/orchestrator/.changeset/config.json new file mode 100644 index 00000000..8208df00 --- /dev/null +++ b/workspaces/orchestrator/.changeset/config.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json", + "changelog": "@changesets/cli/changelog", + "commit": false, + "fixed": [], + "linked": [], + "access": "public", + "baseBranch": "main", + "updateInternalDependencies": "patch", + "privatePackages": { + "tag": false, + "version": false + } +} diff --git a/workspaces/orchestrator/.changeset/metal-eyes-sniff.md b/workspaces/orchestrator/.changeset/metal-eyes-sniff.md new file mode 100644 index 00000000..a845151c --- /dev/null +++ b/workspaces/orchestrator/.changeset/metal-eyes-sniff.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/workspaces/orchestrator/.changeset/red-boats-float.md b/workspaces/orchestrator/.changeset/red-boats-float.md new file mode 100644 index 00000000..30489ee2 --- /dev/null +++ b/workspaces/orchestrator/.changeset/red-boats-float.md @@ -0,0 +1,5 @@ +--- +'@red-hat-developer-hub/backstage-plugin-orchestrator-backend': major +--- + +fix SonataFlowService.ts:fetchWorkflowOverviewBySource to fetch less instances diff --git a/workspaces/orchestrator/.dockerignore b/workspaces/orchestrator/.dockerignore new file mode 100644 index 00000000..05edb626 --- /dev/null +++ b/workspaces/orchestrator/.dockerignore @@ -0,0 +1,8 @@ +.git +.yarn/cache +.yarn/install-state.gz +node_modules +packages/*/src +packages/*/node_modules +plugins +*.local.yaml diff --git a/workspaces/orchestrator/.eslintignore b/workspaces/orchestrator/.eslintignore new file mode 100644 index 00000000..fc5d0d74 --- /dev/null +++ b/workspaces/orchestrator/.eslintignore @@ -0,0 +1,5 @@ +playwright.config.ts +dist-dynamic +dist-scalprum +!.eslintrc.js +!.prettierrc.js \ No newline at end of file diff --git a/workspaces/orchestrator/.eslintrc.js b/workspaces/orchestrator/.eslintrc.js new file mode 100644 index 00000000..59b86f84 --- /dev/null +++ b/workspaces/orchestrator/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('../../.eslintrc.cjs'); diff --git a/workspaces/orchestrator/.gitignore b/workspaces/orchestrator/.gitignore new file mode 100644 index 00000000..fbf81390 --- /dev/null +++ b/workspaces/orchestrator/.gitignore @@ -0,0 +1,54 @@ +# macOS +.DS_Store + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Coverage directory generated when running tests with coverage +coverage + +# Dependencies +node_modules/ + +# Yarn 3 files +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/sdks +!.yarn/versions + +# Node version directives +.nvmrc + +# dotenv environment variables file +.env +.env.test + +# Build output +dist +dist-types + +# Temporary change files created by Vim +*.swp + +# MkDocs build output +site + +# Local configuration files +*.local.yaml + +# Sensitive credentials +*-credentials.yaml + +# vscode database functionality support files +*.session.sql + +# E2E test reports +e2e-test-report/ diff --git a/workspaces/orchestrator/.prettierignore b/workspaces/orchestrator/.prettierignore new file mode 100644 index 00000000..326dea77 --- /dev/null +++ b/workspaces/orchestrator/.prettierignore @@ -0,0 +1,6 @@ +dist +dist-types +coverage +.vscode +.eslintrc.js +generated diff --git a/workspaces/orchestrator/README.md b/workspaces/orchestrator/README.md new file mode 100644 index 00000000..94044a3f --- /dev/null +++ b/workspaces/orchestrator/README.md @@ -0,0 +1,16 @@ +# [Backstage](https://backstage.io) + +This is your newly scaffolded Backstage App, Good Luck! + +To start the app, run: + +```sh +yarn install +yarn dev +``` + +To generate knip reports for this app, run: + +```sh +yarn backstage-repo-tools knip-reports +``` diff --git a/workspaces/orchestrator/app-config.yaml b/workspaces/orchestrator/app-config.yaml new file mode 100644 index 00000000..c05d79ad --- /dev/null +++ b/workspaces/orchestrator/app-config.yaml @@ -0,0 +1,95 @@ +app: + title: RHDH Plugins + baseUrl: http://localhost:3000 + +organization: + name: Red Hat + +backend: + # Used for enabling authentication, secret is shared by all backend plugins + # See https://backstage.io/docs/auth/service-to-service-auth for + # information on the format + # auth: + # keys: + # - secret: ${BACKEND_SECRET} + baseUrl: http://localhost:7007 + listen: + port: 7007 + # Uncomment the following host directive to bind to specific interfaces + # host: 127.0.0.1 + csp: + frame-ancestors: ['http://localhost:3000', 'http://localhost:7007'] + script-src: ["'self'", "'unsafe-inline'", "'unsafe-eval'"] + script-src-elem: ["'self'", "'unsafe-inline'", "'unsafe-eval'"] + connect-src: ["'self'", 'http:', 'https:', 'data:'] + # Content-Security-Policy directives follow the Helmet format: https://helmetjs.github.io/#reference + # Default Helmet Content-Security-Policy values can be removed by setting the key to false + cors: + origin: http://localhost:3000 + methods: [GET, HEAD, PATCH, POST, PUT, DELETE] + credentials: true + # This is for local development only, it is not recommended to use this in production + # The production database configuration is stored in app-config.production.yaml + database: + client: better-sqlite3 + connection: ':memory:' + cache: + store: memory + # workingDirectory: /tmp # Use this to configure a working directory for the scaffolder, defaults to the OS temp-dir + +integrations: {} + +proxy: + '/quay/api': + target: 'https://quay.io' + headers: + X-Requested-With: 'XMLHttpRequest' + # Uncomment the following line to access a private Quay Repository using a token + # Authorization: 'Bearer ' + changeOrigin: true + # Change to "false" in case of using self hosted quay instance with a self-signed certificate + secure: true + +quay: + uiUrl: 'https://quay.io' + +techdocs: + builder: 'local' # Alternatives - 'external' + generator: + runIn: 'docker' # Alternatives - 'local' + publisher: + type: 'local' # Alternatives - 'googleGcs' or 'awsS3'. Read documentation for using alternatives. + +auth: + # see https://backstage.io/docs/auth/ to learn about auth providers + providers: { guest: {} } + +scaffolder: + {} + # see https://backstage.io/docs/features/software-templates/configuration for software template options + +catalog: + import: + entityFilename: catalog-info.yaml + pullRequestBranchName: backstage-integration + rules: + - allow: [Component, System, Group, Resource, Location, Template, API] + locations: + - type: url + target: https://github.com/janus-idp/backstage-showcase/blob/main/catalog-entities/all.yaml + + - type: url + target: https://github.com/redhat-developer/red-hat-developer-hub-software-templates/blob/main/templates.yaml + +dynamicPlugins: + frontend: {} +orchestrator: + sonataFlowService: + baseUrl: http://localhost + port: 8899 + autoStart: true + workflowsSource: + gitRepositoryUrl: https://github.com/parodos-dev/backstage-orchestrator-workflows + localPath: /tmp/orchestrator/repository + dataIndexService: + url: http://localhost:8899 diff --git a/workspaces/orchestrator/backstage.json b/workspaces/orchestrator/backstage.json new file mode 100644 index 00000000..d12c3635 --- /dev/null +++ b/workspaces/orchestrator/backstage.json @@ -0,0 +1 @@ +{ "version": "1.33.0" } diff --git a/workspaces/orchestrator/catalog-info.yaml b/workspaces/orchestrator/catalog-info.yaml new file mode 100644 index 00000000..ee676927 --- /dev/null +++ b/workspaces/orchestrator/catalog-info.yaml @@ -0,0 +1,13 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: orchestrator + description: An example of a Backstage application. + # Example for optional annotations + # annotations: + # github.com/project-slug: backstage/backstage + # backstage.io/techdocs-ref: dir:. +spec: + type: website + owner: john@example.com + lifecycle: experimental diff --git a/workspaces/orchestrator/package.json b/workspaces/orchestrator/package.json new file mode 100644 index 00000000..b225887e --- /dev/null +++ b/workspaces/orchestrator/package.json @@ -0,0 +1,65 @@ +{ + "name": "@internal/orchestrator", + "version": "1.0.0", + "private": true, + "engines": { + "node": "18 || 20" + }, + "scripts": { + "tsc": "tsc", + "dev": "yarn workspaces foreach -A --include backend --include app --parallel -v -i run start", + "tsc:full": "tsc --skipLibCheck true --incremental false", + "build:all": "backstage-cli repo build --all", + "build:api-reports": "yarn build:api-reports:only", + "build:api-reports:only": "backstage-repo-tools api-reports --allow-all-warnings -o ae-wrong-input-file-type --validate-release-tags --exclude 'plugins/orchestrator-swf-editor-envelope'", + "clean": "backstage-cli repo clean", + "test": "backstage-cli repo test", + "test:all": "backstage-cli repo test --coverage", + "fix": "backstage-cli repo fix", + "lint": "backstage-cli repo lint --since origin/main", + "lint:all": "backstage-cli repo lint", + "prettier:check": "prettier --check .", + "prettier:fix": "prettier --write .", + "new": "backstage-cli new --scope @red-hat-developer-hub", + "postinstall": "cd ../../ && yarn install" + }, + "workspaces": { + "packages": [ + "packages/*", + "plugins/*" + ] + }, + "repository": { + "type": "git", + "url": "https://github.com/redhat-developer/rhdh-plugins", + "directory": "workspaces/orchestrator" + }, + "devDependencies": { + "@backstage/cli": "^0.29.0", + "@backstage/e2e-test-utils": "^0.1.1", + "@backstage/repo-tools": "^0.10.0", + "@changesets/cli": "^2.27.1", + "@ianvs/prettier-plugin-sort-imports": "^4.4.0", + "@spotify/prettier-config": "^12.0.0", + "knip": "^5.27.4", + "node-gyp": "^9.0.0", + "prettier": "^2.3.2", + "typescript": "~5.3.0" + }, + "resolutions": { + "@types/react": "^18", + "@types/react-dom": "^18", + "react": "^18", + "react-dom": "^18" + }, + "prettier": "@spotify/prettier-config", + "lint-staged": { + "*.{js,jsx,ts,tsx,mjs,cjs}": [ + "eslint --fix", + "prettier --write" + ], + "*.{json,md}": [ + "prettier --write" + ] + } +} diff --git a/workspaces/orchestrator/packages/README.md b/workspaces/orchestrator/packages/README.md new file mode 100644 index 00000000..c119f3f6 --- /dev/null +++ b/workspaces/orchestrator/packages/README.md @@ -0,0 +1,3 @@ +This is where your own applications and centrally managed libraries live, each in a separate folder of its own. + +From the start there's an app folder (for the frontend) and a backend folder (for the Node backend), but you can also add more modules in here that house your core additions and adaptations, such as themes, common React component libraries, utilities, and similar. diff --git a/workspaces/orchestrator/packages/app/.eslintignore b/workspaces/orchestrator/packages/app/.eslintignore new file mode 100644 index 00000000..a48cf0de --- /dev/null +++ b/workspaces/orchestrator/packages/app/.eslintignore @@ -0,0 +1 @@ +public diff --git a/workspaces/orchestrator/packages/app/.eslintrc.js b/workspaces/orchestrator/packages/app/.eslintrc.js new file mode 100644 index 00000000..8bd689af --- /dev/null +++ b/workspaces/orchestrator/packages/app/.eslintrc.js @@ -0,0 +1,16 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/workspaces/orchestrator/packages/app/e2e-tests/app.test.ts b/workspaces/orchestrator/packages/app/e2e-tests/app.test.ts new file mode 100644 index 00000000..00dae7ef --- /dev/null +++ b/workspaces/orchestrator/packages/app/e2e-tests/app.test.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { expect, test } from '@playwright/test'; + +test('App should render the welcome page', async ({ page }) => { + await page.goto('/'); + + const enterButton = page.getByRole('button', { name: 'Enter' }); + await expect(enterButton).toBeVisible(); + await enterButton.click(); + + await expect(page.getByText('My Company Catalog')).toBeVisible(); +}); diff --git a/workspaces/orchestrator/packages/app/package.json b/workspaces/orchestrator/packages/app/package.json new file mode 100644 index 00000000..d24a3762 --- /dev/null +++ b/workspaces/orchestrator/packages/app/package.json @@ -0,0 +1,83 @@ +{ + "name": "app", + "version": "0.0.3", + "private": true, + "bundled": true, + "backstage": { + "role": "frontend" + }, + "repository": { + "type": "git", + "url": "https://github.com/redhat-developer/rhdh-plugins", + "directory": "workspaces/orchestrator/packages/app" + }, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "clean": "backstage-cli package clean", + "test": "backstage-cli package test", + "lint": "backstage-cli package lint" + }, + "dependencies": { + "@backstage/app-defaults": "^1.5.12", + "@backstage/catalog-model": "^1.7.0", + "@backstage/cli": "^0.28.0", + "@backstage/core-app-api": "^1.15.1", + "@backstage/core-components": "^0.15.1", + "@backstage/core-plugin-api": "^1.10.0", + "@backstage/integration-react": "^1.2.0", + "@backstage/plugin-api-docs": "^0.11.11", + "@backstage/plugin-catalog": "^1.24.0", + "@backstage/plugin-catalog-common": "^1.1.0", + "@backstage/plugin-catalog-graph": "^0.4.11", + "@backstage/plugin-catalog-import": "^0.12.5", + "@backstage/plugin-catalog-react": "^1.14.0", + "@backstage/plugin-org": "^0.6.31", + "@backstage/plugin-permission-react": "^0.4.27", + "@backstage/plugin-scaffolder": "^1.26.1", + "@backstage/plugin-search": "^1.4.18", + "@backstage/plugin-search-react": "^1.8.1", + "@backstage/plugin-techdocs": "^1.11.0", + "@backstage/plugin-techdocs-module-addons-contrib": "^1.1.16", + "@backstage/plugin-techdocs-react": "^1.2.9", + "@backstage/plugin-user-settings": "^0.8.14", + "@backstage/theme": "^0.6.0", + "@mui/icons-material": "5.15.17", + "@mui/lab": "5.0.0-alpha.173", + "@mui/material": "5.15.17", + "@mui/styles": "5.16.7", + "@red-hat-developer-hub/backstage-plugin-orchestrator": "workspace:^", + "@redhat-developer/red-hat-developer-hub-theme": "^0.4.0", + "history": "^5.0.0", + "react": "^18.0.2", + "react-dom": "^18.0.2", + "react-router": "^6.3.0", + "react-router-dom": "^6.3.0", + "react-use": "^17.2.4" + }, + "devDependencies": { + "@backstage/test-utils": "^1.7.0", + "@playwright/test": "^1.32.3", + "@testing-library/dom": "^9.0.0", + "@testing-library/jest-dom": "^6.0.0", + "@testing-library/react": "^14.0.0", + "@testing-library/user-event": "^14.0.0", + "@types/react-dom": "*", + "cross-env": "^7.0.0" + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + }, + "files": [ + "dist" + ] +} diff --git a/workspaces/orchestrator/packages/app/public/android-chrome-192x192.png b/workspaces/orchestrator/packages/app/public/android-chrome-192x192.png new file mode 100644 index 00000000..eec0ae25 Binary files /dev/null and b/workspaces/orchestrator/packages/app/public/android-chrome-192x192.png differ diff --git a/workspaces/orchestrator/packages/app/public/apple-touch-icon.png b/workspaces/orchestrator/packages/app/public/apple-touch-icon.png new file mode 100644 index 00000000..3158830a Binary files /dev/null and b/workspaces/orchestrator/packages/app/public/apple-touch-icon.png differ diff --git a/workspaces/orchestrator/packages/app/public/favicon-16x16.png b/workspaces/orchestrator/packages/app/public/favicon-16x16.png new file mode 100644 index 00000000..58cf61a3 Binary files /dev/null and b/workspaces/orchestrator/packages/app/public/favicon-16x16.png differ diff --git a/workspaces/orchestrator/packages/app/public/favicon-32x32.png b/workspaces/orchestrator/packages/app/public/favicon-32x32.png new file mode 100644 index 00000000..c0915ece Binary files /dev/null and b/workspaces/orchestrator/packages/app/public/favicon-32x32.png differ diff --git a/workspaces/orchestrator/packages/app/public/favicon.ico b/workspaces/orchestrator/packages/app/public/favicon.ico new file mode 100644 index 00000000..5e45e5df Binary files /dev/null and b/workspaces/orchestrator/packages/app/public/favicon.ico differ diff --git a/workspaces/orchestrator/packages/app/public/index.html b/workspaces/orchestrator/packages/app/public/index.html new file mode 100644 index 00000000..18da7c47 --- /dev/null +++ b/workspaces/orchestrator/packages/app/public/index.html @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + <%= config.getOptionalString('app.title') ?? 'Backstage' %> + + + +
+ + + diff --git a/workspaces/orchestrator/packages/app/public/manifest.json b/workspaces/orchestrator/packages/app/public/manifest.json new file mode 100644 index 00000000..4a7c1b4e --- /dev/null +++ b/workspaces/orchestrator/packages/app/public/manifest.json @@ -0,0 +1,15 @@ +{ + "short_name": "Backstage", + "name": "Backstage", + "icons": [ + { + "src": "favicon.ico", + "sizes": "48x48", + "type": "image/png" + } + ], + "start_url": "./index.html", + "display": "standalone", + "theme_color": "#000000", + "background_color": "#ffffff" +} diff --git a/workspaces/orchestrator/packages/app/public/robots.txt b/workspaces/orchestrator/packages/app/public/robots.txt new file mode 100644 index 00000000..01b0f9a1 --- /dev/null +++ b/workspaces/orchestrator/packages/app/public/robots.txt @@ -0,0 +1,2 @@ +# https://www.robotstxt.org/robotstxt.html +User-agent: * diff --git a/workspaces/orchestrator/packages/app/public/safari-pinned-tab.svg b/workspaces/orchestrator/packages/app/public/safari-pinned-tab.svg new file mode 100644 index 00000000..0f500b30 --- /dev/null +++ b/workspaces/orchestrator/packages/app/public/safari-pinned-tab.svg @@ -0,0 +1 @@ +Created by potrace 1.11, written by Peter Selinger 2001-2013 \ No newline at end of file diff --git a/workspaces/orchestrator/packages/app/src/App.test.tsx b/workspaces/orchestrator/packages/app/src/App.test.tsx new file mode 100644 index 00000000..19a8d6cb --- /dev/null +++ b/workspaces/orchestrator/packages/app/src/App.test.tsx @@ -0,0 +1,44 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { render, waitFor } from '@testing-library/react'; +import React from 'react'; +import App from './App'; + +describe('App', () => { + it('should render', async () => { + process.env = { + NODE_ENV: 'test', + APP_CONFIG: [ + { + data: { + app: { title: 'Test' }, + backend: { baseUrl: 'http://localhost:7007' }, + techdocs: { + storageUrl: 'http://localhost:7007/api/techdocs/static/docs', + }, + }, + context: 'test', + }, + ] as any, + }; + + const rendered = render(); + + await waitFor(() => { + expect(rendered.baseElement).toBeInTheDocument(); + }); + }); +}); diff --git a/workspaces/orchestrator/packages/app/src/App.tsx b/workspaces/orchestrator/packages/app/src/App.tsx new file mode 100644 index 00000000..365412bf --- /dev/null +++ b/workspaces/orchestrator/packages/app/src/App.tsx @@ -0,0 +1,142 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { createApp } from '@backstage/app-defaults'; +import { AppRouter, FlatRoutes } from '@backstage/core-app-api'; +import { + AlertDisplay, + OAuthRequestDialog, + SignInPage, +} from '@backstage/core-components'; +import { githubAuthApiRef } from '@backstage/core-plugin-api'; +import { apiDocsPlugin, ApiExplorerPage } from '@backstage/plugin-api-docs'; +import { + CatalogEntityPage, + CatalogIndexPage, + catalogPlugin, +} from '@backstage/plugin-catalog'; +import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common/alpha'; +import { CatalogGraphPage } from '@backstage/plugin-catalog-graph'; +import { + CatalogImportPage, + catalogImportPlugin, +} from '@backstage/plugin-catalog-import'; +import { orgPlugin } from '@backstage/plugin-org'; +import { RequirePermission } from '@backstage/plugin-permission-react'; +import { ScaffolderPage, scaffolderPlugin } from '@backstage/plugin-scaffolder'; +import { SearchPage } from '@backstage/plugin-search'; +import { + TechDocsIndexPage, + techdocsPlugin, + TechDocsReaderPage, +} from '@backstage/plugin-techdocs'; +import { ReportIssue } from '@backstage/plugin-techdocs-module-addons-contrib'; +import { TechDocsAddons } from '@backstage/plugin-techdocs-react'; +import { UserSettingsPage } from '@backstage/plugin-user-settings'; +import { OrchestratorPage } from '@red-hat-developer-hub/backstage-plugin-orchestrator'; +import { getThemes } from '@redhat-developer/red-hat-developer-hub-theme'; +import React from 'react'; +import { Navigate, Route } from 'react-router-dom'; +import { apis } from './apis'; +import { entityPage } from './components/catalog/EntityPage'; +import { Root } from './components/Root'; +import { searchPage } from './components/search/SearchPage'; + +const app = createApp({ + apis, + bindRoutes({ bind }) { + bind(catalogPlugin.externalRoutes, { + createComponent: scaffolderPlugin.routes.root, + viewTechDoc: techdocsPlugin.routes.docRoot, + createFromTemplate: scaffolderPlugin.routes.selectedTemplate, + }); + bind(apiDocsPlugin.externalRoutes, { + registerApi: catalogImportPlugin.routes.importPage, + }); + bind(scaffolderPlugin.externalRoutes, { + registerComponent: catalogImportPlugin.routes.importPage, + viewTechDoc: techdocsPlugin.routes.docRoot, + }); + bind(orgPlugin.externalRoutes, { + catalogIndex: catalogPlugin.routes.catalogIndex, + }); + }, + components: { + SignInPage: props => ( + + ), + }, + themes: getThemes(), +}); + +const routes = ( + + } /> + } /> + } + > + {entityPage} + + } /> + } + > + + + + + } /> + } /> + + + + } + /> + }> + {searchPage} + + } /> + } /> + } /> + +); + +export default app.createRoot( + <> + + + + {routes} + + , +); diff --git a/workspaces/orchestrator/packages/app/src/apis.ts b/workspaces/orchestrator/packages/app/src/apis.ts new file mode 100644 index 00000000..3b1db0b5 --- /dev/null +++ b/workspaces/orchestrator/packages/app/src/apis.ts @@ -0,0 +1,34 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { + AnyApiFactory, + configApiRef, + createApiFactory, +} from '@backstage/core-plugin-api'; +import { + ScmAuth, + ScmIntegrationsApi, + scmIntegrationsApiRef, +} from '@backstage/integration-react'; + +export const apis: AnyApiFactory[] = [ + createApiFactory({ + api: scmIntegrationsApiRef, + deps: { configApi: configApiRef }, + factory: ({ configApi }) => ScmIntegrationsApi.fromConfig(configApi), + }), + ScmAuth.createDefaultApiFactory(), +]; diff --git a/workspaces/orchestrator/packages/app/src/components/Root/LogoFull.tsx b/workspaces/orchestrator/packages/app/src/components/Root/LogoFull.tsx new file mode 100644 index 00000000..1043a909 --- /dev/null +++ b/workspaces/orchestrator/packages/app/src/components/Root/LogoFull.tsx @@ -0,0 +1,45 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { makeStyles } from '@mui/styles'; +import React from 'react'; + +const useStyles = makeStyles({ + svg: { + width: 'auto', + height: 30, + }, + path: { + fill: '#7df3e1', + }, +}); +const LogoFull = () => { + const classes = useStyles(); + + return ( + + + + ); +}; + +export default LogoFull; diff --git a/workspaces/orchestrator/packages/app/src/components/Root/LogoIcon.tsx b/workspaces/orchestrator/packages/app/src/components/Root/LogoIcon.tsx new file mode 100644 index 00000000..25118221 --- /dev/null +++ b/workspaces/orchestrator/packages/app/src/components/Root/LogoIcon.tsx @@ -0,0 +1,46 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { makeStyles } from '@mui/styles'; +import React from 'react'; + +const useStyles = makeStyles({ + svg: { + width: 'auto', + height: 28, + }, + path: { + fill: '#7df3e1', + }, +}); + +const LogoIcon = () => { + const classes = useStyles(); + + return ( + + + + ); +}; + +export default LogoIcon; diff --git a/workspaces/orchestrator/packages/app/src/components/Root/Root.tsx b/workspaces/orchestrator/packages/app/src/components/Root/Root.tsx new file mode 100644 index 00000000..adf17643 --- /dev/null +++ b/workspaces/orchestrator/packages/app/src/components/Root/Root.tsx @@ -0,0 +1,123 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { + Link, + Sidebar, + sidebarConfig, + SidebarDivider, + SidebarGroup, + SidebarItem, + SidebarPage, + SidebarScrollWrapper, + SidebarSpace, + useSidebarOpenState, +} from '@backstage/core-components'; +import { MyGroupsSidebarItem } from '@backstage/plugin-org'; +import { SidebarSearchModal } from '@backstage/plugin-search'; +import { + Settings as SidebarSettings, + UserSettingsSignInAvatar, +} from '@backstage/plugin-user-settings'; +import CreateComponentIcon from '@mui/icons-material/AddCircleOutline'; +import ExtensionIcon from '@mui/icons-material/Extension'; +import HomeIcon from '@mui/icons-material/Home'; +import LibraryBooks from '@mui/icons-material/LibraryBooks'; +import MenuIcon from '@mui/icons-material/Menu'; +import GroupIcon from '@mui/icons-material/People'; +import SearchIcon from '@mui/icons-material/Search'; +import { makeStyles } from '@mui/styles'; +import { OrchestratorIcon } from '@red-hat-developer-hub/backstage-plugin-orchestrator'; +import React, { PropsWithChildren } from 'react'; +import LogoFull from './LogoFull'; +import LogoIcon from './LogoIcon'; + +const useSidebarLogoStyles = makeStyles({ + root: { + width: sidebarConfig.drawerWidthClosed, + height: 3 * sidebarConfig.logoHeight, + display: 'flex', + flexFlow: 'row nowrap', + alignItems: 'center', + marginBottom: -14, + }, + link: { + width: sidebarConfig.drawerWidthClosed, + marginLeft: 24, + }, +}); + +const SidebarLogo = () => { + const classes = useSidebarLogoStyles(); + const { isOpen } = useSidebarOpenState(); + + return ( +
+ + {isOpen ? : } + +
+ ); +}; + +export const Root = ({ children }: PropsWithChildren<{}>) => { + return ( + + + + } to="/search"> + + + + }> + {/* Global nav, not org-specific */} + + + + + + + {/* End global nav */} + + + + + + + + } + to="/settings" + > + + + + {children} + + ); +}; diff --git a/workspaces/orchestrator/packages/app/src/components/Root/index.ts b/workspaces/orchestrator/packages/app/src/components/Root/index.ts new file mode 100644 index 00000000..6e933a21 --- /dev/null +++ b/workspaces/orchestrator/packages/app/src/components/Root/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { Root } from './Root'; diff --git a/workspaces/orchestrator/packages/app/src/components/catalog/EntityPage.tsx b/workspaces/orchestrator/packages/app/src/components/catalog/EntityPage.tsx new file mode 100644 index 00000000..e58be81d --- /dev/null +++ b/workspaces/orchestrator/packages/app/src/components/catalog/EntityPage.tsx @@ -0,0 +1,406 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { + RELATION_API_CONSUMED_BY, + RELATION_API_PROVIDED_BY, + RELATION_CONSUMES_API, + RELATION_DEPENDENCY_OF, + RELATION_DEPENDS_ON, + RELATION_HAS_PART, + RELATION_PART_OF, + RELATION_PROVIDES_API, +} from '@backstage/catalog-model'; +import { EmptyState } from '@backstage/core-components'; +import { + EntityApiDefinitionCard, + EntityConsumedApisCard, + EntityConsumingComponentsCard, + EntityHasApisCard, + EntityProvidedApisCard, + EntityProvidingComponentsCard, +} from '@backstage/plugin-api-docs'; +import { + EntityAboutCard, + EntityDependsOnComponentsCard, + EntityDependsOnResourcesCard, + EntityHasComponentsCard, + EntityHasResourcesCard, + EntityHasSubcomponentsCard, + EntityHasSystemsCard, + EntityLayout, + EntityLinksCard, + EntityOrphanWarning, + EntityProcessingErrorsPanel, + EntityRelationWarning, + EntitySwitch, + hasCatalogProcessingErrors, + hasRelationWarnings, + isComponentType, + isKind, + isOrphan, +} from '@backstage/plugin-catalog'; +import { + Direction, + EntityCatalogGraphCard, +} from '@backstage/plugin-catalog-graph'; +import { + EntityGroupProfileCard, + EntityMembersListCard, + EntityOwnershipCard, + EntityUserProfileCard, +} from '@backstage/plugin-org'; +import { EntityTechdocsContent } from '@backstage/plugin-techdocs'; +import { ReportIssue } from '@backstage/plugin-techdocs-module-addons-contrib'; +import { TechDocsAddons } from '@backstage/plugin-techdocs-react'; +import Button from '@mui/material/Button'; +import Grid from '@mui/material/Grid'; +import React from 'react'; + +const techdocsContent = ( + + + + + +); + +const cicdContent = ( + // This is an example of how you can implement your company's logic in entity page. + // You can for example enforce that all components of type 'service' should use GitHubActions + + {/* + Here you can add support for different CI/CD services, for example + using @backstage-community/plugin-github-actions as follows: + + + + */} + + + + Read more + + } + /> + + +); + +const entityWarningContent = ( + <> + + + + + + + + + + + + + + + + + + + + + + + + +); + +const overviewContent = ( + + {entityWarningContent} + + + + + + + + + + + + + + +); + +const serviceEntityPage = ( + + + {overviewContent} + + + + {cicdContent} + + + + + + + + + + + + + + + + + + + + + + + + + + {techdocsContent} + + +); + +const websiteEntityPage = ( + + + {overviewContent} + + + + {cicdContent} + + + + + + + + + + + + + + + {techdocsContent} + + +); + +/** + * NOTE: This page is designed to work on small screens such as mobile devices. + * This is based on Material UI Grid. If breakpoints are used, each grid item must set the `xs` prop to a column size or to `true`, + * since this does not default. If no breakpoints are used, the items will equitably share the available space. + * https://material-ui.com/components/grid/#basic-grid. + */ + +const defaultEntityPage = ( + + + {overviewContent} + + + + {techdocsContent} + + +); + +const componentPage = ( + + + {serviceEntityPage} + + + + {websiteEntityPage} + + + {defaultEntityPage} + +); + +const apiPage = ( + + + + {entityWarningContent} + + + + + + + + + + + + + + + + + + + + + + + + + + + + +); + +const userPage = ( + + + + {entityWarningContent} + + + + + + + + + +); + +const groupPage = ( + + + + {entityWarningContent} + + + + + + + + + + + + + + + +); + +const systemPage = ( + + + + {entityWarningContent} + + + + + + + + + + + + + + + + + + + + + + + + +); + +const domainPage = ( + + + + {entityWarningContent} + + + + + + + + + + + + +); + +export const entityPage = ( + + + + + + + + + {defaultEntityPage} + +); diff --git a/workspaces/orchestrator/packages/app/src/components/search/SearchPage.tsx b/workspaces/orchestrator/packages/app/src/components/search/SearchPage.tsx new file mode 100644 index 00000000..d02d5c4d --- /dev/null +++ b/workspaces/orchestrator/packages/app/src/components/search/SearchPage.tsx @@ -0,0 +1,142 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { + CatalogIcon, + Content, + DocsIcon, + Header, + Page, +} from '@backstage/core-components'; +import { useApi } from '@backstage/core-plugin-api'; +import { CatalogSearchResultListItem } from '@backstage/plugin-catalog'; +import { + CATALOG_FILTER_EXISTS, + catalogApiRef, +} from '@backstage/plugin-catalog-react'; +import { SearchType } from '@backstage/plugin-search'; +import { + SearchBar, + SearchFilter, + SearchPagination, + SearchResult, + useSearch, +} from '@backstage/plugin-search-react'; +import { TechDocsSearchResultListItem } from '@backstage/plugin-techdocs'; +import Grid from '@mui/material/Grid'; +import Paper from '@mui/material/Paper'; +import { Theme } from '@mui/material/styles'; +import { makeStyles } from '@mui/styles'; +import React from 'react'; + +const useStyles = makeStyles((theme: Theme) => ({ + filter: { + '& + &': { + marginTop: theme.spacing(2.5), + }, + }, +})); + +const SearchPage = () => { + const classes = useStyles(); + const { types } = useSearch(); + const catalogApi = useApi(catalogApiRef); + + return ( + +
+ + + + + + + + + , + }, + { + value: 'techdocs', + name: 'Documentation', + icon: , + }, + ]} + /> + + {types.includes('techdocs') && ( + { + // Return a list of entities which are documented. + const { items } = await catalogApi.getEntities({ + fields: ['metadata.name'], + filter: { + 'metadata.annotations.backstage.io/techdocs-ref': + CATALOG_FILTER_EXISTS, + }, + }); + + const names = items.map(entity => entity.metadata.name); + names.sort(); + return names; + }} + /> + )} + + + + + + + + } /> + } /> + + + + + + ); +}; + +export const searchPage = ; diff --git a/workspaces/orchestrator/packages/app/src/index.tsx b/workspaces/orchestrator/packages/app/src/index.tsx new file mode 100644 index 00000000..23389912 --- /dev/null +++ b/workspaces/orchestrator/packages/app/src/index.tsx @@ -0,0 +1,21 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import '@backstage/cli/asset-types'; +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import App from './App'; + +ReactDOM.createRoot(document.getElementById('root')!).render(); diff --git a/workspaces/orchestrator/packages/app/src/setupTests.ts b/workspaces/orchestrator/packages/app/src/setupTests.ts new file mode 100644 index 00000000..658016ff --- /dev/null +++ b/workspaces/orchestrator/packages/app/src/setupTests.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import '@testing-library/jest-dom'; diff --git a/workspaces/orchestrator/packages/backend/.eslintrc.js b/workspaces/orchestrator/packages/backend/.eslintrc.js new file mode 100644 index 00000000..8bd689af --- /dev/null +++ b/workspaces/orchestrator/packages/backend/.eslintrc.js @@ -0,0 +1,16 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/workspaces/orchestrator/packages/backend/Dockerfile b/workspaces/orchestrator/packages/backend/Dockerfile new file mode 100644 index 00000000..05ad5dff --- /dev/null +++ b/workspaces/orchestrator/packages/backend/Dockerfile @@ -0,0 +1,66 @@ +# This dockerfile builds an image for the backend package. +# It should be executed with the root of the repo as docker context. +# +# Before building this image, be sure to have run the following commands in the repo root: +# +# yarn install --immutable +# yarn tsc +# yarn build:backend +# +# Once the commands have been run, you can build the image using `yarn build-image` + +FROM node:20-bookworm-slim + +# Set Python interpreter for `node-gyp` to use +ENV PYTHON=/usr/bin/python3 + +# Install isolate-vm dependencies, these are needed by the @backstage/plugin-scaffolder-backend. +RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ + --mount=type=cache,target=/var/lib/apt,sharing=locked \ + apt-get update && \ + apt-get install -y --no-install-recommends python3 g++ build-essential && \ + rm -rf /var/lib/apt/lists/* + +# Install sqlite3 dependencies. You can skip this if you don't use sqlite3 in the image, +# in which case you should also move better-sqlite3 to "devDependencies" in package.json. +RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ + --mount=type=cache,target=/var/lib/apt,sharing=locked \ + apt-get update && \ + apt-get install -y --no-install-recommends libsqlite3-dev && \ + rm -rf /var/lib/apt/lists/* + +# From here on we use the least-privileged `node` user to run the backend. +USER node + +# This should create the app dir as `node`. +# If it is instead created as `root` then the `tar` command below will fail: `can't create directory 'packages/': Permission denied`. +# If this occurs, then ensure BuildKit is enabled (`DOCKER_BUILDKIT=1`) so the app dir is correctly created as `node`. +WORKDIR /app + +# Copy files needed by Yarn +COPY --chown=node:node .yarn ./.yarn +COPY --chown=node:node .yarnrc.yml ./ + +# This switches many Node.js dependencies to production mode. +ENV NODE_ENV=production + +# This disables node snapshot for Node 20 to work with the Scaffolder +ENV NODE_OPTIONS "--no-node-snapshot" + +# Copy repo skeleton first, to avoid unnecessary docker cache invalidation. +# The skeleton contains the package.json of each package in the monorepo, +# and along with yarn.lock and the root package.json, that's enough to run yarn install. +COPY --chown=node:node yarn.lock package.json packages/backend/dist/skeleton.tar.gz ./ +RUN tar xzf skeleton.tar.gz && rm skeleton.tar.gz + +RUN --mount=type=cache,target=/home/node/.cache/yarn,sharing=locked,uid=1000,gid=1000 \ + yarn workspaces focus --all --production && rm -rf "$(yarn cache clean)" + +# This will include the examples, if you don't need these simply remove this line +COPY --chown=node:node examples ./examples + +# Then copy the rest of the backend bundle, along with any other files we might want. +COPY --chown=node:node packages/backend/dist/bundle.tar.gz app-config*.yaml ./ +RUN tar xzf bundle.tar.gz && rm bundle.tar.gz + +CMD ["node", "packages/backend", "--config", "app-config.yaml", "--config", "app-config.production.yaml"] \ No newline at end of file diff --git a/workspaces/orchestrator/packages/backend/README.md b/workspaces/orchestrator/packages/backend/README.md new file mode 100644 index 00000000..3607b0a0 --- /dev/null +++ b/workspaces/orchestrator/packages/backend/README.md @@ -0,0 +1,59 @@ +# example-backend + +This package is an EXAMPLE of a Backstage backend. + +The main purpose of this package is to provide a test bed for Backstage plugins +that have a backend part. Feel free to experiment locally or within your fork by +adding dependencies and routes to this backend, to try things out. + +Our goal is to eventually amend the create-app flow of the CLI, such that a +production ready version of a backend skeleton is made alongside the frontend +app. Until then, feel free to experiment here! + +## Development + +To run the example backend, first go to the project root and run + +```bash +yarn install +``` + +You should only need to do this once. + +After that, go to the `packages/backend` directory and run + +```bash +yarn start +``` + +If you want to override any configuration locally, for example adding any secrets, +you can do so in `app-config.local.yaml`. + +The backend starts up on port 7007 per default. + +## Populating The Catalog + +If you want to use the catalog functionality, you need to add so called +locations to the backend. These are places where the backend can find some +entity descriptor data to consume and serve. For more information, see +[Software Catalog Overview - Adding Components to the Catalog](https://backstage.io/docs/features/software-catalog/#adding-components-to-the-catalog). + +To get started quickly, this template already includes some statically configured example locations +in `app-config.yaml` under `catalog.locations`. You can remove and replace these locations as you +like, and also override them for local development in `app-config.local.yaml`. + +## Authentication + +We chose [Passport](http://www.passportjs.org/) as authentication platform due +to its comprehensive set of supported authentication +[strategies](http://www.passportjs.org/packages/). + +Read more about the +[auth-backend](https://github.com/backstage/backstage/blob/master/plugins/auth-backend/README.md) +and +[how to add a new provider](https://github.com/backstage/backstage/blob/master/docs/auth/add-auth-provider.md) + +## Documentation + +- [Backstage Readme](https://github.com/backstage/backstage/blob/master/README.md) +- [Backstage Documentation](https://backstage.io/docs) diff --git a/workspaces/orchestrator/packages/backend/package.json b/workspaces/orchestrator/packages/backend/package.json new file mode 100644 index 00000000..7b61223a --- /dev/null +++ b/workspaces/orchestrator/packages/backend/package.json @@ -0,0 +1,62 @@ +{ + "name": "backend", + "version": "0.0.0", + "main": "dist/index.cjs.js", + "types": "src/index.ts", + "private": true, + "backstage": { + "role": "backend" + }, + "repository": { + "type": "git", + "url": "https://github.com/redhat-developer/rhdh-plugins", + "directory": "workspaces/orchestrator/packages/backend" + }, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "build-image": "docker build ../.. -f Dockerfile --tag backstage" + }, + "dependencies": { + "@backstage/backend-defaults": "^0.5.2", + "@backstage/config": "^1.2.0", + "@backstage/plugin-app-backend": "^0.3.76", + "@backstage/plugin-auth-backend": "^0.23.1", + "@backstage/plugin-auth-backend-module-github-provider": "^0.2.1", + "@backstage/plugin-auth-backend-module-guest-provider": "^0.2.1", + "@backstage/plugin-auth-node": "^0.5.3", + "@backstage/plugin-catalog-backend": "^1.27.1", + "@backstage/plugin-catalog-backend-module-logs": "^0.1.3", + "@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "^0.2.1", + "@backstage/plugin-permission-backend": "^0.5.50", + "@backstage/plugin-permission-backend-module-allow-all-policy": "^0.2.1", + "@backstage/plugin-permission-common": "^0.8.1", + "@backstage/plugin-permission-node": "^0.8.4", + "@backstage/plugin-proxy-backend": "^0.5.7", + "@backstage/plugin-scaffolder-backend": "^1.26.2", + "@backstage/plugin-search-backend": "^1.6.1", + "@backstage/plugin-search-backend-module-catalog": "^0.2.4", + "@backstage/plugin-search-backend-module-pg": "^0.5.37", + "@backstage/plugin-search-backend-module-techdocs": "^0.3.1", + "@backstage/plugin-search-backend-node": "^1.3.4", + "@backstage/plugin-techdocs-backend": "^1.11.1", + "@red-hat-developer-hub/backstage-plugin-orchestrator-backend": "workspace:^", + "app": "link:../app", + "better-sqlite3": "^9.0.0", + "node-gyp": "^10.0.0", + "pg": "^8.11.3", + "winston": "^3.2.1" + }, + "devDependencies": { + "@backstage/cli": "^0.28.0", + "@types/express": "^4.17.6", + "@types/express-serve-static-core": "^4.17.5", + "@types/luxon": "^2.0.4" + }, + "files": [ + "dist" + ] +} diff --git a/workspaces/orchestrator/packages/backend/src/index.ts b/workspaces/orchestrator/packages/backend/src/index.ts new file mode 100644 index 00000000..7fe9e430 --- /dev/null +++ b/workspaces/orchestrator/packages/backend/src/index.ts @@ -0,0 +1,64 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { createBackend } from '@backstage/backend-defaults'; + +const backend = createBackend(); + +backend.add(import('@backstage/plugin-app-backend/alpha')); +backend.add(import('@backstage/plugin-proxy-backend/alpha')); +backend.add(import('@backstage/plugin-scaffolder-backend/alpha')); +backend.add(import('@backstage/plugin-techdocs-backend/alpha')); + +// auth plugin +backend.add(import('@backstage/plugin-auth-backend')); +// See https://backstage.io/docs/backend-system/building-backends/migrating#the-auth-plugin +backend.add(import('@backstage/plugin-auth-backend-module-guest-provider')); +// See https://backstage.io/docs/auth/guest/provider +backend.add(import('@backstage/plugin-auth-backend-module-github-provider')); + +// catalog plugin +backend.add(import('@backstage/plugin-catalog-backend/alpha')); +backend.add( + import('@backstage/plugin-catalog-backend-module-scaffolder-entity-model'), +); + +// See https://backstage.io/docs/features/software-catalog/configuration#subscribing-to-catalog-errors +backend.add(import('@backstage/plugin-catalog-backend-module-logs')); + +// permission plugin +backend.add(import('@backstage/plugin-permission-backend/alpha')); + +// See https://backstage.io/docs/permissions/getting-started for how to create your own permission policy +backend.add( + import('@backstage/plugin-permission-backend-module-allow-all-policy'), +); + +// search plugin +backend.add(import('@backstage/plugin-search-backend/alpha')); + +// search engine +// See https://backstage.io/docs/features/search/search-engines +backend.add(import('@backstage/plugin-search-backend-module-pg/alpha')); + +// search collators +backend.add(import('@backstage/plugin-search-backend-module-catalog/alpha')); +backend.add(import('@backstage/plugin-search-backend-module-techdocs/alpha')); + +backend.add( + import('@red-hat-developer-hub/backstage-plugin-orchestrator-backend'), +); + +backend.start(); diff --git a/workspaces/orchestrator/plugins/README.md b/workspaces/orchestrator/plugins/README.md new file mode 100644 index 00000000..d7865fdb --- /dev/null +++ b/workspaces/orchestrator/plugins/README.md @@ -0,0 +1,9 @@ +# The Plugins Folder + +This is where your own plugins and their associated modules live, each in a +separate folder of its own. + +If you want to create a new plugin here, go to your project root directory, run +the command `yarn new`, and follow the on-screen instructions. + +You can also check out existing plugins on [the plugin marketplace](https://backstage.io/plugins)! diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/.eslintignore b/workspaces/orchestrator/plugins/orchestrator-backend/.eslintignore new file mode 100644 index 00000000..b19336e4 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/.eslintignore @@ -0,0 +1,3 @@ +playwright.config.ts +dist/ +dist-types/ \ No newline at end of file diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/.eslintrc.js b/workspaces/orchestrator/plugins/orchestrator-backend/.eslintrc.js new file mode 100644 index 00000000..bdff83a0 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/.eslintrc.js @@ -0,0 +1,11 @@ +const backstageEslintConfig = require('@backstage/cli/config/eslint-factory')( + __dirname, +); + +module.exports = { + ...backstageEslintConfig, + ignorePatterns: [ + ...backstageEslintConfig.ignorePatterns, + 'static/generated/**', + ], +}; diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/.gitignore b/workspaces/orchestrator/plugins/orchestrator-backend/.gitignore new file mode 100644 index 00000000..7b4d4ba2 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/.gitignore @@ -0,0 +1 @@ +static diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/.prettierignore b/workspaces/orchestrator/plugins/orchestrator-backend/.prettierignore new file mode 100644 index 00000000..45c54605 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/.prettierignore @@ -0,0 +1,13 @@ +dist +dist-types +coverage +.vscode +CHANGELOG.md +generated +templates +*.hbs +renovate.json +dist-dynamic +dist-scalprum +playwright-report +static diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/.prettierrc.js b/workspaces/orchestrator/plugins/orchestrator-backend/.prettierrc.js new file mode 100644 index 00000000..5f81a8a0 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/.prettierrc.js @@ -0,0 +1,20 @@ +// @ts-check + +/** @type {import("@ianvs/prettier-plugin-sort-imports").PrettierConfig} */ +module.exports = { + ...require('@spotify/prettier-config'), + plugins: ['@ianvs/prettier-plugin-sort-imports'], + importOrder: [ + '^react(.*)$', + '', + '^@backstage/(.*)$', + '', + '', + '', + '^@red-hat-developer-hub/(.*)$', + '', + '', + '', + '^[.]', + ], +}; diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/CHANGELOG.md b/workspaces/orchestrator/plugins/orchestrator-backend/CHANGELOG.md new file mode 100644 index 00000000..cf7fd07d --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/CHANGELOG.md @@ -0,0 +1,740 @@ +### Dependencies + +## 4.1.1 + +### Patch Changes + +- 54daa8c: Migrated from [janus-idp/backstage-plugins](https://github.com/janus-idp/backstage-plugins). +- Updated dependencies [54daa8c] + - @red-hat-developer-hub/backstage-plugin-orchestrator-common@1.24.1 + +## 4.1.0 + +### Minor Changes + +- 25f1787: Add enum filters to orchestrator plugin +- 603a162: make error handling consistent in backend and UI + +### Patch Changes + +- Updated dependencies [25f1787] + - @red-hat-developer-hub/backstage-plugin-orchestrator-common@1.24.0 + +## 4.0.1 + +### Patch Changes + +- 0e6bfd3: feat: update Backstage to the latest version + + Update to Backstage 1.32.5 + +- Updated dependencies [0e6bfd3] + - @red-hat-developer-hub/backstage-plugin-orchestrator-common@1.23.1 + - @janus-idp/backstage-plugin-audit-log-node@1.7.1 + - @janus-idp/backstage-plugin-rbac-common@1.12.1 + +## 4.0.0 + +### Minor Changes + +- 8244f28: chore(deps): update to backstage 1.32 + +### Patch Changes + +- Updated dependencies [8244f28] + - @red-hat-developer-hub/backstage-plugin-orchestrator-common@1.23.0 + - @janus-idp/backstage-plugin-audit-log-node@1.7.0 + - @janus-idp/backstage-plugin-rbac-common@1.12.0 + +## 3.0.1 + +### Patch Changes + +- 7342e9b: chore: remove @janus-idp/cli dep and relink local packages + + This update removes `@janus-idp/cli` from all plugins, as it’s no longer necessary. Additionally, packages are now correctly linked with a specified version. + +## 3.0.0 + +### Minor Changes + +- d9551ae: feat(deps): update to backstage 1.31 + +### Patch Changes + +- d9551ae: Change local package references to a `*` +- d9551ae: pin the @janus-idp/cli package +- d9551ae: upgrade to yarn v3 +- d9551ae: Change the export-dynamic script to no longer use any flags and remove the tracking of the dist-dynamic folder +- Updated dependencies [d9551ae] +- Updated dependencies [d9551ae] +- Updated dependencies [d9551ae] + - @red-hat-developer-hub/backstage-plugin-orchestrator-common@1.22.0 + - @janus-idp/backstage-plugin-rbac-common@1.11.0 + - @janus-idp/backstage-plugin-audit-log-node@1.6.0 + +* **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.21.0 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.20.0 +- **@janus-idp/cli:** upgraded to 1.15.2 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.19.0 + +### Dependencies + +- **@janus-idp/backstage-plugin-audit-log-node:** upgraded to 1.5.1 + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.15.1 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.18.2 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.18.1 + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.15.0 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.18.0 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.17.3 + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.14.0 +- **@janus-idp/backstage-plugin-audit-log-node:** upgraded to 1.5.0 +- **@janus-idp/backstage-plugin-rbac-common:** upgraded to 1.10.0 + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.13.2 + +### Dependencies + +- **@janus-idp/backstage-plugin-audit-log-node:** upgraded to 1.4.1 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.17.2 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.17.1 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.17.0 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.16.0 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.15.2 + +### Dependencies + +- **@janus-idp/backstage-plugin-rbac-common:** upgraded to 1.9.0 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.15.1 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.15.0 + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.13.1 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.14.0 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.17.3](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.17.2...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.17.3) (2024-08-06) + +### Dependencies + +- **@janus-idp/backstage-plugin-rbac-common:** upgraded to 1.8.2 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.17.2](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.17.1...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.17.2) (2024-08-05) + +### Dependencies + +- **@janus-idp/backstage-plugin-rbac-common:** upgraded to 1.8.1 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.17.1](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.17.0...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.17.1) (2024-08-02) + +### Bug Fixes + +- **orchestrator:** remove default pagination on v2 endpoints ([#1983](https://github.com/janus-idp/backstage-plugins/issues/1983)) ([5e30274](https://github.com/janus-idp/backstage-plugins/commit/5e302748a25cbad127122407e5258576054eac3d)) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.13.1 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.17.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.16.1...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.17.0) (2024-07-26) + +### Features + +- **deps:** update to backstage 1.29 ([#1900](https://github.com/janus-idp/backstage-plugins/issues/1900)) ([f53677f](https://github.com/janus-idp/backstage-plugins/commit/f53677fb02d6df43a9de98c43a9f101a6db76802)) +- **orchestrator:** use v2 endpoints to retrieve instances ([#1956](https://github.com/janus-idp/backstage-plugins/issues/1956)) ([537502b](https://github.com/janus-idp/backstage-plugins/commit/537502b9d2ac13f2fb3f79188422d2c6e97f41fb)) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.13.0 +- **@janus-idp/backstage-plugin-rbac-common:** upgraded to 1.8.0 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.16.1](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.16.0...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.16.1) (2024-07-24) + +### Bug Fixes + +- **deps:** rollback unreleased plugins ([#1951](https://github.com/janus-idp/backstage-plugins/issues/1951)) ([8b77969](https://github.com/janus-idp/backstage-plugins/commit/8b779694f02f8125587296305276b84cdfeeaebe)) + +### Dependencies + +- **@janus-idp/backstage-plugin-rbac-common:** upgraded to 1.7.2 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.16.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.15.0...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.16.0) (2024-07-24) + +### Features + +- **deps:** update to backstage 1.28 ([#1891](https://github.com/janus-idp/backstage-plugins/issues/1891)) ([1ba1108](https://github.com/janus-idp/backstage-plugins/commit/1ba11088e0de60e90d138944267b83600dc446e5)) +- **orchestrator:** use v2 endpoints to retrieve workflow overviews ([#1892](https://github.com/janus-idp/backstage-plugins/issues/1892)) ([cca1e53](https://github.com/janus-idp/backstage-plugins/commit/cca1e53bc6b3019b1c544f2f62bed8723ebf6130)) + +### Bug Fixes + +- **orchestrator:** resolve broken dynamic plugin publish ([#1906](https://github.com/janus-idp/backstage-plugins/issues/1906)) ([5f99043](https://github.com/janus-idp/backstage-plugins/commit/5f990438ebebf8b23c0c8706852753ad0812c55a)) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.12.0 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.15.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.14.0...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.15.0) (2024-07-12) + +### Features + +- **orchestrator:** fix version ([#1886](https://github.com/janus-idp/backstage-plugins/issues/1886)) ([65c5917](https://github.com/janus-idp/backstage-plugins/commit/65c5917b8fc066a869d1a8e76d5e7b6cb4c8327c)) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.11.0 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.14.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.13.1...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.14.0) (2024-07-11) + +### Features + +- **orchestrator:** change openapi client generator ([#1864](https://github.com/janus-idp/backstage-plugins/issues/1864)) ([d6a4f4c](https://github.com/janus-idp/backstage-plugins/commit/d6a4f4ccfedfd55356305131029fd3d8ca0ab9c5)) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.11.0 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.13.1](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.13.0...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.13.1) (2024-07-01) + +### Bug Fixes + +- **rbac:** update rbac common to fix compilation ([#1858](https://github.com/janus-idp/backstage-plugins/issues/1858)) ([48f142b](https://github.com/janus-idp/backstage-plugins/commit/48f142b447f0d1677ba3f16b2a3c8972b22d0588)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.13.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.12.0...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.13.0) (2024-06-28) + +### Features + +- **orchestrator:** fix build failure from [#1833](https://github.com/janus-idp/backstage-plugins/issues/1833) ([#1850](https://github.com/janus-idp/backstage-plugins/issues/1850)) ([c0c73e6](https://github.com/janus-idp/backstage-plugins/commit/c0c73e638f66c03dae565614b8186938b38d7032)) +- **orchestrator:** remove unneeded orchestrator jira integration and endpoint ([#1833](https://github.com/janus-idp/backstage-plugins/issues/1833)) ([d2a76fd](https://github.com/janus-idp/backstage-plugins/commit/d2a76fd3db028f9774c821759bee5f38b7131c94)) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.10.0 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.12.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.11.0...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.12.0) (2024-06-26) + +### Features + +- **orchestrator:** disable buttons based on permissions ([#1818](https://github.com/janus-idp/backstage-plugins/issues/1818)) ([36504b0](https://github.com/janus-idp/backstage-plugins/commit/36504b05d96dbbf0b2395dc6e5c155c21fa73bcd)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.11.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.10.1...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.11.0) (2024-06-25) + +### Features + +- **orchestrator:** add auditLog and reorganize endpoints declaration ([#1820](https://github.com/janus-idp/backstage-plugins/issues/1820)) ([00d9216](https://github.com/janus-idp/backstage-plugins/commit/00d9216ba76c13fac86933a8605102d6e1768929)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.10.1](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.10.0...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.10.1) (2024-06-19) + +### Bug Fixes + +- **orchestrator:** change log level of cache messages to be debug ([#1824](https://github.com/janus-idp/backstage-plugins/issues/1824)) ([4224612](https://github.com/janus-idp/backstage-plugins/commit/422461224e31b419cd8394e2432af71ed10a986e)) + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.11.1 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.10.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.9.8...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.10.0) (2024-06-13) + +### Features + +- **deps:** update to backstage 1.27 ([#1683](https://github.com/janus-idp/backstage-plugins/issues/1683)) ([a14869c](https://github.com/janus-idp/backstage-plugins/commit/a14869c3f4177049cb8d6552b36c3ffd17e7997d)) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.9.0 +- **@janus-idp/cli:** upgraded to 1.11.0 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.9.8](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.9.7...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.9.8) (2024-06-13) + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.10.1 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.9.7](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.9.6...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.9.7) (2024-06-11) + +### Bug Fixes + +- **orchestrator:** fix error handling in case data index failed to start ([#1804](https://github.com/janus-idp/backstage-plugins/issues/1804)) ([27affb7](https://github.com/janus-idp/backstage-plugins/commit/27affb7815e02127721fd854f7903dca3525dede)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.9.6](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.9.5...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.9.6) (2024-06-05) + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.10.0 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.9.5](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.9.4...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.9.5) (2024-06-04) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.8.1 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.9.4](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.9.3...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.9.4) (2024-06-03) + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.9.0 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.9.3](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.9.2...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.9.3) (2024-05-29) + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.8.10 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.9.2](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.9.1...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.9.2) (2024-05-29) + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.8.9 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.9.1](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.9.0...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.9.1) (2024-05-28) + +### Bug Fixes + +- **orchestrator:** fixed broken workflow viewer ([#1717](https://github.com/janus-idp/backstage-plugins/issues/1717)) ([19cc79b](https://github.com/janus-idp/backstage-plugins/commit/19cc79bb9c1422556ddb9f85a2ac323186808321)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.9.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.8.7...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.9.0) (2024-05-22) + +### Features + +- **orchestrator:** add permissions to orchestrator plugin ([#1599](https://github.com/janus-idp/backstage-plugins/issues/1599)) ([d0a4531](https://github.com/janus-idp/backstage-plugins/commit/d0a453181e177eb1da7b1e231253b76a2d9356a8)) + +### Bug Fixes + +- **orchestrator:** fix the common package reference version ([#1704](https://github.com/janus-idp/backstage-plugins/issues/1704)) ([942b2a3](https://github.com/janus-idp/backstage-plugins/commit/942b2a3b6eb29c0fe88f9c98dea581309d02fded)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.8.7](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.8.6...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.8.7) (2024-05-21) + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.8.6](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.8.5...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.8.6) (2024-05-20) + +### Bug Fixes + +- **orchestrator:** fixes many security-related issues ([#1681](https://github.com/janus-idp/backstage-plugins/issues/1681)) ([3e801c8](https://github.com/janus-idp/backstage-plugins/commit/3e801c84015f925bdecd226a161ef81a5fc69432)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.8.5](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.8.4...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.8.5) (2024-05-16) + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.8.7 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.8.4](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.8.3...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.8.4) (2024-05-15) + +### Documentation + +- **orchestrator:** removes instructions related to the editor ([#1664](https://github.com/janus-idp/backstage-plugins/issues/1664)) ([10a75b2](https://github.com/janus-idp/backstage-plugins/commit/10a75b2706c72751bd774d6fae4332bbc527dc2b)) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.7.2 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.8.3](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.8.2...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.8.3) (2024-05-15) + +### Bug Fixes + +- **orchestrator:** export the `OrchestratorPlugin` accordingly ([#1644](https://github.com/janus-idp/backstage-plugins/issues/1644)) ([4a9d1f8](https://github.com/janus-idp/backstage-plugins/commit/4a9d1f821a30437e73631fac98b1aabc65473fba)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.8.2](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.8.1...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.8.2) (2024-05-09) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.7.1 +- **@janus-idp/cli:** upgraded to 1.8.6 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.8.1](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.8.0...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.8.1) (2024-05-09) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.7.0 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.8.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.7.4...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.8.0) (2024-05-06) + +### Features + +- **orchestrator:** make the internal sonata podman compatible ([#1612](https://github.com/janus-idp/backstage-plugins/issues/1612)) ([e4e528e](https://github.com/janus-idp/backstage-plugins/commit/e4e528e2c10536d029ffec11953f3a1d0309b0c5)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.7.4](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.7.3...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.7.4) (2024-05-02) + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.8.5 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.7.3](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.7.2...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.7.3) (2024-05-02) + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.8.4 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.7.2](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.7.1...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.7.2) (2024-04-30) + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.8.3 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.7.1](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.7.0...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.7.1) (2024-04-30) + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.8.2 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.7.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.6.8...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.7.0) (2024-04-25) + +### Features + +- **orchestrator:** add endpoint to retrigger workflow in error state ([#1343](https://github.com/janus-idp/backstage-plugins/issues/1343)) ([328d23a](https://github.com/janus-idp/backstage-plugins/commit/328d23a7992da125becc8d7775a4ebd68165f243)) + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.8.1 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.6.8](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.6.7...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.6.8) (2024-04-18) + +### Bug Fixes + +- **orchestrator:** allows serving the editor envelope in disconnected environments ([#1450](https://github.com/janus-idp/backstage-plugins/issues/1450)) ([1e778d8](https://github.com/janus-idp/backstage-plugins/commit/1e778d88336dfec79d48ece4fd8d2a035133b70e)) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.6.4 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.6.7](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.6.6...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.6.7) (2024-04-15) + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.8.0 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.6.6](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.6.5...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.6.6) (2024-04-09) + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.7.10 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.6.5](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.6.4...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.6.5) (2024-04-09) + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.7.9 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.6.4](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.6.3...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.6.4) (2024-04-05) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.6.3 +- **@janus-idp/cli:** upgraded to 1.7.8 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.6.3](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.6.2...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.6.3) (2024-04-04) + +### Bug Fixes + +- **orchestrator:** add lastRunId to overview endpoints ([#1449](https://github.com/janus-idp/backstage-plugins/issues/1449)) ([cce56f7](https://github.com/janus-idp/backstage-plugins/commit/cce56f7de3acc41ecd30b1b9962d7817be69de7d)) +- **orchestrator:** only inputs inherited from the assessment workflow should be disabled ([#1436](https://github.com/janus-idp/backstage-plugins/issues/1436)) ([32d9bdf](https://github.com/janus-idp/backstage-plugins/commit/32d9bdfc38c07c4e60f0ce7670fc3813ad0d92c3)) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.6.2 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.6.2](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.6.1...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.6.2) (2024-04-02) + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.7.7 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.6.1](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.6.0...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.6.1) (2024-03-29) + +### Bug Fixes + +- **orchestrator:** fixes v2/instances endpoint ([#1414](https://github.com/janus-idp/backstage-plugins/issues/1414)) ([88b49df](https://github.com/janus-idp/backstage-plugins/commit/88b49df35cf10e231ba69c239e873cb10e7cc25b)) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.6.1 +- **@janus-idp/cli:** upgraded to 1.7.6 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.6.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.5.3...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.6.0) (2024-03-14) + +### Features + +- **orchestrator:** verify availability and cache workflow definition IDs ([#1309](https://github.com/janus-idp/backstage-plugins/issues/1309)) ([4d322f1](https://github.com/janus-idp/backstage-plugins/commit/4d322f1fc5b6f8b1afedf40cfe1b24b2edae2ac1)) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.6.0 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.5.3](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.5.2...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.5.3) (2024-03-12) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.5.1 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.5.2](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.5.1...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.5.2) (2024-03-11) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.5.0 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.5.1](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.5.0...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.5.1) (2024-03-11) + +### Other changes + +- **orchestrator:** add unit tests for v2 endpoints ([#1300](https://github.com/janus-idp/backstage-plugins/issues/1300)) ([9a13138](https://github.com/janus-idp/backstage-plugins/commit/9a13138c61d3cc7331f739da80f020bb68dd61e5)) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.4.1 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.5.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.4.12...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.5.0) (2024-03-07) + +### Features + +- **orchestrator:** support pagination for /instances and /overview ([#1313](https://github.com/janus-idp/backstage-plugins/issues/1313)) ([79d5988](https://github.com/janus-idp/backstage-plugins/commit/79d598816f16c8346b6868bff4cc30d695cad518)) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.4.0 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.4.12](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.4.11...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.4.12) (2024-03-04) + +### Bug Fixes + +- **orchestrator:** increase the number of attempts to fetch the instance after execution ([#1301](https://github.com/janus-idp/backstage-plugins/issues/1301)) ([77dcce3](https://github.com/janus-idp/backstage-plugins/commit/77dcce3adceaf12b583bda5e74be69a5cc273ba1)) + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.7.5 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.4.11](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.4.10...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.4.11) (2024-03-03) + +### Bug Fixes + +- **orchestrator:** stop fetching workflow URI ([#1297](https://github.com/janus-idp/backstage-plugins/issues/1297)) ([2456a28](https://github.com/janus-idp/backstage-plugins/commit/2456a287dbff955a0916b9600e89a39511cd537a)) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.3.7 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.4.10](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.4.9...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.4.10) (2024-02-29) + +### Bug Fixes + +- **orchestrator:** refactor 500 response to use ErrorResponse object ([#1290](https://github.com/janus-idp/backstage-plugins/issues/1290)) ([2580f3d](https://github.com/janus-idp/backstage-plugins/commit/2580f3d38cecf78334964666eb7c127c21b00924)) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.3.6 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.4.9](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.4.8...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.4.9) (2024-02-28) + +### Bug Fixes + +- **orchestrator:** clean up the plugin code ([#1292](https://github.com/janus-idp/backstage-plugins/issues/1292)) ([ad27fb8](https://github.com/janus-idp/backstage-plugins/commit/ad27fb8e98913a6b80feb38ff58a7864e1953a7e)) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.3.5 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.4.8](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.4.7...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.4.8) (2024-02-28) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.3.4 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.4.7](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.4.6...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.4.7) (2024-02-28) + +### Bug Fixes + +- **orchestrator:** handle nullable start/state properties of process instance ([#1277](https://github.com/janus-idp/backstage-plugins/issues/1277)) ([d8a43a5](https://github.com/janus-idp/backstage-plugins/commit/d8a43a5a164f83fc90d037ae3d7a355f5de543e0)) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.3.3 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.4.6](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.4.5...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.4.6) (2024-02-27) + +### Bug Fixes + +- **orchestrator:** workflowId parameter wrongly parsed in getWorkflowOverviewById (v2) ([#1283](https://github.com/janus-idp/backstage-plugins/issues/1283)) ([2cd70d0](https://github.com/janus-idp/backstage-plugins/commit/2cd70d048d707a3b117c5273a1d8bc9fdc03fff7)) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.3.2 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.4.5](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.4.4...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.4.5) (2024-02-27) + +### Bug Fixes + +- **orchestrator:** warn "unknown format X ignored in schema at path Y" ([#1270](https://github.com/janus-idp/backstage-plugins/issues/1270)) ([de3c734](https://github.com/janus-idp/backstage-plugins/commit/de3c734299189b753d924c87aa9b5c9b5f94683c)), closes [/github.com/janus-idp/backstage-plugins/blob/903c7f37a1cf138ac96ef3f631f951866c2014fa/plugins/notifications-backend/src/service/router.ts#L45-L52](https://github.com/janus-idp//github.com/janus-idp/backstage-plugins/blob/903c7f37a1cf138ac96ef3f631f951866c2014fa/plugins/notifications-backend/src/service/router.ts/issues/L45-L52) + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.7.4 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.4.4](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.4.3...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.4.4) (2024-02-26) + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.7.3 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.4.3](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.4.2...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.4.3) (2024-02-23) + +### Bug Fixes + +- **orchestrator:** handle api endpoint failure ([#1254](https://github.com/janus-idp/backstage-plugins/issues/1254)) ([503de1b](https://github.com/janus-idp/backstage-plugins/commit/503de1b028e134cafb5a04045068768f30519409)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.4.2](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.4.1...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.4.2) (2024-02-22) + +### Bug Fixes + +- **orchestrator:** improvements to backend services ([#1252](https://github.com/janus-idp/backstage-plugins/issues/1252)) ([af8e072](https://github.com/janus-idp/backstage-plugins/commit/af8e072f35bc033f5111207c87711c9c0f9ff386)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.4.1](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.4.0...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.4.1) (2024-02-21) + +### Bug Fixes + +- **orchestrator:** implementation of getWorkflowById (v2) ([#1233](https://github.com/janus-idp/backstage-plugins/issues/1233)) ([f9f9008](https://github.com/janus-idp/backstage-plugins/commit/f9f9008d29f244c2ae6d688d3e2dc9b65b705e5b)) +- **orchestrator:** minor improvements and fixes ([#1242](https://github.com/janus-idp/backstage-plugins/issues/1242)) ([c9ec4cb](https://github.com/janus-idp/backstage-plugins/commit/c9ec4cbe1847268e8068edc69c7937c5e133c315)) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.3.1 +- **@janus-idp/cli:** upgraded to 1.7.2 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.4.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.3.1...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.4.0) (2024-02-20) + +### Features + +- **orchestrator:** add OpenAPI v2 implementations ([#1182](https://github.com/janus-idp/backstage-plugins/issues/1182)) ([43ac2f3](https://github.com/janus-idp/backstage-plugins/commit/43ac2f3f492b5c977142a3cfd9868d5e193ceb02)) + +### Bug Fixes + +- **orchestrator:** decommission the ProcessInstance.lastUpdate field ([#1230](https://github.com/janus-idp/backstage-plugins/issues/1230)) ([9724e27](https://github.com/janus-idp/backstage-plugins/commit/9724e27eaa84fe73d7724f28c86409681b7f79f8)) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.3.0 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.3.1](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.3.0...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.3.1) (2024-02-16) + +### Bug Fixes + +- **orchestrator:** resolve mismatch between execution data and composed schema ([#1217](https://github.com/janus-idp/backstage-plugins/issues/1217)) ([af85114](https://github.com/janus-idp/backstage-plugins/commit/af851148935e1ed083709cac145520d7551de737)) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.2.1 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.3.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.2.2...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.3.0) (2024-02-16) + +### Features + +- **orchestrator:** add OpenAPI support ([#1123](https://github.com/janus-idp/backstage-plugins/issues/1123)) ([bd88e23](https://github.com/janus-idp/backstage-plugins/commit/bd88e2304c93761ce6754985074f004a5a3c8c4b)) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.2.0 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.2.2](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.2.1...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.2.2) (2024-02-13) + +### Bug Fixes + +- **orchestrator:** filter out `null` values from action input ([#1199](https://github.com/janus-idp/backstage-plugins/issues/1199)) ([55c3927](https://github.com/janus-idp/backstage-plugins/commit/55c3927fb5211e1ec78719fd38740eb29e481962)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.2.1](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.2.0...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.2.1) (2024-02-05) + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.7.1 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.2.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.1.0...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.2.0) (2024-02-02) + +### Features + +- **orchestrator:** add the ability to rerun workflows in a new instance ([#1141](https://github.com/janus-idp/backstage-plugins/issues/1141)) ([fe326df](https://github.com/janus-idp/backstage-plugins/commit/fe326df569caa5a9e7b7ec809c1c371a2a936010)) + +### Bug Fixes + +- add missing alpha dynamic plugin entry points ([#1161](https://github.com/janus-idp/backstage-plugins/issues/1161)) ([36e9d91](https://github.com/janus-idp/backstage-plugins/commit/36e9d910b8f534fd9db2f8210c9aa7a24560f01d)) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.1.0 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.1.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.0.2...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.1.0) (2024-01-30) + +### Features + +- add new backend system support for existing backend plugins that have not been migrated over yet ([#1132](https://github.com/janus-idp/backstage-plugins/issues/1132)) ([06e16fd](https://github.com/janus-idp/backstage-plugins/commit/06e16fdcf64257dd08297cb727445d9a8a23c522)) + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.7.0 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.0.2](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.0.1...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.0.2) (2024-01-25) + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.6.0 + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend [1.0.1](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.0.0...@red-hat-developer-hub/backstage-plugin-orchestrator-backend@1.0.1) (2024-01-18) + +### Bug Fixes + +- **orchestrator:** regenerate `orchestrator-backend/dist-dynamic/package.json` ([#1083](https://github.com/janus-idp/backstage-plugins/issues/1083)) ([8a8051c](https://github.com/janus-idp/backstage-plugins/commit/8a8051c5eded7bdd3e05d1532e8354709aaccb8b)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator-backend 1.0.0 (2024-01-17) + +### Features + +- **orchestrator:** add orchestrator plugin ([#783](https://github.com/janus-idp/backstage-plugins/issues/783)) ([cf5fe74](https://github.com/janus-idp/backstage-plugins/commit/cf5fe74db6992d9f51f5073bbcf20c8c346357a1)), closes [#28](https://github.com/janus-idp/backstage-plugins/issues/28) [#38](https://github.com/janus-idp/backstage-plugins/issues/38) [#35](https://github.com/janus-idp/backstage-plugins/issues/35) [#21](https://github.com/janus-idp/backstage-plugins/issues/21) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.0.0 diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/README.md b/workspaces/orchestrator/plugins/orchestrator-backend/README.md new file mode 100644 index 00000000..ccdd71d6 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/README.md @@ -0,0 +1,5 @@ +# Orchestrator Backend Plugin for Backstage + +Welcome to the backend package for the Orchestrator plugin! + +For more information about the Orchestrator plugin, see the [Orchestrator Plugin documentation](https://github.com/redhat-developer/rhdh-plugins/tree/main/workspaces/orchestrator/plugins/orchestrator) on GitHub. diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/__fixtures__/mockComposedGreetingWorfklow.ts b/workspaces/orchestrator/plugins/orchestrator-backend/__fixtures__/mockComposedGreetingWorfklow.ts new file mode 100644 index 00000000..61fc03ba --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/__fixtures__/mockComposedGreetingWorfklow.ts @@ -0,0 +1,144 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import type { JsonObject } from '@backstage/types'; + +import { JSONSchema7 } from 'json-schema'; + +import { WorkflowDefinition } from '@red-hat-developer-hub/backstage-plugin-orchestrator-common'; + +const schema = { + $id: 'classpath:/schemas/yamlgreet__main-schema.json', + title: 'Data Input Schema', + $schema: 'http://json-schema.org/draft-07/schema#', + type: 'object', + properties: { + language: { + type: 'object', + properties: { + language: { + title: 'Language', + description: 'Language to greet', + type: 'string', + enum: ['English', 'Spanish'], + default: 'English', + }, + }, + title: 'Language', + }, + name: { + type: 'object', + properties: { + name: { + title: 'Name', + description: 'Name of the person', + type: 'string', + default: 'John Doe', + }, + }, + }, + }, + required: ['name'], +} as JSONSchema7; + +const workflowDefinition = { + id: 'yamlgreet', + version: '1.0', + specVersion: '0.8', + name: 'Greeting workflow', + description: 'YAML based greeting workflow', + dataInputSchema: 'schemas/yamlgreet__main-schema.json', + start: 'ChooseOnLanguage', + functions: [ + { + name: 'greetFunction', + type: 'custom', + operation: 'sysout', + }, + ], + states: [ + { + name: 'ChooseOnLanguage', + type: 'switch', + dataConditions: [ + { + condition: '${ .language.language == "English" }', + transition: 'GreetInEnglish', + }, + { + condition: '${ .language.language == "Spanish" }', + transition: 'GreetInSpanish', + }, + ], + defaultCondition: { + transition: 'GreetInEnglish', + }, + }, + { + name: 'GreetInEnglish', + type: 'inject', + data: { + greeting: 'Hello from YAML Workflow, ', + }, + transition: 'GreetPerson', + }, + { + name: 'GreetInSpanish', + type: 'inject', + data: { + greeting: 'Saludos desde YAML Workflow, ', + }, + transition: 'GreetPerson', + }, + { + name: 'GreetPerson', + type: 'operation', + actions: [ + { + name: 'greetAction', + functionRef: { + refName: 'greetFunction', + arguments: { + message: '.greeting+.name.name', + }, + }, + }, + ], + end: { + terminate: true, + }, + }, + ], +} as WorkflowDefinition; + +const variables = { + workflowdata: { + name: { + name: 'John Doe', + }, + language: { + language: 'Spanish', + }, + greeting: 'hello', + }, +}; + +const mockData: { + schema: JSONSchema7; + workflowDefinition: WorkflowDefinition; + variables: JsonObject; +} = { schema, workflowDefinition, variables }; + +export default mockData; diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/__fixtures__/mockGreetingWorkflowData.ts b/workspaces/orchestrator/plugins/orchestrator-backend/__fixtures__/mockGreetingWorkflowData.ts new file mode 100644 index 00000000..c6750d37 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/__fixtures__/mockGreetingWorkflowData.ts @@ -0,0 +1,129 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import type { JsonObject } from '@backstage/types'; + +import { JSONSchema7 } from 'json-schema'; + +import { WorkflowDefinition } from '@red-hat-developer-hub/backstage-plugin-orchestrator-common'; + +const schema = { + $id: 'classpath:/schemas/yamlgreet__main-schema.json', + title: 'Data Input Schema', + $schema: 'http://json-schema.org/draft-07/schema#', + type: 'object', + properties: { + language: { + title: 'Language', + description: 'Language to greet', + type: 'string', + enum: ['English', 'Spanish'], + default: 'English', + }, + name: { + title: 'Name', + description: 'Name of the person', + type: 'string', + default: 'John Doe', + }, + }, + required: ['name'], +} as JSONSchema7; + +const workflowDefinition = { + id: 'yamlgreet', + version: '1.0', + specVersion: '0.8', + name: 'Greeting workflow', + description: 'YAML based greeting workflow', + dataInputSchema: 'schemas/yamlgreet__main-schema.json', + start: 'ChooseOnLanguage', + functions: [ + { + name: 'greetFunction', + type: 'custom', + operation: 'sysout', + }, + ], + states: [ + { + name: 'ChooseOnLanguage', + type: 'switch', + dataConditions: [ + { + condition: '${ .language == "English" }', + transition: 'GreetInEnglish', + }, + { + condition: '${ .language == "Spanish" }', + transition: 'GreetInSpanish', + }, + ], + defaultCondition: { + transition: 'GreetInEnglish', + }, + }, + { + name: 'GreetInEnglish', + type: 'inject', + data: { + greeting: 'Hello from YAML Workflow, ', + }, + transition: 'GreetPerson', + }, + { + name: 'GreetInSpanish', + type: 'inject', + data: { + greeting: 'Saludos desde YAML Workflow, ', + }, + transition: 'GreetPerson', + }, + { + name: 'GreetPerson', + type: 'operation', + actions: [ + { + name: 'greetAction', + functionRef: { + refName: 'greetFunction', + arguments: { + message: '.greeting+.name', + }, + }, + }, + ], + end: { + terminate: true, + }, + }, + ], +} as WorkflowDefinition; + +const variables = { + workflowdata: { + name: 'John Doe', + greeting: 'Saludos desde YAML Workflow, ', + language: 'Spanish', + }, +}; + +const mockData: { + schema: JSONSchema7; + workflowDefinition: WorkflowDefinition; + variables: JsonObject; +} = { schema, workflowDefinition, variables }; + +export default mockData; diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/__fixtures__/mockSpringBootWorkflowData.ts b/workspaces/orchestrator/plugins/orchestrator-backend/__fixtures__/mockSpringBootWorkflowData.ts new file mode 100644 index 00000000..d9fb13f1 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/__fixtures__/mockSpringBootWorkflowData.ts @@ -0,0 +1,595 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { JSONSchema7 } from 'json-schema'; + +import { WorkflowDefinition } from '@red-hat-developer-hub/backstage-plugin-orchestrator-common'; + +const schema = { + $id: 'classpath:/schemas/spring-boot-backend__main-schema.json', + title: 'Data input schema', + $schema: 'http://json-schema.org/draft-07/schema#', + type: 'object', + properties: { + newComponent: { + $ref: '#/$defs/Provide information about the new component_0', + type: 'object', + }, + javaMetadata: { + $ref: '#/$defs/Provide information about the Java metadata_1', + type: 'object', + }, + ciMethod: { + $ref: '#/$defs/Provide information about the CI method_2', + type: 'object', + }, + }, + $defs: { + 'Provide information about the CI method_2': { + $id: 'classpath:/schemas/spring-boot-backend__ref-schema__CI_Method.json', + title: 'Provide information about the CI method', + $schema: 'http://json-schema.org/draft-07/schema#', + type: 'object', + properties: { + ci: { + title: 'CI Method', + type: 'string', + default: 'github', + oneOf: [ + { + const: 'github', + title: 'GitHub Action', + }, + { + const: 'tekton', + title: 'Tekton', + }, + ], + }, + }, + allOf: [ + { + if: { + properties: { + ci: { + const: 'github', + }, + }, + }, + }, + { + if: { + properties: { + ci: { + const: 'tekton', + }, + }, + }, + then: { + properties: { + imageRepository: { + title: 'Image Registry', + description: 'The registry to use', + type: 'string', + default: 'quay.io', + oneOf: [ + { + const: 'quay.io', + title: 'Quay', + }, + { + const: 'image-registry.openshift-image-registry.svc:5000', + title: 'Internal OpenShift Registry', + }, + ], + }, + imageUrl: { + title: 'Image URL', + description: + 'The Quay.io or OpenShift Image URL //', + type: 'string', + }, + namespace: { + title: 'Namespace', + description: 'The namespace for deploying resources', + type: 'string', + }, + }, + required: ['namespace', 'imageUrl', 'imageRepository'], + }, + }, + ], + }, + 'Provide information about the Java metadata_1': { + $id: 'classpath:/schemas/spring-boot-backend__ref-schema__Java_Metadata.json', + title: 'Provide information about the Java metadata', + $schema: 'http://json-schema.org/draft-07/schema#', + type: 'object', + properties: { + groupId: { + title: 'Group ID', + description: 'Maven Group ID eg (io.janus)', + type: 'string', + default: 'io.janus', + }, + artifactId: { + title: 'Artifact ID', + description: 'Maven Artifact ID', + type: 'string', + default: 'spring-boot-app', + }, + javaPackageName: { + title: 'Java Package Namespace', + description: + 'Name for the Java Package (ensure to use the / character as this is used for folder structure) should match Group ID and Artifact ID', + type: 'string', + default: 'io/janus/spring-boot-app', + }, + version: { + title: 'Version', + description: 'Maven Artifact Version', + type: 'string', + default: '1.0.0-SNAPSHOT', + }, + }, + required: ['groupId', 'artifactId', 'javaPackageName', 'version'], + }, + 'Provide information about the new component_0': { + $id: 'classpath:/schemas/spring-boot-backend__ref-schema__New_Component.json', + title: 'Provide information about the new component', + $schema: 'http://json-schema.org/draft-07/schema#', + type: 'object', + properties: { + orgName: { + title: 'Organization Name', + description: 'Organization name', + type: 'string', + }, + repoName: { + title: 'Repository Name', + description: 'Repository name', + type: 'string', + }, + description: { + title: 'Description', + description: 'Help others understand what this component is for', + type: 'string', + }, + owner: { + title: 'Owner', + description: 'An entity from the catalog', + type: 'string', + }, + system: { + title: 'System', + description: 'An entity from the catalog', + type: 'string', + }, + port: { + title: 'Port', + description: 'Override the port exposed for the application', + type: 'number', + default: 8080, + }, + }, + required: ['orgName', 'repoName', 'owner', 'system', 'port'], + }, + }, +} as JSONSchema7; + +const workflowDefinition = { + id: 'spring-boot-backend', + version: '1.0', + specVersion: '0.8', + name: 'Spring Boot Backend application', + description: + 'Create a starter Spring Boot backend application with a CI pipeline', + dataInputSchema: 'schemas/spring-boot-backend__main-schema.json', + functions: [ + { + name: 'runActionFetchTemplate', + operation: 'specs/actions-openapi.json#fetch:template', + }, + { + name: 'runActionPublishGithub', + operation: 'specs/actions-openapi.json#publish:github', + }, + { + name: 'runActionCatalogRegister', + operation: 'specs/actions-openapi.json#catalog:register', + }, + { + name: 'fs:delete', + operation: 'specs/actions-openapi.json#fs:delete', + }, + { + name: 'sysout', + type: 'custom', + operation: 'sysout', + }, + ], + errors: [ + { + name: 'Error on Action', + code: 'java.lang.RuntimeException', + }, + ], + start: 'Generating the Source Code Component', + states: [ + { + name: 'Generating the Source Code Component', + type: 'operation', + actionMode: 'sequential', + actions: [ + { + name: 'Fetch Template Action - Source Code', + functionRef: { + refName: 'runActionFetchTemplate', + arguments: { + url: 'https://github.com/janus-idp/software-templates/tree/main/templates/github/spring-boot-backend/skeleton', + values: { + orgName: '.newComponent.orgName', + repoName: '.newComponent.repoName', + owner: '.newComponent.owner', + system: '.newComponent.system', + applicationType: 'api', + description: '.newComponent.description', + namespace: '.ciMethod.namespace', + port: '.newComponent.port', + ci: '.ciMethod.ci', + sourceControl: 'github.com', + groupId: '.javaMetadata.groupId', + artifactId: '.javaMetadata.artifactId', + javaPackageName: '.javaMetadata.javaPackageName', + version: '.javaMetadata.version', + }, + }, + }, + actionDataFilter: { + toStateData: '.actionFetchTemplateSourceCodeResult', + }, + }, + ], + onErrors: [ + { + errorRef: 'Error on Action', + transition: 'Handle Error', + }, + ], + compensatedBy: 'Clear File System - Source Code', + transition: 'Generating the CI Component', + }, + { + name: 'Generating the CI Component', + type: 'switch', + dataConditions: [ + { + condition: '${ .ciMethod.ci == "github" }', + transition: 'Generating the CI Component - GitHub', + }, + { + condition: '${ .ciMethod.ci == "tekton" }', + transition: 'Generating the CI Component - Tekton', + }, + ], + defaultCondition: { + transition: 'Generating the CI Component - GitHub', + }, + }, + { + name: 'Generating the CI Component - GitHub', + type: 'operation', + actionMode: 'sequential', + actions: [ + { + name: 'Run Template Fetch Action - CI - GitHub', + functionRef: { + refName: 'runActionFetchTemplate', + arguments: { + url: 'https://github.com/janus-idp/software-templates/tree/main/skeletons/github-actions', + copyWithoutTemplating: ['".github/workflows/"'], + values: { + orgName: '.newComponent.orgName', + repoName: '.newComponent.repoName', + owner: '.newComponent.owner', + system: '.newComponent.system', + applicationType: 'api', + description: '.newComponent.description', + namespace: '.ciMethod.namespace', + port: '.newComponent.port', + ci: '.ciMethod.ci', + sourceControl: 'github.com', + groupId: '.javaMetadata.groupId', + artifactId: '.javaMetadata.artifactId', + javaPackageName: '.javaMetadata.javaPackageName', + version: '.javaMetadata.version', + }, + }, + }, + actionDataFilter: { + toStateData: '.actionTemplateFetchCIResult', + }, + }, + ], + onErrors: [ + { + errorRef: 'Error on Action', + transition: 'Handle Error', + }, + ], + compensatedBy: 'Clear File System - CI', + transition: 'Generating the Catalog Info Component', + }, + { + name: 'Generating the CI Component - Tekton', + type: 'operation', + actionMode: 'sequential', + actions: [ + { + name: 'Run Template Fetch Action - CI - Tekton', + functionRef: { + refName: 'runActionFetchTemplate', + arguments: { + url: 'https://github.com/janus-idp/software-templates/tree/main/skeletons/tekton', + copyWithoutTemplating: ['".github/workflows/"'], + values: { + orgName: '.newComponent.orgName', + repoName: '.newComponent.repoName', + owner: '.newComponent.owner', + system: '.newComponent.system', + applicationType: 'api', + description: '.newComponent.description', + namespace: '.ciMethod.namespace', + imageUrl: '.imageUrl', + imageRepository: '.imageRepository', + imageBuilder: 's2i-go', + port: '.newComponent.port', + ci: '.ciMethod.ci', + sourceControl: 'github.com', + groupId: '.javaMetadata.groupId', + artifactId: '.javaMetadata.artifactId', + javaPackageName: '.javaMetadata.javaPackageName', + version: '.javaMetadata.version', + }, + }, + }, + actionDataFilter: { + toStateData: '.actionTemplateFetchCIResult', + }, + }, + ], + onErrors: [ + { + errorRef: 'Error on Action', + transition: 'Handle Error', + }, + ], + compensatedBy: 'Clear File System - CI', + transition: 'Generating the Catalog Info Component', + }, + { + name: 'Generating the Catalog Info Component', + type: 'operation', + actions: [ + { + name: 'Fetch Template Action - Catalog Info', + functionRef: { + refName: 'runActionFetchTemplate', + arguments: { + url: 'https://github.com/janus-idp/software-templates/tree/main/skeletons/catalog-info', + values: { + orgName: '.newComponent.orgName', + repoName: '.newComponent.repoName', + owner: '.newComponent.owner', + system: '.newComponent.system', + applicationType: 'api', + description: '.newComponent.description', + namespace: '.ciMethod.namespace', + imageUrl: '.ciMethod.imageUrl', + imageRepository: '.ciMethod.imageRepository', + imageBuilder: 's2i-go', + port: '.newComponent.port', + ci: '.ciMethod.ci', + sourceControl: 'github.com', + groupId: '.javaMetadata.groupId', + artifactId: '.javaMetadata.artifactId', + javaPackageName: '.javaMetadata.javaPackageName', + version: '.javaMetadata.version', + }, + }, + }, + actionDataFilter: { + toStateData: '.actionFetchTemplateCatalogInfoResult', + }, + }, + ], + onErrors: [ + { + errorRef: 'Error on Action', + transition: 'Handle Error', + }, + ], + compensatedBy: 'Clear File System - Catalog', + transition: 'Publishing to the Source Code Repository', + }, + { + name: 'Publishing to the Source Code Repository', + type: 'operation', + actionMode: 'sequential', + actions: [ + { + name: 'Publish Github', + functionRef: { + refName: 'runActionPublishGithub', + arguments: { + allowedHosts: ['"github.com"'], + description: 'Workflow Action', + repoUrl: + '"github.com?owner=" + .newComponent.orgName + "&repo=" + .newComponent.repoName', + defaultBranch: 'main', + gitCommitMessage: 'Initial commit', + allowAutoMerge: true, + allowRebaseMerge: true, + }, + }, + actionDataFilter: { + toStateData: '.actionPublishResult', + }, + }, + ], + onErrors: [ + { + errorRef: 'Error on Action', + transition: 'Handle Error', + }, + ], + compensatedBy: 'Remove Source Code Repository', + transition: 'Registering the Catalog Info Component', + }, + { + name: 'Registering the Catalog Info Component', + type: 'operation', + actionMode: 'sequential', + actions: [ + { + name: 'Catalog Register Action', + functionRef: { + refName: 'runActionCatalogRegister', + arguments: { + repoContentsUrl: '.actionPublishResult.repoContentsUrl', + catalogInfoPath: '"/catalog-info.yaml"', + }, + }, + actionDataFilter: { + toStateData: '.actionCatalogRegisterResult', + }, + }, + ], + onErrors: [ + { + errorRef: 'Error on Action', + transition: 'Handle Error', + }, + ], + compensatedBy: 'Remove Catalog Info Component', + end: true, + }, + { + name: 'Handle Error', + type: 'operation', + actions: [ + { + name: 'Error Action', + functionRef: { + refName: 'sysout', + arguments: { + message: 'Error on workflow, triggering compensations', + }, + }, + }, + ], + end: { + compensate: true, + }, + }, + { + name: 'Clear File System - Source Code', + type: 'operation', + usedForCompensation: true, + actions: [ + { + name: 'Clear FS Action', + functionRef: { + refName: 'fs:delete', + arguments: { + files: ['./'], + }, + }, + }, + ], + }, + { + name: 'Clear File System - CI', + type: 'operation', + usedForCompensation: true, + actions: [ + { + name: 'Clear FS Action', + functionRef: { + refName: 'fs:delete', + arguments: { + files: ['./'], + }, + }, + }, + ], + }, + { + name: 'Clear File System - Catalog', + type: 'operation', + usedForCompensation: true, + actions: [ + { + name: 'Clear FS Action', + functionRef: { + refName: 'fs:delete', + arguments: { + files: ['./'], + }, + }, + }, + ], + }, + { + name: 'Remove Source Code Repository', + type: 'operation', + usedForCompensation: true, + actions: [ + { + name: 'Remove Source Code Repository', + functionRef: { + refName: 'sysout', + arguments: { + message: 'Remove Source Code Repository', + }, + }, + }, + ], + }, + { + name: 'Remove Catalog Info Component', + type: 'operation', + usedForCompensation: true, + actions: [ + { + name: 'Remove Catalog Info Component', + functionRef: { + refName: 'sysout', + arguments: { + message: 'Remove Catalog Info Component', + }, + }, + }, + ], + }, + ], +} as WorkflowDefinition; + +const mockData: { + schema: JSONSchema7; + workflowDefinition: WorkflowDefinition; +} = { schema, workflowDefinition }; + +export default mockData; diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/app-config.yaml b/workspaces/orchestrator/plugins/orchestrator-backend/app-config.yaml new file mode 100644 index 00000000..a3a8b8be --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/app-config.yaml @@ -0,0 +1,3 @@ +orchestrator: + dataIndexService: + url: http://sonataflow-platform-data-index-service.sonataflow-infra diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/catalog-info.yaml b/workspaces/orchestrator/plugins/orchestrator-backend/catalog-info.yaml new file mode 100644 index 00000000..25fa8de8 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/catalog-info.yaml @@ -0,0 +1,25 @@ +# https://backstage.io/docs/features/software-catalog/descriptor-format#kind-component +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: red-hat-developer-hub-orchestrator-backend + title: '@red-hat-developer-hub/backstage-plugin-orchestrator-backend' + description: Orchestrator Backend Plugin for Backstage + annotations: + backstage.io/source-location: url:https://github.com/redhat-developer/rhdh-plugins/tree/main/workspaces/orchestrator/plugins/orchestrator-backend + backstage.io/view-url: https://github.com/redhat-developer/rhdh-plugins/blob/main/workspaces/orchestrator/plugins/orchestrator-backend/catalog-info.yaml + backstage.io/edit-url: https://github.com/redhat-developer/rhdh-plugins/edit/main/workspaces/orchestrator/plugins/orchestrator-backend/catalog-info.yaml + github.com/project-slug: red-hat-developer-hub/backstage-plugins + github.com/team-slug: red-hat-developer-hub/orchestrator-codeowners + sonarqube.org/project-key: red_hat_developer_hub_plugins + links: + - url: https://github.com/redhat-developer/rhdh-plugins/tree/main/workspaces/orchestrator/plugins/orchestrator-backend + title: GitHub Source + icon: source + type: source +spec: + type: backstage-backend-plugin + lifecycle: production + owner: orchestrator-team + system: rhdh + subcomponentOf: red-hat-developer-hub-orchestrator diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/dev/index.ts b/workspaces/orchestrator/plugins/orchestrator-backend/dev/index.ts new file mode 100644 index 00000000..ba4666a0 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/dev/index.ts @@ -0,0 +1,24 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { createBackend } from '@backstage/backend-defaults'; + +import { orchestratorPlugin } from '../src/plugin'; + +const backend = createBackend(); + +backend.add(orchestratorPlugin); + +backend.start(); diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/package.json b/workspaces/orchestrator/plugins/orchestrator-backend/package.json new file mode 100644 index 00000000..1051d047 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/package.json @@ -0,0 +1,112 @@ +{ + "name": "@red-hat-developer-hub/backstage-plugin-orchestrator-backend", + "version": "4.1.1", + "license": "Apache-2.0", + "main": "src/index.ts", + "types": "src/index.ts", + "publishConfig": { + "access": "public" + }, + "backstage": { + "role": "backend-plugin", + "supported-versions": "1.32.5", + "pluginId": "orchestrator", + "pluginPackages": [ + "@red-hat-developer-hub/backstage-plugin-orchestrator", + "@red-hat-developer-hub/backstage-plugin-orchestrator-backend", + "@red-hat-developer-hub/backstage-plugin-orchestrator-common" + ] + }, + "exports": { + ".": "./src/index.ts", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "package.json": [ + "package.json" + ] + } + }, + "homepage": "https://red.ht/rhdh", + "repository": { + "type": "git", + "url": "https://github.com/redhat-developer/rhdh-plugins", + "directory": "workspaces/orchestrator/plugins/orchestrator-backend" + }, + "bugs": "https://github.com/redhat-developer/rhdh-plugins/issues", + "keywords": [ + "support:tech-preview", + "lifecycle:active", + "backstage", + "plugin", + "orchestrator", + "workflows" + ], + "files": [ + "app-config.yaml", + "dist", + "dist-dynamic/*.*", + "dist-dynamic/dist/**", + "static" + ], + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "tsc": "tsc", + "prettier:check": "prettier --ignore-unknown --check .", + "prettier:fix": "prettier --ignore-unknown --write .", + "lint:check": "backstage-cli package lint", + "lint:fix": "backstage-cli package lint --fix", + "test": "backstage-cli package test --passWithNoTests --coverage", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "dependencies": { + "@backstage/backend-common": "^0.25.0", + "@backstage/backend-defaults": "^0.5.2", + "@backstage/backend-plugin-api": "^1.0.1", + "@backstage/backend-tasks": "^0.6.1", + "@backstage/catalog-client": "^1.7.1", + "@backstage/errors": "^1.2.4", + "@backstage/integration": "^1.15.1", + "@backstage/plugin-catalog-node": "^1.13.1", + "@backstage/plugin-permission-common": "^0.8.1", + "@backstage/plugin-permission-node": "^0.8.4", + "@backstage/plugin-scaffolder-backend": "^1.26.2", + "@backstage/plugin-scaffolder-node": "^0.5.0", + "@red-hat-developer-hub/backstage-plugin-orchestrator-common": "workspace:^", + "@urql/core": "^4.1.4", + "ajv-formats": "^2.1.1", + "cloudevents": "^8.0.0", + "express": "^4.18.2", + "express-promise-router": "^4.1.1", + "fs-extra": "^10.1.0", + "isomorphic-git": "^1.23.0", + "json-schema": "^0.4.0", + "moment": "^2.29.4", + "openapi-backend": "^5.10.5", + "yn": "^5.0.0" + }, + "devDependencies": { + "@backstage-community/plugin-rbac-common": "^1.12.1", + "@backstage/backend-test-utils": "1.0.2", + "@backstage/cli": "0.28.2", + "@janus-idp/backstage-plugin-audit-log-node": "^1.7.1", + "@types/express": "4.17.21", + "@types/fs-extra": "11.0.4", + "@types/json-schema": "7.0.15", + "prettier": "3.3.3" + }, + "peerDependencies": { + "@backstage-community/plugin-rbac-common": "^1.12.1", + "@janus-idp/backstage-plugin-audit-log-node": "^1.7.1" + }, + "maintainers": [ + "@mlibra", + "@batzionb", + "@gciavarrini" + ], + "author": "The Backstage Community" +} diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/report.api.md b/workspaces/orchestrator/plugins/orchestrator-backend/report.api.md new file mode 100644 index 00000000..d7788cf2 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/report.api.md @@ -0,0 +1,15 @@ +## API Report File for "@red-hat-developer-hub/backstage-plugin-orchestrator-backend" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { BackendFeature } from '@backstage/backend-plugin-api'; + +// @public +const orchestratorPlugin: BackendFeature; +export default orchestratorPlugin; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/src/OrchestratorPlugin.ts b/workspaces/orchestrator/plugins/orchestrator-backend/src/OrchestratorPlugin.ts new file mode 100644 index 00000000..1f2e1540 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/src/OrchestratorPlugin.ts @@ -0,0 +1,75 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { + coreServices, + createBackendPlugin, +} from '@backstage/backend-plugin-api'; +import { catalogServiceRef } from '@backstage/plugin-catalog-node/alpha'; + +import { createRouter } from './routerWrapper'; + +export const orchestratorPlugin = createBackendPlugin({ + pluginId: 'orchestrator', + register(env) { + env.registerInit({ + deps: { + logger: coreServices.logger, + config: coreServices.rootConfig, + discovery: coreServices.discovery, + httpRouter: coreServices.httpRouter, + urlReader: coreServices.urlReader, + scheduler: coreServices.scheduler, + permissions: coreServices.permissions, + httpAuth: coreServices.httpAuth, + auth: coreServices.auth, + catalogApi: catalogServiceRef, + }, + async init({ + logger, + config, + discovery, + httpRouter, + catalogApi, + urlReader, + scheduler, + permissions, + httpAuth, + auth, + }) { + const router = await createRouter({ + config: config, + logger, + discovery: discovery, + catalogApi: catalogApi, + urlReader: urlReader, + scheduler: scheduler, + permissions: permissions, + httpAuth: httpAuth, + auth: auth, + }); + httpRouter.use(router); + httpRouter.addAuthPolicy({ + path: '/static/generated/envelope', + allow: 'unauthenticated', + }); + httpRouter.addAuthPolicy({ + path: '/health', + allow: 'unauthenticated', + }); + }, + }); + }, +}); diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/errorBuilder.ts b/workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/errorBuilder.ts new file mode 100644 index 00000000..fd48657d --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/errorBuilder.ts @@ -0,0 +1,49 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export const NO_DATA_INDEX_URL = 'NO_DATA_INDEX_URL'; +export const NO_BACKEND_EXEC_CTX = 'NO_BACKEND_EXEC_CTX'; +export const NO_CLIENT_PROVIDED = 'NO_CLIENT_PROVIDED'; +export const NO_LOGGER = 'NO_LOGGER'; +export const SWF_BACKEND_NOT_INITED = 'SWF_BACKEND_NOT_INITED'; + +export class ErrorBuilder { + public static NewBackendError(name: string, message: string): Error { + const e = new Error(message); + e.name = name; + return e; + } + + public static GET_NO_DATA_INDEX_URL_ERR(): Error { + return this.NewBackendError( + NO_DATA_INDEX_URL, + 'No data index url specified or found', + ); + } + + public static GET_NO_CLIENT_PROVIDED_ERR(): Error { + return this.NewBackendError( + NO_CLIENT_PROVIDED, + 'No or null graphql client', + ); + } + + public static GET_SWF_BACKEND_NOT_INITED(): Error { + return this.NewBackendError( + SWF_BACKEND_NOT_INITED, + 'The SonataFlow backend is not initialized, call initialize() method before trying to get the workflows.', + ); + } +} diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/filterBuilder.ts b/workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/filterBuilder.ts new file mode 100644 index 00000000..7d94e1a8 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/filterBuilder.ts @@ -0,0 +1,292 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { + FieldFilter, + FieldFilterOperatorEnum, + Filter, + IntrospectionField, + LogicalFilter, + ProcessInstanceStatusDTO, + TypeName, +} from '@red-hat-developer-hub/backstage-plugin-orchestrator-common'; + +import { getProcessInstanceStateFromStatusDTOString } from '../service/api/mapping/V2Mappings'; + +type ProcessType = 'ProcessDefinition' | 'ProcessInstance'; + +function isLogicalFilter(filter: Filter): filter is LogicalFilter { + return (filter as LogicalFilter).filters !== undefined; +} + +function handleLogicalFilter( + introspection: IntrospectionField[], + type: ProcessType, + filter: LogicalFilter, +): string { + if (!filter.operator) return ''; + + const subClauses = filter.filters.map(f => + buildFilterCondition(introspection, type, f), + ); + + return `${filter.operator.toLowerCase()}: {${subClauses.join(', ')}}`; +} + +function handleBetweenOperator(filter: FieldFilter): string { + if (!Array.isArray(filter.value) || filter.value.length !== 2) { + throw new Error('Between operator requires an array of two elements'); + } + return `${filter.field}: {${getGraphQLOperator( + FieldFilterOperatorEnum.Between, + )}: {from: "${filter.value[0]}", to: "${filter.value[1]}"}}`; +} + +function handleIsNullOperator(filter: FieldFilter): string { + return `${filter.field}: {${getGraphQLOperator( + FieldFilterOperatorEnum.IsNull, + )}: ${convertToBoolean(filter.value)}}`; +} + +function isEnumFilter( + fieldName: string, + type: 'ProcessDefinition' | 'ProcessInstance', +): boolean { + if (type === 'ProcessInstance') { + if (fieldName === 'state') { + return true; + } + } + return false; +} + +function convertEnumValue( + fieldName: string, + fieldValue: string, + type: 'ProcessDefinition' | 'ProcessInstance', +): string { + if (type === 'ProcessInstance') { + if (fieldName === 'state') { + const state = (ProcessInstanceStatusDTO as any)[ + fieldValue as keyof typeof ProcessInstanceStatusDTO + ]; + + if (!state) { + throw new Error( + `status ${fieldValue} is not a valid value of ProcessInstanceStatusDTO`, + ); + } + return getProcessInstanceStateFromStatusDTOString(state).valueOf(); + } + } + throw new Error( + `Unsupported enum ${fieldName}: can't convert value ${fieldValue}`, + ); +} + +function isValidEnumOperator(operator: FieldFilterOperatorEnum): boolean { + return ( + operator === FieldFilterOperatorEnum.In || + operator === FieldFilterOperatorEnum.Eq + ); +} + +function handleBinaryOperator( + binaryFilter: FieldFilter, + fieldDef: IntrospectionField, + type: 'ProcessDefinition' | 'ProcessInstance', +): string { + if (isEnumFilter(binaryFilter.field, type)) { + if (!isValidEnumOperator(binaryFilter.operator)) { + throw new Error( + `Invalid operator ${binaryFilter.operator} for enum field ${binaryFilter.field} filter`, + ); + } + binaryFilter.value = convertEnumValue( + binaryFilter.field, + binaryFilter.value, + type, + ); + } + const formattedValue = Array.isArray(binaryFilter.value) + ? `[${binaryFilter.value + .map(v => formatValue(binaryFilter.field, v, fieldDef, type)) + .join(', ')}]` + : formatValue(binaryFilter.field, binaryFilter.value, fieldDef, type); + return `${binaryFilter.field}: {${getGraphQLOperator( + binaryFilter.operator, + )}: ${formattedValue}}`; +} + +export function buildFilterCondition( + introspection: IntrospectionField[], + type: ProcessType, + filters?: Filter, +): string { + if (!filters) { + return ''; + } + + if (isLogicalFilter(filters)) { + return handleLogicalFilter(introspection, type, filters); + } + + if (!isOperatorSupported(filters.operator)) { + throw new Error(`Unsopported operator ${filters.operator}`); + } + + const fieldDef = introspection.find(f => f.name === filters.field); + if (!fieldDef) { + throw new Error(`Can't find field "${filters.field}" definition`); + } + + if (!isOperatorAllowedForField(filters.operator, fieldDef)) { + throw new Error(`Unsupported field type ${fieldDef.type.name}`); + } + + switch (filters.operator) { + case FieldFilterOperatorEnum.IsNull: + return handleIsNullOperator(filters); + case FieldFilterOperatorEnum.Between: + return handleBetweenOperator(filters); + case FieldFilterOperatorEnum.Eq: + case FieldFilterOperatorEnum.Like: + case FieldFilterOperatorEnum.In: + case FieldFilterOperatorEnum.Gt: + case FieldFilterOperatorEnum.Gte: + case FieldFilterOperatorEnum.Lt: + case FieldFilterOperatorEnum.Lte: + return handleBinaryOperator(filters, fieldDef, type); + + default: + throw new Error(`Can't build filter condition`); + } +} + +function isOperatorSupported(operator: FieldFilterOperatorEnum): boolean { + return ( + operator === FieldFilterOperatorEnum.Eq || + operator === FieldFilterOperatorEnum.Like || + operator === FieldFilterOperatorEnum.In || + operator === FieldFilterOperatorEnum.IsNull || + operator === FieldFilterOperatorEnum.Gt || + operator === FieldFilterOperatorEnum.Gte || + operator === FieldFilterOperatorEnum.Lt || + operator === FieldFilterOperatorEnum.Lte || + operator === FieldFilterOperatorEnum.Between + ); +} + +function isFieldFilterSupported(fieldDef: IntrospectionField): boolean { + return fieldDef?.type.name === TypeName.String; +} + +function isOperatorAllowedForField( + operator: FieldFilterOperatorEnum, + fieldDef: IntrospectionField, +): boolean { + const allowedOperators: Record = { + [TypeName.String]: [ + FieldFilterOperatorEnum.In, + FieldFilterOperatorEnum.Like, + FieldFilterOperatorEnum.IsNull, + FieldFilterOperatorEnum.Eq, + ], + [TypeName.Id]: [ + FieldFilterOperatorEnum.In, + FieldFilterOperatorEnum.IsNull, + FieldFilterOperatorEnum.Eq, + ], + [TypeName.Date]: [ + FieldFilterOperatorEnum.IsNull, + FieldFilterOperatorEnum.Eq, + FieldFilterOperatorEnum.Gt, + FieldFilterOperatorEnum.Gte, + FieldFilterOperatorEnum.Lt, + FieldFilterOperatorEnum.Lte, + FieldFilterOperatorEnum.Between, + ], + [TypeName.StringArray]: [], + }; + const allowedForType = allowedOperators[fieldDef.type.name]; + return allowedForType ? allowedForType.includes(operator) : false; +} + +function convertToBoolean(value: any): boolean { + if (typeof value === 'boolean') { + return value; + } + if (typeof value === 'string') { + return value.toLowerCase() === 'true'; + } + if (typeof value === 'number') { + return value === 1; + } + return false; // Default to false for unsupported types +} + +function formatValue( + fieldName: string, + fieldValue: any, + fieldDef: IntrospectionField, + type: ProcessType, +): string { + if (!isFieldFilterSupported) { + throw new Error(`Unsupported field type ${fieldDef.type.name}`); + } + + if (isEnumFilter(fieldName, type)) { + return `${fieldValue}`; + } + if ( + fieldDef.type.name === TypeName.String || + fieldDef.type.name === TypeName.Id || + fieldDef.type.name === TypeName.Date + ) { + return `"${fieldValue}"`; + } + throw new Error( + `Failed to format value for ${fieldName} ${fieldValue} with type ${fieldDef.type.name}`, + ); +} + +function getGraphQLOperator(operator: FieldFilterOperatorEnum): string { + switch (operator) { + case 'EQ': + return 'equal'; + case 'LIKE': + return 'like'; + case 'IN': + return 'in'; + case 'IS_NULL': + return 'isNull'; + case 'GT': + return 'greaterThan'; + case 'GTE': + return 'greaterThanEqual'; + case 'LT': + return 'lessThan'; + case 'LTE': + return 'lessThanEqual'; + // case 'CONTAINS': + // return "contains" + // case 'CONTAINS_ALL': + // case 'CONTAINS_ANY': + case 'BETWEEN': + return 'between'; + default: + throw new Error(`Operation "${operator}" not supported`); + } +} diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/filterBuilders.test.ts b/workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/filterBuilders.test.ts new file mode 100644 index 00000000..8b074f65 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/filterBuilders.test.ts @@ -0,0 +1,568 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { + FieldFilterOperatorEnum, + Filter, + IntrospectionField, + ProcessInstanceState, + ProcessInstanceStatusDTO, + TypeKind, + TypeName, +} from '@red-hat-developer-hub/backstage-plugin-orchestrator-common'; + +import { buildFilterCondition } from './filterBuilder'; + +describe('column filters', () => { + const createIntrospectionField = ( + name: string, + type: TypeName, + ): IntrospectionField => ({ + name, + type: { + name: type, + kind: TypeKind.InputObject, + ofType: null, + }, + }); + + const createFieldFilter = ( + field: string, + operator: FieldFilterOperatorEnum, + value: any, + ): Filter => ({ + field, + operator, + value, + }); + + type FilterTestCase = { + name: string; + introspectionFields: IntrospectionField[]; + filter: Filter | undefined; + expectedResult: string; + }; + describe('empty filter testcases', () => { + const emptyFilterTestCases: FilterTestCase[] = [ + { + name: 'returns empty string when filters are null or undefined', + introspectionFields: [], + filter: undefined, + expectedResult: '', + }, + ]; + emptyFilterTestCases.forEach( + ({ name, introspectionFields, filter, expectedResult }) => { + it(`${name}`, () => { + const result = buildFilterCondition( + introspectionFields, + 'ProcessInstance', + filter, + ); + expect(result).toBe(expectedResult); + }); + }, + ); + }); + describe('stringArgument testcases', () => { + const stringTestCases: FilterTestCase[] = [ + { + name: 'returns correct filter for single string field with equal operator', + introspectionFields: [ + createIntrospectionField('name', TypeName.String), + ], + filter: createFieldFilter( + 'name', + FieldFilterOperatorEnum.Eq, + 'Hello World Workflow', + ), + expectedResult: 'name: {equal: "Hello World Workflow"}', + }, + { + name: 'returns correct filter for single string field with like operator', + introspectionFields: [ + createIntrospectionField('name', TypeName.String), + ], + filter: createFieldFilter( + 'name', + FieldFilterOperatorEnum.Like, + 'Hello%', + ), + expectedResult: 'name: {like: "Hello%"}', + }, + { + name: 'returns correct filter for string field with isNull operator (true)', + introspectionFields: [ + createIntrospectionField('name', TypeName.String), + ], + filter: createFieldFilter('name', FieldFilterOperatorEnum.IsNull, true), + expectedResult: 'name: {isNull: true}', + }, + { + name: 'returns correct filter for string field with isNull operator (false)', + introspectionFields: [ + createIntrospectionField('name', TypeName.String), + ], + filter: createFieldFilter( + 'name', + FieldFilterOperatorEnum.IsNull, + false, + ), + expectedResult: 'name: {isNull: false}', + }, + { + name: 'returns correct filter for string field with isNull operator ("true" as string)', + introspectionFields: [ + createIntrospectionField('name', TypeName.String), + ], + filter: createFieldFilter( + 'name', + FieldFilterOperatorEnum.IsNull, + 'True', + ), + expectedResult: 'name: {isNull: true}', + }, + { + name: 'returns correct filter for string field with isNull operator ("false" as string)', + introspectionFields: [ + createIntrospectionField('name', TypeName.String), + ], + filter: createFieldFilter( + 'name', + FieldFilterOperatorEnum.IsNull, + 'FALSE', + ), + expectedResult: 'name: {isNull: false}', + }, + { + name: 'returns correct filter for string field with in operator (single value)', + introspectionFields: [ + createIntrospectionField('name', TypeName.String), + ], + filter: createFieldFilter('name', FieldFilterOperatorEnum.In, [ + 'Test String', + ]), + expectedResult: 'name: {in: ["Test String"]}', + }, + { + name: 'returns correct filter for string field with in operator (multiple values)', + introspectionFields: [ + createIntrospectionField('name', TypeName.String), + ], + filter: createFieldFilter('name', FieldFilterOperatorEnum.In, [ + 'Test String 1', + 'Test String 2', + 'Test String 3', + ]), + expectedResult: + 'name: {in: ["Test String 1", "Test String 2", "Test String 3"]}', + }, + { + name: 'returns correct OR filter for two string fields with equal operator', + introspectionFields: [ + createIntrospectionField('name', TypeName.String), + createIntrospectionField('processName', TypeName.String), + ], + filter: { + operator: 'OR', + filters: [ + createFieldFilter( + 'name', + FieldFilterOperatorEnum.Eq, + 'Hello World Workflow', + ), + createFieldFilter( + 'processName', + FieldFilterOperatorEnum.Eq, + 'Greeting workflow', + ), + ], + }, + expectedResult: + 'or: {name: {equal: "Hello World Workflow"}, processName: {equal: "Greeting workflow"}}', + }, + { + name: 'returns correct filter for string field with like and isNull operators', + introspectionFields: [ + createIntrospectionField('description', TypeName.String), + ], + filter: { + operator: 'OR', + filters: [ + createFieldFilter( + 'description', + FieldFilterOperatorEnum.Like, + '%Test%', + ), + createFieldFilter( + 'description', + FieldFilterOperatorEnum.IsNull, + true, + ), + ], + }, + expectedResult: + 'or: {description: {like: "%Test%"}, description: {isNull: true}}', + }, + { + name: 'returns correct filter for string field with in, like, equal, and isNull operators', + introspectionFields: [ + createIntrospectionField('name', TypeName.String), + ], + filter: { + operator: 'OR', + filters: [ + createFieldFilter('name', FieldFilterOperatorEnum.In, [ + 'Test String 1', + 'Test String 2', + ]), + createFieldFilter('name', FieldFilterOperatorEnum.Like, '%Test%'), + createFieldFilter( + 'name', + FieldFilterOperatorEnum.Eq, + 'Exact Match', + ), + createFieldFilter('name', FieldFilterOperatorEnum.IsNull, false), + ], + }, + expectedResult: + 'or: {name: {in: ["Test String 1", "Test String 2"]}, name: {like: "%Test%"}, name: {equal: "Exact Match"}, name: {isNull: false}}', + }, + { + name: 'returns correct filter for string field with in, like, equal, and isNull operators', + introspectionFields: [ + createIntrospectionField('name', TypeName.String), + ], + filter: { + operator: 'AND', + filters: [ + createFieldFilter('name', FieldFilterOperatorEnum.In, [ + 'Test String 1', + 'Test String 2', + ]), + createFieldFilter('name', FieldFilterOperatorEnum.Like, '%Test%'), + createFieldFilter( + 'name', + FieldFilterOperatorEnum.Eq, + 'Exact Match', + ), + createFieldFilter('name', FieldFilterOperatorEnum.IsNull, false), + ], + }, + expectedResult: + 'and: {name: {in: ["Test String 1", "Test String 2"]}, name: {like: "%Test%"}, name: {equal: "Exact Match"}, name: {isNull: false}}', + }, + ]; + stringTestCases.forEach( + ({ name, introspectionFields, filter, expectedResult }) => { + it(`${name}`, () => { + const result = buildFilterCondition( + introspectionFields, + 'ProcessInstance', + filter, + ); + expect(result).toBe(expectedResult); + }); + }, + ); + }); + describe('idArgument testcases', () => { + const idTestCases: FilterTestCase[] = [ + { + name: 'returns correct filter for single id field with equal operator', + introspectionFields: [createIntrospectionField('id', TypeName.Id)], + filter: createFieldFilter('id', FieldFilterOperatorEnum.Eq, 'idA'), + expectedResult: 'id: {equal: "idA"}', + }, + { + name: 'returns correct filter for single id field with isNull operator (false as boolean)', + introspectionFields: [createIntrospectionField('id', TypeName.Id)], + filter: createFieldFilter('id', FieldFilterOperatorEnum.IsNull, false), + expectedResult: 'id: {isNull: false}', + }, + { + name: 'returns correct filter for single id field with isNull operator (false as string)', + introspectionFields: [createIntrospectionField('id', TypeName.Id)], + filter: createFieldFilter( + 'id', + FieldFilterOperatorEnum.IsNull, + 'false', + ), + expectedResult: 'id: {isNull: false}', + }, + { + name: 'returns correct filter for single id field with IN operator', + introspectionFields: [createIntrospectionField('id', TypeName.Id)], + filter: createFieldFilter('id', FieldFilterOperatorEnum.In, [ + 'idA', + 'idB', + 'idC', + ]), + expectedResult: 'id: {in: ["idA", "idB", "idC"]}', + }, + { + name: 'returns correct OR filter for multiple id fields with equal, isNull, and IN operators', + introspectionFields: [ + createIntrospectionField('processId', TypeName.Id), + createIntrospectionField('id', TypeName.Id), + ], + filter: { + operator: 'OR', + filters: [ + createFieldFilter('id', FieldFilterOperatorEnum.Eq, 'idA'), + createFieldFilter( + 'processId', + FieldFilterOperatorEnum.IsNull, + 'True', + ), + createFieldFilter('id', 'IN', ['idA', 'idB', 'idC']), + ], + }, + expectedResult: + 'or: {id: {equal: "idA"}, processId: {isNull: true}, id: {in: ["idA", "idB", "idC"]}}', + }, + { + name: 'returns correct AND filter for multiple id fields with equal, isNull, and IN operators', + introspectionFields: [ + createIntrospectionField('processId', TypeName.Id), + createIntrospectionField('id', TypeName.Id), + ], + filter: { + operator: 'AND', + filters: [ + createFieldFilter('id', FieldFilterOperatorEnum.Eq, 'idA'), + createFieldFilter( + 'processId', + FieldFilterOperatorEnum.IsNull, + 'True', + ), + createFieldFilter('id', 'IN', ['idA', 'idB', 'idC']), + ], + }, + expectedResult: + 'and: {id: {equal: "idA"}, processId: {isNull: true}, id: {in: ["idA", "idB", "idC"]}}', + }, + ]; + + idTestCases.forEach( + ({ name, introspectionFields, filter, expectedResult }) => { + it(`${name}`, () => { + const result = buildFilterCondition( + introspectionFields, + 'ProcessInstance', + filter, + ); + expect(result).toBe(expectedResult); + }); + }, + ); + }); + describe('dateArgument testcases', () => { + const testDate1 = '2024-10-10T09:54:40.759Z'; + const testDate2 = '2025-10-10T09:54:40.759Z'; + + const idTestCases: FilterTestCase[] = [ + { + name: 'returns correct filter for single date field with equal operator', + introspectionFields: [createIntrospectionField('start', TypeName.Date)], + filter: createFieldFilter( + 'start', + FieldFilterOperatorEnum.Eq, + testDate1, + ), + expectedResult: `start: {equal: "${testDate1}"}`, + }, + { + name: 'returns correct filter for single date field with isNull operator (false as boolean)', + introspectionFields: [createIntrospectionField('start', TypeName.Date)], + filter: createFieldFilter( + 'start', + FieldFilterOperatorEnum.IsNull, + false, + ), + expectedResult: 'start: {isNull: false}', + }, + { + name: 'returns correct filter for single date field with isNull operator (false as string)', + introspectionFields: [createIntrospectionField('start', TypeName.Date)], + filter: createFieldFilter( + 'start', + FieldFilterOperatorEnum.IsNull, + 'false', + ), + expectedResult: 'start: {isNull: false}', + }, + { + name: 'returns correct filter for single date field with GT operator', + introspectionFields: [createIntrospectionField('start', TypeName.Date)], + filter: createFieldFilter( + 'start', + FieldFilterOperatorEnum.Gt, + testDate1, + ), + expectedResult: `start: {greaterThan: "${testDate1}"}`, + }, + { + name: 'returns correct filter for single date field with GTE operator', + introspectionFields: [createIntrospectionField('start', TypeName.Date)], + filter: createFieldFilter( + 'start', + FieldFilterOperatorEnum.Gte, + testDate1, + ), + expectedResult: `start: {greaterThanEqual: "${testDate1}"}`, + }, + { + name: 'returns correct filter for single date field with LT operator', + introspectionFields: [createIntrospectionField('start', TypeName.Date)], + filter: createFieldFilter( + 'start', + FieldFilterOperatorEnum.Lt, + testDate1, + ), + expectedResult: `start: {lessThan: "${testDate1}"}`, + }, + { + name: 'returns correct filter for single date field with LTE operator', + introspectionFields: [createIntrospectionField('start', TypeName.Date)], + filter: createFieldFilter( + 'start', + FieldFilterOperatorEnum.Lte, + testDate1, + ), + expectedResult: `start: {lessThanEqual: "${testDate1}"}`, + }, + { + name: 'returns correct filter for single date field with BETWEEN operator', + introspectionFields: [createIntrospectionField('start', TypeName.Date)], + filter: createFieldFilter('start', FieldFilterOperatorEnum.Between, [ + testDate1, + testDate2, + ]), + expectedResult: `start: {between: {from: "${testDate1}", to: "${testDate2}"}}`, + }, + { + name: 'returns correct OR filter for multiple id fields with equal, isNull, and GT operators', + introspectionFields: [ + createIntrospectionField('start', TypeName.Date), + createIntrospectionField('end', TypeName.Date), + ], + filter: { + operator: 'OR', + filters: [ + createFieldFilter('start', FieldFilterOperatorEnum.Eq, testDate1), + createFieldFilter('end', FieldFilterOperatorEnum.IsNull, 'False'), + createFieldFilter('end', FieldFilterOperatorEnum.Gt, testDate1), + ], + }, + expectedResult: `or: {start: {equal: "${testDate1}"}, end: {isNull: false}, end: {greaterThan: "${testDate1}"}}`, + }, + { + name: 'returns correct OR filter for multiple id fields with equal, isNull, and GTE operators', + introspectionFields: [ + createIntrospectionField('start', TypeName.Date), + createIntrospectionField('end', TypeName.Date), + ], + filter: { + operator: 'OR', + filters: [ + createFieldFilter('start', FieldFilterOperatorEnum.Eq, testDate1), + createFieldFilter('end', FieldFilterOperatorEnum.IsNull, 'False'), + createFieldFilter('end', FieldFilterOperatorEnum.Gte, testDate1), + ], + }, + expectedResult: `or: {start: {equal: "${testDate1}"}, end: {isNull: false}, end: {greaterThanEqual: "${testDate1}"}}`, + }, + { + name: 'returns correct AND filter for multiple id fields with equal, isNull, and LTE operators', + introspectionFields: [ + createIntrospectionField('start', TypeName.Date), + createIntrospectionField('end', TypeName.Date), + ], + filter: { + operator: 'AND', + filters: [ + createFieldFilter('start', FieldFilterOperatorEnum.Eq, testDate1), + createFieldFilter('end', FieldFilterOperatorEnum.IsNull, 'False'), + createFieldFilter('end', FieldFilterOperatorEnum.Lte, testDate1), + ], + }, + expectedResult: `and: {start: {equal: "${testDate1}"}, end: {isNull: false}, end: {lessThanEqual: "${testDate1}"}}`, + }, + { + name: 'returns correct AND filter for multiple id fields with equal, isNull, LTE, and between operators', + introspectionFields: [ + createIntrospectionField('start', TypeName.Date), + createIntrospectionField('end', TypeName.Date), + ], + filter: { + operator: 'AND', + filters: [ + createFieldFilter('start', FieldFilterOperatorEnum.Eq, testDate1), + createFieldFilter('end', FieldFilterOperatorEnum.IsNull, 'False'), + createFieldFilter('end', FieldFilterOperatorEnum.Lte, testDate1), + createFieldFilter('start', FieldFilterOperatorEnum.Between, [ + testDate1, + testDate2, + ]), + ], + }, + expectedResult: `and: {start: {equal: "${testDate1}"}, end: {isNull: false}, end: {lessThanEqual: "${testDate1}"}, start: {between: {from: "${testDate1}", to: "${testDate2}"}}}`, + }, + ]; + + idTestCases.forEach( + ({ name, introspectionFields, filter, expectedResult }) => { + it(`${name}`, () => { + const result = buildFilterCondition( + introspectionFields, + 'ProcessInstance', + filter, + ); + expect(result).toBe(expectedResult); + }); + }, + ); + }); + describe('enumArgument testcases', () => { + const idTestCases: FilterTestCase[] = [ + { + name: 'returns correct filter for state enum field with equal operator', + introspectionFields: [ + createIntrospectionField('state', TypeName.String), + ], + filter: createFieldFilter( + 'state', + FieldFilterOperatorEnum.Eq, + ProcessInstanceStatusDTO.Completed, + ), + expectedResult: `state: {equal: ${ProcessInstanceState.Completed}}`, + }, + ]; + + idTestCases.forEach( + ({ name, introspectionFields, filter, expectedResult }) => { + it(`${name}`, () => { + const result = buildFilterCondition( + introspectionFields, + 'ProcessInstance', + filter, + ); + expect(result).toBe(expectedResult); + }); + }, + ); + }); +}); diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/queryBuilder.test.ts b/workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/queryBuilder.test.ts new file mode 100644 index 00000000..ab77d65a --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/queryBuilder.test.ts @@ -0,0 +1,103 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { Pagination } from '../types/pagination'; +import { buildGraphQlQuery } from './queryBuilder'; + +describe('buildGraphQlQuery', () => { + const defaultTestParams = { + queryBody: 'id status', + type: 'ProcessInstances' as + | 'ProcessDefinitions' + | 'ProcessInstances' + | 'Jobs', + pagination: { + offset: 0, + limit: 10, + order: 'asc', + sortField: 'name', + } as Pagination | undefined, + whereClause: 'version: "1.0"', + }; + + const getPaginationString = (pagination: Pagination | undefined) => { + const paginationOrder = pagination?.order + ? pagination.order.toUpperCase() + : 'ASC'; + if (pagination) { + return `orderBy: {${pagination.sortField}: ${paginationOrder}}, pagination: {limit: ${pagination.limit}, offset: ${pagination.offset}})`; + } + return undefined; + }; + + type TestCase = { + name: string; + params: typeof defaultTestParams; + expectedResult: string; + }; + + const testCases: TestCase[] = [ + { + name: 'should build a basic query without where clause and pagination', + params: { + type: defaultTestParams.type, + queryBody: defaultTestParams.queryBody, + whereClause: '', + pagination: {}, + }, + expectedResult: `{${defaultTestParams.type} {${defaultTestParams.queryBody} } }`, + }, + { + name: 'should build a query with a where clause', + params: { + type: defaultTestParams.type, + queryBody: defaultTestParams.queryBody, + whereClause: defaultTestParams.whereClause, + pagination: {}, + }, + expectedResult: `{${defaultTestParams.type} (where: {${defaultTestParams.whereClause}}) {${defaultTestParams.queryBody} } }`, + }, + { + name: 'should build a query with pagination', + params: { + type: defaultTestParams.type, + queryBody: defaultTestParams.queryBody, + whereClause: '', + pagination: defaultTestParams.pagination, + }, + expectedResult: `{${defaultTestParams.type} (${getPaginationString( + defaultTestParams.pagination, + )} {${defaultTestParams.queryBody} } }`, + }, + { + name: 'should build a query with both where clause and pagination', + params: { + ...defaultTestParams, + }, + expectedResult: `{${defaultTestParams.type} (where: {${ + defaultTestParams.whereClause + }}, ${getPaginationString(defaultTestParams.pagination)} {${ + defaultTestParams.queryBody + } } }`, + }, + ]; + + testCases.forEach(({ name, params, expectedResult }) => { + it(`${name}`, () => { + const result = buildGraphQlQuery(params); + expect(result).toBe(expectedResult); + }); + }); +}); diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/queryBuilder.ts b/workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/queryBuilder.ts new file mode 100644 index 00000000..e33d20db --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/queryBuilder.ts @@ -0,0 +1,69 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { Pagination } from '../types/pagination'; + +export function buildGraphQlQuery(args: { + type: 'ProcessDefinitions' | 'ProcessInstances' | 'Jobs'; + queryBody: string; + whereClause?: string; + pagination?: Pagination; +}): string { + let query = `{${args.type}`; + + const whereClause = buildWhereClause(args.whereClause); + const paginationClause = buildPaginationClause(args.pagination); + + if (whereClause || paginationClause) { + query += ' ('; + query += [whereClause, paginationClause].filter(Boolean).join(', '); + query += ') '; + } + + query += ` {${args.queryBody} } }`; + + return query.replace(/\s+/g, ' ').trim(); +} + +function buildWhereClause(whereClause?: string): string { + return whereClause ? `where: {${whereClause}}` : ''; +} + +function buildPaginationClause(pagination?: Pagination): string { + if (!pagination) return ''; + + const parts = []; + + if (pagination.sortField !== undefined) { + parts.push( + `orderBy: {${pagination.sortField}: ${ + pagination.order !== undefined ? pagination.order?.toUpperCase() : 'ASC' + }}`, + ); + } + + const paginationParts = []; + if (pagination.limit !== undefined) { + paginationParts.push(`limit: ${pagination.limit}`); + } + if (pagination.offset !== undefined) { + paginationParts.push(`offset: ${pagination.offset}`); + } + if (paginationParts.length) { + parts.push(`pagination: {${paginationParts.join(', ')}}`); + } + + return parts.join(', '); +} diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/src/index.ts b/workspaces/orchestrator/plugins/orchestrator-backend/src/index.ts new file mode 100644 index 00000000..70217b20 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/src/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { orchestratorPlugin as default } from './plugin'; diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/src/plugin.ts b/workspaces/orchestrator/plugins/orchestrator-backend/src/plugin.ts new file mode 100644 index 00000000..0e1c2314 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/src/plugin.ts @@ -0,0 +1,63 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { + coreServices, + createBackendPlugin, +} from '@backstage/backend-plugin-api'; +import { catalogServiceRef } from '@backstage/plugin-catalog-node/alpha'; + +import { createRouter } from './routerWrapper'; + +/** + * @public + * Orchestrator Backend Plugin + */ +export const orchestratorPlugin = createBackendPlugin({ + pluginId: 'orchestrator', + register(env) { + env.registerInit({ + deps: { + logger: coreServices.logger, + config: coreServices.rootConfig, + discovery: coreServices.discovery, + catalogApi: catalogServiceRef, + urlReader: coreServices.urlReader, + permissions: coreServices.permissions, + scheduler: coreServices.scheduler, + auth: coreServices.auth, + httpAuth: coreServices.httpAuth, + http: coreServices.httpRouter, + }, + async init(props) { + const { http } = props; + const router = await createRouter(props); + http.use(router); + http.addAuthPolicy({ + path: '/health', + allow: 'unauthenticated', + }); + http.addAuthPolicy({ + path: '/static', + allow: 'unauthenticated', + }); + http.addAuthPolicy({ + path: '/docs', + allow: 'unauthenticated', + }); + }, + }); + }, +}); diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/src/routerWrapper/index.ts b/workspaces/orchestrator/plugins/orchestrator-backend/src/routerWrapper/index.ts new file mode 100644 index 00000000..a98bf2e6 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/src/routerWrapper/index.ts @@ -0,0 +1,74 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import type { + AuthService, + DiscoveryService, + HttpAuthService, + LoggerService, + PermissionsService, + SchedulerService, + UrlReaderService, +} from '@backstage/backend-plugin-api'; +import type { CatalogApi } from '@backstage/catalog-client'; +import type { Config } from '@backstage/config'; + +import express from 'express'; + +import { DevModeService } from '../service/DevModeService'; +import { createBackendRouter } from '../service/router'; + +export interface RouterOptions { + config: Config; + logger: LoggerService; + discovery: DiscoveryService; + catalogApi: CatalogApi; + urlReader: UrlReaderService; + scheduler: SchedulerService; + permissions: PermissionsService; + httpAuth: HttpAuthService; + auth: AuthService; +} + +export async function createRouter( + args: RouterOptions, +): Promise { + const autoStartDevMode = + args.config.getOptionalBoolean( + 'orchestrator.sonataFlowService.autoStart', + ) ?? false; + + if (autoStartDevMode) { + const devModeService = new DevModeService(args.config, args.logger); + + const isSonataFlowUp = await devModeService.launchDevMode(); + + if (!isSonataFlowUp) { + args.logger.error('SonataFlow is not up. Check your configuration.'); + } + } + + return await createBackendRouter({ + config: args.config, + logger: args.logger, + discovery: args.discovery, + catalogApi: args.catalogApi, + urlReader: args.urlReader, + scheduler: args.scheduler, + permissions: args.permissions, + httpAuth: args.httpAuth, + auth: args.auth, + }); +} diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/src/service/DataIndexService.test.ts b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/DataIndexService.test.ts new file mode 100644 index 00000000..ffffd571 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/DataIndexService.test.ts @@ -0,0 +1,807 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { LoggerService } from '@backstage/backend-plugin-api'; + +import { Client, OperationResult } from '@urql/core'; + +import { + FieldFilter, + FieldFilterOperatorEnum, + LogicalFilter, + NodeInstance, + ProcessInstance, + TypeKind, + TypeName, + WorkflowInfo, +} from '@red-hat-developer-hub/backstage-plugin-orchestrator-common'; + +import * as buildGrahQLFilterUtils from '../helpers/filterBuilder'; +import * as buildGrahQLQueryUtils from '../helpers/queryBuilder'; +import { Pagination } from '../types/pagination'; +import { + mockProcessDefinitionArguments, + mockProcessDefinitionIntrospection, +} from './__fixtures__/mockProcessDefinitionArgumentsData'; +import { + mockProcessInstanceArguments, + mockProcessInstanceIntrospection, +} from './__fixtures__/mockProcessInstanceArgumentsData'; +import { DataIndexService } from './DataIndexService'; + +jest.mock('../helpers/queryBuilder', () => { + return { + __esModule: true, + ...jest.requireActual('../helpers/queryBuilder'), + }; +}); + +jest.mock('../helpers/filterBuilder', () => { + return { + __esModule: true, + ...jest.requireActual('../helpers/filterBuilder'), + }; +}); + +jest.mock('@urql/core', () => { + return { + Client: jest.fn().mockImplementation(() => ({ + query: jest.fn(), + })), + }; +}); + +const mockOperationResult = (data: T, error?: any): OperationResult => ({ + data, + error, + operation: {} as any, + extensions: {}, + hasNext: false, + stale: false, +}); + +const mockWfInfos: WorkflowInfo[] = [ + { + id: '9fa2a881-c932-468d-83a9-687b9f1e62a7', + nodes: [createNodeObject('A'), createNodeObject('B')], + }, +]; + +const createQueryArgs = ( + type: 'ProcessDefinitions' | 'ProcessInstances' | 'Jobs', + queryBody: string, + whereClause?: string, + pagination?: Pagination, +) => ({ + type, + queryBody, + whereClause, + pagination, +}); + +describe('initInputArgs', () => { + type MockableClient = Pick; + const createMockClient = (): jest.Mocked => ({ + query: jest.fn(), + }); + + let loggerMock: LoggerService; + let dataIndexService: DataIndexService; + let mockClient: jest.Mocked; + + beforeEach(() => { + jest.resetAllMocks(); + jest.clearAllMocks(); + // Create a new mock client for each test + mockClient = createMockClient(); + (Client as jest.MockedClass).mockImplementation( + () => mockClient as unknown as Client, + ); + + loggerMock = { + info: jest.fn(), + debug: jest.fn(), + error: jest.fn(), + warn: jest.fn(), + child: jest.fn(), + }; + mockClient.query.mockResolvedValueOnce( + mockOperationResult(mockProcessDefinitionArguments), + ); + dataIndexService = new DataIndexService('fakeUrl', loggerMock); + }); + + it('ProcessDefinition', async () => { + const processDefinitionArguments = + await dataIndexService.initInputProcessDefinitionArgs(); + + expect(mockClient.query).toHaveBeenCalledTimes(1); + expect(mockClient.query).toHaveBeenCalledWith( + dataIndexService.graphQLArgumentQuery('ProcessDefinition'), + {}, + ); + + expect(processDefinitionArguments).toBeDefined(); + expect( + processDefinitionArguments.every( + val => !['and', 'or', 'not'].includes(val.name), + ), + ).toBe(true); + expect(processDefinitionArguments).toHaveLength(3); + expect( + processDefinitionArguments.some( + obj => + obj.name === 'id' && + obj.type.kind === TypeKind.InputObject && + obj.type.name === TypeName.String, + ), + ).toBe(true); + expect( + processDefinitionArguments.some( + obj => + obj.name === 'name' && + obj.type.kind === TypeKind.InputObject && + obj.type.name === TypeName.String, + ), + ).toBe(true); + expect( + processDefinitionArguments.some( + obj => + obj.name === 'version' && + obj.type.kind === TypeKind.InputObject && + obj.type.name === TypeName.String, + ), + ).toBe(true); + }); +}); + +describe('fetchWorkflowInfos', () => { + let loggerMock: LoggerService; + let buildFilterConditionSpy: any; + let buildGraphQlQuerySpy: jest.SpyInstance; + let dataIndexService: DataIndexService; + let mockClient: jest.Mocked; + + const definitionIds = ['id1', 'id2']; + const queryBody = 'id, name, version, type, endpoint, serviceUrl, source'; + const pagination = { limit: 10, offset: 0, order: 'ASC', sortField: 'name' }; + + const filterString = + 'or: {name: {equal: "Hello World Workflow"}, id: {equal: "yamlgreet"}}'; + + const helloWorldFilter = { + field: 'name', + operator: FieldFilterOperatorEnum.Eq, + value: 'Hello World Workflow', + }; + const greetingFilter = { + field: 'id', + operator: FieldFilterOperatorEnum.Eq, + value: 'yamlgreet', + }; + + const logicalFilter: LogicalFilter = { + operator: 'OR', + filters: [helloWorldFilter, greetingFilter], + }; + + beforeEach(() => { + jest.clearAllMocks(); + + mockClient = { + query: jest.fn(), + } as any; + + (Client as jest.Mock).mockImplementation(() => mockClient); + + loggerMock = { + info: jest.fn(), + debug: jest.fn(), + error: jest.fn(), + warn: jest.fn(), + child: jest.fn(), + }; + + dataIndexService = new DataIndexService('fakeUrl', loggerMock); + + // Set up spies on the graphql utility functions + buildGraphQlQuerySpy = jest.spyOn( + buildGrahQLQueryUtils, + 'buildGraphQlQuery', + ); + buildFilterConditionSpy = jest.spyOn( + buildGrahQLFilterUtils, + 'buildFilterCondition', + ); + }); + it('should fetch workflow infos with no parameters', async () => { + // Given + const mockQueryResult = { + ProcessDefinitions: mockWfInfos, + }; + mockClient.query.mockResolvedValueOnce( + mockOperationResult(mockQueryResult), + ); + + const expectedQueryArgs = createQueryArgs('ProcessDefinitions', queryBody); + // When + const result = await dataIndexService.fetchWorkflowInfos({}); + // Then + expect(result).toBeDefined(); + expect(result).toBe(mockQueryResult.ProcessDefinitions); + expect(buildFilterConditionSpy).not.toHaveBeenCalled(); + expect(buildGraphQlQuerySpy).toHaveBeenCalledTimes(1); + expect(buildGraphQlQuerySpy).toHaveBeenCalledWith({ + type: 'ProcessDefinitions', + queryBody, + }); + expect(mockClient.query).toHaveBeenCalled(); + expect(mockClient.query).toHaveBeenCalledWith( + buildGrahQLQueryUtils.buildGraphQlQuery(expectedQueryArgs), + {}, + ); + }); + + it('should fetch workflow infos with definitionIds', async () => { + // Given + const whereClause = `id: {in: ${JSON.stringify(definitionIds)}}`; + const mockQueryResult = { + ProcessDefinitions: mockWfInfos, + }; + mockClient.query.mockResolvedValueOnce( + mockOperationResult(mockQueryResult), + ); + + const expectedQueryArgs = createQueryArgs( + 'ProcessDefinitions', + queryBody, + whereClause, + ); + // When + const result = await dataIndexService.fetchWorkflowInfos({ + definitionIds, + }); + + // Then + expect(result).toBeDefined(); + expect(result).toBe(mockQueryResult.ProcessDefinitions); + expect(buildGraphQlQuerySpy).toHaveBeenCalledTimes(1); + expect(buildGraphQlQuerySpy).toHaveBeenCalledWith({ + type: 'ProcessDefinitions', + queryBody, + whereClause, + }); + expect(buildFilterConditionSpy).not.toHaveBeenCalled(); + expect(mockClient.query).toHaveBeenCalled(); + expect(mockClient.query).toHaveBeenCalledWith( + buildGrahQLQueryUtils.buildGraphQlQuery(expectedQueryArgs), + {}, + ); + }); + + it('should fetch workflow infos with definitionIds and pagination', async () => { + // Given + const mockQueryResult = { + ProcessDefinitions: mockWfInfos, + }; + mockClient.query.mockResolvedValueOnce( + mockOperationResult(mockQueryResult), + ); + + const expectedQueryArgs = createQueryArgs( + 'ProcessDefinitions', + queryBody, + `id: {in: ${JSON.stringify(definitionIds)}}`, + pagination, + ); + // When + const result = await dataIndexService.fetchWorkflowInfos({ + definitionIds, + pagination, + }); + + // Then + expect(result).toBeDefined(); + expect(result).toBe(mockQueryResult.ProcessDefinitions); + expect(buildGraphQlQuerySpy).toHaveBeenCalledTimes(1); + expect(buildGraphQlQuerySpy).toHaveBeenCalledWith({ + type: 'ProcessDefinitions', + queryBody, + whereClause: `id: {in: ${JSON.stringify(definitionIds)}}`, + pagination, + }); + expect(mockClient.query).toHaveBeenCalledTimes(1); + expect(mockClient.query).toHaveBeenCalledWith( + buildGrahQLQueryUtils.buildGraphQlQuery(expectedQueryArgs), + {}, + ); + expect(buildFilterConditionSpy).not.toHaveBeenCalled(); + }); + + it('should fetch workflow infos with only filter', async () => { + // Given + const mockQueryResult = { + ProcessDefinitions: mockWfInfos, + }; + mockClient.query + .mockResolvedValueOnce( + mockOperationResult(mockProcessDefinitionArguments), + ) + .mockResolvedValueOnce(mockOperationResult(mockQueryResult)); + + const expectedQueryArgs = createQueryArgs( + 'ProcessDefinitions', + queryBody, + filterString, + ); + + // When + const result = await dataIndexService.fetchWorkflowInfos({ + filter: logicalFilter, + }); + + // Then + expect(result).toBeDefined(); + expect(result).toBe(mockQueryResult.ProcessDefinitions); + + expect(buildGraphQlQuerySpy).toHaveBeenCalledTimes(1); + expect(buildGraphQlQuerySpy).toHaveBeenCalledWith({ + type: 'ProcessDefinitions', + queryBody, + whereClause: filterString, + }); + expect(buildFilterConditionSpy).toHaveBeenCalledTimes(1); + expect(buildFilterConditionSpy).toHaveBeenCalledWith( + mockProcessDefinitionIntrospection, + 'ProcessDefinition', + logicalFilter, + ); + expect(mockClient.query).toHaveBeenCalledTimes(2); + expect(mockClient.query).toHaveBeenCalledWith( + buildGrahQLQueryUtils.buildGraphQlQuery(expectedQueryArgs), + {}, + ); + }); + + it('should fetch workflow infos with definitionIds and filter', async () => { + // Given + const whereClause = `and: [{id: {in: ${JSON.stringify( + definitionIds, + )}}}, {${filterString}}]`; + // Given + const mockQueryResult = { + ProcessDefinitions: mockWfInfos, + }; + mockClient.query + .mockResolvedValueOnce( + mockOperationResult(mockProcessDefinitionArguments), + ) + .mockResolvedValueOnce(mockOperationResult(mockQueryResult)); + + const expectedQueryArgs = createQueryArgs( + 'ProcessDefinitions', + queryBody, + whereClause, + ); + + // When + const result = await dataIndexService.fetchWorkflowInfos({ + definitionIds, + filter: logicalFilter, + }); + + // Then + + expect(buildGraphQlQuerySpy).toHaveBeenCalledTimes(1); + expect(buildGraphQlQuerySpy).toHaveBeenCalledWith({ + type: 'ProcessDefinitions', + queryBody: 'id, name, version, type, endpoint, serviceUrl, source', + whereClause, + }); + expect(buildFilterConditionSpy).toHaveBeenCalledTimes(1); + expect(buildFilterConditionSpy).toHaveBeenCalledWith( + mockProcessDefinitionIntrospection, + 'ProcessDefinition', + logicalFilter, + ); + expect(mockClient.query).toHaveBeenCalledTimes(2); + expect(mockClient.query).toHaveBeenCalledWith( + buildGrahQLQueryUtils.buildGraphQlQuery(expectedQueryArgs), + {}, + ); + expect(result).toBeDefined(); + expect(result).toBe(mockQueryResult.ProcessDefinitions); + }); + + it('should fetch workflow infos with definitionIds, pagination, and filter', async () => { + // Given + const whereClause = `and: [{id: {in: ${JSON.stringify( + definitionIds, + )}}}, {${filterString}}]`; + // Given + const mockQueryResult = { + ProcessDefinitions: mockWfInfos, + }; + mockClient.query + .mockResolvedValueOnce( + mockOperationResult(mockProcessDefinitionArguments), + ) + .mockResolvedValueOnce(mockOperationResult(mockQueryResult)); + + const expectedQueryArgs = createQueryArgs( + 'ProcessDefinitions', + queryBody, + whereClause, + pagination, + ); + // When + const result = await dataIndexService.fetchWorkflowInfos({ + definitionIds, + pagination, + filter: logicalFilter, + }); + + // Then + + expect(mockClient.query).toHaveBeenCalledTimes(2); + expect(mockClient.query).toHaveBeenCalledWith( + buildGrahQLQueryUtils.buildGraphQlQuery(expectedQueryArgs), + {}, + ); + expect(buildGraphQlQuerySpy).toHaveBeenCalledTimes(2); + expect(buildGraphQlQuerySpy).toHaveBeenCalledWith({ + type: 'ProcessDefinitions', + queryBody, + whereClause, + pagination, + }); + expect(buildFilterConditionSpy).toHaveBeenCalledTimes(1); + expect(buildFilterConditionSpy).toHaveBeenCalledWith( + mockProcessDefinitionIntrospection, + 'ProcessDefinition', + logicalFilter, + ); + expect(result).toBeDefined(); + expect(result).toBe(mockQueryResult.ProcessDefinitions); + }); +}); +describe('fetchInstances', () => { + let loggerMock: LoggerService; + let buildFilterConditionSpy: any; + let buildGraphQlQuerySpy: any; + let mockClient: jest.Mocked; + + let dataIndexService: DataIndexService; + + const definitionIds = ['id', 'name']; + const pagination = { limit: 10, offset: 0, order: 'ASC', sortField: 'name' }; + + const processIdNotNullCondition = 'processId: {isNull: false}'; + const processIdDefinitions = `processId: {in: ${JSON.stringify( + definitionIds, + )}`; + const queryBody = + 'id, processName, processId, businessKey, state, start, end, nodes { id }, variables, parentProcessInstance {id, processName, businessKey}'; + + const mockProcessInstances: ProcessInstance[] = [ + { + id: 'id', + processId: 'processId1', + endpoint: 'endpoint1', + nodes: [createNodeObject('A'), createNodeObject('B')], + }, + { + id: 'name', + processId: 'processId2', + endpoint: 'endpoint2', + nodes: [createNodeObject('C'), createNodeObject('D')], + }, + ]; + + const filterString = + 'or: {processId: {equal: "processId1"}, processName: {like: "processName%"}}'; + + const procName1Filter: FieldFilter = { + field: 'processName', + operator: FieldFilterOperatorEnum.Like, + value: 'processName%', + }; + const procId1Filter: FieldFilter = { + field: 'processId', + operator: FieldFilterOperatorEnum.Eq, + value: 'processId1', + }; + + const logicalFilter: LogicalFilter = { + operator: 'OR', + filters: [procId1Filter, procName1Filter], + }; + const mockQueryResult = { ProcessInstances: mockProcessInstances }; + + beforeEach(() => { + mockClient = { + query: jest.fn(), + } as any; + + (Client as jest.Mock).mockImplementation(() => mockClient); + + const wfInfo: WorkflowInfo = { + id: 'wfinfo1', + source: 'workflow info source', + }; + + loggerMock = { + info: jest.fn(), + debug: jest.fn(), + error: jest.fn(), + warn: jest.fn(), + child: jest.fn(), + }; + dataIndexService = new DataIndexService('fakeUrl', loggerMock); + // Create a spy for method1 + jest.spyOn(dataIndexService, 'fetchWorkflowInfo').mockResolvedValue(wfInfo); + // Set up spies on the graphql utility functions + buildGraphQlQuerySpy = jest.spyOn( + buildGrahQLQueryUtils, + 'buildGraphQlQuery', + ); + buildFilterConditionSpy = jest.spyOn( + buildGrahQLFilterUtils, + 'buildFilterCondition', + ); + + // Clear mocks before each test + jest.clearAllMocks(); + }); + it('should fetch instances with no parameters', async () => { + // Given + const whereClause = processIdNotNullCondition; + mockClient.query.mockResolvedValueOnce( + mockOperationResult(mockQueryResult), + ); + + const expectedQueryArgs = createQueryArgs( + 'ProcessInstances', + queryBody, + whereClause, + ); + + // When + const result = await dataIndexService.fetchInstances({}); + + // Then + expect(result).toBeDefined(); + expect(result).toStrictEqual(mockQueryResult.ProcessInstances); + + expect(buildGraphQlQuerySpy).toHaveBeenCalledTimes(1); + expect(buildGraphQlQuerySpy).toHaveBeenCalledWith({ + type: 'ProcessInstances', + queryBody, + whereClause, + }); + expect(buildFilterConditionSpy).not.toHaveBeenCalled(); + expect(mockClient.query).toHaveBeenCalled(); + expect(mockClient.query).toHaveBeenCalledWith( + buildGrahQLQueryUtils.buildGraphQlQuery(expectedQueryArgs), + {}, + ); + }); + + it('should fetch instances with definitionIds', async () => { + // Given + const whereClause = `and: [{${processIdNotNullCondition}}, {${processIdDefinitions}}}]`; + + mockClient.query.mockResolvedValueOnce( + mockOperationResult(mockQueryResult), + ); + + const expectedQueryArgs = createQueryArgs( + 'ProcessInstances', + queryBody, + whereClause, + ); + // When + const result = await dataIndexService.fetchInstances({ + definitionIds, + }); + + // Then + expect(buildGraphQlQuerySpy).toHaveBeenCalledTimes(1); + expect(buildGraphQlQuerySpy).toHaveBeenCalledWith({ + type: 'ProcessInstances', + queryBody, + whereClause, + pagination: undefined, + }); + expect(buildFilterConditionSpy).not.toHaveBeenCalled(); + expect(mockClient.query).toHaveBeenCalled(); + expect(mockClient.query).toHaveBeenCalledWith( + buildGrahQLQueryUtils.buildGraphQlQuery(expectedQueryArgs), + {}, + ); + expect(result).toBeDefined(); + expect(result).toStrictEqual(mockQueryResult.ProcessInstances); + }); + + it('should fetch instances with definitionIds and pagination', async () => { + // Given + const whereClause = `and: [{${processIdNotNullCondition}}, {${processIdDefinitions}}}]`; + mockClient.query.mockResolvedValueOnce( + mockOperationResult(mockQueryResult), + ); + + const expectedQueryArgs = createQueryArgs( + 'ProcessInstances', + queryBody, + whereClause, + pagination, + ); + // When + const result = await dataIndexService.fetchInstances({ + definitionIds, + + pagination, + }); + + // Then + expect(result).toBeDefined(); + expect(result).toStrictEqual(mockQueryResult.ProcessInstances); + + expect(buildGraphQlQuerySpy).toHaveBeenCalledTimes(1); + expect(buildGraphQlQuerySpy).toHaveBeenCalledWith({ + type: 'ProcessInstances', + queryBody, + whereClause, + pagination, + }); + expect(buildFilterConditionSpy).not.toHaveBeenCalled(); + expect(mockClient.query).toHaveBeenCalledTimes(1); + expect(mockClient.query).toHaveBeenCalledWith( + buildGrahQLQueryUtils.buildGraphQlQuery(expectedQueryArgs), + {}, + ); + }); + + it('should fetch instances with only filter', async () => { + // Given + const whereClause = `and: [{${processIdNotNullCondition}}, {${filterString}}]`; + mockClient.query + .mockResolvedValueOnce(mockOperationResult(mockProcessInstanceArguments)) + .mockResolvedValueOnce(mockOperationResult(mockQueryResult)); + + const expectedQueryArgs = createQueryArgs( + 'ProcessInstances', + queryBody, + whereClause, + ); + // When + const result = await dataIndexService.fetchInstances({ + filter: logicalFilter, + }); + + // Then + expect(result).toBeDefined(); + expect(result).toStrictEqual(mockQueryResult.ProcessInstances); + expect(buildGraphQlQuerySpy).toHaveBeenCalledTimes(1); + expect(buildGraphQlQuerySpy).toHaveBeenCalledWith({ + type: 'ProcessInstances', + queryBody, + whereClause, + }); + expect(buildFilterConditionSpy).toHaveBeenCalledTimes(1); + expect(buildFilterConditionSpy).toHaveBeenCalledWith( + mockProcessInstanceIntrospection, + 'ProcessInstance', + logicalFilter, + ); + expect(mockClient.query).toHaveBeenCalledTimes(2); + expect(mockClient.query).toHaveBeenCalledWith( + buildGrahQLQueryUtils.buildGraphQlQuery(expectedQueryArgs), + {}, + ); + }); + + it('should fetch instances with definitionIds and filter', async () => { + // Given + const whereClause = `and: [{${processIdNotNullCondition}}, {${processIdDefinitions}}}, {${filterString}}]`; + mockClient.query + .mockResolvedValueOnce(mockOperationResult(mockProcessInstanceArguments)) + .mockResolvedValueOnce(mockOperationResult(mockQueryResult)); + const expectedQueryArgs = createQueryArgs( + 'ProcessInstances', + queryBody, + whereClause, + ); + // When + const result = await dataIndexService.fetchInstances({ + definitionIds, + filter: logicalFilter, + }); + + // Then + expect(buildGraphQlQuerySpy).toHaveBeenCalledTimes(1); + expect(buildGraphQlQuerySpy).toHaveBeenCalledWith({ + type: 'ProcessInstances', + queryBody, + whereClause, + }); + expect(buildFilterConditionSpy).toHaveBeenCalledTimes(1); + expect(buildFilterConditionSpy).toHaveBeenCalledWith( + mockProcessInstanceIntrospection, + 'ProcessInstance', + logicalFilter, + ); + expect(mockClient.query).toHaveBeenCalledTimes(2); + expect(mockClient.query).toHaveBeenCalledWith( + buildGrahQLQueryUtils.buildGraphQlQuery(expectedQueryArgs), + {}, + ); + expect(result).toBeDefined(); + expect(result).toStrictEqual(mockQueryResult.ProcessInstances); + }); + + it('should fetch instances with definitionIds, pagination, and filter', async () => { + // Given + const whereClause = `and: [{${processIdNotNullCondition}}, {${processIdDefinitions}}}, {${filterString}}]`; + mockClient.query + .mockResolvedValueOnce(mockOperationResult(mockProcessInstanceArguments)) + .mockResolvedValueOnce(mockOperationResult(mockQueryResult)); + const expectedQueryArgs = createQueryArgs( + 'ProcessInstances', + queryBody, + whereClause, + pagination, + ); + // When + const result = await dataIndexService.fetchInstances({ + definitionIds, + pagination, + filter: logicalFilter, + }); + + // Then + expect(buildGraphQlQuerySpy).toHaveBeenCalledTimes(1); + expect(buildGraphQlQuerySpy).toHaveBeenCalledWith({ + type: 'ProcessInstances', + queryBody, + whereClause, + pagination, + }); + expect(buildFilterConditionSpy).toHaveBeenCalledTimes(1); + expect(buildFilterConditionSpy).toHaveBeenCalledWith( + mockProcessInstanceIntrospection, + 'ProcessInstance', + logicalFilter, + ); + expect(mockClient.query).toHaveBeenCalledTimes(2); + expect(mockClient.query).toHaveBeenCalledWith( + buildGrahQLQueryUtils.buildGraphQlQuery(expectedQueryArgs), + {}, + ); + expect(result).toBeDefined(); + expect(result).toStrictEqual(mockQueryResult.ProcessInstances); + }); +}); + +function createNodeObject(suffix: string): NodeInstance { + return { + id: `node${suffix}`, + name: `node${suffix}`, + enter: new Date('2024-08-01T14:30:00').toISOString(), + type: 'NodeType', + definitionId: `definitionId${suffix}`, + nodeId: `nodeId${suffix}`, + }; +} diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/src/service/DataIndexService.ts b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/DataIndexService.ts new file mode 100644 index 00000000..4b4ddd52 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/DataIndexService.ts @@ -0,0 +1,566 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { LoggerService } from '@backstage/backend-plugin-api'; + +import { Client, fetchExchange, gql } from '@urql/core'; + +import { + Filter, + fromWorkflowSource, + getWorkflowCategory, + IntrospectionField, + parseWorkflowVariables, + ProcessInstance, + WorkflowDefinition, + WorkflowInfo, +} from '@red-hat-developer-hub/backstage-plugin-orchestrator-common'; + +import { ErrorBuilder } from '../helpers/errorBuilder'; +import { buildFilterCondition } from '../helpers/filterBuilder'; +import { buildGraphQlQuery } from '../helpers/queryBuilder'; +import { Pagination } from '../types/pagination'; +import { FETCH_PROCESS_INSTANCES_SORT_FIELD } from './constants'; + +export class DataIndexService { + private readonly client: Client; + public processDefinitionArguments: IntrospectionField[] = []; + public processInstanceArguments: IntrospectionField[] = []; + + public constructor( + private readonly dataIndexUrl: string, + private readonly logger: LoggerService, + ) { + if (!dataIndexUrl.length) { + throw ErrorBuilder.GET_NO_DATA_INDEX_URL_ERR(); + } + + this.client = this.getNewGraphQLClient(); + } + + private getNewGraphQLClient(): Client { + const diURL = `${this.dataIndexUrl}/graphql`; + return new Client({ + url: diURL, + exchanges: [fetchExchange], + }); + } + + public async initInputProcessDefinitionArgs(): Promise { + if (this.processDefinitionArguments.length === 0) { + this.processDefinitionArguments = await this.inspectInputArgument( + 'ProcessDefinition', + ); + } + return this.processDefinitionArguments; // For testing purposes + } + + public graphQLArgumentQuery(type: string): string { + return `query ${type}Argument { + __type(name: "${type}Argument") { + kind + name + inputFields { + name + type { + kind + name + ofType { + kind + name + ofType { + kind + name + ofType { + kind + name + } + } + } + } + } + } + }`; + } + + public async inspectInputArgument( + type: string, + ): Promise { + const result = await this.client.query(this.graphQLArgumentQuery(type), {}); + + this.logger.debug(`Introspection query result: ${JSON.stringify(result)}`); + + if (result?.error) { + this.logger.error(`Error executing introspection query ${result.error}`); + throw result.error; + } + + const pairs: IntrospectionField[] = []; + if (result?.data?.__type?.inputFields) { + for (const field of result.data.__type.inputFields) { + if ( + field.name !== 'and' && + field.name !== 'or' && + field.name !== 'not' + ) { + pairs.push({ + name: field.name, + type: { + name: field.type.name, + kind: field.type.kind, + ofType: field.type.ofType, + }, + }); + } + } + } + return pairs; + } + + public async abortWorkflowInstance(instanceId: string): Promise { + this.logger.info(`Aborting workflow instance ${instanceId}`); + const ProcessInstanceAbortMutationDocument = gql` + mutation ProcessInstanceAbortMutation($id: String) { + ProcessInstanceAbort(id: $id) + } + `; + + const result = await this.client.mutation( + ProcessInstanceAbortMutationDocument, + { id: instanceId }, + ); + + this.logger.debug( + `Abort workflow instance result: ${JSON.stringify(result)}`, + ); + + if (result.error) { + throw new Error( + `Error aborting workflow instance ${instanceId}: ${result.error}`, + ); + } + this.logger.debug(`Successfully aborted workflow instance ${instanceId}`); + } + + public async fetchWorkflowInfo( + definitionId: string, + ): Promise { + const graphQlQuery = `{ ProcessDefinitions ( where: {id: {equal: "${definitionId}" } } ) { id, name, version, type, endpoint, serviceUrl, source } }`; + + const result = await this.client.query(graphQlQuery, {}); + + this.logger.debug( + `Get workflow definition result: ${JSON.stringify(result)}`, + ); + + if (result.error) { + this.logger.error(`Error fetching workflow definition ${result.error}`); + throw result.error; + } + + const processDefinitions = result.data.ProcessDefinitions as WorkflowInfo[]; + + if (processDefinitions.length === 0) { + this.logger.info(`No workflow definition found for ${definitionId}`); + return undefined; + } + + return processDefinitions[0]; + } + + public async fetchWorkflowServiceUrls(): Promise> { + const graphQlQuery = `{ ProcessDefinitions { id, serviceUrl } }`; + + const result = await this.client.query(graphQlQuery, {}); + + this.logger.debug( + `Get workflow service urls result: ${JSON.stringify(result)}`, + ); + + if (result.error) { + this.logger.error(`Error fetching workflow service urls ${result.error}`); + throw result.error; + } + + const processDefinitions = result.data.ProcessDefinitions as WorkflowInfo[]; + return processDefinitions + .filter(definition => definition.serviceUrl) + .map(definition => ({ [definition.id]: definition.serviceUrl! })) + .reduce((acc, curr) => ({ ...acc, ...curr }), {}); + } + + public async fetchWorkflowInfos(args: { + definitionIds?: string[]; + pagination?: Pagination; + filter?: Filter; + }): Promise { + this.logger.info(`fetchWorkflowInfos() called: ${this.dataIndexUrl}`); + const { definitionIds, pagination, filter } = args; + + const definitionIdsCondition = + definitionIds !== undefined && definitionIds.length > 0 + ? `id: {in: ${JSON.stringify(definitionIds)}}` + : undefined; + + const filterCondition = filter + ? buildFilterCondition( + await this.initInputProcessDefinitionArgs(), + 'ProcessDefinition', + filter, + ) + : undefined; + + let whereClause: string | undefined; + if (definitionIds && filter) { + whereClause = `and: [{${definitionIdsCondition}}, {${filterCondition}}]`; + } else if (definitionIdsCondition || filterCondition) { + whereClause = definitionIdsCondition ?? filterCondition; + } else { + whereClause = undefined; + } + + const graphQlQuery = buildGraphQlQuery({ + type: 'ProcessDefinitions', + queryBody: 'id, name, version, type, endpoint, serviceUrl, source', + whereClause, + pagination, + }); + this.logger.debug(`GraphQL query: ${graphQlQuery}`); + const result = await this.client.query(graphQlQuery, {}); + this.logger.debug( + `Get workflow definitions result: ${JSON.stringify(result)}`, + ); + + if (result.error) { + this.logger.error( + `Error fetching data index swf results ${result.error}`, + ); + throw result.error; + } + + return result.data.ProcessDefinitions; + } + + public async fetchInstances(args: { + definitionIds?: string[]; + pagination?: Pagination; + filter?: Filter; + }): Promise { + const { pagination, definitionIds, filter } = args; + if (pagination) pagination.sortField ??= FETCH_PROCESS_INSTANCES_SORT_FIELD; + + const processIdNotNullCondition = 'processId: {isNull: false}'; + const definitionIdsCondition = definitionIds + ? `processId: {in: ${JSON.stringify(definitionIds)}}` + : undefined; + const type = 'ProcessInstance'; + const filterCondition = filter + ? buildFilterCondition( + await this.inspectInputArgument(type), + type, + filter, + ) + : ''; + + let whereClause = ''; + const conditions = []; + + if (processIdNotNullCondition) { + conditions.push(`{${processIdNotNullCondition}}`); + } + + if (definitionIdsCondition) { + conditions.push(`{${definitionIdsCondition}}`); + } + + if (filter) { + conditions.push(`{${filterCondition}}`); + } + + if (conditions.length === 0) { + whereClause = processIdNotNullCondition; + } else if (conditions.length === 1) { + whereClause = conditions[0].slice(1, -1); // Remove the outer braces + } else if (conditions.length > 1) { + whereClause = `and: [${conditions.join(', ')}]`; + } + + const graphQlQuery = buildGraphQlQuery({ + type: 'ProcessInstances', + queryBody: + 'id, processName, processId, businessKey, state, start, end, nodes { id }, variables, parentProcessInstance {id, processName, businessKey}', + whereClause, + pagination, + }); + + this.logger.debug(`GraphQL query: ${graphQlQuery}`); + + const result = await this.client.query(graphQlQuery, {}); + + this.logger.debug( + `Fetch process instances result: ${JSON.stringify(result)}`, + ); + + const processInstancesSrc = result.data + .ProcessInstances as ProcessInstance[]; + + const processInstances = await Promise.all( + processInstancesSrc.map(async instance => { + return await this.getWorkflowDefinitionFromInstance(instance); + }), + ); + return processInstances; + } + + public async fetchInstancesTotalCount( + definitionIds?: string[], + filter?: Filter, + ): Promise { + const definitionIdsCondition = definitionIds + ? `processId: {in: ${JSON.stringify(definitionIds)}}` + : undefined; + this.initInputProcessDefinitionArgs(); + const filterCondition = filter + ? buildFilterCondition( + await this.inspectInputArgument('ProcessInstance'), + 'ProcessInstance', + filter, + ) + : ''; + + let whereClause: string | undefined; + if (definitionIds && filter) { + whereClause = `and: [{${definitionIdsCondition}}, {${filterCondition}}]`; + } else if (definitionIdsCondition || filterCondition) { + whereClause = definitionIdsCondition ?? filterCondition; + } + + const graphQlQuery = buildGraphQlQuery({ + type: 'ProcessInstances', + queryBody: 'id', + whereClause, + }); + this.logger.debug(`GraphQL query: ${graphQlQuery}`); + + const result = await this.client.query(graphQlQuery, {}); + + if (result.error) { + this.logger.error( + `Error when fetching instances total count: ${result.error}`, + ); + throw result.error; + } + + const idArr = result.data.ProcessInstances as ProcessInstance[]; + + return idArr.length; + } + + private async getWorkflowDefinitionFromInstance(instance: ProcessInstance) { + const workflowInfo = await this.fetchWorkflowInfo(instance.processId); + if (!workflowInfo?.source) { + throw new Error( + `Workflow defintion is required to fetch instance ${instance.id}`, + ); + } + const workflowDefinitionSrc: WorkflowDefinition = fromWorkflowSource( + workflowInfo.source, + ); + if (workflowInfo) { + instance.category = getWorkflowCategory(workflowDefinitionSrc); + instance.description = workflowInfo.description; + } + return instance; + } + + public async fetchWorkflowSource( + definitionId: string, + ): Promise { + const graphQlQuery = `{ ProcessDefinitions ( where: {id: {equal: "${definitionId}" } } ) { id, source } }`; + + const result = await this.client.query(graphQlQuery, {}); + + this.logger.debug( + `Fetch workflow source result: ${JSON.stringify(result)}`, + ); + + if (result.error) { + this.logger.error(`Error when fetching workflow source: ${result.error}`); + return undefined; + } + + const processDefinitions = result.data.ProcessDefinitions as WorkflowInfo[]; + + if (processDefinitions.length === 0) { + this.logger.info(`No workflow source found for ${definitionId}`); + return undefined; + } + + return processDefinitions[0].source; + } + + public async fetchInstancesByDefinitionId(args: { + definitionId: string; + limit: number; + offset: number; + }): Promise { + const graphQlQuery = `{ ProcessInstances(where: {processId: {equal: "${args.definitionId}" } }, orderBy: {start:DESC}, pagination: {limit: ${args.limit}, offset: ${args.offset}}) { id, processName, state, start, end } }`; + + const result = await this.client.query(graphQlQuery, {}); + + this.logger.debug( + `Fetch workflow instances result: ${JSON.stringify(result)}`, + ); + + if (result.error) { + this.logger.error( + `Error when fetching workflow instances: ${result.error}`, + ); + throw result.error; + } + + return result.data.ProcessInstances; + } + + public async fetchInstanceVariables( + instanceId: string, + ): Promise { + const graphQlQuery = `{ ProcessInstances (where: { id: {equal: "${instanceId}" } } ) { variables } }`; + + const result = await this.client.query(graphQlQuery, {}); + + this.logger.debug( + `Fetch process instance variables result: ${JSON.stringify(result)}`, + ); + + if (result.error) { + this.logger.error( + `Error when fetching process instance variables: ${result.error}`, + ); + throw result.error; + } + + const processInstances = result.data.ProcessInstances as ProcessInstance[]; + + if (processInstances.length === 0) { + return undefined; + } + + return parseWorkflowVariables(processInstances[0].variables as object); + } + + public async fetchDefinitionIdByInstanceId( + instanceId: string, + ): Promise { + const graphQlQuery = `{ ProcessInstances (where: { id: {equal: "${instanceId}" } } ) { processId } }`; + + const result = await this.client.query(graphQlQuery, {}); + + this.logger.debug( + `Fetch process id from instance result: ${JSON.stringify(result)}`, + ); + + if (result.error) { + this.logger.error( + `Error when fetching process id from instance: ${result.error}`, + ); + throw result.error; + } + + const processInstances = result.data.ProcessInstances as ProcessInstance[]; + + if (processInstances.length === 0) { + return undefined; + } + + return processInstances[0].processId; + } + + public async fetchInstance( + instanceId: string, + ): Promise { + const FindProcessInstanceQuery = gql` + query FindProcessInstanceQuery($instanceId: String!) { + ProcessInstances(where: { id: { equal: $instanceId } }) { + id + processName + processId + serviceUrl + businessKey + state + start + end + nodes { + id + nodeId + definitionId + type + name + enter + exit + } + variables + parentProcessInstance { + id + processName + businessKey + } + error { + nodeDefinitionId + message + } + } + } + `; + + const result = await this.client.query(FindProcessInstanceQuery, { + instanceId, + }); + + this.logger.debug( + `Fetch process instance result: ${JSON.stringify(result)}`, + ); + + if (result.error) { + this.logger.error( + `Error when fetching process instances: ${result.error}`, + ); + throw result.error; + } + + const processInstances = result.data.ProcessInstances as ProcessInstance[]; + + if (processInstances.length === 0) { + return undefined; + } + + const instance = processInstances[0]; + + const workflowInfo = await this.fetchWorkflowInfo(instance.processId); + if (!workflowInfo?.source) { + throw new Error( + `Workflow defintion is required to fetch instance ${instance.id}`, + ); + } + const workflowDefinitionSrc: WorkflowDefinition = fromWorkflowSource( + workflowInfo.source, + ); + if (workflowInfo) { + instance.category = getWorkflowCategory(workflowDefinitionSrc); + instance.description = workflowDefinitionSrc.description; + } + return instance; + } +} diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/src/service/DataInputSchemaService.ts b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/DataInputSchemaService.ts new file mode 100644 index 00000000..ef438e97 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/DataInputSchemaService.ts @@ -0,0 +1,26 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import type { JsonObject } from '@backstage/types'; + +import { WORKFLOW_DATA_KEY } from './constants'; + +export class DataInputSchemaService { + public extractWorkflowData(variables?: object): JsonObject | undefined { + return variables && WORKFLOW_DATA_KEY in variables + ? (variables[WORKFLOW_DATA_KEY] as JsonObject) + : undefined; + } +} diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/src/service/DevModeService.ts b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/DevModeService.ts new file mode 100644 index 00000000..05a9d82d --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/DevModeService.ts @@ -0,0 +1,217 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import type { LoggerService } from '@backstage/backend-plugin-api'; +import type { Config } from '@backstage/config'; + +import fs from 'fs-extra'; + +import { + DEFAULT_SONATAFLOW_BASE_URL, + DEFAULT_SONATAFLOW_CONTAINER_IMAGE, + DEFAULT_SONATAFLOW_PERSISTENCE_PATH, + DEFAULT_WORKFLOWS_PATH, +} from '@red-hat-developer-hub/backstage-plugin-orchestrator-common'; + +import { spawn } from 'child_process'; +import { join, resolve } from 'path'; + +import { GitService } from './GitService'; +import { executeWithRetry } from './Helper'; + +const SONATA_FLOW_RESOURCES_PATH = + '/home/kogito/serverless-workflow-project/src/main/resources'; + +interface LauncherCommand { + command: string; + args: string[]; +} + +interface DevModeConnectionConfig { + host: string; + port?: number; + containerImage: string; + resourcesPath: string; + persistencePath: string; + repoUrl?: string; +} + +export class DevModeService { + private readonly connection: DevModeConnectionConfig; + private readonly gitService; + + constructor(config: Config, private readonly logger: LoggerService) { + this.connection = this.extractConnectionConfig(config); + this.gitService = new GitService(logger, config); + } + + public get devModeUrl(): string { + if (!this.connection.port) { + return this.connection.host; + } + return `${this.connection.host}:${this.connection.port}`; + } + + public async launchDevMode(): Promise { + await this.loadDevWorkflows(); + + const isAlreadyUp = await this.isSonataFlowUp(false, this.devModeUrl); + if (isAlreadyUp) { + return true; + } + + this.launchSonataFlow(); + + return await this.isSonataFlowUp(true, this.devModeUrl); + } + + private async isSonataFlowUp( + withRetry: boolean, + endpoint: string, + ): Promise { + const healthUrl = `${endpoint}/q/health`; + this.logger.info(`Checking SonataFlow health at: ${healthUrl}`); + + try { + const response = await executeWithRetry( + () => fetch(healthUrl), + withRetry ? 15 : 1, + ); + if (response.ok) { + this.logger.info('SonataFlow is up and running'); + return true; + } + } catch (e) { + this.logger.error(`Error when checking SonataFlow health: ${e}`); + } + return false; + } + + private launchSonataFlow(): void { + const launcherCmd = this.createLauncherCommand(); + + this.logger.info( + `Auto starting SonataFlow through: ${ + launcherCmd.command + } ${launcherCmd.args.join(' ')}`, + ); + + const process = spawn(launcherCmd.command, launcherCmd.args, { + shell: false, + }); + + process.on('close', code => { + this.logger.info(`SonataFlow process exited with code ${code}`); + }); + + process.on('exit', code => { + this.logger.info(`SonataFlow process exited with code ${code}`); + }); + + process.on('error', error => { + this.logger.error(`SonataFlow process error: ${error}`); + }); + } + + private createLauncherCommand(): LauncherCommand { + const resourcesAbsPath = resolve( + join(this.connection.resourcesPath, DEFAULT_WORKFLOWS_PATH), + ); + + const launcherArgs = [ + 'run', + '--name', + 'backstage-internal-sonataflow', + '--add-host', + 'host.docker.internal:host-gateway', + ]; + + launcherArgs.push('-e', `QUARKUS_HTTP_PORT=${this.connection.port}`); + + launcherArgs.push('-p', `${this.connection.port}:${this.connection.port}`); + launcherArgs.push('-e', `KOGITO_SERVICE_URL=${this.devModeUrl}`); + launcherArgs.push( + '-v', + `${resourcesAbsPath}:${SONATA_FLOW_RESOURCES_PATH}:Z`, + ); + launcherArgs.push('-e', 'KOGITO.CODEGEN.PROCESS.FAILONERROR=false'); + launcherArgs.push( + '-e', + `QUARKUS_EMBEDDED_POSTGRESQL_DATA_DIR=${this.connection.persistencePath}`, + ); + + launcherArgs.push(this.connection.containerImage); + + return { + command: 'docker', + args: launcherArgs, + }; + } + + private extractConnectionConfig(config: Config): DevModeConnectionConfig { + const host = + config.getOptionalString('orchestrator.sonataFlowService.baseUrl') ?? + DEFAULT_SONATAFLOW_BASE_URL; + const port = config.getOptionalNumber( + 'orchestrator.sonataFlowService.port', + ); + + const resourcesPath = + config.getOptionalString( + 'orchestrator.sonataFlowService.workflowsSource.localPath', + ) ?? ''; + + const containerImage = + config.getOptionalString('orchestrator.sonataFlowService.container') ?? + DEFAULT_SONATAFLOW_CONTAINER_IMAGE; + + const persistencePath = + config.getOptionalString( + 'orchestrator.sonataFlowService.persistence.path', + ) ?? DEFAULT_SONATAFLOW_PERSISTENCE_PATH; + + const repoUrl = + config.getOptionalString( + 'orchestrator.sonataFlowService.workflowsSource.gitRepositoryUrl', + ) ?? ''; + + return { + host, + port, + containerImage, + resourcesPath, + persistencePath, + repoUrl, + }; + } + + public async loadDevWorkflows() { + if (!this.connection.repoUrl) { + this.logger.info( + 'No Git repository configured. Skipping dev workflows loading.', + ); + return; + } + + this.logger.info(`Loading dev workflows from ${this.connection.repoUrl}`); + const localPath = this.connection.resourcesPath; + if (await fs.pathExists(localPath)) { + this.logger.info(`Path ${localPath} already exists. Skipping clone.`); + return; + } + + await this.gitService.clone(this.connection.repoUrl, localPath); + } +} diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/src/service/GitService.ts b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/GitService.ts new file mode 100644 index 00000000..48a29d5f --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/GitService.ts @@ -0,0 +1,108 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import type { LoggerService } from '@backstage/backend-plugin-api'; +import type { Config } from '@backstage/config'; +import { ScmIntegrations } from '@backstage/integration'; + +import { Git } from './GitWrapper'; + +export class GitService { + private readonly git: Git; + + private readonly logger: LoggerService; + private authenticated: boolean; + + private readonly author = { + name: 'backstage-orchestrator', + email: 'orchestrator@backstage.io', + }; + + private readonly committer = { + name: 'backstage-orchestrator', + email: 'orchestrator@backstage.io', + }; + + constructor(logger: LoggerService, config: Config) { + this.logger = logger; + const githubIntegration = ScmIntegrations.fromConfig(config) + .github.list() + .pop(); + this.git = Git.fromAuth({ + username: 'x-access-token', + password: githubIntegration?.config.token, + }); + this.authenticated = !!githubIntegration?.config.token; + } + + async clone(repoURL: string, localPath: string): Promise { + this.logger.info(`cloning repo ${repoURL} into ${localPath}`); + return this.git + .clone({ + url: repoURL, + dir: localPath, + depth: 1, + }) + .then(() => this.git.checkout({ dir: localPath, ref: 'main' })); + } + + async push(dir: string, message: string): Promise { + if (!this.authenticated) { + this.logger.warn( + 'Git integration is required to be configured for push, with the token or credentials', + ); + return; + } + const branch = 'main'; + const force = true; + const remote = 'origin'; + const filepath = '.'; + this.git + .fetch({ remote, dir }) + .then(() => this.git.checkout({ dir, ref: branch })) + .then(() => this.git.add({ dir, filepath })) + .then(() => + this.git.commit({ + dir, + message, + author: this.author, + committer: this.committer, + }), + ) + .then(() => this.git.push({ dir, remote, remoteRef: branch, force })) + .finally(() => this.logger.info('push completed')) + .catch(ex => this.logger.error(ex)); + } + + async pull(localPath: string): Promise { + const remoteBranch = 'origin/main'; + const localBranch = 'main'; + const remote = 'origin'; + this.git + .fetch({ remote, dir: localPath }) + .then(() => this.git.checkout({ dir: localPath, ref: localBranch })) + .then(() => + this.git.merge({ + dir: localPath, + ours: localBranch, + theirs: remoteBranch, + author: this.author, + committer: this.committer, + }), + ) + .finally(() => this.logger.info('merge completed')) + .catch(ex => this.logger.error(ex)); + } +} diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/src/service/GitWrapper/git.ts b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/GitWrapper/git.ts new file mode 100644 index 00000000..9ed2b4a7 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/GitWrapper/git.ts @@ -0,0 +1,355 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { LoggerService } from '@backstage/backend-plugin-api'; + +import fs from 'fs-extra'; +import git, { + AuthCallback, + MergeResult, + ProgressCallback, + ReadCommitResult, +} from 'isomorphic-git'; +import http from 'isomorphic-git/http/node'; + +function isAuthCallbackOptions( + options: StaticAuthOptions | AuthCallbackOptions, +): options is AuthCallbackOptions { + return 'onAuth' in options; +} + +/** + * Configure static credential for authentication + * @public + */ +export type StaticAuthOptions = { + username?: string; + password?: string; + token?: string; + logger?: LoggerService; +}; + +/** + * Configure an authentication callback that can provide credentials on demand + * @public + */ +export type AuthCallbackOptions = { + onAuth: AuthCallback; + logger?: LoggerService; +}; + +/* +provider username password +Azure 'notempty' token +Bitbucket Cloud 'x-token-auth' token +Bitbucket Server username password or token +GitHub 'x-access-token' token +GitLab 'oauth2' token +From : https://isomorphic-git.org/docs/en/onAuth with fix for GitHub +Or token provided as `token` for Bearer auth header +instead of Basic Auth (e.g., Bitbucket Server). +*/ + +/** + * A convenience wrapper around the `isomorphic-git` library. + * @public + */ + +export class Git { + private readonly headers: { + [x: string]: string; + }; + + private constructor( + private readonly config: { + onAuth: AuthCallback; + token?: string; + logger?: LoggerService; + }, + ) { + this.onAuth = config.onAuth; + + this.headers = { + 'user-agent': 'git/@isomorphic-git', + ...(config.token ? { Authorization: `Bearer ${config.token}` } : {}), + }; + } + + async add(options: { dir: string; filepath: string }): Promise { + const { dir, filepath } = options; + this.config.logger?.info(`Adding file {dir=${dir},filepath=${filepath}}`); + + return git.add({ fs, dir, filepath }); + } + + async addRemote(options: { + dir: string; + remote: string; + url: string; + force?: boolean; + }): Promise { + const { dir, url, remote, force } = options; + this.config.logger?.info( + `Creating new remote {dir=${dir},remote=${remote},url=${url}}`, + ); + return git.addRemote({ fs, dir, remote, url, force }); + } + + async deleteRemote(options: { dir: string; remote: string }): Promise { + const { dir, remote } = options; + this.config.logger?.info(`Deleting remote {dir=${dir},remote=${remote}}`); + return git.deleteRemote({ fs, dir, remote }); + } + + async checkout(options: { dir: string; ref: string }): Promise { + const { dir, ref } = options; + this.config.logger?.info(`Checking out branch {dir=${dir},ref=${ref}}`); + + return git.checkout({ fs, dir, ref }); + } + + async branch(options: { dir: string; ref: string }): Promise { + const { dir, ref } = options; + this.config.logger?.info(`Creating branch {dir=${dir},ref=${ref}`); + + return git.branch({ fs, dir, ref }); + } + + async commit(options: { + dir: string; + message: string; + author: { name: string; email: string }; + committer: { name: string; email: string }; + }): Promise { + const { dir, message, author, committer } = options; + this.config.logger?.info( + `Committing file to repo {dir=${dir},message=${message}}`, + ); + return git.commit({ fs, dir, message, author, committer }); + } + + /** https://isomorphic-git.org/docs/en/clone */ + async clone(options: { + url: string; + dir: string; + ref?: string; + depth?: number; + noCheckout?: boolean; + }): Promise { + const { url, dir, ref, depth, noCheckout } = options; + this.config.logger?.info(`Cloning repo {dir=${dir},url=${url}}`); + + try { + return await git.clone({ + fs, + http, + url, + dir, + ref, + singleBranch: true, + depth: depth ?? 1, + noCheckout, + onProgress: this.onProgressHandler(), + headers: this.headers, + onAuth: this.onAuth, + }); + } catch (ex: any) { + this.config.logger?.error(`Failed to clone repo {dir=${dir},url=${url}}`); + if (ex.data) { + throw new Error(`${ex.message} {data=${JSON.stringify(ex.data)}}`); + } + throw ex; + } + } + + /** https://isomorphic-git.org/docs/en/currentBranch */ + async currentBranch(options: { + dir: string; + fullName?: boolean; + }): Promise { + const { dir, fullName = false } = options; + return git.currentBranch({ fs, dir, fullname: fullName }) as Promise< + string | undefined + >; + } + + /** https://isomorphic-git.org/docs/en/fetch */ + async fetch(options: { + dir: string; + remote?: string; + tags?: boolean; + }): Promise { + const { dir, remote = 'origin', tags = false } = options; + this.config.logger?.info( + `Fetching remote=${remote} for repository {dir=${dir}}`, + ); + + try { + await git.fetch({ + fs, + http, + dir, + remote, + tags, + onProgress: this.onProgressHandler(), + headers: this.headers, + onAuth: this.onAuth, + }); + } catch (ex: any) { + this.config.logger?.error( + `Failed to fetch repo {dir=${dir},remote=${remote}}`, + ); + if (ex.data) { + throw new Error(`${ex.message} {data=${JSON.stringify(ex.data)}}`); + } + throw ex; + } + } + + async init(options: { dir: string; defaultBranch?: string }): Promise { + const { dir, defaultBranch = 'master' } = options; + this.config.logger?.info(`Init git repository {dir=${dir}}`); + + return git.init({ + fs, + dir, + defaultBranch, + }); + } + + /** https://isomorphic-git.org/docs/en/merge */ + async merge(options: { + dir: string; + theirs: string; + ours?: string; + author: { name: string; email: string }; + committer: { name: string; email: string }; + }): Promise { + const { dir, theirs, ours, author, committer } = options; + this.config.logger?.info( + `Merging branch '${theirs}' into '${ours}' for repository {dir=${dir}}`, + ); + + // If ours is undefined, current branch is used. + return git.merge({ + fs, + dir, + ours, + theirs, + author, + committer, + }); + } + + async push(options: { + dir: string; + remote: string; + remoteRef?: string; + force?: boolean; + }) { + const { dir, remote, remoteRef, force } = options; + this.config.logger?.info( + `Pushing directory to remote {dir=${dir},remote=${remote}}`, + ); + try { + return await git.push({ + fs, + dir, + http, + onProgress: this.onProgressHandler(), + remoteRef, + force, + headers: this.headers, + remote, + onAuth: this.onAuth, + }); + } catch (ex: any) { + this.config.logger?.error( + `Failed to push to repo {dir=${dir}, remote=${remote}}`, + ); + if (ex.data) { + throw new Error(`${ex.message} {data=${JSON.stringify(ex.data)}}`); + } + throw ex; + } + } + + /** https://isomorphic-git.org/docs/en/readCommit */ + async readCommit(options: { + dir: string; + sha: string; + }): Promise { + const { dir, sha } = options; + return git.readCommit({ fs, dir, oid: sha }); + } + + /** https://isomorphic-git.org/docs/en/remove */ + async remove(options: { dir: string; filepath: string }): Promise { + const { dir, filepath } = options; + this.config.logger?.info( + `Removing file from git index {dir=${dir},filepath=${filepath}}`, + ); + return git.remove({ fs, dir, filepath }); + } + + /** https://isomorphic-git.org/docs/en/resolveRef */ + async resolveRef(options: { dir: string; ref: string }): Promise { + const { dir, ref } = options; + return git.resolveRef({ fs, dir, ref }); + } + + /** https://isomorphic-git.org/docs/en/log */ + async log(options: { + dir: string; + ref?: string; + }): Promise { + const { dir, ref } = options; + return git.log({ + fs, + dir, + ref: ref ?? 'HEAD', + }); + } + + private readonly onAuth: AuthCallback; + + private readonly onProgressHandler = (): ProgressCallback => { + let currentPhase = ''; + + return event => { + if (currentPhase !== event.phase) { + currentPhase = event.phase; + this.config.logger?.info(event.phase); + } + const total = event.total + ? `${Math.round((event.loaded / event.total) * 100)}%` + : event.loaded; + this.config.logger?.debug(`status={${event.phase},total={${total}}}`); + }; + }; + + static readonly fromAuth = ( + options: StaticAuthOptions | AuthCallbackOptions, + ) => { + if (isAuthCallbackOptions(options)) { + const { onAuth, logger } = options; + return new Git({ onAuth, logger }); + } + + const { username, password, token, logger } = options; + return new Git({ onAuth: () => ({ username, password }), token, logger }); + }; +} diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/src/service/GitWrapper/index.ts b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/GitWrapper/index.ts new file mode 100644 index 00000000..1d7fb43f --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/GitWrapper/index.ts @@ -0,0 +1,18 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Based on https://github.com/backstage/backstage/pull/24605/files +export * from './git'; diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/src/service/Helper.test.ts b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/Helper.test.ts new file mode 100644 index 00000000..78b35e3f --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/Helper.test.ts @@ -0,0 +1,64 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { retryAsyncFunction } from './Helper'; + +describe('retryAsyncFunction', () => { + const successfulResponse = 'Success'; + it('should be successful in the first attempt', async () => { + const asyncFnSuccess = jest.fn().mockResolvedValueOnce(successfulResponse); + + const result = await retryAsyncFunction({ + asyncFn: asyncFnSuccess, + maxAttempts: 3, + delayMs: 100, + }); + + expect(result).toBe(successfulResponse); + expect(asyncFnSuccess).toHaveBeenCalledTimes(1); + }); + + it('should throw an error after maximum attempts', async () => { + const asyncFnFailure = jest.fn().mockResolvedValue(undefined); + + await expect( + retryAsyncFunction({ + asyncFn: asyncFnFailure, + maxAttempts: 5, + delayMs: 100, + }), + ).rejects.toThrow(); + + expect(asyncFnFailure).toHaveBeenCalledTimes(5); + }); + + it('should retry until successful after getting some undefined responses', async () => { + const asyncFns = jest + .fn() + .mockResolvedValueOnce(undefined) + .mockResolvedValueOnce(undefined) + .mockResolvedValueOnce(undefined) + .mockResolvedValueOnce(successfulResponse); + + const result = await retryAsyncFunction({ + asyncFn: asyncFns, + maxAttempts: 5, + delayMs: 100, + }); + + expect(result).toBe(successfulResponse); + expect(asyncFns).toHaveBeenCalledTimes(4); + }); +}); diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/src/service/Helper.ts b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/Helper.ts new file mode 100644 index 00000000..73fd4cb7 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/Helper.ts @@ -0,0 +1,91 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import type { LoggerService } from '@backstage/backend-plugin-api'; +import type { Config } from '@backstage/config'; + +import fs from 'fs-extra'; + +import os from 'os'; + +export async function retryAsyncFunction(args: { + asyncFn: () => Promise; + maxAttempts: number; + delayMs: number; +}): Promise { + let result: T | undefined; + for (let i = 0; i < args.maxAttempts; i++) { + result = await args.asyncFn(); + if (result !== undefined) { + return result; + } + await new Promise(resolve => setTimeout(resolve, args.delayMs)); + } + throw new Error('Exceeded maximum number of retries for async function'); +} + +export async function getWorkingDirectory( + config: Config, + logger: LoggerService, +): Promise { + if (!config.has('backend.workingDirectory')) { + return os.tmpdir(); + } + + const workingDirectory = config.getString('backend.workingDirectory'); + try { + // Check if working directory exists and is writable + await fs.access(workingDirectory, fs.constants.F_OK | fs.constants.W_OK); + logger.info(`using working directory: ${workingDirectory}`); + } catch (err: any) { + logger.error( + `working directory ${workingDirectory} ${ + err.code === 'ENOENT' ? 'does not exist' : 'is not writable' + }`, + ); + throw err; + } + return workingDirectory; +} + +export async function executeWithRetry( + action: () => Promise, + maxErrors = 15, +): Promise { + let response: Response; + let errorCount = 0; + // execute with retry + const backoff = 5000; + while (errorCount < maxErrors) { + try { + response = await action(); + if (response.status >= 400) { + errorCount++; + // backoff + await delay(backoff); + } else { + return response; + } + } catch (e) { + errorCount++; + await delay(backoff); + } + } + throw new Error('Unable to execute query.'); +} + +export function delay(time: number) { + return new Promise(r => setTimeout(r, time)); +} diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/src/service/OrchestratorService.test.ts b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/OrchestratorService.test.ts new file mode 100644 index 00000000..6a45ec32 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/OrchestratorService.test.ts @@ -0,0 +1,671 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { + ProcessInstance, + WorkflowDefinition, + WorkflowExecutionResponse, + WorkflowInfo, + WorkflowOverview, +} from '@red-hat-developer-hub/backstage-plugin-orchestrator-common'; + +import { DataIndexService } from './DataIndexService'; +import { OrchestratorService } from './OrchestratorService'; +import { SonataFlowService } from './SonataFlowService'; +import { WorkflowCacheService } from './WorkflowCacheService'; + +// Mocked data helpers +const createInstanceIdMock = (x: number): string => `instance${x}`; +const createDefinitionIdMock = (x: number): string => `definition${x}`; +const createWorkflowInfoMock = (x: number): WorkflowInfo => { + return { + id: createDefinitionIdMock(x), + }; +}; +const createWorkflowOverviewMock = (x: number): WorkflowOverview => { + return { + workflowId: createDefinitionIdMock(x), + format: 'yaml', + }; +}; +const createWorkflowOverviewsMock = (size: number): WorkflowOverview[] => + Array.from({ length: size }, (_, i) => createWorkflowOverviewMock(i + 1)); +const createInstanceMock = (x: number): ProcessInstance => { + return { + id: createInstanceIdMock(x), + processId: createDefinitionIdMock(x), + endpoint: `endpoint${x}`, + nodes: [], + }; +}; +const createInstancesMock = (size: number): ProcessInstance[] => { + const result: ProcessInstance[] = []; + for (let i = 1; i <= size; i++) { + result.push(createInstanceMock(i)); + } + return result; +}; + +// Mocked data +const instanceId = createInstanceIdMock(1); +const definitionId = createDefinitionIdMock(1); +const workflowInfo = createWorkflowInfoMock(1); +const workflowOverview = createWorkflowOverviewMock(1); +const workflowOverviews = createWorkflowOverviewsMock(3); +const instance = createInstanceMock(1); +const instances = createInstancesMock(3); +const serviceUrl = 'http://localhost'; +const inputData = { foo: 'bar' }; + +// Mocked dependencies +const sonataFlowServiceMock = {} as SonataFlowService; +const workflowCacheServiceMock = {} as WorkflowCacheService; +const dataIndexServiceMock = {} as DataIndexService; + +// Target +const orchestratorService = new OrchestratorService( + sonataFlowServiceMock, + dataIndexServiceMock, + workflowCacheServiceMock, +); + +describe('OrchestratorService', () => { + describe('abortWorkflowInstance', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should execute the operation when the workflow is available', async () => { + dataIndexServiceMock.fetchDefinitionIdByInstanceId = jest + .fn() + .mockResolvedValue(definitionId); + workflowCacheServiceMock.isAvailable = jest.fn().mockReturnValue(true); + dataIndexServiceMock.abortWorkflowInstance = jest.fn( + (_instanceId: string) => Promise.resolve(), + ); + + await orchestratorService.abortWorkflowInstance({ + instanceId, + cacheHandler: 'skip', + }); + + expect( + dataIndexServiceMock.fetchDefinitionIdByInstanceId, + ).toHaveBeenCalled(); + expect(dataIndexServiceMock.abortWorkflowInstance).toHaveBeenCalled(); + }); + + it('should skip and not execute the operation when the workflow is not available', async () => { + dataIndexServiceMock.fetchDefinitionIdByInstanceId = jest + .fn() + .mockResolvedValue(definitionId); + workflowCacheServiceMock.isAvailable = jest.fn().mockReturnValue(false); + + await orchestratorService.abortWorkflowInstance({ + instanceId, + cacheHandler: 'skip', + }); + + expect( + dataIndexServiceMock.fetchDefinitionIdByInstanceId, + ).toHaveBeenCalled(); + expect(dataIndexServiceMock.abortWorkflowInstance).not.toHaveBeenCalled(); + }); + + it('should throw an error and not execute the operation when the workflow is not available', async () => { + dataIndexServiceMock.fetchDefinitionIdByInstanceId = jest + .fn() + .mockResolvedValue(definitionId); + workflowCacheServiceMock.isAvailable = jest + .fn() + .mockImplementation(() => { + throw new Error(); + }); + + const promise = orchestratorService.abortWorkflowInstance({ + instanceId, + cacheHandler: 'throw', + }); + + await expect(promise).rejects.toThrow(); + + expect( + dataIndexServiceMock.fetchDefinitionIdByInstanceId, + ).toHaveBeenCalled(); + expect(workflowCacheServiceMock.isAvailable).toHaveBeenCalled(); + expect(dataIndexServiceMock.abortWorkflowInstance).not.toHaveBeenCalled(); + }); + }); + + describe('fetchInstances', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should throw error when data index returns error', async () => { + const errMsg = 'Failed to load instances'; + dataIndexServiceMock.fetchInstances = jest.fn().mockImplementation(() => { + throw new Error(errMsg); + }); + + const promise = orchestratorService.fetchInstances({}); + await expect(promise).rejects.toThrow(errMsg); + }); + + it('should execute the operation', async () => { + dataIndexServiceMock.fetchInstances = jest + .fn() + .mockResolvedValue(instances); + + const result = await orchestratorService.fetchInstances({}); + + expect(result).toHaveLength(instances.length); + expect(dataIndexServiceMock.fetchInstances).toHaveBeenCalled(); + }); + }); + + describe('fetchInstancesTotalCount', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should throw error when data index returns error', async () => { + const errMsg = 'Failed to get instances total count'; + dataIndexServiceMock.fetchInstancesTotalCount = jest + .fn() + .mockImplementation(() => { + throw new Error(errMsg); + }); + const promise = orchestratorService.fetchInstancesTotalCount(); + await expect(promise).rejects.toThrow(errMsg); + }); + + it('should execute the operation', async () => { + dataIndexServiceMock.fetchInstancesTotalCount = jest + .fn() + .mockResolvedValue(instances.length); + + const result = await orchestratorService.fetchInstancesTotalCount(); + + expect(result).toBe(instances.length); + expect(dataIndexServiceMock.fetchInstancesTotalCount).toHaveBeenCalled(); + }); + }); + + describe('fetchWorkflowOverviews', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should throw error when data index returns error', async () => { + const errMsg = 'Failed to get workflows overview'; + sonataFlowServiceMock.fetchWorkflowOverviews = jest + .fn() + .mockImplementation(() => { + throw new Error(errMsg); + }); + + const promise = orchestratorService.fetchWorkflowOverviews({}); + await expect(promise).rejects.toThrow(); + }); + + it('should execute the operation', async () => { + sonataFlowServiceMock.fetchWorkflowOverviews = jest + .fn() + .mockResolvedValue(workflowOverviews); + + const result = await orchestratorService.fetchWorkflowOverviews({}); + + expect(result).toHaveLength(workflowOverviews.length); + expect(sonataFlowServiceMock.fetchWorkflowOverviews).toHaveBeenCalled(); + }); + }); + + describe('fetchWorkflowInfo', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should execute the operation when the workflow is available', async () => { + workflowCacheServiceMock.isAvailable = jest.fn().mockReturnValue(true); + dataIndexServiceMock.fetchWorkflowInfo = jest + .fn() + .mockResolvedValue(workflowInfo); + + const result = await orchestratorService.fetchWorkflowInfo({ + definitionId, + cacheHandler: 'skip', + }); + + expect(result).toBeDefined(); + }); + + it('should skip and not execute the operation when the workflow is not available', async () => { + workflowCacheServiceMock.isAvailable = jest.fn().mockReturnValue(false); + + const result = await orchestratorService.fetchWorkflowInfo({ + definitionId, + cacheHandler: 'skip', + }); + + expect(result).toBeUndefined(); + expect(dataIndexServiceMock.fetchWorkflowInfo).not.toHaveBeenCalled(); + }); + + it('should throw an error and not execute the operation when the workflow is not available', async () => { + workflowCacheServiceMock.isAvailable = jest + .fn() + .mockImplementation(() => { + throw new Error(); + }); + + const promise = orchestratorService.fetchWorkflowInfo({ + definitionId, + cacheHandler: 'throw', + }); + + await expect(promise).rejects.toThrow(); + + expect(dataIndexServiceMock.fetchWorkflowInfo).not.toHaveBeenCalled(); + }); + }); + + describe('fetchWorkflowSource', () => { + const workflowSource = 'workflow source'; + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should execute the operation when the workflow is available', async () => { + workflowCacheServiceMock.isAvailable = jest.fn().mockReturnValue(true); + dataIndexServiceMock.fetchWorkflowSource = jest + .fn() + .mockResolvedValue(workflowSource); + + const result = await orchestratorService.fetchWorkflowSource({ + definitionId, + cacheHandler: 'skip', + }); + + expect(result).toBeDefined(); + }); + + it('should skip and not execute the operation when the workflow is not available', async () => { + workflowCacheServiceMock.isAvailable = jest.fn().mockReturnValue(false); + + const result = await orchestratorService.fetchWorkflowSource({ + definitionId, + cacheHandler: 'skip', + }); + + expect(result).toBeUndefined(); + expect(dataIndexServiceMock.fetchWorkflowSource).not.toHaveBeenCalled(); + }); + + it('should throw an error and not execute the operation when the workflow is not available', async () => { + workflowCacheServiceMock.isAvailable = jest + .fn() + .mockImplementation(() => { + throw new Error(); + }); + + const promise = orchestratorService.fetchWorkflowSource({ + definitionId, + cacheHandler: 'throw', + }); + + await expect(promise).rejects.toThrow(); + + expect(dataIndexServiceMock.fetchWorkflowSource).not.toHaveBeenCalled(); + }); + }); + + describe('fetchInstanceVariables', () => { + const variables: object = { foo: 'bar' }; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should execute the operation when the workflow is available', async () => { + workflowCacheServiceMock.isAvailable = jest.fn().mockReturnValue(true); + dataIndexServiceMock.fetchDefinitionIdByInstanceId = jest + .fn() + .mockResolvedValue(definitionId); + dataIndexServiceMock.fetchInstanceVariables = jest + .fn() + .mockResolvedValue(variables); + + const result = await orchestratorService.fetchInstanceVariables({ + instanceId, + cacheHandler: 'skip', + }); + + expect(result).toBeDefined(); + }); + + it('should skip and not execute the operation when the workflow is not available', async () => { + workflowCacheServiceMock.isAvailable = jest.fn().mockReturnValue(false); + dataIndexServiceMock.fetchDefinitionIdByInstanceId = jest + .fn() + .mockResolvedValue(definitionId); + + const result = await orchestratorService.fetchInstanceVariables({ + instanceId, + cacheHandler: 'skip', + }); + + expect(result).toBeUndefined(); + expect( + dataIndexServiceMock.fetchInstanceVariables, + ).not.toHaveBeenCalled(); + }); + + it('should throw an error and not execute the operation when the workflow is not available', async () => { + workflowCacheServiceMock.isAvailable = jest + .fn() + .mockImplementation(() => { + throw new Error(); + }); + dataIndexServiceMock.fetchDefinitionIdByInstanceId = jest + .fn() + .mockResolvedValue(definitionId); + + const promise = orchestratorService.fetchInstanceVariables({ + instanceId, + cacheHandler: 'throw', + }); + + await expect(promise).rejects.toThrow(); + + expect( + dataIndexServiceMock.fetchInstanceVariables, + ).not.toHaveBeenCalled(); + }); + }); + + describe('fetchInstance', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should execute the operation when the workflow is available', async () => { + workflowCacheServiceMock.isAvailable = jest.fn().mockReturnValue(true); + dataIndexServiceMock.fetchInstance = jest + .fn() + .mockResolvedValue(instance); + + const result = await orchestratorService.fetchInstance({ + instanceId, + cacheHandler: 'skip', + }); + + expect(result).toBeDefined(); + }); + + it('should skip and not execute the operation when the workflow is not available', async () => { + workflowCacheServiceMock.isAvailable = jest.fn().mockReturnValue(false); + + const result = await orchestratorService.fetchInstance({ + instanceId, + cacheHandler: 'skip', + }); + + expect(result).toBeUndefined(); + }); + + it('should throw an error and not execute the operation when the workflow is not available', async () => { + workflowCacheServiceMock.isAvailable = jest + .fn() + .mockImplementation(() => { + throw new Error(); + }); + + const promise = orchestratorService.fetchInstance({ + instanceId, + cacheHandler: 'throw', + }); + + await expect(promise).rejects.toThrow(); + }); + }); + + describe('fetchWorkflowInfoOnService', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should execute the operation when the workflow is available', async () => { + workflowCacheServiceMock.isAvailable = jest.fn().mockReturnValue(true); + sonataFlowServiceMock.fetchWorkflowInfoOnService = jest + .fn() + .mockResolvedValue(workflowInfo); + + const result = await orchestratorService.fetchWorkflowInfoOnService({ + definitionId, + serviceUrl, + cacheHandler: 'skip', + }); + + expect(result).toBeDefined(); + }); + + it('should skip and not execute the operation when the workflow is not available', async () => { + workflowCacheServiceMock.isAvailable = jest.fn().mockReturnValue(false); + + const result = await orchestratorService.fetchWorkflowInfoOnService({ + definitionId, + serviceUrl, + cacheHandler: 'skip', + }); + + expect(result).toBeUndefined(); + expect( + sonataFlowServiceMock.fetchWorkflowInfoOnService, + ).not.toHaveBeenCalled(); + }); + + it('should throw an error and not execute the operation when the workflow is not available', async () => { + workflowCacheServiceMock.isAvailable = jest + .fn() + .mockImplementation(() => { + throw new Error(); + }); + + const promise = orchestratorService.fetchWorkflowInfoOnService({ + definitionId, + serviceUrl, + cacheHandler: 'throw', + }); + + await expect(promise).rejects.toThrow(); + + expect( + sonataFlowServiceMock.fetchWorkflowInfoOnService, + ).not.toHaveBeenCalled(); + }); + }); + + describe('fetchWorkflowDefinition', () => { + const definition: WorkflowDefinition = { + id: 'test_workflowId', + specVersion: '0.8', + states: [{}], + }; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should execute the operation when the workflow is available', async () => { + workflowCacheServiceMock.isAvailable = jest.fn().mockReturnValue(true); + sonataFlowServiceMock.fetchWorkflowDefinition = jest + .fn() + .mockResolvedValue(definition); + + const result = await orchestratorService.fetchWorkflowDefinition({ + definitionId, + cacheHandler: 'skip', + }); + + expect(result).toBeDefined(); + }); + + it('should skip and not execute the operation when the workflow is not available', async () => { + workflowCacheServiceMock.isAvailable = jest.fn().mockReturnValue(false); + + const result = await orchestratorService.fetchWorkflowDefinition({ + definitionId, + cacheHandler: 'skip', + }); + + expect(result).toBeUndefined(); + expect( + sonataFlowServiceMock.fetchWorkflowDefinition, + ).not.toHaveBeenCalled(); + }); + + it('should throw an error and not execute the operation when the workflow is not available', async () => { + workflowCacheServiceMock.isAvailable = jest + .fn() + .mockImplementation(() => { + throw new Error(); + }); + + const promise = orchestratorService.fetchWorkflowDefinition({ + definitionId, + cacheHandler: 'throw', + }); + + await expect(promise).rejects.toThrow(); + + expect( + sonataFlowServiceMock.fetchWorkflowDefinition, + ).not.toHaveBeenCalled(); + }); + }); + + describe('fetchWorkflowOverview', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should execute the operation when the workflow is available', async () => { + workflowCacheServiceMock.isAvailable = jest.fn().mockReturnValue(true); + sonataFlowServiceMock.fetchWorkflowOverview = jest + .fn() + .mockResolvedValue(workflowOverview); + + const result = await orchestratorService.fetchWorkflowOverview({ + definitionId, + cacheHandler: 'skip', + }); + + expect(result).toBeDefined(); + }); + + it('should skip and not execute the operation when the workflow is not available', async () => { + workflowCacheServiceMock.isAvailable = jest.fn().mockReturnValue(false); + + const result = await orchestratorService.fetchWorkflowOverview({ + definitionId, + cacheHandler: 'skip', + }); + + expect(result).toBeUndefined(); + expect( + sonataFlowServiceMock.fetchWorkflowOverview, + ).not.toHaveBeenCalled(); + }); + + it('should throw an error and not execute the operation when the workflow is not available', async () => { + workflowCacheServiceMock.isAvailable = jest + .fn() + .mockImplementation(() => { + throw new Error(); + }); + + const promise = orchestratorService.fetchWorkflowOverview({ + definitionId, + cacheHandler: 'throw', + }); + + await expect(promise).rejects.toThrow(); + + expect( + sonataFlowServiceMock.fetchWorkflowOverview, + ).not.toHaveBeenCalled(); + }); + }); + + describe('executeWorkflow', () => { + const executeResponse: WorkflowExecutionResponse = { + id: createInstanceIdMock(1), + }; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should execute the operation when the workflow is available', async () => { + workflowCacheServiceMock.isAvailable = jest.fn().mockReturnValue(true); + sonataFlowServiceMock.executeWorkflow = jest + .fn() + .mockResolvedValue(executeResponse); + + const result = await orchestratorService.executeWorkflow({ + definitionId, + serviceUrl, + inputData, + cacheHandler: 'skip', + }); + + expect(result).toBeDefined(); + }); + + it('should skip and not execute the operation when the workflow is not available', async () => { + workflowCacheServiceMock.isAvailable = jest.fn().mockReturnValue(false); + + const result = await orchestratorService.executeWorkflow({ + definitionId, + serviceUrl, + inputData, + cacheHandler: 'skip', + }); + + expect(result).toBeUndefined(); + expect(sonataFlowServiceMock.executeWorkflow).not.toHaveBeenCalled(); + }); + + it('should throw an error and not execute the operation when the workflow is not available', async () => { + workflowCacheServiceMock.isAvailable = jest + .fn() + .mockImplementation(() => { + throw new Error(); + }); + + const promise = orchestratorService.executeWorkflow({ + definitionId, + serviceUrl, + inputData, + cacheHandler: 'throw', + }); + + await expect(promise).rejects.toThrow(); + + expect(sonataFlowServiceMock.executeWorkflow).not.toHaveBeenCalled(); + }); + }); +}); diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/src/service/OrchestratorService.ts b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/OrchestratorService.ts new file mode 100644 index 00000000..a54c31b4 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/OrchestratorService.ts @@ -0,0 +1,229 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { + Filter, + ProcessInstance, + ProcessInstanceVariables, + WorkflowDefinition, + WorkflowExecutionResponse, + WorkflowInfo, + WorkflowOverview, +} from '@red-hat-developer-hub/backstage-plugin-orchestrator-common'; + +import { Pagination } from '../types/pagination'; +import { DataIndexService } from './DataIndexService'; +import { SonataFlowService } from './SonataFlowService'; +import { CacheHandler, WorkflowCacheService } from './WorkflowCacheService'; + +export class OrchestratorService { + constructor( + private readonly sonataFlowService: SonataFlowService, + private readonly dataIndexService: DataIndexService, + private readonly workflowCacheService: WorkflowCacheService, + ) {} + + // Data Index Service Wrapper + + public async abortWorkflowInstance(args: { + instanceId: string; + cacheHandler?: CacheHandler; + }): Promise { + const { instanceId, cacheHandler } = args; + const definitionId = + await this.dataIndexService.fetchDefinitionIdByInstanceId(instanceId); + const isWorkflowAvailable = this.workflowCacheService.isAvailable( + definitionId, + cacheHandler, + ); + return isWorkflowAvailable + ? await this.dataIndexService.abortWorkflowInstance(instanceId) + : undefined; + } + + public async fetchWorkflowInfo(args: { + definitionId: string; + cacheHandler?: CacheHandler; + }): Promise { + const { definitionId, cacheHandler } = args; + const isWorkflowAvailable = this.workflowCacheService.isAvailable( + definitionId, + cacheHandler, + ); + return isWorkflowAvailable + ? await this.dataIndexService.fetchWorkflowInfo(definitionId) + : undefined; + } + + public async fetchInstances(args: { + pagination?: Pagination; + filter?: Filter; + workflowId?: string; + }): Promise { + const definitionIds = args.workflowId + ? [args.workflowId] + : this.workflowCacheService.definitionIds; + return await this.dataIndexService.fetchInstances({ + definitionIds: definitionIds, + pagination: args.pagination, + filter: args.filter, + }); + } + + public async fetchInstancesTotalCount( + workflowId?: string, + filter?: Filter, + ): Promise { + const definitionIds = workflowId + ? [workflowId] + : this.workflowCacheService.definitionIds; + return await this.dataIndexService.fetchInstancesTotalCount( + definitionIds, + filter, + ); + } + + public async fetchWorkflowSource(args: { + definitionId: string; + cacheHandler?: CacheHandler; + }): Promise { + const { definitionId, cacheHandler } = args; + const isWorkflowAvailable = this.workflowCacheService.isAvailable( + definitionId, + cacheHandler, + ); + return isWorkflowAvailable + ? await this.dataIndexService.fetchWorkflowSource(definitionId) + : undefined; + } + + public async fetchInstanceVariables(args: { + instanceId: string; + cacheHandler?: CacheHandler; + }): Promise { + const { instanceId, cacheHandler } = args; + const definitionId = + await this.dataIndexService.fetchDefinitionIdByInstanceId(instanceId); + const isWorkflowAvailable = this.workflowCacheService.isAvailable( + definitionId, + cacheHandler, + ); + return isWorkflowAvailable + ? await this.dataIndexService.fetchInstanceVariables(instanceId) + : undefined; + } + + public async fetchInstance(args: { + instanceId: string; + cacheHandler?: CacheHandler; + }): Promise { + const { instanceId, cacheHandler } = args; + const instance = await this.dataIndexService.fetchInstance(instanceId); + const isWorkflowAvailable = this.workflowCacheService.isAvailable( + instance?.processId, + cacheHandler, + ); + return isWorkflowAvailable ? instance : undefined; + } + + // SonataFlow Service Wrapper + + public async fetchWorkflowInfoOnService(args: { + definitionId: string; + serviceUrl: string; + cacheHandler?: CacheHandler; + }): Promise { + const { definitionId, cacheHandler } = args; + const isWorkflowAvailable = this.workflowCacheService.isAvailable( + definitionId, + cacheHandler, + ); + return isWorkflowAvailable + ? await this.sonataFlowService.fetchWorkflowInfoOnService(args) + : undefined; + } + + public async fetchWorkflowDefinition(args: { + definitionId: string; + cacheHandler?: CacheHandler; + }): Promise { + const { definitionId, cacheHandler } = args; + const isWorkflowAvailable = this.workflowCacheService.isAvailable( + definitionId, + cacheHandler, + ); + return isWorkflowAvailable + ? await this.sonataFlowService.fetchWorkflowDefinition(definitionId) + : undefined; + } + + public async fetchWorkflowOverviews(args: { + pagination?: Pagination; + filter?: Filter; + }): Promise { + return await this.sonataFlowService.fetchWorkflowOverviews({ + definitionIds: this.workflowCacheService.definitionIds, + pagination: args.pagination, + filter: args.filter, + }); + } + + public async executeWorkflow(args: { + definitionId: string; + serviceUrl: string; + inputData: ProcessInstanceVariables; + businessKey?: string; + cacheHandler?: CacheHandler; + }): Promise { + const { definitionId, cacheHandler } = args; + const isWorkflowAvailable = this.workflowCacheService.isAvailable( + definitionId, + cacheHandler, + ); + return isWorkflowAvailable + ? await this.sonataFlowService.executeWorkflow(args) + : undefined; + } + + public async retriggerWorkflow(args: { + definitionId: string; + instanceId: string; + serviceUrl: string; + cacheHandler?: CacheHandler; + }): Promise { + const { definitionId, cacheHandler } = args; + const isWorkflowAvailable = this.workflowCacheService.isAvailable( + definitionId, + cacheHandler, + ); + return isWorkflowAvailable + ? await this.sonataFlowService.retriggerInstance(args) + : undefined; + } + + public async fetchWorkflowOverview(args: { + definitionId: string; + cacheHandler?: CacheHandler; + }): Promise { + const { definitionId, cacheHandler } = args; + const isWorkflowAvailable = this.workflowCacheService.isAvailable( + definitionId, + cacheHandler, + ); + return isWorkflowAvailable + ? await this.sonataFlowService.fetchWorkflowOverview(definitionId) + : undefined; + } +} diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/src/service/ScaffolderService.ts b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/ScaffolderService.ts new file mode 100644 index 00000000..7e873842 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/ScaffolderService.ts @@ -0,0 +1,133 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { loggerToWinstonLogger } from '@backstage/backend-common'; +import type { + LoggerService, + UrlReaderService, +} from '@backstage/backend-plugin-api'; +import type { CatalogApi } from '@backstage/catalog-client'; +import type { Config } from '@backstage/config'; +import { ScmIntegrations } from '@backstage/integration'; +import { + createBuiltinActions, + TemplateActionRegistry, +} from '@backstage/plugin-scaffolder-backend'; +import { + ActionContext, + TemplateAction, +} from '@backstage/plugin-scaffolder-node'; +import type { JsonObject, JsonValue } from '@backstage/types'; + +import fs from 'fs-extra'; + +import { randomUUID } from 'crypto'; +import path from 'path'; +import { PassThrough } from 'stream'; + +import { getWorkingDirectory } from './Helper'; + +export interface ActionExecutionContext { + actionId: string; + instanceId: string | undefined; + input: JsonObject; +} + +export class ScaffolderService { + private actionRegistry: TemplateActionRegistry; + private streamLogger = new PassThrough(); + + constructor( + private readonly logger: LoggerService, + private readonly config: Config, + private readonly catalogApi: CatalogApi, + private readonly urlReader: UrlReaderService, + ) { + this.actionRegistry = new TemplateActionRegistry(); + } + + public loadActions(): void { + const actions = [ + ...createBuiltinActions({ + integrations: ScmIntegrations.fromConfig(this.config), + catalogClient: this.catalogApi, + reader: this.urlReader, + config: this.config, + }), + ]; + actions.forEach(a => this.actionRegistry.register(a)); + } + + public getAction(id: string): TemplateAction { + return this.actionRegistry.get(id); + } + + public async executeAction( + actionExecutionContext: ActionExecutionContext, + ): Promise { + if (this.actionRegistry.list().length === 0) { + this.loadActions(); + } + + const action: TemplateAction = this.getAction( + actionExecutionContext.actionId, + ); + const stepOutput: { [outputName: string]: JsonValue } = {}; + + let workspacePath: string; + try { + const workingDirectory = await getWorkingDirectory( + this.config, + this.logger, + ); + workspacePath = path.join( + workingDirectory, + actionExecutionContext.instanceId ?? randomUUID(), + ); + } catch (err: unknown) { + this.logger.error( + `Error getting working directory to execute action ${actionExecutionContext.actionId}`, + err as Error, + ); + throw err; + } + const actionContext: ActionContext = { + input: actionExecutionContext.input, + workspacePath: workspacePath, + // TODO: Move this to LoggerService after scaffolder-node moves to LoggerService + // https://github.com/backstage/backstage/issues/26933 + logger: loggerToWinstonLogger(this.logger), + logStream: this.streamLogger, + createTemporaryDirectory: async () => + await fs.mkdtemp(`${workspacePath}_step-${0}-`), + output(name: string, value: JsonValue) { + stepOutput[name] = value; + }, + getInitiatorCredentials: async () => { + return { + $$type: '@backstage/BackstageCredentials', + principal: 'mock-principal', + }; + }, + checkpoint: async (key, fn) => { + this.logger.info(`Orchestrator ScaffolderService checkpoint ${key}`); + return fn(); + }, + }; + await action.handler(actionContext); + + return stepOutput; + } +} diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/src/service/SonataFlowService.test.ts b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/SonataFlowService.test.ts new file mode 100644 index 00000000..ca7c8ad0 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/SonataFlowService.test.ts @@ -0,0 +1,370 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { LoggerService } from '@backstage/backend-plugin-api'; + +import { WorkflowExecutionResponse } from '@red-hat-developer-hub/backstage-plugin-orchestrator-common'; + +import { DataIndexService } from './DataIndexService'; +import { SonataFlowService } from './SonataFlowService'; + +describe('SonataFlowService', () => { + let loggerMock: jest.Mocked; + let sonataFlowService: SonataFlowService; + + beforeAll(() => { + loggerMock = { + info: jest.fn(), + debug: jest.fn(), + error: jest.fn(), + warn: jest.fn(), + child: jest.fn(), + }; + sonataFlowService = new SonataFlowService( + {} as DataIndexService, + loggerMock, + ); + }); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + afterEach(() => { + jest.resetAllMocks(); + }); + + describe('fetchWorkflowInfoOnService', () => { + const serviceUrl = 'http://example.com'; + const definitionId = 'workflow-123'; + const urlToFetch = 'http://example.com/management/processes/workflow-123'; + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should return workflow info when the fetch response is ok', async () => { + // Given + const mockResponse: Partial = { + ok: true, + json: jest.fn().mockResolvedValue({ id: 'workflow-123' }), + }; + global.fetch = jest.fn().mockResolvedValue(mockResponse as any); + + // When + const result = await sonataFlowService.fetchWorkflowInfoOnService({ + definitionId, + serviceUrl, + }); + + // Then + expect(fetch).toHaveBeenCalledWith(urlToFetch); + expect(result).toEqual({ id: definitionId }); + expect(loggerMock.debug).toHaveBeenCalledWith( + `Fetch workflow info result: {"id":"${definitionId}"}`, + ); + }); + + it('should propagate thrown error when the fetch response is not ok', async () => { + // Given + const mockResponse: Partial = { + ok: false, + status: 500, + statusText: 'Not Found', + json: jest.fn().mockResolvedValue({ + details: 'Error details', + stack: 'Error stack trace', + }), + }; + global.fetch = jest.fn().mockResolvedValue(mockResponse as any); + + // When + let result; + try { + await sonataFlowService.fetchWorkflowInfoOnService({ + definitionId, + serviceUrl, + }); + } catch (error) { + result = error; + } + + expect(result).toBeDefined(); + }); + + it('should propagate thrown error when fetch throws an error', async () => { + // Given + global.fetch = jest.fn().mockRejectedValue(new Error('Network Error')); + + // When + let result; + try { + await sonataFlowService.fetchWorkflowInfoOnService({ + definitionId, + serviceUrl, + }); + } catch (error) { + result = error; + } + + expect(result).toBeDefined(); + }); + }); + describe('executeWorkflow', () => { + const serviceUrl = 'http://example.com/workflows'; + const definitionId = 'workflow-123'; + const urlToFetch = `${serviceUrl}/${definitionId}`; + const inputData = { var1: 'value1' }; + + const expectedFetchRequestInit = (): RequestInit => { + return { + method: 'POST', + body: JSON.stringify(inputData), + headers: { 'content-type': 'application/json' }, + }; + }; + + const setupTest = (responseConfig: { + ok: boolean; + status?: number; + statusText?: string; + json: any; + }): Partial => { + const mockResponse: Partial = { + ok: responseConfig.ok, + status: responseConfig.status || (responseConfig.ok ? 200 : 500), + statusText: responseConfig.statusText, + json: jest.fn().mockResolvedValue(responseConfig.json), + }; + global.fetch = jest.fn().mockResolvedValue(mockResponse as any); + return mockResponse; + }; + + const runErrorTest = async (): Promise< + WorkflowExecutionResponse | undefined + > => { + return await sonataFlowService.executeWorkflow({ + definitionId, + serviceUrl, + inputData, + }); + }; + + beforeEach(() => { + jest.clearAllMocks(); + }); + it('should return workflow execution response when the request is successful', async () => { + // Given + setupTest({ ok: true, json: { id: definitionId, status: 'completed' } }); + + // When + const result = await sonataFlowService.executeWorkflow({ + definitionId, + serviceUrl, + inputData: { var1: 'value1' }, + }); + + // Then + expect(fetch).toHaveBeenCalledWith( + urlToFetch, + expectedFetchRequestInit(), + ); + expect(result).toEqual({ id: definitionId, status: 'completed' }); + expect(loggerMock.debug).toHaveBeenCalledWith( + 'Execute workflow successful. Response: {"id":"workflow-123","status":"completed"}', + ); + // Verify that all other logger methods were not called + expect(loggerMock.debug).toHaveBeenCalledTimes(1); + expect(loggerMock.info).not.toHaveBeenCalled(); + expect(loggerMock.error).not.toHaveBeenCalled(); + expect(loggerMock.warn).not.toHaveBeenCalled(); + expect(loggerMock.child).not.toHaveBeenCalled(); + }); + + it('should include businessKey in the URL if provided', async () => { + // Given + const businessKey = 'key-123'; + setupTest({ ok: true, json: { id: definitionId, status: 'completed' } }); + + // When + const result = await sonataFlowService.executeWorkflow({ + definitionId, + serviceUrl, + inputData, + businessKey, + }); + + // Then + expect(fetch).toHaveBeenCalledWith( + `${serviceUrl}/${definitionId}?businessKey=${businessKey}`, + expectedFetchRequestInit(), + ); + expect(result).toEqual({ id: definitionId, status: 'completed' }); + }); + it('should propagate thrown error when the fetch response is not ok without extra info', async () => { + // When + setupTest({ + ok: false, + status: 500, + statusText: 'Internal Server Error', + json: { details: undefined, stack: undefined }, + }); + + let result; + try { + await runErrorTest(); + } catch (error) { + result = error; + } + + expect(result).toBeDefined(); + }); + it('should propagate thrown exception when the fetch response is not ok with extra info', async () => { + // When + setupTest({ + ok: false, + json: { details: 'Error details test', stack: 'Error stacktrace test' }, + }); + + let result; + try { + await runErrorTest(); + } catch (error) { + result = error; + } + + expect(result).toBeDefined(); + }); + it('should propagate thrown error when fetch throws an error', async () => { + // Given + global.fetch = jest.fn().mockRejectedValue(new Error('Network Error')); + + // When + let result; + try { + await sonataFlowService.executeWorkflow({ + definitionId, + serviceUrl, + inputData: inputData, + }); + } catch (error) { + result = error; + } + + expect(result).toBeDefined(); + }); + }); + + describe('createPrefixFetchErrorMessage', () => { + // Constants + const TEST_URL = 'http://example.com'; + const STATUS_TEXT_BAD_REQUEST = 'Bad Request'; + const STATUS_TEXT_NOT_FOUND = 'Not Found'; + const STATUS_TEXT_INTERNAL_SERVER_ERROR = 'Internal Server Error'; + const DETAILS = 'Some error details'; + const STACK_TRACE = 'Error stack trace'; + + it('should return the correct message with all fields provided', async () => { + // Given + const mockResponseJson = { details: DETAILS, stack: STACK_TRACE }; + const mockResponse = new Response(JSON.stringify(mockResponseJson), { + status: 400, + statusText: STATUS_TEXT_BAD_REQUEST, + }); + + // When + const result = await sonataFlowService.createPrefixFetchErrorMessage( + TEST_URL, + mockResponse, + 'POST', + ); + + // Then + const expectedMessage = `Request POST ${TEST_URL} failed with: StatusCode: 400 StatusText: ${STATUS_TEXT_BAD_REQUEST}, Details: ${DETAILS}, Stack: ${STACK_TRACE}`; + expect(result).toBe(expectedMessage); + }); + + it('should return the correct message without details and stack', async () => { + // Given + const mockResponseJson = {}; + const mockResponse = new Response(JSON.stringify(mockResponseJson), { + status: 404, + statusText: STATUS_TEXT_NOT_FOUND, + }); + + // When + const result = await sonataFlowService.createPrefixFetchErrorMessage( + TEST_URL, + mockResponse, + ); + + // Then + const expectedMessage = `Request GET ${TEST_URL} failed with: StatusCode: 404 StatusText: ${STATUS_TEXT_NOT_FOUND}`; + expect(result).toBe(expectedMessage); + }); + + it('should return the correct message with only status code', async () => { + // Given + const mockResponseJson = {}; + const mockResponse = new Response(JSON.stringify(mockResponseJson), { + status: 500, + }); + + // When + const result = await sonataFlowService.createPrefixFetchErrorMessage( + TEST_URL, + mockResponse, + ); + + // Then + const expectedMessage = `Request GET ${TEST_URL} failed with: StatusCode: 500 Unexpected error`; + expect(result).toBe(expectedMessage); + }); + + it('should return the unexpected error message if no other fields are present', async () => { + // Given + const mockResponseJson = {}; + const mockResponse = new Response(JSON.stringify(mockResponseJson)); + + // When + const result = await sonataFlowService.createPrefixFetchErrorMessage( + TEST_URL, + mockResponse, + ); + + // Then + const expectedMessage = `Request GET ${TEST_URL} failed with: StatusCode: 200 Unexpected error`; + expect(result).toBe(expectedMessage); + }); + + it('should handle response with undefined JSON gracefully', async () => { + // Given + const mockResponse = new Response(undefined, { + status: 500, + statusText: STATUS_TEXT_INTERNAL_SERVER_ERROR, + }); + jest.spyOn(mockResponse, 'json').mockResolvedValue(undefined); + + // When + const result = await sonataFlowService.createPrefixFetchErrorMessage( + TEST_URL, + mockResponse, + ); + + // Then + const expectedMessage = `Request GET ${TEST_URL} failed with: StatusCode: 500 StatusText: ${STATUS_TEXT_INTERNAL_SERVER_ERROR}`; + expect(result).toBe(expectedMessage); + }); + }); +}); diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/src/service/SonataFlowService.ts b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/SonataFlowService.ts new file mode 100644 index 00000000..1206f8de --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/SonataFlowService.ts @@ -0,0 +1,256 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { LoggerService } from '@backstage/backend-plugin-api'; + +import { + extractWorkflowFormat, + Filter, + fromWorkflowSource, + getWorkflowCategory, + ProcessInstanceStateValues, + ProcessInstanceVariables, + WorkflowDefinition, + WorkflowExecutionResponse, + WorkflowInfo, + WorkflowOverview, +} from '@red-hat-developer-hub/backstage-plugin-orchestrator-common'; + +import { Pagination } from '../types/pagination'; +import { DataIndexService } from './DataIndexService'; + +export class SonataFlowService { + constructor( + private readonly dataIndexService: DataIndexService, + private readonly logger: LoggerService, + ) {} + + public async fetchWorkflowInfoOnService(args: { + definitionId: string; + serviceUrl: string; + }): Promise { + const urlToFetch = `${args.serviceUrl}/management/processes/${args.definitionId}`; + const response = await fetch(urlToFetch); + + if (response.ok) { + const json = await response.json(); + this.logger.debug(`Fetch workflow info result: ${JSON.stringify(json)}`); + return json; + } + throw new Error( + await this.createPrefixFetchErrorMessage(urlToFetch, response), + ); + } + + public async fetchWorkflowDefinition( + definitionId: string, + ): Promise { + const source = await this.dataIndexService.fetchWorkflowSource( + definitionId, + ); + if (source) { + return fromWorkflowSource(source); + } + return undefined; + } + + public async fetchWorkflowOverviews(args: { + definitionIds?: string[]; + pagination?: Pagination; + filter?: Filter; + }): Promise { + const { definitionIds, pagination, filter } = args; + const workflowInfos = await this.dataIndexService.fetchWorkflowInfos({ + definitionIds, + pagination, + filter, + }); + if (!workflowInfos?.length) { + return []; + } + const items = await Promise.all( + workflowInfos + .filter(info => info.source) + .map(info => this.fetchWorkflowOverviewBySource(info.source!)), + ); + return items.filter((item): item is WorkflowOverview => !!item); + } + + public async executeWorkflow(args: { + definitionId: string; + serviceUrl: string; + inputData: ProcessInstanceVariables; + businessKey?: string; + }): Promise { + const urlToFetch = args.businessKey + ? `${args.serviceUrl}/${args.definitionId}?businessKey=${args.businessKey}` + : `${args.serviceUrl}/${args.definitionId}`; + + const response = await fetch(urlToFetch, { + method: 'POST', + body: JSON.stringify(args.inputData), + headers: { 'content-type': 'application/json' }, + }); + + const json = await response.json(); + if (json.id) { + this.logger.debug( + `Execute workflow successful. Response: ${JSON.stringify(json)}`, + ); + return json; + } else if (!response.ok) { + const errorMessage = await this.createPrefixFetchErrorMessage( + urlToFetch, + response, + 'POST', + ); + this.logger.error( + `Execute workflow failed. Response: ${JSON.stringify(json)}`, + ); + throw new Error(errorMessage); + } else { + this.logger.error( + `Execute workflow did not return a workflow instance ID. Response: ${JSON.stringify( + json, + )}`, + ); + throw new Error('Execute workflow did not return a workflow instance ID'); + } + } + + public async retriggerInstance(args: { + definitionId: string; + instanceId: string; + serviceUrl: string; + }): Promise { + const urlToFetch = `${args.serviceUrl}/management/processes/${args.definitionId}/instances/${args.instanceId}/retrigger`; + + const response = await fetch(urlToFetch, { + method: 'POST', + }); + + if (!response.ok) { + throw new Error( + `${await this.createPrefixFetchErrorMessage( + urlToFetch, + response, + 'POST', + )}`, + ); + } + + return true; + } + + public async fetchWorkflowOverview( + definitionId: string, + ): Promise { + const source = await this.dataIndexService.fetchWorkflowSource( + definitionId, + ); + if (!source) { + this.logger.debug(`Workflow source not found: ${definitionId}`); + return undefined; + } + return await this.fetchWorkflowOverviewBySource(source); + } + + private async fetchWorkflowOverviewBySource( + source: string, + ): Promise { + let lastTriggered: Date = new Date(0); + let lastRunStatus: ProcessInstanceStateValues | undefined; + let lastRunId: string | undefined; + const definition = fromWorkflowSource(source); + + const processInstances = + await this.dataIndexService.fetchInstancesByDefinitionId({ + definitionId: definition.id, + limit: 1, + offset: 0, + }); + + const pInstance = processInstances[0]; + + if (pInstance.start) { + lastRunId = pInstance.id; + lastTriggered = new Date(pInstance.start); + lastRunStatus = pInstance.state; + } + + return { + workflowId: definition.id, + name: definition.name, + format: extractWorkflowFormat(source), + lastRunId, + lastTriggeredMs: lastTriggered.getTime(), + lastRunStatus, + category: getWorkflowCategory(definition), + description: definition.description, + }; + } + + public async pingWorkflowService(args: { + definitionId: string; + serviceUrl: string; + }): Promise { + const urlToFetch = `${args.serviceUrl}/management/processes/${args.definitionId}`; + const response = await fetch(urlToFetch); + return response.ok; + } + + public async updateInstanceInputData(args: { + definitionId: string; + serviceUrl: string; + instanceId: string; + inputData: ProcessInstanceVariables; + }): Promise { + const { definitionId, serviceUrl, instanceId, inputData } = args; + const urlToFetch = `${serviceUrl}/${definitionId}/${instanceId}`; + const response = await fetch(urlToFetch, { + method: 'PATCH', + body: JSON.stringify(inputData), + headers: { 'content-type': 'application/json' }, + }); + return response.ok; + } + + public async createPrefixFetchErrorMessage( + urlToFetch: string, + response: Response, + httpMethod = 'GET', + ): Promise { + const res = await response.json(); + const errorInfo = []; + let errorMsg = `Request ${httpMethod} ${urlToFetch} failed with: StatusCode: ${response.status}`; + + if (response.statusText) { + errorInfo.push(`StatusText: ${response.statusText}`); + } + if (res?.details) { + errorInfo.push(`Details: ${res?.details}`); + } + if (res?.stack) { + errorInfo.push(`Stack: ${res?.stack}`); + } + if (errorInfo.length > 0) { + errorMsg += ` ${errorInfo.join(', ')}`; + } else { + errorMsg += ' Unexpected error'; + } + + return errorMsg; + } +} diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/src/service/WorkflowCacheService.ts b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/WorkflowCacheService.ts new file mode 100644 index 00000000..2c121c99 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/WorkflowCacheService.ts @@ -0,0 +1,127 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { LoggerService } from '@backstage/backend-plugin-api'; +import { PluginTaskScheduler } from '@backstage/backend-tasks'; + +import { DataIndexService } from './DataIndexService'; +import { SonataFlowService } from './SonataFlowService'; + +export type CacheHandler = 'skip' | 'throw'; + +export class WorkflowCacheService { + private readonly TASK_ID = 'task__Orchestrator__WorkflowCacheService'; + private readonly DEFAULT_FREQUENCY_IN_SECONDS = 5; + private readonly DEFAULT_TIMEOUT_IN_MINUTES = 10; + private readonly definitionIdCache = new Set(); + + constructor( + private readonly logger: LoggerService, + private readonly dataIndexService: DataIndexService, + private readonly sonataFlowService: SonataFlowService, + ) {} + + public get definitionIds(): string[] { + return Array.from(this.definitionIdCache); + } + + public isEmpty(): boolean { + return this.definitionIdCache.size === 0; + } + + public isAvailable( + definitionId?: string, + cacheHandler: CacheHandler = 'skip', + ): boolean { + if (!definitionId) { + return false; + } + const isAvailable = this.definitionIdCache.has(definitionId); + if (!isAvailable && cacheHandler === 'throw') { + throw new Error( + `Workflow service "${definitionId}" not available at the moment`, + ); + } + return isAvailable; + } + + public schedule(args: { + scheduler: PluginTaskScheduler; + frequencyInSeconds?: number; + timeoutInMinutes?: number; + }): void { + const { + scheduler, + frequencyInSeconds = this.DEFAULT_FREQUENCY_IN_SECONDS, + timeoutInMinutes = this.DEFAULT_TIMEOUT_IN_MINUTES, + } = args; + + scheduler.scheduleTask({ + id: this.TASK_ID, + frequency: { seconds: frequencyInSeconds }, + timeout: { minutes: timeoutInMinutes }, + fn: async () => { + await this.runTask(); + }, + }); + } + + private async runTask() { + try { + const idUrlMap = await this.dataIndexService.fetchWorkflowServiceUrls(); + this.definitionIdCache.forEach(definitionId => { + if (!idUrlMap[definitionId]) { + this.definitionIdCache.delete(definitionId); + } + }); + await Promise.all( + Object.entries(idUrlMap).map(async ([definitionId, serviceUrl]) => { + let isServiceUp = false; + try { + isServiceUp = await this.sonataFlowService.pingWorkflowService({ + definitionId, + serviceUrl, + }); + } catch (err) { + this.logger.error( + `Ping workflow ${definitionId} service threw error: ${err}`, + ); + } + if (isServiceUp) { + this.definitionIdCache.add(definitionId); + } else { + this.logger.error( + `Failed to ping service for workflow ${definitionId} at ${serviceUrl}`, + ); + if (this.definitionIdCache.has(definitionId)) { + this.definitionIdCache.delete(definitionId); + } + } + }), + ); + + const workflowDefinitionIds = this.isEmpty() + ? 'empty cache' + : Array.from(this.definitionIdCache).join(', '); + + this.logger.debug( + `${this.TASK_ID} updated the workflow definition ID cache to: ${workflowDefinitionIds}`, + ); + } catch (error) { + this.logger.error(`Error running ${this.TASK_ID}: ${error}`); + return; + } + } +} diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/src/service/__fixtures__/mockProcessDefinitionArgumentsData.ts b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/__fixtures__/mockProcessDefinitionArgumentsData.ts new file mode 100644 index 00000000..8958b318 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/__fixtures__/mockProcessDefinitionArgumentsData.ts @@ -0,0 +1,120 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { + IntrospectionField, + TypeKind, + TypeName, +} from '@red-hat-developer-hub/backstage-plugin-orchestrator-common'; + +export const mockProcessDefinitionArguments = { + __type: { + kind: 'INPUT_OBJECT', + name: 'ProcessDefinitionArgument', + inputFields: [ + { + name: 'and', + type: { + kind: 'LIST', + name: null, + ofType: { + kind: 'NON_NULL', + name: null, + ofType: { + kind: 'INPUT_OBJECT', + name: 'ProcessDefinitionArgument', + ofType: null, + }, + }, + }, + }, + { + name: 'or', + type: { + kind: 'LIST', + name: null, + ofType: { + kind: 'NON_NULL', + name: null, + ofType: { + kind: 'INPUT_OBJECT', + name: 'ProcessDefinitionArgument', + ofType: null, + }, + }, + }, + }, + { + name: 'not', + type: { + kind: 'INPUT_OBJECT', + name: 'ProcessDefinitionArgument', + ofType: null, + }, + }, + { + name: 'id', + type: { + kind: 'INPUT_OBJECT', + name: 'StringArgument', + ofType: null, + }, + }, + { + name: 'name', + type: { + kind: 'INPUT_OBJECT', + name: 'StringArgument', + ofType: null, + }, + }, + { + name: 'version', + type: { + kind: 'INPUT_OBJECT', + name: 'StringArgument', + ofType: null, + }, + }, + ], + }, +}; + +export const mockProcessDefinitionIntrospection: IntrospectionField[] = [ + { + name: 'id', + type: { + kind: TypeKind.InputObject, + name: TypeName.String, + ofType: null, + }, + }, + { + name: 'name', + type: { + kind: TypeKind.InputObject, + name: TypeName.String, + ofType: null, + }, + }, + { + name: 'version', + type: { + kind: TypeKind.InputObject, + name: TypeName.String, + ofType: null, + }, + }, +]; diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/src/service/__fixtures__/mockProcessInstanceArgumentsData.ts b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/__fixtures__/mockProcessInstanceArgumentsData.ts new file mode 100644 index 00000000..2fc79080 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/__fixtures__/mockProcessInstanceArgumentsData.ts @@ -0,0 +1,369 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { + IntrospectionField, + TypeKind, + TypeName, +} from '@red-hat-developer-hub/backstage-plugin-orchestrator-common'; + +export const mockProcessInstanceArguments = { + __type: { + kind: 'INPUT_OBJECT', + name: 'ProcessInstanceArgument', + inputFields: [ + { + name: 'and', + type: { + kind: 'LIST', + name: null, + ofType: { + kind: 'NON_NULL', + name: null, + ofType: { + kind: 'INPUT_OBJECT', + name: 'ProcessInstanceArgument', + ofType: null, + }, + }, + }, + }, + { + name: 'or', + type: { + kind: 'LIST', + name: null, + ofType: { + kind: 'NON_NULL', + name: null, + ofType: { + kind: 'INPUT_OBJECT', + name: 'ProcessInstanceArgument', + ofType: null, + }, + }, + }, + }, + { + name: 'not', + type: { + kind: 'INPUT_OBJECT', + name: 'ProcessInstanceArgument', + ofType: null, + }, + }, + { + name: 'id', + type: { + kind: 'INPUT_OBJECT', + name: 'IdArgument', + ofType: null, + }, + }, + { + name: 'processId', + type: { + kind: 'INPUT_OBJECT', + name: 'StringArgument', + ofType: null, + }, + }, + { + name: 'processName', + type: { + kind: 'INPUT_OBJECT', + name: 'StringArgument', + ofType: null, + }, + }, + { + name: 'parentProcessInstanceId', + type: { + kind: 'INPUT_OBJECT', + name: 'IdArgument', + ofType: null, + }, + }, + { + name: 'rootProcessInstanceId', + type: { + kind: 'INPUT_OBJECT', + name: 'IdArgument', + ofType: null, + }, + }, + { + name: 'rootProcessId', + type: { + kind: 'INPUT_OBJECT', + name: 'StringArgument', + ofType: null, + }, + }, + // { + // name: 'state', + // type: { + // kind: 'INPUT_OBJECT', + // name: 'ProcessInstanceStateArgument', + // ofType: null, + // }, + // }, + // { + // name: 'error', + // type: { + // kind: 'INPUT_OBJECT', + // name: 'ProcessInstanceErrorArgument', + // ofType: null, + // }, + // }, + // { + // name: 'nodes', + // type: { + // kind: 'INPUT_OBJECT', + // name: 'NodeInstanceArgument', + // ofType: null, + // }, + // }, + // { + // name: 'milestones', + // type: { + // kind: 'INPUT_OBJECT', + // name: 'MilestoneArgument', + // ofType: null, + // }, + // }, + { + name: 'endpoint', + type: { + kind: 'INPUT_OBJECT', + name: 'StringArgument', + ofType: null, + }, + }, + // { + // name: 'roles', + // type: { + // kind: 'INPUT_OBJECT', + // name: 'StringArrayArgument', + // ofType: null, + // }, + // }, + { + name: 'start', + type: { + kind: 'INPUT_OBJECT', + name: 'DateArgument', + ofType: null, + }, + }, + { + name: 'end', + type: { + kind: 'INPUT_OBJECT', + name: 'DateArgument', + ofType: null, + }, + }, + // { + // name: 'addons', + // type: { + // kind: 'INPUT_OBJECT', + // name: 'StringArrayArgument', + // ofType: null, + // }, + // }, + { + name: 'lastUpdate', + type: { + kind: 'INPUT_OBJECT', + name: 'DateArgument', + ofType: null, + }, + }, + { + name: 'businessKey', + type: { + kind: 'INPUT_OBJECT', + name: 'StringArgument', + ofType: null, + }, + }, + { + name: 'createdBy', + type: { + kind: 'INPUT_OBJECT', + name: 'StringArgument', + ofType: null, + }, + }, + { + name: 'updatedBy', + type: { + kind: 'INPUT_OBJECT', + name: 'StringArgument', + ofType: null, + }, + }, + ], + }, +}; + +export const mockProcessInstanceIntrospection: IntrospectionField[] = [ + { + name: 'id', + type: { + kind: TypeKind.InputObject, + name: TypeName.Id, + ofType: null, + }, + }, + { + name: 'processId', + type: { + kind: TypeKind.InputObject, + name: TypeName.String, + ofType: null, + }, + }, + { + name: 'processName', + type: { + kind: TypeKind.InputObject, + name: TypeName.String, + ofType: null, + }, + }, + { + name: 'parentProcessInstanceId', + type: { + kind: TypeKind.InputObject, + name: TypeName.Id, + ofType: null, + }, + }, + { + name: 'rootProcessInstanceId', + type: { + kind: TypeKind.InputObject, + name: TypeName.Id, + ofType: null, + }, + }, + { + name: 'rootProcessId', + type: { + kind: TypeKind.InputObject, + name: TypeName.String, + ofType: null, + }, + }, + + // { + // name: 'error', + // type: { + // kind: TypeKind.InputObject, + // name: 'ProcessInstanceErrorArgument', + // ofType: null, + // }, + // }, + // { + // name: 'nodes', + // type: { + // kind: TypeKind.InputObject, + // name: 'NodeInstanceArgument', + // ofType: null, + // }, + // }, + // { + // name: 'milestones', + // type: { + // kind: TypeKind.InputObject, + // name: 'MilestoneArgument', + // ofType: null, + // }, + // }, + { + name: 'endpoint', + type: { + kind: TypeKind.InputObject, + name: TypeName.String, + ofType: null, + }, + }, + // { + // name: 'roles', + // type: { + // kind: TypeKind.InputObject, + // name: TypeName.StringArray, + // ofType: null, + // }, + // }, + { + name: 'start', + type: { + kind: TypeKind.InputObject, + name: TypeName.Date, + ofType: null, + }, + }, + { + name: 'end', + type: { + kind: TypeKind.InputObject, + name: TypeName.Date, + ofType: null, + }, + }, + // { + // name: 'addons', + // type: { + // kind: TypeKind.InputObject, + // name: TypeName.StringArray, + // ofType: null, + // }, + // }, + { + name: 'lastUpdate', + type: { + kind: TypeKind.InputObject, + name: TypeName.Date, + ofType: null, + }, + }, + { + name: 'businessKey', + type: { + kind: TypeKind.InputObject, + name: TypeName.String, + ofType: null, + }, + }, + { + name: 'createdBy', + type: { + kind: TypeKind.InputObject, + name: TypeName.String, + ofType: null, + }, + }, + { + name: 'updatedBy', + type: { + kind: TypeKind.InputObject, + name: TypeName.String, + ofType: null, + }, + }, +]; diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/src/service/api/mapping/V2Mappings.test.ts b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/api/mapping/V2Mappings.test.ts new file mode 100644 index 00000000..7052d514 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/api/mapping/V2Mappings.test.ts @@ -0,0 +1,174 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import moment from 'moment'; + +import { + ProcessInstance, + ProcessInstanceState, + WorkflowOverview, + WorkflowRunStatusDTO, +} from '@red-hat-developer-hub/backstage-plugin-orchestrator-common'; + +import { + generateProcessInstance, + generateTestExecuteWorkflowResponse, + generateTestWorkflowOverview, +} from '../test-utils'; +import { + getProcessInstancesStatusDTOFromString, + mapToExecuteWorkflowResponseDTO, + mapToProcessInstanceDTO, + mapToWorkflowOverviewDTO, + mapToWorkflowRunStatusDTO, + mapWorkflowCategoryDTOFromString, +} from './V2Mappings'; + +describe('scenarios to verify executeWorkflowResponseDTO', () => { + it('correctly maps positive scenario response', async () => { + const execWorkflowResp = generateTestExecuteWorkflowResponse(); + const mappedValue = mapToExecuteWorkflowResponseDTO( + 'test_workflowId', + execWorkflowResp, + ); + expect(mappedValue).toBeDefined(); + expect(mappedValue.id).toBeDefined(); + expect(Object.keys(mappedValue).length).toBe(1); + }); + + it('throws error when no id attribute present in response', async () => { + expect(() => { + mapToExecuteWorkflowResponseDTO('workflowId', { id: '' }); + }).toThrow( + `Error while mapping ExecuteWorkflowResponse to ExecuteWorkflowResponseDTO for workflow with id`, + ); + }); +}); + +describe('scenarios to verify mapToWorkflowOverviewDTO', () => { + it('correctly maps WorkflowOverview', () => { + // Arrange + const overview: WorkflowOverview = generateTestWorkflowOverview({ + category: 'assessment', + }); + + // Act + const result = mapToWorkflowOverviewDTO(overview); + + // Assert + expect(result.workflowId).toBe(overview.workflowId); + expect(result.name).toBe(overview.name); + expect(result.format).toBe(overview.format); + expect(result.lastTriggeredMs).toBe(overview.lastTriggeredMs); + expect(result.lastRunStatus).toBe( + getProcessInstancesStatusDTOFromString(overview.lastRunStatus), + ); + expect(result.category).toBe('assessment'); + expect(result.avgDurationMs).toBe(overview.avgDurationMs); + expect(result.description).toBe(overview.description); + }); +}); +describe('scenarios to verify mapWorkflowCategoryDTOFromString', () => { + test.each([ + { input: 'assessment', expected: 'assessment' }, + { input: 'infrastructure', expected: 'infrastructure' }, + { input: 'random category', expected: 'infrastructure' }, + ])('mapWorkflowCategoryDTOFromString($input)', ({ input, expected }) => { + // Arrange + const overview: WorkflowOverview = generateTestWorkflowOverview({ + category: input, + }); + + // Act + const resultCategory = mapWorkflowCategoryDTOFromString(overview.category); + + // Assert + expect(resultCategory).toBeDefined(); + expect(resultCategory).toBe(expected); + }); +}); + +describe('scenarios to verify mapToProcessInstanceDTO', () => { + it('correctly maps ProcessInstanceDTO for not completed workflow', () => { + // Arrange + const processInstanceV1: ProcessInstance = generateProcessInstance(1); + processInstanceV1.end = undefined; + + // Act + const result = mapToProcessInstanceDTO(processInstanceV1); + + // Assert + expect(result).toBeDefined(); + expect(result.id).toBeDefined(); + expect(result.start).toBeDefined(); + expect(result.start).toEqual(processInstanceV1.start); + expect(result.end).toBeUndefined(); + expect(result.duration).toBeUndefined(); + expect(result.status).toEqual( + getProcessInstancesStatusDTOFromString(processInstanceV1.state), + ); + expect(result.description).toEqual(processInstanceV1.description); + expect(result.category).toEqual('infrastructure'); + expect(result.workflowdata).toEqual( + // @ts-ignore + processInstanceV1?.variables?.workflowdata, + ); + }); + it('correctly maps ProcessInstanceDTO', () => { + // Arrange + const processIntanceV1: ProcessInstance = generateProcessInstance(1); + + const start = moment(processIntanceV1.start); + const end = moment(processIntanceV1.end); + const duration = moment.duration(start.diff(end)).humanize(); + // Act + const result = mapToProcessInstanceDTO(processIntanceV1); + + // Assert + expect(result.id).toBeDefined(); + expect(result.start).toEqual(processIntanceV1.start); + expect(result.end).toBeDefined(); + expect(result.end).toEqual(processIntanceV1.end); + expect(result.duration).toEqual(duration); + + expect(result).toBeDefined(); + expect(result.status).toEqual( + getProcessInstancesStatusDTOFromString(processIntanceV1.state), + ); + expect(result.end).toEqual(processIntanceV1.end); + expect(result.duration).toEqual(duration); + expect(result.duration).toEqual('an hour'); + expect(result.description).toEqual(processIntanceV1.description); + expect(result.category).toEqual('infrastructure'); + expect(result.workflowdata).toEqual( + // @ts-ignore + processIntanceV1?.variables?.workflowdata, + ); + }); +}); + +describe('scenarios to verify mapToWorkflowRunStatusDTO', () => { + it('correctly maps ProcessInstanceState to WorkflowRunStatusDTO', async () => { + const mappedValue: WorkflowRunStatusDTO = mapToWorkflowRunStatusDTO( + ProcessInstanceState.Active, + ); + + expect(mappedValue).toBeDefined(); + expect(mappedValue.key).toBeDefined(); + expect(mappedValue.value).toBeDefined(); + expect(mappedValue.key).toEqual('Active'); + expect(mappedValue.value).toEqual('ACTIVE'); + }); +}); diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/src/service/api/mapping/V2Mappings.ts b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/api/mapping/V2Mappings.ts new file mode 100644 index 00000000..ad889a4c --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/api/mapping/V2Mappings.ts @@ -0,0 +1,209 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import moment from 'moment'; + +import { + capitalize, + ExecuteWorkflowResponseDTO, + extractWorkflowFormat, + fromWorkflowSource, + getWorkflowCategory, + NodeInstance, + NodeInstanceDTO, + ProcessInstance, + ProcessInstanceDTO, + ProcessInstanceState, + ProcessInstanceStatusDTO, + WorkflowCategory, + WorkflowCategoryDTO, + WorkflowDefinition, + WorkflowDTO, + WorkflowExecutionResponse, + WorkflowFormatDTO, + WorkflowOverview, + WorkflowOverviewDTO, + WorkflowRunStatusDTO, +} from '@red-hat-developer-hub/backstage-plugin-orchestrator-common'; + +// Mapping functions +export function mapToWorkflowOverviewDTO( + overview: WorkflowOverview, +): WorkflowOverviewDTO { + return { + name: overview.name, + format: overview.format, + workflowId: overview.workflowId, + avgDurationMs: overview.avgDurationMs, + description: overview.description, + lastRunId: overview.lastRunId, + lastRunStatus: overview.lastRunStatus + ? getProcessInstancesStatusDTOFromString(overview.lastRunStatus) + : undefined, + lastTriggeredMs: overview.lastTriggeredMs, + category: mapWorkflowCategoryDTOFromString(overview.category), + }; +} + +export function mapWorkflowCategoryDTOFromString( + category?: string, +): WorkflowCategoryDTO { + return category?.toLocaleLowerCase() === 'assessment' + ? 'assessment' + : 'infrastructure'; +} + +export function getWorkflowCategoryDTO( + definition: WorkflowDefinition | undefined, +): WorkflowCategoryDTO { + return getWorkflowCategory(definition); +} + +export function getWorkflowFormatDTO(source: string): WorkflowFormatDTO { + return extractWorkflowFormat(source); +} + +export function mapToWorkflowDTO(source: string): WorkflowDTO { + const definition = fromWorkflowSource(source); + return { + annotations: definition.annotations, + category: getWorkflowCategoryDTO(definition), + description: definition.description, + name: definition.name, + format: getWorkflowFormatDTO(source), + id: definition.id, + }; +} + +export function mapWorkflowCategoryDTO( + category?: WorkflowCategory, +): WorkflowCategoryDTO { + if (category === WorkflowCategory.ASSESSMENT) { + return 'assessment'; + } + return 'infrastructure'; +} + +export function getProcessInstancesStatusDTOFromString( + state?: string, +): ProcessInstanceStatusDTO { + switch (state) { + case ProcessInstanceState.Active.valueOf(): + return 'Active'; + case ProcessInstanceState.Error.valueOf(): + return 'Error'; + case ProcessInstanceState.Completed.valueOf(): + return 'Completed'; + case ProcessInstanceState.Aborted.valueOf(): + return 'Aborted'; + case ProcessInstanceState.Suspended.valueOf(): + return 'Suspended'; + case ProcessInstanceState.Pending.valueOf(): + return 'Pending'; + default: + throw new Error( + `state ${state} is not one of the values of type ProcessInstanceStatusDTO`, + ); + } +} + +export function getProcessInstanceStateFromStatusDTOString( + status?: ProcessInstanceStatusDTO, +): string { + switch (status) { + case 'Active': + return ProcessInstanceState.Active.valueOf(); + case 'Error': + return ProcessInstanceState.Error.valueOf(); + case 'Completed': + return ProcessInstanceState.Completed.valueOf(); + case 'Aborted': + return ProcessInstanceState.Aborted.valueOf(); + case 'Suspended': + return ProcessInstanceState.Suspended.valueOf(); + case 'Pending': + return ProcessInstanceState.Pending.valueOf(); + default: + throw new Error( + `status ${status} is not one of the values of type ProcessInstanceState`, + ); + } +} + +export function mapToProcessInstanceDTO( + processInstance: ProcessInstance, +): ProcessInstanceDTO { + const start = moment(processInstance.start); + const end = moment(processInstance.end); + const duration = processInstance.end + ? moment.duration(start.diff(end)).humanize() + : undefined; + + let variables: Record | undefined; + if (typeof processInstance?.variables === 'string') { + variables = JSON.parse(processInstance?.variables); + } else { + variables = processInstance?.variables; + } + + return { + id: processInstance.id, + processId: processInstance.processId, + processName: processInstance.processName, + description: processInstance.description, + serviceUrl: processInstance.serviceUrl, + businessKey: processInstance.businessKey, + endpoint: processInstance.endpoint, + error: processInstance.error, + category: mapWorkflowCategoryDTO(processInstance.category), + start: processInstance.start, + end: processInstance.end, + duration: duration, + // @ts-ignore + workflowdata: variables?.workflowdata, + status: getProcessInstancesStatusDTOFromString(processInstance.state), + nodes: processInstance.nodes.map(mapToNodeInstanceDTO), + }; +} + +export function mapToNodeInstanceDTO( + nodeInstance: NodeInstance, +): NodeInstanceDTO { + return { ...nodeInstance, __typename: 'NodeInstance' }; +} + +export function mapToExecuteWorkflowResponseDTO( + workflowId: string, + workflowExecutionResponse: WorkflowExecutionResponse, +): ExecuteWorkflowResponseDTO { + if (!workflowExecutionResponse?.id) { + throw new Error( + `Error while mapping ExecuteWorkflowResponse to ExecuteWorkflowResponseDTO for workflow with id ${workflowId}`, + ); + } + + return { + id: workflowExecutionResponse.id, + }; +} + +export function mapToWorkflowRunStatusDTO( + status: ProcessInstanceState, +): WorkflowRunStatusDTO { + return { + key: capitalize(status), + value: status, + }; +} diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/src/service/api/mapping/__fixtures__/assessedProcessInstance.json b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/api/mapping/__fixtures__/assessedProcessInstance.json new file mode 100644 index 00000000..f6ebc90f --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/api/mapping/__fixtures__/assessedProcessInstance.json @@ -0,0 +1,143 @@ +{ + "instance": { + "id": "026f38fc-6121-46c7-9fa8-3f4b8207bab9", + "processName": "Assessment", + "processId": "assessment", + "businessKey": null, + "state": "COMPLETED", + "start": "2024-02-15T16:11:35.829Z", + "lastUpdate": "2024-02-15T16:11:35.829Z", + "end": "2024-02-15T16:11:35.822Z", + "nodes": [ + { + "id": "3290d3c5-c7c0-4920-a1dc-7a37d98d22b7", + "nodeId": "_jbpm-unique-51", + "definitionId": "_jbpm-unique-51", + "type": "WorkItemNode", + "name": "execute", + "enter": "2024-02-15T16:11:33.485Z", + "exit": "2024-02-15T16:11:35.828Z" + }, + { + "id": "2813e81e-0c38-424f-a505-639b1d33341b", + "nodeId": "_jbpm-unique-50", + "definitionId": "_jbpm-unique-50", + "type": "StartNode", + "name": "EmbeddedStart", + "enter": "2024-02-15T16:11:33.477Z", + "exit": "2024-02-15T16:11:35.829Z" + }, + { + "id": "f15d5540-0df7-401c-991e-3c45755b1302", + "nodeId": "_jbpm-unique-47", + "definitionId": "_jbpm-unique-47", + "type": "StartNode", + "name": "Start", + "enter": "2024-02-15T16:11:33.472Z", + "exit": "2024-02-15T16:11:35.829Z" + }, + { + "id": "142fcd3a-64e6-4539-a6b9-5ba2064623a1", + "nodeId": "_jbpm-unique-48", + "definitionId": "_jbpm-unique-48", + "type": "EndNode", + "name": "End", + "enter": "2024-02-15T16:11:35.821Z", + "exit": "2024-02-15T16:11:35.827Z" + }, + { + "id": "97e209c4-ae0a-4d09-8b00-4bd9ca062126", + "nodeId": "_jbpm-unique-59", + "definitionId": "_jbpm-unique-59", + "type": "ActionNode", + "name": "Script", + "enter": "2024-02-15T16:11:35.812Z", + "exit": "2024-02-15T16:11:35.827Z" + }, + { + "id": "f415ddd5-ba25-4e0a-be93-797b5f0ae6f3", + "nodeId": "_jbpm-unique-49", + "definitionId": "_jbpm-unique-49", + "type": "CompositeContextNode", + "name": "AssessRepository", + "enter": "2024-02-15T16:11:33.476Z", + "exit": "2024-02-15T16:11:35.827Z" + }, + { + "id": "10879e09-12c0-4770-be2b-d2fd27858edc", + "nodeId": "_jbpm-unique-58", + "definitionId": "_jbpm-unique-58", + "type": "EndNode", + "name": "EmbeddedEnd", + "enter": "2024-02-15T16:11:35.812Z", + "exit": "2024-02-15T16:11:35.827Z" + }, + { + "id": "96bb3b01-2a4a-44b2-b29c-da6dc7448450", + "nodeId": "_jbpm-unique-57", + "definitionId": "_jbpm-unique-57", + "type": "ActionNode", + "name": "Script", + "enter": "2024-02-15T16:11:35.811Z", + "exit": "2024-02-15T16:11:35.827Z" + }, + { + "id": "491975f5-4d6a-4a43-ac00-1e305bfcd97a", + "nodeId": "_jbpm-unique-56", + "definitionId": "_jbpm-unique-56", + "type": "ActionNode", + "name": "logOuput", + "enter": "2024-02-15T16:11:35.809Z", + "exit": "2024-02-15T16:11:35.828Z" + }, + { + "id": "bc4ddb8a-f551-442a-a0d9-7f96a8332a09", + "nodeId": "_jbpm-unique-55", + "definitionId": "_jbpm-unique-55", + "type": "ActionNode", + "name": "Script", + "enter": "2024-02-15T16:11:35.807Z", + "exit": "2024-02-15T16:11:35.828Z" + }, + { + "id": "effbf2d7-8201-48de-8f81-3983fb26d591", + "nodeId": "_jbpm-unique-54", + "definitionId": "_jbpm-unique-54", + "type": "WorkItemNode", + "name": "preCheck", + "enter": "2024-02-15T16:11:33.896Z", + "exit": "2024-02-15T16:11:35.828Z" + }, + { + "id": "54c7da48-de5c-4e62-868b-ad6c7ef25ad3", + "nodeId": "_jbpm-unique-53", + "definitionId": "_jbpm-unique-53", + "type": "ActionNode", + "name": "Script", + "enter": "2024-02-15T16:11:33.894Z", + "exit": "2024-02-15T16:11:35.828Z" + }, + { + "id": "bfc5796c-8aa7-4c4f-aa11-dc91aee24ea2", + "nodeId": "_jbpm-unique-52", + "definitionId": "_jbpm-unique-52", + "type": "ActionNode", + "name": "Script", + "enter": "2024-02-15T16:11:33.826Z", + "exit": "2024-02-15T16:11:35.828Z" + } + ], + "variables": { + "workflowdata": { + "result": "[Object]", + "preCheck": "[Object]", + "repositoryUrl": "https://java.com", + "workflowOptions": "[Object]" + } + }, + "parentProcessInstance": null, + "error": null, + "category": "assessment", + "description": "undefined" + } +} diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/src/service/api/test-utils.ts b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/api/test-utils.ts new file mode 100644 index 00000000..010f4aa0 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/api/test-utils.ts @@ -0,0 +1,158 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import moment from 'moment'; + +import { + ProcessInstance, + ProcessInstanceState, + ProcessInstanceStateValues, + WorkflowCategory, + WorkflowDefinition, + WorkflowExecutionResponse, + WorkflowFormat, + WorkflowInfo, + WorkflowOverview, + WorkflowOverviewListResult, +} from '@red-hat-developer-hub/backstage-plugin-orchestrator-common'; + +const BASE_DATE = '2023-02-19T11:45:21.123Z'; + +interface WorkflowOverviewParams { + suffix?: string; + workflowId?: string; + name?: string; + format?: WorkflowFormat; + lastTriggeredMs?: number; + lastRunStatus?: ProcessInstanceStateValues; + category?: string; + avgDurationMs?: number; + description?: string; +} +export function generateTestWorkflowOverview( + params: WorkflowOverviewParams, +): WorkflowOverview { + return { + workflowId: params.workflowId ?? `testWorkflowId${params.suffix}`, + name: params.name ?? `Test Workflow${params.suffix}`, + format: params.format ?? 'yaml', + lastTriggeredMs: + params.lastTriggeredMs ?? Date.parse('2024-02-09T10:34:56Z'), + lastRunStatus: params.lastRunStatus ?? ProcessInstanceState.Completed, + category: params.category ?? 'assessment', // validate input + avgDurationMs: params.avgDurationMs ?? 1000, + description: params.description ?? 'Test Workflow Description', + }; +} + +export function generateTestWorkflowOverviewList( + howmany: number, + inputParams?: WorkflowOverviewParams, +): WorkflowOverviewListResult { + const res: WorkflowOverviewListResult = { + items: [], + totalCount: howmany, + offset: 0, + limit: 0, + }; + + for (let i = 0; i < howmany; i++) { + const params: WorkflowOverviewParams = inputParams ?? {}; + params.suffix = i.toString(); + res.items.push(generateTestWorkflowOverview(params)); + } + + return res; +} + +export function generateTestWorkflowInfo( + id: string = 'test_workflowId', +): WorkflowInfo { + return { + id: id, + serviceUrl: 'mock/serviceurl', + }; +} + +export function generateTestExecuteWorkflowResponse( + id: string = 'test_execId', +): WorkflowExecutionResponse { + return { + id: id, + }; +} + +export const generateWorkflowDefinition: WorkflowDefinition = { + id: 'quarkus-backend-workflow-ci-switch', + version: '1.0', + specVersion: '0.8', + name: '[WF] Create a starter Quarkus Backend application with a CI pipeline - CI Switch', + description: + '[WF] Create a starter Quarkus Backend application with a CI pipeline - CI Switch', + annotations: ['test_annotation'], + states: [ + { + name: 'Test state', + type: 'operation', + end: true, + }, + ], +}; + +export function generateProcessInstances(howmany: number): ProcessInstance[] { + const processInstances: ProcessInstance[] = []; + for (let i = 0; i < howmany; i++) { + processInstances.push(generateProcessInstance(i)); + } + return processInstances; +} + +export function generateProcessInstance(id: number): ProcessInstance { + return { + id: `processInstance${id}`, + processName: `name${id}`, + processId: `proceesId${id}`, + state: ProcessInstanceState.Active, + start: BASE_DATE, + end: moment(BASE_DATE).add(1, 'hour').toISOString(), + nodes: [], + endpoint: 'enpoint/foo', + serviceUrl: 'service/bar', + source: 'my-source', + category: WorkflowCategory.INFRASTRUCTURE, + description: 'test description 1', + variables: { + foo: 'bar', + workflowdata: { + workflowOptions: { + 'my-category': { + id: 'next-workflow-1', + name: 'Next Workflow One', + }, + 'my-secod-category': [ + { + id: 'next-workflow-20', + name: 'Next Workflow Twenty', + }, + { + id: 'next-workflow-21', + name: 'Next Workflow Twenty One', + }, + ], + }, + }, + }, + }; +} diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/src/service/api/v2.test.ts b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/api/v2.test.ts new file mode 100644 index 00000000..ac29a9fd --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/api/v2.test.ts @@ -0,0 +1,577 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { Request } from 'express'; + +import { + AssessedProcessInstanceDTO, + ExecuteWorkflowResponseDTO, + FieldFilterOperatorEnum, + ProcessInstanceListResultDTO, + SearchRequest, + toWorkflowYaml, + WorkflowOverview, + WorkflowOverviewDTO, + WorkflowOverviewListResultDTO, + WorkflowRunStatusDTO, +} from '@red-hat-developer-hub/backstage-plugin-orchestrator-common'; + +import { buildPagination, buildPaginationTmp } from '../../types/pagination'; +import { OrchestratorService } from '../OrchestratorService'; +import { mapToWorkflowOverviewDTO } from './mapping/V2Mappings'; +import { + generateProcessInstance, + generateProcessInstances, + generateTestExecuteWorkflowResponse, + generateTestWorkflowInfo, + generateTestWorkflowOverview, + generateTestWorkflowOverviewList, + generateWorkflowDefinition, +} from './test-utils'; +import { V2 } from './v2'; + +jest.mock('../Helper.ts', () => ({ + retryAsyncFunction: jest.fn(), +})); + +jest.mock('../OrchestratorService', () => ({ + OrchestratorService: jest.fn(), +})); + +// Helper function to create a mock OrchestratorService instance +const createMockOrchestratorService = (): OrchestratorService => { + const mockOrchestratorService = new OrchestratorService( + {} as any, // Mock sonataFlowService + {} as any, // Mock dataIndexService + {} as any, // Mock workflowCacheService + ); + + mockOrchestratorService.fetchWorkflowOverviews = jest.fn(); + mockOrchestratorService.fetchWorkflowOverview = jest.fn(); + mockOrchestratorService.fetchWorkflowDefinition = jest.fn(); + mockOrchestratorService.fetchWorkflowSource = jest.fn(); + mockOrchestratorService.fetchWorkflowInfo = jest.fn(); + mockOrchestratorService.fetchInstances = jest.fn(); + mockOrchestratorService.fetchInstance = jest.fn(); + mockOrchestratorService.fetchInstancesTotalCount = jest.fn(); + mockOrchestratorService.executeWorkflow = jest.fn(); + mockOrchestratorService.abortWorkflowInstance = jest.fn(); + + return mockOrchestratorService; +}; +const mockOrchestratorService = createMockOrchestratorService(); +const v2 = new V2(mockOrchestratorService); + +describe('getWorkflowOverview', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('0 items in workflow overview list', async () => { + // Arrange + const mockRequest = { + query: {}, + headers: {}, + params: {}, + body: { + paginationInfo: { + offset: 1, + pageSize: 50, + orderBy: 'lastUpdated', + orderDirection: 'DESC', + }, + }, + } as Request; + + const mockOverviewsV1 = { + items: [], + }; + + ( + mockOrchestratorService.fetchWorkflowOverviews as jest.Mock + ).mockResolvedValue(mockOverviewsV1.items); + + // Act + const result: WorkflowOverviewListResultDTO = await v2.getWorkflowsOverview( + buildPagination(mockRequest), + ); + + // Assert + expect(result).toEqual({ + overviews: mockOverviewsV1.items.map(item => + mapToWorkflowOverviewDTO(item), + ), + paginationInfo: { + offset: 1, + pageSize: 50, + totalCount: mockOverviewsV1.items.length, + }, + }); + }); + + it('1 item in workflow overview list', async () => { + // Arrange + const mockRequest: any = { + body: {}, + }; + const mockOverviewsV1 = generateTestWorkflowOverviewList(1, {}); + + ( + mockOrchestratorService.fetchWorkflowOverviews as jest.Mock + ).mockResolvedValue(mockOverviewsV1.items); + + // Act + const result: WorkflowOverviewListResultDTO = await v2.getWorkflowsOverview( + buildPagination(mockRequest), + ); + + // Assert + expect(result).toEqual({ + overviews: mockOverviewsV1.items.map((item: WorkflowOverview) => + mapToWorkflowOverviewDTO(item), + ), + paginationInfo: { + offset: undefined, + pageSize: undefined, + totalCount: mockOverviewsV1.items.length, + }, + }); + }); + + it('many items in workflow overview list', async () => { + // Arrange + const mockRequest: any = { + body: { + paginationInfo: { + offset: 1, + pageSize: 50, + orderBy: 'lastUpdated', + orderDirection: 'DESC', + }, + }, + }; + const mockOverviewsV1 = generateTestWorkflowOverviewList(100, {}); + + ( + mockOrchestratorService.fetchWorkflowOverviews as jest.Mock + ).mockResolvedValue(mockOverviewsV1.items); + + // Act + const result: WorkflowOverviewListResultDTO = await v2.getWorkflowsOverview( + buildPagination(mockRequest), + ); + + // Assert + expect(result).toEqual({ + overviews: mockOverviewsV1.items.map((item: WorkflowOverview) => + mapToWorkflowOverviewDTO(item), + ), + paginationInfo: { + offset: 1, + pageSize: 50, + totalCount: mockOverviewsV1.items.length, + }, + }); + }); + + it('filter test', async () => { + // Arrange + // category = "electronics" AND (price <= 1000 OR (brand IN ("Apple", "Samsung") AND brand like 'Apple')) + const mockRequest: SearchRequest = { + filters: { + operator: 'AND', + filters: [ + { + field: 'category', + operator: FieldFilterOperatorEnum.Eq, + value: 'electronics', + }, + { + operator: 'OR', + filters: [ + { + field: 'price', + operator: FieldFilterOperatorEnum.Lte, + value: 1000, + }, + { + operator: 'AND', + filters: [ + { + field: 'brand', + operator: FieldFilterOperatorEnum.In, + value: ['Apple', 'Samsung'], + }, + { + field: 'brand', + operator: FieldFilterOperatorEnum.Like, + value: 'Apple', + }, + ], + }, + ], + }, + ], + }, + paginationInfo: { + offset: 1, + pageSize: 50, + orderBy: 'lastUpdated', + orderDirection: 'DESC', + }, + }; + const mockOverviewsV1 = generateTestWorkflowOverviewList(100, {}); + + ( + mockOrchestratorService.fetchWorkflowOverviews as jest.Mock + ).mockResolvedValue(mockOverviewsV1.items); + + // Act + const result: WorkflowOverviewListResultDTO = await v2.getWorkflowsOverview( + buildPaginationTmp(mockRequest.paginationInfo), + ); + + // Assert + expect(result).toEqual({ + overviews: mockOverviewsV1.items.map((item: WorkflowOverview) => + mapToWorkflowOverviewDTO(item), + ), + paginationInfo: { + offset: 1, + pageSize: 50, + totalCount: mockOverviewsV1.items.length, + }, + }); + }); + + it('undefined workflow overview list', async () => { + // Arrange + const mockRequest: any = { + query: {}, + }; + ( + mockOrchestratorService.fetchWorkflowOverviews as jest.Mock + ).mockRejectedValue(new Error('no workflow overview')); + + // Act + const promise = v2.getWorkflowsOverview(buildPagination(mockRequest)); + + // Assert + await expect(promise).rejects.toThrow('no workflow overview'); + }); +}); +describe('getWorkflowOverviewById', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('0 items in workflow overview list', async () => { + // Arrange + const mockOverviewsV1 = { + items: [], + }; + ( + mockOrchestratorService.fetchWorkflowOverview as jest.Mock + ).mockResolvedValue(mockOverviewsV1.items); + // Act + const overviewV2 = await v2.getWorkflowOverviewById('test_workflowId'); + + // Assert + expect(overviewV2).toBeDefined(); + expect(overviewV2.workflowId).toBeUndefined(); + expect(overviewV2.name).toBeUndefined(); + expect(overviewV2.format).toBeUndefined(); + expect(overviewV2.lastTriggeredMs).toBeUndefined(); + expect(overviewV2.lastRunStatus).toBeUndefined(); + expect(overviewV2.category).toEqual('infrastructure'); + expect(overviewV2.avgDurationMs).toBeUndefined(); + expect(overviewV2.description).toBeUndefined(); + }); + + it('1 item in workflow overview list', async () => { + // Arrange + const mockOverviewsV1 = generateTestWorkflowOverview({ + name: 'test_workflowId', + }); + + ( + mockOrchestratorService.fetchWorkflowOverview as jest.Mock + ).mockResolvedValue(mockOverviewsV1); + + // Act + const result: WorkflowOverviewDTO = await v2.getWorkflowOverviewById( + 'test_workflowId', + ); + + // Assert + expect(result).toEqual(mapToWorkflowOverviewDTO(mockOverviewsV1)); + }); +}); + +describe('getWorkflowById', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it("Workflow doesn't exists", async () => { + ( + mockOrchestratorService.fetchWorkflowSource as jest.Mock + ).mockRejectedValue(new Error('No definition')); + // Act + const promise = v2.getWorkflowById('test_workflowId'); + + // Assert + await expect(promise).rejects.toThrow('No definition'); + }); + + it('1 items in workflow list', async () => { + const testFormat = 'yaml'; + const wfDefinition = generateWorkflowDefinition; + const source = toWorkflowYaml(wfDefinition); + + ( + mockOrchestratorService.fetchWorkflowSource as jest.Mock + ).mockResolvedValue(source); + // Act + const workflowV2 = await v2.getWorkflowById('test_workflowId'); + + // Assert + expect(workflowV2).toBeDefined(); + expect(workflowV2.id).toBeDefined(); + expect(workflowV2.id).toEqual(wfDefinition.id); + expect(workflowV2.name).toEqual(wfDefinition.name); + expect(workflowV2.format).toEqual(testFormat); + expect(workflowV2.description).toEqual(wfDefinition.description); + expect(workflowV2.category).toEqual('infrastructure'); + expect(workflowV2.annotations).toBeDefined(); + }); +}); + +describe('executeWorkflow', () => { + beforeEach(async () => { + jest.clearAllMocks(); + }); + it('executes a given workflow', async () => { + // Arrange + const workflowInfo = generateTestWorkflowInfo(); + const execResponse = generateTestExecuteWorkflowResponse(); + (mockOrchestratorService.fetchWorkflowInfo as jest.Mock).mockResolvedValue( + workflowInfo, + ); + + (mockOrchestratorService.executeWorkflow as jest.Mock).mockResolvedValue( + execResponse, + ); + const workflowData = { + inputData: { + customAttrib: 'My customAttrib', + }, + }; + // Act + const actualResultV2: ExecuteWorkflowResponseDTO = await v2.executeWorkflow( + workflowData, + workflowInfo.id, + 'businessKey', + ); + + // Assert + expect(actualResultV2).toBeDefined(); + expect(actualResultV2.id).toBeDefined(); + expect(actualResultV2.id).toEqual(execResponse.id); + expect(actualResultV2).toEqual(execResponse); + }); +}); + +describe('getInstances', () => { + const mockRequest: any = { + query: {}, + }; + const pagination = buildPagination(mockRequest); + beforeEach(() => { + jest.clearAllMocks(); + }); + + it("Instance doesn't exist", async () => { + // Arrange + (mockOrchestratorService.fetchInstances as jest.Mock).mockRejectedValue( + new Error('No instance'), + ); + // Act + const promise = v2.getInstances(pagination); + + // Assert + await expect(promise).rejects.toThrow('No instance'); + }); + + it('1 item in process instance list', async () => { + const processInstance = generateProcessInstance(1); + + (mockOrchestratorService.fetchInstances as jest.Mock).mockResolvedValue([ + processInstance, + ]); + + // Act + const processInstanceV2: ProcessInstanceListResultDTO = + await v2.getInstances(pagination); + + // Assert + expect(processInstanceV2).toBeDefined(); + expect(processInstanceV2.items).toBeDefined(); + expect(processInstanceV2.items).toHaveLength(1); + expect(processInstanceV2.items?.[0].id).toEqual(processInstance.id); + }); + it('10 items in process instance list', async () => { + const howmany = 10; + const processInstances = generateProcessInstances(howmany); + + (mockOrchestratorService.fetchInstances as jest.Mock).mockResolvedValue( + processInstances, + ); + + // Act + const processInstanceList: ProcessInstanceListResultDTO = + await v2.getInstances(pagination); + + // Assert + expect(processInstanceList).toBeDefined(); + expect(processInstanceList.items).toBeDefined(); + expect(processInstanceList.items).toHaveLength(howmany); + for (let i = 0; i < howmany; i++) { + expect(processInstanceList.items?.[i].id).toEqual(processInstances[i].id); + } + }); +}); + +describe('getInstanceById', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it("Instance doesn't exist", async () => { + (mockOrchestratorService.fetchInstance as jest.Mock).mockRejectedValue( + new Error('No instance'), + ); + // Act + const promise = v2.getInstanceById('testInstanceId'); + + // Assert + await expect(promise).rejects.toThrow('No instance'); + }); + + it('Instance exists and do not include assessment', async () => { + const processInstance = generateProcessInstance(1); + + (mockOrchestratorService.fetchInstance as jest.Mock).mockResolvedValue( + processInstance, + ); + + // Act + const processInstanceV2: AssessedProcessInstanceDTO = + await v2.getInstanceById(processInstance.id); + + // Assert + expect(mockOrchestratorService.fetchInstance).toHaveBeenCalledTimes(1); + expect(processInstanceV2).toBeDefined(); + expect(processInstanceV2.instance).toBeDefined(); + expect(processInstanceV2.assessedBy).toBeUndefined(); + expect(processInstanceV2.instance.id).toEqual(processInstance.id); + }); + + it('Instance exists, assessment non empty string', async () => { + const processInstance = generateProcessInstance(1); + processInstance.businessKey = 'testBusinessKey'; + const assessedBy = generateProcessInstance(1); + assessedBy.id = processInstance.businessKey; + + (mockOrchestratorService.fetchInstance as jest.Mock) + .mockResolvedValueOnce(processInstance) + .mockResolvedValueOnce(assessedBy); + + // Act + const processInstanceV2: AssessedProcessInstanceDTO = + await v2.getInstanceById(processInstance.id, true); + + // Assert + expect(mockOrchestratorService.fetchInstance).toHaveBeenCalledTimes(2); + expect(processInstanceV2).toBeDefined(); + expect(processInstanceV2.instance).toBeDefined(); + expect(processInstanceV2.assessedBy).toBeDefined(); + expect(processInstanceV2.assessedBy?.id).toEqual( + processInstance.businessKey, + ); + expect(processInstanceV2.instance.id).toEqual(processInstance.id); + }); +}); + +describe('getWorkflowStatuses', () => { + beforeEach(async () => { + jest.clearAllMocks(); + }); + + it('returns all possible workflow status types', async () => { + const expectedResultV2 = [ + { key: 'Active', value: 'ACTIVE' }, + { key: 'Error', value: 'ERROR' }, + { key: 'Completed', value: 'COMPLETED' }, + { key: 'Aborted', value: 'ABORTED' }, + { key: 'Suspended', value: 'SUSPENDED' }, + { key: 'Pending', value: 'PENDING' }, + ]; + + // Act + const actualResultV2: WorkflowRunStatusDTO[] = + await v2.getWorkflowStatuses(); + + // Assert + expect(actualResultV2).toBeDefined(); + expect(actualResultV2).toEqual(expectedResultV2); + }); +}); + +describe('abortWorkflow', () => { + beforeEach(async () => { + jest.clearAllMocks(); + }); + + it('aborts workflows', async () => { + // Arrange + const workflowId = 'testInstanceId'; + ( + mockOrchestratorService.abortWorkflowInstance as jest.Mock + ).mockResolvedValue({} as any); + + const expectedResult = `Workflow instance ${workflowId} successfully aborted`; + + // Act + const actualResult: string = await v2.abortWorkflow(workflowId); + + // Assert + expect(actualResult).toBeDefined(); + expect(actualResult).toEqual(expectedResult); + }); + + it('throws error when abort workflows response has error attribute', async () => { + // Arrange + ( + mockOrchestratorService.abortWorkflowInstance as jest.Mock + ).mockRejectedValue(new Error('Simulated abort workflow error')); + + // Act + const promise = v2.abortWorkflow('instanceId'); + + // Assert + await expect(promise).rejects.toThrow('Simulated abort workflow error'); + }); +}); diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/src/service/api/v2.ts b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/api/v2.ts new file mode 100644 index 00000000..43ec479d --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/api/v2.ts @@ -0,0 +1,277 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { ParsedRequest } from 'openapi-backend'; + +import { + AssessedProcessInstanceDTO, + ExecuteWorkflowRequestDTO, + ExecuteWorkflowResponseDTO, + Filter, + ProcessInstance, + ProcessInstanceListResultDTO, + ProcessInstanceState, + ProcessInstanceVariables, + WorkflowDTO, + WorkflowInfo, + WorkflowOverviewDTO, + WorkflowOverviewListResultDTO, + WorkflowRunStatusDTO, +} from '@red-hat-developer-hub/backstage-plugin-orchestrator-common'; + +import { Pagination } from '../../types/pagination'; +import { retryAsyncFunction } from '../Helper'; +import { OrchestratorService } from '../OrchestratorService'; +import { + mapToExecuteWorkflowResponseDTO, + mapToProcessInstanceDTO, + mapToWorkflowDTO, + mapToWorkflowOverviewDTO, + mapToWorkflowRunStatusDTO, +} from './mapping/V2Mappings'; + +const FETCH_INSTANCE_MAX_ATTEMPTS = 10; +const FETCH_INSTANCE_RETRY_DELAY_MS = 1000; + +export class V2 { + constructor(private readonly orchestratorService: OrchestratorService) {} + + public async getWorkflowsOverview( + pagination: Pagination, + filter?: Filter, + ): Promise { + const overviews = await this.orchestratorService.fetchWorkflowOverviews({ + pagination, + filter, + }); + if (!overviews) { + throw new Error("Couldn't fetch workflow overviews"); + } + const result: WorkflowOverviewListResultDTO = { + overviews: overviews.map(item => mapToWorkflowOverviewDTO(item)), + paginationInfo: { + pageSize: pagination.limit, + offset: pagination.offset, + totalCount: overviews.length, + }, + }; + return result; + } + + public async getWorkflowOverviewById( + workflowId: string, + ): Promise { + const overview = await this.orchestratorService.fetchWorkflowOverview({ + definitionId: workflowId, + cacheHandler: 'throw', + }); + + if (!overview) { + throw new Error(`Couldn't fetch workflow overview for ${workflowId}`); + } + return mapToWorkflowOverviewDTO(overview); + } + + public async getWorkflowById(workflowId: string): Promise { + const resultV1 = await this.getWorkflowSourceById(workflowId); + return mapToWorkflowDTO(resultV1); + } + + public async getWorkflowSourceById(workflowId: string): Promise { + const source = await this.orchestratorService.fetchWorkflowSource({ + definitionId: workflowId, + cacheHandler: 'throw', + }); + + if (!source) { + throw new Error(`Couldn't fetch workflow source for ${workflowId}`); + } + + return source; + } + + public async getInstances( + pagination?: Pagination, + filter?: Filter, + workflowId?: string, + ): Promise { + const instances = await this.orchestratorService.fetchInstances({ + pagination, + filter, + workflowId, + }); + const totalCount = await this.orchestratorService.fetchInstancesTotalCount( + workflowId, + filter, + ); + + const result: ProcessInstanceListResultDTO = { + items: instances?.map(mapToProcessInstanceDTO), + paginationInfo: { + pageSize: pagination?.limit, + offset: pagination?.offset, + totalCount: totalCount, + }, + }; + return result; + } + + public async getInstanceById( + instanceId: string, + includeAssessment: boolean = false, + ): Promise { + const instance = await this.orchestratorService.fetchInstance({ + instanceId, + cacheHandler: 'throw', + }); + + if (!instance) { + throw new Error(`Couldn't fetch process instance ${instanceId}`); + } + + let assessedByInstance: ProcessInstance | undefined; + + if (includeAssessment && instance.businessKey) { + assessedByInstance = await this.orchestratorService.fetchInstance({ + instanceId: instance.businessKey, + cacheHandler: 'throw', + }); + } + + return { + instance: mapToProcessInstanceDTO(instance), + assessedBy: assessedByInstance + ? mapToProcessInstanceDTO(assessedByInstance) + : undefined, + }; + } + + public async executeWorkflow( + executeWorkflowRequestDTO: ExecuteWorkflowRequestDTO, + workflowId: string, + businessKey: string | undefined, + ): Promise { + if (Object.keys(executeWorkflowRequestDTO?.inputData).length === 0) { + throw new Error( + `ExecuteWorkflowRequestDTO.inputData is required for executing workflow with id ${workflowId}`, + ); + } + + const definition = await this.orchestratorService.fetchWorkflowInfo({ + definitionId: workflowId, + cacheHandler: 'throw', + }); + if (!definition) { + throw new Error(`Couldn't fetch workflow definition for ${workflowId}`); + } + if (!definition.serviceUrl) { + throw new Error(`ServiceURL is not defined for workflow ${workflowId}`); + } + const executionResponse = await this.orchestratorService.executeWorkflow({ + definitionId: workflowId, + inputData: + executeWorkflowRequestDTO?.inputData as ProcessInstanceVariables, + serviceUrl: definition.serviceUrl, + businessKey, + cacheHandler: 'throw', + }); + + if (!executionResponse) { + throw new Error(`Couldn't execute workflow ${workflowId}`); + } + + // Making sure the instance data is available before returning + await retryAsyncFunction({ + asyncFn: () => + this.orchestratorService.fetchInstance({ + instanceId: executionResponse.id, + cacheHandler: 'throw', + }), + maxAttempts: FETCH_INSTANCE_MAX_ATTEMPTS, + delayMs: FETCH_INSTANCE_RETRY_DELAY_MS, + }); + + if (!executionResponse) { + throw new Error('Error executing workflow with id ${workflowId}'); + } + + return mapToExecuteWorkflowResponseDTO(workflowId, executionResponse); + } + + public async retriggerInstance( + workflowId: string, + instanceId: string, + ): Promise { + const definition = await this.orchestratorService.fetchWorkflowInfo({ + definitionId: workflowId, + cacheHandler: 'throw', + }); + if (!definition) { + throw new Error(`Couldn't fetch workflow definition for ${workflowId}`); + } + if (!definition.serviceUrl) { + throw new Error(`ServiceURL is not defined for workflow ${workflowId}`); + } + const response = await this.orchestratorService.retriggerWorkflow({ + definitionId: workflowId, + instanceId: instanceId, + serviceUrl: definition.serviceUrl, + cacheHandler: 'throw', + }); + + if (!response) { + throw new Error( + `Couldn't retrigger instance ${instanceId} of workflow ${workflowId}`, + ); + } + } + + public async abortWorkflow(instanceId: string): Promise { + await this.orchestratorService.abortWorkflowInstance({ + instanceId, + cacheHandler: 'throw', + }); + return `Workflow instance ${instanceId} successfully aborted`; + } + + public async getWorkflowStatuses(): Promise { + return [ + ProcessInstanceState.Active, + ProcessInstanceState.Error, + ProcessInstanceState.Completed, + ProcessInstanceState.Aborted, + ProcessInstanceState.Suspended, + ProcessInstanceState.Pending, + ].map(status => mapToWorkflowRunStatusDTO(status)); + } + + public async getWorkflowInputSchemaById( + workflowId: string, + serviceUrl: string, + ): Promise { + return this.orchestratorService.fetchWorkflowInfoOnService({ + definitionId: workflowId, + serviceUrl: serviceUrl, + cacheHandler: 'throw', + }); + } + + public extractQueryParam( + req: ParsedRequest, + key: string, + ): string | undefined { + return req.query[key] as string | undefined; + } +} diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/src/service/constants.ts b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/constants.ts new file mode 100644 index 00000000..537f3c62 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/constants.ts @@ -0,0 +1,19 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export const WORKFLOW_DATA_KEY = 'workflowdata'; + +export const INTERNAL_SERVER_ERROR_MESSAGE = 'internal server error'; +export const FETCH_PROCESS_INSTANCES_SORT_FIELD = 'start'; diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/src/service/router.ts b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/router.ts new file mode 100644 index 00000000..87d48c13 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/router.ts @@ -0,0 +1,841 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { MiddlewareFactory } from '@backstage/backend-defaults/rootHttpRouter'; +import { + HttpAuthService, + LoggerService, + PermissionsService, + resolvePackagePath, + SchedulerService, +} from '@backstage/backend-plugin-api'; +import type { Config } from '@backstage/config'; +import type { DiscoveryApi } from '@backstage/core-plugin-api'; +import { + AuthorizeResult, + BasicPermission, +} from '@backstage/plugin-permission-common'; +import { createPermissionIntegrationRouter } from '@backstage/plugin-permission-node'; +import type { JsonObject, JsonValue } from '@backstage/types'; + +import { UnauthorizedError } from '@backstage-community/plugin-rbac-common'; +import { + AuditLogger, + DefaultAuditLogger, +} from '@janus-idp/backstage-plugin-audit-log-node'; +import { fullFormats } from 'ajv-formats/dist/formats'; +import express, { Router } from 'express'; +import { Request as HttpRequest } from 'express-serve-static-core'; +import { OpenAPIBackend, Request } from 'openapi-backend'; + +import { + Filter, + openApiDocument, + orchestratorPermissions, + orchestratorWorkflowExecutePermission, + orchestratorWorkflowInstanceAbortPermission, + orchestratorWorkflowInstanceReadPermission, + orchestratorWorkflowInstancesReadPermission, + orchestratorWorkflowReadPermission, + QUERY_PARAM_BUSINESS_KEY, + QUERY_PARAM_INCLUDE_ASSESSMENT, +} from '@red-hat-developer-hub/backstage-plugin-orchestrator-common'; + +import * as pkg from '../../package.json'; +import { RouterOptions } from '../routerWrapper'; +import { buildPagination } from '../types/pagination'; +import { V2 } from './api/v2'; +import { INTERNAL_SERVER_ERROR_MESSAGE } from './constants'; +import { DataIndexService } from './DataIndexService'; +import { DataInputSchemaService } from './DataInputSchemaService'; +import { OrchestratorService } from './OrchestratorService'; +import { ScaffolderService } from './ScaffolderService'; +import { SonataFlowService } from './SonataFlowService'; +import { WorkflowCacheService } from './WorkflowCacheService'; + +interface PublicServices { + dataInputSchemaService: DataInputSchemaService; + orchestratorService: OrchestratorService; +} + +interface RouterApi { + openApiBackend: OpenAPIBackend; + v2: V2; +} + +const authorize = async ( + request: HttpRequest, + permission: BasicPermission, + permissionsSvc: PermissionsService, + httpAuth: HttpAuthService, +) => { + const decision = ( + await permissionsSvc.authorize([{ permission: permission }], { + credentials: await httpAuth.credentials(request), + }) + )[0]; + + return decision; +}; + +export async function createBackendRouter( + options: RouterOptions, +): Promise { + const { + config, + logger, + discovery, + catalogApi, + urlReader, + scheduler, + permissions, + auth, + httpAuth, + } = options; + const publicServices = initPublicServices(logger, config, scheduler); + + const routerApi = await initRouterApi(publicServices.orchestratorService); + + const auditLogger = new DefaultAuditLogger({ + logger: logger, + authService: auth, + httpAuthService: httpAuth, + }); + + const router = Router(); + const permissionsIntegrationRouter = createPermissionIntegrationRouter({ + permissions: orchestratorPermissions, + }); + router.use(express.json()); + router.use(permissionsIntegrationRouter); + router.use('/workflows', express.text()); + router.use('/static', express.static(resolvePackagePath(pkg.name, 'static'))); + router.get('/health', (_, response) => { + logger.info('PONG!'); + response.json({ status: 'ok' }); + }); + + const scaffolderService: ScaffolderService = new ScaffolderService( + logger, + config, + catalogApi, + urlReader, + ); + + setupInternalRoutes( + publicServices, + routerApi, + permissions, + httpAuth, + auditLogger, + ); + setupExternalRoutes(router, discovery, scaffolderService, auditLogger); + + router.use((req, res, next) => { + if (!next) { + throw new Error('next is undefined'); + } + + return routerApi.openApiBackend.handleRequest( + req as Request, + req, + res, + next, + ); + }); + + const middleware = MiddlewareFactory.create({ logger, config }); + + router.use(middleware.error()); + + return router; +} + +function initPublicServices( + logger: LoggerService, + config: Config, + scheduler: SchedulerService, +): PublicServices { + const dataIndexUrl = config.getString('orchestrator.dataIndexService.url'); + const dataIndexService = new DataIndexService(dataIndexUrl, logger); + const sonataFlowService = new SonataFlowService(dataIndexService, logger); + + const workflowCacheService = new WorkflowCacheService( + logger, + dataIndexService, + sonataFlowService, + ); + workflowCacheService.schedule({ scheduler: scheduler }); + + const orchestratorService = new OrchestratorService( + sonataFlowService, + dataIndexService, + workflowCacheService, + ); + + const dataInputSchemaService = new DataInputSchemaService(); + + return { + orchestratorService, + dataInputSchemaService, + }; +} + +async function initRouterApi( + orchestratorService: OrchestratorService, +): Promise { + const openApiBackend = new OpenAPIBackend({ + definition: openApiDocument, + strict: false, + ajvOpts: { + strict: false, + strictSchema: false, + verbose: true, + addUsedSchema: false, + formats: fullFormats, // open issue: https://github.com/openapistack/openapi-backend/issues/280 + }, + handlers: { + validationFail: async ( + c, + _req: express.Request, + res: express.Response, + ) => { + console.log('validationFail', c.operation); + res.status(400).json({ err: c.validation.errors }); + }, + notFound: async (_c, req: express.Request, res: express.Response) => { + res.status(404).json({ err: `${req.path} path not found` }); + }, + notImplemented: async (_c, req: express.Request, res: express.Response) => + res.status(500).json({ err: `${req.path} not implemented` }), + }, + }); + await openApiBackend.init(); + const v2 = new V2(orchestratorService); + return { v2, openApiBackend }; +} + +// ====================================================== +// Internal Backstage API calls to delegate to SonataFlow +// ====================================================== +function setupInternalRoutes( + services: PublicServices, + routerApi: RouterApi, + permissions: PermissionsService, + httpAuth: HttpAuthService, + auditLogger: AuditLogger, +) { + function manageDenyAuthorization( + endpointName: string, + endpoint: string, + req: HttpRequest, + ) { + const error = new UnauthorizedError(); + auditLogger.auditLog({ + eventName: `${endpointName}EndpointHit`, + stage: 'authorization', + status: 'failed', + level: 'error', + request: req, + response: { + status: 403, + body: { + errors: [ + { + name: error.name, + message: error.message, + }, + ], + }, + }, + errors: [error], + message: `Not authorize to request the ${endpoint} endpoint`, + }); + throw error; + } + + function auditLogRequestError( + error: any, + endpointName: string, + endpoint: string, + req: HttpRequest, + ) { + auditLogger.auditLog({ + eventName: `${endpointName}EndpointHit`, + stage: 'completion', + status: 'failed', + level: 'error', + request: req, + response: { + status: 500, + body: { + errors: [ + { + name: error.name, + message: error.message || INTERNAL_SERVER_ERROR_MESSAGE, + }, + ], + }, + }, + errors: [error], + message: `Error occured while requesting the '${endpoint}' endpoint`, + }); + } + + // v2 + routerApi.openApiBackend.register( + 'getWorkflowsOverview', + async (_c, req, res: express.Response, next) => { + const endpointName = 'getWorkflowsOverview'; + const endpoint = '/v2/workflows/overview'; + + auditLogger.auditLog({ + eventName: 'getWorkflowsOverview', + stage: 'start', + status: 'succeeded', + level: 'debug', + request: req, + message: `Received request to '${endpoint}' endpoint`, + }); + const decision = await authorize( + req, + orchestratorWorkflowInstancesReadPermission, + permissions, + httpAuth, + ); + if (decision.result === AuthorizeResult.DENY) { + manageDenyAuthorization(endpointName, endpoint, req); + } + return routerApi.v2 + .getWorkflowsOverview(buildPagination(req), getRequestFilters(req)) + .then(result => res.json(result)) + .catch(error => { + auditLogRequestError(error, endpointName, endpoint, req); + next(error); + }); + }, + ); + + // v2 + routerApi.openApiBackend.register( + 'getWorkflowSourceById', + async (c, _req, res, next) => { + const workflowId = c.request.params.workflowId as string; + const endpointName = 'getWorkflowSourceById'; + const endpoint = `/v2/workflows/${workflowId}/source`; + + auditLogger.auditLog({ + eventName: endpointName, + stage: 'start', + status: 'succeeded', + level: 'debug', + request: _req, + message: `Received request to '${endpoint}' endpoint`, + }); + + const decision = await authorize( + _req, + orchestratorWorkflowReadPermission, + permissions, + httpAuth, + ); + if (decision.result === AuthorizeResult.DENY) { + manageDenyAuthorization(endpointName, endpoint, _req); + } + + try { + const result = await routerApi.v2.getWorkflowSourceById(workflowId); + res.status(200).contentType('text/plain').send(result); + } catch (error) { + auditLogRequestError(error, endpointName, endpoint, _req); + next(error); + } + }, + ); + + // v2 + routerApi.openApiBackend.register( + 'executeWorkflow', + async (c, req: express.Request, res: express.Response, next) => { + const workflowId = c.request.params.workflowId as string; + const endpointName = 'executeWorkflow'; + const endpoint = `/v2/workflows/${workflowId}/execute`; + + auditLogger.auditLog({ + eventName: endpointName, + stage: 'start', + status: 'succeeded', + level: 'debug', + request: req, + message: `Received request to '${endpoint}' endpoint`, + }); + + const decision = await authorize( + req, + orchestratorWorkflowExecutePermission, + permissions, + httpAuth, + ); + if (decision.result === AuthorizeResult.DENY) { + manageDenyAuthorization(endpointName, endpoint, req); + } + + const businessKey = routerApi.v2.extractQueryParam( + c.request, + QUERY_PARAM_BUSINESS_KEY, + ); + + const executeWorkflowRequestDTO = req.body; + + return routerApi.v2 + .executeWorkflow(executeWorkflowRequestDTO, workflowId, businessKey) + .then(result => res.status(200).json(result)) + .catch(error => { + auditLogRequestError(error, endpointName, endpoint, req); + next(error); + }); + }, + ); + + // v2 + routerApi.openApiBackend.register( + 'retriggerInstance', + async (c, req: express.Request, res: express.Response, next) => { + const workflowId = c.request.params.workflowId as string; + const instanceId = c.request.params.instanceId as string; + const endpointName = 'retriggerInstance'; + const endpoint = `/v2/workflows/${workflowId}/${instanceId}/retrigger`; + + auditLogger.auditLog({ + eventName: endpointName, + stage: 'start', + status: 'succeeded', + level: 'debug', + request: req, + message: `Received request to '${endpoint}' endpoint`, + }); + + const decision = await authorize( + req, + orchestratorWorkflowExecutePermission, + permissions, + httpAuth, + ); + if (decision.result === AuthorizeResult.DENY) { + manageDenyAuthorization(endpointName, endpoint, req); + } + + await routerApi.v2 + .retriggerInstance(workflowId, instanceId) + .then(result => res.status(200).json(result)) + .catch(error => { + auditLogRequestError(error, endpointName, endpoint, req); + next(error); + }); + }, + ); + + // v2 + routerApi.openApiBackend.register( + 'getWorkflowOverviewById', + async (c, _req: express.Request, res: express.Response, next) => { + const workflowId = c.request.params.workflowId as string; + const endpointName = 'getWorkflowOverviewById'; + const endpoint = `/v2/workflows/${workflowId}/overview`; + + auditLogger.auditLog({ + eventName: endpointName, + stage: 'start', + status: 'succeeded', + level: 'debug', + request: _req, + message: `Received request to '${endpoint}' endpoint`, + }); + + const decision = await authorize( + _req, + orchestratorWorkflowReadPermission, + permissions, + httpAuth, + ); + if (decision.result === AuthorizeResult.DENY) { + manageDenyAuthorization(endpointName, endpoint, _req); + } + return routerApi.v2 + .getWorkflowOverviewById(workflowId) + .then(result => res.json(result)) + .catch(error => { + auditLogRequestError(error, endpointName, endpoint, _req); + next(error); + }); + }, + ); + + // v2 + routerApi.openApiBackend.register( + 'getWorkflowStatuses', + async (_c, _req: express.Request, res: express.Response, next) => { + const endpointName = 'getWorkflowStatuses'; + const endpoint = '/v2/workflows/instances/statuses'; + + auditLogger.auditLog({ + eventName: endpointName, + stage: 'start', + status: 'succeeded', + level: 'debug', + request: _req, + message: `Received request to '${endpoint}' endpoint`, + }); + const decision = await authorize( + _req, + orchestratorWorkflowInstanceReadPermission, + permissions, + httpAuth, + ); + if (decision.result === AuthorizeResult.DENY) { + manageDenyAuthorization(endpointName, endpoint, _req); + } + return routerApi.v2 + .getWorkflowStatuses() + .then(result => res.status(200).json(result)) + .catch(error => { + auditLogRequestError(error, endpointName, endpoint, _req); + next(error); + }); + }, + ); + + // v2 + routerApi.openApiBackend.register( + 'getWorkflowInputSchemaById', + async (c, req: express.Request, res: express.Response, next) => { + const workflowId = c.request.params.workflowId as string; + const instanceId = c.request.query.instanceId as string; + const endpointName = 'getWorkflowInputSchemaById'; + const endpoint = `/v2/workflows/${workflowId}/inputSchema`; + try { + auditLogger.auditLog({ + eventName: endpointName, + stage: 'start', + status: 'succeeded', + level: 'debug', + request: req, + message: `Received request to '${endpoint}' endpoint`, + }); + const decision = await authorize( + req, + orchestratorWorkflowInstanceReadPermission, + permissions, + httpAuth, + ); + if (decision.result === AuthorizeResult.DENY) { + manageDenyAuthorization(endpointName, endpoint, req); + } + + const workflowDefinition = + await services.orchestratorService.fetchWorkflowInfo({ + definitionId: workflowId, + cacheHandler: 'throw', + }); + + if (!workflowDefinition) { + throw new Error( + `Failed to fetch workflow info for workflow ${workflowId}`, + ); + } + const serviceUrl = workflowDefinition.serviceUrl; + if (!serviceUrl) { + throw new Error( + `Service URL is not defined for workflow ${workflowId}`, + ); + } + + const definition = + await services.orchestratorService.fetchWorkflowDefinition({ + definitionId: workflowId, + cacheHandler: 'throw', + }); + + if (!definition) { + throw new Error( + 'Failed to fetch workflow definition for workflow ${workflowId}', + ); + } + + if (!definition.dataInputSchema) { + res.status(200).json({}); + return; + } + + const instanceVariables = instanceId + ? await services.orchestratorService.fetchInstanceVariables({ + instanceId, + cacheHandler: 'throw', + }) + : undefined; + + const workflowData = instanceVariables + ? services.dataInputSchemaService.extractWorkflowData( + instanceVariables, + ) + : undefined; + + const workflowInfo = await routerApi.v2 + .getWorkflowInputSchemaById(workflowId, serviceUrl) + .catch((error: { message: string }) => { + auditLogRequestError(error, endpointName, endpoint, req); + res.status(500).json({ + message: error.message || INTERNAL_SERVER_ERROR_MESSAGE, + }); + }); + + if ( + !workflowInfo || + !workflowInfo.inputSchema || + !workflowInfo.inputSchema.properties + ) { + res.status(200).json({}); + return; + } + + const inputSchemaProps = workflowInfo.inputSchema.properties; + let inputData; + + if (workflowData) { + inputData = Object.keys(inputSchemaProps) + .filter(k => k in workflowData) + .reduce((result, k) => { + if (!workflowData[k]) { + return result; + } + result[k] = workflowData[k]; + return result; + }, {} as JsonObject); + } + + res.status(200).json({ + inputSchema: workflowInfo.inputSchema, + data: inputData, + }); + } catch (err) { + auditLogRequestError(err, endpointName, endpoint, req); + next(err); + } + }, + ); + + // v2 + routerApi.openApiBackend.register( + 'getWorkflowInstances', + async (c, req: express.Request, res: express.Response, next) => { + const endpointName = 'getWorkflowInstances'; + const workflowId = c.request.params.workflowId as string; + const endpoint = `/v2/workflows/${workflowId}/instances`; + + auditLogger.auditLog({ + eventName: endpointName, + stage: 'start', + status: 'succeeded', + level: 'debug', + request: req, + message: `Received request to '${endpoint}' endpoint`, + }); + + const decision = await authorize( + req, + orchestratorWorkflowInstancesReadPermission, + permissions, + httpAuth, + ); + if (decision.result === AuthorizeResult.DENY) { + manageDenyAuthorization(endpointName, endpoint, req); + } + return routerApi.v2 + .getInstances(buildPagination(req), getRequestFilters(req), workflowId) + .then(result => res.json(result)) + .catch(error => { + auditLogRequestError(error, endpointName, endpoint, req); + next(error); + }); + }, + ); + + // v2 + routerApi.openApiBackend.register( + 'getInstances', + async (_c, req: express.Request, res: express.Response, next) => { + const endpointName = 'getInstances'; + const endpoint = `/v2/workflows/instances`; + + auditLogger.auditLog({ + eventName: endpointName, + stage: 'start', + status: 'succeeded', + level: 'debug', + request: req, + message: `Received request to '${endpoint}' endpoint`, + }); + + const decision = await authorize( + req, + orchestratorWorkflowInstancesReadPermission, + permissions, + httpAuth, + ); + if (decision.result === AuthorizeResult.DENY) { + manageDenyAuthorization(endpointName, endpoint, req); + } + return routerApi.v2 + .getInstances(buildPagination(req), getRequestFilters(req)) + .then(result => res.json(result)) + .catch(error => { + auditLogRequestError(error, endpointName, endpoint, req); + next(error); + }); + }, + ); + + // v2 + routerApi.openApiBackend.register( + 'getInstanceById', + async (c, _req: express.Request, res: express.Response, next) => { + const instanceId = c.request.params.instanceId as string; + const endpointName = 'getInstanceById'; + const endpoint = `/v2/workflows/instances/${instanceId}`; + + auditLogger.auditLog({ + eventName: endpointName, + stage: 'start', + status: 'succeeded', + level: 'debug', + request: _req, + message: `Received request to '${endpoint}' endpoint`, + }); + + const decision = await authorize( + _req, + orchestratorWorkflowInstanceReadPermission, + permissions, + httpAuth, + ); + if (decision.result === AuthorizeResult.DENY) { + manageDenyAuthorization(endpointName, endpoint, _req); + } + const includeAssessment = routerApi.v2.extractQueryParam( + c.request, + QUERY_PARAM_INCLUDE_ASSESSMENT, + ); + return routerApi.v2 + .getInstanceById(instanceId, !!includeAssessment) + .then(result => res.status(200).json(result)) + .catch(error => { + auditLogRequestError(error, endpointName, endpoint, _req); + next(error); + }); + }, + ); + + // v2 + routerApi.openApiBackend.register( + 'abortWorkflow', + async (c, _req, res, next) => { + const instanceId = c.request.params.instanceId as string; + const endpointName = 'abortWorkflow'; + const endpoint = `/v2/workflows/instances/${instanceId}/abort`; + + auditLogger.auditLog({ + eventName: endpointName, + stage: 'start', + status: 'succeeded', + level: 'debug', + request: _req, + message: `Received request to '${endpoint}' endpoint`, + }); + + const decision = await authorize( + _req, + orchestratorWorkflowInstanceAbortPermission, + permissions, + httpAuth, + ); + if (decision.result === AuthorizeResult.DENY) { + manageDenyAuthorization(endpointName, endpoint, _req); + } + return routerApi.v2 + .abortWorkflow(instanceId) + .then(result => res.json(result)) + .catch(error => { + auditLogRequestError(error, endpointName, endpoint, _req); + next(error); + }); + }, + ); +} + +// ====================================================== +// External SonataFlow API calls to delegate to Backstage +// ====================================================== +function setupExternalRoutes( + router: express.Router, + discovery: DiscoveryApi, + scaffolderService: ScaffolderService, + auditLogger: AuditLogger, +) { + router.get('/actions', async (req, res) => { + auditLogger.auditLog({ + eventName: 'ActionsEndpointHit', + stage: 'start', + status: 'succeeded', + level: 'debug', + request: req, + message: `Received request to '/actions' endpoint`, + }); + const scaffolderUrl = await discovery.getBaseUrl('scaffolder'); + const response = await fetch(`${scaffolderUrl}/v2/actions`); + const json = await response.json(); + res.status(response.status).json(json); + }); + + router.post('/actions/:actionId', async (req, res) => { + const { actionId } = req.params; + auditLogger.auditLog({ + eventName: 'ActionsActionIdEndpointHit', + stage: 'start', + status: 'succeeded', + level: 'debug', + request: req, + message: `Received request to '/actions/${actionId}' endpoint`, + }); + const instanceId: string | undefined = req.header('kogitoprocinstanceid'); + const body: JsonObject = (await req.body) as JsonObject; + + const filteredBody = Object.fromEntries( + Object.entries(body).filter( + ([, value]) => value !== undefined && value !== null, + ), + ); + + const result: JsonValue = await scaffolderService.executeAction({ + actionId, + instanceId, + input: filteredBody, + }); + res.status(200).json(result); + }); +} + +function getRequestFilters(req: HttpRequest): Filter | undefined { + return req.body.filters ? (req.body.filters as Filter) : undefined; +} diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/src/types/pagination.test.ts b/workspaces/orchestrator/plugins/orchestrator-backend/src/types/pagination.test.ts new file mode 100644 index 00000000..8e54657b --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/src/types/pagination.test.ts @@ -0,0 +1,74 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { buildPagination } from './pagination'; + +describe('buildPagination()', () => { + it('should build the correct pagination obj when no query parameters are passed', () => { + const mockRequest: any = { + body: {}, + }; + expect(buildPagination(mockRequest)).toEqual({}); + }); + it('should build the correct pagination obj when partial query parameters are passed', () => { + const mockRequest: any = { + body: { + paginationInfo: { + orderBy: 'lastUpdated', + }, + }, + }; + expect(buildPagination(mockRequest)).toEqual({ + limit: undefined, + offset: undefined, + order: undefined, + sortField: 'lastUpdated', + }); + }); + it('should build the correct pagination obj when all query parameters are passed', () => { + const mockRequest: any = { + body: { + paginationInfo: { + offset: 1, + pageSize: 50, + orderBy: 'lastUpdated', + orderDirection: 'DESC', + }, + }, + }; + expect(buildPagination(mockRequest)).toEqual({ + limit: 50, + offset: 1, + order: 'DESC', + sortField: 'lastUpdated', + }); + }); + it('should build the correct pagination obj when non numeric value passed to number fields', () => { + const mockRequest: any = { + body: { + paginationInfo: { + offset: 'abc', + pageSize: 'cde', + }, + }, + }; + expect(buildPagination(mockRequest)).toEqual({ + limit: undefined, + offset: undefined, + order: undefined, + sortField: undefined, + }); + }); +}); diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/src/types/pagination.ts b/workspaces/orchestrator/plugins/orchestrator-backend/src/types/pagination.ts new file mode 100644 index 00000000..b60ab673 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-backend/src/types/pagination.ts @@ -0,0 +1,90 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { Request } from 'express-serve-static-core'; + +import { PaginationInfoDTO } from '@red-hat-developer-hub/backstage-plugin-orchestrator-common'; + +export interface Pagination { + offset?: number; + limit?: number; + order?: string; + sortField?: string; +} + +export function buildPagination(req: Request): Pagination { + const pagination: Pagination = { + limit: undefined, + offset: undefined, + order: undefined, + sortField: undefined, + }; + + if (!req.body?.paginationInfo) { + return pagination; + } + const { offset, pageSize, orderBy, orderDirection } = req.body + .paginationInfo as PaginationInfoDTO; + + if (!isNaN(Number(offset))) { + pagination.offset = Number(offset); + } + + if (!isNaN(Number(pageSize))) { + pagination.limit = Number(pageSize); + } + + if (orderBy) { + pagination.sortField = String(orderBy); + } + + if (orderDirection) { + pagination.order = String(orderDirection).toUpperCase(); + } + return pagination; +} + +export function buildPaginationTmp( + paginationInfo?: PaginationInfoDTO, +): Pagination { + const pagination: Pagination = { + limit: undefined, + offset: undefined, + order: undefined, + sortField: undefined, + }; + + if (!paginationInfo) { + return pagination; + } + const { offset, pageSize, orderBy, orderDirection } = paginationInfo; + + if (!isNaN(Number(offset))) { + pagination.offset = Number(offset); + } + + if (!isNaN(Number(pageSize))) { + pagination.limit = Number(pageSize); + } + + if (orderBy) { + pagination.sortField = String(orderBy); + } + + if (orderDirection) { + pagination.order = String(orderDirection).toUpperCase(); + } + return pagination; +} diff --git a/workspaces/orchestrator/plugins/orchestrator-common/.eslintignore b/workspaces/orchestrator/plugins/orchestrator-common/.eslintignore new file mode 100644 index 00000000..812b3dbe --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/.eslintignore @@ -0,0 +1,7 @@ +dist-dynamic +dist-scalprum +CHANGELOG.md +**/generated/** +templates +*.hbs +renovate.json \ No newline at end of file diff --git a/workspaces/orchestrator/plugins/orchestrator-common/.eslintrc.js b/workspaces/orchestrator/plugins/orchestrator-common/.eslintrc.js new file mode 100644 index 00000000..11ceb061 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/.eslintrc.js @@ -0,0 +1,3 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname, { + ignorePatterns: ['src/generated/client/**'], +}); diff --git a/workspaces/orchestrator/plugins/orchestrator-common/.gitignore b/workspaces/orchestrator/plugins/orchestrator-common/.gitignore new file mode 100644 index 00000000..cc6b2d49 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/.gitignore @@ -0,0 +1 @@ +# src/generated/client diff --git a/workspaces/orchestrator/plugins/orchestrator-common/.prettierignore b/workspaces/orchestrator/plugins/orchestrator-common/.prettierignore new file mode 100644 index 00000000..f7783429 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/.prettierignore @@ -0,0 +1,13 @@ +dist +dist-types +coverage +.vscode +CHANGELOG.md +generated +templates +*.hbs +renovate.json +dist-dynamic +dist-scalprum +playwright-report +./src/generated diff --git a/workspaces/orchestrator/plugins/orchestrator-common/.prettierrc.js b/workspaces/orchestrator/plugins/orchestrator-common/.prettierrc.js new file mode 100644 index 00000000..5f81a8a0 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/.prettierrc.js @@ -0,0 +1,20 @@ +// @ts-check + +/** @type {import("@ianvs/prettier-plugin-sort-imports").PrettierConfig} */ +module.exports = { + ...require('@spotify/prettier-config'), + plugins: ['@ianvs/prettier-plugin-sort-imports'], + importOrder: [ + '^react(.*)$', + '', + '^@backstage/(.*)$', + '', + '', + '', + '^@red-hat-developer-hub/(.*)$', + '', + '', + '', + '^[.]', + ], +}; diff --git a/workspaces/orchestrator/plugins/orchestrator-common/CHANGELOG.md b/workspaces/orchestrator/plugins/orchestrator-common/CHANGELOG.md new file mode 100644 index 00000000..ea54021a --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/CHANGELOG.md @@ -0,0 +1,228 @@ +## @red-hat-developer-hub/backstage-plugin-orchestrator-common [1.13.1](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.13.0...@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.13.1) (2024-08-02) + +## 1.24.1 + +### Patch Changes + +- 54daa8c: Migrated from [janus-idp/backstage-plugins](https://github.com/janus-idp/backstage-plugins). + +## 1.24.0 + +### Minor Changes + +- 25f1787: Add enum filters to orchestrator plugin + +## 1.23.1 + +### Patch Changes + +- 0e6bfd3: feat: update Backstage to the latest version + + Update to Backstage 1.32.5 + +## 1.23.0 + +### Minor Changes + +- 8244f28: chore(deps): update to backstage 1.32 + +## 1.22.1 + +### Patch Changes + +- 8bd8660: fix(orchestrator): fix typo in package resolution + +## 1.22.0 + +### Minor Changes + +- d9551ae: feat(deps): update to backstage 1.31 + +### Patch Changes + +- d9551ae: change deps to peer deps in common packages +- d9551ae: upgrade to yarn v3 + +### Bug Fixes + +- **orchestrator:** remove default pagination on v2 endpoints ([#1983](https://github.com/janus-idp/backstage-plugins/issues/1983)) ([5e30274](https://github.com/janus-idp/backstage-plugins/commit/5e302748a25cbad127122407e5258576054eac3d)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator-common [1.13.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.12.0...@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.13.0) (2024-07-26) + +### Features + +- **deps:** update to backstage 1.29 ([#1900](https://github.com/janus-idp/backstage-plugins/issues/1900)) ([f53677f](https://github.com/janus-idp/backstage-plugins/commit/f53677fb02d6df43a9de98c43a9f101a6db76802)) +- **orchestrator:** use v2 endpoints to retrieve instances ([#1956](https://github.com/janus-idp/backstage-plugins/issues/1956)) ([537502b](https://github.com/janus-idp/backstage-plugins/commit/537502b9d2ac13f2fb3f79188422d2c6e97f41fb)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator-common [1.12.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.11.0...@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.12.0) (2024-07-24) + +### Features + +- **deps:** update to backstage 1.28 ([#1891](https://github.com/janus-idp/backstage-plugins/issues/1891)) ([1ba1108](https://github.com/janus-idp/backstage-plugins/commit/1ba11088e0de60e90d138944267b83600dc446e5)) +- **orchestrator:** use v2 endpoints to retrieve workflow overviews ([#1892](https://github.com/janus-idp/backstage-plugins/issues/1892)) ([cca1e53](https://github.com/janus-idp/backstage-plugins/commit/cca1e53bc6b3019b1c544f2f62bed8723ebf6130)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator-common [1.10.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.9.0...@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.10.0) (2024-06-28) + +### Features + +- **orchestrator:** remove unneeded orchestrator jira integration and endpoint ([#1833](https://github.com/janus-idp/backstage-plugins/issues/1833)) ([d2a76fd](https://github.com/janus-idp/backstage-plugins/commit/d2a76fd3db028f9774c821759bee5f38b7131c94)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator-common [1.9.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.8.1...@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.9.0) (2024-06-13) + +### Features + +- **deps:** update to backstage 1.27 ([#1683](https://github.com/janus-idp/backstage-plugins/issues/1683)) ([a14869c](https://github.com/janus-idp/backstage-plugins/commit/a14869c3f4177049cb8d6552b36c3ffd17e7997d)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator-common [1.8.1](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.8.0...@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.8.1) (2024-06-04) + +## @red-hat-developer-hub/backstage-plugin-orchestrator-common [1.8.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.7.2...@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.8.0) (2024-05-22) + +### Features + +- **orchestrator:** add permissions to orchestrator plugin ([#1599](https://github.com/janus-idp/backstage-plugins/issues/1599)) ([d0a4531](https://github.com/janus-idp/backstage-plugins/commit/d0a453181e177eb1da7b1e231253b76a2d9356a8)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator-common [1.7.2](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.7.1...@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.7.2) (2024-05-15) + +### Documentation + +- **orchestrator:** removes instructions related to the editor ([#1664](https://github.com/janus-idp/backstage-plugins/issues/1664)) ([10a75b2](https://github.com/janus-idp/backstage-plugins/commit/10a75b2706c72751bd774d6fae4332bbc527dc2b)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator-common [1.7.1](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.7.0...@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.7.1) (2024-05-09) + +## @red-hat-developer-hub/backstage-plugin-orchestrator-common [1.7.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.6.4...@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.7.0) (2024-05-09) + +### Features + +- **orchestrator:** add ability to re-trigger workflow in error state ([#1624](https://github.com/janus-idp/backstage-plugins/issues/1624)) ([8709a37](https://github.com/janus-idp/backstage-plugins/commit/8709a37d08c2eafc22f10bd2a41f0a105768222d)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator-common [1.6.4](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.6.3...@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.6.4) (2024-04-18) + +### Bug Fixes + +- **orchestrator:** allows serving the editor envelope in disconnected environments ([#1450](https://github.com/janus-idp/backstage-plugins/issues/1450)) ([1e778d8](https://github.com/janus-idp/backstage-plugins/commit/1e778d88336dfec79d48ece4fd8d2a035133b70e)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator-common [1.6.3](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.6.2...@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.6.3) (2024-04-05) + +## @red-hat-developer-hub/backstage-plugin-orchestrator-common [1.6.2](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.6.1...@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.6.2) (2024-04-04) + +### Bug Fixes + +- **orchestrator:** add lastRunId to overview endpoints ([#1449](https://github.com/janus-idp/backstage-plugins/issues/1449)) ([cce56f7](https://github.com/janus-idp/backstage-plugins/commit/cce56f7de3acc41ecd30b1b9962d7817be69de7d)) +- **orchestrator:** update devmode container tag ([#1439](https://github.com/janus-idp/backstage-plugins/issues/1439)) ([d59ad04](https://github.com/janus-idp/backstage-plugins/commit/d59ad044cd5d8d7566464f140cdbc1dfbad85a62)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator-common [1.6.1](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.6.0...@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.6.1) (2024-03-29) + +### Bug Fixes + +- **orchestrator:** fixes v2/instances endpoint ([#1414](https://github.com/janus-idp/backstage-plugins/issues/1414)) ([88b49df](https://github.com/janus-idp/backstage-plugins/commit/88b49df35cf10e231ba69c239e873cb10e7cc25b)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator-common [1.6.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.5.1...@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.6.0) (2024-03-14) + +### Features + +- **orchestrator:** verify availability and cache workflow definition IDs ([#1309](https://github.com/janus-idp/backstage-plugins/issues/1309)) ([4d322f1](https://github.com/janus-idp/backstage-plugins/commit/4d322f1fc5b6f8b1afedf40cfe1b24b2edae2ac1)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator-common [1.5.1](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.5.0...@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.5.1) (2024-03-12) + +### Bug Fixes + +- **orchestrator:** openapi files hash generation use nodejs script ([#1328](https://github.com/janus-idp/backstage-plugins/issues/1328)) ([e91c27e](https://github.com/janus-idp/backstage-plugins/commit/e91c27ecf7066149aa498e5b2e65a1d3653fa448)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator-common [1.5.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.4.1...@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.5.0) (2024-03-11) + +### Features + +- **orchestrator:** verify if auto-generated openapi files are up-to-date ([#1323](https://github.com/janus-idp/backstage-plugins/issues/1323)) ([650b435](https://github.com/janus-idp/backstage-plugins/commit/650b435ac53c517fc5e960734a4d3085399b1608)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator-common [1.4.1](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.4.0...@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.4.1) (2024-03-11) + +### Bug Fixes + +- **orchestrator:** add missing query parameter changes for /overview endpoint ([#1321](https://github.com/janus-idp/backstage-plugins/issues/1321)) ([241576d](https://github.com/janus-idp/backstage-plugins/commit/241576d242cd88e6d264180a69a5e1e9cd282df6)) + +### Other changes + +- **orchestrator:** add unit tests for v2 endpoints ([#1300](https://github.com/janus-idp/backstage-plugins/issues/1300)) ([9a13138](https://github.com/janus-idp/backstage-plugins/commit/9a13138c61d3cc7331f739da80f020bb68dd61e5)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator-common [1.4.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.3.7...@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.4.0) (2024-03-07) + +### Features + +- **orchestrator:** support pagination for /instances and /overview ([#1313](https://github.com/janus-idp/backstage-plugins/issues/1313)) ([79d5988](https://github.com/janus-idp/backstage-plugins/commit/79d598816f16c8346b6868bff4cc30d695cad518)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator-common [1.3.7](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.3.6...@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.3.7) (2024-03-03) + +### Bug Fixes + +- **orchestrator:** stop fetching workflow URI ([#1297](https://github.com/janus-idp/backstage-plugins/issues/1297)) ([2456a28](https://github.com/janus-idp/backstage-plugins/commit/2456a287dbff955a0916b9600e89a39511cd537a)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator-common [1.3.6](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.3.5...@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.3.6) (2024-02-29) + +### Bug Fixes + +- **orchestrator:** refactor 500 response to use ErrorResponse object ([#1290](https://github.com/janus-idp/backstage-plugins/issues/1290)) ([2580f3d](https://github.com/janus-idp/backstage-plugins/commit/2580f3d38cecf78334964666eb7c127c21b00924)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator-common [1.3.5](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.3.4...@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.3.5) (2024-02-28) + +### Bug Fixes + +- **orchestrator:** clean up the plugin code ([#1292](https://github.com/janus-idp/backstage-plugins/issues/1292)) ([ad27fb8](https://github.com/janus-idp/backstage-plugins/commit/ad27fb8e98913a6b80feb38ff58a7864e1953a7e)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator-common [1.3.4](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.3.3...@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.3.4) (2024-02-28) + +### Bug Fixes + +- **orchestrator:** regenerate Open API with new instance state ([#1289](https://github.com/janus-idp/backstage-plugins/issues/1289)) ([8755fdd](https://github.com/janus-idp/backstage-plugins/commit/8755fdd04dac406a4a02bfd7823d0993a6edf0b3)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator-common [1.3.3](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.3.2...@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.3.3) (2024-02-28) + +### Bug Fixes + +- **orchestrator:** handle nullable start/state properties of process instance ([#1277](https://github.com/janus-idp/backstage-plugins/issues/1277)) ([d8a43a5](https://github.com/janus-idp/backstage-plugins/commit/d8a43a5a164f83fc90d037ae3d7a355f5de543e0)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator-common [1.3.2](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.3.1...@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.3.2) (2024-02-27) + +### Bug Fixes + +- **orchestrator:** remove date-time format from spec ([#1282](https://github.com/janus-idp/backstage-plugins/issues/1282)) ([2b59dcf](https://github.com/janus-idp/backstage-plugins/commit/2b59dcf00082e617911289d8813ad02b83800470)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator-common [1.3.1](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.3.0...@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.3.1) (2024-02-21) + +### Bug Fixes + +- **orchestrator:** implementation of getWorkflowById (v2) ([#1233](https://github.com/janus-idp/backstage-plugins/issues/1233)) ([f9f9008](https://github.com/janus-idp/backstage-plugins/commit/f9f9008d29f244c2ae6d688d3e2dc9b65b705e5b)) +- **orchestrator:** minor improvements and fixes ([#1242](https://github.com/janus-idp/backstage-plugins/issues/1242)) ([c9ec4cb](https://github.com/janus-idp/backstage-plugins/commit/c9ec4cbe1847268e8068edc69c7937c5e133c315)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator-common [1.3.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.2.1...@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.3.0) (2024-02-20) + +### Features + +- **orchestrator:** add OpenAPI v2 implementations ([#1182](https://github.com/janus-idp/backstage-plugins/issues/1182)) ([43ac2f3](https://github.com/janus-idp/backstage-plugins/commit/43ac2f3f492b5c977142a3cfd9868d5e193ceb02)) + +### Bug Fixes + +- **orchestrator:** decommission the ProcessInstance.lastUpdate field ([#1230](https://github.com/janus-idp/backstage-plugins/issues/1230)) ([9724e27](https://github.com/janus-idp/backstage-plugins/commit/9724e27eaa84fe73d7724f28c86409681b7f79f8)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator-common [1.2.1](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.2.0...@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.2.1) (2024-02-16) + +### Bug Fixes + +- **orchestrator:** resolve mismatch between execution data and composed schema ([#1217](https://github.com/janus-idp/backstage-plugins/issues/1217)) ([af85114](https://github.com/janus-idp/backstage-plugins/commit/af851148935e1ed083709cac145520d7551de737)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator-common [1.2.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.1.0...@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.2.0) (2024-02-16) + +### Features + +- **orchestrator:** add OpenAPI support ([#1123](https://github.com/janus-idp/backstage-plugins/issues/1123)) ([bd88e23](https://github.com/janus-idp/backstage-plugins/commit/bd88e2304c93761ce6754985074f004a5a3c8c4b)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator-common [1.1.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.0.0...@red-hat-developer-hub/backstage-plugin-orchestrator-common@1.1.0) (2024-02-02) + +### Features + +- **orchestrator:** add the ability to rerun workflows in a new instance ([#1141](https://github.com/janus-idp/backstage-plugins/issues/1141)) ([fe326df](https://github.com/janus-idp/backstage-plugins/commit/fe326df569caa5a9e7b7ec809c1c371a2a936010)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator-common 1.0.0 (2024-01-17) + +### Features + +- **orchestrator:** add orchestrator plugin ([#783](https://github.com/janus-idp/backstage-plugins/issues/783)) ([cf5fe74](https://github.com/janus-idp/backstage-plugins/commit/cf5fe74db6992d9f51f5073bbcf20c8c346357a1)), closes [#28](https://github.com/janus-idp/backstage-plugins/issues/28) [#38](https://github.com/janus-idp/backstage-plugins/issues/38) [#35](https://github.com/janus-idp/backstage-plugins/issues/35) [#21](https://github.com/janus-idp/backstage-plugins/issues/21) diff --git a/workspaces/orchestrator/plugins/orchestrator-common/README.md b/workspaces/orchestrator/plugins/orchestrator-common/README.md new file mode 100644 index 00000000..d8c8dbe2 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/README.md @@ -0,0 +1,5 @@ +# Orchestrator Common Plugin for Backstage + +Welcome to the common package for the Orchestrator plugin! + +For more information about the Orchestrator plugin, see the [Orchestrator Plugin documentation](https://github.com/redhat-developer/rhdh-plugins/tree/main/workspaces/orchestrator/plugins/orchestrator) on GitHub. diff --git a/workspaces/orchestrator/plugins/orchestrator-common/catalog-info.yaml b/workspaces/orchestrator/plugins/orchestrator-common/catalog-info.yaml new file mode 100644 index 00000000..c71e1444 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/catalog-info.yaml @@ -0,0 +1,25 @@ +# https://backstage.io/docs/features/software-catalog/descriptor-format#kind-component +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: red-hat-developer-hub-orchestrator-common + title: '@red-hat-developer-hub/backstage-plugin-orchestrator-common' + description: Orchestrator Common Plugin for Backstage + annotations: + backstage.io/source-location: url:https://github.com/redhat-developer/rhdh-plugins/tree/main/workspaces/orchestrator/plugins/orchestrator-common + backstage.io/view-url: https://github.com/redhat-developer/rhdh-plugins/blob/main/workspaces/orchestrator/plugins/orchestrator-common/catalog-info.yaml + backstage.io/edit-url: https://github.com/redhat-developer/rhdh-plugins/edit/main/workspaces/orchestrator/plugins/orchestrator-common/catalog-info.yaml + github.com/project-slug: red-hat-developer-hub/backstage-plugins + github.com/team-slug: red-hat-developer-hub/orchestrator-codeowners + sonarqube.org/project-key: red_hat_developer_hub_plugins + links: + - url: https://github.com/redhat-developer/rhdh-plugins/tree/main/workspaces/orchestrator/plugins/orchestrator-common + title: GitHub Source + icon: source + type: source +spec: + type: backstage-common-library + lifecycle: production + owner: orchestrator-team + system: rhdh + subcomponentOf: red-hat-developer-hub-orchestrator diff --git a/workspaces/orchestrator/plugins/orchestrator-common/config.d.ts b/workspaces/orchestrator/plugins/orchestrator-common/config.d.ts new file mode 100644 index 00000000..c6dea9f7 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/config.d.ts @@ -0,0 +1,81 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export interface Config { + /** + * Configuration for the Orchestrator plugin. + */ + orchestrator?: { + sonataFlowService: { + /** + * Base URL of the Sonata Flow service. + * Default: http://localhost + */ + baseUrl?: string; + /** + * Port of the Sonata Flow service. + * Default: no port + */ + port?: string; + /** + * Whether to start the Sonata Flow service automatically. + * If set to `false`, the plugin assumes that the SonataFlow service is already running on `baseUrl`:`port` (or just `baseUrl` if `port` is not set). + * Default: false + */ + autoStart?: boolean; + /** + * Workflows definitions source configurations + */ + workflowsSource?: + | { + /** + * Remote git repository where workflows definitions are stored + */ + gitRepositoryUrl: string; + /** + * Path to map workflow resources to SonataFlow service. + * Example: /home/orchestrator/workflows + */ + localPath: string; + } + | { + localPath: string; + }; + + /** + * Container image name of the Sonata Flow service. + * Default: quay.io/kiegroup/kogito-swf-devmode-nightly:main-2024-02-19 + */ + container?: string; + /** + * Persistance configuration of the Sonata Flow service. + */ + persistance?: { + /** + * Path in the container image to store persistance data. + * Default: /home/kogito/persistence + */ + path?: string; + }; + }; + dataIndexService: { + /** + * URL of the Data Index service. + * Example: http://localhost:8099 + */ + url: string; + }; + }; +} diff --git a/workspaces/orchestrator/plugins/orchestrator-common/openapitools.json b/workspaces/orchestrator/plugins/orchestrator-common/openapitools.json new file mode 100644 index 00000000..937a5f35 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/openapitools.json @@ -0,0 +1,7 @@ +{ + "$schema": "../../node_modules/@openapitools/openapi-generator-cli/config.schema.json", + "spaces": 2, + "generator-cli": { + "version": "7.3.0" + } +} diff --git a/workspaces/orchestrator/plugins/orchestrator-common/package.json b/workspaces/orchestrator/plugins/orchestrator-common/package.json new file mode 100644 index 00000000..c89c64ae --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/package.json @@ -0,0 +1,84 @@ +{ + "name": "@red-hat-developer-hub/backstage-plugin-orchestrator-common", + "version": "1.24.1", + "license": "Apache-2.0", + "main": "src/index.ts", + "types": "src/index.ts", + "publishConfig": { + "access": "public", + "main": "dist/index.cjs.js", + "module": "dist/index.esm.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "common-library", + "supported-versions": "1.32.5", + "pluginId": "orchestrator", + "pluginPackages": [ + "@red-hat-developer-hub/backstage-plugin-orchestrator", + "@red-hat-developer-hub/backstage-plugin-orchestrator-backend", + "@red-hat-developer-hub/backstage-plugin-orchestrator-common" + ] + }, + "homepage": "https://red.ht/rhdh", + "repository": { + "type": "git", + "url": "https://github.com/redhat-developer/rhdh-plugins", + "directory": "workspaces/orchestrator/plugins/orchestrator-common" + }, + "bugs": "https://github.com/redhat-developer/rhdh-plugins/issues", + "keywords": [ + "support:tech-preview", + "lifecycle:active", + "backstage", + "plugin", + "orchestrator", + "workflows" + ], + "files": [ + "config.d.ts", + "dist", + "src/generated/docs/html" + ], + "configSchema": "config.d.ts", + "sideEffects": false, + "scripts": { + "build": "backstage-cli package build", + "tsc": "tsc", + "prettier:check": "prettier --ignore-unknown --check .", + "prettier:fix": "prettier --ignore-unknown --write .", + "lint:check": "backstage-cli package lint", + "lint:fix": "backstage-cli package lint --fix", + "test": "backstage-cli package test --passWithNoTests --coverage", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "openapi:generate": "./scripts/openapi.sh generate", + "openapi:check": "./scripts/openapi.sh check" + }, + "peerDependencies": { + "@backstage/plugin-permission-common": "^0.8.1", + "@backstage/types": "^1.1.1", + "@severlessworkflow/sdk-typescript": "^3.0.3", + "axios": "^1.7.4", + "js-yaml": "^4.1.0" + }, + "devDependencies": { + "@backstage/cli": "0.28.2", + "@backstage/plugin-permission-common": "^0.8.1", + "@backstage/types": "1.1.1", + "@openapitools/openapi-generator-cli": "2.13.4", + "@severlessworkflow/sdk-typescript": "3.0.3", + "axios": "^1.7.4", + "js-yaml": "^4.1.0", + "js-yaml-cli": "0.6.0", + "json-schema": "0.4.0", + "prettier": "3.3.3" + }, + "maintainers": [ + "@mlibra", + "@batzionb", + "@gciavarrini" + ], + "author": "The Backstage Community" +} diff --git a/workspaces/orchestrator/plugins/orchestrator-common/report.api.md b/workspaces/orchestrator/plugins/orchestrator-common/report.api.md new file mode 100644 index 00000000..f8dbcab7 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/report.api.md @@ -0,0 +1,2117 @@ +## API Report File for "@red-hat-developer-hub/backstage-plugin-orchestrator-common" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import type { AxiosInstance } from 'axios'; +import type { AxiosPromise } from 'axios'; +import { AxiosResponse } from 'axios'; +import { BasicPermission } from '@backstage/plugin-permission-common'; +import type { JsonObject } from '@backstage/types'; +import type { JSONSchema7 } from 'json-schema'; +import type { JSONSchema7Definition } from 'json-schema'; +import type { RawAxiosRequestConfig } from 'axios'; +import type { Specification } from '@severlessworkflow/sdk-typescript'; + +// Warning: (ae-missing-release-tag) "AssessedProcessInstance" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export interface AssessedProcessInstance { + // (undocumented) + assessedBy?: ProcessInstance; + // (undocumented) + instance: ProcessInstance; +} + +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@export" is not defined in this configuration +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@interface" is not defined in this configuration +// Warning: (ae-missing-release-tag) "AssessedProcessInstanceDTO" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export interface AssessedProcessInstanceDTO { + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'assessedBy'?: ProcessInstanceDTO; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'instance': ProcessInstanceDTO; +} + +// Warning: (ae-missing-release-tag) "ASSESSMENT_WORKFLOW_TYPE" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const ASSESSMENT_WORKFLOW_TYPE = "workflow-type/assessment"; + +// Warning: (ae-missing-release-tag) "capitalize" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const capitalize: (text: S) => Capitalize>; + +// Warning: (ae-missing-release-tag) "Capitalized" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type Capitalized = Capitalize>; + +// Warning: (ae-missing-release-tag) "ComposedSchema" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type ComposedSchema = Omit & { + properties: { + [key: string]: Omit & { + properties: { + [key: string]: JsonObjectSchema; + }; + }; + }; +}; + +// Warning: (ae-missing-release-tag) "Configuration" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export class Configuration { + constructor(param?: ConfigurationParameters); + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string) | ((name?: string, scopes?: string[]) => Promise); + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + apiKey?: string | Promise | ((name: string) => string) | ((name: string) => Promise); + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + baseOptions?: any; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + basePath?: string; + // Warning: (tsdoc-escape-greater-than) The ">" character should be escaped using a backslash to avoid confusion with an HTML tag + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + formDataCtor?: new () => any; + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@return" is not defined in this configuration + isJsonMime(mime: string): boolean; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + password?: string; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + serverIndex?: number; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + username?: string; +} + +// Warning: (ae-missing-release-tag) "ConfigurationParameters" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export interface ConfigurationParameters { + // (undocumented) + accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string) | ((name?: string, scopes?: string[]) => Promise); + // (undocumented) + apiKey?: string | Promise | ((name: string) => string) | ((name: string) => Promise); + // (undocumented) + baseOptions?: any; + // (undocumented) + basePath?: string; + // (undocumented) + formDataCtor?: new () => any; + // (undocumented) + password?: string; + // (undocumented) + serverIndex?: number; + // (undocumented) + username?: string; +} + +// Warning: (ae-missing-release-tag) "DEFAULT_SONATAFLOW_BASE_URL" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const DEFAULT_SONATAFLOW_BASE_URL = "http://localhost"; + +// Warning: (ae-missing-release-tag) "DEFAULT_SONATAFLOW_CONTAINER_IMAGE" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const DEFAULT_SONATAFLOW_CONTAINER_IMAGE = "docker.io/apache/incubator-kie-sonataflow-devmode:latest"; + +// Warning: (ae-missing-release-tag) "DEFAULT_SONATAFLOW_PERSISTENCE_PATH" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const DEFAULT_SONATAFLOW_PERSISTENCE_PATH = "/home/kogito/persistence"; + +// Warning: (ae-missing-release-tag) "DEFAULT_WORKFLOWS_PATH" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const DEFAULT_WORKFLOWS_PATH = "workflows"; + +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@export" is not defined in this configuration +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@class" is not defined in this configuration +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@extends" is not defined in this configuration +// Warning: (ae-forgotten-export) The symbol "BaseAPI" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "DefaultApi" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export class DefaultApi extends BaseAPI { + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@summary" is not defined in this configuration + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen + // Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen + // Warning: (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. + // Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + abortWorkflow(instanceId: string, options?: RawAxiosRequestConfig): Promise>; + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@summary" is not defined in this configuration + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen + // Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen + // Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen + // Warning: (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. + // Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + executeWorkflow(workflowId: string, executeWorkflowRequestDTO: ExecuteWorkflowRequestDTO, options?: RawAxiosRequestConfig): Promise>; + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@summary" is not defined in this configuration + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen + // Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen + // Warning: (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. + // Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen + // Warning: (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. + // Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + getInstanceById(instanceId: string, includeAssessment?: boolean, options?: RawAxiosRequestConfig): Promise>; + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@summary" is not defined in this configuration + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen + // Warning: (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. + // Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen + // Warning: (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. + // Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + getInstances(getInstancesRequest?: GetInstancesRequest, options?: RawAxiosRequestConfig): Promise>; + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen + // Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen + // Warning: (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. + // Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen + // Warning: (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. + // Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + getWorkflowInputSchemaById(workflowId: string, instanceId?: string, options?: RawAxiosRequestConfig): Promise>; + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@summary" is not defined in this configuration + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen + // Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen + // Warning: (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. + // Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen + // Warning: (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. + // Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + getWorkflowInstances(workflowId: string, searchRequest?: SearchRequest, options?: RawAxiosRequestConfig): Promise>; + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen + // Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen + // Warning: (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. + // Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + getWorkflowOverviewById(workflowId: string, options?: RawAxiosRequestConfig): Promise>; + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen + // Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen + // Warning: (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. + // Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + getWorkflowSourceById(workflowId: string, options?: RawAxiosRequestConfig): Promise>; + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen + // Warning: (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. + // Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen + // Warning: (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. + // Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + getWorkflowsOverview(searchRequest?: SearchRequest, options?: RawAxiosRequestConfig): Promise>; + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@summary" is not defined in this configuration + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen + // Warning: (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. + // Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + getWorkflowStatuses(options?: RawAxiosRequestConfig): Promise>; + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@summary" is not defined in this configuration + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen + // Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen + // Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen + // Warning: (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. + // Warning: (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + retriggerInstance(workflowId: string, instanceId: string, options?: RawAxiosRequestConfig): Promise>; +} + +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@export" is not defined in this configuration +// Warning: (ae-missing-release-tag) "DefaultApiAxiosParamCreator" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export const DefaultApiAxiosParamCreator: (configuration?: Configuration) => { + abortWorkflow: (instanceId: string, options?: RawAxiosRequestConfig) => Promise; + executeWorkflow: (workflowId: string, executeWorkflowRequestDTO: ExecuteWorkflowRequestDTO, options?: RawAxiosRequestConfig) => Promise; + getInstanceById: (instanceId: string, includeAssessment?: boolean, options?: RawAxiosRequestConfig) => Promise; + getInstances: (getInstancesRequest?: GetInstancesRequest, options?: RawAxiosRequestConfig) => Promise; + getWorkflowInputSchemaById: (workflowId: string, instanceId?: string, options?: RawAxiosRequestConfig) => Promise; + getWorkflowInstances: (workflowId: string, searchRequest?: SearchRequest, options?: RawAxiosRequestConfig) => Promise; + getWorkflowOverviewById: (workflowId: string, options?: RawAxiosRequestConfig) => Promise; + getWorkflowSourceById: (workflowId: string, options?: RawAxiosRequestConfig) => Promise; + getWorkflowStatuses: (options?: RawAxiosRequestConfig) => Promise; + getWorkflowsOverview: (searchRequest?: SearchRequest, options?: RawAxiosRequestConfig) => Promise; + retriggerInstance: (workflowId: string, instanceId: string, options?: RawAxiosRequestConfig) => Promise; +}; + +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@export" is not defined in this configuration +// Warning: (ae-missing-release-tag) "DefaultApiFactory" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export const DefaultApiFactory: (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) => { + abortWorkflow(instanceId: string, options?: any): AxiosPromise; + executeWorkflow(workflowId: string, executeWorkflowRequestDTO: ExecuteWorkflowRequestDTO, options?: any): AxiosPromise; + getInstanceById(instanceId: string, includeAssessment?: boolean, options?: any): AxiosPromise; + getInstances(getInstancesRequest?: GetInstancesRequest, options?: any): AxiosPromise; + getWorkflowInputSchemaById(workflowId: string, instanceId?: string, options?: any): AxiosPromise; + getWorkflowInstances(workflowId: string, searchRequest?: SearchRequest, options?: any): AxiosPromise; + getWorkflowOverviewById(workflowId: string, options?: any): AxiosPromise; + getWorkflowSourceById(workflowId: string, options?: any): AxiosPromise; + getWorkflowStatuses(options?: any): AxiosPromise>; + getWorkflowsOverview(searchRequest?: SearchRequest, options?: any): AxiosPromise; + retriggerInstance(workflowId: string, instanceId: string, options?: any): AxiosPromise; +}; + +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@export" is not defined in this configuration +// Warning: (ae-missing-release-tag) "DefaultApiFp" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export const DefaultApiFp: (configuration?: Configuration) => { + abortWorkflow(instanceId: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise>; + executeWorkflow(workflowId: string, executeWorkflowRequestDTO: ExecuteWorkflowRequestDTO, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise>; + getInstanceById(instanceId: string, includeAssessment?: boolean, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise>; + getInstances(getInstancesRequest?: GetInstancesRequest, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise>; + getWorkflowInputSchemaById(workflowId: string, instanceId?: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise>; + getWorkflowInstances(workflowId: string, searchRequest?: SearchRequest, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise>; + getWorkflowOverviewById(workflowId: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise>; + getWorkflowSourceById(workflowId: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise>; + getWorkflowStatuses(options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise>>; + getWorkflowsOverview(searchRequest?: SearchRequest, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise>; + retriggerInstance(workflowId: string, instanceId: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise>; +}; + +// Warning: (ae-missing-release-tag) "ellipsis" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const ellipsis: (text: S, prefixLength?: number) => string; + +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@export" is not defined in this configuration +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@interface" is not defined in this configuration +// Warning: (ae-missing-release-tag) "ErrorResponse" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export interface ErrorResponse { + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'additionalInfo'?: string; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'message': string; +} + +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@export" is not defined in this configuration +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@interface" is not defined in this configuration +// Warning: (ae-missing-release-tag) "ExecuteWorkflowRequestDTO" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export interface ExecuteWorkflowRequestDTO { + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'inputData': object; +} + +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@export" is not defined in this configuration +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@interface" is not defined in this configuration +// Warning: (ae-missing-release-tag) "ExecuteWorkflowResponseDTO" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export interface ExecuteWorkflowResponseDTO { + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'id': string; +} + +// Warning: (ae-missing-release-tag) "extractWorkflowFormat" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export function extractWorkflowFormat(source: string): WorkflowFormat; + +// Warning: (ae-missing-release-tag) "extractWorkflowFormatFromUri" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export function extractWorkflowFormatFromUri(uri: string): WorkflowFormat; + +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@export" is not defined in this configuration +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@interface" is not defined in this configuration +// Warning: (ae-missing-release-tag) "FieldFilter" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export interface FieldFilter { + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'field': string; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'operator': FieldFilterOperatorEnum; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'value': FieldFilterValue; +} + +// Warning: (ae-missing-release-tag) "FieldFilterOperatorEnum" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// Warning: (ae-missing-release-tag) "FieldFilterOperatorEnum" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const FieldFilterOperatorEnum: { + readonly Eq: "EQ"; + readonly Gt: "GT"; + readonly Gte: "GTE"; + readonly Lt: "LT"; + readonly Lte: "LTE"; + readonly In: "IN"; + readonly IsNull: "IS_NULL"; + readonly Contains: "CONTAINS"; + readonly ContainsAll: "CONTAINS_ALL"; + readonly ContainsAny: "CONTAINS_ANY"; + readonly Like: "LIKE"; + readonly Between: "BETWEEN"; +}; + +// @public (undocumented) +export type FieldFilterOperatorEnum = typeof FieldFilterOperatorEnum[keyof typeof FieldFilterOperatorEnum]; + +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@export" is not defined in this configuration +// Warning: (ae-missing-release-tag) "FieldFilterValue" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export type FieldFilterValue = any | boolean | number | string; + +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@export" is not defined in this configuration +// Warning: (ae-missing-release-tag) "Filter" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export type Filter = FieldFilter | LogicalFilter; + +// Warning: (ae-missing-release-tag) "fromWorkflowSource" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export function fromWorkflowSource(content: string): WorkflowDefinition; + +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@export" is not defined in this configuration +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@interface" is not defined in this configuration +// Warning: (ae-missing-release-tag) "GetInstancesRequest" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export interface GetInstancesRequest { + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'filters'?: SearchRequest; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'paginationInfo'?: PaginationInfoDTO; +} + +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@export" is not defined in this configuration +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@interface" is not defined in this configuration +// Warning: (ae-missing-release-tag) "GetOverviewsRequestParams" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export interface GetOverviewsRequestParams { + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'filters'?: SearchRequest; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'paginationInfo'?: PaginationInfoDTO; +} + +// Warning: (ae-missing-release-tag) "getWorkflowCategory" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export function getWorkflowCategory(definition: WorkflowDefinition | undefined): WorkflowCategory; + +// Warning: (ae-missing-release-tag) "INFRASTRUCTURE_WORKFLOW_TYPE" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const INFRASTRUCTURE_WORKFLOW_TYPE = "workflow-type/infrastructure"; + +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@export" is not defined in this configuration +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@interface" is not defined in this configuration +// Warning: (ae-missing-release-tag) "InputSchemaResponseDTO" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export interface InputSchemaResponseDTO { + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'data'?: object; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'inputSchema'?: object; +} + +// Warning: (ae-missing-release-tag) "IntrospectionField" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export interface IntrospectionField { + // (undocumented) + name: string; + // (undocumented) + type: IntrospectionTypeRef; +} + +// Warning: (ae-missing-release-tag) "IntrospectionQuery" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export interface IntrospectionQuery { + // (undocumented) + __type: IntrospectionType | null; +} + +// Warning: (ae-missing-release-tag) "IntrospectionType" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export interface IntrospectionType { + // (undocumented) + description: string | null; + // (undocumented) + fields: IntrospectionField[] | null; + // (undocumented) + kind: TypeKind; + // (undocumented) + name: string; +} + +// Warning: (ae-missing-release-tag) "IntrospectionTypeRef" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export interface IntrospectionTypeRef { + // (undocumented) + kind: TypeKind; + // (undocumented) + name: TypeName; + // (undocumented) + ofType: IntrospectionTypeRef | null; +} + +// Warning: (ae-missing-release-tag) "isComposedSchema" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const isComposedSchema: (schema: JSONSchema7 | ComposedSchema) => schema is ComposedSchema; + +// Warning: (ae-missing-release-tag) "isJsonObjectSchema" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const isJsonObjectSchema: (schema: JSONSchema7 | JsonObjectSchema | JSONSchema7Definition) => schema is JsonObjectSchema; + +// Warning: (ae-missing-release-tag) "JsonObjectSchema" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type JsonObjectSchema = Omit & { + properties: { + [key: string]: JSONSchema7; + }; +}; + +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@export" is not defined in this configuration +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@interface" is not defined in this configuration +// Warning: (ae-missing-release-tag) "LogicalFilter" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export interface LogicalFilter { + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'filters': Array; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'operator': LogicalFilterOperatorEnum; +} + +// Warning: (ae-missing-release-tag) "LogicalFilterOperatorEnum" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// Warning: (ae-missing-release-tag) "LogicalFilterOperatorEnum" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const LogicalFilterOperatorEnum: { + readonly And: "AND"; + readonly Or: "OR"; + readonly Not: "NOT"; +}; + +// @public (undocumented) +export type LogicalFilterOperatorEnum = typeof LogicalFilterOperatorEnum[keyof typeof LogicalFilterOperatorEnum]; + +// Warning: (ae-missing-release-tag) "Milestone" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export interface Milestone { + // (undocumented) + __typename?: 'Milestone'; + // (undocumented) + id: string; + // (undocumented) + name: string; + // (undocumented) + status: MilestoneStatus; +} + +// Warning: (ae-missing-release-tag) "MilestoneStatus" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export enum MilestoneStatus { + // (undocumented) + Active = "ACTIVE", + // (undocumented) + Available = "AVAILABLE", + // (undocumented) + Completed = "COMPLETED" +} + +// Warning: (ae-missing-release-tag) "Node" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +interface Node_2 { + // (undocumented) + id: string; + // (undocumented) + name?: string; + // (undocumented) + nodeDefinitionId?: string; + // (undocumented) + type?: string; + // (undocumented) + uniqueId?: string; +} +export { Node_2 as Node } + +// Warning: (ae-missing-release-tag) "NodeInstance" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export interface NodeInstance { + // (undocumented) + __typename?: 'NodeInstance'; + // (undocumented) + definitionId: string; + // (undocumented) + enter: string; + // (undocumented) + exit?: string; + // (undocumented) + id: string; + // (undocumented) + name: string; + // (undocumented) + nodeId: string; + // (undocumented) + type: string; +} + +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@export" is not defined in this configuration +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@interface" is not defined in this configuration +// Warning: (ae-missing-release-tag) "NodeInstanceDTO" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export interface NodeInstanceDTO { + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + '__typename'?: string; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'definitionId'?: string; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'enter'?: string; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'exit'?: string; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'id': string; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'name'?: string; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'nodeId'?: string; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'type'?: string; +} + +// Warning: (ae-forgotten-export) The symbol "OmitDistributive" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "OmitRecursively" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type OmitRecursively = Omit<{ + [P in keyof T]: OmitDistributive; +}, K>; + +// Warning: (ae-missing-release-tag) "openApiDocument" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const openApiDocument: any; + +// Warning: (ae-missing-release-tag) "orchestratorPermissions" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const orchestratorPermissions: BasicPermission[]; + +// Warning: (ae-missing-release-tag) "orchestratorWorkflowExecutePermission" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const orchestratorWorkflowExecutePermission: BasicPermission; + +// Warning: (ae-missing-release-tag) "orchestratorWorkflowInstanceAbortPermission" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const orchestratorWorkflowInstanceAbortPermission: BasicPermission; + +// Warning: (ae-missing-release-tag) "orchestratorWorkflowInstanceReadPermission" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const orchestratorWorkflowInstanceReadPermission: BasicPermission; + +// Warning: (ae-missing-release-tag) "orchestratorWorkflowInstancesReadPermission" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const orchestratorWorkflowInstancesReadPermission: BasicPermission; + +// Warning: (ae-missing-release-tag) "orchestratorWorkflowReadPermission" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const orchestratorWorkflowReadPermission: BasicPermission; + +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@export" is not defined in this configuration +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@interface" is not defined in this configuration +// Warning: (ae-missing-release-tag) "PaginationInfoDTO" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export interface PaginationInfoDTO { + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'offset'?: number; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'orderBy'?: string; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'orderDirection'?: PaginationInfoDTOOrderDirectionEnum; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'pageSize'?: number; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'totalCount'?: number; +} + +// Warning: (ae-missing-release-tag) "PaginationInfoDTOOrderDirectionEnum" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// Warning: (ae-missing-release-tag) "PaginationInfoDTOOrderDirectionEnum" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const PaginationInfoDTOOrderDirectionEnum: { + readonly Asc: "ASC"; + readonly Desc: "DESC"; +}; + +// @public (undocumented) +export type PaginationInfoDTOOrderDirectionEnum = typeof PaginationInfoDTOOrderDirectionEnum[keyof typeof PaginationInfoDTOOrderDirectionEnum]; + +// Warning: (ae-missing-release-tag) "parseWorkflowVariables" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export function parseWorkflowVariables(variables?: object): object | undefined; + +// Warning: (ae-missing-release-tag) "ProcessInstance" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export interface ProcessInstance { + // (undocumented) + addons?: string[]; + // (undocumented) + businessKey?: string; + // (undocumented) + category?: WorkflowCategory; + // (undocumented) + childProcessInstances?: ProcessInstance[]; + // (undocumented) + description?: WorkflowDefinition['description']; + // (undocumented) + diagram?: string; + end?: string; + // (undocumented) + endpoint: string; + // (undocumented) + error?: ProcessInstanceError; + // (undocumented) + errorMessage?: string; + // (undocumented) + id: string; + // (undocumented) + isOpen?: boolean; + // (undocumented) + isSelected?: boolean; + // (undocumented) + milestones?: Milestone[]; + // (undocumented) + nodeDefinitions?: TriggerableNode[]; + // (undocumented) + nodes: NodeInstance[]; + // (undocumented) + parentProcessInstance?: ProcessInstance; + // (undocumented) + parentProcessInstanceId?: string; + // (undocumented) + processId: string; + // (undocumented) + processName?: string; + // (undocumented) + roles?: string[]; + // (undocumented) + rootProcessId?: string; + // (undocumented) + rootProcessInstanceId?: string; + // (undocumented) + serviceUrl?: string; + // (undocumented) + source?: string; + start?: string; + // (undocumented) + state?: ProcessInstanceStateValues; + // (undocumented) + variables?: ProcessInstanceVariables | string; +} + +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@export" is not defined in this configuration +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@interface" is not defined in this configuration +// Warning: (ae-missing-release-tag) "ProcessInstanceDTO" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export interface ProcessInstanceDTO { + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'businessKey'?: string; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'category'?: WorkflowCategoryDTO; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'description'?: string; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'duration'?: string; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'end'?: string; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'endpoint'?: string; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'error'?: ProcessInstanceErrorDTO; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'id': string; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'nodes': Array; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'processId': string; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'processName'?: string; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'serviceUrl'?: string; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'start'?: string; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'status'?: ProcessInstanceStatusDTO; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'workflowdata'?: WorkflowDataDTO; +} + +// Warning: (ae-missing-release-tag) "ProcessInstanceError" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export interface ProcessInstanceError { + // (undocumented) + __typename?: 'ProcessInstanceError'; + // (undocumented) + message?: string; + // (undocumented) + nodeDefinitionId: string; +} + +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@export" is not defined in this configuration +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@interface" is not defined in this configuration +// Warning: (ae-missing-release-tag) "ProcessInstanceErrorDTO" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export interface ProcessInstanceErrorDTO { + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + '__typename'?: string; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'message'?: string; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'nodeDefinitionId': string; +} + +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@export" is not defined in this configuration +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@interface" is not defined in this configuration +// Warning: (ae-missing-release-tag) "ProcessInstanceListResultDTO" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export interface ProcessInstanceListResultDTO { + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'items'?: Array; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'paginationInfo'?: PaginationInfoDTO; +} + +// Warning: (ae-missing-release-tag) "ProcessInstanceState" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export enum ProcessInstanceState { + // (undocumented) + Aborted = "ABORTED", + // (undocumented) + Active = "ACTIVE", + // (undocumented) + Completed = "COMPLETED", + // (undocumented) + Error = "ERROR", + // (undocumented) + Pending = "PENDING", + // (undocumented) + Suspended = "SUSPENDED" +} + +// Warning: (ae-missing-release-tag) "ProcessInstanceStateValues" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type ProcessInstanceStateValues = Uppercase; + +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@export" is not defined in this configuration +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@enum" is not defined in this configuration +// Warning: (ae-missing-release-tag) "ProcessInstanceStatusDTO" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// Warning: (ae-missing-release-tag) "ProcessInstanceStatusDTO" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export const ProcessInstanceStatusDTO: { + readonly Active: "Active"; + readonly Error: "Error"; + readonly Completed: "Completed"; + readonly Aborted: "Aborted"; + readonly Suspended: "Suspended"; + readonly Pending: "Pending"; +}; + +// @public (undocumented) +export type ProcessInstanceStatusDTO = typeof ProcessInstanceStatusDTO[keyof typeof ProcessInstanceStatusDTO]; + +// Warning: (ae-missing-release-tag) "ProcessInstanceVariables" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type ProcessInstanceVariables = Record; + +// Warning: (ae-missing-release-tag) "QUERY_PARAM_ASSESSMENT_INSTANCE_ID" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const QUERY_PARAM_ASSESSMENT_INSTANCE_ID: "assessmentInstanceId"; + +// Warning: (ae-missing-release-tag) "QUERY_PARAM_BUSINESS_KEY" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const QUERY_PARAM_BUSINESS_KEY: "businessKey"; + +// Warning: (ae-missing-release-tag) "QUERY_PARAM_INCLUDE_ASSESSMENT" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const QUERY_PARAM_INCLUDE_ASSESSMENT: "includeAssessment"; + +// Warning: (ae-missing-release-tag) "QUERY_PARAM_INSTANCE_ID" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const QUERY_PARAM_INSTANCE_ID: "instanceId"; + +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@export" is not defined in this configuration +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@interface" is not defined in this configuration +// Warning: (ae-missing-release-tag) "SearchRequest" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export interface SearchRequest { + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'filters'?: Filter; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'paginationInfo'?: PaginationInfoDTO; +} + +// Warning: (ae-missing-release-tag) "toWorkflowJson" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export function toWorkflowJson(definition: WorkflowDefinition): string; + +// Warning: (ae-missing-release-tag) "toWorkflowString" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export function toWorkflowString(definition: WorkflowDefinition, format: WorkflowFormat): string; + +// Warning: (ae-missing-release-tag) "toWorkflowYaml" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export function toWorkflowYaml(definition: WorkflowDefinition): string; + +// Warning: (ae-missing-release-tag) "TriggerableNode" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export interface TriggerableNode { + // (undocumented) + id: number; + // (undocumented) + name: string; + // (undocumented) + nodeDefinitionId: string; + // (undocumented) + type: string; + // (undocumented) + uniqueId: string; +} + +// Warning: (ae-missing-release-tag) "TypeKind" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export enum TypeKind { + // (undocumented) + InputObject = "INPUT_OBJECT" +} + +// Warning: (ae-missing-release-tag) "TypeName" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export enum TypeName { + // (undocumented) + Date = "DateArgument", + // (undocumented) + Id = "IdArgument", + // (undocumented) + String = "StringArgument", + // (undocumented) + StringArray = "StringArrayArgument" +} + +// Warning: (ae-missing-release-tag) "WorkflowCategory" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export enum WorkflowCategory { + // (undocumented) + ASSESSMENT = "assessment", + // (undocumented) + INFRASTRUCTURE = "infrastructure" +} + +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@export" is not defined in this configuration +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@enum" is not defined in this configuration +// Warning: (ae-missing-release-tag) "WorkflowCategoryDTO" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// Warning: (ae-missing-release-tag) "WorkflowCategoryDTO" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export const WorkflowCategoryDTO: { + readonly Assessment: "assessment"; + readonly Infrastructure: "infrastructure"; +}; + +// @public (undocumented) +export type WorkflowCategoryDTO = typeof WorkflowCategoryDTO[keyof typeof WorkflowCategoryDTO]; + +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@export" is not defined in this configuration +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@interface" is not defined in this configuration +// Warning: (ae-missing-release-tag) "WorkflowDataDTO" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export interface WorkflowDataDTO { + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'result'?: WorkflowResultDTO; +} + +// Warning: (ae-missing-release-tag) "WorkflowDefinition" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type WorkflowDefinition = OmitRecursively; + +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@export" is not defined in this configuration +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@interface" is not defined in this configuration +// Warning: (ae-missing-release-tag) "WorkflowDTO" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export interface WorkflowDTO { + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'annotations'?: Array; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'category': WorkflowCategoryDTO; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'description'?: string; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'format': WorkflowFormatDTO; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'id': string; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'name'?: string; +} + +// Warning: (ae-missing-release-tag) "WorkflowExecutionResponse" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export interface WorkflowExecutionResponse { + // (undocumented) + id: string; +} + +// Warning: (ae-missing-release-tag) "WorkflowFormat" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type WorkflowFormat = 'yaml' | 'json'; + +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@export" is not defined in this configuration +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@enum" is not defined in this configuration +// Warning: (ae-missing-release-tag) "WorkflowFormatDTO" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// Warning: (ae-missing-release-tag) "WorkflowFormatDTO" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export const WorkflowFormatDTO: { + readonly Yaml: "yaml"; + readonly Json: "json"; +}; + +// @public (undocumented) +export type WorkflowFormatDTO = typeof WorkflowFormatDTO[keyof typeof WorkflowFormatDTO]; + +// Warning: (ae-missing-release-tag) "WorkflowInfo" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export interface WorkflowInfo { + // (undocumented) + annotations?: string[]; + // (undocumented) + description?: string; + // (undocumented) + endpoint?: string; + // (undocumented) + id: string; + // (undocumented) + inputSchema?: JSONSchema7; + // (undocumented) + metadata?: Map; + // (undocumented) + name?: string; + // (undocumented) + nodes?: Node_2[]; + // (undocumented) + roles?: string[]; + // (undocumented) + serviceUrl?: string; + // (undocumented) + source?: string; + // (undocumented) + type?: string; + // (undocumented) + version?: string; +} + +// Warning: (ae-missing-release-tag) "WorkflowInputSchemaStep" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type WorkflowInputSchemaStep = { + schema: JsonObjectSchema; + title: string; + key: string; + data: JsonObject; + readonlyKeys: string[]; +}; + +// Warning: (ae-missing-release-tag) "WorkflowListResult" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type WorkflowListResult = { + items: WorkflowDefinition[]; + totalCount: number; + offset: number; + limit: number; +}; + +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@export" is not defined in this configuration +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@interface" is not defined in this configuration +// Warning: (ae-missing-release-tag) "WorkflowListResultDTO" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export interface WorkflowListResultDTO { + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'items': Array; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'paginationInfo': PaginationInfoDTO; +} + +// Warning: (ae-missing-release-tag) "WorkflowOverview" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export interface WorkflowOverview { + // (undocumented) + avgDurationMs?: number; + // (undocumented) + category?: string; + // (undocumented) + description?: string; + // (undocumented) + format: WorkflowFormat; + // (undocumented) + lastRunId?: string; + // (undocumented) + lastRunStatus?: ProcessInstanceStateValues; + // (undocumented) + lastTriggeredMs?: number; + // (undocumented) + name?: string; + // (undocumented) + workflowId: string; +} + +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@export" is not defined in this configuration +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@interface" is not defined in this configuration +// Warning: (ae-missing-release-tag) "WorkflowOverviewDTO" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export interface WorkflowOverviewDTO { + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'avgDurationMs'?: number; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'category'?: WorkflowCategoryDTO; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'description'?: string; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'format': WorkflowFormatDTO; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'lastRunId'?: string; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'lastRunStatus'?: ProcessInstanceStatusDTO; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'lastTriggeredMs'?: number; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'name'?: string; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'workflowId': string; +} + +// Warning: (ae-missing-release-tag) "WorkflowOverviewListResult" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type WorkflowOverviewListResult = { + items: WorkflowOverview[]; + totalCount: number; + offset: number; + limit: number; +}; + +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@export" is not defined in this configuration +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@interface" is not defined in this configuration +// Warning: (ae-missing-release-tag) "WorkflowOverviewListResultDTO" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export interface WorkflowOverviewListResultDTO { + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'overviews'?: Array; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'paginationInfo'?: PaginationInfoDTO; +} + +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@export" is not defined in this configuration +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@interface" is not defined in this configuration +// Warning: (ae-missing-release-tag) "WorkflowProgressDTO" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export interface WorkflowProgressDTO { + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + '__typename'?: any; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'definitionId'?: any; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'enter'?: any; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'error'?: ProcessInstanceErrorDTO; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'exit'?: any; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'id': any; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'name'?: any; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'nodeId'?: any; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'status'?: ProcessInstanceStatusDTO; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'type'?: any; +} + +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@export" is not defined in this configuration +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@interface" is not defined in this configuration +// Warning: (ae-missing-release-tag) "WorkflowResultDTO" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export interface WorkflowResultDTO { + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'completedWith'?: WorkflowResultDTOCompletedWithEnum; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'message'?: string; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'nextWorkflows'?: Array; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'outputs'?: Array; +} + +// Warning: (ae-missing-release-tag) "WorkflowResultDTOCompletedWithEnum" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// Warning: (ae-missing-release-tag) "WorkflowResultDTOCompletedWithEnum" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const WorkflowResultDTOCompletedWithEnum: { + readonly Error: "error"; + readonly Success: "success"; +}; + +// @public (undocumented) +export type WorkflowResultDTOCompletedWithEnum = typeof WorkflowResultDTOCompletedWithEnum[keyof typeof WorkflowResultDTOCompletedWithEnum]; + +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@export" is not defined in this configuration +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@interface" is not defined in this configuration +// Warning: (ae-missing-release-tag) "WorkflowResultDTONextWorkflowsInner" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export interface WorkflowResultDTONextWorkflowsInner { + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'id': string; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'name': string; +} + +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@export" is not defined in this configuration +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@interface" is not defined in this configuration +// Warning: (ae-missing-release-tag) "WorkflowResultDTOOutputsInner" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export interface WorkflowResultDTOOutputsInner { + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'format'?: WorkflowResultDTOOutputsInnerFormatEnum; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'key': string; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'value': WorkflowResultDTOOutputsInnerValue; +} + +// Warning: (ae-missing-release-tag) "WorkflowResultDTOOutputsInnerFormatEnum" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// Warning: (ae-missing-release-tag) "WorkflowResultDTOOutputsInnerFormatEnum" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const WorkflowResultDTOOutputsInnerFormatEnum: { + readonly Text: "text"; + readonly Number: "number"; + readonly Link: "link"; +}; + +// @public (undocumented) +export type WorkflowResultDTOOutputsInnerFormatEnum = typeof WorkflowResultDTOOutputsInnerFormatEnum[keyof typeof WorkflowResultDTOOutputsInnerFormatEnum]; + +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@export" is not defined in this configuration +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@interface" is not defined in this configuration +// Warning: (ae-missing-release-tag) "WorkflowResultDTOOutputsInnerValue" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export interface WorkflowResultDTOOutputsInnerValue { +} + +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@export" is not defined in this configuration +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@interface" is not defined in this configuration +// Warning: (ae-missing-release-tag) "WorkflowRunStatusDTO" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export interface WorkflowRunStatusDTO { + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'key'?: string; + // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag + // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration + // Warning: (tsdoc-undefined-tag) The TSDoc tag "@memberof" is not defined in this configuration + 'value'?: string; +} + +// Warnings were encountered during analysis: +// +// src/QueryParams.d.ts:1:22 - (ae-undocumented) Missing documentation for "QUERY_PARAM_BUSINESS_KEY". +// src/QueryParams.d.ts:2:22 - (ae-undocumented) Missing documentation for "QUERY_PARAM_INSTANCE_ID". +// src/QueryParams.d.ts:3:22 - (ae-undocumented) Missing documentation for "QUERY_PARAM_INCLUDE_ASSESSMENT". +// src/QueryParams.d.ts:4:22 - (ae-undocumented) Missing documentation for "QUERY_PARAM_ASSESSMENT_INSTANCE_ID". +// src/constants.d.ts:1:22 - (ae-undocumented) Missing documentation for "DEFAULT_SONATAFLOW_CONTAINER_IMAGE". +// src/constants.d.ts:2:22 - (ae-undocumented) Missing documentation for "DEFAULT_SONATAFLOW_PERSISTENCE_PATH". +// src/constants.d.ts:3:22 - (ae-undocumented) Missing documentation for "DEFAULT_SONATAFLOW_BASE_URL". +// src/constants.d.ts:4:22 - (ae-undocumented) Missing documentation for "DEFAULT_WORKFLOWS_PATH". +// src/constants.d.ts:5:22 - (ae-undocumented) Missing documentation for "ASSESSMENT_WORKFLOW_TYPE". +// src/constants.d.ts:6:22 - (ae-undocumented) Missing documentation for "INFRASTRUCTURE_WORKFLOW_TYPE". +// src/generated/api/definition.d.ts:1:22 - (ae-undocumented) Missing documentation for "openApiDocument". +// src/generated/client/api.d.ts:105:22 - (ae-undocumented) Missing documentation for "FieldFilterOperatorEnum". +// src/generated/client/api.d.ts:119:1 - (ae-undocumented) Missing documentation for "FieldFilterOperatorEnum". +// src/generated/client/api.d.ts:206:22 - (ae-undocumented) Missing documentation for "LogicalFilterOperatorEnum". +// src/generated/client/api.d.ts:211:1 - (ae-undocumented) Missing documentation for "LogicalFilterOperatorEnum". +// src/generated/client/api.d.ts:304:22 - (ae-undocumented) Missing documentation for "PaginationInfoDTOOrderDirectionEnum". +// src/generated/client/api.d.ts:308:1 - (ae-undocumented) Missing documentation for "PaginationInfoDTOOrderDirectionEnum". +// src/generated/client/api.d.ts:463:1 - (ae-undocumented) Missing documentation for "ProcessInstanceStatusDTO". +// src/generated/client/api.d.ts:492:1 - (ae-undocumented) Missing documentation for "WorkflowCategoryDTO". +// src/generated/client/api.d.ts:558:1 - (ae-undocumented) Missing documentation for "WorkflowFormatDTO". +// src/generated/client/api.d.ts:756:22 - (ae-undocumented) Missing documentation for "WorkflowResultDTOCompletedWithEnum". +// src/generated/client/api.d.ts:760:1 - (ae-undocumented) Missing documentation for "WorkflowResultDTOCompletedWithEnum". +// src/generated/client/api.d.ts:805:22 - (ae-undocumented) Missing documentation for "WorkflowResultDTOOutputsInnerFormatEnum". +// src/generated/client/api.d.ts:810:1 - (ae-undocumented) Missing documentation for "WorkflowResultDTOOutputsInnerFormatEnum". +// src/generated/client/api.d.ts:844:8 - (tsdoc-undefined-tag) The TSDoc tag "@summary" is not defined in this configuration +// src/generated/client/api.d.ts:845:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:845:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:846:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:846:19 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:846:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:847:30 - (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// src/generated/client/api.d.ts:847:16 - (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// src/generated/client/api.d.ts:849:5 - (ae-forgotten-export) The symbol "RequestArgs" needs to be exported by the entry point index.d.ts +// src/generated/client/api.d.ts:852:8 - (tsdoc-undefined-tag) The TSDoc tag "@summary" is not defined in this configuration +// src/generated/client/api.d.ts:853:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:853:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:854:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:854:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:855:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:855:19 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:855:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:856:30 - (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// src/generated/client/api.d.ts:856:16 - (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// src/generated/client/api.d.ts:861:8 - (tsdoc-undefined-tag) The TSDoc tag "@summary" is not defined in this configuration +// src/generated/client/api.d.ts:862:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:862:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:863:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:863:25 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:863:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:864:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:864:19 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:864:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:865:30 - (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// src/generated/client/api.d.ts:865:16 - (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// src/generated/client/api.d.ts:870:8 - (tsdoc-undefined-tag) The TSDoc tag "@summary" is not defined in this configuration +// src/generated/client/api.d.ts:871:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:871:37 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:871:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:872:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:872:19 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:872:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:873:30 - (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// src/generated/client/api.d.ts:873:16 - (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// src/generated/client/api.d.ts:878:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:878:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:879:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:879:24 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:879:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:880:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:880:19 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:880:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:881:30 - (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// src/generated/client/api.d.ts:881:16 - (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// src/generated/client/api.d.ts:886:8 - (tsdoc-undefined-tag) The TSDoc tag "@summary" is not defined in this configuration +// src/generated/client/api.d.ts:887:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:887:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:888:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:888:31 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:888:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:889:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:889:19 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:889:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:890:30 - (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// src/generated/client/api.d.ts:890:16 - (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// src/generated/client/api.d.ts:895:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:895:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:896:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:896:19 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:896:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:897:30 - (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// src/generated/client/api.d.ts:897:16 - (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// src/generated/client/api.d.ts:902:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:902:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:903:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:903:19 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:903:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:904:30 - (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// src/generated/client/api.d.ts:904:16 - (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// src/generated/client/api.d.ts:909:8 - (tsdoc-undefined-tag) The TSDoc tag "@summary" is not defined in this configuration +// src/generated/client/api.d.ts:910:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:910:19 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:910:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:911:30 - (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// src/generated/client/api.d.ts:911:16 - (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// src/generated/client/api.d.ts:916:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:916:31 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:916:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:917:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:917:19 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:917:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:918:30 - (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// src/generated/client/api.d.ts:918:16 - (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// src/generated/client/api.d.ts:923:8 - (tsdoc-undefined-tag) The TSDoc tag "@summary" is not defined in this configuration +// src/generated/client/api.d.ts:924:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:924:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:925:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:925:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:926:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:926:19 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:926:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:927:30 - (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// src/generated/client/api.d.ts:927:16 - (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// src/generated/client/api.d.ts:938:8 - (tsdoc-undefined-tag) The TSDoc tag "@summary" is not defined in this configuration +// src/generated/client/api.d.ts:939:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:939:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:940:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:940:19 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:940:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:941:30 - (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// src/generated/client/api.d.ts:941:16 - (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// src/generated/client/api.d.ts:946:8 - (tsdoc-undefined-tag) The TSDoc tag "@summary" is not defined in this configuration +// src/generated/client/api.d.ts:947:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:947:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:948:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:948:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:949:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:949:19 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:949:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:950:30 - (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// src/generated/client/api.d.ts:950:16 - (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// src/generated/client/api.d.ts:955:8 - (tsdoc-undefined-tag) The TSDoc tag "@summary" is not defined in this configuration +// src/generated/client/api.d.ts:956:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:956:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:957:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:957:25 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:957:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:958:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:958:19 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:958:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:959:30 - (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// src/generated/client/api.d.ts:959:16 - (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// src/generated/client/api.d.ts:964:8 - (tsdoc-undefined-tag) The TSDoc tag "@summary" is not defined in this configuration +// src/generated/client/api.d.ts:965:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:965:37 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:965:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:966:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:966:19 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:966:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:967:30 - (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// src/generated/client/api.d.ts:967:16 - (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// src/generated/client/api.d.ts:972:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:972:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:973:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:973:24 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:973:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:974:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:974:19 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:974:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:975:30 - (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// src/generated/client/api.d.ts:975:16 - (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// src/generated/client/api.d.ts:980:8 - (tsdoc-undefined-tag) The TSDoc tag "@summary" is not defined in this configuration +// src/generated/client/api.d.ts:981:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:981:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:982:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:982:31 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:982:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:983:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:983:19 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:983:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:984:30 - (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// src/generated/client/api.d.ts:984:16 - (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// src/generated/client/api.d.ts:989:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:989:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:990:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:990:19 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:990:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:991:30 - (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// src/generated/client/api.d.ts:991:16 - (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// src/generated/client/api.d.ts:996:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:996:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:997:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:997:19 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:997:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:998:30 - (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// src/generated/client/api.d.ts:998:16 - (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// src/generated/client/api.d.ts:1003:8 - (tsdoc-undefined-tag) The TSDoc tag "@summary" is not defined in this configuration +// src/generated/client/api.d.ts:1004:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:1004:19 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:1004:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:1005:30 - (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// src/generated/client/api.d.ts:1005:16 - (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// src/generated/client/api.d.ts:1010:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:1010:31 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:1010:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:1011:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:1011:19 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:1011:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:1012:30 - (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// src/generated/client/api.d.ts:1012:16 - (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// src/generated/client/api.d.ts:1017:8 - (tsdoc-undefined-tag) The TSDoc tag "@summary" is not defined in this configuration +// src/generated/client/api.d.ts:1018:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:1018:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:1019:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:1019:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:1020:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:1020:19 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:1020:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:1021:30 - (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// src/generated/client/api.d.ts:1021:16 - (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// src/generated/client/api.d.ts:1032:8 - (tsdoc-undefined-tag) The TSDoc tag "@summary" is not defined in this configuration +// src/generated/client/api.d.ts:1033:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:1033:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:1034:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:1034:19 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:1034:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:1035:30 - (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// src/generated/client/api.d.ts:1035:16 - (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// src/generated/client/api.d.ts:1040:8 - (tsdoc-undefined-tag) The TSDoc tag "@summary" is not defined in this configuration +// src/generated/client/api.d.ts:1041:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:1041:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:1042:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:1042:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:1043:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:1043:19 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:1043:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:1044:30 - (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// src/generated/client/api.d.ts:1044:16 - (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// src/generated/client/api.d.ts:1049:8 - (tsdoc-undefined-tag) The TSDoc tag "@summary" is not defined in this configuration +// src/generated/client/api.d.ts:1050:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:1050:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:1051:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:1051:25 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:1051:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:1052:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:1052:19 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:1052:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:1053:30 - (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// src/generated/client/api.d.ts:1053:16 - (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// src/generated/client/api.d.ts:1058:8 - (tsdoc-undefined-tag) The TSDoc tag "@summary" is not defined in this configuration +// src/generated/client/api.d.ts:1059:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:1059:37 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:1059:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:1060:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:1060:19 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:1060:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:1061:30 - (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// src/generated/client/api.d.ts:1061:16 - (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// src/generated/client/api.d.ts:1066:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:1066:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:1067:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:1067:24 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:1067:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:1068:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:1068:19 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:1068:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:1069:30 - (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// src/generated/client/api.d.ts:1069:16 - (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// src/generated/client/api.d.ts:1074:8 - (tsdoc-undefined-tag) The TSDoc tag "@summary" is not defined in this configuration +// src/generated/client/api.d.ts:1075:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:1075:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:1076:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:1076:31 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:1076:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:1077:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:1077:19 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:1077:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:1078:30 - (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// src/generated/client/api.d.ts:1078:16 - (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// src/generated/client/api.d.ts:1083:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:1083:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:1084:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:1084:19 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:1084:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:1085:30 - (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// src/generated/client/api.d.ts:1085:16 - (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// src/generated/client/api.d.ts:1090:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:1090:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:1091:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:1091:19 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:1091:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:1092:30 - (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// src/generated/client/api.d.ts:1092:16 - (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// src/generated/client/api.d.ts:1097:8 - (tsdoc-undefined-tag) The TSDoc tag "@summary" is not defined in this configuration +// src/generated/client/api.d.ts:1098:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:1098:19 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:1098:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:1099:30 - (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// src/generated/client/api.d.ts:1099:16 - (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// src/generated/client/api.d.ts:1104:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:1104:31 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:1104:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:1105:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:1105:19 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:1105:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:1106:30 - (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// src/generated/client/api.d.ts:1106:16 - (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// src/generated/client/api.d.ts:1111:8 - (tsdoc-undefined-tag) The TSDoc tag "@summary" is not defined in this configuration +// src/generated/client/api.d.ts:1112:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:1112:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:1113:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:1113:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:1114:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/generated/client/api.d.ts:1114:19 - (tsdoc-param-tag-with-invalid-optional-name) The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets. +// src/generated/client/api.d.ts:1114:15 - (tsdoc-param-tag-with-invalid-type) The @param block should not include a JSDoc-style '{type}' +// src/generated/client/api.d.ts:1115:30 - (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// src/generated/client/api.d.ts:1115:16 - (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// src/generated/client/base.d.ts:27:4 - (tsdoc-undefined-tag) The TSDoc tag "@export" is not defined in this configuration +// src/generated/client/base.d.ts:28:4 - (tsdoc-undefined-tag) The TSDoc tag "@interface" is not defined in this configuration +// src/generated/client/base.d.ts:36:4 - (tsdoc-undefined-tag) The TSDoc tag "@export" is not defined in this configuration +// src/generated/client/base.d.ts:37:4 - (tsdoc-undefined-tag) The TSDoc tag "@class" is not defined in this configuration +// src/generated/client/configuration.d.ts:13:5 - (ae-undocumented) Missing documentation for "apiKey". +// src/generated/client/configuration.d.ts:14:5 - (ae-undocumented) Missing documentation for "username". +// src/generated/client/configuration.d.ts:15:5 - (ae-undocumented) Missing documentation for "password". +// src/generated/client/configuration.d.ts:16:5 - (ae-undocumented) Missing documentation for "accessToken". +// src/generated/client/configuration.d.ts:17:5 - (ae-undocumented) Missing documentation for "basePath". +// src/generated/client/configuration.d.ts:18:5 - (ae-undocumented) Missing documentation for "serverIndex". +// src/generated/client/configuration.d.ts:19:5 - (ae-undocumented) Missing documentation for "baseOptions". +// src/generated/client/configuration.d.ts:20:5 - (ae-undocumented) Missing documentation for "formDataCtor". +// src/generated/client/configuration.d.ts:22:1 - (ae-undocumented) Missing documentation for "Configuration". +// src/models.d.ts:2:1 - (ae-undocumented) Missing documentation for "ProcessInstanceState". +// src/models.d.ts:3:5 - (ae-undocumented) Missing documentation for "Active". +// src/models.d.ts:4:5 - (ae-undocumented) Missing documentation for "Completed". +// src/models.d.ts:5:5 - (ae-undocumented) Missing documentation for "Aborted". +// src/models.d.ts:6:5 - (ae-undocumented) Missing documentation for "Suspended". +// src/models.d.ts:7:5 - (ae-undocumented) Missing documentation for "Error". +// src/models.d.ts:8:5 - (ae-undocumented) Missing documentation for "Pending". +// src/models.d.ts:10:1 - (ae-undocumented) Missing documentation for "ProcessInstanceStateValues". +// src/models.d.ts:11:1 - (ae-undocumented) Missing documentation for "MilestoneStatus". +// src/models.d.ts:12:5 - (ae-undocumented) Missing documentation for "Available". +// src/models.d.ts:13:5 - (ae-undocumented) Missing documentation for "Active". +// src/models.d.ts:14:5 - (ae-undocumented) Missing documentation for "Completed". +// src/models.d.ts:16:1 - (ae-undocumented) Missing documentation for "NodeInstance". +// src/models.d.ts:17:5 - (ae-undocumented) Missing documentation for "__typename". +// src/models.d.ts:18:5 - (ae-undocumented) Missing documentation for "id". +// src/models.d.ts:19:5 - (ae-undocumented) Missing documentation for "name". +// src/models.d.ts:20:5 - (ae-undocumented) Missing documentation for "type". +// src/models.d.ts:21:5 - (ae-undocumented) Missing documentation for "enter". +// src/models.d.ts:22:5 - (ae-undocumented) Missing documentation for "exit". +// src/models.d.ts:23:5 - (ae-undocumented) Missing documentation for "definitionId". +// src/models.d.ts:24:5 - (ae-undocumented) Missing documentation for "nodeId". +// src/models.d.ts:26:1 - (ae-undocumented) Missing documentation for "TriggerableNode". +// src/models.d.ts:27:5 - (ae-undocumented) Missing documentation for "id". +// src/models.d.ts:28:5 - (ae-undocumented) Missing documentation for "name". +// src/models.d.ts:29:5 - (ae-undocumented) Missing documentation for "type". +// src/models.d.ts:30:5 - (ae-undocumented) Missing documentation for "uniqueId". +// src/models.d.ts:31:5 - (ae-undocumented) Missing documentation for "nodeDefinitionId". +// src/models.d.ts:33:1 - (ae-undocumented) Missing documentation for "Milestone". +// src/models.d.ts:34:5 - (ae-undocumented) Missing documentation for "__typename". +// src/models.d.ts:35:5 - (ae-undocumented) Missing documentation for "id". +// src/models.d.ts:36:5 - (ae-undocumented) Missing documentation for "name". +// src/models.d.ts:37:5 - (ae-undocumented) Missing documentation for "status". +// src/models.d.ts:39:1 - (ae-undocumented) Missing documentation for "ProcessInstanceError". +// src/models.d.ts:40:5 - (ae-undocumented) Missing documentation for "__typename". +// src/models.d.ts:41:5 - (ae-undocumented) Missing documentation for "nodeDefinitionId". +// src/models.d.ts:42:5 - (ae-undocumented) Missing documentation for "message". +// src/models.d.ts:44:1 - (ae-undocumented) Missing documentation for "ProcessInstanceVariables". +// src/models.d.ts:45:1 - (ae-undocumented) Missing documentation for "ProcessInstance". +// src/models.d.ts:46:5 - (ae-undocumented) Missing documentation for "id". +// src/models.d.ts:47:5 - (ae-undocumented) Missing documentation for "processId". +// src/models.d.ts:48:5 - (ae-undocumented) Missing documentation for "processName". +// src/models.d.ts:49:5 - (ae-undocumented) Missing documentation for "parentProcessInstanceId". +// src/models.d.ts:50:5 - (ae-undocumented) Missing documentation for "rootProcessInstanceId". +// src/models.d.ts:51:5 - (ae-undocumented) Missing documentation for "rootProcessId". +// src/models.d.ts:52:5 - (ae-undocumented) Missing documentation for "roles". +// src/models.d.ts:53:5 - (ae-undocumented) Missing documentation for "state". +// src/models.d.ts:54:5 - (ae-undocumented) Missing documentation for "endpoint". +// src/models.d.ts:55:5 - (ae-undocumented) Missing documentation for "serviceUrl". +// src/models.d.ts:56:5 - (ae-undocumented) Missing documentation for "nodes". +// src/models.d.ts:57:5 - (ae-undocumented) Missing documentation for "milestones". +// src/models.d.ts:58:5 - (ae-undocumented) Missing documentation for "variables". +// src/models.d.ts:63:5 - (ae-undocumented) Missing documentation for "parentProcessInstance". +// src/models.d.ts:64:5 - (ae-undocumented) Missing documentation for "childProcessInstances". +// src/models.d.ts:65:5 - (ae-undocumented) Missing documentation for "error". +// src/models.d.ts:66:5 - (ae-undocumented) Missing documentation for "addons". +// src/models.d.ts:67:5 - (ae-undocumented) Missing documentation for "businessKey". +// src/models.d.ts:68:5 - (ae-undocumented) Missing documentation for "isSelected". +// src/models.d.ts:69:5 - (ae-undocumented) Missing documentation for "errorMessage". +// src/models.d.ts:70:5 - (ae-undocumented) Missing documentation for "isOpen". +// src/models.d.ts:71:5 - (ae-undocumented) Missing documentation for "diagram". +// src/models.d.ts:72:5 - (ae-undocumented) Missing documentation for "nodeDefinitions". +// src/models.d.ts:73:5 - (ae-undocumented) Missing documentation for "source". +// src/models.d.ts:74:5 - (ae-undocumented) Missing documentation for "category". +// src/models.d.ts:75:5 - (ae-undocumented) Missing documentation for "description". +// src/models.d.ts:77:1 - (ae-undocumented) Missing documentation for "IntrospectionQuery". +// src/models.d.ts:78:5 - (ae-undocumented) Missing documentation for "__type". +// src/models.d.ts:80:1 - (ae-undocumented) Missing documentation for "IntrospectionType". +// src/models.d.ts:81:5 - (ae-undocumented) Missing documentation for "name". +// src/models.d.ts:82:5 - (ae-undocumented) Missing documentation for "kind". +// src/models.d.ts:83:5 - (ae-undocumented) Missing documentation for "description". +// src/models.d.ts:84:5 - (ae-undocumented) Missing documentation for "fields". +// src/models.d.ts:86:1 - (ae-undocumented) Missing documentation for "IntrospectionField". +// src/models.d.ts:87:5 - (ae-undocumented) Missing documentation for "name". +// src/models.d.ts:88:5 - (ae-undocumented) Missing documentation for "type". +// src/models.d.ts:90:1 - (ae-undocumented) Missing documentation for "IntrospectionTypeRef". +// src/models.d.ts:91:5 - (ae-undocumented) Missing documentation for "kind". +// src/models.d.ts:92:5 - (ae-undocumented) Missing documentation for "name". +// src/models.d.ts:93:5 - (ae-undocumented) Missing documentation for "ofType". +// src/models.d.ts:95:1 - (ae-undocumented) Missing documentation for "TypeKind". +// src/models.d.ts:96:5 - (ae-undocumented) Missing documentation for "InputObject". +// src/models.d.ts:98:1 - (ae-undocumented) Missing documentation for "TypeName". +// src/models.d.ts:99:5 - (ae-undocumented) Missing documentation for "Id". +// src/models.d.ts:100:5 - (ae-undocumented) Missing documentation for "String". +// src/models.d.ts:101:5 - (ae-undocumented) Missing documentation for "StringArray". +// src/models.d.ts:102:5 - (ae-undocumented) Missing documentation for "Date". +// src/permissions.d.ts:1:22 - (ae-undocumented) Missing documentation for "orchestratorWorkflowInstancesReadPermission". +// src/permissions.d.ts:2:22 - (ae-undocumented) Missing documentation for "orchestratorWorkflowInstanceReadPermission". +// src/permissions.d.ts:3:22 - (ae-undocumented) Missing documentation for "orchestratorWorkflowReadPermission". +// src/permissions.d.ts:4:22 - (ae-undocumented) Missing documentation for "orchestratorWorkflowExecutePermission". +// src/permissions.d.ts:5:22 - (ae-undocumented) Missing documentation for "orchestratorWorkflowInstanceAbortPermission". +// src/permissions.d.ts:6:22 - (ae-undocumented) Missing documentation for "orchestratorPermissions". +// src/types.d.ts:9:1 - (ae-undocumented) Missing documentation for "OmitRecursively". +// src/types.d.ts:12:1 - (ae-undocumented) Missing documentation for "WorkflowDefinition". +// src/types.d.ts:13:1 - (ae-undocumented) Missing documentation for "WorkflowListResult". +// src/types.d.ts:19:1 - (ae-undocumented) Missing documentation for "WorkflowOverviewListResult". +// src/types.d.ts:25:1 - (ae-undocumented) Missing documentation for "WorkflowFormat". +// src/types.d.ts:26:1 - (ae-undocumented) Missing documentation for "WorkflowInputSchemaStep". +// src/types.d.ts:33:1 - (ae-undocumented) Missing documentation for "JsonObjectSchema". +// src/types.d.ts:38:1 - (ae-undocumented) Missing documentation for "ComposedSchema". +// src/types.d.ts:47:22 - (ae-undocumented) Missing documentation for "isJsonObjectSchema". +// src/types.d.ts:48:22 - (ae-undocumented) Missing documentation for "isComposedSchema". +// src/types.d.ts:49:1 - (ae-undocumented) Missing documentation for "WorkflowExecutionResponse". +// src/types.d.ts:50:5 - (ae-undocumented) Missing documentation for "id". +// src/types.d.ts:52:1 - (ae-undocumented) Missing documentation for "WorkflowCategory". +// src/types.d.ts:53:5 - (ae-undocumented) Missing documentation for "ASSESSMENT". +// src/types.d.ts:54:5 - (ae-undocumented) Missing documentation for "INFRASTRUCTURE". +// src/types.d.ts:56:1 - (ae-undocumented) Missing documentation for "WorkflowOverview". +// src/types.d.ts:57:5 - (ae-undocumented) Missing documentation for "workflowId". +// src/types.d.ts:58:5 - (ae-undocumented) Missing documentation for "format". +// src/types.d.ts:59:5 - (ae-undocumented) Missing documentation for "name". +// src/types.d.ts:60:5 - (ae-undocumented) Missing documentation for "lastRunId". +// src/types.d.ts:61:5 - (ae-undocumented) Missing documentation for "lastTriggeredMs". +// src/types.d.ts:62:5 - (ae-undocumented) Missing documentation for "lastRunStatus". +// src/types.d.ts:63:5 - (ae-undocumented) Missing documentation for "category". +// src/types.d.ts:64:5 - (ae-undocumented) Missing documentation for "avgDurationMs". +// src/types.d.ts:65:5 - (ae-undocumented) Missing documentation for "description". +// src/types.d.ts:67:1 - (ae-undocumented) Missing documentation for "WorkflowInfo". +// src/types.d.ts:68:5 - (ae-undocumented) Missing documentation for "id". +// src/types.d.ts:69:5 - (ae-undocumented) Missing documentation for "type". +// src/types.d.ts:70:5 - (ae-undocumented) Missing documentation for "name". +// src/types.d.ts:71:5 - (ae-undocumented) Missing documentation for "version". +// src/types.d.ts:72:5 - (ae-undocumented) Missing documentation for "annotations". +// src/types.d.ts:73:5 - (ae-undocumented) Missing documentation for "description". +// src/types.d.ts:74:5 - (ae-undocumented) Missing documentation for "inputSchema". +// src/types.d.ts:75:5 - (ae-undocumented) Missing documentation for "endpoint". +// src/types.d.ts:76:5 - (ae-undocumented) Missing documentation for "serviceUrl". +// src/types.d.ts:77:5 - (ae-undocumented) Missing documentation for "roles". +// src/types.d.ts:78:5 - (ae-undocumented) Missing documentation for "source". +// src/types.d.ts:79:5 - (ae-undocumented) Missing documentation for "metadata". +// src/types.d.ts:80:5 - (ae-undocumented) Missing documentation for "nodes". +// src/types.d.ts:82:1 - (ae-undocumented) Missing documentation for "Node". +// src/types.d.ts:83:5 - (ae-undocumented) Missing documentation for "id". +// src/types.d.ts:84:5 - (ae-undocumented) Missing documentation for "type". +// src/types.d.ts:85:5 - (ae-undocumented) Missing documentation for "name". +// src/types.d.ts:86:5 - (ae-undocumented) Missing documentation for "uniqueId". +// src/types.d.ts:87:5 - (ae-undocumented) Missing documentation for "nodeDefinitionId". +// src/types.d.ts:89:1 - (ae-undocumented) Missing documentation for "AssessedProcessInstance". +// src/types.d.ts:90:5 - (ae-undocumented) Missing documentation for "instance". +// src/types.d.ts:91:5 - (ae-undocumented) Missing documentation for "assessedBy". +// src/utils/StringUtils.d.ts:1:1 - (ae-undocumented) Missing documentation for "Capitalized". +// src/utils/StringUtils.d.ts:2:22 - (ae-undocumented) Missing documentation for "capitalize". +// src/utils/StringUtils.d.ts:3:22 - (ae-undocumented) Missing documentation for "ellipsis". +// src/workflow.d.ts:2:1 - (ae-undocumented) Missing documentation for "fromWorkflowSource". +// src/workflow.d.ts:3:1 - (ae-undocumented) Missing documentation for "toWorkflowString". +// src/workflow.d.ts:4:1 - (ae-undocumented) Missing documentation for "toWorkflowJson". +// src/workflow.d.ts:5:1 - (ae-undocumented) Missing documentation for "toWorkflowYaml". +// src/workflow.d.ts:6:1 - (ae-undocumented) Missing documentation for "extractWorkflowFormatFromUri". +// src/workflow.d.ts:7:1 - (ae-undocumented) Missing documentation for "getWorkflowCategory". +// src/workflow.d.ts:8:1 - (ae-undocumented) Missing documentation for "parseWorkflowVariables". +// src/workflow.d.ts:9:1 - (ae-undocumented) Missing documentation for "extractWorkflowFormat". + +// (No @packageDocumentation comment for this package) + +``` diff --git a/workspaces/orchestrator/plugins/orchestrator-common/scripts/openapi.sh b/workspaces/orchestrator/plugins/orchestrator-common/scripts/openapi.sh new file mode 100755 index 00000000..64c714d6 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/scripts/openapi.sh @@ -0,0 +1,82 @@ +#!/bin/bash +pwd +set -e + +GENERATED_FOLDER="./src/generated" +OPENAPI_SPEC_FILE="./src/openapi/openapi.yaml" +API_FOLDER="${GENERATED_FOLDER}/api" +DEFINITION_FILE="${API_FOLDER}/definition.ts" +METADATA_FILE="${GENERATED_FOLDER}/.METADATA.sha1" +CLIENT_FOLDER="${GENERATED_FOLDER}/client" + +openapi_generate() { + # TypeScript Client generation + rm -rf ${CLIENT_FOLDER} + openapi-generator-cli generate -g typescript-axios -i ${OPENAPI_SPEC_FILE} -o ${CLIENT_FOLDER} + + # Docs generation + rm -rf ./src/generated/docs/markdown ./src/generated/docs/html + openapi-generator-cli generate -g markdown -i ${OPENAPI_SPEC_FILE} -o ./src/generated/docs/markdown/ + openapi-generator-cli generate -g html2 -i ${OPENAPI_SPEC_FILE} -o ./src/generated/docs/html + + yaml2json -f ${OPENAPI_SPEC_FILE} + + OPENAPI_SPEC_FILE_JSON=$(tr -d '[:space:]' < "$(dirname $OPENAPI_SPEC_FILE)"/openapi.json) + mkdir -p ${API_FOLDER} + cat << EOF > ${DEFINITION_FILE} +/* eslint-disable */ +/* prettier-ignore */ +// GENERATED FILE DO NOT EDIT. +const OPENAPI = \`${OPENAPI_SPEC_FILE_JSON}\`; +export const openApiDocument = JSON.parse(OPENAPI); +EOF + + rm ./src/openapi/openapi.json + NEW_SHA=$(openapi_checksum) + openapi_update "${NEW_SHA}" +} + +openapi_checksum() { + export CONCATENATED_CONTENT=$(cat ${DEFINITION_FILE} ${OPENAPI_SPEC_FILE}) + node -e $'console.log(crypto.createHash("sha1").update(`${process.env.CONCATENATED_CONTENT}`).digest("hex"))' +} + +openapi_update() { + echo "${1}" > "${METADATA_FILE}" +} + +# Function to check if OpenAPI files are up-to-date +openapi_check() { + + if [ ! -f "${METADATA_FILE}" ]; then + echo "Error: Metadata file '${METADATA_FILE}' not found. Run 'yarn openapi:generate' first." + exit 1 + else + STORED_SHA1=$(cat "${METADATA_FILE}") + fi + + # Generate new SHA-1 checksum + NEW_SHA1=$(openapi_checksum) + + # Check if the stored and current SHA-1 checksums differ + if [ "${STORED_SHA1}" != "${NEW_SHA1}" ]; then + echo "Changes detected in generated files or openapi.yaml. Please run 'yarn openapi:generate' to update." + exit 1 + else + echo "No changes detected in generated files or openapi.yaml. generated files are up to date." + fi +} + +# Check the command passed as an argument +case "$1" in + "generate") + openapi_generate + ;; + "check") + openapi_check + ;; + *) + echo "Error: Invalid command. Please use \"${0} generate\" to generate OpenAPI files or \"${0} check\" to verify their status." + exit 1 + ;; +esac diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/QueryParams.ts b/workspaces/orchestrator/plugins/orchestrator-common/src/QueryParams.ts new file mode 100644 index 00000000..d4339432 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/QueryParams.ts @@ -0,0 +1,20 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export const QUERY_PARAM_BUSINESS_KEY = 'businessKey' as const; +export const QUERY_PARAM_INSTANCE_ID = 'instanceId' as const; +export const QUERY_PARAM_INCLUDE_ASSESSMENT = 'includeAssessment' as const; +export const QUERY_PARAM_ASSESSMENT_INSTANCE_ID = + 'assessmentInstanceId' as const; diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/constants.ts b/workspaces/orchestrator/plugins/orchestrator-common/src/constants.ts new file mode 100644 index 00000000..31b2bd64 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/constants.ts @@ -0,0 +1,25 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export const DEFAULT_SONATAFLOW_CONTAINER_IMAGE = + 'docker.io/apache/incubator-kie-sonataflow-devmode:latest'; +export const DEFAULT_SONATAFLOW_PERSISTENCE_PATH = '/home/kogito/persistence'; +export const DEFAULT_SONATAFLOW_BASE_URL = 'http://localhost'; + +export const DEFAULT_WORKFLOWS_PATH = 'workflows'; + +export const ASSESSMENT_WORKFLOW_TYPE = 'workflow-type/assessment'; +export const INFRASTRUCTURE_WORKFLOW_TYPE = 'workflow-type/infrastructure'; diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/.METADATA.sha1 b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/.METADATA.sha1 new file mode 100644 index 00000000..806eec65 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/.METADATA.sha1 @@ -0,0 +1 @@ +f4fd9f652a05159a3d506540493e275885d54dcd diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/api/definition.ts b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/api/definition.ts new file mode 100644 index 00000000..f77d82c0 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/api/definition.ts @@ -0,0 +1,5 @@ +/* eslint-disable */ +/* prettier-ignore */ +// GENERATED FILE DO NOT EDIT. +const OPENAPI = `{"openapi":"3.1.0","info":{"title":"Orchestratorplugin","description":"APItointeractwithorchestratorplugin","license":{"name":"Apache2.0","url":"http://www.apache.org/licenses/LICENSE-2.0.html"},"version":"0.0.1"},"servers":[{"url":"/"}],"paths":{"/v2/workflows/overview":{"post":{"operationId":"getWorkflowsOverview","description":"Returnsthekeyfieldsoftheworkflowincludingdataonthelastruninstance","requestBody":{"required":false,"description":"Paginationandfilters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchRequest"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkflowOverviewListResultDTO"}}}},"500":{"description":"Errorfetchingworkflowoverviews","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v2/workflows/{workflowId}/overview":{"get":{"operationId":"getWorkflowOverviewById","description":"Returnsthekeyfieldsoftheworkflowincludingdataonthelastruninstance","parameters":[{"name":"workflowId","in":"path","required":true,"description":"Uniqueidentifieroftheworkflow","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkflowOverviewDTO"}}}},"500":{"description":"Errorfetchingworkflowoverview","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v2/workflows/{workflowId}/source":{"get":{"operationId":"getWorkflowSourceById","description":"Gettheworkflow'sdefinition","parameters":[{"name":"workflowId","in":"path","description":"IDoftheworkflowtofetch","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"text/plain":{"schema":{"type":"string"}}}},"500":{"description":"Errorfetchingworkflowsourcebyid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v2/workflows/{workflowId}/inputSchema":{"get":{"operationId":"getWorkflowInputSchemaById","description":"Gettheworkflowinputschema.Itdefinestheinputfieldsoftheworkflow","parameters":[{"name":"workflowId","in":"path","description":"IDoftheworkflowtofetch","required":true,"schema":{"type":"string"}},{"name":"instanceId","in":"query","description":"IDofinstance","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InputSchemaResponseDTO"}}}},"500":{"description":"Errorfetchingworkflowinputschemabyid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v2/workflows/instances":{"post":{"operationId":"getInstances","summary":"Getinstances","description":"Retrieveanarrayofworkflowexecutions(instances)","requestBody":{"required":false,"description":"Parametersforretrievinginstances","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetInstancesRequest"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProcessInstanceListResultDTO"}}}},"500":{"description":"Errorfetchinginstances","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v2/workflows/{workflowId}/instances":{"post":{"operationId":"getWorkflowInstances","summary":"Getinstancesforaspecificworkflow","description":"Retrieveanarrayofworkflowexecutions(instances)forthegivenworkflow","parameters":[{"name":"workflowId","in":"path","required":true,"description":"IDoftheworkflow","schema":{"type":"string"}}],"requestBody":{"required":false,"description":"Parametersforretrievingworkflowinstances","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchRequest"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProcessInstanceListResultDTO"}}}},"500":{"description":"Errorfetchinginstances","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v2/workflows/instances/{instanceId}":{"get":{"summary":"GetWorkflowInstancebyID","description":"Getaworkflowexecution/run(instance)","operationId":"getInstanceById","parameters":[{"name":"instanceId","in":"path","required":true,"description":"IDoftheworkflowinstance","schema":{"type":"string"}},{"name":"includeAssessment","in":"query","required":false,"description":"Whethertoincludeassessment","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"Successfulresponse","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssessedProcessInstanceDTO"}}}},"500":{"description":"Errorfetchinginstance","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v2/workflows/instances/statuses":{"get":{"operationId":"getWorkflowStatuses","summary":"Getworkflowstatuslist","description":"Retrievearraywiththestatusofallinstances","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/WorkflowRunStatusDTO"}}}}},"500":{"description":"Errorfetchingworkflowstatuses","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v2/workflows/{workflowId}/execute":{"post":{"summary":"Executeaworkflow","description":"Executeaworkflow","operationId":"executeWorkflow","parameters":[{"name":"workflowId","in":"path","description":"IDoftheworkflowtoexecute","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecuteWorkflowRequestDTO"}}}},"responses":{"200":{"description":"Successfulexecution","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecuteWorkflowResponseDTO"}}}},"500":{"description":"InternalServerError","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v2/workflows/{workflowId}/{instanceId}/retrigger":{"post":{"summary":"Retriggeraninstance","description":"Retriggeraninstance","operationId":"retriggerInstance","parameters":[{"name":"workflowId","in":"path","description":"IDoftheworkflow","required":true,"schema":{"type":"string"}},{"name":"instanceId","in":"path","description":"IDoftheinstancetoretrigger","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"500":{"description":"InternalServerError","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v2/workflows/instances/{instanceId}/abort":{"delete":{"summary":"Abortaworkflowinstance","operationId":"abortWorkflow","description":"AbortsaworkflowinstanceidentifiedbytheprovidedinstanceId.","parameters":[{"name":"instanceId","in":"path","required":true,"description":"Theidentifieroftheworkflowinstancetoabort.","schema":{"type":"string"}}],"responses":{"200":{"description":"Successfuloperation","content":{"text/plain":{"schema":{"type":"string"}}}},"500":{"description":"Errorabortingworkflow","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}},"components":{"schemas":{"ErrorResponse":{"description":"TheErrorResponseobjectrepresentsacommonstructureforhandlingerrorsinAPIresponses.Itincludesessentialinformationabouttheerror,suchastheerrormessageandadditionaloptionaldetails.","type":"object","properties":{"message":{"description":"Astringprovidingaconciseandhuman-readabledescriptionoftheencounterederror.ThisfieldisrequiredintheErrorResponseobject.","type":"string","default":"internalservererror"},"additionalInfo":{"description":"Anoptionalfieldthatcancontainadditionalinformationorcontextabouttheerror.Itprovidesflexibilityforincludingextradetailsbasedonspecificerrorscenarios.","type":"string"}},"required":["message"]},"GetInstancesRequest":{"type":"object","properties":{"paginationInfo":{"$ref":"#/components/schemas/PaginationInfoDTO"},"filters":{"$ref":"#/components/schemas/SearchRequest"}}},"GetOverviewsRequestParams":{"type":"object","properties":{"paginationInfo":{"$ref":"#/components/schemas/PaginationInfoDTO"},"filters":{"$ref":"#/components/schemas/SearchRequest"}}},"WorkflowOverviewListResultDTO":{"type":"object","properties":{"overviews":{"type":"array","items":{"$ref":"#/components/schemas/WorkflowOverviewDTO"},"minItems":0},"paginationInfo":{"$ref":"#/components/schemas/PaginationInfoDTO"}}},"WorkflowOverviewDTO":{"type":"object","properties":{"workflowId":{"type":"string","description":"Workflowuniqueidentifier","minLength":1},"name":{"type":"string","description":"Workflowname","minLength":1},"format":{"$ref":"#/components/schemas/WorkflowFormatDTO"},"lastRunId":{"type":"string"},"lastTriggeredMs":{"type":"number","minimum":0},"lastRunStatus":{"$ref":"#/components/schemas/ProcessInstanceStatusDTO"},"category":{"$ref":"#/components/schemas/WorkflowCategoryDTO"},"avgDurationMs":{"type":"number","minimum":0},"description":{"type":"string"}},"required":["workflowId","format"]},"PaginationInfoDTO":{"type":"object","properties":{"pageSize":{"type":"number"},"offset":{"type":"number"},"totalCount":{"type":"number"},"orderDirection":{"enum":["ASC","DESC"]},"orderBy":{"type":"string"}},"additionalProperties":false},"WorkflowFormatDTO":{"type":"string","description":"Formatoftheworkflowdefinition","enum":["yaml","json"]},"WorkflowCategoryDTO":{"type":"string","description":"Categoryoftheworkflow","enum":["assessment","infrastructure"]},"WorkflowListResultDTO":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/WorkflowDTO"}},"paginationInfo":{"$ref":"#/components/schemas/PaginationInfoDTO"}},"required":["items","paginationInfo"]},"WorkflowDTO":{"type":"object","properties":{"id":{"type":"string","description":"Workflowuniqueidentifier","minLength":1},"name":{"type":"string","description":"Workflowname","minLength":1},"format":{"$ref":"#/components/schemas/WorkflowFormatDTO"},"category":{"$ref":"#/components/schemas/WorkflowCategoryDTO"},"description":{"type":"string","description":"Descriptionoftheworkflow"},"annotations":{"type":"array","items":{"type":"string"}}},"required":["id","category","format"]},"ProcessInstanceListResultDTO":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ProcessInstanceDTO"}},"paginationInfo":{"$ref":"#/components/schemas/PaginationInfoDTO"}}},"AssessedProcessInstanceDTO":{"type":"object","properties":{"instance":{"$ref":"#/components/schemas/ProcessInstanceDTO"},"assessedBy":{"$ref":"#/components/schemas/ProcessInstanceDTO"}},"required":["instance"]},"ProcessInstanceDTO":{"type":"object","properties":{"id":{"type":"string"},"processId":{"type":"string"},"processName":{"type":"string"},"status":{"$ref":"#/components/schemas/ProcessInstanceStatusDTO"},"endpoint":{"type":"string"},"serviceUrl":{"type":"string"},"start":{"type":"string"},"end":{"type":"string"},"duration":{"type":"string"},"category":{"$ref":"#/components/schemas/WorkflowCategoryDTO"},"description":{"type":"string"},"workflowdata":{"$ref":"#/components/schemas/WorkflowDataDTO"},"businessKey":{"type":"string"},"nodes":{"type":"array","items":{"$ref":"#/components/schemas/NodeInstanceDTO"}},"error":{"$ref":"#/components/schemas/ProcessInstanceErrorDTO"}},"required":["id","processId","nodes"]},"WorkflowDataDTO":{"type":"object","properties":{"result":{"$ref":"#/components/schemas/WorkflowResultDTO"}},"additionalProperties":true},"WorkflowResultDTO":{"description":"Resultofaworkflowexecution","type":"object","properties":{"completedWith":{"description":"Thestateofworkflowcompletion.","type":"string","enum":["error","success"]},"message":{"description":"High-levelsummaryofthecurrentstatus,free-formtext,humanreadable.","type":"string"},"nextWorkflows":{"description":"Listofworkflowssuggestedtorunnext.Itemsatlowerindexesareofhigherpriority.","type":"array","items":{"type":"object","properties":{"id":{"description":"Workflowidentifier","type":"string"},"name":{"description":"Humanreadabletitledescribingtheworkflow.","type":"string"}},"required":["id","name"]}},"outputs":{"description":"Additionalstructuredoutputofworkflowprocessing.Thiscancontainidentifiersofcreatedresources,linkstoresources,logsorotheroutput.","type":"array","items":{"type":"object","properties":{"key":{"description":"Uniqueidentifieroftheoption.Preferablyhuman-readable.","type":"string"},"value":{"description":"Freeformvalueoftheoption.","anyOf":[{"type":"string"},{"type":"number"}]},"format":{"description":"Moredetailedtypeofthe'value'property.Defaultsto'text'.","enum":["text","number","link"]}},"required":["key","value"]}}}},"ProcessInstanceStatusDTO":{"type":"string","description":"Statusoftheworkflowrun","enum":["Active","Error","Completed","Aborted","Suspended","Pending"]},"WorkflowRunStatusDTO":{"type":"object","properties":{"key":{"type":"string"},"value":{"type":"string"}}},"ExecuteWorkflowRequestDTO":{"type":"object","properties":{"inputData":{"type":"object","additionalProperties":true}},"required":["inputData"]},"ExecuteWorkflowResponseDTO":{"type":"object","properties":{"id":{"type":"string"}},"required":["id"]},"WorkflowProgressDTO":{"allOf":[{"$ref":"#/components/schemas/NodeInstanceDTO"},{"type":"object","properties":{"status":{"$ref":"#/components/schemas/ProcessInstanceStatusDTO"},"error":{"$ref":"#/components/schemas/ProcessInstanceErrorDTO"}}}]},"NodeInstanceDTO":{"type":"object","properties":{"__typename":{"type":"string","default":"NodeInstance","description":"Typename"},"id":{"type":"string","description":"NodeinstanceID"},"name":{"type":"string","description":"Nodename"},"type":{"type":"string","description":"Nodetype"},"enter":{"type":"string","description":"Datewhenthenodewasentered"},"exit":{"type":"string","description":"Datewhenthenodewasexited(optional)"},"definitionId":{"type":"string","description":"DefinitionID"},"nodeId":{"type":"string","description":"NodeID"}},"required":["id"]},"ProcessInstanceErrorDTO":{"type":"object","properties":{"__typename":{"type":"string","default":"ProcessInstanceError","description":"Typename"},"nodeDefinitionId":{"type":"string","description":"NodedefinitionID"},"message":{"type":"string","description":"Errormessage(optional)"}},"required":["nodeDefinitionId"]},"SearchRequest":{"type":"object","properties":{"filters":{"$ref":"#/components/schemas/Filter"},"paginationInfo":{"$ref":"#/components/schemas/PaginationInfoDTO"}}},"Filter":{"oneOf":[{"$ref":"#/components/schemas/LogicalFilter"},{"$ref":"#/components/schemas/FieldFilter"}]},"LogicalFilter":{"type":"object","required":["operator","filters"],"properties":{"operator":{"type":"string","enum":["AND","OR","NOT"]},"filters":{"type":"array","items":{"$ref":"#/components/schemas/Filter"}}}},"FieldFilter":{"type":"object","required":["field","operator","value"],"properties":{"field":{"type":"string"},"operator":{"type":"string","enum":["EQ","GT","GTE","LT","LTE","IN","IS_NULL","CONTAINS","CONTAINS_ALL","CONTAINS_ANY","LIKE","BETWEEN"]},"value":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"array","items":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"boolean"}]}}]}}},"InputSchemaResponseDTO":{"type":"object","properties":{"inputSchema":{"type":"object"},"data":{"type":"object"}}}}}}`; +export const openApiDocument = JSON.parse(OPENAPI); diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/client/.gitignore b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/client/.gitignore new file mode 100644 index 00000000..149b5765 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/client/.gitignore @@ -0,0 +1,4 @@ +wwwroot/*.js +node_modules +typings +dist diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/client/.npmignore b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/client/.npmignore new file mode 100644 index 00000000..999d88df --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/client/.npmignore @@ -0,0 +1 @@ +# empty npmignore to ensure all required files (e.g., in the dist folder) are published by npm \ No newline at end of file diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/client/.openapi-generator-ignore b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/client/.openapi-generator-ignore new file mode 100644 index 00000000..7484ee59 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/client/.openapi-generator-ignore @@ -0,0 +1,23 @@ +# OpenAPI Generator Ignore +# Generated by openapi-generator https://github.com/openapitools/openapi-generator + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/client/.openapi-generator/FILES b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/client/.openapi-generator/FILES new file mode 100644 index 00000000..16b445ee --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/client/.openapi-generator/FILES @@ -0,0 +1,9 @@ +.gitignore +.npmignore +.openapi-generator-ignore +api.ts +base.ts +common.ts +configuration.ts +git_push.sh +index.ts diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/client/.openapi-generator/VERSION b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/client/.openapi-generator/VERSION new file mode 100644 index 00000000..8b23b8d4 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/client/.openapi-generator/VERSION @@ -0,0 +1 @@ +7.3.0 \ No newline at end of file diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/client/api.ts b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/client/api.ts new file mode 100644 index 00000000..210da157 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/client/api.ts @@ -0,0 +1,1698 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Orchestrator plugin + * API to interact with orchestrator plugin + * + * The version of the OpenAPI document: 0.0.1 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +import type { Configuration } from './configuration'; +import type { AxiosPromise, AxiosInstance, RawAxiosRequestConfig } from 'axios'; +import globalAxios from 'axios'; +// Some imports not used depending on template conditions +// @ts-ignore +import { DUMMY_BASE_URL, assertParamExists, setApiKeyToObject, setBasicAuthToObject, setBearerAuthToObject, setOAuthToObject, setSearchParams, serializeDataIfNeeded, toPathString, createRequestFunction } from './common'; +import type { RequestArgs } from './base'; +// @ts-ignore +import { BASE_PATH, COLLECTION_FORMATS, BaseAPI, RequiredError, operationServerMap } from './base'; + +/** + * + * @export + * @interface AssessedProcessInstanceDTO + */ +export interface AssessedProcessInstanceDTO { + /** + * + * @type {ProcessInstanceDTO} + * @memberof AssessedProcessInstanceDTO + */ + 'instance': ProcessInstanceDTO; + /** + * + * @type {ProcessInstanceDTO} + * @memberof AssessedProcessInstanceDTO + */ + 'assessedBy'?: ProcessInstanceDTO; +} +/** + * The ErrorResponse object represents a common structure for handling errors in API responses. It includes essential information about the error, such as the error message and additional optional details. + * @export + * @interface ErrorResponse + */ +export interface ErrorResponse { + /** + * A string providing a concise and human-readable description of the encountered error. This field is required in the ErrorResponse object. + * @type {string} + * @memberof ErrorResponse + */ + 'message': string; + /** + * An optional field that can contain additional information or context about the error. It provides flexibility for including extra details based on specific error scenarios. + * @type {string} + * @memberof ErrorResponse + */ + 'additionalInfo'?: string; +} +/** + * + * @export + * @interface ExecuteWorkflowRequestDTO + */ +export interface ExecuteWorkflowRequestDTO { + /** + * + * @type {object} + * @memberof ExecuteWorkflowRequestDTO + */ + 'inputData': object; +} +/** + * + * @export + * @interface ExecuteWorkflowResponseDTO + */ +export interface ExecuteWorkflowResponseDTO { + /** + * + * @type {string} + * @memberof ExecuteWorkflowResponseDTO + */ + 'id': string; +} +/** + * + * @export + * @interface FieldFilter + */ +export interface FieldFilter { + /** + * + * @type {string} + * @memberof FieldFilter + */ + 'field': string; + /** + * + * @type {string} + * @memberof FieldFilter + */ + 'operator': FieldFilterOperatorEnum; + /** + * + * @type {FieldFilterValue} + * @memberof FieldFilter + */ + 'value': FieldFilterValue; +} + +export const FieldFilterOperatorEnum = { + Eq: 'EQ', + Gt: 'GT', + Gte: 'GTE', + Lt: 'LT', + Lte: 'LTE', + In: 'IN', + IsNull: 'IS_NULL', + Contains: 'CONTAINS', + ContainsAll: 'CONTAINS_ALL', + ContainsAny: 'CONTAINS_ANY', + Like: 'LIKE', + Between: 'BETWEEN' +} as const; + +export type FieldFilterOperatorEnum = typeof FieldFilterOperatorEnum[keyof typeof FieldFilterOperatorEnum]; + +/** + * @type FieldFilterValue + * @export + */ +export type FieldFilterValue = any | boolean | number | string; + +/** + * @type Filter + * @export + */ +export type Filter = FieldFilter | LogicalFilter; + +/** + * + * @export + * @interface GetInstancesRequest + */ +export interface GetInstancesRequest { + /** + * + * @type {PaginationInfoDTO} + * @memberof GetInstancesRequest + */ + 'paginationInfo'?: PaginationInfoDTO; + /** + * + * @type {SearchRequest} + * @memberof GetInstancesRequest + */ + 'filters'?: SearchRequest; +} +/** + * + * @export + * @interface GetOverviewsRequestParams + */ +export interface GetOverviewsRequestParams { + /** + * + * @type {PaginationInfoDTO} + * @memberof GetOverviewsRequestParams + */ + 'paginationInfo'?: PaginationInfoDTO; + /** + * + * @type {SearchRequest} + * @memberof GetOverviewsRequestParams + */ + 'filters'?: SearchRequest; +} +/** + * + * @export + * @interface InputSchemaResponseDTO + */ +export interface InputSchemaResponseDTO { + /** + * + * @type {object} + * @memberof InputSchemaResponseDTO + */ + 'inputSchema'?: object; + /** + * + * @type {object} + * @memberof InputSchemaResponseDTO + */ + 'data'?: object; +} +/** + * + * @export + * @interface LogicalFilter + */ +export interface LogicalFilter { + /** + * + * @type {string} + * @memberof LogicalFilter + */ + 'operator': LogicalFilterOperatorEnum; + /** + * + * @type {Array} + * @memberof LogicalFilter + */ + 'filters': Array; +} + +export const LogicalFilterOperatorEnum = { + And: 'AND', + Or: 'OR', + Not: 'NOT' +} as const; + +export type LogicalFilterOperatorEnum = typeof LogicalFilterOperatorEnum[keyof typeof LogicalFilterOperatorEnum]; + +/** + * + * @export + * @interface NodeInstanceDTO + */ +export interface NodeInstanceDTO { + /** + * Type name + * @type {string} + * @memberof NodeInstanceDTO + */ + '__typename'?: string; + /** + * Node instance ID + * @type {string} + * @memberof NodeInstanceDTO + */ + 'id': string; + /** + * Node name + * @type {string} + * @memberof NodeInstanceDTO + */ + 'name'?: string; + /** + * Node type + * @type {string} + * @memberof NodeInstanceDTO + */ + 'type'?: string; + /** + * Date when the node was entered + * @type {string} + * @memberof NodeInstanceDTO + */ + 'enter'?: string; + /** + * Date when the node was exited (optional) + * @type {string} + * @memberof NodeInstanceDTO + */ + 'exit'?: string; + /** + * Definition ID + * @type {string} + * @memberof NodeInstanceDTO + */ + 'definitionId'?: string; + /** + * Node ID + * @type {string} + * @memberof NodeInstanceDTO + */ + 'nodeId'?: string; +} +/** + * + * @export + * @interface PaginationInfoDTO + */ +export interface PaginationInfoDTO { + /** + * + * @type {number} + * @memberof PaginationInfoDTO + */ + 'pageSize'?: number; + /** + * + * @type {number} + * @memberof PaginationInfoDTO + */ + 'offset'?: number; + /** + * + * @type {number} + * @memberof PaginationInfoDTO + */ + 'totalCount'?: number; + /** + * + * @type {string} + * @memberof PaginationInfoDTO + */ + 'orderDirection'?: PaginationInfoDTOOrderDirectionEnum; + /** + * + * @type {string} + * @memberof PaginationInfoDTO + */ + 'orderBy'?: string; +} + +export const PaginationInfoDTOOrderDirectionEnum = { + Asc: 'ASC', + Desc: 'DESC' +} as const; + +export type PaginationInfoDTOOrderDirectionEnum = typeof PaginationInfoDTOOrderDirectionEnum[keyof typeof PaginationInfoDTOOrderDirectionEnum]; + +/** + * + * @export + * @interface ProcessInstanceDTO + */ +export interface ProcessInstanceDTO { + /** + * + * @type {string} + * @memberof ProcessInstanceDTO + */ + 'id': string; + /** + * + * @type {string} + * @memberof ProcessInstanceDTO + */ + 'processId': string; + /** + * + * @type {string} + * @memberof ProcessInstanceDTO + */ + 'processName'?: string; + /** + * + * @type {ProcessInstanceStatusDTO} + * @memberof ProcessInstanceDTO + */ + 'status'?: ProcessInstanceStatusDTO; + /** + * + * @type {string} + * @memberof ProcessInstanceDTO + */ + 'endpoint'?: string; + /** + * + * @type {string} + * @memberof ProcessInstanceDTO + */ + 'serviceUrl'?: string; + /** + * + * @type {string} + * @memberof ProcessInstanceDTO + */ + 'start'?: string; + /** + * + * @type {string} + * @memberof ProcessInstanceDTO + */ + 'end'?: string; + /** + * + * @type {string} + * @memberof ProcessInstanceDTO + */ + 'duration'?: string; + /** + * + * @type {WorkflowCategoryDTO} + * @memberof ProcessInstanceDTO + */ + 'category'?: WorkflowCategoryDTO; + /** + * + * @type {string} + * @memberof ProcessInstanceDTO + */ + 'description'?: string; + /** + * + * @type {WorkflowDataDTO} + * @memberof ProcessInstanceDTO + */ + 'workflowdata'?: WorkflowDataDTO; + /** + * + * @type {string} + * @memberof ProcessInstanceDTO + */ + 'businessKey'?: string; + /** + * + * @type {Array} + * @memberof ProcessInstanceDTO + */ + 'nodes': Array; + /** + * + * @type {ProcessInstanceErrorDTO} + * @memberof ProcessInstanceDTO + */ + 'error'?: ProcessInstanceErrorDTO; +} + + +/** + * + * @export + * @interface ProcessInstanceErrorDTO + */ +export interface ProcessInstanceErrorDTO { + /** + * Type name + * @type {string} + * @memberof ProcessInstanceErrorDTO + */ + '__typename'?: string; + /** + * Node definition ID + * @type {string} + * @memberof ProcessInstanceErrorDTO + */ + 'nodeDefinitionId': string; + /** + * Error message (optional) + * @type {string} + * @memberof ProcessInstanceErrorDTO + */ + 'message'?: string; +} +/** + * + * @export + * @interface ProcessInstanceListResultDTO + */ +export interface ProcessInstanceListResultDTO { + /** + * + * @type {Array} + * @memberof ProcessInstanceListResultDTO + */ + 'items'?: Array; + /** + * + * @type {PaginationInfoDTO} + * @memberof ProcessInstanceListResultDTO + */ + 'paginationInfo'?: PaginationInfoDTO; +} +/** + * Status of the workflow run + * @export + * @enum {string} + */ + +export const ProcessInstanceStatusDTO = { + Active: 'Active', + Error: 'Error', + Completed: 'Completed', + Aborted: 'Aborted', + Suspended: 'Suspended', + Pending: 'Pending' +} as const; + +export type ProcessInstanceStatusDTO = typeof ProcessInstanceStatusDTO[keyof typeof ProcessInstanceStatusDTO]; + + +/** + * + * @export + * @interface SearchRequest + */ +export interface SearchRequest { + /** + * + * @type {Filter} + * @memberof SearchRequest + */ + 'filters'?: Filter; + /** + * + * @type {PaginationInfoDTO} + * @memberof SearchRequest + */ + 'paginationInfo'?: PaginationInfoDTO; +} +/** + * Category of the workflow + * @export + * @enum {string} + */ + +export const WorkflowCategoryDTO = { + Assessment: 'assessment', + Infrastructure: 'infrastructure' +} as const; + +export type WorkflowCategoryDTO = typeof WorkflowCategoryDTO[keyof typeof WorkflowCategoryDTO]; + + +/** + * + * @export + * @interface WorkflowDTO + */ +export interface WorkflowDTO { + /** + * Workflow unique identifier + * @type {string} + * @memberof WorkflowDTO + */ + 'id': string; + /** + * Workflow name + * @type {string} + * @memberof WorkflowDTO + */ + 'name'?: string; + /** + * + * @type {WorkflowFormatDTO} + * @memberof WorkflowDTO + */ + 'format': WorkflowFormatDTO; + /** + * + * @type {WorkflowCategoryDTO} + * @memberof WorkflowDTO + */ + 'category': WorkflowCategoryDTO; + /** + * Description of the workflow + * @type {string} + * @memberof WorkflowDTO + */ + 'description'?: string; + /** + * + * @type {Array} + * @memberof WorkflowDTO + */ + 'annotations'?: Array; +} + + +/** + * + * @export + * @interface WorkflowDataDTO + */ +export interface WorkflowDataDTO { + /** + * + * @type {WorkflowResultDTO} + * @memberof WorkflowDataDTO + */ + 'result'?: WorkflowResultDTO; +} +/** + * Format of the workflow definition + * @export + * @enum {string} + */ + +export const WorkflowFormatDTO = { + Yaml: 'yaml', + Json: 'json' +} as const; + +export type WorkflowFormatDTO = typeof WorkflowFormatDTO[keyof typeof WorkflowFormatDTO]; + + +/** + * + * @export + * @interface WorkflowListResultDTO + */ +export interface WorkflowListResultDTO { + /** + * + * @type {Array} + * @memberof WorkflowListResultDTO + */ + 'items': Array; + /** + * + * @type {PaginationInfoDTO} + * @memberof WorkflowListResultDTO + */ + 'paginationInfo': PaginationInfoDTO; +} +/** + * + * @export + * @interface WorkflowOverviewDTO + */ +export interface WorkflowOverviewDTO { + /** + * Workflow unique identifier + * @type {string} + * @memberof WorkflowOverviewDTO + */ + 'workflowId': string; + /** + * Workflow name + * @type {string} + * @memberof WorkflowOverviewDTO + */ + 'name'?: string; + /** + * + * @type {WorkflowFormatDTO} + * @memberof WorkflowOverviewDTO + */ + 'format': WorkflowFormatDTO; + /** + * + * @type {string} + * @memberof WorkflowOverviewDTO + */ + 'lastRunId'?: string; + /** + * + * @type {number} + * @memberof WorkflowOverviewDTO + */ + 'lastTriggeredMs'?: number; + /** + * + * @type {ProcessInstanceStatusDTO} + * @memberof WorkflowOverviewDTO + */ + 'lastRunStatus'?: ProcessInstanceStatusDTO; + /** + * + * @type {WorkflowCategoryDTO} + * @memberof WorkflowOverviewDTO + */ + 'category'?: WorkflowCategoryDTO; + /** + * + * @type {number} + * @memberof WorkflowOverviewDTO + */ + 'avgDurationMs'?: number; + /** + * + * @type {string} + * @memberof WorkflowOverviewDTO + */ + 'description'?: string; +} + + +/** + * + * @export + * @interface WorkflowOverviewListResultDTO + */ +export interface WorkflowOverviewListResultDTO { + /** + * + * @type {Array} + * @memberof WorkflowOverviewListResultDTO + */ + 'overviews'?: Array; + /** + * + * @type {PaginationInfoDTO} + * @memberof WorkflowOverviewListResultDTO + */ + 'paginationInfo'?: PaginationInfoDTO; +} +/** + * + * @export + * @interface WorkflowProgressDTO + */ +export interface WorkflowProgressDTO { + /** + * Type name + * @type {any} + * @memberof WorkflowProgressDTO + */ + '__typename'?: any; + /** + * Node instance ID + * @type {any} + * @memberof WorkflowProgressDTO + */ + 'id': any; + /** + * Node name + * @type {any} + * @memberof WorkflowProgressDTO + */ + 'name'?: any; + /** + * Node type + * @type {any} + * @memberof WorkflowProgressDTO + */ + 'type'?: any; + /** + * Date when the node was entered + * @type {any} + * @memberof WorkflowProgressDTO + */ + 'enter'?: any; + /** + * Date when the node was exited (optional) + * @type {any} + * @memberof WorkflowProgressDTO + */ + 'exit'?: any; + /** + * Definition ID + * @type {any} + * @memberof WorkflowProgressDTO + */ + 'definitionId'?: any; + /** + * Node ID + * @type {any} + * @memberof WorkflowProgressDTO + */ + 'nodeId'?: any; + /** + * + * @type {ProcessInstanceStatusDTO} + * @memberof WorkflowProgressDTO + */ + 'status'?: ProcessInstanceStatusDTO; + /** + * + * @type {ProcessInstanceErrorDTO} + * @memberof WorkflowProgressDTO + */ + 'error'?: ProcessInstanceErrorDTO; +} + + +/** + * Result of a workflow execution + * @export + * @interface WorkflowResultDTO + */ +export interface WorkflowResultDTO { + /** + * The state of workflow completion. + * @type {string} + * @memberof WorkflowResultDTO + */ + 'completedWith'?: WorkflowResultDTOCompletedWithEnum; + /** + * High-level summary of the current status, free-form text, human readable. + * @type {string} + * @memberof WorkflowResultDTO + */ + 'message'?: string; + /** + * List of workflows suggested to run next. Items at lower indexes are of higher priority. + * @type {Array} + * @memberof WorkflowResultDTO + */ + 'nextWorkflows'?: Array; + /** + * Additional structured output of workflow processing. This can contain identifiers of created resources, links to resources, logs or other output. + * @type {Array} + * @memberof WorkflowResultDTO + */ + 'outputs'?: Array; +} + +export const WorkflowResultDTOCompletedWithEnum = { + Error: 'error', + Success: 'success' +} as const; + +export type WorkflowResultDTOCompletedWithEnum = typeof WorkflowResultDTOCompletedWithEnum[keyof typeof WorkflowResultDTOCompletedWithEnum]; + +/** + * + * @export + * @interface WorkflowResultDTONextWorkflowsInner + */ +export interface WorkflowResultDTONextWorkflowsInner { + /** + * Workflow identifier + * @type {string} + * @memberof WorkflowResultDTONextWorkflowsInner + */ + 'id': string; + /** + * Human readable title describing the workflow. + * @type {string} + * @memberof WorkflowResultDTONextWorkflowsInner + */ + 'name': string; +} +/** + * + * @export + * @interface WorkflowResultDTOOutputsInner + */ +export interface WorkflowResultDTOOutputsInner { + /** + * Unique identifier of the option. Preferably human-readable. + * @type {string} + * @memberof WorkflowResultDTOOutputsInner + */ + 'key': string; + /** + * + * @type {WorkflowResultDTOOutputsInnerValue} + * @memberof WorkflowResultDTOOutputsInner + */ + 'value': WorkflowResultDTOOutputsInnerValue; + /** + * More detailed type of the \'value\' property. Defaults to \'text\'. + * @type {string} + * @memberof WorkflowResultDTOOutputsInner + */ + 'format'?: WorkflowResultDTOOutputsInnerFormatEnum; +} + +export const WorkflowResultDTOOutputsInnerFormatEnum = { + Text: 'text', + Number: 'number', + Link: 'link' +} as const; + +export type WorkflowResultDTOOutputsInnerFormatEnum = typeof WorkflowResultDTOOutputsInnerFormatEnum[keyof typeof WorkflowResultDTOOutputsInnerFormatEnum]; + +/** + * Free form value of the option. + * @export + * @interface WorkflowResultDTOOutputsInnerValue + */ +export interface WorkflowResultDTOOutputsInnerValue { +} +/** + * + * @export + * @interface WorkflowRunStatusDTO + */ +export interface WorkflowRunStatusDTO { + /** + * + * @type {string} + * @memberof WorkflowRunStatusDTO + */ + 'key'?: string; + /** + * + * @type {string} + * @memberof WorkflowRunStatusDTO + */ + 'value'?: string; +} + +/** + * DefaultApi - axios parameter creator + * @export + */ +export const DefaultApiAxiosParamCreator = function (configuration?: Configuration) { + return { + /** + * Aborts a workflow instance identified by the provided instanceId. + * @summary Abort a workflow instance + * @param {string} instanceId The identifier of the workflow instance to abort. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + abortWorkflow: async (instanceId: string, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'instanceId' is not null or undefined + assertParamExists('abortWorkflow', 'instanceId', instanceId) + const localVarPath = `/v2/workflows/instances/{instanceId}/abort` + .replace(`{${"instanceId"}}`, encodeURIComponent(String(instanceId))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'DELETE', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * Execute a workflow + * @summary Execute a workflow + * @param {string} workflowId ID of the workflow to execute + * @param {ExecuteWorkflowRequestDTO} executeWorkflowRequestDTO + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + executeWorkflow: async (workflowId: string, executeWorkflowRequestDTO: ExecuteWorkflowRequestDTO, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'workflowId' is not null or undefined + assertParamExists('executeWorkflow', 'workflowId', workflowId) + // verify required parameter 'executeWorkflowRequestDTO' is not null or undefined + assertParamExists('executeWorkflow', 'executeWorkflowRequestDTO', executeWorkflowRequestDTO) + const localVarPath = `/v2/workflows/{workflowId}/execute` + .replace(`{${"workflowId"}}`, encodeURIComponent(String(workflowId))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + + + localVarHeaderParameter['Content-Type'] = 'application/json'; + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(executeWorkflowRequestDTO, localVarRequestOptions, configuration) + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * Get a workflow execution/run (instance) + * @summary Get Workflow Instance by ID + * @param {string} instanceId ID of the workflow instance + * @param {boolean} [includeAssessment] Whether to include assessment + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getInstanceById: async (instanceId: string, includeAssessment?: boolean, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'instanceId' is not null or undefined + assertParamExists('getInstanceById', 'instanceId', instanceId) + const localVarPath = `/v2/workflows/instances/{instanceId}` + .replace(`{${"instanceId"}}`, encodeURIComponent(String(instanceId))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + if (includeAssessment !== undefined) { + localVarQueryParameter['includeAssessment'] = includeAssessment; + } + + + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * Retrieve an array of workflow executions (instances) + * @summary Get instances + * @param {GetInstancesRequest} [getInstancesRequest] Parameters for retrieving instances + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getInstances: async (getInstancesRequest?: GetInstancesRequest, options: RawAxiosRequestConfig = {}): Promise => { + const localVarPath = `/v2/workflows/instances`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + + + localVarHeaderParameter['Content-Type'] = 'application/json'; + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(getInstancesRequest, localVarRequestOptions, configuration) + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * Get the workflow input schema. It defines the input fields of the workflow + * @param {string} workflowId ID of the workflow to fetch + * @param {string} [instanceId] ID of instance + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getWorkflowInputSchemaById: async (workflowId: string, instanceId?: string, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'workflowId' is not null or undefined + assertParamExists('getWorkflowInputSchemaById', 'workflowId', workflowId) + const localVarPath = `/v2/workflows/{workflowId}/inputSchema` + .replace(`{${"workflowId"}}`, encodeURIComponent(String(workflowId))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + if (instanceId !== undefined) { + localVarQueryParameter['instanceId'] = instanceId; + } + + + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * Retrieve an array of workflow executions (instances) for the given workflow + * @summary Get instances for a specific workflow + * @param {string} workflowId ID of the workflow + * @param {SearchRequest} [searchRequest] Parameters for retrieving workflow instances + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getWorkflowInstances: async (workflowId: string, searchRequest?: SearchRequest, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'workflowId' is not null or undefined + assertParamExists('getWorkflowInstances', 'workflowId', workflowId) + const localVarPath = `/v2/workflows/{workflowId}/instances` + .replace(`{${"workflowId"}}`, encodeURIComponent(String(workflowId))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + + + localVarHeaderParameter['Content-Type'] = 'application/json'; + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(searchRequest, localVarRequestOptions, configuration) + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * Returns the key fields of the workflow including data on the last run instance + * @param {string} workflowId Unique identifier of the workflow + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getWorkflowOverviewById: async (workflowId: string, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'workflowId' is not null or undefined + assertParamExists('getWorkflowOverviewById', 'workflowId', workflowId) + const localVarPath = `/v2/workflows/{workflowId}/overview` + .replace(`{${"workflowId"}}`, encodeURIComponent(String(workflowId))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * Get the workflow\'s definition + * @param {string} workflowId ID of the workflow to fetch + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getWorkflowSourceById: async (workflowId: string, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'workflowId' is not null or undefined + assertParamExists('getWorkflowSourceById', 'workflowId', workflowId) + const localVarPath = `/v2/workflows/{workflowId}/source` + .replace(`{${"workflowId"}}`, encodeURIComponent(String(workflowId))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * Retrieve array with the status of all instances + * @summary Get workflow status list + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getWorkflowStatuses: async (options: RawAxiosRequestConfig = {}): Promise => { + const localVarPath = `/v2/workflows/instances/statuses`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * Returns the key fields of the workflow including data on the last run instance + * @param {SearchRequest} [searchRequest] Pagination and filters + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getWorkflowsOverview: async (searchRequest?: SearchRequest, options: RawAxiosRequestConfig = {}): Promise => { + const localVarPath = `/v2/workflows/overview`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + + + localVarHeaderParameter['Content-Type'] = 'application/json'; + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(searchRequest, localVarRequestOptions, configuration) + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * Retrigger an instance + * @summary Retrigger an instance + * @param {string} workflowId ID of the workflow + * @param {string} instanceId ID of the instance to retrigger + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + retriggerInstance: async (workflowId: string, instanceId: string, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'workflowId' is not null or undefined + assertParamExists('retriggerInstance', 'workflowId', workflowId) + // verify required parameter 'instanceId' is not null or undefined + assertParamExists('retriggerInstance', 'instanceId', instanceId) + const localVarPath = `/v2/workflows/{workflowId}/{instanceId}/retrigger` + .replace(`{${"workflowId"}}`, encodeURIComponent(String(workflowId))) + .replace(`{${"instanceId"}}`, encodeURIComponent(String(instanceId))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + } +}; + +/** + * DefaultApi - functional programming interface + * @export + */ +export const DefaultApiFp = function(configuration?: Configuration) { + const localVarAxiosParamCreator = DefaultApiAxiosParamCreator(configuration) + return { + /** + * Aborts a workflow instance identified by the provided instanceId. + * @summary Abort a workflow instance + * @param {string} instanceId The identifier of the workflow instance to abort. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async abortWorkflow(instanceId: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.abortWorkflow(instanceId, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['DefaultApi.abortWorkflow']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * Execute a workflow + * @summary Execute a workflow + * @param {string} workflowId ID of the workflow to execute + * @param {ExecuteWorkflowRequestDTO} executeWorkflowRequestDTO + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async executeWorkflow(workflowId: string, executeWorkflowRequestDTO: ExecuteWorkflowRequestDTO, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.executeWorkflow(workflowId, executeWorkflowRequestDTO, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['DefaultApi.executeWorkflow']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * Get a workflow execution/run (instance) + * @summary Get Workflow Instance by ID + * @param {string} instanceId ID of the workflow instance + * @param {boolean} [includeAssessment] Whether to include assessment + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async getInstanceById(instanceId: string, includeAssessment?: boolean, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getInstanceById(instanceId, includeAssessment, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['DefaultApi.getInstanceById']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * Retrieve an array of workflow executions (instances) + * @summary Get instances + * @param {GetInstancesRequest} [getInstancesRequest] Parameters for retrieving instances + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async getInstances(getInstancesRequest?: GetInstancesRequest, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getInstances(getInstancesRequest, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['DefaultApi.getInstances']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * Get the workflow input schema. It defines the input fields of the workflow + * @param {string} workflowId ID of the workflow to fetch + * @param {string} [instanceId] ID of instance + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async getWorkflowInputSchemaById(workflowId: string, instanceId?: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getWorkflowInputSchemaById(workflowId, instanceId, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['DefaultApi.getWorkflowInputSchemaById']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * Retrieve an array of workflow executions (instances) for the given workflow + * @summary Get instances for a specific workflow + * @param {string} workflowId ID of the workflow + * @param {SearchRequest} [searchRequest] Parameters for retrieving workflow instances + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async getWorkflowInstances(workflowId: string, searchRequest?: SearchRequest, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getWorkflowInstances(workflowId, searchRequest, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['DefaultApi.getWorkflowInstances']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * Returns the key fields of the workflow including data on the last run instance + * @param {string} workflowId Unique identifier of the workflow + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async getWorkflowOverviewById(workflowId: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getWorkflowOverviewById(workflowId, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['DefaultApi.getWorkflowOverviewById']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * Get the workflow\'s definition + * @param {string} workflowId ID of the workflow to fetch + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async getWorkflowSourceById(workflowId: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getWorkflowSourceById(workflowId, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['DefaultApi.getWorkflowSourceById']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * Retrieve array with the status of all instances + * @summary Get workflow status list + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async getWorkflowStatuses(options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise>> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getWorkflowStatuses(options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['DefaultApi.getWorkflowStatuses']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * Returns the key fields of the workflow including data on the last run instance + * @param {SearchRequest} [searchRequest] Pagination and filters + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async getWorkflowsOverview(searchRequest?: SearchRequest, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getWorkflowsOverview(searchRequest, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['DefaultApi.getWorkflowsOverview']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * Retrigger an instance + * @summary Retrigger an instance + * @param {string} workflowId ID of the workflow + * @param {string} instanceId ID of the instance to retrigger + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async retriggerInstance(workflowId: string, instanceId: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.retriggerInstance(workflowId, instanceId, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['DefaultApi.retriggerInstance']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + } +}; + +/** + * DefaultApi - factory interface + * @export + */ +export const DefaultApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) { + const localVarFp = DefaultApiFp(configuration) + return { + /** + * Aborts a workflow instance identified by the provided instanceId. + * @summary Abort a workflow instance + * @param {string} instanceId The identifier of the workflow instance to abort. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + abortWorkflow(instanceId: string, options?: any): AxiosPromise { + return localVarFp.abortWorkflow(instanceId, options).then((request) => request(axios, basePath)); + }, + /** + * Execute a workflow + * @summary Execute a workflow + * @param {string} workflowId ID of the workflow to execute + * @param {ExecuteWorkflowRequestDTO} executeWorkflowRequestDTO + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + executeWorkflow(workflowId: string, executeWorkflowRequestDTO: ExecuteWorkflowRequestDTO, options?: any): AxiosPromise { + return localVarFp.executeWorkflow(workflowId, executeWorkflowRequestDTO, options).then((request) => request(axios, basePath)); + }, + /** + * Get a workflow execution/run (instance) + * @summary Get Workflow Instance by ID + * @param {string} instanceId ID of the workflow instance + * @param {boolean} [includeAssessment] Whether to include assessment + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getInstanceById(instanceId: string, includeAssessment?: boolean, options?: any): AxiosPromise { + return localVarFp.getInstanceById(instanceId, includeAssessment, options).then((request) => request(axios, basePath)); + }, + /** + * Retrieve an array of workflow executions (instances) + * @summary Get instances + * @param {GetInstancesRequest} [getInstancesRequest] Parameters for retrieving instances + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getInstances(getInstancesRequest?: GetInstancesRequest, options?: any): AxiosPromise { + return localVarFp.getInstances(getInstancesRequest, options).then((request) => request(axios, basePath)); + }, + /** + * Get the workflow input schema. It defines the input fields of the workflow + * @param {string} workflowId ID of the workflow to fetch + * @param {string} [instanceId] ID of instance + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getWorkflowInputSchemaById(workflowId: string, instanceId?: string, options?: any): AxiosPromise { + return localVarFp.getWorkflowInputSchemaById(workflowId, instanceId, options).then((request) => request(axios, basePath)); + }, + /** + * Retrieve an array of workflow executions (instances) for the given workflow + * @summary Get instances for a specific workflow + * @param {string} workflowId ID of the workflow + * @param {SearchRequest} [searchRequest] Parameters for retrieving workflow instances + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getWorkflowInstances(workflowId: string, searchRequest?: SearchRequest, options?: any): AxiosPromise { + return localVarFp.getWorkflowInstances(workflowId, searchRequest, options).then((request) => request(axios, basePath)); + }, + /** + * Returns the key fields of the workflow including data on the last run instance + * @param {string} workflowId Unique identifier of the workflow + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getWorkflowOverviewById(workflowId: string, options?: any): AxiosPromise { + return localVarFp.getWorkflowOverviewById(workflowId, options).then((request) => request(axios, basePath)); + }, + /** + * Get the workflow\'s definition + * @param {string} workflowId ID of the workflow to fetch + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getWorkflowSourceById(workflowId: string, options?: any): AxiosPromise { + return localVarFp.getWorkflowSourceById(workflowId, options).then((request) => request(axios, basePath)); + }, + /** + * Retrieve array with the status of all instances + * @summary Get workflow status list + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getWorkflowStatuses(options?: any): AxiosPromise> { + return localVarFp.getWorkflowStatuses(options).then((request) => request(axios, basePath)); + }, + /** + * Returns the key fields of the workflow including data on the last run instance + * @param {SearchRequest} [searchRequest] Pagination and filters + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getWorkflowsOverview(searchRequest?: SearchRequest, options?: any): AxiosPromise { + return localVarFp.getWorkflowsOverview(searchRequest, options).then((request) => request(axios, basePath)); + }, + /** + * Retrigger an instance + * @summary Retrigger an instance + * @param {string} workflowId ID of the workflow + * @param {string} instanceId ID of the instance to retrigger + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + retriggerInstance(workflowId: string, instanceId: string, options?: any): AxiosPromise { + return localVarFp.retriggerInstance(workflowId, instanceId, options).then((request) => request(axios, basePath)); + }, + }; +}; + +/** + * DefaultApi - object-oriented interface + * @export + * @class DefaultApi + * @extends {BaseAPI} + */ +export class DefaultApi extends BaseAPI { + /** + * Aborts a workflow instance identified by the provided instanceId. + * @summary Abort a workflow instance + * @param {string} instanceId The identifier of the workflow instance to abort. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof DefaultApi + */ + public abortWorkflow(instanceId: string, options?: RawAxiosRequestConfig) { + return DefaultApiFp(this.configuration).abortWorkflow(instanceId, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * Execute a workflow + * @summary Execute a workflow + * @param {string} workflowId ID of the workflow to execute + * @param {ExecuteWorkflowRequestDTO} executeWorkflowRequestDTO + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof DefaultApi + */ + public executeWorkflow(workflowId: string, executeWorkflowRequestDTO: ExecuteWorkflowRequestDTO, options?: RawAxiosRequestConfig) { + return DefaultApiFp(this.configuration).executeWorkflow(workflowId, executeWorkflowRequestDTO, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * Get a workflow execution/run (instance) + * @summary Get Workflow Instance by ID + * @param {string} instanceId ID of the workflow instance + * @param {boolean} [includeAssessment] Whether to include assessment + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof DefaultApi + */ + public getInstanceById(instanceId: string, includeAssessment?: boolean, options?: RawAxiosRequestConfig) { + return DefaultApiFp(this.configuration).getInstanceById(instanceId, includeAssessment, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * Retrieve an array of workflow executions (instances) + * @summary Get instances + * @param {GetInstancesRequest} [getInstancesRequest] Parameters for retrieving instances + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof DefaultApi + */ + public getInstances(getInstancesRequest?: GetInstancesRequest, options?: RawAxiosRequestConfig) { + return DefaultApiFp(this.configuration).getInstances(getInstancesRequest, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * Get the workflow input schema. It defines the input fields of the workflow + * @param {string} workflowId ID of the workflow to fetch + * @param {string} [instanceId] ID of instance + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof DefaultApi + */ + public getWorkflowInputSchemaById(workflowId: string, instanceId?: string, options?: RawAxiosRequestConfig) { + return DefaultApiFp(this.configuration).getWorkflowInputSchemaById(workflowId, instanceId, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * Retrieve an array of workflow executions (instances) for the given workflow + * @summary Get instances for a specific workflow + * @param {string} workflowId ID of the workflow + * @param {SearchRequest} [searchRequest] Parameters for retrieving workflow instances + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof DefaultApi + */ + public getWorkflowInstances(workflowId: string, searchRequest?: SearchRequest, options?: RawAxiosRequestConfig) { + return DefaultApiFp(this.configuration).getWorkflowInstances(workflowId, searchRequest, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * Returns the key fields of the workflow including data on the last run instance + * @param {string} workflowId Unique identifier of the workflow + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof DefaultApi + */ + public getWorkflowOverviewById(workflowId: string, options?: RawAxiosRequestConfig) { + return DefaultApiFp(this.configuration).getWorkflowOverviewById(workflowId, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * Get the workflow\'s definition + * @param {string} workflowId ID of the workflow to fetch + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof DefaultApi + */ + public getWorkflowSourceById(workflowId: string, options?: RawAxiosRequestConfig) { + return DefaultApiFp(this.configuration).getWorkflowSourceById(workflowId, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * Retrieve array with the status of all instances + * @summary Get workflow status list + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof DefaultApi + */ + public getWorkflowStatuses(options?: RawAxiosRequestConfig) { + return DefaultApiFp(this.configuration).getWorkflowStatuses(options).then((request) => request(this.axios, this.basePath)); + } + + /** + * Returns the key fields of the workflow including data on the last run instance + * @param {SearchRequest} [searchRequest] Pagination and filters + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof DefaultApi + */ + public getWorkflowsOverview(searchRequest?: SearchRequest, options?: RawAxiosRequestConfig) { + return DefaultApiFp(this.configuration).getWorkflowsOverview(searchRequest, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * Retrigger an instance + * @summary Retrigger an instance + * @param {string} workflowId ID of the workflow + * @param {string} instanceId ID of the instance to retrigger + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof DefaultApi + */ + public retriggerInstance(workflowId: string, instanceId: string, options?: RawAxiosRequestConfig) { + return DefaultApiFp(this.configuration).retriggerInstance(workflowId, instanceId, options).then((request) => request(this.axios, this.basePath)); + } +} + + + diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/client/base.ts b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/client/base.ts new file mode 100644 index 00000000..ab6429a0 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/client/base.ts @@ -0,0 +1,86 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Orchestrator plugin + * API to interact with orchestrator plugin + * + * The version of the OpenAPI document: 0.0.1 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +import type { Configuration } from './configuration'; +// Some imports not used depending on template conditions +// @ts-ignore +import type { AxiosPromise, AxiosInstance, RawAxiosRequestConfig } from 'axios'; +import globalAxios from 'axios'; + +export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); + +/** + * + * @export + */ +export const COLLECTION_FORMATS = { + csv: ",", + ssv: " ", + tsv: "\t", + pipes: "|", +}; + +/** + * + * @export + * @interface RequestArgs + */ +export interface RequestArgs { + url: string; + options: RawAxiosRequestConfig; +} + +/** + * + * @export + * @class BaseAPI + */ +export class BaseAPI { + protected configuration: Configuration | undefined; + + constructor(configuration?: Configuration, protected basePath: string = BASE_PATH, protected axios: AxiosInstance = globalAxios) { + if (configuration) { + this.configuration = configuration; + this.basePath = configuration.basePath ?? basePath; + } + } +}; + +/** + * + * @export + * @class RequiredError + * @extends {Error} + */ +export class RequiredError extends Error { + constructor(public field: string, msg?: string) { + super(msg); + this.name = "RequiredError" + } +} + +interface ServerMap { + [key: string]: { + url: string, + description: string, + }[]; +} + +/** + * + * @export + */ +export const operationServerMap: ServerMap = { +} diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/client/common.ts b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/client/common.ts new file mode 100644 index 00000000..1bc8f423 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/client/common.ts @@ -0,0 +1,150 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Orchestrator plugin + * API to interact with orchestrator plugin + * + * The version of the OpenAPI document: 0.0.1 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +import type { Configuration } from "./configuration"; +import type { RequestArgs } from "./base"; +import type { AxiosInstance, AxiosResponse } from 'axios'; +import { RequiredError } from "./base"; + +/** + * + * @export + */ +export const DUMMY_BASE_URL = 'https://example.com' + +/** + * + * @throws {RequiredError} + * @export + */ +export const assertParamExists = function (functionName: string, paramName: string, paramValue: unknown) { + if (paramValue === null || paramValue === undefined) { + throw new RequiredError(paramName, `Required parameter ${paramName} was null or undefined when calling ${functionName}.`); + } +} + +/** + * + * @export + */ +export const setApiKeyToObject = async function (object: any, keyParamName: string, configuration?: Configuration) { + if (configuration && configuration.apiKey) { + const localVarApiKeyValue = typeof configuration.apiKey === 'function' + ? await configuration.apiKey(keyParamName) + : await configuration.apiKey; + object[keyParamName] = localVarApiKeyValue; + } +} + +/** + * + * @export + */ +export const setBasicAuthToObject = function (object: any, configuration?: Configuration) { + if (configuration && (configuration.username || configuration.password)) { + object["auth"] = { username: configuration.username, password: configuration.password }; + } +} + +/** + * + * @export + */ +export const setBearerAuthToObject = async function (object: any, configuration?: Configuration) { + if (configuration && configuration.accessToken) { + const accessToken = typeof configuration.accessToken === 'function' + ? await configuration.accessToken() + : await configuration.accessToken; + object["Authorization"] = "Bearer " + accessToken; + } +} + +/** + * + * @export + */ +export const setOAuthToObject = async function (object: any, name: string, scopes: string[], configuration?: Configuration) { + if (configuration && configuration.accessToken) { + const localVarAccessTokenValue = typeof configuration.accessToken === 'function' + ? await configuration.accessToken(name, scopes) + : await configuration.accessToken; + object["Authorization"] = "Bearer " + localVarAccessTokenValue; + } +} + +function setFlattenedQueryParams(urlSearchParams: URLSearchParams, parameter: any, key: string = ""): void { + if (parameter == null) return; + if (typeof parameter === "object") { + if (Array.isArray(parameter)) { + (parameter as any[]).forEach(item => setFlattenedQueryParams(urlSearchParams, item, key)); + } + else { + Object.keys(parameter).forEach(currentKey => + setFlattenedQueryParams(urlSearchParams, parameter[currentKey], `${key}${key !== '' ? '.' : ''}${currentKey}`) + ); + } + } + else { + if (urlSearchParams.has(key)) { + urlSearchParams.append(key, parameter); + } + else { + urlSearchParams.set(key, parameter); + } + } +} + +/** + * + * @export + */ +export const setSearchParams = function (url: URL, ...objects: any[]) { + const searchParams = new URLSearchParams(url.search); + setFlattenedQueryParams(searchParams, objects); + url.search = searchParams.toString(); +} + +/** + * + * @export + */ +export const serializeDataIfNeeded = function (value: any, requestOptions: any, configuration?: Configuration) { + const nonString = typeof value !== 'string'; + const needsSerialization = nonString && configuration && configuration.isJsonMime + ? configuration.isJsonMime(requestOptions.headers['Content-Type']) + : nonString; + return needsSerialization + ? JSON.stringify(value !== undefined ? value : {}) + : (value || ""); +} + +/** + * + * @export + */ +export const toPathString = function (url: URL) { + return url.pathname + url.search + url.hash +} + +/** + * + * @export + */ +export const createRequestFunction = function (axiosArgs: RequestArgs, globalAxios: AxiosInstance, BASE_PATH: string, configuration?: Configuration) { + return >(axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => { + const axiosRequestArgs = {...axiosArgs.options, url: (axios.defaults.baseURL ? '' : configuration?.basePath ?? basePath) + axiosArgs.url}; + return axios.request(axiosRequestArgs); + }; +} diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/client/configuration.ts b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/client/configuration.ts new file mode 100644 index 00000000..aacabb28 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/client/configuration.ts @@ -0,0 +1,110 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Orchestrator plugin + * API to interact with orchestrator plugin + * + * The version of the OpenAPI document: 0.0.1 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +export interface ConfigurationParameters { + apiKey?: string | Promise | ((name: string) => string) | ((name: string) => Promise); + username?: string; + password?: string; + accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string) | ((name?: string, scopes?: string[]) => Promise); + basePath?: string; + serverIndex?: number; + baseOptions?: any; + formDataCtor?: new () => any; +} + +export class Configuration { + /** + * parameter for apiKey security + * @param name security name + * @memberof Configuration + */ + apiKey?: string | Promise | ((name: string) => string) | ((name: string) => Promise); + /** + * parameter for basic security + * + * @type {string} + * @memberof Configuration + */ + username?: string; + /** + * parameter for basic security + * + * @type {string} + * @memberof Configuration + */ + password?: string; + /** + * parameter for oauth2 security + * @param name security name + * @param scopes oauth2 scope + * @memberof Configuration + */ + accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string) | ((name?: string, scopes?: string[]) => Promise); + /** + * override base path + * + * @type {string} + * @memberof Configuration + */ + basePath?: string; + /** + * override server index + * + * @type {number} + * @memberof Configuration + */ + serverIndex?: number; + /** + * base options for axios calls + * + * @type {any} + * @memberof Configuration + */ + baseOptions?: any; + /** + * The FormData constructor that will be used to create multipart form data + * requests. You can inject this here so that execution environments that + * do not support the FormData class can still run the generated client. + * + * @type {new () => FormData} + */ + formDataCtor?: new () => any; + + constructor(param: ConfigurationParameters = {}) { + this.apiKey = param.apiKey; + this.username = param.username; + this.password = param.password; + this.accessToken = param.accessToken; + this.basePath = param.basePath; + this.serverIndex = param.serverIndex; + this.baseOptions = param.baseOptions; + this.formDataCtor = param.formDataCtor; + } + + /** + * Check if the given MIME is a JSON MIME. + * JSON MIME examples: + * application/json + * application/json; charset=UTF8 + * APPLICATION/JSON + * application/vnd.company+json + * @param mime - MIME (Multipurpose Internet Mail Extensions) + * @return True if the given MIME is JSON, false otherwise. + */ + public isJsonMime(mime: string): boolean { + const jsonMime: RegExp = new RegExp('^(application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(;.*)?$', 'i'); + return mime !== null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); + } +} diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/client/git_push.sh b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/client/git_push.sh new file mode 100644 index 00000000..f53a75d4 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/client/git_push.sh @@ -0,0 +1,57 @@ +#!/bin/sh +# ref: https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/ +# +# Usage example: /bin/sh ./git_push.sh wing328 openapi-petstore-perl "minor update" "gitlab.com" + +git_user_id=$1 +git_repo_id=$2 +release_note=$3 +git_host=$4 + +if [ "$git_host" = "" ]; then + git_host="github.com" + echo "[INFO] No command line input provided. Set \$git_host to $git_host" +fi + +if [ "$git_user_id" = "" ]; then + git_user_id="GIT_USER_ID" + echo "[INFO] No command line input provided. Set \$git_user_id to $git_user_id" +fi + +if [ "$git_repo_id" = "" ]; then + git_repo_id="GIT_REPO_ID" + echo "[INFO] No command line input provided. Set \$git_repo_id to $git_repo_id" +fi + +if [ "$release_note" = "" ]; then + release_note="Minor update" + echo "[INFO] No command line input provided. Set \$release_note to $release_note" +fi + +# Initialize the local directory as a Git repository +git init + +# Adds the files in the local repository and stages them for commit. +git add . + +# Commits the tracked changes and prepares them to be pushed to a remote repository. +git commit -m "$release_note" + +# Sets the new remote +git_remote=$(git remote) +if [ "$git_remote" = "" ]; then # git remote not defined + + if [ "$GIT_TOKEN" = "" ]; then + echo "[INFO] \$GIT_TOKEN (environment variable) is not set. Using the git credential in your environment." + git remote add origin https://${git_host}/${git_user_id}/${git_repo_id}.git + else + git remote add origin https://${git_user_id}:"${GIT_TOKEN}"@${git_host}/${git_user_id}/${git_repo_id}.git + fi + +fi + +git pull origin master + +# Pushes (Forces) the changes in the local repository up to the remote repository +echo "Git pushing to https://${git_host}/${git_user_id}/${git_repo_id}.git" +git push origin master 2>&1 | grep -v 'To https' diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/client/index.ts b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/client/index.ts new file mode 100644 index 00000000..abcbe1fc --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/client/index.ts @@ -0,0 +1,18 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Orchestrator plugin + * API to interact with orchestrator plugin + * + * The version of the OpenAPI document: 0.0.1 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +export * from "./api"; +export * from "./configuration"; + diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/html/.openapi-generator-ignore b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/html/.openapi-generator-ignore new file mode 100644 index 00000000..7484ee59 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/html/.openapi-generator-ignore @@ -0,0 +1,23 @@ +# OpenAPI Generator Ignore +# Generated by openapi-generator https://github.com/openapitools/openapi-generator + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/html/.openapi-generator/FILES b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/html/.openapi-generator/FILES new file mode 100644 index 00000000..af3fdae9 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/html/.openapi-generator/FILES @@ -0,0 +1,2 @@ +.openapi-generator-ignore +index.html diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/html/.openapi-generator/VERSION b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/html/.openapi-generator/VERSION new file mode 100644 index 00000000..8b23b8d4 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/html/.openapi-generator/VERSION @@ -0,0 +1 @@ +7.3.0 \ No newline at end of file diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/html/index.html b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/html/index.html new file mode 100644 index 00000000..7e00a245 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/html/index.html @@ -0,0 +1,8028 @@ + + + + + Orchestrator plugin + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+

Orchestrator plugin

+
+
+
+ +
+
+

Default

+
+
+
+

abortWorkflow

+

Abort a workflow instance

+
+
+
+

+

Aborts a workflow instance identified by the provided instanceId.

+

+
+
/v2/workflows/instances/{instanceId}/abort
+

+

Usage and SDK Samples

+

+ + +
+
+
curl -X DELETE \
+ -H "Accept: text/plain,application/json" \
+ "http://localhost/v2/workflows/instances/{instanceId}/abort"
+
+
+
+
import org.openapitools.client.*;
+import org.openapitools.client.auth.*;
+import org.openapitools.client.model.*;
+import org.openapitools.client.api.DefaultApi;
+
+import java.io.File;
+import java.util.*;
+
+public class DefaultApiExample {
+    public static void main(String[] args) {
+
+        // Create an instance of the API class
+        DefaultApi apiInstance = new DefaultApi();
+        String instanceId = instanceId_example; // String | The identifier of the workflow instance to abort.
+
+        try {
+            'String' result = apiInstance.abortWorkflow(instanceId);
+            System.out.println(result);
+        } catch (ApiException e) {
+            System.err.println("Exception when calling DefaultApi#abortWorkflow");
+            e.printStackTrace();
+        }
+    }
+}
+
+
+ +
+
import 'package:openapi/api.dart';
+
+final api_instance = DefaultApi();
+
+final String instanceId = new String(); // String | The identifier of the workflow instance to abort.
+
+try {
+    final result = await api_instance.abortWorkflow(instanceId);
+    print(result);
+} catch (e) {
+    print('Exception when calling DefaultApi->abortWorkflow: $e\n');
+}
+
+
+
+ +
+
import org.openapitools.client.api.DefaultApi;
+
+public class DefaultApiExample {
+    public static void main(String[] args) {
+        DefaultApi apiInstance = new DefaultApi();
+        String instanceId = instanceId_example; // String | The identifier of the workflow instance to abort.
+
+        try {
+            'String' result = apiInstance.abortWorkflow(instanceId);
+            System.out.println(result);
+        } catch (ApiException e) {
+            System.err.println("Exception when calling DefaultApi#abortWorkflow");
+            e.printStackTrace();
+        }
+    }
+}
+
+ +
+

+
+// Create an instance of the API class
+DefaultApi *apiInstance = [[DefaultApi alloc] init];
+String *instanceId = instanceId_example; // The identifier of the workflow instance to abort. (default to null)
+
+// Abort a workflow instance
+[apiInstance abortWorkflowWith:instanceId
+              completionHandler: ^('String' output, NSError* error) {
+    if (output) {
+        NSLog(@"%@", output);
+    }
+    if (error) {
+        NSLog(@"Error: %@", error);
+    }
+}];
+
+
+ +
+
var OrchestratorPlugin = require('orchestrator_plugin');
+
+// Create an instance of the API class
+var api = new OrchestratorPlugin.DefaultApi()
+var instanceId = instanceId_example; // {String} The identifier of the workflow instance to abort.
+
+var callback = function(error, data, response) {
+  if (error) {
+    console.error(error);
+  } else {
+    console.log('API called successfully. Returned data: ' + data);
+  }
+};
+api.abortWorkflow(instanceId, callback);
+
+
+ + +
+
using System;
+using System.Diagnostics;
+using Org.OpenAPITools.Api;
+using Org.OpenAPITools.Client;
+using Org.OpenAPITools.Model;
+
+namespace Example
+{
+    public class abortWorkflowExample
+    {
+        public void main()
+        {
+
+            // Create an instance of the API class
+            var apiInstance = new DefaultApi();
+            var instanceId = instanceId_example;  // String | The identifier of the workflow instance to abort. (default to null)
+
+            try {
+                // Abort a workflow instance
+                'String' result = apiInstance.abortWorkflow(instanceId);
+                Debug.WriteLine(result);
+            } catch (Exception e) {
+                Debug.Print("Exception when calling DefaultApi.abortWorkflow: " + e.Message );
+            }
+        }
+    }
+}
+
+
+ +
+
<?php
+require_once(__DIR__ . '/vendor/autoload.php');
+
+// Create an instance of the API class
+$api_instance = new OpenAPITools\Client\Api\DefaultApi();
+$instanceId = instanceId_example; // String | The identifier of the workflow instance to abort.
+
+try {
+    $result = $api_instance->abortWorkflow($instanceId);
+    print_r($result);
+} catch (Exception $e) {
+    echo 'Exception when calling DefaultApi->abortWorkflow: ', $e->getMessage(), PHP_EOL;
+}
+?>
+
+ +
+
use Data::Dumper;
+use WWW::OPenAPIClient::Configuration;
+use WWW::OPenAPIClient::DefaultApi;
+
+# Create an instance of the API class
+my $api_instance = WWW::OPenAPIClient::DefaultApi->new();
+my $instanceId = instanceId_example; # String | The identifier of the workflow instance to abort.
+
+eval {
+    my $result = $api_instance->abortWorkflow(instanceId => $instanceId);
+    print Dumper($result);
+};
+if ($@) {
+    warn "Exception when calling DefaultApi->abortWorkflow: $@\n";
+}
+
+ +
+
from __future__ import print_statement
+import time
+import openapi_client
+from openapi_client.rest import ApiException
+from pprint import pprint
+
+# Create an instance of the API class
+api_instance = openapi_client.DefaultApi()
+instanceId = instanceId_example # String | The identifier of the workflow instance to abort. (default to null)
+
+try:
+    # Abort a workflow instance
+    api_response = api_instance.abort_workflow(instanceId)
+    pprint(api_response)
+except ApiException as e:
+    print("Exception when calling DefaultApi->abortWorkflow: %s\n" % e)
+
+ +
+
extern crate DefaultApi;
+
+pub fn main() {
+    let instanceId = instanceId_example; // String
+
+    let mut context = DefaultApi::Context::default();
+    let result = client.abortWorkflow(instanceId, &context).wait();
+
+    println!("{:?}", result);
+}
+
+
+
+ +

Scopes

+ + +
+ +

Parameters

+ +
Path parameters
+ + + + + + + + + +
NameDescription
instanceId* + + +
+
+
+ + String + + +
+The identifier of the workflow instance to abort. +
+
+
+ Required +
+
+
+
+ + + + + +

Responses

+

+

+ + + + + + +
+
+
+ +
+ +
+
+

+

+ + + + + + +
+
+
+ +
+ +
+
+
+
+
+
+
+
+

executeWorkflow

+

Execute a workflow

+
+
+
+

+

Execute a workflow

+

+
+
/v2/workflows/{workflowId}/execute
+

+

Usage and SDK Samples

+

+ + +
+
+
curl -X POST \
+ -H "Accept: application/json" \
+ -H "Content-Type: application/json" \
+ "http://localhost/v2/workflows/{workflowId}/execute" \
+ -d '{
+  "inputData" : "{}"
+}'
+
+
+
+
import org.openapitools.client.*;
+import org.openapitools.client.auth.*;
+import org.openapitools.client.model.*;
+import org.openapitools.client.api.DefaultApi;
+
+import java.io.File;
+import java.util.*;
+
+public class DefaultApiExample {
+    public static void main(String[] args) {
+
+        // Create an instance of the API class
+        DefaultApi apiInstance = new DefaultApi();
+        String workflowId = workflowId_example; // String | ID of the workflow to execute
+        ExecuteWorkflowRequestDTO executeWorkflowRequestDTO = ; // ExecuteWorkflowRequestDTO | 
+
+        try {
+            ExecuteWorkflowResponseDTO result = apiInstance.executeWorkflow(workflowId, executeWorkflowRequestDTO);
+            System.out.println(result);
+        } catch (ApiException e) {
+            System.err.println("Exception when calling DefaultApi#executeWorkflow");
+            e.printStackTrace();
+        }
+    }
+}
+
+
+ +
+
import 'package:openapi/api.dart';
+
+final api_instance = DefaultApi();
+
+final String workflowId = new String(); // String | ID of the workflow to execute
+final ExecuteWorkflowRequestDTO executeWorkflowRequestDTO = new ExecuteWorkflowRequestDTO(); // ExecuteWorkflowRequestDTO | 
+
+try {
+    final result = await api_instance.executeWorkflow(workflowId, executeWorkflowRequestDTO);
+    print(result);
+} catch (e) {
+    print('Exception when calling DefaultApi->executeWorkflow: $e\n');
+}
+
+
+
+ +
+
import org.openapitools.client.api.DefaultApi;
+
+public class DefaultApiExample {
+    public static void main(String[] args) {
+        DefaultApi apiInstance = new DefaultApi();
+        String workflowId = workflowId_example; // String | ID of the workflow to execute
+        ExecuteWorkflowRequestDTO executeWorkflowRequestDTO = ; // ExecuteWorkflowRequestDTO | 
+
+        try {
+            ExecuteWorkflowResponseDTO result = apiInstance.executeWorkflow(workflowId, executeWorkflowRequestDTO);
+            System.out.println(result);
+        } catch (ApiException e) {
+            System.err.println("Exception when calling DefaultApi#executeWorkflow");
+            e.printStackTrace();
+        }
+    }
+}
+
+ +
+

+
+// Create an instance of the API class
+DefaultApi *apiInstance = [[DefaultApi alloc] init];
+String *workflowId = workflowId_example; // ID of the workflow to execute (default to null)
+ExecuteWorkflowRequestDTO *executeWorkflowRequestDTO = ; // 
+
+// Execute a workflow
+[apiInstance executeWorkflowWith:workflowId
+    executeWorkflowRequestDTO:executeWorkflowRequestDTO
+              completionHandler: ^(ExecuteWorkflowResponseDTO output, NSError* error) {
+    if (output) {
+        NSLog(@"%@", output);
+    }
+    if (error) {
+        NSLog(@"Error: %@", error);
+    }
+}];
+
+
+ +
+
var OrchestratorPlugin = require('orchestrator_plugin');
+
+// Create an instance of the API class
+var api = new OrchestratorPlugin.DefaultApi()
+var workflowId = workflowId_example; // {String} ID of the workflow to execute
+var executeWorkflowRequestDTO = ; // {ExecuteWorkflowRequestDTO} 
+
+var callback = function(error, data, response) {
+  if (error) {
+    console.error(error);
+  } else {
+    console.log('API called successfully. Returned data: ' + data);
+  }
+};
+api.executeWorkflow(workflowId, executeWorkflowRequestDTO, callback);
+
+
+ + +
+
using System;
+using System.Diagnostics;
+using Org.OpenAPITools.Api;
+using Org.OpenAPITools.Client;
+using Org.OpenAPITools.Model;
+
+namespace Example
+{
+    public class executeWorkflowExample
+    {
+        public void main()
+        {
+
+            // Create an instance of the API class
+            var apiInstance = new DefaultApi();
+            var workflowId = workflowId_example;  // String | ID of the workflow to execute (default to null)
+            var executeWorkflowRequestDTO = new ExecuteWorkflowRequestDTO(); // ExecuteWorkflowRequestDTO | 
+
+            try {
+                // Execute a workflow
+                ExecuteWorkflowResponseDTO result = apiInstance.executeWorkflow(workflowId, executeWorkflowRequestDTO);
+                Debug.WriteLine(result);
+            } catch (Exception e) {
+                Debug.Print("Exception when calling DefaultApi.executeWorkflow: " + e.Message );
+            }
+        }
+    }
+}
+
+
+ +
+
<?php
+require_once(__DIR__ . '/vendor/autoload.php');
+
+// Create an instance of the API class
+$api_instance = new OpenAPITools\Client\Api\DefaultApi();
+$workflowId = workflowId_example; // String | ID of the workflow to execute
+$executeWorkflowRequestDTO = ; // ExecuteWorkflowRequestDTO | 
+
+try {
+    $result = $api_instance->executeWorkflow($workflowId, $executeWorkflowRequestDTO);
+    print_r($result);
+} catch (Exception $e) {
+    echo 'Exception when calling DefaultApi->executeWorkflow: ', $e->getMessage(), PHP_EOL;
+}
+?>
+
+ +
+
use Data::Dumper;
+use WWW::OPenAPIClient::Configuration;
+use WWW::OPenAPIClient::DefaultApi;
+
+# Create an instance of the API class
+my $api_instance = WWW::OPenAPIClient::DefaultApi->new();
+my $workflowId = workflowId_example; # String | ID of the workflow to execute
+my $executeWorkflowRequestDTO = WWW::OPenAPIClient::Object::ExecuteWorkflowRequestDTO->new(); # ExecuteWorkflowRequestDTO | 
+
+eval {
+    my $result = $api_instance->executeWorkflow(workflowId => $workflowId, executeWorkflowRequestDTO => $executeWorkflowRequestDTO);
+    print Dumper($result);
+};
+if ($@) {
+    warn "Exception when calling DefaultApi->executeWorkflow: $@\n";
+}
+
+ +
+
from __future__ import print_statement
+import time
+import openapi_client
+from openapi_client.rest import ApiException
+from pprint import pprint
+
+# Create an instance of the API class
+api_instance = openapi_client.DefaultApi()
+workflowId = workflowId_example # String | ID of the workflow to execute (default to null)
+executeWorkflowRequestDTO =  # ExecuteWorkflowRequestDTO | 
+
+try:
+    # Execute a workflow
+    api_response = api_instance.execute_workflow(workflowId, executeWorkflowRequestDTO)
+    pprint(api_response)
+except ApiException as e:
+    print("Exception when calling DefaultApi->executeWorkflow: %s\n" % e)
+
+ +
+
extern crate DefaultApi;
+
+pub fn main() {
+    let workflowId = workflowId_example; // String
+    let executeWorkflowRequestDTO = ; // ExecuteWorkflowRequestDTO
+
+    let mut context = DefaultApi::Context::default();
+    let result = client.executeWorkflow(workflowId, executeWorkflowRequestDTO, &context).wait();
+
+    println!("{:?}", result);
+}
+
+
+
+ +

Scopes

+ + +
+ +

Parameters

+ +
Path parameters
+ + + + + + + + + +
NameDescription
workflowId* + + +
+
+
+ + String + + +
+ID of the workflow to execute +
+
+
+ Required +
+
+
+
+ + +
Body parameters
+ + + + + + + + + +
NameDescription
executeWorkflowRequestDTO * +

+ +
+
+ + + +

Responses

+

+

+ + + + + + +
+
+
+ +
+ +
+
+

+

+ + + + + + +
+
+
+ +
+ +
+
+
+
+
+
+
+
+

getInstanceById

+

Get Workflow Instance by ID

+
+
+
+

+

Get a workflow execution/run (instance)

+

+
+
/v2/workflows/instances/{instanceId}
+

+

Usage and SDK Samples

+

+ + +
+
+
curl -X GET \
+ -H "Accept: application/json" \
+ "http://localhost/v2/workflows/instances/{instanceId}?includeAssessment=true"
+
+
+
+
import org.openapitools.client.*;
+import org.openapitools.client.auth.*;
+import org.openapitools.client.model.*;
+import org.openapitools.client.api.DefaultApi;
+
+import java.io.File;
+import java.util.*;
+
+public class DefaultApiExample {
+    public static void main(String[] args) {
+
+        // Create an instance of the API class
+        DefaultApi apiInstance = new DefaultApi();
+        String instanceId = instanceId_example; // String | ID of the workflow instance
+        Boolean includeAssessment = true; // Boolean | Whether to include assessment
+
+        try {
+            AssessedProcessInstanceDTO result = apiInstance.getInstanceById(instanceId, includeAssessment);
+            System.out.println(result);
+        } catch (ApiException e) {
+            System.err.println("Exception when calling DefaultApi#getInstanceById");
+            e.printStackTrace();
+        }
+    }
+}
+
+
+ +
+
import 'package:openapi/api.dart';
+
+final api_instance = DefaultApi();
+
+final String instanceId = new String(); // String | ID of the workflow instance
+final Boolean includeAssessment = new Boolean(); // Boolean | Whether to include assessment
+
+try {
+    final result = await api_instance.getInstanceById(instanceId, includeAssessment);
+    print(result);
+} catch (e) {
+    print('Exception when calling DefaultApi->getInstanceById: $e\n');
+}
+
+
+
+ +
+
import org.openapitools.client.api.DefaultApi;
+
+public class DefaultApiExample {
+    public static void main(String[] args) {
+        DefaultApi apiInstance = new DefaultApi();
+        String instanceId = instanceId_example; // String | ID of the workflow instance
+        Boolean includeAssessment = true; // Boolean | Whether to include assessment
+
+        try {
+            AssessedProcessInstanceDTO result = apiInstance.getInstanceById(instanceId, includeAssessment);
+            System.out.println(result);
+        } catch (ApiException e) {
+            System.err.println("Exception when calling DefaultApi#getInstanceById");
+            e.printStackTrace();
+        }
+    }
+}
+
+ +
+

+
+// Create an instance of the API class
+DefaultApi *apiInstance = [[DefaultApi alloc] init];
+String *instanceId = instanceId_example; // ID of the workflow instance (default to null)
+Boolean *includeAssessment = true; // Whether to include assessment (optional) (default to false)
+
+// Get Workflow Instance by ID
+[apiInstance getInstanceByIdWith:instanceId
+    includeAssessment:includeAssessment
+              completionHandler: ^(AssessedProcessInstanceDTO output, NSError* error) {
+    if (output) {
+        NSLog(@"%@", output);
+    }
+    if (error) {
+        NSLog(@"Error: %@", error);
+    }
+}];
+
+
+ +
+
var OrchestratorPlugin = require('orchestrator_plugin');
+
+// Create an instance of the API class
+var api = new OrchestratorPlugin.DefaultApi()
+var instanceId = instanceId_example; // {String} ID of the workflow instance
+var opts = {
+  'includeAssessment': true // {Boolean} Whether to include assessment
+};
+
+var callback = function(error, data, response) {
+  if (error) {
+    console.error(error);
+  } else {
+    console.log('API called successfully. Returned data: ' + data);
+  }
+};
+api.getInstanceById(instanceId, opts, callback);
+
+
+ + +
+
using System;
+using System.Diagnostics;
+using Org.OpenAPITools.Api;
+using Org.OpenAPITools.Client;
+using Org.OpenAPITools.Model;
+
+namespace Example
+{
+    public class getInstanceByIdExample
+    {
+        public void main()
+        {
+
+            // Create an instance of the API class
+            var apiInstance = new DefaultApi();
+            var instanceId = instanceId_example;  // String | ID of the workflow instance (default to null)
+            var includeAssessment = true;  // Boolean | Whether to include assessment (optional)  (default to false)
+
+            try {
+                // Get Workflow Instance by ID
+                AssessedProcessInstanceDTO result = apiInstance.getInstanceById(instanceId, includeAssessment);
+                Debug.WriteLine(result);
+            } catch (Exception e) {
+                Debug.Print("Exception when calling DefaultApi.getInstanceById: " + e.Message );
+            }
+        }
+    }
+}
+
+
+ +
+
<?php
+require_once(__DIR__ . '/vendor/autoload.php');
+
+// Create an instance of the API class
+$api_instance = new OpenAPITools\Client\Api\DefaultApi();
+$instanceId = instanceId_example; // String | ID of the workflow instance
+$includeAssessment = true; // Boolean | Whether to include assessment
+
+try {
+    $result = $api_instance->getInstanceById($instanceId, $includeAssessment);
+    print_r($result);
+} catch (Exception $e) {
+    echo 'Exception when calling DefaultApi->getInstanceById: ', $e->getMessage(), PHP_EOL;
+}
+?>
+
+ +
+
use Data::Dumper;
+use WWW::OPenAPIClient::Configuration;
+use WWW::OPenAPIClient::DefaultApi;
+
+# Create an instance of the API class
+my $api_instance = WWW::OPenAPIClient::DefaultApi->new();
+my $instanceId = instanceId_example; # String | ID of the workflow instance
+my $includeAssessment = true; # Boolean | Whether to include assessment
+
+eval {
+    my $result = $api_instance->getInstanceById(instanceId => $instanceId, includeAssessment => $includeAssessment);
+    print Dumper($result);
+};
+if ($@) {
+    warn "Exception when calling DefaultApi->getInstanceById: $@\n";
+}
+
+ +
+
from __future__ import print_statement
+import time
+import openapi_client
+from openapi_client.rest import ApiException
+from pprint import pprint
+
+# Create an instance of the API class
+api_instance = openapi_client.DefaultApi()
+instanceId = instanceId_example # String | ID of the workflow instance (default to null)
+includeAssessment = true # Boolean | Whether to include assessment (optional) (default to false)
+
+try:
+    # Get Workflow Instance by ID
+    api_response = api_instance.get_instance_by_id(instanceId, includeAssessment=includeAssessment)
+    pprint(api_response)
+except ApiException as e:
+    print("Exception when calling DefaultApi->getInstanceById: %s\n" % e)
+
+ +
+
extern crate DefaultApi;
+
+pub fn main() {
+    let instanceId = instanceId_example; // String
+    let includeAssessment = true; // Boolean
+
+    let mut context = DefaultApi::Context::default();
+    let result = client.getInstanceById(instanceId, includeAssessment, &context).wait();
+
+    println!("{:?}", result);
+}
+
+
+
+ +

Scopes

+ + +
+ +

Parameters

+ +
Path parameters
+ + + + + + + + + +
NameDescription
instanceId* + + +
+
+
+ + String + + +
+ID of the workflow instance +
+
+
+ Required +
+
+
+
+ + + + +
Query parameters
+ + + + + + + + + +
NameDescription
includeAssessment + + +
+
+
+ + Boolean + + +
+Whether to include assessment +
+
+
+
+
+ +

Responses

+

+

+ + + + + + +
+
+
+ +
+ +
+
+

+

+ + + + + + +
+
+
+ +
+ +
+
+
+
+
+
+
+
+

getInstances

+

Get instances

+
+
+
+

+

Retrieve an array of workflow executions (instances)

+

+
+
/v2/workflows/instances
+

+

Usage and SDK Samples

+

+ + +
+
+
curl -X POST \
+ -H "Accept: application/json" \
+ -H "Content-Type: application/json" \
+ "http://localhost/v2/workflows/instances" \
+ -d '{
+  "paginationInfo" : {
+    "offset" : 5.962133916683182,
+    "pageSize" : 1.4658129805029452,
+    "orderDirection" : "ASC",
+    "orderBy" : "orderBy",
+    "totalCount" : 5.637376656633329
+  },
+  "filters" : {
+    "paginationInfo" : {
+      "offset" : 5.962133916683182,
+      "pageSize" : 1.4658129805029452,
+      "orderDirection" : "ASC",
+      "orderBy" : "orderBy",
+      "totalCount" : 5.637376656633329
+    },
+    "filters" : {
+      "filters" : [ null, null ],
+      "operator" : "AND"
+    }
+  }
+}'
+
+
+
+
import org.openapitools.client.*;
+import org.openapitools.client.auth.*;
+import org.openapitools.client.model.*;
+import org.openapitools.client.api.DefaultApi;
+
+import java.io.File;
+import java.util.*;
+
+public class DefaultApiExample {
+    public static void main(String[] args) {
+
+        // Create an instance of the API class
+        DefaultApi apiInstance = new DefaultApi();
+        GetInstancesRequest getInstancesRequest = ; // GetInstancesRequest | 
+
+        try {
+            ProcessInstanceListResultDTO result = apiInstance.getInstances(getInstancesRequest);
+            System.out.println(result);
+        } catch (ApiException e) {
+            System.err.println("Exception when calling DefaultApi#getInstances");
+            e.printStackTrace();
+        }
+    }
+}
+
+
+ +
+
import 'package:openapi/api.dart';
+
+final api_instance = DefaultApi();
+
+final GetInstancesRequest getInstancesRequest = new GetInstancesRequest(); // GetInstancesRequest | 
+
+try {
+    final result = await api_instance.getInstances(getInstancesRequest);
+    print(result);
+} catch (e) {
+    print('Exception when calling DefaultApi->getInstances: $e\n');
+}
+
+
+
+ +
+
import org.openapitools.client.api.DefaultApi;
+
+public class DefaultApiExample {
+    public static void main(String[] args) {
+        DefaultApi apiInstance = new DefaultApi();
+        GetInstancesRequest getInstancesRequest = ; // GetInstancesRequest | 
+
+        try {
+            ProcessInstanceListResultDTO result = apiInstance.getInstances(getInstancesRequest);
+            System.out.println(result);
+        } catch (ApiException e) {
+            System.err.println("Exception when calling DefaultApi#getInstances");
+            e.printStackTrace();
+        }
+    }
+}
+
+ +
+

+
+// Create an instance of the API class
+DefaultApi *apiInstance = [[DefaultApi alloc] init];
+GetInstancesRequest *getInstancesRequest = ; //  (optional)
+
+// Get instances
+[apiInstance getInstancesWith:getInstancesRequest
+              completionHandler: ^(ProcessInstanceListResultDTO output, NSError* error) {
+    if (output) {
+        NSLog(@"%@", output);
+    }
+    if (error) {
+        NSLog(@"Error: %@", error);
+    }
+}];
+
+
+ +
+
var OrchestratorPlugin = require('orchestrator_plugin');
+
+// Create an instance of the API class
+var api = new OrchestratorPlugin.DefaultApi()
+var opts = {
+  'getInstancesRequest':  // {GetInstancesRequest} 
+};
+
+var callback = function(error, data, response) {
+  if (error) {
+    console.error(error);
+  } else {
+    console.log('API called successfully. Returned data: ' + data);
+  }
+};
+api.getInstances(opts, callback);
+
+
+ + +
+
using System;
+using System.Diagnostics;
+using Org.OpenAPITools.Api;
+using Org.OpenAPITools.Client;
+using Org.OpenAPITools.Model;
+
+namespace Example
+{
+    public class getInstancesExample
+    {
+        public void main()
+        {
+
+            // Create an instance of the API class
+            var apiInstance = new DefaultApi();
+            var getInstancesRequest = new GetInstancesRequest(); // GetInstancesRequest |  (optional) 
+
+            try {
+                // Get instances
+                ProcessInstanceListResultDTO result = apiInstance.getInstances(getInstancesRequest);
+                Debug.WriteLine(result);
+            } catch (Exception e) {
+                Debug.Print("Exception when calling DefaultApi.getInstances: " + e.Message );
+            }
+        }
+    }
+}
+
+
+ +
+
<?php
+require_once(__DIR__ . '/vendor/autoload.php');
+
+// Create an instance of the API class
+$api_instance = new OpenAPITools\Client\Api\DefaultApi();
+$getInstancesRequest = ; // GetInstancesRequest | 
+
+try {
+    $result = $api_instance->getInstances($getInstancesRequest);
+    print_r($result);
+} catch (Exception $e) {
+    echo 'Exception when calling DefaultApi->getInstances: ', $e->getMessage(), PHP_EOL;
+}
+?>
+
+ +
+
use Data::Dumper;
+use WWW::OPenAPIClient::Configuration;
+use WWW::OPenAPIClient::DefaultApi;
+
+# Create an instance of the API class
+my $api_instance = WWW::OPenAPIClient::DefaultApi->new();
+my $getInstancesRequest = WWW::OPenAPIClient::Object::GetInstancesRequest->new(); # GetInstancesRequest | 
+
+eval {
+    my $result = $api_instance->getInstances(getInstancesRequest => $getInstancesRequest);
+    print Dumper($result);
+};
+if ($@) {
+    warn "Exception when calling DefaultApi->getInstances: $@\n";
+}
+
+ +
+
from __future__ import print_statement
+import time
+import openapi_client
+from openapi_client.rest import ApiException
+from pprint import pprint
+
+# Create an instance of the API class
+api_instance = openapi_client.DefaultApi()
+getInstancesRequest =  # GetInstancesRequest |  (optional)
+
+try:
+    # Get instances
+    api_response = api_instance.get_instances(getInstancesRequest=getInstancesRequest)
+    pprint(api_response)
+except ApiException as e:
+    print("Exception when calling DefaultApi->getInstances: %s\n" % e)
+
+ +
+
extern crate DefaultApi;
+
+pub fn main() {
+    let getInstancesRequest = ; // GetInstancesRequest
+
+    let mut context = DefaultApi::Context::default();
+    let result = client.getInstances(getInstancesRequest, &context).wait();
+
+    println!("{:?}", result);
+}
+
+
+
+ +

Scopes

+ + +
+ +

Parameters

+ + + +
Body parameters
+ + + + + + + + + +
NameDescription
getInstancesRequest +

Parameters for retrieving instances

+ +
+
+ + + +

Responses

+

+

+ + + + + + +
+
+
+ +
+ +
+
+

+

+ + + + + + +
+
+
+ +
+ +
+
+
+
+
+
+
+
+

getWorkflowInputSchemaById

+

+
+
+
+

+

Get the workflow input schema. It defines the input fields of the workflow

+

+
+
/v2/workflows/{workflowId}/inputSchema
+

+

Usage and SDK Samples

+

+ + +
+
+
curl -X GET \
+ -H "Accept: application/json" \
+ "http://localhost/v2/workflows/{workflowId}/inputSchema?instanceId=instanceId_example"
+
+
+
+
import org.openapitools.client.*;
+import org.openapitools.client.auth.*;
+import org.openapitools.client.model.*;
+import org.openapitools.client.api.DefaultApi;
+
+import java.io.File;
+import java.util.*;
+
+public class DefaultApiExample {
+    public static void main(String[] args) {
+
+        // Create an instance of the API class
+        DefaultApi apiInstance = new DefaultApi();
+        String workflowId = workflowId_example; // String | ID of the workflow to fetch
+        String instanceId = instanceId_example; // String | ID of instance
+
+        try {
+            InputSchemaResponseDTO result = apiInstance.getWorkflowInputSchemaById(workflowId, instanceId);
+            System.out.println(result);
+        } catch (ApiException e) {
+            System.err.println("Exception when calling DefaultApi#getWorkflowInputSchemaById");
+            e.printStackTrace();
+        }
+    }
+}
+
+
+ +
+
import 'package:openapi/api.dart';
+
+final api_instance = DefaultApi();
+
+final String workflowId = new String(); // String | ID of the workflow to fetch
+final String instanceId = new String(); // String | ID of instance
+
+try {
+    final result = await api_instance.getWorkflowInputSchemaById(workflowId, instanceId);
+    print(result);
+} catch (e) {
+    print('Exception when calling DefaultApi->getWorkflowInputSchemaById: $e\n');
+}
+
+
+
+ +
+
import org.openapitools.client.api.DefaultApi;
+
+public class DefaultApiExample {
+    public static void main(String[] args) {
+        DefaultApi apiInstance = new DefaultApi();
+        String workflowId = workflowId_example; // String | ID of the workflow to fetch
+        String instanceId = instanceId_example; // String | ID of instance
+
+        try {
+            InputSchemaResponseDTO result = apiInstance.getWorkflowInputSchemaById(workflowId, instanceId);
+            System.out.println(result);
+        } catch (ApiException e) {
+            System.err.println("Exception when calling DefaultApi#getWorkflowInputSchemaById");
+            e.printStackTrace();
+        }
+    }
+}
+
+ +
+

+
+// Create an instance of the API class
+DefaultApi *apiInstance = [[DefaultApi alloc] init];
+String *workflowId = workflowId_example; // ID of the workflow to fetch (default to null)
+String *instanceId = instanceId_example; // ID of instance (optional) (default to null)
+
+[apiInstance getWorkflowInputSchemaByIdWith:workflowId
+    instanceId:instanceId
+              completionHandler: ^(InputSchemaResponseDTO output, NSError* error) {
+    if (output) {
+        NSLog(@"%@", output);
+    }
+    if (error) {
+        NSLog(@"Error: %@", error);
+    }
+}];
+
+
+ +
+
var OrchestratorPlugin = require('orchestrator_plugin');
+
+// Create an instance of the API class
+var api = new OrchestratorPlugin.DefaultApi()
+var workflowId = workflowId_example; // {String} ID of the workflow to fetch
+var opts = {
+  'instanceId': instanceId_example // {String} ID of instance
+};
+
+var callback = function(error, data, response) {
+  if (error) {
+    console.error(error);
+  } else {
+    console.log('API called successfully. Returned data: ' + data);
+  }
+};
+api.getWorkflowInputSchemaById(workflowId, opts, callback);
+
+
+ + +
+
using System;
+using System.Diagnostics;
+using Org.OpenAPITools.Api;
+using Org.OpenAPITools.Client;
+using Org.OpenAPITools.Model;
+
+namespace Example
+{
+    public class getWorkflowInputSchemaByIdExample
+    {
+        public void main()
+        {
+
+            // Create an instance of the API class
+            var apiInstance = new DefaultApi();
+            var workflowId = workflowId_example;  // String | ID of the workflow to fetch (default to null)
+            var instanceId = instanceId_example;  // String | ID of instance (optional)  (default to null)
+
+            try {
+                InputSchemaResponseDTO result = apiInstance.getWorkflowInputSchemaById(workflowId, instanceId);
+                Debug.WriteLine(result);
+            } catch (Exception e) {
+                Debug.Print("Exception when calling DefaultApi.getWorkflowInputSchemaById: " + e.Message );
+            }
+        }
+    }
+}
+
+
+ +
+
<?php
+require_once(__DIR__ . '/vendor/autoload.php');
+
+// Create an instance of the API class
+$api_instance = new OpenAPITools\Client\Api\DefaultApi();
+$workflowId = workflowId_example; // String | ID of the workflow to fetch
+$instanceId = instanceId_example; // String | ID of instance
+
+try {
+    $result = $api_instance->getWorkflowInputSchemaById($workflowId, $instanceId);
+    print_r($result);
+} catch (Exception $e) {
+    echo 'Exception when calling DefaultApi->getWorkflowInputSchemaById: ', $e->getMessage(), PHP_EOL;
+}
+?>
+
+ +
+
use Data::Dumper;
+use WWW::OPenAPIClient::Configuration;
+use WWW::OPenAPIClient::DefaultApi;
+
+# Create an instance of the API class
+my $api_instance = WWW::OPenAPIClient::DefaultApi->new();
+my $workflowId = workflowId_example; # String | ID of the workflow to fetch
+my $instanceId = instanceId_example; # String | ID of instance
+
+eval {
+    my $result = $api_instance->getWorkflowInputSchemaById(workflowId => $workflowId, instanceId => $instanceId);
+    print Dumper($result);
+};
+if ($@) {
+    warn "Exception when calling DefaultApi->getWorkflowInputSchemaById: $@\n";
+}
+
+ +
+
from __future__ import print_statement
+import time
+import openapi_client
+from openapi_client.rest import ApiException
+from pprint import pprint
+
+# Create an instance of the API class
+api_instance = openapi_client.DefaultApi()
+workflowId = workflowId_example # String | ID of the workflow to fetch (default to null)
+instanceId = instanceId_example # String | ID of instance (optional) (default to null)
+
+try:
+    api_response = api_instance.get_workflow_input_schema_by_id(workflowId, instanceId=instanceId)
+    pprint(api_response)
+except ApiException as e:
+    print("Exception when calling DefaultApi->getWorkflowInputSchemaById: %s\n" % e)
+
+ +
+
extern crate DefaultApi;
+
+pub fn main() {
+    let workflowId = workflowId_example; // String
+    let instanceId = instanceId_example; // String
+
+    let mut context = DefaultApi::Context::default();
+    let result = client.getWorkflowInputSchemaById(workflowId, instanceId, &context).wait();
+
+    println!("{:?}", result);
+}
+
+
+
+ +

Scopes

+ + +
+ +

Parameters

+ +
Path parameters
+ + + + + + + + + +
NameDescription
workflowId* + + +
+
+
+ + String + + +
+ID of the workflow to fetch +
+
+
+ Required +
+
+
+
+ + + + +
Query parameters
+ + + + + + + + + +
NameDescription
instanceId + + +
+
+
+ + String + + +
+ID of instance +
+
+
+
+
+ +

Responses

+

+

+ + + + + + +
+
+
+ +
+ +
+
+

+

+ + + + + + +
+
+
+ +
+ +
+
+
+
+
+
+
+
+

getWorkflowInstances

+

Get instances for a specific workflow

+
+
+
+

+

Retrieve an array of workflow executions (instances) for the given workflow

+

+
+
/v2/workflows/{workflowId}/instances
+

+

Usage and SDK Samples

+

+ + +
+
+
curl -X POST \
+ -H "Accept: application/json" \
+ -H "Content-Type: application/json" \
+ "http://localhost/v2/workflows/{workflowId}/instances" \
+ -d '{
+  "paginationInfo" : {
+    "offset" : 5.962133916683182,
+    "pageSize" : 1.4658129805029452,
+    "orderDirection" : "ASC",
+    "orderBy" : "orderBy",
+    "totalCount" : 5.637376656633329
+  },
+  "filters" : {
+    "filters" : [ null, null ],
+    "operator" : "AND"
+  }
+}'
+
+
+
+
import org.openapitools.client.*;
+import org.openapitools.client.auth.*;
+import org.openapitools.client.model.*;
+import org.openapitools.client.api.DefaultApi;
+
+import java.io.File;
+import java.util.*;
+
+public class DefaultApiExample {
+    public static void main(String[] args) {
+
+        // Create an instance of the API class
+        DefaultApi apiInstance = new DefaultApi();
+        String workflowId = workflowId_example; // String | ID of the workflow
+        SearchRequest searchRequest = ; // SearchRequest | 
+
+        try {
+            ProcessInstanceListResultDTO result = apiInstance.getWorkflowInstances(workflowId, searchRequest);
+            System.out.println(result);
+        } catch (ApiException e) {
+            System.err.println("Exception when calling DefaultApi#getWorkflowInstances");
+            e.printStackTrace();
+        }
+    }
+}
+
+
+ +
+
import 'package:openapi/api.dart';
+
+final api_instance = DefaultApi();
+
+final String workflowId = new String(); // String | ID of the workflow
+final SearchRequest searchRequest = new SearchRequest(); // SearchRequest | 
+
+try {
+    final result = await api_instance.getWorkflowInstances(workflowId, searchRequest);
+    print(result);
+} catch (e) {
+    print('Exception when calling DefaultApi->getWorkflowInstances: $e\n');
+}
+
+
+
+ +
+
import org.openapitools.client.api.DefaultApi;
+
+public class DefaultApiExample {
+    public static void main(String[] args) {
+        DefaultApi apiInstance = new DefaultApi();
+        String workflowId = workflowId_example; // String | ID of the workflow
+        SearchRequest searchRequest = ; // SearchRequest | 
+
+        try {
+            ProcessInstanceListResultDTO result = apiInstance.getWorkflowInstances(workflowId, searchRequest);
+            System.out.println(result);
+        } catch (ApiException e) {
+            System.err.println("Exception when calling DefaultApi#getWorkflowInstances");
+            e.printStackTrace();
+        }
+    }
+}
+
+ +
+

+
+// Create an instance of the API class
+DefaultApi *apiInstance = [[DefaultApi alloc] init];
+String *workflowId = workflowId_example; // ID of the workflow (default to null)
+SearchRequest *searchRequest = ; //  (optional)
+
+// Get instances for a specific workflow
+[apiInstance getWorkflowInstancesWith:workflowId
+    searchRequest:searchRequest
+              completionHandler: ^(ProcessInstanceListResultDTO output, NSError* error) {
+    if (output) {
+        NSLog(@"%@", output);
+    }
+    if (error) {
+        NSLog(@"Error: %@", error);
+    }
+}];
+
+
+ +
+
var OrchestratorPlugin = require('orchestrator_plugin');
+
+// Create an instance of the API class
+var api = new OrchestratorPlugin.DefaultApi()
+var workflowId = workflowId_example; // {String} ID of the workflow
+var opts = {
+  'searchRequest':  // {SearchRequest} 
+};
+
+var callback = function(error, data, response) {
+  if (error) {
+    console.error(error);
+  } else {
+    console.log('API called successfully. Returned data: ' + data);
+  }
+};
+api.getWorkflowInstances(workflowId, opts, callback);
+
+
+ + +
+
using System;
+using System.Diagnostics;
+using Org.OpenAPITools.Api;
+using Org.OpenAPITools.Client;
+using Org.OpenAPITools.Model;
+
+namespace Example
+{
+    public class getWorkflowInstancesExample
+    {
+        public void main()
+        {
+
+            // Create an instance of the API class
+            var apiInstance = new DefaultApi();
+            var workflowId = workflowId_example;  // String | ID of the workflow (default to null)
+            var searchRequest = new SearchRequest(); // SearchRequest |  (optional) 
+
+            try {
+                // Get instances for a specific workflow
+                ProcessInstanceListResultDTO result = apiInstance.getWorkflowInstances(workflowId, searchRequest);
+                Debug.WriteLine(result);
+            } catch (Exception e) {
+                Debug.Print("Exception when calling DefaultApi.getWorkflowInstances: " + e.Message );
+            }
+        }
+    }
+}
+
+
+ +
+
<?php
+require_once(__DIR__ . '/vendor/autoload.php');
+
+// Create an instance of the API class
+$api_instance = new OpenAPITools\Client\Api\DefaultApi();
+$workflowId = workflowId_example; // String | ID of the workflow
+$searchRequest = ; // SearchRequest | 
+
+try {
+    $result = $api_instance->getWorkflowInstances($workflowId, $searchRequest);
+    print_r($result);
+} catch (Exception $e) {
+    echo 'Exception when calling DefaultApi->getWorkflowInstances: ', $e->getMessage(), PHP_EOL;
+}
+?>
+
+ +
+
use Data::Dumper;
+use WWW::OPenAPIClient::Configuration;
+use WWW::OPenAPIClient::DefaultApi;
+
+# Create an instance of the API class
+my $api_instance = WWW::OPenAPIClient::DefaultApi->new();
+my $workflowId = workflowId_example; # String | ID of the workflow
+my $searchRequest = WWW::OPenAPIClient::Object::SearchRequest->new(); # SearchRequest | 
+
+eval {
+    my $result = $api_instance->getWorkflowInstances(workflowId => $workflowId, searchRequest => $searchRequest);
+    print Dumper($result);
+};
+if ($@) {
+    warn "Exception when calling DefaultApi->getWorkflowInstances: $@\n";
+}
+
+ +
+
from __future__ import print_statement
+import time
+import openapi_client
+from openapi_client.rest import ApiException
+from pprint import pprint
+
+# Create an instance of the API class
+api_instance = openapi_client.DefaultApi()
+workflowId = workflowId_example # String | ID of the workflow (default to null)
+searchRequest =  # SearchRequest |  (optional)
+
+try:
+    # Get instances for a specific workflow
+    api_response = api_instance.get_workflow_instances(workflowId, searchRequest=searchRequest)
+    pprint(api_response)
+except ApiException as e:
+    print("Exception when calling DefaultApi->getWorkflowInstances: %s\n" % e)
+
+ +
+
extern crate DefaultApi;
+
+pub fn main() {
+    let workflowId = workflowId_example; // String
+    let searchRequest = ; // SearchRequest
+
+    let mut context = DefaultApi::Context::default();
+    let result = client.getWorkflowInstances(workflowId, searchRequest, &context).wait();
+
+    println!("{:?}", result);
+}
+
+
+
+ +

Scopes

+ + +
+ +

Parameters

+ +
Path parameters
+ + + + + + + + + +
NameDescription
workflowId* + + +
+
+
+ + String + + +
+ID of the workflow +
+
+
+ Required +
+
+
+
+ + +
Body parameters
+ + + + + + + + + +
NameDescription
searchRequest +

Parameters for retrieving workflow instances

+ +
+
+ + + +

Responses

+

+

+ + + + + + +
+
+
+ +
+ +
+
+

+

+ + + + + + +
+
+
+ +
+ +
+
+
+
+
+
+
+
+

getWorkflowOverviewById

+

+
+
+
+

+

Returns the key fields of the workflow including data on the last run instance

+

+
+
/v2/workflows/{workflowId}/overview
+

+

Usage and SDK Samples

+

+ + +
+
+
curl -X GET \
+ -H "Accept: application/json" \
+ "http://localhost/v2/workflows/{workflowId}/overview"
+
+
+
+
import org.openapitools.client.*;
+import org.openapitools.client.auth.*;
+import org.openapitools.client.model.*;
+import org.openapitools.client.api.DefaultApi;
+
+import java.io.File;
+import java.util.*;
+
+public class DefaultApiExample {
+    public static void main(String[] args) {
+
+        // Create an instance of the API class
+        DefaultApi apiInstance = new DefaultApi();
+        String workflowId = workflowId_example; // String | Unique identifier of the workflow
+
+        try {
+            WorkflowOverviewDTO result = apiInstance.getWorkflowOverviewById(workflowId);
+            System.out.println(result);
+        } catch (ApiException e) {
+            System.err.println("Exception when calling DefaultApi#getWorkflowOverviewById");
+            e.printStackTrace();
+        }
+    }
+}
+
+
+ +
+
import 'package:openapi/api.dart';
+
+final api_instance = DefaultApi();
+
+final String workflowId = new String(); // String | Unique identifier of the workflow
+
+try {
+    final result = await api_instance.getWorkflowOverviewById(workflowId);
+    print(result);
+} catch (e) {
+    print('Exception when calling DefaultApi->getWorkflowOverviewById: $e\n');
+}
+
+
+
+ +
+
import org.openapitools.client.api.DefaultApi;
+
+public class DefaultApiExample {
+    public static void main(String[] args) {
+        DefaultApi apiInstance = new DefaultApi();
+        String workflowId = workflowId_example; // String | Unique identifier of the workflow
+
+        try {
+            WorkflowOverviewDTO result = apiInstance.getWorkflowOverviewById(workflowId);
+            System.out.println(result);
+        } catch (ApiException e) {
+            System.err.println("Exception when calling DefaultApi#getWorkflowOverviewById");
+            e.printStackTrace();
+        }
+    }
+}
+
+ +
+

+
+// Create an instance of the API class
+DefaultApi *apiInstance = [[DefaultApi alloc] init];
+String *workflowId = workflowId_example; // Unique identifier of the workflow (default to null)
+
+[apiInstance getWorkflowOverviewByIdWith:workflowId
+              completionHandler: ^(WorkflowOverviewDTO output, NSError* error) {
+    if (output) {
+        NSLog(@"%@", output);
+    }
+    if (error) {
+        NSLog(@"Error: %@", error);
+    }
+}];
+
+
+ +
+
var OrchestratorPlugin = require('orchestrator_plugin');
+
+// Create an instance of the API class
+var api = new OrchestratorPlugin.DefaultApi()
+var workflowId = workflowId_example; // {String} Unique identifier of the workflow
+
+var callback = function(error, data, response) {
+  if (error) {
+    console.error(error);
+  } else {
+    console.log('API called successfully. Returned data: ' + data);
+  }
+};
+api.getWorkflowOverviewById(workflowId, callback);
+
+
+ + +
+
using System;
+using System.Diagnostics;
+using Org.OpenAPITools.Api;
+using Org.OpenAPITools.Client;
+using Org.OpenAPITools.Model;
+
+namespace Example
+{
+    public class getWorkflowOverviewByIdExample
+    {
+        public void main()
+        {
+
+            // Create an instance of the API class
+            var apiInstance = new DefaultApi();
+            var workflowId = workflowId_example;  // String | Unique identifier of the workflow (default to null)
+
+            try {
+                WorkflowOverviewDTO result = apiInstance.getWorkflowOverviewById(workflowId);
+                Debug.WriteLine(result);
+            } catch (Exception e) {
+                Debug.Print("Exception when calling DefaultApi.getWorkflowOverviewById: " + e.Message );
+            }
+        }
+    }
+}
+
+
+ +
+
<?php
+require_once(__DIR__ . '/vendor/autoload.php');
+
+// Create an instance of the API class
+$api_instance = new OpenAPITools\Client\Api\DefaultApi();
+$workflowId = workflowId_example; // String | Unique identifier of the workflow
+
+try {
+    $result = $api_instance->getWorkflowOverviewById($workflowId);
+    print_r($result);
+} catch (Exception $e) {
+    echo 'Exception when calling DefaultApi->getWorkflowOverviewById: ', $e->getMessage(), PHP_EOL;
+}
+?>
+
+ +
+
use Data::Dumper;
+use WWW::OPenAPIClient::Configuration;
+use WWW::OPenAPIClient::DefaultApi;
+
+# Create an instance of the API class
+my $api_instance = WWW::OPenAPIClient::DefaultApi->new();
+my $workflowId = workflowId_example; # String | Unique identifier of the workflow
+
+eval {
+    my $result = $api_instance->getWorkflowOverviewById(workflowId => $workflowId);
+    print Dumper($result);
+};
+if ($@) {
+    warn "Exception when calling DefaultApi->getWorkflowOverviewById: $@\n";
+}
+
+ +
+
from __future__ import print_statement
+import time
+import openapi_client
+from openapi_client.rest import ApiException
+from pprint import pprint
+
+# Create an instance of the API class
+api_instance = openapi_client.DefaultApi()
+workflowId = workflowId_example # String | Unique identifier of the workflow (default to null)
+
+try:
+    api_response = api_instance.get_workflow_overview_by_id(workflowId)
+    pprint(api_response)
+except ApiException as e:
+    print("Exception when calling DefaultApi->getWorkflowOverviewById: %s\n" % e)
+
+ +
+
extern crate DefaultApi;
+
+pub fn main() {
+    let workflowId = workflowId_example; // String
+
+    let mut context = DefaultApi::Context::default();
+    let result = client.getWorkflowOverviewById(workflowId, &context).wait();
+
+    println!("{:?}", result);
+}
+
+
+
+ +

Scopes

+ + +
+ +

Parameters

+ +
Path parameters
+ + + + + + + + + +
NameDescription
workflowId* + + +
+
+
+ + String + + +
+Unique identifier of the workflow +
+
+
+ Required +
+
+
+
+ + + + + +

Responses

+

+

+ + + + + + +
+
+
+ +
+ +
+
+

+

+ + + + + + +
+
+
+ +
+ +
+
+
+
+
+
+
+
+

getWorkflowSourceById

+

+
+
+
+

+

Get the workflow's definition

+

+
+
/v2/workflows/{workflowId}/source
+

+

Usage and SDK Samples

+

+ + +
+
+
curl -X GET \
+ -H "Accept: text/plain,application/json" \
+ "http://localhost/v2/workflows/{workflowId}/source"
+
+
+
+
import org.openapitools.client.*;
+import org.openapitools.client.auth.*;
+import org.openapitools.client.model.*;
+import org.openapitools.client.api.DefaultApi;
+
+import java.io.File;
+import java.util.*;
+
+public class DefaultApiExample {
+    public static void main(String[] args) {
+
+        // Create an instance of the API class
+        DefaultApi apiInstance = new DefaultApi();
+        String workflowId = workflowId_example; // String | ID of the workflow to fetch
+
+        try {
+            'String' result = apiInstance.getWorkflowSourceById(workflowId);
+            System.out.println(result);
+        } catch (ApiException e) {
+            System.err.println("Exception when calling DefaultApi#getWorkflowSourceById");
+            e.printStackTrace();
+        }
+    }
+}
+
+
+ +
+
import 'package:openapi/api.dart';
+
+final api_instance = DefaultApi();
+
+final String workflowId = new String(); // String | ID of the workflow to fetch
+
+try {
+    final result = await api_instance.getWorkflowSourceById(workflowId);
+    print(result);
+} catch (e) {
+    print('Exception when calling DefaultApi->getWorkflowSourceById: $e\n');
+}
+
+
+
+ +
+
import org.openapitools.client.api.DefaultApi;
+
+public class DefaultApiExample {
+    public static void main(String[] args) {
+        DefaultApi apiInstance = new DefaultApi();
+        String workflowId = workflowId_example; // String | ID of the workflow to fetch
+
+        try {
+            'String' result = apiInstance.getWorkflowSourceById(workflowId);
+            System.out.println(result);
+        } catch (ApiException e) {
+            System.err.println("Exception when calling DefaultApi#getWorkflowSourceById");
+            e.printStackTrace();
+        }
+    }
+}
+
+ +
+

+
+// Create an instance of the API class
+DefaultApi *apiInstance = [[DefaultApi alloc] init];
+String *workflowId = workflowId_example; // ID of the workflow to fetch (default to null)
+
+[apiInstance getWorkflowSourceByIdWith:workflowId
+              completionHandler: ^('String' output, NSError* error) {
+    if (output) {
+        NSLog(@"%@", output);
+    }
+    if (error) {
+        NSLog(@"Error: %@", error);
+    }
+}];
+
+
+ +
+
var OrchestratorPlugin = require('orchestrator_plugin');
+
+// Create an instance of the API class
+var api = new OrchestratorPlugin.DefaultApi()
+var workflowId = workflowId_example; // {String} ID of the workflow to fetch
+
+var callback = function(error, data, response) {
+  if (error) {
+    console.error(error);
+  } else {
+    console.log('API called successfully. Returned data: ' + data);
+  }
+};
+api.getWorkflowSourceById(workflowId, callback);
+
+
+ + +
+
using System;
+using System.Diagnostics;
+using Org.OpenAPITools.Api;
+using Org.OpenAPITools.Client;
+using Org.OpenAPITools.Model;
+
+namespace Example
+{
+    public class getWorkflowSourceByIdExample
+    {
+        public void main()
+        {
+
+            // Create an instance of the API class
+            var apiInstance = new DefaultApi();
+            var workflowId = workflowId_example;  // String | ID of the workflow to fetch (default to null)
+
+            try {
+                'String' result = apiInstance.getWorkflowSourceById(workflowId);
+                Debug.WriteLine(result);
+            } catch (Exception e) {
+                Debug.Print("Exception when calling DefaultApi.getWorkflowSourceById: " + e.Message );
+            }
+        }
+    }
+}
+
+
+ +
+
<?php
+require_once(__DIR__ . '/vendor/autoload.php');
+
+// Create an instance of the API class
+$api_instance = new OpenAPITools\Client\Api\DefaultApi();
+$workflowId = workflowId_example; // String | ID of the workflow to fetch
+
+try {
+    $result = $api_instance->getWorkflowSourceById($workflowId);
+    print_r($result);
+} catch (Exception $e) {
+    echo 'Exception when calling DefaultApi->getWorkflowSourceById: ', $e->getMessage(), PHP_EOL;
+}
+?>
+
+ +
+
use Data::Dumper;
+use WWW::OPenAPIClient::Configuration;
+use WWW::OPenAPIClient::DefaultApi;
+
+# Create an instance of the API class
+my $api_instance = WWW::OPenAPIClient::DefaultApi->new();
+my $workflowId = workflowId_example; # String | ID of the workflow to fetch
+
+eval {
+    my $result = $api_instance->getWorkflowSourceById(workflowId => $workflowId);
+    print Dumper($result);
+};
+if ($@) {
+    warn "Exception when calling DefaultApi->getWorkflowSourceById: $@\n";
+}
+
+ +
+
from __future__ import print_statement
+import time
+import openapi_client
+from openapi_client.rest import ApiException
+from pprint import pprint
+
+# Create an instance of the API class
+api_instance = openapi_client.DefaultApi()
+workflowId = workflowId_example # String | ID of the workflow to fetch (default to null)
+
+try:
+    api_response = api_instance.get_workflow_source_by_id(workflowId)
+    pprint(api_response)
+except ApiException as e:
+    print("Exception when calling DefaultApi->getWorkflowSourceById: %s\n" % e)
+
+ +
+
extern crate DefaultApi;
+
+pub fn main() {
+    let workflowId = workflowId_example; // String
+
+    let mut context = DefaultApi::Context::default();
+    let result = client.getWorkflowSourceById(workflowId, &context).wait();
+
+    println!("{:?}", result);
+}
+
+
+
+ +

Scopes

+ + +
+ +

Parameters

+ +
Path parameters
+ + + + + + + + + +
NameDescription
workflowId* + + +
+
+
+ + String + + +
+ID of the workflow to fetch +
+
+
+ Required +
+
+
+
+ + + + + +

Responses

+

+

+ + + + + + +
+
+
+ +
+ +
+
+

+

+ + + + + + +
+
+
+ +
+ +
+
+
+
+
+
+
+
+

getWorkflowStatuses

+

Get workflow status list

+
+
+
+

+

Retrieve array with the status of all instances

+

+
+
/v2/workflows/instances/statuses
+

+

Usage and SDK Samples

+

+ + +
+
+
curl -X GET \
+ -H "Accept: application/json" \
+ "http://localhost/v2/workflows/instances/statuses"
+
+
+
+
import org.openapitools.client.*;
+import org.openapitools.client.auth.*;
+import org.openapitools.client.model.*;
+import org.openapitools.client.api.DefaultApi;
+
+import java.io.File;
+import java.util.*;
+
+public class DefaultApiExample {
+    public static void main(String[] args) {
+
+        // Create an instance of the API class
+        DefaultApi apiInstance = new DefaultApi();
+
+        try {
+            array[WorkflowRunStatusDTO] result = apiInstance.getWorkflowStatuses();
+            System.out.println(result);
+        } catch (ApiException e) {
+            System.err.println("Exception when calling DefaultApi#getWorkflowStatuses");
+            e.printStackTrace();
+        }
+    }
+}
+
+
+ +
+
import 'package:openapi/api.dart';
+
+final api_instance = DefaultApi();
+
+
+try {
+    final result = await api_instance.getWorkflowStatuses();
+    print(result);
+} catch (e) {
+    print('Exception when calling DefaultApi->getWorkflowStatuses: $e\n');
+}
+
+
+
+ +
+
import org.openapitools.client.api.DefaultApi;
+
+public class DefaultApiExample {
+    public static void main(String[] args) {
+        DefaultApi apiInstance = new DefaultApi();
+
+        try {
+            array[WorkflowRunStatusDTO] result = apiInstance.getWorkflowStatuses();
+            System.out.println(result);
+        } catch (ApiException e) {
+            System.err.println("Exception when calling DefaultApi#getWorkflowStatuses");
+            e.printStackTrace();
+        }
+    }
+}
+
+ +
+

+
+// Create an instance of the API class
+DefaultApi *apiInstance = [[DefaultApi alloc] init];
+
+// Get workflow status list
+[apiInstance getWorkflowStatusesWithCompletionHandler: 
+              ^(array[WorkflowRunStatusDTO] output, NSError* error) {
+    if (output) {
+        NSLog(@"%@", output);
+    }
+    if (error) {
+        NSLog(@"Error: %@", error);
+    }
+}];
+
+
+ +
+
var OrchestratorPlugin = require('orchestrator_plugin');
+
+// Create an instance of the API class
+var api = new OrchestratorPlugin.DefaultApi()
+var callback = function(error, data, response) {
+  if (error) {
+    console.error(error);
+  } else {
+    console.log('API called successfully. Returned data: ' + data);
+  }
+};
+api.getWorkflowStatuses(callback);
+
+
+ + +
+
using System;
+using System.Diagnostics;
+using Org.OpenAPITools.Api;
+using Org.OpenAPITools.Client;
+using Org.OpenAPITools.Model;
+
+namespace Example
+{
+    public class getWorkflowStatusesExample
+    {
+        public void main()
+        {
+
+            // Create an instance of the API class
+            var apiInstance = new DefaultApi();
+
+            try {
+                // Get workflow status list
+                array[WorkflowRunStatusDTO] result = apiInstance.getWorkflowStatuses();
+                Debug.WriteLine(result);
+            } catch (Exception e) {
+                Debug.Print("Exception when calling DefaultApi.getWorkflowStatuses: " + e.Message );
+            }
+        }
+    }
+}
+
+
+ +
+
<?php
+require_once(__DIR__ . '/vendor/autoload.php');
+
+// Create an instance of the API class
+$api_instance = new OpenAPITools\Client\Api\DefaultApi();
+
+try {
+    $result = $api_instance->getWorkflowStatuses();
+    print_r($result);
+} catch (Exception $e) {
+    echo 'Exception when calling DefaultApi->getWorkflowStatuses: ', $e->getMessage(), PHP_EOL;
+}
+?>
+
+ +
+
use Data::Dumper;
+use WWW::OPenAPIClient::Configuration;
+use WWW::OPenAPIClient::DefaultApi;
+
+# Create an instance of the API class
+my $api_instance = WWW::OPenAPIClient::DefaultApi->new();
+
+eval {
+    my $result = $api_instance->getWorkflowStatuses();
+    print Dumper($result);
+};
+if ($@) {
+    warn "Exception when calling DefaultApi->getWorkflowStatuses: $@\n";
+}
+
+ +
+
from __future__ import print_statement
+import time
+import openapi_client
+from openapi_client.rest import ApiException
+from pprint import pprint
+
+# Create an instance of the API class
+api_instance = openapi_client.DefaultApi()
+
+try:
+    # Get workflow status list
+    api_response = api_instance.get_workflow_statuses()
+    pprint(api_response)
+except ApiException as e:
+    print("Exception when calling DefaultApi->getWorkflowStatuses: %s\n" % e)
+
+ +
+
extern crate DefaultApi;
+
+pub fn main() {
+
+    let mut context = DefaultApi::Context::default();
+    let result = client.getWorkflowStatuses(&context).wait();
+
+    println!("{:?}", result);
+}
+
+
+
+ +

Scopes

+ + +
+ +

Parameters

+ + + + + + +

Responses

+

+

+ + + + + + +
+
+
+ +
+ +
+
+

+

+ + + + + + +
+
+
+ +
+ +
+
+
+
+
+
+
+
+

getWorkflowsOverview

+

+
+
+
+

+

Returns the key fields of the workflow including data on the last run instance

+

+
+
/v2/workflows/overview
+

+

Usage and SDK Samples

+

+ + +
+
+
curl -X POST \
+ -H "Accept: application/json" \
+ -H "Content-Type: application/json" \
+ "http://localhost/v2/workflows/overview" \
+ -d '{
+  "paginationInfo" : {
+    "offset" : 5.962133916683182,
+    "pageSize" : 1.4658129805029452,
+    "orderDirection" : "ASC",
+    "orderBy" : "orderBy",
+    "totalCount" : 5.637376656633329
+  },
+  "filters" : {
+    "filters" : [ null, null ],
+    "operator" : "AND"
+  }
+}'
+
+
+
+
import org.openapitools.client.*;
+import org.openapitools.client.auth.*;
+import org.openapitools.client.model.*;
+import org.openapitools.client.api.DefaultApi;
+
+import java.io.File;
+import java.util.*;
+
+public class DefaultApiExample {
+    public static void main(String[] args) {
+
+        // Create an instance of the API class
+        DefaultApi apiInstance = new DefaultApi();
+        SearchRequest searchRequest = ; // SearchRequest | 
+
+        try {
+            WorkflowOverviewListResultDTO result = apiInstance.getWorkflowsOverview(searchRequest);
+            System.out.println(result);
+        } catch (ApiException e) {
+            System.err.println("Exception when calling DefaultApi#getWorkflowsOverview");
+            e.printStackTrace();
+        }
+    }
+}
+
+
+ +
+
import 'package:openapi/api.dart';
+
+final api_instance = DefaultApi();
+
+final SearchRequest searchRequest = new SearchRequest(); // SearchRequest | 
+
+try {
+    final result = await api_instance.getWorkflowsOverview(searchRequest);
+    print(result);
+} catch (e) {
+    print('Exception when calling DefaultApi->getWorkflowsOverview: $e\n');
+}
+
+
+
+ +
+
import org.openapitools.client.api.DefaultApi;
+
+public class DefaultApiExample {
+    public static void main(String[] args) {
+        DefaultApi apiInstance = new DefaultApi();
+        SearchRequest searchRequest = ; // SearchRequest | 
+
+        try {
+            WorkflowOverviewListResultDTO result = apiInstance.getWorkflowsOverview(searchRequest);
+            System.out.println(result);
+        } catch (ApiException e) {
+            System.err.println("Exception when calling DefaultApi#getWorkflowsOverview");
+            e.printStackTrace();
+        }
+    }
+}
+
+ +
+

+
+// Create an instance of the API class
+DefaultApi *apiInstance = [[DefaultApi alloc] init];
+SearchRequest *searchRequest = ; //  (optional)
+
+[apiInstance getWorkflowsOverviewWith:searchRequest
+              completionHandler: ^(WorkflowOverviewListResultDTO output, NSError* error) {
+    if (output) {
+        NSLog(@"%@", output);
+    }
+    if (error) {
+        NSLog(@"Error: %@", error);
+    }
+}];
+
+
+ +
+
var OrchestratorPlugin = require('orchestrator_plugin');
+
+// Create an instance of the API class
+var api = new OrchestratorPlugin.DefaultApi()
+var opts = {
+  'searchRequest':  // {SearchRequest} 
+};
+
+var callback = function(error, data, response) {
+  if (error) {
+    console.error(error);
+  } else {
+    console.log('API called successfully. Returned data: ' + data);
+  }
+};
+api.getWorkflowsOverview(opts, callback);
+
+
+ + +
+
using System;
+using System.Diagnostics;
+using Org.OpenAPITools.Api;
+using Org.OpenAPITools.Client;
+using Org.OpenAPITools.Model;
+
+namespace Example
+{
+    public class getWorkflowsOverviewExample
+    {
+        public void main()
+        {
+
+            // Create an instance of the API class
+            var apiInstance = new DefaultApi();
+            var searchRequest = new SearchRequest(); // SearchRequest |  (optional) 
+
+            try {
+                WorkflowOverviewListResultDTO result = apiInstance.getWorkflowsOverview(searchRequest);
+                Debug.WriteLine(result);
+            } catch (Exception e) {
+                Debug.Print("Exception when calling DefaultApi.getWorkflowsOverview: " + e.Message );
+            }
+        }
+    }
+}
+
+
+ +
+
<?php
+require_once(__DIR__ . '/vendor/autoload.php');
+
+// Create an instance of the API class
+$api_instance = new OpenAPITools\Client\Api\DefaultApi();
+$searchRequest = ; // SearchRequest | 
+
+try {
+    $result = $api_instance->getWorkflowsOverview($searchRequest);
+    print_r($result);
+} catch (Exception $e) {
+    echo 'Exception when calling DefaultApi->getWorkflowsOverview: ', $e->getMessage(), PHP_EOL;
+}
+?>
+
+ +
+
use Data::Dumper;
+use WWW::OPenAPIClient::Configuration;
+use WWW::OPenAPIClient::DefaultApi;
+
+# Create an instance of the API class
+my $api_instance = WWW::OPenAPIClient::DefaultApi->new();
+my $searchRequest = WWW::OPenAPIClient::Object::SearchRequest->new(); # SearchRequest | 
+
+eval {
+    my $result = $api_instance->getWorkflowsOverview(searchRequest => $searchRequest);
+    print Dumper($result);
+};
+if ($@) {
+    warn "Exception when calling DefaultApi->getWorkflowsOverview: $@\n";
+}
+
+ +
+
from __future__ import print_statement
+import time
+import openapi_client
+from openapi_client.rest import ApiException
+from pprint import pprint
+
+# Create an instance of the API class
+api_instance = openapi_client.DefaultApi()
+searchRequest =  # SearchRequest |  (optional)
+
+try:
+    api_response = api_instance.get_workflows_overview(searchRequest=searchRequest)
+    pprint(api_response)
+except ApiException as e:
+    print("Exception when calling DefaultApi->getWorkflowsOverview: %s\n" % e)
+
+ +
+
extern crate DefaultApi;
+
+pub fn main() {
+    let searchRequest = ; // SearchRequest
+
+    let mut context = DefaultApi::Context::default();
+    let result = client.getWorkflowsOverview(searchRequest, &context).wait();
+
+    println!("{:?}", result);
+}
+
+
+
+ +

Scopes

+ + +
+ +

Parameters

+ + + +
Body parameters
+ + + + + + + + + +
NameDescription
searchRequest +

Pagination and filters

+ +
+
+ + + +

Responses

+

+

+ + + + + + +
+
+
+ +
+ +
+
+

+

+ + + + + + +
+
+
+ +
+ +
+
+
+
+
+
+
+
+

retriggerInstance

+

Retrigger an instance

+
+
+
+

+

Retrigger an instance

+

+
+
/v2/workflows/{workflowId}/{instanceId}/retrigger
+

+

Usage and SDK Samples

+

+ + +
+
+
curl -X POST \
+ -H "Accept: application/json" \
+ "http://localhost/v2/workflows/{workflowId}/{instanceId}/retrigger"
+
+
+
+
import org.openapitools.client.*;
+import org.openapitools.client.auth.*;
+import org.openapitools.client.model.*;
+import org.openapitools.client.api.DefaultApi;
+
+import java.io.File;
+import java.util.*;
+
+public class DefaultApiExample {
+    public static void main(String[] args) {
+
+        // Create an instance of the API class
+        DefaultApi apiInstance = new DefaultApi();
+        String workflowId = workflowId_example; // String | ID of the workflow
+        String instanceId = instanceId_example; // String | ID of the instance to retrigger
+
+        try {
+            Object result = apiInstance.retriggerInstance(workflowId, instanceId);
+            System.out.println(result);
+        } catch (ApiException e) {
+            System.err.println("Exception when calling DefaultApi#retriggerInstance");
+            e.printStackTrace();
+        }
+    }
+}
+
+
+ +
+
import 'package:openapi/api.dart';
+
+final api_instance = DefaultApi();
+
+final String workflowId = new String(); // String | ID of the workflow
+final String instanceId = new String(); // String | ID of the instance to retrigger
+
+try {
+    final result = await api_instance.retriggerInstance(workflowId, instanceId);
+    print(result);
+} catch (e) {
+    print('Exception when calling DefaultApi->retriggerInstance: $e\n');
+}
+
+
+
+ +
+
import org.openapitools.client.api.DefaultApi;
+
+public class DefaultApiExample {
+    public static void main(String[] args) {
+        DefaultApi apiInstance = new DefaultApi();
+        String workflowId = workflowId_example; // String | ID of the workflow
+        String instanceId = instanceId_example; // String | ID of the instance to retrigger
+
+        try {
+            Object result = apiInstance.retriggerInstance(workflowId, instanceId);
+            System.out.println(result);
+        } catch (ApiException e) {
+            System.err.println("Exception when calling DefaultApi#retriggerInstance");
+            e.printStackTrace();
+        }
+    }
+}
+
+ +
+

+
+// Create an instance of the API class
+DefaultApi *apiInstance = [[DefaultApi alloc] init];
+String *workflowId = workflowId_example; // ID of the workflow (default to null)
+String *instanceId = instanceId_example; // ID of the instance to retrigger (default to null)
+
+// Retrigger an instance
+[apiInstance retriggerInstanceWith:workflowId
+    instanceId:instanceId
+              completionHandler: ^(Object output, NSError* error) {
+    if (output) {
+        NSLog(@"%@", output);
+    }
+    if (error) {
+        NSLog(@"Error: %@", error);
+    }
+}];
+
+
+ +
+
var OrchestratorPlugin = require('orchestrator_plugin');
+
+// Create an instance of the API class
+var api = new OrchestratorPlugin.DefaultApi()
+var workflowId = workflowId_example; // {String} ID of the workflow
+var instanceId = instanceId_example; // {String} ID of the instance to retrigger
+
+var callback = function(error, data, response) {
+  if (error) {
+    console.error(error);
+  } else {
+    console.log('API called successfully. Returned data: ' + data);
+  }
+};
+api.retriggerInstance(workflowId, instanceId, callback);
+
+
+ + +
+
using System;
+using System.Diagnostics;
+using Org.OpenAPITools.Api;
+using Org.OpenAPITools.Client;
+using Org.OpenAPITools.Model;
+
+namespace Example
+{
+    public class retriggerInstanceExample
+    {
+        public void main()
+        {
+
+            // Create an instance of the API class
+            var apiInstance = new DefaultApi();
+            var workflowId = workflowId_example;  // String | ID of the workflow (default to null)
+            var instanceId = instanceId_example;  // String | ID of the instance to retrigger (default to null)
+
+            try {
+                // Retrigger an instance
+                Object result = apiInstance.retriggerInstance(workflowId, instanceId);
+                Debug.WriteLine(result);
+            } catch (Exception e) {
+                Debug.Print("Exception when calling DefaultApi.retriggerInstance: " + e.Message );
+            }
+        }
+    }
+}
+
+
+ +
+
<?php
+require_once(__DIR__ . '/vendor/autoload.php');
+
+// Create an instance of the API class
+$api_instance = new OpenAPITools\Client\Api\DefaultApi();
+$workflowId = workflowId_example; // String | ID of the workflow
+$instanceId = instanceId_example; // String | ID of the instance to retrigger
+
+try {
+    $result = $api_instance->retriggerInstance($workflowId, $instanceId);
+    print_r($result);
+} catch (Exception $e) {
+    echo 'Exception when calling DefaultApi->retriggerInstance: ', $e->getMessage(), PHP_EOL;
+}
+?>
+
+ +
+
use Data::Dumper;
+use WWW::OPenAPIClient::Configuration;
+use WWW::OPenAPIClient::DefaultApi;
+
+# Create an instance of the API class
+my $api_instance = WWW::OPenAPIClient::DefaultApi->new();
+my $workflowId = workflowId_example; # String | ID of the workflow
+my $instanceId = instanceId_example; # String | ID of the instance to retrigger
+
+eval {
+    my $result = $api_instance->retriggerInstance(workflowId => $workflowId, instanceId => $instanceId);
+    print Dumper($result);
+};
+if ($@) {
+    warn "Exception when calling DefaultApi->retriggerInstance: $@\n";
+}
+
+ +
+
from __future__ import print_statement
+import time
+import openapi_client
+from openapi_client.rest import ApiException
+from pprint import pprint
+
+# Create an instance of the API class
+api_instance = openapi_client.DefaultApi()
+workflowId = workflowId_example # String | ID of the workflow (default to null)
+instanceId = instanceId_example # String | ID of the instance to retrigger (default to null)
+
+try:
+    # Retrigger an instance
+    api_response = api_instance.retrigger_instance(workflowId, instanceId)
+    pprint(api_response)
+except ApiException as e:
+    print("Exception when calling DefaultApi->retriggerInstance: %s\n" % e)
+
+ +
+
extern crate DefaultApi;
+
+pub fn main() {
+    let workflowId = workflowId_example; // String
+    let instanceId = instanceId_example; // String
+
+    let mut context = DefaultApi::Context::default();
+    let result = client.retriggerInstance(workflowId, instanceId, &context).wait();
+
+    println!("{:?}", result);
+}
+
+
+
+ +

Scopes

+ + +
+ +

Parameters

+ +
Path parameters
+ + + + + + + + + + + + + +
NameDescription
workflowId* + + +
+
+
+ + String + + +
+ID of the workflow +
+
+
+ Required +
+
+
+
instanceId* + + +
+
+
+ + String + + +
+ID of the instance to retrigger +
+
+
+ Required +
+
+
+
+ + + + + +

Responses

+

+

+ + + + + + +
+
+
+ +
+ +
+
+

+

+ + + + + + +
+
+
+ +
+ +
+
+
+
+
+
+
+ +
+
+
+ + + + + + + + + + + + + + diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/.openapi-generator-ignore b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/.openapi-generator-ignore new file mode 100644 index 00000000..7484ee59 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/.openapi-generator-ignore @@ -0,0 +1,23 @@ +# OpenAPI Generator Ignore +# Generated by openapi-generator https://github.com/openapitools/openapi-generator + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/.openapi-generator/FILES b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/.openapi-generator/FILES new file mode 100644 index 00000000..e774366e --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/.openapi-generator/FILES @@ -0,0 +1,34 @@ +.openapi-generator-ignore +Apis/DefaultApi.md +Models/AssessedProcessInstanceDTO.md +Models/ErrorResponse.md +Models/ExecuteWorkflowRequestDTO.md +Models/ExecuteWorkflowResponseDTO.md +Models/FieldFilter.md +Models/FieldFilter_value.md +Models/Filter.md +Models/GetInstancesRequest.md +Models/GetOverviewsRequestParams.md +Models/InputSchemaResponseDTO.md +Models/LogicalFilter.md +Models/NodeInstanceDTO.md +Models/PaginationInfoDTO.md +Models/ProcessInstanceDTO.md +Models/ProcessInstanceErrorDTO.md +Models/ProcessInstanceListResultDTO.md +Models/ProcessInstanceStatusDTO.md +Models/SearchRequest.md +Models/WorkflowCategoryDTO.md +Models/WorkflowDTO.md +Models/WorkflowDataDTO.md +Models/WorkflowFormatDTO.md +Models/WorkflowListResultDTO.md +Models/WorkflowOverviewDTO.md +Models/WorkflowOverviewListResultDTO.md +Models/WorkflowProgressDTO.md +Models/WorkflowResultDTO.md +Models/WorkflowResultDTO_nextWorkflows_inner.md +Models/WorkflowResultDTO_outputs_inner.md +Models/WorkflowResultDTO_outputs_inner_value.md +Models/WorkflowRunStatusDTO.md +README.md diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/.openapi-generator/VERSION b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/.openapi-generator/VERSION new file mode 100644 index 00000000..8b23b8d4 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/.openapi-generator/VERSION @@ -0,0 +1 @@ +7.3.0 \ No newline at end of file diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Apis/DefaultApi.md b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Apis/DefaultApi.md new file mode 100644 index 00000000..0d275149 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Apis/DefaultApi.md @@ -0,0 +1,318 @@ +# DefaultApi + +All URIs are relative to *http://localhost* + +| Method | HTTP request | Description | +|------------- | ------------- | -------------| +| [**abortWorkflow**](DefaultApi.md#abortWorkflow) | **DELETE** /v2/workflows/instances/{instanceId}/abort | Abort a workflow instance | +| [**executeWorkflow**](DefaultApi.md#executeWorkflow) | **POST** /v2/workflows/{workflowId}/execute | Execute a workflow | +| [**getInstanceById**](DefaultApi.md#getInstanceById) | **GET** /v2/workflows/instances/{instanceId} | Get Workflow Instance by ID | +| [**getInstances**](DefaultApi.md#getInstances) | **POST** /v2/workflows/instances | Get instances | +| [**getWorkflowInputSchemaById**](DefaultApi.md#getWorkflowInputSchemaById) | **GET** /v2/workflows/{workflowId}/inputSchema | | +| [**getWorkflowInstances**](DefaultApi.md#getWorkflowInstances) | **POST** /v2/workflows/{workflowId}/instances | Get instances for a specific workflow | +| [**getWorkflowOverviewById**](DefaultApi.md#getWorkflowOverviewById) | **GET** /v2/workflows/{workflowId}/overview | | +| [**getWorkflowSourceById**](DefaultApi.md#getWorkflowSourceById) | **GET** /v2/workflows/{workflowId}/source | | +| [**getWorkflowStatuses**](DefaultApi.md#getWorkflowStatuses) | **GET** /v2/workflows/instances/statuses | Get workflow status list | +| [**getWorkflowsOverview**](DefaultApi.md#getWorkflowsOverview) | **POST** /v2/workflows/overview | | +| [**retriggerInstance**](DefaultApi.md#retriggerInstance) | **POST** /v2/workflows/{workflowId}/{instanceId}/retrigger | Retrigger an instance | + + + +# **abortWorkflow** +> String abortWorkflow(instanceId) + +Abort a workflow instance + + Aborts a workflow instance identified by the provided instanceId. + +### Parameters + +|Name | Type | Description | Notes | +|------------- | ------------- | ------------- | -------------| +| **instanceId** | **String**| The identifier of the workflow instance to abort. | [default to null] | + +### Return type + +**String** + +### Authorization + +No authorization required + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: text/plain, application/json + + +# **executeWorkflow** +> ExecuteWorkflowResponseDTO executeWorkflow(workflowId, ExecuteWorkflowRequestDTO) + +Execute a workflow + + Execute a workflow + +### Parameters + +|Name | Type | Description | Notes | +|------------- | ------------- | ------------- | -------------| +| **workflowId** | **String**| ID of the workflow to execute | [default to null] | +| **ExecuteWorkflowRequestDTO** | [**ExecuteWorkflowRequestDTO**](../Models/ExecuteWorkflowRequestDTO.md)| | | + +### Return type + +[**ExecuteWorkflowResponseDTO**](../Models/ExecuteWorkflowResponseDTO.md) + +### Authorization + +No authorization required + +### HTTP request headers + +- **Content-Type**: application/json +- **Accept**: application/json + + +# **getInstanceById** +> AssessedProcessInstanceDTO getInstanceById(instanceId, includeAssessment) + +Get Workflow Instance by ID + + Get a workflow execution/run (instance) + +### Parameters + +|Name | Type | Description | Notes | +|------------- | ------------- | ------------- | -------------| +| **instanceId** | **String**| ID of the workflow instance | [default to null] | +| **includeAssessment** | **Boolean**| Whether to include assessment | [optional] [default to false] | + +### Return type + +[**AssessedProcessInstanceDTO**](../Models/AssessedProcessInstanceDTO.md) + +### Authorization + +No authorization required + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json + + +# **getInstances** +> ProcessInstanceListResultDTO getInstances(GetInstancesRequest) + +Get instances + + Retrieve an array of workflow executions (instances) + +### Parameters + +|Name | Type | Description | Notes | +|------------- | ------------- | ------------- | -------------| +| **GetInstancesRequest** | [**GetInstancesRequest**](../Models/GetInstancesRequest.md)| Parameters for retrieving instances | [optional] | + +### Return type + +[**ProcessInstanceListResultDTO**](../Models/ProcessInstanceListResultDTO.md) + +### Authorization + +No authorization required + +### HTTP request headers + +- **Content-Type**: application/json +- **Accept**: application/json + + +# **getWorkflowInputSchemaById** +> InputSchemaResponseDTO getWorkflowInputSchemaById(workflowId, instanceId) + + + + Get the workflow input schema. It defines the input fields of the workflow + +### Parameters + +|Name | Type | Description | Notes | +|------------- | ------------- | ------------- | -------------| +| **workflowId** | **String**| ID of the workflow to fetch | [default to null] | +| **instanceId** | **String**| ID of instance | [optional] [default to null] | + +### Return type + +[**InputSchemaResponseDTO**](../Models/InputSchemaResponseDTO.md) + +### Authorization + +No authorization required + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json + + +# **getWorkflowInstances** +> ProcessInstanceListResultDTO getWorkflowInstances(workflowId, SearchRequest) + +Get instances for a specific workflow + + Retrieve an array of workflow executions (instances) for the given workflow + +### Parameters + +|Name | Type | Description | Notes | +|------------- | ------------- | ------------- | -------------| +| **workflowId** | **String**| ID of the workflow | [default to null] | +| **SearchRequest** | [**SearchRequest**](../Models/SearchRequest.md)| Parameters for retrieving workflow instances | [optional] | + +### Return type + +[**ProcessInstanceListResultDTO**](../Models/ProcessInstanceListResultDTO.md) + +### Authorization + +No authorization required + +### HTTP request headers + +- **Content-Type**: application/json +- **Accept**: application/json + + +# **getWorkflowOverviewById** +> WorkflowOverviewDTO getWorkflowOverviewById(workflowId) + + + + Returns the key fields of the workflow including data on the last run instance + +### Parameters + +|Name | Type | Description | Notes | +|------------- | ------------- | ------------- | -------------| +| **workflowId** | **String**| Unique identifier of the workflow | [default to null] | + +### Return type + +[**WorkflowOverviewDTO**](../Models/WorkflowOverviewDTO.md) + +### Authorization + +No authorization required + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json + + +# **getWorkflowSourceById** +> String getWorkflowSourceById(workflowId) + + + + Get the workflow's definition + +### Parameters + +|Name | Type | Description | Notes | +|------------- | ------------- | ------------- | -------------| +| **workflowId** | **String**| ID of the workflow to fetch | [default to null] | + +### Return type + +**String** + +### Authorization + +No authorization required + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: text/plain, application/json + + +# **getWorkflowStatuses** +> List getWorkflowStatuses() + +Get workflow status list + + Retrieve array with the status of all instances + +### Parameters +This endpoint does not need any parameter. + +### Return type + +[**List**](../Models/WorkflowRunStatusDTO.md) + +### Authorization + +No authorization required + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json + + +# **getWorkflowsOverview** +> WorkflowOverviewListResultDTO getWorkflowsOverview(SearchRequest) + + + + Returns the key fields of the workflow including data on the last run instance + +### Parameters + +|Name | Type | Description | Notes | +|------------- | ------------- | ------------- | -------------| +| **SearchRequest** | [**SearchRequest**](../Models/SearchRequest.md)| Pagination and filters | [optional] | + +### Return type + +[**WorkflowOverviewListResultDTO**](../Models/WorkflowOverviewListResultDTO.md) + +### Authorization + +No authorization required + +### HTTP request headers + +- **Content-Type**: application/json +- **Accept**: application/json + + +# **retriggerInstance** +> Object retriggerInstance(workflowId, instanceId) + +Retrigger an instance + + Retrigger an instance + +### Parameters + +|Name | Type | Description | Notes | +|------------- | ------------- | ------------- | -------------| +| **workflowId** | **String**| ID of the workflow | [default to null] | +| **instanceId** | **String**| ID of the instance to retrigger | [default to null] | + +### Return type + +**Object** + +### Authorization + +No authorization required + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json + diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/AssessedProcessInstanceDTO.md b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/AssessedProcessInstanceDTO.md new file mode 100644 index 00000000..885be91f --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/AssessedProcessInstanceDTO.md @@ -0,0 +1,10 @@ +# AssessedProcessInstanceDTO +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +| **instance** | [**ProcessInstanceDTO**](ProcessInstanceDTO.md) | | [default to null] | +| **assessedBy** | [**ProcessInstanceDTO**](ProcessInstanceDTO.md) | | [optional] [default to null] | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/ErrorResponse.md b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/ErrorResponse.md new file mode 100644 index 00000000..1a22cc3c --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/ErrorResponse.md @@ -0,0 +1,10 @@ +# ErrorResponse +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +| **message** | **String** | A string providing a concise and human-readable description of the encountered error. This field is required in the ErrorResponse object. | [default to internal server error] | +| **additionalInfo** | **String** | An optional field that can contain additional information or context about the error. It provides flexibility for including extra details based on specific error scenarios. | [optional] [default to null] | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/ExecuteWorkflowRequestDTO.md b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/ExecuteWorkflowRequestDTO.md new file mode 100644 index 00000000..5aad2bd3 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/ExecuteWorkflowRequestDTO.md @@ -0,0 +1,9 @@ +# ExecuteWorkflowRequestDTO +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +| **inputData** | [**Object**](.md) | | [default to null] | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/ExecuteWorkflowResponseDTO.md b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/ExecuteWorkflowResponseDTO.md new file mode 100644 index 00000000..1058e878 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/ExecuteWorkflowResponseDTO.md @@ -0,0 +1,9 @@ +# ExecuteWorkflowResponseDTO +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +| **id** | **String** | | [default to null] | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/FieldFilter.md b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/FieldFilter.md new file mode 100644 index 00000000..e0ce280f --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/FieldFilter.md @@ -0,0 +1,11 @@ +# FieldFilter +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +| **field** | **String** | | [default to null] | +| **operator** | **String** | | [default to null] | +| **value** | [**FieldFilter_value**](FieldFilter_value.md) | | [default to null] | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/FieldFilter_value.md b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/FieldFilter_value.md new file mode 100644 index 00000000..7d9890ad --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/FieldFilter_value.md @@ -0,0 +1,8 @@ +# FieldFilter_value +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/Filter.md b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/Filter.md new file mode 100644 index 00000000..cd24e64b --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/Filter.md @@ -0,0 +1,12 @@ +# Filter +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +| **operator** | [**oas_any_type_not_mapped**](AnyType.md) | | [default to null] | +| **filters** | [**oas_any_type_not_mapped**](.md) | | [default to null] | +| **field** | [**oas_any_type_not_mapped**](.md) | | [default to null] | +| **value** | [**FieldFilter_value**](FieldFilter_value.md) | | [default to null] | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/GetInstancesRequest.md b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/GetInstancesRequest.md new file mode 100644 index 00000000..ccd82afa --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/GetInstancesRequest.md @@ -0,0 +1,10 @@ +# GetInstancesRequest +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +| **paginationInfo** | [**PaginationInfoDTO**](PaginationInfoDTO.md) | | [optional] [default to null] | +| **filters** | [**SearchRequest**](SearchRequest.md) | | [optional] [default to null] | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/GetOverviewsRequestParams.md b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/GetOverviewsRequestParams.md new file mode 100644 index 00000000..4765b258 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/GetOverviewsRequestParams.md @@ -0,0 +1,10 @@ +# GetOverviewsRequestParams +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +| **paginationInfo** | [**PaginationInfoDTO**](PaginationInfoDTO.md) | | [optional] [default to null] | +| **filters** | [**SearchRequest**](SearchRequest.md) | | [optional] [default to null] | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/InputSchemaResponseDTO.md b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/InputSchemaResponseDTO.md new file mode 100644 index 00000000..c9309f5d --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/InputSchemaResponseDTO.md @@ -0,0 +1,10 @@ +# InputSchemaResponseDTO +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +| **inputSchema** | [**Object**](.md) | | [optional] [default to null] | +| **data** | [**Object**](.md) | | [optional] [default to null] | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/LogicalFilter.md b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/LogicalFilter.md new file mode 100644 index 00000000..d9aab1e8 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/LogicalFilter.md @@ -0,0 +1,10 @@ +# LogicalFilter +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +| **operator** | **String** | | [default to null] | +| **filters** | [**List**](Filter.md) | | [default to null] | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/NodeInstanceDTO.md b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/NodeInstanceDTO.md new file mode 100644 index 00000000..c0f472d4 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/NodeInstanceDTO.md @@ -0,0 +1,16 @@ +# NodeInstanceDTO +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +| **\_\_typename** | **String** | Type name | [optional] [default to NodeInstance] | +| **id** | **String** | Node instance ID | [default to null] | +| **name** | **String** | Node name | [optional] [default to null] | +| **type** | **String** | Node type | [optional] [default to null] | +| **enter** | **String** | Date when the node was entered | [optional] [default to null] | +| **exit** | **String** | Date when the node was exited (optional) | [optional] [default to null] | +| **definitionId** | **String** | Definition ID | [optional] [default to null] | +| **nodeId** | **String** | Node ID | [optional] [default to null] | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/PaginationInfoDTO.md b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/PaginationInfoDTO.md new file mode 100644 index 00000000..3b2200a6 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/PaginationInfoDTO.md @@ -0,0 +1,13 @@ +# PaginationInfoDTO +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +| **pageSize** | **BigDecimal** | | [optional] [default to null] | +| **offset** | **BigDecimal** | | [optional] [default to null] | +| **totalCount** | **BigDecimal** | | [optional] [default to null] | +| **orderDirection** | **String** | | [optional] [default to null] | +| **orderBy** | **String** | | [optional] [default to null] | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/ProcessInstanceDTO.md b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/ProcessInstanceDTO.md new file mode 100644 index 00000000..e09ee615 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/ProcessInstanceDTO.md @@ -0,0 +1,23 @@ +# ProcessInstanceDTO +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +| **id** | **String** | | [default to null] | +| **processId** | **String** | | [default to null] | +| **processName** | **String** | | [optional] [default to null] | +| **status** | [**ProcessInstanceStatusDTO**](ProcessInstanceStatusDTO.md) | | [optional] [default to null] | +| **endpoint** | **String** | | [optional] [default to null] | +| **serviceUrl** | **String** | | [optional] [default to null] | +| **start** | **String** | | [optional] [default to null] | +| **end** | **String** | | [optional] [default to null] | +| **duration** | **String** | | [optional] [default to null] | +| **category** | [**WorkflowCategoryDTO**](WorkflowCategoryDTO.md) | | [optional] [default to null] | +| **description** | **String** | | [optional] [default to null] | +| **workflowdata** | [**WorkflowDataDTO**](WorkflowDataDTO.md) | | [optional] [default to null] | +| **businessKey** | **String** | | [optional] [default to null] | +| **nodes** | [**List**](NodeInstanceDTO.md) | | [default to null] | +| **error** | [**ProcessInstanceErrorDTO**](ProcessInstanceErrorDTO.md) | | [optional] [default to null] | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/ProcessInstanceErrorDTO.md b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/ProcessInstanceErrorDTO.md new file mode 100644 index 00000000..c21f9ce2 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/ProcessInstanceErrorDTO.md @@ -0,0 +1,11 @@ +# ProcessInstanceErrorDTO +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +| **\_\_typename** | **String** | Type name | [optional] [default to ProcessInstanceError] | +| **nodeDefinitionId** | **String** | Node definition ID | [default to null] | +| **message** | **String** | Error message (optional) | [optional] [default to null] | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/ProcessInstanceListResultDTO.md b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/ProcessInstanceListResultDTO.md new file mode 100644 index 00000000..f6d3ecb0 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/ProcessInstanceListResultDTO.md @@ -0,0 +1,10 @@ +# ProcessInstanceListResultDTO +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +| **items** | [**List**](ProcessInstanceDTO.md) | | [optional] [default to null] | +| **paginationInfo** | [**PaginationInfoDTO**](PaginationInfoDTO.md) | | [optional] [default to null] | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/ProcessInstanceStatusDTO.md b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/ProcessInstanceStatusDTO.md new file mode 100644 index 00000000..04a01f90 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/ProcessInstanceStatusDTO.md @@ -0,0 +1,8 @@ +# ProcessInstanceStatusDTO +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/SearchRequest.md b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/SearchRequest.md new file mode 100644 index 00000000..086b2924 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/SearchRequest.md @@ -0,0 +1,10 @@ +# SearchRequest +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +| **filters** | [**Filter**](Filter.md) | | [optional] [default to null] | +| **paginationInfo** | [**PaginationInfoDTO**](PaginationInfoDTO.md) | | [optional] [default to null] | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/WorkflowCategoryDTO.md b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/WorkflowCategoryDTO.md new file mode 100644 index 00000000..8c4a5e4d --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/WorkflowCategoryDTO.md @@ -0,0 +1,8 @@ +# WorkflowCategoryDTO +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/WorkflowDTO.md b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/WorkflowDTO.md new file mode 100644 index 00000000..9b8de669 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/WorkflowDTO.md @@ -0,0 +1,14 @@ +# WorkflowDTO +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +| **id** | **String** | Workflow unique identifier | [default to null] | +| **name** | **String** | Workflow name | [optional] [default to null] | +| **format** | [**WorkflowFormatDTO**](WorkflowFormatDTO.md) | | [default to null] | +| **category** | [**WorkflowCategoryDTO**](WorkflowCategoryDTO.md) | | [default to null] | +| **description** | **String** | Description of the workflow | [optional] [default to null] | +| **annotations** | **List** | | [optional] [default to null] | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/WorkflowDataDTO.md b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/WorkflowDataDTO.md new file mode 100644 index 00000000..c4a00feb --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/WorkflowDataDTO.md @@ -0,0 +1,9 @@ +# WorkflowDataDTO +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +| **result** | [**WorkflowResultDTO**](WorkflowResultDTO.md) | | [optional] [default to null] | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/WorkflowFormatDTO.md b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/WorkflowFormatDTO.md new file mode 100644 index 00000000..8e76cc57 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/WorkflowFormatDTO.md @@ -0,0 +1,8 @@ +# WorkflowFormatDTO +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/WorkflowListResultDTO.md b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/WorkflowListResultDTO.md new file mode 100644 index 00000000..a634642d --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/WorkflowListResultDTO.md @@ -0,0 +1,10 @@ +# WorkflowListResultDTO +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +| **items** | [**List**](WorkflowDTO.md) | | [default to null] | +| **paginationInfo** | [**PaginationInfoDTO**](PaginationInfoDTO.md) | | [default to null] | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/WorkflowOverviewDTO.md b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/WorkflowOverviewDTO.md new file mode 100644 index 00000000..26ee8165 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/WorkflowOverviewDTO.md @@ -0,0 +1,17 @@ +# WorkflowOverviewDTO +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +| **workflowId** | **String** | Workflow unique identifier | [default to null] | +| **name** | **String** | Workflow name | [optional] [default to null] | +| **format** | [**WorkflowFormatDTO**](WorkflowFormatDTO.md) | | [default to null] | +| **lastRunId** | **String** | | [optional] [default to null] | +| **lastTriggeredMs** | **BigDecimal** | | [optional] [default to null] | +| **lastRunStatus** | [**ProcessInstanceStatusDTO**](ProcessInstanceStatusDTO.md) | | [optional] [default to null] | +| **category** | [**WorkflowCategoryDTO**](WorkflowCategoryDTO.md) | | [optional] [default to null] | +| **avgDurationMs** | **BigDecimal** | | [optional] [default to null] | +| **description** | **String** | | [optional] [default to null] | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/WorkflowOverviewListResultDTO.md b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/WorkflowOverviewListResultDTO.md new file mode 100644 index 00000000..a23dfe25 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/WorkflowOverviewListResultDTO.md @@ -0,0 +1,10 @@ +# WorkflowOverviewListResultDTO +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +| **overviews** | [**List**](WorkflowOverviewDTO.md) | | [optional] [default to null] | +| **paginationInfo** | [**PaginationInfoDTO**](PaginationInfoDTO.md) | | [optional] [default to null] | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/WorkflowProgressDTO.md b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/WorkflowProgressDTO.md new file mode 100644 index 00000000..42a4826a --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/WorkflowProgressDTO.md @@ -0,0 +1,18 @@ +# WorkflowProgressDTO +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +| **\_\_typename** | [**oas_any_type_not_mapped**](.md) | Type name | [optional] [default to NodeInstance] | +| **id** | [**oas_any_type_not_mapped**](.md) | Node instance ID | [default to null] | +| **name** | [**oas_any_type_not_mapped**](.md) | Node name | [optional] [default to null] | +| **type** | [**oas_any_type_not_mapped**](.md) | Node type | [optional] [default to null] | +| **enter** | [**oas_any_type_not_mapped**](.md) | Date when the node was entered | [optional] [default to null] | +| **exit** | [**oas_any_type_not_mapped**](.md) | Date when the node was exited (optional) | [optional] [default to null] | +| **definitionId** | [**oas_any_type_not_mapped**](.md) | Definition ID | [optional] [default to null] | +| **nodeId** | [**oas_any_type_not_mapped**](.md) | Node ID | [optional] [default to null] | +| **status** | [**ProcessInstanceStatusDTO**](ProcessInstanceStatusDTO.md) | | [optional] [default to null] | +| **error** | [**ProcessInstanceErrorDTO**](ProcessInstanceErrorDTO.md) | | [optional] [default to null] | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/WorkflowResultDTO.md b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/WorkflowResultDTO.md new file mode 100644 index 00000000..aa14267f --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/WorkflowResultDTO.md @@ -0,0 +1,12 @@ +# WorkflowResultDTO +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +| **completedWith** | **String** | The state of workflow completion. | [optional] [default to null] | +| **message** | **String** | High-level summary of the current status, free-form text, human readable. | [optional] [default to null] | +| **nextWorkflows** | [**List**](WorkflowResultDTO_nextWorkflows_inner.md) | List of workflows suggested to run next. Items at lower indexes are of higher priority. | [optional] [default to null] | +| **outputs** | [**List**](WorkflowResultDTO_outputs_inner.md) | Additional structured output of workflow processing. This can contain identifiers of created resources, links to resources, logs or other output. | [optional] [default to null] | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/WorkflowResultDTO_nextWorkflows_inner.md b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/WorkflowResultDTO_nextWorkflows_inner.md new file mode 100644 index 00000000..40db1d4d --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/WorkflowResultDTO_nextWorkflows_inner.md @@ -0,0 +1,10 @@ +# WorkflowResultDTO_nextWorkflows_inner +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +| **id** | **String** | Workflow identifier | [default to null] | +| **name** | **String** | Human readable title describing the workflow. | [default to null] | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/WorkflowResultDTO_outputs_inner.md b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/WorkflowResultDTO_outputs_inner.md new file mode 100644 index 00000000..b4b62ad0 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/WorkflowResultDTO_outputs_inner.md @@ -0,0 +1,11 @@ +# WorkflowResultDTO_outputs_inner +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +| **key** | **String** | Unique identifier of the option. Preferably human-readable. | [default to null] | +| **value** | [**WorkflowResultDTO_outputs_inner_value**](WorkflowResultDTO_outputs_inner_value.md) | | [default to null] | +| **format** | **String** | More detailed type of the 'value' property. Defaults to 'text'. | [optional] [default to null] | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/WorkflowResultDTO_outputs_inner_value.md b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/WorkflowResultDTO_outputs_inner_value.md new file mode 100644 index 00000000..9238c591 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/WorkflowResultDTO_outputs_inner_value.md @@ -0,0 +1,8 @@ +# WorkflowResultDTO_outputs_inner_value +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/WorkflowRunStatusDTO.md b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/WorkflowRunStatusDTO.md new file mode 100644 index 00000000..cea0fc3a --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/Models/WorkflowRunStatusDTO.md @@ -0,0 +1,10 @@ +# WorkflowRunStatusDTO +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +| **key** | **String** | | [optional] [default to null] | +| **value** | **String** | | [optional] [default to null] | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/README.md b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/README.md new file mode 100644 index 00000000..3f832609 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/README.md @@ -0,0 +1,62 @@ +# Documentation for Orchestrator plugin + + +## Documentation for API Endpoints + +All URIs are relative to *http://localhost* + +| Class | Method | HTTP request | Description | +|------------ | ------------- | ------------- | -------------| +| *DefaultApi* | [**abortWorkflow**](Apis/DefaultApi.md#abortworkflow) | **DELETE** /v2/workflows/instances/{instanceId}/abort | Abort a workflow instance | +*DefaultApi* | [**executeWorkflow**](Apis/DefaultApi.md#executeworkflow) | **POST** /v2/workflows/{workflowId}/execute | Execute a workflow | +*DefaultApi* | [**getInstanceById**](Apis/DefaultApi.md#getinstancebyid) | **GET** /v2/workflows/instances/{instanceId} | Get Workflow Instance by ID | +*DefaultApi* | [**getInstances**](Apis/DefaultApi.md#getinstances) | **POST** /v2/workflows/instances | Get instances | +*DefaultApi* | [**getWorkflowInputSchemaById**](Apis/DefaultApi.md#getworkflowinputschemabyid) | **GET** /v2/workflows/{workflowId}/inputSchema | Get the workflow input schema. It defines the input fields of the workflow | +*DefaultApi* | [**getWorkflowInstances**](Apis/DefaultApi.md#getworkflowinstances) | **POST** /v2/workflows/{workflowId}/instances | Get instances for a specific workflow | +*DefaultApi* | [**getWorkflowOverviewById**](Apis/DefaultApi.md#getworkflowoverviewbyid) | **GET** /v2/workflows/{workflowId}/overview | Returns the key fields of the workflow including data on the last run instance | +*DefaultApi* | [**getWorkflowSourceById**](Apis/DefaultApi.md#getworkflowsourcebyid) | **GET** /v2/workflows/{workflowId}/source | Get the workflow's definition | +*DefaultApi* | [**getWorkflowStatuses**](Apis/DefaultApi.md#getworkflowstatuses) | **GET** /v2/workflows/instances/statuses | Get workflow status list | +*DefaultApi* | [**getWorkflowsOverview**](Apis/DefaultApi.md#getworkflowsoverview) | **POST** /v2/workflows/overview | Returns the key fields of the workflow including data on the last run instance | +*DefaultApi* | [**retriggerInstance**](Apis/DefaultApi.md#retriggerinstance) | **POST** /v2/workflows/{workflowId}/{instanceId}/retrigger | Retrigger an instance | + + + +## Documentation for Models + + - [AssessedProcessInstanceDTO](./Models/AssessedProcessInstanceDTO.md) + - [ErrorResponse](./Models/ErrorResponse.md) + - [ExecuteWorkflowRequestDTO](./Models/ExecuteWorkflowRequestDTO.md) + - [ExecuteWorkflowResponseDTO](./Models/ExecuteWorkflowResponseDTO.md) + - [FieldFilter](./Models/FieldFilter.md) + - [FieldFilter_value](./Models/FieldFilter_value.md) + - [Filter](./Models/Filter.md) + - [GetInstancesRequest](./Models/GetInstancesRequest.md) + - [GetOverviewsRequestParams](./Models/GetOverviewsRequestParams.md) + - [InputSchemaResponseDTO](./Models/InputSchemaResponseDTO.md) + - [LogicalFilter](./Models/LogicalFilter.md) + - [NodeInstanceDTO](./Models/NodeInstanceDTO.md) + - [PaginationInfoDTO](./Models/PaginationInfoDTO.md) + - [ProcessInstanceDTO](./Models/ProcessInstanceDTO.md) + - [ProcessInstanceErrorDTO](./Models/ProcessInstanceErrorDTO.md) + - [ProcessInstanceListResultDTO](./Models/ProcessInstanceListResultDTO.md) + - [ProcessInstanceStatusDTO](./Models/ProcessInstanceStatusDTO.md) + - [SearchRequest](./Models/SearchRequest.md) + - [WorkflowCategoryDTO](./Models/WorkflowCategoryDTO.md) + - [WorkflowDTO](./Models/WorkflowDTO.md) + - [WorkflowDataDTO](./Models/WorkflowDataDTO.md) + - [WorkflowFormatDTO](./Models/WorkflowFormatDTO.md) + - [WorkflowListResultDTO](./Models/WorkflowListResultDTO.md) + - [WorkflowOverviewDTO](./Models/WorkflowOverviewDTO.md) + - [WorkflowOverviewListResultDTO](./Models/WorkflowOverviewListResultDTO.md) + - [WorkflowProgressDTO](./Models/WorkflowProgressDTO.md) + - [WorkflowResultDTO](./Models/WorkflowResultDTO.md) + - [WorkflowResultDTO_nextWorkflows_inner](./Models/WorkflowResultDTO_nextWorkflows_inner.md) + - [WorkflowResultDTO_outputs_inner](./Models/WorkflowResultDTO_outputs_inner.md) + - [WorkflowResultDTO_outputs_inner_value](./Models/WorkflowResultDTO_outputs_inner_value.md) + - [WorkflowRunStatusDTO](./Models/WorkflowRunStatusDTO.md) + + + +## Documentation for Authorization + +All endpoints do not require authorization. diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/index.ts b/workspaces/orchestrator/plugins/orchestrator-common/src/index.ts new file mode 100644 index 00000000..521a2c91 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/index.ts @@ -0,0 +1,24 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export * from './types'; +export * from './generated/api/definition'; +export * from './generated/client'; +export * from './constants'; +export * from './models'; +export * from './workflow'; +export * from './QueryParams'; +export * from './utils/StringUtils'; +export * from './permissions'; diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/models.ts b/workspaces/orchestrator/plugins/orchestrator-common/src/models.ts new file mode 100644 index 00000000..1fa56edf --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/models.ts @@ -0,0 +1,134 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { WorkflowCategory, WorkflowDefinition } from './types'; + +export enum ProcessInstanceState { + Active = 'ACTIVE', + Completed = 'COMPLETED', + Aborted = 'ABORTED', + Suspended = 'SUSPENDED', + Error = 'ERROR', + Pending = 'PENDING', +} + +export type ProcessInstanceStateValues = Uppercase< + keyof typeof ProcessInstanceState +>; + +export enum MilestoneStatus { + Available = 'AVAILABLE', + Active = 'ACTIVE', + Completed = 'COMPLETED', +} + +export interface NodeInstance { + __typename?: 'NodeInstance'; + id: string; + name: string; + type: string; + enter: string; + exit?: string; + definitionId: string; + nodeId: string; +} + +export interface TriggerableNode { + id: number; + name: string; + type: string; + uniqueId: string; + nodeDefinitionId: string; +} + +export interface Milestone { + __typename?: 'Milestone'; + id: string; + name: string; + status: MilestoneStatus; +} + +export interface ProcessInstanceError { + __typename?: 'ProcessInstanceError'; + nodeDefinitionId: string; + message?: string; +} + +export type ProcessInstanceVariables = Record; + +export interface ProcessInstance { + id: string; + processId: string; + processName?: string; + parentProcessInstanceId?: string; + rootProcessInstanceId?: string; + rootProcessId?: string; + roles?: string[]; + state?: ProcessInstanceStateValues; + endpoint: string; + serviceUrl?: string; + nodes: NodeInstance[]; + milestones?: Milestone[]; + variables?: ProcessInstanceVariables | string; + /** Format: date-time */ + start?: string; + /** Format: date-time */ + end?: string; + parentProcessInstance?: ProcessInstance; + childProcessInstances?: ProcessInstance[]; + error?: ProcessInstanceError; + addons?: string[]; + businessKey?: string; + isSelected?: boolean; + errorMessage?: string; + isOpen?: boolean; + diagram?: string; + nodeDefinitions?: TriggerableNode[]; + source?: string; + category?: WorkflowCategory; + description?: WorkflowDefinition['description']; +} +export interface IntrospectionQuery { + __type: IntrospectionType | null; +} + +export interface IntrospectionType { + name: string; + kind: TypeKind; + description: string | null; + fields: IntrospectionField[] | null; +} + +export interface IntrospectionField { + name: string; + type: IntrospectionTypeRef; +} + +export interface IntrospectionTypeRef { + kind: TypeKind; + name: TypeName; + ofType: IntrospectionTypeRef | null; +} + +export enum TypeKind { + InputObject = 'INPUT_OBJECT', +} + +export enum TypeName { + Id = 'IdArgument', + String = 'StringArgument', + StringArray = 'StringArrayArgument', + Date = 'DateArgument', +} diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/openapi/openapi.yaml b/workspaces/orchestrator/plugins/orchestrator-common/src/openapi/openapi.yaml new file mode 100644 index 00000000..330276e3 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/openapi/openapi.yaml @@ -0,0 +1,727 @@ +openapi: 3.1.0 +info: + title: Orchestrator plugin + description: API to interact with orchestrator plugin + license: + name: Apache 2.0 + url: http://www.apache.org/licenses/LICENSE-2.0.html + version: 0.0.1 +servers: + - url: / +paths: + /v2/workflows/overview: + post: + operationId: getWorkflowsOverview + description: Returns the key fields of the workflow including data on the last run instance + requestBody: + required: false + description: Pagination and filters + content: + application/json: + schema: + $ref: '#/components/schemas/SearchRequest' + responses: + '200': + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/WorkflowOverviewListResultDTO' + '500': + description: Error fetching workflow overviews + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + /v2/workflows/{workflowId}/overview: + get: + operationId: getWorkflowOverviewById + description: Returns the key fields of the workflow including data on the last run instance + parameters: + - name: workflowId + in: path + required: true + description: Unique identifier of the workflow + schema: + type: string + responses: + '200': + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/WorkflowOverviewDTO' + '500': + description: Error fetching workflow overview + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + /v2/workflows/{workflowId}/source: + get: + operationId: getWorkflowSourceById + description: Get the workflow's definition + parameters: + - name: workflowId + in: path + description: ID of the workflow to fetch + required: true + schema: + type: string + responses: + '200': + description: Success + content: + text/plain: + schema: + type: string + '500': + description: Error fetching workflow source by id + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + /v2/workflows/{workflowId}/inputSchema: + get: + operationId: getWorkflowInputSchemaById + description: Get the workflow input schema. It defines the input fields of the workflow + parameters: + - name: workflowId + in: path + description: ID of the workflow to fetch + required: true + schema: + type: string + - name: instanceId + in: query + description: ID of instance + schema: + type: string + responses: + '200': + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/InputSchemaResponseDTO' + '500': + description: Error fetching workflow input schema by id + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + /v2/workflows/instances: + post: + operationId: getInstances + summary: Get instances + description: Retrieve an array of workflow executions (instances) + requestBody: + required: false + description: Parameters for retrieving instances + content: + application/json: + schema: + $ref: '#/components/schemas/GetInstancesRequest' + responses: + '200': + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/ProcessInstanceListResultDTO' + '500': + description: Error fetching instances + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + /v2/workflows/{workflowId}/instances: + post: + operationId: getWorkflowInstances + summary: Get instances for a specific workflow + description: Retrieve an array of workflow executions (instances) for the given workflow + parameters: + - name: workflowId + in: path + required: true + description: ID of the workflow + schema: + type: string + requestBody: + required: false + description: Parameters for retrieving workflow instances + content: + application/json: + schema: + $ref: '#/components/schemas/SearchRequest' + responses: + '200': + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/ProcessInstanceListResultDTO' + '500': + description: Error fetching instances + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + /v2/workflows/instances/{instanceId}: + get: + summary: Get Workflow Instance by ID + description: Get a workflow execution/run (instance) + operationId: getInstanceById + parameters: + - name: instanceId + in: path + required: true + description: ID of the workflow instance + schema: + type: string + - name: includeAssessment + in: query + required: false + description: Whether to include assessment + schema: + type: boolean + default: false + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/AssessedProcessInstanceDTO' + '500': + description: Error fetching instance + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + /v2/workflows/instances/statuses: + get: + operationId: getWorkflowStatuses + summary: Get workflow status list + description: Retrieve array with the status of all instances + responses: + '200': + description: Success + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/WorkflowRunStatusDTO' + '500': + description: Error fetching workflow statuses + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + /v2/workflows/{workflowId}/execute: + post: + summary: Execute a workflow + description: Execute a workflow + operationId: executeWorkflow + parameters: + - name: workflowId + in: path + description: ID of the workflow to execute + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ExecuteWorkflowRequestDTO' + responses: + '200': + description: Successful execution + content: + application/json: + schema: + $ref: '#/components/schemas/ExecuteWorkflowResponseDTO' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + /v2/workflows/{workflowId}/{instanceId}/retrigger: + post: + summary: Retrigger an instance + description: Retrigger an instance + operationId: retriggerInstance + parameters: + - name: workflowId + in: path + description: ID of the workflow + required: true + schema: + type: string + - name: instanceId + in: path + description: ID of the instance to retrigger + required: true + schema: + type: string + responses: + '200': + description: Success + content: + application/json: + schema: + type: object + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + /v2/workflows/instances/{instanceId}/abort: + delete: + summary: Abort a workflow instance + operationId: abortWorkflow + description: Aborts a workflow instance identified by the provided instanceId. + parameters: + - name: instanceId + in: path + required: true + description: The identifier of the workflow instance to abort. + schema: + type: string + responses: + '200': + description: Successful operation + content: + text/plain: + schema: + type: string + '500': + description: Error aborting workflow + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' +components: + schemas: + ErrorResponse: + description: + The ErrorResponse object represents a common structure for handling errors in API responses. + It includes essential information about the error, such as the error message and additional optional details. + type: object + properties: + message: + description: + A string providing a concise and human-readable description of the encountered error. + This field is required in the ErrorResponse object. + type: string + default: internal server error + additionalInfo: + description: + An optional field that can contain additional information or context about the error. + It provides flexibility for including extra details based on specific error scenarios. + type: string + required: + - message + GetInstancesRequest: + type: object + properties: + paginationInfo: + $ref: '#/components/schemas/PaginationInfoDTO' + filters: + $ref: '#/components/schemas/SearchRequest' + GetOverviewsRequestParams: + type: object + properties: + paginationInfo: + $ref: '#/components/schemas/PaginationInfoDTO' + filters: + $ref: '#/components/schemas/SearchRequest' + WorkflowOverviewListResultDTO: + type: object + properties: + overviews: + type: array + items: + $ref: '#/components/schemas/WorkflowOverviewDTO' + minItems: 0 + paginationInfo: + $ref: '#/components/schemas/PaginationInfoDTO' + WorkflowOverviewDTO: + type: object + properties: + workflowId: + type: string + description: Workflow unique identifier + minLength: 1 + name: + type: string + description: Workflow name + minLength: 1 + format: + $ref: '#/components/schemas/WorkflowFormatDTO' + lastRunId: + type: string + lastTriggeredMs: + type: number + minimum: 0 + lastRunStatus: + $ref: '#/components/schemas/ProcessInstanceStatusDTO' + category: + $ref: '#/components/schemas/WorkflowCategoryDTO' + avgDurationMs: + type: number + minimum: 0 + description: + type: string + required: + - workflowId + - format + PaginationInfoDTO: + type: object + properties: + pageSize: + type: number + offset: + type: number + totalCount: + type: number + orderDirection: + enum: + - ASC + - DESC + orderBy: + type: string + additionalProperties: false + WorkflowFormatDTO: + type: string + description: Format of the workflow definition + enum: + - yaml + - json + WorkflowCategoryDTO: + type: string + description: Category of the workflow + enum: + - assessment + - infrastructure + WorkflowListResultDTO: + type: object + properties: + items: + type: array + items: + $ref: '#/components/schemas/WorkflowDTO' + paginationInfo: + $ref: '#/components/schemas/PaginationInfoDTO' + required: + - items + - paginationInfo + WorkflowDTO: + type: object + properties: + id: + type: string + description: Workflow unique identifier + minLength: 1 + name: + type: string + description: Workflow name + minLength: 1 + format: + $ref: '#/components/schemas/WorkflowFormatDTO' + category: + $ref: '#/components/schemas/WorkflowCategoryDTO' + description: + type: string + description: Description of the workflow + annotations: + type: array + items: + type: string + required: + - id + - category + - format + ProcessInstanceListResultDTO: + type: object + properties: + items: + type: array + items: + $ref: '#/components/schemas/ProcessInstanceDTO' + paginationInfo: + $ref: '#/components/schemas/PaginationInfoDTO' + AssessedProcessInstanceDTO: + type: object + properties: + instance: + $ref: '#/components/schemas/ProcessInstanceDTO' + assessedBy: + $ref: '#/components/schemas/ProcessInstanceDTO' + required: + - instance + ProcessInstanceDTO: + type: object + properties: + id: + type: string + processId: + type: string + processName: + type: string + status: + $ref: '#/components/schemas/ProcessInstanceStatusDTO' + endpoint: + type: string + serviceUrl: + type: string + start: + type: string + end: + type: string + duration: + type: string + category: + $ref: '#/components/schemas/WorkflowCategoryDTO' + description: + type: string + workflowdata: + $ref: '#/components/schemas/WorkflowDataDTO' + businessKey: + type: string + nodes: + type: array + items: + $ref: '#/components/schemas/NodeInstanceDTO' + error: + $ref: '#/components/schemas/ProcessInstanceErrorDTO' + required: + - id + - processId + - nodes + WorkflowDataDTO: + type: object + properties: + result: + $ref: '#/components/schemas/WorkflowResultDTO' + additionalProperties: true + WorkflowResultDTO: + # Based on https://github.com/parodos-dev/serverless-workflows/blob/main/shared/schemas/workflow-result-schema.json + description: Result of a workflow execution + type: object + properties: + completedWith: + description: The state of workflow completion. + type: string + enum: + - error + - success + message: + description: High-level summary of the current status, free-form text, human readable. + type: string + nextWorkflows: + description: List of workflows suggested to run next. Items at lower indexes are of higher priority. + type: array + items: + type: object + properties: + id: + description: Workflow identifier + type: string + name: + description: Human readable title describing the workflow. + type: string + required: + - id + - name + outputs: + description: Additional structured output of workflow processing. This can contain identifiers of created resources, links to resources, logs or other output. + type: array + items: + type: object + properties: + key: + description: Unique identifier of the option. Preferably human-readable. + type: string + value: + description: Free form value of the option. + anyOf: + - type: string + - type: number + format: + description: More detailed type of the 'value' property. Defaults to 'text'. + enum: + - text + - number + - link + required: + - key + - value + ProcessInstanceStatusDTO: + type: string + description: Status of the workflow run + enum: + - Active + - Error + - Completed + - Aborted + - Suspended + - Pending + WorkflowRunStatusDTO: + type: object + properties: + key: + type: string + value: + type: string + ExecuteWorkflowRequestDTO: + type: object + properties: + inputData: + type: object + additionalProperties: true + required: + - inputData + ExecuteWorkflowResponseDTO: + type: object + properties: + id: + type: string + required: + - id + WorkflowProgressDTO: + allOf: + - $ref: '#/components/schemas/NodeInstanceDTO' + - type: object + properties: + status: + $ref: '#/components/schemas/ProcessInstanceStatusDTO' + error: + $ref: '#/components/schemas/ProcessInstanceErrorDTO' + NodeInstanceDTO: + type: object + properties: + __typename: + type: string + default: 'NodeInstance' + description: Type name + id: + type: string + description: Node instance ID + name: + type: string + description: Node name + type: + type: string + description: Node type + enter: + type: string + description: Date when the node was entered + exit: + type: string + description: Date when the node was exited (optional) + definitionId: + type: string + description: Definition ID + nodeId: + type: string + description: Node ID + required: + - id + ProcessInstanceErrorDTO: + type: object + properties: + __typename: + type: string + default: 'ProcessInstanceError' + description: Type name + nodeDefinitionId: + type: string + description: Node definition ID + message: + type: string + description: Error message (optional) + required: + - nodeDefinitionId + SearchRequest: + type: object + properties: + filters: + $ref: '#/components/schemas/Filter' + paginationInfo: + $ref: '#/components/schemas/PaginationInfoDTO' + Filter: + oneOf: + - $ref: '#/components/schemas/LogicalFilter' + - $ref: '#/components/schemas/FieldFilter' + LogicalFilter: + type: object + required: + - operator + - filters + properties: + operator: + type: string + enum: [AND, OR, NOT] + filters: + type: array + items: + $ref: '#/components/schemas/Filter' + + FieldFilter: + type: object + required: + - field + - operator + - value + properties: + field: + type: string + operator: + type: string + enum: + [ + EQ, + GT, + GTE, + LT, + LTE, + IN, + IS_NULL, + CONTAINS, + CONTAINS_ALL, + CONTAINS_ANY, + LIKE, + BETWEEN, + ] + # The `value` field should be defined as follows. However, due to a bug (open since May 2023), + # https://github.com/OpenAPITools/openapi-generator/issues/15701 + # using `oneOf` to specify enum values for a property in the schema doesn't generate the enums correctly. + value: + oneOf: + - type: string + - type: number + - type: boolean + - type: array + items: + oneOf: + - type: string + - type: number + - type: boolean + # - type: string + # enum: + # - A + # - B + + InputSchemaResponseDTO: + type: object + properties: + inputSchema: + type: object + data: + type: object diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/permissions.ts b/workspaces/orchestrator/plugins/orchestrator-common/src/permissions.ts new file mode 100644 index 00000000..a2ba67b7 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/permissions.ts @@ -0,0 +1,55 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { createPermission } from '@backstage/plugin-permission-common'; + +export const orchestratorWorkflowInstancesReadPermission = createPermission({ + name: 'orchestrator.workflowInstances.read', + attributes: { + action: 'read', + }, +}); + +export const orchestratorWorkflowInstanceReadPermission = createPermission({ + name: 'orchestrator.workflowInstance.read', + attributes: { + action: 'read', + }, +}); + +export const orchestratorWorkflowReadPermission = createPermission({ + name: 'orchestrator.workflow.read', + attributes: { + action: 'read', + }, +}); + +export const orchestratorWorkflowExecutePermission = createPermission({ + name: 'orchestrator.workflow.execute', + attributes: {}, +}); + +export const orchestratorWorkflowInstanceAbortPermission = createPermission({ + name: 'orchestrator.workflowInstance.abort', + attributes: {}, +}); + +export const orchestratorPermissions = [ + orchestratorWorkflowReadPermission, + orchestratorWorkflowExecutePermission, + orchestratorWorkflowInstancesReadPermission, + orchestratorWorkflowInstanceReadPermission, + orchestratorWorkflowInstanceAbortPermission, +]; diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/types.ts b/workspaces/orchestrator/plugins/orchestrator-common/src/types.ts new file mode 100644 index 00000000..55b8461d --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/types.ts @@ -0,0 +1,142 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import type { JsonObject } from '@backstage/types'; + +import type { Specification } from '@severlessworkflow/sdk-typescript'; +import type { JSONSchema7, JSONSchema7Definition } from 'json-schema'; + +import type { ProcessInstance, ProcessInstanceStateValues } from './models'; + +type Id = { [P in keyof T]: T[P] }; + +type OmitDistributive = T extends any + ? T extends object + ? Id> + : T + : never; + +export type OmitRecursively = Omit< + { [P in keyof T]: OmitDistributive }, + K +>; + +export type WorkflowDefinition = OmitRecursively< + Specification.Workflow, + 'normalize' +>; + +export type WorkflowListResult = { + items: WorkflowDefinition[]; + totalCount: number; + offset: number; + limit: number; +}; + +export type WorkflowOverviewListResult = { + items: WorkflowOverview[]; + totalCount: number; + offset: number; + limit: number; +}; + +export type WorkflowFormat = 'yaml' | 'json'; + +export type WorkflowInputSchemaStep = { + schema: JsonObjectSchema; + title: string; + key: string; + data: JsonObject; + readonlyKeys: string[]; +}; + +export type JsonObjectSchema = Omit & { + properties: { [key: string]: JSONSchema7 }; +}; + +export type ComposedSchema = Omit & { + properties: { + [key: string]: Omit & { + properties: { [key: string]: JsonObjectSchema }; + }; + }; +}; + +export const isJsonObjectSchema = ( + schema: JSONSchema7 | JsonObjectSchema | JSONSchema7Definition, +): schema is JsonObjectSchema => + typeof schema === 'object' && + !!schema.properties && + Object.values(schema.properties).filter( + curSchema => typeof curSchema !== 'object', + ).length === 0; + +export const isComposedSchema = ( + schema: JSONSchema7 | ComposedSchema, +): schema is ComposedSchema => + !!schema.properties && + Object.values(schema.properties).filter( + curSchema => !isJsonObjectSchema(curSchema), + ).length === 0; + +export interface WorkflowExecutionResponse { + id: string; +} + +export enum WorkflowCategory { + ASSESSMENT = 'assessment', + INFRASTRUCTURE = 'infrastructure', +} + +export interface WorkflowOverview { + workflowId: string; + format: WorkflowFormat; + name?: string; + lastRunId?: string; + lastTriggeredMs?: number; + lastRunStatus?: ProcessInstanceStateValues; + category?: string; + avgDurationMs?: number; + description?: string; +} + +export interface WorkflowInfo { + id: string; + type?: string; + name?: string; + version?: string; + annotations?: string[]; + description?: string; + inputSchema?: JSONSchema7; + endpoint?: string; + serviceUrl?: string; + roles?: string[]; + source?: string; + metadata?: Map; + nodes?: Node[]; +} + +export interface Node { + id: string; + type?: string; + name?: string; + uniqueId?: string; + nodeDefinitionId?: string; +} + +export interface AssessedProcessInstance { + instance: ProcessInstance; + assessedBy?: ProcessInstance; +} diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/utils/StringUtils.ts b/workspaces/orchestrator/plugins/orchestrator-common/src/utils/StringUtils.ts new file mode 100644 index 00000000..0e28425e --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/utils/StringUtils.ts @@ -0,0 +1,24 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export type Capitalized = Capitalize>; + +export const capitalize = (text: S): Capitalized => + (text[0].toLocaleUpperCase('en-US') + + text.slice(1).toLocaleLowerCase('en-US')) as Capitalized; + +export const ellipsis = (text: S, prefixLength: number = 8) => + `${text.slice(0, prefixLength)}...`; diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/workflow.test.ts b/workspaces/orchestrator/plugins/orchestrator-common/src/workflow.test.ts new file mode 100644 index 00000000..a158c536 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/workflow.test.ts @@ -0,0 +1,28 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { extractWorkflowFormat } from './workflow'; + +describe('extractWorkflowFormat', () => { + it('should return "json" when input is valid JSON', () => { + const source = '{"name": "workflow", "steps": ["step1", "step2"]}'; + expect(extractWorkflowFormat(source)).toEqual('json'); + }); + + it('should return "yaml" when input is valid YAML', () => { + const source = 'name: workflow\nsteps:\n - step1\n - step2\n'; + expect(extractWorkflowFormat(source)).toEqual('yaml'); + }); +}); diff --git a/workspaces/orchestrator/plugins/orchestrator-common/src/workflow.ts b/workspaces/orchestrator/plugins/orchestrator-common/src/workflow.ts new file mode 100644 index 00000000..7a599af0 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-common/src/workflow.ts @@ -0,0 +1,121 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { Specification } from '@severlessworkflow/sdk-typescript'; +import { dump } from 'js-yaml'; + +import { ASSESSMENT_WORKFLOW_TYPE } from './constants'; +import { WorkflowCategory, WorkflowDefinition, WorkflowFormat } from './types'; + +export function fromWorkflowSource(content: string): WorkflowDefinition { + const parsed = Specification.Workflow.fromSource(content); + const workflow = parsed.sourceModel ?? parsed; + return removeProperty(workflow, 'normalize'); +} + +export function toWorkflowString( + definition: WorkflowDefinition, + format: WorkflowFormat, +): string { + switch (format) { + case 'json': + return toWorkflowJson(definition); + case 'yaml': + return toWorkflowYaml(definition); + default: + throw new Error(`Unsupported format ${format}`); + } +} + +export function toWorkflowJson(definition: WorkflowDefinition): string { + return JSON.stringify(definition, null, 2); +} + +export function toWorkflowYaml(definition: WorkflowDefinition): string { + return dump(definition); +} + +export function extractWorkflowFormatFromUri(uri: string): WorkflowFormat { + const match = RegExp(/\.sw\.(json|yaml|yml)$/).exec(uri); + if (match) { + if (match[1] === 'yml' || match[1] === 'yaml') { + return 'yaml'; + } + if (match[1] === 'json') { + return 'json'; + } + } + throw new Error(`Unsupported workflow format for uri ${uri}`); +} + +export function getWorkflowCategory( + definition: WorkflowDefinition | undefined, +): WorkflowCategory { + if (definition === undefined) { + return WorkflowCategory.INFRASTRUCTURE; + } + return definition?.annotations?.find( + annotation => annotation === ASSESSMENT_WORKFLOW_TYPE, + ) + ? WorkflowCategory.ASSESSMENT + : WorkflowCategory.INFRASTRUCTURE; +} + +function removeProperty(obj: T, propToDelete: string): T { + if (typeof obj !== 'object' || obj === null) { + return obj; + } + + if (Array.isArray(obj)) { + return obj.map(item => removeProperty(item, propToDelete)) as T; + } + + const newObj: any = {}; + + for (const key in obj) { + if (key !== propToDelete) { + newObj[key] = removeProperty(obj[key], propToDelete); // Recurse into nested objects + } + } + + return newObj; +} + +export function parseWorkflowVariables(variables?: object): object | undefined { + if (variables === undefined) { + return undefined; + } + + if (typeof variables === 'string') { + try { + return JSON.parse(variables); + } catch { + throw new Error( + `Error when parsing process instance variables: ${variables}`, + ); + } + } + + return variables; +} + +export function extractWorkflowFormat(source: string): WorkflowFormat { + try { + JSON.parse(source); + return 'json'; + } catch (_) { + return 'yaml'; + } +} diff --git a/workspaces/orchestrator/plugins/orchestrator-form-api/.eslintignore b/workspaces/orchestrator/plugins/orchestrator-form-api/.eslintignore new file mode 100644 index 00000000..b19336e4 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-form-api/.eslintignore @@ -0,0 +1,3 @@ +playwright.config.ts +dist/ +dist-types/ \ No newline at end of file diff --git a/workspaces/orchestrator/plugins/orchestrator-form-api/.eslintrc.js b/workspaces/orchestrator/plugins/orchestrator-form-api/.eslintrc.js new file mode 100644 index 00000000..e2a53a6a --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-form-api/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/workspaces/orchestrator/plugins/orchestrator-form-api/.prettierignore b/workspaces/orchestrator/plugins/orchestrator-form-api/.prettierignore new file mode 100644 index 00000000..fc8357d9 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-form-api/.prettierignore @@ -0,0 +1,12 @@ +dist +dist-types +coverage +.vscode +CHANGELOG.md +generated +templates +*.hbs +renovate.json +dist-dynamic +dist-scalprum +playwright-report diff --git a/workspaces/orchestrator/plugins/orchestrator-form-api/.prettierrc.js b/workspaces/orchestrator/plugins/orchestrator-form-api/.prettierrc.js new file mode 100644 index 00000000..5f81a8a0 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-form-api/.prettierrc.js @@ -0,0 +1,20 @@ +// @ts-check + +/** @type {import("@ianvs/prettier-plugin-sort-imports").PrettierConfig} */ +module.exports = { + ...require('@spotify/prettier-config'), + plugins: ['@ianvs/prettier-plugin-sort-imports'], + importOrder: [ + '^react(.*)$', + '', + '^@backstage/(.*)$', + '', + '', + '', + '^@red-hat-developer-hub/(.*)$', + '', + '', + '', + '^[.]', + ], +}; diff --git a/workspaces/orchestrator/plugins/orchestrator-form-api/CHANGELOG.md b/workspaces/orchestrator/plugins/orchestrator-form-api/CHANGELOG.md new file mode 100644 index 00000000..8ec86a39 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-form-api/CHANGELOG.md @@ -0,0 +1,39 @@ +# @red-hat-developer-hub/backstage-plugin-orchestrator-form-api + +## 1.4.2 + +### Patch Changes + +- 54daa8c: Migrated from [janus-idp/backstage-plugins](https://github.com/janus-idp/backstage-plugins). + +## 1.4.1 + +### Patch Changes + +- 0e6bfd3: feat: update Backstage to the latest version + + Update to Backstage 1.32.5 + +- 67f466a: Resolved the following issues: + + 1. enabled validation using customValidate, and replaced extraErrors with getExtraErrors, since extraErrors is supposed to be populated when running onSubmit, and that isn't exposed to the user. Added busy handling while calling getExtraErrors. + 2. moved FormComponent to a separate component, to avoid buggy behavior and code smells with component generated in a different component. + 3. update formData on each change instead of when moving to next step, to avoid data being cleared. + 4. fix bug in validator - it only worked in first step, because of issue in @rjsf form + 5. removed unnecessary package json-schema that was used just for lint error, and fixed the root cause of lint error when importing types from @types/json-schema + +## 1.4.0 + +### Minor Changes + +- 8244f28: chore(deps): update to backstage 1.32 + +## 1.3.0 + +### Minor Changes + +- d9551ae: feat(deps): update to backstage 1.31 + +### Patch Changes + +- d9551ae: upgrade to yarn v3 diff --git a/workspaces/orchestrator/plugins/orchestrator-form-api/README.md b/workspaces/orchestrator/plugins/orchestrator-form-api/README.md new file mode 100644 index 00000000..122abc16 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-form-api/README.md @@ -0,0 +1,5 @@ +# @red-hat-developer-hub/backstage-plugin-orchestrator-form-api + +This library provides the interface for implementing a factory providing a decorator to customize the orchestrator workflow execution form. + +Details available [here](../orchestrator/docs/extensibleForm.md). diff --git a/workspaces/orchestrator/plugins/orchestrator-form-api/package.json b/workspaces/orchestrator/plugins/orchestrator-form-api/package.json new file mode 100644 index 00000000..e125e29e --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-form-api/package.json @@ -0,0 +1,61 @@ +{ + "name": "@red-hat-developer-hub/backstage-plugin-orchestrator-form-api", + "description": "library for orchestrator form api, enabling creating a factory to extend the workflow execution form", + "version": "1.4.2", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "main": "dist/index.esm.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "web-library", + "supported-versions": "1.32.5" + }, + "sideEffects": false, + "scripts": { + "build": "backstage-cli package build", + "lint:check": "backstage-cli package lint", + "lint:fix": "backstage-cli package lint --fix", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "tsc": "tsc", + "prettier:check": "prettier --ignore-unknown --check .", + "prettier:fix": "prettier --ignore-unknown --write ." + }, + "dependencies": { + "@backstage/core-plugin-api": "^1.10.0", + "@backstage/types": "^1.1.1", + "@rjsf/core": "^5.21.2", + "@rjsf/utils": "^5.21.2" + }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0 || ^18.0.0" + }, + "devDependencies": { + "@backstage/cli": "0.28.2", + "@types/json-schema": "7.0.15", + "@types/react": "^18.2.58", + "prettier": "3.3.3", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-router-dom": "^6.0.0" + }, + "files": [ + "dist" + ], + "maintainers": [ + "@mlibra", + "@batzionb", + "@gciavarrini" + ], + "repository": { + "type": "git", + "url": "https://github.com/redhat-developer/rhdh-plugins", + "directory": "workspaces/orchestrator/plugins/orchestrator-form-api" + }, + "bugs": "https://github.com/redhat-developer/rhdh-plugins/issues" +} diff --git a/workspaces/orchestrator/plugins/orchestrator-form-api/report.api.md b/workspaces/orchestrator/plugins/orchestrator-form-api/report.api.md new file mode 100644 index 00000000..6d335672 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-form-api/report.api.md @@ -0,0 +1,34 @@ +## API Report File for "@red-hat-developer-hub/backstage-plugin-orchestrator-form-api" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +/// + +import { ApiRef } from '@backstage/core-plugin-api'; +import { ErrorSchema } from '@rjsf/utils'; +import { FormProps } from '@rjsf/core'; +import { JsonObject } from '@backstage/types'; +import type { JSONSchema7 } from 'json-schema'; +import { UiSchema } from '@rjsf/utils'; + +// @public +export type FormDecoratorProps = Pick, 'formData' | 'formContext' | 'widgets' | 'onChange' | 'customValidate'> & { + getExtraErrors?: (formData: JsonObject) => Promise> | undefined; +}; + +// @public +export interface OrchestratorFormApi { + getFormDecorator(schema: JSONSchema7, uiSchema: UiSchema, initialFormData?: JsonObject): OrchestratorFormDecorator; +} + +// @public +export const orchestratorFormApiRef: ApiRef; + +// @public +export type OrchestratorFormDecorator = (FormComponent: React.ComponentType) => React.ComponentType; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/workspaces/orchestrator/plugins/orchestrator-form-api/src/api.ts b/workspaces/orchestrator/plugins/orchestrator-form-api/src/api.ts new file mode 100644 index 00000000..10e55764 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-form-api/src/api.ts @@ -0,0 +1,88 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { createApiRef } from '@backstage/core-plugin-api'; +import { JsonObject } from '@backstage/types'; + +import { FormProps } from '@rjsf/core'; +import { ErrorSchema, UiSchema } from '@rjsf/utils'; +import type { JSONSchema7 } from 'json-schema'; + +/** + * @public + * FormDecoratorProps + * + * Type definition for properties passed to a form decorator component. + * This interface extends selected fields from `FormProps` provided by `react-jsonschema-form`, + * with additional custom functionality. + * + * @see {@link https://rjsf-team.github.io/react-jsonschema-form/docs/api-reference/form-props|RJSF Form Props Documentation} + * + * Core properties include: + * - formData: The form's current data + * - formContext: Contextual data shared across form components + * - widgets: Custom widget components for form fields + * - onChange: Handler for form data changes + * - customValidate: Custom validation function + * + * Additional properties: + * - getExtraErrors: Async function to fetch additional validation errors. + * This replaces the static 'extraErrors' prop from react-jsonschema-form, which can't be used as is, since onSubmit isn't exposed. + * The orchestrator form component will call getExtraErrors when running onSubmit. + */ +export type FormDecoratorProps = Pick< + FormProps, + 'formData' | 'formContext' | 'widgets' | 'onChange' | 'customValidate' +> & { + getExtraErrors?: ( + formData: JsonObject, + ) => Promise> | undefined; +}; + +/** + * @public + * OrchestratorFormDecorator + * + */ +export type OrchestratorFormDecorator = ( + FormComponent: React.ComponentType, +) => React.ComponentType; + +/** + * @public + * OrchestratorFormApi + * API to be implemented by factory in a custom plugin + */ +export interface OrchestratorFormApi { + /** + * @public + * getFormDecorator + * return the form decorator + */ + getFormDecorator( + schema: JSONSchema7, + uiSchema: UiSchema, + initialFormData?: JsonObject, + ): OrchestratorFormDecorator; +} + +/** + * @public + * OrchestratorFormApiRef + * + */ +export const orchestratorFormApiRef = createApiRef({ + id: 'plugin.orchestrator.form', +}); diff --git a/workspaces/orchestrator/plugins/orchestrator-form-api/src/index.ts b/workspaces/orchestrator/plugins/orchestrator-form-api/src/index.ts new file mode 100644 index 00000000..547eece5 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-form-api/src/index.ts @@ -0,0 +1,19 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { orchestratorFormApiRef } from './api'; +export type { OrchestratorFormApi } from './api'; +export type { OrchestratorFormDecorator } from './api'; +export type { FormDecoratorProps } from './api'; diff --git a/workspaces/orchestrator/plugins/orchestrator-form-react/.eslintignore b/workspaces/orchestrator/plugins/orchestrator-form-react/.eslintignore new file mode 100644 index 00000000..b19336e4 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-form-react/.eslintignore @@ -0,0 +1,3 @@ +playwright.config.ts +dist/ +dist-types/ \ No newline at end of file diff --git a/workspaces/orchestrator/plugins/orchestrator-form-react/.eslintrc.js b/workspaces/orchestrator/plugins/orchestrator-form-react/.eslintrc.js new file mode 100644 index 00000000..e2a53a6a --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-form-react/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/workspaces/orchestrator/plugins/orchestrator-form-react/.prettierignore b/workspaces/orchestrator/plugins/orchestrator-form-react/.prettierignore new file mode 100644 index 00000000..fc8357d9 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-form-react/.prettierignore @@ -0,0 +1,12 @@ +dist +dist-types +coverage +.vscode +CHANGELOG.md +generated +templates +*.hbs +renovate.json +dist-dynamic +dist-scalprum +playwright-report diff --git a/workspaces/orchestrator/plugins/orchestrator-form-react/.prettierrc.js b/workspaces/orchestrator/plugins/orchestrator-form-react/.prettierrc.js new file mode 100644 index 00000000..5f81a8a0 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-form-react/.prettierrc.js @@ -0,0 +1,20 @@ +// @ts-check + +/** @type {import("@ianvs/prettier-plugin-sort-imports").PrettierConfig} */ +module.exports = { + ...require('@spotify/prettier-config'), + plugins: ['@ianvs/prettier-plugin-sort-imports'], + importOrder: [ + '^react(.*)$', + '', + '^@backstage/(.*)$', + '', + '', + '', + '^@red-hat-developer-hub/(.*)$', + '', + '', + '', + '^[.]', + ], +}; diff --git a/workspaces/orchestrator/plugins/orchestrator-form-react/CHANGELOG.md b/workspaces/orchestrator/plugins/orchestrator-form-react/CHANGELOG.md new file mode 100644 index 00000000..0f24301a --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-form-react/CHANGELOG.md @@ -0,0 +1,139 @@ +### Dependencies + +## 1.4.3 + +### Patch Changes + +- 54daa8c: Migrated from [janus-idp/backstage-plugins](https://github.com/janus-idp/backstage-plugins). +- Updated dependencies [54daa8c] + - @red-hat-developer-hub/backstage-plugin-orchestrator-form-api@1.4.2 + +## 1.4.2 + +### Patch Changes + +- aee9d4a: Hotfix for button background - to share the one with theme. + +## 1.4.1 + +### Patch Changes + +- 0e6bfd3: feat: update Backstage to the latest version + + Update to Backstage 1.32.5 + +- 67f466a: Resolved the following issues: + + 1. enabled validation using customValidate, and replaced extraErrors with getExtraErrors, since extraErrors is supposed to be populated when running onSubmit, and that isn't exposed to the user. Added busy handling while calling getExtraErrors. + 2. moved FormComponent to a separate component, to avoid buggy behavior and code smells with component generated in a different component. + 3. update formData on each change instead of when moving to next step, to avoid data being cleared. + 4. fix bug in validator - it only worked in first step, because of issue in @rjsf form + 5. removed unnecessary package json-schema that was used just for lint error, and fixed the root cause of lint error when importing types from @types/json-schema + +- Updated dependencies [0e6bfd3] +- Updated dependencies [67f466a] + - @red-hat-developer-hub/backstage-plugin-orchestrator-form-api@1.4.1 + +## 1.4.0 + +### Minor Changes + +- 8244f28: chore(deps): update to backstage 1.32 + +### Patch Changes + +- Updated dependencies [8244f28] + - @red-hat-developer-hub/backstage-plugin-orchestrator-form-api@1.4.0 + +## 1.3.1 + +### Patch Changes + +- 7342e9b: chore: remove @janus-idp/cli dep and relink local packages + + This update removes `@janus-idp/cli` from all plugins, as it’s no longer necessary. Additionally, packages are now correctly linked with a specified version. + +## 1.3.0 + +### Minor Changes + +- d9551ae: feat(deps): update to backstage 1.31 + +### Patch Changes + +- d9551ae: Change local package references to a `*` +- d9551ae: upgrade to yarn v3 +- Updated dependencies [d9551ae] +- Updated dependencies [d9551ae] + - @red-hat-developer-hub/backstage-plugin-orchestrator-form-api@1.3.0 + +* **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.21.0 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.20.0 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.19.0 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.18.2 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.18.1 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.18.0 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.17.3 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-form-api:** upgraded to 1.1.0 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.17.2 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.17.1 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.17.0 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.17.0 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.0.0 +- **@red-hat-developer-hub/backstage-plugin-orchestrator-form-api:** upgraded to 1.0.0 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.16.0 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.15.2 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.15.1 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.15.0 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-form-api:** upgraded to 1.0.1 diff --git a/workspaces/orchestrator/plugins/orchestrator-form-react/README.md b/workspaces/orchestrator/plugins/orchestrator-form-react/README.md new file mode 100644 index 00000000..cc0f0fba --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-form-react/README.md @@ -0,0 +1,5 @@ +# backstage-plugin-orchestrator-form-react + +This library provides the form component used in the workflow execution form. It is decoupled from the orchestrator plugin to allow plugins implementing the OrchestratorFormApi test the behavior in a simple backstage developer environment. + +Details available [here](../orchestrator/docs/extensibleForm.md). diff --git a/workspaces/orchestrator/plugins/orchestrator-form-react/package.json b/workspaces/orchestrator/plugins/orchestrator-form-react/package.json new file mode 100644 index 00000000..07dd3ffe --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-form-react/package.json @@ -0,0 +1,75 @@ +{ + "name": "@red-hat-developer-hub/backstage-plugin-orchestrator-form-react", + "description": "Web library for the orchestrator-form plugin", + "version": "1.4.3", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "main": "dist/index.esm.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "web-library", + "pluginId": "orchestrator-form", + "pluginPackages": [ + "@red-hat-developer-hub/backstage-plugin-orchestrator-form-react" + ], + "supported-versions": "1.32.5" + }, + "sideEffects": false, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint:check": "backstage-cli package lint", + "lint:fix": "backstage-cli package lint --fix", + "test": "backstage-cli package test --passWithNoTests --coverage", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "tsc": "tsc", + "prettier:check": "prettier --ignore-unknown --check .", + "prettier:fix": "prettier --ignore-unknown --write ." + }, + "dependencies": { + "@backstage/core-components": "^0.15.1", + "@backstage/core-plugin-api": "^1.10.0", + "@backstage/types": "^1.1.1", + "@material-ui/core": "^4.12.4", + "@red-hat-developer-hub/backstage-plugin-orchestrator-form-api": "workspace:^", + "@rjsf/core": "^5.21.2", + "@rjsf/material-ui": "^5.21.2", + "@rjsf/utils": "^5.21.2", + "@rjsf/validator-ajv8": "^5.21.2", + "json-schema-library": "^9.0.0", + "lodash": "^4.17.21" + }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0 || ^18.0.0" + }, + "devDependencies": { + "@backstage/cli": "0.28.2", + "@types/json-schema": "7.0.15", + "@types/lodash": "^4.14.151", + "@types/react": "^18.2.58", + "prettier": "3.3.3", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-router-dom": "^6.0.0" + }, + "files": [ + "dist" + ], + "maintainers": [ + "@mlibra", + "@batzionb", + "@gciavarrini" + ], + "repository": { + "type": "git", + "url": "https://github.com/redhat-developer/rhdh-plugins", + "directory": "workspaces/orchestrator/plugins/orchestrator-form-react" + }, + "bugs": "https://github.com/redhat-developer/rhdh-plugins/issues" +} diff --git a/workspaces/orchestrator/plugins/orchestrator-form-react/report.api.md b/workspaces/orchestrator/plugins/orchestrator-form-react/report.api.md new file mode 100644 index 00000000..499df749 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-form-react/report.api.md @@ -0,0 +1,31 @@ +## API Report File for "@red-hat-developer-hub/backstage-plugin-orchestrator-form-react" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { JsonObject } from '@backstage/types'; +import type { JSONSchema7 } from 'json-schema'; +import { default as React_2 } from 'react'; + +// @public +export const OrchestratorForm: ({ schema, handleExecute, isExecuting, data, isDataReadonly, }: OrchestratorFormProps) => React_2.JSX.Element; + +// @public +export type OrchestratorFormProps = { + schema: JSONSchema7; + isExecuting: boolean; + handleExecute: (parameters: JsonObject) => Promise; + data?: JsonObject; + isDataReadonly?: boolean; +}; + +// @public +export const SubmitButton: ({ submitting, handleClick, children, focusOnMount, }: { + submitting: boolean; + handleClick?: (() => void) | undefined; + children: React_2.ReactNode; + focusOnMount?: boolean | undefined; +}) => React_2.JSX.Element; + +``` diff --git a/workspaces/orchestrator/plugins/orchestrator-form-react/src/DefaultFormApi.tsx b/workspaces/orchestrator/plugins/orchestrator-form-react/src/DefaultFormApi.tsx new file mode 100644 index 00000000..32d402ec --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-form-react/src/DefaultFormApi.tsx @@ -0,0 +1,33 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; + +import type { JSONSchema7 } from 'json-schema'; + +import { + FormDecoratorProps, + OrchestratorFormApi, + OrchestratorFormDecorator, +} from '@red-hat-developer-hub/backstage-plugin-orchestrator-form-api'; + +class DefaultFormApi implements OrchestratorFormApi { + getFormDecorator(_schema: JSONSchema7): OrchestratorFormDecorator { + return (FormComponent: React.ComponentType) => + FormComponent; + } +} + +export const defaultFormExtensionsApi = new DefaultFormApi(); diff --git a/workspaces/orchestrator/plugins/orchestrator-form-react/src/components/OrchestratorForm.tsx b/workspaces/orchestrator/plugins/orchestrator-form-react/src/components/OrchestratorForm.tsx new file mode 100644 index 00000000..e6ec9fef --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-form-react/src/components/OrchestratorForm.tsx @@ -0,0 +1,157 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React, { Fragment } from 'react'; + +import { JsonObject } from '@backstage/types'; + +import { UiSchema } from '@rjsf/utils'; +import type { JSONSchema7 } from 'json-schema'; + +import generateUiSchema from '../utils/generateUiSchema'; +import { StepperContextProvider } from '../utils/StepperContext'; +import OrchestratorFormStepper, { + OrchestratorFormStep, + OrchestratorFormToolbar, +} from './OrchestratorFormStepper'; +import OrchestratorFormWrapper from './OrchestratorFormWrapper'; +import ReviewStep from './ReviewStep'; + +const getNumSteps = (schema: JSONSchema7): number | undefined => { + if (schema.type !== 'object' || !schema.properties) return undefined; + const isMultiStep = Object.values(schema.properties).every( + prop => (prop as JSONSchema7).type === 'object', + ); + return isMultiStep ? Object.keys(schema.properties).length : undefined; +}; + +const SingleStepForm = ({ + schema, + formData, + onChange, + uiSchema, +}: { + schema: JSONSchema7; + formData: JsonObject; + onChange: (formData: JsonObject) => void; + uiSchema: UiSchema; +}) => { + const steps = React.useMemo(() => { + return [ + { + title: schema.title || 'Inputs', + key: 'schema', + content: ( + + + + ), + }, + ]; + }, [schema, formData, onChange, uiSchema]); + return ; +}; + +/** + * @public + * OrchestratorForm component properties + */ +export type OrchestratorFormProps = { + schema: JSONSchema7; + isExecuting: boolean; + handleExecute: (parameters: JsonObject) => Promise; + data?: JsonObject; + isDataReadonly?: boolean; +}; + +/** + * @public + * The component contains the react-json-schema-form and serves as an extensible form. It allows loading a custom plugin decorator to override the default react-json-schema-form properties. + */ +const OrchestratorForm = ({ + schema, + handleExecute, + isExecuting, + data, + isDataReadonly, +}: OrchestratorFormProps) => { + const [formData, setFormData] = React.useState(data || {}); + const numStepsInMultiStepSchema = React.useMemo( + () => getNumSteps(schema), + [schema], + ); + const isMultiStep = numStepsInMultiStepSchema !== undefined; + + const _handleExecute = React.useCallback(() => { + handleExecute(formData || {}); + }, [formData, handleExecute]); + + const onChange = React.useCallback( + (_formData: JsonObject) => { + setFormData(_formData); + }, + [setFormData], + ); + + const uiSchema = React.useMemo>(() => { + return generateUiSchema( + schema, + isMultiStep, + isDataReadonly ? data : undefined, + ); + }, [schema, isMultiStep, isDataReadonly, data]); + + const reviewStep = React.useMemo( + () => ( + + ), + [formData, schema, isExecuting, _handleExecute], + ); + + return ( + + {isMultiStep ? ( + + + // it is required to pass the fragment so rjsf won't generate a Submit button + ) : ( + + )} + + ); +}; + +export default OrchestratorForm; diff --git a/workspaces/orchestrator/plugins/orchestrator-form-react/src/components/OrchestratorFormStepper.tsx b/workspaces/orchestrator/plugins/orchestrator-form-react/src/components/OrchestratorFormStepper.tsx new file mode 100644 index 00000000..f4ea0731 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-form-react/src/components/OrchestratorFormStepper.tsx @@ -0,0 +1,124 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; + +import { + Button, + makeStyles, + Step, + StepLabel, + Stepper, + Typography, +} from '@material-ui/core'; + +import { useStepperContext } from '../utils/StepperContext'; +import SubmitButton from './SubmitButton'; + +const useStyles = makeStyles(theme => ({ + // Hotfix: this should be fixed in the theme + step: { + '& form': { + '& .field-array > div > div': { + outline: 'inherit !important', + padding: 'inherit !important', + backgroundColor: 'inherit !important', + + '& div > div > div > div': { + // unfortunately there are no better CSS selectors + backgroundColor: 'inherit !important', + }, + }, + }, + }, + regularButton: { + // hotifx for https://issues.redhat.com/browse/FLPATH-1825 + backgroundColor: 'inherit !important', + }, + footer: { + display: 'flex', + flexDirection: 'row', + justifyContent: 'right', + marginTop: theme.spacing(2), + }, + formWrapper: { + padding: theme.spacing(2), + }, +})); + +export type OrchestratorFormStep = { + content: React.ReactNode; + title: string; + key: string; +}; + +const OrchestratorFormStepper = ({ + steps, +}: { + steps: OrchestratorFormStep[]; +}) => { + const { activeStep, reviewStep } = useStepperContext(); + const stepsWithReview = [ + ...steps, + { content: reviewStep, title: 'Review', key: 'review' }, + ]; + const styles = useStyles(); + return ( + <> + + {stepsWithReview?.map((step, index) => ( + + + + {step.title} + + + + ))} + +
+ {stepsWithReview[activeStep].content} +
+ + ); +}; + +export const OrchestratorFormToolbar = () => { + const { activeStep, handleBack, isValidating } = useStepperContext(); + const styles = useStyles(); + return ( +
+ + Next +
+ ); +}; + +export default OrchestratorFormStepper; diff --git a/workspaces/orchestrator/plugins/orchestrator-form-react/src/components/OrchestratorFormWrapper.tsx b/workspaces/orchestrator/plugins/orchestrator-form-react/src/components/OrchestratorFormWrapper.tsx new file mode 100644 index 00000000..cb23a5f5 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-form-react/src/components/OrchestratorFormWrapper.tsx @@ -0,0 +1,171 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; + +import { ErrorPanel } from '@backstage/core-components'; +import { useApiHolder } from '@backstage/core-plugin-api'; +import { JsonObject } from '@backstage/types'; + +import { Grid } from '@material-ui/core'; +import { withTheme } from '@rjsf/core'; +import { Theme as MuiTheme } from '@rjsf/material-ui'; +import { ErrorSchema, UiSchema } from '@rjsf/utils'; +import type { JSONSchema7 } from 'json-schema'; +import omit from 'lodash/omit'; + +import { + FormDecoratorProps, + orchestratorFormApiRef, +} from '@red-hat-developer-hub/backstage-plugin-orchestrator-form-api'; + +import { defaultFormExtensionsApi } from '../DefaultFormApi'; +import { useStepperContext } from '../utils/StepperContext'; +import useValidator from '../utils/useValidator'; +import StepperObjectField from './StepperObjectField'; + +const MuiForm = withTheme(MuiTheme); + +type OrchestratorFormWrapperProps = { + schema: JSONSchema7; + numStepsInMultiStepSchema?: number; + children: React.ReactNode; + formData: JsonObject; + onChange: (formData: JsonObject) => void; + uiSchema: UiSchema; +}; + +const WrapperFormPropsContext = + React.createContext(null); + +const useWrapperFormPropsContext = (): OrchestratorFormWrapperProps => { + const context = React.useContext(WrapperFormPropsContext); + if (context === null) { + throw new Error('OrchestratorFormWrapperProps not provided'); + } + return context; +}; + +const FormComponent = (decoratorProps: FormDecoratorProps) => { + const props = useWrapperFormPropsContext(); + const { + numStepsInMultiStepSchema, + uiSchema, + schema, + onChange, + formData, + children, + } = props; + const [extraErrors, setExtraErrors] = React.useState< + ErrorSchema | undefined + >(); + const isMultiStep = numStepsInMultiStepSchema !== undefined; + const { handleNext, activeStep, handleValidateStarted, handleValidateEnded } = + useStepperContext(); + const [validationError, setValidationError] = React.useState< + Error | undefined + >(); + const validator = useValidator(isMultiStep); + const getActiveKey = () => { + if (!isMultiStep) { + return undefined; + } + return Object.keys(schema.properties || {})[activeStep]; + }; + + const onSubmit = async (_formData: JsonObject) => { + setExtraErrors(undefined); + let _extraErrors: ErrorSchema | undefined = undefined; + let _validationError: Error | undefined = undefined; + if (decoratorProps.getExtraErrors) { + try { + handleValidateStarted(); + _extraErrors = await decoratorProps.getExtraErrors(formData); + const activeKey = getActiveKey(); + setExtraErrors( + activeKey && _extraErrors?.[activeKey] + ? (_extraErrors[activeKey] as ErrorSchema) + : _extraErrors, + ); + } catch (err) { + _validationError = err as Error; + } finally { + handleValidateEnded(); + } + } + setValidationError(_validationError); + if ( + (!_extraErrors || Object.keys(_extraErrors).length === 0) && + !_validationError && + activeStep < (numStepsInMultiStepSchema || 1) + ) { + handleNext(); + } + }; + + return ( + + {validationError && ( + + + + )} + + onSubmit(e.formData || {})} + onChange={e => { + onChange(e.formData || {}); + if (decoratorProps.onChange) { + decoratorProps.onChange(e); + } + }} + > + {children} + + + + ); +}; + +const OrchestratorFormWrapper = ({ + schema, + uiSchema, + formData, + ...props +}: OrchestratorFormWrapperProps) => { + const formApi = + useApiHolder().get(orchestratorFormApiRef) || defaultFormExtensionsApi; + const NewComponent = React.useMemo(() => { + const formDecorator = formApi.getFormDecorator(schema, uiSchema, formData); + return formDecorator(FormComponent); + }, [schema, formApi, uiSchema, formData]); + return ( + + + + ); +}; + +export default OrchestratorFormWrapper; diff --git a/workspaces/orchestrator/plugins/orchestrator-form-react/src/components/ReviewStep.tsx b/workspaces/orchestrator/plugins/orchestrator-form-react/src/components/ReviewStep.tsx new file mode 100644 index 00000000..0479515e --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-form-react/src/components/ReviewStep.tsx @@ -0,0 +1,75 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; + +import { Content, StructuredMetadataTable } from '@backstage/core-components'; +import { JsonObject } from '@backstage/types'; + +import { Box, Button, makeStyles, Paper } from '@material-ui/core'; +import type { JSONSchema7 } from 'json-schema'; + +import generateReviewTableData from '../utils/generateReviewTableData'; +import { useStepperContext } from '../utils/StepperContext'; +import SubmitButton from './SubmitButton'; + +const useStyles = makeStyles(theme => ({ + footer: { + display: 'flex', + flexDirection: 'row', + justifyContent: 'right', + marginTop: theme.spacing(2), + }, +})); + +const ReviewStep = ({ + busy, + schema, + data, + handleExecute, +}: { + busy: boolean; + schema: JSONSchema7; + data: JsonObject; + handleExecute: () => void; +}) => { + const styles = useStyles(); + const { handleBack } = useStepperContext(); + const displayData = React.useMemo(() => { + return generateReviewTableData(schema, data); + }, [schema, data]); + return ( + + + + +
+ + + Run + +
+
+
+ ); +}; + +export default ReviewStep; diff --git a/workspaces/orchestrator/plugins/orchestrator-form-react/src/components/StepperObjectField.tsx b/workspaces/orchestrator/plugins/orchestrator-form-react/src/components/StepperObjectField.tsx new file mode 100644 index 00000000..fad459dd --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-form-react/src/components/StepperObjectField.tsx @@ -0,0 +1,84 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; + +import { JsonObject } from '@backstage/types'; + +import ObjectField from '@rjsf/core/lib/components/fields/ObjectField'; +import { ErrorSchema, FieldProps, IdSchema } from '@rjsf/utils'; +import type { JSONSchema7 } from 'json-schema'; + +import OrchestratorFormStepper, { + OrchestratorFormStep, + OrchestratorFormToolbar, +} from './OrchestratorFormStepper'; + +const StepperObjectField = ({ + formData, + schema, + uiSchema, + onChange, + registry, + idSchema, + errorSchema, + ...props +}: FieldProps) => { + if (schema.properties === undefined) { + throw new Error( + "Stepper object field is not supported for schema that doesn't contain properties", + ); + } + const steps = Object.entries(schema.properties).reduce< + OrchestratorFormStep[] + >((prev, [key, subSchema]) => { + if (typeof subSchema === 'boolean') { + return prev; + } + return [ + ...prev, + { + content: ( + <> + + {...props} + schema={{ ...subSchema, title: '' }} // the title is in the step + uiSchema={uiSchema?.[key] || {}} + formData={(formData?.[key] as JsonObject) || {}} + onChange={data => { + onChange({ ...formData, [key]: data }); + }} + idSchema={idSchema[key] as IdSchema} + registry={{ + ...registry, + fields: { + ...registry.fields, + ObjectField: ObjectField, // undo override of objectfield + }, + }} + errorSchema={errorSchema?.[key] as ErrorSchema} + /> + + + ), + title: subSchema.title || key, + key, + }, + ]; + }, []); + return ; +}; + +export default StepperObjectField; diff --git a/workspaces/orchestrator/plugins/orchestrator-form-react/src/components/SubmitButton.tsx b/workspaces/orchestrator/plugins/orchestrator-form-react/src/components/SubmitButton.tsx new file mode 100644 index 00000000..3ea463fa --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-form-react/src/components/SubmitButton.tsx @@ -0,0 +1,59 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; + +import { Button, CircularProgress } from '@material-ui/core'; + +/** + * @public + * Button with loading state. + */ +const SubmitButton = ({ + submitting, + handleClick, + children, + focusOnMount, +}: { + submitting: boolean; + handleClick?: () => void; + children: React.ReactNode; + focusOnMount?: boolean; +}) => { + const ref = React.useRef(null); + React.useEffect(() => { + if (focusOnMount) { + ref.current?.focus(); + } + }, [focusOnMount]); + return ( + + ); +}; + +export default SubmitButton; diff --git a/workspaces/orchestrator/plugins/orchestrator-form-react/src/components/index.ts b/workspaces/orchestrator/plugins/orchestrator-form-react/src/components/index.ts new file mode 100644 index 00000000..95d06912 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-form-react/src/components/index.ts @@ -0,0 +1,19 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export type { OrchestratorFormProps } from './OrchestratorForm'; +export { default as OrchestratorForm } from './OrchestratorForm'; +export { default as SubmitButton } from './SubmitButton'; diff --git a/workspaces/orchestrator/plugins/orchestrator-form-react/src/components/useStyles.ts b/workspaces/orchestrator/plugins/orchestrator-form-react/src/components/useStyles.ts new file mode 100644 index 00000000..94adcafa --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-form-react/src/components/useStyles.ts @@ -0,0 +1,15 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ diff --git a/workspaces/orchestrator/plugins/orchestrator-form-react/src/index.ts b/workspaces/orchestrator/plugins/orchestrator-form-react/src/index.ts new file mode 100644 index 00000000..94429e1e --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-form-react/src/index.ts @@ -0,0 +1,26 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Web library for the orchestrator-form plugin. + * + * @packageDocumentation + */ + +// In this package you might for example export components or hooks +// that are useful to other plugins or modules. + +export * from './components'; diff --git a/workspaces/orchestrator/plugins/orchestrator-form-react/src/utils/StepperContext.tsx b/workspaces/orchestrator/plugins/orchestrator-form-react/src/utils/StepperContext.tsx new file mode 100644 index 00000000..fc1534d5 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-form-react/src/utils/StepperContext.tsx @@ -0,0 +1,61 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; + +export type StepperContext = { + activeStep: number; + handleNext: () => void; + handleBack: () => void; + reviewStep: React.ReactNode; + isValidating: boolean; + handleValidateStarted: () => void; + handleValidateEnded: () => void; +}; + +const context = React.createContext(null); + +export const useStepperContext = (): StepperContext => { + const multiStepFormContext = React.useContext(context); + if (!multiStepFormContext) { + throw new Error('Context StepperContext is not defined'); + } + return multiStepFormContext; +}; + +export const StepperContextProvider = ({ + children, + reviewStep, +}: { + children: React.ReactNode; + reviewStep: React.ReactNode; +}) => { + const [activeStep, setActiveStep] = React.useState(0); + const [isValidating, setIsValidating] = React.useState(false); + const contextData = React.useMemo(() => { + return { + activeStep, + handleNext: () => { + setActiveStep(curActiveStep => curActiveStep + 1); + }, + handleBack: () => setActiveStep(curActiveStep => curActiveStep - 1), + reviewStep, + isValidating, + handleValidateStarted: () => setIsValidating(true), + handleValidateEnded: () => setIsValidating(false), + }; + }, [setActiveStep, activeStep, reviewStep, isValidating, setIsValidating]); + return {children}; +}; diff --git a/workspaces/orchestrator/plugins/orchestrator-form-react/src/utils/generateReviewTableData.test.ts b/workspaces/orchestrator/plugins/orchestrator-form-react/src/utils/generateReviewTableData.test.ts new file mode 100644 index 00000000..d2066670 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-form-react/src/utils/generateReviewTableData.test.ts @@ -0,0 +1,169 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import type { JSONSchema7 } from 'json-schema'; + +import generateReviewTableData from './generateReviewTableData'; + +describe('mapSchemaToData', () => { + it('should map schema titles to data values correctly', () => { + const schema: JSONSchema7 = { + type: 'object', + title: 'Person', + properties: { + firstName: { + type: 'string', + title: 'First Name', + }, + lastName: { + type: 'string', + title: 'Last Name', + }, + age: { + type: 'number', + title: 'Age', + }, + address: { + type: 'object', + title: 'Address', + properties: { + street: { + type: 'string', + title: 'Street', + }, + city: { + type: 'string', + title: 'City', + }, + }, + }, + }, + }; + + const data = { + firstName: 'John', + lastName: 'Doe', + age: 30, + address: { + street: '123 Main St', + city: 'Somewhere', + }, + }; + + const expectedResult = { + 'First Name': 'John', + 'Last Name': 'Doe', + Age: 30, + Address: { + Street: '123 Main St', + City: 'Somewhere', + }, + }; + + const result = generateReviewTableData(schema, data); + expect(result).toEqual(expectedResult); + }); + + it('should map schema titles to data values with arrays correctly', () => { + const schema: JSONSchema7 = { + type: 'object', + title: 'Person', + properties: { + firstName: { + type: 'string', + title: 'First Name', + }, + hobbies: { + type: 'array', + title: 'Hobbies', + items: { + type: 'string', + }, + }, + }, + }; + + const data = { + firstName: 'Jane', + hobbies: ['reading', 'hiking'], + }; + + const expectedResult = { + 'First Name': 'Jane', + Hobbies: ['reading', 'hiking'], + }; + + const result = generateReviewTableData(schema, data); + expect(result).toEqual(expectedResult); + }); + + it('should map schema titles to data values with complex nesting correctly', () => { + const schema: JSONSchema7 = { + type: 'object', + properties: { + person: { + type: 'object', + title: 'Person', + properties: { + name: { + type: 'string', + title: 'Name', + }, + addresses: { + type: 'array', + title: 'Addresses', + items: { + type: 'object', + properties: { + street: { type: 'string' }, + city: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }; + + const data = { + person: { + name: 'John', + addresses: [ + { street: '123 A St', city: 'City A' }, + { street: '456 B St', city: 'City B' }, + ], + }, + }; + + const expectedResult = { + Person: { + Name: 'John', + Addresses: [ + { + street: '123 A St', + city: 'City A', + }, + { + street: '456 B St', + city: 'City B', + }, + ], + }, + }; + + const result = generateReviewTableData(schema, data); + expect(result).toEqual(expectedResult); + }); +}); diff --git a/workspaces/orchestrator/plugins/orchestrator-form-react/src/utils/generateReviewTableData.ts b/workspaces/orchestrator/plugins/orchestrator-form-react/src/utils/generateReviewTableData.ts new file mode 100644 index 00000000..85131ba0 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-form-react/src/utils/generateReviewTableData.ts @@ -0,0 +1,76 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// import { JSONSchema7 } from 'json-schema'; +import { JsonObject, JsonValue } from '@backstage/types'; + +import type { JSONSchema7 } from 'json-schema'; +import { JsonSchema, Draft07 as JSONSchema } from 'json-schema-library'; + +export function isJsonObject(value?: JsonValue): value is JsonObject { + return typeof value === 'object' && value !== null && !Array.isArray(value); +} + +export function processSchema( + key: string, + value: JsonValue | undefined, + schema: JSONSchema7, + formState: JsonObject, +): JsonObject { + const parsedSchema = new JSONSchema(schema); + const definitionInSchema = + key === '' + ? (schema as JsonSchema) + : parsedSchema.getSchema({ + pointer: `#/${key}`, + data: formState, + }); + + const name = definitionInSchema?.title ?? key; + if (definitionInSchema) { + if (definitionInSchema['ui:widget'] === 'password') { + return { [name]: '******' }; + } + + if (isJsonObject(value)) { + // Recurse nested objects + const nestedValue = Object.entries(value).reduce( + (prev, [nestedKey, _nestedValue]) => { + const curKey = key ? `${key}/${nestedKey}` : nestedKey; + return { + ...prev, + ...processSchema(curKey, _nestedValue, schema, formState), + }; + }, + {}, + ); + return { [name]: nestedValue }; + } + } + + return { [name]: value }; +} + +function generateReviewTableData( + schema: JSONSchema7, + data: JsonObject, +): JsonObject { + schema.title = ''; + const result = processSchema('', data, schema, data); + return result[''] as JsonObject; +} + +export default generateReviewTableData; diff --git a/workspaces/orchestrator/plugins/orchestrator-form-react/src/utils/generateUiSchema.test.ts b/workspaces/orchestrator/plugins/orchestrator-form-react/src/utils/generateUiSchema.test.ts new file mode 100644 index 00000000..46ec7889 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-form-react/src/utils/generateUiSchema.test.ts @@ -0,0 +1,531 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { UiSchema } from '@rjsf/utils'; +import type { JSONSchema7 } from 'json-schema'; + +import generateUiSchema from './generateUiSchema'; + +describe('extract ui schema', () => { + it('if has properties ui: should create ui schema with properties', () => { + const expected = { + name: { 'ui:validationType': 'product', 'ui:autofocus': true }, + color: { 'ui:widget': 'color1', 'ui:validationType': 'color' }, + }; + const mixedSchema: JSONSchema7 = { + title: 'Product', + type: 'object', + properties: { + name: { + type: 'string', + title: 'Product Name', + 'ui:validationType': 'product', + }, + color: { + type: 'string', + title: 'Product Color', + description: 'The color of the product', + 'ui:widget': 'color1', + 'ui:validationType': 'color', + }, + }, + required: ['name', 'color'], + } as JSONSchema7; + const uiSchema = generateUiSchema(mixedSchema, false); + expect(uiSchema).toEqual(expected); + }); + + it('if no properties ui: should create ui schema just with auto focus', () => { + const mixedSchema: JSONSchema7 = { + title: 'Product', + type: 'object', + properties: { + name: { + type: 'string', + title: 'Product Name', + }, + color: { + type: 'string', + title: 'Product Color', + description: 'The color of the product', + }, + }, + required: ['name', 'color'], + } as JSONSchema7; + const uiSchema = generateUiSchema(mixedSchema, false); + expect(uiSchema).toEqual({ name: { 'ui:autofocus': true } }); + }); + + it('should extract from array', () => { + const mixedSchema = { + title: 'A list of tasks', + type: 'object', + required: ['title'], + properties: { + title: { + type: 'string', + title: 'Task list title', + }, + tasks: { + type: 'array', + title: 'Tasks', + items: { + type: 'object', + required: ['title'], + properties: { + title: { + type: 'string', + title: 'Title', + description: 'A sample title', + }, + details: { + type: 'string', + title: 'Task details', + description: 'Enter the task details', + 'ui:widget': 'textarea', + }, + done: { + type: 'boolean', + title: 'Done?', + default: false, + }, + }, + }, + }, + }, + } as JSONSchema7; + const expected = { + title: { + 'ui:autofocus': true, + }, + tasks: { + items: { + details: { + 'ui:widget': 'textarea', + }, + }, + }, + } as UiSchema; + const uiSchema = generateUiSchema(mixedSchema, false); + expect(uiSchema).toEqual(expected); + }); + + it('should extract from array with fixed number of items', () => { + const mixedSchema = { + type: 'object', + properties: { + fixedItemsList: { + type: 'array', + title: 'A list of fixed items', + items: [ + { + title: 'A string value', + type: 'string', + default: 'lorem ipsum', + 'ui:widget': 'textarea', + }, + { + title: 'a boolean value', + type: 'boolean', + }, + ], + additionalItems: { + title: 'Additional item', + type: 'number', + }, + }, + }, + } as JSONSchema7; + const expected = { + fixedItemsList: { + items: [ + { + 'ui:widget': 'textarea', + }, + ], + 'ui:autofocus': true, + }, + } as JSONSchema7; + + const uiSchema = generateUiSchema(mixedSchema, false); + expect(uiSchema).toEqual(expected); + }); + + it('should handle anyOf', () => { + const schemaWithAnyOf = { + title: 'A selection of items', + type: 'object', + properties: { + selectedItem: { + anyOf: [ + { type: 'number', title: 'Number item' }, + { type: 'boolean', title: 'Boolean item' }, + { type: 'string', title: 'Color', 'ui:widget': 'color' }, + ], + }, + }, + } as JSONSchema7; + + const expected = { + selectedItem: { + anyOf: [{}, {}, { 'ui:widget': 'color' }], + 'ui:autofocus': true, + }, + }; + + const uiSchema = generateUiSchema(schemaWithAnyOf, false); + expect(uiSchema).toEqual(expected); + }); + + it('should handle oneOf', () => { + const schemaWithAnyOf = { + title: 'A selection of items', + type: 'object', + properties: { + selectedItem: { + oneOf: [ + { type: 'string', title: 'Color', 'ui:widget': 'color' }, + { type: 'number', title: 'Number item' }, + { type: 'boolean', title: 'Boolean item' }, + ], + }, + }, + } as JSONSchema7; + + const expected = { + selectedItem: { + oneOf: [{ 'ui:widget': 'color' }], + 'ui:autofocus': true, + }, + }; + + const uiSchema = generateUiSchema(schemaWithAnyOf, false); + expect(uiSchema).toEqual(expected); + }); + + it('should handle allOf', () => { + const schemaWithAnyOf = { + title: 'A selection of items', + type: 'object', + properties: { + selectedItem: { + allOf: [ + { type: 'string', title: 'Color', 'ui:widget': 'color' }, + { type: 'number', title: 'Number item' }, + { type: 'boolean', title: 'Boolean item' }, + ], + }, + }, + } as JSONSchema7; + + const expected = { + selectedItem: { + allOf: [{ 'ui:widget': 'color' }], + 'ui:autofocus': true, + }, + }; + + const uiSchema = generateUiSchema(schemaWithAnyOf, false); + expect(uiSchema).toEqual(expected); + }); + + it('should handle referenced schemas', () => { + const refSchema = { + title: 'A referenced schema', + type: 'object', + properties: { + user: { + $ref: '#/definitions/User', + }, + }, + definitions: { + User: { + type: 'object', + properties: { + firstName: { + type: 'string', + title: 'First name', + 'ui:widget': 'textarea', + 'ui:autofocus': true, + }, + lastName: { type: 'string', title: 'Last name' }, + }, + }, + }, + } as JSONSchema7; + + const expected = { + user: { + firstName: { 'ui:autofocus': true, 'ui:widget': 'textarea' }, + }, + }; + + const uiSchema = generateUiSchema(refSchema, true); + expect(uiSchema).toEqual(expected); + }); + + it('should handle schemas with multiple hierarchies', () => { + const complexSchema = { + title: 'Complex schema with multiple hierarchies', + type: 'object', + properties: { + person: { + type: 'object', + properties: { + name: { type: 'string', title: 'Name' }, + password: { + type: 'string', + title: 'Name', + 'ui:widget': 'password', + }, + address: { + type: 'object', + properties: { + street: { + type: 'string', + title: 'Street', + 'ui:widget': 'textarea', + }, + city: { + type: 'string', + title: 'City', + 'ui:widget': 'textarea', + }, + }, + }, + }, + }, + }, + } as JSONSchema7; + + const expected = { + person: { + name: { 'ui:autofocus': true }, + password: { 'ui:widget': 'password' }, + address: { + street: { 'ui:widget': 'textarea' }, + city: { 'ui:widget': 'textarea' }, + }, + }, + }; + + const uiSchema = generateUiSchema(complexSchema, true); + expect(uiSchema).toEqual(expected); + }); + + it('should handle if/then/else schema with ui:widget: "textarea"', () => { + const schemaWithIfThenElse = { + title: 'Conditional Schema', + type: 'object', + properties: { + age: { type: 'number', title: 'Age', 'ui:autofocus': true }, + }, + if: { + properties: { age: { minimum: 18 } }, + }, + then: { + properties: { + canVote: { + type: 'boolean', + title: 'Can vote?', + 'ui:description': 'can vote', + }, + }, + }, + else: { + properties: { + needsConsent: { + type: 'boolean', + title: 'Needs parental consent?', + 'ui:description': 'needs consent', + }, + }, + }, + } as JSONSchema7; + + const expected = { + age: { 'ui:autofocus': true }, + canVote: { 'ui:description': 'can vote' }, + needsConsent: { 'ui:description': 'needs consent' }, + }; + + const uiSchema = generateUiSchema(schemaWithIfThenElse, false); + expect(uiSchema).toEqual(expected); + }); + + it('should handle a complex schema with various ui: properties and $ref, including readonly data', () => { + const complexSchema = { + title: 'Complex Schema Example', + type: 'object', + properties: { + userInfo: { + type: 'object', + properties: { + name: { + type: 'string', + title: 'Name', + 'ui:autofocus': true, + 'ui:widget': 'text', + 'ui:placeholder': 'Enter your name', + 'ui:description': 'Full legal name', + }, + age: { + type: 'number', + title: 'Age', + 'ui:widget': 'updown', + 'ui:help': 'Enter your age in years', + }, + address: { + $ref: '#/definitions/Address', + }, + }, + }, + tasks: { + type: 'array', + title: 'Tasks', + items: { + type: 'object', + required: ['title'], + properties: { + title: { + type: 'string', + title: 'Title', + 'ui:widget': 'color', + 'ui:description': 'Color-coded task title', + }, + details: { + type: 'string', + title: 'Task details', + 'ui:widget': 'textarea', + 'ui:placeholder': 'Describe the task in detail', + }, + done: { + type: 'boolean', + title: 'Done?', + 'ui:widget': 'checkbox', + }, + }, + }, + }, + preferences: { + type: 'object', + properties: { + notifications: { + anyOf: [ + { + type: 'boolean', + title: 'Receive Notifications', + 'ui:widget': 'radio', + 'ui:options': { inline: true }, + }, + { + type: 'string', + title: 'Notification Email', + 'ui:widget': 'email', + 'ui:placeholder': 'you@example.com', + }, + ], + }, + }, + }, + }, + definitions: { + Address: { + type: 'object', + properties: { + street: { + type: 'string', + title: 'Street', + 'ui:widget': 'textarea', + 'ui:placeholder': '123 Main St', + }, + city: { + type: 'string', + title: 'City', + 'ui:widget': 'select', + 'ui:emptyValue': 'Select a city', + }, + }, + }, + }, + } as unknown as JSONSchema7; + + const expected = { + userInfo: { + name: { + 'ui:autofocus': true, + 'ui:widget': 'text', + 'ui:placeholder': 'Enter your name', + 'ui:description': 'Full legal name', + }, + age: { + 'ui:widget': 'updown', + 'ui:help': 'Enter your age in years', + }, + address: { + street: { + 'ui:widget': 'textarea', + 'ui:placeholder': '123 Main St', + }, + city: { + 'ui:widget': 'select', + 'ui:emptyValue': 'Select a city', + }, + }, + }, + tasks: { + items: { + title: { + 'ui:widget': 'color', + 'ui:description': 'Color-coded task title', + }, + details: { + 'ui:widget': 'textarea', + 'ui:placeholder': 'Describe the task in detail', + }, + done: { + 'ui:widget': 'checkbox', + }, + 'ui:readonly': true, + }, + }, + preferences: { + notifications: { + anyOf: [ + { + 'ui:widget': 'radio', + 'ui:options': { inline: true }, + }, + { + 'ui:widget': 'email', + 'ui:placeholder': 'you@example.com', + }, + ], + }, + }, + }; + + const uiSchema = generateUiSchema(complexSchema, true, { + tasks: { + items: { + title: 'purple', + details: 'abc', + done: true, + }, + }, + }); + expect(uiSchema).toEqual(expected); + }); +}); diff --git a/workspaces/orchestrator/plugins/orchestrator-form-react/src/utils/generateUiSchema.ts b/workspaces/orchestrator/plugins/orchestrator-form-react/src/utils/generateUiSchema.ts new file mode 100644 index 00000000..9567ad2e --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-form-react/src/utils/generateUiSchema.ts @@ -0,0 +1,236 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* eslint-disable @typescript-eslint/no-use-before-define */ + +import { JsonObject } from '@backstage/types'; + +import { UiSchema } from '@rjsf/utils'; +import type { JSONSchema7, JSONSchema7Definition } from 'json-schema'; +import get from 'lodash/get'; +import set from 'lodash/set'; + +/** + * Extracts the uiSchema from a mixed JSON Schema that includes + * both standard JSON Schema properties and react-json-schema-form specific + * UI Schema properties (prefixed with 'ui:'). The function does not modify + * the original JSON Schema. + * + * @param mixedSchema - The JSON Schema that contains both standard and UI Schema properties. + * @returns An object representing the uiSchema. + */ + +const getSchemaDefinition = (ref: string, rootSchema: JSONSchema7) => { + const path = ref.replace(/^#\//, '').replace(/\//g, '.'); + return get(rootSchema, path); +}; + +const getStringAfterDot = (input: string) => + input.startsWith('.') ? input.slice(1) : input; + +function replaceSparseArrayElementsdWithEmptyObject(value: any): any { + /* handle cases where ui: properties exists for some of the itmes in the array, for example: + { + "selectedItem": { + "anyOf": [ + , + , + { + "ui:widget": "color", + }, + ], + } + the function will return + { + "selectedItem": { + "anyOf": [ + {}, + {}, + { + "ui:widget": "color", + }, + ], + } + */ + if (Array.isArray(value)) { + return [...value].map(item => { + return item ? replaceSparseArrayElementsdWithEmptyObject(item) : {}; + }); + } else if (value && typeof value === 'object') { + return Object.keys(value).reduce((acc, key) => { + acc[key] = replaceSparseArrayElementsdWithEmptyObject(value[key]); + return acc; + }, {} as Record); + } + return value; +} + +function extractUiSchema(mixedSchema: JSONSchema7): UiSchema { + const rootSchema = mixedSchema; + const result = {}; + + const processObjectProperties = ( + properties: { + [key: string]: JSONSchema7Definition; + }, + path: string, + ) => { + for (const [key, value] of Object.entries(properties)) { + // eslint-disable-next-line @typescript-eslint/no-use-before-define + processObject(value, `${path}.${key}`); + } + }; + + const processObject = (curSchema: JSONSchema7Definition, path: string) => { + if (typeof curSchema === 'boolean') { + return; + } + if (curSchema.$ref) { + processObject(getSchemaDefinition(curSchema.$ref, rootSchema), path); + } else if (curSchema.properties) { + processObjectProperties(curSchema.properties, path); + } else if (curSchema.items) { + processArraySchema(curSchema, path); + } else { + processLeafSchema(curSchema, path); + } + processComposedSchema(curSchema, path); + }; + + const processLeafSchema = ( + leafSchema: JSONSchema7Definition, + path: string, + ) => { + for (const [subSchemaKey, value] of Object.entries(leafSchema)) { + if (subSchemaKey.startsWith('ui:')) { + set(result, getStringAfterDot(`${path}.${subSchemaKey}`), value); + } + } + }; + + const processArrayItems = (items: JSONSchema7Definition[], path: string) => { + for (let i = 0; i < items.length; ++i) { + processObject(items[i], `${path}[${i}]`); + } + }; + + const processArraySchema = (schema: JSONSchema7, path: string) => { + if (Array.isArray(schema.items)) { + processArrayItems(schema.items, `${path}.items`); + } else if (typeof schema.items === 'object') { + processObject(schema.items, `${path}.items`); + } + if (schema.additionalItems && typeof schema.additionalItems === 'object') { + processObject(schema.additionalItems, `${path}.additinalItems`); + } + }; + + const processComposedSchema = (curSchema: JSONSchema7, path: string) => { + if (curSchema.anyOf) { + processArrayItems(curSchema.anyOf, `${path}.anyOf`); + } else if (curSchema.oneOf) { + processArrayItems(curSchema.oneOf, `${path}.oneOf`); + } else if (curSchema.allOf) { + processArrayItems(curSchema.allOf, `${path}.allOf`); + } else if (curSchema.then) { + processObject(curSchema.then, `${path}`); + if (curSchema.else) { + processObject(curSchema.else, `${path}`); + } + } + }; + + processObject(mixedSchema, ''); + return replaceSparseArrayElementsdWithEmptyObject(result); +} + +const addReadonly = ( + data: JsonObject, + uiSchema: UiSchema, + isMultiStep: boolean, +) => { + // make inputs that came from assessment instance variables readonly + if (!isMultiStep) { + for (const key of Object.keys(data)) { + uiSchema[key] = { + ...uiSchema[key], + 'ui:readonly': true, + }; + } + return; + } + for (const [stepKey, stepValue] of Object.entries(data)) { + uiSchema[stepKey] = { + ...uiSchema[stepKey], + }; + for (const key of Object.keys(stepValue as JsonObject)) { + uiSchema[stepKey][key] = { + ...uiSchema[stepKey][key], + 'ui:readonly': true, + }; + } + } +}; + +const addFocusOnFirstElement = ( + schema: JSONSchema7, + uiSchema: UiSchema, + isMultiStep: boolean, +) => { + if (!schema.properties) { + return; + } + if (!isMultiStep) { + const firstKey = Object.keys(schema.properties)[0]; + uiSchema[firstKey] = { + ...uiSchema[firstKey], + 'ui:autofocus': true, + }; + } + for (const [stepKey, subSchema] of Object.entries(schema.properties)) { + if (typeof subSchema !== 'object') { + return; + } + const _subSchema = subSchema.$ref + ? getSchemaDefinition(subSchema.$ref, schema) + : subSchema; + if (!_subSchema.properties) { + return; + } + const subSchemaFirstKey = Object.keys(_subSchema.properties)[0]; + uiSchema[stepKey] = { + ...uiSchema[stepKey], + [subSchemaFirstKey]: { + ...uiSchema[stepKey]?.[subSchemaFirstKey], + 'ui:autofocus': true, + }, + }; + } +}; + +const generateUiSchema = ( + schema: JSONSchema7, + isMultiStep: boolean, + readonlyData?: JsonObject, +): UiSchema => { + const uiSchema = extractUiSchema(schema); + if (readonlyData) { + addReadonly(readonlyData, uiSchema, isMultiStep); + } + addFocusOnFirstElement(schema, uiSchema, isMultiStep); + return uiSchema; +}; + +export default generateUiSchema; diff --git a/workspaces/orchestrator/plugins/orchestrator-form-react/src/utils/useValidator.ts b/workspaces/orchestrator/plugins/orchestrator-form-react/src/utils/useValidator.ts new file mode 100644 index 00000000..09a949f1 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-form-react/src/utils/useValidator.ts @@ -0,0 +1,102 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { JsonObject } from '@backstage/types'; + +import { + createErrorHandler, + CustomValidator, + ErrorSchema, + RJSFValidationError, + unwrapErrorHandler, + ValidationData, + validationDataMerge, + ValidatorType, +} from '@rjsf/utils'; +import validatorAjv from '@rjsf/validator-ajv8'; +import _validator from '@rjsf/validator-ajv8'; +import type { JSONSchema7 } from 'json-schema'; + +import { useStepperContext } from './StepperContext'; + +// add the activeStep to the validator to force rjsf form to rerender when activeStep changes. This doesn't happen because it assumes function are equal. +// see https://github.com/rjsf-team/react-jsonschema-form/blob/v5.18.5/packages/utils/src/deepEquals.ts#L12 + +export type ValidatorTypeForceRender = ValidatorType< + JsonObject, + JSONSchema7 +> & { + activeStep: number; +}; + +const useValidator = (isMultiStepSchema: boolean) => { + const { activeStep } = useStepperContext(); + const validator: ValidatorTypeForceRender = { + activeStep, + validateFormData: ( + formData: JsonObject, + _schema: JSONSchema7, + customValidate: CustomValidator, + ): ValidationData => { + let validationData = validatorAjv.validateFormData(formData, _schema); + + if (customValidate) { + const errorHandler = customValidate( + formData, + createErrorHandler(formData), + ); + const userErrorSchema = unwrapErrorHandler(errorHandler); + validationData = validationDataMerge( + validationData, + userErrorSchema, + ); + } + + if (!isMultiStepSchema) { + return validationData; + } + + const activeKey = Object.keys(_schema.properties || {})[activeStep]; + return { + errors: validationData.errors.filter(err => + err.property?.startsWith(`.${activeKey}.`), + ), + errorSchema: validationData.errorSchema[activeKey] || {}, + }; + }, + + toErrorList: ( + errorSchema?: ErrorSchema, + fieldPath?: string[], + ): RJSFValidationError[] => { + return validatorAjv.toErrorList(errorSchema, fieldPath); + }, + + isValid: ( + _schema: JSONSchema7, + formData: JsonObject | undefined, + rootSchema: JSONSchema7, + ) => { + return validatorAjv.isValid(_schema, formData, rootSchema); + }, + + rawValidation: (_schema: JSONSchema7, formData?: JsonObject) => + validatorAjv.rawValidation(_schema, formData), + }; + + return validator; +}; + +export default useValidator; diff --git a/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope/.eslintignore b/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope/.eslintignore new file mode 100644 index 00000000..b19336e4 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope/.eslintignore @@ -0,0 +1,3 @@ +playwright.config.ts +dist/ +dist-types/ \ No newline at end of file diff --git a/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope/.eslintrc.js b/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope/.eslintrc.js new file mode 100644 index 00000000..e2a53a6a --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope/.prettierignore b/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope/.prettierignore new file mode 100644 index 00000000..fc8357d9 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope/.prettierignore @@ -0,0 +1,12 @@ +dist +dist-types +coverage +.vscode +CHANGELOG.md +generated +templates +*.hbs +renovate.json +dist-dynamic +dist-scalprum +playwright-report diff --git a/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope/.prettierrc.js b/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope/.prettierrc.js new file mode 100644 index 00000000..5f81a8a0 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope/.prettierrc.js @@ -0,0 +1,20 @@ +// @ts-check + +/** @type {import("@ianvs/prettier-plugin-sort-imports").PrettierConfig} */ +module.exports = { + ...require('@spotify/prettier-config'), + plugins: ['@ianvs/prettier-plugin-sort-imports'], + importOrder: [ + '^react(.*)$', + '', + '^@backstage/(.*)$', + '', + '', + '', + '^@red-hat-developer-hub/(.*)$', + '', + '', + '', + '^[.]', + ], +}; diff --git a/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope/README.md b/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope/README.md new file mode 100644 index 00000000..f9741626 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope/README.md @@ -0,0 +1,32 @@ +# @red-hat-developer-hub/backstage-plugin-orchestrator-swf-editor-envelope + +## Description + +This package includes assets that are meant to be served as a single page application. +This package has no entrypoint, therefore it is not suitable to be consumed as a library. +The Orchestrator plugin uses these assets when it renders the Serverless Workflow editor by injecting an `iframe` that loads this application. + +## Development + +1. Build the project using `yarn build`. The `postbuild` script updates the `orchestrator-backend`'s static directory with your changes. +1. Serve the files in the `dist` directroy + +- Either use `@red-hat-developer-hub/backstage-plugin-orchestrator-backend` internal `static` directory (files under `plugins/orchestrator-backend/static/*` are served statically). +- Or, serve the files directly with: + ```sh + yarn dlx serve \ + --port 8080 \ + --cors \ + --debug \ + node_modules/@red-hat-developer-hub/backstage-plugin-orchestrator-swf-editor-envelope/dist + ``` + +3. Add this configuration to the `app-config.yaml`: + ```yaml + backend: + csp: + frame-ancestors: ['http://localhost:3000', 'http://localhost:7007'] + script-src: ["'self'", "'unsafe-inline'", "'unsafe-eval'"] + script-src-elem: ["'self'", "'unsafe-inline'", "'unsafe-eval'"] + connect-src: ["'self'", 'http:', 'https:', 'data:'] + ``` diff --git a/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope/catalog-info.yaml b/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope/catalog-info.yaml new file mode 100644 index 00000000..0eb4df62 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope/catalog-info.yaml @@ -0,0 +1,25 @@ +# https://backstage.io/docs/features/software-catalog/descriptor-format#kind-component +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: red-hat-developer-hub-orchestrator-swf-editor-envelope + title: '@red-hat-developer-hub/backstage-plugin-orchestrator-swf-editor-envelope' + description: Serverless workflow editor envelope for the Orchestrator plugin + annotations: + backstage.io/source-location: url:https://github.com/redhat-developer/rhdh-plugins/tree/main/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope + backstage.io/view-url: https://github.com/redhat-developer/rhdh-plugins/blob/main/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope/catalog-info.yaml + backstage.io/edit-url: https://github.com/redhat-developer/rhdh-plugins/edit/main/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope/catalog-info.yaml + github.com/project-slug: red-hat-developer-hub/backstage-plugins + github.com/team-slug: red-hat-developer-hub/orchestrator-codeowners + sonarqube.org/project-key: red_hat_developer_hub_plugins + links: + - url: https://github.com/redhat-developer/rhdh-plugins/tree/main/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope + title: GitHub Source + icon: source + type: source +spec: + type: backstage-frontend-plugin + lifecycle: production + owner: orchestrator-team + system: rhdh + subcomponentOf: red-hat-developer-hub-plugins diff --git a/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope/package.json b/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope/package.json new file mode 100644 index 00000000..5b3a6780 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope/package.json @@ -0,0 +1,87 @@ +{ + "name": "@red-hat-developer-hub/backstage-plugin-orchestrator-swf-editor-envelope", + "description": "Serverless workflow editor envelope for the Orchestrator plugin", + "version": "1.0.0", + "license": "Apache-2.0", + "publishConfig": { + "access": "public" + }, + "private": true, + "workspaces": { + "nohoist": [ + "@kie-tools/**" + ] + }, + "backstage": { + "role": "web-library", + "supported-versions": "1.32.5", + "pluginId": "orchestrator-swf-editor-envelope", + "pluginPackages": [ + "@red-hat-developer-hub/backstage-plugin-orchestrator-swf-editor-envelope" + ] + }, + "sideEffects": false, + "scripts": { + "build": "scripts/build.sh", + "postbuild": "node scripts/postbuild.js copy", + "clean": "backstage-cli package clean", + "lint:check": "backstage-cli package lint", + "lint:fix": "backstage-cli package lint --fix", + "postpack": "backstage-cli package postpack", + "prepack": "backstage-cli package prepack", + "test": "backstage-cli package test --passWithNoTests --coverage", + "tsc": "tsc", + "prettier:check": "prettier --ignore-unknown --check .", + "prettier:fix": "prettier --ignore-unknown --write ." + }, + "dependencies": { + "@kie-tools-core/editor": "^0.32.0", + "@kie-tools-core/keyboard-shortcuts": "^0.32.0", + "@kie-tools/serverless-workflow-combined-editor": "^0.32.0", + "@kie-tools/serverless-workflow-diagram-editor-assets": "^0.32.0", + "@kie-tools/serverless-workflow-diagram-editor-envelope": "^0.32.0", + "@kie-tools/serverless-workflow-text-editor": "^0.32.0" + }, + "devDependencies": { + "@backstage/cli": "0.28.2", + "clean-webpack-plugin": "4.0.0", + "css-loader": "6.11.0", + "filemanager-webpack-plugin": "8.0.0", + "html-webpack-plugin": "5.6.0", + "monaco-editor": "0.50.0", + "monaco-editor-webpack-plugin": "7.1.0", + "monaco-yaml": "5.1.1", + "node-polyfill-webpack-plugin": "3.0.0", + "prettier": "3.3.3", + "sass": "1.77.2", + "sass-loader": "14.2.1", + "style-loader": "3.3.4", + "terser-webpack-plugin": "5.3.10", + "ts-loader": "9.5.1", + "typescript": "5.4.5", + "webpack": "5.94.0", + "webpack-cli": "5.1.4" + }, + "files": [ + "dist" + ], + "repository": { + "type": "git", + "url": "https://github.com/redhat-developer/rhdh-plugins", + "directory": "workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope" + }, + "keywords": [ + "support:tech-preview", + "lifecycle:active", + "backstage", + "plugin" + ], + "homepage": "https://red.ht/rhdh", + "bugs": "https://github.com/redhat-developer/rhdh-plugins/issues", + "maintainers": [ + "@mlibra", + "@batzionb", + "@gciavarrini" + ], + "author": "The Backstage Community" +} diff --git a/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope/scripts/build.sh b/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope/scripts/build.sh new file mode 100755 index 00000000..50543162 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope/scripts/build.sh @@ -0,0 +1,7 @@ +#!/usr/bin/bash +/* eslint-disable no-console */ + +// disabling building temporarily to not break backstage plugins release job +// https://github.com/janus-idp/backstage-plugins/actions/runs/9255511136/job/25459744222#step:4:4465 +// command should be: webpack --progress +echo "build temporarily disabled"; mkdir -p dist/ diff --git a/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope/scripts/postbuild.js b/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope/scripts/postbuild.js new file mode 100755 index 00000000..58afda73 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope/scripts/postbuild.js @@ -0,0 +1,129 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* eslint-disable no-console */ + +const { dirname } = require('node:path'); +const { + cp, + symlink, + stat, + lstat, + rm, + mkdir, + constants, +} = require('node:fs/promises'); + +const errors = { + ENOENT: 2, // No such file or directory + EINVAL: 22, // Invalid argument +}; + +function locatePkg(pkgName) { + return dirname(require.resolve(`${pkgName}/package.json`)); +} + +async function validateSourceAndDestination(source, destination) { + try { + await stat(source); + } catch (e) { + console.error(`${e.message}\nDid you forget to build the project?`); + process.exit(errors[e.code]); + } + + try { + await stat(destination); + } catch (e) { + console.error(e.message); + process.exit(errors[e.code]); + } +} + +async function main([op]) { + const source = `${dirname(__dirname)}/dist`; + const destination = `${locatePkg( + '@red-hat-developer-hub/backstage-plugin-orchestrator-backend', + )}/static/generated`; + await validateSourceAndDestination(source, destination); + + switch (op) { + case 'debug': { + const msg = [`source=${source}`, `destination=${destination}`] + .join('\n') + .trimEnd(); + console.log(msg); + break; + } + case 'clean': { + await rm(`${destination}/envelope`, { recursive: true, force: true }); + break; + } + case 'copy': { + console.log( + `Copying Editor Envelope files: ${source} -> ${destination}/envelope`, + ); + + let dirExists = false; + try { + const stats = await stat(`${destination}/envelope`, constants.S_IFDIR); + dirExists = stats.isDirectory(); + } catch (error) { + // skip... + } + + if (!dirExists) { + await mkdir(`${destination}/envelope`); + } + + await cp(source, `${destination}/envelope`, { + recursive: true, + force: true, + }); + break; + } + case 'link': { + /** + * This option exists for testing/dev purposes because it saves some space. + * In the orchestrator-backend production artifact the files are copied into its static directory. + */ + + let existsAndIsSymLink = false; + try { + const stats = await lstat(`${destination}/envelope`); + existsAndIsSymLink = stats.isSymbolicLink(); + } catch { + // skip... + } + + if (existsAndIsSymLink) { + await rm(`${destination}/envelope`); + } + + console.log( + `Linking Editor Envelope files: ${destination}/envelope -> ${source}`, + ); + await symlink(source, `${destination}/envelope`); + break; + } + default: + console.error(`Invalid argument: ${op}`); + process.exit(errors.EINVAL); + } +} + +if (require.main === module) { + main(process.argv.slice(2)); +} diff --git a/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope/src/index.ejs b/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope/src/index.ejs new file mode 100644 index 00000000..734b66c9 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope/src/index.ejs @@ -0,0 +1,25 @@ + + + + + + + <%= htmlWebpackPlugin.options.title %> + + + + +
+ + diff --git a/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope/src/init/SwfEditorEnvelopeCombined.ts b/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope/src/init/SwfEditorEnvelopeCombined.ts new file mode 100644 index 00000000..f5e12815 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope/src/init/SwfEditorEnvelopeCombined.ts @@ -0,0 +1,44 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { initCustom } from '@kie-tools-core/editor/dist/envelope'; +import { NoOpKeyboardShortcutsService } from '@kie-tools-core/keyboard-shortcuts/dist/envelope'; +import { + ServerlessWorkflowCombinedEditorApi, + ServerlessWorkflowCombinedEditorChannelApi, +} from '@kie-tools/serverless-workflow-combined-editor/dist/api'; +import { ServerlessWorkflowCombinedEditorEnvelopeApi } from '@kie-tools/serverless-workflow-combined-editor/dist/api/ServerlessWorkflowCombinedEditorEnvelopeApi'; +import { ServerlessWorkflowCombinedEditorFactory } from '@kie-tools/serverless-workflow-combined-editor/dist/editor'; +import { ServerlessWorkflowCombinedEditorEnvelopeApiImpl } from '@kie-tools/serverless-workflow-combined-editor/dist/envelope'; + +initCustom< + ServerlessWorkflowCombinedEditorApi, + ServerlessWorkflowCombinedEditorEnvelopeApi, + ServerlessWorkflowCombinedEditorChannelApi +>({ + container: document.getElementById('root')!, + bus: { + postMessage: (message, targetOrigin: string, _) => + window.parent.postMessage(message, targetOrigin, _), + }, + apiImplFactory: { + create: args => + new ServerlessWorkflowCombinedEditorEnvelopeApiImpl( + args, + new ServerlessWorkflowCombinedEditorFactory(), + ), + }, + keyboardShortcutsService: new NoOpKeyboardShortcutsService(), +}); diff --git a/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope/src/init/SwfEditorEnvelopeDiagram.ts b/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope/src/init/SwfEditorEnvelopeDiagram.ts new file mode 100644 index 00000000..6577f806 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope/src/init/SwfEditorEnvelopeDiagram.ts @@ -0,0 +1,46 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { initCustom } from '@kie-tools-core/editor/dist/envelope'; +import { + ServerlessWorkflowDiagramEditorChannelApi, + ServerlessWorkflowDiagramEditorEnvelopeApi, +} from '@kie-tools/serverless-workflow-diagram-editor-envelope/dist/api'; +import { + ServerlessWorkflowDiagramEditor, + ServerlessWorkflowDiagramEditorEnvelopeApiImpl, + ServerlessWorkflowDiagramEditorFactory, +} from '@kie-tools/serverless-workflow-diagram-editor-envelope/dist/envelope'; + +initCustom< + ServerlessWorkflowDiagramEditor, + ServerlessWorkflowDiagramEditorEnvelopeApi, + ServerlessWorkflowDiagramEditorChannelApi +>({ + container: document.getElementById('root')!, + bus: { + postMessage: (message, targetOrigin: string, _) => + window.parent.postMessage(message, targetOrigin, _), + }, + apiImplFactory: { + create: args => + new ServerlessWorkflowDiagramEditorEnvelopeApiImpl( + args, + new ServerlessWorkflowDiagramEditorFactory({ + shouldLoadResourcesDynamically: true, + }), + ), + }, +}); diff --git a/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope/src/init/SwfEditorEnvelopeText.ts b/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope/src/init/SwfEditorEnvelopeText.ts new file mode 100644 index 00000000..50a61e88 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope/src/init/SwfEditorEnvelopeText.ts @@ -0,0 +1,42 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { initCustom } from '@kie-tools-core/editor/dist/envelope'; +import { + ServerlessWorkflowTextEditorApi, + ServerlessWorkflowTextEditorChannelApi, + ServerlessWorkflowTextEditorEnvelopeApi, +} from '@kie-tools/serverless-workflow-text-editor/dist/api'; +import { ServerlessWorkflowTextEditorFactory } from '@kie-tools/serverless-workflow-text-editor/dist/editor'; +import { ServerlessWorkflowTextEditorEnvelopeApiImpl } from '@kie-tools/serverless-workflow-text-editor/dist/envelope'; + +initCustom< + ServerlessWorkflowTextEditorApi, + ServerlessWorkflowTextEditorEnvelopeApi, + ServerlessWorkflowTextEditorChannelApi +>({ + container: document.getElementById('root')!, + bus: { + postMessage: (message, targetOrigin: string, _) => + window.parent.postMessage(message, targetOrigin, _), + }, + apiImplFactory: { + create: args => + new ServerlessWorkflowTextEditorEnvelopeApiImpl( + args, + new ServerlessWorkflowTextEditorFactory(), + ), + }, +}); diff --git a/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope/webpack.config.js b/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope/webpack.config.js new file mode 100644 index 00000000..da43638b --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator-swf-editor-envelope/webpack.config.js @@ -0,0 +1,181 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +const path = require('node:path'); +const editorAssets = require('@kie-tools/serverless-workflow-diagram-editor-assets'); +const { CleanWebpackPlugin } = require('clean-webpack-plugin'); +const FileManagerPlugin = require('filemanager-webpack-plugin'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); +const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin'); +const TerserPlugin = require('terser-webpack-plugin'); +const NodePolyfillPlugin = require('node-polyfill-webpack-plugin'); + +const loaders = new Map(); +loaders.set('style-loader', require.resolve('style-loader')); +loaders.set('css-loader', require.resolve('css-loader')); +loaders.set('sass-loader', require.resolve('sass-loader')); + +const paths = new Map(); +paths.set('src', path.resolve(__dirname, 'src')); +paths.set('dist', path.resolve(__dirname, 'dist')); +paths.set('diagram', path.resolve(paths.get('dist'), 'diagram')); +paths.set('tsconfig', path.resolve(__dirname, 'tsconfig.json')); + +const entryPoints = new Map(); +entryPoints.set( + 'diagram', + path.resolve(paths.get('src'), 'init/SwfEditorEnvelopeDiagram.ts'), +); +entryPoints.set( + 'combined', + path.resolve(paths.get('src'), 'init/SwfEditorEnvelopeCombined.ts'), +); +entryPoints.set( + 'text', + path.resolve(paths.get('src'), 'init/SwfEditorEnvelopeText.ts'), +); + +function makeHtmlWebpackPluginOptions(editorType) { + return { + title: 'Serverless Workflow Editor Envelope', + filename: `serverless-workflow-${editorType}-editor-envelope.html`, + templateParameters: { + jsBundleFilename: `${editorType}.bundle.js`, + }, + inject: false, + }; +} + +/** @type {import('webpack-cli').CallableOption} */ +module.exports = (_env, argv) => ({ + mode: argv.mode ?? 'production', + optimization: { + splitChunks: { + cacheGroups: { + monacoEditorMin: { + test: /[\\/]node_modules[\\/]monaco-editor/, + name: 'monaco-editor', + chunks: 'async', + }, + }, + }, + minimizer: [ + new TerserPlugin({ + terserOptions: { + format: { + comments: false, + }, + }, + extractComments: false, + }), + ], + }, + performance: { + maxEntrypointSize: 1024 * 1024 * 15, + maxAssetSize: 1024 * 1024 * 15, + }, + entry: { + combined: entryPoints.get('combined'), + diagram: entryPoints.get('diagram'), + text: entryPoints.get('text'), + }, + plugins: [ + new CleanWebpackPlugin(), + new NodePolyfillPlugin(), + new HtmlWebpackPlugin(makeHtmlWebpackPluginOptions('combined')), + new HtmlWebpackPlugin(makeHtmlWebpackPluginOptions('diagram')), + new HtmlWebpackPlugin(makeHtmlWebpackPluginOptions('text')), + new MonacoWebpackPlugin({ + languages: ['json'], + customLanguages: [ + { + label: 'yaml', + entry: ['monaco-yaml', 'vs/basic-languages/yaml/yaml.contribution'], + worker: { + id: 'monaco-yaml/yamlWorker', + entry: 'monaco-yaml/yaml.worker.js', + }, + }, + ], + }), + new FileManagerPlugin({ + events: { + onEnd: [ + { + copy: [ + { + source: editorAssets.swEditorPath(), + destination: paths.get('diagram'), + options: { + globOptions: { ignore: ['**/WEB-INF/**/*'] }, + }, + }, + ], + }, + ], + }, + }), + ], + module: { + rules: [ + { + test: /\.m?js$/, + resolve: { + fullySpecified: false, + }, + }, + { + test: /\.tsx?$/, + include: [paths.get('src')], + use: [ + { + loader: 'ts-loader', + options: { + configFile: paths.get('tsconfig'), + allowTsInNodeModules: true, + }, + }, + ], + }, + { + test: /\.s[ac]ss$/i, + use: [ + loaders.get('style-loader'), + loaders.get('css-loader'), + loaders.get('sass-loader'), + ], + }, + { + test: /\.css$/, + use: [loaders.get('style-loader'), loaders.get('css-loader')], + }, + { + test: /\.(svg|ttf|eot|woff|woff2)$/, + type: 'asset/inline', + }, + ], + }, + output: { + path: paths.get('dist'), + filename: '[name].bundle.js', + chunkFilename: '[name].chunk.js', + }, + resolve: { + extensions: ['.ts', '.tsx', '.js', '.jsx', '.mjs'], + alias: { + prettier$: require.resolve('prettier/standalone'), + }, + }, +}); diff --git a/workspaces/orchestrator/plugins/orchestrator/.eslintignore b/workspaces/orchestrator/plugins/orchestrator/.eslintignore new file mode 100644 index 00000000..b19336e4 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator/.eslintignore @@ -0,0 +1,3 @@ +playwright.config.ts +dist/ +dist-types/ \ No newline at end of file diff --git a/workspaces/orchestrator/plugins/orchestrator/.eslintrc.js b/workspaces/orchestrator/plugins/orchestrator/.eslintrc.js new file mode 100644 index 00000000..e2a53a6a --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/workspaces/orchestrator/plugins/orchestrator/.prettierignore b/workspaces/orchestrator/plugins/orchestrator/.prettierignore new file mode 100644 index 00000000..fc8357d9 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator/.prettierignore @@ -0,0 +1,12 @@ +dist +dist-types +coverage +.vscode +CHANGELOG.md +generated +templates +*.hbs +renovate.json +dist-dynamic +dist-scalprum +playwright-report diff --git a/workspaces/orchestrator/plugins/orchestrator/.prettierrc.js b/workspaces/orchestrator/plugins/orchestrator/.prettierrc.js new file mode 100644 index 00000000..5f81a8a0 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator/.prettierrc.js @@ -0,0 +1,20 @@ +// @ts-check + +/** @type {import("@ianvs/prettier-plugin-sort-imports").PrettierConfig} */ +module.exports = { + ...require('@spotify/prettier-config'), + plugins: ['@ianvs/prettier-plugin-sort-imports'], + importOrder: [ + '^react(.*)$', + '', + '^@backstage/(.*)$', + '', + '', + '', + '^@red-hat-developer-hub/(.*)$', + '', + '', + '', + '^[.]', + ], +}; diff --git a/workspaces/orchestrator/plugins/orchestrator/CHANGELOG.md b/workspaces/orchestrator/plugins/orchestrator/CHANGELOG.md new file mode 100644 index 00000000..238cf099 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator/CHANGELOG.md @@ -0,0 +1,822 @@ +### Dependencies + +## 2.4.1 + +### Patch Changes + +- 54daa8c: Migrated from [janus-idp/backstage-plugins](https://github.com/janus-idp/backstage-plugins). +- Updated dependencies [54daa8c] + - @red-hat-developer-hub/backstage-plugin-orchestrator-common@1.24.1 + - @red-hat-developer-hub/backstage-plugin-orchestrator-form-api@1.4.2 + - @red-hat-developer-hub/backstage-plugin-orchestrator-form-react@1.4.3 + +## 2.4.0 + +### Minor Changes + +- 603a162: make error handling consistent in backend and UI + +### Patch Changes + +- 8a76b49: Makes very long workflow result messages still readable. +- b2a7181: Fix filtering by status on the Workflow Runs tab. +- Updated dependencies [aee9d4a] +- Updated dependencies [25f1787] + - @red-hat-developer-hub/backstage-plugin-orchestrator-form-react@1.4.2 + - @red-hat-developer-hub/backstage-plugin-orchestrator-common@1.24.0 + +## 2.3.2 + +### Patch Changes + +- 76674da: Fixes issue when WorkflowResult panel fails on malformed provided result. + +## 2.3.1 + +### Patch Changes + +- 0e6bfd3: feat: update Backstage to the latest version + + Update to Backstage 1.32.5 + +- Updated dependencies [0e6bfd3] +- Updated dependencies [67f466a] + - @red-hat-developer-hub/backstage-plugin-orchestrator-form-react@1.4.1 + - @red-hat-developer-hub/backstage-plugin-orchestrator-form-api@1.4.1 + - @red-hat-developer-hub/backstage-plugin-orchestrator-common@1.23.1 + +## 2.3.0 + +### Minor Changes + +- 8244f28: chore(deps): update to backstage 1.32 + +### Patch Changes + +- Updated dependencies [8244f28] + - @red-hat-developer-hub/backstage-plugin-orchestrator-form-react@1.4.0 + - @red-hat-developer-hub/backstage-plugin-orchestrator-form-api@1.4.0 + - @red-hat-developer-hub/backstage-plugin-orchestrator-common@1.23.0 + +## 2.2.1 + +### Patch Changes + +- 7342e9b: chore: remove @janus-idp/cli dep and relink local packages + + This update removes `@janus-idp/cli` from all plugins, as it’s no longer necessary. Additionally, packages are now correctly linked with a specified version. + +- Updated dependencies [7342e9b] + - @red-hat-developer-hub/backstage-plugin-orchestrator-form-react@1.3.1 + +## 2.2.0 + +### Minor Changes + +- d9551ae: feat(deps): update to backstage 1.31 + +### Patch Changes + +- d9551ae: Change local package references to a `*` +- d9551ae: pin the @janus-idp/cli package +- d9551ae: upgrade to yarn v3 +- Updated dependencies [d9551ae] +- Updated dependencies [d9551ae] +- Updated dependencies [d9551ae] +- Updated dependencies [d9551ae] + - @red-hat-developer-hub/backstage-plugin-orchestrator-form-react@1.3.0 + - @red-hat-developer-hub/backstage-plugin-orchestrator-common@1.22.0 + - @red-hat-developer-hub/backstage-plugin-orchestrator-form-api@1.3.0 + +* **@red-hat-developer-hub/backstage-plugin-orchestrator-form-react:** upgraded to 1.2.1 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.21.0 +- **@red-hat-developer-hub/backstage-plugin-orchestrator-form-react:** upgraded to 1.2.0 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.21.0 +- **@red-hat-developer-hub/backstage-plugin-orchestrator-form-api:** upgraded to 1.2.0 +- **@red-hat-developer-hub/backstage-plugin-orchestrator-form-react:** upgraded to 1.2.0 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.20.0 +- **@red-hat-developer-hub/backstage-plugin-orchestrator-form-react:** upgraded to 1.1.6 +- **@janus-idp/cli:** upgraded to 1.15.2 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.19.0 +- **@red-hat-developer-hub/backstage-plugin-orchestrator-form-react:** upgraded to 1.1.5 + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.15.1 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.18.2 +- **@red-hat-developer-hub/backstage-plugin-orchestrator-form-react:** upgraded to 1.1.4 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.18.1 +- **@red-hat-developer-hub/backstage-plugin-orchestrator-form-react:** upgraded to 1.1.3 + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.15.0 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.18.0 +- **@red-hat-developer-hub/backstage-plugin-orchestrator-form-react:** upgraded to 1.1.2 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.17.3 +- **@red-hat-developer-hub/backstage-plugin-orchestrator-form-react:** upgraded to 1.1.1 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-form-api:** upgraded to 1.1.0 +- **@red-hat-developer-hub/backstage-plugin-orchestrator-form-react:** upgraded to 1.1.0 +- **@janus-idp/cli:** upgraded to 1.14.0 + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.13.2 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.17.2 +- **@red-hat-developer-hub/backstage-plugin-orchestrator-form-react:** upgraded to 1.0.10 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.17.1 +- **@red-hat-developer-hub/backstage-plugin-orchestrator-form-react:** upgraded to 1.0.9 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.17.0 +- **@red-hat-developer-hub/backstage-plugin-orchestrator-form-react:** upgraded to 1.0.8 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.16.0 +- **@red-hat-developer-hub/backstage-plugin-orchestrator-form-react:** upgraded to 1.0.6 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.15.2 +- **@red-hat-developer-hub/backstage-plugin-orchestrator-form-react:** upgraded to 1.0.5 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-form-react:** upgraded to 1.0.4 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.15.1 +- **@red-hat-developer-hub/backstage-plugin-orchestrator-form-react:** upgraded to 1.0.3 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.15.0 +- **@red-hat-developer-hub/backstage-plugin-orchestrator-form-react:** upgraded to 1.0.2 + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.13.1 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-form-api:** upgraded to 1.0.1 +- **@red-hat-developer-hub/backstage-plugin-orchestrator-form-react:** upgraded to 1.0.1 + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.14.0 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.18.1](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.18.0...@red-hat-developer-hub/backstage-plugin-orchestrator@1.18.1) (2024-08-02) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.13.1 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.18.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.17.0...@red-hat-developer-hub/backstage-plugin-orchestrator@1.18.0) (2024-07-26) + +### Features + +- **deps:** update to backstage 1.29 ([#1900](https://github.com/janus-idp/backstage-plugins/issues/1900)) ([f53677f](https://github.com/janus-idp/backstage-plugins/commit/f53677fb02d6df43a9de98c43a9f101a6db76802)) +- **orchestrator:** use v2 endpoints to retrieve instances ([#1956](https://github.com/janus-idp/backstage-plugins/issues/1956)) ([537502b](https://github.com/janus-idp/backstage-plugins/commit/537502b9d2ac13f2fb3f79188422d2c6e97f41fb)) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.13.0 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.17.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.16.1...@red-hat-developer-hub/backstage-plugin-orchestrator@1.17.0) (2024-07-24) + +### Features + +- **deps:** update to backstage 1.28 ([#1891](https://github.com/janus-idp/backstage-plugins/issues/1891)) ([1ba1108](https://github.com/janus-idp/backstage-plugins/commit/1ba11088e0de60e90d138944267b83600dc446e5)) +- **orchestrator:** use v2 endpoints to retrieve workflow overviews ([#1892](https://github.com/janus-idp/backstage-plugins/issues/1892)) ([cca1e53](https://github.com/janus-idp/backstage-plugins/commit/cca1e53bc6b3019b1c544f2f62bed8723ebf6130)) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.12.0 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.16.1](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.16.0...@red-hat-developer-hub/backstage-plugin-orchestrator@1.16.1) (2024-07-11) + +### Bug Fixes + +- **orchestrator:** returned scrolling bars to instance page cards ([#1880](https://github.com/janus-idp/backstage-plugins/issues/1880)) ([08545da](https://github.com/janus-idp/backstage-plugins/commit/08545daabd02a7ba6f9f12dedf237afbff1cd67a)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.16.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.15.0...@red-hat-developer-hub/backstage-plugin-orchestrator@1.16.0) (2024-06-28) + +### Features + +- **orchestrator:** remove unneeded orchestrator jira integration and endpoint ([#1833](https://github.com/janus-idp/backstage-plugins/issues/1833)) ([d2a76fd](https://github.com/janus-idp/backstage-plugins/commit/d2a76fd3db028f9774c821759bee5f38b7131c94)) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.10.0 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.15.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.14.1...@red-hat-developer-hub/backstage-plugin-orchestrator@1.15.0) (2024-06-26) + +### Features + +- **orchestrator:** disable buttons based on permissions ([#1818](https://github.com/janus-idp/backstage-plugins/issues/1818)) ([36504b0](https://github.com/janus-idp/backstage-plugins/commit/36504b05d96dbbf0b2395dc6e5c155c21fa73bcd)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.14.1](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.14.0...@red-hat-developer-hub/backstage-plugin-orchestrator@1.14.1) (2024-06-19) + +### Bug Fixes + +- **matomo:** add default export for new backend system ([#1822](https://github.com/janus-idp/backstage-plugins/issues/1822)) ([5e72920](https://github.com/janus-idp/backstage-plugins/commit/5e72920209589535d503bb28e77f54175a0bd946)) + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.11.1 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.14.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.13.7...@red-hat-developer-hub/backstage-plugin-orchestrator@1.14.0) (2024-06-13) + +### Features + +- **deps:** update to backstage 1.27 ([#1683](https://github.com/janus-idp/backstage-plugins/issues/1683)) ([a14869c](https://github.com/janus-idp/backstage-plugins/commit/a14869c3f4177049cb8d6552b36c3ffd17e7997d)) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.9.0 +- **@janus-idp/cli:** upgraded to 1.11.0 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.13.7](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.13.6...@red-hat-developer-hub/backstage-plugin-orchestrator@1.13.7) (2024-06-13) + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.10.1 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.13.6](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.13.5...@red-hat-developer-hub/backstage-plugin-orchestrator@1.13.6) (2024-06-05) + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.10.0 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.13.5](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.13.4...@red-hat-developer-hub/backstage-plugin-orchestrator@1.13.5) (2024-06-04) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.8.1 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.13.4](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.13.3...@red-hat-developer-hub/backstage-plugin-orchestrator@1.13.4) (2024-06-03) + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.9.0 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.13.3](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.13.2...@red-hat-developer-hub/backstage-plugin-orchestrator@1.13.3) (2024-05-31) + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.13.2](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.13.1...@red-hat-developer-hub/backstage-plugin-orchestrator@1.13.2) (2024-05-29) + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.8.10 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.13.1](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.13.0...@red-hat-developer-hub/backstage-plugin-orchestrator@1.13.1) (2024-05-29) + +### Bug Fixes + +- **orchestrator:** upgrade to mui v5 ([#1727](https://github.com/janus-idp/backstage-plugins/issues/1727)) ([8b935dc](https://github.com/janus-idp/backstage-plugins/commit/8b935dc3c85fbe4030564301820d946effa78426)) + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.8.9 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.13.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.12.6...@red-hat-developer-hub/backstage-plugin-orchestrator@1.13.0) (2024-05-28) + +### Features + +- **orchestrator:** add permissions to orchestrator plugin ([#1599](https://github.com/janus-idp/backstage-plugins/issues/1599)) ([d0a4531](https://github.com/janus-idp/backstage-plugins/commit/d0a453181e177eb1da7b1e231253b76a2d9356a8)) +- **orchestrator:** label a Workflow assessment result as recommended ([#1705](https://github.com/janus-idp/backstage-plugins/issues/1705)) ([7e24e86](https://github.com/janus-idp/backstage-plugins/commit/7e24e86eb3094fa00b22aa77f79fb0e04dbf86f7)) + +### Bug Fixes + +- **deps:** update dependency monaco-editor to ^0.49.0 ([#1690](https://github.com/janus-idp/backstage-plugins/issues/1690)) ([34308a3](https://github.com/janus-idp/backstage-plugins/commit/34308a3ba669666ab2ddd61b2ac0073edd98f8ce)) +- **orchestrator:** bump `rjsf` dependencies ([#1715](https://github.com/janus-idp/backstage-plugins/issues/1715)) ([ea31cdb](https://github.com/janus-idp/backstage-plugins/commit/ea31cdbd7cb0a8842119f6d5d5dbd689e31040aa)) +- **orchestrator:** fix the common package reference version ([#1704](https://github.com/janus-idp/backstage-plugins/issues/1704)) ([942b2a3](https://github.com/janus-idp/backstage-plugins/commit/942b2a3b6eb29c0fe88f9c98dea581309d02fded)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.12.6](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.12.5...@red-hat-developer-hub/backstage-plugin-orchestrator@1.12.6) (2024-05-21) + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.12.5](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.12.4...@red-hat-developer-hub/backstage-plugin-orchestrator@1.12.5) (2024-05-20) + +### Bug Fixes + +- **orchestrator:** fixes many security-related issues ([#1681](https://github.com/janus-idp/backstage-plugins/issues/1681)) ([3e801c8](https://github.com/janus-idp/backstage-plugins/commit/3e801c84015f925bdecd226a161ef81a5fc69432)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.12.4](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.12.3...@red-hat-developer-hub/backstage-plugin-orchestrator@1.12.4) (2024-05-16) + +### Bug Fixes + +- **orchestrator:** remove the need of react dev dependencies ([#1650](https://github.com/janus-idp/backstage-plugins/issues/1650)) ([5e60875](https://github.com/janus-idp/backstage-plugins/commit/5e60875932b906fd40e282d53b277a0f29efc67f)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.12.3](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.12.2...@red-hat-developer-hub/backstage-plugin-orchestrator@1.12.3) (2024-05-16) + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.8.7 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.12.2](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.12.1...@red-hat-developer-hub/backstage-plugin-orchestrator@1.12.2) (2024-05-15) + +### Documentation + +- **orchestrator:** removes instructions related to the editor ([#1664](https://github.com/janus-idp/backstage-plugins/issues/1664)) ([10a75b2](https://github.com/janus-idp/backstage-plugins/commit/10a75b2706c72751bd774d6fae4332bbc527dc2b)) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.7.2 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.12.1](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.12.0...@red-hat-developer-hub/backstage-plugin-orchestrator@1.12.1) (2024-05-15) + +### Bug Fixes + +- **orchestrator:** export the `OrchestratorPlugin` accordingly ([#1644](https://github.com/janus-idp/backstage-plugins/issues/1644)) ([4a9d1f8](https://github.com/janus-idp/backstage-plugins/commit/4a9d1f821a30437e73631fac98b1aabc65473fba)) + +### Other changes + +- **orchestrator:** add OrchestratorClient unit tests ([#1640](https://github.com/janus-idp/backstage-plugins/issues/1640)) ([2a2dc55](https://github.com/janus-idp/backstage-plugins/commit/2a2dc5581aa04b20bdf973ecb8310d179d6fd1a5)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.12.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.11.2...@red-hat-developer-hub/backstage-plugin-orchestrator@1.12.0) (2024-05-14) + +### Features + +- **deps:** use RHDH themes in the backstage app and dev pages ([#1480](https://github.com/janus-idp/backstage-plugins/issues/1480)) ([8263bf0](https://github.com/janus-idp/backstage-plugins/commit/8263bf099736cbb0d0f2316082d338ba81fa6927)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.11.2](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.11.1...@red-hat-developer-hub/backstage-plugin-orchestrator@1.11.2) (2024-05-13) + +### Bug Fixes + +- **orchestrator:** typos mentioning OpenShift ([#1639](https://github.com/janus-idp/backstage-plugins/issues/1639)) ([7ff4c75](https://github.com/janus-idp/backstage-plugins/commit/7ff4c754f73681e1a596d56721972af8872f3211)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.11.1](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.11.0...@red-hat-developer-hub/backstage-plugin-orchestrator@1.11.1) (2024-05-09) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.7.1 +- **@janus-idp/cli:** upgraded to 1.8.6 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.11.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.10.6...@red-hat-developer-hub/backstage-plugin-orchestrator@1.11.0) (2024-05-09) + +### Features + +- **orchestrator:** add ability to re-trigger workflow in error state ([#1624](https://github.com/janus-idp/backstage-plugins/issues/1624)) ([8709a37](https://github.com/janus-idp/backstage-plugins/commit/8709a37d08c2eafc22f10bd2a41f0a105768222d)) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.7.0 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.10.6](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.10.5...@red-hat-developer-hub/backstage-plugin-orchestrator@1.10.6) (2024-05-06) + +### Bug Fixes + +- **orchestrator:** disabled MUI table thirdSortClick ([#1614](https://github.com/janus-idp/backstage-plugins/issues/1614)) ([5e541bd](https://github.com/janus-idp/backstage-plugins/commit/5e541bd217500c83bd8d9eb94cf060805ef4b8a9)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.10.5](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.10.4...@red-hat-developer-hub/backstage-plugin-orchestrator@1.10.5) (2024-05-02) + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.8.5 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.10.4](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.10.3...@red-hat-developer-hub/backstage-plugin-orchestrator@1.10.4) (2024-05-02) + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.8.4 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.10.3](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.10.2...@red-hat-developer-hub/backstage-plugin-orchestrator@1.10.3) (2024-05-02) + +### Bug Fixes + +- **orchestrator:** disable sorting ID column in workflow runs table ([#1595](https://github.com/janus-idp/backstage-plugins/issues/1595)) ([4d4875e](https://github.com/janus-idp/backstage-plugins/commit/4d4875eb4f91a3a3464b1ecbdcf647e9f1b84be5)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.10.2](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.10.1...@red-hat-developer-hub/backstage-plugin-orchestrator@1.10.2) (2024-04-30) + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.8.3 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.10.1](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.10.0...@red-hat-developer-hub/backstage-plugin-orchestrator@1.10.1) (2024-04-30) + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.8.2 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.10.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.9.4...@red-hat-developer-hub/backstage-plugin-orchestrator@1.10.0) (2024-04-25) + +### Features + +- **orchestrator:** add endpoint to retrigger workflow in error state ([#1343](https://github.com/janus-idp/backstage-plugins/issues/1343)) ([328d23a](https://github.com/janus-idp/backstage-plugins/commit/328d23a7992da125becc8d7775a4ebd68165f243)) + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.8.1 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.9.4](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.9.3...@red-hat-developer-hub/backstage-plugin-orchestrator@1.9.4) (2024-04-18) + +### Bug Fixes + +- **orchestrator:** allows serving the editor envelope in disconnected environments ([#1450](https://github.com/janus-idp/backstage-plugins/issues/1450)) ([1e778d8](https://github.com/janus-idp/backstage-plugins/commit/1e778d88336dfec79d48ece4fd8d2a035133b70e)) + +### Documentation + +- **orchestrator:** fix quick start urls to private repo and make image urls raw ([#1521](https://github.com/janus-idp/backstage-plugins/issues/1521)) ([eefd264](https://github.com/janus-idp/backstage-plugins/commit/eefd2642b0dd3a2d6eb26eaf229c97a280adf07c)) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.6.4 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.9.3](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.9.2...@red-hat-developer-hub/backstage-plugin-orchestrator@1.9.3) (2024-04-16) + +### Bug Fixes + +- fix typo in orchestrator documentation ([#1508](https://github.com/janus-idp/backstage-plugins/issues/1508)) ([bfa360a](https://github.com/janus-idp/backstage-plugins/commit/bfa360af97b5daf1902c267cd682e51cb6d71c83)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.9.2](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.9.1...@red-hat-developer-hub/backstage-plugin-orchestrator@1.9.2) (2024-04-15) + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.8.0 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.9.1](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.9.0...@red-hat-developer-hub/backstage-plugin-orchestrator@1.9.1) (2024-04-15) + +### Documentation + +- **orchestrator:** add a quickstart for users ([#1499](https://github.com/janus-idp/backstage-plugins/issues/1499)) ([28fe8da](https://github.com/janus-idp/backstage-plugins/commit/28fe8da644350facb4c414f1bd5ff48ba4801b24)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.9.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.8.9...@red-hat-developer-hub/backstage-plugin-orchestrator@1.9.0) (2024-04-10) + +### Features + +- **orchestrator:** make workflow last run status as link to the workflow last run details page ([#1488](https://github.com/janus-idp/backstage-plugins/issues/1488)) ([fc2f94e](https://github.com/janus-idp/backstage-plugins/commit/fc2f94ed4ff2cb0795ba3b65eeea57eae3a8640c)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.8.9](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.8.8...@red-hat-developer-hub/backstage-plugin-orchestrator@1.8.9) (2024-04-09) + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.7.10 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.8.8](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.8.7...@red-hat-developer-hub/backstage-plugin-orchestrator@1.8.8) (2024-04-09) + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.7.9 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.8.7](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.8.6...@red-hat-developer-hub/backstage-plugin-orchestrator@1.8.7) (2024-04-05) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.6.3 +- **@janus-idp/cli:** upgraded to 1.7.8 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.8.6](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.8.5...@red-hat-developer-hub/backstage-plugin-orchestrator@1.8.6) (2024-04-04) + +### Documentation + +- **orchestrator:** add OpenAPI doc ([#1441](https://github.com/janus-idp/backstage-plugins/issues/1441)) ([f6275e2](https://github.com/janus-idp/backstage-plugins/commit/f6275e2b37f467e65c267f951db8c413a69eb923)) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.6.2 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.8.5](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.8.4...@red-hat-developer-hub/backstage-plugin-orchestrator@1.8.5) (2024-04-02) + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.7.7 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.8.4](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.8.3...@red-hat-developer-hub/backstage-plugin-orchestrator@1.8.4) (2024-03-29) + +### Bug Fixes + +- **orchestrator:** fixes v2/instances endpoint ([#1414](https://github.com/janus-idp/backstage-plugins/issues/1414)) ([88b49df](https://github.com/janus-idp/backstage-plugins/commit/88b49df35cf10e231ba69c239e873cb10e7cc25b)) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.6.1 +- **@janus-idp/cli:** upgraded to 1.7.6 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.8.3](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.8.2...@red-hat-developer-hub/backstage-plugin-orchestrator@1.8.3) (2024-03-26) + +### Bug Fixes + +- **orchestrator:** remove error on Reset workflow ([#1393](https://github.com/janus-idp/backstage-plugins/issues/1393)) ([6ce210d](https://github.com/janus-idp/backstage-plugins/commit/6ce210dfb3ac82a887985057ea234cf8b6065068)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.8.2](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.8.1...@red-hat-developer-hub/backstage-plugin-orchestrator@1.8.2) (2024-03-17) + +### Bug Fixes + +- **orchestrator:** fix dropdown look ([#1344](https://github.com/janus-idp/backstage-plugins/issues/1344)) ([9284299](https://github.com/janus-idp/backstage-plugins/commit/9284299710f4d498deb098a94a2be57e6d7516a6)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.8.1](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.8.0...@red-hat-developer-hub/backstage-plugin-orchestrator@1.8.1) (2024-03-14) + +### Bug Fixes + +- **orchestrator:** update the installation instructions ([#1336](https://github.com/janus-idp/backstage-plugins/issues/1336)) ([d77e388](https://github.com/janus-idp/backstage-plugins/commit/d77e3887ee838a0d4ce075ab976203f13f2037c8)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.8.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.7.8...@red-hat-developer-hub/backstage-plugin-orchestrator@1.8.0) (2024-03-14) + +### Features + +- **orchestrator:** verify availability and cache workflow definition IDs ([#1309](https://github.com/janus-idp/backstage-plugins/issues/1309)) ([4d322f1](https://github.com/janus-idp/backstage-plugins/commit/4d322f1fc5b6f8b1afedf40cfe1b24b2edae2ac1)) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.6.0 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.7.8](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.7.7...@red-hat-developer-hub/backstage-plugin-orchestrator@1.7.8) (2024-03-12) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.5.1 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.7.7](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.7.6...@red-hat-developer-hub/backstage-plugin-orchestrator@1.7.7) (2024-03-11) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.5.0 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.7.6](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.7.5...@red-hat-developer-hub/backstage-plugin-orchestrator@1.7.6) (2024-03-11) + +### Other changes + +- **orchestrator:** add unit tests for v2 endpoints ([#1300](https://github.com/janus-idp/backstage-plugins/issues/1300)) ([9a13138](https://github.com/janus-idp/backstage-plugins/commit/9a13138c61d3cc7331f739da80f020bb68dd61e5)) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.4.1 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.7.5](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.7.4...@red-hat-developer-hub/backstage-plugin-orchestrator@1.7.5) (2024-03-07) + +### Bug Fixes + +- **orchestraotr:** resolved grey background appears in actions column in workflows table ([#1317](https://github.com/janus-idp/backstage-plugins/issues/1317)) ([cd7b4e7](https://github.com/janus-idp/backstage-plugins/commit/cd7b4e7267c804c75b4bccf927b48c32f7943ed6)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.7.4](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.7.3...@red-hat-developer-hub/backstage-plugin-orchestrator@1.7.4) (2024-03-07) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.4.0 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.7.3](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.7.2...@red-hat-developer-hub/backstage-plugin-orchestrator@1.7.3) (2024-03-07) + +### Bug Fixes + +- **orchestrator:** fix abort button and rerun button disable issue ([#1311](https://github.com/janus-idp/backstage-plugins/issues/1311)) ([0c98279](https://github.com/janus-idp/backstage-plugins/commit/0c982798872f2cb1a3b9fef7ab15850474cb03a7)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.7.2](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.7.1...@red-hat-developer-hub/backstage-plugin-orchestrator@1.7.2) (2024-03-04) + +### Bug Fixes + +- **orchestrator:** walk around the state field is empty issue when fetch instance ([#1299](https://github.com/janus-idp/backstage-plugins/issues/1299)) ([e5c33c0](https://github.com/janus-idp/backstage-plugins/commit/e5c33c06fc66a6ff393365282f825c5fdc4713c9)) + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.7.5 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.7.1](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.7.0...@red-hat-developer-hub/backstage-plugin-orchestrator@1.7.1) (2024-03-03) + +### Bug Fixes + +- **orchestrator:** stop fetching workflow URI ([#1297](https://github.com/janus-idp/backstage-plugins/issues/1297)) ([2456a28](https://github.com/janus-idp/backstage-plugins/commit/2456a287dbff955a0916b9600e89a39511cd537a)) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.3.7 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.7.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.6.7...@red-hat-developer-hub/backstage-plugin-orchestrator@1.7.0) (2024-03-03) + +### Features + +- **orchestrator:** display a description modal before triggering infra-wfs that resulted from an assessment wf ([#1284](https://github.com/janus-idp/backstage-plugins/issues/1284)) ([ec293c9](https://github.com/janus-idp/backstage-plugins/commit/ec293c9e79efd77873e17d07b1511ad9fdda8842)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.6.7](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.6.6...@red-hat-developer-hub/backstage-plugin-orchestrator@1.6.7) (2024-02-29) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.3.6 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.6.6](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.6.5...@red-hat-developer-hub/backstage-plugin-orchestrator@1.6.6) (2024-02-28) + +### Bug Fixes + +- **orchestrator:** clean up the plugin code ([#1292](https://github.com/janus-idp/backstage-plugins/issues/1292)) ([ad27fb8](https://github.com/janus-idp/backstage-plugins/commit/ad27fb8e98913a6b80feb38ff58a7864e1953a7e)) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.3.5 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.6.5](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.6.4...@red-hat-developer-hub/backstage-plugin-orchestrator@1.6.5) (2024-02-28) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.3.4 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.6.4](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.6.3...@red-hat-developer-hub/backstage-plugin-orchestrator@1.6.4) (2024-02-28) + +### Bug Fixes + +- **orchestrator:** handle nullable start/state properties of process instance ([#1277](https://github.com/janus-idp/backstage-plugins/issues/1277)) ([d8a43a5](https://github.com/janus-idp/backstage-plugins/commit/d8a43a5a164f83fc90d037ae3d7a355f5de543e0)) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.3.3 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.6.3](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.6.2...@red-hat-developer-hub/backstage-plugin-orchestrator@1.6.3) (2024-02-27) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.3.2 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.6.2](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.6.1...@red-hat-developer-hub/backstage-plugin-orchestrator@1.6.2) (2024-02-27) + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.7.4 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.6.1](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.6.0...@red-hat-developer-hub/backstage-plugin-orchestrator@1.6.1) (2024-02-26) + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.7.3 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.6.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.5.2...@red-hat-developer-hub/backstage-plugin-orchestrator@1.6.0) (2024-02-22) + +### Features + +- **orchestrator:** display a alert dialog when the user fails to abort a running workflow ([#1239](https://github.com/janus-idp/backstage-plugins/issues/1239)) ([44cb11b](https://github.com/janus-idp/backstage-plugins/commit/44cb11b80739f772f4caa4c2834287eec162b826)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.5.2](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.5.1...@red-hat-developer-hub/backstage-plugin-orchestrator@1.5.2) (2024-02-21) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.3.1 +- **@janus-idp/cli:** upgraded to 1.7.2 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.5.1](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.5.0...@red-hat-developer-hub/backstage-plugin-orchestrator@1.5.1) (2024-02-20) + +### Bug Fixes + +- **orchestrator:** decommission the ProcessInstance.lastUpdate field ([#1230](https://github.com/janus-idp/backstage-plugins/issues/1230)) ([9724e27](https://github.com/janus-idp/backstage-plugins/commit/9724e27eaa84fe73d7724f28c86409681b7f79f8)) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.3.0 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.5.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.4.3...@red-hat-developer-hub/backstage-plugin-orchestrator@1.5.0) (2024-02-18) + +### Features + +- **orchestrator:** display a confirmation dialog before the user aborts a running workflow ([#1215](https://github.com/janus-idp/backstage-plugins/issues/1215)) ([1453cf8](https://github.com/janus-idp/backstage-plugins/commit/1453cf8d42b14372c1a5c1973510450d24ae4b5a)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.4.3](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.4.2...@red-hat-developer-hub/backstage-plugin-orchestrator@1.4.3) (2024-02-16) + +### Bug Fixes + +- **orchestrator:** resolve mismatch between execution data and composed schema ([#1217](https://github.com/janus-idp/backstage-plugins/issues/1217)) ([af85114](https://github.com/janus-idp/backstage-plugins/commit/af851148935e1ed083709cac145520d7551de737)) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.2.1 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.4.2](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.4.1...@red-hat-developer-hub/backstage-plugin-orchestrator@1.4.2) (2024-02-16) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.2.0 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.4.1](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.4.0...@red-hat-developer-hub/backstage-plugin-orchestrator@1.4.1) (2024-02-14) + +### Bug Fixes + +- **orchestrator:** the instance details card content is cropped ([#1196](https://github.com/janus-idp/backstage-plugins/issues/1196)) ([eb45070](https://github.com/janus-idp/backstage-plugins/commit/eb450709e8e34972386f4e34ee842208e323a3fb)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.4.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.3.3...@red-hat-developer-hub/backstage-plugin-orchestrator@1.4.0) (2024-02-12) + +### Features + +- build Information dialog component to show confirmation or alert ([#1176](https://github.com/janus-idp/backstage-plugins/issues/1176)) ([ee8cc1d](https://github.com/janus-idp/backstage-plugins/commit/ee8cc1dad2f10d698b8fb7e19ef0f9abe3b6c6c7)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.3.3](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.3.2...@red-hat-developer-hub/backstage-plugin-orchestrator@1.3.3) (2024-02-08) + +### Bug Fixes + +- **orchestrator:** resolve inconsistency with workflow run average duration format ([#1191](https://github.com/janus-idp/backstage-plugins/issues/1191)) ([0d82e90](https://github.com/janus-idp/backstage-plugins/commit/0d82e90a15fc8e90a4855188586986235394e3d3)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.3.2](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.3.1...@red-hat-developer-hub/backstage-plugin-orchestrator@1.3.2) (2024-02-07) + +### Bug Fixes + +- **orchestrator:** removes the divider from the workflow definition card ([#1181](https://github.com/janus-idp/backstage-plugins/issues/1181)) ([c2fe940](https://github.com/janus-idp/backstage-plugins/commit/c2fe940fa395842c705f1371872791fdbd77095c)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.3.1](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.3.0...@red-hat-developer-hub/backstage-plugin-orchestrator@1.3.1) (2024-02-05) + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.7.1 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.3.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.2.0...@red-hat-developer-hub/backstage-plugin-orchestrator@1.3.0) (2024-02-02) + +### Features + +- **orchestrator:** add the ability to rerun workflows in a new instance ([#1141](https://github.com/janus-idp/backstage-plugins/issues/1141)) ([fe326df](https://github.com/janus-idp/backstage-plugins/commit/fe326df569caa5a9e7b7ec809c1c371a2a936010)) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.1.0 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.2.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.1.3...@red-hat-developer-hub/backstage-plugin-orchestrator@1.2.0) (2024-01-30) + +### Features + +- add new backend system support for existing backend plugins that have not been migrated over yet ([#1132](https://github.com/janus-idp/backstage-plugins/issues/1132)) ([06e16fd](https://github.com/janus-idp/backstage-plugins/commit/06e16fdcf64257dd08297cb727445d9a8a23c522)) + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.7.0 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.1.3](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.1.2...@red-hat-developer-hub/backstage-plugin-orchestrator@1.1.3) (2024-01-30) + +### Bug Fixes + +- **orchestrator:** resolve bug in workflow instance page assessed by link ([#1142](https://github.com/janus-idp/backstage-plugins/issues/1142)) ([48724f8](https://github.com/janus-idp/backstage-plugins/commit/48724f8d90ec9927ed07382061bce78171ccb1b2)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.1.2](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.1.1...@red-hat-developer-hub/backstage-plugin-orchestrator@1.1.2) (2024-01-29) + +### Bug Fixes + +- **orchestrator:** fixes sorting by name in the workflows list ([#1135](https://github.com/janus-idp/backstage-plugins/issues/1135)) ([2a023e1](https://github.com/janus-idp/backstage-plugins/commit/2a023e156a69ca3cf102ba9a77f076e3289b60b4)) +- **orchestrator:** fixes sorting workflow runs ([#1136](https://github.com/janus-idp/backstage-plugins/issues/1136)) ([7c3d0f6](https://github.com/janus-idp/backstage-plugins/commit/7c3d0f62abf861faae82d84cf1d25213d1791dc5)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.1.1](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.1.0...@red-hat-developer-hub/backstage-plugin-orchestrator@1.1.1) (2024-01-25) + +### Bug Fixes + +- **orchestrator:** set default workflow runs table size to 20 ([#1127](https://github.com/janus-idp/backstage-plugins/issues/1127)) ([c5e14fd](https://github.com/janus-idp/backstage-plugins/commit/c5e14fd8e343df7d8c6db7f539fbbd2747e7792e)) + +### Documentation + +- **orchestrator:** adds a section about deploying as a dynamic plugins ([#1125](https://github.com/janus-idp/backstage-plugins/issues/1125)) ([eaff621](https://github.com/janus-idp/backstage-plugins/commit/eaff621cf39ab76909446616230de48512714187)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.1.0](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.0.2...@red-hat-developer-hub/backstage-plugin-orchestrator@1.1.0) (2024-01-25) + +### Features + +- **orchestrator:** add auto refresh to workflow instance list and details pages ([#1081](https://github.com/janus-idp/backstage-plugins/issues/1081)) ([fc30645](https://github.com/janus-idp/backstage-plugins/commit/fc30645ff740e914708a20f1fa1e2e118f771433)) + +### Dependencies + +- **@janus-idp/cli:** upgraded to 1.6.0 + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.0.2](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.0.1...@red-hat-developer-hub/backstage-plugin-orchestrator@1.0.2) (2024-01-24) + +### Bug Fixes + +- **orchestrator:** do not show duration when ProcessInstance.end time is n/a ([#1112](https://github.com/janus-idp/backstage-plugins/issues/1112)) ([75e6bbe](https://github.com/janus-idp/backstage-plugins/commit/75e6bbe8737742494817112b8da0fc50be5ff245)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator [1.0.1](https://github.com/janus-idp/backstage-plugins/compare/@red-hat-developer-hub/backstage-plugin-orchestrator@1.0.0...@red-hat-developer-hub/backstage-plugin-orchestrator@1.0.1) (2024-01-18) + +### Bug Fixes + +- **orchestrator:** update the navigation bar icon according to UX ([#1078](https://github.com/janus-idp/backstage-plugins/issues/1078)) ([da3d8fc](https://github.com/janus-idp/backstage-plugins/commit/da3d8fc7a33f01729ead1d515d16ebefc47326c3)) + +## @red-hat-developer-hub/backstage-plugin-orchestrator 1.0.0 (2024-01-17) + +### Features + +- **orchestrator:** add orchestrator plugin ([#783](https://github.com/janus-idp/backstage-plugins/issues/783)) ([cf5fe74](https://github.com/janus-idp/backstage-plugins/commit/cf5fe74db6992d9f51f5073bbcf20c8c346357a1)), closes [#28](https://github.com/janus-idp/backstage-plugins/issues/28) [#38](https://github.com/janus-idp/backstage-plugins/issues/38) [#35](https://github.com/janus-idp/backstage-plugins/issues/35) [#21](https://github.com/janus-idp/backstage-plugins/issues/21) + +### Dependencies + +- **@red-hat-developer-hub/backstage-plugin-orchestrator-common:** upgraded to 1.0.0 diff --git a/workspaces/orchestrator/plugins/orchestrator/README.md b/workspaces/orchestrator/plugins/orchestrator/README.md new file mode 100644 index 00000000..601c9ec1 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator/README.md @@ -0,0 +1,263 @@ +# Orchestrator Plugin for Backstage + +The Orchestrator for Backstage is a mechanism designed to facilitate the implementation and execution of developer self-service flows. It serves as a vital component that enhances and augments the existing scaffolder functionality of Backstage with a more flexible and powerful set of features including long-running and asynchronous flows. + +The orchestrator works harmoniously with other Backstage components such as the Software Catalog, permissions, and plugins as well as others. By leveraging its capabilities, organizations can orchestrate and coordinate developer self-service flows effectively. + +## Context + +The Backstage Orchestrator plugin aims to provide a better option to Scaffolder, based on workflows to have a more flexible and powerful tool that addresses the need by streamlining and automating processes, allowing developers to focus more on coding and innovation. + +The orchestrator relies on [SonataFlow](https://sonataflow.org/), a powerful tool for building cloud-native workflow applications. + +The main idea is to keep the same user experience for users, leveraging the UI components, input forms, and flow that Scaffolder provides, this way it should be straightforward for users and transparent no matter whether using Templates or Workflows, both can live together being compatible with integration points. + +The orchestrator controls the flow orchestrating operations/tasks that may be executed in any external service including Scaffolder Actions, this way it is possible to leverage any existing Action hence Software Templates can be easily migrated to workflows opening the door to extend them to more complex use cases. + +## Capabilities + +**Advanced core capabilities** + +- Stateful/long-lived +- Branching and parallelism +- Error management and compensation +- Event-driven supporting [CloudEvents](https://cloudevents.io) +- Audit logging +- Sub-flows +- Choreography +- Timer/timeout control +- Built-in powerful expression evaluation with JQ +- Low Code/No code +- Cloud-native architecture Kubernetes/OpenShift with Operator support +- OpenAPI / REST built-in integration etc. + +**Client-side tooling** + +- Orchestration visualization / graphical editor +- Integration with service catalog/actions +- GitHub integration +- Form generation +- Runtime monitoring of instances +- Dashboards +- Potential custom integrations (user interaction, notifications, etc.) + +## For administrators + +### Installation + +The Orchestrator plugin is composed of the following packages: + +- `@red-hat-developer-hub/backstage-plugin-orchestrator-backend` package connects the Backstage server to the Orchestrator. For setup process, see [Backend Setup](#setting-up-the-orchestrator-backend-package) +- `@red-hat-developer-hub/backstage-plugin-orchestrator` package contains frontend components for the Orchestrator plugin. For setup process, see [Frontend Setup](#setting-up-the-orchestrator-frontend-package) +- `@red-hat-developer-hub/backstage-plugin-orchestrator-common` package contains shared code between the Orchestrator plugin packages. + +#### Prerequisites for running the plugins locally in development mode + +- Docker up and running + +#### Setting up the Orchestrator as a dynamic plugin in a Helm deployment + +Please follow this link for instructions: https://github.com/janus-idp/backstage-showcase/blob/main/docs/dynamic-plugins/installing-plugins.md#installing-external-dynamic-plugins. + +#### Setting up the configuration for the Orchestrator plugin + +The following configuration is required for the Orchestrator plugin to work properly: + +```yaml title="app-config.yaml" +backend: + csp: + frame-ancestors: ['http://localhost:3000', 'http://localhost:7007'] + script-src: ["'self'", "'unsafe-inline'", "'unsafe-eval'"] + script-src-elem: ["'self'", "'unsafe-inline'", "'unsafe-eval'"] + connect-src: ["'self'", 'http:', 'https:', 'data:'] +orchestrator: + sonataFlowService: + baseUrl: http://localhost + port: 8899 + autoStart: true + workflowsSource: + gitRepositoryUrl: https://github.com/parodos-dev/backstage-orchestrator-workflows + localPath: /tmp/orchestrator/repository + dataIndexService: + url: http://localhost:8899 +``` + +- When interacting with an existing SonataFlow infrastructure, the `sonataFlowService` config section must be entirely omitted and the `dataIndexService.url` must point to the existing Data Index Service. + +For more information about the configuration options, including other optional properties, see the [config.d.ts](../orchestrator-common/config.d.ts) file. + +#### Setting up the Orchestrator backend package + +1. Install the Orchestrator backend plugin using the following command: + + ```console + yarn workspace backend add @red-hat-developer-hub/backstage-plugin-orchestrator-backend + ``` + +1. Add the following code to the `packages/backend/src/index.ts` file: + + ```ts title="packages/backend/src/index.ts" + const backend = createBackend(); + + /* highlight-add-next-line */ + backend.add( + import('@red-hat-developer-hub/backstage-plugin-orchestrator-backend'), + ); + + backend.start(); + ``` + +#### Setting up the Orchestrator frontend package + +1. Install the Orchestrator frontend plugin using the following command: + + ```console + yarn workspace app add @red-hat-developer-hub/backstage-plugin-orchestrator + ``` + +1. Add a route to the `OrchestratorPage` and the customized template card component to Backstage App (`packages/app/src/App.tsx`): + + ```tsx title="packages/app/src/App.tsx" + /* highlight-add-next-line */ + import { OrchestratorPage } from '@red-hat-developer-hub/backstage-plugin-orchestrator'; + + const routes = ( + + {/* ... */} + {/* highlight-add-next-line */} + } /> + + ); + ``` + +1. Add the Orchestrator to Backstage sidebar (`packages/app/src/components/Root/Root.tsx`): + + ```tsx title="packages/app/src/components/Root/Root.tsx" + /* highlight-add-next-line */ + import { OrchestratorIcon } from '@red-hat-developer-hub/backstage-plugin-orchestrator'; + + export const Root = ({ children }: PropsWithChildren<{}>) => ( + + + }> + {/* ... */} + {/* highlight-add-start */} + + {/* highlight-add-end */} + + {/* ... */} + + {children} + + ); + ``` + +### Extensible Workflow Execution Form + +The `orchestrator` plugin includes an extensible form for executing forms. For detailed guidance see the [Extensible Workflow Execution Form Documentation](https://github.com/redhat-developer/rhdh-plugins/blob/main/workspaces/orchestrator/plugins/orchestrator/docs/extensibleForm.md). + +## For users + +### Using the Orchestrator plugin in Backstage + +The Orchestrator plugin enhances the Backstage with the execution of developer self-service flows. It provides a graphical editor to visualize workflow definitions, and a dashboard to monitor the execution of the workflows. + +Refer to the [Quick start](https://github.com/redhat-developer/rhdh-plugins/blob/main/workspaces/orchestrator/plugins/orchestrator/docs/quickstart.md) to install the Orchestrator using the helm chart and execute a sample workflow through the Red Hat Developer Hub orchestrator plugin UI. + +## OpenAPI + +The plugin provides OpenAPI `v2` endpoints definition to facilitate communication between the frontend and backend. This approach minimizes the data that needs to be sent to the frontend, provides flexibility and avoids dependencies on changes in the [CNCF serverless specification](https://github.com/serverlessworkflow/specification/blob/main/specification.md). It also allows for a seamless transition if there's a need to replace the backend implementation. + +In addition, by leveraging on OpenAPI spec, it is possible to generate clients and create CI steps. + +OpenAPI specification [file](https://github.com/redhat-developer/rhdh-plugins/blob/main/workspaces/orchestrator/plugins/orchestrator-common/src/openapi/openapi.yaml) is available in [orchestrator-common](https://github.com/redhat-developer/rhdh-plugins/blob/main/workspaces/orchestrator/plugins/orchestrator-common). +OpenAPI specification documentation is available [here](https://github.com/redhat-developer/rhdh-plugins/blob/main/workspaces/orchestrator/plugins/orchestrator-common/src/generated/docs/markdown/README.md) + +### orchestrator-common + +The typescript client is generated in [generated](https://github.com/redhat-developer/rhdh-plugins/blob/main/workspaces/orchestrator/plugins/orchestrator-common/src/generated/client) folder from openapi.yaml specification file. + +### orchestrator-backend + +The orchestrator backend can use the generated schema to validate the HTTP requests and responses. + +### audit log + +The orchestrator backend has audit logs for all incoming requests. + +For more information about audit logs in RHDH, please refer to [the official documentation](https://docs.redhat.com/en/documentation/red_hat_developer_hub/1.2/html/getting_started_with_red_hat_developer_hub/assembly-audit-log#con-audit-log-config_assembly-audit-log). +[The official Log storage OpenShift documentation](https://docs.openshift.com/container-platform/4.15/observability/logging/log_storage/about-log-storage.html) may also be of interest. + +#### Development instruction + +Checkout the backstage-plugin + +`git clone git@github.com:red-hat-developer-hub/backstage-plugins.git` + +If you need to change the OpenAPI spec, edit the [openapi.yaml](https://github.com/redhat-developer/rhdh-plugins/blob/main/workspaces/orchestrator/plugins/orchestrator-common/src/openapi/openapi.yaml) according to your needs and then execute from the project root folder: + +`yarn --cwd plugins/orchestrator-common openapi` + +This command updates the [generated files](https://github.com/redhat-developer/rhdh-plugins/blob/main/workspaces/orchestrator/plugins/orchestrator-common/src/generated) including API, client and docs. + +> NOTE: Do not manually edit auto-generated files + +If you add a new component in the spec, then you need to export the generated typescript object [here](https://github.com/redhat-developer/rhdh-plugins/blob/main/workspaces/orchestrator/plugins/orchestrator-common/src/generated/client/api.ts). For example, if you define + +```yaml +components: + schemas: + Person: + type: object + properties: + name: + type: string + surname: + type: string +``` + +then + +```typescript +export type Person = components['schemas']['Person']; +``` + +When defining a new endpoint, you have to define the `operationId`. +That `id` is the one that you can use to implement the endpoint logic. + +For example, let's assume you add + +```yaml +paths: + /names: + get: + operationId: getNames + description: Get a list of names + responses: + '200': + description: Success + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Person' +``` + +Then you can implement the endpoint in [router.ts](https://github.com/redhat-developer/rhdh-plugins/blob/main/workspaces/orchestrator/plugins/orchestrator-backend/src/service/router.ts) referring the operationId `getNames`: + +```typescript +api.register('getNames', async (_c, _req, res: express.Response, next) => { + // YOUR LOGIC HERE + const result: Person[] = [ + { name: 'John', surname: 'Snow' }, + { name: 'John', surname: 'Black' }, + ]; + + res.status(200).json(result); +}); +``` diff --git a/workspaces/orchestrator/plugins/orchestrator/app-config.yaml b/workspaces/orchestrator/plugins/orchestrator/app-config.yaml new file mode 100644 index 00000000..7320e931 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator/app-config.yaml @@ -0,0 +1,14 @@ +dynamicPlugins: + frontend: + red-hat-developer-hub.backstage-plugin-orchestrator: + appIcons: + - name: orchestratorIcon + module: OrchestratorPlugin + importName: OrchestratorIcon + dynamicRoutes: + - path: /orchestrator + importName: OrchestratorPage + module: OrchestratorPlugin + menuItem: + icon: orchestratorIcon + text: Orchestrator diff --git a/workspaces/orchestrator/plugins/orchestrator/catalog-info.yaml b/workspaces/orchestrator/plugins/orchestrator/catalog-info.yaml new file mode 100644 index 00000000..d320e9ac --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator/catalog-info.yaml @@ -0,0 +1,51 @@ +# https://backstage.io/docs/features/software-catalog/descriptor-format#kind-component +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: red-hat-developer-hub-orchestrator + title: Orchestrator plugin + description: Orchestrator Plugin for Backstage + annotations: + backstage.io/source-location: url:https://github.com/redhat-developer/rhdh-plugins/tree/main/workspaces/orchestrator/plugins/orchestrator + backstage.io/view-url: https://github.com/redhat-developer/rhdh-plugins/blob/main/workspaces/orchestrator/plugins/orchestrator/catalog-info.yaml + backstage.io/edit-url: https://github.com/redhat-developer/rhdh-plugins/edit/main/workspaces/orchestrator/plugins/orchestrator/catalog-info.yaml + github.com/project-slug: red-hat-developer-hub/backstage-plugins + github.com/team-slug: red-hat-developer-hub/orchestrator-codeowners + sonarqube.org/project-key: red_hat_developer_hub_plugins + links: + - url: https://github.com/redhat-developer/rhdh-plugins/tree/main/workspaces/orchestrator/plugins/orchestrator + title: GitHub Source + icon: source + type: source +spec: + type: backstage-plugin + lifecycle: production + owner: orchestrator-team + system: rhdh + subcomponentOf: red-hat-developer-hub-plugins +--- +# https://backstage.io/docs/features/software-catalog/descriptor-format#kind-component +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: red-hat-developer-hub-orchestrator-frontend + title: '@red-hat-developer-hub/backstage-plugin-orchestrator' + description: Orchestrator Plugin for Backstage + annotations: + backstage.io/source-location: url:https://github.com/redhat-developer/rhdh-plugins/tree/main/workspaces/orchestrator/plugins/orchestrator + backstage.io/view-url: https://github.com/redhat-developer/rhdh-plugins/blob/main/workspaces/orchestrator/plugins/orchestrator/catalog-info.yaml + backstage.io/edit-url: https://github.com/redhat-developer/rhdh-plugins/edit/main/workspaces/orchestrator/plugins/orchestrator/catalog-info.yaml + github.com/project-slug: red-hat-developer-hub/backstage-plugins + github.com/team-slug: red-hat-developer-hub/orchestrator-codeowners + sonarqube.org/project-key: red_hat_developer_hub_plugins + links: + - url: https://github.com/redhat-developer/rhdh-plugins/tree/main/workspaces/orchestrator/plugins/orchestrator + title: GitHub Source + icon: source + type: source +spec: + type: backstage-frontend-plugin + lifecycle: production + owner: orchestrator-team + system: rhdh + subcomponentOf: red-hat-developer-hub-orchestrator diff --git a/workspaces/orchestrator/plugins/orchestrator/dev/index.tsx b/workspaces/orchestrator/plugins/orchestrator/dev/index.tsx new file mode 100644 index 00000000..1f072b9a --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator/dev/index.tsx @@ -0,0 +1,32 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; + +import { createDevApp } from '@backstage/dev-utils'; + +import { getAllThemes } from '@redhat-developer/red-hat-developer-hub-theme'; + +import { OrchestratorPage, orchestratorPlugin } from '../src'; + +createDevApp() + .registerPlugin(orchestratorPlugin) + .addThemes(getAllThemes()) + .addPage({ + element: , + title: 'Root Page', + path: '/orchestrator', + }) + .render(); diff --git a/workspaces/orchestrator/plugins/orchestrator/docs/Permissions.md b/workspaces/orchestrator/plugins/orchestrator/docs/Permissions.md new file mode 100644 index 00000000..80151873 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator/docs/Permissions.md @@ -0,0 +1,47 @@ +The Orchestrator plugin protects its backend endpoints with the builtin permission mechanism and combines it with +the RBAC plugin. The result is control over what users can see or execute. + +## Orchestrator Permissions + +| Name | Resource Type | Policy | Description | Requirements | +| ----------------------------------- | -------------- | ------ | ----------------------------------------------------------------- | ------------ | +| orchestrator.workflowInstances.read | named resource | read | Allows the user to read orchestrator workflows overview | | +| orchestrator.workflowInstance.read | named resource | read | Allows the user to read the details of a single workflow instance | | +| orchestrator.workflowInstance.abort | named resource | use | Allows the user to abort a workflow instance | | +| orchestrator.workflow.read | named resource | read | Allows the user to read the workflow definitions | | +| orchestrator.workflow.execute | named resource | use | Allows the user to execute a workflow | | + +## Policy File + +To get started with policies, we recommend defining 2 roles and assigning them to groups or users. + +See the example [policy file](./rbac-policy.csv) + +```csv +p, role:default/workflowViewer, orchestrator.workflowInstances.read, read, allow +p, role:default/workflowViewer, orchestrator.workflowInstance.read, read, allow + +p, role:default/workflowAdmin, orchestrator.workflow.read, read, allow +p, role:default/workflowAdmin, orchestrator.workflow.execute, use, allow +p, role:default/workflowAdmin, orchestrator.workflowInstance.abort, use, deny +p, role:default/workflowAdmin, orchestrator.workflowInstances.read, read, allow +p, role:default/workflowAdmin, orchestrator.workflowInstance.read, read, allow + +g, user:default/guest, role:default/workflowViewer +g, user:default/myOrgUser, role:default/workflowAdmin +g, group:default/platformAdmins, role:default/worflowAdmin +``` + +See https://casbin.org/docs/rbac for more information about casbin rules + +## Enable permissions + +To enable permissions, you need to add the following in the [app-config file](../../../app-config.yaml): + +``` +permission: + enabled: true + rbac: + policies-csv-file: + policyFileReload: true +``` diff --git a/workspaces/orchestrator/plugins/orchestrator/docs/executePageNext.png b/workspaces/orchestrator/plugins/orchestrator/docs/executePageNext.png new file mode 100644 index 00000000..0d6c04ad Binary files /dev/null and b/workspaces/orchestrator/plugins/orchestrator/docs/executePageNext.png differ diff --git a/workspaces/orchestrator/plugins/orchestrator/docs/executePageRun.png b/workspaces/orchestrator/plugins/orchestrator/docs/executePageRun.png new file mode 100644 index 00000000..108d87a5 Binary files /dev/null and b/workspaces/orchestrator/plugins/orchestrator/docs/executePageRun.png differ diff --git a/workspaces/orchestrator/plugins/orchestrator/docs/extensibleForm.md b/workspaces/orchestrator/plugins/orchestrator/docs/extensibleForm.md new file mode 100644 index 00000000..7a6d7e46 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator/docs/extensibleForm.md @@ -0,0 +1,136 @@ +# Extensible Workflow Execution Form + +This capability enables developers to extend and customize the `react-jsonschema-form` workflow execution form component. It is designed to enable developers to implement a Backstage plugin that provides a custom decorator for the workflow execution form. This decorator supports overriding a selected set of [react-json-schema-form properties](https://rjsf-team.github.io/react-jsonschema-form/docs/api-reference/form-props) enabling the following features: + +- **Custom Validations:** Extend default JSON schema validation with: + - **Synchronous Validation** via the `customValidate` property. + - **Asynchronous Validation** via the `getExtraErrors` property, for validations requiring backend calls. +- **Custom Components:** Replace default form components by overriding the `widgets` property. +- **Interdependent Field Values:** Manage complex inter-field dependencies using the `onChange` and `formData` properties. + +The custom decorator is delivered via a factory method that leverages a [Backstage utility API](https://backstage.io/docs/api/utility-apis) provided by the orchestrator. To trigger the desired behavior, the workflow schema should include custom UI properties. + +For reference, an example plugin can be found [here](https://github.com/parodos-dev/custom-form-example-plugin). + +## API + +To implement the API, include @red-hat-developer-hub/backstage-plugin-orchestrator-form-api package as a dependency. +This package provides the `FormExtensionsApi` interface and related types. + +```typescript +export type FormDecoratorProps = Pick< + FormProps, + 'formData' | 'formContext' | 'widgets' | 'onChange' | 'customValidate' +> & { + getExtraErrors?: ( + formData: JsonObject, + ) => Promise> | undefined; +}; + +export type FormDecorator = ( + FormComponent: React.ComponentType, +) => React.ComponentType; + +export interface FormExtensionsApi { + getFormDecorator(schema: JSONSchema7): FormDecorator; +} +``` + +### Example API Implementation + +```typescript +class CustomFormApi implements FormExtensionsApi { + getFormDecorator(schema: JSONSchema7) { + return (FormComponent: React.ComponentType>) => { + const widgets = {CountryWidget}; // CountryWidget needs to be implemneted and imported + return () => ; + }; + } +} +``` + +### Plugin Creation Example + +```typescript +export const formApiFactory = createApiFactory({ + api: orchestratorFormApiRef, + deps: {}, + factory() { + return new CustomFormApi(); + }, +}); + +export const testFactoryPlugin = createPlugin({ + id: 'custom-form-plugin', + apis: [formApiFactory], +}); +``` + +### Schema example for above plugin + +```typescript +{ + "type": "object", + "properties": { + "personalDetails": { + "type": "object", + "title": "Personal Details", + "properties": { + "name": { + "type": "string", + "title": "Name" + }, + "country": { + "type": "string", + "title": "Country", + "ui:widget": "CountryWidget" + } + } + }, + "contactDetails": { + "type": "object", + "title": "Contact Details", + "properties": { + "email": { + "type": "string", + "title": "Email" + }, + "phone": { + "type": "string", + "title": "Phone Number" + } + } + } + } +} +``` + +### Dynamic plugin configuration example + +Add the following to backstage config to integrate the plugin: + +```yaml +dynamicPlugins: + frontend: + custom-form-plugin: + apiFactories: + - importName: formApiFactory +``` + +### Referencing the custom behavior in the schema + +The workflow execution schema adheres to the [json-schema](https://json-schema.org/) format, which allows for extending the schema with custom properties beyond the official specification. This flexibility enables the inclusion of additional [uiSchema](https://rjsf-team.github.io/react-jsonschema-form/docs/api-reference/uiSchema/) fields directly within the schema, as demonstrated in the example above. + +### How It All Comes Together + +The `orchestrator-form-react` plugin implements the form component for workflow execution. It integrates with the custom API provided by the developer's plugin to generate and customize the form. The `orchestrator` plugin then incorporates this form into the workflow execution page. + +The `orchestrator-form-react` plugin handles the following key tasks: + +- **Generating the UI Schema:** It extracts custom UI schema fields from the main schema, automatically generates the [uiSchema](https://rjsf-team.github.io/react-jsonschema-form/docs/api-reference/uiSchema/), and passes it to the `react-jsonschema-form` component, enabling advanced UI customizations. + +- **Organizing Forms into Wizard-Style Steps:** If the schema is an object containing nested objects (i.e., the root is an object, and its properties are also objects), the plugin organizes the form into multiple steps. Each nested object becomes a separate step in a wizard-style interface. For example, the schema provided above results in two steps: _Personal Details_ and _Contact Details_. + +The [`orchestrator-form-react`](https://github.com/janus-idp/backstage-plugins/tree/main/plugins/orchestrator-form-react) plugin is designed to operate independently of the main orchestrator plugin. This modularity allows developers to test and validate form behavior in a standalone Backstage development environment before integrating it with the full orchestrator setup. + +To use this plugin, add the `@red-hat-developer-hub/backstage-plugin-orchestrator-form-react` package as a dependency in your project. diff --git a/workspaces/orchestrator/plugins/orchestrator/docs/orchestratorIcon.png b/workspaces/orchestrator/plugins/orchestrator/docs/orchestratorIcon.png new file mode 100644 index 00000000..7fb8aade Binary files /dev/null and b/workspaces/orchestrator/plugins/orchestrator/docs/orchestratorIcon.png differ diff --git a/workspaces/orchestrator/plugins/orchestrator/docs/quickstart.md b/workspaces/orchestrator/plugins/orchestrator/docs/quickstart.md new file mode 100644 index 00000000..064cb238 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator/docs/quickstart.md @@ -0,0 +1,35 @@ +## Quickstart Guide + +This quickstart guide will help you install the Orchestrator using the helm chart and execute a sample workflow through the Red Hat Developer Hub orchestrator plugin UI. + +1. **Install Orchestrator**: + Follow the [installation instructions for Orchestrator](https://www.parodos.dev/orchestrator-helm-chart/). + +2. **Install a sample workflow**: + Follow the [installation instructions for the greetings workflow](https://github.com/parodos-dev/serverless-workflows-config/blob/gh-pages/docs/greeting/README.md). + +3. **Access Red Hat Developer Hub**: + Open your web browser and navigate to the Red Hat Developer Hub application. Retrieve the URL using the following OpenShift CLI command. + + ```bash + oc get route backstage-backstage -n rhdh-operator -o jsonpath='{.spec.host}' + ``` + + Make sure the route is accessible to you locally. + +4. **Login to backstage** + Login to backstage with the Guest account. + +5. **Navigate to Orchestrator**: + Navigate to the Orchestrator page by clicking on the Orchestrator icon in the left navigation menu. + ![orchestratorIcon](https://raw.githubusercontent.com/janus-idp/backstage-plugins/main/plugins/orchestrator/docs/orchestratorIcon.png) + +6. **Execute Greeting Workflow**: + Click on the 'Execute' button in the ACTIONS column of the Greeting workflow. + ![workflowsPage](https://raw.githubusercontent.com/janus-idp/backstage-plugins/main/plugins/orchestrator/docs/workflowsPage.png) + The 'Run workflow' page will open. Click 'Next step' and then 'Run' + ![executePageNext](https://raw.githubusercontent.com/janus-idp/backstage-plugins/main/plugins/orchestrator/docs/executePageNext.png) + ![executePageRun](https://raw.githubusercontent.com/janus-idp/backstage-plugins/main/plugins/orchestrator/docs/executePageRun.png) +7. **Monitor Workflow Status**: + Wait for the status of the Greeting workflow execution to become _Completed_. This may take a moment. + ![workflowCompleted](https://raw.githubusercontent.com/janus-idp/backstage-plugins/main/plugins/orchestrator/docs/workflowCompleted.png) diff --git a/workspaces/orchestrator/plugins/orchestrator/docs/rbac-policy.csv b/workspaces/orchestrator/plugins/orchestrator/docs/rbac-policy.csv new file mode 100644 index 00000000..6dbc6d70 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator/docs/rbac-policy.csv @@ -0,0 +1,11 @@ +p, role:default/workflowViewer, orchestrator.workflowInstances.read, read, allow +p, role:default/workflowViewer, orchestrator.workflowInstance.read, read, allow + +p, role:default/workflowAdmin, orchestrator.workflow.read, read, allow +p, role:default/workflowAdmin, orchestrator.workflow.execute, use, allow +p, role:default/workflowAdmin, orchestrator.workflowInstance.abort, use, allow +p, role:default/workflowAdmin, orchestrator.workflowInstances.read, read, allow +p, role:default/workflowAdmin, orchestrator.workflowInstance.read, read, allow + +g, user:default/guest, role:default/workflowViewer +g, user:default/rgolangh, role:default/workflowAdmin diff --git a/workspaces/orchestrator/plugins/orchestrator/docs/workflowCompleted.png b/workspaces/orchestrator/plugins/orchestrator/docs/workflowCompleted.png new file mode 100644 index 00000000..1180e60e Binary files /dev/null and b/workspaces/orchestrator/plugins/orchestrator/docs/workflowCompleted.png differ diff --git a/workspaces/orchestrator/plugins/orchestrator/docs/workflowsPage.png b/workspaces/orchestrator/plugins/orchestrator/docs/workflowsPage.png new file mode 100644 index 00000000..499d07c2 Binary files /dev/null and b/workspaces/orchestrator/plugins/orchestrator/docs/workflowsPage.png differ diff --git a/workspaces/orchestrator/plugins/orchestrator/package.json b/workspaces/orchestrator/plugins/orchestrator/package.json new file mode 100644 index 00000000..ca893079 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator/package.json @@ -0,0 +1,122 @@ +{ + "name": "@red-hat-developer-hub/backstage-plugin-orchestrator", + "version": "2.4.1", + "license": "Apache-2.0", + "main": "src/index.ts", + "types": "src/index.ts", + "publishConfig": { + "access": "public", + "main": "dist/index.esm.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "frontend-plugin", + "supported-versions": "1.32.5", + "pluginId": "orchestrator", + "pluginPackages": [ + "@red-hat-developer-hub/backstage-plugin-orchestrator", + "@red-hat-developer-hub/backstage-plugin-orchestrator-backend", + "@red-hat-developer-hub/backstage-plugin-orchestrator-common" + ] + }, + "homepage": "https://red.ht/rhdh", + "repository": { + "type": "git", + "url": "https://github.com/redhat-developer/rhdh-plugins", + "directory": "workspaces/orchestrator/plugins/orchestrator" + }, + "bugs": "https://github.com/redhat-developer/rhdh-plugins/issues", + "keywords": [ + "support:tech-preview", + "lifecycle:active", + "backstage", + "plugin", + "orchestrator", + "workflows" + ], + "files": [ + "app-config.yaml", + "dist", + "dist-scalprum" + ], + "sideEffects": false, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "tsc": "tsc", + "prettier:check": "prettier --ignore-unknown --check .", + "prettier:fix": "prettier --ignore-unknown --write .", + "lint:check": "backstage-cli package lint", + "lint:fix": "backstage-cli package lint --fix", + "test": "backstage-cli package test --passWithNoTests --coverage", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "dependencies": { + "@backstage/core-components": "^0.15.1", + "@backstage/core-plugin-api": "^1.10.0", + "@backstage/errors": "^1.2.4", + "@backstage/plugin-catalog": "^1.24.0", + "@backstage/plugin-permission-react": "^0.4.27", + "@kie-tools-core/editor": "^0.32.0", + "@kie-tools-core/notifications": "^0.32.0", + "@kie-tools-core/react-hooks": "^0.32.0", + "@kie-tools/serverless-workflow-combined-editor": "^0.32.0", + "@kie-tools/serverless-workflow-language-service": "^0.32.0", + "@kie-tools/serverless-workflow-service-catalog": "^0.32.0", + "@monaco-editor/react": "^4.6.0", + "@red-hat-developer-hub/backstage-plugin-orchestrator-common": "workspace:^", + "@red-hat-developer-hub/backstage-plugin-orchestrator-form-api": "workspace:^", + "@red-hat-developer-hub/backstage-plugin-orchestrator-form-react": "workspace:^", + "axios": "^1.7.7", + "moment": "^2.29.4", + "monaco-editor": "^0.49.0", + "react-json-view": "^1.21.3", + "react-moment": "^1.1.3", + "react-use": "^17.4.0", + "swr": "^2.0.0", + "uuid": "^11.0.3", + "vscode-languageserver-types": "3.17.5" + }, + "devDependencies": { + "@backstage/cli": "0.28.2", + "@backstage/dev-utils": "1.1.2", + "@backstage/test-utils": "1.7.0", + "@backstage/types": "1.1.1", + "@material-ui/core": "^4.12.4", + "@material-ui/icons": "^4.11.3", + "@material-ui/lab": "^4.0.0-alpha.45", + "@mui/icons-material": "^5.15.8", + "@redhat-developer/red-hat-developer-hub-theme": "0.4.0", + "@testing-library/dom": "^10.0.0", + "@testing-library/jest-dom": "^6.0.0", + "@testing-library/react": "^15.0.0", + "@types/json-schema": "7.0.15", + "@types/react": "^18.2.58", + "@types/react-dom": "^18.2.19", + "@types/uuid": "^9.0.0", + "prettier": "3.3.3" + }, + "peerDependencies": { + "@material-ui/core": "^4.12.4", + "@material-ui/icons": "^4.11.3", + "@material-ui/lab": "^4.0.0-alpha.45", + "@mui/icons-material": "^5.15.8", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-router-dom": "^6.0.0" + }, + "scalprum": { + "name": "janus-idp.backstage-plugin-orchestrator", + "exposedModules": { + "OrchestratorPlugin": "./src/index.ts" + } + }, + "maintainers": [ + "@mlibra", + "@batzionb", + "@gciavarrini" + ], + "author": "The Backstage Community" +} diff --git a/workspaces/orchestrator/plugins/orchestrator/report.api.md b/workspaces/orchestrator/plugins/orchestrator/report.api.md new file mode 100644 index 00000000..7ea24e81 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator/report.api.md @@ -0,0 +1,28 @@ +## API Report File for "@red-hat-developer-hub/backstage-plugin-orchestrator" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +/// + +import { BackstagePlugin } from '@backstage/core-plugin-api'; +import { JSX as JSX_2 } from 'react'; +import { default as React_2 } from 'react'; +import { RouteRef } from '@backstage/core-plugin-api'; +import { SvgIconProps } from '@material-ui/core'; + +// @public +export const OrchestratorIcon: (props: SvgIconProps) => React_2.JSX.Element; + +// @public +export const OrchestratorPage: () => JSX_2.Element; + +// @public +export const orchestratorPlugin: BackstagePlugin< { +root: RouteRef; +}, {}, {}>; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/workspaces/orchestrator/plugins/orchestrator/src/api/OrchestratorClient.test.ts b/workspaces/orchestrator/plugins/orchestrator/src/api/OrchestratorClient.test.ts new file mode 100644 index 00000000..9eb1bdf8 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator/src/api/OrchestratorClient.test.ts @@ -0,0 +1,627 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { DiscoveryApi, IdentityApi } from '@backstage/core-plugin-api'; +import type { JsonObject } from '@backstage/types'; + +import axios, { + AxiosRequestConfig, + AxiosResponse, + InternalAxiosRequestConfig, + RawAxiosResponseHeaders, +} from 'axios'; + +import { + AssessedProcessInstanceDTO, + DefaultApi, + ExecuteWorkflowResponseDTO, + PaginationInfoDTO, + ProcessInstanceListResultDTO, + QUERY_PARAM_INCLUDE_ASSESSMENT, + WorkflowFormatDTO, + WorkflowOverviewDTO, + WorkflowOverviewListResultDTO, +} from '@red-hat-developer-hub/backstage-plugin-orchestrator-common'; + +import { + OrchestratorClient, + OrchestratorClientOptions, +} from './OrchestratorClient'; + +jest.mock('axios'); + +describe('OrchestratorClient', () => { + let mockDiscoveryApi: jest.Mocked; + let mockIdentityApi: jest.Mocked; + let orchestratorClientOptions: jest.Mocked; + let orchestratorClient: OrchestratorClient; + const baseUrl = 'https://api.example.com'; + const mockToken = 'test-token'; + const defaultAuthHeaders = { Authorization: `Bearer ${mockToken}` }; + + const mockFetch = jest.fn(); + (global as any).fetch = mockFetch; // Cast global to any to avoid TypeScript errors + + beforeEach(() => { + jest.clearAllMocks(); + // Create a mock DiscoveryApi with a mocked implementation of getBaseUrl + mockDiscoveryApi = { + getBaseUrl: jest.fn().mockResolvedValue(baseUrl), + } as jest.Mocked; + mockIdentityApi = { + getCredentials: jest.fn().mockResolvedValue({ token: mockToken }), + getProfileInfo: jest + .fn() + .mockResolvedValue({ displayName: 'test', email: 'test@test' }), + getBackstageIdentity: jest + .fn() + .mockResolvedValue({ userEntityRef: 'default/test' }), + signOut: jest.fn().mockImplementation(), + } as jest.Mocked; + + // Create OrchestratorClientOptions with the mocked DiscoveryApi + orchestratorClientOptions = { + discoveryApi: mockDiscoveryApi, + identityApi: mockIdentityApi, + axiosInstance: axios, + }; + orchestratorClient = new OrchestratorClient(orchestratorClientOptions); + }); + + describe('executeWorkflow', () => { + const workflowId = 'workflow123'; + + const setupTest = ( + executionId: string, + parameters: JsonObject, + businessKey?: string, + ) => { + const mockExecResponse: ExecuteWorkflowResponseDTO = { id: executionId }; + const mockResponse: AxiosResponse = { + data: mockExecResponse, + status: 200, + statusText: 'OK', + headers: {} as RawAxiosResponseHeaders, + config: {} as InternalAxiosRequestConfig, + }; + + const executeWorkflowSpy = jest.spyOn( + DefaultApi.prototype, + 'executeWorkflow', + ); + axios.request = jest.fn().mockResolvedValueOnce(mockResponse); + + const args = { workflowId, parameters, businessKey }; + + return { mockExecResponse, executeWorkflowSpy, args }; + }; + + const getExpectations = ( + result: any, + mockExecResponse: ExecuteWorkflowResponseDTO, + executeWorkflowSpy: jest.SpyInstance, + parameters: JsonObject, + ) => { + return () => { + expect(result).toBeDefined(); + expect(result.data).toEqual(mockExecResponse); + expect(axios.request).toHaveBeenCalledTimes(1); + expect(axios.request).toHaveBeenCalledWith({ + ...getAxiosTestRequest(`/v2/workflows/${workflowId}/execute`), + data: JSON.stringify({ inputData: parameters }), + method: 'POST', + headers: { + 'Content-Type': 'application/json', + ...defaultAuthHeaders, + }, + }); + expect(executeWorkflowSpy).toHaveBeenCalledTimes(1); + expect(executeWorkflowSpy).toHaveBeenCalledWith( + workflowId, + { inputData: parameters }, + getDefaultTestRequestConfig(), + ); + }; + }; + + it('should execute workflow with empty parameters', async () => { + // Given + const { mockExecResponse, executeWorkflowSpy, args } = setupTest( + 'execId001', + {}, + ); + + // When + const result = await orchestratorClient.executeWorkflow(args); + + // Then + expect( + getExpectations(result, mockExecResponse, executeWorkflowSpy, {}), + ).not.toThrow(); + }); + it('should execute workflow with business key', async () => { + // Given + const { mockExecResponse, executeWorkflowSpy, args } = setupTest( + 'execId001', + {}, + 'business123', + ); + + const result = await orchestratorClient.executeWorkflow(args); + + expect( + getExpectations(result, mockExecResponse, executeWorkflowSpy, {}), + ).not.toThrow(); + }); + it('should execute workflow with parameters and business key', async () => { + // Given + const parameters = { param1: 'one', param2: 2, param3: true }; + const { mockExecResponse, executeWorkflowSpy, args } = setupTest( + 'execId001', + parameters, + 'business123', + ); + + const result = await orchestratorClient.executeWorkflow(args); + + expect( + getExpectations( + result, + mockExecResponse, + executeWorkflowSpy, + parameters, + ), + ).not.toThrow(); + }); + }); + describe('abortWorkflow', () => { + it('should abort a workflow instance successfully', async () => { + // Given + const instanceId = 'instance123'; + + const mockResponse: AxiosResponse = { + data: instanceId, + status: 200, + statusText: 'OK', + headers: {} as RawAxiosResponseHeaders, + config: {} as InternalAxiosRequestConfig, + }; + + const abortWorkflowSpy = jest.spyOn( + DefaultApi.prototype, + 'abortWorkflow', + ); + axios.request = jest.fn().mockResolvedValueOnce(mockResponse); + // When + const result = await orchestratorClient.abortWorkflowInstance(instanceId); + + // Then + expect(result).toBeDefined(); + expect(result.data).toEqual(instanceId); + expect(axios.request).toHaveBeenCalledTimes(1); + expect(axios.request).toHaveBeenCalledWith({ + ...getAxiosTestRequest(`/v2/workflows/instances/${instanceId}/abort`), + method: 'DELETE', + headers: { + ...defaultAuthHeaders, + }, + }); + expect(abortWorkflowSpy).toHaveBeenCalledTimes(1); + expect(abortWorkflowSpy).toHaveBeenCalledWith( + instanceId, + getDefaultTestRequestConfig(), + ); + }); + + it('should throw a ResponseError if aborting the workflow instance fails', async () => { + // Given + const instanceId = 'instance123'; + + // Mock fetch to simulate a failure + axios.request = jest + .fn() + .mockRejectedValueOnce(new Error('Simulated error')); + // When + const promise = orchestratorClient.abortWorkflowInstance(instanceId); + + // Then + await expect(promise).rejects.toThrow(); + }); + }); + describe('getWorkflowSource', () => { + it('should return workflow source when successful', async () => { + // Given + const workflowId = 'workflow123'; + const mockWorkflowSource = 'test workflow source'; + const responseConfigOptions = getDefaultTestRequestConfig(); + responseConfigOptions.responseType = 'text'; + const mockResponse: AxiosResponse = { + data: mockWorkflowSource, + status: 200, + statusText: 'OK', + headers: {} as RawAxiosResponseHeaders, + config: {} as InternalAxiosRequestConfig, + }; + // Mock axios request to simulate a successful response + jest.spyOn(axios, 'request').mockResolvedValueOnce(mockResponse); + + // Spy DefaultApi + const getSourceSpy = jest.spyOn( + DefaultApi.prototype, + 'getWorkflowSourceById', + ); + + // When + const result = await orchestratorClient.getWorkflowSource(workflowId); + + // Then + expect(result).toBeDefined(); + expect(result.data).toEqual(mockWorkflowSource); + expect(axios.request).toHaveBeenCalledTimes(1); + expect(axios.request).toHaveBeenCalledWith({ + ...getAxiosTestRequest(`/v2/workflows/${workflowId}/source`), + method: 'GET', + headers: { + ...defaultAuthHeaders, + }, + responseType: 'text', + }); + expect(getSourceSpy).toHaveBeenCalledTimes(1); + expect(getSourceSpy).toHaveBeenCalledWith( + workflowId, + responseConfigOptions, + ); + }); + + it('should throw a ResponseError when fetching the workflow source fails', async () => { + // Given + const workflowId = 'workflow123'; + + // Mock fetch to simulate a failure + axios.request = jest + .fn() + .mockRejectedValueOnce(new Error('Simulated error')); + // When + const promise = orchestratorClient.getWorkflowSource(workflowId); + + // Then + await expect(promise).rejects.toThrow(); + }); + }); + describe('listWorkflowOverviews', () => { + it('should return workflow overviews when successful', async () => { + // Given + const paginationInfo: PaginationInfoDTO = { + offset: 1, + pageSize: 5, + orderBy: 'name', + orderDirection: 'ASC', + }; + const mockWorkflowOverviews: WorkflowOverviewListResultDTO = { + overviews: [ + { + workflowId: 'workflow123', + name: 'Workflow 1', + format: WorkflowFormatDTO.Yaml, + }, + { + workflowId: 'workflow456', + name: 'Workflow 2', + format: WorkflowFormatDTO.Yaml, + }, + ], + paginationInfo: paginationInfo, + }; + + const mockResponse: AxiosResponse = { + data: mockWorkflowOverviews, + status: 200, + statusText: 'OK', + headers: {} as RawAxiosResponseHeaders, + config: {} as InternalAxiosRequestConfig, + }; + + // Spy DefaultApi + const getWorkflowsOverviewSpy = jest.spyOn( + DefaultApi.prototype, + 'getWorkflowsOverview', + ); + + // Mock axios request to simulate a successful response + jest.spyOn(axios, 'request').mockResolvedValueOnce(mockResponse); + + // When + const result = await orchestratorClient.listWorkflowOverviews( + paginationInfo, + ); + + // Then + expect(result).toBeDefined(); + expect(result.data).toEqual(mockWorkflowOverviews); + expect(axios.request).toHaveBeenCalledTimes(1); + expect(axios.request).toHaveBeenCalledWith({ + ...getAxiosTestRequest('v2/workflows/overview'), + data: JSON.stringify({ paginationInfo }), + method: 'POST', + headers: { + 'Content-Type': 'application/json', + ...defaultAuthHeaders, + }, + }); + expect(getWorkflowsOverviewSpy).toHaveBeenCalledTimes(1); + expect(getWorkflowsOverviewSpy).toHaveBeenCalledWith( + { paginationInfo }, + getDefaultTestRequestConfig(), + ); + }); + it('should throw a ResponseError when listing workflow overviews fails', async () => { + // Given + + // Mock fetch to simulate a failure + axios.request = jest + .fn() + .mockRejectedValueOnce(new Error('Simulated error')); + + // When + const promise = orchestratorClient.listWorkflowOverviews(); + + // Then + await expect(promise).rejects.toThrow(); + }); + }); + describe('listInstances', () => { + it('should return instances when successful', async () => { + // Given + const paginationInfo: PaginationInfoDTO = { + offset: 1, + pageSize: 5, + orderBy: 'name', + orderDirection: 'ASC', + }; + + const mockInstances: ProcessInstanceListResultDTO = { + items: [{ id: 'instance123', processId: 'process001', nodes: [] }], + paginationInfo, + }; + + const mockResponse: AxiosResponse = { + data: mockInstances, + status: 200, + statusText: 'OK', + headers: {} as RawAxiosResponseHeaders, + config: {} as InternalAxiosRequestConfig, + }; + + // Spy DefaultApi + const getInstancesSpy = jest.spyOn(DefaultApi.prototype, 'getInstances'); + + // Mock axios request to simulate a successful response + jest.spyOn(axios, 'request').mockResolvedValueOnce(mockResponse); + + // When + const result = await orchestratorClient.listInstances({ paginationInfo }); + // Then + expect(result).toBeDefined(); + expect(result.data).toEqual(mockInstances); + expect(axios.request).toHaveBeenCalledTimes(1); + expect(axios.request).toHaveBeenCalledWith({ + ...getAxiosTestRequest('v2/workflows/instances'), + data: JSON.stringify({ paginationInfo }), + headers: { + 'Content-Type': 'application/json', + ...defaultAuthHeaders, + }, + method: 'POST', + }); + expect(getInstancesSpy).toHaveBeenCalledTimes(1); + expect(getInstancesSpy).toHaveBeenCalledWith( + { paginationInfo }, + getDefaultTestRequestConfig(), + ); + }); + + it('should throw a ResponseError when listing instances fails', async () => { + // Given + axios.request = jest + .fn() + .mockRejectedValueOnce(new Error('Simulated error')); + // When + const promise = orchestratorClient.listInstances({}); + + // Then + await expect(promise).rejects.toThrow(); + }); + }); + describe('getInstance', () => { + it('should return instance when successful', async () => { + // Given + const instanceId = 'instance123'; + const instanceIdParent = 'instance000'; + const includeAssessment = false; + const mockInstance: AssessedProcessInstanceDTO = { + instance: { id: instanceId, processId: 'process002', nodes: [] }, + assessedBy: { + id: instanceIdParent, + processId: 'process001', + nodes: [], + }, + }; + + const mockResponse: AxiosResponse = { + data: mockInstance, + status: 200, + statusText: 'OK', + headers: {} as RawAxiosResponseHeaders, + config: {} as InternalAxiosRequestConfig, + }; + // Mock axios request to simulate a successful response + jest.spyOn(axios, 'request').mockResolvedValueOnce(mockResponse); + + // Spy DefaultApi + const getInstanceSpy = jest.spyOn( + DefaultApi.prototype, + 'getInstanceById', + ); + // When + const result = await orchestratorClient.getInstance( + instanceId, + includeAssessment, + ); + + // Then + expect(result).toBeDefined(); + expect(result.data).toEqual(mockInstance); + expect(axios.request).toHaveBeenCalledTimes(1); + expect(axios.request).toHaveBeenCalledWith( + getAxiosTestRequest( + `v2/workflows/instances/${instanceId}`, + includeAssessment, + ), + ); + expect(getInstanceSpy).toHaveBeenCalledTimes(1); + expect(getInstanceSpy).toHaveBeenCalledWith( + instanceId, + includeAssessment, + getDefaultTestRequestConfig(), + ); + }); + + it('should throw a ResponseError when fetching the instance fails', async () => { + // Given + const instanceId = 'instance123'; + + axios.request = jest + .fn() + .mockRejectedValueOnce(new Error('Simulated error')); + // When + const promise = orchestratorClient.getInstance(instanceId); + + // Then + await expect(promise).rejects.toThrow(); + }); + }); + describe('getWorkflowOverview', () => { + it('should return workflow overview when successful', async () => { + // Given + const workflowId = 'workflow123'; + const mockOverview = { + workflowId: workflowId, + name: 'Workflow 1', + format: WorkflowFormatDTO.Yaml, + }; + + const mockResponse: AxiosResponse = { + data: mockOverview, + status: 200, + statusText: 'OK', + headers: {} as RawAxiosResponseHeaders, + config: {} as InternalAxiosRequestConfig, + }; + + // Spy DefaultApi + const getWorkflowOverviewByIdSpy = jest.spyOn( + DefaultApi.prototype, + 'getWorkflowOverviewById', + ); + + // Mock axios request to simulate a successful response + jest.spyOn(axios, 'request').mockResolvedValueOnce(mockResponse); + + // When + const result = await orchestratorClient.getWorkflowOverview(workflowId); + + // Then + expect(result).toBeDefined(); + expect(result.data).toEqual(mockOverview); + expect(axios.request).toHaveBeenCalledTimes(1); + expect(axios.request).toHaveBeenCalledWith( + getAxiosTestRequest(`v2/workflows/${workflowId}/overview`), + ); + expect(getWorkflowOverviewByIdSpy).toHaveBeenCalledTimes(1); + expect(getWorkflowOverviewByIdSpy).toHaveBeenCalledWith( + workflowId, + getDefaultTestRequestConfig(), + ); + }); + + it('should throw a ResponseError when fetching the workflow overview fails', async () => { + // Given + const workflowId = 'workflow123'; + + // Given + // Mock fetch to simulate a failure + axios.request = jest + .fn() + .mockRejectedValueOnce(new Error('Simulated error')); + + // When + const promise = orchestratorClient.getWorkflowOverview(workflowId); + + // Then + await expect(promise).rejects.toThrow(); + }); + }); + function getDefaultTestRequestConfig(): AxiosRequestConfig { + return { + baseURL: baseUrl, + headers: { Authorization: `Bearer ${mockToken}` }, + }; + } + + function getAxiosTestRequest( + endpoint: string, + includeAssessment?: boolean, + paginationInfo?: PaginationInfoDTO, + method: string = 'GET', + ): AxiosRequestConfig { + const req = getDefaultTestRequestConfig(); + + return { + ...req, + method, + url: buildURLWithPagination(endpoint, includeAssessment, paginationInfo), + }; + } + + function buildURLWithPagination( + endpoint: string, + includeAssessment?: boolean, + paginationInfo?: PaginationInfoDTO, + ): string { + const url = new URL(endpoint, baseUrl); + if (includeAssessment !== undefined) { + url.searchParams.append( + QUERY_PARAM_INCLUDE_ASSESSMENT, + String(includeAssessment), + ); + } + if (paginationInfo?.offset !== undefined) { + url.searchParams.append('page', paginationInfo.offset.toString()); + } + + if (paginationInfo?.pageSize !== undefined) { + url.searchParams.append('pageSize', paginationInfo.pageSize.toString()); + } + + if (paginationInfo?.orderBy !== undefined) { + url.searchParams.append('orderBy', paginationInfo.orderBy); + } + + if (paginationInfo?.orderDirection !== undefined) { + url.searchParams.append('orderDirection', paginationInfo.orderDirection); + } + return url.toString(); + } +}); diff --git a/workspaces/orchestrator/plugins/orchestrator/src/api/OrchestratorClient.ts b/workspaces/orchestrator/plugins/orchestrator/src/api/OrchestratorClient.ts new file mode 100644 index 00000000..3d1d8ebe --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator/src/api/OrchestratorClient.ts @@ -0,0 +1,243 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { DiscoveryApi, IdentityApi } from '@backstage/core-plugin-api'; +import type { JsonObject } from '@backstage/types'; + +import axios, { + AxiosInstance, + AxiosRequestConfig, + AxiosResponse, + isAxiosError, + RawAxiosRequestHeaders, +} from 'axios'; + +import { + AssessedProcessInstanceDTO, + Configuration, + DefaultApi, + ExecuteWorkflowResponseDTO, + Filter, + GetInstancesRequest, + InputSchemaResponseDTO, + PaginationInfoDTO, + ProcessInstanceListResultDTO, + WorkflowOverviewDTO, + WorkflowOverviewListResultDTO, +} from '@red-hat-developer-hub/backstage-plugin-orchestrator-common'; + +import { OrchestratorApi } from './api'; + +const getError = (err: unknown): Error => { + if ( + isAxiosError<{ error: { message: string; name: string } }>(err) && + err.response?.data?.error?.message + ) { + const error = new Error(err.response?.data?.error?.message); + error.name = err.response?.data?.error?.name || 'Error'; + return error; + } + return err as Error; +}; + +export interface OrchestratorClientOptions { + discoveryApi: DiscoveryApi; + identityApi: IdentityApi; + axiosInstance?: AxiosInstance; +} +export class OrchestratorClient implements OrchestratorApi { + private readonly discoveryApi: DiscoveryApi; + private readonly identityApi: IdentityApi; + private axiosInstance?: AxiosInstance; + + private baseUrl: string | null = null; + constructor(options: OrchestratorClientOptions) { + this.discoveryApi = options.discoveryApi; + this.identityApi = options.identityApi; + this.axiosInstance = options.axiosInstance; + } + + async getDefaultAPI(): Promise { + const baseUrl = await this.getBaseUrl(); + const { token: idToken } = await this.identityApi.getCredentials(); + + // Fixme: Following makes mocking of global axios complicated in the tests, ideally there should be just one axios instance: + this.axiosInstance = + this.axiosInstance || + axios.create({ + baseURL: baseUrl, + headers: { + ...(idToken && { Authorization: `Bearer ${idToken}` }), + }, + withCredentials: true, + }); + const config = new Configuration({ + basePath: baseUrl, + }); + + return new DefaultApi(config, baseUrl, this.axiosInstance); + } + private async getBaseUrl(): Promise { + if (!this.baseUrl) { + this.baseUrl = await this.discoveryApi.getBaseUrl('orchestrator'); + } + + return this.baseUrl; + } + + async executeWorkflow(args: { + workflowId: string; + parameters: JsonObject; + businessKey?: string; + }): Promise> { + const defaultApi = await this.getDefaultAPI(); + const reqConfigOption: AxiosRequestConfig = + await this.getDefaultReqConfig(); + try { + return await defaultApi.executeWorkflow( + args.workflowId, + { inputData: args.parameters }, + reqConfigOption, + ); + } catch (err) { + throw getError(err); + } + } + + async abortWorkflowInstance( + instanceId: string, + ): Promise> { + const defaultApi = await this.getDefaultAPI(); + const reqConfigOption: AxiosRequestConfig = + await this.getDefaultReqConfig(); + try { + return await defaultApi.abortWorkflow(instanceId, reqConfigOption); + } catch (err) { + throw getError(err); + } + } + + async getWorkflowSource(workflowId: string): Promise> { + const defaultApi = await this.getDefaultAPI(); + const reqConfigOption: AxiosRequestConfig = + await this.getDefaultReqConfig(); + reqConfigOption.responseType = 'text'; + try { + return await defaultApi.getWorkflowSourceById( + workflowId, + reqConfigOption, + ); + } catch (err) { + throw getError(err); + } + } + + async listWorkflowOverviews( + paginationInfo?: PaginationInfoDTO, + filters?: Filter, + ): Promise> { + const defaultApi = await this.getDefaultAPI(); + const reqConfigOption: AxiosRequestConfig = + await this.getDefaultReqConfig(); + try { + return await defaultApi.getWorkflowsOverview( + { paginationInfo, filters }, + reqConfigOption, + ); + } catch (err) { + throw getError(err); + } + } + + async listInstances( + args: GetInstancesRequest, + ): Promise> { + const defaultApi = await this.getDefaultAPI(); + const reqConfigOption: AxiosRequestConfig = + await this.getDefaultReqConfig(); + try { + return await defaultApi.getInstances(args, reqConfigOption); + } catch (err) { + throw getError(err); + } + } + + async getInstance( + instanceId: string, + includeAssessment = false, + ): Promise> { + const defaultApi = await this.getDefaultAPI(); + const reqConfigOption: AxiosRequestConfig = + await this.getDefaultReqConfig(); + try { + return await defaultApi.getInstanceById( + instanceId, + includeAssessment, + reqConfigOption, + ); + } catch (err) { + throw getError(err); + } + } + + async getWorkflowDataInputSchema( + workflowId: string, + instanceId?: string, + ): Promise> { + const defaultApi = await this.getDefaultAPI(); + const reqConfigOption: AxiosRequestConfig = + await this.getDefaultReqConfig(); + try { + return await defaultApi.getWorkflowInputSchemaById( + workflowId, + instanceId, + reqConfigOption, + ); + } catch (err) { + throw getError(err); + } + } + + async getWorkflowOverview( + workflowId: string, + ): Promise> { + const defaultApi = await this.getDefaultAPI(); + const reqConfigOption: AxiosRequestConfig = + await this.getDefaultReqConfig(); + try { + return await defaultApi.getWorkflowOverviewById( + workflowId, + reqConfigOption, + ); + } catch (err) { + throw getError(err); + } + } + + // getDefaultReqConfig is a convenience wrapper that includes authentication and other necessary headers + private async getDefaultReqConfig( + additionalHeaders?: RawAxiosRequestHeaders, + ): Promise { + const idToken = await this.identityApi.getCredentials(); + const reqConfigOption: AxiosRequestConfig = { + baseURL: await this.getBaseUrl(), + headers: { + Authorization: `Bearer ${idToken.token}`, + ...additionalHeaders, + }, + }; + return reqConfigOption; + } +} diff --git a/workspaces/orchestrator/plugins/orchestrator/src/api/api.ts b/workspaces/orchestrator/plugins/orchestrator/src/api/api.ts new file mode 100644 index 00000000..472f130a --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator/src/api/api.ts @@ -0,0 +1,67 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { createApiRef } from '@backstage/core-plugin-api'; +import type { JsonObject } from '@backstage/types'; + +import { AxiosResponse } from 'axios'; + +import { + AssessedProcessInstanceDTO, + ExecuteWorkflowResponseDTO, + GetInstancesRequest, + InputSchemaResponseDTO, + ProcessInstanceListResultDTO, + WorkflowOverviewDTO, + WorkflowOverviewListResultDTO, +} from '@red-hat-developer-hub/backstage-plugin-orchestrator-common'; + +export interface OrchestratorApi { + abortWorkflowInstance(instanceId: string): Promise>; + + executeWorkflow(args: { + workflowId: string; + parameters: JsonObject; + businessKey?: string; + }): Promise>; + + getWorkflowSource(workflowId: string): Promise>; + + getInstance( + instanceId: string, + includeAssessment: boolean, + ): Promise>; + + getWorkflowDataInputSchema( + workflowId: string, + instanceId?: string, + ): Promise>; + + getWorkflowOverview( + workflowId: string, + ): Promise>; + + listWorkflowOverviews(): Promise< + AxiosResponse + >; + + listInstances( + args?: GetInstancesRequest, + ): Promise>; +} + +export const orchestratorApiRef = createApiRef({ + id: 'plugin.orchestrator.api', +}); diff --git a/workspaces/orchestrator/plugins/orchestrator/src/api/index.ts b/workspaces/orchestrator/plugins/orchestrator/src/api/index.ts new file mode 100644 index 00000000..e1d7b02f --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator/src/api/index.ts @@ -0,0 +1,18 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { OrchestratorClient } from './OrchestratorClient'; +export type { OrchestratorClientOptions } from './OrchestratorClient'; +export { orchestratorApiRef } from './api'; diff --git a/workspaces/orchestrator/plugins/orchestrator/src/components/BaseOrchestratorPage.tsx b/workspaces/orchestrator/plugins/orchestrator/src/components/BaseOrchestratorPage.tsx new file mode 100644 index 00000000..21c62e92 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator/src/components/BaseOrchestratorPage.tsx @@ -0,0 +1,47 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React, { PropsWithChildren } from 'react'; + +import { Content, Header, Page } from '@backstage/core-components'; + +export interface BaseOrchestratorProps { + title?: string; + subtitle?: string; + type?: string; + typeLink?: string; + noPadding?: boolean; +} + +export const BaseOrchestratorPage = ({ + title, + subtitle, + type, + typeLink, + noPadding, + children, +}: PropsWithChildren) => { + return ( + +
+ {children} + + ); +}; diff --git a/workspaces/orchestrator/plugins/orchestrator/src/components/ExecuteWorkflowPage/ExecuteWorkflowPage.tsx b/workspaces/orchestrator/plugins/orchestrator/src/components/ExecuteWorkflowPage/ExecuteWorkflowPage.tsx new file mode 100644 index 00000000..3254a121 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator/src/components/ExecuteWorkflowPage/ExecuteWorkflowPage.tsx @@ -0,0 +1,151 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React, { useCallback, useState } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { useAsync } from 'react-use'; + +import { + InfoCard, + Progress, + ResponseErrorPanel, + useQueryParamState, +} from '@backstage/core-components'; +import { + useApi, + useRouteRef, + useRouteRefParams, +} from '@backstage/core-plugin-api'; +import type { JsonObject } from '@backstage/types'; + +import { Grid } from '@material-ui/core'; + +import { + InputSchemaResponseDTO, + QUERY_PARAM_ASSESSMENT_INSTANCE_ID, + QUERY_PARAM_INSTANCE_ID, +} from '@red-hat-developer-hub/backstage-plugin-orchestrator-common'; +import { OrchestratorForm } from '@red-hat-developer-hub/backstage-plugin-orchestrator-form-react'; + +import { orchestratorApiRef } from '../../api'; +import { + executeWorkflowRouteRef, + workflowInstanceRouteRef, +} from '../../routes'; +import { getErrorObject } from '../../utils/ErrorUtils'; +import { BaseOrchestratorPage } from '../BaseOrchestratorPage'; +import JsonTextAreaForm from './JsonTextAreaForm'; + +export const ExecuteWorkflowPage = () => { + const orchestratorApi = useApi(orchestratorApiRef); + const { workflowId } = useRouteRefParams(executeWorkflowRouteRef); + const [isExecuting, setIsExecuting] = useState(false); + const [updateError, setUpdateError] = React.useState(); + const [instanceId] = useQueryParamState(QUERY_PARAM_INSTANCE_ID); + const [assessmentInstanceId] = useQueryParamState( + QUERY_PARAM_ASSESSMENT_INSTANCE_ID, + ); + const navigate = useNavigate(); + const instanceLink = useRouteRef(workflowInstanceRouteRef); + const { + value, + loading, + error: responseError, + } = useAsync(async (): Promise => { + const res = await orchestratorApi.getWorkflowDataInputSchema( + workflowId, + assessmentInstanceId || instanceId, + ); + return res.data; + }, [orchestratorApi, workflowId]); + const schema = value?.inputSchema; + const data = value?.data; + const { + value: workflowName, + loading: workflowNameLoading, + error: workflowNameError, + } = useAsync(async (): Promise => { + const res = await orchestratorApi.getWorkflowOverview(workflowId); + return res.data.name || ''; + }, [orchestratorApi, workflowId]); + + const handleExecute = useCallback( + async (parameters: JsonObject) => { + setUpdateError(undefined); + try { + setIsExecuting(true); + const response = await orchestratorApi.executeWorkflow({ + workflowId, + parameters, + businessKey: assessmentInstanceId, + }); + navigate(instanceLink({ instanceId: response.data.id })); + } catch (err) { + setUpdateError(getErrorObject(err)); + } finally { + setIsExecuting(false); + } + }, + [orchestratorApi, workflowId, navigate, instanceLink, assessmentInstanceId], + ); + + const error = responseError || workflowNameError; + let pageContent; + + if (loading || workflowNameLoading) { + pageContent = ; + } else if (error) { + pageContent = ; + } else { + pageContent = ( + + {updateError && ( + + + + )} + + + {!!schema ? ( + + ) : ( + + )} + + + + ); + } + + return ( + + {pageContent} + + ); +}; diff --git a/workspaces/orchestrator/plugins/orchestrator/src/components/ExecuteWorkflowPage/JsonTextAreaForm.tsx b/workspaces/orchestrator/plugins/orchestrator/src/components/ExecuteWorkflowPage/JsonTextAreaForm.tsx new file mode 100644 index 00000000..f2edc3b5 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator/src/components/ExecuteWorkflowPage/JsonTextAreaForm.tsx @@ -0,0 +1,83 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; + +import type { JsonObject } from '@backstage/types'; + +import { Box, Grid, useTheme } from '@material-ui/core'; +import { Alert, AlertTitle } from '@material-ui/lab'; +import { Editor } from '@monaco-editor/react'; + +import { SubmitButton } from '@red-hat-developer-hub/backstage-plugin-orchestrator-form-react'; + +const DEFAULT_VALUE = JSON.stringify({ myKey: 'myValue' }, null, 4); + +const JsonTextAreaForm = ({ + isExecuting, + handleExecute, +}: { + isExecuting: boolean; + handleExecute: (parameters: JsonObject) => Promise; +}) => { + const [jsonText, setJsonText] = React.useState(DEFAULT_VALUE); + const theme = useTheme(); + const getParameters = (): JsonObject => { + if (!jsonText) { + return {}; + } + const parameters = JSON.parse(jsonText); + return parameters as JsonObject; + }; + + return ( + + + + Missing JSON Schema for Input Form. + Type the input data in JSON format below. +
+ If you prefer using a form to start the workflow, ensure a valid JSON + schema is provided in the 'dataInputSchema' property of your workflow + definition file. +
+
+ + + setJsonText(value ?? '')} + height="30rem" + theme={theme.palette.type === 'dark' ? 'vs-dark' : 'light'} + options={{ + minimap: { enabled: false }, + }} + /> + + + + handleExecute(getParameters())} + > + Run + + +
+ ); +}; + +export default JsonTextAreaForm; diff --git a/workspaces/orchestrator/plugins/orchestrator/src/components/InfoDialog.tsx b/workspaces/orchestrator/plugins/orchestrator/src/components/InfoDialog.tsx new file mode 100644 index 00000000..d4452899 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator/src/components/InfoDialog.tsx @@ -0,0 +1,77 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React, { forwardRef, ForwardRefRenderFunction } from 'react'; + +import { + Box, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + IconButton, + makeStyles, + Typography, +} from '@material-ui/core'; +import CloseIcon from '@material-ui/icons/Close'; + +export type InfoDialogProps = { + title: string; + open: boolean; + onClose?: () => void; + dialogActions?: React.ReactNode; + children?: React.ReactNode; +}; + +export type ParentComponentRef = HTMLElement; + +const useStyles = makeStyles(_theme => ({ + closeBtn: { + position: 'absolute', + right: 8, + top: 8, + }, +})); + +export const RefForwardingInfoDialog: ForwardRefRenderFunction< + ParentComponentRef, + InfoDialogProps +> = (props, forwardedRef): JSX.Element | null => { + const { title, open = false, onClose, children, dialogActions } = props; + const classes = useStyles(); + + return ( + onClose} open={open} ref={forwardedRef}> + + + {title} + + + + + + + {children} + + {dialogActions} + + ); +}; + +export const InfoDialog = forwardRef(RefForwardingInfoDialog); diff --git a/workspaces/orchestrator/plugins/orchestrator/src/components/OrchestratorIcon.tsx b/workspaces/orchestrator/plugins/orchestrator/src/components/OrchestratorIcon.tsx new file mode 100644 index 00000000..fd6709fa --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator/src/components/OrchestratorIcon.tsx @@ -0,0 +1,32 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; + +import { SvgIcon, SvgIconProps } from '@material-ui/core'; + +/** + * @public + * Orchestrator icon + */ +const OrchestratorIcon = (props: SvgIconProps) => ( + + + + + +); + +export default OrchestratorIcon; diff --git a/workspaces/orchestrator/plugins/orchestrator/src/components/OrchestratorPage.tsx b/workspaces/orchestrator/plugins/orchestrator/src/components/OrchestratorPage.tsx new file mode 100644 index 00000000..ea9eacca --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator/src/components/OrchestratorPage.tsx @@ -0,0 +1,41 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; + +import { TabbedLayout } from '@backstage/core-components'; + +import { workflowInstancesRouteRef } from '../routes'; +import { BaseOrchestratorPage } from './BaseOrchestratorPage'; +import { WorkflowRunsTabContent } from './WorkflowRunsTabContent'; +import { WorkflowsTabContent } from './WorkflowsTabContent'; + +export const OrchestratorPage = () => { + return ( + + + + + + + + + + + ); +}; diff --git a/workspaces/orchestrator/plugins/orchestrator/src/components/Paragraph.tsx b/workspaces/orchestrator/plugins/orchestrator/src/components/Paragraph.tsx new file mode 100644 index 00000000..482a856e --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator/src/components/Paragraph.tsx @@ -0,0 +1,33 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React, { PropsWithChildren } from 'react'; + +import { Typography } from '@material-ui/core'; +import { Variant } from '@material-ui/core/styles/createTypography'; + +export const Paragraph = ( + props: PropsWithChildren<{ variant?: Variant | 'inherit' }>, +) => { + return ( + + {props.children} + + ); +}; diff --git a/workspaces/orchestrator/plugins/orchestrator/src/components/Router.tsx b/workspaces/orchestrator/plugins/orchestrator/src/components/Router.tsx new file mode 100644 index 00000000..db1b8908 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator/src/components/Router.tsx @@ -0,0 +1,47 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; +import { Route, Routes } from 'react-router-dom'; + +import { + executeWorkflowRouteRef, + workflowDefinitionsRouteRef, + workflowInstanceRouteRef, +} from '../routes'; +import { ExecuteWorkflowPage } from './ExecuteWorkflowPage/ExecuteWorkflowPage'; +import { OrchestratorPage } from './OrchestratorPage'; +import { WorkflowDefinitionViewerPage } from './WorkflowDefinitionViewerPage'; +import { WorkflowInstancePage } from './WorkflowInstancePage'; + +export const Router = () => { + return ( + + } /> + } + /> + } + /> + } + /> + + ); +}; diff --git a/workspaces/orchestrator/plugins/orchestrator/src/components/Selector.tsx b/workspaces/orchestrator/plugins/orchestrator/src/components/Selector.tsx new file mode 100644 index 00000000..39b08ae9 --- /dev/null +++ b/workspaces/orchestrator/plugins/orchestrator/src/components/Selector.tsx @@ -0,0 +1,84 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; + +import { Select, SelectedItems } from '@backstage/core-components'; + +import { makeStyles, Typography } from '@material-ui/core'; + +const useStyles = makeStyles(theme => ({ + root: { + display: 'flex', + alignItems: 'baseline', + '& label + div': { + marginTop: '0px', + }, + }, + select: { + width: '10rem', + }, + label: { + color: theme.palette.text.primary, + fontSize: theme.typography.fontSize, + paddingRight: '0.5rem', + fontWeight: 'bold', + }, +})); + +const ALL_ITEMS = '___all___'; + +type BackstageSelectProps = Parameters[0]; +export type SelectorProps = Omit & { + includeAll?: boolean; + onChange: (item: string) => void; +}; + +export const Selector = ({ + includeAll = true, + ...otherProps +}: SelectorProps) => { + const styles = useStyles(); + + const selectItems = React.useMemo( + () => + includeAll + ? [{ label: 'All', value: ALL_ITEMS }, ...otherProps.items] + : otherProps.items, + [includeAll, otherProps.items], + ); + + const handleChange = React.useCallback( + (item: SelectedItems) => otherProps.onChange(item as string), + [otherProps], + ); + + return ( +
+ {otherProps.label} +
+