diff --git a/.github/workflows/block-apps.yml b/.github/workflows/block-apps.yml
index 0ad038d64..dd68ba4bf 100644
--- a/.github/workflows/block-apps.yml
+++ b/.github/workflows/block-apps.yml
@@ -1,4 +1,4 @@
-name: Block PRs on following apps supernova, huereka, greenhouse and greenhouse-management
+name: Block PRs on apps supernova, huereka, greenhouse and greenhouse-management and libs communicator, oauth and juno-ui-components
on:
pull_request:
@@ -75,12 +75,15 @@ jobs:
echo libs: ${{ needs.changes.outputs.libs }}
echo app changes: ${{ needs.changes.outputs.app-changes }}
echo lib changes: ${{ needs.changes.outputs.lib-changes }}
- - name: Check if any of the apps are supernova, huereka, greenhouse or greenhouse-management
+ - name: Check if changes belongs to apps supernova, huereka, greenhouse or greenhouse-management or libs communicator, oauth or juno-ui-components
if: |
contains(needs.changes.outputs.app-changes, 'supernova') ||
contains(needs.changes.outputs.app-changes, 'huereka') ||
contains(needs.changes.outputs.app-changes, 'greenhouse') ||
- contains(needs.changes.outputs.app-changes, 'greenhouse-management')
+ contains(needs.changes.outputs.app-changes, 'greenhouse-management') ||
+ contains(needs.changes.outputs.lib-changes, 'communicator') ||
+ contains(needs.changes.outputs.lib-changes, 'oauth') ||
+ contains(needs.changes.outputs.lib-changes, 'juno-ui-components')
run: |
- echo "::error not allowed to make changes to supernova, huereka, greenhouse or greenhouse-management apps"
+ echo "::error not allowed to make changes to supernova, huereka, greenhouse or greenhouse-management apps or communicator, oauth or juno-ui-components libs"
exit 1
diff --git a/apps/assets-overview/jest.config.js b/apps/assets-overview/jest.config.js
index d16f3da9d..fd60a61f4 100644
--- a/apps/assets-overview/jest.config.js
+++ b/apps/assets-overview/jest.config.js
@@ -8,7 +8,7 @@ module.exports = {
testEnvironment: "jsdom",
setupFilesAfterEnv: ["/setupTests.js"],
transformIgnorePatterns: [
- "node_modules/(?!(juno-ui-components|messages-provider)/)",
+ "node_modules/(?!(juno-ui-components|messages-provider|url-state-router|utils)/)",
],
moduleNameMapper: {
// Jest currently doesn't support resources with query parameters.
diff --git a/apps/assets-overview/package.json b/apps/assets-overview/package.json
index 25b94a563..0316dd4c7 100644
--- a/apps/assets-overview/package.json
+++ b/apps/assets-overview/package.json
@@ -31,9 +31,9 @@
"github-markdown-css": "^5.1.0",
"jest": "^29.3.1",
"jest-environment-jsdom": "^29.3.1",
- "juno-ui-components": "*",
+ "juno-ui-components": "https://assets.juno.global.cloud.sap/libs/juno-ui-components@2.13.8/package.tgz",
"luxon": "3.3.0",
- "messages-provider": "*",
+ "messages-provider": "https://assets.juno.global.cloud.sap/libs/messages-provider@0.1.12/package.tgz",
"postcss": "^8.4.21",
"postcss-url": "^10.1.3",
"prop-types": "15.8.1",
@@ -45,10 +45,10 @@
"sass": "^1.60.0",
"shadow-dom-testing-library": "^1.7.1",
"tailwindcss": "^3.3.1",
- "url-state-provider": "*",
- "url-state-router": "*",
+ "url-state-provider": "https://assets.juno.global.cloud.sap/libs/url-state-provider@1.3.2/package.tgz",
+ "url-state-router": "https://assets.juno.global.cloud.sap/libs/url-state-router@1.0.3/package.tgz",
"util": "^0.12.4",
- "utils": "*",
+ "utils": "https://assets.juno.global.cloud.sap/libs/utils@1.1.6/package.tgz",
"zustand": "4.3.7"
},
"scripts": {
@@ -60,15 +60,15 @@
"peerDependencies": {
"@tanstack/react-query": "4.28.0",
"custom-event-polyfill": "1.0.7",
- "juno-ui-components": "*",
+ "juno-ui-components": "https://assets.juno.global.cloud.sap/libs/juno-ui-components@2.13.8/package.tgz",
"luxon": "3.3.0",
- "messages-provider": "*",
+ "messages-provider": "https://assets.juno.global.cloud.sap/libs/messages-provider@0.1.12/package.tgz",
"prop-types": "15.8.1",
"react": "18.2.0",
"react-dom": "18.2.0",
- "url-state-provider": "*",
- "url-state-router": "*",
- "utils": "*",
+ "url-state-provider": "https://assets.juno.global.cloud.sap/libs/url-state-provider@1.3.2/package.tgz",
+ "url-state-router": "https://assets.juno.global.cloud.sap/libs/url-state-router@1.0.3/package.tgz",
+ "utils": "https://assets.juno.global.cloud.sap/libs/utils@1.1.6/package.tgz",
"zustand": "4.3.7"
},
"appProps": {
diff --git a/apps/auth/package.json b/apps/auth/package.json
index b2d1c80fa..0c3c4ac2a 100644
--- a/apps/auth/package.json
+++ b/apps/auth/package.json
@@ -25,14 +25,14 @@
"autoprefixer": "^10.4.2",
"babel-jest": "^29.3.1",
"babel-plugin-transform-import-meta": "^2.2.0",
- "communicator": "*",
+ "communicator": "https://assets.juno.global.cloud.sap/libs/communicator@2.2.6/package.tgz",
"custom-event-polyfill": "^1.0.7",
"esbuild": "^0.17.12",
"interweave": "^13.0.0",
"jest": "^29.3.1",
"jest-environment-jsdom": "^29.3.1",
- "juno-ui-components": "*",
- "oauth": "*",
+ "juno-ui-components": "https://assets.juno.global.cloud.sap/libs/juno-ui-components@2.13.8/package.tgz",
+ "oauth": "https://assets.juno.global.cloud.sap/libs/oauth@1.2.1/package.tgz",
"postcss": "^8.4.21",
"postcss-url": "^10.1.3",
"prop-types": "^15.8.1",
@@ -52,7 +52,7 @@
"peerDependencies": {
"custom-event-polyfill": "^1.0.7",
"juno-ui-components": "latest",
- "oauth": "*",
+ "oauth": "https://assets.juno.global.cloud.sap/libs/oauth@1.2.1/package.tgz",
"prop-types": "^15.8.1",
"react": "18.2.0",
"react-dom": "^18.2.0"
diff --git a/apps/dashboard/package.json b/apps/dashboard/package.json
index 258a3d5e0..8b6a12424 100644
--- a/apps/dashboard/package.json
+++ b/apps/dashboard/package.json
@@ -26,7 +26,7 @@
"babel-plugin-transform-import-meta": "^2.2.0",
"jest": "^29.3.1",
"jest-environment-jsdom": "^29.3.1",
- "juno-ui-components": "*",
+ "juno-ui-components": "https://assets.juno.global.cloud.sap/libs/juno-ui-components@2.13.8/package.tgz",
"luxon": "^2.3.0",
"postcss": "^8.4.21",
"postcss-url": "^10.1.3",
@@ -47,7 +47,7 @@
},
"peerDependencies": {
"custom-event-polyfill": "^1.0.7",
- "juno-ui-components": "*",
+ "juno-ui-components": "https://assets.juno.global.cloud.sap/libs/juno-ui-components@2.13.8/package.tgz",
"luxon": "^2.3.0",
"prop-types": "^15.8.1",
"react": "18.2.0",
diff --git a/apps/dashboard/src/store.js b/apps/dashboard/src/store.js
index d906a33b2..558705b6c 100644
--- a/apps/dashboard/src/store.js
+++ b/apps/dashboard/src/store.js
@@ -42,6 +42,16 @@ const DOMAINS = {
"HCM",
"HDA",
"HEC",
+ "IAAS-20e8bf",
+ "IAAS-45b91f",
+ "IAAS-de5955",
+ "IAAS-9d6a56",
+ "IAAS-b56735",
+ "IAAS-ec5a3e",
+ "IAAS-d3495f",
+ "IAAS-90876f",
+ "IAAS-7ff5dd",
+ "IAAS-34a24e",
"KYMA",
"NEO",
"ORA",
diff --git a/apps/exampleapp/jest.config.js b/apps/exampleapp/jest.config.js
index 5f65d6a46..33ea7ddfe 100644
--- a/apps/exampleapp/jest.config.js
+++ b/apps/exampleapp/jest.config.js
@@ -7,7 +7,9 @@ module.exports = {
transform: { "\\.[jt]sx?$": "babel-jest" },
testEnvironment: "jsdom",
setupFilesAfterEnv: ["/setupTests.js"],
- transformIgnorePatterns: ["node_modules/(?!(juno-ui-components)/)"],
+ transformIgnorePatterns: [
+ "node_modules/(?!(juno-ui-components|oauth|messages-provider|utils)/)",
+ ],
moduleNameMapper: {
// Jest currently doesn't support resources with query parameters.
// Therefore we add the optional query parameter matcher at the end
diff --git a/apps/exampleapp/package.json b/apps/exampleapp/package.json
index 1a1e48134..0fe86bbff 100644
--- a/apps/exampleapp/package.json
+++ b/apps/exampleapp/package.json
@@ -29,10 +29,10 @@
"esbuild": "^0.17.19",
"jest": "^29.3.1",
"jest-environment-jsdom": "^29.3.1",
- "juno-ui-components": "*",
+ "juno-ui-components": "https://assets.juno.global.cloud.sap/libs/juno-ui-components@2.13.8/package.tgz",
"luxon": "^2.3.0",
- "messages-provider": "*",
- "oauth": "*",
+ "messages-provider": "https://assets.juno.global.cloud.sap/libs/messages-provider@0.1.12/package.tgz",
+ "oauth": "https://assets.juno.global.cloud.sap/libs/oauth@1.2.1/package.tgz",
"postcss": "^8.4.21",
"postcss-url": "^10.1.3",
"prop-types": "^15.8.1",
@@ -42,9 +42,9 @@
"sass": "^1.60.0",
"shadow-dom-testing-library": "^1.7.1",
"tailwindcss": "^3.3.1",
- "url-state-provider": "*",
+ "url-state-provider": "https://assets.juno.global.cloud.sap/libs/url-state-provider@1.3.2/package.tgz",
"util": "^0.12.4",
- "utils": "*",
+ "utils": "https://assets.juno.global.cloud.sap/libs/utils@1.1.6/package.tgz",
"zustand": "4.3.7"
},
"scripts": {
@@ -55,15 +55,15 @@
"peerDependencies": {
"@tanstack/react-query": "4.28.0",
"custom-event-polyfill": "^1.0.7",
- "juno-ui-components": "*",
+ "juno-ui-components": "https://assets.juno.global.cloud.sap/libs/juno-ui-components@2.13.8/package.tgz",
"luxon": "^2.3.0",
- "messages-provider": "*",
- "oauth": "*",
+ "messages-provider": "https://assets.juno.global.cloud.sap/libs/messages-provider@0.1.12/package.tgz",
+ "oauth": "https://assets.juno.global.cloud.sap/libs/oauth@1.2.1/package.tgz",
"prop-types": "^15.8.1",
"react": "18.2.0",
"react-dom": "^18.2.0",
- "url-state-provider": "*",
- "utils": "*",
+ "url-state-provider": "https://assets.juno.global.cloud.sap/libs/url-state-provider@1.3.2/package.tgz",
+ "utils": "https://assets.juno.global.cloud.sap/libs/utils@1.1.6/package.tgz",
"zustand": "4.3.7"
},
"importmapExtras": {
diff --git a/apps/greenhouse-management/LICENSE b/apps/greenhouse-management/LICENSE
deleted file mode 100644
index 261eeb9e9..000000000
--- a/apps/greenhouse-management/LICENSE
+++ /dev/null
@@ -1,201 +0,0 @@
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/apps/greenhouse-management/README.md b/apps/greenhouse-management/README.md
deleted file mode 100644
index 5adc53806..000000000
--- a/apps/greenhouse-management/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# Greenhouse Management App
-
-This is the shell app for Greenhouse Management Apps. It is the host for all management apps that are part of Greenhouse.
diff --git a/apps/greenhouse-management/__mocks__/client.js b/apps/greenhouse-management/__mocks__/client.js
deleted file mode 100644
index 84531d3c2..000000000
--- a/apps/greenhouse-management/__mocks__/client.js
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import { JSDOM } from "jsdom"
-const dom = new JSDOM()
-global.document = dom.window.document
-global.window = dom.window
diff --git a/apps/greenhouse-management/__mocks__/fileMock.js b/apps/greenhouse-management/__mocks__/fileMock.js
deleted file mode 100644
index 27ce65aca..000000000
--- a/apps/greenhouse-management/__mocks__/fileMock.js
+++ /dev/null
@@ -1,6 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-module.exports = "test-file-stub"
diff --git a/apps/greenhouse-management/babel.config.js b/apps/greenhouse-management/babel.config.js
deleted file mode 100644
index 0719e2fec..000000000
--- a/apps/greenhouse-management/babel.config.js
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-module.exports = {
- env: {
- test: {
- presets: ["@babel/preset-env", "@babel/preset-react"],
- plugins: [["babel-plugin-transform-import-meta", { module: "ES6" }]],
- },
- },
-}
diff --git a/apps/greenhouse-management/esbuild.config.js b/apps/greenhouse-management/esbuild.config.js
deleted file mode 100644
index 2394388b8..000000000
--- a/apps/greenhouse-management/esbuild.config.js
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-const esbuild = require("esbuild")
-const fs = require("node:fs/promises")
-const pkg = require("./package.json")
-const postcss = require("postcss")
-const sass = require("sass")
-const { transform } = require("@svgr/core")
-const url = require("postcss-url")
-// this function generates app props based on package.json and propSecrets.json
-const appProps = require("../../helpers/appProps")
-
-if (!/.+\/.+\.js/.test(pkg.module))
- throw new Error(
- "module value is incorrect, use DIR/FILE.js like build/index.js"
- )
-
-const isProduction = process.env.NODE_ENV === "production"
-// If the jspm server fails and we cannot use external packages
-// in our import map then IGNORE_EXTERNALS (global env variable)
-// should be set to true
-const IGNORE_EXTERNALS = process.env.IGNORE_EXTERNALS === "true"
-// in dev environment we prefix output file with public
-let outfile = `${isProduction ? "" : "public/"}${pkg.main || pkg.module}`
-// get output from outputfile
-let outdir = outfile.slice(0, outfile.lastIndexOf("/"))
-const args = process.argv.slice(2)
-const watch = args.indexOf("--watch") >= 0
-const serve = args.indexOf("--serve") >= 0
-
-// helpers for console log
-const green = "\x1b[32m%s\x1b[0m"
-const yellow = "\x1b[33m%s\x1b[0m"
-const clear = "\033c"
-
-const build = async () => {
- // delete build folder and re-create it as an empty folder
- await fs.rm(outdir, { recursive: true, force: true })
- await fs.mkdir(outdir, { recursive: true })
-
- // build app
- let ctx = await esbuild.context({
- bundle: true,
- minify: isProduction,
- // target: ["es2020"],
- target: ["es2020"], //["chrome64", "firefox67", "safari11.1", "edge79"],
- format: "esm",
- platform: "browser",
- // built-in loaders: js, jsx, ts, tsx, css, json, text, base64, dataurl, file, binary
- loader: { ".js": "jsx" },
- sourcemap: !isProduction,
- // here we exclude package from bundle which are defined in peerDependencies
- // our importmap generator uses also the peerDependencies to create the importmap
- // it means all packages defined in peerDependencies are in browser available via the importmap
- external:
- isProduction && !IGNORE_EXTERNALS
- ? Object.keys(pkg.peerDependencies || {})
- : [],
- entryPoints: [pkg.source],
- outdir,
- // this step is important for performance reason.
- // the main file (index.js) contains minimal code needed to
- // load the app via dynamic import (splitting: true)
- splitting: true,
- // we suport only esm!
- format: "esm",
- plugins: [
- // minimal plugin to log the recompiling process.
- {
- name: "start/end",
- setup(build) {
- build.onStart(() => {
- console.log(clear)
- console.log(yellow, "Compiling...")
- })
- build.onEnd(() => console.log(green, "Done!"))
- },
- },
-
- // this custom plugin rewrites SVG imports to
- // dataurls, paths or react components based on the
- // search param and size
- {
- name: "svg-loader",
- setup(build) {
- build.onLoad(
- // consider only .svg files
- { filter: /.\.(svg)$/, namespace: "file" },
- async (args) => {
- let contents = await fs.readFile(args.path)
- // built-in loaders: js, jsx, ts, tsx, css, json, text, base64, dataurl, file, binary
- let loader = "text"
- if (args.suffix === "?url") {
- // as URL
- const maxSize = 10240 // 10Kb
- // use dataurl loader for small files and file loader for big files!
- loader = contents.length <= maxSize ? "dataurl" : "file"
- } else {
- // as react component
- // use react component loader (jsx)
- loader = "jsx"
- contents = await transform(contents, {
- plugins: ["@svgr/plugin-jsx"],
- })
- }
-
- return { contents, loader }
- }
- )
- },
- },
-
- // this custom plugin rewrites image imports to
- // dataurls or urls based on the size
- {
- name: "image-loader",
- setup(build) {
- build.onLoad(
- // consider only .svg files
- { filter: /.\.(png|jpg|jpeg|gif)$/, namespace: "file" },
- async (args) => {
- let contents = await fs.readFile(args.path)
- const maxSize = 10240 // 10Kb
- // built-in loaders: js, jsx, ts, tsx, css, json, text, base64, dataurl, file, binary
- // use dataurl loader for small files and file loader for big files!
- loader = contents.length <= maxSize ? "dataurl" : "file"
-
- return { contents, loader }
- }
- )
- },
- },
-
- // this custom plugin parses the style files
- {
- name: "parse-styles",
- setup(build) {
- build.onLoad(
- // consider only .scss and .css files
- { filter: /.\.(css|scss)$/, namespace: "file" },
- async (args) => {
- let content
- // handle scss, convert to css
- if (args.path.endsWith(".scss")) {
- const result = sass.renderSync({ file: args.path })
- content = result.css
- } else {
- // read file content
- content = await fs.readFile(args.path)
- }
-
- // postcss plugins
- const plugins = [
- require("tailwindcss"),
- require("autoprefixer"),
- // rewrite urls inside css
- url({
- url: "inline",
- // maxSize: 10, // use dataurls if files are smaller than 10k
- // fallback: "copy", // if files are bigger use copy method
- // assetsPath: "./build/assets",
- // useHash: true,
- // optimizeSvgEncode: true,
- }),
- ]
-
- const { css } = await postcss(plugins).process(content, {
- from: args.path,
- to: outdir,
- })
- // built-in loaders: js, jsx, ts, tsx, css, json, text, base64, dataurl, file, binary
- return { contents: css, loader: "text" }
- }
- )
- },
- },
- ],
- })
-
- // watch and serve
- if (watch || serve) {
- if (watch) await ctx.watch()
- if (serve) {
- // generate app props based on package.json and secretProps.json
- await fs.writeFile(
- `./${outdir}/appProps.js`,
- `export default ${JSON.stringify(appProps())}`
- )
-
- let { host, port } = await ctx.serve({
- host: "0.0.0.0",
- port: parseInt(process.env.APP_PORT || process.env.PORT || 3000),
- servedir: "public",
- })
- console.log("serve on", `${host}:${port}`)
- }
- } else {
- await ctx.rebuild()
- await ctx.dispose()
- }
-}
-
-build()
diff --git a/apps/greenhouse-management/jest.config.js b/apps/greenhouse-management/jest.config.js
deleted file mode 100644
index cdc33f045..000000000
--- a/apps/greenhouse-management/jest.config.js
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-module.exports = {
- transform: { "\\.[jt]sx?$": "babel-jest" },
- testEnvironment: "jsdom",
- setupFilesAfterEnv: ["/setupTests.js"],
- transformIgnorePatterns: [
- "node_modules/(?!(juno-ui-components|url-state-router|communicator|oauth|url-state-provider|messages-provider|policy-engine)/)",
- ],
- moduleNameMapper: {
- // Jest currently doesn't support resources with query parameters.
- // Therefore we add the optional query parameter matcher at the end
- // https://github.com/facebook/jest/issues/4181
- "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)(\\?.+)?$":
- require.resolve("./__mocks__/fileMock"),
- "\\.(css|less|scss)$": require.resolve("./__mocks__/styleMock"),
- },
-}
diff --git a/apps/greenhouse-management/package.json b/apps/greenhouse-management/package.json
deleted file mode 100644
index 726518edb..000000000
--- a/apps/greenhouse-management/package.json
+++ /dev/null
@@ -1,118 +0,0 @@
-{
- "name": "greenhouse-management",
- "version": "1.1.13",
- "managementPluginConfig": {
- "clusters": {
- "label": "Clusters",
- "name": "greenhouse-cluster-admin",
- "version": "1.6.7"
- },
- "teams": {
- "label": "Teams",
- "name": "greenhouse-team-admin",
- "version": "1.5.2"
- },
- "plugins": {
- "label": "Plugins",
- "name": "greenhouse-plugin-admin",
- "version": "1.0.7"
- }
- },
- "author": "UI-Team",
- "contributors": [
- "Arturo Reuschenbach Puncernau",
- "Tillman Haupt"
- ],
- "repository": "https://github.com/sapcc/juno/tree/main/apps/greenhouse-management",
- "license": "MIT",
- "source": "src/index.js",
- "module": "build/index.js",
- "private": true,
- "devDependencies": {
- "@babel/core": "^7.20.2",
- "@babel/preset-env": "^7.20.2",
- "@babel/preset-react": "^7.18.6",
- "@svgr/core": "^7.0.0",
- "@svgr/plugin-jsx": "^7.0.0",
- "@tanstack/react-query": "4.28.0",
- "@testing-library/dom": "^8.19.0",
- "@testing-library/jest-dom": "^5.16.5",
- "@testing-library/react": "^13.4.0",
- "@testing-library/user-event": "^14.4.3",
- "assert": "^2.0.0",
- "autoprefixer": "^10.4.2",
- "babel-jest": "^29.3.1",
- "babel-plugin-transform-import-meta": "^2.2.0",
- "jest": "^29.3.1",
- "jest-environment-jsdom": "^29.3.1",
- "juno-ui-components": "*",
- "luxon": "^2.3.0",
- "messages-provider": "*",
- "postcss": "^8.4.21",
- "postcss-url": "^10.1.3",
- "prop-types": "^15.8.1",
- "react": "18.2.0",
- "react-dom": "^18.2.0",
- "react-test-renderer": "^18.2.0",
- "sapcc-k8sclient": "^1.0.2",
- "sass": "^1.60.0",
- "shadow-dom-testing-library": "^1.7.1",
- "tailwindcss": "^3.3.1",
- "url-state-provider": "*",
- "util": "^0.12.4",
- "utils": "*",
- "zustand": "4.3.7",
- "esbuild": "^0.19.5"
- },
- "scripts": {
- "test": "jest",
- "start": "NODE_ENV=development node esbuild.config.js --serve --watch",
- "build": "NODE_ENV=production node esbuild.config.js"
- },
- "peerDependencies": {
- "@tanstack/react-query": "4.28.0",
- "juno-ui-components": "*",
- "luxon": "^2.3.0",
- "messages-provider": "*",
- "prop-types": "^15.8.1",
- "react": "18.2.0",
- "react-dom": "^18.2.0",
- "url-state-provider": "*",
- "utils": "*",
- "zustand": "4.3.7"
- },
- "importmapExtras": {
- "zustand/middleware": "4.3.7"
- },
- "appProps": {
- "theme": {
- "value": "theme-dark",
- "type": "optional",
- "description": "Override the default theme. Possible values are theme-light or theme-dark (default)"
- },
- "assetsUrl": {
- "value": "URL to the assets server",
- "type": "required",
- "description": "This value is usually set by the Widget Loader. However, if this app is loaded via import or importShim, then this props parameter should be set."
- },
- "apiEndpoint": {
- "value": "",
- "type": "required",
- "description": "Endpoint URL of the API"
- },
- "embedded": {
- "value": "false",
- "type": "optional",
- "description": "Set to true if app is to be embedded in another existing app or page, like e.g. Elektra. If set to true the app won't render a page header/footer and instead render only the content. The default value is false."
- },
- "environment": {
- "value": "production",
- "type": "optional",
- "description": "environment name, e.g. production, qa, development, etc. This property can be used to load different plugins for different environments."
- }
- },
- "appDependencies": {
- "auth": "latest"
- },
- "appPreview": true
-}
\ No newline at end of file
diff --git a/apps/greenhouse-management/public/favicon-16x16.png b/apps/greenhouse-management/public/favicon-16x16.png
deleted file mode 100644
index 7e9bcaa7f..000000000
Binary files a/apps/greenhouse-management/public/favicon-16x16.png and /dev/null differ
diff --git a/apps/greenhouse-management/public/favicon-32x32.png b/apps/greenhouse-management/public/favicon-32x32.png
deleted file mode 100644
index dfe0b8018..000000000
Binary files a/apps/greenhouse-management/public/favicon-32x32.png and /dev/null differ
diff --git a/apps/greenhouse-management/public/favicon.ico b/apps/greenhouse-management/public/favicon.ico
deleted file mode 100644
index 3effd3438..000000000
Binary files a/apps/greenhouse-management/public/favicon.ico and /dev/null differ
diff --git a/apps/greenhouse-management/public/index.html b/apps/greenhouse-management/public/index.html
deleted file mode 100644
index acf58ccd9..000000000
--- a/apps/greenhouse-management/public/index.html
+++ /dev/null
@@ -1,68 +0,0 @@
-
-
-
-
-
-
-
-
-
-
- Template Dev
-
-
-
-
-
-
-
-
diff --git a/apps/greenhouse-management/secretProps.template.json b/apps/greenhouse-management/secretProps.template.json
deleted file mode 100644
index 1b12d4815..000000000
--- a/apps/greenhouse-management/secretProps.template.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "assetsUrl": "https://assets.server.com/",
- "endpoint": "https://endpoint/api/v1",
- "appDependencies": {
- "auth": {
- "authIssuerUrl": "https://auth.backend.com/",
- "authClientId": "clientId"
- }
- }
-}
diff --git a/apps/greenhouse-management/setupTests.js b/apps/greenhouse-management/setupTests.js
deleted file mode 100644
index db44c9038..000000000
--- a/apps/greenhouse-management/setupTests.js
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-// jest-dom adds custom jest matchers for asserting on DOM nodes.
-// allows you to do things like:
-// expect(element).toHaveTextContent(/react/i)
-// learn more: https://github.com/testing-library/jest-dom
-import "@testing-library/jest-dom"
diff --git a/apps/greenhouse-management/src/App.js b/apps/greenhouse-management/src/App.js
deleted file mode 100644
index f3172b51c..000000000
--- a/apps/greenhouse-management/src/App.js
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import React from "react"
-
-import {
- AppBody,
- AppShellProvider,
- MainContainer,
- MainContainerInner,
- ContentContainer,
-} from "juno-ui-components"
-import StoreProvider from "./components/StoreProvider"
-import UrlState from "./components/UrlState"
-
-import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
-import AppContent from "./AppContent"
-import styles from "./styles.scss"
-import OrgInfo from "./components/OrgInfo"
-import SideNav from "./components/SideNav"
-import AsyncWorker from "./components/AsyncWorker"
-import { MessagesProvider, Messages } from "messages-provider"
-import Auth from "./components/Auth"
-
-const App = (props = {}) => {
- // to be deleted
- const queryClient = new QueryClient({
- defaultOptions: {
- queries: {
- meta: {
- endpoint: props.endpoint || props.currentHost || "",
- },
- },
- },
- })
-
- // support only embeded mode for now. This will probably never be started standalone
- // page layout is copied from juno-ui-components/src/components/AppShell/AppShell.component.js
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- )
-}
-
-const StyledApp = (props) => {
- return (
-
-
-
-
-
-
-
-
- )
-}
-
-export default StyledApp
diff --git a/apps/greenhouse-management/src/App.test.js b/apps/greenhouse-management/src/App.test.js
deleted file mode 100644
index 3605e4c6b..000000000
--- a/apps/greenhouse-management/src/App.test.js
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import React from "react"
-import { render, act } from "@testing-library/react"
-// support shadow dom queries
-// https://reactjsexample.com/an-extension-of-dom-testing-library-to-provide-hooks-into-the-shadow-dom/
-import { screen } from "shadow-dom-testing-library"
-import App from "./App"
-
-test("renders app", async () => {
- await act(() => render())
-
- expect(screen.getByShadowTestId("greenhouse-management")).toBeInTheDocument()
-
-})
diff --git a/apps/greenhouse-management/src/AppContent.js b/apps/greenhouse-management/src/AppContent.js
deleted file mode 100644
index 585902d70..000000000
--- a/apps/greenhouse-management/src/AppContent.js
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import React, { useLayoutEffect } from "react"
-import PluginContainer from "./components/PluginContainer"
-import { useApiEndpoint, useAssetsUrl } from "./components/StoreProvider"
-import { useActions as messageActions } from "messages-provider"
-import { Container } from "juno-ui-components"
-
-const AppContent = () => {
- const { addMessage } = messageActions()
- const apiEndpoint = useApiEndpoint()
- const assetsUrl = useAssetsUrl()
-
- useLayoutEffect(() => {
- if (!apiEndpoint) {
- addMessage({
- variant: "warning",
- text: " required api endpoint not set",
- })
- }
-
- if (!assetsUrl) {
- addMessage({
- variant: "warning",
- text: "required assets url not set",
- })
- }
-
- // Make these two props required
- // if a required prop is missing do not set the assetsUrl and no plugin will be loaded
- if (!apiEndpoint || !assetsUrl) return
- }, [])
-
- return (
-
-
-
- )
-}
-
-export default AppContent
diff --git a/apps/greenhouse-management/src/assets/.gitkeep b/apps/greenhouse-management/src/assets/.gitkeep
deleted file mode 100644
index e69de29bb..000000000
diff --git a/apps/greenhouse-management/src/assets/juno-danger.svg b/apps/greenhouse-management/src/assets/juno-danger.svg
deleted file mode 100644
index cb8cfcd53..000000000
--- a/apps/greenhouse-management/src/assets/juno-danger.svg
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
\ No newline at end of file
diff --git a/apps/greenhouse-management/src/assets/map.svg b/apps/greenhouse-management/src/assets/map.svg
deleted file mode 100644
index 936f0f29b..000000000
--- a/apps/greenhouse-management/src/assets/map.svg
+++ /dev/null
@@ -1,4421 +0,0 @@
-
-
-
-
-
diff --git a/apps/greenhouse-management/src/assets/rocket.gif b/apps/greenhouse-management/src/assets/rocket.gif
deleted file mode 100644
index 6edcdce74..000000000
Binary files a/apps/greenhouse-management/src/assets/rocket.gif and /dev/null differ
diff --git a/apps/greenhouse-management/src/components/AsyncWorker.jsx b/apps/greenhouse-management/src/components/AsyncWorker.jsx
deleted file mode 100644
index 637f47ed8..000000000
--- a/apps/greenhouse-management/src/components/AsyncWorker.jsx
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import React from "react"
-import useUrlState from "../hooks/useUrlState"
-import useCommunication from "../hooks/useCommunication"
-
-const AsyncWorker = () => {
- useUrlState()
- useCommunication()
- return null
-}
-
-export default AsyncWorker
diff --git a/apps/greenhouse-management/src/components/Auth.jsx b/apps/greenhouse-management/src/components/Auth.jsx
deleted file mode 100644
index 3c730ffaa..000000000
--- a/apps/greenhouse-management/src/components/Auth.jsx
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import React from "react"
-import { useIsLoggedIn } from "./StoreProvider"
-import HintLoading from "./shared/HintLoading"
-
-// Adds a loading screen while during auth
-// Shows children when auth is complete
-const Auth = ({ children }) => {
- const authLoggedIn = useIsLoggedIn()
-
- return (
- <>
- {!!authLoggedIn ? (
- children
- ) : (
-
- )}
- >
- )
-}
-
-export default Auth
diff --git a/apps/greenhouse-management/src/components/OrgInfo.jsx b/apps/greenhouse-management/src/components/OrgInfo.jsx
deleted file mode 100644
index 01e0206af..000000000
--- a/apps/greenhouse-management/src/components/OrgInfo.jsx
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import React, { useMemo, useEffect, useState } from "react"
-import { createClient } from "sapcc-k8sclient"
-import { useApiEndpoint, useAuthData } from "./StoreProvider"
-import { useActions } from "messages-provider"
-
-// Shows organization info
-
-const OrgInfo = () => {
- const apiEndpoint = useApiEndpoint()
- const [org, setOrg] = useState(null)
- const { addMessage } = useActions()
-
- const authData = useAuthData()
-
- const orgName = useMemo(() => {
- if (!authData?.raw?.groups) return null
- const orgString = authData?.raw?.groups.find(
- (g) => g.indexOf("organization:") === 0
- )
- if (!orgString) return null
- return orgString.split(":")[1]
- }, [authData?.raw?.groups])
-
- const client = useMemo(() => {
- if (!apiEndpoint || !authData?.JWT) return null
- return createClient({ apiEndpoint, token: authData?.JWT })
- }, [apiEndpoint, authData?.JWT])
-
- useEffect(() => {
- if (!client || !orgName) return
- // plugin configs
- client
- .get(`/apis/greenhouse.sap/v1alpha1/organizations/${orgName}`)
- .then((res) => {
- setOrg({
- name: res?.spec?.displayName,
- description: res?.spec?.description,
- })
- })
- .catch((err) => {
- addMessage({
- variant: "error",
- text: `Failed to fetch organization info. ${err.message}`,
- })
- })
- }, [client, orgName])
-
- return (
-
-
-
Organization
- {org?.name &&
{org?.name}
}
- {!org?.name &&
Loading...
}
-
- {org?.description && (
-
{org?.description}
- )}
- {!org?.name && }
- {/*
-
-
Thing 1
-
- 23
-
-
-
-
-
Thing 2
-
- 42
-
-
-
-
-
Thing 3
-
- 4711
-
-
-
*/}
-
- )
-}
-
-export default OrgInfo
diff --git a/apps/greenhouse-management/src/components/Plugin.jsx b/apps/greenhouse-management/src/components/Plugin.jsx
deleted file mode 100644
index 1f1e06d1d..000000000
--- a/apps/greenhouse-management/src/components/Plugin.jsx
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import React, { useEffect, useMemo, useRef, useState } from "react"
-import { useAppLoader } from "utils"
-import { useAssetsUrl, usePluginActive } from "./StoreProvider"
-import { Messages, useActions } from "messages-provider"
-import { parseError } from "../lib/helpers"
-import { Stack, Button } from "juno-ui-components"
-import HintLoading from "./shared/HintLoading"
-
-const Plugin = ({ config }) => {
- const { addMessage } = useActions()
- const assetsUrl = useAssetsUrl()
- const { mount } = useAppLoader(assetsUrl)
- const holder = useRef()
- const activePlugin = usePluginActive()
-
- // local state
- const [displayReload, setDisplayReload] = useState(false)
- const [reload, setReload] = useState(0)
- const [isMountedApp, setIsMountedApp] = useState(false)
-
- // element to mount the app
- const el = document.createElement("div")
- el.classList.add("inline")
- const app = useRef(el)
-
- // mount the app each time the component is reloaded losing the state
- useEffect(() => {
- if (!mount || !assetsUrl || !config) return
- // mount the app
- mount(app.current, config)
- .then((loaded) => {
- if (!loaded) return
- setIsMountedApp(true)
- })
- .catch((error) => {
- setDisplayReload(true)
- addMessage({
- variant: "error",
- text: `${config?.name}: ` + parseError(error),
- })
- })
- }, [mount, reload, config, assetsUrl])
-
- const displayPluging = useMemo(
- () => activePlugin === config?.name,
- [activePlugin, config]
- )
-
- useEffect(() => {
- // if assetsUrl still null when rendering for first time the component then mountApp also return null and we skip here
- if (!isMountedApp) return
-
- if (displayPluging) {
- // append to holder
- holder.current.appendChild(app.current)
- } else {
- // remove from holder
- if (holder.current.contains(app.current))
- holder.current.removeChild(app.current)
- }
- }, [isMountedApp, displayPluging])
-
- return (
-
- Uh-oh! Our plugin {config?.label} encountered a hiccup.{" "}
-
-
- No worries, just give it a little nudge by clicking the{" "}
- Reload button below.
-
-
- )}
- >
- )}
-
- )
-}
-
-export default Plugin
diff --git a/apps/greenhouse-management/src/components/PluginContainer.jsx b/apps/greenhouse-management/src/components/PluginContainer.jsx
deleted file mode 100644
index 45d7f8b04..000000000
--- a/apps/greenhouse-management/src/components/PluginContainer.jsx
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import React, { useState } from "react"
-import { Container } from "juno-ui-components"
-import { usePluginConfig } from "./StoreProvider"
-import Plugin from "./Plugin"
-import { MessagesProvider } from "messages-provider"
-
-const PluginContainer = () => {
- const pluginConfig = usePluginConfig()
-
- return (
- <>
- {Object.keys(pluginConfig).map((key, index) => (
-
-
-
- ))}
- >
- )
-}
-
-export default PluginContainer
diff --git a/apps/greenhouse-management/src/components/SideNav.js b/apps/greenhouse-management/src/components/SideNav.js
deleted file mode 100644
index 26a9b14c5..000000000
--- a/apps/greenhouse-management/src/components/SideNav.js
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import React from "react"
-import { SideNavigation, SideNavigationItem } from "juno-ui-components"
-import { usePluginConfig, usePluginActive, useActions } from "./StoreProvider"
-
-const SideNav = () => {
- const pluginConfig = usePluginConfig()
- const pluginActive = usePluginActive()
- const { setPluginActive } = useActions()
-
- return (
-
- {Object.keys(pluginConfig).map((key, index) => (
- setPluginActive(pluginConfig[key]?.name)}
- />
- ))}
-
- )
-}
-
-export default SideNav
diff --git a/apps/greenhouse-management/src/components/StoreProvider.js b/apps/greenhouse-management/src/components/StoreProvider.js
deleted file mode 100644
index 58596117a..000000000
--- a/apps/greenhouse-management/src/components/StoreProvider.js
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import React, { createContext, useContext } from "react"
-import { useStore as create } from "zustand"
-import createStore from "../lib/store"
-
-const StoreContext = createContext()
-const StoreProvider = ({ options, children }) => (
-
- {children}
-
-)
-
-const useAppStore = (selector) => create(useContext(StoreContext), selector)
-
-export const useIsUrlStateSetup = () =>
- useAppStore((state) => state.isUrlStateSetup)
-export const useAssetsUrl = () => useAppStore((state) => state.assetsUrl)
-export const usePluginConfig = () => useAppStore((state) => state.pluginConfig)
-export const usePluginActive = () => useAppStore((state) => state.pluginActive)
-export const useApiEndpoint = () => useAppStore((state) => state.apiEndpoint)
-export const useAuthData = () => useAppStore((state) => state.authData.data)
-export const useAuthAppLoaded = () =>
- useAppStore((state) => state.authAppLoaded)
-export const useIsLoggedIn = () =>
- useAppStore((state) => state.authData.loggedIn)
-
-export const useActions = () => useAppStore((state) => state.actions)
-
-export default StoreProvider
diff --git a/apps/greenhouse-management/src/components/UrlState.jsx b/apps/greenhouse-management/src/components/UrlState.jsx
deleted file mode 100644
index ba0316bdd..000000000
--- a/apps/greenhouse-management/src/components/UrlState.jsx
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import React from "react"
-import HintLoading from "./shared/HintLoading"
-import { useIsUrlStateSetup } from "./StoreProvider"
-
-const UrlState = ({ children }) => {
- const isUrlStateSetup = useIsUrlStateSetup()
-
- return (
- <>
- {isUrlStateSetup ? children : }
- >
- )
-}
-
-export default UrlState
diff --git a/apps/greenhouse-management/src/components/shared/HintLoading.js b/apps/greenhouse-management/src/components/shared/HintLoading.js
deleted file mode 100644
index b4091b753..000000000
--- a/apps/greenhouse-management/src/components/shared/HintLoading.js
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import React, { useMemo } from "react"
-import { Stack, Spinner } from "juno-ui-components"
-
-const centeredProps = {
- alignment: "center",
- distribution: "center",
- direction: "vertical",
- className: "h-full",
-}
-
-const HintLoading = ({ text, centered }) => {
- const stackProps = useMemo(() => {
- return centered ? centeredProps : {}
- }, [centered])
-
- return (
-
-
-
- {text ? {text} : Loading...}
-
-
- )
-}
-
-export default HintLoading
diff --git a/apps/greenhouse-management/src/hooks/.gitkeep b/apps/greenhouse-management/src/hooks/.gitkeep
deleted file mode 100644
index e69de29bb..000000000
diff --git a/apps/greenhouse-management/src/hooks/useCommunication.js b/apps/greenhouse-management/src/hooks/useCommunication.js
deleted file mode 100644
index 7e1e7390b..000000000
--- a/apps/greenhouse-management/src/hooks/useCommunication.js
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import { useEffect } from "react"
-import { get, watch } from "communicator"
-import { useActions } from "../components/StoreProvider"
-
-const useCommunication = () => {
- const { setAuthData: setAuthData } = useActions()
- const { setAuthAppLoaded: setAuthAppLoaded } = useActions()
-
- useEffect(() => {
- if (!setAuthData || !setAuthAppLoaded) return
- get("AUTH_APP_LOADED", setAuthAppLoaded, {
- consumerID: "greenhouse-management",
- debug: true,
- })
- const unwatchLoaded = watch("AUTH_APP_LOADED", setAuthAppLoaded, {
- debug: true,
- consumerID: "greenhouse-management",
- })
-
- get("AUTH_GET_DATA", setAuthData, {
- consumerID: "greenhouse-management",
- debug: true,
- })
- const unwatchUpdate = watch("AUTH_UPDATE_DATA", setAuthData, {
- debug: true,
- consumerID: "greenhouse-management",
- })
-
- return () => {
- if (unwatchLoaded) unwatchLoaded()
- if (unwatchUpdate) unwatchUpdate()
- }
- }, [setAuthData, setAuthAppLoaded])
-}
-
-export default useCommunication
diff --git a/apps/greenhouse-management/src/hooks/useUrlState.js b/apps/greenhouse-management/src/hooks/useUrlState.js
deleted file mode 100644
index 22377a222..000000000
--- a/apps/greenhouse-management/src/hooks/useUrlState.js
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import { useEffect, useLayoutEffect } from "react"
-import { registerConsumer } from "url-state-provider"
-import {
- useActions,
- useIsUrlStateSetup,
- usePluginActive,
- useIsLoggedIn,
-} from "../components/StoreProvider"
-
-// url state manager
-const URL_APP_STATE_KEY = "greenhouse-management"
-const ACTIVE_APP_KEY = "a"
-const urlStateManager = registerConsumer(URL_APP_STATE_KEY)
-
-const useUrlState = () => {
- const { setPluginActive, setIsUrlStateSetup } = useActions()
- const isUrlStateSetup = useIsUrlStateSetup()
- const pluginActive = usePluginActive()
- const isLoggedIn = useIsLoggedIn()
-
- // Initial state from URL AFTER
- // WARNING. To get the right state from the URL do following:
- // If this app is embbeded in another app with authentication
- // - Mount this app after the login is success in the parent app
- // or
- // - Wait here until you get logged in
- useLayoutEffect(() => {
- if (!isLoggedIn || isUrlStateSetup) return
-
- let active = urlStateManager.currentState()?.[ACTIVE_APP_KEY]
- if (active) setPluginActive(active)
- setIsUrlStateSetup(true)
- }, [isUrlStateSetup, isLoggedIn])
-
- // sync URL state
- useEffect(() => {
- if (!isUrlStateSetup) return
-
- // if the current state is the same as the new state, don't push
- // this prevents the history from being filled with the same state
- // and therefore prevents the forward button from being disabled
- // This small optimization allows the user to go back and forth!
- if (urlStateManager.currentState()?.[ACTIVE_APP_KEY] === pluginActive)
- return
-
- urlStateManager.push({ [ACTIVE_APP_KEY]: pluginActive })
- }, [isUrlStateSetup, pluginActive])
-}
-
-export default useUrlState
diff --git a/apps/greenhouse-management/src/index.js b/apps/greenhouse-management/src/index.js
deleted file mode 100644
index f6f988315..000000000
--- a/apps/greenhouse-management/src/index.js
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import { createRoot } from "react-dom/client"
-import React from "react"
-
-// export mount and unmount functions
-export const mount = (container, options = {}) => {
- import("./App").then((App) => {
- mount.root = createRoot(container)
- mount.root.render(React.createElement(App.default, options?.props))
- })
-}
-
-export const unmount = () => mount.root && mount.root.unmount()
diff --git a/apps/greenhouse-management/src/lib/helpers.js b/apps/greenhouse-management/src/lib/helpers.js
deleted file mode 100644
index 531d03702..000000000
--- a/apps/greenhouse-management/src/lib/helpers.js
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-export const parseError = (error) => {
- let errMsg = JSON.stringify(error)
- if (error?.message) {
- errMsg = error?.message
- try {
- errMsg = JSON.parse(error?.message).msg
- } catch (error) {}
- }
- return errMsg
-}
diff --git a/apps/greenhouse-management/src/lib/store.js b/apps/greenhouse-management/src/lib/store.js
deleted file mode 100644
index cd1a3c95b..000000000
--- a/apps/greenhouse-management/src/lib/store.js
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import { createStore } from "zustand"
-import { devtools } from "zustand/middleware"
-import { managementPluginConfig } from "../../package.json"
-import { useActions as messageActions } from "messages-provider"
-
-export default (options) => {
- // check the managementPluginConfig is an object and not array or string
- const { addMessage } = messageActions()
- let configs = managementPluginConfig
-
- // check if the managementPluginConfig is an object with key values
- if (
- typeof configs !== "object" ||
- Array.isArray(configs) ||
- Object.keys(configs).length === 0
- ) {
- configs = {}
- addMessage({
- variant: "error",
- text: "managementPluginConfig is not an object with key values in the package.json",
- })
- }
-
- // set the endpoint and embedded props for the management plugin coming from the package.json
- Object.keys(configs).forEach((key) => {
- // pull latest version in dev and qa
- configs[key].version = options.environment =='qa' || options.environment == 'development' ? 'latest' : configs[key].version
- configs[key].props = {
- endpoint: options.apiEndpoint,
- embedded: true,
- }
- })
-
- return createStore(
- devtools((set, get) => ({
- isUrlStateSetup: false,
- assetsUrl: options.assetsUrl,
- apiEndpoint: options.apiEndpoint,
- pluginConfig: configs,
- authData: {
- loggedIn: false,
- error: null,
- data: null,
- },
- authAppLoaded: false,
- pluginActive: "greenhouse-cluster-admin", // name of the active plugin default
-
- actions: {
- setPluginActive: (pluginId) => {
- // find the pluginConfig which plugin name matches the plugin id
- const plugin = Object.values(get().pluginConfig).find(
- (plugin) => plugin.name === pluginId
- )
- if (!plugin) return
-
- set(
- (state) => {
- state.pluginActive = plugin.name
- },
- false,
- "setPluginActive"
- )
- },
- setIsUrlStateSetup: (isSetup) =>
- set(
- (state) => {
- state.isUrlStateSetup = isSetup
- },
- false,
- "setIsUrlStateSetup"
- ),
- setAuthData: (data) =>
- set(
- (state) => ({
- authData: {
- ...state.auth,
- loggedIn: data ? data.loggedIn : false,
- error: data ? data.error : null,
- data: data ? data.auth : null,
- },
- }),
- false,
- "setAuthData"
- ),
- setAuthAppLoaded: (loaded) =>
- set(
- (state) => {
- state.authAppLoaded = loaded
- },
- false,
- "setAuthAppLoaded"
- ),
- },
- }))
- )
-}
diff --git a/apps/greenhouse-management/src/styles.scss b/apps/greenhouse-management/src/styles.scss
deleted file mode 100644
index 8e3a75e65..000000000
--- a/apps/greenhouse-management/src/styles.scss
+++ /dev/null
@@ -1,20 +0,0 @@
-// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
-// SPDX-License-Identifier: Apache-2.0
-
-/* Do not remove these tailwind directives. Without them styles won't work as expected */
-@tailwind base;
-@tailwind components;
-@tailwind utilities;
-
-
-/* If necessary, app styles can be added below */
-
-.svg-bg-test {
- background: url('assets/juno-danger.svg')
-}
-
-// .svg-bg-test-big-file {
-// background: left 80px no-repeat url('assets/map.svg')
-// }
-
-
diff --git a/apps/greenhouse-management/tailwind.config.js b/apps/greenhouse-management/tailwind.config.js
deleted file mode 100644
index 81b1f8fef..000000000
--- a/apps/greenhouse-management/tailwind.config.js
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-// opacity helper to make custom colors work with opacity
-function withOpacity(variableName) {
- return ({ opacityVariable, opacityValue }) => {
- if (opacityValue !== undefined) {
- return `rgba(var(${variableName}), ${opacityValue})`
- }
- if (opacityVariable !== undefined) {
- return `rgba(var(${variableName}), var(${opacityVariable}, 1))`
- }
- return `rgb(var(${variableName}))`
- }
-}
-
-module.exports = {
- presets: [
- require("juno-ui-components/build/lib/tailwind.config"), // important, do not change
- ],
- prefix: "", // important, do not change
- content: ["./src/**/*.{js,jsx,ts,tsx}", "./public/index.html"],
- corePlugins: {
- preflight: false, // important, do not change
- },
- theme: {},
- plugins: [],
-}
diff --git a/apps/greenhouse/.gitignore b/apps/greenhouse/.gitignore
deleted file mode 100644
index dbaccf123..000000000
--- a/apps/greenhouse/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-*.plugin.config.yaml
diff --git a/apps/greenhouse/LICENSE b/apps/greenhouse/LICENSE
deleted file mode 100644
index 261eeb9e9..000000000
--- a/apps/greenhouse/LICENSE
+++ /dev/null
@@ -1,201 +0,0 @@
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/apps/greenhouse/README.md b/apps/greenhouse/README.md
deleted file mode 100644
index 055d183d9..000000000
--- a/apps/greenhouse/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# Greenhouse App
-
-This is the shell app for Project Greenhouse. It is the host for all apps that are part of Greenhouse.
diff --git a/apps/greenhouse/__mocks__/client.js b/apps/greenhouse/__mocks__/client.js
deleted file mode 100644
index 84531d3c2..000000000
--- a/apps/greenhouse/__mocks__/client.js
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import { JSDOM } from "jsdom"
-const dom = new JSDOM()
-global.document = dom.window.document
-global.window = dom.window
diff --git a/apps/greenhouse/__mocks__/styleMock.js b/apps/greenhouse/__mocks__/styleMock.js
deleted file mode 100644
index d74516001..000000000
--- a/apps/greenhouse/__mocks__/styleMock.js
+++ /dev/null
@@ -1,6 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-module.exports = {}
diff --git a/apps/greenhouse/babel.config.js b/apps/greenhouse/babel.config.js
deleted file mode 100644
index 0719e2fec..000000000
--- a/apps/greenhouse/babel.config.js
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-module.exports = {
- env: {
- test: {
- presets: ["@babel/preset-env", "@babel/preset-react"],
- plugins: [["babel-plugin-transform-import-meta", { module: "ES6" }]],
- },
- },
-}
diff --git a/apps/greenhouse/esbuild.config.js b/apps/greenhouse/esbuild.config.js
deleted file mode 100644
index 2394388b8..000000000
--- a/apps/greenhouse/esbuild.config.js
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-const esbuild = require("esbuild")
-const fs = require("node:fs/promises")
-const pkg = require("./package.json")
-const postcss = require("postcss")
-const sass = require("sass")
-const { transform } = require("@svgr/core")
-const url = require("postcss-url")
-// this function generates app props based on package.json and propSecrets.json
-const appProps = require("../../helpers/appProps")
-
-if (!/.+\/.+\.js/.test(pkg.module))
- throw new Error(
- "module value is incorrect, use DIR/FILE.js like build/index.js"
- )
-
-const isProduction = process.env.NODE_ENV === "production"
-// If the jspm server fails and we cannot use external packages
-// in our import map then IGNORE_EXTERNALS (global env variable)
-// should be set to true
-const IGNORE_EXTERNALS = process.env.IGNORE_EXTERNALS === "true"
-// in dev environment we prefix output file with public
-let outfile = `${isProduction ? "" : "public/"}${pkg.main || pkg.module}`
-// get output from outputfile
-let outdir = outfile.slice(0, outfile.lastIndexOf("/"))
-const args = process.argv.slice(2)
-const watch = args.indexOf("--watch") >= 0
-const serve = args.indexOf("--serve") >= 0
-
-// helpers for console log
-const green = "\x1b[32m%s\x1b[0m"
-const yellow = "\x1b[33m%s\x1b[0m"
-const clear = "\033c"
-
-const build = async () => {
- // delete build folder and re-create it as an empty folder
- await fs.rm(outdir, { recursive: true, force: true })
- await fs.mkdir(outdir, { recursive: true })
-
- // build app
- let ctx = await esbuild.context({
- bundle: true,
- minify: isProduction,
- // target: ["es2020"],
- target: ["es2020"], //["chrome64", "firefox67", "safari11.1", "edge79"],
- format: "esm",
- platform: "browser",
- // built-in loaders: js, jsx, ts, tsx, css, json, text, base64, dataurl, file, binary
- loader: { ".js": "jsx" },
- sourcemap: !isProduction,
- // here we exclude package from bundle which are defined in peerDependencies
- // our importmap generator uses also the peerDependencies to create the importmap
- // it means all packages defined in peerDependencies are in browser available via the importmap
- external:
- isProduction && !IGNORE_EXTERNALS
- ? Object.keys(pkg.peerDependencies || {})
- : [],
- entryPoints: [pkg.source],
- outdir,
- // this step is important for performance reason.
- // the main file (index.js) contains minimal code needed to
- // load the app via dynamic import (splitting: true)
- splitting: true,
- // we suport only esm!
- format: "esm",
- plugins: [
- // minimal plugin to log the recompiling process.
- {
- name: "start/end",
- setup(build) {
- build.onStart(() => {
- console.log(clear)
- console.log(yellow, "Compiling...")
- })
- build.onEnd(() => console.log(green, "Done!"))
- },
- },
-
- // this custom plugin rewrites SVG imports to
- // dataurls, paths or react components based on the
- // search param and size
- {
- name: "svg-loader",
- setup(build) {
- build.onLoad(
- // consider only .svg files
- { filter: /.\.(svg)$/, namespace: "file" },
- async (args) => {
- let contents = await fs.readFile(args.path)
- // built-in loaders: js, jsx, ts, tsx, css, json, text, base64, dataurl, file, binary
- let loader = "text"
- if (args.suffix === "?url") {
- // as URL
- const maxSize = 10240 // 10Kb
- // use dataurl loader for small files and file loader for big files!
- loader = contents.length <= maxSize ? "dataurl" : "file"
- } else {
- // as react component
- // use react component loader (jsx)
- loader = "jsx"
- contents = await transform(contents, {
- plugins: ["@svgr/plugin-jsx"],
- })
- }
-
- return { contents, loader }
- }
- )
- },
- },
-
- // this custom plugin rewrites image imports to
- // dataurls or urls based on the size
- {
- name: "image-loader",
- setup(build) {
- build.onLoad(
- // consider only .svg files
- { filter: /.\.(png|jpg|jpeg|gif)$/, namespace: "file" },
- async (args) => {
- let contents = await fs.readFile(args.path)
- const maxSize = 10240 // 10Kb
- // built-in loaders: js, jsx, ts, tsx, css, json, text, base64, dataurl, file, binary
- // use dataurl loader for small files and file loader for big files!
- loader = contents.length <= maxSize ? "dataurl" : "file"
-
- return { contents, loader }
- }
- )
- },
- },
-
- // this custom plugin parses the style files
- {
- name: "parse-styles",
- setup(build) {
- build.onLoad(
- // consider only .scss and .css files
- { filter: /.\.(css|scss)$/, namespace: "file" },
- async (args) => {
- let content
- // handle scss, convert to css
- if (args.path.endsWith(".scss")) {
- const result = sass.renderSync({ file: args.path })
- content = result.css
- } else {
- // read file content
- content = await fs.readFile(args.path)
- }
-
- // postcss plugins
- const plugins = [
- require("tailwindcss"),
- require("autoprefixer"),
- // rewrite urls inside css
- url({
- url: "inline",
- // maxSize: 10, // use dataurls if files are smaller than 10k
- // fallback: "copy", // if files are bigger use copy method
- // assetsPath: "./build/assets",
- // useHash: true,
- // optimizeSvgEncode: true,
- }),
- ]
-
- const { css } = await postcss(plugins).process(content, {
- from: args.path,
- to: outdir,
- })
- // built-in loaders: js, jsx, ts, tsx, css, json, text, base64, dataurl, file, binary
- return { contents: css, loader: "text" }
- }
- )
- },
- },
- ],
- })
-
- // watch and serve
- if (watch || serve) {
- if (watch) await ctx.watch()
- if (serve) {
- // generate app props based on package.json and secretProps.json
- await fs.writeFile(
- `./${outdir}/appProps.js`,
- `export default ${JSON.stringify(appProps())}`
- )
-
- let { host, port } = await ctx.serve({
- host: "0.0.0.0",
- port: parseInt(process.env.APP_PORT || process.env.PORT || 3000),
- servedir: "public",
- })
- console.log("serve on", `${host}:${port}`)
- }
- } else {
- await ctx.rebuild()
- await ctx.dispose()
- }
-}
-
-build()
diff --git a/apps/greenhouse/jest.config.js b/apps/greenhouse/jest.config.js
deleted file mode 100644
index 0cb80394c..000000000
--- a/apps/greenhouse/jest.config.js
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-module.exports = {
- transform: { "\\.[jt]sx?$": "babel-jest" },
- testEnvironment: "jsdom",
- setupFilesAfterEnv: ["/setupTests.js"],
- transformIgnorePatterns: [
- "node_modules/(?!(juno-ui-components|communicator)/)",
- ],
- moduleNameMapper: {
- // Jest currently doesn't support resources with query parameters.
- // Therefore we add the optional query parameter matcher at the end
- // https://github.com/facebook/jest/issues/4181
- "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)(\\?.+)?$":
- require.resolve("./__mocks__/fileMock"),
- "\\.(css|less|scss)$": require.resolve("./__mocks__/styleMock"),
- },
-}
diff --git a/apps/greenhouse/package.json b/apps/greenhouse/package.json
deleted file mode 100644
index df0c1778c..000000000
--- a/apps/greenhouse/package.json
+++ /dev/null
@@ -1,121 +0,0 @@
-{
- "name": "greenhouse",
- "version": "0.1.20",
- "managementVersion": "1.1.13",
- "author": "UI-Team",
- "contributors": [
- "Andreas Pfau",
- "Arturo Reuschenbach Puncernau",
- "Esther Schmitz"
- ],
- "repository": "https://github.com/sapcc/juno/tree/main/apps/greenhouse",
- "license": "Apache-2.0",
- "source": "src/index.js",
- "module": "build/index.js",
- "private": true,
- "devDependencies": {
- "@babel/core": "^7.20.2",
- "@babel/preset-env": "^7.20.2",
- "@babel/preset-react": "^7.18.6",
- "@svgr/core": "^7.0.0",
- "@svgr/plugin-jsx": "^7.0.0",
- "@tailwindui/react": "^0.1.1",
- "@testing-library/dom": "^8.19.0",
- "@testing-library/jest-dom": "^5.16.5",
- "@testing-library/react": "^13.4.0",
- "@testing-library/user-event": "^14.4.3",
- "assert": "^2.0.0",
- "autoprefixer": "^10.4.2",
- "babel-jest": "^29.3.1",
- "babel-plugin-transform-import-meta": "^2.2.0",
- "communicator": "*",
- "jest": "^29.3.1",
- "jest-environment-jsdom": "^29.3.1",
- "juno-ui-components": "*",
- "messages-provider": "*",
- "immer": "^9.0.21",
- "postcss": "^8.4.21",
- "postcss-url": "^10.1.3",
- "prop-types": "^15.8.1",
- "react": "18.2.0",
- "react-dom": "^18.2.0",
- "react-test-renderer": "^18.2.0",
- "sapcc-k8sclient": "^1.0.2",
- "sass": "^1.60.0",
- "shadow-dom-testing-library": "^1.7.1",
- "tailwindcss": "^3.3.1",
- "url-state-provider": "*",
- "util": "^0.12.4",
- "utils": "*",
- "zustand": "4.3.7"
- },
- "scripts": {
- "test": "jest",
- "start": "NODE_ENV=development node esbuild.config.js --serve --watch",
- "build": "NODE_ENV=production node esbuild.config.js"
- },
- "peerDependencies": {
- "juno-ui-components": "*",
- "messages-provider": "*",
- "prop-types": "^15.8.1",
- "react": "18.2.0",
- "react-dom": "^18.2.0",
- "url-state-provider": "*",
- "utils": "*",
- "zustand": "4.3.7"
- },
- "importmapExtras": {
- "zustand/middleware": "4.3.7"
- },
- "appProps": {
- "authIssuerUrl": {
- "value": "https://endpoint_url_of_the_openid_provider.com",
- "type": "required",
- "description": "Endpoint URL of the OpenID provider"
- },
- "authClientId": {
- "value": "tbd",
- "type": "required",
- "description": "OIDC client id. "
- },
- "theme": {
- "value": "theme-dark",
- "description": "Override the default theme. Possible values are theme-light or theme-dark (default)"
- },
- "embedded": {
- "value": "false",
- "description": "Set to true if app is to be embedded in another existing app or page, like e.g. Elektra. If set to true the app won't render a page header/footer and instead render only the content"
- },
- "currentHost": {
- "value": "URL TO ASSETS SERVER",
- "type": "required",
- "description": "This value is usually set by the Widget Loader. However, if this app is loaded via import or importShim, then this props parameter should be set."
- },
- "apiEndpoint": {
- "value": "URL TO K8S API",
- "type": "required",
- "description": "This value is necessary to communicate with the Kubernetes API. All the information you need comes from this API."
- },
- "mockAuth": {
- "value": false,
- "type": "optional",
- "description": "mock the OIDC data, allowed values are 'true', 'false' (default), or json (pure or base64 encoded)"
- },
- "demoOrg": {
- "value": "demo",
- "type": "optional",
- "description": "if organization name is equal to this value, then the app will be in demo mode. That means that the authentication will be mocked and plugins are loaded from demo org."
- },
- "demoUserToken": {
- "value": "token for demo user",
- "type": "optional",
- "description": "if both demoOrg and demoUserToken are set and organization name is equal to demoOrg, then this token will be used for authentication."
- },
- "environment": {
- "value": "production",
- "type": "optional",
- "description": "environment name, e.g. production, qa, development, etc. This property can be used to load different plugins for different environments."
- }
- },
- "appPreview": true
-}
\ No newline at end of file
diff --git a/apps/greenhouse/public/android-chrome-192x192.png b/apps/greenhouse/public/android-chrome-192x192.png
deleted file mode 100644
index 5459a8ded..000000000
Binary files a/apps/greenhouse/public/android-chrome-192x192.png and /dev/null differ
diff --git a/apps/greenhouse/public/android-chrome-512x512.png b/apps/greenhouse/public/android-chrome-512x512.png
deleted file mode 100644
index fb06c927e..000000000
Binary files a/apps/greenhouse/public/android-chrome-512x512.png and /dev/null differ
diff --git a/apps/greenhouse/public/apple-touch-icon.png b/apps/greenhouse/public/apple-touch-icon.png
deleted file mode 100644
index c76354909..000000000
Binary files a/apps/greenhouse/public/apple-touch-icon.png and /dev/null differ
diff --git a/apps/greenhouse/public/favicon.ico b/apps/greenhouse/public/favicon.ico
deleted file mode 100644
index 7e28ca348..000000000
Binary files a/apps/greenhouse/public/favicon.ico and /dev/null differ
diff --git a/apps/greenhouse/public/favicon.svg b/apps/greenhouse/public/favicon.svg
deleted file mode 100644
index ebe3eb28d..000000000
--- a/apps/greenhouse/public/favicon.svg
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
diff --git a/apps/greenhouse/public/index.html b/apps/greenhouse/public/index.html
deleted file mode 100644
index 02fcbdbba..000000000
--- a/apps/greenhouse/public/index.html
+++ /dev/null
@@ -1,47 +0,0 @@
-
-
-
-
-
-
-
-
- Greenhouse Dev
-
-
-
-
-
-
-
-
diff --git a/apps/greenhouse/secretProps.template.json b/apps/greenhouse/secretProps.template.json
deleted file mode 100644
index 825e7f86c..000000000
--- a/apps/greenhouse/secretProps.template.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "authIssuerUrl": "https://auth.backend.com/",
- "authClientId": "client-id",
- "currentHost": "https://assets.server.com/",
- "apiEndpoint": "https://api.greenhouse.com/",
- "environment": "dev"
-}
diff --git a/apps/greenhouse/setupTests.js b/apps/greenhouse/setupTests.js
deleted file mode 100644
index db44c9038..000000000
--- a/apps/greenhouse/setupTests.js
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-// jest-dom adds custom jest matchers for asserting on DOM nodes.
-// allows you to do things like:
-// expect(element).toHaveTextContent(/react/i)
-// learn more: https://github.com/testing-library/jest-dom
-import "@testing-library/jest-dom"
diff --git a/apps/greenhouse/src/Shell.js b/apps/greenhouse/src/Shell.js
deleted file mode 100644
index 05102e02f..000000000
--- a/apps/greenhouse/src/Shell.js
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import React, { useLayoutEffect } from "react"
-
-import ShellLayout from "./components/layout/ShellLayout"
-import Auth from "./components/Auth"
-import styles from "./styles.scss"
-import { AppShellProvider } from "juno-ui-components"
-import PluginContainer from "./components/PluginContainer"
-import AsyncWorker from "./components/AsyncWorker"
-import StoreProvider, { useGlobalsActions } from "./components/StoreProvider"
-import { MessagesProvider } from "messages-provider"
-
-const Shell = (props = {}) => {
- const { setApiEndpoint, setAssetsHost, setDemoUserToken, setEnvironment } =
- useGlobalsActions()
-
- // INIT
- // on app initial load save Endpoint and URL_STATE_KEY so it can be
- // used from overall in the application
- useLayoutEffect(() => {
- if (!setApiEndpoint || !setAssetsHost || !setDemoUserToken) return
- // set to empty string to fetch local test data in dev mode
- setEnvironment(props.environment)
- setApiEndpoint(props.apiEndpoint)
- setAssetsHost(props.currentHost)
- setDemoUserToken(props.demoUserToken)
- }, [setApiEndpoint, setAssetsHost, setDemoUserToken])
-
- return (
-
-
-
-
-
- )
-}
-
-const StyledShell = (props) => {
- return (
-
- {/* load styles inside the shadow dom */}
-
-
-
-
-
-
-
-
- )
-}
-
-export default StyledShell
diff --git a/apps/greenhouse/src/Shell.test.js b/apps/greenhouse/src/Shell.test.js
deleted file mode 100644
index e8b0e3ed5..000000000
--- a/apps/greenhouse/src/Shell.test.js
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import React from "react"
-import { render, act } from "@testing-library/react"
-// support shadow dom queries
-// https://reactjsexample.com/an-extension-of-dom-testing-library-to-provide-hooks-into-the-shadow-dom/
-import { screen } from "shadow-dom-testing-library"
-import Shell from "./Shell"
-import Auth from "./components/Auth"
-import StoreProvider from "./components/StoreProvider"
-
-jest.mock("communicator")
-jest.mock("./components/Auth")
-
-test("renders app", async () => {
- await act(() =>
- render(
-
-
-
- )
- )
-
- expect(Auth).toHaveBeenCalled()
-})
diff --git a/apps/greenhouse/src/actions.js b/apps/greenhouse/src/actions.js
deleted file mode 100644
index 4c818af6b..000000000
--- a/apps/greenhouse/src/actions.js
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-const ENDPOINT = "https://endpoint-url-here.com"
-
-class HTTPError extends Error {
- constructor(code, message) {
- super(message || code)
- this.name = "HTTPError"
- this.statusCode = code
- }
-}
-
-const encodeUrlParamsFromObject = (options) => {
- if (!options) return ""
- let encodedOptions = Object.keys(options)
- .map((k) => `${encodeURIComponent(k)}=${encodeURIComponent(options[k])}`)
- .join("&")
- return `&${encodedOptions}`
-}
-
-// Check response status
-const checkStatus = (response) => {
- if (response.status < 400) {
- return response
- } else {
- return response.text().then((message) => {
- var error = new HTTPError(response.status, message || response.statusText)
- error.statusCode = response.status
- return Promise.reject(error)
- })
- }
-}
-
-// Example fetch call. Adjust as needed for your API
-export const exampleFetch = ({ queryKey }) => {
- const [_key, endpoint, options] = queryKey
- const query = encodeUrlParamsFromObject(options)
- return fetch(`${endpoint}/colors.json?${query}`, {
- method: "GET",
- headers: {
- "Content-Type": "application/json",
- Accept: "application/json",
- },
- })
- .then(checkStatus)
- .then((response) => {
- return response.json()
- })
-}
diff --git a/apps/greenhouse/src/assets/ccloud_shape.svg b/apps/greenhouse/src/assets/ccloud_shape.svg
deleted file mode 100644
index 04216ebd0..000000000
--- a/apps/greenhouse/src/assets/ccloud_shape.svg
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
diff --git a/apps/greenhouse/src/assets/greenhouse_logo.svg b/apps/greenhouse/src/assets/greenhouse_logo.svg
deleted file mode 100644
index 785a0527a..000000000
--- a/apps/greenhouse/src/assets/greenhouse_logo.svg
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
diff --git a/apps/greenhouse/src/assets/juno_default_app.svg b/apps/greenhouse/src/assets/juno_default_app.svg
deleted file mode 100644
index cc350ee28..000000000
--- a/apps/greenhouse/src/assets/juno_default_app.svg
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
diff --git a/apps/greenhouse/src/assets/juno_doop.svg b/apps/greenhouse/src/assets/juno_doop.svg
deleted file mode 100644
index ddf2c0308..000000000
--- a/apps/greenhouse/src/assets/juno_doop.svg
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
diff --git a/apps/greenhouse/src/assets/juno_heureka.svg b/apps/greenhouse/src/assets/juno_heureka.svg
deleted file mode 100644
index 9ee687510..000000000
--- a/apps/greenhouse/src/assets/juno_heureka.svg
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
diff --git a/apps/greenhouse/src/assets/juno_supernova.svg b/apps/greenhouse/src/assets/juno_supernova.svg
deleted file mode 100644
index 16781ca3e..000000000
--- a/apps/greenhouse/src/assets/juno_supernova.svg
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
diff --git a/apps/greenhouse/src/components/AsyncWorker.jsx b/apps/greenhouse/src/components/AsyncWorker.jsx
deleted file mode 100644
index de26545c4..000000000
--- a/apps/greenhouse/src/components/AsyncWorker.jsx
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import React, { useEffect } from "react"
-import useUrlState from "../hooks/useUrlState"
-import useCommunication from "../hooks/useCommunication"
-import { useAuthData, useAuthLoggedIn } from "../components/StoreProvider"
-
-const currentUrl = new URL(window.location.href)
-let match = currentUrl.host.match(/^(.+)\.dashboard\..+/)
-let orgName = match ? match[1] : currentUrl.searchParams.get("org")
-
-const AsyncWorker = () => {
- const authData = useAuthData()
- const authLoggedIn = useAuthLoggedIn()
-
- useCommunication()
- useUrlState()
-
- // read org name from token and adjust url to contain the org name
- useEffect(() => {
- if (!authLoggedIn) return
-
- if (!orgName) {
- const orgString = authData?.raw?.groups?.find(
- (g) => g.indexOf("organization:") === 0
- )
-
- if (orgString) {
- const name = orgString.split(":")[1]
- let url = new URL(window.location.href)
- url.searchParams.set("org", name)
- window.history.replaceState(null, null, url.href)
- }
- }
- }, [authLoggedIn, authData])
-
- return null
-}
-
-export default AsyncWorker
diff --git a/apps/greenhouse/src/components/Auth.jsx b/apps/greenhouse/src/components/Auth.jsx
deleted file mode 100644
index 2405a930d..000000000
--- a/apps/greenhouse/src/components/Auth.jsx
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import React, { useEffect, useState, createRef } from "react"
-import { Button, LoadingIndicator, Spinner, Stack } from "juno-ui-components"
-import {
- useAuthAppLoaded,
- useAuthLoggedIn,
- useAuthIsProcessing,
- useAuthError,
- useAuthActions,
- useGlobalsActions,
- useGlobalsAssetsHost,
-} from "../components/StoreProvider"
-import { useAppLoader } from "utils"
-import { useActions } from "messages-provider"
-
-const currentUrl = new URL(window.location.href)
-let match = currentUrl.host.match(/^(.+)\.dashboard\..+/)
-let orgName = match ? match[1] : currentUrl.searchParams.get("org")
-
-/**
- * Auth Component:
- *
- * This component is responsible for managing user authentication and loading the authentication app dynamically.
- * It receives the following props:
- * - clientId: The client ID for authentication.
- * - issuerUrl: The URL of the authentication issuer.
- * - mock: A flag indicating whether to use mock authentication.
- * - children: The content to be displayed when the user is logged in.
- *
- * The component uses custom hooks to handle authentication states and data. It dynamically loads the authentication
- * app via the use of the useAppLoader hook. When mounted, the component connects to the authentication events,
- * allowing seamless authentication experiences.
- *
- * The Auth component renders three main sections:
- * 1. A div element with a data-app attribute set to "greenhouse-auth" and a ref for loading the authentication app.
- * 2. If the user is logged in, the children are rendered.
- * 3. If the user is not logged in, a stack containing loading indicators, messages, and a "Sign in" button is rendered.
- * The component handles various loading states, shows a long loading indicator after 5 seconds, and displays specific
- * messages based on the authentication status.
- *
- * Note: The component reads organization information from the token and adjusts the URL accordingly after the user is logged in.
- */
-const Auth = ({
- clientId,
- issuerUrl,
- mock,
- children,
- demoOrg,
- demoUserToken,
-}) => {
- const assetsHost = useGlobalsAssetsHost()
- const authAppLoaded = useAuthAppLoaded()
- const authLoggedIn = useAuthLoggedIn()
- const authIsProcessing = useAuthIsProcessing()
- const authError = useAuthError()
- const { login } = useAuthActions()
- const { setDemoMode } = useGlobalsActions()
- const { addMessage } = useActions()
-
- const ref = createRef()
- const { mount } = useAppLoader(assetsHost)
- const [loading, setLoading] = useState(!authAppLoaded)
- const [longLoading, setLongLoading] = useState(false)
-
- // in this useEffect we load the auth app via import (see mount)
- // It should happen just once!
- // The connection to the auth events happens in the useCommunication hook!
- // wait until assetsHost is set to avoid a warning on mount
- useEffect(() => {
- if (!assetsHost || !clientId || !issuerUrl) return
-
- // if current orgName is the demo org, we mock the auth app
- if (demoOrg === orgName) {
- // we mock the auth app with default groups
- mock = JSON.stringify({
- groups: ["organization:demo", "role:ccloud:admin"],
- })
- // set demo mode
- // see in useCommunication hook, there we redefine the authData.JWT wit demoUserToken if demo mode is set
- setDemoMode(true)
- }
-
- mount(ref.current, {
- id: "auth",
- name: "auth",
- version: "latest",
- props: {
- issuerUrl: issuerUrl,
- clientId: clientId,
- mock: mock,
- debug: true,
- initialLogin: true,
- requestParams: JSON.stringify({
- connector_id: !orgName ? undefined : orgName,
- }),
- },
- })
- // add mount to the dependencies since it changes depending on the assetsHost
- }, [mount, clientId, issuerUrl, assetsHost])
-
- // timeout for waiting for auth
- useEffect(() => {
- setLoading(!authAppLoaded)
- if (authAppLoaded) return
- // set timeout for waiting for auth app
- let loadingTimer
- if (!authAppLoaded) {
- loadingTimer = setTimeout(() => {
- if (!authAppLoaded) setLoading(false)
- }, 30000) // 30 seconds
- }
-
- return () => loadingTimer && clearTimeout(loadingTimer)
- }, [authAppLoaded, setLoading])
-
- // set long loading
- useEffect(() => {
- let longLoadingTimer = setTimeout(() => setLongLoading(true), 5000) // long loading if longer than 5 seconds
- return () => longLoadingTimer && clearTimeout(longLoadingTimer)
- }, [])
-
- return (
- <>
-
-
- {!!authLoggedIn && children}
-
- {!authLoggedIn && (
-
- {loading || authIsProcessing ? (
- <>
- {longLoading ? (
-
- ) : (
-
- )}
- {loading ? "Loading..." : "Signing on..."}
- >
- ) : (
- <>
- {authAppLoaded ? (
- <>
-
- {authError
- ? "You have been logged out. Please sign in again."
- : "Please sign in before you can use Greenhouse."}
-
-
- >
- ) : (
- "Looks like the auth app is missing!"
- )}
- >
- )}
-
- )}
- >
- )
-}
-
-export default Auth
diff --git a/apps/greenhouse/src/components/Avatar.jsx b/apps/greenhouse/src/components/Avatar.jsx
deleted file mode 100644
index 6e41eb812..000000000
--- a/apps/greenhouse/src/components/Avatar.jsx
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import React from "react"
-import { Stack } from "juno-ui-components"
-
-const avatarCss = `
-h-8
-w-8
-bg-theme-background-lvl-2
-rounded-full
-bg-cover
-`
-
-const Avatar = ({ userName, url }) => {
- return (
-
- {url && (
-
- )}
- {userName && {userName}}
-
- )
-}
-
-export default Avatar
diff --git a/apps/greenhouse/src/components/NotificationsContainer.jsx b/apps/greenhouse/src/components/NotificationsContainer.jsx
deleted file mode 100644
index 61afdffc8..000000000
--- a/apps/greenhouse/src/components/NotificationsContainer.jsx
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import React from "react"
-import { Messages } from "messages-provider"
-import { useDemoMode } from "./StoreProvider"
-
-const NotificationsContainer = () => {
- const demoMode = useDemoMode()
-
- return (
- <>
- {demoMode && (
-
- Welcome to the Greenhouse demo system! We're glad you're here! Just a
- quick heads up: you won't find any live data here. Enjoy exploring!
-
- )}
- {/* do not use a container here to align the messages to the ones coming from each plugin */}
-
- >
- )
-}
-
-export default NotificationsContainer
diff --git a/apps/greenhouse/src/components/Plugin.jsx b/apps/greenhouse/src/components/Plugin.jsx
deleted file mode 100644
index 45ac97e77..000000000
--- a/apps/greenhouse/src/components/Plugin.jsx
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import React, { useEffect, useState, useMemo, useRef } from "react"
-import { useAppLoader } from "utils"
-import { usePlugin, useGlobalsAssetsHost } from "../components/StoreProvider"
-import { Messages, useActions } from "messages-provider"
-import { parseError } from "../lib/helpers"
-import { Stack, Button } from "juno-ui-components"
-
-const Plugin = ({ id }) => {
- const assetsHost = useGlobalsAssetsHost()
- const { mount } = useAppLoader(assetsHost)
- const holder = useRef()
- const config = usePlugin().config()
- const activeApps = usePlugin().active()
- const { addMessage } = useActions()
-
- const [displayReload, setDisplayReload] = useState(false)
- const [reload, setReload] = useState(0)
- const [isMounted, setIsMounted] = useState(false)
-
- // element to mount the app
- const el = document.createElement("div")
- el.classList.add("inline")
- const app = useRef(el)
-
- // mount the app each time the component is reloaded losing the state
- useEffect(() => {
- if (!mount || !assetsHost || !config) return
- // mount the app
- mount(app.current, {
- ...config[id],
- props: { ...config[id]?.props, embedded: true },
- })
- .then((loaded) => {
- if (!loaded) return
- setIsMounted(true)
- })
- .catch((error) => {
- setDisplayReload(true)
- addMessage({
- variant: "error",
- text: `${config?.name}: ` + parseError(error),
- })
- })
- }, [mount, reload, config, assetsHost])
-
- const displayPluging = useMemo(
- () => activeApps.indexOf(id) >= 0,
- [activeApps, config]
- )
-
- useEffect(() => {
- if (!config[id] || !isMounted) return
-
- if (displayPluging) {
- // add to holder
- holder.current.appendChild(app.current)
- } else {
- // remove from holder
- if (holder.current.contains(app.current))
- holder.current.removeChild(app.current)
- }
- }, [isMounted, displayPluging])
-
- return (
-
-
- {item?.Component?.Name}
-
- {item?.State}
-
- )
-}
-
-export default VulnerabilitiesListItem
diff --git a/apps/heureka/src/components/vulnerabilities/VulnerabilitiesTab.jsx b/apps/heureka/src/components/vulnerabilities/VulnerabilitiesTab.jsx
deleted file mode 100644
index f48d1cab5..000000000
--- a/apps/heureka/src/components/vulnerabilities/VulnerabilitiesTab.jsx
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import React from "react"
-import VulnerabilitiesListController from "./VulnerabilitiesListController"
-import Filters from "../filters/Filters"
-
-const VulnerabilitiesTab = () => {
- return (
- <>
-
-
- >
- )
-}
-
-export default VulnerabilitiesTab
diff --git a/apps/heureka/src/helpers.js b/apps/heureka/src/helpers.js
deleted file mode 100644
index 37a89b7d6..000000000
--- a/apps/heureka/src/helpers.js
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import { DateTime } from "luxon"
-
-export const parseError = (error) => {
- if (!error || (typeof error === "object" && Object.keys(error).length === 0))
- return "An error occurred. There is no further information"
- let errMsg = JSON.stringify(error)
- if (error?.message) {
- errMsg = error?.message
- try {
- const msgJson = JSON.parse(error?.message)
- if (msgJson.error) errMsg = msgJson.error
- if (msgJson.msg) errMsg = msgJson.msg
- } catch (error) {}
- }
- return errMsg
-}
-
-export const usersListToString = (users) => {
- if (!users) users = []
- if (!Array.isArray(users)) users = [users]
-
- return users.map((user) => `${user.Name} (${user.SapID})`).join(", ")
-}
-
-export const THREAD_LEVEL_LOW = "low"
-export const THREAD_LEVEL_MEDIUM = "medium"
-export const THREAD_LEVEL_HIGH = "high"
-export const THREAD_LEVEL_CRITICAL = "critical"
-
-export const threadLevelToWeight = (level) => {
- switch (level?.toLowerCase()) {
- case THREAD_LEVEL_LOW:
- return 3
- case THREAD_LEVEL_MEDIUM:
- return 5
- case THREAD_LEVEL_HIGH:
- return 8
- case THREAD_LEVEL_CRITICAL:
- return 10
- }
-}
-
-export const classifyVulnerabilitiesV2 = (vulnerabilites = []) => {
- if (!vulnerabilites) vulnerabilites = []
- if (!Array.isArray(vulnerabilites)) vulnerabilites = [vulnerabilites]
- let severities = { low: 0, medium: 0, high: 0, critical: 0 }
- vulnerabilites.forEach((vulnerability) => {
- // use of ThreatLevelOverall to get the index
- switch (vulnerability?.ThreatLevelOverall?.toLowerCase()) {
- case THREAD_LEVEL_LOW:
- return (severities.low += 1)
- case THREAD_LEVEL_MEDIUM:
- return (severities.medium += 1)
- case THREAD_LEVEL_HIGH:
- return (severities.high += 1)
- case THREAD_LEVEL_CRITICAL:
- return (severities.critical += 1)
- }
- })
- return severities
-}
-
-export const classifyVulnerabilities = (components = []) => {
- if (!components) components = []
- if (!Array.isArray(components)) components = [components]
-
- let severities = { low: 0, medium: 0, high: 0, critical: 0 }
- components.forEach((component) => {
- // collect vulnerabilities from one component
- if (component?.Vulnerabilities) {
- const vulnerabilites = component?.Vulnerabilities
- vulnerabilites.forEach((vulnerability) => {
- // use of ThreatLevelOverall to get the index
- switch (vulnerability?.ThreatLevelOverall?.toLowerCase()) {
- case THREAD_LEVEL_LOW:
- return (severities.low += 1)
- case THREAD_LEVEL_MEDIUM:
- return (severities.medium += 1)
- case THREAD_LEVEL_HIGH:
- return (severities.high += 1)
- case THREAD_LEVEL_CRITICAL:
- return (severities.critical += 1)
- }
- })
- }
- })
- return severities
-}
-
-export const COMPONENT_TYPE_KEPPEL = "KeppelImage"
-
-export const componentTypes = () => {
- return [COMPONENT_TYPE_KEPPEL]
-}
-
-export const componentDetailsByType = (component) => {
- let detailKeys = []
- switch (component.Type) {
- case COMPONENT_TYPE_KEPPEL:
- detailKeys = [
- {
- label: "Version",
- value: componentVersionByType(component),
- },
- {
- label: "Maintainer",
- value: component?.Details?.Maintainer,
- },
- {
- label: "Region",
- value: component?.Details?.Region,
- },
- {
- label: "Source Repository",
- value: component?.Details?.SourceRepository,
- },
- ]
- default:
- }
- return detailKeys
-}
-
-export const componentVersionByType = (component) => {
- let version = ""
- switch (component.Type) {
- case COMPONENT_TYPE_KEPPEL:
- if (component?.Details?.PushedAt) {
- version = DateTime.fromSeconds(
- component?.Details?.PushedAt
- ).toLocaleString(DateTime.DATETIME_SHORT)
- }
- default:
- }
- return version
-}
-
-export const changeLogExample1 = {
- ID: "4323",
- Type: "automatic",
- Components: [{ Name: "ubuntu" }, { Name: "alpine" }],
- BeforeState: [
- {
- ID: "333",
- Name: "ubuntu",
- Type: "KeppelImage",
- Details: { PushedAt: 1543974164 },
- Vulnerabilities: [
- {
- ID: 666,
- ThreatLevelOverall: "Critical",
- },
- ],
- },
- ],
- AfterState: [
- {
- ID: "334",
- Name: "alpine",
- Type: "KeppelImage",
- Details: { PushedAt: 1608021867 },
- Vulnerabilities: [],
- },
- ],
- CreatedAt: "2022-05-04 19:15:00.000",
-}
-
-export const changeLogExample2 = {
- ID: "1234",
- Type: "manually",
- Components: [
- {
- Name: "absent-metrics-operator",
- Type: "KeppelImage",
- Details: { PushedAt: 1608021867 },
- },
- ],
- BeforeState: [],
- AfterState: [],
- CreatedAt: "2022-04-29 14:15:00.000",
-}
-
-export const patchExampl1 = {
- ID: "123",
- Type: "automatic",
- Changes: [changeLogExample1],
- CreatedAt: "2022-07-06 18:15:00.000",
- Evidences: [],
-}
-
-export const patchExampl2 = {
- ID: "456",
- Type: "automatic",
- Changes: [changeLogExample2],
- CreatedAt: "2022-05-04 19:15:00.000",
- Evidences: [],
-}
diff --git a/apps/heureka/src/helpers.test.js b/apps/heureka/src/helpers.test.js
deleted file mode 100644
index 691a20feb..000000000
--- a/apps/heureka/src/helpers.test.js
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import { parseError, classifyVulnerabilities } from "./helpers"
-
-describe("Helpers", () => {
- describe("parseError", () => {
- test("return error as string if no object with message", () => {
- expect(parseError({ error: "This is an error text" })).toEqual(
- '{"error":"This is an error text"}'
- )
- })
- test("return error message if object with message attr exists", () => {
- expect(parseError({ message: "This is an error text" })).toEqual(
- "This is an error text"
- )
- })
- test("return error message if object message has attr msg", () => {
- expect(
- parseError({ message: '{ "msg": "This is an error text" }' })
- ).toEqual("This is an error text")
- })
- test("return error message if object message has attr error", () => {
- expect(
- parseError({ message: '{ "error": "This is an error text" }' })
- ).toEqual("This is an error text")
- })
- test("return standard error message if no object message available", () => {
- expect(parseError({})).toEqual(
- "An error occurred. There is no further information"
- )
- })
- test("return standard error message if no object message available", () => {
- expect(parseError()).toEqual(
- "An error occurred. There is no further information"
- )
- })
- test("return error text if just a string is available", () => {
- expect(parseError("This is a mega error")).toEqual(
- '"This is a mega error"'
- )
- })
- })
-
- describe("classifyVulnerabilities", () => {
- test("return empty results if no components provided", () => {
- expect(classifyVulnerabilities(classifyVulnerabilities)).toEqual({
- low: 0,
- medium: 0,
- high: 0,
- critical: 0,
- })
- })
- test("return empty results if null provided", () => {
- expect(classifyVulnerabilities(null)).toEqual({
- low: 0,
- medium: 0,
- high: 0,
- critical: 0,
- })
- })
- test("map to array if object instead of array provided", () => {
- expect(
- classifyVulnerabilities({
- Vulnerabilities: [{ ThreatLevelOverall: "Medium" }],
- })
- ).toEqual({
- low: 0,
- medium: 1,
- high: 0,
- critical: 0,
- })
- })
- test("classify all possibilities with and without capital letter", () => {
- const component1 = {
- Vulnerabilities: [
- { ThreatLevelOverall: "High" },
- { ThreatLevelOverall: "Low" },
- ],
- }
- const component2 = {
- Vulnerabilities: [
- { ThreatLevelOverall: "Critical" },
- { ThreatLevelOverall: "Medium" },
- ],
- }
- const component3 = {
- Vulnerabilities: [{ ThreatLevelOverall: "medium" }],
- }
- expect(
- classifyVulnerabilities([component1, component2, component3])
- ).toEqual({
- low: 1,
- medium: 2,
- high: 1,
- critical: 1,
- })
- })
- })
-})
diff --git a/apps/heureka/src/hooks/useCommunication.js b/apps/heureka/src/hooks/useCommunication.js
deleted file mode 100644
index a22ef054e..000000000
--- a/apps/heureka/src/hooks/useCommunication.js
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import React, { useReducer, useEffect, useCallback } from "react"
-import { broadcast, get, watch } from "communicator"
-import useStore from "./useStore"
-
-const useCommunication = () => {
- console.log("[heureka] useCommunication setup")
-
- const setAuth = useStore((state) => state.setAuth)
- const setLoggedIn = useStore((state) => state.setLoggedIn)
- const setLoggedOut = useStore((state) => state.setLoggedOut)
- const setLogin = useStore((state) => state.setLogin)
-
- useEffect(() => {
- // get manually the current auth object in case the this app mist the first auth update message
- // this is the case this app is loaded after the Auth app.
- get(
- "AUTH_GET_DATA",
- (data) => {
- setAuth(data.auth)
- setLoggedIn(data.loggedIn)
- },
- { debug: true }
- )
- // watch for auth updates messages
- // with the watcher we get the auth object when this app is loaded before the Auth app
- const unwatch = watch(
- "AUTH_UPDATE_DATA",
- (data) => {
- setAuth(data.auth)
- setLoggedIn(data.loggedIn)
- },
- { debug: true }
- )
- return unwatch
- }, [setAuth, setLoggedIn])
-
- setLogin(() => {
- broadcast("AUTH_LOGIN", "heureka", { debug: true })
- })
-
- setLoggedOut(() => {
- broadcast("AUTH_LOGOUT", "heureka")
- })
-}
-
-export default useCommunication
diff --git a/apps/heureka/src/hooks/useQueryClientFn.js b/apps/heureka/src/hooks/useQueryClientFn.js
deleted file mode 100644
index 756353278..000000000
--- a/apps/heureka/src/hooks/useQueryClientFn.js
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import { useEffect, useMemo } from "react"
-import { useQueryClient } from "@tanstack/react-query"
-import { useEndpoint, useActions } from "../components/StoreProvider"
-import { request } from "graphql-request"
-import sevicesQuery from "../lib/queries/services"
-import vulnerabilityMatchesQuery from "../lib/queries/vulnerabilityMatches"
-import ServiceFilterQuery from "../lib/queries/serviceFilters"
-
-// hook to register query defaults that depends on the queryClient and options
-const useQueryClientFn = () => {
- const queryClient = useQueryClient()
- const endpoint = useEndpoint()
- const { setQueryClientFnReady } = useActions()
-
- /*
- As stated in getQueryDefaults, the order of registration of query defaults does matter. Since the first matching defaults are returned by getQueryDefaults, the registration should be made in the following order: from the least generic key to the most generic one. This way, in case of specific key, the first matching one would be the expected one.
- */
- useEffect(() => {
- if (!queryClient || !endpoint) return
- console.log("useQueryClientFn::: setting defaults")
-
- queryClient.setQueryDefaults(["services"], {
- queryFn: async ({ queryKey }) => {
- const [_key, options] = queryKey
- console.log("useQueryClientFn::: queryKey: ", queryKey, options)
- return await request(endpoint, sevicesQuery(), options)
- },
- })
-
- queryClient.setQueryDefaults(["vulnerabilities"], {
- queryFn: async ({ queryKey }) => {
- const [_key, options] = queryKey
- console.log("useQueryClientFn::: queryKey: ", queryKey)
- return await request(endpoint, vulnerabilityMatchesQuery(), options)
- },
- })
-
- queryClient.setQueryDefaults(["serviceFilters"], {
- queryFn: async ({ queryKey }) => {
- console.log("useQueryClientFn::: queryKey: ", queryKey)
- return await request(endpoint, ServiceFilterQuery())
- },
- staleTime: Infinity, // this do not change often keep it until reload
- })
-
- // set queryClientFnReady to true once
- setQueryClientFnReady(true)
- }, [queryClient, endpoint])
-}
-
-export default useQueryClientFn
diff --git a/apps/heureka/src/hooks/useUrlState.js b/apps/heureka/src/hooks/useUrlState.js
deleted file mode 100644
index af5835d23..000000000
--- a/apps/heureka/src/hooks/useUrlState.js
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import { useState, useEffect } from "react"
-import { registerConsumer } from "url-state-provider"
-import { useActions, useActiveTab } from "../components/StoreProvider"
-
-const DEFAULT_KEY = "heureka"
-const ACTIVE_TAB = "t"
-
-const useUrlState = (key) => {
- const [isURLRead, setIsURLRead] = useState(false)
- // it is possible to have two apps instances on the same page
- // int his case the key should be different per app
- const urlStateManager = registerConsumer(key || DEFAULT_KEY)
-
- const { setActiveTab } = useActions()
- const activeTab = useActiveTab()
-
- // Set initial state from URL (on login)
- useEffect(() => {
- if (isURLRead) return
- console.log(
- `HEUREKA: (${key || DEFAULT_KEY}) setting up state from url:`,
- urlStateManager.currentState()
- )
-
- // READ the url state and set the state
- const newTabIndex = urlStateManager.currentState()?.[ACTIVE_TAB]
- // SAVE the state
- if (newTabIndex) setActiveTab(newTabIndex)
- setIsURLRead(true)
- }, [isURLRead])
-
- // SYNC states to URL state
- useEffect(() => {
- if (!isURLRead) return
- urlStateManager.push({
- [ACTIVE_TAB]: activeTab,
- })
- }, [isURLRead, activeTab])
-}
-
-export default useUrlState
diff --git a/apps/heureka/src/img/app_bg_example.svg b/apps/heureka/src/img/app_bg_example.svg
deleted file mode 100644
index b28325349..000000000
--- a/apps/heureka/src/img/app_bg_example.svg
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
diff --git a/apps/heureka/src/index.js b/apps/heureka/src/index.js
deleted file mode 100644
index f6f988315..000000000
--- a/apps/heureka/src/index.js
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import { createRoot } from "react-dom/client"
-import React from "react"
-
-// export mount and unmount functions
-export const mount = (container, options = {}) => {
- import("./App").then((App) => {
- mount.root = createRoot(container)
- mount.root.render(React.createElement(App.default, options?.props))
- })
-}
-
-export const unmount = () => mount.root && mount.root.unmount()
diff --git a/apps/heureka/src/lib/queries/serviceFilters.js b/apps/heureka/src/lib/queries/serviceFilters.js
deleted file mode 100644
index 5ba6c2080..000000000
--- a/apps/heureka/src/lib/queries/serviceFilters.js
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import { gql } from "graphql-request"
-
-// gql
-// It is there for convenience so that you can get the tooling support
-// like prettier formatting and IDE syntax highlighting.
-// You can use gql from graphql-tag if you need it for some reason too.
-export default () => gql`
- {
- __type(name: "ServiceFilter") {
- name
- inputFields {
- name
- type {
- name
- kind
- ofType {
- name
- kind
- enumValues {
- name
- }
- }
- }
- }
- }
- }
-`
diff --git a/apps/heureka/src/lib/queries/services.js b/apps/heureka/src/lib/queries/services.js
deleted file mode 100644
index ab294fb75..000000000
--- a/apps/heureka/src/lib/queries/services.js
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import { gql } from "graphql-request"
-
-// gql
-// It is there for convenience so that you can get the tooling support
-// like prettier formatting and IDE syntax highlighting.
-// You can use gql from graphql-tag if you need it for some reason too.
-export default () => gql`
- query ($filter: ServiceFilter, $first: Int, $after: String) {
- Services(filter: $filter, first: $first, after: $after) {
- __typename
- totalCount
- edges {
- node {
- id
- name
- owners {
- totalCount
- edges {
- node {
- id
- sapID
- name
- }
- cursor
- }
- pageInfo {
- hasNextPage
- nextPageAfter
- }
- }
- supportGroups {
- totalCount
- edges {
- node {
- id
- name
- }
- cursor
- }
- pageInfo {
- hasNextPage
- nextPageAfter
- }
- }
- activities {
- totalCount
- edges {
- node {
- id
- }
- cursor
- }
- pageInfo {
- hasNextPage
- nextPageAfter
- }
- }
- advisoryRepositories {
- totalCount
- edges {
- node {
- id
- name
- url
- created_at
- updated_at
- }
- cursor
- priority
- created_at
- updated_at
- }
- pageInfo {
- hasNextPage
- nextPageAfter
- }
- }
- }
- cursor
- }
- pageInfo {
- hasNextPage
- nextPageAfter
- }
- }
- }
-`
diff --git a/apps/heureka/src/lib/queries/vulnerabilityMatches.js b/apps/heureka/src/lib/queries/vulnerabilityMatches.js
deleted file mode 100644
index 0c3b3d806..000000000
--- a/apps/heureka/src/lib/queries/vulnerabilityMatches.js
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import { gql } from "graphql-request"
-
-// gql
-// It is there for convenience so that you can get the tooling support
-// like prettier formatting and IDE syntax highlighting.
-// You can use gql from graphql-tag if you need it for some reason too.
-export default () => gql`
- query ($filter: VulnerabilityMatchFilter, $first: Int, $after: String) {
- VulnerabilityMatches(filter: $filter, first: $first, after: $after) {
- __typename
- totalCount
- edges {
- node {
- id
- status
- remediationDate
- discoveryDate
- targetRemediationDate
- severity {
- value
- score
- }
- evidences {
- totalCount
- edges {
- node {
- id
- description
- }
- cursor
- }
- pageInfo {
- hasNextPage
- nextPageAfter
- }
- }
- vulnerabilityDisclosureId
- vulnerabilityDisclosure {
- id
- lastModified
- }
- componentInstanceId
- componentInstance {
- id
- ccrn
- count
- }
- vulnerabilityMatchChanges {
- totalCount
- edges {
- node {
- id
- action
- vulnerabilityMatchId
- activityId
- }
- cursor
- }
- pageInfo {
- hasNextPage
- nextPageAfter
- }
- }
- }
- cursor
- }
- pageInfo {
- hasNextPage
- hasPreviousPage
- isValidPage
- pageNumber
- nextPageAfter
- pages {
- after
- isCurrent
- pageNumber
- pageCount
- }
- }
- }
- }
-`
diff --git a/apps/heureka/src/lib/store.js b/apps/heureka/src/lib/store.js
deleted file mode 100644
index b35ad2071..000000000
--- a/apps/heureka/src/lib/store.js
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import { createStore } from "zustand"
-import { devtools } from "zustand/middleware"
-import produce from "immer"
-
-export default (options) =>
- createStore(
- devtools((set, get) => ({
- isUrlStateSetup: false,
- queryClientFnReady: false,
- endpoint: options?.apiEndpoint,
-
- activeTab: "services",
- tabs: {
- services: {
- queryOptions: {
- first: 20,
- },
- },
- vulnerabilities: {
- queryOptions: {
- first: 20,
- },
- },
- },
-
- actions: {
- setQueryClientFnReady: (readiness) =>
- set(
- (state) => {
- state.queryClientFnReady = readiness
- },
- false,
- "setQueryClientFnReady"
- ),
- setActiveTab: (index) =>
- set(
- (state) => {
- state.activeTab = index
- },
- false,
- "setActiveTab"
- ),
- setQueryOptions: (tab, options) =>
- set(
- produce((state) => {
- state.tabs[tab].queryOptions = options
- }),
- false,
- "setQueryOptions"
- ),
- },
- }))
- )
diff --git a/apps/heureka/src/queries.js b/apps/heureka/src/queries.js
deleted file mode 100644
index 210c7fcf0..000000000
--- a/apps/heureka/src/queries.js
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import { useQuery } from "@tanstack/react-query"
-import {
- services,
- serviceFilters,
- service,
- components,
- componentFilters,
- component,
- vulnerabilities,
- vulnerability,
- vulnerabilityFilters,
- users,
- user,
- userFilters,
-} from "./actions"
-
-// get all services
-export const getServices = (bearerToken, endpoint, options) => {
- return useQuery({
- queryKey: ["services", bearerToken, endpoint, options],
- queryFn: services,
- // The query will not execute until the bearerToken exists
- enabled: !!bearerToken,
- // The data from the last successful fetch available while new data is being requested, even though the query key has changed.
- // When the new data arrives, the previous data is seamlessly swapped to show the new data.
- // isPreviousData is made available to know what data the query is currently providing you
- keepPreviousData: true,
- })
-}
-
-export const getServiceFilters = (bearerToken, endpoint, options) => {
- return useQuery({
- queryKey: ["serviceFilters", bearerToken, endpoint, options],
- queryFn: serviceFilters,
- // The query will not execute until the bearerToken exists
- enabled: !!bearerToken,
- // The data from the last successful fetch available while new data is being requested, even though the query key has changed.
- // When the new data arrives, the previous data is seamlessly swapped to show the new data.
- // isPreviousData is made available to know what data the query is currently providing you
- keepPreviousData: true,
- // If a user leaves your application and returns to stale data, React Query automatically requests fresh data for you in the background.
- // You can disable this globally or per-query using the refetchOnWindowFocus option
- refetchOnWindowFocus: false,
- })
-}
-
-export const getService = (
- bearerToken,
- endpoint,
- serviceId,
- placeholderData
-) => {
- return useQuery({
- queryKey: ["service", bearerToken, endpoint, serviceId],
- queryFn: service,
- // The query will not execute until the bearerToken exists
- enabled: !!bearerToken,
- // Placeholder data allows a query to behave as if it already has data, similar to the initialData option,
- // but the data is not persisted to the cache. This comes in handy for situations where you have enough partial (or fake)
- // data to render the query successfully while the actual data is fetched in the background.
- placeholderData: placeholderData,
- })
-}
-
-// get all components
-export const getComponents = (bearerToken, endpoint, options) => {
- return useQuery({
- queryKey: ["components", bearerToken, endpoint, options],
- queryFn: components,
- // The query will not execute until the bearerToken exists
- enabled: !!bearerToken,
- // The data from the last successful fetch available while new data is being requested, even though the query key has changed.
- // When the new data arrives, the previous data is seamlessly swapped to show the new data.
- // isPreviousData is made available to know what data the query is currently providing you
- keepPreviousData: true,
- })
-}
-
-export const getComponentFilters = (bearerToken, endpoint, options) => {
- return useQuery({
- queryKey: ["componentFilters", bearerToken, endpoint, options],
- queryFn: componentFilters,
- // The query will not execute until the bearerToken exists
- enabled: !!bearerToken,
- // The data from the last successful fetch available while new data is being requested, even though the query key has changed.
- // When the new data arrives, the previous data is seamlessly swapped to show the new data.
- // isPreviousData is made available to know what data the query is currently providing you
- keepPreviousData: true,
- // If a user leaves your application and returns to stale data, React Query automatically requests fresh data for you in the background.
- // You can disable this globally or per-query using the refetchOnWindowFocus option
- refetchOnWindowFocus: false,
- })
-}
-
-export const getComponent = (
- bearerToken,
- endpoint,
- componentId,
- placeholderData
-) => {
- return useQuery({
- queryKey: ["component", bearerToken, endpoint, componentId],
- queryFn: component,
- // The query will not execute until the bearerToken exists
- enabled: !!bearerToken,
- // Placeholder data allows a query to behave as if it already has data, similar to the initialData option,
- // but the data is not persisted to the cache. This comes in handy for situations where you have enough partial (or fake)
- // data to render the query successfully while the actual data is fetched in the background.
- placeholderData: placeholderData,
- })
-}
-
-export const getVulnerabilities = (bearerToken, endpoint, options) => {
- return useQuery({
- queryKey: ["vulnerabilities", bearerToken, endpoint, options],
- queryFn: vulnerabilities,
- // The query will not execute until the bearerToken exists
- enabled: !!bearerToken,
- // The data from the last successful fetch available while new data is being requested, even though the query key has changed.
- // When the new data arrives, the previous data is seamlessly swapped to show the new data.
- // isPreviousData is made available to know what data the query is currently providing you
- keepPreviousData: true,
- })
-}
-
-export const getVulnerability = (
- bearerToken,
- endpoint,
- vulnerabilityId,
- placeholderData
-) => {
- return useQuery({
- queryKey: ["user", bearerToken, endpoint, vulnerabilityId],
- queryFn: vulnerability,
- // The query will not execute until the bearerToken exists
- enabled: !!bearerToken,
- // Placeholder data allows a query to behave as if it already has data, similar to the initialData option,
- // but the data is not persisted to the cache. This comes in handy for situations where you have enough partial (or fake)
- // data to render the query successfully while the actual data is fetched in the background.
- placeholderData: placeholderData,
- })
-}
-
-export const getVulnerabilityFilters = (bearerToken, endpoint, options) => {
- return useQuery({
- queryKey: ["vulnerabilityFilters", bearerToken, endpoint, options],
- queryFn: vulnerabilityFilters,
- // The query will not execute until the bearerToken exists
- enabled: !!bearerToken,
- // The data from the last successful fetch available while new data is being requested, even though the query key has changed.
- // When the new data arrives, the previous data is seamlessly swapped to show the new data.
- // isPreviousData is made available to know what data the query is currently providing you
- keepPreviousData: true,
- // If a user leaves your application and returns to stale data, React Query automatically requests fresh data for you in the background.
- // You can disable this globally or per-query using the refetchOnWindowFocus option
- refetchOnWindowFocus: false,
- })
-}
-
-export const getUsers = (bearerToken, endpoint, options) => {
- return useQuery({
- queryKey: ["users", bearerToken, endpoint, options],
- queryFn: users,
- // The query will not execute until the bearerToken exists
- enabled: !!bearerToken,
- // The data from the last successful fetch available while new data is being requested, even though the query key has changed.
- // When the new data arrives, the previous data is seamlessly swapped to show the new data.
- // isPreviousData is made available to know what data the query is currently providing you
- keepPreviousData: true,
- })
-}
-
-export const getUser = (bearerToken, endpoint, userId, placeholderData) => {
- return useQuery({
- queryKey: ["user", bearerToken, endpoint, userId],
- queryFn: user,
- // The query will not execute until the bearerToken exists
- enabled: !!bearerToken,
- // Placeholder data allows a query to behave as if it already has data, similar to the initialData option,
- // but the data is not persisted to the cache. This comes in handy for situations where you have enough partial (or fake)
- // data to render the query successfully while the actual data is fetched in the background.
- placeholderData: placeholderData,
- })
-}
-
-export const getUserFilters = (bearerToken, endpoint, options) => {
- return useQuery({
- queryKey: ["userFilters", endpoint, options],
- queryFn: userFilters,
- // The query will not execute until the bearerToken exists
- enabled: !!bearerToken,
- // The data from the last successful fetch available while new data is being requested, even though the query key has changed.
- // When the new data arrives, the previous data is seamlessly swapped to show the new data.
- // isPreviousData is made available to know what data the query is currently providing you
- keepPreviousData: true,
- // If a user leaves your application and returns to stale data, React Query automatically requests fresh data for you in the background.
- // You can disable this globally or per-query using the refetchOnWindowFocus option
- refetchOnWindowFocus: false,
- })
-}
diff --git a/apps/heureka/src/styles.js b/apps/heureka/src/styles.js
deleted file mode 100644
index d18e47105..000000000
--- a/apps/heureka/src/styles.js
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-export const DetailContentHeading = `
-jn-font-bold
-jn-text-lg
-jn-text-theme-high
-jn-pb-2
- `
-
-export const DetailSection = `
-mt-6
-`
-
-export const DetailSectionHeader = `
-font-bold
-mt-4
-text-lg
-`
-
-export const DetailSectionBox = `
-bg-theme-background-lvl-1
-rounded
-pb-0.5
-`
diff --git a/apps/heureka/src/styles.scss b/apps/heureka/src/styles.scss
deleted file mode 100644
index 8c927175f..000000000
--- a/apps/heureka/src/styles.scss
+++ /dev/null
@@ -1,12 +0,0 @@
-// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
-// SPDX-License-Identifier: Apache-2.0
-
-/* Do not remove these tailwind directives. Without them styles won't work as expected */
-@tailwind base;
-@tailwind components;
-@tailwind utilities;
-
-
-/* If necessary, app styles can be added below */
-
-
diff --git a/apps/heureka/tailwind.config.js b/apps/heureka/tailwind.config.js
deleted file mode 100644
index 4ee65e3b0..000000000
--- a/apps/heureka/tailwind.config.js
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-// opacity helper to make custom colors work with opacity
-function withOpacity(variableName) {
- return ({ opacityVariable, opacityValue }) => {
- if (opacityValue !== undefined) {
- return `rgba(var(${variableName}), ${opacityValue})`
- }
- if (opacityVariable !== undefined) {
- return `rgba(var(${variableName}), var(${opacityVariable}, 1))`
- }
- return `rgb(var(${variableName}))`
- }
-}
-
-module.exports = {
- presets: [require("juno-ui-components/build/lib/tailwind.config")],
- prefix: "", // important, do not change
- content: ["./src/**/*.{js,jsx,ts,tsx}", "./public/index.html"],
- corePlugins: {
- preflight: false,
- },
- theme: {},
- plugins: [],
-}
diff --git a/apps/playground/package.json b/apps/playground/package.json
index 1b2b95459..1b2255011 100644
--- a/apps/playground/package.json
+++ b/apps/playground/package.json
@@ -29,7 +29,7 @@
"esbuild": "^0.19.5",
"jest": "^29.3.1",
"jest-environment-jsdom": "^29.3.1",
- "juno-ui-components": "*",
+ "juno-ui-components": "https://assets.juno.global.cloud.sap/libs/juno-ui-components@2.13.8/package.tgz",
"postcss": "^8.4.21",
"postcss-url": "^10.1.3",
"prop-types": "^15.8.1",
@@ -40,7 +40,7 @@
"sass": "^1.60.0",
"shadow-dom-testing-library": "^1.7.1",
"tailwindcss": "^3.3.1",
- "url-state-provider": "*",
+ "url-state-provider": "https://assets.juno.global.cloud.sap/libs/url-state-provider@1.3.2/package.tgz",
"util": "^0.12.4",
"zustand": "4.3.7"
},
@@ -50,11 +50,11 @@
"build": "NODE_ENV=production node esbuild.config.js"
},
"peerDependencies": {
- "juno-ui-components": "*",
+ "juno-ui-components": "https://assets.juno.global.cloud.sap/libs/juno-ui-components@2.13.8/package.tgz",
"prop-types": "^15.8.1",
"react": "18.2.0",
"react-dom": "18.2.0",
- "url-state-provider": "*",
+ "url-state-provider": "https://assets.juno.global.cloud.sap/libs/url-state-provider@1.3.2/package.tgz",
"zustand": "4.3.7"
},
"importmapExtras": {
diff --git a/apps/supernova/LICENSE b/apps/supernova/LICENSE
deleted file mode 100644
index 261eeb9e9..000000000
--- a/apps/supernova/LICENSE
+++ /dev/null
@@ -1,201 +0,0 @@
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/apps/supernova/README.md b/apps/supernova/README.md
deleted file mode 100644
index b6c41b801..000000000
--- a/apps/supernova/README.md
+++ /dev/null
@@ -1,134 +0,0 @@
-Supernova is an alternative UI for Prometheus Alertmanager with some quality of life improvements:
-
-- Micro frontend design based on [Juno UI components](https://ui.juno.global.cloud.sap)
-- Predefined filter categories
-- Easy filtering
-- Autodiscover of the support group and added automatically as filter
-- Aggregation and counting of alerts by region and severity
-- Automatic URL linking for URLs in descriptions
-- Parsing of alert labels for included external links
-- Display of active and expired silences for a given alert
-- Warning of an existing silence displaying the exact expiration time when creating new silences
-
-## Concepts
-
-### Alerts
-
-Alerting rules offer the capability to define alert conditions using expressions in the Prometheus expression language. These rules enable you to specify conditions that trigger alerts, and subsequently send notifications regarding the firing alerts to an external service. Whenever the alert expression results in one or more vector elements at a given point in time, the alert counts as active for these elements `label sets`.
-
-#### Labels
-
-The labels clause allows specifying a set of additional labels to be attached to the alert. Following is a live example of a set of labels from an alert of the `support group:containers` with `severity:info` in the `region:eu-de-2`.
-
-```js
-{
- ...
- "labels": {
- "alertname": "PodOOMKilled",
- "cluster": "eu-de-2",
- "cluster_type": "metal",
- "context": "memory",
- "label_ccloud_support_group": "containers",
- "meta": "Pod kube-system/kube-system-metal-owner-label-injector-28150200-2vgk5 OOMKilled",
- "namespace": "kube-system",
- "no_alert_on_absence": "true",
- "playbook": "docs/support/playbook/kubernetes/k8s_pod_oomkilled",
- "pod_name": "kube-system-metal-owner-label-injector-28150200-2vgk5",
- "prometheus": "kube-monitoring/kubernetes",
- "region": "eu-de-2",
- "service": "resources",
- "severity": "info",
- "support_group": "containers",
- "tier": "k8s",
- "status": "active"
- }
- ...
-}
-```
-
-### Silences
-
-Silences are a straightforward way to simply mute alerts for a given time. A silence is configured based on matchers. Incoming alerts are checked whether they match all the equality matchers of an active silence. If they do, no notifications will be sent out for that alert.
-
-#### Matchers
-
-A matcher is a string with a syntax inspired by PromQL and OpenMetrics. Matchers are ANDed together, meaning that all matchers must evaluate to "true" when tested against the labels on a given alert.
-
-When utilizing Supernova to add a silence, the matchers will be preselected based on the alert you selected. Moreover, through the advanced section, you have the option to include additional labels that are excluded by default. These exclusions are dependent on the configured excluded labels, which will be explained in detail in the section below.
-
-Given an alert with following labels:
-
-```js
-{
- ...
- fingerprint: "alert123",
- labels: {
- severity: "critical",
- support_group: "containers",
- service: "automation",
- }
- ...
-}
-```
-
-In order to prevent the alert from continuing to trigger, we require a silence that includes the following matchers:
-
-```js
-{
- ...
- id: "silence123",
- matchers: [
- { name: "severity", value: "critical" },
- { name: "support_group", value: "containers" },
- { name: "service", value: "automation" },
- ],
- ...
-}
-```
-
-## Configuration
-
-### Filter labels
-
-Filter labels are a set of labels that are utilized to define the criteria by which alerts will be filtered, if those labels exist within the fetched alerts. These filter labels enable you to selectively narrow down the alerts based on specific label values, resulting in a more targeted and refined alert filtering process.
-
-To set the filter labels:
-
-1. Utilize the app prop `filterLabels`, which is used during the setup of the script tag. For further information, please consult the [Get Started]() section.
-
-### Silence excluded alert labels
-
-Excluded labels are a collection of labels that are automatically excluded by default when configuring silence matchers. These labels, such as `pod`, `pod_name` or `instance`, often undergo frequent value changes, causing new alerts to be triggered that are not covered by the existing silence.
-
-Consider the following example: an alert is triggered when a pod runs out of memory and gets killed `Out Of Memory killed`. When this pod is recreated, it receives a different name. If the pod runs again out of memory because of the same issue, a new alarm will be triggered, but it won't be covered if we had used the `pod_name` as a matcher in the silence configuration.
-
-PodOOMKilled alarm labels example:
-
-```js
-{
- "alertname": "PodOOMKilled",
- "cluster": "eu-de-1",
- "cluster_type": "metal",
- "context": "memory",
- "label_ccloud_service": "keppel",
- "label_ccloud_support_group": "containers",
- "meta": "Pod keppel/keppel-janitor-6dc777bcbf-5xrns OOMKilled",
- "namespace": "keppel",
- "no_alert_on_absence": "true",
- "playbook": "docs/support/playbook/kubernetes/k8s_pod_oomkilled",
- "pod_name": "keppel-janitor-6dc777bcbf-5xrns",
- "prometheus": "kube-monitoring/kubernetes",
- "region": "eu-de-1",
- "service": "resources",
- "severity": "info",
- "support_group": "containers",
- "tier": "k8s",
- "status": "active"
-}
-```
-
-If the end user wishes to include any excluded labels as matchers, they can easily do so by expanding the advanced section during the silence creation process. This allows for greater flexibility and customization when configuring the silence matchers.
-
-To set the excluded alert labels:
-
-1. Utilize the app prop `silenceExcludedLabels`, which is used during the setup of the script tag. For further information, please consult the [Get Started]() section.
diff --git a/apps/supernova/__mocks__/client.js b/apps/supernova/__mocks__/client.js
deleted file mode 100644
index 84531d3c2..000000000
--- a/apps/supernova/__mocks__/client.js
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import { JSDOM } from "jsdom"
-const dom = new JSDOM()
-global.document = dom.window.document
-global.window = dom.window
diff --git a/apps/supernova/__mocks__/fileMock.js b/apps/supernova/__mocks__/fileMock.js
deleted file mode 100644
index 27ce65aca..000000000
--- a/apps/supernova/__mocks__/fileMock.js
+++ /dev/null
@@ -1,6 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-module.exports = "test-file-stub"
diff --git a/apps/supernova/__mocks__/styleMock.js b/apps/supernova/__mocks__/styleMock.js
deleted file mode 100644
index d74516001..000000000
--- a/apps/supernova/__mocks__/styleMock.js
+++ /dev/null
@@ -1,6 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-module.exports = {}
diff --git a/apps/supernova/babel.config.js b/apps/supernova/babel.config.js
deleted file mode 100644
index abc1af7d1..000000000
--- a/apps/supernova/babel.config.js
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-module.exports = {
- presets: ["@babel/preset-env", "@babel/preset-react"],
- env: {
- test: {
- plugins: [["babel-plugin-transform-import-meta", { module: "ES6" }]],
- },
- },
-}
diff --git a/apps/supernova/esbuild.config.js b/apps/supernova/esbuild.config.js
deleted file mode 100644
index 70ff2bed5..000000000
--- a/apps/supernova/esbuild.config.js
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-const esbuild = require("esbuild")
-const fs = require("node:fs/promises")
-const pkg = require("./package.json")
-const postcss = require("postcss")
-const sass = require("sass")
-const { transform } = require("@svgr/core")
-const url = require("postcss-url")
-// this function generates app props based on package.json and propSecrets.json
-const appProps = require("../../helpers/appProps")
-
-if (!/.+\/.+\.js/.test(pkg.module))
- throw new Error(
- "module value is incorrect, use DIR/FILE.js like build/index.js"
- )
-
-const isProduction = process.env.NODE_ENV === "production"
-const IGNORE_EXTERNALS = process.env.IGNORE_EXTERNALS === "true"
-// in dev environment we prefix output file with public
-let outfile = `${isProduction ? "" : "public/"}${pkg.main || pkg.module}`
-// get output from outputfile
-let outdir = outfile.slice(0, outfile.lastIndexOf("/"))
-const args = process.argv.slice(2)
-const watch = args.indexOf("--watch") >= 0
-const serve = args.indexOf("--serve") >= 0
-
-const green = "\x1b[32m%s\x1b[0m"
-const yellow = "\x1b[33m%s\x1b[0m"
-const clear = "\033c"
-
-// shared config
-const config = {
- bundle: true,
- minify: isProduction,
- // target: ["es2020"],
- target: ["es2020"], //["chrome64", "firefox67", "safari11.1", "edge79"],
- format: "esm",
- platform: "browser",
- // built-in loaders: js, jsx, ts, tsx, css, json, text, base64, dataurl, file, binary
- loader: { ".js": "jsx" },
- sourcemap: isProduction ? false : "both",
- external:
- isProduction && !IGNORE_EXTERNALS
- ? Object.keys(pkg.peerDependencies || {})
- : [],
-}
-
-const build = async () => {
- // delete build folder
- await fs.rm(outdir, { recursive: true, force: true })
- await fs.mkdir(outdir, { recursive: true })
-
- // build web workers
- try {
- const workerFiles = await fs.readdir("src/workers")
- for (let f of workerFiles) {
- await esbuild.build({
- ...config,
- entryPoints: [`src/workers/${f}`],
- outfile: `${outdir}/workers/${f}`,
- })
- }
- } catch (e) {
- console.log("WARNING: BUILD WEB WORKERS", e.message)
- }
-
- // build app
- let ctx = await esbuild.context({
- ...config,
- entryPoints: [pkg.source],
- outdir,
- splitting: true,
- format: "esm",
- plugins: [
- {
- name: "start/end",
- setup(build) {
- build.onStart(() => {
- // console.log(clear)
- console.log(yellow, "Compiling...")
- })
- build.onEnd((result) => console.log(green, "Done!"))
- },
- },
- // this custom plugin rewrites SVG imports to
- // dataurls, paths or react components based on the
- // search param and size
- {
- name: "svg-loader",
- setup(build) {
- build.onLoad(
- // consider only .svg files
- { filter: /.\.(svg)$/, namespace: "file" },
- async (args) => {
- let contents = await fs.readFile(args.path)
- // built-in loaders: js, jsx, ts, tsx, css, json, text, base64, dataurl, file, binary
- let loader = "text"
- if (args.suffix === "?url") {
- // as URL
- const maxSize = 10240 // 10Kb
- // use dataurl loader for small files and file loader for big files!
- loader = contents.length <= maxSize ? "dataurl" : "file"
- } else {
- // as react component
- // use react component loader (jsx)
- loader = "jsx"
- contents = await transform(contents, {
- plugins: ["@svgr/plugin-jsx"],
- })
- }
-
- return { contents, loader }
- }
- )
- },
- },
-
- // this custom plugin rewrites image imports to
- // dataurls or urls based on the size
- {
- name: "image-loader",
- setup(build) {
- build.onLoad(
- // consider only .svg files
- { filter: /.\.(png|jpg|jpeg|gif)$/, namespace: "file" },
- async (args) => {
- let contents = await fs.readFile(args.path)
- const maxSize = 10240 // 10Kb
- // built-in loaders: js, jsx, ts, tsx, css, json, text, base64, dataurl, file, binary
- // use dataurl loader for small files and file loader for big files!
- loader = contents.length <= maxSize ? "dataurl" : "file"
-
- return { contents, loader }
- }
- )
- },
- },
-
- // this custom plugin parses the style files
- {
- name: "parse-styles",
- setup(build) {
- build.onLoad(
- // consider only .scss and .css files
- { filter: /.\.(css|scss)$/, namespace: "file" },
- async (args) => {
- let content
- // handle scss, convert to css
- if (args.path.endsWith(".scss")) {
- const result = sass.renderSync({ file: args.path })
- content = result.css
- } else {
- // read file content
- content = await fs.readFile(args.path)
- }
-
- // postcss plugins
- const plugins = [
- require("tailwindcss"),
- require("autoprefixer"),
- // rewrite urls inside css
- url({
- url: "inline",
- // maxSize: 10, // use dataurls if files are smaller than 10k
- // fallback: "copy", // if files are bigger use copy method
- // assetsPath: "./build/assets",
- // useHash: true,
- // optimizeSvgEncode: true,
- }),
- ]
-
- const { css } = await postcss(plugins).process(content, {
- from: args.path,
- to: outdir,
- })
- // built-in loaders: js, jsx, ts, tsx, css, json, text, base64, dataurl, file, binary
- return { contents: css, loader: "text" }
- }
- )
- },
- },
- ],
- })
-
- if (watch || serve) {
- if (watch) await ctx.watch()
- if (serve) {
- // generate app props based on package.json and secretProps.json
- await fs.writeFile(
- `./${outdir}/appProps.js`,
- `export default ${JSON.stringify(appProps())}`
- )
-
- let { host, port } = await ctx.serve({
- host: "0.0.0.0",
- port: parseInt(process.env.APP_PORT || process.env.PORT || 3000),
- servedir: "public",
- })
- console.log("serve on", `${host}:${port}`)
- }
- } else {
- await ctx.rebuild()
- await ctx.dispose()
- }
-}
-
-build()
diff --git a/apps/supernova/jest.config.js b/apps/supernova/jest.config.js
deleted file mode 100644
index 0cb80394c..000000000
--- a/apps/supernova/jest.config.js
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-module.exports = {
- transform: { "\\.[jt]sx?$": "babel-jest" },
- testEnvironment: "jsdom",
- setupFilesAfterEnv: ["/setupTests.js"],
- transformIgnorePatterns: [
- "node_modules/(?!(juno-ui-components|communicator)/)",
- ],
- moduleNameMapper: {
- // Jest currently doesn't support resources with query parameters.
- // Therefore we add the optional query parameter matcher at the end
- // https://github.com/facebook/jest/issues/4181
- "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)(\\?.+)?$":
- require.resolve("./__mocks__/fileMock"),
- "\\.(css|less|scss)$": require.resolve("./__mocks__/styleMock"),
- },
-}
diff --git a/apps/supernova/package.json b/apps/supernova/package.json
deleted file mode 100644
index a17f9842a..000000000
--- a/apps/supernova/package.json
+++ /dev/null
@@ -1,106 +0,0 @@
-{
- "name": "supernova",
- "version": "0.9.11",
- "author": "UI-Team",
- "contributors": [
- "Esther Schmitz",
- "Arturo Reuschenbach Puncernau"
- ],
- "repository": "https://github.com/sapcc/juno/tree/main/apps/supernova",
- "license": "Apache-2.0",
- "source": "src/index.js",
- "module": "build/index.js",
- "private": true,
- "devDependencies": {
- "@babel/core": "^7.20.2",
- "@svgr/core": "^7.0.0",
- "@svgr/plugin-jsx": "^7.0.0",
- "@tanstack/react-query": "4.28.0",
- "@testing-library/dom": "^8.19.0",
- "@testing-library/jest-dom": "^5.16.5",
- "@testing-library/react": "^13.4.0",
- "@testing-library/user-event": "^14.4.3",
- "assert": "^2.0.0",
- "autoprefixer": "^10.4.2",
- "babel-jest": "^29.3.1",
- "babel-plugin-transform-import-meta": "^2.2.0",
- "communicator": "*",
- "esbuild": "^0.17.11",
- "esbuild-sass-plugin": "^2.6.0",
- "immer": "^9.0.21",
- "interweave": "^13.0.0",
- "jest": "^29.3.1",
- "jest-environment-jsdom": "^29.3.1",
- "juno-ui-components": "*",
- "luxon": "^2.3.0",
- "messages-provider": "*",
- "postcss": "^8.4.21",
- "postcss-url": "^10.1.3",
- "prop-types": "^15.8.1",
- "react": "18.2.0",
- "react-dom": "^18.2.0",
- "react-test-renderer": "^18.2.0",
- "sass": "^1.60.0",
- "shadow-dom-testing-library": "^1.7.1",
- "tailwindcss": "^3.3.1",
- "url-state-provider": "*",
- "util": "^0.12.4",
- "zustand": "4.3.7"
- },
- "peerDependencies": {
- "@tanstack/react-query": "4.28.0",
- "custom-event-polyfill": "^1.0.7",
- "juno-ui-components": "*",
- "luxon": "^2.3.0",
- "messages-provider": "*",
- "prop-types": "^15.8.1",
- "react": "18.2.0",
- "react-dom": "^18.2.0",
- "url-state-provider": "*",
- "zustand": "4.3.7"
- },
- "importmapExtras": {
- "zustand/middleware": "4.3.7"
- },
- "scripts": {
- "start": "NODE_ENV=development node esbuild.config.js --port=$APP_PORT --serve --watch",
- "test": "jest",
- "build": "NODE_ENV=production node esbuild.config.js"
- },
- "appProps": {
- "theme": {
- "value": "theme-dark",
- "type": "optional",
- "description": "Override the default theme. Possible values are theme-light or theme-dark (default)"
- },
- "embedded": {
- "value": "false",
- "type": "optional",
- "description": "Set to true if app is to be embedded in another existing app or page, like e.g. Elektra. If set to true the app won't render a page header/footer and instead render only the content. The default value is false."
- },
- "endpoint": {
- "value": "",
- "type": "required",
- "description": "Alertmanager API Endpoint URL"
- },
- "filterLabels": {
- "value": null,
- "type": "optional",
- "description": "FilterLabels are the labels shown in the filter dropdown, enabling users to filter alerts based on specific criteria. The 'Status' label serves as a default filter, automatically computed from the alert status attribute and will be not overwritten. The labels must be an array of strings. Example: [\"app\", \"cluster\", \"cluster_type\"]"
- },
- "silenceExcludedLabels": {
- "value": null,
- "type": "optional",
- "description": "SilenceExcludedLabels are labels that are initially excluded by default when creating a silence. However, they can be added if necessary when utilizing the advanced options in the silence form. The labels must be an array of strings. Example: [\"pod\", \"pod_name\", \"instance\"]"
- },
- "silenceTemplates": {
- "value": null,
- "type": "optional",
- "description": "SilenceTemplates are pre-defined silence templates that can be used to scheduled Maintenance Windows. The format consists of a list of objects including description, editable_labels (array of strings specifying the labels that users can modify), fixed_labels (map containing fixed labels and their corresponding values), status, and title."
- }
- },
- "appDependencies": {
- "auth": "latest"
- },
- "appPreview": true
-}
diff --git a/apps/supernova/public/favicon.ico b/apps/supernova/public/favicon.ico
deleted file mode 100644
index 9ebc4bb2e..000000000
Binary files a/apps/supernova/public/favicon.ico and /dev/null differ
diff --git a/apps/supernova/public/index.html b/apps/supernova/public/index.html
deleted file mode 100644
index 13beb9f20..000000000
--- a/apps/supernova/public/index.html
+++ /dev/null
@@ -1,54 +0,0 @@
-
-
-
-
-
-
-
- Supernova Dev
-
-
-
-
-
-
-
-
-
diff --git a/apps/supernova/public/index_test.html b/apps/supernova/public/index_test.html
deleted file mode 100644
index aa41d46a8..000000000
--- a/apps/supernova/public/index_test.html
+++ /dev/null
@@ -1,60 +0,0 @@
-
-
-
-
-
-
-
- Supernova Dev
-
-
-
-
-
-
-
-
-
-
diff --git a/apps/supernova/setupTests.js b/apps/supernova/setupTests.js
deleted file mode 100644
index db44c9038..000000000
--- a/apps/supernova/setupTests.js
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-// jest-dom adds custom jest matchers for asserting on DOM nodes.
-// allows you to do things like:
-// expect(element).toHaveTextContent(/react/i)
-// learn more: https://github.com/testing-library/jest-dom
-import "@testing-library/jest-dom"
diff --git a/apps/supernova/src/App.jsx b/apps/supernova/src/App.jsx
deleted file mode 100644
index 1663c5e2d..000000000
--- a/apps/supernova/src/App.jsx
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import React, { useLayoutEffect } from "react"
-
-import { AppShellProvider } from "juno-ui-components"
-import AppContent from "./AppContent"
-import styles from "./styles.scss"
-import {
- useGlobalsActions,
- useFilterActions,
- useSilencesActions,
- useAlertsActions,
- StoreProvider,
-} from "./hooks/useAppStore"
-import AsyncWorker from "./components/AsyncWorker"
-import { MessagesProvider } from "messages-provider"
-import CustomAppShell from "./components/CustomAppShell"
-
-function App(props = {}) {
- const { setLabels, setPredefinedFilters, setActivePredefinedFilter } =
- useFilterActions()
- const { setEmbedded, setApiEndpoint } = useGlobalsActions()
- const { setExcludedLabels } = useSilencesActions()
-
- useLayoutEffect(() => {
- // filterLabels are the labels shown in the filter dropdown, enabling users to filter alerts based on specific criteria. Default is status.
- if (props.filterLabels) setLabels(props.filterLabels)
-
- // silenceExcludedLabels are labels that are initially excluded by default when creating a silence. However, they can be added if necessary when utilizing the advanced options in the silence form.
- if (props.silenceExcludedLabels)
- setExcludedLabels(props.silenceExcludedLabels)
-
- // predefined filters config
- const predefinedFilters = [
- {
- name: "prod",
- displayName: "Prod",
- matchers: {
- // regex that matches anything except regions that start with qa-de-
- region: "^(?!qa-de-).*",
- },
- },
- {
- name: "prod-qa",
- displayName: "Prod + QA",
- matchers: {
- // regex that matches anything except regions that start with qa-de- and end with a number that is not 1
- // regex is used in RegExp constructor, so we need to escape the backslashes for flags
- region: "^(?!qa-de-(?!1$)\\d+).*",
- },
- },
- {
- name: "labs",
- displayName: "Labs",
- matchers: {
- // regex that matches all regions that start with qa-de- and end with a number that is not 1
- // regex is used in RegExp constructor, so we need to escape the backslashes for flags
- region: "^qa-de-(?!1$)\\d+",
- },
- },
- {
- name: "all",
- displayName: "All",
- matchers: {
- region: ".*",
- },
- },
- ]
- setPredefinedFilters(predefinedFilters)
-
- // initially active predefined filter
- const initialPredefinedFilter = "prod"
- setActivePredefinedFilter(initialPredefinedFilter)
-
- // save the apiEndpoint. It is also used outside the alertManager hook
- setApiEndpoint(props.endpoint)
- }, [])
-
- useLayoutEffect(() => {
- if (props.embedded === "true" || props.embedded === true) setEmbedded(true)
- }, [])
-
- return (
-
-
-
-
-
-
- )
-}
-
-const StyledApp = (props) => {
- return (
-
- {/* load appstyles inside the shadow dom */}
-
-
-
-
-
- )
-}
-
-export default StyledApp
diff --git a/apps/supernova/src/App.test.js b/apps/supernova/src/App.test.js
deleted file mode 100644
index cb360db19..000000000
--- a/apps/supernova/src/App.test.js
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import React from "react"
-import { render, act } from "@testing-library/react"
-
-// support shadow dom queries
-// https://reactjsexample.com/an-extension-of-dom-testing-library-to-provide-hooks-into-the-shadow-dom/
-import { screen } from "shadow-dom-testing-library"
-
-jest.mock("./hooks/useCommunication", () => {
- return jest.fn(() => ({}))
-})
-jest.mock("./hooks/useAlertmanagerAPI", () => {
- return jest.fn(() => ({}))
-})
-
-import App from "./App"
-
-test("renders app", async () => {
- render()
-
- let loginTitle = await screen.queryAllByShadowText(/Supernova/i)
- expect(loginTitle.length > 0).toBe(true)
-})
diff --git a/apps/supernova/src/AppContent.jsx b/apps/supernova/src/AppContent.jsx
deleted file mode 100644
index 0e365d145..000000000
--- a/apps/supernova/src/AppContent.jsx
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import React, { useEffect } from "react"
-import { useActions, Messages } from "messages-provider"
-import { Container, Spinner, Stack } from "juno-ui-components"
-import {
- useAlertsError,
- useAlertsIsLoading,
- useAlertsIsUpdating,
- useAlertsUpdatedAt,
- useAlertsTotalCounts,
- useAuthLoggedIn,
- useAuthError,
- useSilencesError,
-} from "./hooks/useAppStore"
-import AlertsList from "./components/alerts/AlertsList"
-import RegionsList from "./components/regions/RegionsList"
-import StatusBar from "./components/status/StatusBar"
-import Filters from "./components/filters/Filters"
-import WelcomeView from "./components/WelcomeView"
-import { parseError } from "./helpers"
-import AlertDetail from "./components/alerts/AlertDetail"
-import PredefinedFilters from "./components/filters/PredefinedFilters"
-
-const AppContent = () => {
- const { addMessage } = useActions()
- const loggedIn = useAuthLoggedIn()
- const authError = useAuthError()
-
- // alerts
- const alertsError = useAlertsError()
- const isAlertsLoading = useAlertsIsLoading()
- const totalCounts = useAlertsTotalCounts()
- const isAlertsUpdating = useAlertsIsUpdating()
- const updatedAt = useAlertsUpdatedAt()
-
- // silences
- const silencesError = useSilencesError()
-
- useEffect(() => {
- if (!authError) return
- addMessage({
- variant: "error",
- text: parseError(authError),
- })
- }, [authError])
-
- useEffect(() => {
- // since the API call is done in a web worker and not logging aware, we need to show the error just in case the user is logged in
- if (!alertsError || !loggedIn) return
-
- // if user uses firefox warn to activate `allow_client_cert`. Should be enough to do it just here since the API call is done in a web worker and nothing else will be loaded until the alerts are loaded
- const isFirefox = navigator.userAgent.toLowerCase().includes("firefox")
- if (isFirefox) {
- addMessage({
- variant: "warning",
- text: (
-
- Firefox detected. Please ensure that you have activated{" "}
- allow_client_cert to enable the retrieval of alerts and
- silences from the API.
-
- ),
- })
- }
-
- addMessage({
- variant: "error",
- text: parseError(alertsError),
- })
- }, [alertsError, loggedIn])
-
- useEffect(() => {
- // since the API call is done in a web worker and not logging aware, we need to show the error just in case the user is logged in
- if (!silencesError || !loggedIn) return
- addMessage({
- variant: "error",
- text: parseError(silencesError),
- })
- }, [silencesError, loggedIn])
-
- return (
-
-
- {loggedIn && !authError ? (
- <>
-
-
- {isAlertsLoading ? (
-
- Loading
-
-
- ) : (
- <>
-
-
-
-
- >
- )}
- >
- ) : (
-
- )}
-
- )
-}
-
-export default AppContent
diff --git a/apps/supernova/src/api/apiService.js b/apps/supernova/src/api/apiService.js
deleted file mode 100644
index b81b93bc5..000000000
--- a/apps/supernova/src/api/apiService.js
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-/**
- * This module implements a service to retrieve information from an API
- * @module apiService
- */
-
-// default value for watch interval
-const DEFAULT_INTERVAL = 300000
-
-/**
- * This function implements the actual service.
- * @param {object} initialConfig
- */
-function ApiService(initialConfig) {
- // default config
- let config = {
- serviceName: null,
- initialFetch: true, // Set this to false to disable this service from automatically running.
- fetchFn: null, // The promise function that the service will use to request data
- watch: true, // if true runs the fetchFn periodically with an interval defined in watchInterval
- watchInterval: DEFAULT_INTERVAL, // 5 min
- onFetchStart: null,
- onFetchEnd: null,
- onFetchError: null,
- debug: false,
- }
-
- let initialFetchPerformed = false
-
- // get the allowed config keys from default config
- const allowedOptions = Object.keys(config)
- // variable to hold the watch timer created by setInterval
- let watchTimer
-
- // This function performs the request to get the target data
- const update = () => {
- if (config.fetchFn) {
- // call onFetchStart if defined
- // This is useful to inform the listener that a new fetch is starting
- if (config.onFetchStart) config.onFetchStart()
- if (config?.debug)
- console.info(`ApiService::${config.serviceName || ""}: start fetch`)
- initialFetchPerformed = true
- return config
- .fetchFn()
- .then(() => {
- if (config.onFetchEnd) config.onFetchEnd()
- })
- .catch((error) => {
- if (error?.httperror) {
- error.message = "API: " + error.message
- }
- if (error.message == "Failed to fetch") {
- error.message =
- "Could not reach endpoint. Possible causes could include network issues, incorrect URL, or server outages."
- }
-
- console.warn(`ApiService::${config.serviceName || ""}:`, error)
- if (config.onFetchError) config.onFetchError(error)
- })
- } else {
- if (config?.debug)
- console.warn(
- `ApiService::${config.serviceName || ""}: missing fetch function`
- )
- return
- }
- }
-
- // update watcher if config has changed
- const updateWatcher = (oldConfig) => {
- // do nothing if watch and watchInterval are the same
- if (
- initialFetchPerformed &&
- oldConfig.watch === config.watch &&
- oldConfig.watchInterval === config.watchInterval
- )
- return
-
- // delete last watcher
- clearInterval(watchTimer)
-
- // create a new watcher which calls the update method
- if (config.watch) {
- watchTimer = setInterval(update, config.watchInterval || DEFAULT_INTERVAL)
- }
- }
-
- // this function is public and used to update the config
- this.configure = (newOptions) => {
- const oldConfig = { ...config }
- // update apiService config
- config = { ...config, ...newOptions }
-
- // check for allowed keys
- Object.keys(config).forEach(
- (key) => allowedOptions.indexOf(key) < 0 && delete config[key]
- )
-
- if (config?.debug)
- console.log(
- `ApiService::${config.serviceName || ""}: new config: `,
- config
- )
-
- // update watcher will check the config relevant attribute changed to update the watcher
- updateWatcher(oldConfig)
- if (config.initialFetch && !initialFetchPerformed) update()
- }
-
- // make it possible to update explicitly, not by a watcher!
- this.fetch = update
-
- // set the config initially
- this.configure(initialConfig)
-}
-
-export default ApiService
diff --git a/apps/supernova/src/api/client.js b/apps/supernova/src/api/client.js
deleted file mode 100644
index bfbcc8f49..000000000
--- a/apps/supernova/src/api/client.js
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-class HTTPError extends Error {
- constructor(code, message) {
- super(message || code)
- this.name = "HTTPError"
- this.statusCode = code
- }
-}
-
-// Check response status
-const checkStatus = (response) => {
- if (response.status < 400) {
- return response
- } else {
- return response.text().then((message) => {
- var error = new HTTPError(response.status, message || response.statusText)
- error.statusCode = response.status
- error.httperror = true
- return Promise.reject(error)
- })
- }
-}
-
-const DEFAULT_HEADERS = {
- "Content-Type": "application/json",
- Accept: "application/json",
-}
-
-const request = (url, options = {}) => {
- const requestOptions = { headers: DEFAULT_HEADERS, ...options }
-
- return fetch(url, requestOptions)
- .then(checkStatus)
- .then((response) => response.json())
-}
-
-export const head = (url, options = {}) =>
- request(url, { method: "HEAD", ...options })
-export const get = (url, options = {}) =>
- request(url, { method: "GET", ...options })
-export const post = (url, options = {}) =>
- request(url, { method: "POST", ...options })
-export const put = (url, options = {}) =>
- request(url, { method: "PUT", ...options })
-export const patch = (url, options = {}) =>
- request(url, { method: "PATCH", ...options })
-export const del = (url, options = {}) =>
- request(url, { method: "DELETE", ...options })
-export const copy = (url, options = {}) =>
- request(url, { method: "COPY", ...options })
diff --git a/apps/supernova/src/components/AsyncWorker.jsx b/apps/supernova/src/components/AsyncWorker.jsx
deleted file mode 100644
index 98cc4cc8e..000000000
--- a/apps/supernova/src/components/AsyncWorker.jsx
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import React from "react"
-import useCommunication from "../hooks/useCommunication"
-import useAlertmanagerAPI from "../hooks/useAlertmanagerAPI"
-import useUrlState from "../hooks/useUrlState"
-
-const AsyncWorker = ({ endpoint }) => {
- useCommunication()
- useAlertmanagerAPI(endpoint)
- useUrlState()
- return null
-}
-
-export default AsyncWorker
diff --git a/apps/supernova/src/components/Avatar.jsx b/apps/supernova/src/components/Avatar.jsx
deleted file mode 100644
index 6e41eb812..000000000
--- a/apps/supernova/src/components/Avatar.jsx
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import React from "react"
-import { Stack } from "juno-ui-components"
-
-const avatarCss = `
-h-8
-w-8
-bg-theme-background-lvl-2
-rounded-full
-bg-cover
-`
-
-const Avatar = ({ userName, url }) => {
- return (
-
- {url && (
-
- )}
- {userName && {userName}}
-
- )
-}
-
-export default Avatar
diff --git a/apps/supernova/src/components/CustomAppShell.jsx b/apps/supernova/src/components/CustomAppShell.jsx
deleted file mode 100644
index b35fceb8b..000000000
--- a/apps/supernova/src/components/CustomAppShell.jsx
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import React, { useMemo } from "react"
-import { AppShell, PageHeader } from "juno-ui-components"
-import {
- useAuthData,
- useAuthLoggedIn,
- useGlobalsEmbedded,
- useAuthActions,
-} from "../hooks/useAppStore"
-import HeaderUser from "./HeaderUser"
-
-const CustomAppShell = ({ children }) => {
- const embedded = useGlobalsEmbedded()
- const authData = useAuthData()
- const loggedIn = useAuthLoggedIn()
- const { logout } = useAuthActions()
-
- const pageHeader = useMemo(() => {
- return (
-
- {loggedIn && }
-
- )
- }, [loggedIn, authData, logout])
-
- return (
-
- {children}
-
- )
-}
-
-export default CustomAppShell
diff --git a/apps/supernova/src/components/HeaderUser.jsx b/apps/supernova/src/components/HeaderUser.jsx
deleted file mode 100644
index 8cdff6776..000000000
--- a/apps/supernova/src/components/HeaderUser.jsx
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import React from "react"
-import { Stack, Button } from "juno-ui-components"
-import Avatar from "./Avatar"
-
-const HeaderUser = ({ auth, logout }) => {
- return (
-
-
-
-
-
-
- )
-}
-
-export default HeaderUser
diff --git a/apps/supernova/src/components/WelcomeView.jsx b/apps/supernova/src/components/WelcomeView.jsx
deleted file mode 100644
index 292817a42..000000000
--- a/apps/supernova/src/components/WelcomeView.jsx
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import React from "react"
-import { Stack, Button, Spinner } from "juno-ui-components"
-import { useAuthIsProcessing, useAuthActions } from "../hooks/useAppStore"
-
-const WelcomeView = () => {
- const { login } = useAuthActions()
- const authIsProcessing = useAuthIsProcessing()
- return (
-
-
Welcome to the Converged Cloud Alertmanager
- {authIsProcessing ? (
-
- ) : (
- <>
-
Login to track and manage your alerts
-
- >
- )}
-
- )
-}
-
-export default WelcomeView
diff --git a/apps/supernova/src/components/alerts/Alert.jsx b/apps/supernova/src/components/alerts/Alert.jsx
deleted file mode 100644
index 044202459..000000000
--- a/apps/supernova/src/components/alerts/Alert.jsx
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import React, { forwardRef, useRef } from "react"
-
-import { DataGridCell, DataGridRow } from "juno-ui-components"
-
-import { useGlobalsActions, useShowDetailsFor } from "../../hooks/useAppStore"
-import AlertLabels from "./shared/AlertLabels"
-import AlertLinks from "./shared/AlertLinks"
-import SilenceNew from "../silences/SilenceNew"
-import AlertIcon from "./shared/AlertIcon"
-import AlertDescription from "./shared/AlertDescription"
-import AlertTimestamp from "./shared/AlertTimestamp"
-import AlertStatus from "./AlertStatus"
-import AlertRegion from "./shared/AlertRegion"
-
-const cellSeverityClasses = (severity) => {
- let borderColor = "border-text-theme-default"
- switch (severity) {
- case "critical":
- borderColor = "border-theme-danger"
- break
- case "warning":
- borderColor = "border-theme-warning"
- break
- case "info":
- borderColor = "border-theme-info"
- break
- }
-
- return `
- border-l-2
- ${borderColor}
- h-full
- pl-5
- `
-}
-
-const Alert = ({ alert }, ref) => {
- const { setShowDetailsFor } = useGlobalsActions()
- const rowRef = useRef(null)
-
- const handleShowDetails = (e) => {
- // Using the rowRef to check what was clicked
- // if the click was not on the row itself or on the row's direct children (i.e. the cells)
- // then we don't want to show the details because then the click was on a child of one of the cells
- // an additional check is made for targets with className "interactive". If the target has this then the click
- // handling should proceed even if the previous condition was true
- if ((e.target.parentNode !== rowRef.current) && !e.target.classList.contains("interactive")) return
-
- e.stopPropagation()
- e.preventDefault()
- setShowDetailsFor(alert?.fingerprint)
- }
-
- return (
- handleShowDetails(e)}
- >
-
-
- We couldn't find anything. It's possible that the matching
- alerts are not active at the moment, or the chosen filters could
- be overly limiting.
-
-
-
-
- )}
- {isAddingItems && (
-
- Loading ...
-
- )}
-
- )
-}
-
-export default AlertsList
diff --git a/apps/supernova/src/components/alerts/shared/AlertDescription.jsx b/apps/supernova/src/components/alerts/shared/AlertDescription.jsx
deleted file mode 100644
index e9ffbd49f..000000000
--- a/apps/supernova/src/components/alerts/shared/AlertDescription.jsx
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import React from "react"
-import { Markup } from "interweave"
-
-import { descriptionParsed } from "../../../lib/utils"
-
-
-const AlertDescription = ({description, subdued}) => {
-
- return (
- $1"
- )
- )}
- tagName="div"
- className={subdued ? "text-theme-light" : ""}
- />
- )
-}
-
-export default AlertDescription
\ No newline at end of file
diff --git a/apps/supernova/src/components/alerts/shared/AlertIcon.jsx b/apps/supernova/src/components/alerts/shared/AlertIcon.jsx
deleted file mode 100644
index e85826895..000000000
--- a/apps/supernova/src/components/alerts/shared/AlertIcon.jsx
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import React, { forwardRef } from "react"
-
-import { Icon } from "juno-ui-components"
-
-
-const AlertIcon = ({severity}, ref) => {
-
- const iconColor = () => {
-
- switch (severity) {
- case "critical":
- return "text-theme-danger"
- case "warning":
- return "text-theme-warning"
- case "info":
- return "text-theme-info"
- }
-
- }
-
- return (
- <>
- {severity === "critical" ? (
-
- ) : severity?.match(/^(warning|info)$/) ? (
-
- ) : (
-
- )}
- >
- )
-}
-
-export default forwardRef(AlertIcon)
\ No newline at end of file
diff --git a/apps/supernova/src/components/alerts/shared/AlertLabels.jsx b/apps/supernova/src/components/alerts/shared/AlertLabels.jsx
deleted file mode 100644
index cf172256d..000000000
--- a/apps/supernova/src/components/alerts/shared/AlertLabels.jsx
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import React from "react"
-
-import { Pill, Stack } from "juno-ui-components"
-
-import {
- useActiveFilters,
- useFilterLabels,
- useFilterActions,
-} from "../../../hooks/useAppStore"
-
-/**
- * For each of the given alert's labels which is included in the configured filterLabels render a Pill showing filterLabel and filterValue
- */
-const AlertLabels = ({ alert, showAll}) => {
- const filterLabels = showAll ? Object.keys(alert?.labels) : useFilterLabels()
- const activeFilters = useActiveFilters()
- const { addActiveFilter, removeActiveFilter } = useFilterActions()
-
- const handleLabelClick = (e, filterLabel, filterValue) => {
- // if filter isn't already active, add it
- if (!activeFilters?.[filterLabel]?.includes(filterValue)) {
- e.stopPropagation()
- addActiveFilter(filterLabel, filterValue)
- } else {
- // otherwise remove it
- handleRemoveFilter(e, filterLabel, filterValue)
- }
- }
-
- const handleRemoveFilter = (e, filterLabel, filterValue) => {
- e.stopPropagation()
- removeActiveFilter(filterLabel, filterValue)
- }
-
- return (
-
- {filterLabels.map((filterLabel) => {
- let value = alert?.labels?.[filterLabel]
- let isActive = activeFilters?.[filterLabel]?.includes(value)
-
- return (
- value && (
- handleLabelClick(e, filterLabel, value)}
- closeable={isActive}
- onClose={(e, _) => handleRemoveFilter(e, filterLabel, value)}
- />
- )
- )
- })}
-
- )
-}
-
-export default AlertLabels
diff --git a/apps/supernova/src/components/alerts/shared/AlertLinks.jsx b/apps/supernova/src/components/alerts/shared/AlertLinks.jsx
deleted file mode 100644
index 0ba9a37e7..000000000
--- a/apps/supernova/src/components/alerts/shared/AlertLinks.jsx
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import React from "react"
-
-import { Stack } from "juno-ui-components"
-
-const AlertLinks = ({ alert, className }) => {
-
- return (
-
- {alert?.generatorURL && (
- e.stopPropagation()}
- >
- Prometheus
-
- )}
- {alert?.labels?.playbook && (
- e.stopPropagation()}
- >
- Playbook
-
- )}
- {alert?.labels?.kibana && (
- e.stopPropagation()}
- >
- Logs
-
- )}
- {alert?.labels?.dashboard && (
- e.stopPropagation()}
- >
- Grafana
-
- )}
- {alert?.labels?.spc && (
- e.stopPropagation()}
- >
- SPC Ticket
-
- )}
- {alert?.labels?.sentry && (
- e.stopPropagation()}
- >
- Sentry
-
- )}
- {alert?.labels?.cloudops && (
- e.stopPropagation()}
- >
- CloudOps
-
- )}
- {alert?.labels?.report && (
- e.stopPropagation()}
- >
- Report
-
- )}
- {alert?.annotations?.mail_subject && (
- e.stopPropagation()}
- >
- Email Owner
-
- )}
-
- )
-}
-
-export default AlertLinks
diff --git a/apps/supernova/src/components/alerts/shared/AlertRegion.jsx b/apps/supernova/src/components/alerts/shared/AlertRegion.jsx
deleted file mode 100644
index 04e4e2d14..000000000
--- a/apps/supernova/src/components/alerts/shared/AlertRegion.jsx
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import React from "react"
-
-
-const AlertRegion = ({ region, cluster }) => {
-
- return (
- <>
- {region}
- {region !== cluster && (
- <>
-
- {cluster}
- >
- )}
- >
- )
-}
-
-export default AlertRegion
\ No newline at end of file
diff --git a/apps/supernova/src/components/alerts/shared/AlertSilencesList.jsx b/apps/supernova/src/components/alerts/shared/AlertSilencesList.jsx
deleted file mode 100644
index 1f3601cf8..000000000
--- a/apps/supernova/src/components/alerts/shared/AlertSilencesList.jsx
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import React, { useMemo } from "react"
-import { DateTime } from "luxon"
-
-import {
- Badge,
- DataGrid,
- DataGridCell,
- DataGridHeadCell,
- DataGridRow,
-} from "juno-ui-components"
-
-import { useSilencesActions } from "../../../hooks/useAppStore"
-
-const badgeVariant = (state) => {
- switch (state) {
- case "active":
- return "info"
- case "processing":
- return "warning"
- default:
- return "default"
- }
-}
-
-const AlertSilencesList = ({ alert }) => {
- const dateFormat = { ...DateTime.DATETIME_SHORT }
- const timeFormat = { ...DateTime.TIME_24_WITH_SHORT_OFFSET }
-
- const formatDateTime = (timestamp) => {
- const time = DateTime.fromISO(timestamp)
- return time.toLocaleString(dateFormat)
- }
-
- const { getMappingSilences, getExpiredSilences } = useSilencesActions()
-
- const activeSilences = getMappingSilences(alert)
- const expiredSilences = getExpiredSilences(alert)
- console.log("expiredSilences", expiredSilences)
- const silenceList = activeSilences.concat(expiredSilences)
-
- return (
- <>
- {silenceList.length > 0 && (
- <>
-
Silences
-
-
- Status
- Silence start
- Silence end
- Created by
- Comment
-
- {silenceList.map((silence) => (
-
-
-
- The default silence configuration excludes the following
- matchers because they typically make the silence too specific
- which can lead to alerts bypassing the silence unexpectedly. If
- you do want to include any of these matchers in the silence
- configuration, click on them to add them. If you change your
- mind, click again to remove.
-
+ )
+}
+
+NavigationItem.propTypes = {
+ /** Whether the navigation item is the currently active item. If an acitve item is set on the parent, the one on the parent will win. */
+ active: PropTypes.bool,
+ /** Styles to apply to the active item*/
+ activeItemStyles: PropTypes.string,
+ /** The aria-label of the item */
+ ariaLabel: PropTypes.string,
+ /** Pass custom classNames to the item itself. */
+ className: PropTypes.string,
+ /** The child string of the item. Will override `label` when passed. */
+ children: PropTypes.string,
+ /** Whether the item is disabled */
+ disabled: PropTypes.bool,
+ /** An icon to render in the item */
+ icon: PropTypes.oneOf(knownIcons),
+ /* Pass styles that apply to IN-active items only, in the event activeStyles are overwritten by defaultStyles affecting the same CSS property*/
+ inactiveItemStyles: PropTypes.string,
+ /** The label of the item. Will be rendered if no children are passed */
+ label: PropTypes.string,
+ /** The href of the item. The item will be rendered as an `` element when passed, instead of a `