diff --git a/.github/workflows/update-dependencies.yml b/.github/workflows/update-dependencies.yml
index 49832b1af..02b26b460 100644
--- a/.github/workflows/update-dependencies.yml
+++ b/.github/workflows/update-dependencies.yml
@@ -34,4 +34,4 @@ jobs:
git add dependencies.json
git commit -m "Update dependencies"
git push origin ${{ env.BRANCH_NAME }}
- gh pr create -f -B main
+ gh pr create -f -B main --head ${{ env.BRANCH_NAME }}
diff --git a/eslint.config.mjs b/eslint.config.mjs
index 64332d716..971ae0ac8 100644
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -37,7 +37,7 @@ export default tseslint.config(
files: ["**/*.tsx"],
...reactPlugin.configs.flat["jsx-runtime"]
},
- // TODO: Fix types by updating "eslint-plugin-react-hooks" once the following issue is resolved
+ // TODO: fix types by updating "eslint-plugin-react-hooks" once the following issue is resolved
// https://github.com/facebook/react/issues/28313
// https://github.com/facebook/react/pull/30774
{
@@ -74,5 +74,15 @@ export default tseslint.config(
rules: {
"react/jsx-curly-brace-presence": "off"
}
+ },
+ {
+ files: ["src/redux/services/digmaCodeGen.ts"],
+ rules: {
+ "@typescript-eslint/dot-notation": "warn",
+ "@typescript-eslint/no-redundant-type-constituents": "warn",
+ "@typescript-eslint/no-explicit-any": "warn",
+ "@typescript-eslint/consistent-indexed-object-style": "warn",
+ "@typescript-eslint/consistent-type-definitions": "warn"
+ }
}
);
diff --git a/openapi-config.ts b/openapi-config.ts
new file mode 100644
index 000000000..8c2d5455d
--- /dev/null
+++ b/openapi-config.ts
@@ -0,0 +1,57 @@
+import type { ConfigFile } from "@rtk-query/codegen-openapi";
+
+const config: ConfigFile = {
+ schemaFile: "./swagger.json",
+ apiFile: "./src/redux/services/digmaEmpty.ts",
+ apiImport: "digmaEmptyApi",
+ outputFile: "./src/redux/services/digmaCodeGen.ts",
+ exportName: "digmaCodeGenApi",
+ endpointOverrides: [
+ "postCodeAnalyticsErrorsCodeobjectSummary",
+ "postCodeAnalyticsCodeObjectsRecentActivity",
+ "postCodeAnalyticsCodeObjectsLens",
+ "postCodeAnalyticsCodeobjectsStatus",
+ "postCodeAnalyticsCodeObjectsSpanNavigation",
+ "postCodeAnalyticsEventsLatest",
+ "postCodeAnalyticsUserUsageStats",
+ "postErrors",
+ "postErrorsFilters",
+ "postGraphsGraphForSpanScaling",
+ "postGraphsGraphForSpanPercentiles",
+ "postHighlightsPerformance",
+ "postHighlightsTopInsights",
+ "postInsightsGetMethodUsage",
+ "postInsightsTypesForJaeger",
+ "postInsightsIssues",
+ "postHighlightsImpact",
+ "postHighlightsScaling",
+ "postLiveDataLiveData",
+ "postReportsServicesIssues",
+ "postReportsEndpointsIssues",
+ "postTestingGetLatestTestsOfSpan"
+ ].map((pattern) => ({
+ pattern,
+ type: "query"
+ })),
+ filterEndpoints: [
+ /About/,
+ /Assets/,
+ /Authentication/,
+ /CodeAnalytics/,
+ /Dashboard/,
+ /Environments/,
+ /Errors/,
+ /Graphs/,
+ /Highlights/,
+ /Insights/,
+ /InsightsActions/,
+ /LiveData/,
+ /Reports/,
+ /Services/,
+ /Spans/,
+ /Testing/
+ ],
+ hooks: true
+};
+
+export default config;
diff --git a/package-lock.json b/package-lock.json
index 06ad01ba8..884e1de10 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -44,6 +44,7 @@
"@babel/preset-typescript": "^7.23.2",
"@eslint/js": "^9.16.0",
"@octokit/rest": "^21.0.2",
+ "@rtk-query/codegen-openapi": "^2.0.0",
"@storybook/addon-a11y": "^8.4.7",
"@storybook/addon-designs": "^8.0.4",
"@storybook/addon-essentials": "^8.4.7",
@@ -124,6 +125,99 @@
"node": ">=6.0.0"
}
},
+ "node_modules/@apidevtools/json-schema-ref-parser": {
+ "version": "11.7.2",
+ "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-11.7.2.tgz",
+ "integrity": "sha512-4gY54eEGEstClvEkGnwVkTkrx0sqwemEFG5OSRRn3tD91XH0+Q8XIkYIfo7IwEWPpJZwILb9GUXeShtplRc/eA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jsdevtools/ono": "^7.1.3",
+ "@types/json-schema": "^7.0.15",
+ "js-yaml": "^4.1.0"
+ },
+ "engines": {
+ "node": ">= 16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/philsturgeon"
+ }
+ },
+ "node_modules/@apidevtools/openapi-schemas": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz",
+ "integrity": "sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@apidevtools/swagger-methods": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz",
+ "integrity": "sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@apidevtools/swagger-parser": {
+ "version": "10.1.1",
+ "resolved": "https://registry.npmjs.org/@apidevtools/swagger-parser/-/swagger-parser-10.1.1.tgz",
+ "integrity": "sha512-u/kozRnsPO/x8QtKYJOqoGtC4kH6yg1lfYkB9Au0WhYB0FNLpyFusttQtvhlwjtG3rOwiRz4D8DnnXa8iEpIKA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@apidevtools/json-schema-ref-parser": "11.7.2",
+ "@apidevtools/openapi-schemas": "^2.1.0",
+ "@apidevtools/swagger-methods": "^3.0.2",
+ "@jsdevtools/ono": "^7.1.3",
+ "ajv": "^8.17.1",
+ "ajv-draft-04": "^1.0.0",
+ "call-me-maybe": "^1.0.2"
+ },
+ "peerDependencies": {
+ "openapi-types": ">=7"
+ }
+ },
+ "node_modules/@apidevtools/swagger-parser/node_modules/ajv": {
+ "version": "8.17.1",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
+ "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3",
+ "fast-uri": "^3.0.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/@apidevtools/swagger-parser/node_modules/ajv-draft-04": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz",
+ "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "ajv": "^8.5.0"
+ },
+ "peerDependenciesMeta": {
+ "ajv": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@apidevtools/swagger-parser/node_modules/json-schema-traverse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@babel/code-frame": {
"version": "7.25.7",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.25.7.tgz",
@@ -2652,6 +2746,13 @@
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
+ "node_modules/@exodus/schemasafe": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@exodus/schemasafe/-/schemasafe-1.3.0.tgz",
+ "integrity": "sha512-5Aap/GaRupgNx/feGBwLLTVv8OQFfv3pq2lPRzPg9R+IOBnDgghTGW7l7EuVXOvg5cc/xSAlRW8rBrjIC3Nvqw==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@figspec/components": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@figspec/components/-/components-1.0.3.tgz",
@@ -3730,6 +3831,13 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
+ "node_modules/@jsdevtools/ono": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz",
+ "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@jsonjoy.com/base64": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz",
@@ -3872,6 +3980,14 @@
"node": ">= 8"
}
},
+ "node_modules/@oazapfts/runtime": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@oazapfts/runtime/-/runtime-1.0.3.tgz",
+ "integrity": "sha512-8tKiYffhwTGHSHYGnZ3oneLGCjX0po/XAXQ5Ng9fqKkvIdl/xz8+Vh8i+6xjzZqvZ2pLVpUcuSfnvNI/x67L0g==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true
+ },
"node_modules/@octokit/auth-token": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-5.1.1.tgz",
@@ -4069,6 +4185,52 @@
"node": ">=14.0.0"
}
},
+ "node_modules/@rtk-query/codegen-openapi": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@rtk-query/codegen-openapi/-/codegen-openapi-2.0.0.tgz",
+ "integrity": "sha512-uIOshfqX6bcsMpiwUMKAC+oFEw2fUxICMruhXunB6wq7tHpUg2b+gz+qGjiWAWw1Ly6g6jjvb3N4HRxWy9Yqew==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@apidevtools/swagger-parser": "^10.0.2",
+ "commander": "^6.2.0",
+ "lodash.camelcase": "^4.3.0",
+ "oazapfts": "^6.1.0",
+ "prettier": "^3.2.5",
+ "semver": "^7.3.5",
+ "swagger2openapi": "^7.0.4",
+ "typescript": "^5.5.4"
+ },
+ "bin": {
+ "rtk-query-codegen-openapi": "lib/bin/cli.mjs"
+ }
+ },
+ "node_modules/@rtk-query/codegen-openapi/node_modules/commander": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
+ "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/@rtk-query/codegen-openapi/node_modules/prettier": {
+ "version": "3.4.2",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz",
+ "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "prettier": "bin/prettier.cjs"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/prettier/prettier?sponsor=1"
+ }
+ },
"node_modules/@sinclair/typebox": {
"version": "0.27.8",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
@@ -7528,6 +7690,13 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/call-me-maybe": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz",
+ "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/callsites": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
@@ -9591,6 +9760,13 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/es6-promise": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz",
+ "integrity": "sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/esbuild": {
"version": "0.24.0",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.0.tgz",
@@ -10264,6 +10440,13 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/fast-safe-stringify": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz",
+ "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/fast-uri": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.3.tgz",
@@ -11486,6 +11669,13 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/http2-client": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/http2-client/-/http2-client-1.3.5.tgz",
+ "integrity": "sha512-EC2utToWl4RKfs5zd36Mxq7nzHHBuomZboI0yYL6Y0RmBgT7Sgkq4rQ0ezFTYoIsSs7Tm9SJe+o2FcAg6GBhGA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/https-proxy-agent": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
@@ -14987,6 +15177,13 @@
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
+ "node_modules/lodash.camelcase": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
+ "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/lodash.clamp": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/lodash.clamp/-/lodash.clamp-4.0.3.tgz",
@@ -15596,6 +15793,65 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/node-fetch": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
+ "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "whatwg-url": "^5.0.0"
+ },
+ "engines": {
+ "node": "4.x || >=6.0.0"
+ },
+ "peerDependencies": {
+ "encoding": "^0.1.0"
+ },
+ "peerDependenciesMeta": {
+ "encoding": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/node-fetch-h2": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/node-fetch-h2/-/node-fetch-h2-2.3.0.tgz",
+ "integrity": "sha512-ofRW94Ab0T4AOh5Fk8t0h8OBWrmjb0SSB20xh1H8YnPV9EJ+f5AMoYSUQ2zgJ4Iq2HAK0I2l5/Nequ8YzFS3Hg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "http2-client": "^1.2.5"
+ },
+ "engines": {
+ "node": "4.x || >=6.0.0"
+ }
+ },
+ "node_modules/node-fetch/node_modules/tr46": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/node-fetch/node_modules/webidl-conversions": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
+ "dev": true,
+ "license": "BSD-2-Clause"
+ },
+ "node_modules/node-fetch/node_modules/whatwg-url": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+ "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "tr46": "~0.0.3",
+ "webidl-conversions": "^3.0.0"
+ }
+ },
"node_modules/node-forge": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
@@ -15613,6 +15869,16 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/node-readfiles": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/node-readfiles/-/node-readfiles-0.2.0.tgz",
+ "integrity": "sha512-SU00ZarexNlE4Rjdm83vglt5Y9yiQ+XI1XpflWlb7q7UTN1JUItm69xMeiQCTxtTfnzt+83T8Cx+vI2ED++VDA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es6-promise": "^3.2.1"
+ }
+ },
"node_modules/node-releases": {
"version": "2.0.18",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz",
@@ -15659,6 +15925,102 @@
"integrity": "sha512-cTGB9ptp9dY9A5VbMSe7fQBcl/tt22Vcqdq8+eN93rblOuE0aCFu4aZ2vMwct/2t+lFnosm8RkQW1I0Omb1UtQ==",
"dev": true
},
+ "node_modules/oas-kit-common": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/oas-kit-common/-/oas-kit-common-1.0.8.tgz",
+ "integrity": "sha512-pJTS2+T0oGIwgjGpw7sIRU8RQMcUoKCDWFLdBqKB2BNmGpbBMH2sdqAaOXUg8OzonZHU0L7vfJu1mJFEiYDWOQ==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "fast-safe-stringify": "^2.0.7"
+ }
+ },
+ "node_modules/oas-linter": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/oas-linter/-/oas-linter-3.2.2.tgz",
+ "integrity": "sha512-KEGjPDVoU5K6swgo9hJVA/qYGlwfbFx+Kg2QB/kd7rzV5N8N5Mg6PlsoCMohVnQmo+pzJap/F610qTodKzecGQ==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@exodus/schemasafe": "^1.0.0-rc.2",
+ "should": "^13.2.1",
+ "yaml": "^1.10.0"
+ },
+ "funding": {
+ "url": "https://github.com/Mermade/oas-kit?sponsor=1"
+ }
+ },
+ "node_modules/oas-resolver": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/oas-resolver/-/oas-resolver-2.5.6.tgz",
+ "integrity": "sha512-Yx5PWQNZomfEhPPOphFbZKi9W93CocQj18NlD2Pa4GWZzdZpSJvYwoiuurRI7m3SpcChrnO08hkuQDL3FGsVFQ==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "node-fetch-h2": "^2.3.0",
+ "oas-kit-common": "^1.0.8",
+ "reftools": "^1.1.9",
+ "yaml": "^1.10.0",
+ "yargs": "^17.0.1"
+ },
+ "bin": {
+ "resolve": "resolve.js"
+ },
+ "funding": {
+ "url": "https://github.com/Mermade/oas-kit?sponsor=1"
+ }
+ },
+ "node_modules/oas-schema-walker": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/oas-schema-walker/-/oas-schema-walker-1.1.5.tgz",
+ "integrity": "sha512-2yucenq1a9YPmeNExoUa9Qwrt9RFkjqaMAA1X+U7sbb0AqBeTIdMHky9SQQ6iN94bO5NW0W4TRYXerG+BdAvAQ==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "funding": {
+ "url": "https://github.com/Mermade/oas-kit?sponsor=1"
+ }
+ },
+ "node_modules/oas-validator": {
+ "version": "5.0.8",
+ "resolved": "https://registry.npmjs.org/oas-validator/-/oas-validator-5.0.8.tgz",
+ "integrity": "sha512-cu20/HE5N5HKqVygs3dt94eYJfBi0TsZvPVXDhbXQHiEityDN+RROTleefoKRKKJ9dFAF2JBkDHgvWj0sjKGmw==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "call-me-maybe": "^1.0.1",
+ "oas-kit-common": "^1.0.8",
+ "oas-linter": "^3.2.2",
+ "oas-resolver": "^2.5.6",
+ "oas-schema-walker": "^1.1.5",
+ "reftools": "^1.1.9",
+ "should": "^13.2.1",
+ "yaml": "^1.10.0"
+ },
+ "funding": {
+ "url": "https://github.com/Mermade/oas-kit?sponsor=1"
+ }
+ },
+ "node_modules/oazapfts": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/oazapfts/-/oazapfts-6.1.0.tgz",
+ "integrity": "sha512-+E0db72jn0AMJ36ZzEXF3qCZ+T4pnOem/tmiJVql1Kx4qkWBE4YGeiUicp3gkzLJ/OrmpvSyAufI8eZ7sODCYg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@apidevtools/swagger-parser": "^10.1.0",
+ "lodash": "^4.17.21",
+ "minimist": "^1.2.8",
+ "swagger2openapi": "^7.0.8",
+ "tapable": "^2.2.1",
+ "typescript": "^5.4.5"
+ },
+ "bin": {
+ "oazapfts": "cli.js"
+ },
+ "peerDependencies": {
+ "@oazapfts/runtime": "*"
+ }
+ },
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
@@ -15839,6 +16201,14 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/openapi-types": {
+ "version": "12.1.3",
+ "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz",
+ "integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true
+ },
"node_modules/optionator": {
"version": "0.9.4",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
@@ -17190,6 +17560,16 @@
"node": ">=6"
}
},
+ "node_modules/reftools": {
+ "version": "1.1.9",
+ "resolved": "https://registry.npmjs.org/reftools/-/reftools-1.1.9.tgz",
+ "integrity": "sha512-OVede/NQE13xBQ+ob5CKd5KyeJYU2YInb1bmV4nRoOfquZPkAkxuOXicSe1PvqIuZZ4kD13sPKBbR7UFDmli6w==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "funding": {
+ "url": "https://github.com/Mermade/oas-kit?sponsor=1"
+ }
+ },
"node_modules/regenerate": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
@@ -17993,6 +18373,66 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/should": {
+ "version": "13.2.3",
+ "resolved": "https://registry.npmjs.org/should/-/should-13.2.3.tgz",
+ "integrity": "sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "should-equal": "^2.0.0",
+ "should-format": "^3.0.3",
+ "should-type": "^1.4.0",
+ "should-type-adaptors": "^1.0.1",
+ "should-util": "^1.0.0"
+ }
+ },
+ "node_modules/should-equal": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-2.0.0.tgz",
+ "integrity": "sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "should-type": "^1.4.0"
+ }
+ },
+ "node_modules/should-format": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/should-format/-/should-format-3.0.3.tgz",
+ "integrity": "sha512-hZ58adtulAk0gKtua7QxevgUaXTTXxIi8t41L3zo9AHvjXO1/7sdLECuHeIN2SRtYXpNkmhoUP2pdeWgricQ+Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "should-type": "^1.3.0",
+ "should-type-adaptors": "^1.0.1"
+ }
+ },
+ "node_modules/should-type": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz",
+ "integrity": "sha512-MdAsTu3n25yDbIe1NeN69G4n6mUnJGtSJHygX3+oN0ZbO3DTiATnf7XnYJdGT42JCXurTb1JI0qOBR65shvhPQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/should-type-adaptors": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.1.0.tgz",
+ "integrity": "sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "should-type": "^1.3.0",
+ "should-util": "^1.0.0"
+ }
+ },
+ "node_modules/should-util": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/should-util/-/should-util-1.0.1.tgz",
+ "integrity": "sha512-oXF8tfxx5cDk8r2kYqlkUJzZpDBqVY/II2WhvU0n9Y3XYvAYRmeaf1PvvIvTgPnv4KJ+ES5M0PyDq5Jp+Ygy2g==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/side-channel": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
@@ -18980,6 +19420,34 @@
"integrity": "sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==",
"dev": true
},
+ "node_modules/swagger2openapi": {
+ "version": "7.0.8",
+ "resolved": "https://registry.npmjs.org/swagger2openapi/-/swagger2openapi-7.0.8.tgz",
+ "integrity": "sha512-upi/0ZGkYgEcLeGieoz8gT74oWHA0E7JivX7aN9mAf+Tc7BQoRBvnIGHoPDw+f9TXTW4s6kGYCZJtauP6OYp7g==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "call-me-maybe": "^1.0.1",
+ "node-fetch": "^2.6.1",
+ "node-fetch-h2": "^2.3.0",
+ "node-readfiles": "^0.2.0",
+ "oas-kit-common": "^1.0.8",
+ "oas-resolver": "^2.5.6",
+ "oas-schema-walker": "^1.1.5",
+ "oas-validator": "^5.0.8",
+ "reftools": "^1.1.9",
+ "yaml": "^1.10.0",
+ "yargs": "^17.0.1"
+ },
+ "bin": {
+ "boast": "boast.js",
+ "oas-validate": "oas-validate.js",
+ "swagger2openapi": "swagger2openapi.js"
+ },
+ "funding": {
+ "url": "https://github.com/Mermade/oas-kit?sponsor=1"
+ }
+ },
"node_modules/symbol-tree": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
diff --git a/package.json b/package.json
index 02e8e5caa..b69c3d2a1 100644
--- a/package.json
+++ b/package.json
@@ -13,6 +13,7 @@
"start": "webpack serve --config webpack.dev.ts --env PLATFORM=Web",
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build",
+ "generate-types": "npx @rtk-query/codegen-openapi openapi-config.ts",
"get-jaeger-ui": "node --experimental-transform-types ./scripts/get-jaeger-ui.mts",
"update-dependencies": "node --experimental-transform-types ./scripts/update-dependencies.mts",
"prebuild": "rimraf dist && npm run get-jaeger-ui",
@@ -54,6 +55,7 @@
"@babel/preset-typescript": "^7.23.2",
"@eslint/js": "^9.16.0",
"@octokit/rest": "^21.0.2",
+ "@rtk-query/codegen-openapi": "^2.0.0",
"@storybook/addon-a11y": "^8.4.7",
"@storybook/addon-designs": "^8.0.4",
"@storybook/addon-essentials": "^8.4.7",
diff --git a/src/components/Admin/Reports/CodeIssues/Header/styles.ts b/src/components/Admin/Reports/CodeIssues/Header/styles.ts
deleted file mode 100644
index afb878773..000000000
--- a/src/components/Admin/Reports/CodeIssues/Header/styles.ts
+++ /dev/null
@@ -1,86 +0,0 @@
-import styled from "styled-components";
-import {
- subheading2BoldTypography,
- subheading2RegularTypography
-} from "../../../../common/App/typographies";
-import { Select } from "../../../../common/v3/Select";
-import { Toggle } from "../../../../common/v3/Toggle";
-import { OptionButton } from "../../../../common/v3/Toggle/styles";
-
-export const Container = styled.div`
- display: flex;
- gap: 24px;
- flex-direction: column;
-`;
-
-export const TitleContainer = styled.div`
- display: flex;
- gap: 8px;
- overflow: hidden;
-`;
-
-export const Title = styled.span`
- ${subheading2BoldTypography}
-
- overflow: hidden;
- white-space: nowrap;
- text-overflow: ellipsis;
- color: ${({ theme }) => theme.colors.v3.text.primary};
-`;
-
-export const TitleSuffix = styled.span`
- ${subheading2RegularTypography}
-
- color: ${({ theme }) => theme.colors.v3.text.secondary};
-`;
-
-export const Row = styled.div`
- display: flex;
- justify-content: space-between;
- align-items: center;
- gap: 18px;
-`;
-
-export const FilterSelect = styled(Select)`
- height: 36px;
- min-width: 190px;
- border-radius: 8px;
-`;
-
-export const Filters = styled(Row)`
- display: flex;
- gap: 18px;
-`;
-
-const StyledToggle = styled(Toggle)`
- align-items: center;
- background-color: transparent;
- border-radius: 8px;
- border-color: ${({ theme }) => theme.colors.v3.stroke.primaryLight};
-`;
-
-export const ViewModeToggle = styled(StyledToggle)`
- padding: 6px;
-
- ${OptionButton} {
- padding: 6px;
- }
-`;
-
-export const TimeModeToggle = styled(StyledToggle)`
- padding: 0;
-
- ${OptionButton} {
- padding: 10px 16px;
-
- &:first-child {
- border-bottom-right-radius: 0;
- border-top-right-radius: 0;
- }
-
- &:last-child {
- border-bottom-left-radius: 0;
- border-top-left-radius: 0;
- }
- }
-`;
diff --git a/src/components/Admin/Reports/CodeIssues/Header/types.ts b/src/components/Admin/Reports/CodeIssues/Header/types.ts
deleted file mode 100644
index 4374b2435..000000000
--- a/src/components/Admin/Reports/CodeIssues/Header/types.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-export interface HeaderProps {
- onGoBack: () => void;
-}
-export interface GetServicesPayload {
- environment: string | null;
-}
diff --git a/src/components/Admin/Reports/CodeIssues/index.tsx b/src/components/Admin/Reports/CodeIssues/index.tsx
index 48e0153b0..87210cac5 100644
--- a/src/components/Admin/Reports/CodeIssues/index.tsx
+++ b/src/components/Admin/Reports/CodeIssues/index.tsx
@@ -1,41 +1,28 @@
-import { useEffect, useMemo } from "react";
import {
useAdminDispatch,
useAdminSelector
} from "../../../../containers/Admin/hooks";
-import { getFeatureFlagValue } from "../../../../featureFlags";
-import {
- useGetAboutQuery,
- useGetEndpointsIssuesQuery,
- useGetEnvironmentServicesQuery,
- useGetEnvironmentsQuery,
- useGetServicesIssuesQuery
-} from "../../../../redux/services/digma";
+import { useMount } from "../../../../hooks/useMount";
+import type { IssueCriticality } from "../../../../redux/services/types";
import {
+ clear,
+ setCriticalityLevels,
+ setPeriodInDays,
+ setSelectedEndpoints,
setSelectedEnvironmentId,
setSelectedService,
- setViewLevel
-} from "../../../../redux/slices/codeIssuesReportSlice";
-import { FeatureFlag } from "../../../../types";
-import { Chart } from "../../../Dashboard/MetricsReport/Chart";
-import { EmptyState } from "../../../Dashboard/MetricsReport/EmptyState";
-import { Table } from "../../../Dashboard/MetricsReport/Table";
-import type {
- EndpointIssuesData,
- GetMetricsReportDataPayloadV1,
- GetMetricsReportDataPayloadV2,
- ScoreCriterion,
- ServiceIssuesData
-} from "../../../Dashboard/MetricsReport/types";
-import {
- transformEndpointsData,
- transformServicesData
-} from "../../../Dashboard/MetricsReport/utils";
-import { Header } from "./Header";
+ setSelectedServices,
+ setTimeMode,
+ setViewLevel,
+ setViewMode,
+ type IssuesReportTimeMode,
+ type IssuesReportViewLevel,
+ type IssuesReportViewMode
+} from "../../../../redux/slices/issuesReportSlice";
+import { IssuesReport } from "../../../common/IssuesReport";
import * as s from "./styles";
export const CodeIssues = () => {
- // TODO: create selectors
const selectedEnvironmentId = useAdminSelector(
(state) => state.codeIssuesReport.selectedEnvironmentId
);
@@ -62,208 +49,87 @@ export const CodeIssues = () => {
const dispatch = useAdminDispatch();
- const { data: about } = useGetAboutQuery();
-
- const { data: environments } = useGetEnvironmentsQuery();
-
- useEffect(() => {
- if (environments && environments.length > 0 && !selectedEnvironmentId) {
- dispatch(setSelectedEnvironmentId(environments[0].id));
- }
- }, [environments, selectedEnvironmentId, dispatch]);
+ useMount(() => {
+ return () => {
+ dispatch(clear());
+ };
+ });
- const isInitialized = Boolean(environments && about);
-
- const { data: services } = useGetEnvironmentServicesQuery(
- {
- environment: selectedEnvironmentId ?? null
- },
+ const handleTileTitleClick = () =>
+ // viewLevel: IssuesReportViewLevel,
+ // value: string
{
- skip: !selectedEnvironmentId || viewLevel !== "services"
- }
- );
-
- const isDataFilterEnabled = Boolean(
- about &&
- getFeatureFlagValue(
- about,
- FeatureFlag.IS_METRICS_REPORT_DATA_FILTER_ENABLED
- )
- );
-
- const getServicesIssuesPayloadV1: GetMetricsReportDataPayloadV1 =
- useMemo(() => {
- const servicesArray =
- selectedServices.length > 0 ? selectedServices : services ?? [];
-
- return {
- keys: servicesArray.map((x) => ({
- environment: selectedEnvironmentId ?? "",
- service: x,
- lastDays: timeMode === "baseline" ? null : periodInDays
- }))
- };
- }, [
- selectedServices,
- services,
- selectedEnvironmentId,
- timeMode,
- periodInDays
- ]);
-
- const getServicesIssuesPayloadV2: GetMetricsReportDataPayloadV2 =
- useMemo(() => {
- const servicesArray =
- selectedServices.length > 0 ? selectedServices : services ?? [null];
-
- return {
- criticalities: criticalityLevels,
- keys: servicesArray.map((x) => ({
- environment: selectedEnvironmentId ?? "",
- service: x,
- lastDays: timeMode === "baseline" ? null : periodInDays
- }))
- };
- }, [
- selectedServices,
- services,
- selectedEnvironmentId,
- criticalityLevels,
- timeMode,
- periodInDays
- ]);
-
- const getServicesIssuesPayload = isDataFilterEnabled
- ? getServicesIssuesPayloadV2
- : getServicesIssuesPayloadV1;
+ // TODO: implement
+ };
- const { data: servicesIssues } = useGetServicesIssuesQuery(
- getServicesIssuesPayload,
+ const handleTileIssuesStatsClick = () =>
+ // viewLevel: IssuesReportViewLevel,
+ // value: string
{
- skip:
- !isInitialized ||
- !selectedEnvironmentId ||
- !services ||
- viewLevel !== "services"
- }
- );
+ // TODO: implement
+ };
- const { data: endpointsIssues } = useGetEndpointsIssuesQuery(
- {
- environment: selectedEnvironmentId ?? "",
- service: selectedService ?? "",
- endpoints: selectedEndpoints,
- criticalities: criticalityLevels,
- lastDays: timeMode === "baseline" ? null : periodInDays
- },
- {
- skip:
- !isInitialized ||
- !selectedEnvironmentId ||
- !selectedService ||
- viewLevel !== "endpoints"
- }
- );
-
- const handleTitleClick = (value: string) => {
- if (viewLevel === "services") {
- dispatch(setSelectedService(value));
- dispatch(setViewLevel("endpoints"));
- }
-
- // TODO: make optional for endpoints
+ const handleSelectedEnvironmentIdChange = (environmentId: string) => {
+ dispatch(setSelectedEnvironmentId(environmentId));
};
- const handleIssuesStatsClick = () => {
- // TODO: remove and make optional
+ const handleSelectedServicesChange = (services: string[]) => {
+ dispatch(setSelectedServices(services));
};
- const handleGoBack = () => {
- dispatch(setViewLevel("services"));
- dispatch(setSelectedService(null));
+ const handleSelectedEndpointsChange = (endpoints: string[]) => {
+ dispatch(setSelectedEndpoints(endpoints));
};
- const isCriticalityEnabled = Boolean(
- about &&
- getFeatureFlagValue(
- about,
- FeatureFlag.IS_METRICS_REPORT_CRITICALITY_ENABLED
- )
- );
-
- const scoreCriterion: ScoreCriterion = isCriticalityEnabled
- ? "criticality"
- : "impact";
+ const handleCriticalityLevelsChange = (criticalities: IssueCriticality[]) => {
+ dispatch(setCriticalityLevels(criticalities));
+ };
- const data =
- (viewLevel === "services"
- ? servicesIssues?.reports
- : endpointsIssues?.reports) ?? [];
- const transformedData =
- viewLevel === "services"
- ? transformServicesData(data as ServiceIssuesData[], scoreCriterion)
- : transformEndpointsData(data as EndpointIssuesData[], scoreCriterion);
+ const handlePeriodInDaysChange = (periodInDays: number) => {
+ dispatch(setPeriodInDays(periodInDays));
+ };
- const renderContent = () => {
- if (
- (viewLevel === "services" && !servicesIssues) ||
- (viewLevel === "endpoints" && !endpointsIssues)
- ) {
- return ;
- }
+ const handleTimeModeChange = (timeMode: IssuesReportTimeMode) => {
+ dispatch(setTimeMode(timeMode));
+ };
- if (data.length === 0) {
- if (viewLevel === "services") {
- return ;
- }
+ const handleViewModeChange = (viewMode: IssuesReportViewMode) => {
+ dispatch(setViewMode(viewMode));
+ };
- if (viewLevel === "endpoints") {
- return ;
- }
- }
+ const handleViewLevelChange = (viewLevel: IssuesReportViewLevel) => {
+ dispatch(setViewLevel(viewLevel));
+ };
- return (
- <>
- {viewMode === "table" && (
-
- )}
- {viewMode === "treemap" && (
-
- )}
- >
- );
+ const handleSelectedServiceChange = (service: string | null) => {
+ dispatch(setSelectedService(service));
};
return (
-
-
- {isInitialized ? (
- environments && environments.length > 0 ? (
- <>
-
- {renderContent()}
- >
- ) : (
-
- )
- ) : (
-
- )}
-
-
+
+
+
);
};
diff --git a/src/components/Admin/Reports/CodeIssues/styles.ts b/src/components/Admin/Reports/CodeIssues/styles.ts
index 938ce95a4..6bf807248 100644
--- a/src/components/Admin/Reports/CodeIssues/styles.ts
+++ b/src/components/Admin/Reports/CodeIssues/styles.ts
@@ -1,59 +1,7 @@
import styled from "styled-components";
-import { bodyRegularTypography } from "../../../common/App/typographies";
export const Container = styled.div`
- display: flex;
- flex-direction: column;
height: 100%;
- width: 100%;
- padding: 24px 24px 16px;
- gap: 24px;
+ padding: 24px;
box-sizing: border-box;
- overflow: auto;
`;
-
-export const Footer = styled.div`
- align-items: center;
- display: flex;
- justify-content: start;
- gap: 8px;
- margin-top: auto;
- color: ${({ theme }) => theme.colors.v3.text.disabled};
- ${bodyRegularTypography}
-`;
-
-export const Section = styled.div`
- display: flex;
- height: 100%;
- width: 100%;
- flex-direction: column;
- position: relative;
- overflow: auto;
-`;
-
-// export const ContainerBackgroundGradient = styled.div`
-// z-index: -1;
-// position: absolute;
-// margin: auto;
-// right: -24%;
-// bottom: -117%;
-// height: 160%;
-// width: 146%;
-// border-radius: 100%;
-// opacity: 0.7;
-// background: radial-gradient(
-// 50% 50% at 50% 50%,
-// rgb(79 93 163 / 60%) 0%,
-// rgb(79 93 163 / 0%) 100%
-// );
-// filter: blur(5px);
-// `;
-
-// export const SectionBackground = styled.div`
-// z-index: -1;
-// position: absolute;
-// inset: 0;
-// height: 100%;
-// width: 100%;
-// background: ${({ theme }) => theme.colors.v3.surface.secondary};
-// `;
diff --git a/src/components/Admin/styles.ts b/src/components/Admin/styles.ts
index 11d6337c6..b803fb4c8 100644
--- a/src/components/Admin/styles.ts
+++ b/src/components/Admin/styles.ts
@@ -10,10 +10,11 @@ export const ContentContainer = styled.div`
display: flex;
flex-direction: column;
flex-grow: 1;
+ height: 100%;
overflow: hidden;
`;
export const MainContainer = styled.main`
+ height: 100%;
overflow: auto;
- flex-grow: 1;
`;
diff --git a/src/components/Dashboard/MetricsReport/Chart/types.ts b/src/components/Dashboard/MetricsReport/Chart/types.ts
deleted file mode 100644
index 15bec0be9..000000000
--- a/src/components/Dashboard/MetricsReport/Chart/types.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import type {
- PresentationalReportData,
- ReportTimeMode,
- ReportViewLevel,
- ScoreCriterion
-} from "../types";
-
-export interface ChartProps {
- data: PresentationalReportData[];
- onTitleClick: (value: string) => void;
- onIssuesStatsClick: (value: string) => void;
- scoreCriterion: ScoreCriterion;
- viewLevel: ReportViewLevel;
- timeMode: ReportTimeMode;
-}
diff --git a/src/components/Dashboard/MetricsReport/Header/ReportHeader.stories.tsx b/src/components/Dashboard/MetricsReport/Header/ReportHeader.stories.tsx
deleted file mode 100644
index c3363437b..000000000
--- a/src/components/Dashboard/MetricsReport/Header/ReportHeader.stories.tsx
+++ /dev/null
@@ -1,50 +0,0 @@
-import type { Meta, StoryObj } from "@storybook/react";
-
-import { Header } from ".";
-import { actions as globalActions } from "../../../../actions";
-import { actions } from "../../actions";
-
-// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction
-const meta: Meta = {
- title: "Dashboard/MetricsReport/Header",
- component: Header,
- parameters: {
- // More on how to position stories at: https://storybook.js.org/docs/react/configure/story-layout
- layout: "fullscreen"
- }
-};
-
-export default meta;
-
-type Story = StoryObj;
-
-// More on writing stories with args: https://storybook.js.org/docs/react/writing-stories/args
-export const Default: Story = {
- play: () => {
- window.setTimeout(() => {
- window.postMessage({
- type: "digma",
- action: globalActions.SET_ENVIRONMENTS,
- payload: [
- {
- id: "test1",
- name: "test1",
- type: "Public"
- },
- {
- id: "test2",
- name: "test2",
- type: "Public"
- }
- ]
- });
- }, 500);
- window.setTimeout(() => {
- window.postMessage({
- type: "digma",
- action: actions.SET_SERVICES,
- payload: ["service 3", "service 1", "service 2", "service 4"]
- });
- }, 500);
- }
-};
diff --git a/src/components/Dashboard/MetricsReport/Header/index.tsx b/src/components/Dashboard/MetricsReport/Header/index.tsx
deleted file mode 100644
index 2320392fd..000000000
--- a/src/components/Dashboard/MetricsReport/Header/index.tsx
+++ /dev/null
@@ -1,395 +0,0 @@
-import { useEffect, useMemo } from "react";
-import { getFeatureFlagValue } from "../../../../featureFlags";
-import type { DataFetcherConfiguration } from "../../../../hooks/useFetchData";
-import { useFetchData } from "../../../../hooks/useFetchData";
-import { useConfigSelector } from "../../../../store/config/useConfigSelector";
-import { useMetricsReportSelector } from "../../../../store/metricsReport/useMetricsReportSelector";
-import { useStore } from "../../../../store/useStore";
-import { FeatureFlag } from "../../../../types";
-import { sendUserActionTrackingEvent } from "../../../../utils/actions/sendUserActionTrackingEvent";
-import { formatUnit } from "../../../../utils/formatUnit";
-import { CodeIcon } from "../../../common/icons/12px/CodeIcon";
-import { DurationBreakdownIcon } from "../../../common/icons/12px/DurationBreakdownIcon";
-import { WrenchIcon } from "../../../common/icons/12px/WrenchIcon";
-import { InfinityIcon } from "../../../common/icons/16px/InfinityIcon";
-import { TableIcon } from "../../../common/icons/16px/TableIcon";
-import { TreemapIcon } from "../../../common/icons/16px/TreemapIcon";
-import { ChevronIcon } from "../../../common/icons/20px/ChevronIcon";
-import { DatabaseIcon } from "../../../common/icons/DatabaseIcon";
-import { Direction } from "../../../common/icons/types";
-import type { ToggleValue } from "../../../common/Toggle/types";
-import { NewIconButton } from "../../../common/v3/NewIconButton";
-import { Tooltip } from "../../../common/v3/Tooltip";
-import { actions } from "../../actions";
-import { trackingEvents } from "../tracking";
-import type {
- Criticality,
- GetServiceEndpointsPayload,
- GetServiceEnvironmentsPayload,
- ReportTimeMode,
- ReportViewMode,
- SetServiceEndpointsPayload,
- SetServiceEnvironmentsPayload
-} from "../types";
-import * as s from "./styles";
-import type { GetServicesPayload, HeaderProps } from "./types";
-
-const criticalityOptions: { id: Criticality; label: string }[] = [
- {
- id: "High",
- label: "Critical"
- },
- {
- id: "Medium",
- label: "Medium"
- },
- {
- id: "Low",
- label: "Low"
- }
-];
-
-const DEFAULT_PERIOD = 7;
-
-export const Header = ({ onGoBack }: HeaderProps) => {
- const { environments, backendInfo } = useConfigSelector();
- const {
- metricsReportSelectedPeriodInDays: periodInDays,
- metricsReportViewLevel: viewLevel,
- metricsReportTimeMode: timeMode,
- metricsReportSelectedServices: selectedServices,
- metricsReportSelectedEndpoints: selectedEndpoints,
- metricsReportSelectedEnvironmentId: selectedEnvironmentId,
- metricsReportSelectedCriticalityLevels: selectedCriticalityLevels,
- metricsReportSelectedService: selectedService,
- metricsReportServiceEnvironments: serviceEnvironments,
- metricsReportViewMode: viewMode
- } = useMetricsReportSelector();
-
- const {
- setMetricsReportSelectedEnvironmentId: setSelectedEnvironmentId,
- setMetricsReportSelectedServices: setSelectedServices,
- setMetricsReportSelectedEndpoints: setSelectedEndpoints,
- setMetricsReportSelectedCriticalityLevels: setSelectedCriticalityLevels,
- setMetricsReportSelectedPeriodInDays: setPeriodInDays,
- setMetricsReportServiceEnvironments: setServiceEnvironments,
- setMetricsReportServiceEndpoints: setServiceEndpoints,
- setMetricsReportViewMode: setViewMode,
- setMetricsReportTimeMode: setTimeMode,
- setMetricsReportServices: setServices,
- setMetricsReportServicesIssuesData: setServicesIssuesData,
- setMetricsReportEndpointsIssuesData: setEndpointIssuesData
- } = useStore.getState();
-
- const environmentsToSelect = useMemo(
- () => (viewLevel === "services" ? environments : serviceEnvironments) ?? [],
- [viewLevel, environments, serviceEnvironments]
- );
-
- const selectedEnvironment = useMemo(
- () =>
- environmentsToSelect?.find((x) => x.id === selectedEnvironmentId) ?? null,
- [selectedEnvironmentId, environmentsToSelect]
- );
-
- const isDataFilterEnabled = Boolean(
- getFeatureFlagValue(
- backendInfo,
- FeatureFlag.IS_METRICS_REPORT_DATA_FILTER_ENABLED
- )
- );
-
- const dataFetcherServicesConfiguration: DataFetcherConfiguration = {
- requestAction: actions.GET_SERVICES,
- responseAction: actions.SET_SERVICES,
- refreshOnPayloadChange: true,
- isEnabled: Boolean(selectedEnvironmentId && viewLevel === "services")
- };
-
- const getServicesPayload: GetServicesPayload = useMemo(
- () => ({ environment: selectedEnvironmentId ?? null }),
- [selectedEnvironmentId]
- );
-
- const { data: services } = useFetchData(
- dataFetcherServicesConfiguration,
- getServicesPayload
- );
-
- useEffect(() => {
- if (services) {
- setServices(services);
- }
- }, [services, setServices]);
-
- const dataFetcherEnvironmentsConfiguration: DataFetcherConfiguration = {
- requestAction: actions.GET_SERVICE_ENVIRONMENTS,
- responseAction: actions.SET_SERVICE_ENVIRONMENTS,
- refreshOnPayloadChange: true,
- isEnabled: Boolean(
- selectedEnvironmentId && selectedService && viewLevel === "endpoints"
- )
- };
-
- const getEnvironmentsPayload: GetServiceEnvironmentsPayload = useMemo(
- () => ({
- service: selectedService ?? ""
- }),
- [selectedService]
- );
-
- const { data: serviceEnvironmentsData } = useFetchData<
- GetServiceEnvironmentsPayload,
- SetServiceEnvironmentsPayload
- >(dataFetcherEnvironmentsConfiguration, getEnvironmentsPayload);
-
- const dataFetcherEndpointsConfiguration: DataFetcherConfiguration = {
- requestAction: actions.GET_SERVICE_ENDPOINTS_DATA,
- responseAction: actions.SET_SERVICE_ENDPOINTS_DATA,
- refreshOnPayloadChange: true,
- isEnabled: Boolean(selectedEnvironmentId && selectedService)
- };
-
- useEffect(() => {
- if (serviceEnvironmentsData?.environments) {
- setServiceEnvironments(serviceEnvironmentsData?.environments);
- }
- }, [serviceEnvironmentsData, setServiceEnvironments]);
-
- const getEndpointsPayload: GetServiceEndpointsPayload = useMemo(
- () => ({
- environment: selectedEnvironmentId ?? "",
- service: selectedService ?? ""
- }),
- [selectedEnvironmentId, selectedService]
- );
-
- const { data: endpointsData } = useFetchData<
- GetServiceEndpointsPayload,
- SetServiceEndpointsPayload
- >(dataFetcherEndpointsConfiguration, getEndpointsPayload);
-
- useEffect(() => {
- if (endpointsData?.endpoints) {
- setServiceEndpoints(endpointsData.endpoints);
- }
- }, [endpointsData, setServiceEndpoints]);
-
- const handleGoBack = () => {
- onGoBack();
- };
-
- const handleSelectedEnvironmentChanged = (option: string | string[]) => {
- sendUserActionTrackingEvent(trackingEvents.ENVIRONMENT_FILTER_SELECTED);
- const newItem = Array.isArray(option) ? option[0] : option;
- setSelectedEnvironmentId(newItem);
- setSelectedServices([]);
- setSelectedEndpoints([]);
- };
-
- const handleSelectedServicesChanged = (option: string | string[]) => {
- sendUserActionTrackingEvent(trackingEvents.SERVICE_FILTER_SELECTED);
- const newItem = Array.isArray(option) ? option : [option];
- setSelectedServices(newItem);
- };
-
- const handleSelectedEndpointsChanged = (option: string | string[]) => {
- sendUserActionTrackingEvent(trackingEvents.ENDPOINT_FILTER_SELECTED);
- const newItem = Array.isArray(option) ? option : [option];
- setSelectedEndpoints(newItem);
- };
-
- const handleDataChanged = (option: string | string[]) => {
- sendUserActionTrackingEvent(trackingEvents.DATA_FILTER_SELECTED);
- const newItem = Array.isArray(option) ? option : [option];
- setSelectedCriticalityLevels(newItem as Criticality[]);
- };
-
- const handlePeriodChanged = (option: string | string[]) => {
- sendUserActionTrackingEvent(trackingEvents.PERIOD_FILTER_CHANGED);
- const newItem = Array.isArray(option) ? option : [option];
- if (newItem.length === 0) {
- setPeriodInDays(DEFAULT_PERIOD);
- return;
- }
-
- const value = newItem[0];
- const newValue = Number(value);
- setPeriodInDays(newValue);
- };
-
- const handleViewModeChanged = (value: ToggleValue) => {
- sendUserActionTrackingEvent(trackingEvents.VIEW_MODE_CHANGED, { value });
- const newViewMode = value as ReportViewMode;
- setViewMode(newViewMode);
- };
-
- const handleTimeModeChanged = (value: ToggleValue) => {
- sendUserActionTrackingEvent(trackingEvents.TIME_MODE_CHANGED, { value });
- const newTimeMode = value as ReportTimeMode;
- setTimeMode(newTimeMode);
- if (viewLevel === "services") {
- setServicesIssuesData(null);
- }
- if (viewLevel === "endpoints") {
- setEndpointIssuesData(null);
- }
- };
-
- const title =
- viewLevel === "endpoints"
- ? `${selectedService ?? ""} Service`
- : "Issues Map";
- const titleSuffix = viewLevel === "endpoints" ? " Endpoints" : "";
- const tooltipTitle = `${title} ${titleSuffix}`;
-
- return (
-
-
-
- {viewLevel === "endpoints" ? (
- <>
- (
-
- )}
- size={"small"}
- buttonType={"secondaryBorderless"}
- onClick={handleGoBack}
- />
-
-
- {title}
- {titleSuffix}
-
-
- >
- ) : (
- {title}
- )}
-
-
-
-
-
- a.name.localeCompare(b.name))
- .map((x) => ({
- label: x.name,
- value: x.id,
- enabled: true,
- selected: x.id === selectedEnvironmentId
- }))}
- showSelectedState={true}
- icon={(props) =>
- selectedEnvironment?.type === "Public" ? (
-
- ) : (
-
- )
- }
- onChange={handleSelectedEnvironmentChanged}
- placeholder={selectedEnvironment?.name ?? "Select Environments"}
- disabled={environmentsToSelect.length === 0}
- />
- {viewLevel === "endpoints" ? (
- ({
- label: x.displayName,
- value: x.spanCodeObjectId,
- enabled: true,
- selected: selectedEndpoints.includes(x.spanCodeObjectId)
- })) ?? []
- }
- useShift={false}
- sameWidth={false}
- showSelectedState={true}
- multiselect={true}
- icon={WrenchIcon}
- onChange={handleSelectedEndpointsChanged}
- searchable={true}
- placeholder={
- selectedEndpoints.length > 0 ? "Endpoints" : "All Endpoints"
- }
- disabled={!endpointsData || endpointsData.endpoints.length === 0}
- />
- ) : (
- ({
- label: service,
- value: service,
- enabled: true,
- selected: selectedServices.includes(service)
- })) ?? []
- }
- showSelectedState={true}
- multiselect={true}
- icon={WrenchIcon}
- onChange={handleSelectedServicesChanged}
- placeholder={
- selectedServices.length > 0 ? "Services" : "All Services"
- }
- disabled={!services || services.length === 0}
- />
- )}
- {timeMode === "changes" && (
- ({
- value: x.toString(),
- label: `${x} ${formatUnit(x, "Day")}`,
- selected: x === periodInDays,
- enabled: true
- }))}
- showSelectedState={false}
- icon={DurationBreakdownIcon}
- onChange={handlePeriodChanged}
- placeholder={`Period: ${periodInDays} ${formatUnit(
- periodInDays,
- "day"
- )}`}
- />
- )}
- {isDataFilterEnabled && (
- ({
- label: item.label,
- value: item.id,
- enabled: true,
- selected: selectedCriticalityLevels.includes(item.id)
- }))}
- multiselect={true}
- icon={DatabaseIcon}
- onChange={handleDataChanged}
- placeholder={"Data"}
- />
- )}
-
-
- },
- {
- value: "table",
- icon: (props) =>
- }
- ]}
- value={viewMode}
- onValueChange={handleViewModeChanged}
- />
-
-
- );
-};
diff --git a/src/components/Dashboard/MetricsReport/Header/types.ts b/src/components/Dashboard/MetricsReport/Header/types.ts
deleted file mode 100644
index 4374b2435..000000000
--- a/src/components/Dashboard/MetricsReport/Header/types.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-export interface HeaderProps {
- onGoBack: () => void;
-}
-export interface GetServicesPayload {
- environment: string | null;
-}
diff --git a/src/components/Dashboard/MetricsReport/MetricsReport.stories.tsx b/src/components/Dashboard/MetricsReport/MetricsReport.stories.tsx
index b5b84909c..569533b7c 100644
--- a/src/components/Dashboard/MetricsReport/MetricsReport.stories.tsx
+++ b/src/components/Dashboard/MetricsReport/MetricsReport.stories.tsx
@@ -1,8 +1,8 @@
import type { Meta, StoryObj } from "@storybook/react";
import { MetricsReport } from ".";
+import { mockedReport } from "../../common/IssuesReport/Table/mockData";
import { actions } from "../actions";
-import { mockedReport } from "./Table/mockData";
// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction
const meta: Meta = {
diff --git a/src/components/Dashboard/MetricsReport/index.tsx b/src/components/Dashboard/MetricsReport/index.tsx
index 16280f1b7..0b428aec3 100644
--- a/src/components/Dashboard/MetricsReport/index.tsx
+++ b/src/components/Dashboard/MetricsReport/index.tsx
@@ -1,68 +1,62 @@
-import { useEffect, useLayoutEffect, useMemo } from "react";
-import { getFeatureFlagValue } from "../../../featureFlags";
+import { useLayoutEffect } from "react";
+import {
+ useDashboardDispatch,
+ useDashboardSelector
+} from "../../../containers/Dashboard/hooks";
import { useMount } from "../../../hooks/useMount";
-import { useConfigSelector } from "../../../store/config/useConfigSelector";
-import { useMetricsReportSelector } from "../../../store/metricsReport/useMetricsReportSelector";
-import { useStore } from "../../../store/useStore";
+import { type IssueCriticality } from "../../../redux/services/types";
+import {
+ setCriticalityLevels,
+ setPeriodInDays,
+ setSelectedEndpoints,
+ setSelectedEnvironmentId,
+ setSelectedService,
+ setSelectedServices,
+ setTimeMode,
+ setViewLevel,
+ setViewMode,
+ type IssuesReportTimeMode,
+ type IssuesReportViewLevel,
+ type IssuesReportViewMode
+} from "../../../redux/slices/issuesReportSlice";
import { isString } from "../../../typeGuards/isString";
-import { FeatureFlag, SCOPE_CHANGE_EVENTS } from "../../../types";
+import { SCOPE_CHANGE_EVENTS } from "../../../types";
import { changeScope } from "../../../utils/actions/changeScope";
+import { IssuesReport } from "../../common/IssuesReport";
import { DigmaLogoIcon } from "../../common/icons/16px/DigmaLogoIcon";
import { actions } from "../actions";
-import { Chart } from "./Chart";
-import { EmptyState } from "./EmptyState";
-import { Header } from "./Header";
import * as s from "./styles";
-import { Table } from "./Table";
-import type {
- EndpointIssuesData,
- GetEndpointsIssuesPayload,
- ScoreCriterion,
- ServiceIssuesData,
- UseServicesIssuesDataProps
-} from "./types";
-import { useEndpointsIssuesData } from "./useEndpointsIssuesData";
-import { useServicesIssuesData } from "./useServicesIssuesData";
-import { transformEndpointsData, transformServicesData } from "./utils";
export const MetricsReport = () => {
- const { environments, backendInfo } = useConfigSelector();
- const {
- metricsReportViewLevel: viewLevel,
- metricsReportViewMode: viewMode,
- metricsReportTimeMode: timeMode,
- metricsReportSelectedEnvironmentId: selectedEnvironmentId,
- metricsReportSelectedService: selectedService,
- metricsReportSelectedServices: selectedServices,
- metricsReportSelectedCriticalityLevels: selectedCriticalityLevels,
- metricsReportSelectedPeriodInDays: selectedPeriodInDays,
- metricsReportSelectedEndpoints: selectedEndpoints,
- metricsReportServices: services,
- metricsReportServicesIssuesData: servicesIssuesData,
- metricsReportEndpointsIssuesData: endpointsIssuesData
- } = useMetricsReportSelector();
-
- const {
- setMetricsReportSelectedService: setSelectedService,
- setMetricsReportSelectedEnvironmentId: setSelectedEnvironmentId,
- setMetricsReportViewLevel: setViewLevel,
- setMetricsReportServicesIssuesData: setServicesIssuesData,
- setMetricsReportEndpointsIssuesData: setEndpointsIssuesData
- } = useStore.getState();
-
- const isCriticalityEnabled = Boolean(
- backendInfo &&
- getFeatureFlagValue(
- backendInfo,
- FeatureFlag.IS_METRICS_REPORT_CRITICALITY_ENABLED
- )
+ const selectedEnvironmentId = useDashboardSelector(
+ (state) => state.metricsReport.selectedEnvironmentId
+ );
+ const criticalityLevels = useDashboardSelector(
+ (state) => state.metricsReport.criticalityLevels
+ );
+ const periodInDays = useDashboardSelector(
+ (state) => state.metricsReport.periodInDays
+ );
+ const selectedService = useDashboardSelector(
+ (state) => state.metricsReport.selectedService
+ );
+ const selectedServices = useDashboardSelector(
+ (state) => state.metricsReport.selectedServices
+ );
+ const viewLevel = useDashboardSelector(
+ (state) => state.metricsReport.viewLevel
+ );
+ const viewMode = useDashboardSelector(
+ (state) => state.metricsReport.viewMode
+ );
+ const timeMode = useDashboardSelector(
+ (state) => state.metricsReport.timeMode
+ );
+ const selectedEndpoints = useDashboardSelector(
+ (state) => state.metricsReport.selectedEndpoints
);
- const scoreCriterion: ScoreCriterion = isCriticalityEnabled
- ? "criticality"
- : "impact";
-
- const isInitialized = environments && backendInfo;
+ const dispatch = useDashboardDispatch();
useLayoutEffect(() => {
window.sendMessageToDigma({
@@ -76,73 +70,6 @@ export const MetricsReport = () => {
}
});
- const useServiceIssuesDataPayload: UseServicesIssuesDataProps =
- useMemo(() => {
- return {
- environmentId: selectedEnvironmentId,
- services:
- selectedServices.length > 0 ? selectedServices : services ?? [],
- criticalities: selectedCriticalityLevels,
- lastDays: timeMode === "baseline" ? null : selectedPeriodInDays
- };
- }, [
- selectedEnvironmentId,
- selectedServices,
- selectedCriticalityLevels,
- selectedPeriodInDays,
- services,
- timeMode
- ]);
-
- const { data: servicesData } = useServicesIssuesData(
- useServiceIssuesDataPayload,
- Boolean(
- isInitialized &&
- selectedEnvironmentId &&
- services &&
- viewLevel === "services"
- )
- );
-
- useEffect(() => {
- if (servicesData) {
- setServicesIssuesData(servicesData.reports);
- }
- }, [servicesData, setServicesIssuesData]);
-
- const endpointsIssuesPayload: GetEndpointsIssuesPayload = useMemo(
- () => ({
- environment: selectedEnvironmentId ?? "",
- service: selectedService ?? "",
- endpoints: selectedEndpoints,
- criticalities: selectedCriticalityLevels,
- lastDays: timeMode === "baseline" ? null : selectedPeriodInDays
- }),
- [
- selectedEnvironmentId,
- selectedService,
- selectedEndpoints,
- selectedCriticalityLevels,
- selectedPeriodInDays,
- timeMode
- ]
- );
- const { data: endpointsData } = useEndpointsIssuesData(
- endpointsIssuesPayload,
- Boolean(
- isInitialized &&
- selectedEnvironmentId &&
- selectedService &&
- viewLevel === "endpoints"
- )
- );
-
- useEffect(() => {
- if (endpointsData) {
- setEndpointsIssuesData(endpointsData.reports);
- }
- }, [endpointsData, setEndpointsIssuesData]);
-
const goToEndpointIssues = ({
spanCodeObjectId,
service,
@@ -167,12 +94,10 @@ export const MetricsReport = () => {
});
};
- const handleTitleClick = (value: string) => {
- if (viewLevel === "services") {
- setSelectedService(value);
- setViewLevel("endpoints");
- }
-
+ const handleTileTitleClick = (
+ viewLevel: IssuesReportViewLevel,
+ value: string
+ ) => {
if (viewLevel === "endpoints" && selectedEnvironmentId && selectedService) {
goToEndpointIssues({
spanCodeObjectId: value,
@@ -182,7 +107,10 @@ export const MetricsReport = () => {
}
};
- const handleIssuesStatsClick = (value: string) => {
+ const handleIssuesStatsClick = (
+ viewLevel: IssuesReportViewLevel,
+ value: string
+ ) => {
if (viewLevel === "services") {
changeScope({
span: null,
@@ -206,84 +134,75 @@ export const MetricsReport = () => {
}
};
- const handleGoBack = () => {
- setViewLevel("services");
- setSelectedService(null);
+ const handleSelectedEnvironmentIdChange = (environmentId: string) => {
+ dispatch(setSelectedEnvironmentId(environmentId));
};
- const data =
- (viewLevel === "services" ? servicesIssuesData : endpointsIssuesData) ?? [];
- const transformedData =
- viewLevel === "services"
- ? transformServicesData(data as ServiceIssuesData[], scoreCriterion)
- : transformEndpointsData(data as EndpointIssuesData[], scoreCriterion);
+ const handleSelectedServicesChange = (services: string[]) => {
+ dispatch(setSelectedServices(services));
+ };
- const renderContent = () => {
- if (
- (viewLevel === "services" && !servicesIssuesData) ||
- (viewLevel === "endpoints" && !endpointsIssuesData)
- ) {
- return ;
- }
+ const handleSelectedEndpointsChange = (endpoints: string[]) => {
+ dispatch(setSelectedEndpoints(endpoints));
+ };
- if (data.length === 0) {
- if (viewLevel === "services") {
- return ;
- }
+ const handleCriticalityLevelsChange = (criticalities: IssueCriticality[]) => {
+ dispatch(setCriticalityLevels(criticalities));
+ };
- if (viewLevel === "endpoints") {
- return ;
- }
- }
+ const handlePeriodInDaysChange = (periodInDays: number) => {
+ dispatch(setPeriodInDays(periodInDays));
+ };
+
+ const handleTimeModeChange = (timeMode: IssuesReportTimeMode) => {
+ dispatch(setTimeMode(timeMode));
+ };
+
+ const handleViewModeChange = (viewMode: IssuesReportViewMode) => {
+ dispatch(setViewMode(viewMode));
+ };
+
+ const handleViewLevelChange = (viewLevel: IssuesReportViewLevel) => {
+ dispatch(setViewLevel(viewLevel));
+ };
- return (
- <>
- {viewMode === "table" && (
-
- )}
- {viewMode === "treemap" && (
-
- )}
- >
- );
+ const handleSelectedServiceChange = (service: string | null) => {
+ dispatch(setSelectedService(service));
};
return (
-
-
+
+
-
- {isInitialized ? (
- environments.length > 0 ? (
- <>
-
- {renderContent()}
- >
- ) : (
-
- )
- ) : (
-
- )}
+
+
© {new Date().getFullYear()} digma.ai
-
-
+
+
);
};
diff --git a/src/components/Dashboard/MetricsReport/styles.ts b/src/components/Dashboard/MetricsReport/styles.ts
index a3a1c2896..952c87ed9 100644
--- a/src/components/Dashboard/MetricsReport/styles.ts
+++ b/src/components/Dashboard/MetricsReport/styles.ts
@@ -2,27 +2,6 @@ import styled from "styled-components";
import { bodyRegularTypography } from "../../common/App/typographies";
export const Container = styled.div`
- display: flex;
- flex-direction: column;
- height: 100%;
- width: 100%;
- padding: 24px 24px 16px;
- gap: 24px;
- box-sizing: border-box;
- overflow: auto;
-`;
-
-export const Footer = styled.div`
- align-items: center;
- display: flex;
- justify-content: start;
- gap: 8px;
- margin-top: auto;
- color: ${({ theme }) => theme.colors.v3.text.disabled};
- ${bodyRegularTypography}
-`;
-
-export const Section = styled.div`
display: flex;
height: 100%;
flex-direction: column;
@@ -30,6 +9,15 @@ export const Section = styled.div`
overflow: hidden;
`;
+export const ContainerBackground = styled.div`
+ z-index: -1;
+ position: absolute;
+ inset: 0;
+ height: 100%;
+ width: 100%;
+ background: ${({ theme }) => theme.colors.v3.surface.secondary};
+`;
+
export const ContainerBackgroundGradient = styled.div`
z-index: -1;
position: absolute;
@@ -48,11 +36,22 @@ export const ContainerBackgroundGradient = styled.div`
filter: blur(5px);
`;
-export const SectionBackground = styled.div`
- z-index: -1;
- position: absolute;
- inset: 0;
+export const ContentContainer = styled.div`
+ display: flex;
+ flex-direction: column;
height: 100%;
width: 100%;
- background: ${({ theme }) => theme.colors.v3.surface.secondary};
+ padding: 24px 24px 16px;
+ gap: 24px;
+ box-sizing: border-box;
+`;
+
+export const Footer = styled.div`
+ align-items: center;
+ display: flex;
+ justify-content: start;
+ gap: 8px;
+ margin-top: auto;
+ color: ${({ theme }) => theme.colors.v3.text.disabled};
+ ${bodyRegularTypography}
`;
diff --git a/src/components/Dashboard/MetricsReport/types.ts b/src/components/Dashboard/MetricsReport/types.ts
deleted file mode 100644
index 8e19e46aa..000000000
--- a/src/components/Dashboard/MetricsReport/types.ts
+++ /dev/null
@@ -1,105 +0,0 @@
-import type { EnvironmentType } from "../../common/App/types";
-import type { Severity } from "./Table/types";
-
-export type Criticality = "Low" | "Medium" | "High";
-
-export type ReportViewMode = "treemap" | "table";
-
-export type ReportTimeMode = "baseline" | "changes";
-
-export type ScoreCriterion = "impact" | "criticality";
-
-export type ReportViewLevel = "services" | "endpoints";
-
-export interface UseServicesIssuesDataProps {
- environmentId: string | null;
- services: string[];
- criticalities: Criticality[];
- lastDays: number | null;
-}
-
-export interface GetMetricsReportDataPayloadV1 {
- keys: {
- environment: string;
- service: string;
- lastDays: number | null;
- }[];
-}
-
-export interface GetMetricsReportDataPayloadV2 {
- criticalities: Criticality[];
- keys: {
- environment: string;
- service: string | null;
- lastDays: number | null;
- }[];
-}
-
-export interface ServiceIssuesData {
- key: {
- environment: string;
- service: string;
- lastDays: number | null;
- };
- issues: number;
- impact: number;
- criticality: number;
-}
-
-export interface SetMetricsReportDataPayload {
- reports: ServiceIssuesData[];
-}
-
-export interface GetServiceEndpointsPayload {
- environment: string;
- service: string;
-}
-
-export interface EndpointData {
- displayName: string;
- spanCodeObjectId: string;
-}
-
-export interface SetServiceEndpointsPayload {
- endpoints: EndpointData[];
-}
-
-export interface GetEndpointsIssuesPayload {
- environment: string;
- service: string;
- endpoints: string[];
- criticalities: Criticality[];
- lastDays: number | null;
-}
-
-export interface EndpointIssuesData {
- displayName: string;
- spanCodeObjectId: string;
- issues: number;
- impact: number;
- criticality: number;
-}
-
-export interface SetEndpointsIssuesPayload {
- reports: EndpointIssuesData[];
-}
-
-export interface GetServiceEnvironmentsPayload {
- service: string;
-}
-
-export interface SetServiceEnvironmentsPayload {
- environments: {
- id: string;
- name: string;
- type: EnvironmentType;
- }[];
-}
-
-export interface PresentationalReportData {
- id: string;
- name: string;
- score: number;
- criticalIssuesCount: number;
- severity: Severity;
-}
diff --git a/src/components/Dashboard/MetricsReport/useEndpointsIssuesData.ts b/src/components/Dashboard/MetricsReport/useEndpointsIssuesData.ts
deleted file mode 100644
index 065244bff..000000000
--- a/src/components/Dashboard/MetricsReport/useEndpointsIssuesData.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import type { DataFetcherConfiguration } from "../../../hooks/useFetchData";
-import { useFetchData } from "../../../hooks/useFetchData";
-import { actions } from "../actions";
-import type {
- GetEndpointsIssuesPayload,
- SetEndpointsIssuesPayload
-} from "./types";
-
-export const useEndpointsIssuesData = (
- payload: GetEndpointsIssuesPayload,
- isEnabled: boolean
-) => {
- const dataFetcherServiceDataConfiguration: DataFetcherConfiguration = {
- requestAction: actions.GET_ENDPOINTS_ISSUES,
- responseAction: actions.SET_ENDPOINTS_ISSUES,
- refreshOnPayloadChange: true,
- isEnabled
- };
-
- const { data } = useFetchData<
- GetEndpointsIssuesPayload,
- SetEndpointsIssuesPayload
- >(dataFetcherServiceDataConfiguration, payload);
-
- return {
- data
- };
-};
diff --git a/src/components/Dashboard/MetricsReport/useServicesIssuesData.ts b/src/components/Dashboard/MetricsReport/useServicesIssuesData.ts
deleted file mode 100644
index 1e3b499cc..000000000
--- a/src/components/Dashboard/MetricsReport/useServicesIssuesData.ts
+++ /dev/null
@@ -1,72 +0,0 @@
-import { useMemo } from "react";
-import { getFeatureFlagValue } from "../../../featureFlags";
-import type { DataFetcherConfiguration } from "../../../hooks/useFetchData";
-import { useFetchData } from "../../../hooks/useFetchData";
-import { useConfigSelector } from "../../../store/config/useConfigSelector";
-import { FeatureFlag } from "../../../types";
-import { actions } from "../actions";
-import type {
- GetMetricsReportDataPayloadV1,
- GetMetricsReportDataPayloadV2,
- SetMetricsReportDataPayload,
- UseServicesIssuesDataProps
-} from "./types";
-
-export const useServicesIssuesData = (
- {
- services,
- environmentId,
- criticalities,
- lastDays
- }: UseServicesIssuesDataProps,
- isEnabled: boolean
-) => {
- const { backendInfo } = useConfigSelector();
- const isDataFilterEnabled = Boolean(
- getFeatureFlagValue(
- backendInfo,
- FeatureFlag.IS_METRICS_REPORT_DATA_FILTER_ENABLED
- )
- );
-
- const dataFetcherServiceDataConfiguration: DataFetcherConfiguration = {
- requestAction: actions.GET_METRICS_REPORT_DATA,
- responseAction: actions.SET_METRICS_REPORT_DATA,
- refreshOnPayloadChange: true,
- isEnabled
- };
-
- const payloadV1: GetMetricsReportDataPayloadV1 = useMemo(() => {
- return {
- keys: services.map((x) => ({
- environment: environmentId ?? "",
- service: x,
- lastDays
- }))
- };
- }, [services, environmentId, lastDays]);
-
- const payloadV2: GetMetricsReportDataPayloadV2 = useMemo(() => {
- const servicesArray = services.length > 0 ? services : [null];
-
- return {
- criticalities,
- keys: servicesArray.map((x) => ({
- environment: environmentId ?? "",
- service: x,
- lastDays: lastDays
- }))
- };
- }, [services, environmentId, criticalities, lastDays]);
-
- const payload = isDataFilterEnabled ? payloadV2 : payloadV1;
-
- const { data } = useFetchData<
- GetMetricsReportDataPayloadV1 | GetMetricsReportDataPayloadV2,
- SetMetricsReportDataPayload
- >(dataFetcherServiceDataConfiguration, payload);
-
- return {
- data
- };
-};
diff --git a/src/components/Dashboard/Report/ReportHeader/index.tsx b/src/components/Dashboard/Report/ReportHeader/index.tsx
index e57bfc49b..0c22ad8e6 100644
--- a/src/components/Dashboard/Report/ReportHeader/index.tsx
+++ b/src/components/Dashboard/Report/ReportHeader/index.tsx
@@ -78,7 +78,7 @@ export const ReportHeader = ({
{
- // TODO
+ // TODO: implement
}}
onRefresh={() => {
handleRefresh();
diff --git a/src/components/Insights/InsightsCatalog/InsightsPage/insightCards/common/InsightCard/index.tsx b/src/components/Insights/InsightsCatalog/InsightsPage/insightCards/common/InsightCard/index.tsx
index c6cb96df6..a8b4c7e04 100644
--- a/src/components/Insights/InsightsCatalog/InsightsPage/insightCards/common/InsightCard/index.tsx
+++ b/src/components/Insights/InsightsCatalog/InsightsPage/insightCards/common/InsightCard/index.tsx
@@ -328,7 +328,7 @@ export const InsightCard = ({
label={"Pin"}
title={"Pin"}
onClick={() =>
- //TODO: implement
+ // TODO: implement
{
return undefined;
}
diff --git a/src/components/InstallationWizard/index.tsx b/src/components/InstallationWizard/index.tsx
index 4c8a786b7..6bd61c9ee 100644
--- a/src/components/InstallationWizard/index.tsx
+++ b/src/components/InstallationWizard/index.tsx
@@ -77,7 +77,7 @@ export const InstallationWizard = () => {
// const [userEmail, setUserEmail] = useState("");
// const [isUserEmailCaptured, setIsUserEmailCaptured] = useState(false);
- // TO DO:
+ // TODO:
// add environment variable for presetting the correct installation type
// if Digma already installed
// const preselectedInstallationType =
diff --git a/src/components/Dashboard/MetricsReport/Chart/Chart.stories.tsx b/src/components/common/IssuesReport/Chart/Chart.stories.tsx
similarity index 95%
rename from src/components/Dashboard/MetricsReport/Chart/Chart.stories.tsx
rename to src/components/common/IssuesReport/Chart/Chart.stories.tsx
index e6508384f..c558c4359 100644
--- a/src/components/Dashboard/MetricsReport/Chart/Chart.stories.tsx
+++ b/src/components/common/IssuesReport/Chart/Chart.stories.tsx
@@ -7,7 +7,7 @@ import { transformServicesData } from "../utils";
// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction
const meta: Meta = {
- title: "Dashboard/MetricsReport/Chart",
+ title: "common/IssuesReport/Chart",
component: Chart,
parameters: {
// More on how to position stories at: https://storybook.js.org/docs/react/configure/story-layout
diff --git a/src/components/Dashboard/MetricsReport/Chart/ReportTile/TooltipKeyValue/index.tsx b/src/components/common/IssuesReport/Chart/ReportTile/TooltipKeyValue/index.tsx
similarity index 100%
rename from src/components/Dashboard/MetricsReport/Chart/ReportTile/TooltipKeyValue/index.tsx
rename to src/components/common/IssuesReport/Chart/ReportTile/TooltipKeyValue/index.tsx
diff --git a/src/components/Dashboard/MetricsReport/Chart/ReportTile/TooltipKeyValue/styles.ts b/src/components/common/IssuesReport/Chart/ReportTile/TooltipKeyValue/styles.ts
similarity index 79%
rename from src/components/Dashboard/MetricsReport/Chart/ReportTile/TooltipKeyValue/styles.ts
rename to src/components/common/IssuesReport/Chart/ReportTile/TooltipKeyValue/styles.ts
index 9b62cd90c..4dbda53c1 100644
--- a/src/components/Dashboard/MetricsReport/Chart/ReportTile/TooltipKeyValue/styles.ts
+++ b/src/components/common/IssuesReport/Chart/ReportTile/TooltipKeyValue/styles.ts
@@ -1,5 +1,5 @@
import styled from "styled-components";
-import { footnoteRegularTypography } from "../../../../../common/App/typographies";
+import { footnoteRegularTypography } from "../../../../App/typographies";
export const Container = styled.div`
${footnoteRegularTypography}
diff --git a/src/components/Dashboard/MetricsReport/Chart/ReportTile/TooltipKeyValue/types.ts b/src/components/common/IssuesReport/Chart/ReportTile/TooltipKeyValue/types.ts
similarity index 100%
rename from src/components/Dashboard/MetricsReport/Chart/ReportTile/TooltipKeyValue/types.ts
rename to src/components/common/IssuesReport/Chart/ReportTile/TooltipKeyValue/types.ts
diff --git a/src/components/Dashboard/MetricsReport/Chart/ReportTile/index.tsx b/src/components/common/IssuesReport/Chart/ReportTile/index.tsx
similarity index 78%
rename from src/components/Dashboard/MetricsReport/Chart/ReportTile/index.tsx
rename to src/components/common/IssuesReport/Chart/ReportTile/index.tsx
index babf3e831..8d3295618 100644
--- a/src/components/Dashboard/MetricsReport/Chart/ReportTile/index.tsx
+++ b/src/components/common/IssuesReport/Chart/ReportTile/index.tsx
@@ -1,12 +1,12 @@
import type { MouseEvent } from "react";
-import { Tile } from "../../../../common/TreeMap/Tile";
-import type { ReportTimeMode } from "../../types";
+import type { IssuesReportTimeMode } from "../../../../../redux/slices/issuesReportSlice";
+import { Tile } from "../../../TreeMap/Tile";
import * as s from "./styles";
import { TooltipKeyValue } from "./TooltipKeyValue";
import type { ReportTileProps } from "./types";
-const getFormattedNumber = (viewMode: ReportTimeMode, value: number) =>
- `${viewMode === "changes" && value > 0 ? "+" : ""}${value}`;
+const getFormattedNumber = (timeMode: IssuesReportTimeMode, value: number) =>
+ `${timeMode === "changes" && value > 0 ? "+" : ""}${value}`;
export const ReportTile = ({
name,
@@ -14,15 +14,15 @@ export const ReportTile = ({
scoreCriterion,
score,
severity,
- viewMode,
+ timeMode,
onTitleClick,
onIssuesClick
}: ReportTileProps) => {
const formattedCriticalIssuesCount = getFormattedNumber(
- viewMode,
+ timeMode,
criticalIssuesCount
);
- const formattedScore = getFormattedNumber(viewMode, score);
+ const formattedScore = getFormattedNumber(timeMode, score);
const handleTitleClick = () => {
if (onTitleClick) {
diff --git a/src/components/Dashboard/MetricsReport/Chart/ReportTile/styles.ts b/src/components/common/IssuesReport/Chart/ReportTile/styles.ts
similarity index 81%
rename from src/components/Dashboard/MetricsReport/Chart/ReportTile/styles.ts
rename to src/components/common/IssuesReport/Chart/ReportTile/styles.ts
index 2c7a7b6a0..7ec68962c 100644
--- a/src/components/Dashboard/MetricsReport/Chart/ReportTile/styles.ts
+++ b/src/components/common/IssuesReport/Chart/ReportTile/styles.ts
@@ -1,5 +1,5 @@
import styled from "styled-components";
-import { subheading2BoldTypography } from "../../../../common/App/typographies";
+import { subheading2BoldTypography } from "../../../App/typographies";
export const TooltipContent = styled.div`
color: ${({ theme }) => theme.colors.v3.text.primary};
diff --git a/src/components/Dashboard/MetricsReport/Chart/ReportTile/types.ts b/src/components/common/IssuesReport/Chart/ReportTile/types.ts
similarity index 60%
rename from src/components/Dashboard/MetricsReport/Chart/ReportTile/types.ts
rename to src/components/common/IssuesReport/Chart/ReportTile/types.ts
index 73440388c..25c59897e 100644
--- a/src/components/Dashboard/MetricsReport/Chart/ReportTile/types.ts
+++ b/src/components/common/IssuesReport/Chart/ReportTile/types.ts
@@ -1,5 +1,6 @@
+import type { IssuesReportTimeMode } from "../../../../../redux/slices/issuesReportSlice";
import type { Severity } from "../../Table/types";
-import type { ReportTimeMode, ScoreCriterion } from "../../types";
+import type { ScoreCriterion } from "../../types";
export interface ReportTileProps {
name: string;
@@ -7,7 +8,7 @@ export interface ReportTileProps {
scoreCriterion: ScoreCriterion;
score: number;
severity: Severity;
- viewMode: ReportTimeMode;
+ timeMode: IssuesReportTimeMode;
onTitleClick?: () => void;
onIssuesClick?: () => void;
}
diff --git a/src/components/Dashboard/MetricsReport/Chart/index.tsx b/src/components/common/IssuesReport/Chart/index.tsx
similarity index 92%
rename from src/components/Dashboard/MetricsReport/Chart/index.tsx
rename to src/components/common/IssuesReport/Chart/index.tsx
index 743eac382..18cbda43f 100644
--- a/src/components/Dashboard/MetricsReport/Chart/index.tsx
+++ b/src/components/common/IssuesReport/Chart/index.tsx
@@ -4,9 +4,9 @@ import useDimensions from "react-cool-dimensions";
import useScrollbarSize from "react-scrollbar-size";
import type { Input } from "squarify";
import { sendUserActionTrackingEvent } from "../../../../utils/actions/sendUserActionTrackingEvent";
-import { TreeMap } from "../../../common/TreeMap";
-import type { TileData } from "../../../common/TreeMap/types";
-import { trackingEvents } from "../tracking";
+import { trackingEvents } from "../../../Dashboard/MetricsReport/tracking";
+import { TreeMap } from "../../TreeMap";
+import type { TileData } from "../../TreeMap/types";
import { ReportTile } from "./ReportTile";
import * as s from "./styles";
import type { ChartProps } from "./types";
@@ -65,7 +65,7 @@ export const Chart = ({
scoreCriterion={scoreCriterion}
score={score}
severity={x.severity}
- viewMode={timeMode}
+ timeMode={timeMode}
onIssuesClick={handleSeeIssuesClick}
onTitleClick={viewLevel === "services" ? handleTitleClick : undefined}
/>
@@ -86,6 +86,7 @@ export const Chart = ({
void;
+ onIssuesStatsClick: (value: string) => void;
+ scoreCriterion: ScoreCriterion;
+ viewLevel: IssuesReportViewLevel;
+ timeMode: IssuesReportTimeMode;
+}
diff --git a/src/components/Dashboard/MetricsReport/EmptyState/EmptyState.stories.tsx b/src/components/common/IssuesReport/EmptyState/EmptyState.stories.tsx
similarity index 94%
rename from src/components/Dashboard/MetricsReport/EmptyState/EmptyState.stories.tsx
rename to src/components/common/IssuesReport/EmptyState/EmptyState.stories.tsx
index 2e25176db..d7bed4a71 100644
--- a/src/components/Dashboard/MetricsReport/EmptyState/EmptyState.stories.tsx
+++ b/src/components/common/IssuesReport/EmptyState/EmptyState.stories.tsx
@@ -4,7 +4,7 @@ import { EmptyState } from ".";
// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction
const meta: Meta = {
- title: "Dashboard/MetricsReport/EmptyState",
+ title: "common/IssuesReport/EmptyState",
component: EmptyState,
parameters: {
// More on how to position stories at: https://storybook.js.org/docs/react/configure/story-layout
diff --git a/src/components/Dashboard/MetricsReport/EmptyState/index.tsx b/src/components/common/IssuesReport/EmptyState/index.tsx
similarity index 83%
rename from src/components/Dashboard/MetricsReport/EmptyState/index.tsx
rename to src/components/common/IssuesReport/EmptyState/index.tsx
index 818327a82..e206e54c1 100644
--- a/src/components/Dashboard/MetricsReport/EmptyState/index.tsx
+++ b/src/components/common/IssuesReport/EmptyState/index.tsx
@@ -1,8 +1,8 @@
-import { CrossCircleIcon } from "../../../common/icons/20px/CrossCircleIcon";
-import { CardsColoredIcon } from "../../../common/icons/CardsColoredIcon";
-import { EmptyState as CommonEmptyState } from "../../../common/v3/EmptyState";
-import type { EmptyStateProps as CommonEmptyStateProps } from "../../../common/v3/EmptyState/types";
-import { NewButton } from "../../../common/v3/NewButton";
+import { CrossCircleIcon } from "../../icons/20px/CrossCircleIcon";
+import { CardsColoredIcon } from "../../icons/CardsColoredIcon";
+import { EmptyState as CommonEmptyState } from "../../v3/EmptyState";
+import type { EmptyStateProps as CommonEmptyStateProps } from "../../v3/EmptyState/types";
+import { NewButton } from "../../v3/NewButton";
import * as s from "./styles";
import type { EmptyStatePreset, EmptyStateProps } from "./types";
diff --git a/src/components/Dashboard/MetricsReport/EmptyState/styles.ts b/src/components/common/IssuesReport/EmptyState/styles.ts
similarity index 67%
rename from src/components/Dashboard/MetricsReport/EmptyState/styles.ts
rename to src/components/common/IssuesReport/EmptyState/styles.ts
index 7884e2909..ff237b7ba 100644
--- a/src/components/Dashboard/MetricsReport/EmptyState/styles.ts
+++ b/src/components/common/IssuesReport/EmptyState/styles.ts
@@ -1,5 +1,5 @@
import styled from "styled-components";
-import { Spinner as CommonSpinner } from "../../../common/v3/Spinner";
+import { Spinner as CommonSpinner } from "../../v3/Spinner";
export const Spinner = styled(CommonSpinner)`
color: ${({ theme }) => theme.colors.v3.surface.gray};
diff --git a/src/components/Dashboard/MetricsReport/EmptyState/types.ts b/src/components/common/IssuesReport/EmptyState/types.ts
similarity index 87%
rename from src/components/Dashboard/MetricsReport/EmptyState/types.ts
rename to src/components/common/IssuesReport/EmptyState/types.ts
index dd74a7022..21bf7310e 100644
--- a/src/components/Dashboard/MetricsReport/EmptyState/types.ts
+++ b/src/components/common/IssuesReport/EmptyState/types.ts
@@ -1,4 +1,4 @@
-import type { EmptyStateProps as CommonEmptyStateProps } from "../../../common/v3/EmptyState/types";
+import type { EmptyStateProps as CommonEmptyStateProps } from "../../v3/EmptyState/types";
export type EmptyStatePreset =
| "noEndpoints"
diff --git a/src/components/Admin/Reports/CodeIssues/Header/Header.stories.tsx b/src/components/common/IssuesReport/Header/Header.stories.tsx
similarity index 82%
rename from src/components/Admin/Reports/CodeIssues/Header/Header.stories.tsx
rename to src/components/common/IssuesReport/Header/Header.stories.tsx
index f33f66ca7..a98df4866 100644
--- a/src/components/Admin/Reports/CodeIssues/Header/Header.stories.tsx
+++ b/src/components/common/IssuesReport/Header/Header.stories.tsx
@@ -4,7 +4,7 @@ import { Header } from ".";
// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction
const meta: Meta = {
- title: "Admin/Reports/CodeIssues/Header",
+ title: "common/IssuesReport/Header",
component: Header,
parameters: {
// More on how to position stories at: https://storybook.js.org/docs/react/configure/story-layout
@@ -17,4 +17,8 @@ export default meta;
type Story = StoryObj;
// More on writing stories with args: https://storybook.js.org/docs/react/writing-stories/args
-export const Default: Story = {};
+export const Default: Story = {
+ args: {
+ defaultTitle: "Code Issues"
+ }
+};
diff --git a/src/components/Admin/Reports/CodeIssues/Header/index.tsx b/src/components/common/IssuesReport/Header/index.tsx
similarity index 70%
rename from src/components/Admin/Reports/CodeIssues/Header/index.tsx
rename to src/components/common/IssuesReport/Header/index.tsx
index bb32394bd..be9ecaf6c 100644
--- a/src/components/Admin/Reports/CodeIssues/Header/index.tsx
+++ b/src/components/common/IssuesReport/Header/index.tsx
@@ -1,50 +1,40 @@
import { useMemo } from "react";
-import {
- useAdminDispatch,
- useAdminSelector
-} from "../../../../../containers/Admin/hooks";
-import { getFeatureFlagValue } from "../../../../../featureFlags";
+import { getFeatureFlagValue } from "../../../../featureFlags";
import {
useGetAboutQuery,
useGetEnvironmentServicesQuery,
useGetEnvironmentsQuery,
useGetServiceEndpointsQuery,
useGetServiceEnvironmentsQuery
-} from "../../../../../redux/services/digma";
-import {
- setCriticalityLevels,
- setPeriodInDays,
- setSelectedEndpoints,
- setSelectedEnvironmentId,
- setSelectedServices,
- setTimeMode,
- setViewMode
-} from "../../../../../redux/slices/codeIssuesReportSlice";
-import { FeatureFlag } from "../../../../../types";
-import { sendUserActionTrackingEvent } from "../../../../../utils/actions/sendUserActionTrackingEvent";
-import { formatUnit } from "../../../../../utils/formatUnit";
-import { CodeIcon } from "../../../../common/icons/12px/CodeIcon";
-import { DurationBreakdownIcon } from "../../../../common/icons/12px/DurationBreakdownIcon";
-import { WrenchIcon } from "../../../../common/icons/12px/WrenchIcon";
-import { InfinityIcon } from "../../../../common/icons/16px/InfinityIcon";
-import { TableIcon } from "../../../../common/icons/16px/TableIcon";
-import { TreemapIcon } from "../../../../common/icons/16px/TreemapIcon";
-import { ChevronIcon } from "../../../../common/icons/20px/ChevronIcon";
-import { DatabaseIcon } from "../../../../common/icons/DatabaseIcon";
-import { Direction } from "../../../../common/icons/types";
-import type { ToggleValue } from "../../../../common/Toggle/types";
-import { NewIconButton } from "../../../../common/v3/NewIconButton";
-import { Tooltip } from "../../../../common/v3/Tooltip";
-import { trackingEvents } from "../../../../Dashboard/MetricsReport/tracking";
+} from "../../../../redux/services/digma";
+import type { IssueCriticality } from "../../../../redux/services/types";
import type {
- Criticality,
- ReportTimeMode,
- ReportViewMode
-} from "../../../../Dashboard/MetricsReport/types";
+ IssuesReportTimeMode,
+ IssuesReportViewMode
+} from "../../../../redux/slices/issuesReportSlice";
+import { FeatureFlag } from "../../../../types";
+import { sendUserActionTrackingEvent } from "../../../../utils/actions/sendUserActionTrackingEvent";
+import { formatUnit } from "../../../../utils/formatUnit";
+import { trackingEvents } from "../../../Dashboard/MetricsReport/tracking";
+import { CodeIcon } from "../../icons/12px/CodeIcon";
+import { DurationBreakdownIcon } from "../../icons/12px/DurationBreakdownIcon";
+import { WrenchIcon } from "../../icons/12px/WrenchIcon";
+import { InfinityIcon } from "../../icons/16px/InfinityIcon";
+import { TableIcon } from "../../icons/16px/TableIcon";
+import { TreemapIcon } from "../../icons/16px/TreemapIcon";
+import { ChevronIcon } from "../../icons/20px/ChevronIcon";
+import { DatabaseIcon } from "../../icons/DatabaseIcon";
+import { Direction } from "../../icons/types";
+import type { ToggleValue } from "../../Toggle/types";
+import { NewIconButton } from "../../v3/NewIconButton";
+import { Tooltip } from "../../v3/Tooltip";
import * as s from "./styles";
import type { HeaderProps } from "./types";
-const criticalityOptions: { id: Criticality; label: string }[] = [
+const criticalityOptions: {
+ id: IssueCriticality;
+ label: string;
+}[] = [
{
id: "High",
label: "Critical"
@@ -61,34 +51,26 @@ const criticalityOptions: { id: Criticality; label: string }[] = [
const DEFAULT_PERIOD = 7;
-export const Header = ({ onGoBack }: HeaderProps) => {
- // TODO: create selectors
- const selectedEnvironmentId = useAdminSelector(
- (state) => state.codeIssuesReport.selectedEnvironmentId
- );
- const selectedCriticalityLevels = useAdminSelector(
- (state) => state.codeIssuesReport.criticalityLevels
- );
- const periodInDays = useAdminSelector(
- (state) => state.codeIssuesReport.periodInDays
- );
- const selectedService = useAdminSelector(
- (state) => state.codeIssuesReport.selectedService
- );
- const selectedServices = useAdminSelector(
- (state) => state.codeIssuesReport.selectedServices
- );
- const viewLevel = useAdminSelector(
- (state) => state.codeIssuesReport.viewLevel
- );
- const viewMode = useAdminSelector((state) => state.codeIssuesReport.viewMode);
- const timeMode = useAdminSelector((state) => state.codeIssuesReport.timeMode);
- const selectedEndpoints = useAdminSelector(
- (state) => state.codeIssuesReport.selectedEndpoints
- );
-
- const dispatch = useAdminDispatch();
-
+export const Header = ({
+ viewMode,
+ viewLevel,
+ timeMode,
+ selectedEnvironmentId,
+ selectedService,
+ criticalityLevels,
+ periodInDays,
+ selectedEndpoints,
+ selectedServices,
+ onSelectedEnvironmentIdChange,
+ onSelectedServicesChange,
+ onSelectedEndpointsChange,
+ onCriticalityLevelsChange,
+ onPeriodInDaysChange,
+ onTimeModeChange,
+ onViewModeChange,
+ defaultTitle,
+ onGoBack
+}: HeaderProps) => {
const { data: about } = useGetAboutQuery();
const { data: environments } = useGetEnvironmentsQuery();
@@ -151,67 +133,58 @@ export const Header = ({ onGoBack }: HeaderProps) => {
const handleSelectedEnvironmentChanged = (option: string | string[]) => {
sendUserActionTrackingEvent(trackingEvents.ENVIRONMENT_FILTER_SELECTED);
const newItem = Array.isArray(option) ? option[0] : option;
- dispatch(setSelectedEnvironmentId(newItem));
- dispatch(setSelectedServices([]));
- dispatch(setSelectedEndpoints([]));
+ onSelectedEnvironmentIdChange(newItem);
+ onSelectedServicesChange([]);
+ onSelectedEndpointsChange([]);
};
const handleSelectedServicesChanged = (option: string | string[]) => {
sendUserActionTrackingEvent(trackingEvents.SERVICE_FILTER_SELECTED);
const newItem = Array.isArray(option) ? option : [option];
- dispatch(setSelectedServices(newItem));
+ onSelectedServicesChange(newItem);
};
const handleSelectedEndpointsChanged = (option: string | string[]) => {
sendUserActionTrackingEvent(trackingEvents.ENDPOINT_FILTER_SELECTED);
const newItem = Array.isArray(option) ? option : [option];
- dispatch(setSelectedEndpoints(newItem));
+ onSelectedEndpointsChange(newItem);
};
const handleDataChanged = (option: string | string[]) => {
sendUserActionTrackingEvent(trackingEvents.DATA_FILTER_SELECTED);
const newItem = Array.isArray(option) ? option : [option];
- dispatch(setCriticalityLevels(newItem as Criticality[]));
+ onCriticalityLevelsChange(newItem as IssueCriticality[]);
};
const handlePeriodChanged = (option: string | string[]) => {
sendUserActionTrackingEvent(trackingEvents.PERIOD_FILTER_CHANGED);
const newItem = Array.isArray(option) ? option : [option];
if (newItem.length === 0) {
- dispatch(setPeriodInDays(DEFAULT_PERIOD));
+ onPeriodInDaysChange(DEFAULT_PERIOD);
return;
}
const value = newItem[0];
const newValue = Number(value);
- dispatch(setPeriodInDays(newValue));
+ onPeriodInDaysChange(newValue);
};
const handleViewModeChanged = (value: ToggleValue) => {
sendUserActionTrackingEvent(trackingEvents.VIEW_MODE_CHANGED, { value });
- const newViewMode = value as ReportViewMode;
- dispatch(setViewMode(newViewMode));
+ const newViewMode = value as IssuesReportViewMode;
+ onViewModeChange(newViewMode);
};
const handleTimeModeChanged = (value: ToggleValue) => {
sendUserActionTrackingEvent(trackingEvents.TIME_MODE_CHANGED, { value });
- const newTimeMode = value as ReportTimeMode;
- dispatch(setTimeMode(newTimeMode));
-
- // TODO: check if still needed
- // if (selectedViewLevel === "services") {
- // setServicesIssuesData(null);
- // }
-
- // if (selectedViewLevel === "endpoints") {
- // setEndpointIssuesData(null);
- // }
+ const newTimeMode = value as IssuesReportTimeMode;
+ onTimeModeChange(newTimeMode);
};
const title =
viewLevel === "endpoints"
? `${selectedService ?? ""} Service`
- : "Code Issues";
+ : defaultTitle;
const titleSuffix = viewLevel === "endpoints" ? " Endpoints" : "";
const tooltipTitle = `${title} ${titleSuffix}`;
@@ -339,7 +312,7 @@ export const Header = ({ onGoBack }: HeaderProps) => {
label: item.label,
value: item.id,
enabled: true,
- selected: selectedCriticalityLevels.includes(item.id)
+ selected: criticalityLevels.includes(item.id)
}))}
multiselect={true}
icon={DatabaseIcon}
diff --git a/src/components/Dashboard/MetricsReport/Header/styles.ts b/src/components/common/IssuesReport/Header/styles.ts
similarity index 87%
rename from src/components/Dashboard/MetricsReport/Header/styles.ts
rename to src/components/common/IssuesReport/Header/styles.ts
index 6f7fed821..421a73219 100644
--- a/src/components/Dashboard/MetricsReport/Header/styles.ts
+++ b/src/components/common/IssuesReport/Header/styles.ts
@@ -2,10 +2,10 @@ import styled from "styled-components";
import {
subheading2BoldTypography,
subheading2RegularTypography
-} from "../../../common/App/typographies";
-import { Select } from "../../../common/v3/Select";
-import { Toggle } from "../../../common/v3/Toggle";
-import { OptionButton } from "../../../common/v3/Toggle/styles";
+} from "../../App/typographies";
+import { Select } from "../../v3/Select";
+import { Toggle } from "../../v3/Toggle";
+import { OptionButton } from "../../v3/Toggle/styles";
export const Container = styled.div`
display: flex;
diff --git a/src/components/common/IssuesReport/Header/types.ts b/src/components/common/IssuesReport/Header/types.ts
new file mode 100644
index 000000000..5c1bca51a
--- /dev/null
+++ b/src/components/common/IssuesReport/Header/types.ts
@@ -0,0 +1,27 @@
+import type { IssueCriticality } from "../../../../redux/services/types";
+import type {
+ IssuesReportTimeMode,
+ IssuesReportViewLevel,
+ IssuesReportViewMode
+} from "../../../../redux/slices/issuesReportSlice";
+
+export interface HeaderProps {
+ viewMode: IssuesReportViewMode;
+ viewLevel: IssuesReportViewLevel;
+ timeMode: IssuesReportTimeMode;
+ selectedEnvironmentId: string | null;
+ selectedService: string | null;
+ criticalityLevels: IssueCriticality[];
+ periodInDays: number;
+ selectedEndpoints: string[];
+ selectedServices: string[];
+ onSelectedEnvironmentIdChange: (environmentId: string) => void;
+ onSelectedServicesChange: (services: string[]) => void;
+ onSelectedEndpointsChange: (endpoints: string[]) => void;
+ onCriticalityLevelsChange: (criticalities: IssueCriticality[]) => void;
+ onPeriodInDaysChange: (periodInDays: number) => void;
+ onTimeModeChange: (timeMode: IssuesReportTimeMode) => void;
+ onViewModeChange: (viewMode: IssuesReportViewMode) => void;
+ onGoBack: () => void;
+ defaultTitle: string;
+}
diff --git a/src/components/common/IssuesReport/IssuesReport.stories.tsx b/src/components/common/IssuesReport/IssuesReport.stories.tsx
new file mode 100644
index 000000000..3721fc015
--- /dev/null
+++ b/src/components/common/IssuesReport/IssuesReport.stories.tsx
@@ -0,0 +1,19 @@
+import type { Meta, StoryObj } from "@storybook/react";
+import { IssuesReport } from ".";
+
+// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction
+const meta: Meta = {
+ title: "common/IssuesReport",
+ component: IssuesReport,
+ parameters: {
+ // More on how to position stories at: https://storybook.js.org/docs/react/configure/story-layout
+ layout: "fullscreen"
+ }
+};
+
+export default meta;
+
+type Story = StoryObj;
+
+// More on writing stories with args: https://storybook.js.org/docs/react/writing-stories/args
+export const Default: Story = {};
diff --git a/src/components/Dashboard/MetricsReport/Table/Table.stories.tsx b/src/components/common/IssuesReport/Table/Table.stories.tsx
similarity index 95%
rename from src/components/Dashboard/MetricsReport/Table/Table.stories.tsx
rename to src/components/common/IssuesReport/Table/Table.stories.tsx
index 3f3fb8ebc..11110a205 100644
--- a/src/components/Dashboard/MetricsReport/Table/Table.stories.tsx
+++ b/src/components/common/IssuesReport/Table/Table.stories.tsx
@@ -6,7 +6,7 @@ import { mockedReport } from "./mockData";
// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction
const meta: Meta = {
- title: "Dashboard/MetricsReport/Table",
+ title: "common/IssuesReport/Table",
component: Table,
parameters: {
// More on how to position stories at: https://storybook.js.org/docs/react/configure/story-layout
diff --git a/src/components/Dashboard/MetricsReport/Table/index.tsx b/src/components/common/IssuesReport/Table/index.tsx
similarity index 96%
rename from src/components/Dashboard/MetricsReport/Table/index.tsx
rename to src/components/common/IssuesReport/Table/index.tsx
index 876ce94f0..2d587f996 100644
--- a/src/components/Dashboard/MetricsReport/Table/index.tsx
+++ b/src/components/common/IssuesReport/Table/index.tsx
@@ -10,11 +10,11 @@ import {
import type { ReactNode } from "react";
import { useState } from "react";
import { sendUserActionTrackingEvent } from "../../../../utils/actions/sendUserActionTrackingEvent";
-import { SortIcon } from "../../../common/icons/16px/SortIcon";
-import { ChevronIcon } from "../../../common/icons/20px/ChevronIcon";
-import { Direction } from "../../../common/icons/types";
-import { Tooltip } from "../../../common/v3/Tooltip";
-import { trackingEvents } from "../tracking";
+import { trackingEvents } from "../../../Dashboard/MetricsReport/tracking";
+import { SortIcon } from "../../icons/16px/SortIcon";
+import { ChevronIcon } from "../../icons/20px/ChevronIcon";
+import { Direction } from "../../icons/types";
+import { Tooltip } from "../../v3/Tooltip";
import type { PresentationalReportData } from "../types";
import * as s from "./styles";
import type { ColumnMeta, Severity, TableProps } from "./types";
diff --git a/src/components/Dashboard/MetricsReport/Table/mockData.ts b/src/components/common/IssuesReport/Table/mockData.ts
similarity index 93%
rename from src/components/Dashboard/MetricsReport/Table/mockData.ts
rename to src/components/common/IssuesReport/Table/mockData.ts
index 91ad17221..5cd9f2657 100644
--- a/src/components/Dashboard/MetricsReport/Table/mockData.ts
+++ b/src/components/common/IssuesReport/Table/mockData.ts
@@ -1,4 +1,4 @@
-import type { SetMetricsReportDataPayload } from "../types";
+import type { SetMetricsReportDataPayload } from "../../../../redux/services/types";
export const mockedReport: SetMetricsReportDataPayload = {
reports: [
diff --git a/src/components/Dashboard/MetricsReport/Table/styles.ts b/src/components/common/IssuesReport/Table/styles.ts
similarity index 98%
rename from src/components/Dashboard/MetricsReport/Table/styles.ts
rename to src/components/common/IssuesReport/Table/styles.ts
index 17867b644..eae6bec39 100644
--- a/src/components/Dashboard/MetricsReport/Table/styles.ts
+++ b/src/components/common/IssuesReport/Table/styles.ts
@@ -2,7 +2,7 @@ import styled from "styled-components";
import {
subheading1BoldTypography,
subheading1RegularTypography
-} from "../../../common/App/typographies";
+} from "../../App/typographies";
import type { TableBodyCellProps, TableCellContentProps } from "./types";
export const Table = styled.table`
diff --git a/src/components/Dashboard/MetricsReport/Table/types.ts b/src/components/common/IssuesReport/Table/types.ts
similarity index 71%
rename from src/components/Dashboard/MetricsReport/Table/types.ts
rename to src/components/common/IssuesReport/Table/types.ts
index a2a9d5464..4250179c3 100644
--- a/src/components/Dashboard/MetricsReport/Table/types.ts
+++ b/src/components/common/IssuesReport/Table/types.ts
@@ -1,17 +1,16 @@
import type {
- PresentationalReportData,
- ReportTimeMode,
- ReportViewLevel,
- ScoreCriterion
-} from "../types";
+ IssuesReportTimeMode,
+ IssuesReportViewLevel
+} from "../../../../redux/slices/issuesReportSlice";
+import type { PresentationalReportData, ScoreCriterion } from "../types";
export interface TableProps {
data: PresentationalReportData[];
- timeMode: ReportTimeMode;
+ timeMode: IssuesReportTimeMode;
onTitleClick: (value: string) => void;
onIssuesStatsClick: (value: string) => void;
scoreCriterion: ScoreCriterion;
- viewLevel: ReportViewLevel;
+ viewLevel: IssuesReportViewLevel;
}
export type ContentAlignment = "left" | "center" | "right";
diff --git a/src/components/common/IssuesReport/index.tsx b/src/components/common/IssuesReport/index.tsx
new file mode 100644
index 000000000..926b8d771
--- /dev/null
+++ b/src/components/common/IssuesReport/index.tsx
@@ -0,0 +1,267 @@
+import { useEffect, useMemo } from "react";
+import { getFeatureFlagValue } from "../../../featureFlags";
+import {
+ useGetAboutQuery,
+ useGetEndpointsIssuesQuery,
+ useGetEnvironmentServicesQuery,
+ useGetEnvironmentsQuery,
+ useGetServicesIssuesQuery
+} from "../../../redux/services/digma";
+import type {
+ EndpointIssuesData,
+ GetMetricsReportDataPayloadV1,
+ GetMetricsReportDataPayloadV2,
+ ServiceIssuesData
+} from "../../../redux/services/types";
+import { FeatureFlag } from "../../../types";
+import { Chart } from "./Chart";
+import { EmptyState } from "./EmptyState";
+import { Header } from "./Header";
+import * as s from "./styles";
+import { Table } from "./Table";
+import type { IssuesReportProps, ScoreCriterion } from "./types";
+import { transformEndpointsData, transformServicesData } from "./utils";
+
+export const IssuesReport = ({
+ viewMode,
+ viewLevel,
+ timeMode,
+ selectedEnvironmentId,
+ selectedService,
+ criticalityLevels,
+ periodInDays,
+ selectedEndpoints,
+ selectedServices,
+ defaultHeaderTitle,
+ onSelectedEnvironmentIdChange,
+ onSelectedServicesChange,
+ onSelectedEndpointsChange,
+ onCriticalityLevelsChange,
+ onPeriodInDaysChange,
+ onTimeModeChange,
+ onViewModeChange,
+ onViewLevelChange,
+ onTileTitleClick,
+ onTileIssuesStatsClick,
+ onSelectedServiceChange
+}: IssuesReportProps) => {
+ const { data: about } = useGetAboutQuery();
+ const { data: environments } = useGetEnvironmentsQuery();
+
+ useEffect(() => {
+ if (environments && environments.length > 0 && !selectedEnvironmentId) {
+ onSelectedEnvironmentIdChange(environments[0].id);
+ }
+ }, [environments, selectedEnvironmentId, onSelectedEnvironmentIdChange]);
+
+ const isInitialized = Boolean(environments && about);
+
+ const { data: services } = useGetEnvironmentServicesQuery(
+ {
+ environment: selectedEnvironmentId ?? null
+ },
+ {
+ skip: !selectedEnvironmentId || viewLevel !== "services"
+ }
+ );
+
+ const isDataFilterEnabled = Boolean(
+ about &&
+ getFeatureFlagValue(
+ about,
+ FeatureFlag.IS_METRICS_REPORT_DATA_FILTER_ENABLED
+ )
+ );
+
+ const getServicesIssuesPayloadV1: GetMetricsReportDataPayloadV1 =
+ useMemo(() => {
+ const servicesArray =
+ selectedServices.length > 0 ? selectedServices : services ?? [];
+
+ return {
+ keys: servicesArray.map((x) => ({
+ environment: selectedEnvironmentId ?? "",
+ service: x,
+ lastDays: timeMode === "baseline" ? null : periodInDays
+ }))
+ };
+ }, [
+ selectedServices,
+ services,
+ selectedEnvironmentId,
+ timeMode,
+ periodInDays
+ ]);
+
+ const getServicesIssuesPayloadV2: GetMetricsReportDataPayloadV2 =
+ useMemo(() => {
+ const servicesArray =
+ selectedServices.length > 0 ? selectedServices : services ?? [null];
+
+ return {
+ criticalities: criticalityLevels,
+ keys: servicesArray.map((x) => ({
+ environment: selectedEnvironmentId ?? "",
+ service: x,
+ lastDays: timeMode === "baseline" ? null : periodInDays
+ }))
+ };
+ }, [
+ selectedServices,
+ services,
+ selectedEnvironmentId,
+ criticalityLevels,
+ timeMode,
+ periodInDays
+ ]);
+
+ const getServicesIssuesPayload = isDataFilterEnabled
+ ? getServicesIssuesPayloadV2
+ : getServicesIssuesPayloadV1;
+
+ const { data: servicesIssues } = useGetServicesIssuesQuery(
+ getServicesIssuesPayload,
+ {
+ skip:
+ !isInitialized ||
+ !selectedEnvironmentId ||
+ !services ||
+ viewLevel !== "services"
+ }
+ );
+
+ const { data: endpointsIssues } = useGetEndpointsIssuesQuery(
+ {
+ environment: selectedEnvironmentId ?? "",
+ service: selectedService ?? "",
+ endpoints: selectedEndpoints,
+ criticalities: criticalityLevels,
+ lastDays: timeMode === "baseline" ? null : periodInDays
+ },
+ {
+ skip:
+ !isInitialized ||
+ !selectedEnvironmentId ||
+ !selectedService ||
+ viewLevel !== "endpoints"
+ }
+ );
+
+ const handleTitleClick = (value: string) => {
+ if (viewLevel === "services") {
+ onSelectedServiceChange(value);
+ onViewLevelChange("endpoints");
+ }
+ onTileTitleClick(viewLevel, value);
+ };
+
+ const handleIssuesStatsClick = (value: string) => {
+ onTileIssuesStatsClick(viewLevel, value);
+ };
+
+ const handleGoBack = () => {
+ onViewLevelChange("services");
+ onSelectedServiceChange(null);
+ };
+
+ const isCriticalityEnabled = Boolean(
+ about &&
+ getFeatureFlagValue(
+ about,
+ FeatureFlag.IS_METRICS_REPORT_CRITICALITY_ENABLED
+ )
+ );
+
+ const scoreCriterion: ScoreCriterion = isCriticalityEnabled
+ ? "criticality"
+ : "impact";
+
+ const data =
+ (viewLevel === "services"
+ ? servicesIssues?.reports
+ : endpointsIssues?.reports) ?? [];
+ const transformedData =
+ viewLevel === "services"
+ ? transformServicesData(data as ServiceIssuesData[], scoreCriterion)
+ : transformEndpointsData(data as EndpointIssuesData[], scoreCriterion);
+
+ const renderContent = () => {
+ if (
+ (viewLevel === "services" && !servicesIssues) ||
+ (viewLevel === "endpoints" && !endpointsIssues)
+ ) {
+ return ;
+ }
+
+ if (data.length === 0) {
+ if (viewLevel === "services") {
+ return ;
+ }
+
+ if (viewLevel === "endpoints") {
+ return ;
+ }
+ }
+
+ return (
+ <>
+ {viewMode === "table" && (
+
+ )}
+ {viewMode === "treemap" && (
+
+ )}
+ >
+ );
+ };
+
+ return (
+
+ {isInitialized ? (
+ environments && environments.length > 0 ? (
+ <>
+
+ {renderContent()}
+ >
+ ) : (
+
+ )
+ ) : (
+
+ )}
+
+ );
+};
diff --git a/src/components/common/IssuesReport/styles.ts b/src/components/common/IssuesReport/styles.ts
new file mode 100644
index 000000000..25d294026
--- /dev/null
+++ b/src/components/common/IssuesReport/styles.ts
@@ -0,0 +1,9 @@
+import styled from "styled-components";
+
+export const Container = styled.div`
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ width: 100%;
+ gap: 24px;
+`;
diff --git a/src/components/common/IssuesReport/types.ts b/src/components/common/IssuesReport/types.ts
new file mode 100644
index 000000000..ff1367515
--- /dev/null
+++ b/src/components/common/IssuesReport/types.ts
@@ -0,0 +1,44 @@
+import type { IssueCriticality } from "../../../redux/services/types";
+import type {
+ IssuesReportTimeMode,
+ IssuesReportViewLevel,
+ IssuesReportViewMode
+} from "../../../redux/slices/issuesReportSlice";
+import type { Severity } from "../../common/IssuesReport/Table/types";
+
+export interface IssuesReportProps {
+ viewMode: IssuesReportViewMode;
+ viewLevel: IssuesReportViewLevel;
+ timeMode: IssuesReportTimeMode;
+ selectedEnvironmentId: string | null;
+ selectedService: string | null;
+ criticalityLevels: IssueCriticality[];
+ periodInDays: number;
+ selectedEndpoints: string[];
+ selectedServices: string[];
+ defaultHeaderTitle: string;
+ onSelectedEnvironmentIdChange: (environmentId: string) => void;
+ onSelectedServicesChange: (services: string[]) => void;
+ onSelectedEndpointsChange: (endpoints: string[]) => void;
+ onCriticalityLevelsChange: (criticalities: IssueCriticality[]) => void;
+ onPeriodInDaysChange: (periodInDays: number) => void;
+ onTimeModeChange: (timeMode: IssuesReportTimeMode) => void;
+ onViewModeChange: (viewMode: IssuesReportViewMode) => void;
+ onTileTitleClick: (viewLevel: IssuesReportViewLevel, value: string) => void;
+ onTileIssuesStatsClick: (
+ viewLevel: IssuesReportViewLevel,
+ value: string
+ ) => void;
+ onViewLevelChange: (viewLevel: IssuesReportViewLevel) => void;
+ onSelectedServiceChange: (service: string | null) => void;
+}
+
+export type ScoreCriterion = "impact" | "criticality";
+
+export interface PresentationalReportData {
+ id: string;
+ name: string;
+ score: number;
+ criticalIssuesCount: number;
+ severity: Severity;
+}
diff --git a/src/components/Dashboard/MetricsReport/utils.ts b/src/components/common/IssuesReport/utils.ts
similarity index 93%
rename from src/components/Dashboard/MetricsReport/utils.ts
rename to src/components/common/IssuesReport/utils.ts
index 5c787dfe1..1f9106434 100644
--- a/src/components/Dashboard/MetricsReport/utils.ts
+++ b/src/components/common/IssuesReport/utils.ts
@@ -1,10 +1,9 @@
-import type { Severity } from "./Table/types";
import type {
EndpointIssuesData,
- PresentationalReportData,
- ScoreCriterion,
ServiceIssuesData
-} from "./types";
+} from "../../../redux/services/types";
+import type { Severity } from "./Table/types";
+import type { PresentationalReportData, ScoreCriterion } from "./types";
const getSeverity = (min: number, max: number, value: number): Severity => {
const normalizedMin = Math.max(min, 0);
diff --git a/src/components/common/TreeMap/Tile/types.ts b/src/components/common/TreeMap/Tile/types.ts
index 598a6db3e..2b1ec0557 100644
--- a/src/components/common/TreeMap/Tile/types.ts
+++ b/src/components/common/TreeMap/Tile/types.ts
@@ -1,5 +1,5 @@
import type { ReactNode } from "react";
-import type { Severity } from "../../../Dashboard/MetricsReport/Table/types";
+import type { Severity } from "../../IssuesReport/Table/types";
export interface TileProps {
title: string;
diff --git a/src/components/common/TreeMap/TreeMap.stories.tsx b/src/components/common/TreeMap/TreeMap.stories.tsx
index 7f5c47115..aeea599e4 100644
--- a/src/components/common/TreeMap/TreeMap.stories.tsx
+++ b/src/components/common/TreeMap/TreeMap.stories.tsx
@@ -1,6 +1,6 @@
import type { Meta, StoryObj } from "@storybook/react";
import { TreeMap } from ".";
-import { ReportTile } from "../../Dashboard/MetricsReport/Chart/ReportTile";
+import { ReportTile } from "../IssuesReport/Chart/ReportTile";
// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction
const meta: Meta = {
@@ -36,7 +36,7 @@ export const Default: Story = {
score={1500}
scoreCriterion={"criticality"}
severity={"Top"}
- viewMode={"baseline"}
+ timeMode={"baseline"}
/>
)
},
@@ -50,7 +50,7 @@ export const Default: Story = {
score={710}
scoreCriterion={"criticality"}
severity={"High"}
- viewMode={"baseline"}
+ timeMode={"baseline"}
/>
)
},
@@ -64,7 +64,7 @@ export const Default: Story = {
score={530}
scoreCriterion={"criticality"}
severity={"Medium"}
- viewMode={"baseline"}
+ timeMode={"baseline"}
/>
)
},
@@ -78,7 +78,7 @@ export const Default: Story = {
score={100}
scoreCriterion={"criticality"}
severity={"Low"}
- viewMode={"baseline"}
+ timeMode={"baseline"}
/>
)
},
@@ -92,7 +92,7 @@ export const Default: Story = {
score={100}
scoreCriterion={"criticality"}
severity={"Low"}
- viewMode={"baseline"}
+ timeMode={"baseline"}
/>
)
}
diff --git a/src/components/common/TreeMap/index.tsx b/src/components/common/TreeMap/index.tsx
index be3a535f9..3cc2e170b 100644
--- a/src/components/common/TreeMap/index.tsx
+++ b/src/components/common/TreeMap/index.tsx
@@ -4,12 +4,17 @@ import { isNull } from "../../../typeGuards/isNull";
import type { TileData, TreeMapProps } from "./types";
const normalizeData = (data: Input[]) => {
+ if (data.length === 0) {
+ return data;
+ }
+
const MIN_MAX_RATIO = 5;
const NORMALIZED_MIN = 1;
const NORMALIZED_MAX = MIN_MAX_RATIO;
- const dataMin = Math.min(...data.map((item) => item.value)) || NORMALIZED_MIN;
- const dataMax = Math.max(...data.map((item) => item.value)) || NORMALIZED_MIN;
+ const values = data.map((item) => item.value);
+ const dataMin = Math.min(...values);
+ const dataMax = Math.max(...values);
if (dataMin === dataMax) {
return data.map((item) => ({
@@ -18,18 +23,15 @@ const normalizeData = (data: Input[]) => {
}));
}
- const dataMinMaxRatio = dataMax / dataMin;
-
- return dataMinMaxRatio > MIN_MAX_RATIO
- ? data.map((item) => ({
- id: item.id,
- value:
- ((item.value - dataMin) * (NORMALIZED_MAX - NORMALIZED_MIN)) /
- (dataMax - dataMin) +
- NORMALIZED_MIN, // min-max normalization
- content: item.content
- }))
- : data;
+ return data.map((item) => ({
+ id: item.id,
+ value:
+ ((Math.max(0, item.value) - dataMin) *
+ (NORMALIZED_MAX - NORMALIZED_MIN)) /
+ (dataMax - dataMin) +
+ NORMALIZED_MIN, // min-max normalization
+ content: item.content
+ }));
};
const calculateTiles = (
@@ -73,10 +75,11 @@ export const TreeMap = ({
data,
width,
height,
- minTileDimensions
+ minTileDimensions,
+ normalize
}: TreeMapProps) => {
const container = { x0: 0, y0: 0, x1: width ?? 0, y1: height ?? 0 };
- const normalizedData = normalizeData(data);
+ const normalizedData = normalize ? normalizeData(data) : data;
const sortedData = [...normalizedData].sort((a, b) => b.value - a.value);
const tilesData = calculateTiles(sortedData, container, minTileDimensions);
diff --git a/src/components/common/TreeMap/types.ts b/src/components/common/TreeMap/types.ts
index bcacf80cd..fa4c1f560 100644
--- a/src/components/common/TreeMap/types.ts
+++ b/src/components/common/TreeMap/types.ts
@@ -7,6 +7,7 @@ export interface TileData {
}
export interface TreeMapProps {
+ normalize?: boolean;
padding?: number;
data: Input[];
width: number | null;
diff --git a/src/containers/Admin/store.ts b/src/containers/Admin/store.ts
index 72c37458a..3daeaa3bf 100644
--- a/src/containers/Admin/store.ts
+++ b/src/containers/Admin/store.ts
@@ -2,11 +2,11 @@ import { configureStore } from "@reduxjs/toolkit";
import { setupListeners } from "@reduxjs/toolkit/query";
import { authApi } from "../../redux/services/auth";
import { digmaApi } from "../../redux/services/digma";
-import codeIssuesReportSlice from "../../redux/slices/codeIssuesReportSlice";
+import issuesReportSlice from "../../redux/slices/issuesReportSlice";
export const store = configureStore({
reducer: {
- codeIssuesReport: codeIssuesReportSlice,
+ codeIssuesReport: issuesReportSlice,
[authApi.reducerPath]: authApi.reducer,
[digmaApi.reducerPath]: digmaApi.reducer
},
diff --git a/src/containers/Dashboard/hooks.ts b/src/containers/Dashboard/hooks.ts
new file mode 100644
index 000000000..7f9e9b4ef
--- /dev/null
+++ b/src/containers/Dashboard/hooks.ts
@@ -0,0 +1,5 @@
+import { useDispatch, useSelector } from "react-redux";
+import type { DashboardDispatch, DashboardRootState } from "./store";
+
+export const useDashboardDispatch = useDispatch.withTypes();
+export const useDashboardSelector = useSelector.withTypes();
diff --git a/src/containers/Dashboard/index.tsx b/src/containers/Dashboard/index.tsx
index e6a171636..e913c27ae 100644
--- a/src/containers/Dashboard/index.tsx
+++ b/src/containers/Dashboard/index.tsx
@@ -1,5 +1,6 @@
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
+import { Provider } from "react-redux";
import {
cancelMessage,
initializeDigmaMessageListener,
@@ -11,6 +12,7 @@ import { App } from "../../components/common/App";
import { dispatcher } from "../../dispatcher";
import { isString } from "../../typeGuards/isString";
import { handleUncaughtError } from "../../utils/handleUncaughtError";
+import { store } from "../Dashboard/store";
import { GlobalStyle } from "./styles";
const APP_ID = "dashboard";
@@ -44,10 +46,12 @@ if (rootElement) {
const root = createRoot(rootElement);
root.render(
-
-
- {getView()}
-
+
+
+
+ {getView()}
+
+
);
}
diff --git a/src/containers/Dashboard/store.ts b/src/containers/Dashboard/store.ts
new file mode 100644
index 000000000..38814dd68
--- /dev/null
+++ b/src/containers/Dashboard/store.ts
@@ -0,0 +1,18 @@
+import { configureStore } from "@reduxjs/toolkit";
+import { setupListeners } from "@reduxjs/toolkit/query";
+import { digmaApi } from "../../redux/services/digma";
+import issuesReportSlice from "../../redux/slices/issuesReportSlice";
+
+export const store = configureStore({
+ reducer: {
+ metricsReport: issuesReportSlice,
+ [digmaApi.reducerPath]: digmaApi.reducer
+ },
+ middleware: (getDefaultMiddleware) =>
+ getDefaultMiddleware().concat(digmaApi.middleware)
+});
+
+setupListeners(store.dispatch);
+
+export type DashboardRootState = ReturnType;
+export type DashboardDispatch = typeof store.dispatch;
diff --git a/src/redux/services/digma.ts b/src/redux/services/digma.ts
index f8381b622..4f2dcab03 100644
--- a/src/redux/services/digma.ts
+++ b/src/redux/services/digma.ts
@@ -1,22 +1,20 @@
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
-import type { GetServicesPayload } from "../../components/Dashboard/MetricsReport/Header/types";
-import {
- type GetEndpointsIssuesPayload,
- type GetMetricsReportDataPayloadV1,
- type GetMetricsReportDataPayloadV2,
- type GetServiceEndpointsPayload,
- type GetServiceEnvironmentsPayload,
- type SetEndpointsIssuesPayload,
- type SetMetricsReportDataPayload,
- type SetServiceEndpointsPayload,
- type SetServiceEnvironmentsPayload
-} from "../../components/Dashboard/MetricsReport/types";
import { isString } from "../../typeGuards/isString";
import type {
GetAboutResponse,
+ GetEndpointsIssuesPayload,
+ GetEnvironmentServicesPayload,
GetEnvironmentServicesResponse,
GetEnvironmentsResponse,
- GetUserProfileResponse
+ GetMetricsReportDataPayloadV1,
+ GetMetricsReportDataPayloadV2,
+ GetServiceEndpointsPayload,
+ GetServiceEnvironmentsPayload,
+ GetUserProfileResponse,
+ SetEndpointsIssuesPayload,
+ SetMetricsReportDataPayload,
+ SetServiceEndpointsPayload,
+ SetServiceEnvironmentsPayload
} from "./types";
export const digmaApi = createApi({
@@ -59,7 +57,7 @@ export const digmaApi = createApi({
}),
getEnvironmentServices: builder.query<
GetEnvironmentServicesResponse,
- GetServicesPayload
+ GetEnvironmentServicesPayload
>({
query: (data) => ({
url: "services/getServices",
diff --git a/src/redux/services/digmaEmpty.ts b/src/redux/services/digmaEmpty.ts
new file mode 100644
index 000000000..03b1a3c36
--- /dev/null
+++ b/src/redux/services/digmaEmpty.ts
@@ -0,0 +1,13 @@
+import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
+import { isString } from "../../typeGuards/isString";
+
+export const digmaEmptyApi = createApi({
+ reducerPath: "digmaApi",
+ baseQuery: fetchBaseQuery({
+ baseUrl: isString(window.digmaApiProxyPrefix)
+ ? window.digmaApiProxyPrefix
+ : "/api/",
+ credentials: "same-origin"
+ }),
+ endpoints: () => ({})
+});
diff --git a/src/redux/services/types.ts b/src/redux/services/types.ts
index 117a63774..93a642e6a 100644
--- a/src/redux/services/types.ts
+++ b/src/redux/services/types.ts
@@ -1,4 +1,9 @@
-import type { DeploymentType } from "../../components/common/App/types";
+import type {
+ DeploymentType,
+ EnvironmentType
+} from "../../components/common/App/types";
+
+export type IssueCriticality = "Low" | "Medium" | "High";
export interface GetAboutResponse {
applicationVersion: string;
@@ -11,10 +16,92 @@ export interface GetUserProfileResponse {
email: string;
}
+export interface GetMetricsReportDataPayloadV1 {
+ keys: {
+ environment: string;
+ service: string;
+ lastDays: number | null;
+ }[];
+}
+
+export interface GetMetricsReportDataPayloadV2 {
+ criticalities: IssueCriticality[];
+ keys: {
+ environment: string;
+ service: string | null;
+ lastDays: number | null;
+ }[];
+}
+
+export interface ServiceIssuesData {
+ key: {
+ environment: string;
+ service: string;
+ lastDays: number | null;
+ };
+ issues: number;
+ impact: number;
+ criticality: number;
+}
+
+export interface SetMetricsReportDataPayload {
+ reports: ServiceIssuesData[];
+}
+
+export interface GetServiceEndpointsPayload {
+ environment: string;
+ service: string;
+}
+
+export interface EndpointData {
+ displayName: string;
+ spanCodeObjectId: string;
+}
+
+export interface SetServiceEndpointsPayload {
+ endpoints: EndpointData[];
+}
+
+export interface GetEndpointsIssuesPayload {
+ environment: string;
+ service: string;
+ endpoints: string[];
+ criticalities: IssueCriticality[];
+ lastDays: number | null;
+}
+
+export interface EndpointIssuesData {
+ displayName: string;
+ spanCodeObjectId: string;
+ issues: number;
+ impact: number;
+ criticality: number;
+}
+
+export interface SetEndpointsIssuesPayload {
+ reports: EndpointIssuesData[];
+}
+
+export interface GetServiceEnvironmentsPayload {
+ service: string;
+}
+
+export interface SetServiceEnvironmentsPayload {
+ environments: {
+ id: string;
+ name: string;
+ type: EnvironmentType;
+ }[];
+}
+
export type GetEnvironmentsResponse = {
type: "Private" | "Public";
id: string;
name: string;
}[];
+export interface GetEnvironmentServicesPayload {
+ environment: string | null;
+}
+
export type GetEnvironmentServicesResponse = string[];
diff --git a/src/redux/slices/codeIssuesReportSlice.ts b/src/redux/slices/issuesReportSlice.ts
similarity index 60%
rename from src/redux/slices/codeIssuesReportSlice.ts
rename to src/redux/slices/issuesReportSlice.ts
index 9f2ef34d9..6144f8b4e 100644
--- a/src/redux/slices/codeIssuesReportSlice.ts
+++ b/src/redux/slices/issuesReportSlice.ts
@@ -1,25 +1,26 @@
import type { PayloadAction } from "@reduxjs/toolkit";
import { createSlice } from "@reduxjs/toolkit";
-import type {
- Criticality,
- ReportTimeMode,
- ReportViewLevel,
- ReportViewMode
-} from "../../components/Dashboard/MetricsReport/types";
+import type { IssueCriticality } from "../services/types";
-export interface CodeIssuesReportState {
- viewMode: ReportViewMode;
- viewLevel: ReportViewLevel;
- timeMode: ReportTimeMode;
+export type IssuesReportViewMode = "treemap" | "table";
+
+export type IssuesReportTimeMode = "baseline" | "changes";
+
+export type IssuesReportViewLevel = "services" | "endpoints";
+
+export interface IssuesReportState {
+ viewMode: IssuesReportViewMode;
+ viewLevel: IssuesReportViewLevel;
+ timeMode: IssuesReportTimeMode;
selectedEnvironmentId: string | null;
selectedService: string | null;
- criticalityLevels: Criticality[];
+ criticalityLevels: IssueCriticality[];
periodInDays: number;
selectedEndpoints: string[];
selectedServices: string[];
}
-const initialState: CodeIssuesReportState = {
+const initialState: IssuesReportState = {
viewMode: "treemap",
viewLevel: "services",
timeMode: "baseline",
@@ -31,17 +32,17 @@ const initialState: CodeIssuesReportState = {
selectedServices: []
};
-export const codeIssuesReportSlice = createSlice({
- name: "codeIssuesReport",
+export const issuesReportSlice = createSlice({
+ name: "issuesReport",
initialState,
reducers: {
- setViewMode: (state, action: PayloadAction) => {
+ setViewMode: (state, action: PayloadAction) => {
state.viewMode = action.payload;
},
- setViewLevel: (state, action: PayloadAction) => {
+ setViewLevel: (state, action: PayloadAction) => {
state.viewLevel = action.payload;
},
- setTimeMode: (state, action: PayloadAction) => {
+ setTimeMode: (state, action: PayloadAction) => {
state.timeMode = action.payload;
},
setSelectedEnvironmentId: (state, action: PayloadAction) => {
@@ -50,7 +51,10 @@ export const codeIssuesReportSlice = createSlice({
setSelectedService: (state, action: PayloadAction) => {
state.selectedService = action.payload;
},
- setCriticalityLevels: (state, action: PayloadAction) => {
+ setCriticalityLevels: (
+ state,
+ action: PayloadAction
+ ) => {
state.criticalityLevels = action.payload;
},
setPeriodInDays: (state, action: PayloadAction) => {
@@ -61,7 +65,8 @@ export const codeIssuesReportSlice = createSlice({
},
setSelectedServices: (state, action: PayloadAction) => {
state.selectedServices = action.payload;
- }
+ },
+ clear: () => initialState
}
});
@@ -74,7 +79,8 @@ export const {
setCriticalityLevels,
setPeriodInDays,
setSelectedEndpoints,
- setSelectedServices
-} = codeIssuesReportSlice.actions;
+ setSelectedServices,
+ clear
+} = issuesReportSlice.actions;
-export default codeIssuesReportSlice.reducer;
+export default issuesReportSlice.reducer;
diff --git a/src/store/metricsReport/metricsReportSlice.ts b/src/store/metricsReport/metricsReportSlice.ts
deleted file mode 100644
index 20d18b77b..000000000
--- a/src/store/metricsReport/metricsReportSlice.ts
+++ /dev/null
@@ -1,89 +0,0 @@
-import { createSlice } from "zustand-slices";
-import type {
- Criticality,
- EndpointData,
- EndpointIssuesData,
- ReportTimeMode,
- ReportViewLevel,
- ReportViewMode,
- ServiceIssuesData
-} from "../../components/Dashboard/MetricsReport/types";
-import type { Environment } from "../../components/common/App/types";
-
-export interface MetricsReportState {
- metricsReportViewMode: ReportViewMode;
- metricsReportViewLevel: ReportViewLevel;
- metricsReportTimeMode: ReportTimeMode;
- metricsReportSelectedEnvironmentId: string | null;
- metricsReportSelectedService: string | null;
- metricsReportSelectedCriticalityLevels: Criticality[];
- metricsReportSelectedPeriodInDays: number;
- metricsReportSelectedEndpoints: string[];
- metricsReportSelectedServices: string[];
- metricsReportServices: string[] | null;
- metricsReportServicesIssuesData: ServiceIssuesData[] | null;
- metricsReportServiceEnvironments: Environment[] | null;
- metricsReportServiceEndpoints: EndpointData[] | null;
- metricsReportEndpointsIssuesData: EndpointIssuesData[] | null;
-}
-
-const initialState: MetricsReportState = {
- metricsReportViewMode: "treemap",
- metricsReportViewLevel: "services",
- metricsReportTimeMode: "baseline",
- metricsReportSelectedEnvironmentId: null,
- metricsReportSelectedService: null,
- metricsReportSelectedCriticalityLevels: ["Medium", "High"],
- metricsReportSelectedPeriodInDays: 7,
- metricsReportSelectedEndpoints: [],
- metricsReportSelectedServices: [],
- metricsReportServices: null,
- metricsReportServicesIssuesData: null,
- metricsReportServiceEnvironments: null,
- metricsReportServiceEndpoints: null,
- metricsReportEndpointsIssuesData: null
-};
-
-const set =
- (update: Partial) => (state: MetricsReportState) => ({
- ...state,
- ...update
- });
-
-export const metricsReportSlice = createSlice({
- name: "metricsReport",
- value: initialState,
- actions: {
- setMetricsReportViewMode: (viewMode: ReportViewMode) =>
- set({ metricsReportViewMode: viewMode }),
- setMetricsReportViewLevel: (viewLevel: ReportViewLevel) =>
- set({ metricsReportViewLevel: viewLevel }),
- setMetricsReportTimeMode: (timeMode: ReportTimeMode) =>
- set({ metricsReportTimeMode: timeMode }),
- setMetricsReportSelectedEnvironmentId: (environmentId: string) =>
- set({ metricsReportSelectedEnvironmentId: environmentId }),
- setMetricsReportSelectedService: (selectedService: string | null) =>
- set({ metricsReportSelectedService: selectedService }),
- setMetricsReportSelectedCriticalityLevels: (
- criticalityLevels: Criticality[]
- ) => set({ metricsReportSelectedCriticalityLevels: criticalityLevels }),
- setMetricsReportSelectedPeriodInDays: (periodInDays: number) =>
- set({ metricsReportSelectedPeriodInDays: periodInDays }),
- setMetricsReportSelectedEndpoints: (endpoints: string[]) =>
- set({ metricsReportSelectedEndpoints: endpoints }),
- setMetricsReportSelectedServices: (services: string[]) =>
- set({ metricsReportSelectedServices: services }),
- setMetricsReportServices: (services: string[] | null) =>
- set({ metricsReportServices: services }),
- setMetricsReportServicesIssuesData: (
- servicesData: ServiceIssuesData[] | null
- ) => set({ metricsReportServicesIssuesData: servicesData }),
- setMetricsReportServiceEnvironments: (environments: Environment[] | null) =>
- set({ metricsReportServiceEnvironments: environments }),
- setMetricsReportServiceEndpoints: (endpoints: EndpointData[] | null) =>
- set({ metricsReportServiceEndpoints: endpoints }),
- setMetricsReportEndpointsIssuesData: (data: EndpointIssuesData[] | null) =>
- set({ metricsReportEndpointsIssuesData: data }),
- resetMetricsReport: () => set(initialState)
- }
-});
diff --git a/src/store/metricsReport/useMetricsReportSelector.ts b/src/store/metricsReport/useMetricsReportSelector.ts
deleted file mode 100644
index ae674852c..000000000
--- a/src/store/metricsReport/useMetricsReportSelector.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-import { useStore } from "../useStore";
-
-export const useMetricsReportSelector = () =>
- useStore((state) => state.metricsReport);
diff --git a/src/store/useStore.ts b/src/store/useStore.ts
index 912f71813..471f4d308 100644
--- a/src/store/useStore.ts
+++ b/src/store/useStore.ts
@@ -5,18 +5,11 @@ import { assetsSlice } from "./assets/assetsSlice";
import { configSlice } from "./config/configSlice";
import { errorsSlice } from "./errors/errorsSlice";
import { insightsSlice } from "./insights/insightsSlice";
-import { metricsReportSlice } from "./metricsReport/metricsReportSlice";
import { withMutableActions } from "./withMutableActions";
export const useStore = create(
withMutableActions(
- withSlices(
- configSlice,
- insightsSlice,
- assetsSlice,
- metricsReportSlice,
- errorsSlice
- ),
+ withSlices(configSlice, insightsSlice, assetsSlice, errorsSlice),
{
setScope: (scope: Scope) => (_, set) => {
set((state) =>