mirror of
https://github.com/outbackdingo/openapi-ui.git
synced 2026-01-27 02:19:42 +00:00
18
.env
18
.env
@@ -7,8 +7,10 @@ VITE_CUSTOM_TENANT_TEXT=
|
||||
VITE_CUSTOMIZATION_API_GROUP=incloud.io
|
||||
VITE_CUSTOMIZATION_API_VERSION=v1alpha
|
||||
|
||||
VITE_CUSTOMIZATION_NAVIGATION_RESOURCE_NAME=navigations
|
||||
VITE_CUSTOMIZATION_NAVIGATION_RESOURCE=navigation
|
||||
VITE_CUSTOMIZATION_NAVIGATION_RESOURCE_PLURAL=navigations
|
||||
VITE_CUSTOMIZATION_NAVIGATION_RESOURCE_NAME=navigation
|
||||
|
||||
VITE_CUSTOMIZATION_SIDEBAR_FALLBACK_ID = fallback
|
||||
|
||||
VITE_USE_NAMESPACE_NAV=true
|
||||
|
||||
@@ -17,15 +19,15 @@ VITE_HIDE_INSIDE=false
|
||||
VITE_NAVIGATE_FROM_CLUSTERLIST=/openapi-ui/~recordValue~/builtin-table/namespaces
|
||||
|
||||
VITE_PROJECTS_API_GROUP=incloud.io
|
||||
VITE_PROJECTS_VERSION=v1alpha
|
||||
VITE_PROJECTS_RESOURCE_NAME=projects
|
||||
VITE_PROJECTS_API_VERSION=v1alpha
|
||||
VITE_PROJECTS_PLURAL=projects
|
||||
|
||||
VITE_MARKETPLACE_RESOURCE_NAME=marketplacepanels
|
||||
VITE_MARKETPLACE_PLURAL=marketplacepanels
|
||||
VITE_MARKETPLACE_KIND=MarketplacePanel
|
||||
|
||||
VITE_INSTANCES_API_GROUP=incloud.io
|
||||
VITE_INSTANCES_VERSION=v1alpha1
|
||||
VITE_INSTANCES_RESOURCE_NAME=v1alpha1
|
||||
VITE_INSTANCES_API_VERSION=v1alpha1
|
||||
VITE_INSTANCES_PLURAL=v1alpha1
|
||||
|
||||
VITE_BFF_URL=
|
||||
|
||||
@@ -50,4 +52,4 @@ VITE_BASE_NAMESPACE_FACTORY_KEY=base-factory-clusterscoped-builtin
|
||||
|
||||
VITE_CUSTOM_NAMESPACE_API_RESOURCE_API_GROUP=
|
||||
VITE_CUSTOM_NAMESPACE_API_RESOURCE_API_VERSION=
|
||||
VITE_CUSTOM_NAMESPACE_API_RESOURCE_RESOURCE_NAME=
|
||||
VITE_CUSTOM_NAMESPACE_API_RESOURCE_PLURAL=
|
||||
|
||||
@@ -9,8 +9,10 @@ KUBE_API_URL=
|
||||
CUSTOMIZATION_API_GROUP=
|
||||
CUSTOMIZATION_API_VERSION=
|
||||
|
||||
CUSTOMIZATION_NAVIGATION_RESOURCE_PLURAL=
|
||||
CUSTOMIZATION_NAVIGATION_RESOURCE_NAME=
|
||||
CUSTOMIZATION_NAVIGATION_RESOURCE=
|
||||
|
||||
CUSTOMIZATION_SIDEBAR_FALLBACK_ID=
|
||||
|
||||
USE_NAMESPACE_NAV=
|
||||
|
||||
@@ -19,15 +21,15 @@ HIDE_INSIDE=
|
||||
NAVIGATE_FROM_CLUSTERLIST=
|
||||
|
||||
PROJECTS_API_GROUP=
|
||||
PROJECTS_VERSION=
|
||||
PROJECTS_RESOURCE_NAME=
|
||||
PROJECTS_API_VERSION=
|
||||
PROJECTS_PLURAL=
|
||||
|
||||
MARKETPLACE_RESOURCE_NAME=
|
||||
MARKETPLACE_PLURAL
|
||||
MARKETPLACE_KIND=
|
||||
|
||||
INSTANCES_API_GROUP=
|
||||
INSTANCES_VERSION=
|
||||
INSTANCES_RESOURCE_NAME=
|
||||
INSTANCES_API_VERSION=
|
||||
INSTANCES_PLURAL=
|
||||
|
||||
BFF_URL=
|
||||
|
||||
@@ -52,4 +54,4 @@ BASE_NAMESPACE_FACTORY_KEY=
|
||||
|
||||
CUSTOM_NAMESPACE_API_RESOURCE_API_GROUP=
|
||||
CUSTOM_NAMESPACE_API_RESOURCE_API_VERSION=
|
||||
CUSTOM_NAMESPACE_API_RESOURCE_RESOURCE_NAME=
|
||||
CUSTOM_NAMESPACE_API_RESOURCE_PLURAL=
|
||||
|
||||
85
README.md
85
README.md
@@ -9,45 +9,46 @@ Define interfaces in YAML; the app discovers CRDs, watches their objects, and bu
|
||||
|
||||
This app can be configured through environment variables.
|
||||
|
||||
| Variable | Type | Description |
|
||||
| --------------------------------------------- | --------- | --------------------------------------------------------------------------------------- |
|
||||
| `BASEPREFIX` | `string` | Base URL for the app. `/openapi-ui` |
|
||||
| `KUBE_API_URL` | `string` | URL for the Kubernetes API. `http://api.incloud-web.svc.default.in-cloud.internal:8081` |
|
||||
| `BFF_URL` | `string` | URL for the BFF |
|
||||
| `TITLE_TEXT` | `string` | Page title |
|
||||
| `LOGO_TEXT` | `string` | Logo text near icon |
|
||||
| `ICON_SVG` | `string` | Favicon base64 encoded |
|
||||
| `FOOTER_TEXT` | `string` | Footer text |
|
||||
| `CUSTOM_LOGO_SVG` | `string` | Base64 encoded svg |
|
||||
| `CUSTOM_TENANT_TEXT` | `string` | Custom tenant text override |
|
||||
| `LOGIN_URL` | `string` | Login endpoint. `/oauth/token` |
|
||||
| `LOGOUT_URL` | `string` | Logout endpoint. `/oauth/logout` |
|
||||
| `LOGIN_USERNAME_FIELD` | `string` | Field from login endpoint response. `name` |
|
||||
| `CUSTOMIZATION_API_GROUP` | `string` | API group for customization resources. `front.in-cloud.io` |
|
||||
| `CUSTOMIZATION_API_VERSION` | `string` | API version for customization resources. `v1alpha1` |
|
||||
| `CUSTOMIZATION_NAVIGATION_RESOURCE_NAME` | `string` | Resource plural name for navigation settings. `navigations` |
|
||||
| `CUSTOMIZATION_NAVIGATION_RESOURCE` | `string` | Resource name for navigation settings. `navigation` |
|
||||
| `USE_NAMESPACE_NAV` | `boolean` | Use namespaces instead of project/instances. `true` |
|
||||
| `HIDE_INSIDE` | `boolean` | Use namespaces instead of project/instances. `true` |
|
||||
| `NAVIGATE_FROM_CLUSTERLIST` | `string` | Location to be navigated after selecting cluster. `/openapi-ui/clusters/~recordValue~` |
|
||||
| `PROJECTS_API_GROUP` | `string` | API group for projects resources. If not using namespace nav. |
|
||||
| `PROJECTS_VERSION` | `string` | API version for projects resources. If not using namespace nav. |
|
||||
| `PROJECTS_RESOURCE_NAME` | `string` | Plural name for projects resources. If not using namespace nav. |
|
||||
| `INSTANCES_API_GROUP` | `string` | API group for instances resources. If not using namespace nav. |
|
||||
| `INSTANCES_VERSION` | `string` | API version for instances resources. If not using namespace nav. |
|
||||
| `INSTANCES_RESOURCE_NAME` | `string` | Plural name for instances resources. If not using namespace nav. |
|
||||
| `MARKETPLACE_RESOURCE_NAME` | `string` | Plural name for marketplace resources for related factory component. |
|
||||
| `MARKETPLACE_KIND` | `string` | Kind name for marketplace resources for related factory component. |
|
||||
| `NODE_TERMINAL_DEFAULT_PROFILE` | `string` | Default profile for node terminal component. `baseline` |
|
||||
| `REMOVE_BACKLINK` | `boolean` | Remove backlink arrow from right-side navigation |
|
||||
| `REMOVE_BACKLINK_TEXT` | `boolean` | Remove backlink text from right-side navigation |
|
||||
| `DOCS_URL` | `string` | URL to navigate from question mark |
|
||||
| `SEARCH_TABLE_CUSTOMIZATION_PREFIX` | `string` | Search tables Customization id prefix |
|
||||
| `BASE_FACTORY_NAMESPACED_API_KEY` | `string` | Base factory key for namespaced API resources |
|
||||
| `BASE_FACTORY_CLUSTERSCOPED_API_KEY` | `string` | Base factory key for clusterscoped API resources |
|
||||
| `BASE_FACTORY_NAMESPACED_BUILTIN_KEY` | `string` | Base factory key for namespaced builtin (v1) resources |
|
||||
| `BASE_FACTORY_CLUSTERSCOPED_BUILTIN_KEY` | `string` | Base factory key for clusterscoped builtin (v1) resources |
|
||||
| `BASE_NAMESPACE_FACTORY_KEY` | `string` | Base factory key for namespaces |
|
||||
| `CUSTOM_NAMESPACE_API_RESOURCE_API_GROUP` | `string` | Custom namespace resource: api group |
|
||||
| `CUSTOM_NAMESPACE_API_RESOURCE_API_VERSION` | `string` | Custom namespace resource: api version |
|
||||
| `CUSTOM_NAMESPACE_API_RESOURCE_RESOURCE_NAME` | `string` | Custom namespace resource: resource name |
|
||||
| Variable | Type | Description |
|
||||
| ------------------------------------------- | --------- | --------------------------------------------------------------------------------------- |
|
||||
| `BASEPREFIX` | `string` | Base URL for the app. `/openapi-ui` |
|
||||
| `KUBE_API_URL` | `string` | URL for the Kubernetes API. `http://api.incloud-web.svc.default.in-cloud.internal:8081` |
|
||||
| `BFF_URL` | `string` | URL for the BFF |
|
||||
| `TITLE_TEXT` | `string` | Page title |
|
||||
| `LOGO_TEXT` | `string` | Logo text near icon |
|
||||
| `ICON_SVG` | `string` | Favicon base64 encoded |
|
||||
| `FOOTER_TEXT` | `string` | Footer text |
|
||||
| `CUSTOM_LOGO_SVG` | `string` | Base64 encoded svg |
|
||||
| `CUSTOM_TENANT_TEXT` | `string` | Custom tenant text override |
|
||||
| `LOGIN_URL` | `string` | Login endpoint. `/oauth/token` |
|
||||
| `LOGOUT_URL` | `string` | Logout endpoint. `/oauth/logout` |
|
||||
| `LOGIN_USERNAME_FIELD` | `string` | Field from login endpoint response. `name` |
|
||||
| `CUSTOMIZATION_API_GROUP` | `string` | API group for customization resources. `front.in-cloud.io` |
|
||||
| `CUSTOMIZATION_API_VERSION` | `string` | API version for customization resources. `v1alpha1` |
|
||||
| `CUSTOMIZATION_NAVIGATION_RESOURCE_PLURAL` | `string` | Resource plural name for navigation settings. `navigations` |
|
||||
| `CUSTOMIZATION_NAVIGATION_RESOURCE_NAME` | `string` | Resource name for navigation settings. `navigation` |
|
||||
| `CUSTOMIZATION_SIDEBAR_FALLBACK_ID` | `string` | `spec.id` to find in `sidebars` to fallback. Use `-namespaced` for NS-pages |
|
||||
| `USE_NAMESPACE_NAV` | `boolean` | Use namespaces instead of project/instances. `true` |
|
||||
| `HIDE_INSIDE` | `boolean` | Use namespaces instead of project/instances. `true` |
|
||||
| `NAVIGATE_FROM_CLUSTERLIST` | `string` | Location to be navigated after selecting cluster. `/openapi-ui/clusters/~recordValue~` |
|
||||
| `PROJECTS_API_GROUP` | `string` | API group for projects resources. If not using namespace nav. |
|
||||
| `PROJECTS_API_VERSION` | `string` | API version for projects resources. If not using namespace nav. |
|
||||
| `PROJECTS_PLURAL` | `string` | Plural name for projects resources. If not using namespace nav. |
|
||||
| `INSTANCES_API_GROUP` | `string` | API group for instances resources. If not using namespace nav. |
|
||||
| `INSTANCES_API_VERSION` | `string` | API version for instances resources. If not using namespace nav. |
|
||||
| `INSTANCES_PLURAL` | `string` | Plural name for instances resources. If not using namespace nav. |
|
||||
| `MARKETPLACE_PLURAL` | `string` | Plural name for marketplace resources for related factory component. |
|
||||
| `MARKETPLACE_KIND` | `string` | Kind name for marketplace resources for related factory component. |
|
||||
| `NODE_TERMINAL_DEFAULT_PROFILE` | `string` | Default profile for node terminal component. `baseline` |
|
||||
| `REMOVE_BACKLINK` | `boolean` | Remove backlink arrow from right-side navigation |
|
||||
| `REMOVE_BACKLINK_TEXT` | `boolean` | Remove backlink text from right-side navigation |
|
||||
| `DOCS_URL` | `string` | URL to navigate from question mark |
|
||||
| `SEARCH_TABLE_CUSTOMIZATION_PREFIX` | `string` | Search tables Customization id prefix |
|
||||
| `BASE_FACTORY_NAMESPACED_API_KEY` | `string` | Base factory key for namespaced API resources |
|
||||
| `BASE_FACTORY_CLUSTERSCOPED_API_KEY` | `string` | Base factory key for clusterscoped API resources |
|
||||
| `BASE_FACTORY_NAMESPACED_BUILTIN_KEY` | `string` | Base factory key for namespaced builtin (v1) resources |
|
||||
| `BASE_FACTORY_CLUSTERSCOPED_BUILTIN_KEY` | `string` | Base factory key for clusterscoped builtin (v1) resources |
|
||||
| `BASE_NAMESPACE_FACTORY_KEY` | `string` | Base factory key for namespaces |
|
||||
| `CUSTOM_NAMESPACE_API_RESOURCE_API_GROUP` | `string` | Custom namespace resource: api group |
|
||||
| `CUSTOM_NAMESPACE_API_RESOURCE_API_VERSION` | `string` | Custom namespace resource: api version |
|
||||
| `CUSTOM_NAMESPACE_API_RESOURCE_PLURAL` | `string` | Custom namespace resource: plural name |
|
||||
|
||||
97
package-lock.json
generated
97
package-lock.json
generated
@@ -11,7 +11,7 @@
|
||||
"@ant-design/icons": "5.6.0",
|
||||
"@monaco-editor/react": "4.6.0",
|
||||
"@originjs/vite-plugin-federation": "1.3.6",
|
||||
"@prorobotech/openapi-k8s-toolkit": "^1.0.3",
|
||||
"@prorobotech/openapi-k8s-toolkit": "^1.1.0-alpha.20",
|
||||
"@readme/openapi-parser": "4.0.0",
|
||||
"@reduxjs/toolkit": "2.2.5",
|
||||
"@tanstack/react-query": "5.62.2",
|
||||
@@ -146,7 +146,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-5.6.0.tgz",
|
||||
"integrity": "sha512-Mb6QkQmPLZsmIHJ6oBsoyKrrT8/kAUdQ6+8q38e2bQSclROi69SiDlI4zZroaIPseae1w110RJH0zGrphAvlSQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@ant-design/colors": "^7.0.0",
|
||||
"@ant-design/icons-svg": "^4.4.0",
|
||||
@@ -258,7 +257,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.27.1.tgz",
|
||||
"integrity": "sha512-IaaGWsQqfsQWVLqMn9OB92MNN7zukfVA4s7KKAI0KfrrDsZ0yhi5uV4baBuLuN7n3vsZpwP8asPPcVwApxvjBQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@ampproject/remapping": "^2.2.0",
|
||||
"@babel/code-frame": "^7.27.1",
|
||||
@@ -1859,6 +1857,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz",
|
||||
"integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.1.90"
|
||||
}
|
||||
@@ -1879,7 +1878,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
@@ -1903,7 +1901,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -1960,6 +1957,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz",
|
||||
"integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"colorspace": "1.1.x",
|
||||
"enabled": "2.0.x",
|
||||
@@ -2804,9 +2802,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@prorobotech/openapi-k8s-toolkit": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@prorobotech/openapi-k8s-toolkit/-/openapi-k8s-toolkit-1.0.3.tgz",
|
||||
"integrity": "sha512-A8RFEd8CYdvYwnGHSOFEGZ+hotMWvtRRnXsZAcFycBF+oy6GNxCOCSfHv8IWlXfD7Rr4i7Xhp8MtDijAty+80g==",
|
||||
"version": "1.1.0-alpha.20",
|
||||
"resolved": "https://registry.npmjs.org/@prorobotech/openapi-k8s-toolkit/-/openapi-k8s-toolkit-1.1.0-alpha.20.tgz",
|
||||
"integrity": "sha512-jptUG4OV2SLTgt3Z3rBUf2GNOGgS4QCTxOcrrkoreC0wyCkubTcI7+rflc29B2OOGcEi/2F6GCVf/H4qimgDnA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@monaco-editor/react": "4.6.0",
|
||||
@@ -3711,7 +3709,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.62.2.tgz",
|
||||
"integrity": "sha512-fkTpKKfwTJtVPKVR+ag7YqFgG/7TRVVPzduPAUF9zRCiiA8Wu305u+KJl8rCrh98Qce77vzIakvtUyzWLtaPGA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@tanstack/query-core": "5.62.2"
|
||||
},
|
||||
@@ -3728,7 +3725,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.62.2.tgz",
|
||||
"integrity": "sha512-s4+88OZ6ygD4ziNfUgh9y1XxsGqpscI77c8EaLP7KwEfa5WqnlB9MT/uslFkFq3vwb8JhMjB7Osv2MYrSMry6w==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@tanstack/query-devtools": "5.61.4"
|
||||
},
|
||||
@@ -3863,7 +3859,6 @@
|
||||
"integrity": "sha512-24xqse6+VByVLIr+xWaQ9muX1B4bXJKXBbjszbld/UEDslGLY53+ZucF44HCmLbMPejTzGG9XgR+3m2/Wqu1kw==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/prop-types": "*",
|
||||
"@types/scheduler": "*",
|
||||
@@ -3953,7 +3948,8 @@
|
||||
"version": "1.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz",
|
||||
"integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@types/use-sync-external-store": {
|
||||
"version": "0.0.3",
|
||||
@@ -4001,6 +3997,7 @@
|
||||
"integrity": "sha512-LKMrmwCPoLhM45Z00O1ulb6jwyVr2kr3XJp+G+tSEZcbauNnScewcQwtJqXDhXeYPDEjZ8C1SjXm015CirEmGg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "8.32.1",
|
||||
"@typescript-eslint/types": "8.32.1",
|
||||
@@ -4026,6 +4023,7 @@
|
||||
"integrity": "sha512-7IsIaIDeZn7kffk7qXC3o6Z4UblZJKV3UBpkvRNpr5NSyLji7tvTcvmnMNYuYLyh26mN8W723xpo3i4MlD33vA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.32.1",
|
||||
"@typescript-eslint/visitor-keys": "8.32.1"
|
||||
@@ -4044,6 +4042,7 @@
|
||||
"integrity": "sha512-ar0tjQfObzhSaW3C3QNmTc5ofj0hDoNQ5XWrCy6zDyabdr0TWhCkClp+rywGNj/odAFBVzzJrK4tEq5M4Hmu4w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.32.1",
|
||||
"eslint-visitor-keys": "^4.2.0"
|
||||
@@ -4062,6 +4061,7 @@
|
||||
"integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
@@ -4188,6 +4188,7 @@
|
||||
"integrity": "sha512-YmybwXUJcgGqgAp6bEsgpPXEg6dcCyPyCSr0CAAueacR/CCBi25G3V8gGQ2kRzQRBNol7VQknxMs9HvVa9Rvfg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
@@ -4202,6 +4203,7 @@
|
||||
"integrity": "sha512-Y3AP9EIfYwBb4kWGb+simvPaqQoT5oJuzzj9m0i6FCY6SPvlomY2Ei4UEMm7+FXtlNJbor80ximyslzaQF6xhg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.32.1",
|
||||
"@typescript-eslint/visitor-keys": "8.32.1",
|
||||
@@ -4229,6 +4231,7 @@
|
||||
"integrity": "sha512-ar0tjQfObzhSaW3C3QNmTc5ofj0hDoNQ5XWrCy6zDyabdr0TWhCkClp+rywGNj/odAFBVzzJrK4tEq5M4Hmu4w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.32.1",
|
||||
"eslint-visitor-keys": "^4.2.0"
|
||||
@@ -4247,6 +4250,7 @@
|
||||
"integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
@@ -4260,6 +4264,7 @@
|
||||
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
@@ -4273,6 +4278,7 @@
|
||||
"integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18.12"
|
||||
},
|
||||
@@ -4433,8 +4439,7 @@
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-5.5.0.tgz",
|
||||
"integrity": "sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/accepts": {
|
||||
"version": "1.3.8",
|
||||
@@ -4455,7 +4460,6 @@
|
||||
"integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
@@ -4478,7 +4482,6 @@
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
|
||||
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"fast-uri": "^3.0.1",
|
||||
@@ -4535,7 +4538,6 @@
|
||||
"resolved": "https://registry.npmjs.org/antd/-/antd-5.26.4.tgz",
|
||||
"integrity": "sha512-e1EnOvEkvvqcQ18dxfzChBJyJACyih13WpNf2OtnP9z2POh/SF0fXL+ynUemT1zfr+p+P1po/tmHXaMc5PMghg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@ant-design/colors": "^7.2.1",
|
||||
"@ant-design/cssinjs": "^1.23.0",
|
||||
@@ -4853,7 +4855,8 @@
|
||||
"version": "3.2.6",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz",
|
||||
"integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/async-function": {
|
||||
"version": "1.0.0",
|
||||
@@ -5256,7 +5259,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"caniuse-lite": "^1.0.30001716",
|
||||
"electron-to-chromium": "^1.5.149",
|
||||
@@ -5506,6 +5508,7 @@
|
||||
"resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz",
|
||||
"integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"color-convert": "^1.9.3",
|
||||
"color-string": "^1.6.0"
|
||||
@@ -5535,6 +5538,7 @@
|
||||
"resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
|
||||
"integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"color-name": "^1.0.0",
|
||||
"simple-swizzle": "^0.2.2"
|
||||
@@ -5545,6 +5549,7 @@
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"color-name": "1.1.3"
|
||||
}
|
||||
@@ -5553,7 +5558,8 @@
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/colord": {
|
||||
"version": "2.9.3",
|
||||
@@ -5566,6 +5572,7 @@
|
||||
"resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz",
|
||||
"integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"color": "^3.1.3",
|
||||
"text-hex": "1.0.x"
|
||||
@@ -5963,8 +5970,7 @@
|
||||
"version": "1.11.13",
|
||||
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz",
|
||||
"integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.4.1",
|
||||
@@ -6194,7 +6200,8 @@
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz",
|
||||
"integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/encodeurl": {
|
||||
"version": "1.0.2",
|
||||
@@ -6563,7 +6570,6 @@
|
||||
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.2.0",
|
||||
"@eslint-community/regexpp": "^4.6.1",
|
||||
@@ -6725,7 +6731,6 @@
|
||||
"integrity": "sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"array-includes": "^3.1.6",
|
||||
"array.prototype.findlastindex": "^1.2.2",
|
||||
@@ -6805,7 +6810,6 @@
|
||||
"integrity": "sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.7",
|
||||
"aria-query": "^5.1.3",
|
||||
@@ -6891,7 +6895,6 @@
|
||||
"integrity": "sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"array-includes": "^3.1.6",
|
||||
"array.prototype.flatmap": "^1.3.1",
|
||||
@@ -6923,7 +6926,6 @@
|
||||
"integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
@@ -7501,7 +7503,8 @@
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz",
|
||||
"integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/file-entry-cache": {
|
||||
"version": "6.0.1",
|
||||
@@ -7604,7 +7607,8 @@
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz",
|
||||
"integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.15.9",
|
||||
@@ -8741,6 +8745,7 @@
|
||||
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
|
||||
"integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
@@ -9031,7 +9036,8 @@
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz",
|
||||
"integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/language-subtag-registry": {
|
||||
"version": "0.3.23",
|
||||
@@ -9127,6 +9133,7 @@
|
||||
"resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz",
|
||||
"integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@colors/colors": "1.6.0",
|
||||
"@types/triple-beam": "^1.3.2",
|
||||
@@ -9672,6 +9679,7 @@
|
||||
"resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz",
|
||||
"integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"fn.name": "1.x.x"
|
||||
}
|
||||
@@ -9680,8 +9688,7 @@
|
||||
"version": "12.1.3",
|
||||
"resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz",
|
||||
"integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/optionator": {
|
||||
"version": "0.9.4",
|
||||
@@ -9967,7 +9974,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.8",
|
||||
"picocolors": "^1.1.1",
|
||||
@@ -10017,7 +10023,6 @@
|
||||
"integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"cssesc": "^3.0.0",
|
||||
"util-deprecate": "^1.0.2"
|
||||
@@ -10089,7 +10094,6 @@
|
||||
"integrity": "sha512-o2YR9qtniXvwEZlOKbveKfDQVyqxbEIWn48Z8m3ZJjBjcCmUy3xZGIv+7AkaeuaTr6yPXJjwv07ZWlsWbEy1rQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"prettier": "bin/prettier.cjs"
|
||||
},
|
||||
@@ -10135,7 +10139,6 @@
|
||||
"resolved": "https://registry.npmjs.org/prom-client/-/prom-client-15.1.3.tgz",
|
||||
"integrity": "sha512-6ZiOBfCywsD4k1BN9IX0uZhF+tJkV8q8llP64G5Hajs4JOeVLPCwpPVcpXy3BwYiUGgyJzsJJQeOIv7+hDSq8g==",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@opentelemetry/api": "^1.4.0",
|
||||
"tdigest": "^0.1.1"
|
||||
@@ -10912,7 +10915,6 @@
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
|
||||
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0"
|
||||
},
|
||||
@@ -10925,7 +10927,6 @@
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
|
||||
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"scheduler": "^0.23.2"
|
||||
@@ -10984,7 +10985,6 @@
|
||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.25.1.tgz",
|
||||
"integrity": "sha512-0tUDpbFvk35iv+N89dWNrJp+afLgd+y4VtorJZuOCXK0kkCWjEvb3vTJM++SYvMEpbVwXKf3FjeVveVEb6JpDQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@remix-run/router": "1.18.0",
|
||||
"react-router": "6.25.1"
|
||||
@@ -11028,8 +11028,7 @@
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
|
||||
"integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/redux-thunk": {
|
||||
"version": "3.1.0",
|
||||
@@ -11261,7 +11260,6 @@
|
||||
"integrity": "sha512-HqMFpUbWlf/tvcxBFNKnJyzc7Lk+XO3FGc3pbNBLqEbOz0gPLRgcrlS3UF4MfUrVlstOaP/q0kM6GVvi+LrLRg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/estree": "1.0.7"
|
||||
},
|
||||
@@ -11400,6 +11398,7 @@
|
||||
"resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz",
|
||||
"integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
@@ -11684,6 +11683,7 @@
|
||||
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
|
||||
"integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"is-arrayish": "^0.3.1"
|
||||
}
|
||||
@@ -11692,7 +11692,8 @@
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
|
||||
"integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/slash": {
|
||||
"version": "2.0.0",
|
||||
@@ -11758,6 +11759,7 @@
|
||||
"resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
|
||||
"integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
@@ -12282,7 +12284,8 @@
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz",
|
||||
"integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/text-table": {
|
||||
"version": "0.2.0",
|
||||
@@ -12345,6 +12348,7 @@
|
||||
"resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz",
|
||||
"integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">= 14.0.0"
|
||||
}
|
||||
@@ -12974,7 +12978,6 @@
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
|
||||
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
@@ -13211,7 +13214,6 @@
|
||||
"integrity": "sha512-IeL5f8OO5nylsgzd9tq4qD2QqI0k2CQLGrWD0rCN0EQJZpBK5vJAx0I+GDkMOXxQX/OfFHMuLIx6ddAxGX/k+Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.21.3",
|
||||
"postcss": "^8.4.43",
|
||||
@@ -13463,6 +13465,7 @@
|
||||
"resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz",
|
||||
"integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"logform": "^2.7.0",
|
||||
"readable-stream": "^3.6.2",
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
"@ant-design/icons": "5.6.0",
|
||||
"@monaco-editor/react": "4.6.0",
|
||||
"@originjs/vite-plugin-federation": "1.3.6",
|
||||
"@prorobotech/openapi-k8s-toolkit": "1.0.3",
|
||||
"@prorobotech/openapi-k8s-toolkit": "1.1.0-alpha.20",
|
||||
"@readme/openapi-parser": "4.0.0",
|
||||
"@reduxjs/toolkit": "2.2.5",
|
||||
"@tanstack/react-query": "5.62.2",
|
||||
|
||||
@@ -29,14 +29,19 @@ const CUSTOMIZATION_API_GROUP =
|
||||
const CUSTOMIZATION_API_VERSION =
|
||||
process.env.LOCAL === 'true' ? options?.CUSTOMIZATION_API_VERSION : process.env.CUSTOMIZATION_API_VERSION
|
||||
|
||||
const CUSTOMIZATION_NAVIGATION_RESOURCE_PLURAL =
|
||||
process.env.LOCAL === 'true'
|
||||
? options?.CUSTOMIZATION_NAVIGATION_RESOURCE_PLURAL
|
||||
: process.env.CUSTOMIZATION_NAVIGATION_RESOURCE_PLURAL
|
||||
const CUSTOMIZATION_NAVIGATION_RESOURCE_NAME =
|
||||
process.env.LOCAL === 'true'
|
||||
? options?.CUSTOMIZATION_NAVIGATION_RESOURCE_NAME
|
||||
: process.env.CUSTOMIZATION_NAVIGATION_RESOURCE_NAME
|
||||
const CUSTOMIZATION_NAVIGATION_RESOURCE =
|
||||
|
||||
const CUSTOMIZATION_SIDEBAR_FALLBACK_ID =
|
||||
process.env.LOCAL === 'true'
|
||||
? options?.CUSTOMIZATION_NAVIGATION_RESOURCE
|
||||
: process.env.CUSTOMIZATION_NAVIGATION_RESOURCE
|
||||
? options?.CUSTOMIZATION_SIDEBAR_FALLBACK_ID
|
||||
: process.env.CUSTOMIZATION_SIDEBAR_FALLBACK_ID
|
||||
|
||||
const USE_NAMESPACE_NAV = process.env.LOCAL === 'true' ? options?.USE_NAMESPACE_NAV : process.env.USE_NAMESPACE_NAV
|
||||
const HIDE_INSIDE = process.env.LOCAL === 'true' ? options?.HIDE_INSIDE : process.env.HIDE_INSIDE
|
||||
@@ -45,19 +50,18 @@ const NAVIGATE_FROM_CLUSTERLIST =
|
||||
process.env.LOCAL === 'true' ? options?.NAVIGATE_FROM_CLUSTERLIST : process.env.NAVIGATE_FROM_CLUSTERLIST
|
||||
|
||||
const PROJECTS_API_GROUP = process.env.LOCAL === 'true' ? options?.PROJECTS_API_GROUP : process.env.PROJECTS_API_GROUP
|
||||
const PROJECTS_VERSION = process.env.LOCAL === 'true' ? options?.PROJECTS_VERSION : process.env.PROJECTS_VERSION
|
||||
const PROJECTS_RESOURCE_NAME =
|
||||
process.env.LOCAL === 'true' ? options?.PROJECTS_RESOURCE_NAME : process.env.PROJECTS_RESOURCE_NAME
|
||||
const PROJECTS_API_VERSION =
|
||||
process.env.LOCAL === 'true' ? options?.PROJECTS_API_VERSION : process.env.PROJECTS_API_VERSION
|
||||
const PROJECTS_PLURAL = process.env.LOCAL === 'true' ? options?.PROJECTS_PLURAL : process.env.PROJECTS_PLURAL
|
||||
|
||||
const MARKETPLACE_RESOURCE_NAME =
|
||||
process.env.LOCAL === 'true' ? options?.MARKETPLACE_RESOURCE_NAME : process.env.MARKETPLACE_RESOURCE_NAME
|
||||
const MARKETPLACE_PLURAL = process.env.LOCAL === 'true' ? options?.MARKETPLACE_PLURAL : process.env.MARKETPLACE_PLURAL
|
||||
const MARKETPLACE_KIND = process.env.LOCAL === 'true' ? options?.MARKETPLACE_KIND : process.env.MARKETPLACE_KIND
|
||||
|
||||
const INSTANCES_API_GROUP =
|
||||
process.env.LOCAL === 'true' ? options?.INSTANCES_API_GROUP : process.env.INSTANCES_API_GROUP
|
||||
const INSTANCES_VERSION = process.env.LOCAL === 'true' ? options?.INSTANCES_VERSION : process.env.INSTANCES_VERSION
|
||||
const INSTANCES_RESOURCE_NAME =
|
||||
process.env.LOCAL === 'true' ? options?.INSTANCES_RESOURCE_NAME : process.env.INSTANCES_RESOURCE_NAME
|
||||
const INSTANCES_API_VERSION =
|
||||
process.env.LOCAL === 'true' ? options?.INSTANCES_API_VERSION : process.env.INSTANCES_API_VERSION
|
||||
const INSTANCES_PLURAL = process.env.LOCAL === 'true' ? options?.INSTANCES_PLURAL : process.env.INSTANCES_PLURAL
|
||||
|
||||
const BFF_URL = process.env.LOCAL === 'true' ? options?.BFF_URL : process.env.BFF_URL
|
||||
|
||||
@@ -105,10 +109,10 @@ const CUSTOM_NAMESPACE_API_RESOURCE_API_VERSION =
|
||||
process.env.LOCAL === 'true'
|
||||
? options?.CUSTOM_NAMESPACE_API_RESOURCE_API_VERSION
|
||||
: process.env.CUSTOM_NAMESPACE_API_RESOURCE_API_VERSION
|
||||
const CUSTOM_NAMESPACE_API_RESOURCE_RESOURCE_NAME =
|
||||
const CUSTOM_NAMESPACE_API_RESOURCE_PLURAL =
|
||||
process.env.LOCAL === 'true'
|
||||
? options?.CUSTOM_NAMESPACE_API_RESOURCE_RESOURCE_NAME
|
||||
: process.env.CUSTOM_NAMESPACE_API_RESOURCE_RESOURCE_NAME
|
||||
? options?.CUSTOM_NAMESPACE_API_RESOURCE_PLURAL
|
||||
: process.env.CUSTOM_NAMESPACE_API_RESOURCE_PLURAL
|
||||
|
||||
const healthcheck = require('express-healthcheck')
|
||||
const promBundle = require('express-prom-bundle')
|
||||
@@ -220,6 +224,9 @@ app.get(`${basePrefix ? basePrefix : ''}/env.js`, (_, res) => {
|
||||
${CUSTOM_TENANT_TEXT ? ` CUSTOM_TENANT_TEXT: "${CUSTOM_TENANT_TEXT}",` : ''}
|
||||
CUSTOMIZATION_API_GROUP: ${JSON.stringify(CUSTOMIZATION_API_GROUP) || '"check envs"'},
|
||||
CUSTOMIZATION_API_VERSION: ${JSON.stringify(CUSTOMIZATION_API_VERSION) || '"check envs"'},
|
||||
CUSTOMIZATION_NAVIGATION_RESOURCE_PLURAL: ${
|
||||
JSON.stringify(CUSTOMIZATION_NAVIGATION_RESOURCE_PLURAL) || '"check envs"'
|
||||
},
|
||||
CUSTOMIZATION_NAVIGATION_RESOURCE_NAME: ${
|
||||
JSON.stringify(CUSTOMIZATION_NAVIGATION_RESOURCE_NAME) || '"check envs"'
|
||||
},
|
||||
@@ -234,22 +241,22 @@ app.get(`${basePrefix ? basePrefix : ''}/env.js`, (_, res) => {
|
||||
: ''
|
||||
}
|
||||
${
|
||||
CUSTOM_NAMESPACE_API_RESOURCE_RESOURCE_NAME
|
||||
? ` CUSTOM_NAMESPACE_API_RESOURCE_RESOURCE_NAME: "${CUSTOM_NAMESPACE_API_RESOURCE_RESOURCE_NAME}",`
|
||||
CUSTOM_NAMESPACE_API_RESOURCE_PLURAL
|
||||
? ` CUSTOM_NAMESPACE_API_RESOURCE_PLURAL: "${CUSTOM_NAMESPACE_API_RESOURCE_PLURAL}",`
|
||||
: ''
|
||||
}
|
||||
CUSTOMIZATION_NAVIGATION_RESOURCE: ${JSON.stringify(CUSTOMIZATION_NAVIGATION_RESOURCE) || '"check envs"'},
|
||||
CUSTOMIZATION_SIDEBAR_FALLBACK_ID: ${JSON.stringify(CUSTOMIZATION_SIDEBAR_FALLBACK_ID) || '"check envs"'},
|
||||
USE_NAMESPACE_NAV: ${USE_NAMESPACE_NAV ? JSON.stringify(USE_NAMESPACE_NAV).toLowerCase() : '"false"'},
|
||||
HIDE_INSIDE: ${HIDE_INSIDE ? JSON.stringify(HIDE_INSIDE).toLowerCase() : '"false"'},
|
||||
NAVIGATE_FROM_CLUSTERLIST: ${JSON.stringify(NAVIGATE_FROM_CLUSTERLIST) || '"check envs"'},
|
||||
PROJECTS_API_GROUP: ${JSON.stringify(PROJECTS_API_GROUP) || '"check envs"'},
|
||||
PROJECTS_VERSION: ${JSON.stringify(PROJECTS_VERSION) || '"check envs"'},
|
||||
PROJECTS_RESOURCE_NAME: ${JSON.stringify(PROJECTS_RESOURCE_NAME) || '"check envs"'},
|
||||
MARKETPLACE_RESOURCE_NAME: ${JSON.stringify(MARKETPLACE_RESOURCE_NAME) || '"check envs"'},
|
||||
PROJECTS_API_VERSION: ${JSON.stringify(PROJECTS_API_VERSION) || '"check envs"'},
|
||||
PROJECTS_PLURAL: ${JSON.stringify(PROJECTS_PLURAL) || '"check envs"'},
|
||||
MARKETPLACE_PLURAL: ${JSON.stringify(MARKETPLACE_PLURAL) || '"check envs"'},
|
||||
MARKETPLACE_KIND: ${JSON.stringify(MARKETPLACE_KIND) || '"check envs"'},
|
||||
INSTANCES_API_GROUP: ${JSON.stringify(INSTANCES_API_GROUP) || '"check envs"'},
|
||||
INSTANCES_VERSION: ${JSON.stringify(INSTANCES_VERSION) || '"check envs"'},
|
||||
INSTANCES_RESOURCE_NAME: ${JSON.stringify(INSTANCES_RESOURCE_NAME) || '"check envs"'},
|
||||
INSTANCES_API_VERSION: ${JSON.stringify(INSTANCES_API_VERSION) || '"check envs"'},
|
||||
INSTANCES_PLURAL: ${JSON.stringify(INSTANCES_PLURAL) || '"check envs"'},
|
||||
NODE_TERMINAL_DEFAULT_PROFILE: ${JSON.stringify(NODE_TERMINAL_DEFAULT_PROFILE) || '"general"'},
|
||||
LOGIN_URL: ${JSON.stringify(LOGIN_URL) || '"check envs"'},
|
||||
LOGOUT_URL: ${JSON.stringify(LOGOUT_URL) || '"check envs"'},
|
||||
|
||||
109
src/App.tsx
109
src/App.tsx
@@ -12,25 +12,25 @@ import { setBaseprefix } from 'store/federation/federation/baseprefix'
|
||||
import {
|
||||
MainPage,
|
||||
ListClustersPage,
|
||||
ListProjectsPage,
|
||||
ProjectInfoPage,
|
||||
RedirectProjectsPage,
|
||||
RedirectProjectInfoPage,
|
||||
ListInsideClustersAndNsPage,
|
||||
ListInsideApiPage,
|
||||
ListInsideCrdByApiGroupPage,
|
||||
ListInsideApiByApiGroupPage,
|
||||
TableCrdPage,
|
||||
// TableCrdPage,
|
||||
TableApiPage,
|
||||
TableBuiltinPage,
|
||||
FormBuiltinPage,
|
||||
FormApiPage,
|
||||
FormCrdPage,
|
||||
// FormCrdPage,
|
||||
FactoryPage,
|
||||
FactoryAdminPage,
|
||||
// FactoryAdminPage,
|
||||
SearchPage,
|
||||
} from 'pages'
|
||||
import { getBasePrefix } from 'utils/getBaseprefix'
|
||||
import { colorsLight, colorsDark, sizes } from 'constants/colors'
|
||||
import { MainLayout } from 'templates/MainLayout'
|
||||
import { MainLayout, AppShell } from 'templates'
|
||||
|
||||
type TAppProps = {
|
||||
isFederation?: boolean
|
||||
@@ -58,73 +58,40 @@ export const App: FC<TAppProps> = ({ isFederation, forcedTheme }) => {
|
||||
<Route element={<MainLayout forcedTheme={forcedTheme} />}>
|
||||
<Route path={`${prefix}/`} element={<MainPage />} />
|
||||
<Route path={`${prefix}/clusters`} element={<ListClustersPage />} />
|
||||
<Route path={`${prefix}/clusters/:clusterName`} element={<ListProjectsPage />} />
|
||||
|
||||
<Route path={`${prefix}/:cluster/:namespace?/:syntheticProject?/*`} element={<AppShell />}>
|
||||
{/* <Route path="crd-table/:apiGroup/:apiVersion/:apiExtensionVersion/:crdName" element={<TableCrdPage />} /> */}
|
||||
<Route path="api-table/:apiGroup/:apiVersion/:plural" element={<TableApiPage />} />
|
||||
<Route path="builtin-table/:plural" element={<TableBuiltinPage />} />
|
||||
{/* <Route path="forms/crds/:apiGroup/:apiVersion/:plural/:name?/"" element={<FormCrdPage />} /> */}
|
||||
<Route path="forms/apis/:apiGroup/:apiVersion/:plural/:name?/" element={<FormApiPage />} />
|
||||
<Route path="forms/builtin/:apiVersion/:plural/:name?/" element={<FormBuiltinPage />} />
|
||||
<Route path="factory/:key/*" element={<FactoryPage />} />
|
||||
<Route path="search/*" element={<SearchPage />} />
|
||||
</Route>
|
||||
|
||||
<Route path={`${prefix}/inside/:cluster/:namespace?/:syntheticProject?/*`} element={<AppShell inside />}>
|
||||
{/* <Route path="crd-table/:apiGroup/:apiVersion/:apiExtensionVersion/:crdName" element={<TableCrdPage inside />} /> */}
|
||||
<Route path="api-table/:apiGroup/:apiVersion/:plural" element={<TableApiPage inside />} />
|
||||
<Route path="builtin-table/:plural" element={<TableBuiltinPage inside />} />
|
||||
{/* <Route path="forms/crds/:apiGroup/:apiVersion/:plural/:name?/"" element={<FormCrdPage />} /> */}
|
||||
<Route path="forms/builtin/:apiVersion/:plural/:name?/" element={<FormBuiltinPage />} />
|
||||
<Route path="forms/apis/:apiGroup/:apiVersion/:plural/:name?/" element={<FormApiPage />} />
|
||||
</Route>
|
||||
|
||||
<Route path={`${prefix}/inside/`} element={<MainPage />} />
|
||||
<Route path={`${prefix}/clusters/:clusterName/projects/:namespace`} element={<ProjectInfoPage />} />
|
||||
<Route path={`${prefix}/inside/clusters`} element={<ListInsideClustersAndNsPage inside />} />
|
||||
<Route path={`${prefix}/inside/:clusterName/:namespace?/apis`} element={<ListInsideApiPage inside />} />
|
||||
<Route
|
||||
path={`${prefix}/inside/:clusterName/:namespace?/crds-by-api/:apiGroup/:apiVersion/:apiExtensionVersion`}
|
||||
element={<ListInsideCrdByApiGroupPage inside />}
|
||||
/>
|
||||
<Route
|
||||
path={`${prefix}/inside/:clusterName/:namespace?/apis-by-api/:apiGroup/:apiVersion/`}
|
||||
element={<ListInsideApiByApiGroupPage inside />}
|
||||
/>
|
||||
<Route
|
||||
path={`${prefix}/:clusterName/:namespace?/:syntheticProject?/crd-table/:apiGroup/:apiVersion/:apiExtensionVersion/:crdName`}
|
||||
element={<TableCrdPage />}
|
||||
/>
|
||||
<Route
|
||||
path={`${prefix}/:clusterName/:namespace?/:syntheticProject?/api-table/:apiGroup/:apiVersion/:typeName`}
|
||||
element={<TableApiPage />}
|
||||
/>
|
||||
<Route
|
||||
path={`${prefix}/:clusterName/:namespace?/:syntheticProject?/builtin-table/:typeName`}
|
||||
element={<TableBuiltinPage />}
|
||||
/>
|
||||
<Route
|
||||
path={`${prefix}/:clusterName/:namespace?/:syntheticProject?/forms/builtin/:apiVersion/:typeName/:entryName?/`}
|
||||
element={<FormBuiltinPage />}
|
||||
/>
|
||||
<Route
|
||||
path={`${prefix}/:clusterName/:namespace?/:syntheticProject?/forms/apis/:apiGroup/:apiVersion/:typeName/:entryName?/`}
|
||||
element={<FormApiPage />}
|
||||
/>
|
||||
<Route
|
||||
path={`${prefix}/:clusterName/:namespace?/:syntheticProject?/forms/crds/:apiGroup/:apiVersion/:typeName/:entryName?/`}
|
||||
element={<FormCrdPage />}
|
||||
/>
|
||||
<Route
|
||||
path={`${prefix}/inside/:clusterName/:namespace?/:syntheticProject?/crd-table/:apiGroup/:apiVersion/:apiExtensionVersion/:crdName`}
|
||||
element={<TableCrdPage inside />}
|
||||
/>
|
||||
<Route
|
||||
path={`${prefix}/inside/:clusterName/:namespace?/:syntheticProject?/api-table/:apiGroup/:apiVersion/:typeName`}
|
||||
element={<TableApiPage inside />}
|
||||
/>
|
||||
<Route
|
||||
path={`${prefix}/inside/:clusterName/:namespace?/:syntheticProject?/builtin-table/:typeName`}
|
||||
element={<TableBuiltinPage inside />}
|
||||
/>
|
||||
<Route
|
||||
path={`${prefix}/inside/:clusterName/:namespace?/:syntheticProject?/forms/builtin/:apiVersion/:typeName/:entryName?/`}
|
||||
element={<FormBuiltinPage inside />}
|
||||
/>
|
||||
<Route
|
||||
path={`${prefix}/inside/:clusterName/:namespace?/:syntheticProject?/forms/apis/:apiGroup/:apiVersion/:typeName/:entryName?/`}
|
||||
element={<FormApiPage inside />}
|
||||
/>
|
||||
<Route
|
||||
path={`${prefix}/inside/:clusterName/:namespace?/:syntheticProject?/forms/crds/:apiGroup/:apiVersion/:typeName/:entryName?/`}
|
||||
element={<FormCrdPage inside />}
|
||||
/>
|
||||
<Route
|
||||
path={`${prefix}/:clusterName/:namespace?/:syntheticProject?/factory/:key/*`}
|
||||
element={<FactoryPage />}
|
||||
/>
|
||||
<Route path={`${prefix}/:clusterName/:namespace?/:syntheticProject?/search/*`} element={<SearchPage />} />
|
||||
<Route path={`${prefix}/factory-admin/*`} element={<FactoryAdminPage />} />
|
||||
<Route path={`${prefix}/inside/:cluster/:namespace?/*`} element={<AppShell inside />}>
|
||||
<Route path="apis" element={<ListInsideApiPage />} />
|
||||
<Route
|
||||
path="crds-by-api/:apiGroup/:apiVersion/:apiExtensionVersion"
|
||||
element={<ListInsideCrdByApiGroupPage />}
|
||||
/>
|
||||
<Route path="apis-by-api/:apiGroup/:apiVersion/" element={<ListInsideApiByApiGroupPage />} />
|
||||
</Route>
|
||||
|
||||
<Route path={`${prefix}/clusters/:cluster`} element={<RedirectProjectsPage />} />
|
||||
<Route path={`${prefix}/clusters/:cluster/projects/:namespace`} element={<RedirectProjectInfoPage />} />
|
||||
</Route>
|
||||
</Routes>
|
||||
)
|
||||
|
||||
@@ -4,15 +4,15 @@ import { useSelector } from 'react-redux'
|
||||
import { RootState } from 'store/store'
|
||||
|
||||
export const RedirectProjectInfo: FC = () => {
|
||||
const { clusterName, namespace } = useParams()
|
||||
const { cluster, namespace } = useParams()
|
||||
const navigate = useNavigate()
|
||||
const baseprefix = useSelector((state: RootState) => state.baseprefix.baseprefix)
|
||||
|
||||
navigate(`${baseprefix}/${clusterName}/${namespace}/factory/project/${namespace}`)
|
||||
navigate(`${baseprefix}/${cluster}/${namespace}/factory/project/${namespace}`)
|
||||
|
||||
useEffect(() => {
|
||||
navigate(`${baseprefix}/${clusterName}/${namespace}/factory/project/${namespace}`)
|
||||
}, [clusterName, namespace, baseprefix, navigate])
|
||||
navigate(`${baseprefix}/${cluster}/${namespace}/factory/project/${namespace}`)
|
||||
}, [cluster, namespace, baseprefix, navigate])
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -4,24 +4,24 @@ import { useSelector } from 'react-redux'
|
||||
import { RootState } from 'store/store'
|
||||
import {
|
||||
BASE_PROJECTS_API_GROUP,
|
||||
BASE_PROJECTS_VERSION,
|
||||
BASE_PROJECTS_RESOURCE_NAME,
|
||||
BASE_PROJECTS_API_VERSION,
|
||||
BASE_PROJECTS_PLURAL,
|
||||
} from 'constants/customizationApiGroupAndVersion'
|
||||
|
||||
export const RedirectProjectList: FC = () => {
|
||||
const { clusterName } = useParams()
|
||||
const { cluster } = useParams()
|
||||
const navigate = useNavigate()
|
||||
const baseprefix = useSelector((state: RootState) => state.baseprefix.baseprefix)
|
||||
|
||||
navigate(
|
||||
`${baseprefix}/${clusterName}/api-table/${BASE_PROJECTS_API_GROUP}/${BASE_PROJECTS_VERSION}/${BASE_PROJECTS_RESOURCE_NAME}`,
|
||||
`${baseprefix}/${cluster}/api-table/${BASE_PROJECTS_API_GROUP}/${BASE_PROJECTS_API_VERSION}/${BASE_PROJECTS_PLURAL}`,
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
navigate(
|
||||
`${baseprefix}/${clusterName}/api-table/${BASE_PROJECTS_API_GROUP}/${BASE_PROJECTS_VERSION}/${BASE_PROJECTS_RESOURCE_NAME}`,
|
||||
`${baseprefix}/${cluster}/api-table/${BASE_PROJECTS_API_GROUP}/${BASE_PROJECTS_API_VERSION}/${BASE_PROJECTS_PLURAL}`,
|
||||
)
|
||||
}, [clusterName, baseprefix, navigate])
|
||||
}, [cluster, baseprefix, navigate])
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { FC, useState, useEffect } from 'react'
|
||||
import { useParams } from 'react-router-dom'
|
||||
import { BlackholeFormDataProvider, TJSON } from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { BlackholeFormProvider, TJSON } from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { useSelector } from 'react-redux'
|
||||
import type { RootState } from 'store/store'
|
||||
import {
|
||||
@@ -17,7 +17,7 @@ type TBlackholeFormProps = {
|
||||
data:
|
||||
| {
|
||||
type: 'builtin'
|
||||
typeName: string
|
||||
plural: string
|
||||
prefillValuesSchema?: TJSON
|
||||
prefillValueNamespaceOnly?: string
|
||||
}
|
||||
@@ -25,7 +25,7 @@ type TBlackholeFormProps = {
|
||||
type: 'apis'
|
||||
apiGroup: string
|
||||
apiVersion: string
|
||||
typeName: string
|
||||
plural: string
|
||||
prefillValuesSchema?: TJSON
|
||||
prefillValueNamespaceOnly?: string
|
||||
}
|
||||
@@ -71,19 +71,19 @@ export const BlackholeForm: FC<TBlackholeFormProps> = ({ data, customizationId,
|
||||
}, [])
|
||||
|
||||
const urlParams = {
|
||||
clusterName: params.clusterName,
|
||||
cluster: params.cluster,
|
||||
namespace: params.namespace,
|
||||
syntheticProject: params.syntheticProject,
|
||||
entryName: params.entryName,
|
||||
name: params.name,
|
||||
}
|
||||
|
||||
const urlParamsForPermissions = {
|
||||
apiGroup: params.apiGroup,
|
||||
typeName: params.typeName,
|
||||
plural: params.plural,
|
||||
}
|
||||
|
||||
return (
|
||||
<BlackholeFormDataProvider
|
||||
<BlackholeFormProvider
|
||||
theme={theme}
|
||||
cluster={cluster}
|
||||
urlParams={urlParams}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { FC } from 'react'
|
||||
import { useLocation, useParams } from 'react-router-dom'
|
||||
import { ManageableBreadcrumbsWithDataProvider } from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { ManageableBreadcrumbsProvider } from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { BASE_API_GROUP, BASE_API_VERSION } from 'constants/customizationApiGroupAndVersion'
|
||||
|
||||
type TManageableBreadCrumbsProps = {
|
||||
@@ -12,13 +12,13 @@ export const ManageableBreadcrumbs: FC<TManageableBreadCrumbsProps> = ({ idToCom
|
||||
const location = useLocation()
|
||||
const { pathname } = useLocation()
|
||||
const params = useParams()
|
||||
const clusterName = params?.clusterName || ''
|
||||
const cluster = params?.cluster || ''
|
||||
const namespace = params?.namespace || ''
|
||||
const syntheticProject = params?.syntheticProject || ''
|
||||
const apiGroup = params?.apiGroup || ''
|
||||
const apiVersion = params?.apiVersion || ''
|
||||
const typeName = params?.typeName || ''
|
||||
const entryName = params?.entryName || ''
|
||||
const plural = params?.plural || ''
|
||||
const name = params?.name || ''
|
||||
const apiExtensionVersion = params?.apiExtensionVersion || ''
|
||||
const crdName = params?.crdName || ''
|
||||
|
||||
@@ -30,15 +30,15 @@ export const ManageableBreadcrumbs: FC<TManageableBreadCrumbsProps> = ({ idToCom
|
||||
}, {})
|
||||
|
||||
return (
|
||||
<ManageableBreadcrumbsWithDataProvider
|
||||
<ManageableBreadcrumbsProvider
|
||||
idToCompare={idToCompare}
|
||||
uri={`/api/clusters/${clusterName}/k8s/apis/${BASE_API_GROUP}/${BASE_API_VERSION}/${
|
||||
inside ? 'breadcrumbsinsides' : 'breadcrumbs'
|
||||
}/`}
|
||||
refetchInterval={5000}
|
||||
isEnabled={clusterName !== undefined}
|
||||
cluster={cluster}
|
||||
apiGroup={BASE_API_GROUP}
|
||||
apiVersion={BASE_API_VERSION}
|
||||
plural={inside ? 'breadcrumbsinsides' : 'breadcrumbs'}
|
||||
isEnabled={cluster !== undefined}
|
||||
replaceValues={{
|
||||
clusterName,
|
||||
cluster,
|
||||
projectName: '',
|
||||
instanceName: '',
|
||||
namespace,
|
||||
@@ -46,8 +46,8 @@ export const ManageableBreadcrumbs: FC<TManageableBreadCrumbsProps> = ({ idToCom
|
||||
entryType: '',
|
||||
apiGroup,
|
||||
apiVersion,
|
||||
typeName,
|
||||
entryName,
|
||||
plural,
|
||||
name,
|
||||
apiExtensionVersion,
|
||||
crdName,
|
||||
...replaceValuesPartsOfUrls,
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
import React, { FC, useState, useEffect } from 'react'
|
||||
import { theme as antdtheme } from 'antd'
|
||||
import { useLocation, useParams } from 'react-router-dom'
|
||||
import { ManageableSidebarWithDataProvider } from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { ManageableSidebarProvider } from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { useSelector } from 'react-redux'
|
||||
import type { RootState } from 'store/store'
|
||||
// import { HEAD_FIRST_ROW, SIDEBAR_CLUSTER_HEIGHT } from 'constants/blocksSizes'
|
||||
import { HEAD_FIRST_ROW } from 'constants/blocksSizes'
|
||||
import { BASE_API_GROUP, BASE_API_VERSION } from 'constants/customizationApiGroupAndVersion'
|
||||
import {
|
||||
BASE_API_GROUP,
|
||||
BASE_API_VERSION,
|
||||
CUSTOMIZATION_SIDEBAR_FALLBACK_ID,
|
||||
} from 'constants/customizationApiGroupAndVersion'
|
||||
import { Styled } from './styled'
|
||||
|
||||
type TManageableSidebarProps = {
|
||||
@@ -25,7 +28,7 @@ export const ManageableSidebar: FC<TManageableSidebarProps> = ({
|
||||
const location = useLocation()
|
||||
const { pathname } = useLocation()
|
||||
const params = useParams()
|
||||
const clusterName = params?.clusterName || ''
|
||||
const cluster = params?.cluster || ''
|
||||
const namespace = params?.namespace || ''
|
||||
const syntheticProject = params?.syntheticProject || ''
|
||||
const theme = useSelector((state: RootState) => state.openapiTheme.theme)
|
||||
@@ -34,7 +37,6 @@ export const ManageableSidebar: FC<TManageableSidebarProps> = ({
|
||||
const [height, setHeight] = useState(0)
|
||||
|
||||
useEffect(() => {
|
||||
// const height = window.innerHeight - HEAD_FIRST_ROW - SIDEBAR_CLUSTER_HEIGHT - 2
|
||||
const height = window.innerHeight - HEAD_FIRST_ROW - 2
|
||||
setHeight(height)
|
||||
|
||||
@@ -66,12 +68,14 @@ export const ManageableSidebar: FC<TManageableSidebarProps> = ({
|
||||
$colorBorder={token.colorBorder}
|
||||
$maxHeight={height}
|
||||
>
|
||||
<ManageableSidebarWithDataProvider
|
||||
uri={`/api/clusters/${clusterName}/k8s/apis/${BASE_API_GROUP}/${BASE_API_VERSION}/sidebars/`}
|
||||
refetchInterval={5000}
|
||||
isEnabled={clusterName !== undefined}
|
||||
<ManageableSidebarProvider
|
||||
cluster={cluster}
|
||||
apiGroup={BASE_API_GROUP}
|
||||
apiVersion={BASE_API_VERSION}
|
||||
plural="sidebars"
|
||||
isEnabled={cluster !== undefined}
|
||||
replaceValues={{
|
||||
clusterName,
|
||||
cluster,
|
||||
projectName,
|
||||
instanceName,
|
||||
namespace,
|
||||
@@ -80,6 +84,9 @@ export const ManageableSidebar: FC<TManageableSidebarProps> = ({
|
||||
}}
|
||||
pathname={pathname}
|
||||
idToCompare={idToCompare}
|
||||
fallbackIdToCompare={
|
||||
namespace ? `${CUSTOMIZATION_SIDEBAR_FALLBACK_ID}-namespaced` : CUSTOMIZATION_SIDEBAR_FALLBACK_ID
|
||||
}
|
||||
currentTags={currentTags}
|
||||
noMarginTop
|
||||
/>
|
||||
|
||||
@@ -10,12 +10,10 @@ import {
|
||||
usePermissions,
|
||||
DeleteModal,
|
||||
DeleteModalMany,
|
||||
// checkIfBuiltInInstanceNamespaceScoped,
|
||||
// checkIfApiInstanceNamespaceScoped,
|
||||
useBuiltinResources,
|
||||
useApiResources,
|
||||
useK8sSmartResource,
|
||||
Spacer,
|
||||
getLinkToForm,
|
||||
TSingleResource,
|
||||
} from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { FlexGrow, PaddingContainer } from 'components'
|
||||
import { TABLE_PROPS } from 'constants/tableProps'
|
||||
@@ -28,17 +26,16 @@ import {
|
||||
TABLE_ADD_BUTTON_HEIGHT,
|
||||
} from 'constants/blocksSizes'
|
||||
import { OverflowContainer } from './atoms'
|
||||
import { getDataItems } from './utils'
|
||||
|
||||
type TTableApiBuiltinProps = {
|
||||
namespace?: string
|
||||
resourceType: 'builtin' | 'api'
|
||||
apiGroup?: string // api
|
||||
apiVersion: string // api
|
||||
typeName: string
|
||||
plural: string
|
||||
labels?: string[]
|
||||
fields?: string[]
|
||||
limit: string | null
|
||||
limit?: number
|
||||
inside?: boolean
|
||||
customizationIdPrefix: string
|
||||
searchMount?: boolean
|
||||
@@ -50,7 +47,7 @@ export const TableApiBuiltin: FC<TTableApiBuiltinProps> = ({
|
||||
resourceType,
|
||||
apiGroup,
|
||||
apiVersion,
|
||||
typeName,
|
||||
plural,
|
||||
labels,
|
||||
fields,
|
||||
limit,
|
||||
@@ -72,8 +69,6 @@ export const TableApiBuiltin: FC<TTableApiBuiltinProps> = ({
|
||||
)
|
||||
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([])
|
||||
const [selectedRowsData, setSelectedRowsData] = useState<{ name: string; endpoint: string }[]>([])
|
||||
// const [isNamespaced, setIsNamespaced] = useState<boolean>()
|
||||
// const [isNamespacedLoading, setIsNamespacedLoading] = useState<boolean>()
|
||||
|
||||
const [height, setHeight] = useState(0)
|
||||
|
||||
@@ -99,77 +94,28 @@ export const TableApiBuiltin: FC<TTableApiBuiltinProps> = ({
|
||||
}
|
||||
}, [])
|
||||
|
||||
// useEffect(() => {
|
||||
// setIsNamespacedLoading(true)
|
||||
// if (resourceType === 'builtin') {
|
||||
// checkIfBuiltInInstanceNamespaceScoped({
|
||||
// typeName,
|
||||
// clusterName: cluster,
|
||||
// })
|
||||
// .then(({ isNamespaceScoped }) => {
|
||||
// if (isNamespaceScoped) {
|
||||
// setIsNamespaced(isNamespaceScoped)
|
||||
// } else {
|
||||
// setIsNamespaced(false)
|
||||
// }
|
||||
// })
|
||||
// .finally(() => setIsNamespacedLoading(false))
|
||||
// }
|
||||
// if (resourceType === 'api' && apiGroup && apiVersion) {
|
||||
// checkIfApiInstanceNamespaceScoped({
|
||||
// apiGroup,
|
||||
// apiVersion,
|
||||
// typeName,
|
||||
// clusterName: cluster,
|
||||
// })
|
||||
// .then(({ isNamespaceScoped }) => {
|
||||
// if (isNamespaceScoped) {
|
||||
// setIsNamespaced(true)
|
||||
// } else {
|
||||
// setIsNamespaced(false)
|
||||
// }
|
||||
// })
|
||||
// .finally(() => setIsNamespacedLoading(false))
|
||||
// }
|
||||
// }, [resourceType, cluster, typeName, apiGroup, apiVersion])
|
||||
|
||||
const createPermission = usePermissions({
|
||||
group: apiGroup || undefined,
|
||||
resource: typeName,
|
||||
apiGroup: apiGroup || undefined,
|
||||
plural,
|
||||
namespace: params.namespace,
|
||||
clusterName: cluster,
|
||||
cluster,
|
||||
verb: 'create',
|
||||
refetchInterval: false,
|
||||
})
|
||||
|
||||
const {
|
||||
isPending: isPendingBuiltin,
|
||||
error: errorBuiltin,
|
||||
data: dataBuiltin,
|
||||
} = useBuiltinResources({
|
||||
clusterName: cluster,
|
||||
data: dataItems,
|
||||
isLoading,
|
||||
error,
|
||||
} = useK8sSmartResource<{ items: TSingleResource[] }>({
|
||||
cluster,
|
||||
namespace,
|
||||
typeName,
|
||||
labels,
|
||||
fields,
|
||||
limit,
|
||||
isEnabled: resourceType === 'builtin',
|
||||
})
|
||||
|
||||
const {
|
||||
isPending: isPendingApi,
|
||||
error: errorApi,
|
||||
data: dataApi,
|
||||
} = useApiResources({
|
||||
clusterName: cluster,
|
||||
namespace,
|
||||
apiGroup: apiGroup || '',
|
||||
apiGroup,
|
||||
apiVersion: apiVersion || '',
|
||||
typeName,
|
||||
labels,
|
||||
fields,
|
||||
plural,
|
||||
labelSelector: labels ? encodeURIComponent(labels.join(',')) : undefined,
|
||||
fieldSelector: fields ? encodeURIComponent(fields.join(',')) : undefined,
|
||||
limit,
|
||||
isEnabled: resourceType === 'api' && !!apiGroup && !!apiVersion,
|
||||
})
|
||||
|
||||
const onDeleteHandle = (name: string, endpoint: string) => {
|
||||
@@ -192,86 +138,62 @@ export const TableApiBuiltin: FC<TTableApiBuiltinProps> = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
{((resourceType === 'builtin' && isPendingBuiltin) || (resourceType === 'api' && isPendingApi)) && <Spin />}
|
||||
{resourceType === 'builtin' && errorBuiltin && (
|
||||
<Alert message={`An error has occurred: ${errorBuiltin?.message} `} type="error" />
|
||||
)}
|
||||
{resourceType === 'api' && errorApi && (
|
||||
<Alert message={`An error has occurred: ${errorApi?.message} `} type="error" />
|
||||
)}
|
||||
{isLoading && <Spin />}
|
||||
{error && <Alert message={`An error has occurred: ${error} `} type="error" />}
|
||||
<OverflowContainer height={height} searchMount={searchMount}>
|
||||
{!errorBuiltin &&
|
||||
!errorApi &&
|
||||
((resourceType === 'builtin' && dataBuiltin) || (resourceType === 'api' && dataApi)) && (
|
||||
<EnrichedTableProvider
|
||||
key={resourceType === 'builtin' ? `/v1/${typeName}` : `/${apiGroup}/${apiVersion}/${typeName}`}
|
||||
customizationId={
|
||||
resourceType === 'builtin'
|
||||
? `${customizationIdPrefix}/v1/${typeName}`
|
||||
: `${customizationIdPrefix}/${apiGroup}/${apiVersion}/${typeName}`
|
||||
}
|
||||
tableMappingsReplaceValues={{
|
||||
clusterName: params.clusterName,
|
||||
projectName: params.projectName,
|
||||
instanceName: params.instanceName,
|
||||
namespace: params.namespace,
|
||||
syntheticProject: params.syntheticProject,
|
||||
entryType: params.entryType,
|
||||
apiGroup: params.apiGroup,
|
||||
apiVersion: params.apiVersion,
|
||||
typeName: params.typeName,
|
||||
entryName: params.entryName,
|
||||
apiExtensionVersion: params.apiExtensionVersion,
|
||||
crdName: params.crdName,
|
||||
...replaceValuesPartsOfUrls,
|
||||
}}
|
||||
cluster={cluster}
|
||||
namespace={namespace}
|
||||
theme={theme}
|
||||
baseprefix={inside ? `${baseprefix}/inside` : baseprefix}
|
||||
dataItems={getDataItems({ resourceType, dataBuiltin, dataApi })}
|
||||
k8sResource={{
|
||||
resource: typeName,
|
||||
apiGroup,
|
||||
apiVersion,
|
||||
}}
|
||||
// isNamespaced={isNamespaced}
|
||||
// isNamespacedLoading={isNamespacedLoading}
|
||||
dataForControls={{
|
||||
cluster,
|
||||
syntheticProject: params.syntheticProject,
|
||||
resource: typeName,
|
||||
apiGroup,
|
||||
apiVersion,
|
||||
}}
|
||||
dataForControlsInternal={{
|
||||
onDeleteHandle,
|
||||
}}
|
||||
selectData={{
|
||||
selectedRowKeys,
|
||||
onChange: (selectedRowKeys: React.Key[], selectedRowsData: { name: string; endpoint: string }[]) => {
|
||||
setSelectedRowKeys(selectedRowKeys)
|
||||
setSelectedRowsData(selectedRowsData)
|
||||
},
|
||||
}}
|
||||
tableProps={{ ...TABLE_PROPS, disablePagination: !searchMount }}
|
||||
// maxHeight={height - 65}
|
||||
/>
|
||||
)}
|
||||
{/* {selectedRowKeys.length > 0 && (
|
||||
<MarginTopContainer $top={-40}>
|
||||
<Flex gap={16}>
|
||||
<Button type="primary" onClick={clearSelected}>
|
||||
<ClearOutlined />
|
||||
Clear
|
||||
</Button>
|
||||
<Button type="primary" onClick={() => setIsDeleteModalManyOpen(selectedRowsData)}>
|
||||
<MinusOutlined />
|
||||
Delete
|
||||
</Button>
|
||||
</Flex>
|
||||
</MarginTopContainer>
|
||||
)} */}
|
||||
{!error && dataItems && (
|
||||
<EnrichedTableProvider
|
||||
key={resourceType === 'builtin' ? `/v1/${plural}` : `/${apiGroup}/${apiVersion}/${plural}`}
|
||||
customizationId={
|
||||
resourceType === 'builtin'
|
||||
? `${customizationIdPrefix}/v1/${plural}`
|
||||
: `${customizationIdPrefix}/${apiGroup}/${apiVersion}/${plural}`
|
||||
}
|
||||
tableMappingsReplaceValues={{
|
||||
cluster: params.cluster,
|
||||
projectName: params.projectName,
|
||||
instanceName: params.instanceName,
|
||||
namespace: params.namespace,
|
||||
syntheticProject: params.syntheticProject,
|
||||
entryType: params.entryType,
|
||||
apiGroup: params.apiGroup,
|
||||
apiVersion: params.apiVersion,
|
||||
plural: params.plural,
|
||||
name: params.name,
|
||||
apiExtensionVersion: params.apiExtensionVersion,
|
||||
crdName: params.crdName,
|
||||
...replaceValuesPartsOfUrls,
|
||||
}}
|
||||
cluster={cluster}
|
||||
namespace={namespace}
|
||||
theme={theme}
|
||||
baseprefix={inside ? `${baseprefix}/inside` : baseprefix}
|
||||
dataItems={dataItems.items}
|
||||
k8sResource={{
|
||||
plural,
|
||||
apiGroup,
|
||||
apiVersion,
|
||||
}}
|
||||
dataForControls={{
|
||||
cluster,
|
||||
syntheticProject: params.syntheticProject,
|
||||
plural,
|
||||
apiGroup,
|
||||
apiVersion,
|
||||
}}
|
||||
dataForControlsInternal={{
|
||||
onDeleteHandle,
|
||||
}}
|
||||
selectData={{
|
||||
selectedRowKeys,
|
||||
onChange: (selectedRowKeys: React.Key[], selectedRowsData: { name: string; endpoint: string }[]) => {
|
||||
setSelectedRowKeys(selectedRowKeys)
|
||||
setSelectedRowsData(selectedRowsData)
|
||||
},
|
||||
}}
|
||||
tableProps={{ ...TABLE_PROPS, disablePagination: !searchMount }}
|
||||
/>
|
||||
)}
|
||||
</OverflowContainer>
|
||||
{searchMount ? <Spacer $space={12} $samespace /> : <FlexGrow />}
|
||||
<PaddingContainer $padding="4px">
|
||||
@@ -286,15 +208,13 @@ export const TableApiBuiltin: FC<TTableApiBuiltinProps> = ({
|
||||
syntheticProject: params.syntheticProject,
|
||||
apiGroup,
|
||||
apiVersion,
|
||||
typeName,
|
||||
plural,
|
||||
inside,
|
||||
fullPath,
|
||||
searchMount,
|
||||
})
|
||||
navigate(url)
|
||||
}}
|
||||
// loading={isNamespaced ? false : createPermission.isPending}
|
||||
// disabled={isNamespaced ? false : !createPermission.data?.status.allowed}
|
||||
loading={createPermission.isPending}
|
||||
disabled={!createPermission.data?.status.allowed}
|
||||
>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { TBuiltinResources, TApiResources, TJSON } from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { TSingleResource, TJSON } from '@prorobotech/openapi-k8s-toolkit'
|
||||
|
||||
export const getDataItems = ({
|
||||
resourceType,
|
||||
@@ -6,8 +6,8 @@ export const getDataItems = ({
|
||||
dataApi,
|
||||
}: {
|
||||
resourceType: 'builtin' | 'api'
|
||||
dataBuiltin?: TBuiltinResources
|
||||
dataApi?: TApiResources
|
||||
dataBuiltin?: TSingleResource[]
|
||||
dataApi?: TSingleResource[]
|
||||
}): TJSON[] => {
|
||||
return resourceType === 'builtin' ? dataBuiltin?.items || [] : dataApi?.items || []
|
||||
return resourceType === 'builtin' ? dataBuiltin || [] : dataApi || []
|
||||
}
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
import React, { FC, useState, useEffect } from 'react'
|
||||
import { Spin, Alert } from 'antd'
|
||||
import { usePermissions, checkIfApiInstanceNamespaceScoped, useCrdData } from '@prorobotech/openapi-k8s-toolkit'
|
||||
import {
|
||||
usePermissions,
|
||||
checkIfApiInstanceNamespaceScoped,
|
||||
// useCrdData,
|
||||
useK8sSmartResource,
|
||||
TCRD,
|
||||
} from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { useSelector } from 'react-redux'
|
||||
import { RootState } from 'store/store'
|
||||
import { ResourceInfo } from './molecules'
|
||||
@@ -28,19 +34,29 @@ export const TableCrdInfo: FC<TTableCrdInfoProps> = ({
|
||||
|
||||
const [isNamespaced, setIsNamespaced] = useState<boolean>()
|
||||
|
||||
const { isPending, error, data } = useCrdData({
|
||||
clusterName: cluster,
|
||||
crdName,
|
||||
apiExtensionVersion,
|
||||
const {
|
||||
data: dataArr,
|
||||
isLoading: isPending,
|
||||
error,
|
||||
} = useK8sSmartResource<{
|
||||
items: TCRD[]
|
||||
}>({
|
||||
cluster,
|
||||
apiGroup: 'apiextensions.k8s.io',
|
||||
apiVersion: apiExtensionVersion,
|
||||
plural: 'customresourcedefinitions',
|
||||
fieldSelector: `metadata.name=${crdName}`,
|
||||
})
|
||||
|
||||
const data = dataArr?.items && dataArr.items.length > 0 ? dataArr.items[0] : undefined
|
||||
|
||||
useEffect(() => {
|
||||
if (data && !isPending && !error) {
|
||||
checkIfApiInstanceNamespaceScoped({
|
||||
apiGroup,
|
||||
apiVersion,
|
||||
typeName: data.spec.names.plural,
|
||||
clusterName: cluster,
|
||||
plural: data.spec.names.plural,
|
||||
cluster,
|
||||
}).then(({ isNamespaceScoped }) => {
|
||||
if (isNamespaceScoped) {
|
||||
setIsNamespaced(true)
|
||||
@@ -50,28 +66,28 @@ export const TableCrdInfo: FC<TTableCrdInfoProps> = ({
|
||||
}, [cluster, data, isPending, error, apiGroup, apiVersion])
|
||||
|
||||
const createPermission = usePermissions({
|
||||
group: apiGroup,
|
||||
resource: data ? data.spec.names.singular : '',
|
||||
apiGroup,
|
||||
plural: data ? data.spec.names.singular : '',
|
||||
namespace: '',
|
||||
clusterName: cluster,
|
||||
cluster,
|
||||
verb: 'create',
|
||||
refetchInterval: false,
|
||||
})
|
||||
|
||||
const updatePermission = usePermissions({
|
||||
group: apiGroup,
|
||||
resource: data ? data.spec.names.singular : '',
|
||||
apiGroup,
|
||||
plural: data ? data.spec.names.singular : '',
|
||||
namespace: '',
|
||||
clusterName: cluster,
|
||||
cluster,
|
||||
verb: 'update',
|
||||
refetchInterval: false,
|
||||
})
|
||||
|
||||
const deletePermission = usePermissions({
|
||||
group: apiGroup,
|
||||
resource: data ? data.spec.names.singular : '',
|
||||
apiGroup,
|
||||
plural: data ? data.spec.names.singular : '',
|
||||
namespace: '',
|
||||
clusterName: cluster,
|
||||
cluster,
|
||||
verb: 'delete',
|
||||
refetchInterval: false,
|
||||
})
|
||||
@@ -79,10 +95,12 @@ export const TableCrdInfo: FC<TTableCrdInfoProps> = ({
|
||||
return (
|
||||
<>
|
||||
{isPending && <Spin />}
|
||||
{error && <Alert message={`An error has occurred: ${error?.message} `} type="error" />}
|
||||
{error && (
|
||||
<Alert message={`An error has occurred: ${typeof error === 'string' ? error : error?.message} `} type="error" />
|
||||
)}
|
||||
{!error && data && data.spec && (
|
||||
<ResourceInfo
|
||||
clusterName={cluster}
|
||||
cluster={cluster}
|
||||
namespace={namespace}
|
||||
crdName={crdName}
|
||||
crdPluralName={data.spec.names.plural}
|
||||
|
||||
@@ -10,7 +10,9 @@ import {
|
||||
DeleteModal,
|
||||
DeleteModalMany,
|
||||
TAdditionalPrinterColumns,
|
||||
useCrdResources,
|
||||
// useCrdResources,
|
||||
useK8sSmartResource,
|
||||
TJSON,
|
||||
} from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { FlexGrow, OverflowMaxHeightContainer, PaddingContainer } from 'components'
|
||||
import { TABLE_PROPS } from 'constants/tableProps'
|
||||
@@ -24,7 +26,7 @@ import {
|
||||
} from 'constants/blocksSizes'
|
||||
|
||||
type TResourceInfoProps = {
|
||||
clusterName: string
|
||||
cluster: string
|
||||
namespace?: string
|
||||
crdName: string
|
||||
crdPluralName: string
|
||||
@@ -42,7 +44,7 @@ type TResourceInfoProps = {
|
||||
}
|
||||
|
||||
export const ResourceInfo: FC<TResourceInfoProps> = ({
|
||||
clusterName,
|
||||
cluster,
|
||||
namespace,
|
||||
crdName,
|
||||
crdPluralName,
|
||||
@@ -57,7 +59,6 @@ export const ResourceInfo: FC<TResourceInfoProps> = ({
|
||||
const location = useLocation()
|
||||
const navigate = useNavigate()
|
||||
const params = useParams()
|
||||
const cluster = useSelector((state: RootState) => state.cluster.cluster)
|
||||
const theme = useSelector((state: RootState) => state.openapiTheme.theme)
|
||||
const baseprefix = useSelector((state: RootState) => state.baseprefix.baseprefix)
|
||||
|
||||
@@ -92,12 +93,17 @@ export const ResourceInfo: FC<TResourceInfoProps> = ({
|
||||
}
|
||||
}, [])
|
||||
|
||||
const { isPending, error, data } = useCrdResources({
|
||||
clusterName,
|
||||
namespace,
|
||||
const {
|
||||
data,
|
||||
isLoading: isPending,
|
||||
error,
|
||||
} = useK8sSmartResource<{
|
||||
items: TJSON[]
|
||||
}>({
|
||||
cluster,
|
||||
apiGroup,
|
||||
apiVersion,
|
||||
crdName: crdPluralName,
|
||||
plural: crdPluralName,
|
||||
})
|
||||
|
||||
let resourceSchema = {}
|
||||
@@ -143,7 +149,7 @@ export const ResourceInfo: FC<TResourceInfoProps> = ({
|
||||
// key={`/${apiGroup}/${apiVersion}/${crdPluralName}`}
|
||||
// customizationId={`${customizationIdPrefix}/${apiGroup}/${apiVersion}/${crdPluralName}`}
|
||||
// tableMappingsReplaceValues={{
|
||||
// clusterName: params.clusterName,
|
||||
// cluster: params.cluster,
|
||||
// projectName: params.projectName,
|
||||
// instanceName: params.instanceName,
|
||||
// namespace: params.namespace,
|
||||
@@ -151,8 +157,8 @@ export const ResourceInfo: FC<TResourceInfoProps> = ({
|
||||
// entryType: params.entryType,
|
||||
// apiGroup: params.apiGroup,
|
||||
// apiVersion: params.apiVersion,
|
||||
// typeName: params.typeName,
|
||||
// entryName: params.entryName,
|
||||
// plural: params.plural,
|
||||
// name: params.name,
|
||||
// apiExtensionVersion: params.apiExtensionVersion,
|
||||
// crdName: params.crdName,
|
||||
// ...replaceValuesPartsOfUrls,
|
||||
@@ -167,12 +173,12 @@ export const ResourceInfo: FC<TResourceInfoProps> = ({
|
||||
// cluster,
|
||||
// syntheticProject: params.syntheticProject,
|
||||
// pathPrefix: 'forms/crds',
|
||||
// typeName: crdPluralName,
|
||||
// plural: crdPluralName,
|
||||
// apiVersion: `${apiGroup}/${apiVersion}`,
|
||||
// backlink: `${baseprefix}${inside ? '/inside' : ''}/${cluster}${namespace ? `/${namespace}` : ''}${
|
||||
// params.syntheticProject ? `/${params.syntheticProject}` : ''
|
||||
// }/crd-table/${apiGroup}/${apiVersion}/${apiExtensionVersion}/${crdName}`,
|
||||
// deletePathPrefix: `/api/clusters/${clusterName}/k8s/apis`,
|
||||
// deletePathPrefix: `/api/clusters/${cluster}/k8s/apis`,
|
||||
// onDeleteHandle,
|
||||
// permissions: {
|
||||
// canUpdate: permissions.canUpdate,
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
DynamicComponents,
|
||||
DynamicRendererWithProviders,
|
||||
TDynamicComponentsAppTypeMap,
|
||||
useDirectUnknownResource,
|
||||
useK8sSmartResource,
|
||||
TFactoryResponse,
|
||||
ContentCard,
|
||||
} from '@prorobotech/openapi-k8s-toolkit'
|
||||
@@ -44,11 +44,11 @@ export const Factory: FC<TFactoryProps> = ({ setSidebarTags }) => {
|
||||
}
|
||||
}, [])
|
||||
|
||||
const { data: factoryData } = useDirectUnknownResource<TFactoryResponse<TDynamicComponentsAppTypeMap>>({
|
||||
uri: `/api/clusters/${cluster}/k8s/apis/${BASE_API_GROUP}/${BASE_API_VERSION}/factories/`,
|
||||
refetchInterval: false,
|
||||
queryKey: ['factories', cluster || 'no-cluster'],
|
||||
isEnabled: cluster !== undefined,
|
||||
const { data: factoryData } = useK8sSmartResource<TFactoryResponse<TDynamicComponentsAppTypeMap>>({
|
||||
cluster,
|
||||
apiGroup: BASE_API_GROUP,
|
||||
apiVersion: BASE_API_VERSION,
|
||||
plural: 'factories',
|
||||
})
|
||||
|
||||
const { spec } = factoryData?.items.find(({ spec }) => spec.key === key) ?? { spec: undefined }
|
||||
|
||||
@@ -7,11 +7,11 @@ type TCreateApisFormProps = {
|
||||
namespace?: string
|
||||
apiGroup: string
|
||||
apiVersion: string
|
||||
typeName: string
|
||||
plural: string
|
||||
backLink?: string | null
|
||||
}
|
||||
|
||||
export const CreateApisForm: FC<TCreateApisFormProps> = ({ namespace, apiGroup, apiVersion, typeName, backLink }) => {
|
||||
export const CreateApisForm: FC<TCreateApisFormProps> = ({ namespace, apiGroup, apiVersion, plural, backLink }) => {
|
||||
const [currentMode, setCurrentMode] = useState<string>('OpenAPI')
|
||||
const [currentModeDisabled, setCurrentModeDisabled] = useState<boolean>(false)
|
||||
|
||||
@@ -45,10 +45,10 @@ export const CreateApisForm: FC<TCreateApisFormProps> = ({ namespace, apiGroup,
|
||||
type: 'apis',
|
||||
apiGroup,
|
||||
apiVersion,
|
||||
typeName,
|
||||
plural,
|
||||
prefillValueNamespaceOnly: namespace,
|
||||
}}
|
||||
customizationId={`default-/${apiGroup}/${apiVersion}/${typeName}`}
|
||||
customizationId={`default-/${apiGroup}/${apiVersion}/${plural}`}
|
||||
isCreate
|
||||
backlink={backLink}
|
||||
modeData={modeData}
|
||||
|
||||
@@ -8,8 +8,8 @@ import { BlackholeForm } from 'components'
|
||||
type TUpdateApisFormProps = {
|
||||
apiGroup: string
|
||||
apiVersion: string
|
||||
typeName: string
|
||||
entryName: string
|
||||
plural: string
|
||||
name: string
|
||||
namespace?: string
|
||||
backLink?: string | null
|
||||
}
|
||||
@@ -17,8 +17,8 @@ type TUpdateApisFormProps = {
|
||||
export const UpdateApisForm: FC<TUpdateApisFormProps> = ({
|
||||
apiGroup,
|
||||
apiVersion,
|
||||
typeName,
|
||||
entryName,
|
||||
plural,
|
||||
name,
|
||||
namespace,
|
||||
backLink,
|
||||
}) => {
|
||||
@@ -42,12 +42,12 @@ export const UpdateApisForm: FC<TUpdateApisFormProps> = ({
|
||||
}
|
||||
|
||||
const { data, isPending, error } = useApiResourceSingle({
|
||||
clusterName: cluster,
|
||||
cluster,
|
||||
namespace,
|
||||
apiGroup,
|
||||
apiVersion,
|
||||
typeName,
|
||||
entryName,
|
||||
plural,
|
||||
name,
|
||||
refetchInterval: false,
|
||||
})
|
||||
|
||||
@@ -59,8 +59,6 @@ export const UpdateApisForm: FC<TUpdateApisFormProps> = ({
|
||||
return <Alert message={`An error has occurred: ${error?.message} `} type="error" />
|
||||
}
|
||||
|
||||
/* eslint-disable-next-line @typescript-eslint/no-unused-vars */
|
||||
// const { status: _, ...noStatusData } = data
|
||||
/* eslint-disable-next-line @typescript-eslint/no-unused-vars */
|
||||
const { managedFields: __, ...metadata } = data.metadata
|
||||
|
||||
@@ -80,11 +78,10 @@ export const UpdateApisForm: FC<TUpdateApisFormProps> = ({
|
||||
type: 'apis',
|
||||
apiGroup,
|
||||
apiVersion,
|
||||
typeName,
|
||||
// prefillValuesSchema: { ...noStatusData, metadata },
|
||||
plural,
|
||||
prefillValuesSchema: { ...data, metadata },
|
||||
}}
|
||||
customizationId={`default-/${apiGroup}/${apiVersion}/${typeName}`}
|
||||
customizationId={`default-/${apiGroup}/${apiVersion}/${plural}`}
|
||||
backlink={backLink}
|
||||
modeData={modeData}
|
||||
/>
|
||||
|
||||
@@ -5,11 +5,11 @@ import { BlackholeForm } from 'components'
|
||||
|
||||
type TCreateBuiltinFormProps = {
|
||||
namespace?: string
|
||||
typeName: string
|
||||
plural: string
|
||||
backLink?: string | null
|
||||
}
|
||||
|
||||
export const CreateBuiltinForm: FC<TCreateBuiltinFormProps> = ({ namespace, typeName, backLink }) => {
|
||||
export const CreateBuiltinForm: FC<TCreateBuiltinFormProps> = ({ namespace, plural, backLink }) => {
|
||||
const [currentMode, setCurrentMode] = useState<string>('OpenAPI')
|
||||
const [currentModeDisabled, setCurrentModeDisabled] = useState<boolean>(false)
|
||||
|
||||
@@ -41,10 +41,10 @@ export const CreateBuiltinForm: FC<TCreateBuiltinFormProps> = ({ namespace, type
|
||||
<BlackholeForm
|
||||
data={{
|
||||
type: 'builtin',
|
||||
typeName,
|
||||
plural,
|
||||
prefillValueNamespaceOnly: namespace,
|
||||
}}
|
||||
customizationId={`default-/v1/${typeName}`}
|
||||
customizationId={`default-/v1/${plural}`}
|
||||
isCreate
|
||||
backlink={backLink}
|
||||
modeData={modeData}
|
||||
|
||||
@@ -6,13 +6,13 @@ import { RootState } from 'store/store'
|
||||
import { BlackholeForm } from 'components'
|
||||
|
||||
type TUpdateBuiltinFormProps = {
|
||||
typeName: string
|
||||
entryName: string
|
||||
plural: string
|
||||
name: string
|
||||
namespace?: string
|
||||
backLink?: string | null
|
||||
}
|
||||
|
||||
export const UpdateBuiltinForm: FC<TUpdateBuiltinFormProps> = ({ typeName, entryName, namespace, backLink }) => {
|
||||
export const UpdateBuiltinForm: FC<TUpdateBuiltinFormProps> = ({ plural, name, namespace, backLink }) => {
|
||||
const cluster = useSelector((state: RootState) => state.cluster.cluster)
|
||||
|
||||
const [currentMode, setCurrentMode] = useState<string>('OpenAPI')
|
||||
@@ -33,10 +33,10 @@ export const UpdateBuiltinForm: FC<TUpdateBuiltinFormProps> = ({ typeName, entry
|
||||
}
|
||||
|
||||
const { data, isPending, error } = useBuiltinResourceSingle({
|
||||
clusterName: cluster,
|
||||
cluster,
|
||||
namespace,
|
||||
typeName,
|
||||
entryName,
|
||||
plural,
|
||||
name,
|
||||
refetchInterval: false,
|
||||
})
|
||||
|
||||
@@ -48,8 +48,6 @@ export const UpdateBuiltinForm: FC<TUpdateBuiltinFormProps> = ({ typeName, entry
|
||||
return <Alert message={`An error has occurred: ${error?.message} `} type="error" />
|
||||
}
|
||||
|
||||
/* eslint-disable-next-line @typescript-eslint/no-unused-vars */
|
||||
// const { status: _, ...noStatusData } = data
|
||||
/* eslint-disable-next-line @typescript-eslint/no-unused-vars */
|
||||
const { managedFields: __, ...metadata } = data.metadata
|
||||
|
||||
@@ -67,11 +65,10 @@ export const UpdateBuiltinForm: FC<TUpdateBuiltinFormProps> = ({ typeName, entry
|
||||
<BlackholeForm
|
||||
data={{
|
||||
type: 'builtin',
|
||||
typeName,
|
||||
// prefillValuesSchema: { ...noStatusData, metadata },
|
||||
plural,
|
||||
prefillValuesSchema: { ...data, metadata },
|
||||
}}
|
||||
customizationId={`default-/v1/${typeName}`}
|
||||
customizationId={`default-/v1/${plural}`}
|
||||
backlink={backLink}
|
||||
modeData={modeData}
|
||||
/>
|
||||
|
||||
@@ -7,11 +7,11 @@ type TCreateCrdsFormProps = {
|
||||
namespace?: string
|
||||
apiGroup: string
|
||||
apiVersion: string
|
||||
typeName: string
|
||||
plural: string
|
||||
backLink?: string | null
|
||||
}
|
||||
|
||||
export const CreateCrdsForm: FC<TCreateCrdsFormProps> = ({ namespace, apiGroup, apiVersion, typeName, backLink }) => {
|
||||
export const CreateCrdsForm: FC<TCreateCrdsFormProps> = ({ namespace, apiGroup, apiVersion, plural, backLink }) => {
|
||||
const [currentMode, setCurrentMode] = useState<string>('OpenAPI')
|
||||
const [currentModeDisabled, setCurrentModeDisabled] = useState<boolean>(false)
|
||||
|
||||
@@ -45,10 +45,10 @@ export const CreateCrdsForm: FC<TCreateCrdsFormProps> = ({ namespace, apiGroup,
|
||||
type: 'apis',
|
||||
apiGroup,
|
||||
apiVersion,
|
||||
typeName,
|
||||
plural,
|
||||
prefillValueNamespaceOnly: namespace,
|
||||
}}
|
||||
customizationId={`default-/${apiGroup}/${apiVersion}/${typeName}`}
|
||||
customizationId={`default-/${apiGroup}/${apiVersion}/${plural}`}
|
||||
isCreate
|
||||
backlink={backLink}
|
||||
modeData={modeData}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { FC, useState } from 'react'
|
||||
import { Spin, Alert, Segmented } from 'antd'
|
||||
import { useCrdResourceSingle, Spacer } from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { useK8sSmartResource, TSingleResource, Spacer } from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { useSelector } from 'react-redux'
|
||||
import { RootState } from 'store/store'
|
||||
import { BlackholeForm } from 'components'
|
||||
@@ -8,8 +8,8 @@ import { BlackholeForm } from 'components'
|
||||
type TUpdateCrdsFormProps = {
|
||||
apiGroup: string
|
||||
apiVersion: string
|
||||
typeName: string
|
||||
entryName: string
|
||||
plural: string
|
||||
name: string
|
||||
namespace?: string
|
||||
backLink?: string | null
|
||||
}
|
||||
@@ -17,8 +17,8 @@ type TUpdateCrdsFormProps = {
|
||||
export const UpdateCrdsForm: FC<TUpdateCrdsFormProps> = ({
|
||||
apiGroup,
|
||||
apiVersion,
|
||||
typeName,
|
||||
entryName,
|
||||
plural,
|
||||
name,
|
||||
namespace,
|
||||
backLink,
|
||||
}) => {
|
||||
@@ -41,26 +41,37 @@ export const UpdateCrdsForm: FC<TUpdateCrdsFormProps> = ({
|
||||
onDisabled: onCurrentModeDisabled,
|
||||
}
|
||||
|
||||
const { data, isPending, error } = useCrdResourceSingle({
|
||||
clusterName: cluster,
|
||||
const {
|
||||
data: dataArr,
|
||||
isLoading: isPending,
|
||||
error,
|
||||
} = useK8sSmartResource<{
|
||||
items: TSingleResource[]
|
||||
}>({
|
||||
cluster,
|
||||
namespace,
|
||||
apiGroup,
|
||||
apiVersion,
|
||||
crdName: typeName,
|
||||
entryName,
|
||||
refetchInterval: false,
|
||||
plural,
|
||||
fieldSelector: `metadata.name=${name}`,
|
||||
})
|
||||
|
||||
const data = dataArr?.items && dataArr.items.length > 0 ? dataArr.items[0] : undefined
|
||||
|
||||
if (isPending) {
|
||||
return <Spin />
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return <Alert message={`An error has occurred: ${error?.message} `} type="error" />
|
||||
return (
|
||||
<Alert message={`An error has occurred: ${typeof error === 'string' ? error : error?.message} `} type="error" />
|
||||
)
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
return <Alert message={`An error has occurred: No data `} type="error" />
|
||||
}
|
||||
|
||||
/* eslint-disable-next-line @typescript-eslint/no-unused-vars */
|
||||
// const { status: _, ...noStatusData } = data
|
||||
/* eslint-disable-next-line @typescript-eslint/no-unused-vars */
|
||||
const { managedFields: __, ...metadata } = data.metadata
|
||||
|
||||
@@ -80,11 +91,10 @@ export const UpdateCrdsForm: FC<TUpdateCrdsFormProps> = ({
|
||||
type: 'apis',
|
||||
apiGroup,
|
||||
apiVersion,
|
||||
typeName,
|
||||
// prefillValuesSchema: { ...noStatusData, metadata },
|
||||
plural,
|
||||
prefillValuesSchema: { ...data, metadata },
|
||||
}}
|
||||
customizationId={`default-/${apiGroup}/${apiVersion}/${typeName}`}
|
||||
customizationId={`default-/${apiGroup}/${apiVersion}/${plural}`}
|
||||
backlink={backLink}
|
||||
modeData={modeData}
|
||||
/>
|
||||
|
||||
@@ -20,10 +20,6 @@ export const User: FC = () => {
|
||||
placement="top"
|
||||
menu={{
|
||||
items: [
|
||||
// {
|
||||
// key: '1',
|
||||
// label: <ThemeSelector />,
|
||||
// },
|
||||
...(BASE_HIDE_INSIDE === 'true'
|
||||
? []
|
||||
: [
|
||||
|
||||
@@ -12,8 +12,7 @@ type THeaderProps = {
|
||||
}
|
||||
|
||||
export const HeaderSecond: FC<THeaderProps> = ({ inside, isSearch }) => {
|
||||
// const { projectName, instanceName, clusterName, entryType, namespace, syntheticProject } = useParams()
|
||||
const { projectName, instanceName, clusterName, namespace, syntheticProject } = useParams()
|
||||
const { projectName, instanceName, cluster, namespace, syntheticProject } = useParams()
|
||||
const { token } = theme.useToken()
|
||||
|
||||
const possibleProject = syntheticProject && namespace ? syntheticProject : namespace
|
||||
@@ -23,17 +22,17 @@ export const HeaderSecond: FC<THeaderProps> = ({ inside, isSearch }) => {
|
||||
<Styled.BackgroundContainer $bgColor={token.colorFillSecondary} $borderRadius={token.borderRadius}>
|
||||
<Styled.PaddingContainer $height={HEAD_SECOND_ROW}>
|
||||
<Flex gap={18}>
|
||||
{inside ? <SelectorClusterInside clusterName={clusterName} /> : <SelectorCluster clusterName={clusterName} />}
|
||||
{inside && <SelectorInside clusterName={clusterName} namespace={namespace} />}
|
||||
{inside ? <SelectorClusterInside cluster={cluster} /> : <SelectorCluster cluster={cluster} />}
|
||||
{inside && <SelectorInside cluster={cluster} namespace={namespace} />}
|
||||
{!inside && !isSearch && BASE_USE_NAMESPACE_NAV !== 'true' && (
|
||||
<Selector
|
||||
clusterName={clusterName}
|
||||
cluster={cluster}
|
||||
projectName={projectName || possibleProject}
|
||||
instanceName={instanceName || possibleInstance}
|
||||
/>
|
||||
)}
|
||||
{!inside && (isSearch || BASE_USE_NAMESPACE_NAV === 'true') && (
|
||||
<SelectorNamespace clusterName={clusterName} namespace={namespace} />
|
||||
<SelectorNamespace cluster={cluster} namespace={namespace} />
|
||||
)}
|
||||
</Flex>
|
||||
</Styled.PaddingContainer>
|
||||
|
||||
@@ -1,61 +1,60 @@
|
||||
import React, { FC, useState } from 'react'
|
||||
import { Flex, Typography } from 'antd'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { useDirectUnknownResource } from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { useK8sSmartResource, TNavigationResource } from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { useNavSelector } from 'hooks/useNavSelector'
|
||||
import { useMountEffect } from 'hooks/useMountEffect'
|
||||
import { EntrySelect } from 'components/atoms'
|
||||
import {
|
||||
BASE_API_GROUP,
|
||||
BASE_API_VERSION,
|
||||
BASE_CUSTOMIZATION_NAVIGATION_RESOURCE_PLURAL,
|
||||
BASE_CUSTOMIZATION_NAVIGATION_RESOURCE_NAME,
|
||||
BASE_CUSTOMIZATION_NAVIGATION_RESOURCE,
|
||||
} from 'constants/customizationApiGroupAndVersion'
|
||||
|
||||
type TSelectorProps = {
|
||||
clusterName?: string
|
||||
cluster?: string
|
||||
projectName?: string
|
||||
instanceName?: string
|
||||
}
|
||||
|
||||
export const Selector: FC<TSelectorProps> = ({ clusterName, projectName, instanceName }) => {
|
||||
export const Selector: FC<TSelectorProps> = ({ cluster, projectName, instanceName }) => {
|
||||
const navigate = useNavigate()
|
||||
|
||||
const [selectedClusterName, setSelectedClusterName] = useState(clusterName)
|
||||
const [selectedCluster, setSelectedCluster] = useState(cluster)
|
||||
const [selectedProjectName, setSelectedProjectName] = useState(projectName)
|
||||
const [selectedInstanceName, setSelectedInstanceName] = useState(instanceName)
|
||||
|
||||
// const { projectsInSidebar, instancesInSidebar, allInstancesLoadingSuccess, clustersInSidebar } = useNavSelector(
|
||||
const { projectsInSidebar, instancesInSidebar, allInstancesLoadingSuccess } = useNavSelector(
|
||||
selectedClusterName,
|
||||
selectedCluster,
|
||||
projectName,
|
||||
)
|
||||
|
||||
const { data: navigationData } = useDirectUnknownResource<{
|
||||
spec: { projects: { clear: string; change: string }; instances: { clear: string; change: string } }
|
||||
const { data: navigationDataArr } = useK8sSmartResource<{
|
||||
items: TNavigationResource[]
|
||||
}>({
|
||||
uri: `/api/clusters/${clusterName}/k8s/apis/${BASE_API_GROUP}/${BASE_API_VERSION}/${BASE_CUSTOMIZATION_NAVIGATION_RESOURCE_NAME}/${BASE_CUSTOMIZATION_NAVIGATION_RESOURCE}`,
|
||||
refetchInterval: false,
|
||||
queryKey: ['navigation', clusterName || 'no-cluster'],
|
||||
isEnabled: clusterName !== undefined,
|
||||
cluster: cluster || '',
|
||||
apiGroup: BASE_API_GROUP,
|
||||
apiVersion: BASE_API_VERSION,
|
||||
plural: BASE_CUSTOMIZATION_NAVIGATION_RESOURCE_PLURAL,
|
||||
fieldSelector: `metadata.name=${BASE_CUSTOMIZATION_NAVIGATION_RESOURCE_NAME}`,
|
||||
isEnabled: cluster !== undefined,
|
||||
})
|
||||
|
||||
// const handleClusterChange = (value: string) => {
|
||||
// setSelectedClusterName(value)
|
||||
// navigate(`${baseprefix}/clusters/${value}`)
|
||||
// }
|
||||
const navigationData =
|
||||
navigationDataArr?.items && navigationDataArr.items.length > 0 ? navigationDataArr.items[0] : undefined
|
||||
|
||||
const handleProjectChange = (value?: string) => {
|
||||
if (value && value !== 'all') {
|
||||
setSelectedProjectName(value)
|
||||
const changeUrl =
|
||||
navigationData?.spec.projects.change
|
||||
.replace('{selectedCluster}', selectedClusterName || 'no-cluster')
|
||||
navigationData?.spec?.projects?.change
|
||||
.replace('{selectedCluster}', selectedCluster || 'no-cluster')
|
||||
.replace('{value}', value) || 'no navigation data'
|
||||
navigate(changeUrl)
|
||||
} else {
|
||||
const clearUrl =
|
||||
navigationData?.spec.projects.clear.replace('{selectedCluster}', selectedClusterName || 'no-cluster') ||
|
||||
navigationData?.spec?.projects?.clear.replace('{selectedCluster}', selectedCluster || 'no-cluster') ||
|
||||
'no navigation data'
|
||||
navigate(clearUrl)
|
||||
}
|
||||
@@ -65,32 +64,32 @@ export const Selector: FC<TSelectorProps> = ({ clusterName, projectName, instanc
|
||||
if (value && value !== 'all') {
|
||||
setSelectedInstanceName(value)
|
||||
const changeUrl =
|
||||
navigationData?.spec.instances.change
|
||||
.replace('{selectedCluster}', selectedClusterName || 'no-cluster')
|
||||
navigationData?.spec?.instances?.change
|
||||
.replace('{selectedCluster}', selectedCluster || 'no-cluster')
|
||||
.replace('{selectedProject}', selectedProjectName || 'no-project')
|
||||
.replace('{value}', value) || 'no navigation data'
|
||||
navigate(changeUrl)
|
||||
} else {
|
||||
const clearUrl =
|
||||
navigationData?.spec.instances.clear
|
||||
.replace('{selectedCluster}', selectedClusterName || 'no-cluster')
|
||||
navigationData?.spec?.instances?.clear
|
||||
.replace('{selectedCluster}', selectedCluster || 'no-cluster')
|
||||
.replace('{selectedProject}', selectedProjectName || 'no-project') || 'no navigation data'
|
||||
navigate(clearUrl)
|
||||
}
|
||||
}
|
||||
|
||||
useMountEffect(() => {
|
||||
setSelectedClusterName(clusterName)
|
||||
setSelectedCluster(cluster)
|
||||
setSelectedProjectName(projectName)
|
||||
setSelectedInstanceName(instanceName)
|
||||
}, [projectName, instanceName, clusterName])
|
||||
}, [projectName, instanceName, cluster])
|
||||
|
||||
return (
|
||||
<Flex gap={18} justify="start" align="center">
|
||||
{/* <EntrySelect
|
||||
placeholder="Cluster"
|
||||
options={clustersInSidebar}
|
||||
value={selectedClusterName}
|
||||
value={selectedCluster}
|
||||
onChange={handleClusterChange}
|
||||
/> */}
|
||||
<Typography.Text>Project: </Typography.Text>
|
||||
@@ -99,7 +98,7 @@ export const Selector: FC<TSelectorProps> = ({ clusterName, projectName, instanc
|
||||
options={[{ value: 'all', label: 'All Namespaces' }, ...projectsInSidebar]}
|
||||
value={selectedProjectName || 'all'}
|
||||
onChange={handleProjectChange}
|
||||
disabled={selectedClusterName === undefined || projectsInSidebar.length === 0}
|
||||
disabled={selectedCluster === undefined || projectsInSidebar.length === 0}
|
||||
/>
|
||||
<Typography.Text>Instance: </Typography.Text>
|
||||
<EntrySelect
|
||||
@@ -108,7 +107,7 @@ export const Selector: FC<TSelectorProps> = ({ clusterName, projectName, instanc
|
||||
value={selectedInstanceName || 'all'}
|
||||
onChange={handleInstanceChange}
|
||||
disabled={
|
||||
selectedClusterName === undefined ||
|
||||
selectedCluster === undefined ||
|
||||
selectedProjectName === undefined ||
|
||||
(allInstancesLoadingSuccess && instancesInSidebar.length === 0)
|
||||
}
|
||||
|
||||
@@ -9,21 +9,20 @@ import { EntrySelect } from 'components/atoms'
|
||||
import { BASE_NAVIGATE_FROM_CLUSTERLIST } from 'constants/customizationApiGroupAndVersion'
|
||||
|
||||
type TSelectorClusterProps = {
|
||||
clusterName?: string
|
||||
cluster?: string
|
||||
}
|
||||
|
||||
export const SelectorCluster: FC<TSelectorClusterProps> = ({ clusterName }) => {
|
||||
export const SelectorCluster: FC<TSelectorClusterProps> = ({ cluster }) => {
|
||||
const navigate = useNavigate()
|
||||
const baseprefix = useSelector((state: RootState) => state.baseprefix.baseprefix)
|
||||
|
||||
const [selectedClusterName, setSelectedClusterName] = useState(clusterName)
|
||||
const [selectedCluster, setSelectedCluster] = useState(cluster)
|
||||
|
||||
const { clustersInSidebar } = useNavSelectorClusters()
|
||||
|
||||
const handleClusterChange = (value?: string) => {
|
||||
if (value) {
|
||||
setSelectedClusterName(value)
|
||||
// navigate(`${baseprefix}/clusters/${value}`)
|
||||
setSelectedCluster(value)
|
||||
navigate(BASE_NAVIGATE_FROM_CLUSTERLIST.replace('~recordValue~', value))
|
||||
} else {
|
||||
navigate(`${baseprefix}/clusters/`)
|
||||
@@ -31,8 +30,8 @@ export const SelectorCluster: FC<TSelectorClusterProps> = ({ clusterName }) => {
|
||||
}
|
||||
|
||||
useMountEffect(() => {
|
||||
setSelectedClusterName(clusterName)
|
||||
}, [clusterName])
|
||||
setSelectedCluster(cluster)
|
||||
}, [cluster])
|
||||
|
||||
return (
|
||||
<Flex gap={18} justify="start" align="center">
|
||||
@@ -40,9 +39,8 @@ export const SelectorCluster: FC<TSelectorClusterProps> = ({ clusterName }) => {
|
||||
<EntrySelect
|
||||
placeholder="Select Cluster"
|
||||
options={clustersInSidebar}
|
||||
value={selectedClusterName}
|
||||
value={selectedCluster}
|
||||
onChange={handleClusterChange}
|
||||
// fullwidth
|
||||
/>
|
||||
</Flex>
|
||||
)
|
||||
|
||||
@@ -8,20 +8,20 @@ import { useMountEffect } from 'hooks/useMountEffect'
|
||||
import { EntrySelect } from 'components/atoms'
|
||||
|
||||
type TSelectorClusterInsideProps = {
|
||||
clusterName?: string
|
||||
cluster?: string
|
||||
}
|
||||
|
||||
export const SelectorClusterInside: FC<TSelectorClusterInsideProps> = ({ clusterName }) => {
|
||||
export const SelectorClusterInside: FC<TSelectorClusterInsideProps> = ({ cluster }) => {
|
||||
const navigate = useNavigate()
|
||||
const baseprefix = useSelector((state: RootState) => state.baseprefix.baseprefix)
|
||||
|
||||
const [selectedClusterName, setSelectedClusterName] = useState(clusterName)
|
||||
const [selectedCluster, setSelectedCluster] = useState(cluster)
|
||||
|
||||
const { clustersInSidebar } = useNavSelectorInside(selectedClusterName)
|
||||
const { clustersInSidebar } = useNavSelectorInside(selectedCluster)
|
||||
|
||||
const handleClusterChange = (value?: string) => {
|
||||
if (value) {
|
||||
setSelectedClusterName(value)
|
||||
setSelectedCluster(value)
|
||||
navigate(`${baseprefix}/inside/${value}/apis`)
|
||||
} else {
|
||||
navigate(`${baseprefix}/inside/`)
|
||||
@@ -29,8 +29,8 @@ export const SelectorClusterInside: FC<TSelectorClusterInsideProps> = ({ cluster
|
||||
}
|
||||
|
||||
useMountEffect(() => {
|
||||
setSelectedClusterName(clusterName)
|
||||
}, [clusterName])
|
||||
setSelectedCluster(cluster)
|
||||
}, [cluster])
|
||||
|
||||
return (
|
||||
<Flex gap={18} justify="start" align="center">
|
||||
@@ -38,9 +38,8 @@ export const SelectorClusterInside: FC<TSelectorClusterInsideProps> = ({ cluster
|
||||
<EntrySelect
|
||||
placeholder="Select Cluster"
|
||||
options={clustersInSidebar}
|
||||
value={selectedClusterName}
|
||||
value={selectedCluster}
|
||||
onChange={handleClusterChange}
|
||||
// fullwidth
|
||||
/>
|
||||
</Flex>
|
||||
)
|
||||
|
||||
@@ -6,24 +6,18 @@ import { useMountEffect } from 'hooks/useMountEffect'
|
||||
import { EntrySelect } from 'components/atoms'
|
||||
|
||||
type TSelectorInsideProps = {
|
||||
clusterName?: string
|
||||
cluster?: string
|
||||
namespace?: string
|
||||
}
|
||||
|
||||
export const SelectorInside: FC<TSelectorInsideProps> = ({ clusterName, namespace }) => {
|
||||
export const SelectorInside: FC<TSelectorInsideProps> = ({ cluster, namespace }) => {
|
||||
const navigate = useNavigate()
|
||||
const params = useParams()
|
||||
|
||||
const [selectedClusterName, setSelectedClusterName] = useState<string | undefined>(clusterName)
|
||||
const [selectedCluster, setSelectedCluster] = useState<string | undefined>(cluster)
|
||||
const [selectedNamespace, setSelectedNamespace] = useState<string | undefined>(namespace)
|
||||
|
||||
// const { namespacesInSidebar, clustersInSidebar } = useNavSelectorInside(selectedClusterName)
|
||||
const { namespacesInSidebar } = useNavSelectorInside(selectedClusterName)
|
||||
|
||||
// const handleClusterChange = (value: string) => {
|
||||
// setSelectedClusterName(value)
|
||||
// navigate(`${baseprefix}/inside/${value}/apis`)
|
||||
// }
|
||||
const { namespacesInSidebar } = useNavSelectorInside(selectedCluster)
|
||||
|
||||
const handleNamepsaceChange = (value?: string) => {
|
||||
if (value && value !== 'all' && params.namespace) {
|
||||
@@ -44,25 +38,19 @@ export const SelectorInside: FC<TSelectorInsideProps> = ({ clusterName, namespac
|
||||
}
|
||||
|
||||
useMountEffect(() => {
|
||||
setSelectedClusterName(clusterName)
|
||||
setSelectedCluster(cluster)
|
||||
setSelectedNamespace(namespace)
|
||||
}, [namespace, clusterName])
|
||||
}, [namespace, cluster])
|
||||
|
||||
return (
|
||||
<Flex gap={18} justify="start" align="center">
|
||||
{/* <EntrySelect
|
||||
placeholder="Cluster"
|
||||
options={clustersInSidebar}
|
||||
value={selectedClusterName}
|
||||
onChange={handleClusterChange}
|
||||
/> */}
|
||||
<Typography.Text>Namespace: </Typography.Text>
|
||||
<EntrySelect
|
||||
placeholder="Namespace"
|
||||
options={[{ value: 'all', label: 'All Namespaces' }, ...namespacesInSidebar]}
|
||||
value={selectedNamespace || 'all'}
|
||||
onChange={handleNamepsaceChange}
|
||||
disabled={selectedClusterName === undefined || namespacesInSidebar.length === 0}
|
||||
disabled={selectedCluster === undefined || namespacesInSidebar.length === 0}
|
||||
/>
|
||||
</Flex>
|
||||
)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { FC, useState } from 'react'
|
||||
import { Flex, Typography } from 'antd'
|
||||
import { useLocation, useNavigate } from 'react-router-dom'
|
||||
import { useDirectUnknownResource } from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { useK8sSmartResource, TNavigationResource } from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { useSelector } from 'react-redux'
|
||||
import type { RootState } from 'store/store'
|
||||
import { useNavSelectorInside } from 'hooks/useNavSelectorInside'
|
||||
@@ -11,35 +11,40 @@ import { EntrySelect } from 'components/atoms'
|
||||
import {
|
||||
BASE_API_GROUP,
|
||||
BASE_API_VERSION,
|
||||
BASE_CUSTOMIZATION_NAVIGATION_RESOURCE_PLURAL,
|
||||
BASE_CUSTOMIZATION_NAVIGATION_RESOURCE_NAME,
|
||||
BASE_CUSTOMIZATION_NAVIGATION_RESOURCE,
|
||||
} from 'constants/customizationApiGroupAndVersion'
|
||||
|
||||
type TSelectorNamespaceProps = {
|
||||
clusterName?: string
|
||||
cluster?: string
|
||||
namespace?: string
|
||||
}
|
||||
|
||||
export const SelectorNamespace: FC<TSelectorNamespaceProps> = ({ clusterName, namespace }) => {
|
||||
export const SelectorNamespace: FC<TSelectorNamespaceProps> = ({ cluster, namespace }) => {
|
||||
const navigate = useNavigate()
|
||||
const location = useLocation()
|
||||
|
||||
const baseprefix = useSelector((state: RootState) => state.baseprefix.baseprefix)
|
||||
|
||||
const [selectedClusterName, setSelectedClusterName] = useState(clusterName)
|
||||
const [selectedCluster, setSelectedCluster] = useState(cluster)
|
||||
const [selectedNamespace, setSelectedNamespace] = useState(namespace)
|
||||
|
||||
const { namespacesInSidebar } = useNavSelectorInside(selectedClusterName)
|
||||
const { namespacesInSidebar } = useNavSelectorInside(selectedCluster)
|
||||
|
||||
const { data: navigationData } = useDirectUnknownResource<{
|
||||
spec: { namespaces: { clear: string; change: string } }
|
||||
const { data: navigationDataArr } = useK8sSmartResource<{
|
||||
items: TNavigationResource[]
|
||||
}>({
|
||||
uri: `/api/clusters/${clusterName}/k8s/apis/${BASE_API_GROUP}/${BASE_API_VERSION}/${BASE_CUSTOMIZATION_NAVIGATION_RESOURCE_NAME}/${BASE_CUSTOMIZATION_NAVIGATION_RESOURCE}`,
|
||||
refetchInterval: false,
|
||||
queryKey: ['navigation', clusterName || 'no-cluster'],
|
||||
isEnabled: clusterName !== undefined,
|
||||
cluster: cluster || '',
|
||||
apiGroup: BASE_API_GROUP,
|
||||
apiVersion: BASE_API_VERSION,
|
||||
plural: BASE_CUSTOMIZATION_NAVIGATION_RESOURCE_PLURAL,
|
||||
fieldSelector: `metadata.name=${BASE_CUSTOMIZATION_NAVIGATION_RESOURCE_NAME}`,
|
||||
isEnabled: cluster !== undefined,
|
||||
})
|
||||
|
||||
const navigationData =
|
||||
navigationDataArr?.items && navigationDataArr.items.length > 0 ? navigationDataArr.items[0] : undefined
|
||||
|
||||
const isSearchPage = useIsSearchPage(baseprefix || '')
|
||||
|
||||
const handleNamepsaceChange = (value?: string) => {
|
||||
@@ -47,10 +52,10 @@ export const SelectorNamespace: FC<TSelectorNamespaceProps> = ({ clusterName, na
|
||||
const { pathname, search, hash } = location
|
||||
const segs = pathname.split('/')
|
||||
|
||||
// Assume pattern: /prefix/:clusterName/:namespace?/:syntheticProject?/search/*
|
||||
// Assume pattern: /prefix/:cluster/:namespace?/:syntheticProject?/search/*
|
||||
// Find the "search" segment index
|
||||
const searchIdx = segs.indexOf('search')
|
||||
const clusterIdx = segs.indexOf(selectedClusterName || '')
|
||||
const clusterIdx = segs.indexOf(selectedCluster || '')
|
||||
if (clusterIdx === -1) {
|
||||
return
|
||||
} // bail if we can't find the cluster
|
||||
@@ -82,22 +87,22 @@ export const SelectorNamespace: FC<TSelectorNamespaceProps> = ({ clusterName, na
|
||||
if (value && value !== 'all') {
|
||||
setSelectedNamespace(value)
|
||||
const changeUrl =
|
||||
navigationData?.spec.namespaces.change
|
||||
.replace('{selectedCluster}', selectedClusterName || 'no-cluster')
|
||||
navigationData?.spec?.namespaces?.change
|
||||
.replace('{selectedCluster}', selectedCluster || 'no-cluster')
|
||||
.replace('{value}', value) || 'no navigation data'
|
||||
navigate(changeUrl)
|
||||
} else {
|
||||
const clearUrl =
|
||||
navigationData?.spec.namespaces.clear.replace('{selectedCluster}', selectedClusterName || 'no-cluster') ||
|
||||
navigationData?.spec?.namespaces?.clear.replace('{selectedCluster}', selectedCluster || 'no-cluster') ||
|
||||
'no navigation data'
|
||||
navigate(clearUrl)
|
||||
}
|
||||
}
|
||||
|
||||
useMountEffect(() => {
|
||||
setSelectedClusterName(clusterName)
|
||||
setSelectedCluster(cluster)
|
||||
setSelectedNamespace(namespace)
|
||||
}, [namespace, clusterName])
|
||||
}, [namespace, cluster])
|
||||
|
||||
return (
|
||||
<Flex gap={18} justify="start" align="center">
|
||||
@@ -107,7 +112,7 @@ export const SelectorNamespace: FC<TSelectorNamespaceProps> = ({ clusterName, na
|
||||
options={[{ value: 'all', label: 'All Namespaces' }, ...namespacesInSidebar]}
|
||||
value={selectedNamespace || 'all'}
|
||||
onChange={handleNamepsaceChange}
|
||||
disabled={selectedClusterName === undefined || namespacesInSidebar.length === 0}
|
||||
disabled={selectedCluster === undefined || namespacesInSidebar.length === 0}
|
||||
/>
|
||||
</Flex>
|
||||
)
|
||||
|
||||
@@ -33,16 +33,16 @@ export const ListInsideAllResources: FC<TListInsideAllResourcesProps> = ({ names
|
||||
}>()
|
||||
|
||||
const apiGroupList = useApisResourceTypes({
|
||||
clusterName: cluster,
|
||||
cluster,
|
||||
})
|
||||
|
||||
const builtInData = useBuiltinResourceTypes({
|
||||
clusterName: cluster,
|
||||
cluster,
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
getGroupsByCategory({
|
||||
clusterName: cluster,
|
||||
cluster,
|
||||
namespace,
|
||||
apiGroupListData: apiGroupList.data,
|
||||
builtinResourceTypesData: builtInData.data,
|
||||
|
||||
@@ -27,13 +27,13 @@ export const ListInsideApisByApiGroup: FC<TListInsideApisByApiGroupProps> = ({ n
|
||||
const navigate = useNavigate()
|
||||
|
||||
const { isPending, error, data } = useApiResourceTypesByGroup({
|
||||
clusterName: cluster,
|
||||
cluster,
|
||||
apiGroup,
|
||||
apiVersion,
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
filterIfApiInstanceNamespaceScoped({ namespace, data, apiGroup, apiVersion, clusterName: cluster }).then(data =>
|
||||
filterIfApiInstanceNamespaceScoped({ namespace, data, apiGroup, apiVersion, cluster }).then(data =>
|
||||
setFilteredResources(data),
|
||||
)
|
||||
}, [namespace, data, apiGroup, apiVersion, cluster])
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/* eslint-disable no-nested-ternary */
|
||||
import React, { FC, useState } from 'react'
|
||||
import { Button, Alert, Spin, Typography } from 'antd'
|
||||
import { filterSelectOptions, Spacer, useBuiltinResources, useApiResources } from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { filterSelectOptions, Spacer, TSingleResource, useK8sSmartResource } from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { useSelector, useDispatch } from 'react-redux'
|
||||
import { RootState } from 'store/store'
|
||||
@@ -8,7 +9,7 @@ import { setCluster } from 'store/cluster/cluster/cluster'
|
||||
import {
|
||||
CUSTOM_NAMESPACE_API_RESOURCE_API_GROUP,
|
||||
CUSTOM_NAMESPACE_API_RESOURCE_API_VERSION,
|
||||
CUSTOM_NAMESPACE_API_RESOURCE_RESOURCE_NAME,
|
||||
CUSTOM_NAMESPACE_API_RESOURCE_PLURAL,
|
||||
} from 'constants/customizationApiGroupAndVersion'
|
||||
import { Styled } from './styled'
|
||||
|
||||
@@ -22,30 +23,33 @@ export const ListInsideClusterAndNs: FC = () => {
|
||||
const [selectedCluster, setSelectedCluster] = useState<string>()
|
||||
const [selectedNamespace, setSelectedNamespace] = useState<string>()
|
||||
|
||||
const isCustomNamespaceResource =
|
||||
const isCustomNamespaceResource: boolean =
|
||||
CUSTOM_NAMESPACE_API_RESOURCE_API_GROUP &&
|
||||
typeof CUSTOM_NAMESPACE_API_RESOURCE_API_GROUP === 'string' &&
|
||||
CUSTOM_NAMESPACE_API_RESOURCE_API_GROUP.length > 0 &&
|
||||
CUSTOM_NAMESPACE_API_RESOURCE_API_VERSION &&
|
||||
typeof CUSTOM_NAMESPACE_API_RESOURCE_API_VERSION === 'string' &&
|
||||
CUSTOM_NAMESPACE_API_RESOURCE_API_VERSION.length > 0 &&
|
||||
CUSTOM_NAMESPACE_API_RESOURCE_RESOURCE_NAME &&
|
||||
typeof CUSTOM_NAMESPACE_API_RESOURCE_RESOURCE_NAME === 'string' &&
|
||||
CUSTOM_NAMESPACE_API_RESOURCE_RESOURCE_NAME.length > 0
|
||||
CUSTOM_NAMESPACE_API_RESOURCE_PLURAL &&
|
||||
typeof CUSTOM_NAMESPACE_API_RESOURCE_PLURAL === 'string' &&
|
||||
CUSTOM_NAMESPACE_API_RESOURCE_PLURAL.length > 0
|
||||
|
||||
const namespacesData = useBuiltinResources({
|
||||
clusterName: selectedCluster || '',
|
||||
typeName: 'namespaces',
|
||||
limit: null,
|
||||
const namespacesData = useK8sSmartResource<{
|
||||
items: TSingleResource[]
|
||||
}>({
|
||||
cluster: selectedCluster || '',
|
||||
apiVersion: 'v1',
|
||||
plural: 'namespaces',
|
||||
isEnabled: Boolean(selectedCluster !== undefined && !isCustomNamespaceResource),
|
||||
})
|
||||
|
||||
const namespacesDataCustom = useApiResources({
|
||||
clusterName: selectedCluster || '',
|
||||
const namespacesDataCustom = useK8sSmartResource<{
|
||||
items: TSingleResource[]
|
||||
}>({
|
||||
cluster: selectedCluster || '',
|
||||
apiGroup: CUSTOM_NAMESPACE_API_RESOURCE_API_GROUP,
|
||||
apiVersion: CUSTOM_NAMESPACE_API_RESOURCE_API_VERSION,
|
||||
typeName: CUSTOM_NAMESPACE_API_RESOURCE_RESOURCE_NAME,
|
||||
limit: null,
|
||||
plural: CUSTOM_NAMESPACE_API_RESOURCE_PLURAL,
|
||||
isEnabled: Boolean(selectedCluster !== undefined && isCustomNamespaceResource),
|
||||
})
|
||||
|
||||
@@ -70,7 +74,6 @@ export const ListInsideClusterAndNs: FC = () => {
|
||||
if (typeof value === 'string') {
|
||||
dispatch(setCluster(value))
|
||||
setSelectedCluster(value)
|
||||
// navigate(`/${value}/apis`)
|
||||
}
|
||||
}}
|
||||
onClear={() => {
|
||||
@@ -80,13 +83,19 @@ export const ListInsideClusterAndNs: FC = () => {
|
||||
/>
|
||||
)}
|
||||
<Spacer $space={8} $samespace />
|
||||
{selectedCluster && (isCustomNamespaceResource ? namespacesDataCustom.isPending : namespacesData.isPending) && (
|
||||
{selectedCluster && (isCustomNamespaceResource ? namespacesDataCustom.isLoading : namespacesData.isLoading) && (
|
||||
<Spin />
|
||||
)}
|
||||
{selectedCluster && (isCustomNamespaceResource ? namespacesDataCustom.error : namespacesData.error) && (
|
||||
<Alert
|
||||
message={`An error has occurred: ${
|
||||
isCustomNamespaceResource ? namespacesDataCustom.error?.message : namespacesData.error?.message
|
||||
isCustomNamespaceResource
|
||||
? typeof namespacesDataCustom.error === 'string'
|
||||
? namespacesDataCustom.error
|
||||
: namespacesDataCustom.error?.message
|
||||
: typeof namespacesData.error === 'string'
|
||||
? namespacesData.error
|
||||
: namespacesData.error?.message
|
||||
} `}
|
||||
type="error"
|
||||
/>
|
||||
|
||||
@@ -30,13 +30,13 @@ export const ListInsideCrdsByApiGroup: FC<TListInsideCrdsByApiGroupProps> = ({
|
||||
const [filteredResources, setFilteredResources] = useState<TApiGroupResourceTypeList['resources']>()
|
||||
|
||||
const { isPending, error, data } = useApiResourceTypesByGroup({
|
||||
clusterName: cluster,
|
||||
cluster,
|
||||
apiGroup,
|
||||
apiVersion,
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
filterIfApiInstanceNamespaceScoped({ namespace, data, apiGroup, apiVersion, clusterName: cluster }).then(data =>
|
||||
filterIfApiInstanceNamespaceScoped({ namespace, data, apiGroup, apiVersion, cluster }).then(data =>
|
||||
setFilteredResources(data),
|
||||
)
|
||||
}, [namespace, data, apiGroup, apiVersion, cluster])
|
||||
|
||||
@@ -100,7 +100,7 @@ export const Search: FC = () => {
|
||||
useEffect(() => {
|
||||
setIsLoading(true)
|
||||
setError(undefined)
|
||||
getKinds({ clusterName: cluster })
|
||||
getKinds({ cluster })
|
||||
.then(data => {
|
||||
setKindIndex(data)
|
||||
setKindWithVersion(getSortedKindsAll(data))
|
||||
|
||||
@@ -40,7 +40,7 @@ export const SearchEntry: FC<TSearchEntryProps> = ({ resource, labels, fields, f
|
||||
|
||||
const { FIELD_NAME } = constants
|
||||
|
||||
const [apiGroup, apiVersion, typeName] = resource.split('~')
|
||||
const [apiGroup, apiVersion, plural] = resource.split('~')
|
||||
|
||||
const kindName = kindByGvr(kindsWithVersion)(resource)
|
||||
const abbr = getUppercase(kindName && kindName.length ? kindName : 'Loading')
|
||||
@@ -60,6 +60,8 @@ export const SearchEntry: FC<TSearchEntryProps> = ({ resource, labels, fields, f
|
||||
form.setFieldsValue({ [FIELD_NAME]: cur.filter(v => v !== value) })
|
||||
}
|
||||
|
||||
const limitSp = searchParams.get('limit')
|
||||
|
||||
return (
|
||||
<Styled.Container $colorBorder={token.colorBorder} $colorText={token.colorText}>
|
||||
<Flex justify="space-between" align="center">
|
||||
@@ -89,16 +91,16 @@ export const SearchEntry: FC<TSearchEntryProps> = ({ resource, labels, fields, f
|
||||
{isOpen && (
|
||||
<>
|
||||
<Spacer $space={12} $samespace />
|
||||
{typeName && (
|
||||
{plural && (
|
||||
<TableApiBuiltin
|
||||
resourceType={apiGroup.length > 0 ? 'api' : 'builtin'}
|
||||
namespace={isNamespaceResource ? namespace : undefined}
|
||||
apiGroup={apiGroup.length > 0 ? apiGroup : undefined}
|
||||
apiVersion={apiVersion}
|
||||
typeName={typeName}
|
||||
plural={plural}
|
||||
labels={labels?.length ? labels : undefined}
|
||||
fields={fields?.length ? fields : undefined}
|
||||
limit={searchParams.get('limit')}
|
||||
limit={limitSp && limitSp.length > 0 ? Number(limitSp) : undefined}
|
||||
customizationIdPrefix={tableCustomizationIdPrefix}
|
||||
searchMount
|
||||
kindName={kindName}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import styled from 'styled-components'
|
||||
// import { HEAD_FIRST_ROW, SIDEBAR_CLUSTER_HEIGHT } from 'constants/blocksSizes'
|
||||
import { HEAD_FIRST_ROW } from 'constants/blocksSizes'
|
||||
|
||||
type TBackgroundContainerProps = {
|
||||
@@ -16,15 +15,6 @@ const BackgroundContainer = styled.div<TBackgroundContainerProps>`
|
||||
height: calc(100vh - ${HEAD_FIRST_ROW}px);
|
||||
`
|
||||
|
||||
// const ClusterSelectorContainer = styled.div`
|
||||
// height: ${SIDEBAR_CLUSTER_HEIGHT}px;
|
||||
// display: flex;
|
||||
// justify-content: center;
|
||||
// align-items: center;
|
||||
// padding: 12px;
|
||||
// `
|
||||
|
||||
export const Styled = {
|
||||
BackgroundContainer,
|
||||
// ClusterSelectorContainer,
|
||||
}
|
||||
|
||||
@@ -4,8 +4,6 @@ export const NAV_HEIGHT = 50
|
||||
export const FOOTER_HEIGHT = 38
|
||||
export const MAIN_CONTENT_HORIZONTAL_PADDING = 24
|
||||
export const BACKLINK_HEIGHT = 26
|
||||
/* sidebar */
|
||||
// export const SIDEBAR_CLUSTER_HEIGHT = 56
|
||||
/* computed only */
|
||||
export const BREADCRUMBS_HEIGHT = 26
|
||||
export const CONTENT_CARD_PADDING = 25
|
||||
|
||||
@@ -27,12 +27,17 @@ export const BASE_API_VERSION = import.meta.env.DEV
|
||||
? window._env_.CUSTOMIZATION_API_VERSION || import.meta.env.VITE_CUSTOMIZATION_API_VERSION
|
||||
: window._env_.CUSTOMIZATION_API_VERSION
|
||||
|
||||
export const BASE_CUSTOMIZATION_NAVIGATION_RESOURCE_PLURAL = import.meta.env.DEV
|
||||
? window._env_.CUSTOMIZATION_NAVIGATION_RESOURCE_PLURAL ||
|
||||
import.meta.env.VITE_CUSTOMIZATION_NAVIGATION_RESOURCE_PLURAL
|
||||
: window._env_.CUSTOMIZATION_NAVIGATION_RESOURCE_PLURAL
|
||||
export const BASE_CUSTOMIZATION_NAVIGATION_RESOURCE_NAME = import.meta.env.DEV
|
||||
? window._env_.CUSTOMIZATION_NAVIGATION_RESOURCE_NAME || import.meta.env.VITE_CUSTOMIZATION_NAVIGATION_RESOURCE_NAME
|
||||
: window._env_.CUSTOMIZATION_NAVIGATION_RESOURCE_NAME
|
||||
export const BASE_CUSTOMIZATION_NAVIGATION_RESOURCE = import.meta.env.DEV
|
||||
? window._env_.CUSTOMIZATION_NAVIGATION_RESOURCE || import.meta.env.VITE_CUSTOMIZATION_NAVIGATION_RESOURCE
|
||||
: window._env_.CUSTOMIZATION_NAVIGATION_RESOURCE
|
||||
|
||||
export const CUSTOMIZATION_SIDEBAR_FALLBACK_ID = import.meta.env.DEV
|
||||
? window._env_.CUSTOMIZATION_SIDEBAR_FALLBACK_ID || import.meta.env.VITE_CUSTOMIZATION_SIDEBAR_FALLBACK_ID
|
||||
: window._env_.CUSTOMIZATION_SIDEBAR_FALLBACK_ID
|
||||
|
||||
export const BASE_USE_NAMESPACE_NAV = import.meta.env.DEV
|
||||
? window._env_.USE_NAMESPACE_NAV || import.meta.env.VITE_USE_NAMESPACE_NAV
|
||||
@@ -49,29 +54,29 @@ export const BASE_NAVIGATE_FROM_CLUSTERLIST = import.meta.env.DEV
|
||||
export const BASE_PROJECTS_API_GROUP = import.meta.env.DEV
|
||||
? window._env_.PROJECTS_API_GROUP || import.meta.env.VITE_PROJECTS_API_GROUP
|
||||
: window._env_.PROJECTS_API_GROUP
|
||||
export const BASE_PROJECTS_VERSION = import.meta.env.DEV
|
||||
? window._env_.PROJECTS_VERSION || import.meta.env.VITE_PROJECTS_VERSION
|
||||
: window._env_.PROJECTS_VERSION
|
||||
export const BASE_PROJECTS_RESOURCE_NAME = import.meta.env.DEV
|
||||
? window._env_.PROJECTS_RESOURCE_NAME || import.meta.env.VITE_PROJECTS_RESOURCE_NAME
|
||||
: window._env_.PROJECTS_RESOURCE_NAME
|
||||
export const BASE_PROJECTS_API_VERSION = import.meta.env.DEV
|
||||
? window._env_.PROJECTS_API_VERSION || import.meta.env.VITE_PROJECTS_API_VERSION
|
||||
: window._env_.PROJECTS_API_VERSION
|
||||
export const BASE_PROJECTS_PLURAL = import.meta.env.DEV
|
||||
? window._env_.PROJECTS_PLURAL || import.meta.env.VITE_PROJECTS_PLURAL
|
||||
: window._env_.PROJECTS_PLURAL
|
||||
|
||||
export const BASE_MARKETPLACE_RESOURCE_NAME = import.meta.env.DEV
|
||||
? window._env_.MARKETPLACE_RESOURCE_NAME || import.meta.env.VITE_MARKETPLACE_RESOURCE_NAME
|
||||
: window._env_.MARKETPLACE_RESOURCE_NAME
|
||||
export const BASE_MARKETPLACE_PLURAL = import.meta.env.DEV
|
||||
? window._env_.MARKETPLACE_PLURAL || import.meta.env.VITE_MARKETPLACE_PLURAL
|
||||
: window._env_.MARKETPLACE_PLURAL
|
||||
export const BASE_MARKETPLACE_KIND = import.meta.env.DEV
|
||||
? import.meta.env.VITE_MARKETPLACE_KIND
|
||||
: window._env_.MARKETPLACE_KIND
|
||||
|
||||
export const BASE_INSTANCES_API_GROUP = import.meta.env.DEV
|
||||
export const BASE_INSTANCES_API_GROUP: string | undefined = import.meta.env.DEV
|
||||
? window._env_.INSTANCES_API_GROUP || import.meta.env.VITE_INSTANCES_API_GROUP
|
||||
: window._env_.INSTANCES_API_GROUP
|
||||
export const BASE_INSTANCES_VERSION = import.meta.env.DEV
|
||||
? window._env_.INSTANCES_VERSION || import.meta.env.VITE_INSTANCES_VERSION
|
||||
: window._env_.INSTANCES_VERSION
|
||||
export const BASE_INSTANCES_RESOURCE_NAME = import.meta.env.DEV
|
||||
? window._env_.INSTANCES_RESOURCE_NAME || import.meta.env.VITE_INSTANCES_RESOURCE_NAME
|
||||
: window._env_.INSTANCES_RESOURCE_NAME
|
||||
export const BASE_INSTANCES_API_VERSION = import.meta.env.DEV
|
||||
? window._env_.INSTANCES_API_VERSION || import.meta.env.VITE_INSTANCES_API_VERSION
|
||||
: window._env_.INSTANCES_API_VERSION
|
||||
export const BASE_INSTANCES_PLURAL = import.meta.env.DEV
|
||||
? window._env_.INSTANCES_PLURAL || import.meta.env.VITE_INSTANCES_PLURAL
|
||||
: window._env_.INSTANCES_PLURAL
|
||||
|
||||
export const NODE_TERMINAL_DEFAULT_PROFILE = import.meta.env.DEV
|
||||
? window._env_.NODE_TERMINAL_DEFAULT_PROFILE || import.meta.env.VITE_NODE_TERMINAL_DEFAULT_PROFILE
|
||||
@@ -119,14 +124,13 @@ export const BASE_NAMESPACE_FACTORY_KEY = import.meta.env.DEV
|
||||
? window._env_.BASE_NAMESPACE_FACTORY_KEY || import.meta.env.VITE_BASE_NAMESPACE_FACTORY_KEY
|
||||
: window._env_.BASE_NAMESPACE_FACTORY_KEY
|
||||
|
||||
export const CUSTOM_NAMESPACE_API_RESOURCE_API_GROUP = import.meta.env.DEV
|
||||
export const CUSTOM_NAMESPACE_API_RESOURCE_API_GROUP: string | undefined = import.meta.env.DEV
|
||||
? window._env_.CUSTOM_NAMESPACE_API_RESOURCE_API_GROUP || import.meta.env.VITE_CUSTOM_NAMESPACE_API_RESOURCE_API_GROUP
|
||||
: window._env_.CUSTOM_NAMESPACE_API_RESOURCE_API_GROUP
|
||||
export const CUSTOM_NAMESPACE_API_RESOURCE_API_VERSION = import.meta.env.DEV
|
||||
? window._env_.CUSTOM_NAMESPACE_API_RESOURCE_API_VERSION ||
|
||||
import.meta.env.VITE_CUSTOM_NAMESPACE_API_RESOURCE_API_VERSION
|
||||
: window._env_.CUSTOM_NAMESPACE_API_RESOURCE_API_VERSION
|
||||
export const CUSTOM_NAMESPACE_API_RESOURCE_RESOURCE_NAME = import.meta.env.DEV
|
||||
? window._env_.CUSTOM_NAMESPACE_API_RESOURCE_RESOURCE_NAME ||
|
||||
import.meta.env.VITE_CUSTOM_NAMESPACE_API_RESOURCE_RESOURCE_NAME
|
||||
: window._env_.CUSTOM_NAMESPACE_API_RESOURCE_RESOURCE_NAME
|
||||
export const CUSTOM_NAMESPACE_API_RESOURCE_PLURAL = import.meta.env.DEV
|
||||
? window._env_.CUSTOM_NAMESPACE_API_RESOURCE_PLURAL || import.meta.env.VITE_CUSTOM_NAMESPACE_API_RESOURCE_PLURAL
|
||||
: window._env_.CUSTOM_NAMESPACE_API_RESOURCE_PLURAL
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useLocation, matchPath } from 'react-router-dom'
|
||||
export const useIsSearchPage = (prefix: string) => {
|
||||
const { pathname } = useLocation()
|
||||
const base = `/${prefix}`.replace(/\/{2,}/g, '/').replace(/\/$/, '')
|
||||
const pattern = `${base}/:clusterName/:namespace?/:syntheticProject?/search/*`
|
||||
const pattern = `${base}/:cluster/:namespace?/:syntheticProject?/search/*`
|
||||
|
||||
return Boolean(matchPath({ path: pattern }, pathname))
|
||||
}
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
import {
|
||||
useApiResources,
|
||||
TClusterList,
|
||||
TSingleResource,
|
||||
useDirectUnknownResource,
|
||||
useK8sSmartResource,
|
||||
TNavigationResource,
|
||||
} from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { useSelector } from 'react-redux'
|
||||
import { RootState } from 'store/store'
|
||||
import {
|
||||
BASE_API_GROUP,
|
||||
BASE_API_VERSION,
|
||||
BASE_CUSTOMIZATION_NAVIGATION_RESOURCE_PLURAL,
|
||||
BASE_CUSTOMIZATION_NAVIGATION_RESOURCE_NAME,
|
||||
BASE_CUSTOMIZATION_NAVIGATION_RESOURCE,
|
||||
BASE_PROJECTS_API_GROUP,
|
||||
BASE_PROJECTS_VERSION,
|
||||
BASE_PROJECTS_RESOURCE_NAME,
|
||||
BASE_PROJECTS_API_VERSION,
|
||||
BASE_PROJECTS_PLURAL,
|
||||
BASE_INSTANCES_API_GROUP,
|
||||
BASE_INSTANCES_VERSION,
|
||||
BASE_INSTANCES_RESOURCE_NAME,
|
||||
BASE_INSTANCES_API_VERSION,
|
||||
BASE_INSTANCES_PLURAL,
|
||||
} from 'constants/customizationApiGroupAndVersion'
|
||||
import { parseAll } from './utils'
|
||||
|
||||
@@ -47,48 +47,61 @@ const mappedInstanceToOptionInSidebar = ({
|
||||
label: instance.metadata.name,
|
||||
})
|
||||
|
||||
export const useNavSelector = (clusterName?: string, projectName?: string) => {
|
||||
export const useNavSelector = (cluster?: string, projectName?: string) => {
|
||||
const clusterList = useSelector((state: RootState) => state.clusterList.clusterList)
|
||||
|
||||
const { data: navigationData } = useDirectUnknownResource<{
|
||||
spec: { instances: { mapOptionsPattern: string } }
|
||||
const { data: navigationDataArr } = useK8sSmartResource<{
|
||||
items: TNavigationResource[]
|
||||
}>({
|
||||
uri: `/api/clusters/${clusterName}/k8s/apis/${BASE_API_GROUP}/${BASE_API_VERSION}/${BASE_CUSTOMIZATION_NAVIGATION_RESOURCE_NAME}/${BASE_CUSTOMIZATION_NAVIGATION_RESOURCE}`,
|
||||
refetchInterval: false,
|
||||
queryKey: ['navigation', clusterName || 'no-cluster'],
|
||||
isEnabled: clusterName !== undefined,
|
||||
cluster: cluster || '',
|
||||
apiGroup: BASE_API_GROUP,
|
||||
apiVersion: BASE_API_VERSION,
|
||||
plural: BASE_CUSTOMIZATION_NAVIGATION_RESOURCE_PLURAL,
|
||||
fieldSelector: `metadata.name=${BASE_CUSTOMIZATION_NAVIGATION_RESOURCE_NAME}`,
|
||||
isEnabled: cluster !== undefined,
|
||||
})
|
||||
|
||||
const { data: projects } = useApiResources({
|
||||
clusterName: clusterName || '',
|
||||
namespace: '',
|
||||
const navigationData =
|
||||
navigationDataArr?.items && navigationDataArr.items.length > 0 ? navigationDataArr.items[0] : undefined
|
||||
|
||||
const { data: projects } = useK8sSmartResource<{
|
||||
items: TSingleResource[]
|
||||
}>({
|
||||
cluster: cluster || '',
|
||||
apiGroup: BASE_PROJECTS_API_GROUP,
|
||||
apiVersion: BASE_PROJECTS_VERSION,
|
||||
typeName: BASE_PROJECTS_RESOURCE_NAME,
|
||||
limit: null,
|
||||
isEnabled: clusterName !== undefined,
|
||||
apiVersion: BASE_PROJECTS_API_VERSION,
|
||||
plural: BASE_PROJECTS_PLURAL,
|
||||
isEnabled: cluster !== undefined,
|
||||
})
|
||||
|
||||
const { data: instances, isSuccess: allInstancesLoadingSuccess } = useApiResources({
|
||||
clusterName: clusterName || '',
|
||||
namespace: '',
|
||||
const {
|
||||
data: instances,
|
||||
isLoading: isInstancesLoading,
|
||||
isError: isInstancesError,
|
||||
} = useK8sSmartResource<{
|
||||
items: TSingleResource[]
|
||||
}>({
|
||||
cluster: cluster || '',
|
||||
apiGroup: BASE_INSTANCES_API_GROUP,
|
||||
apiVersion: BASE_INSTANCES_VERSION,
|
||||
typeName: BASE_INSTANCES_RESOURCE_NAME,
|
||||
limit: null,
|
||||
isEnabled: clusterName !== undefined,
|
||||
apiVersion: BASE_INSTANCES_API_VERSION,
|
||||
plural: BASE_INSTANCES_PLURAL,
|
||||
isEnabled: cluster !== undefined,
|
||||
})
|
||||
|
||||
const allInstancesLoadingSuccess: boolean = Boolean(
|
||||
instances && instances.items && !isInstancesError && !isInstancesLoading,
|
||||
)
|
||||
|
||||
const clustersInSidebar = clusterList ? clusterList.map(mappedClusterToOptionInSidebar) : []
|
||||
const projectsInSidebar = clusterName && projects ? projects.items.map(mappedProjectToOptionInSidebar) : []
|
||||
const projectsInSidebar = cluster && projects ? projects.items.map(mappedProjectToOptionInSidebar) : []
|
||||
const instancesInSidebar =
|
||||
clusterName && instances
|
||||
cluster && instances
|
||||
? instances.items
|
||||
.filter(item => item.metadata.namespace === projectName)
|
||||
.map(item =>
|
||||
mappedInstanceToOptionInSidebar({
|
||||
instance: item,
|
||||
templateString: navigationData?.spec.instances.mapOptionsPattern,
|
||||
templateString: navigationData?.spec?.instances?.mapOptionsPattern,
|
||||
}),
|
||||
)
|
||||
: []
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { TClusterList, TSingleResource, useBuiltinResources, useApiResources } from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { TClusterList, TSingleResource, useK8sSmartResource } from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { useSelector } from 'react-redux'
|
||||
import { RootState } from 'store/store'
|
||||
import {
|
||||
CUSTOM_NAMESPACE_API_RESOURCE_API_GROUP,
|
||||
CUSTOM_NAMESPACE_API_RESOURCE_API_VERSION,
|
||||
CUSTOM_NAMESPACE_API_RESOURCE_RESOURCE_NAME,
|
||||
CUSTOM_NAMESPACE_API_RESOURCE_PLURAL,
|
||||
} from 'constants/customizationApiGroupAndVersion'
|
||||
|
||||
const mappedClusterToOptionInSidebar = ({ name }: TClusterList[number]): { value: string; label: string } => ({
|
||||
@@ -17,7 +17,7 @@ const mappedNamespaceToOptionInSidebar = ({ metadata }: TSingleResource): { valu
|
||||
label: metadata.name,
|
||||
})
|
||||
|
||||
export const useNavSelectorInside = (clusterName?: string) => {
|
||||
export const useNavSelectorInside = (cluster?: string) => {
|
||||
const clusterList = useSelector((state: RootState) => state.clusterList.clusterList)
|
||||
|
||||
const isCustomNamespaceResource =
|
||||
@@ -27,30 +27,33 @@ export const useNavSelectorInside = (clusterName?: string) => {
|
||||
CUSTOM_NAMESPACE_API_RESOURCE_API_VERSION &&
|
||||
typeof CUSTOM_NAMESPACE_API_RESOURCE_API_VERSION === 'string' &&
|
||||
CUSTOM_NAMESPACE_API_RESOURCE_API_VERSION.length > 0 &&
|
||||
CUSTOM_NAMESPACE_API_RESOURCE_RESOURCE_NAME &&
|
||||
typeof CUSTOM_NAMESPACE_API_RESOURCE_RESOURCE_NAME === 'string' &&
|
||||
CUSTOM_NAMESPACE_API_RESOURCE_RESOURCE_NAME.length > 0
|
||||
CUSTOM_NAMESPACE_API_RESOURCE_PLURAL &&
|
||||
typeof CUSTOM_NAMESPACE_API_RESOURCE_PLURAL === 'string' &&
|
||||
CUSTOM_NAMESPACE_API_RESOURCE_PLURAL.length > 0
|
||||
|
||||
const { data: namespaces } = useBuiltinResources({
|
||||
clusterName: clusterName || '',
|
||||
typeName: 'namespaces',
|
||||
limit: null,
|
||||
isEnabled: Boolean(clusterName !== undefined && !isCustomNamespaceResource),
|
||||
const { data: namespaces } = useK8sSmartResource<{
|
||||
items: TSingleResource[]
|
||||
}>({
|
||||
cluster: cluster || '',
|
||||
apiVersion: 'v1',
|
||||
plural: 'namespaces',
|
||||
isEnabled: Boolean(cluster !== undefined && !isCustomNamespaceResource),
|
||||
})
|
||||
|
||||
const { data: namespacesCustom } = useApiResources({
|
||||
clusterName: clusterName || '',
|
||||
const { data: namespacesCustom } = useK8sSmartResource<{
|
||||
items: TSingleResource[]
|
||||
}>({
|
||||
cluster: cluster || '',
|
||||
apiGroup: CUSTOM_NAMESPACE_API_RESOURCE_API_GROUP,
|
||||
apiVersion: CUSTOM_NAMESPACE_API_RESOURCE_API_VERSION,
|
||||
typeName: CUSTOM_NAMESPACE_API_RESOURCE_RESOURCE_NAME,
|
||||
limit: null,
|
||||
isEnabled: Boolean(clusterName !== undefined && isCustomNamespaceResource),
|
||||
plural: CUSTOM_NAMESPACE_API_RESOURCE_PLURAL,
|
||||
isEnabled: Boolean(cluster !== undefined && !isCustomNamespaceResource),
|
||||
})
|
||||
|
||||
const clustersInSidebar = clusterList ? clusterList.map(mappedClusterToOptionInSidebar) : []
|
||||
const namespacesInSidebar = clusterName && namespaces ? namespaces.items.map(mappedNamespaceToOptionInSidebar) : []
|
||||
const namespacesInSidebar = cluster && namespaces ? namespaces.items.map(mappedNamespaceToOptionInSidebar) : []
|
||||
const namespacesInSidebarCustom =
|
||||
clusterName && namespacesCustom ? namespacesCustom.items.map(mappedNamespaceToOptionInSidebar) : []
|
||||
cluster && namespacesCustom ? namespacesCustom.items.map(mappedNamespaceToOptionInSidebar) : []
|
||||
|
||||
return {
|
||||
clustersInSidebar,
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
import React, { useState } from 'react'
|
||||
import { Modal, Button, Form, Select } from 'antd'
|
||||
import { ComponentType } from './types'
|
||||
|
||||
export const componentTypes: ComponentType[] = [
|
||||
'antdText',
|
||||
'antdCard',
|
||||
'antdFlex',
|
||||
'antdRow',
|
||||
'antdCol',
|
||||
'partsOfUrl',
|
||||
'multiQuery',
|
||||
'parsedText',
|
||||
]
|
||||
|
||||
interface AddComponentModalProps {
|
||||
onAdd: (type: ComponentType) => void
|
||||
title?: string
|
||||
}
|
||||
|
||||
export const AddComponentModal: React.FC<AddComponentModalProps> = ({ onAdd, title = 'Add Component' }) => {
|
||||
const [visible, setVisible] = useState(false)
|
||||
const [form] = Form.useForm()
|
||||
|
||||
const handleSubmit = (values: { type: ComponentType }) => {
|
||||
onAdd(values.type)
|
||||
setVisible(false)
|
||||
form.resetFields()
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button onClick={() => setVisible(true)}>Add</Button>
|
||||
<Modal title={title} visible={visible} onCancel={() => setVisible(false)} footer={null}>
|
||||
<Form form={form} onFinish={handleSubmit}>
|
||||
<Form.Item label="Component Type" name="type" rules={[{ required: true }]}>
|
||||
<Select>
|
||||
{componentTypes.map(type => (
|
||||
<Select.Option key={type} value={type}>
|
||||
{type}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Button type="primary" htmlType="submit">
|
||||
Add
|
||||
</Button>
|
||||
</Form>
|
||||
</Modal>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
/* eslint-disable no-console */
|
||||
/* eslint-disable no-param-reassign */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import React, { useEffect } from 'react'
|
||||
import { Form, Input, Select, Button, Switch } from 'antd'
|
||||
|
||||
const { TextArea } = Input
|
||||
const { Option } = Select
|
||||
|
||||
interface AntdCardFormProps {
|
||||
initialValues: any // This would be `TDynamicComponentsAppTypeMap['antdCard']`
|
||||
onSave: (data: any) => void
|
||||
}
|
||||
|
||||
export const AntdCardForm: React.FC<AntdCardFormProps> = ({ initialValues, onSave }) => {
|
||||
const [form] = Form.useForm()
|
||||
|
||||
useEffect(() => {
|
||||
form.setFieldsValue(initialValues)
|
||||
}, [initialValues, form])
|
||||
|
||||
const handleSubmit = (values: any) => {
|
||||
try {
|
||||
if (values.style) {
|
||||
values.style = JSON.parse(values.style)
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('Invalid JSON for style', e)
|
||||
return
|
||||
}
|
||||
|
||||
onSave(values)
|
||||
}
|
||||
|
||||
return (
|
||||
<Form form={form} onFinish={handleSubmit} layout="vertical" initialValues={initialValues}>
|
||||
<Form.Item label="ID" name="id" rules={[{ required: true }]}>
|
||||
<Input disabled />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label="Title" name="title">
|
||||
<Input placeholder="Card title" />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label="Bordered" name="bordered" valuePropName="checked">
|
||||
<Switch defaultChecked />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label="Cover Image URL" name="cover">
|
||||
<Input placeholder="https://example.com/image.jpg" />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label="Style (JSON)" name="style">
|
||||
<TextArea rows={4} placeholder='e.g. {"width": "300px", "margin": "10px"}' />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label="Size" name="size">
|
||||
<Select defaultValue="default">
|
||||
<Option value="default">Default</Option>
|
||||
<Option value="small">Small</Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label="Extra Content (Right Side)" name="extra">
|
||||
<Input placeholder="Extra content like links or buttons" />
|
||||
</Form.Item>
|
||||
|
||||
<Button type="primary" htmlType="submit">
|
||||
Save
|
||||
</Button>
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
/* eslint-disable no-console */
|
||||
/* eslint-disable no-param-reassign */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import React, { useEffect } from 'react'
|
||||
import { Form, Input, Select, Button } from 'antd'
|
||||
|
||||
interface AntdTextFormProps {
|
||||
initialValues: any
|
||||
onSave: (data: any) => void
|
||||
}
|
||||
|
||||
export const AntdTextForm: React.FC<AntdTextFormProps> = ({ initialValues, onSave }) => {
|
||||
const [form] = Form.useForm()
|
||||
|
||||
useEffect(() => {
|
||||
form.setFieldsValue(initialValues)
|
||||
}, [initialValues, form])
|
||||
|
||||
const handleSubmit = (values: any) => {
|
||||
try {
|
||||
if (values.style) {
|
||||
values.style = JSON.parse(values.style)
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('Invalid JSON for style', e)
|
||||
}
|
||||
onSave(values)
|
||||
}
|
||||
|
||||
return (
|
||||
<Form form={form} onFinish={handleSubmit} layout="vertical" initialValues={initialValues}>
|
||||
<Form.Item label="ID" name="id" rules={[{ required: true }]}>
|
||||
<Input disabled />
|
||||
</Form.Item>
|
||||
<Form.Item label="Text" name="text" rules={[{ required: true }]}>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item label="Type" name="type">
|
||||
<Select allowClear>
|
||||
<Select.Option value="">Default</Select.Option>
|
||||
<Select.Option value="secondary">Secondary</Select.Option>
|
||||
<Select.Option value="success">Success</Select.Option>
|
||||
<Select.Option value="warning">Warning</Select.Option>
|
||||
<Select.Option value="danger">Danger</Select.Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Form.Item label="Style (JSON)" name="style">
|
||||
<Input.TextArea rows={4} placeholder='e.g. {"color": "red"}' />
|
||||
</Form.Item>
|
||||
<Button type="primary" htmlType="submit">
|
||||
Save
|
||||
</Button>
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
/* eslint-disable no-console */
|
||||
/* TODO: REFACTOR */
|
||||
import React, { useState } from 'react'
|
||||
import { Button, Typography, Modal, Input } from 'antd'
|
||||
|
||||
import { ComponentNode } from './ComponentNode'
|
||||
import { AddComponentModal } from './AddComponentModal'
|
||||
import { Component, ComponentType, TDynamicComponentsAppTypeMap } from './types'
|
||||
|
||||
const { Title } = Typography
|
||||
const { TextArea } = Input
|
||||
|
||||
export const AppComponentAdmin: React.FC = () => {
|
||||
const [components, setComponents] = useState<Component[]>([])
|
||||
const [maxId, setMaxId] = useState(1)
|
||||
const [jsonOutput, setJsonOutput] = useState<string>('')
|
||||
const [isModalVisible, setIsModalVisible] = useState(false)
|
||||
|
||||
const getNewId = () => {
|
||||
const newId = maxId + 1
|
||||
setMaxId(newId)
|
||||
return newId
|
||||
}
|
||||
|
||||
const generateDefaultData = (type: ComponentType): TDynamicComponentsAppTypeMap[ComponentType] => {
|
||||
const base = { id: getNewId() }
|
||||
switch (type) {
|
||||
case 'antdText':
|
||||
return { ...base, text: '' }
|
||||
case 'antdCard':
|
||||
return { ...base, title: '' }
|
||||
case 'antdFlex':
|
||||
return { ...base, justify: 'start', align: 'start' }
|
||||
case 'antdRow':
|
||||
return { ...base }
|
||||
case 'antdCol':
|
||||
return { ...base, span: 12 }
|
||||
case 'partsOfUrl':
|
||||
case 'multiQuery':
|
||||
case 'parsedText':
|
||||
return { ...base, text: '' }
|
||||
default:
|
||||
return base
|
||||
}
|
||||
}
|
||||
|
||||
const addComponent = (type: ComponentType) => {
|
||||
const newComponent: Component = {
|
||||
type,
|
||||
data: generateDefaultData(type),
|
||||
children: [],
|
||||
}
|
||||
setComponents(prev => [...prev, newComponent])
|
||||
}
|
||||
|
||||
const updateComponent = (index: number, updated: Component) => {
|
||||
setComponents(prev => {
|
||||
const newComponents = [...prev]
|
||||
newComponents[index] = updated
|
||||
return newComponents
|
||||
})
|
||||
}
|
||||
|
||||
const deleteComponent = (index: number) => {
|
||||
setComponents(prev => {
|
||||
const newComponents = [...prev]
|
||||
newComponents.splice(index, 1)
|
||||
return newComponents
|
||||
})
|
||||
}
|
||||
|
||||
const handleSaveAll = () => {
|
||||
const output = JSON.stringify(
|
||||
{
|
||||
data: components,
|
||||
},
|
||||
null,
|
||||
2,
|
||||
)
|
||||
setJsonOutput(output)
|
||||
setIsModalVisible(true)
|
||||
}
|
||||
|
||||
const handleCopyToClipboard = () => {
|
||||
navigator.clipboard.writeText(jsonOutput)
|
||||
console.log('Copied to clipboard!')
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{ padding: 20 }}>
|
||||
<Title level={3}>Component Admin Panel</Title>
|
||||
<AddComponentModal onAdd={addComponent} title="Add Root Component" />
|
||||
|
||||
<div style={{ marginTop: 20 }}>
|
||||
{components.map((component, index) => (
|
||||
<ComponentNode
|
||||
key={component.data.id}
|
||||
component={component}
|
||||
onUpdate={updated => updateComponent(index, updated)}
|
||||
onDelete={() => deleteComponent(index)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Save Button */}
|
||||
<Button type="primary" onClick={handleSaveAll} style={{ marginTop: 20 }}>
|
||||
Save All as JSON
|
||||
</Button>
|
||||
|
||||
{/* JSON Output Modal */}
|
||||
<Modal
|
||||
title="Final JSON Output"
|
||||
open={isModalVisible}
|
||||
onCancel={() => setIsModalVisible(false)}
|
||||
footer={[
|
||||
<Button key="copy" onClick={handleCopyToClipboard}>
|
||||
Copy to Clipboard
|
||||
</Button>,
|
||||
<Button key="close" onClick={() => setIsModalVisible(false)}>
|
||||
Close
|
||||
</Button>,
|
||||
]}
|
||||
>
|
||||
<TextArea value={jsonOutput} readOnly rows={20} style={{ fontFamily: 'monospace' }} />
|
||||
</Modal>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
// src/ComponentForm.tsx
|
||||
import React from 'react'
|
||||
import { DynamicComponentForm } from './DynamicComponentForm'
|
||||
import type { ComponentType } from './types'
|
||||
|
||||
interface ComponentFormProps {
|
||||
type: ComponentType
|
||||
data: any
|
||||
onSave: (data: any) => void
|
||||
}
|
||||
|
||||
export const ComponentForm: React.FC<ComponentFormProps> = ({ type, data, onSave }) => {
|
||||
return <DynamicComponentForm type={type} initialValues={data} onSave={onSave} />
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import React from 'react'
|
||||
import { ComponentType } from './types'
|
||||
import { AntdTextForm } from './AntdTextForm'
|
||||
import { AntdCardForm } from './AntdCardForm'
|
||||
import { TextWithIdForm } from './TextWithIdForm'
|
||||
|
||||
interface ComponentFormProps {
|
||||
type: ComponentType
|
||||
data: any
|
||||
onSave: (data: any) => void
|
||||
}
|
||||
|
||||
export const ComponentForm: React.FC<ComponentFormProps> = ({ type, data, onSave }) => {
|
||||
switch (type) {
|
||||
case 'antdText':
|
||||
return <AntdTextForm initialValues={data} onSave={onSave} />
|
||||
case 'antdCard':
|
||||
return <AntdCardForm initialValues={data} onSave={onSave} />
|
||||
case 'partsOfUrl':
|
||||
case 'multiQuery':
|
||||
case 'parsedText':
|
||||
return <TextWithIdForm initialValues={data} onSave={onSave} />
|
||||
default:
|
||||
return <div>Unsupported component type</div>
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
import React from 'react'
|
||||
import { Button } from 'antd'
|
||||
import { Component, ComponentType } from './types'
|
||||
import { EditComponentModal } from './EditComponentModal'
|
||||
import { AddComponentModal } from './AddComponentModal'
|
||||
import { generateDefaultData } from './utils'
|
||||
|
||||
interface ComponentNodeProps {
|
||||
component: Component
|
||||
onUpdate: (component: Component) => void
|
||||
onDelete: () => void
|
||||
}
|
||||
|
||||
export const ComponentNode: React.FC<ComponentNodeProps> = ({ component, onUpdate, onDelete }) => {
|
||||
const handleAddChild = (type: ComponentType) => {
|
||||
const newChild: Component = {
|
||||
type,
|
||||
data: generateDefaultData(type),
|
||||
children: [],
|
||||
}
|
||||
const updated = { ...component }
|
||||
updated.children = updated.children ? [...updated.children, newChild] : [newChild]
|
||||
onUpdate(updated)
|
||||
}
|
||||
|
||||
const handleUpdateChild = (index: number, updatedChild: Component) => {
|
||||
const updated = { ...component }
|
||||
updated.children![index] = updatedChild
|
||||
onUpdate(updated)
|
||||
}
|
||||
|
||||
const handleDeleteChild = (index: number) => {
|
||||
const updated = { ...component }
|
||||
updated.children!.splice(index, 1)
|
||||
onUpdate(updated)
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{ border: '1px solid #ccc', padding: 10, margin: '10px 0' }}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
|
||||
<span>
|
||||
<strong>{component.type}</strong> (ID: {component.data.id})
|
||||
</span>
|
||||
<div>
|
||||
<EditComponentModal component={component} onSave={onUpdate} />
|
||||
<AddComponentModal onAdd={handleAddChild} title="Add Child" />
|
||||
<Button danger size="small" onClick={onDelete} style={{ marginLeft: 8 }}>
|
||||
Delete
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ marginLeft: 20, marginTop: 10 }}>
|
||||
{component.children?.map((child, idx) => (
|
||||
<ComponentNode
|
||||
key={child.data.id}
|
||||
component={child}
|
||||
onUpdate={updated => handleUpdateChild(idx, updated)}
|
||||
onDelete={() => handleDeleteChild(idx)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
/* eslint-disable no-console */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
// src/DynamicComponentForm.tsx
|
||||
import React, { useEffect } from 'react'
|
||||
import { Form, Input, Select, Switch, Button, Typography } from 'antd'
|
||||
|
||||
import { componentMetaMap } from './utils'
|
||||
import type { ComponentType } from './types'
|
||||
|
||||
const { TextArea } = Input
|
||||
const { Option } = Select
|
||||
|
||||
interface DynamicComponentFormProps {
|
||||
type: ComponentType
|
||||
initialValues: any
|
||||
onSave: (data: any) => void
|
||||
}
|
||||
|
||||
export const DynamicComponentForm: React.FC<DynamicComponentFormProps> = ({ type, initialValues, onSave }) => {
|
||||
const [form] = Form.useForm()
|
||||
|
||||
useEffect(() => {
|
||||
form.setFieldsValue(initialValues)
|
||||
}, [initialValues, form])
|
||||
|
||||
const handleSubmit = (values: any) => {
|
||||
try {
|
||||
const parsedValues = Object.entries(values).reduce((acc, [key, value]) => {
|
||||
const meta = componentMetaMap[type]?.[key]
|
||||
|
||||
if (meta?.inputType === 'json') {
|
||||
if (typeof value === 'string') {
|
||||
try {
|
||||
acc[key] = JSON.parse(value)
|
||||
} catch (e) {
|
||||
console.warn(`Invalid JSON for ${key}:`, value)
|
||||
acc[key] = value // Keep original string
|
||||
}
|
||||
} else {
|
||||
acc[key] = value // Already parsed or non-string
|
||||
}
|
||||
} else {
|
||||
acc[key] = value
|
||||
}
|
||||
|
||||
return acc
|
||||
}, {} as any)
|
||||
|
||||
onSave(parsedValues)
|
||||
} catch (e) {
|
||||
console.log('Invalid JSON input', e)
|
||||
}
|
||||
}
|
||||
|
||||
const renderFormItem = (prop: string, meta: any) => {
|
||||
const value = initialValues[prop]
|
||||
|
||||
switch (meta.inputType) {
|
||||
case 'text':
|
||||
return <Input placeholder={meta.label} />
|
||||
case 'textarea':
|
||||
return <TextArea rows={4} placeholder={meta.label} />
|
||||
case 'json':
|
||||
return (
|
||||
<TextArea
|
||||
rows={4}
|
||||
placeholder={`e.g. {"color": "red"}`}
|
||||
defaultValue={value ? JSON.stringify(value, null, 2) : ''}
|
||||
/>
|
||||
)
|
||||
case 'boolean':
|
||||
return <Switch defaultChecked={value} />
|
||||
case 'select':
|
||||
return (
|
||||
<Select defaultValue={value}>
|
||||
{meta.options?.map((opt: { label: string; value: string }) => (
|
||||
<Option key={opt.value} value={opt.value}>
|
||||
{opt.label}
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
)
|
||||
case 'number':
|
||||
return <Input type="number" placeholder={meta.label} />
|
||||
default:
|
||||
return <Input />
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Form form={form} onFinish={handleSubmit} layout="vertical">
|
||||
{/* ID (always present and read-only) */}
|
||||
<Form.Item label="ID" name="id" rules={[{ required: true }]}>
|
||||
<Input disabled />
|
||||
</Form.Item>
|
||||
|
||||
{/* Render dynamic props */}
|
||||
{Object.entries(componentMetaMap[type] || {}).map(([prop, meta]) => (
|
||||
<Form.Item key={prop} label={meta.label} name={prop}>
|
||||
{renderFormItem(prop, meta)}
|
||||
</Form.Item>
|
||||
))}
|
||||
|
||||
{/* Submit Button */}
|
||||
<Button type="primary" htmlType="submit" style={{ marginTop: 16 }}>
|
||||
Save
|
||||
</Button>
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
/* eslint-disable react/button-has-type */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import React, { useState } from 'react'
|
||||
import { Modal } from 'antd'
|
||||
import { ComponentForm } from './ComponentForm'
|
||||
import { Component } from './types'
|
||||
|
||||
interface EditComponentModalProps {
|
||||
component: Component
|
||||
onSave: (component: Component) => void
|
||||
}
|
||||
|
||||
export const EditComponentModal: React.FC<EditComponentModalProps> = ({ component, onSave }) => {
|
||||
const [open, setOpen] = useState(false)
|
||||
|
||||
const handleSave = (data: any) => {
|
||||
onSave({ ...component, data })
|
||||
setOpen(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<button onClick={() => setOpen(true)}>Edit</button>
|
||||
<Modal
|
||||
title={`Edit ${component.type}`}
|
||||
open={open} // ✅ Use open instead of visible
|
||||
onCancel={() => setOpen(false)}
|
||||
footer={null}
|
||||
>
|
||||
<ComponentForm type={component.type} data={component.data} onSave={handleSave} />
|
||||
</Modal>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
import React, { useEffect } from 'react'
|
||||
import { Form, Input, Button } from 'antd'
|
||||
|
||||
interface TextWithIdFormProps {
|
||||
initialValues: {
|
||||
id: number
|
||||
text: string
|
||||
}
|
||||
onSave: (data: { id: number; text: string }) => void
|
||||
}
|
||||
|
||||
export const TextWithIdForm: React.FC<TextWithIdFormProps> = ({ initialValues, onSave }) => {
|
||||
const [form] = Form.useForm()
|
||||
|
||||
useEffect(() => {
|
||||
form.setFieldsValue(initialValues)
|
||||
}, [initialValues, form])
|
||||
|
||||
const handleSubmit = (values: { id: number; text: string }) => {
|
||||
onSave(values)
|
||||
}
|
||||
|
||||
return (
|
||||
<Form form={form} onFinish={handleSubmit} layout="vertical" initialValues={initialValues}>
|
||||
<Form.Item label="ID" name="id" rules={[{ required: true }]}>
|
||||
<Input disabled />
|
||||
</Form.Item>
|
||||
<Form.Item label="Text" name="text" rules={[{ required: true }]}>
|
||||
<Input.TextArea
|
||||
rows={4}
|
||||
placeholder="Enter text (you can use variables like {5}, {reqs[0]['metadata']} etc.)"
|
||||
/>
|
||||
</Form.Item>
|
||||
<Button type="primary" htmlType="submit">
|
||||
Save
|
||||
</Button>
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
export { AppComponentAdmin as FactoryAdminPage } from './AppComponentAdmin'
|
||||
@@ -1,26 +0,0 @@
|
||||
import type {
|
||||
CardProps as AntdCardProps,
|
||||
FlexProps as AntdFlexProps,
|
||||
RowProps as AntdRowProps,
|
||||
ColProps as AntdColProps,
|
||||
} from 'antd'
|
||||
import { TextProps as AntdTextProps } from 'antd/es/typography/Text'
|
||||
|
||||
export type TDynamicComponentsAppTypeMap = {
|
||||
antdText: { id: number; text: string } & Omit<AntdTextProps, 'id'>
|
||||
antdCard: { id: number } & Omit<AntdCardProps, 'id'>
|
||||
antdFlex: { id: number } & Omit<AntdFlexProps, 'id' | 'children'>
|
||||
antdRow: { id: number } & Omit<AntdRowProps, 'id' | 'children'>
|
||||
antdCol: { id: number } & Omit<AntdColProps, 'id' | 'children'>
|
||||
partsOfUrl: { id: number; text: string }
|
||||
multiQuery: { id: number; text: string }
|
||||
parsedText: { id: number; text: string }
|
||||
}
|
||||
|
||||
export type ComponentType = keyof TDynamicComponentsAppTypeMap
|
||||
|
||||
export type Component = {
|
||||
type: ComponentType
|
||||
data: TDynamicComponentsAppTypeMap[ComponentType]
|
||||
children?: Component[]
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
// src/utils.ts
|
||||
import type { ComponentType, TDynamicComponentsAppTypeMap } from './types'
|
||||
|
||||
export const generateDefaultData = (type: ComponentType): TDynamicComponentsAppTypeMap[ComponentType] => {
|
||||
const base = { id: Math.floor(Math.random() * 100000) } // Simplified ID generation
|
||||
switch (type) {
|
||||
case 'antdText':
|
||||
return { ...base, text: '' }
|
||||
case 'antdCard':
|
||||
return { ...base, title: '' }
|
||||
case 'antdFlex':
|
||||
return { ...base, justify: 'start', align: 'start' }
|
||||
case 'antdRow':
|
||||
return { ...base }
|
||||
case 'antdCol':
|
||||
return { ...base, span: 12 }
|
||||
case 'partsOfUrl':
|
||||
case 'multiQuery':
|
||||
case 'parsedText':
|
||||
return { ...base, text: '' }
|
||||
default:
|
||||
return base
|
||||
}
|
||||
}
|
||||
|
||||
// Define property metadata for each component
|
||||
type PropertyMeta = {
|
||||
label: string
|
||||
inputType: 'text' | 'textarea' | 'json' | 'boolean' | 'select' | 'number'
|
||||
options?: { label: string; value: any }[]
|
||||
}
|
||||
|
||||
type ComponentMetaMap = {
|
||||
[key in ComponentType]: Record<string, PropertyMeta>
|
||||
}
|
||||
|
||||
export const componentMetaMap: ComponentMetaMap = {
|
||||
antdText: {
|
||||
text: { label: 'Text', inputType: 'textarea' },
|
||||
type: {
|
||||
label: 'Type',
|
||||
inputType: 'select',
|
||||
options: [
|
||||
{ label: 'Default', value: '' },
|
||||
{ label: 'Secondary', value: 'secondary' },
|
||||
{ label: 'Success', value: 'success' },
|
||||
{ label: 'Warning', value: 'warning' },
|
||||
{ label: 'Danger', value: 'danger' },
|
||||
],
|
||||
},
|
||||
style: { label: 'Style (JSON)', inputType: 'json' },
|
||||
},
|
||||
antdCard: {
|
||||
title: { label: 'Title', inputType: 'text' },
|
||||
bordered: { label: 'Bordered', inputType: 'boolean' },
|
||||
cover: { label: 'Cover Image URL', inputType: 'text' },
|
||||
size: {
|
||||
label: 'Size',
|
||||
inputType: 'select',
|
||||
options: [
|
||||
{ label: 'Default', value: 'default' },
|
||||
{ label: 'Small', value: 'small' },
|
||||
],
|
||||
},
|
||||
extra: { label: 'Extra Content', inputType: 'text' },
|
||||
style: { label: 'Style (JSON)', inputType: 'json' },
|
||||
},
|
||||
antdFlex: {
|
||||
justify: {
|
||||
label: 'Justify',
|
||||
inputType: 'select',
|
||||
options: [
|
||||
{ label: 'Start', value: 'start' },
|
||||
{ label: 'End', value: 'end' },
|
||||
{ label: 'Center', value: 'center' },
|
||||
{ label: 'Space Around', value: 'space-around' },
|
||||
{ label: 'Space Between', value: 'space-between' },
|
||||
],
|
||||
},
|
||||
align: {
|
||||
label: 'Align',
|
||||
inputType: 'select',
|
||||
options: [
|
||||
{ label: 'Start', value: 'start' },
|
||||
{ label: 'End', value: 'end' },
|
||||
{ label: 'Center', value: 'center' },
|
||||
{ label: 'Baseline', value: 'baseline' },
|
||||
{ label: 'Stretch', value: 'stretch' },
|
||||
],
|
||||
},
|
||||
gap: { label: 'Gap (number)', inputType: 'number' },
|
||||
},
|
||||
antdRow: {
|
||||
gutter: { label: 'Gutter', inputType: 'number' },
|
||||
style: { label: 'Style (JSON)', inputType: 'json' },
|
||||
},
|
||||
antdCol: {
|
||||
span: { label: 'Span (1-24)', inputType: 'number' },
|
||||
offset: { label: 'Offset', inputType: 'number' },
|
||||
},
|
||||
partsOfUrl: {
|
||||
text: { label: 'Text', inputType: 'textarea' },
|
||||
},
|
||||
multiQuery: {
|
||||
text: { label: 'Text', inputType: 'textarea' },
|
||||
},
|
||||
parsedText: {
|
||||
text: { label: 'Text', inputType: 'textarea' },
|
||||
},
|
||||
}
|
||||
@@ -1,44 +1,23 @@
|
||||
import React, { FC, useState } from 'react'
|
||||
import { useParams } from 'react-router-dom'
|
||||
import { ManageableBreadcrumbs, ManageableSidebar, Factory, NavigationContainer } from 'components'
|
||||
import { getBreadcrumbsIdPrefix } from 'utils/getBreadcrumbsIdPrefix'
|
||||
import { getSidebarIdPrefix } from 'utils/getSidebarIdPrefix'
|
||||
import { BaseTemplate } from 'templates'
|
||||
import React, { FC, useEffect } from 'react'
|
||||
import { useParams, useOutletContext } from 'react-router-dom'
|
||||
import { Factory } from 'components'
|
||||
import { TChromeCtx } from 'templates'
|
||||
|
||||
export const FactoryPage: FC = () => {
|
||||
const { namespace, syntheticProject, key } = useParams()
|
||||
const { key } = useParams()
|
||||
|
||||
const [currentTags, setCurrentTags] = useState<string[]>()
|
||||
const { setCurrentTags, setSidebarSuffix, setBreadcrumbsSuffix } = useOutletContext<TChromeCtx>()
|
||||
|
||||
const possibleProject = syntheticProject && namespace ? syntheticProject : namespace
|
||||
const possibleInstance = syntheticProject && namespace ? namespace : undefined
|
||||
useEffect(() => {
|
||||
setSidebarSuffix(`factory-${key}`)
|
||||
setBreadcrumbsSuffix(`factory-${key}`)
|
||||
|
||||
const breadcrumbsId = `${getBreadcrumbsIdPrefix({
|
||||
instance: !!syntheticProject,
|
||||
project: !!namespace,
|
||||
})}factory-${key}`
|
||||
return () => {
|
||||
setCurrentTags(undefined)
|
||||
setSidebarSuffix(undefined)
|
||||
setBreadcrumbsSuffix(undefined)
|
||||
}
|
||||
}, [key, setSidebarSuffix, setBreadcrumbsSuffix, setCurrentTags])
|
||||
|
||||
const sidebarId = `${getSidebarIdPrefix({
|
||||
instance: !!syntheticProject,
|
||||
project: !!namespace,
|
||||
})}factory-${key}`
|
||||
|
||||
return (
|
||||
<BaseTemplate
|
||||
sidebar={
|
||||
<ManageableSidebar
|
||||
instanceName={possibleInstance}
|
||||
projectName={possibleProject}
|
||||
idToCompare={sidebarId}
|
||||
currentTags={currentTags}
|
||||
/>
|
||||
}
|
||||
// withNoCluster
|
||||
>
|
||||
<NavigationContainer>
|
||||
<ManageableBreadcrumbs idToCompare={breadcrumbsId} />
|
||||
</NavigationContainer>
|
||||
<Factory setSidebarTags={setCurrentTags} key={key} />
|
||||
</BaseTemplate>
|
||||
)
|
||||
return <Factory setSidebarTags={setCurrentTags} key={key} />
|
||||
}
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
import React, { FC } from 'react'
|
||||
import { ContentCard } from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { useParams, useSearchParams } from 'react-router-dom'
|
||||
import { useSelector } from 'react-redux'
|
||||
import type { RootState } from 'store/store'
|
||||
import {
|
||||
CreateApisForm,
|
||||
UpdateApisForm,
|
||||
BackLink,
|
||||
ManageableBreadcrumbs,
|
||||
ManageableSidebar,
|
||||
NavigationContainer,
|
||||
} from 'components'
|
||||
import { getSidebarIdPrefix } from 'utils/getSidebarIdPrefix'
|
||||
import { getBreadcrumbsIdPrefix } from 'utils/getBreadcrumbsIdPrefix'
|
||||
import { getFormsBackLink } from 'utils/getBacklink'
|
||||
import { BASE_USE_NAMESPACE_NAV } from 'constants/customizationApiGroupAndVersion'
|
||||
import { BaseTemplate } from 'templates'
|
||||
|
||||
type TFormApiPageProps = {
|
||||
inside?: boolean
|
||||
}
|
||||
|
||||
export const FormApiPage: FC<TFormApiPageProps> = ({ inside }) => {
|
||||
const { clusterName, syntheticProject, namespace, apiGroup, apiVersion, typeName, entryName } = useParams()
|
||||
const [searchParams] = useSearchParams()
|
||||
const baseprefix = useSelector((state: RootState) => state.baseprefix.baseprefix)
|
||||
|
||||
const possibleProject = syntheticProject && namespace ? syntheticProject : namespace
|
||||
const possibleInstance = syntheticProject && namespace ? namespace : undefined
|
||||
|
||||
if (!typeName || !apiGroup || !apiVersion) {
|
||||
return null
|
||||
}
|
||||
|
||||
const backLink = searchParams.get('backlink')?.startsWith('/') ? searchParams.get('backlink') : undefined
|
||||
|
||||
const preparedBacklink = getFormsBackLink({
|
||||
backLink,
|
||||
clusterName,
|
||||
possibleProject,
|
||||
possibleInstance,
|
||||
baseprefix,
|
||||
namespacesMode: BASE_USE_NAMESPACE_NAV === 'true',
|
||||
})
|
||||
|
||||
const sidebarId = `${getSidebarIdPrefix({ instance: !!syntheticProject, project: !!namespace, inside })}api-form`
|
||||
const breadcrumbsId = `${getBreadcrumbsIdPrefix({
|
||||
instance: !!syntheticProject,
|
||||
project: !!namespace,
|
||||
inside,
|
||||
})}api-form${entryName ? '-edit' : ''}`
|
||||
|
||||
return (
|
||||
<BaseTemplate
|
||||
inside={inside}
|
||||
sidebar={
|
||||
<ManageableSidebar
|
||||
instanceName={possibleInstance}
|
||||
projectName={possibleProject}
|
||||
idToCompare={sidebarId}
|
||||
currentTags={[`${apiGroup}/${apiVersion}/${typeName}`]}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<NavigationContainer>
|
||||
<ManageableBreadcrumbs idToCompare={breadcrumbsId} inside={inside} />
|
||||
<BackLink
|
||||
to={preparedBacklink}
|
||||
title={`${entryName ? 'Update' : 'Create'} ${apiGroup}/${apiVersion}/${typeName}${
|
||||
entryName ? `/${entryName}` : ''
|
||||
}`}
|
||||
/>
|
||||
</NavigationContainer>
|
||||
<ContentCard flexGrow={1} displayFlex flexFlow="column">
|
||||
{entryName ? (
|
||||
<UpdateApisForm
|
||||
namespace={namespace}
|
||||
apiGroup={apiGroup}
|
||||
apiVersion={apiVersion}
|
||||
typeName={typeName}
|
||||
entryName={entryName}
|
||||
backLink={backLink}
|
||||
/>
|
||||
) : (
|
||||
<CreateApisForm
|
||||
namespace={namespace}
|
||||
apiGroup={apiGroup}
|
||||
apiVersion={apiVersion}
|
||||
typeName={typeName}
|
||||
backLink={backLink}
|
||||
/>
|
||||
)}
|
||||
</ContentCard>
|
||||
</BaseTemplate>
|
||||
)
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
import React, { FC } from 'react'
|
||||
import { ContentCard } from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { useParams, useSearchParams } from 'react-router-dom'
|
||||
import { useSelector } from 'react-redux'
|
||||
import type { RootState } from 'store/store'
|
||||
import {
|
||||
CreateBuiltinForm,
|
||||
UpdateBuiltinForm,
|
||||
BackLink,
|
||||
ManageableBreadcrumbs,
|
||||
ManageableSidebar,
|
||||
NavigationContainer,
|
||||
} from 'components'
|
||||
import { getSidebarIdPrefix } from 'utils/getSidebarIdPrefix'
|
||||
import { getBreadcrumbsIdPrefix } from 'utils/getBreadcrumbsIdPrefix'
|
||||
import { getFormsBackLink } from 'utils/getBacklink'
|
||||
import { BASE_USE_NAMESPACE_NAV } from 'constants/customizationApiGroupAndVersion'
|
||||
import { BaseTemplate } from 'templates'
|
||||
|
||||
type TFormBuiltinPageProps = {
|
||||
inside?: boolean
|
||||
}
|
||||
|
||||
export const FormBuiltinPage: FC<TFormBuiltinPageProps> = ({ inside }) => {
|
||||
const { clusterName, syntheticProject, namespace, typeName, entryName } = useParams()
|
||||
const [searchParams] = useSearchParams()
|
||||
const baseprefix = useSelector((state: RootState) => state.baseprefix.baseprefix)
|
||||
|
||||
const possibleProject = syntheticProject && namespace ? syntheticProject : namespace
|
||||
const possibleInstance = syntheticProject && namespace ? namespace : undefined
|
||||
|
||||
if (!typeName) {
|
||||
return null
|
||||
}
|
||||
|
||||
const backLink = searchParams.get('backlink')?.startsWith('/') ? searchParams.get('backlink') : undefined
|
||||
|
||||
const preparedBacklink = getFormsBackLink({
|
||||
backLink,
|
||||
clusterName,
|
||||
possibleProject,
|
||||
possibleInstance,
|
||||
baseprefix,
|
||||
namespacesMode: BASE_USE_NAMESPACE_NAV === 'true',
|
||||
})
|
||||
|
||||
const sidebarId = `${getSidebarIdPrefix({ instance: !!syntheticProject, project: !!namespace, inside })}builtin-form`
|
||||
const breadcrumbsId = `${getBreadcrumbsIdPrefix({
|
||||
instance: !!syntheticProject,
|
||||
project: !!namespace,
|
||||
inside,
|
||||
})}builtin-form${entryName ? '-edit' : ''}`
|
||||
|
||||
return (
|
||||
<BaseTemplate
|
||||
inside={inside}
|
||||
sidebar={
|
||||
<ManageableSidebar
|
||||
instanceName={possibleInstance}
|
||||
projectName={possibleProject}
|
||||
idToCompare={sidebarId}
|
||||
currentTags={[typeName]}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<NavigationContainer>
|
||||
<ManageableBreadcrumbs idToCompare={breadcrumbsId} inside={inside} />
|
||||
<BackLink
|
||||
to={preparedBacklink}
|
||||
title={`${entryName ? 'Update' : 'Create'} ${typeName}${entryName ? `/${entryName}` : ''}`}
|
||||
/>
|
||||
</NavigationContainer>
|
||||
<ContentCard flexGrow={1} displayFlex flexFlow="column">
|
||||
{entryName ? (
|
||||
<UpdateBuiltinForm namespace={namespace} typeName={typeName} entryName={entryName} backLink={backLink} />
|
||||
) : (
|
||||
<CreateBuiltinForm namespace={namespace} typeName={typeName} backLink={backLink} />
|
||||
)}
|
||||
</ContentCard>
|
||||
</BaseTemplate>
|
||||
)
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
import React, { FC } from 'react'
|
||||
import { ContentCard } from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { useParams, useSearchParams } from 'react-router-dom'
|
||||
import { useSelector } from 'react-redux'
|
||||
import type { RootState } from 'store/store'
|
||||
import {
|
||||
CreateCrdsForm,
|
||||
UpdateCrdsForm,
|
||||
BackLink,
|
||||
ManageableBreadcrumbs,
|
||||
ManageableSidebar,
|
||||
NavigationContainer,
|
||||
} from 'components'
|
||||
import { getSidebarIdPrefix } from 'utils/getSidebarIdPrefix'
|
||||
import { getBreadcrumbsIdPrefix } from 'utils/getBreadcrumbsIdPrefix'
|
||||
import { getFormsBackLink } from 'utils/getBacklink'
|
||||
import { BASE_USE_NAMESPACE_NAV } from 'constants/customizationApiGroupAndVersion'
|
||||
import { BaseTemplate } from 'templates'
|
||||
|
||||
type TFormCrdPageProps = {
|
||||
inside?: boolean
|
||||
}
|
||||
|
||||
export const FormCrdPage: FC<TFormCrdPageProps> = ({ inside }) => {
|
||||
const { clusterName, syntheticProject, apiGroup, apiVersion, namespace, typeName, entryName } = useParams()
|
||||
const [searchParams] = useSearchParams()
|
||||
const baseprefix = useSelector((state: RootState) => state.baseprefix.baseprefix)
|
||||
|
||||
const possibleProject = syntheticProject && namespace ? syntheticProject : namespace
|
||||
const possibleInstance = syntheticProject && namespace ? namespace : undefined
|
||||
|
||||
if (!typeName || !apiGroup || !apiVersion) {
|
||||
return null
|
||||
}
|
||||
|
||||
const backLink = searchParams.get('backlink')?.startsWith('/') ? searchParams.get('backlink') : undefined
|
||||
|
||||
const preparedBacklink = getFormsBackLink({
|
||||
backLink,
|
||||
clusterName,
|
||||
possibleProject,
|
||||
possibleInstance,
|
||||
baseprefix,
|
||||
namespacesMode: BASE_USE_NAMESPACE_NAV === 'true',
|
||||
})
|
||||
|
||||
const sidebarId = `${getSidebarIdPrefix({ instance: !!syntheticProject, project: !!namespace, inside })}crd-form`
|
||||
const breadcrumbsId = `${getBreadcrumbsIdPrefix({
|
||||
instance: !!syntheticProject,
|
||||
project: !!namespace,
|
||||
inside,
|
||||
})}crd-form${entryName ? '-edit' : ''}`
|
||||
|
||||
return (
|
||||
<BaseTemplate
|
||||
inside={inside}
|
||||
sidebar={
|
||||
<ManageableSidebar
|
||||
instanceName={possibleInstance}
|
||||
projectName={possibleProject}
|
||||
idToCompare={sidebarId}
|
||||
currentTags={[`${apiGroup}/${apiVersion}/${typeName}`]}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<NavigationContainer>
|
||||
<ManageableBreadcrumbs idToCompare={breadcrumbsId} inside={inside} />
|
||||
<BackLink
|
||||
to={preparedBacklink}
|
||||
title={`${entryName ? 'Update' : 'Create'} ${apiGroup}/${apiVersion}/${typeName}${
|
||||
entryName ? `/${entryName}` : ''
|
||||
}`}
|
||||
/>
|
||||
</NavigationContainer>
|
||||
<ContentCard flexGrow={1} displayFlex flexFlow="column">
|
||||
{entryName ? (
|
||||
<UpdateCrdsForm
|
||||
namespace={namespace}
|
||||
apiGroup={apiGroup}
|
||||
apiVersion={apiVersion}
|
||||
typeName={typeName}
|
||||
entryName={entryName}
|
||||
backLink={backLink}
|
||||
/>
|
||||
) : (
|
||||
<CreateCrdsForm
|
||||
namespace={namespace}
|
||||
apiGroup={apiGroup}
|
||||
apiVersion={apiVersion}
|
||||
typeName={typeName}
|
||||
backLink={backLink}
|
||||
/>
|
||||
)}
|
||||
</ContentCard>
|
||||
</BaseTemplate>
|
||||
)
|
||||
}
|
||||
85
src/pages/Forms/FormApiPage/FormApiPage.tsx
Normal file
85
src/pages/Forms/FormApiPage/FormApiPage.tsx
Normal file
@@ -0,0 +1,85 @@
|
||||
import React, { FC, useEffect } from 'react'
|
||||
import { ContentCard } from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { useParams, useSearchParams, useOutletContext } from 'react-router-dom'
|
||||
import { useSelector } from 'react-redux'
|
||||
import type { RootState } from 'store/store'
|
||||
import { CreateApisForm, UpdateApisForm } from 'components'
|
||||
import { getFormsBackLink } from 'utils/getBacklink'
|
||||
import { BASE_USE_NAMESPACE_NAV } from 'constants/customizationApiGroupAndVersion'
|
||||
import { TChromeCtx } from 'templates'
|
||||
|
||||
export const FormApiPage: FC = () => {
|
||||
const { cluster, syntheticProject, namespace, apiGroup, apiVersion, plural, name } = useParams()
|
||||
const [searchParams] = useSearchParams()
|
||||
const baseprefix = useSelector((state: RootState) => state.baseprefix.baseprefix)
|
||||
|
||||
const possibleProject = syntheticProject && namespace ? syntheticProject : namespace
|
||||
const possibleInstance = syntheticProject && namespace ? namespace : undefined
|
||||
|
||||
const backLink = searchParams.get('backlink')?.startsWith('/') ? searchParams.get('backlink') : undefined
|
||||
|
||||
const preparedBacklink = getFormsBackLink({
|
||||
backLink,
|
||||
cluster,
|
||||
possibleProject,
|
||||
possibleInstance,
|
||||
baseprefix,
|
||||
namespacesMode: BASE_USE_NAMESPACE_NAV === 'true',
|
||||
})
|
||||
|
||||
const { setCurrentTags, setSidebarSuffix, setBreadcrumbsSuffix, setBacklinkTo, setBacklinkTitle } =
|
||||
useOutletContext<TChromeCtx>()
|
||||
|
||||
useEffect(() => {
|
||||
setSidebarSuffix('api-form')
|
||||
setBreadcrumbsSuffix(`api-form${name ? '-edit' : ''}`)
|
||||
setCurrentTags([`${apiGroup}/${apiVersion}/${plural}`])
|
||||
setBacklinkTo(preparedBacklink)
|
||||
setBacklinkTitle(`${name ? 'Update' : 'Create'} ${apiGroup}/${apiVersion}/${plural}${name ? `/${name}` : ''}`)
|
||||
|
||||
return () => {
|
||||
setCurrentTags(undefined)
|
||||
setSidebarSuffix(undefined)
|
||||
setBreadcrumbsSuffix(undefined)
|
||||
setBacklinkTo(undefined)
|
||||
setBacklinkTitle(undefined)
|
||||
}
|
||||
}, [
|
||||
apiGroup,
|
||||
apiVersion,
|
||||
plural,
|
||||
name,
|
||||
preparedBacklink,
|
||||
setSidebarSuffix,
|
||||
setBreadcrumbsSuffix,
|
||||
setCurrentTags,
|
||||
setBacklinkTo,
|
||||
setBacklinkTitle,
|
||||
])
|
||||
if (!plural || !apiGroup || !apiVersion) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<ContentCard flexGrow={1} displayFlex flexFlow="column">
|
||||
{name ? (
|
||||
<UpdateApisForm
|
||||
namespace={namespace}
|
||||
apiGroup={apiGroup}
|
||||
apiVersion={apiVersion}
|
||||
plural={plural}
|
||||
name={name}
|
||||
backLink={backLink}
|
||||
/>
|
||||
) : (
|
||||
<CreateApisForm
|
||||
namespace={namespace}
|
||||
apiGroup={apiGroup}
|
||||
apiVersion={apiVersion}
|
||||
plural={plural}
|
||||
backLink={backLink}
|
||||
/>
|
||||
)}
|
||||
</ContentCard>
|
||||
)
|
||||
}
|
||||
71
src/pages/Forms/FormBuiltinPage/FormBuiltinPage.tsx
Normal file
71
src/pages/Forms/FormBuiltinPage/FormBuiltinPage.tsx
Normal file
@@ -0,0 +1,71 @@
|
||||
import React, { FC, useEffect } from 'react'
|
||||
import { ContentCard } from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { useParams, useSearchParams, useOutletContext } from 'react-router-dom'
|
||||
import { useSelector } from 'react-redux'
|
||||
import type { RootState } from 'store/store'
|
||||
import { CreateBuiltinForm, UpdateBuiltinForm } from 'components'
|
||||
import { getFormsBackLink } from 'utils/getBacklink'
|
||||
import { BASE_USE_NAMESPACE_NAV } from 'constants/customizationApiGroupAndVersion'
|
||||
import { TChromeCtx } from 'templates'
|
||||
|
||||
export const FormBuiltinPage: FC = () => {
|
||||
const { cluster, syntheticProject, namespace, plural, name } = useParams()
|
||||
const [searchParams] = useSearchParams()
|
||||
const baseprefix = useSelector((state: RootState) => state.baseprefix.baseprefix)
|
||||
|
||||
const possibleProject = syntheticProject && namespace ? syntheticProject : namespace
|
||||
const possibleInstance = syntheticProject && namespace ? namespace : undefined
|
||||
|
||||
const backLink = searchParams.get('backlink')?.startsWith('/') ? searchParams.get('backlink') : undefined
|
||||
|
||||
const preparedBacklink = getFormsBackLink({
|
||||
backLink,
|
||||
cluster,
|
||||
possibleProject,
|
||||
possibleInstance,
|
||||
baseprefix,
|
||||
namespacesMode: BASE_USE_NAMESPACE_NAV === 'true',
|
||||
})
|
||||
|
||||
const { setCurrentTags, setSidebarSuffix, setBreadcrumbsSuffix, setBacklinkTo, setBacklinkTitle } =
|
||||
useOutletContext<TChromeCtx>()
|
||||
|
||||
useEffect(() => {
|
||||
setSidebarSuffix('builtin-form')
|
||||
setBreadcrumbsSuffix(`builtin-form${name ? '-edit' : ''}`)
|
||||
setCurrentTags([`${plural}`])
|
||||
setBacklinkTo(preparedBacklink)
|
||||
setBacklinkTitle(`${name ? 'Update' : 'Create'} ${plural}${name ? `/${name}` : ''}`)
|
||||
|
||||
return () => {
|
||||
setCurrentTags(undefined)
|
||||
setSidebarSuffix(undefined)
|
||||
setBreadcrumbsSuffix(undefined)
|
||||
setBacklinkTo(undefined)
|
||||
setBacklinkTitle(undefined)
|
||||
}
|
||||
}, [
|
||||
plural,
|
||||
name,
|
||||
preparedBacklink,
|
||||
setSidebarSuffix,
|
||||
setBreadcrumbsSuffix,
|
||||
setCurrentTags,
|
||||
setBacklinkTo,
|
||||
setBacklinkTitle,
|
||||
])
|
||||
|
||||
if (!plural) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<ContentCard flexGrow={1} displayFlex flexFlow="column">
|
||||
{name ? (
|
||||
<UpdateBuiltinForm namespace={namespace} plural={plural} name={name} backLink={backLink} />
|
||||
) : (
|
||||
<CreateBuiltinForm namespace={namespace} plural={plural} backLink={backLink} />
|
||||
)}
|
||||
</ContentCard>
|
||||
)
|
||||
}
|
||||
85
src/pages/Forms/FormCrdPage/FormCrdPage.tsx
Normal file
85
src/pages/Forms/FormCrdPage/FormCrdPage.tsx
Normal file
@@ -0,0 +1,85 @@
|
||||
import React, { FC, useEffect } from 'react'
|
||||
import { ContentCard } from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { useParams, useSearchParams, useOutletContext } from 'react-router-dom'
|
||||
import { useSelector } from 'react-redux'
|
||||
import type { RootState } from 'store/store'
|
||||
import { CreateCrdsForm, UpdateCrdsForm } from 'components'
|
||||
import { getFormsBackLink } from 'utils/getBacklink'
|
||||
import { BASE_USE_NAMESPACE_NAV } from 'constants/customizationApiGroupAndVersion'
|
||||
import { TChromeCtx } from 'templates'
|
||||
|
||||
export const FormCrdPage: FC = () => {
|
||||
const { cluster, syntheticProject, apiGroup, apiVersion, namespace, plural, name } = useParams()
|
||||
const [searchParams] = useSearchParams()
|
||||
const baseprefix = useSelector((state: RootState) => state.baseprefix.baseprefix)
|
||||
|
||||
const possibleProject = syntheticProject && namespace ? syntheticProject : namespace
|
||||
const possibleInstance = syntheticProject && namespace ? namespace : undefined
|
||||
|
||||
const backLink = searchParams.get('backlink')?.startsWith('/') ? searchParams.get('backlink') : undefined
|
||||
|
||||
const preparedBacklink = getFormsBackLink({
|
||||
backLink,
|
||||
cluster,
|
||||
possibleProject,
|
||||
possibleInstance,
|
||||
baseprefix,
|
||||
namespacesMode: BASE_USE_NAMESPACE_NAV === 'true',
|
||||
})
|
||||
|
||||
const { setCurrentTags, setSidebarSuffix, setBreadcrumbsSuffix, setBacklinkTo, setBacklinkTitle } =
|
||||
useOutletContext<TChromeCtx>()
|
||||
|
||||
useEffect(() => {
|
||||
setSidebarSuffix('crd-form')
|
||||
setBreadcrumbsSuffix(`crd-form${name ? '-edit' : ''}`)
|
||||
setCurrentTags([`${apiGroup}/${apiVersion}/${plural}`])
|
||||
setBacklinkTo(preparedBacklink)
|
||||
setBacklinkTitle(`${plural ? 'Update' : 'Create'} ${apiGroup}/${apiVersion}/${plural}${name ? `/${name}` : ''}`)
|
||||
|
||||
return () => {
|
||||
setCurrentTags(undefined)
|
||||
setSidebarSuffix(undefined)
|
||||
setBreadcrumbsSuffix(undefined)
|
||||
setBacklinkTo(undefined)
|
||||
setBacklinkTitle(undefined)
|
||||
}
|
||||
}, [
|
||||
apiGroup,
|
||||
apiVersion,
|
||||
plural,
|
||||
name,
|
||||
preparedBacklink,
|
||||
setSidebarSuffix,
|
||||
setBreadcrumbsSuffix,
|
||||
setCurrentTags,
|
||||
setBacklinkTo,
|
||||
setBacklinkTitle,
|
||||
])
|
||||
|
||||
if (!plural || !apiGroup || !apiVersion) {
|
||||
return null
|
||||
}
|
||||
return (
|
||||
<ContentCard flexGrow={1} displayFlex flexFlow="column">
|
||||
{name ? (
|
||||
<UpdateCrdsForm
|
||||
namespace={namespace}
|
||||
apiGroup={apiGroup}
|
||||
apiVersion={apiVersion}
|
||||
plural={plural}
|
||||
name={name}
|
||||
backLink={backLink}
|
||||
/>
|
||||
) : (
|
||||
<CreateCrdsForm
|
||||
namespace={namespace}
|
||||
apiGroup={apiGroup}
|
||||
apiVersion={apiVersion}
|
||||
plural={plural}
|
||||
backLink={backLink}
|
||||
/>
|
||||
)}
|
||||
</ContentCard>
|
||||
)
|
||||
}
|
||||
2
src/pages/Forms/index.ts
Normal file
2
src/pages/Forms/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export { FormApiPage } from './FormApiPage'
|
||||
export { FormBuiltinPage } from './FormBuiltinPage'
|
||||
@@ -0,0 +1,31 @@
|
||||
import React, { FC, useEffect } from 'react'
|
||||
import { ContentCard } from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { useParams, useOutletContext } from 'react-router-dom'
|
||||
import { ListInsideApisByApiGroup } from 'components'
|
||||
import { TChromeCtx } from 'templates'
|
||||
|
||||
export const ListInsideApiByApiGroupPage: FC = () => {
|
||||
const { namespace, apiGroup, apiVersion } = useParams()
|
||||
|
||||
const { setSidebarSuffix, setBreadcrumbsSuffix, setUseOnlyNamespace } = useOutletContext<TChromeCtx>()
|
||||
|
||||
useEffect(() => {
|
||||
setSidebarSuffix('api-by-api')
|
||||
setBreadcrumbsSuffix('api-by-api')
|
||||
setUseOnlyNamespace(true)
|
||||
|
||||
return () => {
|
||||
setSidebarSuffix(undefined)
|
||||
setBreadcrumbsSuffix(undefined)
|
||||
setUseOnlyNamespace(false)
|
||||
}
|
||||
}, [setSidebarSuffix, setBreadcrumbsSuffix, setUseOnlyNamespace])
|
||||
|
||||
return (
|
||||
<ContentCard flexGrow={1} displayFlex flexFlow="column">
|
||||
{apiGroup && apiVersion && (
|
||||
<ListInsideApisByApiGroup namespace={namespace} apiGroup={apiGroup} apiVersion={apiVersion} />
|
||||
)}
|
||||
</ContentCard>
|
||||
)
|
||||
}
|
||||
29
src/pages/Insides/ListInsideApiPage/ListInsideApiPage.tsx
Normal file
29
src/pages/Insides/ListInsideApiPage/ListInsideApiPage.tsx
Normal file
@@ -0,0 +1,29 @@
|
||||
import React, { FC, useEffect } from 'react'
|
||||
import { ContentCard } from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { useParams, useOutletContext } from 'react-router-dom'
|
||||
import { ListInsideAllResources } from 'components'
|
||||
import { TChromeCtx } from 'templates'
|
||||
|
||||
export const ListInsideApiPage: FC = () => {
|
||||
const { namespace } = useParams()
|
||||
|
||||
const { setSidebarSuffix, setBreadcrumbsSuffix, setUseOnlyNamespace } = useOutletContext<TChromeCtx>()
|
||||
|
||||
useEffect(() => {
|
||||
setSidebarSuffix('apis')
|
||||
setBreadcrumbsSuffix('apis')
|
||||
setUseOnlyNamespace(true)
|
||||
|
||||
return () => {
|
||||
setSidebarSuffix(undefined)
|
||||
setBreadcrumbsSuffix(undefined)
|
||||
setUseOnlyNamespace(false)
|
||||
}
|
||||
}, [setSidebarSuffix, setBreadcrumbsSuffix, setUseOnlyNamespace])
|
||||
|
||||
return (
|
||||
<ContentCard flexGrow={1} displayFlex flexFlow="column">
|
||||
<ListInsideAllResources namespace={namespace} />
|
||||
</ContentCard>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import React, { FC, useEffect } from 'react'
|
||||
import { ContentCard } from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { useParams, useOutletContext } from 'react-router-dom'
|
||||
import { ListInsideCrdsByApiGroup } from 'components'
|
||||
import { TChromeCtx } from 'templates'
|
||||
|
||||
export const ListInsideCrdByApiGroupPage: FC = () => {
|
||||
const { namespace, apiGroup, apiVersion, apiExtensionVersion } = useParams()
|
||||
|
||||
const { setSidebarSuffix, setBreadcrumbsSuffix, setUseOnlyNamespace } = useOutletContext<TChromeCtx>()
|
||||
|
||||
useEffect(() => {
|
||||
setSidebarSuffix('crd-by-api')
|
||||
setBreadcrumbsSuffix('crd-by-api')
|
||||
setUseOnlyNamespace(true)
|
||||
|
||||
return () => {
|
||||
setSidebarSuffix(undefined)
|
||||
setBreadcrumbsSuffix(undefined)
|
||||
setUseOnlyNamespace(false)
|
||||
}
|
||||
}, [setSidebarSuffix, setBreadcrumbsSuffix, setUseOnlyNamespace])
|
||||
|
||||
return (
|
||||
<ContentCard flexGrow={1} displayFlex flexFlow="column">
|
||||
{apiGroup && apiVersion && apiExtensionVersion && (
|
||||
<ListInsideCrdsByApiGroup
|
||||
namespace={namespace}
|
||||
apiGroup={apiGroup}
|
||||
apiVersion={apiVersion}
|
||||
apiExtensionVersion={apiExtensionVersion}
|
||||
/>
|
||||
)}
|
||||
</ContentCard>
|
||||
)
|
||||
}
|
||||
4
src/pages/Insides/index.ts
Normal file
4
src/pages/Insides/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export { ListInsideClustersAndNsPage } from './ListInsideClustersAndNsPage'
|
||||
export { ListInsideApiPage } from './ListInsideApiPage'
|
||||
export { ListInsideCrdByApiGroupPage } from './ListInsideCrdByApiGroupPage'
|
||||
export { ListInsideApiByApiGroupPage } from './ListInsideApiByApiGroupPage'
|
||||
@@ -1,31 +0,0 @@
|
||||
import React, { FC } from 'react'
|
||||
import { ContentCard } from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { useParams } from 'react-router-dom'
|
||||
import { ListInsideApisByApiGroup, ManageableBreadcrumbs, ManageableSidebar, NavigationContainer } from 'components'
|
||||
import { getSidebarIdPrefix } from 'utils/getSidebarIdPrefix'
|
||||
import { getBreadcrumbsIdPrefix } from 'utils/getBreadcrumbsIdPrefix'
|
||||
import { BaseTemplate } from 'templates'
|
||||
|
||||
type TListInsideApiByApiGroupPageProps = {
|
||||
inside?: boolean
|
||||
}
|
||||
|
||||
export const ListInsideApiByApiGroupPage: FC<TListInsideApiByApiGroupPageProps> = ({ inside }) => {
|
||||
const { namespace, apiGroup, apiVersion } = useParams()
|
||||
|
||||
const sidebarId = `${getSidebarIdPrefix({ namespace: !!namespace, inside })}api-by-api`
|
||||
const breadcrumbsId = `${getBreadcrumbsIdPrefix({ namespace: !!namespace, inside })}api-by-api`
|
||||
|
||||
return (
|
||||
<BaseTemplate inside={inside} sidebar={<ManageableSidebar idToCompare={sidebarId} />}>
|
||||
<NavigationContainer>
|
||||
<ManageableBreadcrumbs idToCompare={breadcrumbsId} inside />
|
||||
</NavigationContainer>
|
||||
<ContentCard flexGrow={1} displayFlex flexFlow="column">
|
||||
{apiGroup && apiVersion && (
|
||||
<ListInsideApisByApiGroup namespace={namespace} apiGroup={apiGroup} apiVersion={apiVersion} />
|
||||
)}
|
||||
</ContentCard>
|
||||
</BaseTemplate>
|
||||
)
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
import React, { FC } from 'react'
|
||||
import { ContentCard } from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { useParams } from 'react-router-dom'
|
||||
import { ListInsideAllResources, ManageableBreadcrumbs, ManageableSidebar, NavigationContainer } from 'components'
|
||||
import { getSidebarIdPrefix } from 'utils/getSidebarIdPrefix'
|
||||
import { getBreadcrumbsIdPrefix } from 'utils/getBreadcrumbsIdPrefix'
|
||||
import { BaseTemplate } from 'templates'
|
||||
|
||||
type TListInsideApiPageProps = {
|
||||
inside?: boolean
|
||||
}
|
||||
|
||||
export const ListInsideApiPage: FC<TListInsideApiPageProps> = ({ inside }) => {
|
||||
const { namespace } = useParams()
|
||||
|
||||
const sidebarId = `${getSidebarIdPrefix({ namespace: !!namespace, inside })}apis`
|
||||
const breadcrumbsId = `${getBreadcrumbsIdPrefix({ namespace: !!namespace, inside })}apis`
|
||||
|
||||
return (
|
||||
<BaseTemplate inside={inside} sidebar={<ManageableSidebar idToCompare={sidebarId} />}>
|
||||
<NavigationContainer>
|
||||
<ManageableBreadcrumbs idToCompare={breadcrumbsId} inside />
|
||||
</NavigationContainer>
|
||||
<ContentCard flexGrow={1} displayFlex flexFlow="column">
|
||||
<ListInsideAllResources namespace={namespace} />
|
||||
</ContentCard>
|
||||
</BaseTemplate>
|
||||
)
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
import React, { FC } from 'react'
|
||||
import { ContentCard } from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { useParams } from 'react-router-dom'
|
||||
import { ListInsideCrdsByApiGroup, ManageableBreadcrumbs, ManageableSidebar, NavigationContainer } from 'components'
|
||||
import { getSidebarIdPrefix } from 'utils/getSidebarIdPrefix'
|
||||
import { getBreadcrumbsIdPrefix } from 'utils/getBreadcrumbsIdPrefix'
|
||||
import { BaseTemplate } from 'templates'
|
||||
|
||||
type TListInsideCrdByApiGroupPageProps = {
|
||||
inside?: boolean
|
||||
}
|
||||
|
||||
export const ListInsideCrdByApiGroupPage: FC<TListInsideCrdByApiGroupPageProps> = ({ inside }) => {
|
||||
const { namespace, apiGroup, apiVersion, apiExtensionVersion } = useParams()
|
||||
|
||||
const sidebarId = `${getSidebarIdPrefix({ namespace: !!namespace, inside })}crd-by-api`
|
||||
const breadcrumbsId = `${getBreadcrumbsIdPrefix({ namespace: !!namespace, inside })}crd-by-api`
|
||||
|
||||
return (
|
||||
<BaseTemplate inside={inside} sidebar={<ManageableSidebar idToCompare={sidebarId} />}>
|
||||
<NavigationContainer>
|
||||
<ManageableBreadcrumbs idToCompare={breadcrumbsId} inside />
|
||||
</NavigationContainer>
|
||||
<ContentCard flexGrow={1} displayFlex flexFlow="column">
|
||||
{apiGroup && apiVersion && apiExtensionVersion && (
|
||||
<ListInsideCrdsByApiGroup
|
||||
namespace={namespace}
|
||||
apiGroup={apiGroup}
|
||||
apiVersion={apiVersion}
|
||||
apiExtensionVersion={apiExtensionVersion}
|
||||
/>
|
||||
)}
|
||||
</ContentCard>
|
||||
</BaseTemplate>
|
||||
)
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
export { ListProjectsPage } from './ListProjectsPage'
|
||||
@@ -1 +0,0 @@
|
||||
export { ProjectInfoPage } from './ProjectInfoPage'
|
||||
@@ -2,7 +2,7 @@ import React, { FC } from 'react'
|
||||
import { RedirectProjectInfo } from 'components'
|
||||
import { BaseTemplate } from 'templates'
|
||||
|
||||
export const ProjectInfoPage: FC = () => {
|
||||
export const RedirectProjectInfoPage: FC = () => {
|
||||
return (
|
||||
<BaseTemplate>
|
||||
<RedirectProjectInfo />
|
||||
1
src/pages/RedirectProjectInfoPage/index.ts
Normal file
1
src/pages/RedirectProjectInfoPage/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { RedirectProjectInfoPage } from './RedirectProjectInfoPage'
|
||||
@@ -2,7 +2,7 @@ import React, { FC } from 'react'
|
||||
import { RedirectProjectList } from 'components'
|
||||
import { BaseTemplate } from 'templates'
|
||||
|
||||
export const ListProjectsPage: FC = () => {
|
||||
export const RedirectProjectsPage: FC = () => {
|
||||
return (
|
||||
<BaseTemplate>
|
||||
<RedirectProjectList />
|
||||
1
src/pages/RedirectProjectsPage/index.ts
Normal file
1
src/pages/RedirectProjectsPage/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { RedirectProjectsPage } from './RedirectProjectsPage'
|
||||
@@ -1,47 +1,32 @@
|
||||
import React, { FC } from 'react'
|
||||
import React, { FC, useEffect } from 'react'
|
||||
import { ContentCard } from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { useParams } from 'react-router-dom'
|
||||
import { BackLink, ManageableBreadcrumbs, ManageableSidebar, NavigationContainer, Search } from 'components'
|
||||
import { getSidebarIdPrefix } from 'utils/getSidebarIdPrefix'
|
||||
import { getBreadcrumbsIdPrefix } from 'utils/getBreadcrumbsIdPrefix'
|
||||
import { BaseTemplate } from 'templates'
|
||||
import { useOutletContext } from 'react-router-dom'
|
||||
import { Search } from 'components'
|
||||
import { TChromeCtx } from 'templates'
|
||||
|
||||
export const SearchPage: FC = () => {
|
||||
const { namespace, syntheticProject } = useParams()
|
||||
const { setCurrentTags, setSidebarSuffix, setBreadcrumbsSuffix, setUseOnlyNamespace, setBaseTemplateSearchBoolean } =
|
||||
useOutletContext<TChromeCtx>()
|
||||
|
||||
const possibleProject = syntheticProject && namespace ? syntheticProject : namespace
|
||||
const possibleInstance = syntheticProject && namespace ? namespace : undefined
|
||||
useEffect(() => {
|
||||
setCurrentTags(['search'])
|
||||
setSidebarSuffix('search-page')
|
||||
setBreadcrumbsSuffix('search-page')
|
||||
setUseOnlyNamespace(true)
|
||||
setBaseTemplateSearchBoolean(true)
|
||||
|
||||
// const sidebarId = `${getSidebarIdPrefix({ instance: !!syntheticProject, project: !!namespace })}search-page`
|
||||
// const breadcrumbsId = `${getBreadcrumbsIdPrefix({
|
||||
// instance: !!syntheticProject,
|
||||
// project: !!namespace,
|
||||
// })}search-page`
|
||||
const sidebarId = `${getSidebarIdPrefix({ namespace: !!namespace })}search-page`
|
||||
const breadcrumbsId = `${getBreadcrumbsIdPrefix({
|
||||
namespace: !!namespace,
|
||||
})}search-page`
|
||||
return () => {
|
||||
setCurrentTags(undefined)
|
||||
setSidebarSuffix(undefined)
|
||||
setBreadcrumbsSuffix(undefined)
|
||||
setUseOnlyNamespace(false)
|
||||
setBaseTemplateSearchBoolean(false)
|
||||
}
|
||||
}, [setSidebarSuffix, setBreadcrumbsSuffix, setCurrentTags, setUseOnlyNamespace, setBaseTemplateSearchBoolean])
|
||||
|
||||
return (
|
||||
<BaseTemplate
|
||||
inside={false}
|
||||
isSearch
|
||||
sidebar={
|
||||
<ManageableSidebar
|
||||
instanceName={possibleInstance}
|
||||
projectName={possibleProject}
|
||||
idToCompare={sidebarId}
|
||||
currentTags={['search']}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<NavigationContainer>
|
||||
<ManageableBreadcrumbs idToCompare={breadcrumbsId} inside={false} />
|
||||
<BackLink title="Search" />
|
||||
</NavigationContainer>
|
||||
<ContentCard flexGrow={1} displayFlex flexFlow="column">
|
||||
<Search />
|
||||
</ContentCard>
|
||||
</BaseTemplate>
|
||||
<ContentCard flexGrow={1} displayFlex flexFlow="column">
|
||||
<Search />
|
||||
</ContentCard>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
import React, { FC } from 'react'
|
||||
import { ContentCard } from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { useParams, useSearchParams } from 'react-router-dom'
|
||||
import { useSelector } from 'react-redux'
|
||||
import type { RootState } from 'store/store'
|
||||
import { TableApiBuiltin, BackLink, ManageableBreadcrumbs, ManageableSidebar, NavigationContainer } from 'components'
|
||||
import { getSidebarIdPrefix } from 'utils/getSidebarIdPrefix'
|
||||
import { getBreadcrumbsIdPrefix } from 'utils/getBreadcrumbsIdPrefix'
|
||||
import { getTableCustomizationIdPrefix } from 'utils/getTableCustomizationIdPrefix'
|
||||
import { getTablesBackLink } from 'utils/getBacklink'
|
||||
import { BaseTemplate } from 'templates'
|
||||
import {
|
||||
BASE_USE_NAMESPACE_NAV,
|
||||
BASE_PROJECTS_API_GROUP,
|
||||
BASE_PROJECTS_VERSION,
|
||||
BASE_PROJECTS_RESOURCE_NAME,
|
||||
} from 'constants/customizationApiGroupAndVersion'
|
||||
|
||||
type TTableApiPageProps = {
|
||||
inside?: boolean
|
||||
}
|
||||
|
||||
export const TableApiPage: FC<TTableApiPageProps> = ({ inside }) => {
|
||||
const { clusterName, namespace, syntheticProject, apiGroup, apiVersion, typeName } = useParams()
|
||||
const [searchParams] = useSearchParams()
|
||||
const baseprefix = useSelector((state: RootState) => state.baseprefix.baseprefix)
|
||||
|
||||
const possibleProject = syntheticProject && namespace ? syntheticProject : namespace
|
||||
const possibleInstance = syntheticProject && namespace ? namespace : undefined
|
||||
|
||||
const backlink = getTablesBackLink({
|
||||
clusterName,
|
||||
possibleProject,
|
||||
possibleInstance,
|
||||
namespace,
|
||||
baseprefix,
|
||||
inside,
|
||||
namespacesMode: BASE_USE_NAMESPACE_NAV === 'true',
|
||||
})
|
||||
|
||||
const sidebarId = `${getSidebarIdPrefix({ instance: !!syntheticProject, project: !!namespace, inside })}api-table`
|
||||
const breadcrumbsId = `${getBreadcrumbsIdPrefix({
|
||||
instance: !!syntheticProject,
|
||||
project: !!namespace,
|
||||
inside,
|
||||
})}api-table`
|
||||
const tableCustomizationIdPrefix = getTableCustomizationIdPrefix({
|
||||
instance: !!syntheticProject,
|
||||
project: BASE_USE_NAMESPACE_NAV !== 'true' && !!namespace,
|
||||
namespace: !!namespace,
|
||||
inside,
|
||||
})
|
||||
|
||||
const isProjectList =
|
||||
!namespace &&
|
||||
apiGroup === BASE_PROJECTS_API_GROUP &&
|
||||
apiVersion === BASE_PROJECTS_VERSION &&
|
||||
typeName === BASE_PROJECTS_RESOURCE_NAME
|
||||
const sidebarIdProjectList = `${getSidebarIdPrefix({})}projects-list`
|
||||
const breadcrumbsIdProjectList = `${getBreadcrumbsIdPrefix({})}projects-list`
|
||||
|
||||
return (
|
||||
<BaseTemplate
|
||||
inside={inside}
|
||||
sidebar={
|
||||
<ManageableSidebar
|
||||
instanceName={possibleInstance}
|
||||
projectName={possibleProject}
|
||||
idToCompare={isProjectList ? sidebarIdProjectList : sidebarId}
|
||||
currentTags={[`${apiGroup}/${apiVersion}/${typeName}`]}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<NavigationContainer>
|
||||
<ManageableBreadcrumbs idToCompare={isProjectList ? breadcrumbsIdProjectList : breadcrumbsId} inside={inside} />
|
||||
<BackLink to={backlink} title={`${apiGroup}/${apiVersion}/${typeName}`} />
|
||||
</NavigationContainer>
|
||||
<ContentCard flexGrow={1} displayFlex flexFlow="column">
|
||||
{typeName && apiGroup && apiVersion && (
|
||||
<TableApiBuiltin
|
||||
resourceType="api"
|
||||
namespace={namespace}
|
||||
apiGroup={apiGroup}
|
||||
apiVersion={apiVersion}
|
||||
typeName={typeName}
|
||||
key={`${apiGroup}-${apiVersion}-${namespace}-${typeName}`}
|
||||
limit={searchParams.get('limit')}
|
||||
inside={inside}
|
||||
customizationIdPrefix={tableCustomizationIdPrefix}
|
||||
/>
|
||||
)}
|
||||
</ContentCard>
|
||||
</BaseTemplate>
|
||||
)
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
import React, { FC } from 'react'
|
||||
import { ContentCard } from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { useParams, useSearchParams } from 'react-router-dom'
|
||||
import { useSelector } from 'react-redux'
|
||||
import type { RootState } from 'store/store'
|
||||
import { TableApiBuiltin, BackLink, ManageableBreadcrumbs, ManageableSidebar, NavigationContainer } from 'components'
|
||||
import { getSidebarIdPrefix } from 'utils/getSidebarIdPrefix'
|
||||
import { getBreadcrumbsIdPrefix } from 'utils/getBreadcrumbsIdPrefix'
|
||||
import { getTableCustomizationIdPrefix } from 'utils/getTableCustomizationIdPrefix'
|
||||
import { getTablesBackLink } from 'utils/getBacklink'
|
||||
import { BaseTemplate } from 'templates'
|
||||
import { BASE_USE_NAMESPACE_NAV } from 'constants/customizationApiGroupAndVersion'
|
||||
|
||||
type TTableBuiltinPageProps = {
|
||||
inside?: boolean
|
||||
}
|
||||
|
||||
export const TableBuiltinPage: FC<TTableBuiltinPageProps> = ({ inside }) => {
|
||||
const { clusterName, namespace, syntheticProject, typeName } = useParams()
|
||||
const [searchParams] = useSearchParams()
|
||||
const baseprefix = useSelector((state: RootState) => state.baseprefix.baseprefix)
|
||||
|
||||
const possibleProject = syntheticProject && namespace ? syntheticProject : namespace
|
||||
const possibleInstance = syntheticProject && namespace ? namespace : undefined
|
||||
|
||||
const backlink = getTablesBackLink({
|
||||
clusterName,
|
||||
possibleProject,
|
||||
possibleInstance,
|
||||
namespace,
|
||||
baseprefix,
|
||||
inside,
|
||||
namespacesMode: BASE_USE_NAMESPACE_NAV === 'true',
|
||||
})
|
||||
|
||||
const sidebarId = `${getSidebarIdPrefix({ instance: !!syntheticProject, project: !!namespace, inside })}builtin-table`
|
||||
const breadcrumbsId = `${getBreadcrumbsIdPrefix({
|
||||
instance: !!syntheticProject,
|
||||
project: !!namespace,
|
||||
inside,
|
||||
})}builtin-table`
|
||||
const tableCustomizationIdPrefix = getTableCustomizationIdPrefix({
|
||||
instance: !!syntheticProject,
|
||||
project: BASE_USE_NAMESPACE_NAV !== 'true' && !!namespace,
|
||||
namespace: !!namespace,
|
||||
inside,
|
||||
})
|
||||
|
||||
return (
|
||||
<BaseTemplate
|
||||
inside={inside}
|
||||
sidebar={
|
||||
<ManageableSidebar
|
||||
instanceName={possibleInstance}
|
||||
projectName={possibleProject}
|
||||
idToCompare={sidebarId}
|
||||
currentTags={[`${typeName}`]}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<NavigationContainer>
|
||||
<ManageableBreadcrumbs idToCompare={breadcrumbsId} inside={inside} />
|
||||
<BackLink to={backlink} title={typeName} />
|
||||
</NavigationContainer>
|
||||
<ContentCard flexGrow={1} displayFlex flexFlow="column">
|
||||
{typeName && (
|
||||
<TableApiBuiltin
|
||||
resourceType="builtin"
|
||||
apiVersion="v1"
|
||||
key={`${namespace}-${typeName}`}
|
||||
namespace={namespace}
|
||||
typeName={typeName}
|
||||
limit={searchParams.get('limit')}
|
||||
inside={inside}
|
||||
customizationIdPrefix={tableCustomizationIdPrefix}
|
||||
/>
|
||||
)}
|
||||
</ContentCard>
|
||||
</BaseTemplate>
|
||||
)
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
import React, { FC } from 'react'
|
||||
import { ContentCard } from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { useParams } from 'react-router-dom'
|
||||
import { useSelector } from 'react-redux'
|
||||
import type { RootState } from 'store/store'
|
||||
import { TableCrdInfo, BackLink, ManageableBreadcrumbs, ManageableSidebar, NavigationContainer } from 'components'
|
||||
import { getSidebarIdPrefix } from 'utils/getSidebarIdPrefix'
|
||||
import { getBreadcrumbsIdPrefix } from 'utils/getBreadcrumbsIdPrefix'
|
||||
import { getTableCustomizationIdPrefix } from 'utils/getTableCustomizationIdPrefix'
|
||||
import { getTablesBackLink } from 'utils/getBacklink'
|
||||
import { BaseTemplate } from 'templates'
|
||||
import { BASE_USE_NAMESPACE_NAV } from 'constants/customizationApiGroupAndVersion'
|
||||
|
||||
type TTableCrdPageProps = {
|
||||
inside?: boolean
|
||||
}
|
||||
|
||||
export const TableCrdPage: FC<TTableCrdPageProps> = ({ inside }) => {
|
||||
const { clusterName, namespace, syntheticProject, apiGroup, apiVersion, apiExtensionVersion, crdName } = useParams()
|
||||
const baseprefix = useSelector((state: RootState) => state.baseprefix.baseprefix)
|
||||
|
||||
const possibleProject = syntheticProject && namespace ? syntheticProject : namespace
|
||||
const possibleInstance = syntheticProject && namespace ? namespace : undefined
|
||||
|
||||
const backlink = getTablesBackLink({
|
||||
clusterName,
|
||||
possibleProject,
|
||||
possibleInstance,
|
||||
namespace,
|
||||
baseprefix,
|
||||
inside,
|
||||
namespacesMode: BASE_USE_NAMESPACE_NAV === 'true',
|
||||
})
|
||||
|
||||
const sidebarId = `${getSidebarIdPrefix({ instance: !!syntheticProject, project: !!namespace, inside })}crd-table`
|
||||
const breadcrumbsId = `${getBreadcrumbsIdPrefix({
|
||||
instance: !!syntheticProject,
|
||||
project: !!namespace,
|
||||
inside,
|
||||
})}crd-table`
|
||||
const tableCustomizationIdPrefix = getTableCustomizationIdPrefix({
|
||||
instance: !!syntheticProject,
|
||||
project: BASE_USE_NAMESPACE_NAV !== 'true' && !!namespace,
|
||||
namespace: !!namespace,
|
||||
inside,
|
||||
})
|
||||
|
||||
return (
|
||||
<BaseTemplate
|
||||
inside={inside}
|
||||
sidebar={
|
||||
<ManageableSidebar
|
||||
instanceName={possibleInstance}
|
||||
projectName={possibleProject}
|
||||
idToCompare={sidebarId}
|
||||
currentTags={[`${apiGroup}/${apiVersion}/${crdName}`]}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<NavigationContainer>
|
||||
<ManageableBreadcrumbs idToCompare={breadcrumbsId} inside={inside} />
|
||||
<BackLink to={backlink} title={`${apiGroup}/${apiVersion}/${crdName}`} />
|
||||
</NavigationContainer>
|
||||
<ContentCard flexGrow={1} displayFlex flexFlow="column">
|
||||
{crdName && apiGroup && apiVersion && apiExtensionVersion && (
|
||||
<TableCrdInfo
|
||||
namespace={namespace}
|
||||
apiGroup={apiGroup}
|
||||
apiVersion={apiVersion}
|
||||
crdName={crdName}
|
||||
apiExtensionVersion={apiExtensionVersion}
|
||||
inside={inside}
|
||||
customizationIdPrefix={tableCustomizationIdPrefix}
|
||||
/>
|
||||
)}
|
||||
</ContentCard>
|
||||
</BaseTemplate>
|
||||
)
|
||||
}
|
||||
103
src/pages/Tables/TableApiPage/TableApiPage.tsx
Normal file
103
src/pages/Tables/TableApiPage/TableApiPage.tsx
Normal file
@@ -0,0 +1,103 @@
|
||||
import React, { FC, useEffect } from 'react'
|
||||
import { ContentCard } from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { useParams, useSearchParams, useOutletContext } from 'react-router-dom'
|
||||
import { useSelector } from 'react-redux'
|
||||
import type { RootState } from 'store/store'
|
||||
import { TableApiBuiltin } from 'components'
|
||||
import { getTableCustomizationIdPrefix } from 'utils/getTableCustomizationIdPrefix'
|
||||
import { getTablesBackLink } from 'utils/getBacklink'
|
||||
import { TChromeCtx } from 'templates'
|
||||
import {
|
||||
BASE_USE_NAMESPACE_NAV,
|
||||
BASE_PROJECTS_API_GROUP,
|
||||
BASE_PROJECTS_API_VERSION,
|
||||
BASE_PROJECTS_PLURAL,
|
||||
} from 'constants/customizationApiGroupAndVersion'
|
||||
|
||||
type TTableApiPageProps = {
|
||||
inside?: boolean
|
||||
}
|
||||
|
||||
export const TableApiPage: FC<TTableApiPageProps> = ({ inside }) => {
|
||||
const { cluster, namespace, syntheticProject, apiGroup, apiVersion, plural } = useParams()
|
||||
const [searchParams] = useSearchParams()
|
||||
const baseprefix = useSelector((state: RootState) => state.baseprefix.baseprefix)
|
||||
|
||||
const isProjectList =
|
||||
!namespace &&
|
||||
apiGroup === BASE_PROJECTS_API_GROUP &&
|
||||
apiVersion === BASE_PROJECTS_API_VERSION &&
|
||||
plural === BASE_PROJECTS_PLURAL
|
||||
const breadcrumbsIdProjectList = 'projects-list'
|
||||
|
||||
const possibleProject = syntheticProject && namespace ? syntheticProject : namespace
|
||||
const possibleInstance = syntheticProject && namespace ? namespace : undefined
|
||||
|
||||
const preparedBacklink = getTablesBackLink({
|
||||
cluster,
|
||||
possibleProject,
|
||||
possibleInstance,
|
||||
namespace,
|
||||
baseprefix,
|
||||
inside,
|
||||
namespacesMode: BASE_USE_NAMESPACE_NAV === 'true',
|
||||
})
|
||||
|
||||
const { setCurrentTags, setSidebarSuffix, setBreadcrumbsSuffix, setBacklinkTo, setBacklinkTitle } =
|
||||
useOutletContext<TChromeCtx>()
|
||||
|
||||
useEffect(() => {
|
||||
setSidebarSuffix('builtin-table')
|
||||
setBreadcrumbsSuffix(isProjectList ? breadcrumbsIdProjectList : 'api-table')
|
||||
setCurrentTags([`${plural}`])
|
||||
setBacklinkTo(preparedBacklink)
|
||||
setBacklinkTitle(undefined)
|
||||
|
||||
return () => {
|
||||
setCurrentTags(undefined)
|
||||
setSidebarSuffix(undefined)
|
||||
setBreadcrumbsSuffix(undefined)
|
||||
setBacklinkTo(undefined)
|
||||
setBacklinkTitle(`${apiGroup}/${apiVersion}/${plural}`)
|
||||
}
|
||||
}, [
|
||||
plural,
|
||||
isProjectList,
|
||||
breadcrumbsIdProjectList,
|
||||
preparedBacklink,
|
||||
apiGroup,
|
||||
apiVersion,
|
||||
setSidebarSuffix,
|
||||
setBreadcrumbsSuffix,
|
||||
setCurrentTags,
|
||||
setBacklinkTo,
|
||||
setBacklinkTitle,
|
||||
])
|
||||
|
||||
const tableCustomizationIdPrefix = getTableCustomizationIdPrefix({
|
||||
instance: !!syntheticProject,
|
||||
project: BASE_USE_NAMESPACE_NAV !== 'true' && !!namespace,
|
||||
namespace: !!namespace,
|
||||
inside,
|
||||
})
|
||||
|
||||
const limitSp = searchParams.get('limit')
|
||||
|
||||
return (
|
||||
<ContentCard flexGrow={1} displayFlex flexFlow="column">
|
||||
{plural && apiGroup && apiVersion && (
|
||||
<TableApiBuiltin
|
||||
resourceType="api"
|
||||
namespace={namespace}
|
||||
apiGroup={apiGroup}
|
||||
apiVersion={apiVersion}
|
||||
plural={plural}
|
||||
key={`${apiGroup}-${apiVersion}-${namespace}-${plural}`}
|
||||
limit={limitSp && limitSp.length > 0 ? Number(limitSp) : undefined}
|
||||
inside={inside}
|
||||
customizationIdPrefix={tableCustomizationIdPrefix}
|
||||
/>
|
||||
)}
|
||||
</ContentCard>
|
||||
)
|
||||
}
|
||||
86
src/pages/Tables/TableBuiltinPage/TableBuiltinPage.tsx
Normal file
86
src/pages/Tables/TableBuiltinPage/TableBuiltinPage.tsx
Normal file
@@ -0,0 +1,86 @@
|
||||
import React, { FC, useEffect } from 'react'
|
||||
import { ContentCard } from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { useParams, useSearchParams, useOutletContext } from 'react-router-dom'
|
||||
import { useSelector } from 'react-redux'
|
||||
import type { RootState } from 'store/store'
|
||||
import { TableApiBuiltin } from 'components'
|
||||
import { getTableCustomizationIdPrefix } from 'utils/getTableCustomizationIdPrefix'
|
||||
import { getTablesBackLink } from 'utils/getBacklink'
|
||||
import { TChromeCtx } from 'templates'
|
||||
import { BASE_USE_NAMESPACE_NAV } from 'constants/customizationApiGroupAndVersion'
|
||||
|
||||
type TTableBuiltinPageProps = {
|
||||
inside?: boolean
|
||||
}
|
||||
|
||||
export const TableBuiltinPage: FC<TTableBuiltinPageProps> = ({ inside }) => {
|
||||
const { cluster, namespace, syntheticProject, plural } = useParams()
|
||||
const [searchParams] = useSearchParams()
|
||||
const baseprefix = useSelector((state: RootState) => state.baseprefix.baseprefix)
|
||||
|
||||
const possibleProject = syntheticProject && namespace ? syntheticProject : namespace
|
||||
const possibleInstance = syntheticProject && namespace ? namespace : undefined
|
||||
|
||||
const preparedBacklink = getTablesBackLink({
|
||||
cluster,
|
||||
possibleProject,
|
||||
possibleInstance,
|
||||
namespace,
|
||||
baseprefix,
|
||||
inside,
|
||||
namespacesMode: BASE_USE_NAMESPACE_NAV === 'true',
|
||||
})
|
||||
|
||||
const { setCurrentTags, setSidebarSuffix, setBreadcrumbsSuffix, setBacklinkTo, setBacklinkTitle } =
|
||||
useOutletContext<TChromeCtx>()
|
||||
|
||||
useEffect(() => {
|
||||
setSidebarSuffix('builtin-table')
|
||||
setBreadcrumbsSuffix('builtin-table')
|
||||
setCurrentTags([`${plural}`])
|
||||
setBacklinkTo(preparedBacklink)
|
||||
setBacklinkTitle(plural)
|
||||
|
||||
return () => {
|
||||
setCurrentTags(undefined)
|
||||
setSidebarSuffix(undefined)
|
||||
setBreadcrumbsSuffix(undefined)
|
||||
setBacklinkTo(undefined)
|
||||
setBacklinkTitle(undefined)
|
||||
}
|
||||
}, [
|
||||
plural,
|
||||
preparedBacklink,
|
||||
setSidebarSuffix,
|
||||
setBreadcrumbsSuffix,
|
||||
setCurrentTags,
|
||||
setBacklinkTo,
|
||||
setBacklinkTitle,
|
||||
])
|
||||
|
||||
const tableCustomizationIdPrefix = getTableCustomizationIdPrefix({
|
||||
instance: !!syntheticProject,
|
||||
project: BASE_USE_NAMESPACE_NAV !== 'true' && !!namespace,
|
||||
namespace: !!namespace,
|
||||
inside,
|
||||
})
|
||||
|
||||
const limitSp = searchParams.get('limit')
|
||||
|
||||
return (
|
||||
<ContentCard flexGrow={1} displayFlex flexFlow="column">
|
||||
{plural && (
|
||||
<TableApiBuiltin
|
||||
resourceType="builtin"
|
||||
apiVersion="v1"
|
||||
key={`${namespace}-${plural}`}
|
||||
namespace={namespace}
|
||||
plural={plural}
|
||||
limit={limitSp && limitSp.length > 0 ? Number(limitSp) : undefined}
|
||||
inside={inside}
|
||||
customizationIdPrefix={tableCustomizationIdPrefix}
|
||||
/>
|
||||
)}
|
||||
</ContentCard>
|
||||
)
|
||||
}
|
||||
84
src/pages/Tables/TableCrdPage/TableCrdPage.tsx
Normal file
84
src/pages/Tables/TableCrdPage/TableCrdPage.tsx
Normal file
@@ -0,0 +1,84 @@
|
||||
import React, { FC, useEffect } from 'react'
|
||||
import { ContentCard } from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { useParams, useOutletContext } from 'react-router-dom'
|
||||
import { useSelector } from 'react-redux'
|
||||
import type { RootState } from 'store/store'
|
||||
import { TableCrdInfo } from 'components'
|
||||
import { getTableCustomizationIdPrefix } from 'utils/getTableCustomizationIdPrefix'
|
||||
import { getTablesBackLink } from 'utils/getBacklink'
|
||||
import { TChromeCtx } from 'templates'
|
||||
import { BASE_USE_NAMESPACE_NAV } from 'constants/customizationApiGroupAndVersion'
|
||||
|
||||
type TTableCrdPageProps = {
|
||||
inside?: boolean
|
||||
}
|
||||
|
||||
export const TableCrdPage: FC<TTableCrdPageProps> = ({ inside }) => {
|
||||
const { cluster, namespace, syntheticProject, apiGroup, apiVersion, apiExtensionVersion, crdName } = useParams()
|
||||
const baseprefix = useSelector((state: RootState) => state.baseprefix.baseprefix)
|
||||
|
||||
const possibleProject = syntheticProject && namespace ? syntheticProject : namespace
|
||||
const possibleInstance = syntheticProject && namespace ? namespace : undefined
|
||||
|
||||
const preparedBacklink = getTablesBackLink({
|
||||
cluster,
|
||||
possibleProject,
|
||||
possibleInstance,
|
||||
namespace,
|
||||
baseprefix,
|
||||
inside,
|
||||
namespacesMode: BASE_USE_NAMESPACE_NAV === 'true',
|
||||
})
|
||||
|
||||
const { setCurrentTags, setSidebarSuffix, setBreadcrumbsSuffix, setBacklinkTo, setBacklinkTitle } =
|
||||
useOutletContext<TChromeCtx>()
|
||||
|
||||
useEffect(() => {
|
||||
setSidebarSuffix('crd-table')
|
||||
setBreadcrumbsSuffix('crd-table')
|
||||
setCurrentTags([`${apiGroup}/${apiVersion}/${crdName}`])
|
||||
setBacklinkTo(preparedBacklink)
|
||||
setBacklinkTitle(`${apiGroup}/${apiVersion}/${crdName}`)
|
||||
|
||||
return () => {
|
||||
setCurrentTags(undefined)
|
||||
setSidebarSuffix(undefined)
|
||||
setBreadcrumbsSuffix(undefined)
|
||||
setBacklinkTo(undefined)
|
||||
setBacklinkTitle(undefined)
|
||||
}
|
||||
}, [
|
||||
apiGroup,
|
||||
apiVersion,
|
||||
crdName,
|
||||
preparedBacklink,
|
||||
setSidebarSuffix,
|
||||
setBreadcrumbsSuffix,
|
||||
setCurrentTags,
|
||||
setBacklinkTo,
|
||||
setBacklinkTitle,
|
||||
])
|
||||
|
||||
const tableCustomizationIdPrefix = getTableCustomizationIdPrefix({
|
||||
instance: !!syntheticProject,
|
||||
project: BASE_USE_NAMESPACE_NAV !== 'true' && !!namespace,
|
||||
namespace: !!namespace,
|
||||
inside,
|
||||
})
|
||||
|
||||
return (
|
||||
<ContentCard flexGrow={1} displayFlex flexFlow="column">
|
||||
{crdName && apiGroup && apiVersion && apiExtensionVersion && (
|
||||
<TableCrdInfo
|
||||
namespace={namespace}
|
||||
apiGroup={apiGroup}
|
||||
apiVersion={apiVersion}
|
||||
crdName={crdName}
|
||||
apiExtensionVersion={apiExtensionVersion}
|
||||
inside={inside}
|
||||
customizationIdPrefix={tableCustomizationIdPrefix}
|
||||
/>
|
||||
)}
|
||||
</ContentCard>
|
||||
)
|
||||
}
|
||||
2
src/pages/Tables/index.ts
Normal file
2
src/pages/Tables/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export { TableApiPage } from './TableApiPage'
|
||||
export { TableBuiltinPage } from './TableBuiltinPage'
|
||||
@@ -1,21 +1,29 @@
|
||||
export { MainPage } from './MainPage'
|
||||
/* main routing */
|
||||
export { MainPage } from './MainPage'
|
||||
export { ListClustersPage } from './ListClustersPage'
|
||||
export { ListProjectsPage } from './ListProjectsPage'
|
||||
export { ProjectInfoPage } from './ProjectInfoPage'
|
||||
/* inside routing */
|
||||
export { ListInsideClustersAndNsPage } from './ListInsideClustersAndNsPage'
|
||||
export { ListInsideApiPage } from './ListInsideApiPage'
|
||||
export { ListInsideCrdByApiGroupPage } from './ListInsideCrdByApiGroupPage'
|
||||
export { ListInsideApiByApiGroupPage } from './ListInsideApiByApiGroupPage'
|
||||
/* common routing */
|
||||
export { TableCrdPage } from './TableCrdPage'
|
||||
export { TableApiPage } from './TableApiPage'
|
||||
export { TableBuiltinPage } from './TableBuiltinPage'
|
||||
export { FormCrdPage } from './FormCrdPage'
|
||||
export { FormApiPage } from './FormApiPage'
|
||||
export { FormBuiltinPage } from './FormBuiltinPage'
|
||||
/* tables */
|
||||
export {
|
||||
// TableCrdPage,
|
||||
TableApiPage,
|
||||
TableBuiltinPage,
|
||||
} from './Tables'
|
||||
/* forms */
|
||||
export {
|
||||
// FormCrdPage,
|
||||
FormApiPage,
|
||||
FormBuiltinPage,
|
||||
} from './Forms'
|
||||
/* factory */
|
||||
export { FactoryPage } from './FactoryPage'
|
||||
export { FactoryAdminPage } from './FactoryAdminPage'
|
||||
/* search */
|
||||
export { SearchPage } from './SearchPage'
|
||||
/* inside routing */
|
||||
export {
|
||||
ListInsideClustersAndNsPage,
|
||||
ListInsideApiPage,
|
||||
ListInsideCrdByApiGroupPage,
|
||||
ListInsideApiByApiGroupPage,
|
||||
} from './Insides'
|
||||
/* redirects */
|
||||
export { RedirectProjectsPage } from './RedirectProjectsPage'
|
||||
export { RedirectProjectInfoPage } from './RedirectProjectInfoPage'
|
||||
|
||||
@@ -21,5 +21,3 @@ export const themeSlice = createSlice({
|
||||
})
|
||||
|
||||
export const { setTheme } = themeSlice.actions
|
||||
|
||||
// export default themeSlice
|
||||
|
||||
97
src/templates/AppShell/AppShell.tsx
Normal file
97
src/templates/AppShell/AppShell.tsx
Normal file
@@ -0,0 +1,97 @@
|
||||
import React, { FC, useState, useMemo } from 'react'
|
||||
import { Outlet, useParams } from 'react-router-dom'
|
||||
import { BaseTemplate } from 'templates'
|
||||
import { ManageableSidebar, NavigationContainer, ManageableBreadcrumbs, BackLink } from 'components'
|
||||
import { getSidebarIdPrefix } from 'utils/getSidebarIdPrefix'
|
||||
import { getBreadcrumbsIdPrefix } from 'utils/getBreadcrumbsIdPrefix'
|
||||
|
||||
export type TChromeCtx = {
|
||||
setCurrentTags: (tags?: string[]) => void
|
||||
setSidebarSuffix: (suffix?: string) => void
|
||||
setBreadcrumbsSuffix: (suffix?: string) => void
|
||||
setBacklinkTo: (backlinkTo?: string) => void
|
||||
setBacklinkTitle: (backlinkTitle?: string) => void
|
||||
setUseOnlyNamespace: (flag: boolean) => void
|
||||
setBaseTemplateSearchBoolean: (flag: boolean) => void
|
||||
}
|
||||
|
||||
export const AppShell: FC<{ inside?: boolean }> = ({ inside }) => {
|
||||
const { namespace, syntheticProject } = useParams()
|
||||
|
||||
const possibleProject = syntheticProject && namespace ? syntheticProject : namespace
|
||||
const possibleInstance = syntheticProject && namespace ? namespace : undefined
|
||||
|
||||
const [currentTags, setCurrentTagsState] = useState<string[] | undefined>()
|
||||
const [sidebarSuffix, setSidebarSuffix] = useState<string | undefined>()
|
||||
const [breadcrumbsSuffix, setBreadcrumbsSuffix] = useState<string | undefined>()
|
||||
const [backlinkTo, setBacklinkTo] = useState<string | undefined>()
|
||||
const [backlinkTitle, setBacklinkTitle] = useState<string | undefined>()
|
||||
const [useOnlyNamespace, setUseOnlyNamespace] = useState<boolean>(false)
|
||||
const [baseTemplateSearchBoolean, setBaseTemplateSearchBoolean] = useState<boolean>(false)
|
||||
|
||||
// Commit tags only on actual content change to avoid sidebar refetch
|
||||
const setCurrentTags = React.useCallback((next?: string[]) => {
|
||||
setCurrentTagsState(prev => {
|
||||
// eslint-disable-next-line one-var
|
||||
const a = prev ?? [],
|
||||
b = next ?? []
|
||||
if (a.length === b.length && a.every((v, i) => v === b[i])) return prev
|
||||
return next
|
||||
})
|
||||
}, [])
|
||||
|
||||
const sidebarId = useMemo(
|
||||
() =>
|
||||
`${getSidebarIdPrefix({ instance: !!syntheticProject, project: !!namespace, useOnlyNamespace, inside })}${
|
||||
sidebarSuffix ?? 'app-shell'
|
||||
}`,
|
||||
[syntheticProject, namespace, sidebarSuffix, useOnlyNamespace, inside],
|
||||
)
|
||||
|
||||
const breadcrumbsId = useMemo(
|
||||
() =>
|
||||
`${getBreadcrumbsIdPrefix({
|
||||
namespace: !!namespace,
|
||||
instance: !!syntheticProject,
|
||||
project: !!namespace,
|
||||
useOnlyNamespace,
|
||||
inside,
|
||||
})}${breadcrumbsSuffix ?? 'app-shell'}`,
|
||||
[syntheticProject, namespace, breadcrumbsSuffix, useOnlyNamespace, inside],
|
||||
)
|
||||
|
||||
const sidebarEl = React.useMemo(
|
||||
() => (
|
||||
<ManageableSidebar
|
||||
instanceName={possibleInstance}
|
||||
projectName={possibleProject}
|
||||
idToCompare={sidebarId}
|
||||
currentTags={currentTags}
|
||||
/>
|
||||
),
|
||||
[possibleInstance, possibleProject, sidebarId, currentTags],
|
||||
)
|
||||
|
||||
const ctx = useMemo<TChromeCtx>(
|
||||
() => ({
|
||||
setCurrentTags,
|
||||
setSidebarSuffix,
|
||||
setBreadcrumbsSuffix,
|
||||
setBacklinkTo,
|
||||
setBacklinkTitle,
|
||||
setUseOnlyNamespace,
|
||||
setBaseTemplateSearchBoolean,
|
||||
}),
|
||||
[setCurrentTags],
|
||||
)
|
||||
|
||||
return (
|
||||
<BaseTemplate inside={inside} sidebar={sidebarEl} isSearch={baseTemplateSearchBoolean}>
|
||||
<NavigationContainer>
|
||||
<ManageableBreadcrumbs idToCompare={breadcrumbsId} inside={inside} />
|
||||
{backlinkTo && backlinkTitle && <BackLink to={backlinkTo} title={backlinkTitle} />}
|
||||
</NavigationContainer>
|
||||
<Outlet context={ctx} />
|
||||
</BaseTemplate>
|
||||
)
|
||||
}
|
||||
2
src/templates/AppShell/index.ts
Normal file
2
src/templates/AppShell/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export { AppShell } from './AppShell'
|
||||
export type { TChromeCtx } from './AppShell'
|
||||
@@ -5,7 +5,6 @@ import type { RootState } from 'store/store'
|
||||
import { DefaultLayout, HeaderSecond, Footer, Sidebar, RowFlexGrow, FlexCol } from 'components'
|
||||
|
||||
type TBaseTemplateProps = {
|
||||
// withNoCluster?: boolean
|
||||
children?: ReactNode | undefined
|
||||
inside?: boolean
|
||||
isSearch?: boolean
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user