only api and builtin cats | new selectors logic | new table controls design | new table container

This commit is contained in:
typescreep
2025-07-02 14:43:02 +03:00
parent 7104c13e7a
commit d6d0dd3ab5
18 changed files with 356 additions and 173 deletions

8
package-lock.json generated
View File

@@ -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.44",
"@prorobotech/openapi-k8s-toolkit": "^0.0.1-alpha.45",
"@readme/openapi-parser": "4.0.0",
"@reduxjs/toolkit": "2.2.5",
"@tanstack/react-query": "5.62.2",
@@ -2807,9 +2807,9 @@
}
},
"node_modules/@prorobotech/openapi-k8s-toolkit": {
"version": "0.0.1-alpha.44",
"resolved": "https://registry.npmjs.org/@prorobotech/openapi-k8s-toolkit/-/openapi-k8s-toolkit-0.0.1-alpha.44.tgz",
"integrity": "sha512-bw0vhZT5lQn6ci6Y3dVR0vBk8FdkOW+ZZzkMSi/JuexpVWm9x8O+PJmcSiXmoSnjwzPJtA/XUuqsxmDq1PODTw==",
"version": "0.0.1-alpha.45",
"resolved": "https://registry.npmjs.org/@prorobotech/openapi-k8s-toolkit/-/openapi-k8s-toolkit-0.0.1-alpha.45.tgz",
"integrity": "sha512-+YltuzIeZDT/HAcLCyJzhBsq5a2Zz9ahZF0NYzaS/V6msZYjueoKbtl0OF4vGI8aUENuiEH1VfMY1i2w7vRp2A==",
"license": "MIT",
"dependencies": {
"@monaco-editor/react": "4.6.0",

View File

@@ -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.44",
"@prorobotech/openapi-k8s-toolkit": "0.0.1-alpha.45",
"@readme/openapi-parser": "4.0.0",
"@reduxjs/toolkit": "2.2.5",
"@tanstack/react-query": "5.62.2",

View File

@@ -8,7 +8,7 @@ type TEntrySelectProps = {
value: string
}[]
value?: string
onChange: (val: string) => void
onChange: (val?: string) => void
disabled?: boolean
fullwidth?: boolean
}
@@ -19,9 +19,10 @@ export const EntrySelect: FC<TEntrySelectProps> = ({ placeholder, value, disable
placeholder={placeholder}
value={value}
options={options.map(({ value, label }) => ({ label, value }))}
onChange={(selectedValue: string) => onChange(selectedValue)}
onChange={(selectedValue?: string) => onChange(selectedValue)}
disabled={disabled}
style={{ width: fullwidth ? '100%' : '200px' }}
allowClear
/>
)
}

View File

@@ -0,0 +1,9 @@
import styled from 'styled-components'
type TMarinTopContainerProps = {
$top: number
}
export const MarginTopContainer = styled.div<TMarinTopContainerProps>`
margin-top: ${({ $top }) => $top}px;
`

View File

@@ -0,0 +1 @@
export * from './MarginTopContainer'

View File

@@ -0,0 +1,11 @@
import styled from 'styled-components'
type TOverflowMaxHeightContainerProps = {
$maxHeight: number
}
export const OverflowMaxHeightContainer = styled.div<TOverflowMaxHeightContainerProps>`
overflow-x: auto;
scrollbar-width: thin;
height: ${({ $maxHeight }) => $maxHeight}px;
`

View File

@@ -0,0 +1 @@
export * from './OverflowMaxHeightContainer'

View File

@@ -11,3 +11,5 @@ export * from './RowFlexGrow'
export * from './FlexCol'
export * from './NavigationContainer'
export * from './EntrySelect'
export * from './OverflowMaxHeightContainer'
export * from './MarginTopContainer'

View File

@@ -6,6 +6,11 @@ import { RootState } from 'store/store'
import { useNavSelector } from 'hooks/useNavSelector'
import { useMountEffect } from 'hooks/useMountEffect'
import { EntrySelect } from 'components/atoms'
import {
BASE_INSTANCES_API_GROUP,
BASE_INSTANCES_VERSION,
BASE_INSTANCES_RESOURCE_NAME,
} from 'constants/customizationApiGroupAndVersion'
type TSelectorProps = {
clusterName?: string
@@ -32,14 +37,24 @@ export const Selector: FC<TSelectorProps> = ({ clusterName, projectName, instanc
// navigate(`${baseprefix}/clusters/${value}`)
// }
const handleProjectChange = (value: string) => {
setSelectedProjectName(value)
navigate(`${baseprefix}/clusters/${selectedClusterName}/projects/${value}`)
const handleProjectChange = (value?: string) => {
if (value) {
setSelectedProjectName(value)
navigate(`${baseprefix}/clusters/${selectedClusterName}/projects/${value}`)
} else {
navigate(`${baseprefix}/clusters/${selectedClusterName}/`)
}
}
const handleInstanceChange = (value: string) => {
setSelectedInstanceName(value)
navigate(`${baseprefix}/${selectedClusterName}/${value}/${selectedProjectName}/api-table/apps/v1/deployments`)
const handleInstanceChange = (value?: string) => {
if (value) {
setSelectedInstanceName(value)
navigate(`${baseprefix}/${selectedClusterName}/${value}/${selectedProjectName}/api-table/apps/v1/deployments`)
} else {
navigate(
`${baseprefix}/${selectedClusterName}/${selectedProjectName}/api-table/${BASE_INSTANCES_API_GROUP}/${BASE_INSTANCES_VERSION}/${BASE_INSTANCES_RESOURCE_NAME}`,
)
}
}
useMountEffect(() => {

View File

@@ -1,8 +1,6 @@
import React, { FC, useState } from 'react'
import { Flex } from 'antd'
import { useNavigate } from 'react-router-dom'
import { useSelector } from 'react-redux'
import { RootState } from 'store/store'
import { useNavigate, useParams } from 'react-router-dom'
import { useNavSelectorInside } from 'hooks/useNavSelectorInside'
import { useMountEffect } from 'hooks/useMountEffect'
import { EntrySelect } from 'components/atoms'
@@ -14,7 +12,7 @@ type TSelectorInsideProps = {
export const SelectorInside: FC<TSelectorInsideProps> = ({ clusterName, namespace }) => {
const navigate = useNavigate()
const baseprefix = useSelector((state: RootState) => state.baseprefix.baseprefix)
const params = useParams()
const [selectedClusterName, setSelectedClusterName] = useState(clusterName)
const [selectedNamespace, setSelectedNamespace] = useState(namespace)
@@ -27,9 +25,22 @@ export const SelectorInside: FC<TSelectorInsideProps> = ({ clusterName, namespac
// navigate(`${baseprefix}/inside/${value}/apis`)
// }
const handleNamepsaceChange = (value: string) => {
setSelectedNamespace(value)
navigate(`${baseprefix}/inside/${selectedClusterName}/${value}/apis`)
const handleNamepsaceChange = (value?: string) => {
if (value && params.namespace) {
setSelectedNamespace(value)
const pathnames = window.location.pathname.split('/')
const newPathNames = [...pathnames.slice(0, 4), value, ...pathnames.slice(5)]
navigate(newPathNames.join('/'))
} else if (value && !params.namespace) {
setSelectedNamespace(value)
const pathnames = window.location.pathname.split('/')
const newPathNames = [...pathnames.slice(0, 4), value, ...pathnames.slice(4)]
navigate(newPathNames.join('/'))
} else {
const pathnames = window.location.pathname.split('/')
const newPathnames = pathnames.filter((_, i) => i !== 4)
navigate(newPathnames.join('/'))
}
}
useMountEffect(() => {

View File

@@ -51,11 +51,12 @@ export const ListInsideAllResources: FC<TListInsideAllResourcesProps> = ({ names
})
}, [cluster, namespace, apiGroupList.data, builtInData.data])
const { crdGroups, nonCrdGroups, builtinGroups, apiExtensionVersion } = groupsByCategory || {}
// const { crdGroups, nonCrdGroups, builtinGroups, apiExtensionVersion } = groupsByCategory || {}
const { nonCrdGroups, builtinGroups } = groupsByCategory || {}
return (
<Styled.Grid>
<div>
{/* <div>
<Flex justify="center">
<TitleWithNoTopMargin level={3}>CRD Groups</TitleWithNoTopMargin>
</Flex>
@@ -83,7 +84,7 @@ export const ListInsideAllResources: FC<TListInsideAllResourcesProps> = ({ names
}}
/>
)}
</div>
</div> */}
<div>
<Flex justify="center">
<TitleWithNoTopMargin level={3}>API Groups</TitleWithNoTopMargin>

View File

@@ -3,7 +3,8 @@ import styled from 'styled-components'
const Grid = styled.div`
display: grid;
grid-gap: 72px;
grid-template-columns: repeat(3, 1fr);
/* grid-template-columns: repeat(3, 1fr); */
grid-template-columns: repeat(2, 1fr);
height: 100%;
min-height: 80vh;
`

View File

@@ -19,9 +19,13 @@ export const Selector: FC<TSelectorProps> = ({ clusterName, projectName }) => {
const { clustersInSidebar } = useNavSelector(selectedClusterName, projectName)
const handleClusterChange = (value: string) => {
setSelectedClusterName(value)
navigate(`${baseprefix}/clusters/${value}`)
const handleClusterChange = (value?: string) => {
if (value) {
setSelectedClusterName(value)
navigate(`${baseprefix}/clusters/${value}`)
} else {
navigate(`${baseprefix}/clusters/`)
}
}
useMountEffect(() => {

View File

@@ -18,9 +18,13 @@ export const SelectorInside: FC<TSelectorInsideProps> = ({ clusterName }) => {
const { clustersInSidebar } = useNavSelectorInside(selectedClusterName)
const handleClusterChange = (value: string) => {
setSelectedClusterName(value)
navigate(`${baseprefix}/inside/${value}/apis`)
const handleClusterChange = (value?: string) => {
if (value) {
setSelectedClusterName(value)
navigate(`${baseprefix}/inside/${value}/apis`)
} else {
navigate(`${baseprefix}/inside/`)
}
}
useMountEffect(() => {

View File

@@ -1,7 +1,7 @@
import React, { FC, useState, useEffect } from 'react'
import { useNavigate, useParams, useLocation } from 'react-router-dom'
import { Spin, Alert, Button, Flex } from 'antd'
import { PlusOutlined } from '@ant-design/icons'
import { PlusOutlined, ClearOutlined, MinusOutlined } from '@ant-design/icons'
import { useSelector } from 'react-redux'
import { RootState } from 'store/store'
import {
@@ -19,8 +19,16 @@ import {
useBuiltinResources,
} from '@prorobotech/openapi-k8s-toolkit'
import { BASE_API_GROUP, BASE_API_VERSION } from 'constants/customizationApiGroupAndVersion'
import { FlexGrow } from 'components'
import { FlexGrow, OverflowMaxHeightContainer, MarginTopContainer } from 'components'
import { TABLE_PROPS } from 'constants/tableProps'
import {
HEAD_FIRST_ROW,
HEAD_SECOND_ROW,
FOOTER_HEIGHT,
NAV_HEIGHT,
CONTENT_CARD_PADDING,
TABLE_ADD_BUTTON_HEIGHT,
} from 'constants/blocksSizes'
type TTableBuiltinInfoProps = {
namespace?: string
@@ -46,6 +54,30 @@ export const TableBuiltinInfo: FC<TTableBuiltinInfoProps> = ({ namespace, typeNa
const [selectedRowsData, setSelectedRowsData] = useState<{ name: string; endpoint: string }[]>([])
const [isNamespaced, setIsNamespaced] = useState<boolean>()
const [height, setHeight] = useState(0)
useEffect(() => {
const height =
window.innerHeight -
HEAD_FIRST_ROW -
HEAD_SECOND_ROW -
NAV_HEIGHT -
CONTENT_CARD_PADDING * 2 -
FOOTER_HEIGHT -
TABLE_ADD_BUTTON_HEIGHT
setHeight(height)
const handleResize = () => {
setHeight(height)
}
window.addEventListener('resize', handleResize)
return () => {
window.removeEventListener('resize', handleResize)
}
}, [])
const createPermission = usePermissions({
apiGroup: '',
typeName,
@@ -158,43 +190,59 @@ export const TableBuiltinInfo: FC<TTableBuiltinInfoProps> = ({ namespace, typeNa
<>
{isPending && <Spin />}
{error && <Alert message={`An error has occurred: ${error?.message} `} type="error" />}
{!error && data && (
<EnrichedTableProvider
theme={theme}
baseprefix={inside ? `${baseprefix}/inside` : baseprefix}
dataItems={data.items}
additionalPrinterColumns={ensuredCustomOverrides || additionalPrinterColumns}
additionalPrinterColumnsUndefinedValues={ensuredCustomOverridesUndefinedValues}
additionalPrinterColumnsTrimLengths={ensuredCustomOverridesTrimLengths}
additionalPrinterColumnsColWidths={ensuredCustomOverridesColWidths}
dataForControls={{
cluster,
syntheticProject: params.syntheticProject,
pathPrefix: 'forms/builtin',
typeName,
apiVersion: 'v1',
backlink: `${baseprefix}${inside ? '/inside' : ''}/${cluster}${namespace ? `/${namespace}` : ''}${
params.syntheticProject ? `/${params.syntheticProject}` : ''
}/builtin-table/${typeName}`,
deletePathPrefix: `/api/clusters/${cluster}/k8s/api`,
onDeleteHandle,
permissions: {
canUpdate: isNamespaced ? true : updatePermission.data?.status.allowed,
canDelete: isNamespaced ? true : deletePermission.data?.status.allowed,
},
}}
pathToNavigate={tableMappingSpecific?.pathToNavigate}
recordKeysForNavigation={tableMappingSpecific?.keysToParse}
selectData={{
selectedRowKeys,
onChange: (selectedRowKeys: React.Key[], selectedRowsData: { name: string; endpoint: string }[]) => {
setSelectedRowKeys(selectedRowKeys)
setSelectedRowsData(selectedRowsData)
},
}}
tableProps={TABLE_PROPS}
/>
)}
<OverflowMaxHeightContainer $maxHeight={height}>
{!error && data && (
<EnrichedTableProvider
theme={theme}
baseprefix={inside ? `${baseprefix}/inside` : baseprefix}
dataItems={data.items}
additionalPrinterColumns={ensuredCustomOverrides || additionalPrinterColumns}
additionalPrinterColumnsUndefinedValues={ensuredCustomOverridesUndefinedValues}
additionalPrinterColumnsTrimLengths={ensuredCustomOverridesTrimLengths}
additionalPrinterColumnsColWidths={ensuredCustomOverridesColWidths}
dataForControls={{
cluster,
syntheticProject: params.syntheticProject,
pathPrefix: 'forms/builtin',
typeName,
apiVersion: 'v1',
backlink: `${baseprefix}${inside ? '/inside' : ''}/${cluster}${namespace ? `/${namespace}` : ''}${
params.syntheticProject ? `/${params.syntheticProject}` : ''
}/builtin-table/${typeName}`,
deletePathPrefix: `/api/clusters/${cluster}/k8s/api`,
onDeleteHandle,
permissions: {
canUpdate: isNamespaced ? true : updatePermission.data?.status.allowed,
canDelete: isNamespaced ? true : deletePermission.data?.status.allowed,
},
}}
pathToNavigate={tableMappingSpecific?.pathToNavigate}
recordKeysForNavigation={tableMappingSpecific?.keysToParse}
selectData={{
selectedRowKeys,
onChange: (selectedRowKeys: React.Key[], selectedRowsData: { name: string; endpoint: string }[]) => {
setSelectedRowKeys(selectedRowKeys)
setSelectedRowsData(selectedRowsData)
},
}}
tableProps={TABLE_PROPS}
/>
)}
{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 />
<Flex justify="space-between">
<Button
@@ -214,14 +262,6 @@ export const TableBuiltinInfo: FC<TTableBuiltinInfoProps> = ({ namespace, typeNa
<PlusOutlined />
Add
</Button>
{selectedRowKeys.length > 0 && (
<Flex gap={8}>
<Button onClick={clearSelected}>Clear</Button>
<Button onClick={() => setIsDeleteModalManyOpen(selectedRowsData)} danger>
Delete
</Button>
</Flex>
)}
</Flex>
{isDeleteModalOpen && (
<DeleteModal

View File

@@ -1,7 +1,7 @@
import React, { FC, useState } from 'react'
import React, { FC, useState, useEffect } from 'react'
import { useNavigate, useParams, useLocation } from 'react-router-dom'
import { Spin, Alert, Button, Flex } from 'antd'
import { PlusOutlined } from '@ant-design/icons'
import { PlusOutlined, ClearOutlined, MinusOutlined } from '@ant-design/icons'
import { useSelector } from 'react-redux'
import { RootState } from 'store/store'
import {
@@ -16,8 +16,16 @@ import {
parseCustomOverrides,
} from '@prorobotech/openapi-k8s-toolkit'
import { BASE_API_GROUP, BASE_API_VERSION } from 'constants/customizationApiGroupAndVersion'
import { FlexGrow } from 'components'
import { FlexGrow, OverflowMaxHeightContainer, MarginTopContainer } from 'components'
import { TABLE_PROPS } from 'constants/tableProps'
import {
HEAD_FIRST_ROW,
HEAD_SECOND_ROW,
FOOTER_HEIGHT,
NAV_HEIGHT,
CONTENT_CARD_PADDING,
TABLE_ADD_BUTTON_HEIGHT,
} from 'constants/blocksSizes'
type TResourceInfoProps = {
clusterName: string
@@ -62,6 +70,30 @@ export const ResourceInfo: FC<TResourceInfoProps> = ({
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([])
const [selectedRowsData, setSelectedRowsData] = useState<{ name: string; endpoint: string }[]>([])
const [height, setHeight] = useState(0)
useEffect(() => {
const height =
window.innerHeight -
HEAD_FIRST_ROW -
HEAD_SECOND_ROW -
NAV_HEIGHT -
CONTENT_CARD_PADDING * 2 -
FOOTER_HEIGHT -
TABLE_ADD_BUTTON_HEIGHT
setHeight(height)
const handleResize = () => {
setHeight(height)
}
window.addEventListener('resize', handleResize)
return () => {
window.removeEventListener('resize', handleResize)
}
}, [])
const { isPending, error, data } = useCrdResources({
clusterName,
namespace,
@@ -142,44 +174,60 @@ export const ResourceInfo: FC<TResourceInfoProps> = ({
<>
{isPending && <Spin />}
{error && <Alert message={`An error has occurred: ${error?.message} `} type="error" />}
{!error && data && (
<EnrichedTableProvider
theme={theme}
baseprefix={inside ? `${baseprefix}/inside` : baseprefix}
dataItems={data.items}
resourceSchema={resourceSchema}
additionalPrinterColumns={ensuredCustomOverrides || crdAdditionalPrinterColumns}
additionalPrinterColumnsUndefinedValues={ensuredCustomOverridesUndefinedValues}
additionalPrinterColumnsTrimLengths={ensuredCustomOverridesTrimLengths}
additionalPrinterColumnsColWidths={ensuredCustomOverridesColWidths}
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,
},
}}
pathToNavigate={tableMappingSpecific?.pathToNavigate}
recordKeysForNavigation={tableMappingSpecific?.keysToParse}
selectData={{
selectedRowKeys,
onChange: (selectedRowKeys: React.Key[], selectedRowsData: { name: string; endpoint: string }[]) => {
setSelectedRowKeys(selectedRowKeys)
setSelectedRowsData(selectedRowsData)
},
}}
tableProps={TABLE_PROPS}
/>
)}
<OverflowMaxHeightContainer $maxHeight={height}>
{!error && data && (
<EnrichedTableProvider
theme={theme}
baseprefix={inside ? `${baseprefix}/inside` : baseprefix}
dataItems={data.items}
resourceSchema={resourceSchema}
additionalPrinterColumns={ensuredCustomOverrides || crdAdditionalPrinterColumns}
additionalPrinterColumnsUndefinedValues={ensuredCustomOverridesUndefinedValues}
additionalPrinterColumnsTrimLengths={ensuredCustomOverridesTrimLengths}
additionalPrinterColumnsColWidths={ensuredCustomOverridesColWidths}
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,
},
}}
pathToNavigate={tableMappingSpecific?.pathToNavigate}
recordKeysForNavigation={tableMappingSpecific?.keysToParse}
selectData={{
selectedRowKeys,
onChange: (selectedRowKeys: React.Key[], selectedRowsData: { name: string; endpoint: string }[]) => {
setSelectedRowKeys(selectedRowKeys)
setSelectedRowsData(selectedRowsData)
},
}}
tableProps={TABLE_PROPS}
/>
)}
{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 />
<Flex justify="space-between">
<Button
@@ -201,14 +249,6 @@ export const ResourceInfo: FC<TResourceInfoProps> = ({
<PlusOutlined />
Add
</Button>
{selectedRowKeys.length > 0 && (
<Flex gap={8}>
<Button onClick={clearSelected}>Clear</Button>
<Button onClick={() => setIsDeleteModalManyOpen(selectedRowsData)} danger>
Delete
</Button>
</Flex>
)}
</Flex>
{isDeleteModalOpen && (
<DeleteModal

View File

@@ -1,7 +1,8 @@
/* eslint-disable max-lines-per-function */
import React, { FC, useState, useEffect } from 'react'
import { useNavigate, useParams, useLocation } from 'react-router-dom'
import { Spin, Alert, Button, Flex } from 'antd'
import { PlusOutlined } from '@ant-design/icons'
import { PlusOutlined, ClearOutlined, MinusOutlined } from '@ant-design/icons'
import { useSelector } from 'react-redux'
import { RootState } from 'store/store'
import {
@@ -19,8 +20,16 @@ import {
parseCustomOverrides,
} from '@prorobotech/openapi-k8s-toolkit'
import { BASE_API_GROUP, BASE_API_VERSION } from 'constants/customizationApiGroupAndVersion'
import { FlexGrow } from 'components'
import { FlexGrow, OverflowMaxHeightContainer, MarginTopContainer } from 'components'
import { TABLE_PROPS } from 'constants/tableProps'
import {
HEAD_FIRST_ROW,
HEAD_SECOND_ROW,
FOOTER_HEIGHT,
NAV_HEIGHT,
CONTENT_CARD_PADDING,
TABLE_ADD_BUTTON_HEIGHT,
} from 'constants/blocksSizes'
type TTableNonCrdInfoProps = {
namespace?: string
@@ -54,6 +63,30 @@ export const TableNonCrdInfo: FC<TTableNonCrdInfoProps> = ({
const [selectedRowsData, setSelectedRowsData] = useState<{ name: string; endpoint: string }[]>([])
const [isNamespaced, setIsNamespaced] = useState<boolean>()
const [height, setHeight] = useState(0)
useEffect(() => {
const height =
window.innerHeight -
HEAD_FIRST_ROW -
HEAD_SECOND_ROW -
NAV_HEIGHT -
CONTENT_CARD_PADDING * 2 -
FOOTER_HEIGHT -
TABLE_ADD_BUTTON_HEIGHT
setHeight(height)
const handleResize = () => {
setHeight(height)
}
window.addEventListener('resize', handleResize)
return () => {
window.removeEventListener('resize', handleResize)
}
}, [])
useEffect(() => {
checkIfApiInstanceNamespaceScoped({
apiGroup,
@@ -173,43 +206,59 @@ export const TableNonCrdInfo: FC<TTableNonCrdInfoProps> = ({
<>
{isPending && <Spin />}
{error && <Alert message={`An error has occurred: ${error?.message} `} type="error" />}
{!error && data && (
<EnrichedTableProvider
theme={theme}
baseprefix={inside ? `${baseprefix}/inside` : baseprefix}
dataItems={data.items}
additionalPrinterColumns={ensuredCustomOverrides || additionalPrinterColumns}
additionalPrinterColumnsUndefinedValues={ensuredCustomOverridesUndefinedValues}
additionalPrinterColumnsTrimLengths={ensuredCustomOverridesTrimLengths}
additionalPrinterColumnsColWidths={ensuredCustomOverridesColWidths}
dataForControls={{
cluster,
syntheticProject: params.syntheticProject,
pathPrefix: 'forms/apis',
typeName,
apiVersion: `${apiGroup}/${apiVersion}`,
backlink: `${baseprefix}${inside ? '/inside' : ''}/${cluster}${namespace ? `/${namespace}` : ''}${
params.syntheticProject ? `/${params.syntheticProject}` : ''
}/api-table/${apiGroup}/${apiVersion}/${typeName}`,
deletePathPrefix: `/api/clusters/${cluster}/k8s/apis`,
onDeleteHandle,
permissions: {
canUpdate: isNamespaced ? true : updatePermission.data?.status.allowed,
canDelete: isNamespaced ? true : deletePermission.data?.status.allowed,
},
}}
pathToNavigate={tableMappingSpecific?.pathToNavigate}
recordKeysForNavigation={tableMappingSpecific?.keysToParse}
selectData={{
selectedRowKeys,
onChange: (selectedRowKeys: React.Key[], selectedRowsData: { name: string; endpoint: string }[]) => {
setSelectedRowKeys(selectedRowKeys)
setSelectedRowsData(selectedRowsData)
},
}}
tableProps={TABLE_PROPS}
/>
)}
<OverflowMaxHeightContainer $maxHeight={height}>
{!error && data && (
<EnrichedTableProvider
theme={theme}
baseprefix={inside ? `${baseprefix}/inside` : baseprefix}
dataItems={data.items}
additionalPrinterColumns={ensuredCustomOverrides || additionalPrinterColumns}
additionalPrinterColumnsUndefinedValues={ensuredCustomOverridesUndefinedValues}
additionalPrinterColumnsTrimLengths={ensuredCustomOverridesTrimLengths}
additionalPrinterColumnsColWidths={ensuredCustomOverridesColWidths}
dataForControls={{
cluster,
syntheticProject: params.syntheticProject,
pathPrefix: 'forms/apis',
typeName,
apiVersion: `${apiGroup}/${apiVersion}`,
backlink: `${baseprefix}${inside ? '/inside' : ''}/${cluster}${namespace ? `/${namespace}` : ''}${
params.syntheticProject ? `/${params.syntheticProject}` : ''
}/api-table/${apiGroup}/${apiVersion}/${typeName}`,
deletePathPrefix: `/api/clusters/${cluster}/k8s/apis`,
onDeleteHandle,
permissions: {
canUpdate: isNamespaced ? true : updatePermission.data?.status.allowed,
canDelete: isNamespaced ? true : deletePermission.data?.status.allowed,
},
}}
pathToNavigate={tableMappingSpecific?.pathToNavigate}
recordKeysForNavigation={tableMappingSpecific?.keysToParse}
selectData={{
selectedRowKeys,
onChange: (selectedRowKeys: React.Key[], selectedRowsData: { name: string; endpoint: string }[]) => {
setSelectedRowKeys(selectedRowKeys)
setSelectedRowsData(selectedRowsData)
},
}}
tableProps={TABLE_PROPS}
/>
)}
{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 />
<Flex justify="space-between">
<Button
@@ -231,14 +280,6 @@ export const TableNonCrdInfo: FC<TTableNonCrdInfoProps> = ({
<PlusOutlined />
Add
</Button>
{selectedRowKeys.length > 0 && (
<Flex gap={8}>
<Button onClick={clearSelected}>Clear</Button>
<Button onClick={() => setIsDeleteModalManyOpen(selectedRowsData)} danger>
Delete
</Button>
</Flex>
)}
</Flex>
{isDeleteModalOpen && (
<DeleteModal

View File

@@ -11,3 +11,4 @@ export const BREADCRUMBS_HEIGHT = 26
export const CONTENT_CARD_PADDING = 25
export const BLACKHOLE_FORM_VIEW_SWITCH_HEIGHT = 42
export const BLACKHOLE_FORM_SUBMIT_ROW_HEIGHT = 48
export const TABLE_ADD_BUTTON_HEIGHT = 35