diff --git a/.env b/.env
index 4bed8ba..d2345d9 100644
--- a/.env
+++ b/.env
@@ -1,3 +1,9 @@
+VITE_TITLE_TEXT="OpenAPI UI"
+VITE_LOGO_TEXT="In-Cloud"
+VITE_FOOTER_TEXT="PRO Robotech"
+VITE_CUSTOM_LOGO_SVG=
+VITE_CUSTOM_TENANT_TEXT=
+
VITE_CUSTOMIZATION_API_GROUP=incloud.io
VITE_CUSTOMIZATION_API_VERSION=v1alpha
@@ -39,3 +45,7 @@ VITE_BASE_FACTORY_CLUSTERSCOPED_API_KEY=base-factory-clusterscoped-api
VITE_BASE_FACTORY_NAMESPACED_BUILTIN_KEY=base-factory-namespaced-builtin
VITE_BASE_FACTORY_CLUSTERSCOPED_BUILTIN_KEY=base-factory-clusterscoped-builtin
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=
diff --git a/.env.options.dist b/.env.options.dist
index 4efefbc..504093f 100644
--- a/.env.options.dist
+++ b/.env.options.dist
@@ -1,3 +1,9 @@
+TITLE_TEXT=
+LOGO_TEXT=
+FOOTER_TEXT=
+CUSTOM_LOGO_SVG=
+CUSTOM_TENANT_TEXT=
+
KUBE_API_URL=
CUSTOMIZATION_API_GROUP=
@@ -41,3 +47,7 @@ BASE_FACTORY_CLUSTERSCOPED_API_KEY=
BASE_FACTORY_NAMESPACED_BUILTIN_KEY=
BASE_FACTORY_CLUSTERSCOPED_BUILTIN_KEY=
BASE_NAMESPACE_FACTORY_KEY=
+
+CUSTOM_NAMESPACE_API_RESOURCE_API_GROUP=
+CUSTOM_NAMESPACE_API_RESOURCE_API_VERSION=
+CUSTOM_NAMESPACE_API_RESOURCE_RESOURCE_NAME=
diff --git a/README.md b/README.md
index e9e09cd..7c73b3f 100644
--- a/README.md
+++ b/README.md
@@ -9,30 +9,43 @@ 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 |
-| `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` |
-| `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 |
+| 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 |
+| `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` |
+| `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 |
diff --git a/package-lock.json b/package-lock.json
index 9871879..5502083 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -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": "^0.0.1-alpha.154",
+ "@prorobotech/openapi-k8s-toolkit": "^0.0.1-alpha.156",
"@readme/openapi-parser": "4.0.0",
"@reduxjs/toolkit": "2.2.5",
"@tanstack/react-query": "5.62.2",
@@ -2804,9 +2804,9 @@
}
},
"node_modules/@prorobotech/openapi-k8s-toolkit": {
- "version": "0.0.1-alpha.154",
- "resolved": "https://registry.npmjs.org/@prorobotech/openapi-k8s-toolkit/-/openapi-k8s-toolkit-0.0.1-alpha.154.tgz",
- "integrity": "sha512-m/xi/HWTiDj8nNRoym0GQpMbxtIdoq32/z/r7lYGrYxQmq15VvF5FhRbB2utY1J1tK6WnzMqXnFOM0J19qJ/Ag==",
+ "version": "0.0.1-alpha.156",
+ "resolved": "https://registry.npmjs.org/@prorobotech/openapi-k8s-toolkit/-/openapi-k8s-toolkit-0.0.1-alpha.156.tgz",
+ "integrity": "sha512-uMKzfdcEAbzKAFPWNIjcQMUtjhLmuUETs+1p+4K752HLB+31t9W1Fl5GOiySbpIWhoM7R9Y1mw5efe7/f04aRQ==",
"license": "MIT",
"dependencies": {
"@monaco-editor/react": "4.6.0",
diff --git a/package.json b/package.json
index 2fb9303..6ec3b44 100644
--- a/package.json
+++ b/package.json
@@ -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": "0.0.1-alpha.154",
+ "@prorobotech/openapi-k8s-toolkit": "0.0.1-alpha.156",
"@readme/openapi-parser": "4.0.0",
"@reduxjs/toolkit": "2.2.5",
"@tanstack/react-query": "5.62.2",
diff --git a/server/getDynamicIndex.ts b/server/getDynamicIndex.ts
index 3be5d00..eee0311 100644
--- a/server/getDynamicIndex.ts
+++ b/server/getDynamicIndex.ts
@@ -2,6 +2,23 @@ export const getDynamicIndex = (baseprefix: string): string => {
try {
const mainJs = 'index-react.js'
const mainCss = 'style.css'
+ const titleText = process.env.TITLE_TEXT || 'OpenAPI UI'
+ const iconSvg = process.env.ICON_SVG || ''
+
+ // Generate favicon from SVG if provided
+ const generateFavicon = (): string => {
+ if (!iconSvg) {
+ return ''
+ }
+ try {
+ const decodedSvg = Buffer.from(iconSvg, 'base64').toString('utf-8')
+ const dataUri = `data:image/svg+xml;base64,${decodedSvg}`
+ return ``
+ } catch (error) {
+ console.error('Error processing icon SVG:', error)
+ return ''
+ }
+ }
return `
@@ -14,7 +31,8 @@ export const getDynamicIndex = (baseprefix: string): string => {
href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,700;0,900;1,100;1,300;1,400;1,700;1,900&display=swap"
rel="stylesheet"
/>
- OpenAPI UI
+ ${titleText}
+ ${generateFavicon()}
diff --git a/server/index.ts b/server/index.ts
index d1bf62f..cb69d3d 100644
--- a/server/index.ts
+++ b/server/index.ts
@@ -18,6 +18,12 @@ if (process.env.LOCAL === 'true') {
const KUBE_API_URL = process.env.LOCAL === 'true' ? options?.KUBE_API_URL : process.env.KUBE_API_URL
+const TITLE_TEXT = process.env.LOCAL === 'true' ? options?.TITLE_TEXT : process.env.TITLE_TEXT
+const LOGO_TEXT = process.env.LOCAL === 'true' ? options?.LOGO_TEXT : process.env.LOGO_TEXT
+const FOOTER_TEXT = process.env.LOCAL === 'true' ? options?.FOOTER_TEXT : process.env.FOOTER_TEXT
+const CUSTOM_LOGO_SVG = process.env.LOCAL === 'true' ? options?.CUSTOM_LOGO_SVG : process.env.CUSTOM_LOGO_SVG
+const CUSTOM_TENANT_TEXT = process.env.LOCAL === 'true' ? options?.CUSTOM_TENANT_TEXT : process.env.CUSTOM_TENANT_TEXT
+
const CUSTOMIZATION_API_GROUP =
process.env.LOCAL === 'true' ? options?.CUSTOMIZATION_API_GROUP : process.env.CUSTOMIZATION_API_GROUP
const CUSTOMIZATION_API_VERSION =
@@ -90,6 +96,19 @@ const BASE_FACTORY_CLUSTERSCOPED_BUILTIN_KEY =
const BASE_NAMESPACE_FACTORY_KEY =
process.env.LOCAL === 'true' ? options?.BASE_NAMESPACE_FACTORY_KEY : process.env.BASE_NAMESPACE_FACTORY_KEY
+const CUSTOM_NAMESPACE_API_RESOURCE_API_GROUP =
+ process.env.LOCAL === 'true'
+ ? options?.CUSTOM_NAMESPACE_API_RESOURCE_API_GROUP
+ : process.env.CUSTOM_NAMESPACE_API_RESOURCE_API_GROUP
+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 =
+ process.env.LOCAL === 'true'
+ ? options?.CUSTOM_NAMESPACE_API_RESOURCE_RESOURCE_NAME
+ : process.env.CUSTOM_NAMESPACE_API_RESOURCE_RESOURCE_NAME
+
const healthcheck = require('express-healthcheck')
const promBundle = require('express-prom-bundle')
@@ -193,11 +212,31 @@ app.get(`${basePrefix ? basePrefix : ''}/env.js`, (_, res) => {
`
window._env_ = {
${basePrefix ? ` BASEPREFIX: "${basePrefix}",` : ''}
+ TITLE_TEXT: ${JSON.stringify(TITLE_TEXT) || '"check envs"'},
+ LOGO_TEXT: ${JSON.stringify(LOGO_TEXT) || '"check envs"'},
+ FOOTER_TEXT: ${JSON.stringify(FOOTER_TEXT) || '"check envs"'},
+ ${CUSTOM_LOGO_SVG ? ` CUSTOM_LOGO_SVG: "${CUSTOM_LOGO_SVG}",` : ''}
+ ${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_NAME: ${
JSON.stringify(CUSTOMIZATION_NAVIGATION_RESOURCE_NAME) || '"check envs"'
},
+ ${
+ CUSTOM_NAMESPACE_API_RESOURCE_API_GROUP
+ ? ` CUSTOM_NAMESPACE_API_RESOURCE_API_GROUP: "${CUSTOM_NAMESPACE_API_RESOURCE_API_GROUP}",`
+ : ''
+ }
+ ${
+ CUSTOM_NAMESPACE_API_RESOURCE_API_VERSION
+ ? ` CUSTOM_NAMESPACE_API_RESOURCE_API_VERSION: "${CUSTOM_NAMESPACE_API_RESOURCE_API_VERSION}",`
+ : ''
+ }
+ ${
+ CUSTOM_NAMESPACE_API_RESOURCE_RESOURCE_NAME
+ ? ` CUSTOM_NAMESPACE_API_RESOURCE_RESOURCE_NAME: "${CUSTOM_NAMESPACE_API_RESOURCE_RESOURCE_NAME}",`
+ : ''
+ }
CUSTOMIZATION_NAVIGATION_RESOURCE: ${JSON.stringify(CUSTOMIZATION_NAVIGATION_RESOURCE) || '"check envs"'},
USE_NAMESPACE_NAV: ${USE_NAMESPACE_NAV ? JSON.stringify(USE_NAMESPACE_NAV).toLowerCase() : '"false"'},
NAVIGATE_FROM_CLUSTERLIST: ${JSON.stringify(NAVIGATE_FROM_CLUSTERLIST) || '"check envs"'},
diff --git a/src/components/molecules/ManageableSidebar/styled.ts b/src/components/molecules/ManageableSidebar/styled.ts
index 7297439..4c811f5 100644
--- a/src/components/molecules/ManageableSidebar/styled.ts
+++ b/src/components/molecules/ManageableSidebar/styled.ts
@@ -18,6 +18,7 @@ const Container = styled.div`
direction: rtl;
max-height: ${({ $maxHeight }) => $maxHeight || 'initial'};
user-select: none;
+ border-top-right-radius: 12px;
& ul {
direction: ltr;
diff --git a/src/components/organisms/Footer/Footer.tsx b/src/components/organisms/Footer/Footer.tsx
index c302c01..f36d824 100644
--- a/src/components/organisms/Footer/Footer.tsx
+++ b/src/components/organisms/Footer/Footer.tsx
@@ -1,11 +1,14 @@
import React, { FC } from 'react'
import { Typography } from 'antd'
+import { FOOTER_TEXT } from 'constants/customizationApiGroupAndVersion'
import { Styled } from './styled'
export const Footer: FC = () => {
return (
- PRO Robotech © {new Date().getFullYear()}
+
+ {FOOTER_TEXT} © {new Date().getFullYear()}
+
)
}
diff --git a/src/components/organisms/Header/organisms/Logo/Logo.tsx b/src/components/organisms/Header/organisms/Logo/Logo.tsx
index 7823147..1adf2a0 100644
--- a/src/components/organisms/Header/organisms/Logo/Logo.tsx
+++ b/src/components/organisms/Header/organisms/Logo/Logo.tsx
@@ -3,6 +3,8 @@ import { Flex, theme as antdtheme } from 'antd'
import { useNavigate } from 'react-router-dom'
import { useSelector } from 'react-redux'
import { RootState } from 'store/store'
+import { LOGO_TEXT, CUSTOM_LOGO_SVG, CUSTOM_TENANT_TEXT } from 'constants/customizationApiGroupAndVersion'
+import { renderLogo } from './utils'
import { Styled } from './styled'
export const Logo: FC = () => {
@@ -17,14 +19,23 @@ export const Logo: FC = () => {
return (
-
- navigate(`${baseprefix}`)}>In-Cloud
- {tenant}
+ {CUSTOM_LOGO_SVG && typeof CUSTOM_LOGO_SVG === 'string' && CUSTOM_LOGO_SVG.length > 0 ? (
+ renderLogo(CUSTOM_LOGO_SVG, token.colorText)
+ ) : (
+
+ )}
+
+ navigate(`${baseprefix}`)}>{LOGO_TEXT}
+
+ {CUSTOM_TENANT_TEXT && typeof CUSTOM_TENANT_TEXT === 'string' && CUSTOM_TENANT_TEXT.length > 0
+ ? CUSTOM_TENANT_TEXT
+ : tenant}
+
)
diff --git a/src/components/organisms/Header/organisms/Logo/utils.tsx b/src/components/organisms/Header/organisms/Logo/utils.tsx
new file mode 100644
index 0000000..1d04d21
--- /dev/null
+++ b/src/components/organisms/Header/organisms/Logo/utils.tsx
@@ -0,0 +1,17 @@
+export const renderLogo = (customLogo: string, colorText: string): JSX.Element | null => {
+ if (customLogo) {
+ // Decode base64 SVG and replace all fill placeholders
+ try {
+ const decodedSvg = atob(customLogo)
+ // Replace all instances of {token.colorText} with actual color
+ const svgWithFill = decodedSvg.replace(/\{token\.colorText\}/g, `"${colorText}"`)
+ // eslint-disable-next-line react/no-danger
+ return
+ } catch (error) {
+ // eslint-disable-next-line no-console
+ console.error('Error decoding custom logo:', error)
+ return null
+ }
+ }
+ return null
+}
diff --git a/src/components/organisms/ListInsideClusterAndNs/ListInsideClusterAndNs.tsx b/src/components/organisms/ListInsideClusterAndNs/ListInsideClusterAndNs.tsx
index b6fb99f..ac56e5f 100644
--- a/src/components/organisms/ListInsideClusterAndNs/ListInsideClusterAndNs.tsx
+++ b/src/components/organisms/ListInsideClusterAndNs/ListInsideClusterAndNs.tsx
@@ -1,10 +1,15 @@
import React, { FC, useState } from 'react'
import { Button, Alert, Spin, Typography } from 'antd'
-import { filterSelectOptions, Spacer, useBuiltinResources } from '@prorobotech/openapi-k8s-toolkit'
+import { filterSelectOptions, Spacer, useBuiltinResources, useApiResources } from '@prorobotech/openapi-k8s-toolkit'
import { useNavigate } from 'react-router-dom'
import { useSelector, useDispatch } from 'react-redux'
import { RootState } from 'store/store'
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,
+} from 'constants/customizationApiGroupAndVersion'
import { Styled } from './styled'
export const ListInsideClusterAndNs: FC = () => {
@@ -17,11 +22,31 @@ export const ListInsideClusterAndNs: FC = () => {
const [selectedCluster, setSelectedCluster] = useState()
const [selectedNamespace, setSelectedNamespace] = useState()
+ const isCustomNamespaceResource =
+ 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
+
const namespacesData = useBuiltinResources({
clusterName: selectedCluster || '',
typeName: 'namespaces',
limit: null,
- isEnabled: selectedCluster !== undefined,
+ isEnabled: selectedCluster !== undefined && !isCustomNamespaceResource,
+ })
+
+ const namespacesDataCustom = useApiResources({
+ clusterName: selectedCluster || '',
+ apiGroup: CUSTOM_NAMESPACE_API_RESOURCE_API_GROUP,
+ apiVersion: CUSTOM_NAMESPACE_API_RESOURCE_API_VERSION,
+ typeName: CUSTOM_NAMESPACE_API_RESOURCE_RESOURCE_NAME,
+ limit: null,
+ isEnabled: selectedCluster !== undefined && isCustomNamespaceResource,
})
return (
@@ -55,33 +80,62 @@ export const ListInsideClusterAndNs: FC = () => {
/>
)}
- {selectedCluster && namespacesData.isPending && }
- {selectedCluster && namespacesData.error && (
-
+ {selectedCluster && (isCustomNamespaceResource ? namespacesDataCustom.isPending : namespacesData.isPending) && (
+
)}
- {selectedCluster && selectedCluster.length > 0 && namespacesData.data && namespacesData.data.items.length > 0 && (
- <>
- Namespace
-
- ({
- label: ns.metadata.name,
- value: ns.metadata.name,
- }))}
- filterOption={filterSelectOptions}
- allowClear
- showSearch
- onSelect={value => {
- if (typeof value === 'string') {
- setSelectedNamespace(value)
- }
- }}
- onClear={() => setSelectedNamespace(undefined)}
- />
-
- >
+ {selectedCluster && (isCustomNamespaceResource ? namespacesDataCustom.error : namespacesData.error) && (
+
)}
+ {selectedCluster &&
+ selectedCluster.length > 0 &&
+ ((!isCustomNamespaceResource && namespacesData.data && namespacesData.data.items.length > 0) ||
+ (isCustomNamespaceResource && namespacesDataCustom.data && namespacesDataCustom.data.items.length > 0)) && (
+ <>
+ Namespace
+
+ {isCustomNamespaceResource ? (
+ ({
+ label: ns.metadata.name,
+ value: ns.metadata.name,
+ }))}
+ filterOption={filterSelectOptions}
+ allowClear
+ showSearch
+ onSelect={value => {
+ if (typeof value === 'string') {
+ setSelectedNamespace(value)
+ }
+ }}
+ onClear={() => setSelectedNamespace(undefined)}
+ />
+ ) : (
+ ({
+ label: ns.metadata.name,
+ value: ns.metadata.name,
+ }))}
+ filterOption={filterSelectOptions}
+ allowClear
+ showSearch
+ onSelect={value => {
+ if (typeof value === 'string') {
+ setSelectedNamespace(value)
+ }
+ }}
+ onClear={() => setSelectedNamespace(undefined)}
+ />
+ )}
+
+ >
+ )}