mirror of
https://github.com/outbackdingo/openapi-ui.git
synced 2026-01-27 18:19:50 +00:00
8
package-lock.json
generated
8
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": "^0.0.1-alpha.129",
|
||||
"@prorobotech/openapi-k8s-toolkit": "^0.0.1-alpha.137",
|
||||
"@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.129",
|
||||
"resolved": "https://registry.npmjs.org/@prorobotech/openapi-k8s-toolkit/-/openapi-k8s-toolkit-0.0.1-alpha.129.tgz",
|
||||
"integrity": "sha512-V5hrvOfbx7ZXCHu3sDYfvVKJPEbiymMk7Zb/1cQNfkyzjqvBB2JVRVEGVR9c6uyuWOHchBAMkiw2S5c5pm+yfQ==",
|
||||
"version": "0.0.1-alpha.137",
|
||||
"resolved": "https://registry.npmjs.org/@prorobotech/openapi-k8s-toolkit/-/openapi-k8s-toolkit-0.0.1-alpha.137.tgz",
|
||||
"integrity": "sha512-40wpiC8aRBmXZiNnkqYjqo15UEjF9mowoSGqe1/xzxFdjjeZtSBoDoGhLMFy/j6QBCvgaYnNH7mYqxZg5MS7rg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@monaco-editor/react": "4.6.0",
|
||||
|
||||
@@ -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.129",
|
||||
"@prorobotech/openapi-k8s-toolkit": "0.0.1-alpha.137",
|
||||
"@readme/openapi-parser": "4.0.0",
|
||||
"@reduxjs/toolkit": "2.2.5",
|
||||
"@tanstack/react-query": "5.62.2",
|
||||
|
||||
153
src/App.tsx
153
src/App.tsx
@@ -30,6 +30,7 @@ import {
|
||||
} from 'pages'
|
||||
import { getBasePrefix } from 'utils/getBaseprefix'
|
||||
import { colorsLight, colorsDark, sizes } from 'constants/colors'
|
||||
import { MainLayout } from 'templates/MainLayout'
|
||||
|
||||
type TAppProps = {
|
||||
isFederation?: boolean
|
||||
@@ -54,87 +55,77 @@ export const App: FC<TAppProps> = ({ isFederation, forcedTheme }) => {
|
||||
|
||||
const renderRoutes = (prefix = '') => (
|
||||
<Routes>
|
||||
<Route path={`${prefix}/`} element={<MainPage forcedTheme={forcedTheme} />} />
|
||||
<Route path={`${prefix}/clusters`} element={<ListClustersPage forcedTheme={forcedTheme} />} />
|
||||
<Route path={`${prefix}/clusters/:clusterName`} element={<ListProjectsPage forcedTheme={forcedTheme} />} />
|
||||
<Route path={`${prefix}/inside/`} element={<MainPage forcedTheme={forcedTheme} />} />
|
||||
<Route
|
||||
path={`${prefix}/clusters/:clusterName/projects/:namespace`}
|
||||
element={<ProjectInfoPage forcedTheme={forcedTheme} />}
|
||||
/>
|
||||
<Route
|
||||
path={`${prefix}/inside/clusters`}
|
||||
element={<ListInsideClustersAndNsPage forcedTheme={forcedTheme} inside />}
|
||||
/>
|
||||
<Route
|
||||
path={`${prefix}/inside/:clusterName/:namespace?/apis`}
|
||||
element={<ListInsideApiPage forcedTheme={forcedTheme} inside />}
|
||||
/>
|
||||
<Route
|
||||
path={`${prefix}/inside/:clusterName/:namespace?/crds-by-api/:apiGroup/:apiVersion/:apiExtensionVersion`}
|
||||
element={<ListInsideCrdByApiGroupPage forcedTheme={forcedTheme} inside />}
|
||||
/>
|
||||
<Route
|
||||
path={`${prefix}/inside/:clusterName/:namespace?/apis-by-api/:apiGroup/:apiVersion/`}
|
||||
element={<ListInsideApiByApiGroupPage forcedTheme={forcedTheme} inside />}
|
||||
/>
|
||||
<Route
|
||||
path={`${prefix}/:clusterName/:namespace?/:syntheticProject?/crd-table/:apiGroup/:apiVersion/:apiExtensionVersion/:crdName`}
|
||||
element={<TableCrdPage forcedTheme={forcedTheme} />}
|
||||
/>
|
||||
<Route
|
||||
path={`${prefix}/:clusterName/:namespace?/:syntheticProject?/api-table/:apiGroup/:apiVersion/:typeName`}
|
||||
element={<TableApiPage forcedTheme={forcedTheme} />}
|
||||
/>
|
||||
<Route
|
||||
path={`${prefix}/:clusterName/:namespace?/:syntheticProject?/builtin-table/:typeName`}
|
||||
element={<TableBuiltinPage forcedTheme={forcedTheme} />}
|
||||
/>
|
||||
<Route
|
||||
path={`${prefix}/:clusterName/:namespace?/:syntheticProject?/forms/builtin/:apiVersion/:typeName/:entryName?/`}
|
||||
element={<FormBuiltinPage forcedTheme={forcedTheme} />}
|
||||
/>
|
||||
<Route
|
||||
path={`${prefix}/:clusterName/:namespace?/:syntheticProject?/forms/apis/:apiGroup/:apiVersion/:typeName/:entryName?/`}
|
||||
element={<FormApiPage forcedTheme={forcedTheme} />}
|
||||
/>
|
||||
<Route
|
||||
path={`${prefix}/:clusterName/:namespace?/:syntheticProject?/forms/crds/:apiGroup/:apiVersion/:typeName/:entryName?/`}
|
||||
element={<FormCrdPage forcedTheme={forcedTheme} />}
|
||||
/>
|
||||
<Route
|
||||
path={`${prefix}/inside/:clusterName/:namespace?/:syntheticProject?/crd-table/:apiGroup/:apiVersion/:apiExtensionVersion/:crdName`}
|
||||
element={<TableCrdPage forcedTheme={forcedTheme} inside />}
|
||||
/>
|
||||
<Route
|
||||
path={`${prefix}/inside/:clusterName/:namespace?/:syntheticProject?/api-table/:apiGroup/:apiVersion/:typeName`}
|
||||
element={<TableApiPage forcedTheme={forcedTheme} inside />}
|
||||
/>
|
||||
<Route
|
||||
path={`${prefix}/inside/:clusterName/:namespace?/:syntheticProject?/builtin-table/:typeName`}
|
||||
element={<TableBuiltinPage forcedTheme={forcedTheme} inside />}
|
||||
/>
|
||||
<Route
|
||||
path={`${prefix}/inside/:clusterName/:namespace?/:syntheticProject?/forms/builtin/:apiVersion/:typeName/:entryName?/`}
|
||||
element={<FormBuiltinPage forcedTheme={forcedTheme} inside />}
|
||||
/>
|
||||
<Route
|
||||
path={`${prefix}/inside/:clusterName/:namespace?/:syntheticProject?/forms/apis/:apiGroup/:apiVersion/:typeName/:entryName?/`}
|
||||
element={<FormApiPage forcedTheme={forcedTheme} inside />}
|
||||
/>
|
||||
<Route
|
||||
path={`${prefix}/inside/:clusterName/:namespace?/:syntheticProject?/forms/crds/:apiGroup/:apiVersion/:typeName/:entryName?/`}
|
||||
element={<FormCrdPage forcedTheme={forcedTheme} inside />}
|
||||
/>
|
||||
<Route
|
||||
path={`${prefix}/:clusterName/:namespace?/:syntheticProject?/factory/:key/*`}
|
||||
element={<FactoryPage forcedTheme={forcedTheme} />}
|
||||
/>
|
||||
<Route
|
||||
path={`${prefix}/:clusterName/:namespace?/:syntheticProject?/search/*`}
|
||||
element={<SearchPage forcedTheme={forcedTheme} />}
|
||||
/>
|
||||
<Route path={`${prefix}/factory-admin/*`} element={<FactoryAdminPage />} />
|
||||
<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}/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>
|
||||
</Routes>
|
||||
)
|
||||
|
||||
|
||||
@@ -10,11 +10,12 @@ import {
|
||||
usePermissions,
|
||||
DeleteModal,
|
||||
DeleteModalMany,
|
||||
checkIfBuiltInInstanceNamespaceScoped,
|
||||
checkIfApiInstanceNamespaceScoped,
|
||||
// checkIfBuiltInInstanceNamespaceScoped,
|
||||
// checkIfApiInstanceNamespaceScoped,
|
||||
useBuiltinResources,
|
||||
useApiResources,
|
||||
Spacer,
|
||||
getLinkToForm,
|
||||
} from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { FlexGrow, PaddingContainer } from 'components'
|
||||
import { TABLE_PROPS } from 'constants/tableProps'
|
||||
@@ -27,13 +28,13 @@ import {
|
||||
TABLE_ADD_BUTTON_HEIGHT,
|
||||
} from 'constants/blocksSizes'
|
||||
import { OverflowContainer } from './atoms'
|
||||
import { getDataItems, getBackLinkToTable, getLinkToForm } from './utils'
|
||||
import { getDataItems } from './utils'
|
||||
|
||||
type TTableApiBuiltinProps = {
|
||||
namespace?: string
|
||||
resourceType: 'builtin' | 'api'
|
||||
apiGroup?: string // api
|
||||
apiVersion?: string // api
|
||||
apiVersion: string // api
|
||||
typeName: string
|
||||
labels?: string[]
|
||||
fields?: string[]
|
||||
@@ -71,7 +72,8 @@ 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 [isNamespaced, setIsNamespaced] = useState<boolean>()
|
||||
// const [isNamespacedLoading, setIsNamespacedLoading] = useState<boolean>()
|
||||
|
||||
const [height, setHeight] = useState(0)
|
||||
|
||||
@@ -97,58 +99,49 @@ export const TableApiBuiltin: FC<TTableApiBuiltinProps> = ({
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (resourceType === 'builtin') {
|
||||
checkIfBuiltInInstanceNamespaceScoped({
|
||||
typeName,
|
||||
clusterName: cluster,
|
||||
}).then(({ isNamespaceScoped }) => {
|
||||
if (isNamespaceScoped) {
|
||||
setIsNamespaced(isNamespaceScoped)
|
||||
}
|
||||
})
|
||||
}
|
||||
if (resourceType === 'api' && apiGroup && apiVersion) {
|
||||
checkIfApiInstanceNamespaceScoped({
|
||||
apiGroup,
|
||||
apiVersion,
|
||||
typeName,
|
||||
clusterName: cluster,
|
||||
}).then(({ isNamespaceScoped }) => {
|
||||
if (isNamespaceScoped) {
|
||||
setIsNamespaced(true)
|
||||
}
|
||||
})
|
||||
}
|
||||
}, [resourceType, cluster, typeName, apiGroup, apiVersion])
|
||||
// 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({
|
||||
apiGroup: apiGroup || '',
|
||||
typeName,
|
||||
namespace: '',
|
||||
group: apiGroup || undefined,
|
||||
resource: typeName,
|
||||
namespace: params.namespace,
|
||||
clusterName: cluster,
|
||||
verb: 'create',
|
||||
refetchInterval: false,
|
||||
})
|
||||
|
||||
const updatePermission = usePermissions({
|
||||
apiGroup: apiGroup || '',
|
||||
typeName,
|
||||
namespace: '',
|
||||
clusterName: cluster,
|
||||
verb: 'update',
|
||||
refetchInterval: false,
|
||||
})
|
||||
|
||||
const deletePermission = usePermissions({
|
||||
apiGroup: apiGroup || '',
|
||||
typeName,
|
||||
namespace: '',
|
||||
clusterName: cluster,
|
||||
verb: 'delete',
|
||||
refetchInterval: false,
|
||||
})
|
||||
|
||||
const {
|
||||
isPending: isPendingBuiltin,
|
||||
error: errorBuiltin,
|
||||
@@ -233,35 +226,26 @@ export const TableApiBuiltin: FC<TTableApiBuiltinProps> = ({
|
||||
...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,
|
||||
pathPrefix: resourceType === 'builtin' ? 'forms/builtin' : 'forms/apis',
|
||||
typeName,
|
||||
apiVersion: resourceType === 'builtin' ? 'v1' : `${apiGroup}/${apiVersion}`,
|
||||
backlink: getBackLinkToTable({
|
||||
resourceType,
|
||||
cluster,
|
||||
baseprefix,
|
||||
namespace,
|
||||
syntheticProject: params.syntheticProject,
|
||||
apiGroup,
|
||||
apiVersion,
|
||||
typeName,
|
||||
inside,
|
||||
fullPath,
|
||||
searchMount,
|
||||
}),
|
||||
deletePathPrefix:
|
||||
resourceType === 'builtin' ? `/api/clusters/${cluster}/k8s/api` : `/api/clusters/${cluster}/k8s/apis`,
|
||||
resource: typeName,
|
||||
apiGroup,
|
||||
apiVersion,
|
||||
}}
|
||||
dataForControlsInternal={{
|
||||
onDeleteHandle,
|
||||
permissions: {
|
||||
canUpdate: isNamespaced ? true : updatePermission.data?.status.allowed,
|
||||
canDelete: isNamespaced ? true : deletePermission.data?.status.allowed,
|
||||
},
|
||||
}}
|
||||
selectData={{
|
||||
selectedRowKeys,
|
||||
@@ -271,7 +255,6 @@ export const TableApiBuiltin: FC<TTableApiBuiltinProps> = ({
|
||||
},
|
||||
}}
|
||||
tableProps={{ ...TABLE_PROPS, disablePagination: !searchMount }}
|
||||
namespaceScopedWithoutNamespace={isNamespaced && !namespace}
|
||||
// maxHeight={height - 65}
|
||||
/>
|
||||
)}
|
||||
@@ -297,7 +280,6 @@ export const TableApiBuiltin: FC<TTableApiBuiltinProps> = ({
|
||||
type="primary"
|
||||
onClick={() => {
|
||||
const url = getLinkToForm({
|
||||
resourceType,
|
||||
cluster,
|
||||
baseprefix,
|
||||
namespace,
|
||||
@@ -311,8 +293,10 @@ export const TableApiBuiltin: FC<TTableApiBuiltinProps> = ({
|
||||
})
|
||||
navigate(url)
|
||||
}}
|
||||
loading={isNamespaced ? false : createPermission.isPending}
|
||||
disabled={isNamespaced ? false : !createPermission.data?.status.allowed}
|
||||
// loading={isNamespaced ? false : createPermission.isPending}
|
||||
// disabled={isNamespaced ? false : !createPermission.data?.status.allowed}
|
||||
loading={createPermission.isPending}
|
||||
disabled={!createPermission.data?.status.allowed}
|
||||
>
|
||||
<PlusOutlined />
|
||||
Add {kindName}
|
||||
|
||||
@@ -11,178 +11,3 @@ export const getDataItems = ({
|
||||
}): TJSON[] => {
|
||||
return resourceType === 'builtin' ? dataBuiltin?.items || [] : dataApi?.items || []
|
||||
}
|
||||
|
||||
export const getBackLinkToBuiltinTable = ({
|
||||
cluster,
|
||||
baseprefix,
|
||||
namespace,
|
||||
syntheticProject,
|
||||
typeName,
|
||||
inside,
|
||||
fullPath,
|
||||
searchMount,
|
||||
}: {
|
||||
cluster: string
|
||||
baseprefix?: string
|
||||
namespace?: string
|
||||
syntheticProject?: string
|
||||
typeName: string
|
||||
inside?: boolean
|
||||
fullPath: string
|
||||
searchMount?: boolean
|
||||
}): string => {
|
||||
if (searchMount) {
|
||||
return encodeURIComponent(fullPath)
|
||||
}
|
||||
const root = `${baseprefix}${inside ? '/inside' : ''}/${cluster}`
|
||||
const mainRoute = `${root}${namespace ? `/${namespace}` : ''}${syntheticProject ? `/${syntheticProject}` : ''}`
|
||||
|
||||
return `${mainRoute}/builtin-table/${typeName}`
|
||||
}
|
||||
|
||||
export const getBackLinkToApiTable = ({
|
||||
cluster,
|
||||
baseprefix,
|
||||
namespace,
|
||||
syntheticProject,
|
||||
apiGroup,
|
||||
apiVersion,
|
||||
typeName,
|
||||
inside,
|
||||
fullPath,
|
||||
searchMount,
|
||||
}: {
|
||||
cluster: string
|
||||
baseprefix?: string
|
||||
namespace?: string
|
||||
syntheticProject?: string
|
||||
apiGroup?: string // api
|
||||
apiVersion?: string // api
|
||||
typeName: string
|
||||
inside?: boolean
|
||||
fullPath: string
|
||||
searchMount?: boolean
|
||||
}): string => {
|
||||
if (searchMount) {
|
||||
return encodeURIComponent(fullPath)
|
||||
}
|
||||
|
||||
const root = `${baseprefix}${inside ? '/inside' : ''}/${cluster}`
|
||||
const mainRoute = `${root}${namespace ? `/${namespace}` : ''}${syntheticProject ? `/${syntheticProject}` : ''}`
|
||||
|
||||
return `${mainRoute}/api-table/${apiGroup}/${apiVersion}/${typeName}`
|
||||
}
|
||||
|
||||
export const getBackLinkToTable = ({
|
||||
resourceType,
|
||||
...rest
|
||||
}: {
|
||||
resourceType: 'builtin' | 'api'
|
||||
cluster: string
|
||||
baseprefix?: string
|
||||
namespace?: string
|
||||
syntheticProject?: string
|
||||
apiGroup?: string // api
|
||||
apiVersion?: string // api
|
||||
typeName: string
|
||||
inside?: boolean
|
||||
fullPath: string
|
||||
searchMount?: boolean
|
||||
}): string => {
|
||||
return resourceType === 'builtin' ? getBackLinkToBuiltinTable({ ...rest }) : getBackLinkToApiTable({ ...rest })
|
||||
}
|
||||
|
||||
export const getLinkToBuiltinForm = ({
|
||||
cluster,
|
||||
baseprefix,
|
||||
namespace,
|
||||
syntheticProject,
|
||||
typeName,
|
||||
inside,
|
||||
fullPath,
|
||||
searchMount,
|
||||
}: {
|
||||
cluster: string
|
||||
baseprefix?: string
|
||||
namespace?: string
|
||||
syntheticProject?: string
|
||||
typeName: string
|
||||
inside?: boolean
|
||||
fullPath: string
|
||||
searchMount?: boolean
|
||||
}): string => {
|
||||
const root = `${baseprefix}${inside ? '/inside' : ''}/${cluster}`
|
||||
const mainRoute = `${root}${namespace ? `/${namespace}` : ''}${syntheticProject ? `/${syntheticProject}` : ''}`
|
||||
const backlink = getBackLinkToBuiltinTable({
|
||||
cluster,
|
||||
baseprefix,
|
||||
namespace,
|
||||
syntheticProject,
|
||||
typeName,
|
||||
inside,
|
||||
fullPath,
|
||||
searchMount,
|
||||
})
|
||||
|
||||
return `${mainRoute}/forms/builtin/v1/${typeName}?backlink=${backlink}`
|
||||
}
|
||||
|
||||
export const getLinkToApiForm = ({
|
||||
cluster,
|
||||
baseprefix,
|
||||
namespace,
|
||||
syntheticProject,
|
||||
apiGroup,
|
||||
apiVersion,
|
||||
typeName,
|
||||
inside,
|
||||
fullPath,
|
||||
searchMount,
|
||||
}: {
|
||||
cluster: string
|
||||
baseprefix?: string
|
||||
namespace?: string
|
||||
syntheticProject?: string
|
||||
apiGroup?: string // api
|
||||
apiVersion?: string // api
|
||||
typeName: string
|
||||
inside?: boolean
|
||||
fullPath: string
|
||||
searchMount?: boolean
|
||||
}): string => {
|
||||
const root = `${baseprefix}${inside ? '/inside' : ''}/${cluster}`
|
||||
const mainRoute = `${root}${namespace ? `/${namespace}` : ''}${syntheticProject ? `/${syntheticProject}` : ''}`
|
||||
const backlink = getBackLinkToApiTable({
|
||||
cluster,
|
||||
baseprefix,
|
||||
namespace,
|
||||
syntheticProject,
|
||||
apiGroup,
|
||||
apiVersion,
|
||||
typeName,
|
||||
inside,
|
||||
fullPath,
|
||||
searchMount,
|
||||
})
|
||||
|
||||
return `${mainRoute}/forms/apis/${apiGroup}/${apiVersion}/${typeName}?backlink=${backlink}`
|
||||
}
|
||||
|
||||
export const getLinkToForm = ({
|
||||
resourceType,
|
||||
...rest
|
||||
}: {
|
||||
resourceType: 'builtin' | 'api'
|
||||
cluster: string
|
||||
baseprefix?: string
|
||||
namespace?: string
|
||||
syntheticProject?: string
|
||||
apiGroup?: string // api
|
||||
apiVersion?: string // api
|
||||
typeName: string
|
||||
inside?: boolean
|
||||
fullPath: string
|
||||
searchMount?: boolean
|
||||
}): string => {
|
||||
return resourceType === 'builtin' ? getLinkToBuiltinForm({ ...rest }) : getLinkToApiForm({ ...rest })
|
||||
}
|
||||
|
||||
@@ -50,8 +50,8 @@ export const TableCrdInfo: FC<TTableCrdInfoProps> = ({
|
||||
}, [cluster, data, isPending, error, apiGroup, apiVersion])
|
||||
|
||||
const createPermission = usePermissions({
|
||||
apiGroup,
|
||||
typeName: data ? data.spec.names.singular : '',
|
||||
group: apiGroup,
|
||||
resource: data ? data.spec.names.singular : '',
|
||||
namespace: '',
|
||||
clusterName: cluster,
|
||||
verb: 'create',
|
||||
@@ -59,8 +59,8 @@ export const TableCrdInfo: FC<TTableCrdInfoProps> = ({
|
||||
})
|
||||
|
||||
const updatePermission = usePermissions({
|
||||
apiGroup,
|
||||
typeName: data ? data.spec.names.singular : '',
|
||||
group: apiGroup,
|
||||
resource: data ? data.spec.names.singular : '',
|
||||
namespace: '',
|
||||
clusterName: cluster,
|
||||
verb: 'update',
|
||||
@@ -68,8 +68,8 @@ export const TableCrdInfo: FC<TTableCrdInfoProps> = ({
|
||||
})
|
||||
|
||||
const deletePermission = usePermissions({
|
||||
apiGroup,
|
||||
typeName: data ? data.spec.names.singular : '',
|
||||
group: apiGroup,
|
||||
resource: data ? data.spec.names.singular : '',
|
||||
namespace: '',
|
||||
clusterName: cluster,
|
||||
verb: 'delete',
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
import React, { FC, useState, useEffect } from 'react'
|
||||
import { useLocation, useNavigate, useParams } from 'react-router-dom'
|
||||
import { Spin, Alert, Button, Flex } from 'antd'
|
||||
@@ -130,133 +131,135 @@ export const ResourceInfo: FC<TResourceInfoProps> = ({
|
||||
return acc
|
||||
}, {})
|
||||
|
||||
return (
|
||||
<>
|
||||
{isPending && <Spin />}
|
||||
{error && <Alert message={`An error has occurred: ${error?.message} `} type="error" />}
|
||||
<OverflowMaxHeightContainer $maxHeight={height}>
|
||||
{!error && data && (
|
||||
<EnrichedTableProvider
|
||||
key={`/${apiGroup}/${apiVersion}/${crdPluralName}`}
|
||||
customizationId={`${customizationIdPrefix}/${apiGroup}/${apiVersion}/${crdPluralName}`}
|
||||
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,
|
||||
}}
|
||||
forceDefaultAdditionalPrinterColumns={crdAdditionalPrinterColumns}
|
||||
cluster={cluster}
|
||||
theme={theme}
|
||||
baseprefix={inside ? `${baseprefix}/inside` : baseprefix}
|
||||
dataItems={data.items}
|
||||
resourceSchema={resourceSchema}
|
||||
dataForControls={{
|
||||
cluster,
|
||||
syntheticProject: params.syntheticProject,
|
||||
pathPrefix: 'forms/crds',
|
||||
typeName: 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`,
|
||||
onDeleteHandle,
|
||||
permissions: {
|
||||
canUpdate: permissions.canUpdate,
|
||||
canDelete: permissions.canDelete,
|
||||
},
|
||||
}}
|
||||
selectData={{
|
||||
selectedRowKeys,
|
||||
onChange: (selectedRowKeys: React.Key[], selectedRowsData: { name: string; endpoint: string }[]) => {
|
||||
setSelectedRowKeys(selectedRowKeys)
|
||||
setSelectedRowsData(selectedRowsData)
|
||||
},
|
||||
}}
|
||||
tableProps={{ ...TABLE_PROPS, disablePagination: true }}
|
||||
// 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>
|
||||
)} */}
|
||||
</OverflowMaxHeightContainer>
|
||||
<FlexGrow />
|
||||
<PaddingContainer $padding="4px">
|
||||
<Flex justify="space-between">
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={() =>
|
||||
navigate(
|
||||
`${baseprefix}${inside ? '/inside' : ''}/${cluster}${namespace ? `/${namespace}` : ''}${
|
||||
params.syntheticProject ? `/${params.syntheticProject}` : ''
|
||||
}/forms/crds/${apiGroup}/${apiVersion}/${crdPluralName}?backlink=${baseprefix}${
|
||||
inside ? '/inside' : ''
|
||||
}/${cluster}${namespace ? `/${namespace}` : ''}${
|
||||
params.syntheticProject ? `/${params.syntheticProject}` : ''
|
||||
}/crd-table/${apiGroup}/${apiVersion}/${apiExtensionVersion}/${crdName}`,
|
||||
)
|
||||
}
|
||||
loading={permissions.canCreate === undefined}
|
||||
disabled={permissions.canCreate === false}
|
||||
>
|
||||
<PlusOutlined />
|
||||
Add
|
||||
</Button>
|
||||
{selectedRowKeys.length > 0 && (
|
||||
<Flex gap={16}>
|
||||
<Button type="primary" onClick={clearSelected}>
|
||||
<ClearOutlined />
|
||||
Clear
|
||||
</Button>
|
||||
<Button type="primary" onClick={() => setIsDeleteModalManyOpen(selectedRowsData)}>
|
||||
<MinusOutlined />
|
||||
Delete
|
||||
</Button>
|
||||
</Flex>
|
||||
)}
|
||||
</Flex>
|
||||
</PaddingContainer>
|
||||
{isDeleteModalOpen && (
|
||||
<DeleteModal
|
||||
name={isDeleteModalOpen.name}
|
||||
onClose={() => {
|
||||
setIsDeleteModalOpen(false)
|
||||
clearSelected()
|
||||
}}
|
||||
endpoint={isDeleteModalOpen.endpoint}
|
||||
/>
|
||||
)}
|
||||
{isDeleteModalManyOpen !== false && (
|
||||
<DeleteModalMany
|
||||
data={isDeleteModalManyOpen}
|
||||
onClose={() => {
|
||||
setIsDeleteModalManyOpen(false)
|
||||
clearSelected()
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
return <div>Most likely deprecated</div>
|
||||
|
||||
// return (
|
||||
// <>
|
||||
// {isPending && <Spin />}
|
||||
// {error && <Alert message={`An error has occurred: ${error?.message} `} type="error" />}
|
||||
// <OverflowMaxHeightContainer $maxHeight={height}>
|
||||
// {!error && data && (
|
||||
// <EnrichedTableProvider
|
||||
// key={`/${apiGroup}/${apiVersion}/${crdPluralName}`}
|
||||
// customizationId={`${customizationIdPrefix}/${apiGroup}/${apiVersion}/${crdPluralName}`}
|
||||
// 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,
|
||||
// }}
|
||||
// forceDefaultAdditionalPrinterColumns={crdAdditionalPrinterColumns}
|
||||
// cluster={cluster}
|
||||
// theme={theme}
|
||||
// baseprefix={inside ? `${baseprefix}/inside` : baseprefix}
|
||||
// dataItems={data.items}
|
||||
// resourceSchema={resourceSchema}
|
||||
// dataForControls={{
|
||||
// cluster,
|
||||
// syntheticProject: params.syntheticProject,
|
||||
// pathPrefix: 'forms/crds',
|
||||
// typeName: 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`,
|
||||
// onDeleteHandle,
|
||||
// permissions: {
|
||||
// canUpdate: permissions.canUpdate,
|
||||
// canDelete: permissions.canDelete,
|
||||
// },
|
||||
// }}
|
||||
// selectData={{
|
||||
// selectedRowKeys,
|
||||
// onChange: (selectedRowKeys: React.Key[], selectedRowsData: { name: string; endpoint: string }[]) => {
|
||||
// setSelectedRowKeys(selectedRowKeys)
|
||||
// setSelectedRowsData(selectedRowsData)
|
||||
// },
|
||||
// }}
|
||||
// tableProps={{ ...TABLE_PROPS, disablePagination: true }}
|
||||
// // 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>
|
||||
// )} */}
|
||||
// </OverflowMaxHeightContainer>
|
||||
// <FlexGrow />
|
||||
// <PaddingContainer $padding="4px">
|
||||
// <Flex justify="space-between">
|
||||
// <Button
|
||||
// type="primary"
|
||||
// onClick={() =>
|
||||
// navigate(
|
||||
// `${baseprefix}${inside ? '/inside' : ''}/${cluster}${namespace ? `/${namespace}` : ''}${
|
||||
// params.syntheticProject ? `/${params.syntheticProject}` : ''
|
||||
// }/forms/crds/${apiGroup}/${apiVersion}/${crdPluralName}?backlink=${baseprefix}${
|
||||
// inside ? '/inside' : ''
|
||||
// }/${cluster}${namespace ? `/${namespace}` : ''}${
|
||||
// params.syntheticProject ? `/${params.syntheticProject}` : ''
|
||||
// }/crd-table/${apiGroup}/${apiVersion}/${apiExtensionVersion}/${crdName}`,
|
||||
// )
|
||||
// }
|
||||
// loading={permissions.canCreate === undefined}
|
||||
// disabled={permissions.canCreate === false}
|
||||
// >
|
||||
// <PlusOutlined />
|
||||
// Add
|
||||
// </Button>
|
||||
// {selectedRowKeys.length > 0 && (
|
||||
// <Flex gap={16}>
|
||||
// <Button type="primary" onClick={clearSelected}>
|
||||
// <ClearOutlined />
|
||||
// Clear
|
||||
// </Button>
|
||||
// <Button type="primary" onClick={() => setIsDeleteModalManyOpen(selectedRowsData)}>
|
||||
// <MinusOutlined />
|
||||
// Delete
|
||||
// </Button>
|
||||
// </Flex>
|
||||
// )}
|
||||
// </Flex>
|
||||
// </PaddingContainer>
|
||||
// {isDeleteModalOpen && (
|
||||
// <DeleteModal
|
||||
// name={isDeleteModalOpen.name}
|
||||
// onClose={() => {
|
||||
// setIsDeleteModalOpen(false)
|
||||
// clearSelected()
|
||||
// }}
|
||||
// endpoint={isDeleteModalOpen.endpoint}
|
||||
// />
|
||||
// )}
|
||||
// {isDeleteModalManyOpen !== false && (
|
||||
// <DeleteModalMany
|
||||
// data={isDeleteModalManyOpen}
|
||||
// onClose={() => {
|
||||
// setIsDeleteModalManyOpen(false)
|
||||
// clearSelected()
|
||||
// }}
|
||||
// />
|
||||
// )}
|
||||
// </>
|
||||
// )
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ export const User: FC = () => {
|
||||
// },
|
||||
{
|
||||
key: '2',
|
||||
label: <div onClick={() => navigate(`${baseprefix}/inside`)}>Inside</div>,
|
||||
label: <div onClick={() => navigate(`${baseprefix}/inside/clusters`)}>Inside</div>,
|
||||
},
|
||||
{
|
||||
key: '3',
|
||||
|
||||
@@ -38,7 +38,7 @@ export const SelectorCluster: FC<TSelectorClusterProps> = ({ clusterName }) => {
|
||||
<Flex gap={18} justify="start" align="center">
|
||||
<Typography.Text>Cluster: </Typography.Text>
|
||||
<EntrySelect
|
||||
placeholder="Cluster"
|
||||
placeholder="Select Cluster"
|
||||
options={clustersInSidebar}
|
||||
value={selectedClusterName}
|
||||
onChange={handleClusterChange}
|
||||
|
||||
@@ -36,7 +36,7 @@ export const SelectorClusterInside: FC<TSelectorClusterInsideProps> = ({ cluster
|
||||
<Flex gap={18} justify="start" align="center">
|
||||
<Typography.Text>Cluster: </Typography.Text>
|
||||
<EntrySelect
|
||||
placeholder="Cluster"
|
||||
placeholder="Select Cluster"
|
||||
options={clustersInSidebar}
|
||||
value={selectedClusterName}
|
||||
onChange={handleClusterChange}
|
||||
|
||||
@@ -14,8 +14,8 @@ export const SelectorInside: FC<TSelectorInsideProps> = ({ clusterName, namespac
|
||||
const navigate = useNavigate()
|
||||
const params = useParams()
|
||||
|
||||
const [selectedClusterName, setSelectedClusterName] = useState(clusterName)
|
||||
const [selectedNamespace, setSelectedNamespace] = useState(namespace)
|
||||
const [selectedClusterName, setSelectedClusterName] = useState<string | undefined>(clusterName)
|
||||
const [selectedNamespace, setSelectedNamespace] = useState<string | undefined>(namespace)
|
||||
|
||||
// const { namespacesInSidebar, clustersInSidebar } = useNavSelectorInside(selectedClusterName)
|
||||
const { namespacesInSidebar } = useNavSelectorInside(selectedClusterName)
|
||||
|
||||
@@ -18,9 +18,10 @@ export const ListInsideClusterAndNs: FC = () => {
|
||||
const [selectedNamespace, setSelectedNamespace] = useState<string>()
|
||||
|
||||
const namespacesData = useBuiltinResources({
|
||||
clusterName: cluster,
|
||||
clusterName: selectedCluster || '',
|
||||
typeName: 'namespaces',
|
||||
limit: null,
|
||||
isEnabled: selectedCluster !== undefined,
|
||||
})
|
||||
|
||||
return (
|
||||
|
||||
@@ -94,7 +94,7 @@ export const SearchEntry: FC<TSearchEntryProps> = ({ resource, labels, fields, f
|
||||
resourceType={apiGroup.length > 0 ? 'api' : 'builtin'}
|
||||
namespace={isNamespaceResource ? namespace : undefined}
|
||||
apiGroup={apiGroup.length > 0 ? apiGroup : undefined}
|
||||
apiVersion={apiGroup.length > 0 ? apiVersion : undefined}
|
||||
apiVersion={apiVersion}
|
||||
typeName={typeName}
|
||||
labels={labels?.length ? labels : undefined}
|
||||
fields={fields?.length ? fields : undefined}
|
||||
|
||||
@@ -66,6 +66,7 @@ export const useNavSelector = (clusterName?: string, projectName?: string) => {
|
||||
apiVersion: BASE_PROJECTS_VERSION,
|
||||
typeName: BASE_PROJECTS_RESOURCE_NAME,
|
||||
limit: null,
|
||||
isEnabled: clusterName !== undefined,
|
||||
})
|
||||
|
||||
const { data: instances, isSuccess: allInstancesLoadingSuccess } = useApiResources({
|
||||
@@ -75,6 +76,7 @@ export const useNavSelector = (clusterName?: string, projectName?: string) => {
|
||||
apiVersion: BASE_INSTANCES_VERSION,
|
||||
typeName: BASE_INSTANCES_RESOURCE_NAME,
|
||||
limit: null,
|
||||
isEnabled: clusterName !== undefined,
|
||||
})
|
||||
|
||||
const clustersInSidebar = clusterList ? clusterList.map(mappedClusterToOptionInSidebar) : []
|
||||
|
||||
@@ -19,6 +19,7 @@ export const useNavSelectorInside = (clusterName?: string) => {
|
||||
clusterName: clusterName || '',
|
||||
typeName: 'namespaces',
|
||||
limit: null,
|
||||
isEnabled: Boolean(clusterName),
|
||||
})
|
||||
|
||||
const clustersInSidebar = clusterList ? clusterList.map(mappedClusterToOptionInSidebar) : []
|
||||
|
||||
@@ -5,11 +5,7 @@ import { getBreadcrumbsIdPrefix } from 'utils/getBreadcrumbsIdPrefix'
|
||||
import { getSidebarIdPrefix } from 'utils/getSidebarIdPrefix'
|
||||
import { BaseTemplate } from 'templates'
|
||||
|
||||
type TFactoryPageProps = {
|
||||
forcedTheme?: 'light' | 'dark'
|
||||
}
|
||||
|
||||
export const FactoryPage: FC<TFactoryPageProps> = ({ forcedTheme }) => {
|
||||
export const FactoryPage: FC = () => {
|
||||
const { namespace, syntheticProject, key } = useParams()
|
||||
|
||||
const [currentTags, setCurrentTags] = useState<string[]>()
|
||||
@@ -29,7 +25,6 @@ export const FactoryPage: FC<TFactoryPageProps> = ({ forcedTheme }) => {
|
||||
|
||||
return (
|
||||
<BaseTemplate
|
||||
forcedTheme={forcedTheme}
|
||||
sidebar={
|
||||
<ManageableSidebar
|
||||
instanceName={possibleInstance}
|
||||
@@ -38,7 +33,7 @@ export const FactoryPage: FC<TFactoryPageProps> = ({ forcedTheme }) => {
|
||||
currentTags={currentTags}
|
||||
/>
|
||||
}
|
||||
withNoCluster
|
||||
// withNoCluster
|
||||
>
|
||||
<NavigationContainer>
|
||||
<ManageableBreadcrumbs idToCompare={breadcrumbsId} />
|
||||
|
||||
@@ -18,11 +18,10 @@ import { BASE_USE_NAMESPACE_NAV } from 'constants/customizationApiGroupAndVersio
|
||||
import { BaseTemplate } from 'templates'
|
||||
|
||||
type TFormApiPageProps = {
|
||||
forcedTheme?: 'light' | 'dark'
|
||||
inside?: boolean
|
||||
}
|
||||
|
||||
export const FormApiPage: FC<TFormApiPageProps> = ({ forcedTheme, inside }) => {
|
||||
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)
|
||||
@@ -54,7 +53,6 @@ export const FormApiPage: FC<TFormApiPageProps> = ({ forcedTheme, inside }) => {
|
||||
|
||||
return (
|
||||
<BaseTemplate
|
||||
forcedTheme={forcedTheme}
|
||||
inside={inside}
|
||||
sidebar={
|
||||
<ManageableSidebar
|
||||
|
||||
@@ -18,11 +18,10 @@ import { BASE_USE_NAMESPACE_NAV } from 'constants/customizationApiGroupAndVersio
|
||||
import { BaseTemplate } from 'templates'
|
||||
|
||||
type TFormBuiltinPageProps = {
|
||||
forcedTheme?: 'light' | 'dark'
|
||||
inside?: boolean
|
||||
}
|
||||
|
||||
export const FormBuiltinPage: FC<TFormBuiltinPageProps> = ({ forcedTheme, inside }) => {
|
||||
export const FormBuiltinPage: FC<TFormBuiltinPageProps> = ({ inside }) => {
|
||||
const { clusterName, syntheticProject, namespace, typeName, entryName } = useParams()
|
||||
const [searchParams] = useSearchParams()
|
||||
const baseprefix = useSelector((state: RootState) => state.baseprefix.baseprefix)
|
||||
@@ -54,7 +53,6 @@ export const FormBuiltinPage: FC<TFormBuiltinPageProps> = ({ forcedTheme, inside
|
||||
|
||||
return (
|
||||
<BaseTemplate
|
||||
forcedTheme={forcedTheme}
|
||||
inside={inside}
|
||||
sidebar={
|
||||
<ManageableSidebar
|
||||
|
||||
@@ -18,11 +18,10 @@ import { BASE_USE_NAMESPACE_NAV } from 'constants/customizationApiGroupAndVersio
|
||||
import { BaseTemplate } from 'templates'
|
||||
|
||||
type TFormCrdPageProps = {
|
||||
forcedTheme?: 'light' | 'dark'
|
||||
inside?: boolean
|
||||
}
|
||||
|
||||
export const FormCrdPage: FC<TFormCrdPageProps> = ({ forcedTheme, inside }) => {
|
||||
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)
|
||||
@@ -54,7 +53,6 @@ export const FormCrdPage: FC<TFormCrdPageProps> = ({ forcedTheme, inside }) => {
|
||||
|
||||
return (
|
||||
<BaseTemplate
|
||||
forcedTheme={forcedTheme}
|
||||
inside={inside}
|
||||
sidebar={
|
||||
<ManageableSidebar
|
||||
|
||||
@@ -7,11 +7,7 @@ import type { RootState } from 'store/store'
|
||||
import { ListClusters, NavigationContainer } from 'components'
|
||||
import { BaseTemplate } from 'templates'
|
||||
|
||||
type TListClustersPageProps = {
|
||||
forcedTheme?: 'light' | 'dark'
|
||||
}
|
||||
|
||||
export const ListClustersPage: FC<TListClustersPageProps> = ({ forcedTheme }) => {
|
||||
export const ListClustersPage: FC = () => {
|
||||
const baseprefix = useSelector((state: RootState) => state.baseprefix.baseprefix)
|
||||
|
||||
const breadcrumbItems = [
|
||||
@@ -26,7 +22,7 @@ export const ListClustersPage: FC<TListClustersPageProps> = ({ forcedTheme }) =>
|
||||
]
|
||||
|
||||
return (
|
||||
<BaseTemplate withNoCluster forcedTheme={forcedTheme}>
|
||||
<BaseTemplate>
|
||||
<NavigationContainer>
|
||||
<Breadcrumb items={breadcrumbItems} separator=">" />
|
||||
</NavigationContainer>
|
||||
|
||||
@@ -7,18 +7,17 @@ import { getBreadcrumbsIdPrefix } from 'utils/getBreadcrumbsIdPrefix'
|
||||
import { BaseTemplate } from 'templates'
|
||||
|
||||
type TListInsideApiByApiGroupPageProps = {
|
||||
forcedTheme?: 'light' | 'dark'
|
||||
inside?: boolean
|
||||
}
|
||||
|
||||
export const ListInsideApiByApiGroupPage: FC<TListInsideApiByApiGroupPageProps> = ({ forcedTheme, inside }) => {
|
||||
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 forcedTheme={forcedTheme} inside={inside} sidebar={<ManageableSidebar idToCompare={sidebarId} />}>
|
||||
<BaseTemplate inside={inside} sidebar={<ManageableSidebar idToCompare={sidebarId} />}>
|
||||
<NavigationContainer>
|
||||
<ManageableBreadcrumbs idToCompare={breadcrumbsId} inside />
|
||||
</NavigationContainer>
|
||||
|
||||
@@ -7,18 +7,17 @@ import { getBreadcrumbsIdPrefix } from 'utils/getBreadcrumbsIdPrefix'
|
||||
import { BaseTemplate } from 'templates'
|
||||
|
||||
type TListInsideApiPageProps = {
|
||||
forcedTheme?: 'light' | 'dark'
|
||||
inside?: boolean
|
||||
}
|
||||
|
||||
export const ListInsideApiPage: FC<TListInsideApiPageProps> = ({ forcedTheme, inside }) => {
|
||||
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 forcedTheme={forcedTheme} inside={inside} sidebar={<ManageableSidebar idToCompare={sidebarId} />}>
|
||||
<BaseTemplate inside={inside} sidebar={<ManageableSidebar idToCompare={sidebarId} />}>
|
||||
<NavigationContainer>
|
||||
<ManageableBreadcrumbs idToCompare={breadcrumbsId} inside />
|
||||
</NavigationContainer>
|
||||
|
||||
@@ -8,11 +8,10 @@ import { ListInsideClusterAndNs, NavigationContainer } from 'components'
|
||||
import { BaseTemplate } from 'templates'
|
||||
|
||||
type TListInsideClustersAndNsPageProps = {
|
||||
forcedTheme?: 'light' | 'dark'
|
||||
inside?: boolean
|
||||
}
|
||||
|
||||
export const ListInsideClustersAndNsPage: FC<TListInsideClustersAndNsPageProps> = ({ forcedTheme, inside }) => {
|
||||
export const ListInsideClustersAndNsPage: FC<TListInsideClustersAndNsPageProps> = ({ inside }) => {
|
||||
const baseprefix = useSelector((state: RootState) => state.baseprefix.baseprefix)
|
||||
|
||||
const breadcrumbItems = [
|
||||
@@ -27,7 +26,7 @@ export const ListInsideClustersAndNsPage: FC<TListInsideClustersAndNsPageProps>
|
||||
]
|
||||
|
||||
return (
|
||||
<BaseTemplate withNoCluster forcedTheme={forcedTheme} inside={inside}>
|
||||
<BaseTemplate inside={inside}>
|
||||
<NavigationContainer>
|
||||
<Breadcrumb items={breadcrumbItems} separator=">" />
|
||||
</NavigationContainer>
|
||||
|
||||
@@ -7,18 +7,17 @@ import { getBreadcrumbsIdPrefix } from 'utils/getBreadcrumbsIdPrefix'
|
||||
import { BaseTemplate } from 'templates'
|
||||
|
||||
type TListInsideCrdByApiGroupPageProps = {
|
||||
forcedTheme?: 'light' | 'dark'
|
||||
inside?: boolean
|
||||
}
|
||||
|
||||
export const ListInsideCrdByApiGroupPage: FC<TListInsideCrdByApiGroupPageProps> = ({ forcedTheme, inside }) => {
|
||||
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 forcedTheme={forcedTheme} inside={inside} sidebar={<ManageableSidebar idToCompare={sidebarId} />}>
|
||||
<BaseTemplate inside={inside} sidebar={<ManageableSidebar idToCompare={sidebarId} />}>
|
||||
<NavigationContainer>
|
||||
<ManageableBreadcrumbs idToCompare={breadcrumbsId} inside />
|
||||
</NavigationContainer>
|
||||
|
||||
@@ -2,13 +2,9 @@ import React, { FC } from 'react'
|
||||
import { RedirectProjectList } from 'components'
|
||||
import { BaseTemplate } from 'templates'
|
||||
|
||||
type TListProjectsPageProps = {
|
||||
forcedTheme?: 'light' | 'dark'
|
||||
}
|
||||
|
||||
export const ListProjectsPage: FC<TListProjectsPageProps> = ({ forcedTheme }) => {
|
||||
export const ListProjectsPage: FC = () => {
|
||||
return (
|
||||
<BaseTemplate forcedTheme={forcedTheme}>
|
||||
<BaseTemplate>
|
||||
<RedirectProjectList />
|
||||
</BaseTemplate>
|
||||
)
|
||||
|
||||
@@ -2,16 +2,12 @@ import React, { FC, useEffect } from 'react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { BaseTemplate } from 'templates'
|
||||
|
||||
type TMainPageProps = {
|
||||
forcedTheme?: 'light' | 'dark'
|
||||
}
|
||||
|
||||
export const MainPage: FC<TMainPageProps> = ({ forcedTheme }) => {
|
||||
export const MainPage: FC = () => {
|
||||
const navigate = useNavigate()
|
||||
|
||||
useEffect(() => {
|
||||
navigate('./clusters')
|
||||
}, [navigate])
|
||||
|
||||
return <BaseTemplate withNoCluster forcedTheme={forcedTheme} />
|
||||
return <BaseTemplate />
|
||||
}
|
||||
|
||||
@@ -2,13 +2,9 @@ import React, { FC } from 'react'
|
||||
import { RedirectProjectInfo } from 'components'
|
||||
import { BaseTemplate } from 'templates'
|
||||
|
||||
type TProjectInfoPageProps = {
|
||||
forcedTheme?: 'light' | 'dark'
|
||||
}
|
||||
|
||||
export const ProjectInfoPage: FC<TProjectInfoPageProps> = ({ forcedTheme }) => {
|
||||
export const ProjectInfoPage: FC = () => {
|
||||
return (
|
||||
<BaseTemplate forcedTheme={forcedTheme}>
|
||||
<BaseTemplate>
|
||||
<RedirectProjectInfo />
|
||||
</BaseTemplate>
|
||||
)
|
||||
|
||||
@@ -6,11 +6,7 @@ import { getSidebarIdPrefix } from 'utils/getSidebarIdPrefix'
|
||||
import { getBreadcrumbsIdPrefix } from 'utils/getBreadcrumbsIdPrefix'
|
||||
import { BaseTemplate } from 'templates'
|
||||
|
||||
type TSearchPageProps = {
|
||||
forcedTheme?: 'light' | 'dark'
|
||||
}
|
||||
|
||||
export const SearchPage: FC<TSearchPageProps> = ({ forcedTheme }) => {
|
||||
export const SearchPage: FC = () => {
|
||||
const { namespace, syntheticProject } = useParams()
|
||||
|
||||
const possibleProject = syntheticProject && namespace ? syntheticProject : namespace
|
||||
@@ -28,7 +24,6 @@ export const SearchPage: FC<TSearchPageProps> = ({ forcedTheme }) => {
|
||||
|
||||
return (
|
||||
<BaseTemplate
|
||||
forcedTheme={forcedTheme}
|
||||
inside={false}
|
||||
isSearch
|
||||
sidebar={
|
||||
|
||||
@@ -17,11 +17,10 @@ import {
|
||||
} from 'constants/customizationApiGroupAndVersion'
|
||||
|
||||
type TTableApiPageProps = {
|
||||
forcedTheme?: 'light' | 'dark'
|
||||
inside?: boolean
|
||||
}
|
||||
|
||||
export const TableApiPage: FC<TTableApiPageProps> = ({ forcedTheme, inside }) => {
|
||||
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)
|
||||
@@ -62,7 +61,6 @@ export const TableApiPage: FC<TTableApiPageProps> = ({ forcedTheme, inside }) =>
|
||||
|
||||
return (
|
||||
<BaseTemplate
|
||||
forcedTheme={forcedTheme}
|
||||
inside={inside}
|
||||
sidebar={
|
||||
<ManageableSidebar
|
||||
@@ -85,6 +83,7 @@ export const TableApiPage: FC<TTableApiPageProps> = ({ forcedTheme, inside }) =>
|
||||
apiGroup={apiGroup}
|
||||
apiVersion={apiVersion}
|
||||
typeName={typeName}
|
||||
key={`${apiGroup}-${apiVersion}-${namespace}-${typeName}`}
|
||||
limit={searchParams.get('limit')}
|
||||
inside={inside}
|
||||
customizationIdPrefix={tableCustomizationIdPrefix}
|
||||
|
||||
@@ -12,11 +12,10 @@ import { BaseTemplate } from 'templates'
|
||||
import { BASE_USE_NAMESPACE_NAV } from 'constants/customizationApiGroupAndVersion'
|
||||
|
||||
type TTableBuiltinPageProps = {
|
||||
forcedTheme?: 'light' | 'dark'
|
||||
inside?: boolean
|
||||
}
|
||||
|
||||
export const TableBuiltinPage: FC<TTableBuiltinPageProps> = ({ forcedTheme, inside }) => {
|
||||
export const TableBuiltinPage: FC<TTableBuiltinPageProps> = ({ inside }) => {
|
||||
const { clusterName, namespace, syntheticProject, typeName } = useParams()
|
||||
const [searchParams] = useSearchParams()
|
||||
const baseprefix = useSelector((state: RootState) => state.baseprefix.baseprefix)
|
||||
@@ -49,7 +48,6 @@ export const TableBuiltinPage: FC<TTableBuiltinPageProps> = ({ forcedTheme, insi
|
||||
|
||||
return (
|
||||
<BaseTemplate
|
||||
forcedTheme={forcedTheme}
|
||||
inside={inside}
|
||||
sidebar={
|
||||
<ManageableSidebar
|
||||
@@ -68,6 +66,8 @@ export const TableBuiltinPage: FC<TTableBuiltinPageProps> = ({ forcedTheme, insi
|
||||
{typeName && (
|
||||
<TableApiBuiltin
|
||||
resourceType="builtin"
|
||||
apiVersion="v1"
|
||||
key={`${namespace}-${typeName}`}
|
||||
namespace={namespace}
|
||||
typeName={typeName}
|
||||
limit={searchParams.get('limit')}
|
||||
|
||||
@@ -12,11 +12,10 @@ import { BaseTemplate } from 'templates'
|
||||
import { BASE_USE_NAMESPACE_NAV } from 'constants/customizationApiGroupAndVersion'
|
||||
|
||||
type TTableCrdPageProps = {
|
||||
forcedTheme?: 'light' | 'dark'
|
||||
inside?: boolean
|
||||
}
|
||||
|
||||
export const TableCrdPage: FC<TTableCrdPageProps> = ({ forcedTheme, inside }) => {
|
||||
export const TableCrdPage: FC<TTableCrdPageProps> = ({ inside }) => {
|
||||
const { clusterName, namespace, syntheticProject, apiGroup, apiVersion, apiExtensionVersion, crdName } = useParams()
|
||||
const baseprefix = useSelector((state: RootState) => state.baseprefix.baseprefix)
|
||||
|
||||
@@ -48,7 +47,6 @@ export const TableCrdPage: FC<TTableCrdPageProps> = ({ forcedTheme, inside }) =>
|
||||
|
||||
return (
|
||||
<BaseTemplate
|
||||
forcedTheme={forcedTheme}
|
||||
inside={inside}
|
||||
sidebar={
|
||||
<ManageableSidebar
|
||||
|
||||
@@ -1,132 +1,32 @@
|
||||
import React, { FC, ReactNode, useEffect, useCallback } from 'react'
|
||||
import { Layout, theme as antdtheme, Alert, Col } from 'antd'
|
||||
import { useClusterList } from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { useSelector, useDispatch } from 'react-redux'
|
||||
import { useParams, useNavigate } from 'react-router-dom'
|
||||
import React, { FC, ReactNode } from 'react'
|
||||
import { Col } from 'antd'
|
||||
import { useSelector } from 'react-redux'
|
||||
import type { RootState } from 'store/store'
|
||||
import { setTheme } from 'store/theme/theme/theme'
|
||||
import { setCluster } from 'store/cluster/cluster/cluster'
|
||||
import { setClusterList } from 'store/clusterList/clusterList/clusterList'
|
||||
import {
|
||||
DefaultLayout,
|
||||
DefaultColorProvider,
|
||||
Header,
|
||||
HeaderSecond,
|
||||
Footer,
|
||||
Sidebar,
|
||||
RowFlexGrow,
|
||||
FlexCol,
|
||||
} from 'components'
|
||||
import { Styled } from './styled'
|
||||
import { DefaultLayout, HeaderSecond, Footer, Sidebar, RowFlexGrow, FlexCol } from 'components'
|
||||
|
||||
type TBaseTemplateProps = {
|
||||
withNoCluster?: boolean
|
||||
// withNoCluster?: boolean
|
||||
children?: ReactNode | undefined
|
||||
forcedTheme?: 'dark' | 'light'
|
||||
inside?: boolean
|
||||
isSearch?: boolean
|
||||
sidebar?: ReactNode
|
||||
}
|
||||
|
||||
export const BaseTemplate: FC<TBaseTemplateProps> = ({
|
||||
children,
|
||||
withNoCluster,
|
||||
forcedTheme,
|
||||
inside,
|
||||
isSearch,
|
||||
sidebar,
|
||||
}) => {
|
||||
const navigate = useNavigate()
|
||||
const { clusterName } = useParams()
|
||||
const { useToken } = antdtheme
|
||||
const { token } = useToken()
|
||||
const dispatch = useDispatch()
|
||||
const theme = useSelector((state: RootState) => state.openapiTheme.theme)
|
||||
export const BaseTemplate: FC<TBaseTemplateProps> = ({ children, inside, isSearch, sidebar }) => {
|
||||
const isFederation = useSelector((state: RootState) => state.federation.isFederation)
|
||||
const baseprefix = useSelector((state: RootState) => state.baseprefix.baseprefix)
|
||||
const clusterListQuery = useClusterList({ refetchInterval: false })
|
||||
|
||||
useEffect(() => {
|
||||
if (forcedTheme) {
|
||||
return
|
||||
}
|
||||
const localStorageTheme = localStorage.getItem('theme')
|
||||
if (localStorageTheme && (localStorageTheme === 'dark' || localStorageTheme === 'light')) {
|
||||
dispatch(setTheme(localStorageTheme))
|
||||
} else if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
||||
localStorage.setItem('theme', 'dark')
|
||||
dispatch(setTheme('dark'))
|
||||
} else {
|
||||
localStorage.setItem('theme', 'light')
|
||||
dispatch(setTheme('light'))
|
||||
}
|
||||
}, [dispatch, forcedTheme])
|
||||
|
||||
useEffect(() => {
|
||||
if (forcedTheme) {
|
||||
dispatch(setTheme(forcedTheme))
|
||||
}
|
||||
}, [dispatch, forcedTheme])
|
||||
|
||||
const handleStorage = useCallback(() => {
|
||||
const localStorageTheme = localStorage.getItem('theme')
|
||||
if (localStorageTheme && (localStorageTheme === 'dark' || localStorageTheme === 'light')) {
|
||||
dispatch(setTheme(localStorageTheme))
|
||||
}
|
||||
}, [dispatch])
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener('storage', handleStorage)
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('storage', handleStorage)
|
||||
}
|
||||
}, [handleStorage])
|
||||
|
||||
useEffect(() => {
|
||||
if (clusterListQuery.data) {
|
||||
dispatch(setClusterList(clusterListQuery.data))
|
||||
}
|
||||
}, [clusterListQuery, dispatch])
|
||||
|
||||
if (clusterName) {
|
||||
dispatch(setCluster(clusterName))
|
||||
}
|
||||
|
||||
if (clusterName === undefined) {
|
||||
dispatch(setCluster(''))
|
||||
}
|
||||
|
||||
if (!clusterName && !withNoCluster) {
|
||||
navigate(`${baseprefix}/`)
|
||||
}
|
||||
|
||||
return (
|
||||
<DefaultColorProvider $color={token.colorText}>
|
||||
<Styled.Container $isDark={theme === 'dark'}>
|
||||
<Layout>
|
||||
<DefaultLayout.Layout $bgColor={token.colorBgLayout}>
|
||||
<DefaultLayout.ContentContainer>
|
||||
<Header />
|
||||
<RowFlexGrow wrap={false}>
|
||||
<Col span="250px">
|
||||
<Sidebar sidebar={sidebar} />
|
||||
</Col>
|
||||
<FlexCol flex="auto">
|
||||
<DefaultLayout.ContentPadding $isFederation={isFederation}>
|
||||
<HeaderSecond inside={inside} isSearch={isSearch} />
|
||||
{clusterListQuery.error && (
|
||||
<Alert message={`Cluster List Error: ${clusterListQuery.error?.message} `} type="error" />
|
||||
)}
|
||||
{children}
|
||||
</DefaultLayout.ContentPadding>
|
||||
<Footer />
|
||||
</FlexCol>
|
||||
</RowFlexGrow>
|
||||
</DefaultLayout.ContentContainer>
|
||||
</DefaultLayout.Layout>
|
||||
</Layout>
|
||||
</Styled.Container>
|
||||
</DefaultColorProvider>
|
||||
<RowFlexGrow wrap={false}>
|
||||
<Col span="250px">
|
||||
<Sidebar sidebar={sidebar} />
|
||||
</Col>
|
||||
<FlexCol flex="auto">
|
||||
<DefaultLayout.ContentPadding $isFederation={isFederation}>
|
||||
<HeaderSecond inside={inside} isSearch={isSearch} />
|
||||
{children}
|
||||
</DefaultLayout.ContentPadding>
|
||||
<Footer />
|
||||
</FlexCol>
|
||||
</RowFlexGrow>
|
||||
)
|
||||
}
|
||||
|
||||
95
src/templates/MainLayout/MainLayout.tsx
Normal file
95
src/templates/MainLayout/MainLayout.tsx
Normal file
@@ -0,0 +1,95 @@
|
||||
import React, { FC, ReactNode, useEffect, useCallback } from 'react'
|
||||
import { Layout, theme as antdtheme, Alert } from 'antd'
|
||||
import { useClusterList } from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { useSelector, useDispatch } from 'react-redux'
|
||||
import { useParams, Outlet } from 'react-router-dom'
|
||||
import type { RootState } from 'store/store'
|
||||
import { setTheme } from 'store/theme/theme/theme'
|
||||
import { setCluster } from 'store/cluster/cluster/cluster'
|
||||
import { setClusterList } from 'store/clusterList/clusterList/clusterList'
|
||||
import { DefaultLayout, DefaultColorProvider, Header } from 'components'
|
||||
import { Styled } from './styled'
|
||||
|
||||
type TMainLayoutProps = {
|
||||
children?: ReactNode | undefined
|
||||
forcedTheme?: 'dark' | 'light'
|
||||
}
|
||||
|
||||
export const MainLayout: FC<TMainLayoutProps> = ({ children, forcedTheme }) => {
|
||||
const { clusterName } = useParams()
|
||||
const { useToken } = antdtheme
|
||||
const { token } = useToken()
|
||||
const dispatch = useDispatch()
|
||||
const theme = useSelector((state: RootState) => state.openapiTheme.theme)
|
||||
const clusterListQuery = useClusterList({ refetchInterval: false })
|
||||
|
||||
useEffect(() => {
|
||||
if (forcedTheme) {
|
||||
return
|
||||
}
|
||||
const localStorageTheme = localStorage.getItem('theme')
|
||||
if (localStorageTheme && (localStorageTheme === 'dark' || localStorageTheme === 'light')) {
|
||||
dispatch(setTheme(localStorageTheme))
|
||||
} else if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
||||
localStorage.setItem('theme', 'dark')
|
||||
dispatch(setTheme('dark'))
|
||||
} else {
|
||||
localStorage.setItem('theme', 'light')
|
||||
dispatch(setTheme('light'))
|
||||
}
|
||||
}, [dispatch, forcedTheme])
|
||||
|
||||
useEffect(() => {
|
||||
if (forcedTheme) {
|
||||
dispatch(setTheme(forcedTheme))
|
||||
}
|
||||
}, [dispatch, forcedTheme])
|
||||
|
||||
const handleStorage = useCallback(() => {
|
||||
const localStorageTheme = localStorage.getItem('theme')
|
||||
if (localStorageTheme && (localStorageTheme === 'dark' || localStorageTheme === 'light')) {
|
||||
dispatch(setTheme(localStorageTheme))
|
||||
}
|
||||
}, [dispatch])
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener('storage', handleStorage)
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('storage', handleStorage)
|
||||
}
|
||||
}, [handleStorage])
|
||||
|
||||
useEffect(() => {
|
||||
if (clusterListQuery.data) {
|
||||
dispatch(setClusterList(clusterListQuery.data))
|
||||
}
|
||||
}, [clusterListQuery, dispatch])
|
||||
|
||||
if (clusterName) {
|
||||
dispatch(setCluster(clusterName))
|
||||
}
|
||||
|
||||
if (clusterName === undefined) {
|
||||
dispatch(setCluster(''))
|
||||
}
|
||||
|
||||
return (
|
||||
<DefaultColorProvider $color={token.colorText}>
|
||||
<Styled.Container $isDark={theme === 'dark'}>
|
||||
<Layout>
|
||||
<DefaultLayout.Layout $bgColor={token.colorBgLayout}>
|
||||
<DefaultLayout.ContentContainer>
|
||||
<Header />
|
||||
{clusterListQuery.error && (
|
||||
<Alert message={`Cluster List Error: ${clusterListQuery.error?.message} `} type="error" />
|
||||
)}
|
||||
<Outlet />
|
||||
{children}
|
||||
</DefaultLayout.ContentContainer>
|
||||
</DefaultLayout.Layout>
|
||||
</Layout>
|
||||
</Styled.Container>
|
||||
</DefaultColorProvider>
|
||||
)
|
||||
}
|
||||
1
src/templates/MainLayout/index.ts
Normal file
1
src/templates/MainLayout/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { MainLayout } from './MainLayout'
|
||||
Reference in New Issue
Block a user