From 14dae500a1a9174a3a9ff7339c3d7983c7587d2b Mon Sep 17 00:00:00 2001 From: Hope Hadfield Date: Wed, 10 Jun 2026 16:09:03 -0400 Subject: [PATCH] chore(repo): archive sandbox workspace Signed-off-by: Hope Hadfield --- .github/CODEOWNERS | 1 - .github/archived-plugins.json | 9 + .github/labeler.yml | 3 - .github/pr-labeler.yml | 4 - .../workspace/rhdh-sandbox-presets.json | 28 - .github/renovate.json | 1 - ARCHIVED_WORKSPACES.md | 1 + codecov.yml | 3 - workspaces/sandbox/.changeset/README.md | 8 - workspaces/sandbox/.changeset/config.json | 14 - workspaces/sandbox/.dockerignore | 8 - workspaces/sandbox/.eslintignore | 1 - workspaces/sandbox/.eslintrc.js | 1 - workspaces/sandbox/.gitignore | 68 - workspaces/sandbox/.prettierignore | 6 - workspaces/sandbox/Makefile | 5 - workspaces/sandbox/README.md | 52 - workspaces/sandbox/app-config.production.yaml | 67 - workspaces/sandbox/app-config.yaml | 88 - workspaces/sandbox/backstage.json | 3 - workspaces/sandbox/catalog-info.yaml | 16 - .../sandbox/deploy/base/app-config.yaml | 82 - .../sandbox/deploy/base/dynamic-plugins.yaml | 90 - .../sandbox/deploy/base/kustomization.yaml | 6 - .../sandbox/images/know_build_issue.png | Bin 308545 -> 0 bytes workspaces/sandbox/make/sandbox.mk | 57 - workspaces/sandbox/package.json | 78 - workspaces/sandbox/plugins/README.md | 7 - .../sandbox/plugins/sandbox/.eslintrc.js | 1 - .../sandbox/plugins/sandbox/@types/index.d.ts | 31 - .../plugins/sandbox/ANALYTICS-EVENTS.md | 79 - .../sandbox/plugins/sandbox/CHANGELOG.md | 18 - workspaces/sandbox/plugins/sandbox/README.md | 14 - .../plugins/sandbox/app-config.dynamic.yaml | 93 - .../sandbox/plugins/sandbox/config.d.ts | 44 - .../sandbox/plugins/sandbox/dev/index.tsx | 42 - .../sandbox/plugins/sandbox/knip-report.md | 16 - .../sandbox/plugins/sandbox/package.json | 106 - .../sandbox/plugins/sandbox/report.api.md | 38 - .../sandbox/src/api/AnsibleBackendClient.tsx | 125 - .../sandbox/src/api/KubeBackendClient.tsx | 259 - .../src/api/RegistrationBackendClient.tsx | 240 - .../sandbox/src/api/SecureFetchClient.tsx | 50 - .../__tests__/AnsibleBackendClient.test.tsx | 243 - .../api/__tests__/KubeBackendClient.test.tsx | 502 - .../RegistrationBackendClient.test.tsx | 330 - .../sandbox/plugins/sandbox/src/api/index.ts | 59 - .../sandbox/src/assets/images/art0.svg | 224 - .../sandbox/src/assets/images/art1.svg | 15 - .../sandbox/src/assets/images/art2.svg | 897 - .../sandbox/src/assets/images/art3.svg | 44 - .../sandbox/src/assets/images/art4.svg | 14 - .../sandbox/src/assets/images/art5.svg | 341 - .../assets/images/sandbox-banner-image.svg | 9 - .../sandbox/src/assets/logos/ansible.svg | 9 - .../sandbox/src/assets/logos/devspaces.svg | 9 - .../src/assets/logos/logo_hat-only.svg | 1 - .../sandbox/src/assets/logos/openshift-ai.svg | 9 - .../assets/logos/openshift-virtualization.svg | 9 - .../sandbox/src/assets/logos/openshift.svg | 9 - .../Modals/AccessCodeInputModal.tsx | 227 - .../Modals/AnsibleDeleteInstanceModal.tsx | 113 - .../Modals/AnsibleLaunchInfoModal.tsx | 516 - .../Modals/PhoneVerificationModal.tsx | 138 - .../PhoneNumberStep.tsx | 271 - .../VerificationCodeStep.tsx | 401 - .../__tests__/PhoneNumberStep.test.tsx | 232 - .../__tests__/VerificationCodeStep.test.tsx | 455 - .../Modals/PhoneVerificationSteps/index.ts | 18 - .../__tests__/AccessCodeInputModal.test.tsx | 363 - .../AnsibleDeleteInstanceModal.test.tsx | 98 - .../__tests__/AnsibleLaunchInfoModal.test.tsx | 332 - .../__tests__/PhoneVerificationModal.test.tsx | 113 - .../sandbox/src/components/Modals/index.ts | 20 - .../SandboxActivitiesCard.tsx | 94 - .../SandboxActivitiesGrid.tsx | 84 - .../SandboxActivitiesPage.tsx | 35 - .../__tests__/SandboxActivitiesCard.test.tsx | 142 - .../__tests__/SandboxActivitiesGrid.test.tsx | 115 - .../SandboxActivities/articleData.ts | 83 - .../SandboxCatalog/SandboxCatalogBanner.tsx | 330 - .../SandboxCatalog/SandboxCatalogCard.tsx | 335 - .../SandboxCatalogCardButton.tsx | 166 - .../SandboxCatalogCardDeleteButton.tsx | 69 - .../SandboxCatalog/SandboxCatalogFooter.tsx | 156 - .../SandboxCatalog/SandboxCatalogGrid.tsx | 55 - .../SandboxCatalog/SandboxCatalogPage.tsx | 49 - .../__tests__/SandboxCatalogBanner.test.tsx | 400 - .../__tests__/SandboxCatalogCard.test.tsx | 309 - .../SandboxCatalogCardButton.test.tsx | 346 - .../SandboxCatalogCardDeleteButton.test.tsx | 88 - .../__tests__/SandboxCatalogFooter.test.tsx | 218 - .../__tests__/SandboxCatalogGrid.test.tsx | 173 - .../__tests__/productData.test.tsx | 114 - .../components/SandboxCatalog/productData.tsx | 184 - .../sandbox/src/components/SandboxHeader.tsx | 143 - .../src/components/SignIn/RHSSOSignInPage.tsx | 35 - .../__tests__/SandboxHeader.test.tsx | 121 - .../sandbox/plugins/sandbox/src/const.ts | 17 - .../hooks/__tests__/useGreenCorners.test.ts | 159 - .../sandbox/src/hooks/useGreenCorners.ts | 51 - .../sandbox/src/hooks/useProductURLs.ts | 97 - .../plugins/sandbox/src/hooks/useRecaptcha.ts | 27 - .../sandbox/src/hooks/useSandboxContext.tsx | 292 - .../sandbox/plugins/sandbox/src/index.ts | 24 - .../plugins/sandbox/src/plugin.test.ts | 145 - .../sandbox/plugins/sandbox/src/plugin.ts | 165 - .../sandbox/plugins/sandbox/src/routes.ts | 20 - .../sandbox/plugins/sandbox/src/setupTests.ts | 17 - .../sandbox/plugins/sandbox/src/types/aap.ts | 43 - .../plugins/sandbox/src/types/index.ts | 18 - .../sandbox/plugins/sandbox/src/types/kube.ts | 132 - .../plugins/sandbox/src/types/registration.ts | 59 - .../src/utils/__tests__/aap-utils.test.ts | 301 - .../src/utils/__tests__/common.test.ts | 103 - .../src/utils/__tests__/cookie-utils.test.ts | 86 - .../src/utils/__tests__/marketo-utils.test.ts | 280 - .../src/utils/__tests__/phone-utils.test.ts | 72 - .../src/utils/__tests__/recaptcha.test.ts | 59 - .../utils/__tests__/register-utils.test.ts | 93 - .../utils/__tests__/segment-analytics.test.ts | 374 - .../plugins/sandbox/src/utils/aap-utils.ts | 422 - .../plugins/sandbox/src/utils/common.ts | 54 - .../plugins/sandbox/src/utils/cookie-utils.ts | 31 - .../plugins/sandbox/src/utils/eddl-utils.ts | 134 - .../sandbox/src/utils/marketo-utils.ts | 101 - .../plugins/sandbox/src/utils/phone-utils.ts | 21 - .../plugins/sandbox/src/utils/recaptcha.ts | 30 - .../sandbox/src/utils/register-utils.ts | 39 - .../sandbox/src/utils/segment-analytics.ts | 154 - .../sandbox/sandboxplaywright.config.ts | 81 - workspaces/sandbox/tsconfig.json | 19 - workspaces/sandbox/yarn.lock | 23356 ---------------- 133 files changed, 10 insertions(+), 38794 deletions(-) delete mode 100644 .github/renovate-presets/workspace/rhdh-sandbox-presets.json delete mode 100644 workspaces/sandbox/.changeset/README.md delete mode 100644 workspaces/sandbox/.changeset/config.json delete mode 100644 workspaces/sandbox/.dockerignore delete mode 100644 workspaces/sandbox/.eslintignore delete mode 100644 workspaces/sandbox/.eslintrc.js delete mode 100644 workspaces/sandbox/.gitignore delete mode 100644 workspaces/sandbox/.prettierignore delete mode 100644 workspaces/sandbox/Makefile delete mode 100644 workspaces/sandbox/README.md delete mode 100644 workspaces/sandbox/app-config.production.yaml delete mode 100644 workspaces/sandbox/app-config.yaml delete mode 100644 workspaces/sandbox/backstage.json delete mode 100644 workspaces/sandbox/catalog-info.yaml delete mode 100644 workspaces/sandbox/deploy/base/app-config.yaml delete mode 100644 workspaces/sandbox/deploy/base/dynamic-plugins.yaml delete mode 100644 workspaces/sandbox/deploy/base/kustomization.yaml delete mode 100644 workspaces/sandbox/images/know_build_issue.png delete mode 100644 workspaces/sandbox/make/sandbox.mk delete mode 100644 workspaces/sandbox/package.json delete mode 100644 workspaces/sandbox/plugins/README.md delete mode 100644 workspaces/sandbox/plugins/sandbox/.eslintrc.js delete mode 100644 workspaces/sandbox/plugins/sandbox/@types/index.d.ts delete mode 100644 workspaces/sandbox/plugins/sandbox/ANALYTICS-EVENTS.md delete mode 100644 workspaces/sandbox/plugins/sandbox/CHANGELOG.md delete mode 100644 workspaces/sandbox/plugins/sandbox/README.md delete mode 100644 workspaces/sandbox/plugins/sandbox/app-config.dynamic.yaml delete mode 100644 workspaces/sandbox/plugins/sandbox/config.d.ts delete mode 100644 workspaces/sandbox/plugins/sandbox/dev/index.tsx delete mode 100644 workspaces/sandbox/plugins/sandbox/knip-report.md delete mode 100644 workspaces/sandbox/plugins/sandbox/package.json delete mode 100644 workspaces/sandbox/plugins/sandbox/report.api.md delete mode 100644 workspaces/sandbox/plugins/sandbox/src/api/AnsibleBackendClient.tsx delete mode 100644 workspaces/sandbox/plugins/sandbox/src/api/KubeBackendClient.tsx delete mode 100644 workspaces/sandbox/plugins/sandbox/src/api/RegistrationBackendClient.tsx delete mode 100644 workspaces/sandbox/plugins/sandbox/src/api/SecureFetchClient.tsx delete mode 100644 workspaces/sandbox/plugins/sandbox/src/api/__tests__/AnsibleBackendClient.test.tsx delete mode 100644 workspaces/sandbox/plugins/sandbox/src/api/__tests__/KubeBackendClient.test.tsx delete mode 100644 workspaces/sandbox/plugins/sandbox/src/api/__tests__/RegistrationBackendClient.test.tsx delete mode 100644 workspaces/sandbox/plugins/sandbox/src/api/index.ts delete mode 100644 workspaces/sandbox/plugins/sandbox/src/assets/images/art0.svg delete mode 100644 workspaces/sandbox/plugins/sandbox/src/assets/images/art1.svg delete mode 100644 workspaces/sandbox/plugins/sandbox/src/assets/images/art2.svg delete mode 100644 workspaces/sandbox/plugins/sandbox/src/assets/images/art3.svg delete mode 100644 workspaces/sandbox/plugins/sandbox/src/assets/images/art4.svg delete mode 100644 workspaces/sandbox/plugins/sandbox/src/assets/images/art5.svg delete mode 100644 workspaces/sandbox/plugins/sandbox/src/assets/images/sandbox-banner-image.svg delete mode 100644 workspaces/sandbox/plugins/sandbox/src/assets/logos/ansible.svg delete mode 100644 workspaces/sandbox/plugins/sandbox/src/assets/logos/devspaces.svg delete mode 100644 workspaces/sandbox/plugins/sandbox/src/assets/logos/logo_hat-only.svg delete mode 100644 workspaces/sandbox/plugins/sandbox/src/assets/logos/openshift-ai.svg delete mode 100644 workspaces/sandbox/plugins/sandbox/src/assets/logos/openshift-virtualization.svg delete mode 100644 workspaces/sandbox/plugins/sandbox/src/assets/logos/openshift.svg delete mode 100644 workspaces/sandbox/plugins/sandbox/src/components/Modals/AccessCodeInputModal.tsx delete mode 100644 workspaces/sandbox/plugins/sandbox/src/components/Modals/AnsibleDeleteInstanceModal.tsx delete mode 100644 workspaces/sandbox/plugins/sandbox/src/components/Modals/AnsibleLaunchInfoModal.tsx delete mode 100644 workspaces/sandbox/plugins/sandbox/src/components/Modals/PhoneVerificationModal.tsx delete mode 100644 workspaces/sandbox/plugins/sandbox/src/components/Modals/PhoneVerificationSteps/PhoneNumberStep.tsx delete mode 100644 workspaces/sandbox/plugins/sandbox/src/components/Modals/PhoneVerificationSteps/VerificationCodeStep.tsx delete mode 100644 workspaces/sandbox/plugins/sandbox/src/components/Modals/PhoneVerificationSteps/__tests__/PhoneNumberStep.test.tsx delete mode 100644 workspaces/sandbox/plugins/sandbox/src/components/Modals/PhoneVerificationSteps/__tests__/VerificationCodeStep.test.tsx delete mode 100644 workspaces/sandbox/plugins/sandbox/src/components/Modals/PhoneVerificationSteps/index.ts delete mode 100644 workspaces/sandbox/plugins/sandbox/src/components/Modals/__tests__/AccessCodeInputModal.test.tsx delete mode 100644 workspaces/sandbox/plugins/sandbox/src/components/Modals/__tests__/AnsibleDeleteInstanceModal.test.tsx delete mode 100644 workspaces/sandbox/plugins/sandbox/src/components/Modals/__tests__/AnsibleLaunchInfoModal.test.tsx delete mode 100644 workspaces/sandbox/plugins/sandbox/src/components/Modals/__tests__/PhoneVerificationModal.test.tsx delete mode 100644 workspaces/sandbox/plugins/sandbox/src/components/Modals/index.ts delete mode 100644 workspaces/sandbox/plugins/sandbox/src/components/SandboxActivities/SandboxActivitiesCard.tsx delete mode 100644 workspaces/sandbox/plugins/sandbox/src/components/SandboxActivities/SandboxActivitiesGrid.tsx delete mode 100644 workspaces/sandbox/plugins/sandbox/src/components/SandboxActivities/SandboxActivitiesPage.tsx delete mode 100644 workspaces/sandbox/plugins/sandbox/src/components/SandboxActivities/__tests__/SandboxActivitiesCard.test.tsx delete mode 100644 workspaces/sandbox/plugins/sandbox/src/components/SandboxActivities/__tests__/SandboxActivitiesGrid.test.tsx delete mode 100644 workspaces/sandbox/plugins/sandbox/src/components/SandboxActivities/articleData.ts delete mode 100644 workspaces/sandbox/plugins/sandbox/src/components/SandboxCatalog/SandboxCatalogBanner.tsx delete mode 100644 workspaces/sandbox/plugins/sandbox/src/components/SandboxCatalog/SandboxCatalogCard.tsx delete mode 100644 workspaces/sandbox/plugins/sandbox/src/components/SandboxCatalog/SandboxCatalogCardButton.tsx delete mode 100644 workspaces/sandbox/plugins/sandbox/src/components/SandboxCatalog/SandboxCatalogCardDeleteButton.tsx delete mode 100644 workspaces/sandbox/plugins/sandbox/src/components/SandboxCatalog/SandboxCatalogFooter.tsx delete mode 100644 workspaces/sandbox/plugins/sandbox/src/components/SandboxCatalog/SandboxCatalogGrid.tsx delete mode 100644 workspaces/sandbox/plugins/sandbox/src/components/SandboxCatalog/SandboxCatalogPage.tsx delete mode 100644 workspaces/sandbox/plugins/sandbox/src/components/SandboxCatalog/__tests__/SandboxCatalogBanner.test.tsx delete mode 100644 workspaces/sandbox/plugins/sandbox/src/components/SandboxCatalog/__tests__/SandboxCatalogCard.test.tsx delete mode 100644 workspaces/sandbox/plugins/sandbox/src/components/SandboxCatalog/__tests__/SandboxCatalogCardButton.test.tsx delete mode 100644 workspaces/sandbox/plugins/sandbox/src/components/SandboxCatalog/__tests__/SandboxCatalogCardDeleteButton.test.tsx delete mode 100644 workspaces/sandbox/plugins/sandbox/src/components/SandboxCatalog/__tests__/SandboxCatalogFooter.test.tsx delete mode 100644 workspaces/sandbox/plugins/sandbox/src/components/SandboxCatalog/__tests__/SandboxCatalogGrid.test.tsx delete mode 100644 workspaces/sandbox/plugins/sandbox/src/components/SandboxCatalog/__tests__/productData.test.tsx delete mode 100644 workspaces/sandbox/plugins/sandbox/src/components/SandboxCatalog/productData.tsx delete mode 100644 workspaces/sandbox/plugins/sandbox/src/components/SandboxHeader.tsx delete mode 100644 workspaces/sandbox/plugins/sandbox/src/components/SignIn/RHSSOSignInPage.tsx delete mode 100644 workspaces/sandbox/plugins/sandbox/src/components/__tests__/SandboxHeader.test.tsx delete mode 100644 workspaces/sandbox/plugins/sandbox/src/const.ts delete mode 100644 workspaces/sandbox/plugins/sandbox/src/hooks/__tests__/useGreenCorners.test.ts delete mode 100644 workspaces/sandbox/plugins/sandbox/src/hooks/useGreenCorners.ts delete mode 100644 workspaces/sandbox/plugins/sandbox/src/hooks/useProductURLs.ts delete mode 100644 workspaces/sandbox/plugins/sandbox/src/hooks/useRecaptcha.ts delete mode 100644 workspaces/sandbox/plugins/sandbox/src/hooks/useSandboxContext.tsx delete mode 100644 workspaces/sandbox/plugins/sandbox/src/index.ts delete mode 100644 workspaces/sandbox/plugins/sandbox/src/plugin.test.ts delete mode 100644 workspaces/sandbox/plugins/sandbox/src/plugin.ts delete mode 100644 workspaces/sandbox/plugins/sandbox/src/routes.ts delete mode 100644 workspaces/sandbox/plugins/sandbox/src/setupTests.ts delete mode 100644 workspaces/sandbox/plugins/sandbox/src/types/aap.ts delete mode 100644 workspaces/sandbox/plugins/sandbox/src/types/index.ts delete mode 100644 workspaces/sandbox/plugins/sandbox/src/types/kube.ts delete mode 100644 workspaces/sandbox/plugins/sandbox/src/types/registration.ts delete mode 100644 workspaces/sandbox/plugins/sandbox/src/utils/__tests__/aap-utils.test.ts delete mode 100644 workspaces/sandbox/plugins/sandbox/src/utils/__tests__/common.test.ts delete mode 100644 workspaces/sandbox/plugins/sandbox/src/utils/__tests__/cookie-utils.test.ts delete mode 100644 workspaces/sandbox/plugins/sandbox/src/utils/__tests__/marketo-utils.test.ts delete mode 100644 workspaces/sandbox/plugins/sandbox/src/utils/__tests__/phone-utils.test.ts delete mode 100644 workspaces/sandbox/plugins/sandbox/src/utils/__tests__/recaptcha.test.ts delete mode 100644 workspaces/sandbox/plugins/sandbox/src/utils/__tests__/register-utils.test.ts delete mode 100644 workspaces/sandbox/plugins/sandbox/src/utils/__tests__/segment-analytics.test.ts delete mode 100644 workspaces/sandbox/plugins/sandbox/src/utils/aap-utils.ts delete mode 100644 workspaces/sandbox/plugins/sandbox/src/utils/common.ts delete mode 100644 workspaces/sandbox/plugins/sandbox/src/utils/cookie-utils.ts delete mode 100644 workspaces/sandbox/plugins/sandbox/src/utils/eddl-utils.ts delete mode 100644 workspaces/sandbox/plugins/sandbox/src/utils/marketo-utils.ts delete mode 100644 workspaces/sandbox/plugins/sandbox/src/utils/phone-utils.ts delete mode 100644 workspaces/sandbox/plugins/sandbox/src/utils/recaptcha.ts delete mode 100644 workspaces/sandbox/plugins/sandbox/src/utils/register-utils.ts delete mode 100644 workspaces/sandbox/plugins/sandbox/src/utils/segment-analytics.ts delete mode 100644 workspaces/sandbox/sandboxplaywright.config.ts delete mode 100644 workspaces/sandbox/tsconfig.json delete mode 100644 workspaces/sandbox/yarn.lock diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 49de5dac16..c1bcf5e41c 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -30,7 +30,6 @@ /workspaces/orchestrator @redhat-developer/rhdh-plugins-maintainers @lholmquist @lokanandaprabhu @redhat-developer/rhdh-plugins @karthikjeeyar @christoph-jerolimov /workspaces/quickstart @redhat-developer/rhdh-plugins-maintainers @redhat-developer/rhdh-ui @divyanshiGupta @its-mitesh-kumar /workspaces/cost-management @redhat-developer/rhdh-plugins-maintainers @ydayagi @mareklibra @batzionb @PreetiW @asmasarw -/workspaces/sandbox @redhat-developer/rhdh-plugins-maintainers @lucifergene @rohitkrai03 @karthikjeeyar @xcoulon @alexeykazakov @mfrancisc @rsoaresd @jrosental @rajivnathan @MatousJobanek /workspaces/scorecard @redhat-developer/rhdh-plugins-maintainers @redhat-developer/rhdh-plugins @redhat-developer/rhdh-ui @christoph-jerolimov @its-mitesh-kumar @eswaraiahsapram /workspaces/theme @redhat-developer/rhdh-plugins-maintainers @redhat-developer/rhdh-ui @ciiay @logonoff /workspaces/translations @redhat-developer/rhdh-plugins-maintainers @redhat-developer/rhdh-ui @ciiay @debsmita1 @karthikjeeyar diff --git a/.github/archived-plugins.json b/.github/archived-plugins.json index 7b763f7ee9..3d0bdf08f4 100644 --- a/.github/archived-plugins.json +++ b/.github/archived-plugins.json @@ -8,6 +8,15 @@ "gitTag": "@red-hat-developer-hub/backstage-plugin-openshift-image-registry@1.18.0", "reason": "No longer maintained", "archivedDate": "2026-04-01" + }, + { + "pluginName": "@red-hat-developer-hub/backstage-plugin-sandbox", + "version": "0.1.0", + "workspace": "sandbox", + "plugin": "sandbox", + "gitTag": "@red-hat-developer-hub/backstage-plugin-sandbox@0.1.0", + "reason": "No longer maintained", + "archivedDate": "2026-06-10" } ] } diff --git a/.github/labeler.yml b/.github/labeler.yml index dd87015c7a..17cc15b416 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -52,9 +52,6 @@ workspace/quickstart: workspace/repo-tools: - 'Workspace\\s*repo-tools' -workspace/sandbox: - - 'Workspace\\s*sandbox' - workspace/scorecard: - 'Workspace\\s*scorecard' diff --git a/.github/pr-labeler.yml b/.github/pr-labeler.yml index 21f152eaf4..41fe8f2fc7 100644 --- a/.github/pr-labeler.yml +++ b/.github/pr-labeler.yml @@ -70,10 +70,6 @@ workspace/repo-tools: - changed-files: - any-glob-to-any-file: ['workspaces/repo-tools/**'] -workspace/sandbox: - - changed-files: - - any-glob-to-any-file: ['workspaces/sandbox/**'] - workspace/scorecard: - changed-files: - any-glob-to-any-file: ['workspaces/scorecard/**'] diff --git a/.github/renovate-presets/workspace/rhdh-sandbox-presets.json b/.github/renovate-presets/workspace/rhdh-sandbox-presets.json deleted file mode 100644 index 9e1544f244..0000000000 --- a/.github/renovate-presets/workspace/rhdh-sandbox-presets.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "packageRules": [ - { - "description": "all Sandbox minor updates", - "matchFileNames": ["workspaces/sandbox/**"], - "extends": [ - "github>redhat-developer/rhdh-plugins//.github/renovate-presets/base/rhdh-minor-presets(Sandbox)" - ], - "addLabels": ["team/sandbox", "sandbox"] - }, - { - "description": "all Sandbox patch updates", - "matchFileNames": ["workspaces/sandbox/**"], - "extends": [ - "github>redhat-developer/rhdh-plugins//.github/renovate-presets/base/rhdh-patch-presets(Sandbox)" - ], - "addLabels": ["team/sandbox", "sandbox"] - }, - { - "description": "all Sandbox dev dependency updates", - "matchFileNames": ["workspaces/sandbox/**"], - "extends": [ - "github>redhat-developer/rhdh-plugins//.github/renovate-presets/base/rhdh-devdependency-presets(Sandbox)" - ], - "addLabels": ["team/sandbox", "sandbox"] - } - ] -} diff --git a/.github/renovate.json b/.github/renovate.json index e6d4c007a3..2395aef51d 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -56,7 +56,6 @@ "github>redhat-developer/rhdh-plugins//.github/renovate-presets/workspace/rhdh-theme-presets", "github>redhat-developer/rhdh-plugins//.github/renovate-presets/workspace/rhdh-adoption-insights-presets", "github>redhat-developer/rhdh-plugins//.github/renovate-presets/workspace/rhdh-orchestrator-presets", - "github>redhat-developer/rhdh-plugins//.github/renovate-presets/workspace/rhdh-sandbox-presets", "github>redhat-developer/rhdh-plugins//.github/renovate-presets/workspace/rhdh-cost-management-presets", "github>redhat-developer/rhdh-plugins//.github/renovate-presets/workspace/rhdh-quickstart-presets", "github>redhat-developer/rhdh-plugins//.github/renovate-presets/workspace/rhdh-mcp-integrations-presets", diff --git a/ARCHIVED_WORKSPACES.md b/ARCHIVED_WORKSPACES.md index 9a9806faa9..fc829e4229 100644 --- a/ARCHIVED_WORKSPACES.md +++ b/ARCHIVED_WORKSPACES.md @@ -17,3 +17,4 @@ When a workspace or plugin is archived: | Workspace | Package | Reason | Source | | ------------------------ | ------------------------------------------------------------------ | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | openshift-image-registry | `@red-hat-developer-hub/backstage-plugin-openshift-image-registry` | No longer maintained | [@red-hat-developer-hub/backstage-plugin-openshift-image-registry@1.18.0](https://github.com/redhat-developer/rhdh-plugins/tree/%40red-hat-developer-hub%2Fbackstage-plugin-openshift-image-registry%401.18.0/workspaces/openshift-image-registry) | +| sandbox | `@red-hat-developer-hub/backstage-plugin-sandbox` | No longer maintained | [@red-hat-developer-hub/backstage-plugin-sandbox@0.1.0](https://github.com/redhat-developer/rhdh-plugins/tree/%40red-hat-developer-hub%2Fbackstage-plugin-sandbox%400.1.0/workspaces/sandbox) | diff --git a/codecov.yml b/codecov.yml index 63a3452ac9..a7ab6717b2 100644 --- a/codecov.yml +++ b/codecov.yml @@ -139,9 +139,6 @@ flag_management: - name: repo-tools paths: - workspaces/repo-tools/ - - name: sandbox - paths: - - workspaces/sandbox/ - name: scorecard paths: - workspaces/scorecard/ diff --git a/workspaces/sandbox/.changeset/README.md b/workspaces/sandbox/.changeset/README.md deleted file mode 100644 index e5b6d8d6a6..0000000000 --- a/workspaces/sandbox/.changeset/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# 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/sandbox/.changeset/config.json b/workspaces/sandbox/.changeset/config.json deleted file mode 100644 index 8208df00f2..0000000000 --- a/workspaces/sandbox/.changeset/config.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "$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/sandbox/.dockerignore b/workspaces/sandbox/.dockerignore deleted file mode 100644 index 05edb62650..0000000000 --- a/workspaces/sandbox/.dockerignore +++ /dev/null @@ -1,8 +0,0 @@ -.git -.yarn/cache -.yarn/install-state.gz -node_modules -packages/*/src -packages/*/node_modules -plugins -*.local.yaml diff --git a/workspaces/sandbox/.eslintignore b/workspaces/sandbox/.eslintignore deleted file mode 100644 index 129be7add2..0000000000 --- a/workspaces/sandbox/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -sandboxplaywright.config.ts diff --git a/workspaces/sandbox/.eslintrc.js b/workspaces/sandbox/.eslintrc.js deleted file mode 100644 index 59b86f8412..0000000000 --- a/workspaces/sandbox/.eslintrc.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('../../.eslintrc.cjs'); diff --git a/workspaces/sandbox/.gitignore b/workspaces/sandbox/.gitignore deleted file mode 100644 index b63d5a3359..0000000000 --- a/workspaces/sandbox/.gitignore +++ /dev/null @@ -1,68 +0,0 @@ -# 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 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/ - -# generated by 'npx @janus-idp/cli@3.3.1 package package-dynamic-plugins --export-to .' -index.json - - -# Environment variables -**/.env - -# Playwright -**/node_modules/ -**/test-results/ -**/playwright-report/ -**/blob-report/ -**/playwright/.cache/ \ No newline at end of file diff --git a/workspaces/sandbox/.prettierignore b/workspaces/sandbox/.prettierignore deleted file mode 100644 index 4f5a69b9d0..0000000000 --- a/workspaces/sandbox/.prettierignore +++ /dev/null @@ -1,6 +0,0 @@ -dist -dist-types -dist-dynamic -coverage -.vscode -.eslintrc.js diff --git a/workspaces/sandbox/Makefile b/workspaces/sandbox/Makefile deleted file mode 100644 index 4d53244a84..0000000000 --- a/workspaces/sandbox/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# It's necessary to set this because some environments don't link sh -> bash. -SHELL := /bin/bash - -include ./make/*.mk -.DEFAULT_GOAL := help \ No newline at end of file diff --git a/workspaces/sandbox/README.md b/workspaces/sandbox/README.md deleted file mode 100644 index 9a75e79385..0000000000 --- a/workspaces/sandbox/README.md +++ /dev/null @@ -1,52 +0,0 @@ -# Developer Sandbox Plugin for Red Hat Developer Hub - -This plugin provides the new developer sandbox experience for the Red Hat Developer Hub. - -## Configuration - -This plugin needs the following to be configured in the `app-config.local.yaml` file: - -1. The URL of the registration-service-api production server. -2. The URL of the kube-api production server. -3. The site key for Google Recaptcha. The keys can be obtained from the Google Recaptcha admin console. - -```sh -yarn install -yarn dev -``` - -To generate knip reports for this app, run: - -```sh -yarn backstage-repo-tools knip-reports -``` - -## Development - -To start the app locally, run: - -1. `cd workspaces/sandbox` -2. `yarn install` -3. `make start-rhdh-local` - -Please, note that every time you want to re deploy, you need to run: -`make stop-rhdh-local` - -NOTE: the app uses prod RH SSO as auth provider and sandbox stage backend by default -( those can be configured in `deploy/app-config.yaml` ) - -Known issues: - -- sometimes the local node build fails and you'll have to run `make stop-rhdh-local` and `make start-rhdh-local` again. - This is what you will see when the build fails: - ![Known Issues](./images/known_build_issue.png) - -## Upgrading backstage - -For upgrading backstage the `backstage-cli` should be used, for example: - -```shell -npx backstage-cli versions:bump --release 1.36.1 -``` - -More details on the upgrade process are available [keeping-backstage-updated](https://backstage.io/docs/getting-started/keeping-backstage-updated/) diff --git a/workspaces/sandbox/app-config.production.yaml b/workspaces/sandbox/app-config.production.yaml deleted file mode 100644 index 94f8f27f22..0000000000 --- a/workspaces/sandbox/app-config.production.yaml +++ /dev/null @@ -1,67 +0,0 @@ -app: - title: Developer Sandbox - branding: - fullLogo: 'data:image/png;base64,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' - fullLogoWidth: 100 - baseUrl: https://sandbox.redhat.com - sidebar: - search: false - administration: false - settings: false - -# Used for enabling the full page redirect flow rather than the popup flow for Red Hat SSO -enableExperimentalRedirectFlow: true - -organization: - name: Red Hat - -backend: - baseUrl: https://sandbox.redhat.com - csp: - img-src: - - "'self'" - - 'data:' - - 'https://catamphetamine.github.io' - script-src: - - "'self'" - - "'unsafe-eval'" - - 'https://cdn.segment.com' - - 'https://www.google.com' - - 'https://www.gstatic.com' - script-src-elem: - - "'self'" - - 'https://cdn.segment.com' - - 'https://www.google.com' - - 'https://www.gstatic.com' - frame-src: - - "'self'" - - 'https://www.google.com' - cors: - origin: https://sandbox.redhat.com - database: - client: better-sqlite3 - connection: ':memory:' - -auth: - environment: production - session: - secret: 'dummy' - providers: - oidc: - production: - metadataUrl: ${AUTH_OIDC_METADATA_URL} - clientId: ${AUTH_OIDC_CLIENT_ID} - clientSecret: ${AUTH_OIDC_CLIENT_SECRET} - prompt: auto - signIn: - resolvers: - - resolver: emailLocalPartMatchingUserEntityName - dangerouslyAllowSignInWithoutUserInCatalog: true - -signInPage: oidc - -sandbox: - signupAPI: ${SIGNUP_API} - kubeAPI: ${KUBE_API} - recaptcha: - siteKey: ${RECAPTCHA_SITE_KEY} diff --git a/workspaces/sandbox/app-config.yaml b/workspaces/sandbox/app-config.yaml deleted file mode 100644 index e234d6ce9d..0000000000 --- a/workspaces/sandbox/app-config.yaml +++ /dev/null @@ -1,88 +0,0 @@ -app: - title: Developer Sandbox - baseUrl: http://localhost:3000 - -# Used for enabling the full page redirect flow rather than the popup flow for Red Hat SSO -enableExperimentalRedirectFlow: true - -organization: - name: Red Hat - -sandbox: - signupAPI: ${SIGNUP_API} - kubeAPI: ${KUBE_API} - recaptcha: - siteKey: ${RECAPTCHA_SITE_KEY} - -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: - connect-src: ["'self'", 'http:', 'https:'] - # 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:' - # workingDirectory: /tmp # Use this to configure a working directory for the scaffolder, defaults to the OS temp-dir - -integrations: - github: - - host: github.com - # This is a Personal Access Token or PAT from GitHub. You can find out how to generate this token, and more information - # about setting up the GitHub integration here: https://backstage.io/docs/integrations/github/locations#configuration - token: ${GITHUB_TOKEN} - ### Example for how to add your GitHub Enterprise instance using the API: - # - host: ghe.example.net - # apiBaseUrl: https://ghe.example.net/api/v3 - # token: ${GHE_TOKEN} - - ### Example for how to add a proxy endpoint for the frontend. - ### A typical reason to do this is to handle HTTPS and CORS for internal services. - # endpoints: - # '/test': - # target: 'https://example.com' - # changeOrigin: true - -# Reference documentation http://backstage.io/docs/features/techdocs/configuration -# Note: After experimenting with basic setup, use CI/CD to generate docs -# and an external cloud storage when deploying TechDocs for production use-case. -# https://backstage.io/docs/features/techdocs/how-to-guides#how-to-migrate-from-techdocs-basic-to-recommended-deployment-approach -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: - # See https://backstage.io/docs/auth/guest/provider - 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, API, Resource, Location] diff --git a/workspaces/sandbox/backstage.json b/workspaces/sandbox/backstage.json deleted file mode 100644 index e235680d16..0000000000 --- a/workspaces/sandbox/backstage.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "version": "1.36.1" -} diff --git a/workspaces/sandbox/catalog-info.yaml b/workspaces/sandbox/catalog-info.yaml deleted file mode 100644 index 813533d6e4..0000000000 --- a/workspaces/sandbox/catalog-info.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: backstage.io/v1alpha1 -kind: Component -metadata: - name: sandbox - title: Sandbox - 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: backstage-plugin - owner: john@example.com - lifecycle: active - system: rhdh - subcomponentOf: rhdh-plugins diff --git a/workspaces/sandbox/deploy/base/app-config.yaml b/workspaces/sandbox/deploy/base/app-config.yaml deleted file mode 100644 index 1e28fa4db2..0000000000 --- a/workspaces/sandbox/deploy/base/app-config.yaml +++ /dev/null @@ -1,82 +0,0 @@ -app: - title: Developer Sandbox - baseUrl: http://localhost:3000 - -# this is required in order to be able to open the SSO login in full page mode. -enableExperimentalRedirectFlow: true - -backend: - baseUrl: http://localhost:3000 - csp: - img-src: - - "'self'" - - 'data:' - - 'https://catamphetamine.github.io' - - 'https://consent.trustarc.com' - script-src: - - "'self'" - - "'unsafe-eval'" - - "'unsafe-inline'" - - 'https://cdn.segment.com' - - 'https://www.google.com' - - 'https://www.gstatic.com' - - 'https://static.redhat.com' - - 'https://consent.trustarc.com' - - 'https://www.redhat.com/ma/dpal.js' - - 'https://assets.adobedtm.com' - - 'https://www.youtube.com' - - 'https://s.ytimg.com' - - 'https://adobedc.demdex.net' - - 'https://smetrics.redhat.com' - script-src-elem: - - "'self'" - - "'unsafe-inline'" - - 'https://cdn.segment.com' - - 'https://www.google.com' - - 'https://www.gstatic.com' - - 'https://static.redhat.com' - - 'https://consent.trustarc.com' - - 'https://www.redhat.com/ma/dpal.js' - - 'https://assets.adobedtm.com' - - 'https://www.youtube.com' - - 'https://s.ytimg.com' - - 'https://adobedc.demdex.net' - - 'https://smetrics.redhat.com' - frame-src: - - "'self'" - - 'https://www.google.com' - - 'https://static.redhat.com' - - 'https://consent.trustarc.com' - - 'https://consent-pref.trustarc.com' - - 'https://www.youtube.com' - - 'https://www.youtube-nocookie.com' - listen: - port: 3000 - cors: - origin: http://localhost:3000 - methods: [GET, HEAD, PATCH, POST, PUT, DELETE] - credentials: true - database: - client: better-sqlite3 - connection: ':memory:' -auth: - environment: production - session: - secret: 'dummy' - providers: - oidc: - production: - metadataUrl: https://sso.redhat.com/auth/realms/redhat-external - clientId: crtoolchain-local - clientSecret: dummy - prompt: auto - signIn: - resolvers: - - resolver: emailLocalPartMatchingUserEntityName - dangerouslyAllowSignInWithoutUserInCatalog: true -signInPage: oidc -sandbox: - signupAPI: https://registration-service-toolchain-host-operator.apps.sandbox.x8i5.p1.openshiftapps.com/api/v1 - kubeAPI: https://api-toolchain-host-operator.apps.sandbox.x8i5.p1.openshiftapps.com - recaptcha: - siteKey: 6Lc_164lAAAAAPvrC0WO-XDljvZ2DZ3UQ38A4XR0 diff --git a/workspaces/sandbox/deploy/base/dynamic-plugins.yaml b/workspaces/sandbox/deploy/base/dynamic-plugins.yaml deleted file mode 100644 index 5e5696044d..0000000000 --- a/workspaces/sandbox/deploy/base/dynamic-plugins.yaml +++ /dev/null @@ -1,90 +0,0 @@ -includes: - - dynamic-plugins.default.yaml -plugins: - - disabled: false - package: ./local-plugins/red-hat-developer-hub-backstage-plugin-sandbox - pluginConfig: - dynamicPlugins: - frontend: - default.main-menu-items: - menuItems: - default.home: - title: Home - icon: homeIcon - to: '/' - priority: 200 - default.activities: - title: Activities - icon: activitiesIcon - to: '/activities' - priority: 100 - default.catalog: - title: '' - default.apis: - title: '' - default.learning-path: - title: '' - default.create: - title: '' - red-hat-developer-hub.backstage-plugin-sandbox: - signInPage: - importName: RHSSOSignInPage - appIcons: - - name: homeIcon - importName: SandboxHomeIcon - - name: activitiesIcon - importName: SandboxActivitiesIcon - dynamicRoutes: - - path: / - importName: SandboxPage - - path: /activities - importName: SandboxActivitiesPage - - # Global Header - - package: ./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-global-header - disabled: false - pluginConfig: - dynamicPlugins: - frontend: - red-hat-developer-hub.backstage-plugin-global-header: - mountPoints: - - mountPoint: application/header - importName: GlobalHeader - config: - position: above-main-content - - mountPoint: global.header/component - importName: Spacer - config: - priority: 99 - props: - growFactor: 1 - minWidth: 1 - - mountPoint: global.header/component - importName: ProfileDropdown - config: - priority: 10 - - mountPoint: global.header/profile - importName: MenuItemLink - config: - priority: 100 - props: - title: Settings - link: /settings - icon: manageAccounts - - mountPoint: global.header/profile - importName: LogoutButton - config: - priority: 10 - - # Techdocs - - package: ./dynamic-plugins/dist/backstage-plugin-techdocs-backend-dynamic - disabled: true - - - package: ./dynamic-plugins/dist/backstage-plugin-techdocs - disabled: true - - - package: ./dynamic-plugins/dist/backstage-plugin-techdocs-module-addons-contrib - disabled: true - - - package: ./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-dynamic-home-page - disabled: true diff --git a/workspaces/sandbox/deploy/base/kustomization.yaml b/workspaces/sandbox/deploy/base/kustomization.yaml deleted file mode 100644 index 760fcc9f5f..0000000000 --- a/workspaces/sandbox/deploy/base/kustomization.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization - -resources: - - app-config.local.yaml - - dynamic-plugins.yaml diff --git a/workspaces/sandbox/images/know_build_issue.png b/workspaces/sandbox/images/know_build_issue.png deleted file mode 100644 index 1fd46ccd982a2ba6a7bc93cc805bbbb475f0705d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 308545 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

BbUF#CB$T%LCdA{S@y-P7dUxCZo>Y-tNwQa5?3@ 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"SS~%OE!Udsc*m#6jnk@=x;fVroQdDuur& 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

mymm81&+a~Hjw@KYq7{t&Vm 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≫(V?xHKDirco!=ezSMQ7UtiNVw+iWMn%t03> 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

f-8w5H^{kz@+5tzp*V0Qv3$xW?nbt%! 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 .env; \ - echo "RHDH_IMAGE=quay.io/rhdh-community/rhdh:next" >> .env; \ - echo ".env file generated for macOS arm64"; \ - else \ - echo "Skipping .env generation: OS=$$OS, ARCH=$$ARCH"; \ - fi - -.PHONY: start-rhdh-local -start-rhdh-local: clone-rhdh-local generate-env - rm -rf plugins/sandbox/dist-dynamic - rm -rf red-hat-developer-hub-backstage-plugin-sandbox - podman run -it --rm -w /home -v $(PWD):/home node:22 bash -c "yarn install && npx --yes @red-hat-developer-hub/cli@latest plugin package --export-to . && exit" - cp -r red-hat-developer-hub-backstage-plugin-sandbox $(RHDH_LOCAL_DIR)/local-plugins/ - cp deploy/base/app-config.yaml $(RHDH_LOCAL_DIR)/configs/app-config/app-config.yaml - cp deploy/base/dynamic-plugins.yaml $(RHDH_LOCAL_DIR)/configs/dynamic-plugins/dynamic-plugins.override.yaml - cd $(RHDH_LOCAL_DIR) && \ - yq e '.services.rhdh.ports = ["3000:3000"] | (.services.rhdh.ports) |= map(. style="double")' -i compose.yaml && \ - podman-compose up -d && \ - echo "UI is up and running at: http://localhost:3000" - -.PHONY: stop-rhdh-local -stop-rhdh-local: - cd $(RHDH_LOCAL_DIR) && \ - podman-compose down -v && \ - rm -rf $(RHDH_LOCAL_DIR) - -.PHONY: restart-rhdh-local -restart-rhdh-local: stop-rhdh-local start-rhdh-local diff --git a/workspaces/sandbox/package.json b/workspaces/sandbox/package.json deleted file mode 100644 index baf9038a5c..0000000000 --- a/workspaces/sandbox/package.json +++ /dev/null @@ -1,78 +0,0 @@ -{ - "name": "@internal/sandbox", - "version": "1.0.0", - "private": true, - "engines": { - "node": "22 || 24" - }, - "scripts": { - "dev": "yarn workspaces foreach -A --include backend --include app --parallel -v -i run start", - "start": "yarn workspace app start", - "start-backend": "yarn workspace backend start", - "build:backend": "yarn workspace backend build", - "tsc": "tsc", - "tsc:full": "tsc --skipLibCheck true --incremental false", - "build:all": "backstage-cli repo build --all", - "build:api-reports": "yarn build:api-reports:only --tsc", - "build:api-reports:only": "backstage-repo-tools api-reports -o ae-wrong-input-file-type --validate-release-tags", - "build:knip-reports": "backstage-repo-tools knip-reports", - "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", - "lint:check": "backstage-cli package lint", - "lint:fix": "backstage-cli package lint --fix", - "prettier:check": "prettier --check .", - "new": "backstage-cli new --scope @red-hat-developer-hub", - "postinstall": "cd ../../ && yarn install", - "test:base": "playwright test --config=sandboxplaywright.config.ts", - "tests": "npm run test:base", - "test:ui": "npm run test:base -- --ui", - "test:headless": "npm run test:base -- --headless", - "test:headed": "npm run test:base -- --headed", - "test:debug": "npm run test:base -- --debug", - "test:chromium": "npm run test:base -- --project=chromium", - "test:firefox": "npm run test:base -- --project=firefox", - "test:webkit": "npm run test:base -- --project=webkit" - }, - "workspaces": { - "packages": [ - "packages/*", - "plugins/*" - ] - }, - "repository": { - "type": "git", - "url": "https://github.com/redhat-developer/rhdh-plugins", - "directory": "workspaces/sandbox" - }, - "devDependencies": { - "@backstage/cli": "^0.30.0", - "@backstage/e2e-test-utils": "^0.1.1", - "@backstage/repo-tools": "^0.13.0", - "@changesets/cli": "^2.27.1", - "@playwright/test": "^1.52.0", - "@spotify/prettier-config": "^12.0.0", - "@types/lodash": "^4.17.16", - "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" - }, - "prettier": "@spotify/prettier-config", - "lint-staged": { - "*.{js,jsx,ts,tsx,mjs,cjs}": [ - "eslint --fix", - "prettier --write" - ], - "*.{json,md}": [ - "prettier --write" - ] - } -} diff --git a/workspaces/sandbox/plugins/README.md b/workspaces/sandbox/plugins/README.md deleted file mode 100644 index 4fc1756606..0000000000 --- a/workspaces/sandbox/plugins/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# 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. diff --git a/workspaces/sandbox/plugins/sandbox/.eslintrc.js b/workspaces/sandbox/plugins/sandbox/.eslintrc.js deleted file mode 100644 index e2a53a6ad2..0000000000 --- a/workspaces/sandbox/plugins/sandbox/.eslintrc.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/workspaces/sandbox/plugins/sandbox/@types/index.d.ts b/workspaces/sandbox/plugins/sandbox/@types/index.d.ts deleted file mode 100644 index 80a79a4747..0000000000 --- a/workspaces/sandbox/plugins/sandbox/@types/index.d.ts +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright Red Hat, Inc. - * - * 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. - */ -declare let grecaptcha: { - enterprise: ReCaptchaV3.ReCaptcha; -}; - -declare namespace ReCaptchaV3 { - interface ReCaptcha { - execute(siteKey: string, action: Action): PromiseLike; - ready(callback: () => void): void; - } - interface Action { - /** - * the name of the action. Actions may only contain alphanumeric characters and slashes, and must not be user-specific. - */ - action: string; - } -} diff --git a/workspaces/sandbox/plugins/sandbox/ANALYTICS-EVENTS.md b/workspaces/sandbox/plugins/sandbox/ANALYTICS-EVENTS.md deleted file mode 100644 index 4004d304a3..0000000000 --- a/workspaces/sandbox/plugins/sandbox/ANALYTICS-EVENTS.md +++ /dev/null @@ -1,79 +0,0 @@ -# Developer Sandbox - Analytics Events - -This document lists all analytics events sent to **Segment**, **Adobe Analytics (EDDL)**, and **Marketo**. - -## Track Events - -All events are sent to Segment and Adobe Analytics with the following patterns. Additionally, **Catalog clicks only** are sent to Marketo: - -- **Segment**: Event name = `{text} {verb}` where verb is `launched` (CTA) or `clicked` (non-CTA) -- **Adobe CTA**: Pushed to `window.appEventData` as `Master Link Clicked` -- **Adobe non-CTA**: Automatically tracked via data attributes -- **Marketo**: Catalog clicks only sent to Workato webhook for Marketo integration - -| Event Text | Section | Link Type | Segment Event Name | Adobe Tracking | Description | Intcmp ID | -| -------------------------------------------------------------------------------------- | ------------ | --------- | -------------------------------------------------------------------------------------------- | --------------- | ---------------------------------------------------------------------------- | ------------------ | -| **OpenShift** | Catalog | cta | `OpenShift launched` | Manual push | User clicks to launch OpenShift console for their sandbox environment | 701Pe00000dnCEYIA2 | -| **OpenShift AI** | Catalog | cta | `OpenShift AI launched` | Manual push | User clicks to launch OpenShift AI dashboard for ML/AI workloads | 701Pe00000do2uiIAA | -| **Dev Spaces** | Catalog | cta | `Dev Spaces launched` | Manual push | User clicks to launch OpenShift Dev Spaces cloud development environment | 701Pe00000doTQCIA2 | -| **Ansible Automation Platform** | Catalog | cta | `Ansible Automation Platform launched` | Manual push | User clicks to provision or access Ansible Automation Platform instance | 701Pe00000dowQXIAY | -| **OpenShift Virtualization** | Catalog | cta | `OpenShift Virtualization launched` | Manual push | User clicks to launch OpenShift Virtualization console for VM management | 701Pe00000dov6IIAQ | -| **Get Started - Ansible** | Catalog | cta | `Get Started - Ansible launched` | Manual push | User clicks to access their provisioned Ansible instance from the modal | 701Pe00000dowQXIAY | -| **Get started with your Developer Sandbox** | Activities | default | `Get started with your Developer Sandbox clicked` | Data attributes | User clicks to view the getting started tutorial for Developer Sandbox | - | -| **Streamline automation in OpenShift Dev Spaces with Ansible** | Activities | default | `Streamline automation in OpenShift Dev Spaces with Ansible clicked` | Data attributes | User clicks to view learning resource about Ansible automation in Dev Spaces | - | -| **How to deploy a Java application on Kubernetes in minutes** | Activities | default | `How to deploy a Java application on Kubernetes in minutes clicked` | Data attributes | User clicks to view Java application deployment tutorial | - | -| **Foundations of OpenShift** | Activities | default | `Foundations of OpenShift clicked` | Data attributes | User clicks to view foundational OpenShift learning resource | - | -| **Using OpenShift Pipelines** | Activities | default | `Using OpenShift Pipelines clicked` | Data attributes | User clicks to view CI/CD pipelines tutorial for OpenShift | - | -| **OpenShift virtualization and application modernization using the Developer Sandbox** | Activities | default | `OpenShift virtualization and application modernization using the Developer Sandbox clicked` | Data attributes | User clicks to view learning resource about VM management and modernization | - | -| **Contact Red Hat Sales** | Support | cta | `Contact Red Hat Sales launched` | Manual push | User clicks to contact Red Hat sales team for support or purchasing | - | -| **Send Code** | Verification | cta | `Send Code launched` | Manual push | User submits their phone number to receive a verification code via SMS | - | -| **Cancel Verification** | Verification | cta | `Cancel Verification launched` | Manual push | User cancels the phone verification process and closes the modal | - | -| **Start Trial** | Verification | cta | `Start Trial launched` | Manual push | User submits the verification code to complete signup and start their trial | - | -| **Resend Code** | Verification | cta | `Resend Code launched` | Manual push | User requests a new verification code to be sent to their phone | - | - -### Event Properties - -All events include these properties: - -| Property | Value Pattern | Example | -| ------------------ | ------------------------------ | ----------------------------- | -| `category` | `Developer Sandbox\|{Section}` | `Developer Sandbox\|Catalog` | -| `regions` | `sandbox-{section-lowercase}` | `sandbox-catalog` | -| `text` | Event text from table above | `OpenShift` | -| `href` | Destination URL | `https://console.example.com` | -| `linkType` | `cta` or `default` | `cta` | -| `internalCampaign` | Campaign ID (if applicable) | `701Pe00000dnCEYIA2` | - -## Identify & Group Calls - -| Call Type | Platform | Trigger | ID Used | Traits/Properties | -| ------------ | -------- | ------------------------------------------- | ----------- | ------------------------------------------------------------------------------- | -| **Identify** | Segment | First time `userID` available in session | `userID` | `{ company: [user company], email_domain: [user email domain] }` (when present) | -| **Group** | Segment | First time `accountID` available in session | `accountID` | `{ ebs: [account number] }` (when present) | - -## Marketo Integration (Catalog Clicks Only) - -Catalog clicks are sent to Marketo via a Workato webhook. The webhook URL is fetched dynamically from the `/uiconfig` API endpoint (`workatoWebHookURL` field). - -### Marketo Payload - -| Field | Source | Example | Description | -| --------------------- | --------------------------- | -------------------------------- | --------------------------------------------------- | -| `C_FirstName` | `userData.givenName` | `John` | User's first name | -| `C_LastName` | `userData.familyName` | `Doe` | User's last name | -| `C_EmailAddress` | `userData.email` | `jdtest@test.com` | User's email address (required for tracking) | -| `C_Company` | `userData.company` | `Red Hat` | User's company (empty if not available) | -| `A_Timestamp` | Current UTC timestamp | `2025/10/20 14:57:46` | Timestamp of the click in UTC (YYYY/MM/DD HH:mm:ss) | -| `F_FormData_Source` | Fixed value | `sandbox-redhat-com-integration` | Fixed identifier for this integration | -| `A_OfferID` | `internalCampaign` (Intcmp) | `701Pe00000dnCEYIA2` | Product offer ID from intcmp parameter | -| `A_TacticID_External` | Cookie: `rh_omni_tc` | `RHCTN1250000786344` | External tactic ID from Red Hat marketing cookie | -| `A_TacticID_Internal` | Cookie: `rh_omni_itc` | `RHCTE1250000786360` | Internal tactic ID from Red Hat marketing cookie | -| `Status` | Fixed value | `Engaged` | User engagement status | - -## Notes - -- **Segment** tracks all events (both CTA and non-CTA) -- **Adobe** manually tracks CTA events; non-CTA events use automatic tracking via dpal.js -- **Marketo** tracks Catalog clicks only via Workato webhook integration -- All tracking is non-blocking and includes error handling -- Scripts loaded: `trustarc.js` (privacy), `dpal.js` (Adobe tracking) diff --git a/workspaces/sandbox/plugins/sandbox/CHANGELOG.md b/workspaces/sandbox/plugins/sandbox/CHANGELOG.md deleted file mode 100644 index 28cea4e252..0000000000 --- a/workspaces/sandbox/plugins/sandbox/CHANGELOG.md +++ /dev/null @@ -1,18 +0,0 @@ -# @red-hat-developer-hub/backstage-plugin-sandbox - -## 0.1.0 - -### Minor Changes - -- cf219fd: Added a custom Sign in page which sends users directly the Red Hat account login, skipping the OIDC login page. - -### Patch Changes - -- 5e70ed1: Bug Fixes -- a9e5f32: Updated dependency `@openapitools/openapi-generator-cli` to `2.20.0`. - Updated dependency `prettier` to `3.5.3`. - Updated dependency `@redhat-developer/red-hat-developer-hub-theme` to `0.5.1`. - Updated dependency `@red-hat-developer-hub/backstage-plugin-theme` to `^0.6.0`. - Updated dependency `@janus-idp/cli` to `3.5.0`. -- 61dc50a: Add OAuth Header to the Sandbox API calls -- 5ad094e: Added Home and Activities pages diff --git a/workspaces/sandbox/plugins/sandbox/README.md b/workspaces/sandbox/plugins/sandbox/README.md deleted file mode 100644 index bb71b37397..0000000000 --- a/workspaces/sandbox/plugins/sandbox/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# Sandbox Frontend Plugin - -Welcome to the sandbox plugin! - -_This plugin was created through the Backstage CLI_ - -## Getting started - -To start the frontend app, run: - -```sh -yarn install -yarn start -``` diff --git a/workspaces/sandbox/plugins/sandbox/app-config.dynamic.yaml b/workspaces/sandbox/plugins/sandbox/app-config.dynamic.yaml deleted file mode 100644 index 31929688cf..0000000000 --- a/workspaces/sandbox/plugins/sandbox/app-config.dynamic.yaml +++ /dev/null @@ -1,93 +0,0 @@ -includes: - - dynamic-plugins.default.yaml -plugins: - - disabled: false - package: oci://quay.io/!red-hat-developer-hub-backstage-plugin-sandbox - pluginConfig: - dynamicPlugins: - frontend: - default.main-menu-items: - menuItems: - default.home: - title: Home - icon: homeIcon - to: '/' - priority: 200 - default.activities: - title: Activities - icon: activitiesIcon - to: '/activities' - priority: 100 - default.catalog: - title: '' - default.apis: - title: '' - default.learning-path: - title: '' - default.create: - title: '' - red-hat-developer-hub.backstage-plugin-sandbox: - signInPage: - importName: RHSSOSignInPage - appIcons: - - name: homeIcon - importName: SandboxHomeIcon - - name: activitiesIcon - importName: SandboxActivitiesIcon - dynamicRoutes: - - path: / - importName: SandboxPage - - path: /activities - importName: SandboxActivitiesPage - - # Global Header - # Hidden the Search Bar and the Create Icon - # Moved the Profile Dropdown to the right - - package: ./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-global-header - disabled: false - pluginConfig: - dynamicPlugins: - frontend: - red-hat-developer-hub.backstage-plugin-global-header: - mountPoints: - - mountPoint: application/header - importName: GlobalHeader - config: - position: above-main-content - - mountPoint: global.header/component - importName: Spacer - config: - priority: 99 - props: - growFactor: 1 - minWidth: 1 - - mountPoint: global.header/component - importName: ProfileDropdown - config: - priority: 10 - - mountPoint: global.header/profile - importName: MenuItemLink - config: - priority: 100 - props: - title: Settings - link: /settings - icon: manageAccounts - - mountPoint: global.header/profile - importName: LogoutButton - config: - priority: 10 - - # Techdocs: Disabled - - package: ./dynamic-plugins/dist/backstage-plugin-techdocs-backend-dynamic - disabled: true - - - package: ./dynamic-plugins/dist/backstage-plugin-techdocs - disabled: true - - - package: ./dynamic-plugins/dist/backstage-plugin-techdocs-module-addons-contrib - disabled: true - - # Dynamic Home Page: Disabled - - package: ./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-dynamic-home-page - disabled: true diff --git a/workspaces/sandbox/plugins/sandbox/config.d.ts b/workspaces/sandbox/plugins/sandbox/config.d.ts deleted file mode 100644 index 948cda8dfd..0000000000 --- a/workspaces/sandbox/plugins/sandbox/config.d.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright Red Hat, Inc. - * - * 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 required for using sandbox - * @visibility frontend - */ - sandbox: { - /** - * The URL of the sandbox service - * @visibility frontend - */ - signupAPI: string; - /** - * The URL of the sandbox service - * @visibility frontend - */ - kubeAPI: string; - /** - * @visibility frontend - */ - recaptcha: { - /** - * The recaptcha site key - * @visibility frontend - */ - siteKey: string; - }; - }; -} diff --git a/workspaces/sandbox/plugins/sandbox/dev/index.tsx b/workspaces/sandbox/plugins/sandbox/dev/index.tsx deleted file mode 100644 index cf3b5561e7..0000000000 --- a/workspaces/sandbox/plugins/sandbox/dev/index.tsx +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright Red Hat, Inc. - * - * 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 HomeOutlinedIcon from '@mui/icons-material/HomeOutlined'; -import StarOutlineOutlinedIcon from '@mui/icons-material/StarOutlineOutlined'; -import { createDevApp } from '@backstage/dev-utils'; -import { getAllThemes } from '@red-hat-developer-hub/backstage-plugin-theme'; -import { - sandboxPlugin, - SandboxPage, - SandboxActivitiesPage, -} from '../src/plugin'; - -createDevApp() - .registerPlugin(sandboxPlugin) - .addThemes(getAllThemes()) - .addPage({ - element: , - title: 'Home', - icon: HomeOutlinedIcon, - path: '/', - }) - .addPage({ - element: , - title: 'Activities', - icon: StarOutlineOutlinedIcon, - path: '/activities', - }) - .render(); diff --git a/workspaces/sandbox/plugins/sandbox/knip-report.md b/workspaces/sandbox/plugins/sandbox/knip-report.md deleted file mode 100644 index ba11982646..0000000000 --- a/workspaces/sandbox/plugins/sandbox/knip-report.md +++ /dev/null @@ -1,16 +0,0 @@ -# Knip report - -## Unused dependencies (1) - -| Name | Location | Severity | -| :-------- | :---------------- | :------- | -| react-use | package.json:51:6 | error | - -## Unused devDependencies (4) - -| Name | Location | Severity | -| :-------------------------- | :---------------- | :------- | -| @testing-library/user-event | package.json:67:6 | error | -| @backstage/core-app-api | package.json:61:6 | error | -| react-router | package.json:71:6 | error | -| msw | package.json:68:6 | error | diff --git a/workspaces/sandbox/plugins/sandbox/package.json b/workspaces/sandbox/plugins/sandbox/package.json deleted file mode 100644 index aa4afdba61..0000000000 --- a/workspaces/sandbox/plugins/sandbox/package.json +++ /dev/null @@ -1,106 +0,0 @@ -{ - "name": "@red-hat-developer-hub/backstage-plugin-sandbox", - "version": "0.1.0", - "main": "src/index.ts", - "types": "src/index.ts", - "license": "Apache-2.0", - "private": true, - "publishConfig": { - "access": "public", - "main": "dist/index.esm.js", - "types": "dist/index.d.ts" - }, - "repository": { - "type": "git", - "url": "https://github.com/redhat-developer/rhdh-plugins", - "directory": "workspaces/sandbox/plugins/sandbox" - }, - "backstage": { - "role": "frontend-plugin", - "pluginId": "sandbox", - "pluginPackage": "@red-hat-developer-hub/backstage-plugin-sandbox", - "pluginPackages": [ - "@red-hat-developer-hub/backstage-plugin-sandbox" - ] - }, - "sideEffects": [ - "./**/*.css" - ], - "scripts": { - "build": "backstage-cli package build", - "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", - "start": "backstage-cli package start", - "test": "backstage-cli package test --passWithNoTests --coverage", - "tsc": "tsc", - "prettier:check": "prettier --ignore-unknown --check .", - "prettier:fix": "prettier --ignore-unknown --write ." - }, - "dependencies": { - "@backstage/core-app-api": "^1.15.5", - "@backstage/core-components": "^0.16.4", - "@backstage/core-plugin-api": "^1.10.4", - "@backstage/theme": "^0.6.4", - "@lit/react": "^1.0.5", - "@mui/icons-material": "^5.16.14", - "@mui/material": "^5.16.14", - "@rhds/elements": "^2.0.1", - "@rhds/icons": "^1.1.1", - "@segment/analytics-next": "^1.0.0", - "libphonenumber-js": "^1.12.8", - "lodash": "^4.17.21", - "react-phone-number-input": "^3.4.12", - "react-use": "^17.2.4" - }, - "peerDependencies": { - "react": "^16.13.1 || ^17.0.0 || ^18.0.0", - "react-dom": "^18.0.2", - "react-router": "^6.3.0", - "react-router-dom": "^6.3.0" - }, - "devDependencies": { - "@backstage/cli": "^0.30.0", - "@backstage/dev-utils": "^1.1.7", - "@backstage/test-utils": "^1.7.5", - "@red-hat-developer-hub/backstage-plugin-theme": "^0.12.0", - "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.0.0", - "msw": "^1.0.0", - "react": "^16.13.1 || ^17.0.0 || ^18.0.0", - "react-dom": "^18.0.2", - "react-router": "^6.3.0", - "react-router-dom": "^6.3.0" - }, - "files": [ - "dist", - "config.d.ts", - "dist-scalprum", - "dist-dynamic/*.*", - "dist-dynamic/dist/*.*", - "dist-dynamic/dist-dynamic/*.*", - "dist-dynamic/dist-scalprum/*.*", - "app-config.dynamic.yaml" - ], - "scalprum": { - "name": "red-hat-developer-hub.backstage-plugin-sandbox", - "exposedModules": { - "PluginRoot": "./src/index.ts" - } - }, - "configSchema": "config.d.ts", - "keywords": [ - "backstage", - "plugin" - ], - "homepage": "https://red.ht/rhdh", - "bugs": "https://github.com/redhat-developer/rhdh-plugins/issues", - "maintainers": [ - "@lucifergene", - "@rohitkrai03" - ], - "author": "Red Hat" -} diff --git a/workspaces/sandbox/plugins/sandbox/report.api.md b/workspaces/sandbox/plugins/sandbox/report.api.md deleted file mode 100644 index 72ae47012a..0000000000 --- a/workspaces/sandbox/plugins/sandbox/report.api.md +++ /dev/null @@ -1,38 +0,0 @@ -## API Report File for "@red-hat-developer-hub/backstage-plugin-sandbox" - -> 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 { IconComponent } from '@backstage/core-plugin-api'; -import { JSX as JSX_2 } from 'react'; -import { RouteRef } from '@backstage/core-plugin-api'; - -// @public -export const RHSSOSignInPage: (props: any) => JSX_2.Element; - -// @public -export const SandboxActivitiesIcon: IconComponent; - -// @public -export const SandboxActivitiesPage: () => JSX_2.Element; - -// @public -export const SandboxHomeIcon: IconComponent; - -// @public -export const SandboxPage: () => JSX_2.Element; - -// @public -export const sandboxPlugin: BackstagePlugin< - { - root: RouteRef; - }, - {}, - {} ->; - -// (No @packageDocumentation comment for this package) -``` diff --git a/workspaces/sandbox/plugins/sandbox/src/api/AnsibleBackendClient.tsx b/workspaces/sandbox/plugins/sandbox/src/api/AnsibleBackendClient.tsx deleted file mode 100644 index dcc0e9d045..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/api/AnsibleBackendClient.tsx +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright Red Hat, Inc. - * - * 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 { ConfigApi } from '@backstage/core-plugin-api'; -import { errorMessage } from '../utils/common'; -import { AAPObject } from '../utils/aap-utils'; -import { AAPData } from '../types'; -import { SecureFetchApi } from './SecureFetchClient'; - -export type AnsibleBackendClientOptions = { - configApi: ConfigApi; - secureFetchApi: SecureFetchApi; -}; - -export interface AAPService { - getAAP(namespace: string): Promise; - createAAP(namespace: string): Promise; - unIdleAAP(namespace: string): Promise; - deleteAAPCR(namespace: string): Promise; -} - -export class AnsibleBackendClient implements AAPService { - private readonly configApi: ConfigApi; - private readonly secureFetchApi: SecureFetchApi; - - constructor(options: AnsibleBackendClientOptions) { - this.configApi = options.configApi; - this.secureFetchApi = options.secureFetchApi; - } - - private readonly kubeAPI = async (): Promise => { - const kubeAPI = this.configApi.getString('sandbox.kubeAPI'); - return kubeAPI; - }; - - getAAP = async (namespace: string): Promise => { - const kubeApi = await this.kubeAPI(); - const projectAAPUrl = `/apis/aap.ansible.com/v1alpha1/namespaces/${namespace}/ansibleautomationplatforms`; - const response = await this.secureFetchApi.fetch( - `${kubeApi}${projectAAPUrl}`, - { - method: 'GET', - }, - ); - - if (!response.ok) { - const error = await response.json(); - throw new Error(errorMessage(error)); - } - return response.json(); - }; - - createAAP = async (namespace: string): Promise => { - const kubeApi = await this.kubeAPI(); - const projectAAPUrl = `/apis/aap.ansible.com/v1alpha1/namespaces/${namespace}/ansibleautomationplatforms`; - const response = await this.secureFetchApi.fetch( - `${kubeApi}${projectAAPUrl}`, - { - method: 'POST', - body: AAPObject, - headers: { - 'Content-Type': 'application/yaml', - }, - }, - ); - - if (!response.ok && response.status !== 409) { - const error = await response.json(); - throw new Error(errorMessage(error)); - } - }; - - unIdleAAP = async (namespace: string): Promise => { - const kubeApi = await this.kubeAPI(); - const projectAAPUrl = `/apis/aap.ansible.com/v1alpha1/namespaces/${namespace}/ansibleautomationplatforms/sandbox-aap`; - const response = await this.secureFetchApi.fetch( - `${kubeApi}${projectAAPUrl}`, - { - method: 'PATCH', - body: JSON.stringify({ - spec: { - idle_aap: false, - }, - }), - headers: { - 'Content-Type': 'application/merge-patch+json', - }, - }, - ); - - if (!response.ok) { - const error = await response.json(); - throw new Error(errorMessage(error)); - } - }; - - deleteAAPCR = async (namespace: string): Promise => { - const kubeApi = await this.kubeAPI(); - const projectAAPUrl = `/apis/aap.ansible.com/v1alpha1/namespaces/${namespace}/ansibleautomationplatforms/sandbox-aap`; - const response = await this.secureFetchApi.fetch( - `${kubeApi}${projectAAPUrl}`, - { - method: 'DELETE', - }, - ); - - if (!response.ok && response.status !== 404) { - const error = await response.json(); - throw new Error(errorMessage(error)); - } - }; -} diff --git a/workspaces/sandbox/plugins/sandbox/src/api/KubeBackendClient.tsx b/workspaces/sandbox/plugins/sandbox/src/api/KubeBackendClient.tsx deleted file mode 100644 index cb0f08d92e..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/api/KubeBackendClient.tsx +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright Red Hat, Inc. - * - * 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 { ConfigApi } from '@backstage/core-plugin-api'; -import { errorMessage } from '../utils/common'; -import { - DeploymentData, - PersistentVolumeClaimData, - SecretItem, - StatefulSetData, -} from '../types'; -import { SecureFetchApi } from './SecureFetchClient'; - -export type KubeBackendClientOptions = { - configApi: ConfigApi; - secureFetchApi: SecureFetchApi; -}; - -export interface KubeAPIService { - deleteSecretsAndPVCs( - k8sObjects: StatefulSetData | DeploymentData | void, - userNamespace: string, - ): Promise; - deletePVCsForSTS( - k8sObjects: StatefulSetData | void, - userNamespace: string, - ): Promise; - getSecret( - namespace: string, - secretName: string, - ): Promise; - getPersistentVolumeClaims( - namespace: string, - labels?: string, - ): Promise; - getDeployments( - namespace: string, - labels?: string, - ): Promise; - getStatefulSets( - namespace: string, - labels?: string, - ): Promise; -} - -export class KubeBackendClient implements KubeAPIService { - private readonly configApi: ConfigApi; - private readonly secureFetchApi: SecureFetchApi; - - constructor(options: KubeBackendClientOptions) { - this.configApi = options.configApi; - this.secureFetchApi = options.secureFetchApi; - } - - private readonly kubeAPI = (): string => { - const kubeAPI = this.configApi.getString('sandbox.kubeAPI'); - return kubeAPI; - }; - - private readonly projectPersistentVolumeClaimUrl = ( - namespace: string, - labelSelector?: string, - ): string => { - let url = `/api/v1/namespaces/${namespace}/persistentvolumeclaims`; - if (labelSelector) { - url += `?labelSelector=${labelSelector}`; - } - return url; - }; - - private readonly projectDeploymentUrl = ( - namespace: string, - labelSelector?: string, - ) => { - let url = `/apis/apps/v1/namespaces/${namespace}/deployments`; - if (labelSelector) { - url += `?labelSelector=${labelSelector}`; - } - return url; - }; - - private readonly projectStatefulSetUrl = ( - namespace: string, - labelSelector?: string, - ) => { - let url = `/apis/apps/v1/namespaces/${namespace}/statefulsets`; - if (labelSelector) { - url += `?labelSelector=${labelSelector}`; - } - return url; - }; - - deleteSecretsAndPVCs = async ( - k8sObjects: StatefulSetData | DeploymentData | void, - userNamespace: string, - ): Promise => { - if (k8sObjects && k8sObjects.items.length > 0) { - const kubeApi = await this.kubeAPI(); - - for (const k8sObject of k8sObjects.items) { - const volumes = k8sObject?.spec?.template?.spec?.volumes; - if (!volumes) continue; - - for (const volume of volumes) { - // delete pvc if any - if (volume.persistentVolumeClaim?.claimName) { - const pvcURL = `/api/v1/namespaces/${userNamespace}/persistentvolumeclaims/${volume.persistentVolumeClaim.claimName}`; - const response = await this.secureFetchApi.fetch( - `${kubeApi}${pvcURL}`, - { - method: 'DELETE', - }, - ); - if (!response.ok && response.status !== 404) { - const error = await response.json(); - throw new Error(errorMessage(error)); - } - } - - // delete secret if any - if (volume.secret?.secretName) { - const secretURL = `/api/v1/namespaces/${userNamespace}/secrets/${volume.secret.secretName}`; - const response = await this.secureFetchApi.fetch( - `${kubeApi}${secretURL}`, - { - method: 'DELETE', - }, - ); - if (!response.ok && response.status !== 404) { - const error = await response.json(); - throw new Error(errorMessage(error)); - } - } - } - } - } - }; - - deletePVCsForSTS = async ( - k8sObjects: StatefulSetData | void, - userNamespace: string, - ): Promise => { - if (k8sObjects && k8sObjects.items.length > 0) { - const kubeApi = await this.kubeAPI(); - - for (const k8sObject of k8sObjects.items) { - const volumeClaimTemplates = k8sObject?.spec?.volumeClaimTemplates; - if (!volumeClaimTemplates) continue; - - for (const volumeClaim of volumeClaimTemplates) { - const pvcs = await this.getPersistentVolumeClaims( - userNamespace, - `app.kubernetes.io%2Fname%3D${volumeClaim.metadata.name}`, - ); - - if (pvcs && pvcs.items.length > 0) { - for (const pvc of pvcs.items) { - const pvcURL = `/api/v1/namespaces/${userNamespace}/persistentvolumeclaims/${pvc.metadata.name}`; - const response = await this.secureFetchApi.fetch( - `${kubeApi}${pvcURL}`, - { - method: 'DELETE', - }, - ); - if (!response.ok && response.status !== 404) { - const error = await response.json(); - throw new Error(errorMessage(error)); - } - } - } - } - } - } - }; - - getSecret = async ( - namespace: string, - secretName: string, - ): Promise => { - const kubeApi = await this.kubeAPI(); - const projectSecretURL = `/api/v1/namespaces/${namespace}/secrets/${secretName}`; - const response = await this.secureFetchApi.fetch( - `${kubeApi}${projectSecretURL}`, - { - method: 'GET', - }, - ); - - if (!response.ok) { - const error = await response.json(); - throw new Error(errorMessage(error)); - } - return response.json(); - }; - - getPersistentVolumeClaims = async ( - namespace: string, - labels?: string, - ): Promise => { - const kubeApi = await this.kubeAPI(); - const url = this.projectPersistentVolumeClaimUrl(namespace, labels); - const response = await this.secureFetchApi.fetch(`${kubeApi}${url}`, { - method: 'GET', - }); - - if (!response.ok) { - const error = await response.json(); - throw new Error(errorMessage(error)); - } - return response.json(); - }; - - getDeployments = async ( - namespace: string, - labels?: string, - ): Promise => { - const kubeApi = await this.kubeAPI(); - const url = this.projectDeploymentUrl(namespace, labels); - const response = await this.secureFetchApi.fetch(`${kubeApi}${url}`, { - method: 'GET', - }); - - if (!response.ok) { - const error = await response.json(); - throw new Error(errorMessage(error)); - } - return response.json(); - }; - - getStatefulSets = async ( - namespace: string, - labels?: string, - ): Promise => { - const kubeApi = await this.kubeAPI(); - const url = this.projectStatefulSetUrl(namespace, labels); - const response = await this.secureFetchApi.fetch(`${kubeApi}${url}`, { - method: 'GET', - }); - - if (!response.ok) { - const error = await response.json(); - throw new Error(errorMessage(error)); - } - return response.json(); - }; -} diff --git a/workspaces/sandbox/plugins/sandbox/src/api/RegistrationBackendClient.tsx b/workspaces/sandbox/plugins/sandbox/src/api/RegistrationBackendClient.tsx deleted file mode 100644 index 8f88be0a92..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/api/RegistrationBackendClient.tsx +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Copyright Red Hat, Inc. - * - * 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 { ConfigApi } from '@backstage/core-plugin-api'; -import { isValidCountryCode, isValidPhoneNumber } from '../utils/phone-utils'; -import { CommonResponse, SignupData } from '../types'; -import { SecureFetchApi } from './SecureFetchClient'; - -export type RegistrationBackendClientOptions = { - configApi: ConfigApi; - secureFetchApi: SecureFetchApi; -}; - -export interface UIConfig { - workatoWebHookURL?: string; -} - -export interface RegistrationService { - getRecaptchaAPIKey(): string; - getSignUpData(): Promise; - signup(): Promise; - initiatePhoneVerification( - countryCode: string, - phoneNumber: string, - ): Promise; - completePhoneVerification(code: string): Promise; - verifyActivationCode(code: string): Promise; - getSegmentWriteKey(): Promise; - getUIConfig(): Promise; -} - -export class RegistrationBackendClient implements RegistrationService { - private readonly configApi: ConfigApi; - private readonly secureFetchApi: SecureFetchApi; - - constructor(options: RegistrationBackendClientOptions) { - this.configApi = options.configApi; - this.secureFetchApi = options.secureFetchApi; - } - - private readonly signupAPI = (): string => { - const signupAPI = this.configApi.getString('sandbox.signupAPI'); - return `${signupAPI}/signup`; - }; - - getRecaptchaAPIKey = (): string => { - return ( - this.configApi.getOptionalString('sandbox.recaptcha.siteKey') ?? - 'test-api-key' - ); - }; - - getSignUpData = async (): Promise => { - const signupURL = await this.signupAPI(); - const response = await this.secureFetchApi.fetch(signupURL, { - method: 'GET', - }); - if (!response.ok) { - if (response.status === 404) { - return undefined; - } - throw new Error( - `Unexpected status code: ${response.status} ${response.statusText}`, - ); - } - return response.json(); - }; - - getRecaptchaToken = async (): Promise => { - return new Promise((resolve, reject) => { - const apiKey = this.getRecaptchaAPIKey(); - let timeout = false; - const captchaTimeout = setTimeout(() => { - timeout = true; - reject(new Error('Recaptcha timeout.')); - }, 10000); - if (grecaptcha?.enterprise) { - grecaptcha.enterprise.ready(async () => { - if (!timeout) { - clearTimeout(captchaTimeout); - try { - resolve( - await grecaptcha.enterprise.execute(apiKey, { - action: 'SIGNUP', - }), - ); - } catch (e) { - reject(new Error('Recaptcha failure.')); - } - } - }); - } else { - reject(new Error('Recaptcha failure.')); - } - }); - }; - - signup = async (): Promise => { - let token = ''; - try { - token = await this.getRecaptchaToken(); - } catch (err) { - throw new Error(`Error getting recaptcha token: ${err}`); - } - const signupURL = await this.signupAPI(); - await this.secureFetchApi.fetch(signupURL, { - method: 'POST', - headers: { - 'Recaptcha-Token': token, - }, - body: null, - }); - }; - - initiatePhoneVerification = async ( - countryCode: string, - phoneNumber: string, - ): Promise => { - const verificationURL = `${await this.signupAPI()}/verification`; - if (!isValidCountryCode(countryCode)) { - throw new Error('Invalid country code.'); - } - if (!isValidPhoneNumber(phoneNumber)) { - throw new Error('Invalid phone number.'); - } - const response = await this.secureFetchApi.fetch(verificationURL, { - method: 'PUT', - body: JSON.stringify({ - country_code: countryCode, - phone_number: phoneNumber, - }), - }); - - if (!response.ok) { - const error: CommonResponse = await response.json(); - // handle backend error messages and make it more user-friendly - if ( - error?.message.includes("Invalid 'To' Phone Number") || - error?.message.includes("'To' number cannot be a Short Code:") || - error?.message.includes( - "Message cannot be sent with the current combination of 'To'", - ) || - error?.message.includes('is not a valid mobile number') - ) { - throw new Error( - 'Invalid phone number. Please verify the country code and number format, then try again.', - ); - } else if (error?.message.includes('phone number already in use')) { - throw new Error( - 'This phone number is already in use. Please use a different number.', - ); - } else { - throw new Error(error?.message); - } - } - }; - - completePhoneVerification = async (code: string): Promise => { - const verificationURL = `${await this.signupAPI()}/verification`; - const response = await this.secureFetchApi.fetch( - `${verificationURL}/${code}`, - { - method: 'GET', - }, - ); - - if (!response.ok) { - const error: CommonResponse = await response.json(); - throw new Error(error?.message); - } - }; - - verifyActivationCode = async (code: string): Promise => { - const verificationURL = `${await this.signupAPI()}/verification/activation-code`; - const response = await this.secureFetchApi.fetch(verificationURL, { - method: 'POST', - body: JSON.stringify({ - code: code, - }), - }); - - if (!response.ok) { - const error: CommonResponse = await response.json(); - throw new Error(error?.message); - } - }; - - getSegmentWriteKey = async (): Promise => { - const signupAPI = this.configApi.getString('sandbox.signupAPI'); - const response = await this.secureFetchApi.fetch( - `${signupAPI}/analytics/segment-write-key`, - { - method: 'GET', - }, - ); - - if (!response.ok) { - throw new Error(`Failed to fetch Segment write key: ${response.status}`); - } - - const writeKey = await response.text(); - return writeKey.trim(); - }; - - getUIConfig = async (): Promise => { - try { - const signupAPI = this.configApi.getString('sandbox.signupAPI'); - const response = await this.secureFetchApi.fetch( - `${signupAPI}/uiconfig`, - { - method: 'GET', - }, - ); - - if (!response.ok) { - // Return empty config if fetch fails - UI config is optional - return {}; - } - - return response.json(); - } catch (error) { - // Return empty config on any error - UI config is optional - return {}; - } - }; -} diff --git a/workspaces/sandbox/plugins/sandbox/src/api/SecureFetchClient.tsx b/workspaces/sandbox/plugins/sandbox/src/api/SecureFetchClient.tsx deleted file mode 100644 index 4fc4162575..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/api/SecureFetchClient.tsx +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright Red Hat, Inc. - * - * 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 { OAuthApi } from '@backstage/core-plugin-api'; - -export type SecureFetchClientOptions = { - oauthApi: OAuthApi; -}; - -export interface SecureFetchApi { - fetch(input: RequestInfo | URL, init?: RequestInit): Promise; -} - -export class SecureFetchClient implements SecureFetchApi { - private readonly oauthApi: OAuthApi; - - constructor(options: SecureFetchClientOptions) { - this.oauthApi = options.oauthApi; - } - - fetch = async ( - input: RequestInfo | URL, - init?: RequestInit, - ): Promise => { - const token = await this.oauthApi.getAccessToken(); - const headers = new Headers(init?.headers); - - if (token) { - headers.set('Accept', 'application/json'); - headers.set('Authorization', `Bearer ${token}`); - } - - return fetch(input, { - ...init, - headers, - }); - }; -} diff --git a/workspaces/sandbox/plugins/sandbox/src/api/__tests__/AnsibleBackendClient.test.tsx b/workspaces/sandbox/plugins/sandbox/src/api/__tests__/AnsibleBackendClient.test.tsx deleted file mode 100644 index 6d78dcc080..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/api/__tests__/AnsibleBackendClient.test.tsx +++ /dev/null @@ -1,243 +0,0 @@ -/* - * Copyright Red Hat, Inc. - * - * 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 { ConfigApi } from '@backstage/core-plugin-api'; -import { AnsibleBackendClient } from '../AnsibleBackendClient'; -import { SecureFetchApi } from '../SecureFetchClient'; - -// Helper to create a mock Response object -const createMockResponse = (options: { - ok: boolean; - status?: number; - statusText?: string; - json?: () => Promise; -}): Response => { - const { ok, status = 200, statusText = '', json } = options; - return { - ok, - status, - statusText, - headers: new Headers(), - redirected: false, - type: 'basic', - url: 'http://mock', - json: json || (() => Promise.resolve({})), - text: () => Promise.resolve(''), - blob: () => Promise.resolve(new Blob()), - arrayBuffer: () => Promise.resolve(new ArrayBuffer(0)), - formData: () => Promise.resolve(new FormData()), - bodyUsed: false, - body: null, - clone: function () { - return this; - }, - } as Response; -}; - -describe('AnsibleBackendClient', () => { - let mockConfigApi: jest.Mocked; - let mockSecureFetchApi: jest.Mocked; - let client: AnsibleBackendClient; - const testNamespace = 'test-namespace'; - const mockKubeApi = 'http://kube-api'; - - beforeEach(() => { - mockConfigApi = { - getString: jest.fn(), - getOptionalString: jest.fn(), - } as any; - - mockSecureFetchApi = { - fetch: jest.fn(), - } as any; - - client = new AnsibleBackendClient({ - configApi: mockConfigApi, - secureFetchApi: mockSecureFetchApi, - }); - - mockConfigApi.getString.mockReturnValue(mockKubeApi); - }); - - describe('getAAP', () => { - it('should return AAP data on successful response', async () => { - const mockData = { name: 'sandbox-aap', status: 'Running' }; - mockSecureFetchApi.fetch.mockResolvedValue( - createMockResponse({ - ok: true, - json: () => Promise.resolve(mockData), - }), - ); - - const result = await client.getAAP(testNamespace); - expect(result).toEqual(mockData); - expect(mockSecureFetchApi.fetch).toHaveBeenCalledWith( - expect.stringContaining( - `/apis/aap.ansible.com/v1alpha1/namespaces/${testNamespace}/ansibleautomationplatforms`, - ), - expect.objectContaining({ method: 'GET' }), - ); - }); - - it('should throw error on unsuccessful response', async () => { - const errorData = { message: 'Not found' }; - mockSecureFetchApi.fetch.mockResolvedValue( - createMockResponse({ - ok: false, - status: 404, - json: () => Promise.resolve(errorData), - }), - ); - - await expect(client.getAAP(testNamespace)).rejects.toThrow(); - }); - }); - - describe('createAAP', () => { - const aapObject = '"kind":"AnsibleAutomationPlatform"'; - - it('should successfully create AAP', async () => { - mockSecureFetchApi.fetch.mockResolvedValue( - createMockResponse({ - ok: true, - }), - ); - - await expect(client.createAAP(testNamespace)).resolves.not.toThrow(); - expect(mockSecureFetchApi.fetch).toHaveBeenCalledWith( - expect.stringContaining( - `/apis/aap.ansible.com/v1alpha1/namespaces/${testNamespace}/ansibleautomationplatforms`, - ), - expect.objectContaining({ - method: 'POST', - body: expect.stringContaining(aapObject), - headers: { - 'Content-Type': 'application/yaml', - }, - }), - ); - }); - - it('should not throw error on 409 Conflict response', async () => { - mockSecureFetchApi.fetch.mockResolvedValue( - createMockResponse({ - ok: false, - status: 409, - }), - ); - - await expect(client.createAAP(testNamespace)).resolves.not.toThrow(); - }); - - it('should throw error on other unsuccessful responses', async () => { - const errorData = { message: 'Internal error' }; - mockSecureFetchApi.fetch.mockResolvedValue( - createMockResponse({ - ok: false, - status: 500, - json: () => Promise.resolve(errorData), - }), - ); - - await expect(client.createAAP(testNamespace)).rejects.toThrow(); - }); - }); - - describe('unIdleAAP', () => { - it('should successfully unidle AAP', async () => { - mockSecureFetchApi.fetch.mockResolvedValue( - createMockResponse({ - ok: true, - }), - ); - - await expect(client.unIdleAAP(testNamespace)).resolves.not.toThrow(); - expect(mockSecureFetchApi.fetch).toHaveBeenCalledWith( - expect.stringContaining( - `/apis/aap.ansible.com/v1alpha1/namespaces/${testNamespace}/ansibleautomationplatforms/sandbox-aap`, - ), - expect.objectContaining({ - method: 'PATCH', - headers: { - 'Content-Type': 'application/merge-patch+json', - }, - body: JSON.stringify({ - spec: { - idle_aap: false, - }, - }), - }), - ); - }); - - it('should throw error on unsuccessful response', async () => { - const errorData = { message: 'Failed to unidle' }; - mockSecureFetchApi.fetch.mockResolvedValue( - createMockResponse({ - ok: false, - status: 400, - json: () => Promise.resolve(errorData), - }), - ); - - await expect(client.unIdleAAP(testNamespace)).rejects.toThrow(); - }); - }); - - describe('deleteAAPCR', () => { - it('should successfully delete AAP CR', async () => { - mockSecureFetchApi.fetch.mockResolvedValue( - createMockResponse({ - ok: true, - }), - ); - - await expect(client.deleteAAPCR(testNamespace)).resolves.not.toThrow(); - expect(mockSecureFetchApi.fetch).toHaveBeenCalledWith( - expect.stringContaining( - `/apis/aap.ansible.com/v1alpha1/namespaces/${testNamespace}/ansibleautomationplatforms/sandbox-aap`, - ), - expect.objectContaining({ - method: 'DELETE', - }), - ); - }); - - it('should not throw error on 404 Not Found response', async () => { - mockSecureFetchApi.fetch.mockResolvedValue( - createMockResponse({ - ok: false, - status: 404, - }), - ); - - await expect(client.deleteAAPCR(testNamespace)).resolves.not.toThrow(); - }); - - it('should throw error on other unsuccessful responses', async () => { - const errorData = { message: 'Internal error' }; - mockSecureFetchApi.fetch.mockResolvedValue( - createMockResponse({ - ok: false, - status: 500, - json: () => Promise.resolve(errorData), - }), - ); - - await expect(client.deleteAAPCR(testNamespace)).rejects.toThrow(); - }); - }); -}); diff --git a/workspaces/sandbox/plugins/sandbox/src/api/__tests__/KubeBackendClient.test.tsx b/workspaces/sandbox/plugins/sandbox/src/api/__tests__/KubeBackendClient.test.tsx deleted file mode 100644 index 6c1b47e0ed..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/api/__tests__/KubeBackendClient.test.tsx +++ /dev/null @@ -1,502 +0,0 @@ -/* - * Copyright Red Hat, Inc. - * - * 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 { ConfigApi } from '@backstage/core-plugin-api'; -import { KubeBackendClient } from '../KubeBackendClient'; -import { SecureFetchApi } from '../SecureFetchClient'; -import { - DeploymentData, - PersistentVolumeClaimData, - StatefulSetData, - SecretItem, -} from '../../types'; - -// Helper to create a mock Response object -const createMockResponse = (options: { - ok: boolean; - status?: number; - statusText?: string; - json?: () => Promise; -}): Response => { - const { ok, status = 200, statusText = '', json } = options; - return { - ok, - status, - statusText, - headers: new Headers(), - redirected: false, - type: 'basic', - url: 'http://mock', - json: json || (() => Promise.resolve({})), - text: () => Promise.resolve(''), - blob: () => Promise.resolve(new Blob()), - arrayBuffer: () => Promise.resolve(new ArrayBuffer(0)), - formData: () => Promise.resolve(new FormData()), - bodyUsed: false, - body: null, - clone: function () { - return this; - }, - } as Response; -}; - -const commonMetadata = { - uuid: 'test-uuid', - creationTimestamp: '2025-05-15T00:00:00Z', - labels: { - app: 'test', - }, -}; - -describe('KubeBackendClient', () => { - let mockConfigApi: jest.Mocked; - let mockSecureFetchApi: jest.Mocked; - let client: KubeBackendClient; - const testNamespace = 'test-namespace'; - const mockKubeApi = 'http://kube-api'; - - beforeEach(() => { - mockConfigApi = { - getString: jest.fn(), - getOptionalString: jest.fn(), - } as any; - - mockSecureFetchApi = { - fetch: jest.fn(), - } as any; - - client = new KubeBackendClient({ - configApi: mockConfigApi, - secureFetchApi: mockSecureFetchApi, - }); - - mockConfigApi.getString.mockReturnValue(mockKubeApi); - }); - - describe('deleteSecretsAndPVCs', () => { - const mockDeploymentData: DeploymentData = { - items: [ - { - metadata: { - name: 'test-deployment', - ...commonMetadata, - }, - status: { - conditions: [{ type: 'Available', status: 'True' }], - }, - spec: { - replicas: 1, - template: { - metadata: { - labels: { - app: 'test', - deployment: 'test', - }, - }, - spec: { - volumes: [ - { - persistentVolumeClaim: { claimName: 'test-pvc' }, - name: 'test-volume', - }, - { - secret: { secretName: 'test-secret' }, - name: 'test-secret-volume', - }, - ], - }, - }, - }, - }, - ], - }; - - it('should delete PVCs and secrets successfully', async () => { - mockSecureFetchApi.fetch.mockResolvedValue( - createMockResponse({ - ok: true, - }), - ); - - await expect( - client.deleteSecretsAndPVCs(mockDeploymentData, testNamespace), - ).resolves.not.toThrow(); - - expect(mockSecureFetchApi.fetch).toHaveBeenCalledWith( - expect.stringContaining( - `/api/v1/namespaces/${testNamespace}/persistentvolumeclaims/test-pvc`, - ), - expect.objectContaining({ method: 'DELETE' }), - ); - - expect(mockSecureFetchApi.fetch).toHaveBeenCalledWith( - expect.stringContaining( - `/api/v1/namespaces/${testNamespace}/secrets/test-secret`, - ), - expect.objectContaining({ method: 'DELETE' }), - ); - }); - - it('should not throw on 404 responses', async () => { - mockSecureFetchApi.fetch.mockResolvedValue( - createMockResponse({ - ok: false, - status: 404, - }), - ); - - await expect( - client.deleteSecretsAndPVCs(mockDeploymentData, testNamespace), - ).resolves.not.toThrow(); - }); - - it('should throw on other error responses', async () => { - mockSecureFetchApi.fetch.mockResolvedValue( - createMockResponse({ - ok: false, - status: 500, - json: () => Promise.resolve({ message: 'Internal error' }), - }), - ); - - await expect( - client.deleteSecretsAndPVCs(mockDeploymentData, testNamespace), - ).rejects.toThrow(); - }); - }); - - describe('deletePVCsForSTS', () => { - const mockStatefulSetData: StatefulSetData = { - items: [ - { - metadata: { - name: 'test-statefulset', - ...commonMetadata, - }, - spec: { - replicas: 1, - template: { - metadata: { - labels: { - app: 'test', - deployment: 'test', - }, - }, - spec: {}, - }, - volumeClaimTemplates: [ - { - metadata: { - name: 'test-template', - ...commonMetadata, - }, - }, - ], - }, - status: { - conditions: [], - }, - }, - ], - }; - - const mockPVCData: PersistentVolumeClaimData = { - items: [ - { - metadata: { - name: 'test-pvc-1', - ...commonMetadata, - }, - }, - ], - }; - - it('should delete PVCs for StatefulSet successfully', async () => { - mockSecureFetchApi.fetch - .mockResolvedValueOnce( - createMockResponse({ - ok: true, - json: () => Promise.resolve(mockPVCData), - }), - ) - .mockResolvedValueOnce( - createMockResponse({ - ok: true, - }), - ); - - await expect( - client.deletePVCsForSTS(mockStatefulSetData, testNamespace), - ).resolves.not.toThrow(); - - expect(mockSecureFetchApi.fetch).toHaveBeenCalledWith( - expect.stringContaining( - `/api/v1/namespaces/${testNamespace}/persistentvolumeclaims/test-pvc-1`, - ), - expect.objectContaining({ method: 'DELETE' }), - ); - }); - }); - - describe('getSecret', () => { - const secretName = 'test-secret'; - const mockSecret: SecretItem = { - metadata: { - name: secretName, - uuid: 'test-secret-uuid', - creationTimestamp: '2025-05-15T00:00:00Z', - }, - data: { password: 'test-value' }, - }; - - it('should return secret data on successful response', async () => { - mockSecureFetchApi.fetch.mockResolvedValue( - createMockResponse({ - ok: true, - json: () => Promise.resolve(mockSecret), - }), - ); - - const result = await client.getSecret(testNamespace, secretName); - expect(result).toEqual(mockSecret); - expect(mockSecureFetchApi.fetch).toHaveBeenCalledWith( - expect.stringContaining( - `/api/v1/namespaces/${testNamespace}/secrets/${secretName}`, - ), - expect.objectContaining({ method: 'GET' }), - ); - }); - }); - - describe('getPersistentVolumeClaims', () => { - const mockPVCs: PersistentVolumeClaimData = { - items: [ - { - metadata: { - name: 'pvc-1', - ...commonMetadata, - }, - }, - { - metadata: { - name: 'pvc-2', - ...commonMetadata, - }, - }, - ], - }; - - it('should return PVCs without labels', async () => { - mockSecureFetchApi.fetch.mockResolvedValue( - createMockResponse({ - ok: true, - json: () => Promise.resolve(mockPVCs), - }), - ); - - const result = await client.getPersistentVolumeClaims(testNamespace); - expect(result).toEqual(mockPVCs); - expect(mockSecureFetchApi.fetch).toHaveBeenCalledWith( - expect.stringContaining( - `/api/v1/namespaces/${testNamespace}/persistentvolumeclaims`, - ), - expect.objectContaining({ method: 'GET' }), - ); - }); - - it('should return PVCs with label selector', async () => { - const labels = 'app=test'; - mockSecureFetchApi.fetch.mockResolvedValue( - createMockResponse({ - ok: true, - json: () => Promise.resolve(mockPVCs), - }), - ); - - await client.getPersistentVolumeClaims(testNamespace, labels); - expect(mockSecureFetchApi.fetch).toHaveBeenCalledWith( - expect.stringContaining(`labelSelector=${labels}`), - expect.any(Object), - ); - }); - }); - - describe('getDeployments', () => { - const mockDeployments: DeploymentData = { - items: [ - { - metadata: { - name: 'deployment-1', - ...commonMetadata, - }, - status: { - conditions: [{ type: 'Available', status: 'True' }], - }, - spec: { - replicas: 1, - template: { - metadata: { - labels: { - app: 'test', - deployment: 'test', - }, - }, - spec: {}, - }, - }, - }, - { - metadata: { - name: 'deployment-2', - ...commonMetadata, - }, - status: { - conditions: [{ type: 'Available', status: 'True' }], - }, - spec: { - replicas: 1, - template: { - metadata: { - labels: { - app: 'test', - deployment: 'test', - }, - }, - spec: {}, - }, - }, - }, - ], - }; - - it('should return deployments without labels', async () => { - mockSecureFetchApi.fetch.mockResolvedValue( - createMockResponse({ - ok: true, - json: () => Promise.resolve(mockDeployments), - }), - ); - - const result = await client.getDeployments(testNamespace); - expect(result).toEqual(mockDeployments); - expect(mockSecureFetchApi.fetch).toHaveBeenCalledWith( - expect.stringContaining( - `/apis/apps/v1/namespaces/${testNamespace}/deployments`, - ), - expect.objectContaining({ method: 'GET' }), - ); - }); - - it('should return deployments with label selector', async () => { - const labels = 'app=test'; - mockSecureFetchApi.fetch.mockResolvedValue( - createMockResponse({ - ok: true, - json: () => Promise.resolve(mockDeployments), - }), - ); - - await client.getDeployments(testNamespace, labels); - expect(mockSecureFetchApi.fetch).toHaveBeenCalledWith( - expect.stringContaining(`labelSelector=${labels}`), - expect.any(Object), - ); - }); - }); - - describe('getStatefulSets', () => { - const mockStatefulSets: StatefulSetData = { - items: [ - { - metadata: { - name: 'statefulset-1', - ...commonMetadata, - }, - status: { - conditions: [{ type: 'Available', status: 'True' }], - }, - spec: { - replicas: 1, - template: { - metadata: { - labels: { - app: 'test', - deployment: 'test', - }, - }, - spec: {}, - }, - }, - }, - { - metadata: { - name: 'statefulset-2', - ...commonMetadata, - }, - status: { - conditions: [{ type: 'Available', status: 'True' }], - }, - spec: { - replicas: 1, - template: { - metadata: { - labels: { - app: 'test', - deployment: 'test', - }, - }, - spec: {}, - }, - }, - }, - ], - }; - - it('should return statefulsets without labels', async () => { - mockSecureFetchApi.fetch.mockResolvedValue( - createMockResponse({ - ok: true, - json: () => Promise.resolve(mockStatefulSets), - }), - ); - - const result = await client.getStatefulSets(testNamespace); - expect(result).toEqual(mockStatefulSets); - expect(mockSecureFetchApi.fetch).toHaveBeenCalledWith( - expect.stringContaining( - `/apis/apps/v1/namespaces/${testNamespace}/statefulsets`, - ), - expect.objectContaining({ method: 'GET' }), - ); - }); - - it('should return statefulsets with label selector', async () => { - const labels = 'app=test'; - mockSecureFetchApi.fetch.mockResolvedValue( - createMockResponse({ - ok: true, - json: () => Promise.resolve(mockStatefulSets), - }), - ); - - await client.getStatefulSets(testNamespace, labels); - expect(mockSecureFetchApi.fetch).toHaveBeenCalledWith( - expect.stringContaining(`labelSelector=${labels}`), - expect.any(Object), - ); - }); - }); -}); diff --git a/workspaces/sandbox/plugins/sandbox/src/api/__tests__/RegistrationBackendClient.test.tsx b/workspaces/sandbox/plugins/sandbox/src/api/__tests__/RegistrationBackendClient.test.tsx deleted file mode 100644 index 421f781cd3..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/api/__tests__/RegistrationBackendClient.test.tsx +++ /dev/null @@ -1,330 +0,0 @@ -/* - * Copyright Red Hat, Inc. - * - * 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 { ConfigApi } from '@backstage/core-plugin-api'; -import { RegistrationBackendClient } from '../RegistrationBackendClient'; -import { SecureFetchApi } from '../SecureFetchClient'; - -// Helper to create a mock Response object -const createMockResponse = (options: { - ok: boolean; - status?: number; - statusText?: string; - json?: () => Promise; -}): Response => { - const { ok, status = 200, statusText = '', json } = options; - return { - ok, - status, - statusText, - headers: new Headers(), - redirected: false, - type: 'basic', - url: 'http://mock', - json: json || (() => Promise.resolve({})), - text: () => Promise.resolve(''), - blob: () => Promise.resolve(new Blob()), - arrayBuffer: () => Promise.resolve(new ArrayBuffer(0)), - formData: () => Promise.resolve(new FormData()), - bodyUsed: false, - body: null, - clone: function () { - return this; - }, - } as Response; -}; - -describe('RegistrationBackendClient', () => { - let mockConfigApi: jest.Mocked; - let mockSecureFetchApi: jest.Mocked; - let client: RegistrationBackendClient; - - beforeEach(() => { - mockConfigApi = { - getString: jest.fn(), - getOptionalString: jest.fn(), - } as any; - - mockSecureFetchApi = { - fetch: jest.fn(), - } as any; - - client = new RegistrationBackendClient({ - configApi: mockConfigApi, - secureFetchApi: mockSecureFetchApi, - }); - - // Mock the global grecaptcha object - (global as any).grecaptcha = { - enterprise: { - ready: jest.fn(callback => callback()), - execute: jest.fn(), - }, - }; - }); - - describe('getRecaptchaAPIKey', () => { - it('should return configured API key', () => { - mockConfigApi.getOptionalString.mockReturnValue('test-key'); - expect(client.getRecaptchaAPIKey()).toBe('test-key'); - }); - - it('should return default API key if not configured', () => { - mockConfigApi.getOptionalString.mockReturnValue(undefined); - expect(client.getRecaptchaAPIKey()).toBe('test-api-key'); - }); - }); - - describe('getSignUpData', () => { - it('should return signup data on successful response', async () => { - mockConfigApi.getString.mockReturnValue('http://api'); - const mockData = { someData: 'value' }; - mockSecureFetchApi.fetch.mockResolvedValue( - createMockResponse({ - ok: true, - json: () => Promise.resolve(mockData), - }), - ); - - const result = await client.getSignUpData(); - expect(result).toEqual(mockData); - }); - - it('should return undefined on 404 response', async () => { - mockConfigApi.getString.mockReturnValue('http://api'); - mockSecureFetchApi.fetch.mockResolvedValue( - createMockResponse({ - ok: false, - status: 404, - }), - ); - - const result = await client.getSignUpData(); - expect(result).toBeUndefined(); - }); - - it('should throw error on other unsuccessful responses', async () => { - mockConfigApi.getString.mockReturnValue('http://api'); - mockSecureFetchApi.fetch.mockResolvedValue( - createMockResponse({ - ok: false, - status: 500, - statusText: 'Server Error', - }), - ); - - await expect(client.getSignUpData()).rejects.toThrow( - 'Unexpected status code: 500 Server Error', - ); - }); - }); - - describe('initiatePhoneVerification', () => { - const validCountryCode = '+1'; - const validPhoneNumber = '1234567890'; - - beforeEach(() => { - mockConfigApi.getString.mockReturnValue('http://api'); - }); - - it('should successfully initiate phone verification', async () => { - mockSecureFetchApi.fetch.mockResolvedValue( - createMockResponse({ - ok: true, - }), - ); - - await expect( - client.initiatePhoneVerification(validCountryCode, validPhoneNumber), - ).resolves.not.toThrow(); - }); - - it('should throw error for invalid phone number format', async () => { - mockSecureFetchApi.fetch.mockResolvedValue( - createMockResponse({ - ok: false, - status: 400, - json: () => - Promise.resolve({ - message: "Invalid 'To' Phone Number", - }), - }), - ); - - await expect( - client.initiatePhoneVerification(validCountryCode, validPhoneNumber), - ).rejects.toThrow( - 'Invalid phone number. Please verify the country code and number format, then try again.', - ); - }); - - it('should throw error for already used phone number', async () => { - mockSecureFetchApi.fetch.mockResolvedValue( - createMockResponse({ - ok: false, - status: 400, - json: () => - Promise.resolve({ - message: 'phone number already in use', - }), - }), - ); - - await expect( - client.initiatePhoneVerification(validCountryCode, validPhoneNumber), - ).rejects.toThrow( - 'This phone number is already in use. Please use a different number.', - ); - }); - }); - - describe('completePhoneVerification', () => { - const validCode = '123456'; - - beforeEach(() => { - mockConfigApi.getString.mockReturnValue('http://api'); - }); - - it('should successfully complete phone verification', async () => { - mockSecureFetchApi.fetch.mockResolvedValue( - createMockResponse({ - ok: true, - }), - ); - - await expect( - client.completePhoneVerification(validCode), - ).resolves.not.toThrow(); - }); - - it('should throw error on unsuccessful verification', async () => { - const errorMessage = 'Invalid verification code'; - mockSecureFetchApi.fetch.mockResolvedValue( - createMockResponse({ - ok: false, - status: 400, - json: () => - Promise.resolve({ - message: errorMessage, - }), - }), - ); - - await expect(client.completePhoneVerification(validCode)).rejects.toThrow( - errorMessage, - ); - }); - }); - - describe('verifyActivationCode', () => { - const validCode = '123456'; - - beforeEach(() => { - mockConfigApi.getString.mockReturnValue('http://api'); - }); - - it('should successfully verify activation code', async () => { - mockSecureFetchApi.fetch.mockResolvedValue( - createMockResponse({ - ok: true, - }), - ); - - await expect( - client.verifyActivationCode(validCode), - ).resolves.not.toThrow(); - }); - - it('should throw error on unsuccessful verification', async () => { - const errorMessage = 'Invalid activation code'; - mockSecureFetchApi.fetch.mockResolvedValue( - createMockResponse({ - ok: false, - status: 400, - json: () => - Promise.resolve({ - message: errorMessage, - }), - }), - ); - - await expect(client.verifyActivationCode(validCode)).rejects.toThrow( - errorMessage, - ); - }); - }); - - describe('getUIConfig', () => { - it('should return UI config with workatoWebHookURL', async () => { - const mockUIConfig = { - workatoWebHookURL: 'https://webhooks.test', - }; - - mockSecureFetchApi.fetch.mockResolvedValue( - createMockResponse({ - ok: true, - json: () => Promise.resolve(mockUIConfig), - }), - ); - - const result = await client.getUIConfig(); - - expect(result).toEqual(mockUIConfig); - expect(mockSecureFetchApi.fetch).toHaveBeenCalledWith( - expect.stringContaining('/uiconfig'), - expect.objectContaining({ method: 'GET' }), - ); - }); - - it('should return empty config if workatoWebHookURL is not present', async () => { - const mockUIConfig = {}; - - mockSecureFetchApi.fetch.mockResolvedValue( - createMockResponse({ - ok: true, - json: () => Promise.resolve(mockUIConfig), - }), - ); - - const result = await client.getUIConfig(); - - expect(result).toEqual({}); - expect(result.workatoWebHookURL).toBeUndefined(); - }); - - it('should return empty config on unsuccessful response', async () => { - mockSecureFetchApi.fetch.mockResolvedValue( - createMockResponse({ - ok: false, - status: 500, - json: () => Promise.resolve({}), - }), - ); - - const result = await client.getUIConfig(); - - expect(result).toEqual({}); - }); - - it('should return empty config on fetch error', async () => { - mockSecureFetchApi.fetch.mockRejectedValue(new Error('Network failure')); - - const result = await client.getUIConfig(); - - expect(result).toEqual({}); - }); - }); -}); diff --git a/workspaces/sandbox/plugins/sandbox/src/api/index.ts b/workspaces/sandbox/plugins/sandbox/src/api/index.ts deleted file mode 100644 index 04ebe86b6c..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/api/index.ts +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright Red Hat, Inc. - * - * 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 { - ApiRef, - BackstageIdentityApi, - createApiRef, - OAuthApi, - OpenIdConnectApi, - ProfileInfoApi, - SessionApi, -} from '@backstage/core-plugin-api'; -import { RegistrationService } from './RegistrationBackendClient'; -import { KubeAPIService } from './KubeBackendClient'; -import { AAPService } from './AnsibleBackendClient'; -import { SecureFetchApi } from './SecureFetchClient'; - -export * from './SecureFetchClient'; -export * from './RegistrationBackendClient'; -export * from './KubeBackendClient'; -export * from './AnsibleBackendClient'; - -export const keycloakApiRef: ApiRef< - OpenIdConnectApi & - ProfileInfoApi & - BackstageIdentityApi & - SessionApi & - OAuthApi -> = createApiRef({ - id: 'plugin.sandbox.keycloak.api-ref', -}); - -export const secureFetchApiRef = createApiRef({ - id: 'plugin.sandbox.secure-fetch.api-ref', -}); - -export const registerApiRef = createApiRef({ - id: 'plugin.sandbox.registration.api-ref', -}); - -export const kubeApiRef = createApiRef({ - id: 'plugin.sandbox.kube.api-ref', -}); - -export const aapApiRef = createApiRef({ - id: 'plugin.sandbox.aap.api-ref', -}); diff --git a/workspaces/sandbox/plugins/sandbox/src/assets/images/art0.svg b/workspaces/sandbox/plugins/sandbox/src/assets/images/art0.svg deleted file mode 100644 index 516e70ac1f..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/assets/images/art0.svg +++ /dev/null @@ -1,224 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/workspaces/sandbox/plugins/sandbox/src/assets/images/art1.svg b/workspaces/sandbox/plugins/sandbox/src/assets/images/art1.svg deleted file mode 100644 index ebc5df3978..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/assets/images/art1.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/workspaces/sandbox/plugins/sandbox/src/assets/images/art2.svg b/workspaces/sandbox/plugins/sandbox/src/assets/images/art2.svg deleted file mode 100644 index 4b524884bf..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/assets/images/art2.svg +++ /dev/null @@ -1,897 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/workspaces/sandbox/plugins/sandbox/src/assets/images/art3.svg b/workspaces/sandbox/plugins/sandbox/src/assets/images/art3.svg deleted file mode 100644 index 4b04293dc3..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/assets/images/art3.svg +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/workspaces/sandbox/plugins/sandbox/src/assets/images/art4.svg b/workspaces/sandbox/plugins/sandbox/src/assets/images/art4.svg deleted file mode 100644 index 9a82ac0159..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/assets/images/art4.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/workspaces/sandbox/plugins/sandbox/src/assets/images/art5.svg b/workspaces/sandbox/plugins/sandbox/src/assets/images/art5.svg deleted file mode 100644 index 65093bacfe..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/assets/images/art5.svg +++ /dev/null @@ -1,341 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/workspaces/sandbox/plugins/sandbox/src/assets/images/sandbox-banner-image.svg b/workspaces/sandbox/plugins/sandbox/src/assets/images/sandbox-banner-image.svg deleted file mode 100644 index caf3712fc2..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/assets/images/sandbox-banner-image.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/workspaces/sandbox/plugins/sandbox/src/assets/logos/ansible.svg b/workspaces/sandbox/plugins/sandbox/src/assets/logos/ansible.svg deleted file mode 100644 index 3329c8a164..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/assets/logos/ansible.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/workspaces/sandbox/plugins/sandbox/src/assets/logos/devspaces.svg b/workspaces/sandbox/plugins/sandbox/src/assets/logos/devspaces.svg deleted file mode 100644 index c9d1c8f11d..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/assets/logos/devspaces.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/workspaces/sandbox/plugins/sandbox/src/assets/logos/logo_hat-only.svg b/workspaces/sandbox/plugins/sandbox/src/assets/logos/logo_hat-only.svg deleted file mode 100644 index 062df671c1..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/assets/logos/logo_hat-only.svg +++ /dev/null @@ -1 +0,0 @@ -RedHat-Logo-Hat-Color \ No newline at end of file diff --git a/workspaces/sandbox/plugins/sandbox/src/assets/logos/openshift-ai.svg b/workspaces/sandbox/plugins/sandbox/src/assets/logos/openshift-ai.svg deleted file mode 100644 index 294f5abefb..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/assets/logos/openshift-ai.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/workspaces/sandbox/plugins/sandbox/src/assets/logos/openshift-virtualization.svg b/workspaces/sandbox/plugins/sandbox/src/assets/logos/openshift-virtualization.svg deleted file mode 100644 index 3b937b4eda..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/assets/logos/openshift-virtualization.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/workspaces/sandbox/plugins/sandbox/src/assets/logos/openshift.svg b/workspaces/sandbox/plugins/sandbox/src/assets/logos/openshift.svg deleted file mode 100644 index efd6c7b3b4..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/assets/logos/openshift.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/workspaces/sandbox/plugins/sandbox/src/components/Modals/AccessCodeInputModal.tsx b/workspaces/sandbox/plugins/sandbox/src/components/Modals/AccessCodeInputModal.tsx deleted file mode 100644 index a323e4fbc2..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/components/Modals/AccessCodeInputModal.tsx +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright Red Hat, Inc. - * - * 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, { useEffect, useRef, useState } from 'react'; -import { useTheme } from '@mui/material/styles'; -import Button from '@mui/material/Button'; -import Dialog from '@mui/material/Dialog'; -import DialogTitle from '@mui/material/DialogTitle'; -import DialogContent from '@mui/material/DialogContent'; -import DialogContentText from '@mui/material/DialogContentText'; -import DialogActions from '@mui/material/DialogActions'; -import ErrorIcon from '@mui/icons-material/Error'; -import TextField from '@mui/material/TextField'; -import IconButton from '@mui/material/IconButton'; -import CloseIcon from '@mui/icons-material/Close'; -import Stack from '@mui/material/Stack'; -import { useApi } from '@backstage/core-plugin-api'; -import { registerApiRef } from '../../api'; -import { useSandboxContext } from '../../hooks/useSandboxContext'; -import Typography from '@mui/material/Typography'; -import CircularProgress from '@mui/material/CircularProgress'; -import { errorMessage } from '../../utils/common'; - -type AccessCodeInputModalProps = { - modalOpen: boolean; - setOpen: React.Dispatch>; -}; - -export const AccessCodeInputModal: React.FC = ({ - modalOpen, - setOpen, -}) => { - const theme = useTheme(); - const registerApi = useApi(registerApiRef); - const { refetchUserData } = useSandboxContext(); - const [loading, setLoading] = useState(false); - const [accessCode, setAccessCode] = useState(['', '', '', '', '']); - const [accessCodeError, setAccessCodeError] = React.useState< - string | undefined - >(); - const inputRefs = useRef([]); - - useEffect(() => { - if (modalOpen) { - // Focus on the first input field when modal opens - setTimeout(() => inputRefs.current[0]?.focus(), 100); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [modalOpen]); - - const handleClose = () => { - setOpen(false); - setAccessCode(['', '', '', '', '']); - setAccessCodeError(undefined); - }; - - const handleChange = ( - index: number, - event: React.ChangeEvent, - ) => { - const value = event.target.value; - - // Only allow alphanumeric characters - if (value && !/^[A-Za-z0-9]$/.test(value)) return; - - const newAccessCode = [...accessCode]; - newAccessCode[index] = value; - setAccessCode(newAccessCode); - - // Move focus to next input - if (value && index < accessCode.length - 1) { - inputRefs.current[index + 1].focus(); - } - }; - - // Handle Backspace: Move focus to previous box if empty - const handleKeyDown = ( - index: number, - event: React.KeyboardEvent, - ) => { - if (event.key === 'Backspace' && !accessCode[index] && index > 0) { - inputRefs.current[index - 1].focus(); - } - }; - - const handleStartTrialClick = async () => { - try { - setAccessCodeError(undefined); - setLoading(true); - await registerApi.verifyActivationCode(accessCode.join('')); - refetchUserData(); - handleClose(); - } catch (e) { - setAccessCodeError(errorMessage(e)); - } finally { - setLoading(false); - } - }; - - return ( -

- - Enter the activation code - - - - - - - If you have an activation code, enter it now. - - - {accessCode.map((digit, index) => ( - handleChange(index, e)} - onKeyDown={e => - handleKeyDown(index, e as React.KeyboardEvent) - } - inputRef={el => (inputRefs.current[index] = el)} - variant="outlined" - inputProps={{ - maxLength: 1, - style: { textAlign: 'center', fontWeight: 400 }, - }} - /> - ))} - - {accessCodeError && ( - -
- - {accessCodeError} -
-
- )} -
- - - - -
- ); -}; - -export default AccessCodeInputModal; diff --git a/workspaces/sandbox/plugins/sandbox/src/components/Modals/AnsibleDeleteInstanceModal.tsx b/workspaces/sandbox/plugins/sandbox/src/components/Modals/AnsibleDeleteInstanceModal.tsx deleted file mode 100644 index eba4d05726..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/components/Modals/AnsibleDeleteInstanceModal.tsx +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright Red Hat, Inc. - * - * 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 from '@mui/material/Button'; -import Dialog from '@mui/material/Dialog'; -import DialogActions from '@mui/material/DialogActions'; -import DialogContent from '@mui/material/DialogContent'; -import DialogTitle from '@mui/material/DialogTitle'; -import IconButton from '@mui/material/IconButton'; -import WarningIcon from '@mui/icons-material/Warning'; -import Typography from '@mui/material/Typography'; -import { useTheme } from '@mui/material/styles'; -import CloseIcon from '@mui/icons-material/Close'; - -type AnsibleDeleteInstanceModalProps = { - modalOpen: boolean; - setOpen: React.Dispatch>; - handleAnsibleDeleteInstance: () => void; -}; - -export const AnsibleDeleteInstanceModal: React.FC< - AnsibleDeleteInstanceModalProps -> = ({ modalOpen, setOpen, handleAnsibleDeleteInstance }) => { - const theme = useTheme(); - - const handleClose = () => { - setOpen(false); - }; - - return ( - - -
- -
Delete instance?
-
-
- - - {' '} - - - Your AAP instance will be deleted. Consider backing up your work - before continuing. - - - - - - -
- ); -}; - -export default AnsibleDeleteInstanceModal; diff --git a/workspaces/sandbox/plugins/sandbox/src/components/Modals/AnsibleLaunchInfoModal.tsx b/workspaces/sandbox/plugins/sandbox/src/components/Modals/AnsibleLaunchInfoModal.tsx deleted file mode 100644 index 1c6e0c3e97..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/components/Modals/AnsibleLaunchInfoModal.tsx +++ /dev/null @@ -1,516 +0,0 @@ -/* - * Copyright Red Hat, Inc. - * - * 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, { useState } from 'react'; -import Alert from '@mui/material/Alert'; -import Box from '@mui/material/Box'; -import Button from '@mui/material/Button'; -import CircularProgress from '@mui/material/CircularProgress'; -import Dialog from '@mui/material/Dialog'; -import DialogActions from '@mui/material/DialogActions'; -import DialogContent from '@mui/material/DialogContent'; -import DialogTitle from '@mui/material/DialogTitle'; -import IconButton from '@mui/material/IconButton'; -import InputAdornment from '@mui/material/InputAdornment'; -import InputLabel from '@mui/material/InputLabel'; -import Stack from '@mui/material/Stack'; -import TextField from '@mui/material/TextField'; -import Typography from '@mui/material/Typography'; -import { useTheme } from '@mui/material/styles'; -import CheckCircleIcon from '@mui/icons-material/CheckCircle'; -import CloseIcon from '@mui/icons-material/Close'; -import ContentCopy from '@mui/icons-material/ContentCopy'; -import ErrorIcon from '@mui/icons-material/Error'; -import OpenInNewIcon from '@mui/icons-material/OpenInNew'; -import { Visibility, VisibilityOff } from '@mui/icons-material'; -import { Link } from '@backstage/core-components'; -import { useSandboxContext } from '../../hooks/useSandboxContext'; -import { AnsibleStatus } from '../../utils/aap-utils'; -import { useTrackAnalytics } from '../../utils/eddl-utils'; -import { Intcmp } from '../../hooks/useProductURLs'; - -// Import the logos -import AnsibleLogo from '../../assets/logos/ansible.svg'; -import RedHatLogo from '../../assets/logos/logo_hat-only.svg'; - -type AnsibleLaunchInfoModalProps = { - modalOpen: boolean; - setOpen: React.Dispatch>; -}; - -export const AnsibleLaunchInfoModal: React.FC = ({ - modalOpen, - setOpen, -}) => { - const theme = useTheme(); - - const { - ansibleUILink, - ansibleUIUser, - ansibleUIPassword, - ansibleError, - ansibleStatus, - } = useSandboxContext(); - - const trackAnalytics = useTrackAnalytics(); - - // Handle CTA click for analytics - const handleAnsibleCtaClick = async () => { - if (ansibleUILink) { - await trackAnalytics( - 'Get Started - Ansible', - 'Catalog', - ansibleUILink, - Intcmp.AAP, - 'cta', - ); - } - }; - const [showPassword, setShowPassword] = useState(false); - - const handleClose = () => { - setOpen(false); - }; - - const handleTogglePassword = () => { - setShowPassword(prev => !prev); - }; - - return ( - - {ansibleStatus === AnsibleStatus.READY ? ( - <> - -
- -
- Ansible Automation Platform instance provisioned -
-
-
- - - - - - To get started with your AAP instance, you will need{' '} - - two different accounts - - : - - - {/* Section 1: AAP admin account */} - - - - 1. - - - - AAP admin account - - - - - Log in to your AAP admin account within the new tab. Use the - provided username and password to access your AAP instance. - - - - - - Username: - - - - - window.navigator.clipboard.writeText( - ansibleUIUser || '', - ) - } - > - - - - ), - sx: { - fontWeight: 450, - color: theme.palette.text.secondary, - height: '2rem', - width: '20rem', - paddingY: '4px', - '& .v5-MuiInputBase-input': { - paddingY: '10px', - }, - }, - }} - /> - - - - - Password: - - - - - - {showPassword ? ( - - ) : ( - - )} - - - window.navigator.clipboard.writeText( - ansibleUIPassword || '', - ) - } - > - - - - - ), - sx: { - fontWeight: 450, - color: theme.palette.text.secondary, - height: '2rem', - width: '20rem', - paddingY: '4px', - '& .v5-MuiInputBase-input': { - paddingY: '10px', - }, - }, - }} - /> - - - - - {/* Section 2: Red Hat account */} - - - - 2. - - - - Red Hat account - - - - - Once logged in, you'll need to activate your subscription. On - the activation form, select "username and password" and then - enter your Red Hat account credentials. - - - - - Access this information again by clicking the{' '} - Launch button on the Ansible Automation Platform - sandbox card. - - - {ansibleError && - !ansibleUIUser && - !ansibleUIPassword && - !ansibleUILink && ( - -
- - {ansibleError} -
-
- )} -
- - - - - - - ) : ( - <> - {' '} - -
-
- Provisioning Ansible Automation Platform (AAP) instance -
-
-
- - - {' '} - - - Provisioning can take up to 30 minutes. When ready, your instance - will remain active for several hours. - -
- - New to Ansible Automation Platform? Get up to speed with our{' '} - - introductory learning path. - - - -
-
- - - - - - You can close this modal. Follow the status of your instance - on the AAP sandbox card. - - -
-
- - - - - )} -
- ); -}; - -export default AnsibleLaunchInfoModal; diff --git a/workspaces/sandbox/plugins/sandbox/src/components/Modals/PhoneVerificationModal.tsx b/workspaces/sandbox/plugins/sandbox/src/components/Modals/PhoneVerificationModal.tsx deleted file mode 100644 index 6cfaca76cb..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/components/Modals/PhoneVerificationModal.tsx +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright Red Hat, Inc. - * - * 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, { useState } from 'react'; -import { E164Number } from 'libphonenumber-js/types.cjs'; -import { Country, getCountryCallingCode } from 'react-phone-number-input'; -import Dialog from '@mui/material/Dialog'; -import { useTheme } from '@mui/material/styles'; -import { useApi } from '@backstage/core-plugin-api'; -import { registerApiRef } from '../../api'; -import { - PhoneNumberStep, - VerificationCodeStep, -} from './PhoneVerificationSteps'; -import { errorMessage } from '../../utils/common'; -import { Product } from '../SandboxCatalog/productData'; - -type PhoneVerificationModalProps = { - id: Product; - modalOpen: boolean; - setOpen: React.Dispatch>; - setAnsibleCredsModalOpen: React.Dispatch>; - setRefetchingUserData: React.Dispatch>; -}; - -export const PhoneVerificationModal: React.FC = ({ - id, - modalOpen, - setOpen, - setAnsibleCredsModalOpen, - setRefetchingUserData, -}) => { - const theme = useTheme(); - const registerApi = useApi(registerApiRef); - const [enterOTP, setEnterOTP] = useState(false); - const [phoneNumber, setPhoneNumber] = useState(); - const [country, setCountry] = useState(undefined); - const [otp, setOtp] = useState(['', '', '', '', '', '']); - - const [loading, setLoading] = useState(false); - const [phoneSubmitError, setPhoneSubmitError] = React.useState< - string | undefined - >(); - - const handleClose = () => { - setCountry(undefined); - setPhoneNumber(undefined); - setOtp(['', '', '', '', '', '']); - setOpen(false); - setEnterOTP(false); - setPhoneSubmitError(undefined); - }; - - const handlePhoneNumberSubmit = async () => { - if (!country) return; - - const countryCallingCode = `+${getCountryCallingCode(country)}`; - const phoneWithoutCountryCode = (phoneNumber as string)?.replace( - countryCallingCode, - '', - ); - try { - setPhoneSubmitError(undefined); - setLoading(true); - await registerApi.initiatePhoneVerification( - countryCallingCode, - phoneWithoutCountryCode, - ); - - setEnterOTP(true); - } catch (e) { - setPhoneSubmitError(errorMessage(e)); - } finally { - setLoading(false); - } - }; - - const handleEditPhoneNumber = () => { - setEnterOTP(false); - setOtp(['', '', '', '', '', '']); - }; - - return ( - - {!enterOTP ? ( - - ) : ( - - )} - - ); -}; - -export default PhoneVerificationModal; diff --git a/workspaces/sandbox/plugins/sandbox/src/components/Modals/PhoneVerificationSteps/PhoneNumberStep.tsx b/workspaces/sandbox/plugins/sandbox/src/components/Modals/PhoneVerificationSteps/PhoneNumberStep.tsx deleted file mode 100644 index 1d809048a8..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/components/Modals/PhoneVerificationSteps/PhoneNumberStep.tsx +++ /dev/null @@ -1,271 +0,0 @@ -/* - * Copyright Red Hat, Inc. - * - * 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, { ForwardedRef, forwardRef } from 'react'; -import { E164Number } from 'libphonenumber-js/types.cjs'; -import { default as RPNInput, Country } from 'react-phone-number-input'; -import { useTheme } from '@mui/material/styles'; -import Box from '@mui/material/Box'; -import Button from '@mui/material/Button'; -import ErrorIcon from '@mui/icons-material/Error'; -import Select, { SelectChangeEvent } from '@mui/material/Select'; -import MenuItem from '@mui/material/MenuItem'; -import TextField, { TextFieldProps } from '@mui/material/TextField'; -import Typography from '@mui/material/Typography'; -import DialogTitle from '@mui/material/DialogTitle'; -import DialogContent from '@mui/material/DialogContent'; -import DialogContentText from '@mui/material/DialogContentText'; -import DialogActions from '@mui/material/DialogActions'; -import IconButton from '@mui/material/IconButton'; -import CloseIcon from '@mui/icons-material/Close'; - -import CircularProgress from '@mui/material/CircularProgress'; -import { useTrackAnalytics } from '../../../utils/eddl-utils'; - -const FLAG_FETCH_URL = - 'https://catamphetamine.github.io/country-flag-icons/3x2'; - -type CountrySelectFieldProps = { - value: Country | undefined; - onChange: (value: Country) => void; - options: { label: string; value: Country }[]; -}; - -type PhoneNumberFormProps = { - phoneNumber: E164Number | undefined; - setPhoneNumber: React.Dispatch>; - setCountry: React.Dispatch>; - country: Country | undefined; - handleClose: () => void; - handlePhoneNumberSubmit: () => void; - loading?: boolean; - error?: string; -}; - -export const PhoneNumberStep: React.FC = ({ - phoneNumber, - setPhoneNumber, - setCountry, - country, - handleClose, - handlePhoneNumberSubmit, - loading, - error, -}) => { - const theme = useTheme(); - const trackAnalytics = useTrackAnalytics(); - - // Handle Send Code click for analytics tracking - const handleSendCodeClick = async ( - event: React.MouseEvent, - ) => { - event.preventDefault(); - event.stopPropagation(); - - await trackAnalytics( - 'Send Code', - 'Verification', - window.location.href, - undefined, - 'cta', - ); - handlePhoneNumberSubmit(); - }; - - // Handle Cancel click for analytics tracking - const handleCancelClick = async ( - event: React.MouseEvent, - ) => { - event.preventDefault(); - event.stopPropagation(); - - await trackAnalytics( - 'Cancel Verification', - 'Verification', - window.location.href, - undefined, - 'cta', - ); - handleClose(); - }; - - const PhoneInputField = forwardRef(function PhoneInputField( - props: TextFieldProps, - ref: ForwardedRef>, - ) { - return ( - - ); - }); - - const CountrySelectField = ({ - value, - onChange, - options, - }: CountrySelectFieldProps) => { - const handleSelect = (event: SelectChangeEvent) => { - onChange(event.target.value as Country); - setCountry(event.target.value as Country); - }; - return ( - - ); - }; - - return ( - <> - - Let's verify you - - - - - - - - Enter your phone number and we'll send you a text message with a - verification code. - -
- -
- {error && ( - -
- - {error} -
-
- )} -
- - - - - - ); -}; - -export default PhoneNumberStep; diff --git a/workspaces/sandbox/plugins/sandbox/src/components/Modals/PhoneVerificationSteps/VerificationCodeStep.tsx b/workspaces/sandbox/plugins/sandbox/src/components/Modals/PhoneVerificationSteps/VerificationCodeStep.tsx deleted file mode 100644 index 8b5f003111..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/components/Modals/PhoneVerificationSteps/VerificationCodeStep.tsx +++ /dev/null @@ -1,401 +0,0 @@ -/* - * Copyright Red Hat, Inc. - * - * 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, { useEffect, useRef, useState } from 'react'; -import { E164Number, parsePhoneNumber } from 'libphonenumber-js/min'; -import { useTheme } from '@mui/material/styles'; -import Typography from '@mui/material/Typography'; -import Button from '@mui/material/Button'; -import DialogTitle from '@mui/material/DialogTitle'; -import DialogContent from '@mui/material/DialogContent'; -import DialogContentText from '@mui/material/DialogContentText'; -import DialogActions from '@mui/material/DialogActions'; -import TextField from '@mui/material/TextField'; -import Stack from '@mui/material/Stack'; -import ErrorIcon from '@mui/icons-material/Error'; -import IconButton from '@mui/material/IconButton'; -import EditIcon from '@mui/icons-material/Edit'; -import CloseIcon from '@mui/icons-material/Close'; -import CheckCircleIcon from '@mui/icons-material/CheckCircle'; -import CircularProgress from '@mui/material/CircularProgress'; -import { isValidOTP } from '../../../utils/phone-utils'; -import { Product } from '../../SandboxCatalog/productData'; -import { signupDataToStatus } from '../../../utils/register-utils'; -import { productsURLMapping } from '../../../hooks/useProductURLs'; -import { errorMessage } from '../../../utils/common'; -import { useSandboxContext } from '../../../hooks/useSandboxContext'; -import { Country, getCountryCallingCode } from 'react-phone-number-input'; -import { useApi } from '@backstage/core-plugin-api'; -import { registerApiRef } from '../../../api'; -import { useTrackAnalytics } from '../../../utils/eddl-utils'; - -type VerificationCodeProps = { - id: Product; - otp: string[]; - setOtp: React.Dispatch>; - country: Country | undefined; - phoneNumber: E164Number | undefined; - handleEditPhoneNumber: () => void; - handleClose: () => void; - setAnsibleCredsModalOpen: React.Dispatch>; - setRefetchingUserData: React.Dispatch>; - setLoading: React.Dispatch>; - loading?: boolean; -}; - -export const VerificationCodeStep: React.FC = ({ - id, - otp, - setOtp, - country, - phoneNumber, - handleEditPhoneNumber, - setAnsibleCredsModalOpen, - setRefetchingUserData, - handleClose, - loading, - setLoading, -}) => { - const theme = useTheme(); - const trackAnalytics = useTrackAnalytics(); - - const inputRefs = useRef([]); - const { refetchUserData, handleAAPInstance } = useSandboxContext(); - const [verificationCodeError, setVerificationCodeError] = React.useState< - string | undefined - >(); - const [codeResent, setCodeResent] = useState(false); - const registerApi = useApi(registerApiRef); - - useEffect(() => { - // Focus on the first input box when modal opens - if (!otp[0]) { - // Focus on the first input box when modal opens - setTimeout(() => inputRefs.current[0]?.focus(), 100); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [window.open]); - - const handleChange = ( - index: number, - event: React.ChangeEvent, - ) => { - const value = event.target.value; - if (!isValidOTP(value)) return; - - const newOtp = [...otp]; - newOtp[index] = value; - setOtp(newOtp); - - // Move focus to next input - if (value && index < otp.length - 1) { - inputRefs.current[index + 1].focus(); - } - }; - - // Handle Backspace: Move focus to previous box if empty - const handleKeyDown = ( - index: number, - event: React.KeyboardEvent, - ) => { - if (event.key === 'Backspace' && !otp[index] && index > 0) { - inputRefs.current[index - 1].focus(); - } - }; - - const createPhoneString = (phone: E164Number | undefined) => { - if (!phone) return ''; - try { - const parsedPhoneNumber = parsePhoneNumber(phone); - return `+${parsedPhoneNumber.countryCallingCode} ${parsedPhoneNumber.nationalNumber}`; - } catch { - return ''; - } - }; - - const handleResendCode = async () => { - if (codeResent || !country) return; - - const countryCallingCode = `+${getCountryCallingCode(country)}`; - setOtp(['', '', '', '', '', '']); - try { - setVerificationCodeError(undefined); - setLoading(true); - await registerApi.initiatePhoneVerification( - countryCallingCode, - (phoneNumber as string)?.replace(countryCallingCode, ''), - ); - setCodeResent(true); - } catch (e) { - setVerificationCodeError(errorMessage(e)); - } finally { - setLoading(false); - } - }; - - const handleStartTrialClick = async (pdt: Product) => { - try { - setVerificationCodeError(undefined); - setLoading(true); - await registerApi.completePhoneVerification(otp.join('')); - const maxAttempts = 60; - const retryInterval = 1000; // 1 second - - // Poll until user is found or max attempts reached - let urlToOpen = ''; - let userReady = false; - for (let i = 0; i < maxAttempts; i++) { - setRefetchingUserData(true); - await new Promise(resolve => setTimeout(resolve, retryInterval)); - - // Fetch the latest user data and check if user is found - const userData = await refetchUserData(); - if (userData) { - const userStatus = signupDataToStatus(userData); - userReady = userStatus === 'ready'; - - const verificationRequired = userStatus === 'verify'; - // if verification is required we can stop fetching the data - if (verificationRequired) { - break; - } - - // if user is ready we can stop fetching the data - if (userReady) { - // if namespace is not defined we can continue fetching the data - if (!userData?.defaultUserNamespace) { - // eslint-disable-next-line - console.error( - 'user is ready but default namespace is not defined yet...', - ); - continue; - } - const productURLs = productsURLMapping(userData); - // find the link to open if any - urlToOpen = productURLs.find(pu => pu.id === id)?.url || ''; - // User has signed up and the trial is ready and user selects the AAP Trial - if (pdt === Product.AAP) { - handleAAPInstance(userData.defaultUserNamespace as string); - setAnsibleCredsModalOpen(true); - } else if (urlToOpen) { - window.open(urlToOpen, '_blank'); - } - break; - } - } - } - handleClose(); - } catch (error) { - setVerificationCodeError(errorMessage(error)); - } finally { - setLoading(false); - setRefetchingUserData(false); - } - }; - - // Handle Start Trial click for analytics tracking - const handleStartTrialClickWithTracking = async ( - event: React.MouseEvent, - pdt: Product, - ) => { - event.preventDefault(); - event.stopPropagation(); - - await trackAnalytics( - 'Start Trial', - 'Verification', - window.location.href, - undefined, - 'cta', - ); - handleStartTrialClick(pdt); - }; - - // Handle Resend Code click for analytics tracking - const handleResendCodeClickWithTracking = async ( - event: React.MouseEvent, - ) => { - event.preventDefault(); - event.stopPropagation(); - - await trackAnalytics( - 'Resend Code', - 'Verification', - window.location.href, - undefined, - 'cta', - ); - handleResendCode(); - }; - - // Handle Cancel click for analytics tracking - const handleCancelVerificationClick = async ( - event: React.MouseEvent, - ) => { - event.preventDefault(); - event.stopPropagation(); - - await trackAnalytics( - 'Cancel Verification', - 'Verification', - window.location.href, - undefined, - 'cta', - ); - handleClose(); - }; - - return ( - <> - - Enter the verification code - - - - - - - We've sent a verification code to {createPhoneString(phoneNumber)}.{' '} - - - - - - {otp.map((digit, index) => ( - handleChange(index, e)} - onKeyDown={e => - handleKeyDown(index, e as React.KeyboardEvent) - } - inputRef={el => (inputRefs.current[index] = el)} - variant="outlined" - inputProps={{ - maxLength: 1, - style: { textAlign: 'center', fontWeight: 400 }, - }} - /> - ))} - - { - handleResendCodeClickWithTracking(event); - inputRefs.current[0]?.focus(); - }} - > -
- {codeResent ? ( - <> - Resent successful - - - ) : ( - 'Resend code' - )} -
-
- - {verificationCodeError && ( - -
- - {verificationCodeError} -
-
- )} -
- - - - - - ); -}; - -export default VerificationCodeStep; diff --git a/workspaces/sandbox/plugins/sandbox/src/components/Modals/PhoneVerificationSteps/__tests__/PhoneNumberStep.test.tsx b/workspaces/sandbox/plugins/sandbox/src/components/Modals/PhoneVerificationSteps/__tests__/PhoneNumberStep.test.tsx deleted file mode 100644 index e8226e650e..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/components/Modals/PhoneVerificationSteps/__tests__/PhoneNumberStep.test.tsx +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright Red Hat, Inc. - * - * 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 { fireEvent, render, screen, waitFor } from '@testing-library/react'; -import { PhoneNumberStep } from '../PhoneNumberStep'; -import { E164Number } from 'libphonenumber-js/types'; -import { Country } from 'react-phone-number-input'; -import { parsePhoneNumber } from 'libphonenumber-js/min'; -import { PhoneNumber } from 'libphonenumber-js'; -import * as eddlUtils from '../../../../utils/eddl-utils'; - -// Mock the useTrackAnalytics hook -jest.mock('../../../../utils/eddl-utils', () => ({ - ...jest.requireActual('../../../../utils/eddl-utils'), - useTrackAnalytics: jest.fn(), -})); - -// Mock the props interface if it's not exported from the component file -declare module '../PhoneNumberStep' { - interface PhoneNumberFormProps { - phoneNumber: E164Number | undefined; - setPhoneNumber: React.Dispatch< - React.SetStateAction - >; - setCountry: React.Dispatch>; - country: Country | undefined; - handleClose: () => void; - handlePhoneNumberSubmit: () => void; - loading?: boolean; - error?: string; - } -} - -describe('PhoneNumberStep', () => { - const mockTrackAnalytics = jest.fn(); - const mockSetPhoneNumber = jest.fn(); - const mockHandleClose = jest.fn(); - const mockHandlePhoneNumberSubmit = jest.fn(); - const mockSetCountry = jest.fn(); - const phoneNumber = parsePhoneNumber(' 8 (800) 555-35-35 ', 'RU'); - - beforeEach(() => { - jest.clearAllMocks(); - // Mock the useTrackAnalytics hook to return a mock function - mockTrackAnalytics.mockResolvedValue(undefined); // Make it async - (eddlUtils.useTrackAnalytics as jest.Mock).mockReturnValue( - mockTrackAnalytics, - ); - }); - - function renderComponent(inputPhoneNumber: PhoneNumber, error?: string) { - render( - , - ); - } - - test('should render modal', () => { - renderComponent(phoneNumber); - // expected text should be there - expect(screen.getByText("Let's verify you")).toBeInTheDocument(); - expect( - screen.getByText( - "Enter your phone number and we'll send you a text message with a verification code.", - ), - ).toBeInTheDocument(); - // country code selection should be there - const phoneInputs = screen.getAllByTestId('tel-input'); - expect(phoneInputs).toHaveLength(1); - // phone number input should be there - const countryInputs = screen.getAllByTestId('country-code-select'); - expect(countryInputs).toHaveLength(1); - // submit phone button should be there - const submitButton = screen.getAllByTestId('submit-phone-button'); - expect(submitButton).toHaveLength(1); - // close button should be there - const closeButton = screen.getAllByTestId('close-phone-button'); - expect(closeButton).toHaveLength(1); - }); - - test('should submit phone number when clicking send code button', async () => { - renderComponent(phoneNumber); - // Find and click send code button - const submitPhoneNumberButton = screen.getByRole('button', { - name: /Send code/i, - }); - fireEvent.click(submitPhoneNumberButton); - - // Wait for the async tracking call to complete - await waitFor(() => { - expect(mockHandlePhoneNumberSubmit).toHaveBeenCalled(); - }); - }); - - test('should show an error when phone number is invalid', async () => { - const invalidPhoneNumber = parsePhoneNumber(' 8 (800) xxxx ', 'RU'); - renderComponent(invalidPhoneNumber, 'invalid phone number error'); - // Find and click send code - const submitPhoneNumberButton = screen.getByRole('button', { - name: /Send code/i, - }); - fireEvent.click(submitPhoneNumberButton); - - // Wait for the async tracking call to complete - await waitFor(() => { - expect(mockHandlePhoneNumberSubmit).toHaveBeenCalled(); - }); - - // expect mock error from backend to be displayed - expect(screen.getByText('invalid phone number error')).toBeInTheDocument(); - // submit button should be enabled so user can retry with new number - expect(screen.getByText(/Send code/i).closest('button')).toBeEnabled(); - }); - - test('closes the modal when the close button is clicked', async () => { - renderComponent(phoneNumber); - const closeButton = screen.getByRole('button', { name: /Cancel/i }); - fireEvent.click(closeButton); - - // Wait for the async tracking call to complete - await waitFor(() => { - expect(mockHandleClose).toHaveBeenCalled(); - }); - }); - - test('should not have a default country when no country is provided', () => { - render( - , - ); - - // The country select should be present but not have a default selected value - const countrySelect = screen.getByTestId('country-code-select'); - expect(countrySelect).toBeInTheDocument(); - - // The input value should be empty (no default country) - const selectInput = countrySelect.querySelector('input'); - expect(selectInput).toHaveValue(''); - - // No country calling code should be displayed when no country is selected - const phoneInput = screen.getByTestId('tel-input'); - expect( - phoneInput.querySelector('[data-testid="tel-input"] input'), - ).toHaveValue(''); - }); - - test('should not display duplicate country code in phone input field', () => { - const usPhoneNumber = parsePhoneNumber('+17373072270', 'US'); - render( - , - ); - - const phoneInput = screen.getByTestId('tel-input'); - const inputElement = phoneInput.querySelector('input'); - const inputValue = inputElement?.value || ''; - expect(inputValue).toBe('+1 737 307 2270'); - }); - - describe('Analytics tracking', () => { - test('calls trackAnalytics with correct parameters when Send Code is clicked', async () => { - renderComponent(phoneNumber); - const sendCodeButton = screen.getByRole('button', { name: /Send code/i }); - - const clickEvent = fireEvent.click(sendCodeButton); - - await waitFor(() => { - expect(mockTrackAnalytics).toHaveBeenCalledWith( - 'Send Code', - 'Verification', - window.location.href, - undefined, - 'cta', - ); - }); - expect(mockHandlePhoneNumberSubmit).toHaveBeenCalled(); - expect(clickEvent).toBe(false); // Event was prevented - }); - - test('calls trackAnalytics with correct parameters when Cancel is clicked', async () => { - renderComponent(phoneNumber); - const cancelButton = screen.getByRole('button', { name: /Cancel/i }); - - const clickEvent = fireEvent.click(cancelButton); - - await waitFor(() => { - expect(mockTrackAnalytics).toHaveBeenCalledWith( - 'Cancel Verification', - 'Verification', - window.location.href, - undefined, - 'cta', - ); - }); - expect(mockHandleClose).toHaveBeenCalled(); - expect(clickEvent).toBe(false); // Event was prevented - }); - }); -}); diff --git a/workspaces/sandbox/plugins/sandbox/src/components/Modals/PhoneVerificationSteps/__tests__/VerificationCodeStep.test.tsx b/workspaces/sandbox/plugins/sandbox/src/components/Modals/PhoneVerificationSteps/__tests__/VerificationCodeStep.test.tsx deleted file mode 100644 index 9f3f746465..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/components/Modals/PhoneVerificationSteps/__tests__/VerificationCodeStep.test.tsx +++ /dev/null @@ -1,455 +0,0 @@ -/* - * Copyright Red Hat, Inc. - * - * 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 { fireEvent, render, screen, waitFor } from '@testing-library/react'; -import { E164Number } from 'libphonenumber-js/types'; -import { parsePhoneNumber } from 'libphonenumber-js/min'; -import VerificationCodeStep from '../VerificationCodeStep'; -import { Product } from '../../../SandboxCatalog/productData'; -import { Country } from 'react-phone-number-input'; -import { useSandboxContext } from '../../../../hooks/useSandboxContext'; -import { act } from 'react-dom/test-utils'; -import * as eddlUtils from '../../../../utils/eddl-utils'; - -jest.mock('@backstage/core-plugin-api', () => ({ - ...jest.requireActual('@backstage/core-plugin-api'), - useApi: jest.fn().mockReturnValue({ - completePhoneVerification: jest.fn(), - }), -})); - -jest.useFakeTimers(); // control timers -// mock hooks -jest.mock('../../../../hooks/useSandboxContext'); -jest.mock('../../../../utils/eddl-utils', () => ({ - ...jest.requireActual('../../../../utils/eddl-utils'), - useTrackAnalytics: jest.fn(), -})); - -// Mock the props interface if it's not exported from the component file -declare module '../VerificationCodeStep' { - interface VerificationCodeProps { - id: Product; - otp: string[]; - setOtp: React.Dispatch>; - country: Country | undefined; - phoneNumber: E164Number | undefined; - handleEditPhoneNumber: () => void; - handleClose: () => void; - setAnsibleCredsModalOpen: React.Dispatch>; - setLoading: React.Dispatch>; - loading?: boolean; - } -} - -describe('VerificationCodeStep', () => { - const mockTrackAnalytics = jest.fn(); - const mockSetOpt = jest.fn(); - const mockHandleClose = jest.fn(); - const mockHandleEditPhoneNumber = jest.fn(); - const mockSetLoading = jest.fn(); - const mockSetAnsibleCredsModalOpen = jest.fn(); - const mockRefetchingUserData = jest.fn(); - const mockRefetchAAP = jest.fn(); - const mockOpen = jest.fn(); - const otpCode: string[] = ['1', '2', '3', '4', '5']; - const phoneNumber = parsePhoneNumber('8 (800) 555-35-35', 'RU'); - const mockCountry: Country = 'RU'; - - const defaultUserData = { - name: 'bob', - consoleURL: 'https://sandboxcluster.test/', - cheDashboardURL: 'https://devspaces.test/', - proxyURL: 'https://api-sandboxcluster.test', - rhodsMemberURL: 'https://rhods-dashboard.test/', - apiEndpoint: 'https://api.test:6443', - clusterName: 'sandboxcluster.test', - defaultUserNamespace: 'bob-2-dev', - compliantUsername: 'bob-2', - username: 'bob', - status: { - ready: true, - reason: 'Provisioned', - verificationRequired: false, - }, - } as any; - - const defaultProps = { - id: Product.OPENSHIFT_CONSOLE, - otp: otpCode, - setOtp: mockSetOpt, - phoneNumber: phoneNumber.number, - handleEditPhoneNumber: mockHandleEditPhoneNumber, - handleClose: mockHandleClose, - setLoading: mockSetLoading, - setAnsibleCredsModalOpen: mockSetAnsibleCredsModalOpen, - setRefetchingUserData: mockRefetchingUserData, - loading: false, - country: mockCountry, - }; - - beforeEach(() => { - jest.clearAllMocks(); - mockTrackAnalytics.mockResolvedValue(undefined); - (eddlUtils.useTrackAnalytics as jest.Mock).mockReturnValue( - mockTrackAnalytics, - ); - }); - - function renderComponent(props = {}) { - render(); - } - - test('should render modal', () => { - const mockRefetchUserData = jest.fn(); - const mockHandleAAPInstance = jest.fn(); - const mockUseSandboxContext = useSandboxContext as jest.MockedFunction< - typeof useSandboxContext - >; - mockUseSandboxContext.mockReturnValue({ - refetchUserData: mockRefetchUserData, - refetchAAP: mockRefetchAAP, - handleAAPInstance: mockHandleAAPInstance, - } as any); - - renderComponent(); - // expected text should be there - expect(screen.getByText('Enter the verification code')).toBeInTheDocument(); - const sentMessageDialog = screen.getAllByTestId('sent-message-dialog'); - expect(sentMessageDialog[0]).toHaveTextContent( - "We've sent a verification code to +7 8005553535.", - ); - // submit phone button should be there - const submitButton = screen.getAllByTestId('submit-opt-button'); - expect(submitButton).toHaveLength(1); - // opt inputs are there - const optInputFields = screen.getAllByTestId('opt-inputs'); - expect(optInputFields).toHaveLength(5); - // resend opt should be there - const resendOptLink = screen.getAllByTestId('resend-code-link'); - expect(resendOptLink).toHaveLength(1); - // close button should be there - const closeButton = screen.getAllByTestId('close-opt-button'); - expect(closeButton).toHaveLength(2); - }); - - test('should submit opt code when clicking start trial and open selected url', async () => { - window.open = mockOpen; // override window.open with mock - const mockRefetchUserData = jest.fn().mockReturnValue(defaultUserData); - const mockHandleAAPInstance = jest.fn(); - const mockUseSandboxContext = useSandboxContext as jest.MockedFunction< - typeof useSandboxContext - >; - mockUseSandboxContext.mockReturnValue({ - refetchUserData: mockRefetchUserData, - refetchAAP: mockRefetchAAP, - handleAAPInstance: mockHandleAAPInstance, - } as any); - - renderComponent(); - const submitButton = screen.getByRole('button', { name: /Start trial/i }); - fireEvent.click(submitButton); - - // advance timers to trigger all retries - for (let i = 0; i < 5; i++) { - jest.advanceTimersByTime(1000); - await Promise.resolve(); // allow awaiting the timer to flush - } - - expect(mockRefetchUserData).toHaveBeenCalled(); - expect(mockOpen).toHaveBeenCalledWith( - `https://sandboxcluster.test//k8s/cluster/projects/bob-2-dev`, - '_blank', - ); // check it opens the url after signup - mockOpen.mockRestore(); - }); - - test('should submit opt code when clicking start trial and provision AAP', async () => { - const mockRefetchUserData = jest.fn().mockReturnValue(defaultUserData); - const mockHandleAAPInstance = jest.fn(); - const mockUseSandboxContext = useSandboxContext as jest.MockedFunction< - typeof useSandboxContext - >; - mockUseSandboxContext.mockReturnValue({ - refetchUserData: mockRefetchUserData, - refetchAAP: mockRefetchAAP, - handleAAPInstance: mockHandleAAPInstance, - } as any); - - renderComponent({ id: Product.AAP }); - const submitButton = screen.getByRole('button', { name: /Start trial/i }); - fireEvent.click(submitButton); - - // advance timers to trigger all retries - for (let i = 0; i < 5; i++) { - jest.advanceTimersByTime(1000); - await Promise.resolve(); // allow awaiting the timer to flush - } - - expect(mockRefetchUserData).toHaveBeenCalled(); - expect(mockHandleAAPInstance).toHaveBeenCalledWith('bob-2-dev'); // check it calls the aap specific functionality - expect(mockHandleClose).toHaveBeenCalled(); // it closes the modal after - }); - - test('closes the modal when the close button is clicked', async () => { - const mockRefetchUserData = jest.fn(); - const mockHandleAAPInstance = jest.fn(); - const mockUseSandboxContext = useSandboxContext as jest.MockedFunction< - typeof useSandboxContext - >; - mockUseSandboxContext.mockReturnValue({ - refetchUserData: mockRefetchUserData, - refetchAAP: mockRefetchAAP, - handleAAPInstance: mockHandleAAPInstance, - } as any); - - renderComponent(); - const closeButton = screen.getByRole('button', { name: /Cancel/i }); - fireEvent.click(closeButton); - - await waitFor(() => { - expect(mockHandleClose).toHaveBeenCalled(); - }); - }); - - test('does not open URL when defaultUserNamespace is undefined', async () => { - const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(); - window.open = mockOpen; // override window.open with mock - const mockHandleAAPInstance = jest.fn(); - const mockRefetchUserData = jest.fn().mockReturnValue({ - ...defaultUserData, - defaultUserNamespace: undefined, - }); - const mockUseSandboxContext = useSandboxContext as jest.MockedFunction< - typeof useSandboxContext - >; - mockUseSandboxContext.mockReturnValue({ - refetchUserData: mockRefetchUserData, - refetchAAP: mockRefetchAAP, - handleAAPInstance: mockHandleAAPInstance, - } as any); - - renderComponent(); - const submitButton = screen.getByRole('button', { name: /Start trial/i }); - await act(async () => { - fireEvent.click(submitButton); - // advance timers to trigger all retries - for (let i = 0; i < 5; i++) { - jest.advanceTimersByTime(1000); - await Promise.resolve(); // allow awaiting the timer to flush - } - }); - - expect(mockRefetchUserData).toHaveBeenCalled(); - await waitFor( - () => { - expect(consoleErrorSpy).toHaveBeenCalledWith( - 'user is ready but default namespace is not defined yet...', - ); - }, - { timeout: 6000 }, - ); - consoleErrorSpy.mockRestore(); - expect(mockOpen).not.toHaveBeenCalled(); // verify window.open is not called - mockOpen.mockRestore(); - }); - - test('does not invoke handleAAP when defaultUserNamespace is undefined', async () => { - const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(); - const mockHandleAAPInstance = jest.fn(); - const mockRefetchUserData = jest.fn().mockReturnValue({ - ...defaultUserData, - defaultUserNamespace: undefined, - }); - const mockUseSandboxContext = useSandboxContext as jest.MockedFunction< - typeof useSandboxContext - >; - mockUseSandboxContext.mockReturnValue({ - refetchUserData: mockRefetchUserData, - refetchAAP: mockRefetchAAP, - handleAAPInstance: mockHandleAAPInstance, - } as any); - - renderComponent({ id: Product.AAP }); - const submitButton = screen.getByRole('button', { name: /Start trial/i }); - await act(async () => { - fireEvent.click(submitButton); - // advance timers to trigger all retries - for (let i = 0; i < 5; i++) { - jest.advanceTimersByTime(1000); - await Promise.resolve(); // allow awaiting the timer to flush - } - }); - - expect(mockRefetchUserData).toHaveBeenCalled(); - expect(mockHandleAAPInstance).not.toHaveBeenCalled(); // verify handleAAP is not called - await waitFor( - () => { - expect(consoleErrorSpy).toHaveBeenCalledWith( - 'user is ready but default namespace is not defined yet...', - ); - }, - { timeout: 6000 }, - ); - consoleErrorSpy.mockRestore(); - }); - - test('does not open URL when verification is required', async () => { - window.open = mockOpen; // override window.open with mock - const mockHandleAAPInstance = jest.fn(); - const mockRefetchUserData = jest.fn().mockReturnValue({ - ...defaultUserData, - status: { - ready: false, - reason: 'VerificationRequired', - verificationRequired: true, - }, - }); - const mockUseSandboxContext = useSandboxContext as jest.MockedFunction< - typeof useSandboxContext - >; - mockUseSandboxContext.mockReturnValue({ - refetchUserData: mockRefetchUserData, - refetchAAP: mockRefetchAAP, - handleAAPInstance: mockHandleAAPInstance, - } as any); - - renderComponent(); - const submitButton = screen.getByRole('button', { name: /Start trial/i }); - await act(async () => { - fireEvent.click(submitButton); - // advance timers to trigger all retries - for (let i = 0; i < 5; i++) { - jest.advanceTimersByTime(1000); - await Promise.resolve(); // allow awaiting the timer to flush - } - }); - - expect(mockRefetchUserData).toHaveBeenCalled(); - expect(mockOpen).not.toHaveBeenCalled(); // verify window.open is not called - mockOpen.mockRestore(); - }); - - test('does not invoke handleAAP when verification is required', async () => { - const mockHandleAAPInstance = jest.fn(); - const mockRefetchUserData = jest.fn().mockReturnValue({ - ...defaultUserData, - status: { - ready: false, - reason: 'VerificationRequired', - verificationRequired: true, - }, - }); - const mockUseSandboxContext = useSandboxContext as jest.MockedFunction< - typeof useSandboxContext - >; - mockUseSandboxContext.mockReturnValue({ - refetchUserData: mockRefetchUserData, - refetchAAP: mockRefetchAAP, - handleAAPInstance: mockHandleAAPInstance, - } as any); - - renderComponent({ id: Product.AAP }); - const submitButton = screen.getByRole('button', { name: /Start trial/i }); - await act(async () => { - fireEvent.click(submitButton); - // advance timers to trigger all retries - for (let i = 0; i < 5; i++) { - jest.advanceTimersByTime(1000); - await Promise.resolve(); // allow awaiting the timer to flush - } - }); - - expect(mockRefetchUserData).toHaveBeenCalled(); - expect(mockHandleAAPInstance).not.toHaveBeenCalled(); // verify handleAAP is not called - }); - - describe('Analytics tracking', () => { - let mockRefetchUserData: jest.Mock; - let mockHandleAAPInstance: jest.Mock; - - beforeEach(() => { - mockRefetchUserData = jest.fn(); - mockHandleAAPInstance = jest.fn(); - const mockUseSandboxContext = useSandboxContext as jest.MockedFunction< - typeof useSandboxContext - >; - mockUseSandboxContext.mockReturnValue({ - refetchUserData: mockRefetchUserData, - refetchAAP: mockRefetchAAP, - handleAAPInstance: mockHandleAAPInstance, - } as any); - }); - - test('calls trackAnalytics with correct parameters when Start Trial is clicked', async () => { - renderComponent(); - - const startTrialButton = screen.getByRole('button', { - name: /Start trial/i, - }); - const clickEvent = fireEvent.click(startTrialButton); - - await waitFor(() => { - expect(mockTrackAnalytics).toHaveBeenCalledWith( - 'Start Trial', - 'Verification', - window.location.href, - undefined, - 'cta', - ); - }); - expect(clickEvent).toBe(false); // Event was prevented - }); - - test('calls trackAnalytics with correct parameters when Resend Code is clicked', async () => { - renderComponent(); - - const resendCodeLink = screen.getByTestId('resend-code-link'); - const clickEvent = fireEvent.click(resendCodeLink); - - await waitFor(() => { - expect(mockTrackAnalytics).toHaveBeenCalledWith( - 'Resend Code', - 'Verification', - window.location.href, - undefined, - 'cta', - ); - }); - expect(clickEvent).toBe(false); // Event was prevented - }); - - test('calls trackAnalytics with correct parameters when Cancel is clicked', async () => { - renderComponent(); - - const cancelButton = screen.getByRole('button', { name: /Cancel/i }); - const clickEvent = fireEvent.click(cancelButton); - - await waitFor(() => { - expect(mockTrackAnalytics).toHaveBeenCalledWith( - 'Cancel Verification', - 'Verification', - window.location.href, - undefined, - 'cta', - ); - }); - expect(mockHandleClose).toHaveBeenCalled(); - expect(clickEvent).toBe(false); // Event was prevented - }); - }); -}); diff --git a/workspaces/sandbox/plugins/sandbox/src/components/Modals/PhoneVerificationSteps/index.ts b/workspaces/sandbox/plugins/sandbox/src/components/Modals/PhoneVerificationSteps/index.ts deleted file mode 100644 index 7ebdb91b2d..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/components/Modals/PhoneVerificationSteps/index.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright Red Hat, Inc. - * - * 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 { default as PhoneNumberStep } from './PhoneNumberStep'; -export { default as VerificationCodeStep } from './VerificationCodeStep'; diff --git a/workspaces/sandbox/plugins/sandbox/src/components/Modals/__tests__/AccessCodeInputModal.test.tsx b/workspaces/sandbox/plugins/sandbox/src/components/Modals/__tests__/AccessCodeInputModal.test.tsx deleted file mode 100644 index ea7cc10bea..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/components/Modals/__tests__/AccessCodeInputModal.test.tsx +++ /dev/null @@ -1,363 +0,0 @@ -/* - * Copyright Red Hat, Inc. - * - * 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 { render, screen, waitFor } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; -import { ThemeProvider } from '@mui/material/styles'; -import { createTheme } from '@mui/material/styles'; -import { TestApiProvider } from '@backstage/test-utils'; -import { AccessCodeInputModal } from '../AccessCodeInputModal'; -import { registerApiRef } from '../../../api'; -import { useSandboxContext } from '../../../hooks/useSandboxContext'; -import { AnsibleStatus } from '../../../utils/aap-utils'; - -const mockRegisterApi = { - verifyActivationCode: jest.fn(), -}; - -const mockRefetchUserData = jest.fn(); - -const theme = createTheme(); - -const renderComponent = (modalOpen: boolean = true) => { - const mockSetOpen = jest.fn(); - - return { - ...render( - - - - - , - ), - mockSetOpen, - }; -}; - -jest.mock('../../../hooks/useSandboxContext'); - -describe('AccessCodeInputModal', () => { - const mockUseSandboxContext = useSandboxContext as jest.MockedFunction< - typeof useSandboxContext - >; - - beforeEach(() => { - jest.clearAllMocks(); - mockUseSandboxContext.mockReturnValue({ - refetchUserData: mockRefetchUserData, - loading: false, - userFound: false, - userReady: false, - ansibleStatus: AnsibleStatus.UNKNOWN, - verificationRequired: false, - userData: undefined, - signupUser: jest.fn(), - refetchAAP: jest.fn(), - ansibleData: undefined, - ansibleUIUser: undefined, - } as any); - }); - - it('renders modal when open', () => { - renderComponent(true); - - expect(screen.getByText('Enter the activation code')).toBeInTheDocument(); - expect( - screen.getByText('If you have an activation code, enter it now.'), - ).toBeInTheDocument(); - }); - - it('does not render modal when closed', () => { - renderComponent(false); - - expect( - screen.queryByText('Enter the activation code'), - ).not.toBeInTheDocument(); - }); - - it('renders 5 input fields', () => { - renderComponent(); - - const inputs = screen.getAllByRole('textbox'); - expect(inputs).toHaveLength(5); - }); - - it('allows uppercase letters in input fields', async () => { - const user = userEvent.setup(); - renderComponent(); - - const inputs = screen.getAllByRole('textbox'); - - await user.type(inputs[0], 'A'); - expect(inputs[0]).toHaveValue('A'); - }); - - it('allows lowercase letters in input fields', async () => { - const user = userEvent.setup(); - renderComponent(); - - const inputs = screen.getAllByRole('textbox'); - - await user.type(inputs[0], 'a'); - expect(inputs[0]).toHaveValue('a'); - }); - - it('allows numbers in input fields', async () => { - const user = userEvent.setup(); - renderComponent(); - - const inputs = screen.getAllByRole('textbox'); - - await user.type(inputs[0], '1'); - expect(inputs[0]).toHaveValue('1'); - }); - - it('rejects special characters', async () => { - const user = userEvent.setup(); - renderComponent(); - - const inputs = screen.getAllByRole('textbox'); - - await user.type(inputs[0], '@'); - expect(inputs[0]).toHaveValue(''); - - await user.type(inputs[0], '#'); - expect(inputs[0]).toHaveValue(''); - - await user.type(inputs[0], ' '); - expect(inputs[0]).toHaveValue(''); - }); - - it('moves focus to next input after entering valid character', async () => { - const user = userEvent.setup(); - renderComponent(); - - const inputs = screen.getAllByRole('textbox'); - - // Click on first input to focus it - await user.click(inputs[0]); - expect(inputs[0]).toHaveFocus(); - - // Type a character - await user.keyboard('A'); - - // Check that value was set and focus moved - expect(inputs[0]).toHaveValue('A'); - await waitFor(() => { - expect(inputs[1]).toHaveFocus(); - }); - }); - - it('moves focus to previous input on backspace when current input is empty', async () => { - const user = userEvent.setup(); - renderComponent(); - - const inputs = screen.getAllByRole('textbox'); - - // Type in first input - await user.type(inputs[0], 'A'); - - // Second input should be focused, press backspace - await user.keyboard('{Backspace}'); - - // First input should now be focused - expect(inputs[0]).toHaveFocus(); - }); - - it('limits input to one character per field', async () => { - const user = userEvent.setup(); - renderComponent(); - - const inputs = screen.getAllByRole('textbox'); - - await user.type(inputs[0], 'ABC'); - expect(inputs[0]).toHaveValue('A'); - }); - - it('disables Start trial button when not all fields are filled', () => { - renderComponent(); - - const startTrialButton = screen.getByText('Start trial'); - expect(startTrialButton).toBeDisabled(); - }); - - it('enables Start trial button when all fields are filled', async () => { - const user = userEvent.setup(); - renderComponent(); - - const inputs = screen.getAllByRole('textbox'); - - // Fill all inputs by typing once in the first input - auto-focus will handle the rest - await user.click(inputs[0]); - await user.type(inputs[0], 'ABCDE'); // Type 5 characters to fill all 5 inputs - - // Wait for all inputs to be filled - await waitFor(() => { - inputs.forEach((input, index) => { - expect(input).toHaveValue(String.fromCharCode(65 + index)); // A, B, C, D, E - }); - }); - - // Wait for the button to become enabled with longer timeout - await waitFor( - () => { - const startTrialButton = screen.getByText('Start trial'); - expect(startTrialButton).not.toBeDisabled(); - }, - { timeout: 5000 }, - ); - }); - - it('calls verifyActivationCode with correct code when Start trial is clicked', async () => { - const user = userEvent.setup(); - mockRegisterApi.verifyActivationCode.mockResolvedValue(undefined); - - renderComponent(); - - const inputs = screen.getAllByRole('textbox'); - const testCode = 'ABCDE'; - - // Fill all inputs by typing the code in the first input - auto-focus will distribute - await user.click(inputs[0]); - await user.type(inputs[0], testCode); - - // Wait for all inputs to be filled - await waitFor(() => { - inputs.forEach((input, index) => { - expect(input).toHaveValue(testCode[index]); - }); - }); - - // Wait for button to be enabled before clicking with longer timeout - const startTrialButton = await waitFor( - () => { - const button = screen.getByText('Start trial'); - expect(button).not.toBeDisabled(); - return button; - }, - { timeout: 5000 }, - ); - - await user.click(startTrialButton); - - await waitFor(() => { - expect(mockRegisterApi.verifyActivationCode).toHaveBeenCalledWith( - 'ABCDE', - ); - }); - }); - - it('displays error message when verification fails', async () => { - const user = userEvent.setup(); - const errorMessage = 'Invalid activation code'; - mockRegisterApi.verifyActivationCode.mockRejectedValue( - new Error(errorMessage), - ); - - renderComponent(); - - const inputs = screen.getAllByRole('textbox'); - - // Fill all inputs by typing the code in the first input - auto-focus will distribute - await user.click(inputs[0]); - await user.type(inputs[0], 'AAAAA'); - - // Wait for all inputs to be filled - await waitFor(() => { - inputs.forEach(input => { - expect(input).toHaveValue('A'); - }); - }); - - // Wait for button to be enabled before clicking with longer timeout - const startTrialButton = await waitFor( - () => { - const button = screen.getByText('Start trial'); - expect(button).not.toBeDisabled(); - return button; - }, - { timeout: 5000 }, - ); - - await user.click(startTrialButton); - - await waitFor(() => { - expect(screen.getByText(errorMessage)).toBeInTheDocument(); - }); - }); - - it('closes modal and resets state when close button is clicked', async () => { - const user = userEvent.setup(); - const { mockSetOpen } = renderComponent(); - - const inputs = screen.getAllByRole('textbox'); - await user.type(inputs[0], 'A'); - - const closeButton = screen.getByLabelText('close'); - await user.click(closeButton); - - expect(mockSetOpen).toHaveBeenCalledWith(false); - }); - - it('closes modal and resets state when cancel button is clicked', async () => { - const user = userEvent.setup(); - const { mockSetOpen } = renderComponent(); - - const inputs = screen.getAllByRole('textbox'); - await user.type(inputs[0], 'A'); - - const cancelButton = screen.getByText('Cancel'); - await user.click(cancelButton); - - expect(mockSetOpen).toHaveBeenCalledWith(false); - }); - - it('calls refetchUserData after successful verification', async () => { - const user = userEvent.setup(); - mockRegisterApi.verifyActivationCode.mockResolvedValue(undefined); - - renderComponent(); - - const inputs = screen.getAllByRole('textbox'); - - // Fill all inputs by typing the code in the first input - auto-focus will distribute - await user.click(inputs[0]); - await user.type(inputs[0], 'AAAAA'); - - // Wait for all inputs to be filled - await waitFor(() => { - inputs.forEach(input => { - expect(input).toHaveValue('A'); - }); - }); - - // Wait for button to be enabled with a longer timeout - const startTrialButton = await waitFor( - () => { - const button = screen.getByText('Start trial'); - expect(button).not.toBeDisabled(); - return button; - }, - { timeout: 5000 }, - ); - - await user.click(startTrialButton); - - await waitFor(() => { - expect(mockRefetchUserData).toHaveBeenCalled(); - }); - }); -}); diff --git a/workspaces/sandbox/plugins/sandbox/src/components/Modals/__tests__/AnsibleDeleteInstanceModal.test.tsx b/workspaces/sandbox/plugins/sandbox/src/components/Modals/__tests__/AnsibleDeleteInstanceModal.test.tsx deleted file mode 100644 index d8f1719fb6..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/components/Modals/__tests__/AnsibleDeleteInstanceModal.test.tsx +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright Red Hat, Inc. - * - * 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 { render, screen, fireEvent } from '@testing-library/react'; -import { ThemeProvider, createTheme } from '@mui/material/styles'; -import AnsibleDeleteInstanceModal from '../AnsibleDeleteInstanceModal'; - -describe('AnsibleDeleteInstanceModal', () => { - const mockSetOpen = jest.fn(); - const mockHandleAnsibleDeleteInstance = jest.fn(); - const theme = createTheme(); - - const renderComponent = (props = {}) => { - return render( - - - , - ); - }; - - beforeEach(() => { - jest.clearAllMocks(); - }); - - test('renders the modal with the correct title and warning', () => { - renderComponent(); - - expect(screen.getByText('Delete instance?')).toBeInTheDocument(); - expect( - screen.getByText( - 'Your AAP instance will be deleted. Consider backing up your work before continuing.', - ), - ).toBeInTheDocument(); - }); - - test('closes the modal when the close button is clicked', () => { - renderComponent(); - - const closeButton = screen.getByRole('button', { name: /close/i }); - fireEvent.click(closeButton); - - expect(mockSetOpen).toHaveBeenCalledWith(false); - }); - - test('calls setOpen(false) when the cancel button is clicked', () => { - renderComponent(); - - const cancelButton = screen.getByRole('button', { name: /cancel/i }); - fireEvent.click(cancelButton); - - expect(mockSetOpen).toHaveBeenCalledWith(false); - }); - - test('calls handleAnsibleDeleteInstance when the delete button is clicked', () => { - renderComponent(); - - const deleteButton = screen.getByRole('button', { - name: /delete instance/i, - }); - fireEvent.click(deleteButton); - - expect(mockHandleAnsibleDeleteInstance).toHaveBeenCalledTimes(1); - }); - - test('displays warning icon', () => { - renderComponent(); - - const warningIcon = document.querySelector( - 'svg[data-testid="WarningIcon"]', - ); - expect(warningIcon).toBeInTheDocument(); - }); - - test('does not render when modalOpen is false', () => { - renderComponent({ modalOpen: false }); - - expect(screen.queryByText('Delete instance?')).not.toBeInTheDocument(); - }); -}); diff --git a/workspaces/sandbox/plugins/sandbox/src/components/Modals/__tests__/AnsibleLaunchInfoModal.test.tsx b/workspaces/sandbox/plugins/sandbox/src/components/Modals/__tests__/AnsibleLaunchInfoModal.test.tsx deleted file mode 100644 index 1677b33be2..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/components/Modals/__tests__/AnsibleLaunchInfoModal.test.tsx +++ /dev/null @@ -1,332 +0,0 @@ -/* - * Copyright Red Hat, Inc. - * - * 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 { render, screen, fireEvent } from '@testing-library/react'; -import { ThemeProvider, createTheme } from '@mui/material/styles'; -import { AnsibleLaunchInfoModal } from '../AnsibleLaunchInfoModal'; -import { useSandboxContext } from '../../../hooks/useSandboxContext'; -import { AnsibleStatus } from '../../../utils/aap-utils'; -import { wrapInTestApp } from '@backstage/test-utils'; -import { Intcmp } from '../../../hooks/useProductURLs'; -import * as eddlUtils from '../../../utils/eddl-utils'; - -// Mock the useSandboxContext hook -jest.mock('../../../hooks/useSandboxContext'); - -// Mock the EDDL utils -jest.mock('../../../utils/eddl-utils'); - -// Mock clipboard API -Object.defineProperty(window.navigator, 'clipboard', { - value: { - writeText: jest.fn(), - }, -}); - -describe('AnsibleLaunchInfoModal', () => { - const theme = createTheme(); - const mockSetOpen = jest.fn(); - - const defaultProps = { - modalOpen: true, - setOpen: mockSetOpen, - }; - - const mockUseSandboxContext = useSandboxContext as jest.MockedFunction< - typeof useSandboxContext - >; - const mockUseTrackAnalytics = jest.spyOn(eddlUtils, 'useTrackAnalytics'); - - const mockTrackAnalytics = jest.fn(); - - beforeEach(() => { - jest.clearAllMocks(); - // Setup window.appEventData for tests - (global as any).window = { appEventData: [] }; - - // Mock useTrackAnalytics to return our mock function - mockUseTrackAnalytics.mockReturnValue(mockTrackAnalytics); - }); - - const renderModal = (contextOverrides = {}) => { - mockUseSandboxContext.mockReturnValue({ - ansibleUILink: 'https://ansible.example.com', - ansibleUIUser: 'testuser', - ansibleUIPassword: 'password123', - ansibleError: null, - ansibleStatus: AnsibleStatus.READY, - ...contextOverrides, - } as any); - - return render( - wrapInTestApp( - - - , - ), - ); - }; - - it('renders the ready state with correct content', () => { - renderModal(); - - // Check for header - expect( - screen.getByText(/Ansible Automation Platform instance provisioned/i), - ).toBeInTheDocument(); - - // Check for the introductory text with "two different accounts" - expect( - screen.getByText(/To get started with your AAP instance, you will need/i), - ).toBeInTheDocument(); - expect(screen.getByText(/two different accounts/i)).toBeInTheDocument(); - - // Check for numbered sections - expect(screen.getByText('1.')).toBeInTheDocument(); - expect(screen.getByText('2.')).toBeInTheDocument(); - - // Check for section titles - expect(screen.getByText('AAP admin account')).toBeInTheDocument(); - expect(screen.getByText('Red Hat account')).toBeInTheDocument(); - - // Check for credentials section - const usernameLabel = screen.getByText('Username:'); - expect(usernameLabel).toBeInTheDocument(); - - const passwordLabel = screen.getByText('Password:'); - expect(passwordLabel).toBeInTheDocument(); - - // Check for the new "Get started" button - expect( - screen.getByRole('button', { - name: /Get started/i, - }), - ).toBeInTheDocument(); - - // Check for logos (by alt text) - expect(screen.getByAltText('Ansible')).toBeInTheDocument(); - expect(screen.getByAltText('Red Hat')).toBeInTheDocument(); - }); - - it('renders the provisioning state with correct content', async () => { - renderModal({ ansibleStatus: AnsibleStatus.PROVISIONING }); - - // Check for provisioning title - expect( - screen.getByText(/Provisioning Ansible Automation Platform/i), - ).toBeInTheDocument(); - - // Check for provisioning message - expect( - screen.getByText(/Provisioning can take up to 30 minutes/i), - ).toBeInTheDocument(); - - // Check for modal close hint - expect(screen.getByText(/You can close this modal/i)).toBeInTheDocument(); - - // Check for the loading spinner - expect(screen.getByRole('progressbar')).toBeInTheDocument(); - - // Check for the info alert - expect(screen.getByRole('alert')).toHaveTextContent( - /You can close this modal. Follow the status of your instance on the AAP sandbox card./i, - ); - }); - - it('calls setOpen when the X button is clicked', () => { - renderModal(); - - const closeIcon = screen.getByLabelText('close'); - fireEvent.click(closeIcon); - - expect(mockSetOpen).toHaveBeenCalledWith(false); - }); - - it('toggles password visibility when visibility button is clicked', () => { - renderModal(); - - // Find all password input fields - const inputs = document.querySelectorAll('input[type="password"]'); - expect(inputs.length).toBeGreaterThan(0); // Ensure we have at least one password field - - const passwordField = inputs[0] as HTMLInputElement; - - // Find the visibility toggle button - should have Visibility or VisibilityOff icon - const visibilityButtons = screen - .getAllByRole('button') - .filter(button => button.innerHTML.includes('Visibility')); - - expect(visibilityButtons.length).toBeGreaterThan(0); - const toggleButton = visibilityButtons[0]; - - // Initial state (should be password) - expect(passwordField.type).toBe('password'); - - // Click to show - fireEvent.click(toggleButton); - expect(passwordField.type).toBe('text'); - - // Click to hide - fireEvent.click(toggleButton); - expect(passwordField.type).toBe('password'); - }); - - it('copies username to clipboard when copy button is clicked', () => { - renderModal(); - - // Get all the copy buttons in the document by looking for ContentCopy icon - const copyButtons = screen - .getAllByRole('button') - .filter(button => button.innerHTML.includes('ContentCopy')); - - // First copy button should be for username - fireEvent.click(copyButtons[0]); - expect(window.navigator.clipboard.writeText).toHaveBeenCalledWith( - 'testuser', - ); - }); - - it('copies password to clipboard when copy button is clicked', () => { - renderModal(); - - // Get all the copy buttons in the document by looking for ContentCopy icon - const copyButtons = screen - .getAllByRole('button') - .filter(button => button.innerHTML.includes('ContentCopy')); - - // Second copy button should be for password - fireEvent.click(copyButtons[1]); - expect(window.navigator.clipboard.writeText).toHaveBeenCalledWith( - 'password123', - ); - }); - - it('shows error message when ansibleError is provided', () => { - const errorMessage = 'Failed to provision AAP instance'; - renderModal({ - ansibleStatus: AnsibleStatus.READY, - ansibleError: errorMessage, - ansibleUIUser: undefined, - ansibleUIPassword: '', - ansibleUILink: undefined, - }); - - // Look for error icon and message - const errorIcon = document.querySelector('[data-testid="ErrorIcon"]'); - expect(errorIcon).toBeInTheDocument(); - expect(screen.getByText(errorMessage)).toBeInTheDocument(); - }); - - it('contains section descriptions for both accounts', () => { - renderModal(); - - // Check for AAP admin account description - expect( - screen.getByText(/Log in to your AAP admin account within the new tab/i), - ).toBeInTheDocument(); - - // Check for Red Hat account description - expect( - screen.getByText( - /Once logged in, you'll need to activate your subscription/i, - ), - ).toBeInTheDocument(); - }); - - it('has the correct link target for the Get started button', () => { - renderModal(); - - const getStartedButton = screen.getByRole('button', { - name: /Get started/i, - }); - - // The button should be wrapped in a Link component that targets the ansible URL - const linkElement = getStartedButton.closest('a'); - expect(linkElement).toHaveAttribute('href', `https://ansible.example.com`); - expect(linkElement).toHaveAttribute('target', '_blank'); - }); - - it('displays the launch button instruction text', () => { - renderModal(); - - expect( - screen.getByText(/Access this information again by clicking the/i), - ).toBeInTheDocument(); - expect(screen.getByText(/Launch/i)).toBeInTheDocument(); - expect( - screen.getByText( - /button on the Ansible Automation Platform sandbox card/i, - ), - ).toBeInTheDocument(); - }); - - describe('CTA Event Pushing', () => { - it('should disable automatic tracking and push CTA event when Get started link is clicked', () => { - renderModal(); - - const getStartedButton = screen.getByRole('button', { - name: /Get started/i, - }); - - // The button should be wrapped in a Link component - const linkElement = getStartedButton.closest('a'); - - // Should have automatic tracking disabled - expect(linkElement).toHaveAttribute( - 'data-analytics-track-by-analytics-manager', - 'false', - ); - - // Click the link - fireEvent.click(linkElement!); - - // Should push CTA event with correct parameters - expect(mockTrackAnalytics).toHaveBeenCalledWith( - 'Get Started - Ansible', - 'Catalog', - 'https://ansible.example.com', - Intcmp.AAP, - 'cta', - ); - }); - - it('should not push CTA event if ansibleUILink is not available', () => { - // Clear all mocks to ensure clean state - jest.clearAllMocks(); - - const contextOverrides = { - ansibleStatus: AnsibleStatus.READY, - ansibleUILink: undefined, // No link available - ansibleUIUser: 'admin', - ansibleUIPassword: 'password123', - ansibleError: null, - }; - - renderModal(contextOverrides); - - const getStartedButton = screen.getByRole('button', { - name: /Get started/i, - }); - - const linkElement = getStartedButton.closest('a'); - fireEvent.click(linkElement!); - - // Should not push event when link is not available - expect(mockTrackAnalytics).not.toHaveBeenCalled(); - }); - }); -}); diff --git a/workspaces/sandbox/plugins/sandbox/src/components/Modals/__tests__/PhoneVerificationModal.test.tsx b/workspaces/sandbox/plugins/sandbox/src/components/Modals/__tests__/PhoneVerificationModal.test.tsx deleted file mode 100644 index 3da59557bd..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/components/Modals/__tests__/PhoneVerificationModal.test.tsx +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright Red Hat, Inc. - * - * 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 { render, screen, fireEvent } from '@testing-library/react'; -import { PhoneVerificationModal } from '../PhoneVerificationModal'; -import { registerApiRef } from '../../../api'; -import { useSandboxContext } from '../../../hooks/useSandboxContext'; // Corrected path -import { TestApiProvider } from '@backstage/test-utils'; -import { AnsibleStatus } from '../../../utils/aap-utils'; -import { Product } from '../../SandboxCatalog/productData'; - -// Mock dependencies -jest.mock('../../../hooks/useSandboxContext'); -jest.mock('../../../utils/common', () => ({ - errorMessage: jest.fn(e => e.message || 'Unknown error'), -})); - -// Mock the props interface if it's not exported from the component file -declare module '../PhoneVerificationModal' { - interface PhoneVerificationModalProps { - modalOpen: boolean; - setOpen: (open: boolean) => void; - } -} - -describe('PhoneVerificationModal', () => { - const mockInitiatePhoneVerification = jest.fn(); - const mockCompletePhoneVerification = jest.fn(); - const mockRefetchUserData = jest.fn(); - const mockSetOpen = jest.fn(); - const mockSetRefetchingUserData = jest.fn(); - const mockSetAnsibleCredsOpen = jest.fn(); - - const mockRegisterApi = { - initiatePhoneVerification: mockInitiatePhoneVerification, - completePhoneVerification: mockCompletePhoneVerification, - // Add other required methods from the API - getRecaptchaAPIKey: jest.fn(), - getSignUpData: jest.fn(), - signup: jest.fn(), - verifyActivationCode: jest.fn(), - }; - - const mockUseSandboxContext = useSandboxContext as jest.MockedFunction< - typeof useSandboxContext - >; - - beforeEach(() => { - jest.clearAllMocks(); - mockUseSandboxContext.mockReturnValue({ - refetchUserData: mockRefetchUserData, - loading: false, - userFound: false, - userReady: false, - ansibleStatus: AnsibleStatus.UNKNOWN, - verificationRequired: false, - userData: undefined, - signupUser: jest.fn(), - refetchAAP: jest.fn(), - ansibleData: undefined, - ansibleUIUser: undefined, - } as any); - }); - - const renderComponent = () => { - return render( - - - , - ); - }; - - test('should open the modal', () => { - renderComponent(); - - expect(screen.getByText("Let's verify you")).toBeInTheDocument(); - expect( - screen.getByText( - "Enter your phone number and we'll send you a text message with a verification code.", - ), - ).toBeInTheDocument(); - }); - - test('should handle modal close', () => { - renderComponent(); - - // Find and click close button/icon - const closeButton = screen.getByRole('button', { name: /close/i }); - fireEvent.click(closeButton); - - expect(mockSetOpen).toHaveBeenCalledWith(false); - }); -}); diff --git a/workspaces/sandbox/plugins/sandbox/src/components/Modals/index.ts b/workspaces/sandbox/plugins/sandbox/src/components/Modals/index.ts deleted file mode 100644 index f52e756713..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/components/Modals/index.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright Red Hat, Inc. - * - * 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 { default as AccessCodeInputModal } from './AccessCodeInputModal'; -export { default as AnsibleLaunchInfoModal } from './AnsibleLaunchInfoModal'; -export { default as PhoneVerificationModal } from './PhoneVerificationModal'; -export { default as AnsibleDeleteInstanceModal } from './AnsibleDeleteInstanceModal'; diff --git a/workspaces/sandbox/plugins/sandbox/src/components/SandboxActivities/SandboxActivitiesCard.tsx b/workspaces/sandbox/plugins/sandbox/src/components/SandboxActivities/SandboxActivitiesCard.tsx deleted file mode 100644 index 688915ecb8..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/components/SandboxActivities/SandboxActivitiesCard.tsx +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright Red Hat, Inc. - * - * 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 Card from '@mui/material/Card'; -import CardContent from '@mui/material/CardContent'; -import Typography from '@mui/material/Typography'; -import CardMedia from '@mui/material/CardMedia'; -import { useTheme } from '@mui/material/styles'; -import { Link } from '@backstage/core-components'; -import { - getEddlDataAttributes, - useTrackAnalytics, -} from '../../utils/eddl-utils'; - -type SandboxActivitiesCardProps = { - article: { - img: string; - title: string; - description: string; - link: string; - }; -}; - -export const SandboxActivitiesCard: React.FC = ({ - article: { img, title, description, link }, -}) => { - const theme = useTheme(); - const trackAnalytics = useTrackAnalytics(); - const eddlAttributes = getEddlDataAttributes(title, 'Activities'); - - // Handle activity click for analytics tracking - const handleActivityClick = async () => { - await trackAnalytics(title, 'Activities', link); - }; - - return ( - - - - - - {title} - - - {description} - - - - - ); -}; diff --git a/workspaces/sandbox/plugins/sandbox/src/components/SandboxActivities/SandboxActivitiesGrid.tsx b/workspaces/sandbox/plugins/sandbox/src/components/SandboxActivities/SandboxActivitiesGrid.tsx deleted file mode 100644 index 2f02da729a..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/components/SandboxActivities/SandboxActivitiesGrid.tsx +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright Red Hat, Inc. - * - * 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 Box from '@mui/material/Box'; -import Typography from '@mui/material/Typography'; -import { useTheme } from '@mui/material/styles'; -import { ItemCardGrid } from '@backstage/core-components'; -import { SandboxActivitiesCard } from './SandboxActivitiesCard'; -import { articleData } from './articleData'; - -const FeaturedArticles: React.FC = () => { - const theme = useTheme(); - - return ( - - - Featured - - - {articleData?.featured?.map(article => ( - - ))} - - - ); -}; - -const Articles: React.FC = () => { - const theme = useTheme(); - - return ( - - - {articleData?.other?.map(article => ( - - ))} - - - ); -}; - -export const SandboxActivitiesGrid: React.FC = () => { - return ( - <> - - - - ); -}; diff --git a/workspaces/sandbox/plugins/sandbox/src/components/SandboxActivities/SandboxActivitiesPage.tsx b/workspaces/sandbox/plugins/sandbox/src/components/SandboxActivities/SandboxActivitiesPage.tsx deleted file mode 100644 index 985ffe7747..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/components/SandboxActivities/SandboxActivitiesPage.tsx +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright Red Hat, Inc. - * - * 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 { Page, Content } from '@backstage/core-components'; -import { SandboxHeader } from '../SandboxHeader'; -import { SandboxActivitiesGrid } from './SandboxActivitiesGrid'; -import { SandboxCatalogFooter } from '../SandboxCatalog/SandboxCatalogFooter'; -import { SandboxProvider } from '../../hooks/useSandboxContext'; - -export const SandboxActivitiesPage = () => { - return ( - - - - - - - - - - ); -}; diff --git a/workspaces/sandbox/plugins/sandbox/src/components/SandboxActivities/__tests__/SandboxActivitiesCard.test.tsx b/workspaces/sandbox/plugins/sandbox/src/components/SandboxActivities/__tests__/SandboxActivitiesCard.test.tsx deleted file mode 100644 index 8a3ad43236..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/components/SandboxActivities/__tests__/SandboxActivitiesCard.test.tsx +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright Red Hat, Inc. - * - * 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 { render, screen } from '@testing-library/react'; -import { SandboxActivitiesCard } from '../SandboxActivitiesCard'; -import { ThemeProvider } from '@mui/material/styles'; -import { lightTheme } from '@backstage/theme'; -import { wrapInTestApp } from '@backstage/test-utils'; -import * as eddlUtils from '../../../utils/eddl-utils'; - -// Mock the useTrackAnalytics hook -jest.mock('../../../utils/eddl-utils', () => ({ - ...jest.requireActual('../../../utils/eddl-utils'), - useTrackAnalytics: jest.fn(), -})); - -describe('SandboxActivitiesCard', () => { - const mockTrackAnalytics = jest.fn(); - const mockArticle = { - img: 'test-image.jpg', - title: 'Test Article', - description: 'This is a test article description', - link: '/test-link', - }; - - beforeEach(() => { - jest.clearAllMocks(); - // Mock the useTrackAnalytics hook to return a mock function - (eddlUtils.useTrackAnalytics as jest.Mock).mockReturnValue( - mockTrackAnalytics, - ); - }); - - const renderCard = () => { - return render( - wrapInTestApp( - - - , - ), - ); - }; - - it('renders without errors', () => { - renderCard(); - expect(screen.getByText(mockArticle.title)).toBeInTheDocument(); - }); - - it('displays the correct article title', () => { - renderCard(); - const titleElement = screen.getByText(mockArticle.title); - expect(titleElement).toBeInTheDocument(); - expect(titleElement.tagName).toBe('H5'); - }); - - it('displays the correct article description', () => { - renderCard(); - const descriptionElement = screen.getByText(mockArticle.description); - expect(descriptionElement).toBeInTheDocument(); - }); - - it('renders the image with correct attributes', () => { - renderCard(); - const imageElement = screen.getByRole('img'); - expect(imageElement).toHaveAttribute('src', mockArticle.img); - expect(imageElement).toHaveAttribute('alt', mockArticle.title); - expect(imageElement).toHaveAttribute('height', '120'); - }); - - it('links to the correct destination', () => { - renderCard(); - const linkElement = screen.getByRole('link'); - expect(linkElement).toHaveAttribute('href', mockArticle.link); - }); - - it('has no text decoration on the link', () => { - renderCard(); - const linkElement = screen.getByRole('link'); - expect(linkElement).toHaveStyle('text-decoration: none'); - }); - - it('creates a card with the expected styling', () => { - renderCard(); - const cardElement = screen.getByRole('link').firstChild; - - // Check that it's using the Card component by inspecting class names - expect(cardElement).toHaveClass(/MuiCard-root/); - - // Check it has no elevation - expect(cardElement).toHaveClass(/MuiPaper-elevation0/); - }); - - it('applies appropriate typographic styles', () => { - renderCard(); - const titleElement = screen.getByText(mockArticle.title); - const descriptionElement = screen.getByText(mockArticle.description); - - // Check title is primary color - expect(titleElement).toHaveClass(/MuiTypography-h5/); - - // Check description is secondary color - expect(descriptionElement).toHaveClass(/MuiTypography-body2/); - - // Check description has italic style - expect(descriptionElement).toHaveStyle('font-style: italic'); - }); - - describe('EDDL data attributes', () => { - it('should have correct Red Hat EDDL data attributes for activities', () => { - renderCard(); - - const linkElement = screen.getByRole('link'); - - expect(linkElement).toHaveAttribute( - 'data-analytics-category', - 'Developer Sandbox|Activities', - ); - expect(linkElement).toHaveAttribute( - 'data-analytics-text', - 'Test Article', - ); - expect(linkElement).toHaveAttribute( - 'data-analytics-region', - 'sandbox-activities', - ); - }); - }); -}); diff --git a/workspaces/sandbox/plugins/sandbox/src/components/SandboxActivities/__tests__/SandboxActivitiesGrid.test.tsx b/workspaces/sandbox/plugins/sandbox/src/components/SandboxActivities/__tests__/SandboxActivitiesGrid.test.tsx deleted file mode 100644 index 30cc321045..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/components/SandboxActivities/__tests__/SandboxActivitiesGrid.test.tsx +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright Red Hat, Inc. - * - * 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 { render, screen } from '@testing-library/react'; -import { SandboxActivitiesGrid } from '../SandboxActivitiesGrid'; -import { articleData } from '../articleData'; -import { ThemeProvider } from '@mui/material/styles'; -import { lightTheme } from '@backstage/theme'; -import { wrapInTestApp } from '@backstage/test-utils'; -import { SandboxActivitiesCard } from '../SandboxActivitiesCard'; - -// Mock the SandboxActivitiesCard component -jest.mock('../SandboxActivitiesCard', () => ({ - SandboxActivitiesCard: jest.fn(() =>
), -})); - -// Mock the articleData -jest.mock('../articleData', () => ({ - articleData: { - featured: [ - { - img: 'featured-image.jpg', - title: 'Featured Article', - description: 'This is a featured article', - link: '/featured-link', - }, - ], - other: [ - { - img: 'other-image-1.jpg', - title: 'Other Article 1', - description: 'This is another article', - link: '/other-link-1', - }, - { - img: 'other-image-2.jpg', - title: 'Other Article 2', - description: 'This is yet another article', - link: '/other-link-2', - }, - ], - }, -})); - -describe('SandboxActivitiesGrid', () => { - beforeEach(() => { - jest.clearAllMocks(); - }); - - const renderGrid = () => { - return render( - wrapInTestApp( - - - , - ), - ); - }; - - it('renders the featured and other articles sections', () => { - renderGrid(); - - // Check for Featured heading - expect(screen.getByText('Featured')).toBeInTheDocument(); - - // Check that we have the right number of cards rendered (1 featured + 2 other) - const cards = screen.getAllByTestId('mock-card'); - expect(cards).toHaveLength(3); - }); - - it('renders the correct number of cards for other articles', () => { - renderGrid(); - - // SandboxActivitiesCard should be called once for each featured article - // and once for each other article - expect(SandboxActivitiesCard).toHaveBeenCalledTimes( - articleData.featured.length + articleData.other.length, - ); - }); - - describe('Articles component', () => { - // Directly testing the Articles component would require exposing it, - // but we can test its behavior through the parent component - - it('renders correctly when there are no other articles', () => { - // Temporarily modify the mock to have no other articles - const originalOther = articleData.other; - articleData.other = []; - - renderGrid(); - - // Should only render the featured article cards - expect(SandboxActivitiesCard).toHaveBeenCalledTimes( - articleData.featured.length, - ); - - // Restore the original mock - articleData.other = originalOther; - }); - }); -}); diff --git a/workspaces/sandbox/plugins/sandbox/src/components/SandboxActivities/articleData.ts b/workspaces/sandbox/plugins/sandbox/src/components/SandboxActivities/articleData.ts deleted file mode 100644 index 62560d5560..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/components/SandboxActivities/articleData.ts +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright Red Hat, Inc. - * - * 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 Art0 from '../../assets/images/art0.svg'; -import Art1 from '../../assets/images/art1.svg'; -import Art2 from '../../assets/images/art2.svg'; -import Art3 from '../../assets/images/art3.svg'; -import Art4 from '../../assets/images/art4.svg'; -import Art5 from '../../assets/images/art5.svg'; - -type ArticleData = { - img: string; - title: string; - description: string; - link: string; -}; - -type Articles = { - featured: ArticleData[]; - other: ArticleData[]; -}; - -export const articleData: Articles = { - featured: [ - { - img: Art0, - title: 'Get started with your Developer Sandbox', - description: - 'Learn how to set up and use the Developer Sandbox, and learn to develop quicker than ever before.', - link: 'https://developers.redhat.com/learn/openshift/get-started-your-developer-sandbox', - }, - { - img: Art1, - title: 'Streamline automation in OpenShift Dev Spaces with Ansible', - description: - 'Learn how to transform the way you develop and test Ansible automations by using OpenShift Dev Spaces, which provides isolated and tailored development environments.', - link: 'https://developers.redhat.com/learn/openshift/streamline-automation-openshift-dev-spaces-ansible', - }, - { - img: Art2, - title: 'How to deploy a Java application on Kubernetes in minutes', - description: - 'Modernize a legacy Java application by creating microservices, moving it into a container, then deploying it to Red Hat OpenShift using only Kubernetes commands.', - link: 'https://developers.redhat.com/learn/java/how-deploy-java-application-kubernetes-minutes', - }, - ], - other: [ - { - img: Art3, - title: 'Foundations of OpenShift', - description: - 'Learn the foundations of OpenShift through hands-on experience deploying and working with applications.', - link: 'https://developers.redhat.com/learn/openshift/foundations-openshift', - }, - { - img: Art4, - title: 'Using OpenShift Pipelines', - description: - 'Learn how to use OpenShift Pipelines for automated builds and deployments – known as CI/CD – of container-based applications to reduce mistakes, improve productivity, and promote more thorough testing.', - link: 'https://developers.redhat.com/learn/openshift/using-openshift-pipelines', - }, - { - img: Art5, - title: - 'OpenShift virtualization and application modernization using the Developer Sandbox', - description: - 'Learn how to create and manage your virtual machines (VMs) using Red Hat OpenShift and the Developer Sandbox, a no-cost OpenShift cluster with no need for setup or configuration.', - link: 'https://developers.redhat.com/learn/openshift/openshift-virtualization-and-application-modernization-using-developer-sandbox', - }, - ], -}; diff --git a/workspaces/sandbox/plugins/sandbox/src/components/SandboxCatalog/SandboxCatalogBanner.tsx b/workspaces/sandbox/plugins/sandbox/src/components/SandboxCatalog/SandboxCatalogBanner.tsx deleted file mode 100644 index 252863153b..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/components/SandboxCatalog/SandboxCatalogBanner.tsx +++ /dev/null @@ -1,330 +0,0 @@ -/* - * Copyright Red Hat, Inc. - * - * 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 Box from '@mui/material/Box'; -import Typography from '@mui/material/Typography'; -import Card from '@mui/material/Card'; -import Stack from '@mui/material/Stack'; -import Skeleton from '@mui/material/Skeleton'; -import Popover from '@mui/material/Popover'; -import IconButton from '@mui/material/IconButton'; -import Link from '@mui/material/Link'; -import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined'; -import CloseIcon from '@mui/icons-material/Close'; -import OpenInNewIcon from '@mui/icons-material/OpenInNew'; -import { useTheme } from '@mui/material/styles'; -import Image from '../../assets/images/sandbox-banner-image.svg'; -import { useSandboxContext } from '../../hooks/useSandboxContext'; -import { calculateDaysBetweenDates } from '../../utils/common'; - -export const SandboxCatalogBanner: React.FC = () => { - const theme = useTheme(); - const { userData, pendingApproval, verificationRequired, loading } = - useSandboxContext(); - const [anchorEl, setAnchorEl] = React.useState(null); - - const calculateDaysLeft = React.useCallback(() => { - if (userData?.endDate) { - const trialEndDate = new Date(userData?.endDate); - return calculateDaysBetweenDates(new Date(), trialEndDate); - } - // unable to compute days - return undefined; - }, [userData?.endDate]); - - const handleInfoClick = (event: React.MouseEvent) => { - setAnchorEl(event.currentTarget); - }; - - const handlePopoverClose = () => { - setAnchorEl(null); - }; - - const open = Boolean(anchorEl); - - return ( - - - - Red Hat Trial - - - - {loading ? ( - <> - - - - - ) : ( - <> - {userData ? ( - <> - - Welcome, {userData.givenName || userData.compliantUsername} - - - - {(() => { - if (verificationRequired) { - return 'Click on "Try it" to initiate your free, no commitment 30-day trial.'; - } - if (pendingApproval) { - return 'Please wait for your trial to be approved.'; - } - if (userData?.endDate) { - const daysLeft = calculateDaysLeft(); - return `Your free trial expires in ${daysLeft} ${ - daysLeft === 1 ? 'day' : 'days' - }`; - } - return ''; - })()} - - {userData?.endDate && ( - - - - )} - - - ) : ( - <> - - Try Red Hat products - - - Explore, experiment, and see what's possible - - - Click on "Try it" to initiate your free, no commitment - 30-day trial. - - - )} - - )} - - - - - - - - - - - Trial expiration - - - - Once this trial expires, you can start a new one immediately. Your - work from this trial will be deleted. To save your work, follow the - instructions in our documentation. - - - - View documentation - - - - - - ); -}; diff --git a/workspaces/sandbox/plugins/sandbox/src/components/SandboxCatalog/SandboxCatalogCard.tsx b/workspaces/sandbox/plugins/sandbox/src/components/SandboxCatalog/SandboxCatalogCard.tsx deleted file mode 100644 index a1b59fcfdd..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/components/SandboxCatalog/SandboxCatalogCard.tsx +++ /dev/null @@ -1,335 +0,0 @@ -/* - * Copyright Red Hat, Inc. - * - * 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, { useState } from 'react'; -import { useTheme } from '@mui/material/styles'; -import Box from '@mui/material/Box'; -import Stack from '@mui/material/Stack'; -import Card from '@mui/material/Card'; -import Tooltip from '@mui/material/Tooltip'; -import DoneIcon from '@mui/icons-material/Done'; -import Typography from '@mui/material/Typography'; -import CardMedia from '@mui/material/CardMedia'; -import CardContent from '@mui/material/CardContent'; -import CardActions from '@mui/material/CardActions'; -import { SandboxCatalogCardButton } from './SandboxCatalogCardButton'; -import { SandboxCatalogCardDeleteButton } from './SandboxCatalogCardDeleteButton'; -import { - AnsibleDeleteInstanceModal, - AnsibleLaunchInfoModal, - PhoneVerificationModal, -} from '../Modals'; -import { useSandboxContext } from '../../hooks/useSandboxContext'; -import { useApi } from '@backstage/core-plugin-api'; -import { aapApiRef, kubeApiRef } from '../../api'; -import { Product } from './productData'; -import { signupDataToStatus } from '../../utils/register-utils'; -import { productsURLMapping } from '../../hooks/useProductURLs'; - -type SandboxCatalogCardProps = { - id: Product; - title: string; - image: string; - description: { - icon: React.ReactNode; - value: string; - }[]; - link: string; - greenCorner: boolean; - showGreenCorner: () => void; -}; - -const CatalogCardGreenCorner = ({ show }: { show: boolean }) => { - const theme = useTheme(); - if (!show) { - return ( - // Empty box to keep the layout consistent - - ); - } - return ( - - - - - - ); -}; - -export const SandboxCatalogCard: React.FC = ({ - id, - title, - image, - description, - link, - greenCorner, - showGreenCorner, -}) => { - const theme = useTheme(); - const kubeApi = useApi(kubeApiRef); - const aapApi = useApi(aapApiRef); - let { userData, userFound, userReady, verificationRequired } = - useSandboxContext(); - const { handleAAPInstance, signupUser, refetchUserData, refetchAAP } = - useSandboxContext(); - const [ansibleCredsModalOpen, setAnsibleCredsModalOpen] = - React.useState(false); - const [verifyPhoneModalOpen, setVerifyPhoneModalOpen] = useState(false); - const [refetchingUserData, setRefetchingUserData] = useState(false); - const [deleteAnsibleModalOpen, setDeleteAnsibleModalOpen] = useState(false); - const [deleting, setDeleting] = useState(false); - - const handleTryButtonClick = async (pdt: Product) => { - // User is not yet signed up - let urlToOpen = link; - if (!userFound) { - signupUser(); - - const maxAttempts = 5; - const retryInterval = 1000; // 1 second - - // Poll until user is found or max attempts reached - for (let i = 0; i < maxAttempts; i++) { - setRefetchingUserData(true); - await new Promise(resolve => setTimeout(resolve, retryInterval)); - - try { - // Fetch the latest user data and check if user is found - userData = await refetchUserData(); - if (userData) { - userFound = true; - const userStatus = signupDataToStatus(userData); - verificationRequired = userStatus === 'verify'; - userReady = userStatus === 'ready'; - const userNamespaceReady = - userData?.defaultUserNamespace !== undefined; - // if user is ready or verification is required we can stop fetching the data - if ((userReady || verificationRequired) && userNamespaceReady) { - const productURLs = productsURLMapping(userData); - // find the link to open if any - urlToOpen = productURLs.find(pu => pu.id === id)?.url || ''; - if (urlToOpen && !verificationRequired) { - // open url if user is ready and no further verification is required - window.open(urlToOpen, '_blank'); - showGreenCorner(); - } - break; - } - } - } catch (error) { - // eslint-disable-next-line no-console - console.error('Error fetching user data:', error); - } finally { - setRefetchingUserData(false); - } - } - } - - // User has signed up but require verification - if (userFound && verificationRequired) { - setVerifyPhoneModalOpen(true); - return; - } - - // User has signed up and the trial is ready and user selects the AAP Trial - if (userFound && userReady && pdt === Product.AAP) { - if (!userData?.defaultUserNamespace) { - // eslint-disable-next-line - console.error( - 'unable to provision AAP. user namespace is not defined.', - ); - return; - } - handleAAPInstance(userData.defaultUserNamespace); - setAnsibleCredsModalOpen(true); - showGreenCorner(); - } - }; - - const handleDeleteButtonClick = async (pdt: Product) => { - if (deleting) { - return; - } - - setDeleteAnsibleModalOpen(false); - setDeleting(true); - const userNamespace = userData?.defaultUserNamespace; - if (!userNamespace) { - // eslint-disable-next-line - console.error( - 'unable to delete aap instance. user namespace is undefined', - ); - return; - } - if (pdt === Product.AAP) { - refetchAAP(userNamespace); - const aapLabelSelector = - 'app.kubernetes.io%2Fmanaged-by+in+%28aap-gateway-operator%2Caap-operator%2Cautomationcontroller-operator%2Cautomationhub-operator%2Ceda-operator%2Clightspeed-operator%29&limit=50'; - - try { - const aapDeployments = await kubeApi.getDeployments( - userNamespace, - aapLabelSelector, - ); - const aapStatefulSets = await kubeApi.getStatefulSets( - userNamespace, - aapLabelSelector, - ); - await aapApi.deleteAAPCR(userNamespace); - await kubeApi.deleteSecretsAndPVCs(aapDeployments, userNamespace); - await kubeApi.deleteSecretsAndPVCs(aapStatefulSets, userNamespace); - await kubeApi.deletePVCsForSTS(aapStatefulSets, userNamespace); - } catch (e) { - // eslint-disable-next-line no-console - console.error(e); - } - } - refetchAAP(userNamespace); - setDeleting(false); - }; - - return ( - <> - - - - - {title} - - {title} - - - - - {description?.map(point => ( - -
- {point.icon} {point.value} -
-
- ))} -
- - - setDeleteAnsibleModalOpen(true)} - isDeleting={deleting} - /> - -
- - - handleDeleteButtonClick(id)} - /> - - ); -}; diff --git a/workspaces/sandbox/plugins/sandbox/src/components/SandboxCatalog/SandboxCatalogCardButton.tsx b/workspaces/sandbox/plugins/sandbox/src/components/SandboxCatalog/SandboxCatalogCardButton.tsx deleted file mode 100644 index 09bcf160be..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/components/SandboxCatalog/SandboxCatalogCardButton.tsx +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright Red Hat, Inc. - * - * 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 from '@mui/material/Button'; -import { Theme } from '@mui/material/styles'; -import OpenInNewIcon from '@mui/icons-material/OpenInNew'; -import CircularProgress from '@mui/material/CircularProgress'; -import { Link } from '@backstage/core-components'; -import { useSandboxContext } from '../../hooks/useSandboxContext'; -import { AnsibleStatus } from '../../utils/aap-utils'; -import { Product } from './productData'; -import { useTrackAnalytics } from '../../utils/eddl-utils'; -import { Intcmp } from '../../hooks/useProductURLs'; - -type SandboxCatalogCardButtonProps = { - link: string; - id: Product; - title: string; - handleTryButtonClick: (id: Product) => void; - theme: Theme; - refetchingUserData?: boolean; -}; - -export const SandboxCatalogCardButton: React.FC< - SandboxCatalogCardButtonProps -> = ({ link, id, title, handleTryButtonClick, theme, refetchingUserData }) => { - const { loading, userFound, verificationRequired, userReady, ansibleStatus } = - useSandboxContext(); - const [clicked, setClicked] = React.useState(false); - const trackAnalytics = useTrackAnalytics(); - - const handleClick = () => { - if (!clicked) setClicked(true); - handleTryButtonClick(id); - }; - - const label = (() => { - if (id === Product.AAP) { - if (ansibleStatus === AnsibleStatus.IDLED) { - return 'Reprovision'; - } - if (ansibleStatus === AnsibleStatus.PROVISIONING) { - return 'Provisioning'; - } - if (ansibleStatus === AnsibleStatus.READY) { - return 'Launch'; - } - return 'Provision'; - } - return 'Try it'; - })(); - - let endIcon; - if ( - (loading && clicked) || - (userFound && !userReady && !verificationRequired && clicked) || - (refetchingUserData && clicked) - ) { - endIcon = ; - } else if (id !== Product.AAP) { - endIcon = ; - } else if ( - ansibleStatus === AnsibleStatus.UNKNOWN || - ansibleStatus === AnsibleStatus.PROVISIONING - ) { - endIcon = ; - } else { - endIcon = null; - } - - const buttonSx = { - border: `1px solid ${ - theme.palette.mode === 'dark' ? '#92c5f9' : theme.palette.primary.main - }`, - marginTop: theme.spacing(0.5), - '&:hover': { - backgroundColor: 'rgba(25, 118, 210, 0.04)', - borderColor: '#1976d2', - }, - }; - - // Get the intcmp parameter for this product - const getIntcmpFromProduct = (productId: Product): string | undefined => { - switch (productId) { - case Product.OPENSHIFT_CONSOLE: - return Intcmp.OPENSHIFT_CONSOLE; - case Product.DEVSPACES: - return Intcmp.DEVSPACES; - case Product.OPENSHIFT_AI: - return Intcmp.RHODS; - case Product.OPENSHIFT_VIRT: - return Intcmp.OPENSHIFT_VIRT; - case Product.AAP: - return Intcmp.AAP; - default: - return undefined; - } - }; - - const intcmp = getIntcmpFromProduct(id); - - // Handle CTA click for analytics - const handleCtaClick = async () => { - await trackAnalytics(title, 'Catalog', link, intcmp, 'cta'); - }; - - const buttonContent = ( - - ); - - return userFound && !loading && !verificationRequired ? ( - - {buttonContent} - - ) : ( - // When there's no link, we push CTA event on button click - - ); -}; diff --git a/workspaces/sandbox/plugins/sandbox/src/components/SandboxCatalog/SandboxCatalogCardDeleteButton.tsx b/workspaces/sandbox/plugins/sandbox/src/components/SandboxCatalog/SandboxCatalogCardDeleteButton.tsx deleted file mode 100644 index fb7bd08825..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/components/SandboxCatalog/SandboxCatalogCardDeleteButton.tsx +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright Red Hat, Inc. - * - * 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 from '@mui/material/Button'; -import { Theme } from '@mui/material/styles'; -import CircularProgress from '@mui/material/CircularProgress'; -import { useSandboxContext } from '../../hooks/useSandboxContext'; -import { AnsibleStatus } from '../../utils/aap-utils'; -import { Product } from './productData'; - -type SandboxCatalogCardDeleteButtonProps = { - id: Product; - handleDeleteButtonClick: (id: Product) => void; - theme: Theme; - isDeleting: boolean; -}; - -export const SandboxCatalogCardDeleteButton: React.FC< - SandboxCatalogCardDeleteButtonProps -> = ({ id, handleDeleteButtonClick, theme, isDeleting }) => { - const { ansibleStatus } = useSandboxContext(); - - if ( - id === Product.AAP && - (ansibleStatus === AnsibleStatus.READY || - ansibleStatus === AnsibleStatus.PROVISIONING || - ansibleStatus === AnsibleStatus.UNKNOWN) - ) { - return ( - - ); - } - return null; -}; diff --git a/workspaces/sandbox/plugins/sandbox/src/components/SandboxCatalog/SandboxCatalogFooter.tsx b/workspaces/sandbox/plugins/sandbox/src/components/SandboxCatalog/SandboxCatalogFooter.tsx deleted file mode 100644 index bc9d1292a9..0000000000 --- a/workspaces/sandbox/plugins/sandbox/src/components/SandboxCatalog/SandboxCatalogFooter.tsx +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright Red Hat, Inc. - * - * 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 Box from '@mui/material/Box'; -import Typography from '@mui/material/Typography'; -import { useTheme } from '@mui/material/styles'; -import Link from '@mui/material/Link'; -import { AccessCodeInputModal } from '../Modals/AccessCodeInputModal'; -import { FooterCopyright } from '@rhds/elements/react/rh-footer/rh-footer-copyright'; -import { FooterUniversal } from '@rhds/elements/react/rh-footer/rh-footer-universal'; - -import '@rhds/elements/rh-footer/rh-footer-lightdom.css'; -import { useEffect, useRef } from 'react'; - -// Create the TrustArc element once, outside of any component -let trustArcElement: HTMLSpanElement | null = null; - -const createTrustArcElement = () => { - if (!trustArcElement) { - trustArcElement = document.createElement('span'); - trustArcElement.id = 'teconsent'; - trustArcElement.style.display = 'none'; - } - return trustArcElement; -}; - -const CookieConsentElement = () => { - const consentRef = useRef(null); - - useEffect(() => { - const spanElement = createTrustArcElement(); - - if (consentRef.current && !consentRef.current.contains(spanElement)) { - consentRef.current.appendChild(spanElement); - } - }); - - return
  • ; -}; - -export const SandboxCatalogFooter = () => { - const theme = useTheme(); - const [accessCodeModalOpen, setAccessCodeModalOpen] = React.useState(false); - - const handleClick = () => { - setAccessCodeModalOpen(true); - }; - - return ( - <> - - - Have an activation code?{' '} - - Click here - - -