From 7995897087eb053118e7d66f5623c16a6a239236 Mon Sep 17 00:00:00 2001 From: typescreep Date: Thu, 6 Nov 2025 04:04:46 +0300 Subject: [PATCH 01/32] tables with list-then-watch --- src/App.tsx | 5 ++ .../TableApiBuiltin/TableApiBuiltin.tsx | 82 ++++++++++++------- .../molecules/TableApiBuiltin/utils.ts | 8 +- .../molecules/SearchEntry/SearchEntry.tsx | 4 +- .../ListThenWatchPage/ListThenWatchPage.tsx | 81 ++++++++++++++++++ src/pages/ListThenWatchPage/index.ts | 1 + src/pages/TableApiPage/TableApiPage.tsx | 4 +- .../TableBuiltinPage/TableBuiltinPage.tsx | 4 +- src/pages/index.ts | 2 + 9 files changed, 155 insertions(+), 36 deletions(-) create mode 100644 src/pages/ListThenWatchPage/ListThenWatchPage.tsx create mode 100644 src/pages/ListThenWatchPage/index.ts diff --git a/src/App.tsx b/src/App.tsx index 6711b2b..ecae2df 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -27,6 +27,7 @@ import { FactoryPage, FactoryAdminPage, SearchPage, + ListThenWatchPage, } from 'pages' import { getBasePrefix } from 'utils/getBaseprefix' import { colorsLight, colorsDark, sizes } from 'constants/colors' @@ -125,6 +126,10 @@ export const App: FC = ({ isFederation, forcedTheme }) => { /> } /> } /> + } + /> ) diff --git a/src/components/molecules/TableApiBuiltin/TableApiBuiltin.tsx b/src/components/molecules/TableApiBuiltin/TableApiBuiltin.tsx index 4a27a36..201d4f9 100644 --- a/src/components/molecules/TableApiBuiltin/TableApiBuiltin.tsx +++ b/src/components/molecules/TableApiBuiltin/TableApiBuiltin.tsx @@ -12,8 +12,7 @@ import { DeleteModalMany, // checkIfBuiltInInstanceNamespaceScoped, // checkIfApiInstanceNamespaceScoped, - useBuiltinResources, - useApiResources, + useListWatch, Spacer, getLinkToForm, } from '@prorobotech/openapi-k8s-toolkit' @@ -38,7 +37,7 @@ type TTableApiBuiltinProps = { typeName: string labels?: string[] fields?: string[] - limit: string | null + limit?: number inside?: boolean customizationIdPrefix: string searchMount?: boolean @@ -143,35 +142,62 @@ export const TableApiBuiltin: FC = ({ }) const { - isPending: isPendingBuiltin, - error: errorBuiltin, - data: dataBuiltin, - } = useBuiltinResources({ - clusterName: cluster, - namespace, - typeName, - labels, - fields, - limit, + state: stateCore, + status: statusCore, + lastError: lastErrorCore, + } = useListWatch({ + wsUrl: `/api/clusters/${cluster}/openapi-bff-ws/listThenWatch/listWatchWs`, + paused: false, + ignoreRemove: false, + autoDrain: true, + preserveStateOnUrlChange: true, + pageSize: limit, + query: { + namespace, + apiVersion: apiVersion || '', + plural: typeName, + labelSelector: labels ? encodeURIComponent(labels.join(',')) : undefined, + fieldSelector: fields ? encodeURIComponent(fields.join(',')) : undefined, + }, isEnabled: resourceType === 'builtin', }) + const isPendingBuiltin = statusCore === 'connecting' + const errorBuiltin = statusCore === 'closed' && lastErrorCore ? lastErrorCore : undefined + const dataBuiltin = stateCore.order.map(key => { + const res = stateCore.byKey[key] + return res + }) + const { - isPending: isPendingApi, - error: errorApi, - data: dataApi, - } = useApiResources({ - clusterName: cluster, - namespace, - apiGroup: apiGroup || '', - apiVersion: apiVersion || '', - typeName, - labels, - fields, - limit, + state: stateApi, + status: statusApi, + lastError: lastErrorApi, + } = useListWatch({ + wsUrl: `/api/clusters/${cluster}/openapi-bff-ws/listThenWatch/listWatchWs`, + paused: false, + ignoreRemove: false, + autoDrain: true, + preserveStateOnUrlChange: true, + pageSize: limit, + query: { + namespace, + apiGroup: apiGroup || '', + apiVersion: apiVersion || '', + plural: typeName, + labelSelector: labels ? labels.join(',') : undefined, + fieldSelector: fields ? fields.join(',') : undefined, + }, isEnabled: resourceType === 'api' && !!apiGroup && !!apiVersion, }) + const isPendingApi = statusApi === 'connecting' + const errorApi = statusApi === 'closed' && lastErrorApi ? lastErrorApi : undefined + const dataApi = stateApi.order.map(key => { + const res = stateApi.byKey[key] + return res + }) + const onDeleteHandle = (name: string, endpoint: string) => { setIsDeleteModalOpen({ name, endpoint }) } @@ -194,11 +220,9 @@ export const TableApiBuiltin: FC = ({ <> {((resourceType === 'builtin' && isPendingBuiltin) || (resourceType === 'api' && isPendingApi)) && } {resourceType === 'builtin' && errorBuiltin && ( - - )} - {resourceType === 'api' && errorApi && ( - + )} + {resourceType === 'api' && errorApi && } {!errorBuiltin && !errorApi && diff --git a/src/components/molecules/TableApiBuiltin/utils.ts b/src/components/molecules/TableApiBuiltin/utils.ts index dde900f..1e4cd77 100644 --- a/src/components/molecules/TableApiBuiltin/utils.ts +++ b/src/components/molecules/TableApiBuiltin/utils.ts @@ -1,4 +1,4 @@ -import { TBuiltinResources, TApiResources, TJSON } from '@prorobotech/openapi-k8s-toolkit' +import { TSingleResource, TJSON } from '@prorobotech/openapi-k8s-toolkit' export const getDataItems = ({ resourceType, @@ -6,8 +6,8 @@ export const getDataItems = ({ dataApi, }: { resourceType: 'builtin' | 'api' - dataBuiltin?: TBuiltinResources - dataApi?: TApiResources + dataBuiltin?: TSingleResource[] + dataApi?: TSingleResource[] }): TJSON[] => { - return resourceType === 'builtin' ? dataBuiltin?.items || [] : dataApi?.items || [] + return resourceType === 'builtin' ? dataBuiltin || [] : dataApi || [] } diff --git a/src/components/organisms/Search/molecules/SearchEntry/SearchEntry.tsx b/src/components/organisms/Search/molecules/SearchEntry/SearchEntry.tsx index 169bd9f..28e6ab0 100644 --- a/src/components/organisms/Search/molecules/SearchEntry/SearchEntry.tsx +++ b/src/components/organisms/Search/molecules/SearchEntry/SearchEntry.tsx @@ -60,6 +60,8 @@ export const SearchEntry: FC = ({ resource, labels, fields, f form.setFieldsValue({ [FIELD_NAME]: cur.filter(v => v !== value) }) } + const limitSp = searchParams.get('limit') + return ( @@ -98,7 +100,7 @@ export const SearchEntry: FC = ({ resource, labels, fields, f typeName={typeName} labels={labels?.length ? labels : undefined} fields={fields?.length ? fields : undefined} - limit={searchParams.get('limit')} + limit={limitSp && limitSp.length > 0 ? Number(limitSp) : undefined} customizationIdPrefix={tableCustomizationIdPrefix} searchMount kindName={kindName} diff --git a/src/pages/ListThenWatchPage/ListThenWatchPage.tsx b/src/pages/ListThenWatchPage/ListThenWatchPage.tsx new file mode 100644 index 0000000..4d4775d --- /dev/null +++ b/src/pages/ListThenWatchPage/ListThenWatchPage.tsx @@ -0,0 +1,81 @@ +/* eslint-disable no-void */ +/* eslint-disable no-console */ +/* eslint-disable react/button-has-type */ +import { useState, FC } from 'react' +import { useListWatch, TUseListWatchQuery } from '@prorobotech/openapi-k8s-toolkit' + +export const ListThenWatchPage: FC = () => { + const [queryState, setQueryState] = useState({ + apiGroup: '', + apiVersion: 'v1', + plural: 'pods', + namespace: 'incloud-web', + }) + + const { state, total, status, lastError, reconnect } = useListWatch({ + wsUrl: '/api/clusters/default/openapi-bff-ws/listThenWatch/listWatchWs', + paused: false, + ignoreRemove: false, + autoDrain: true, + preserveStateOnUrlChange: true, + isEnabled: true, + query: queryState, + }) + + const switchNamespace = (ns: string) => { + setQueryState(prev => ({ + ...prev, + namespace: ns, + initialContinue: undefined, + })) + } + + if (status === 'connecting') { + return
🔄 Connecting to API server…
+ } + + if (status === 'closed' && lastError) { + return
⚠️ Error: {lastError}
+ } + + if (status === 'closed') { + return ( +
+ ❌ Connection closed. +
+ ) + } + + return ( +
+
+ + Status: {status} + + {lastError && • {lastError}} + + + Total: {total} +
+ +
    + {state.order.map(key => { + const res = state.byKey[key] + const name = res.metadata?.name ?? key + const ns = res.metadata?.namespace ?? '' + return ( +
  • +
    + {ns}/{name} +
    +
  • + ) + })} +
+
+ ) +} diff --git a/src/pages/ListThenWatchPage/index.ts b/src/pages/ListThenWatchPage/index.ts new file mode 100644 index 0000000..0a6ad10 --- /dev/null +++ b/src/pages/ListThenWatchPage/index.ts @@ -0,0 +1 @@ +export { ListThenWatchPage } from './ListThenWatchPage' diff --git a/src/pages/TableApiPage/TableApiPage.tsx b/src/pages/TableApiPage/TableApiPage.tsx index 87d2724..02a1fad 100644 --- a/src/pages/TableApiPage/TableApiPage.tsx +++ b/src/pages/TableApiPage/TableApiPage.tsx @@ -59,6 +59,8 @@ export const TableApiPage: FC = ({ inside }) => { const sidebarIdProjectList = `${getSidebarIdPrefix({})}projects-list` const breadcrumbsIdProjectList = `${getBreadcrumbsIdPrefix({})}projects-list` + const limitSp = searchParams.get('limit') + return ( = ({ inside }) => { apiVersion={apiVersion} typeName={typeName} key={`${apiGroup}-${apiVersion}-${namespace}-${typeName}`} - limit={searchParams.get('limit')} + limit={limitSp && limitSp.length > 0 ? Number(limitSp) : undefined} inside={inside} customizationIdPrefix={tableCustomizationIdPrefix} /> diff --git a/src/pages/TableBuiltinPage/TableBuiltinPage.tsx b/src/pages/TableBuiltinPage/TableBuiltinPage.tsx index d36f48b..e1b6f96 100644 --- a/src/pages/TableBuiltinPage/TableBuiltinPage.tsx +++ b/src/pages/TableBuiltinPage/TableBuiltinPage.tsx @@ -46,6 +46,8 @@ export const TableBuiltinPage: FC = ({ inside }) => { inside, }) + const limitSp = searchParams.get('limit') + return ( = ({ inside }) => { key={`${namespace}-${typeName}`} namespace={namespace} typeName={typeName} - limit={searchParams.get('limit')} + limit={limitSp && limitSp.length > 0 ? Number(limitSp) : undefined} inside={inside} customizationIdPrefix={tableCustomizationIdPrefix} /> diff --git a/src/pages/index.ts b/src/pages/index.ts index 82d8723..b032f86 100644 --- a/src/pages/index.ts +++ b/src/pages/index.ts @@ -19,3 +19,5 @@ export { FactoryPage } from './FactoryPage' export { FactoryAdminPage } from './FactoryAdminPage' /* search */ export { SearchPage } from './SearchPage' +/* list-then-watch */ +export { ListThenWatchPage } from './ListThenWatchPage' From 9af91a7ec5c72854d3b7309bc56ff500cc78088f Mon Sep 17 00:00:00 2001 From: typescreep Date: Thu, 6 Nov 2025 04:50:15 +0300 Subject: [PATCH 02/32] list-then-watch --- package-lock.json | 8 ++++---- package.json | 2 +- .../ManageableBreadcrumbs/ManageableBreadcrumbs.tsx | 8 ++++---- .../molecules/ManageableSidebar/ManageableSidebar.tsx | 6 ++++-- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1d1c035..a275bd3 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.160", + "@prorobotech/openapi-k8s-toolkit": "^0.0.1-alpha.161", "@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.160", - "resolved": "https://registry.npmjs.org/@prorobotech/openapi-k8s-toolkit/-/openapi-k8s-toolkit-0.0.1-alpha.160.tgz", - "integrity": "sha512-brg6dJ0Tw1YY88xbPBWp6E/+8LEmTIKvPqDvS5MKOKWK375jYu585hV+B5qxmseB3OMl/IJg1Dipn8D6QefCeA==", + "version": "0.0.1-alpha.161", + "resolved": "https://registry.npmjs.org/@prorobotech/openapi-k8s-toolkit/-/openapi-k8s-toolkit-0.0.1-alpha.161.tgz", + "integrity": "sha512-sjgfoyW46i+XLrMk8gzGx4t/DXcXiqyc4EQahyQmxSIBk6ipuKVJ7zblGOOB4uOQNLf64yNC0mDG2cRDIPk5ng==", "license": "MIT", "dependencies": { "@monaco-editor/react": "4.6.0", diff --git a/package.json b/package.json index 79a5bf0..e32eca8 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.160", + "@prorobotech/openapi-k8s-toolkit": "0.0.1-alpha.161", "@readme/openapi-parser": "4.0.0", "@reduxjs/toolkit": "2.2.5", "@tanstack/react-query": "5.62.2", diff --git a/src/components/molecules/ManageableBreadcrumbs/ManageableBreadcrumbs.tsx b/src/components/molecules/ManageableBreadcrumbs/ManageableBreadcrumbs.tsx index c154621..65a6304 100644 --- a/src/components/molecules/ManageableBreadcrumbs/ManageableBreadcrumbs.tsx +++ b/src/components/molecules/ManageableBreadcrumbs/ManageableBreadcrumbs.tsx @@ -32,10 +32,10 @@ export const ManageableBreadcrumbs: FC = ({ idToCom return ( = ({ $maxHeight={height} > Date: Thu, 6 Nov 2025 22:05:11 +0300 Subject: [PATCH 03/32] multiline height --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index a275bd3..2b4eef4 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.161", + "@prorobotech/openapi-k8s-toolkit": "^1.1.0-alpha.1", "@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.161", - "resolved": "https://registry.npmjs.org/@prorobotech/openapi-k8s-toolkit/-/openapi-k8s-toolkit-0.0.1-alpha.161.tgz", - "integrity": "sha512-sjgfoyW46i+XLrMk8gzGx4t/DXcXiqyc4EQahyQmxSIBk6ipuKVJ7zblGOOB4uOQNLf64yNC0mDG2cRDIPk5ng==", + "version": "1.1.0-alpha.1", + "resolved": "https://registry.npmjs.org/@prorobotech/openapi-k8s-toolkit/-/openapi-k8s-toolkit-1.1.0-alpha.1.tgz", + "integrity": "sha512-vuE+cysEhQj0SAUNO/ByJw1OLih5KQUkTEzoJZ4I135/ciQXpMOY9QnXlcTnFxwafb1rnk4APBsAuYPTR4SpyQ==", "license": "MIT", "dependencies": { "@monaco-editor/react": "4.6.0", diff --git a/package.json b/package.json index e32eca8..5baf5f4 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.161", + "@prorobotech/openapi-k8s-toolkit": "1.1.0-alpha.1", "@readme/openapi-parser": "4.0.0", "@reduxjs/toolkit": "2.2.5", "@tanstack/react-query": "5.62.2", From dd356a200cc900e7da31d4ef22490edc1eb842e2 Mon Sep 17 00:00:00 2001 From: typescreep Date: Fri, 7 Nov 2025 17:12:19 +0300 Subject: [PATCH 04/32] gated hook for resource fetching --- package-lock.json | 8 +- package.json | 2 +- .../ManageableBreadcrumbs.tsx | 2 +- .../ManageableSidebar/ManageableSidebar.tsx | 2 +- .../TableApiBuiltin/TableApiBuiltin.tsx | 192 +++++++----------- 5 files changed, 80 insertions(+), 126 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2b4eef4..702da31 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": "^1.1.0-alpha.1", + "@prorobotech/openapi-k8s-toolkit": "^1.1.0-alpha.2", "@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": "1.1.0-alpha.1", - "resolved": "https://registry.npmjs.org/@prorobotech/openapi-k8s-toolkit/-/openapi-k8s-toolkit-1.1.0-alpha.1.tgz", - "integrity": "sha512-vuE+cysEhQj0SAUNO/ByJw1OLih5KQUkTEzoJZ4I135/ciQXpMOY9QnXlcTnFxwafb1rnk4APBsAuYPTR4SpyQ==", + "version": "1.1.0-alpha.2", + "resolved": "https://registry.npmjs.org/@prorobotech/openapi-k8s-toolkit/-/openapi-k8s-toolkit-1.1.0-alpha.2.tgz", + "integrity": "sha512-aNOTBpOevJ1VqZ6e2w1yDpv//+4TGdk0j0fsJa465bOQJbFZLQIAxepZ+T2SY81mnVen24IMZhPBwn9VNEYJWA==", "license": "MIT", "dependencies": { "@monaco-editor/react": "4.6.0", diff --git a/package.json b/package.json index 5baf5f4..97662e1 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": "1.1.0-alpha.1", + "@prorobotech/openapi-k8s-toolkit": "1.1.0-alpha.2", "@readme/openapi-parser": "4.0.0", "@reduxjs/toolkit": "2.2.5", "@tanstack/react-query": "5.62.2", diff --git a/src/components/molecules/ManageableBreadcrumbs/ManageableBreadcrumbs.tsx b/src/components/molecules/ManageableBreadcrumbs/ManageableBreadcrumbs.tsx index 65a6304..6743c05 100644 --- a/src/components/molecules/ManageableBreadcrumbs/ManageableBreadcrumbs.tsx +++ b/src/components/molecules/ManageableBreadcrumbs/ManageableBreadcrumbs.tsx @@ -32,7 +32,7 @@ export const ManageableBreadcrumbs: FC = ({ idToCom return ( = ({ $maxHeight={height} > = ({ }) const { - state: stateCore, - status: statusCore, - lastError: lastErrorCore, - } = useListWatch({ - wsUrl: `/api/clusters/${cluster}/openapi-bff-ws/listThenWatch/listWatchWs`, - paused: false, - ignoreRemove: false, - autoDrain: true, - preserveStateOnUrlChange: true, - pageSize: limit, - query: { - namespace, - apiVersion: apiVersion || '', - plural: typeName, - labelSelector: labels ? encodeURIComponent(labels.join(',')) : undefined, - fieldSelector: fields ? encodeURIComponent(fields.join(',')) : undefined, - }, - isEnabled: resourceType === 'builtin', - }) - - const isPendingBuiltin = statusCore === 'connecting' - const errorBuiltin = statusCore === 'closed' && lastErrorCore ? lastErrorCore : undefined - const dataBuiltin = stateCore.order.map(key => { - const res = stateCore.byKey[key] - return res - }) - - const { - state: stateApi, - status: statusApi, - lastError: lastErrorApi, - } = useListWatch({ - wsUrl: `/api/clusters/${cluster}/openapi-bff-ws/listThenWatch/listWatchWs`, - paused: false, - ignoreRemove: false, - autoDrain: true, - preserveStateOnUrlChange: true, - pageSize: limit, - query: { - namespace, - apiGroup: apiGroup || '', - apiVersion: apiVersion || '', - plural: typeName, - labelSelector: labels ? labels.join(',') : undefined, - fieldSelector: fields ? fields.join(',') : undefined, - }, - isEnabled: resourceType === 'api' && !!apiGroup && !!apiVersion, - }) - - const isPendingApi = statusApi === 'connecting' - const errorApi = statusApi === 'closed' && lastErrorApi ? lastErrorApi : undefined - const dataApi = stateApi.order.map(key => { - const res = stateApi.byKey[key] - return res + data: dataItems, + isLoading, + error, + } = useK8sSmartResource<{ items: TSingleResource[] }>({ + cluster, + namespace, + group: apiGroup || undefined, + version: apiVersion || '', + plural: typeName, + labelSelector: labels ? encodeURIComponent(labels.join(',')) : undefined, + fieldSelector: fields ? encodeURIComponent(fields.join(',')) : undefined, + limit, }) const onDeleteHandle = (name: string, endpoint: string) => { @@ -218,70 +177,65 @@ export const TableApiBuiltin: FC = ({ return ( <> - {((resourceType === 'builtin' && isPendingBuiltin) || (resourceType === 'api' && isPendingApi)) && } - {resourceType === 'builtin' && errorBuiltin && ( - - )} - {resourceType === 'api' && errorApi && } + {isLoading && } + {error && } - {!errorBuiltin && - !errorApi && - ((resourceType === 'builtin' && dataBuiltin) || (resourceType === 'api' && dataApi)) && ( - { - setSelectedRowKeys(selectedRowKeys) - setSelectedRowsData(selectedRowsData) - }, - }} - tableProps={{ ...TABLE_PROPS, disablePagination: !searchMount }} - // maxHeight={height - 65} - /> - )} + {!error && dataItems && ( + { + setSelectedRowKeys(selectedRowKeys) + setSelectedRowsData(selectedRowsData) + }, + }} + tableProps={{ ...TABLE_PROPS, disablePagination: !searchMount }} + // maxHeight={height - 65} + /> + )} {/* {selectedRowKeys.length > 0 && ( From ac0b1099d506d92df11c3cefa9a49f932fa5b28e Mon Sep 17 00:00:00 2001 From: typescreep Date: Mon, 10 Nov 2025 04:50:14 +0300 Subject: [PATCH 05/32] multi query hybrid hook --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 702da31..36fdc3e 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": "^1.1.0-alpha.2", + "@prorobotech/openapi-k8s-toolkit": "^1.1.0-alpha.4", "@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": "1.1.0-alpha.2", - "resolved": "https://registry.npmjs.org/@prorobotech/openapi-k8s-toolkit/-/openapi-k8s-toolkit-1.1.0-alpha.2.tgz", - "integrity": "sha512-aNOTBpOevJ1VqZ6e2w1yDpv//+4TGdk0j0fsJa465bOQJbFZLQIAxepZ+T2SY81mnVen24IMZhPBwn9VNEYJWA==", + "version": "1.1.0-alpha.4", + "resolved": "https://registry.npmjs.org/@prorobotech/openapi-k8s-toolkit/-/openapi-k8s-toolkit-1.1.0-alpha.4.tgz", + "integrity": "sha512-sZ5y4CKwk7Rf9ShqGJDbba5yGbA4hz2FEXFm6fXkVm+qx6X6gp5IXVS26IgZD7H7ulAUIxcLR7FwxzU6Q9PSDA==", "license": "MIT", "dependencies": { "@monaco-editor/react": "4.6.0", diff --git a/package.json b/package.json index 97662e1..7c904fa 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": "1.1.0-alpha.2", + "@prorobotech/openapi-k8s-toolkit": "1.1.0-alpha.4", "@readme/openapi-parser": "4.0.0", "@reduxjs/toolkit": "2.2.5", "@tanstack/react-query": "5.62.2", From 1f463004caec66e53eb4052d5b5835571c5c30bd Mon Sep 17 00:00:00 2001 From: typescreep Date: Tue, 11 Nov 2025 02:05:24 +0300 Subject: [PATCH 06/32] uid to watchkey | factories websockets --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 36fdc3e..2c877fd 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": "^1.1.0-alpha.4", + "@prorobotech/openapi-k8s-toolkit": "^1.1.0-alpha.5", "@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": "1.1.0-alpha.4", - "resolved": "https://registry.npmjs.org/@prorobotech/openapi-k8s-toolkit/-/openapi-k8s-toolkit-1.1.0-alpha.4.tgz", - "integrity": "sha512-sZ5y4CKwk7Rf9ShqGJDbba5yGbA4hz2FEXFm6fXkVm+qx6X6gp5IXVS26IgZD7H7ulAUIxcLR7FwxzU6Q9PSDA==", + "version": "1.1.0-alpha.5", + "resolved": "https://registry.npmjs.org/@prorobotech/openapi-k8s-toolkit/-/openapi-k8s-toolkit-1.1.0-alpha.5.tgz", + "integrity": "sha512-JgRwGwNhhY7Rh7/c0QYzhWBMqQYwdVaef4ogwPNURJdXRext7gie5pSsxJVey2p1qc9O6K4AI4DQMEHccr8fcw==", "license": "MIT", "dependencies": { "@monaco-editor/react": "4.6.0", diff --git a/package.json b/package.json index 7c904fa..446cc63 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": "1.1.0-alpha.4", + "@prorobotech/openapi-k8s-toolkit": "1.1.0-alpha.5", "@readme/openapi-parser": "4.0.0", "@reduxjs/toolkit": "2.2.5", "@tanstack/react-query": "5.62.2", From aec50c47db5ebcea917910d43d409f1edcc7efa1 Mon Sep 17 00:00:00 2001 From: typescreep Date: Tue, 11 Nov 2025 02:21:18 +0300 Subject: [PATCH 07/32] factories, navigation resource via hooks --- src/components/organisms/Factory/Factory.tsx | 19 ++++++++---- .../organisms/Selector/Selector.tsx | 29 +++++++++++++---- .../SelectorNamespace/SelectorNamespace.tsx | 31 +++++++++++++++---- src/hooks/useNavSelector/useNavSelector.ts | 29 +++++++++++++---- 4 files changed, 84 insertions(+), 24 deletions(-) diff --git a/src/components/organisms/Factory/Factory.tsx b/src/components/organisms/Factory/Factory.tsx index 2da5374..6ed21ae 100644 --- a/src/components/organisms/Factory/Factory.tsx +++ b/src/components/organisms/Factory/Factory.tsx @@ -4,7 +4,8 @@ import { DynamicComponents, DynamicRendererWithProviders, TDynamicComponentsAppTypeMap, - useDirectUnknownResource, + // useDirectUnknownResource, + useK8sSmartResource, TFactoryResponse, ContentCard, } from '@prorobotech/openapi-k8s-toolkit' @@ -44,11 +45,17 @@ export const Factory: FC = ({ setSidebarTags }) => { } }, []) - const { data: factoryData } = useDirectUnknownResource>({ - uri: `/api/clusters/${cluster}/k8s/apis/${BASE_API_GROUP}/${BASE_API_VERSION}/factories/`, - refetchInterval: false, - queryKey: ['factories', cluster || 'no-cluster'], - isEnabled: cluster !== undefined, + // const { data: factoryData } = useDirectUnknownResource>({ + // uri: `/api/clusters/${cluster}/k8s/apis/${BASE_API_GROUP}/${BASE_API_VERSION}/factories/`, + // refetchInterval: false, + // queryKey: ['factories', cluster || 'no-cluster'], + // isEnabled: cluster !== undefined, + // }) + const { data: factoryData } = useK8sSmartResource>({ + cluster, + group: BASE_API_GROUP, + version: BASE_API_VERSION, + plural: 'factories', }) const { spec } = factoryData?.items.find(({ spec }) => spec.key === key) ?? { spec: undefined } diff --git a/src/components/organisms/HeaderSecond/organisms/Selector/Selector.tsx b/src/components/organisms/HeaderSecond/organisms/Selector/Selector.tsx index a7c0cdb..9fdfeda 100644 --- a/src/components/organisms/HeaderSecond/organisms/Selector/Selector.tsx +++ b/src/components/organisms/HeaderSecond/organisms/Selector/Selector.tsx @@ -1,7 +1,10 @@ import React, { FC, useState } from 'react' import { Flex, Typography } from 'antd' import { useNavigate } from 'react-router-dom' -import { useDirectUnknownResource } from '@prorobotech/openapi-k8s-toolkit' +import { + // useDirectUnknownResource, + useK8sSmartResource, +} from '@prorobotech/openapi-k8s-toolkit' import { useNavSelector } from 'hooks/useNavSelector' import { useMountEffect } from 'hooks/useMountEffect' import { EntrySelect } from 'components/atoms' @@ -31,15 +34,29 @@ export const Selector: FC = ({ clusterName, projectName, instanc projectName, ) - const { data: navigationData } = useDirectUnknownResource<{ - spec: { projects: { clear: string; change: string }; instances: { clear: string; change: string } } + // const { data: navigationData } = useDirectUnknownResource<{ + // spec: { projects: { clear: string; change: string }; instances: { clear: string; change: string } } + // }>({ + // uri: `/api/clusters/${clusterName}/k8s/apis/${BASE_API_GROUP}/${BASE_API_VERSION}/${BASE_CUSTOMIZATION_NAVIGATION_RESOURCE_NAME}/${BASE_CUSTOMIZATION_NAVIGATION_RESOURCE}`, + // refetchInterval: false, + // queryKey: ['navigation', clusterName || 'no-cluster'], + // isEnabled: clusterName !== undefined, + // }) + + const { data: navigationDataArr } = useK8sSmartResource<{ + items: { spec: { projects: { clear: string; change: string }; instances: { clear: string; change: string } } }[] }>({ - uri: `/api/clusters/${clusterName}/k8s/apis/${BASE_API_GROUP}/${BASE_API_VERSION}/${BASE_CUSTOMIZATION_NAVIGATION_RESOURCE_NAME}/${BASE_CUSTOMIZATION_NAVIGATION_RESOURCE}`, - refetchInterval: false, - queryKey: ['navigation', clusterName || 'no-cluster'], + cluster: clusterName || '', + group: BASE_API_GROUP, + version: BASE_API_VERSION, + plural: BASE_CUSTOMIZATION_NAVIGATION_RESOURCE_NAME, + fieldSelector: `metadata.name=${BASE_CUSTOMIZATION_NAVIGATION_RESOURCE}`, isEnabled: clusterName !== undefined, }) + const navigationData = + navigationDataArr?.items && navigationDataArr.items.length > 0 ? navigationDataArr.items[0] : undefined + // const handleClusterChange = (value: string) => { // setSelectedClusterName(value) // navigate(`${baseprefix}/clusters/${value}`) diff --git a/src/components/organisms/HeaderSecond/organisms/SelectorNamespace/SelectorNamespace.tsx b/src/components/organisms/HeaderSecond/organisms/SelectorNamespace/SelectorNamespace.tsx index c3bf2a1..46c9ce5 100644 --- a/src/components/organisms/HeaderSecond/organisms/SelectorNamespace/SelectorNamespace.tsx +++ b/src/components/organisms/HeaderSecond/organisms/SelectorNamespace/SelectorNamespace.tsx @@ -1,7 +1,10 @@ import React, { FC, useState } from 'react' import { Flex, Typography } from 'antd' import { useLocation, useNavigate } from 'react-router-dom' -import { useDirectUnknownResource } from '@prorobotech/openapi-k8s-toolkit' +import { + // useDirectUnknownResource, + useK8sSmartResource, +} from '@prorobotech/openapi-k8s-toolkit' import { useSelector } from 'react-redux' import type { RootState } from 'store/store' import { useNavSelectorInside } from 'hooks/useNavSelectorInside' @@ -31,15 +34,31 @@ export const SelectorNamespace: FC = ({ clusterName, na const { namespacesInSidebar } = useNavSelectorInside(selectedClusterName) - const { data: navigationData } = useDirectUnknownResource<{ - spec: { namespaces: { clear: string; change: string } } + // const { data: navigationData } = useDirectUnknownResource<{ + // spec: { namespaces: { clear: string; change: string } } + // }>({ + // uri: `/api/clusters/${clusterName}/k8s/apis/${BASE_API_GROUP}/${BASE_API_VERSION}/${BASE_CUSTOMIZATION_NAVIGATION_RESOURCE_NAME}/${BASE_CUSTOMIZATION_NAVIGATION_RESOURCE}`, + // refetchInterval: false, + // queryKey: ['navigation', clusterName || 'no-cluster'], + // isEnabled: clusterName !== undefined, + // }) + + const { data: navigationDataArr } = useK8sSmartResource<{ + items: { + spec: { namespaces: { clear: string; change: string } } + }[] }>({ - uri: `/api/clusters/${clusterName}/k8s/apis/${BASE_API_GROUP}/${BASE_API_VERSION}/${BASE_CUSTOMIZATION_NAVIGATION_RESOURCE_NAME}/${BASE_CUSTOMIZATION_NAVIGATION_RESOURCE}`, - refetchInterval: false, - queryKey: ['navigation', clusterName || 'no-cluster'], + cluster: clusterName || '', + group: BASE_API_GROUP, + version: BASE_API_VERSION, + plural: BASE_CUSTOMIZATION_NAVIGATION_RESOURCE_NAME, + fieldSelector: `metadata.name=${BASE_CUSTOMIZATION_NAVIGATION_RESOURCE}`, isEnabled: clusterName !== undefined, }) + const navigationData = + navigationDataArr?.items && navigationDataArr.items.length > 0 ? navigationDataArr.items[0] : undefined + const isSearchPage = useIsSearchPage(baseprefix || '') const handleNamepsaceChange = (value?: string) => { diff --git a/src/hooks/useNavSelector/useNavSelector.ts b/src/hooks/useNavSelector/useNavSelector.ts index 4bc12ef..e338a32 100644 --- a/src/hooks/useNavSelector/useNavSelector.ts +++ b/src/hooks/useNavSelector/useNavSelector.ts @@ -2,7 +2,8 @@ import { useApiResources, TClusterList, TSingleResource, - useDirectUnknownResource, + // useDirectUnknownResource, + useK8sSmartResource, } from '@prorobotech/openapi-k8s-toolkit' import { useSelector } from 'react-redux' import { RootState } from 'store/store' @@ -50,15 +51,31 @@ const mappedInstanceToOptionInSidebar = ({ export const useNavSelector = (clusterName?: string, projectName?: string) => { const clusterList = useSelector((state: RootState) => state.clusterList.clusterList) - const { data: navigationData } = useDirectUnknownResource<{ - spec: { instances: { mapOptionsPattern: string } } + // const { data: navigationData } = useDirectUnknownResource<{ + // spec: { instances: { mapOptionsPattern: string } } + // }>({ + // uri: `/api/clusters/${clusterName}/k8s/apis/${BASE_API_GROUP}/${BASE_API_VERSION}/${BASE_CUSTOMIZATION_NAVIGATION_RESOURCE_NAME}/${BASE_CUSTOMIZATION_NAVIGATION_RESOURCE}`, + // refetchInterval: false, + // queryKey: ['navigation', clusterName || 'no-cluster'], + // isEnabled: clusterName !== undefined, + // }) + + const { data: navigationDataArr } = useK8sSmartResource<{ + items: { + spec: { instances: { mapOptionsPattern: string } } + }[] }>({ - uri: `/api/clusters/${clusterName}/k8s/apis/${BASE_API_GROUP}/${BASE_API_VERSION}/${BASE_CUSTOMIZATION_NAVIGATION_RESOURCE_NAME}/${BASE_CUSTOMIZATION_NAVIGATION_RESOURCE}`, - refetchInterval: false, - queryKey: ['navigation', clusterName || 'no-cluster'], + cluster: clusterName || '', + group: BASE_API_GROUP, + version: BASE_API_VERSION, + plural: BASE_CUSTOMIZATION_NAVIGATION_RESOURCE_NAME, + fieldSelector: `metadata.name=${BASE_CUSTOMIZATION_NAVIGATION_RESOURCE}`, isEnabled: clusterName !== undefined, }) + const navigationData = + navigationDataArr?.items && navigationDataArr.items.length > 0 ? navigationDataArr.items[0] : undefined + const { data: projects } = useApiResources({ clusterName: clusterName || '', namespace: '', From a7d98362dd135548599354583ab402fdfc3aacd5 Mon Sep 17 00:00:00 2001 From: typescreep Date: Tue, 11 Nov 2025 02:32:11 +0300 Subject: [PATCH 08/32] crds sockets --- .../molecules/TableCrdInfo/TableCrdInfo.tsx | 36 ++++++++++++--- .../molecules/ResourceInfo/ResourceInfo.tsx | 29 +++++++++--- .../Forms/CrdsForms/UpdateCrdsForm.tsx | 46 +++++++++++++++---- 3 files changed, 89 insertions(+), 22 deletions(-) diff --git a/src/components/molecules/TableCrdInfo/TableCrdInfo.tsx b/src/components/molecules/TableCrdInfo/TableCrdInfo.tsx index fbd8519..72cc1bc 100644 --- a/src/components/molecules/TableCrdInfo/TableCrdInfo.tsx +++ b/src/components/molecules/TableCrdInfo/TableCrdInfo.tsx @@ -1,6 +1,12 @@ import React, { FC, useState, useEffect } from 'react' import { Spin, Alert } from 'antd' -import { usePermissions, checkIfApiInstanceNamespaceScoped, useCrdData } from '@prorobotech/openapi-k8s-toolkit' +import { + usePermissions, + checkIfApiInstanceNamespaceScoped, + // useCrdData, + useK8sSmartResource, + TCRD, +} from '@prorobotech/openapi-k8s-toolkit' import { useSelector } from 'react-redux' import { RootState } from 'store/store' import { ResourceInfo } from './molecules' @@ -28,12 +34,28 @@ export const TableCrdInfo: FC = ({ const [isNamespaced, setIsNamespaced] = useState() - const { isPending, error, data } = useCrdData({ - clusterName: cluster, - crdName, - apiExtensionVersion, + // const { isPending, error, data } = useCrdData({ + // clusterName: cluster, + // crdName, + // apiExtensionVersion, + // }) + + const { + data: dataArr, + isLoading: isPending, + error, + } = useK8sSmartResource<{ + items: TCRD[] + }>({ + cluster, + group: 'apiextensions.k8s.io', + version: apiExtensionVersion, + plural: 'customresourcedefinitions', + fieldSelector: `metadata.name=${crdName}`, }) + const data = dataArr?.items && dataArr.items.length > 0 ? dataArr.items[0] : undefined + useEffect(() => { if (data && !isPending && !error) { checkIfApiInstanceNamespaceScoped({ @@ -79,7 +101,9 @@ export const TableCrdInfo: FC = ({ return ( <> {isPending && } - {error && } + {error && ( + + )} {!error && data && data.spec && ( = ({ } }, []) - const { isPending, error, data } = useCrdResources({ - clusterName, - namespace, - apiGroup, - apiVersion, - crdName: crdPluralName, + // const { isPending, error, data } = useCrdResources({ + // clusterName, + // namespace, + // apiGroup, + // apiVersion, + // crdName: crdPluralName, + // }) + + const { + data, + isLoading: isPending, + error, + } = useK8sSmartResource<{ + items: TJSON[] + }>({ + cluster: clusterName, + group: apiGroup, + version: apiVersion, + plural: crdPluralName, }) let resourceSchema = {} diff --git a/src/components/organisms/Forms/CrdsForms/UpdateCrdsForm.tsx b/src/components/organisms/Forms/CrdsForms/UpdateCrdsForm.tsx index 35714cb..7f4cb5d 100644 --- a/src/components/organisms/Forms/CrdsForms/UpdateCrdsForm.tsx +++ b/src/components/organisms/Forms/CrdsForms/UpdateCrdsForm.tsx @@ -1,6 +1,11 @@ import React, { FC, useState } from 'react' import { Spin, Alert, Segmented } from 'antd' -import { useCrdResourceSingle, Spacer } from '@prorobotech/openapi-k8s-toolkit' +import { + // useCrdResourceSingle, + useK8sSmartResource, + TSingleResource, + Spacer, +} from '@prorobotech/openapi-k8s-toolkit' import { useSelector } from 'react-redux' import { RootState } from 'store/store' import { BlackholeForm } from 'components' @@ -41,22 +46,45 @@ export const UpdateCrdsForm: FC = ({ onDisabled: onCurrentModeDisabled, } - const { data, isPending, error } = useCrdResourceSingle({ - clusterName: cluster, + // const { data, isPending, error } = useCrdResourceSingle({ + // clusterName: cluster, + // namespace, + // apiGroup, + // apiVersion, + // crdName: typeName, + // entryName, + // refetchInterval: false, + // }) + + const { + data: dataArr, + isLoading: isPending, + error, + } = useK8sSmartResource<{ + items: TSingleResource[] + }>({ + cluster, namespace, - apiGroup, - apiVersion, - crdName: typeName, - entryName, - refetchInterval: false, + group: apiGroup, + version: apiVersion, + plural: typeName, + fieldSelector: `metadata.name=${entryName}`, }) + const data = dataArr?.items && dataArr.items.length > 0 ? dataArr.items[0] : undefined + if (isPending) { return } if (error) { - return + return ( + + ) + } + + if (!data) { + return } /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ From 10cfafaf471a451822001455e25c130ca8381617 Mon Sep 17 00:00:00 2001 From: typescreep Date: Tue, 11 Nov 2025 02:52:02 +0300 Subject: [PATCH 09/32] navs hooks --- .../ListInsideClusterAndNs.tsx | 61 ++++++++++++++----- src/hooks/useNavSelector/useNavSelector.ts | 58 +++++++++++++----- src/hooks/useNavSelectorInside.ts | 49 +++++++++++---- 3 files changed, 127 insertions(+), 41 deletions(-) diff --git a/src/components/organisms/ListInsideClusterAndNs/ListInsideClusterAndNs.tsx b/src/components/organisms/ListInsideClusterAndNs/ListInsideClusterAndNs.tsx index 4f52a36..8576d24 100644 --- a/src/components/organisms/ListInsideClusterAndNs/ListInsideClusterAndNs.tsx +++ b/src/components/organisms/ListInsideClusterAndNs/ListInsideClusterAndNs.tsx @@ -1,6 +1,14 @@ +/* eslint-disable no-nested-ternary */ import React, { FC, useState } from 'react' import { Button, Alert, Spin, Typography } from 'antd' -import { filterSelectOptions, Spacer, useBuiltinResources, useApiResources } from '@prorobotech/openapi-k8s-toolkit' +import { + filterSelectOptions, + Spacer, + TSingleResource, + // useBuiltinResources, + // useApiResources, + useK8sSmartResource, +} from '@prorobotech/openapi-k8s-toolkit' import { useNavigate } from 'react-router-dom' import { useSelector, useDispatch } from 'react-redux' import { RootState } from 'store/store' @@ -33,20 +41,39 @@ export const ListInsideClusterAndNs: FC = () => { 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, + // const namespacesData = useBuiltinResources({ + // clusterName: selectedCluster || '', + // typeName: 'namespaces', + // limit: null, + // isEnabled: Boolean(selectedCluster !== undefined && !isCustomNamespaceResource), + // }) + + const namespacesData = useK8sSmartResource<{ + items: TSingleResource[] + }>({ + cluster: selectedCluster || '', + version: 'v1', + plural: 'namespaces', isEnabled: Boolean(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: Boolean(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: Boolean(selectedCluster !== undefined && isCustomNamespaceResource), + // }) + + const namespacesDataCustom = useK8sSmartResource<{ + items: TSingleResource[] + }>({ + cluster: selectedCluster || '', + group: CUSTOM_NAMESPACE_API_RESOURCE_API_GROUP, + version: CUSTOM_NAMESPACE_API_RESOURCE_API_VERSION, + plural: CUSTOM_NAMESPACE_API_RESOURCE_RESOURCE_NAME, + isEnabled: Boolean(selectedCluster !== undefined && !isCustomNamespaceResource), }) return ( @@ -80,13 +107,19 @@ export const ListInsideClusterAndNs: FC = () => { /> )} - {selectedCluster && (isCustomNamespaceResource ? namespacesDataCustom.isPending : namespacesData.isPending) && ( + {selectedCluster && (isCustomNamespaceResource ? namespacesDataCustom.isLoading : namespacesData.isLoading) && ( )} {selectedCluster && (isCustomNamespaceResource ? namespacesDataCustom.error : namespacesData.error) && ( diff --git a/src/hooks/useNavSelector/useNavSelector.ts b/src/hooks/useNavSelector/useNavSelector.ts index e338a32..1ae504e 100644 --- a/src/hooks/useNavSelector/useNavSelector.ts +++ b/src/hooks/useNavSelector/useNavSelector.ts @@ -1,5 +1,5 @@ import { - useApiResources, + // useApiResources, TClusterList, TSingleResource, // useDirectUnknownResource, @@ -76,26 +76,54 @@ export const useNavSelector = (clusterName?: string, projectName?: string) => { const navigationData = navigationDataArr?.items && navigationDataArr.items.length > 0 ? navigationDataArr.items[0] : undefined - const { data: projects } = useApiResources({ - clusterName: clusterName || '', - namespace: '', - apiGroup: BASE_PROJECTS_API_GROUP, - apiVersion: BASE_PROJECTS_VERSION, - typeName: BASE_PROJECTS_RESOURCE_NAME, - limit: null, + // const { data: projects } = useApiResources({ + // clusterName: clusterName || '', + // namespace: '', + // apiGroup: BASE_PROJECTS_API_GROUP, + // apiVersion: BASE_PROJECTS_VERSION, + // typeName: BASE_PROJECTS_RESOURCE_NAME, + // limit: null, + // isEnabled: clusterName !== undefined, + // }) + + const { data: projects } = useK8sSmartResource<{ + items: TSingleResource[] + }>({ + cluster: clusterName || '', + group: BASE_PROJECTS_API_GROUP, + version: BASE_PROJECTS_VERSION, + plural: BASE_PROJECTS_RESOURCE_NAME, isEnabled: clusterName !== undefined, }) - const { data: instances, isSuccess: allInstancesLoadingSuccess } = useApiResources({ - clusterName: clusterName || '', - namespace: '', - apiGroup: BASE_INSTANCES_API_GROUP, - apiVersion: BASE_INSTANCES_VERSION, - typeName: BASE_INSTANCES_RESOURCE_NAME, - limit: null, + // const { data: instances, isSuccess: allInstancesLoadingSuccess } = useApiResources({ + // clusterName: clusterName || '', + // namespace: '', + // apiGroup: BASE_INSTANCES_API_GROUP, + // apiVersion: BASE_INSTANCES_VERSION, + // typeName: BASE_INSTANCES_RESOURCE_NAME, + // limit: null, + // isEnabled: clusterName !== undefined, + // }) + + const { + data: instances, + isLoading: isInstancesLoading, + isError: isInstancesError, + } = useK8sSmartResource<{ + items: TSingleResource[] + }>({ + cluster: clusterName || '', + group: BASE_INSTANCES_API_GROUP, + version: BASE_INSTANCES_VERSION, + plural: BASE_INSTANCES_RESOURCE_NAME, isEnabled: clusterName !== undefined, }) + const allInstancesLoadingSuccess: boolean = Boolean( + instances && instances.items && !isInstancesError && !isInstancesLoading, + ) + const clustersInSidebar = clusterList ? clusterList.map(mappedClusterToOptionInSidebar) : [] const projectsInSidebar = clusterName && projects ? projects.items.map(mappedProjectToOptionInSidebar) : [] const instancesInSidebar = diff --git a/src/hooks/useNavSelectorInside.ts b/src/hooks/useNavSelectorInside.ts index 7358170..58c4b06 100644 --- a/src/hooks/useNavSelectorInside.ts +++ b/src/hooks/useNavSelectorInside.ts @@ -1,4 +1,10 @@ -import { TClusterList, TSingleResource, useBuiltinResources, useApiResources } from '@prorobotech/openapi-k8s-toolkit' +import { + TClusterList, + TSingleResource, + // useBuiltinResources, + // useApiResources, + useK8sSmartResource, +} from '@prorobotech/openapi-k8s-toolkit' import { useSelector } from 'react-redux' import { RootState } from 'store/store' import { @@ -31,20 +37,39 @@ export const useNavSelectorInside = (clusterName?: string) => { typeof CUSTOM_NAMESPACE_API_RESOURCE_RESOURCE_NAME === 'string' && CUSTOM_NAMESPACE_API_RESOURCE_RESOURCE_NAME.length > 0 - const { data: namespaces } = useBuiltinResources({ - clusterName: clusterName || '', - typeName: 'namespaces', - limit: null, + // const { data: namespaces } = useBuiltinResources({ + // clusterName: clusterName || '', + // typeName: 'namespaces', + // limit: null, + // isEnabled: Boolean(clusterName !== undefined && !isCustomNamespaceResource), + // }) + + const { data: namespaces } = useK8sSmartResource<{ + items: TSingleResource[] + }>({ + cluster: clusterName || '', + version: 'v1', + plural: 'namespaces', isEnabled: Boolean(clusterName !== undefined && !isCustomNamespaceResource), }) - const { data: namespacesCustom } = useApiResources({ - clusterName: clusterName || '', - apiGroup: CUSTOM_NAMESPACE_API_RESOURCE_API_GROUP, - apiVersion: CUSTOM_NAMESPACE_API_RESOURCE_API_VERSION, - typeName: CUSTOM_NAMESPACE_API_RESOURCE_RESOURCE_NAME, - limit: null, - isEnabled: Boolean(clusterName !== undefined && isCustomNamespaceResource), + // const { data: namespacesCustom } = useApiResources({ + // clusterName: clusterName || '', + // apiGroup: CUSTOM_NAMESPACE_API_RESOURCE_API_GROUP, + // apiVersion: CUSTOM_NAMESPACE_API_RESOURCE_API_VERSION, + // typeName: CUSTOM_NAMESPACE_API_RESOURCE_RESOURCE_NAME, + // limit: null, + // isEnabled: Boolean(clusterName !== undefined && isCustomNamespaceResource), + // }) + + const { data: namespacesCustom } = useK8sSmartResource<{ + items: TSingleResource[] + }>({ + cluster: clusterName || '', + group: CUSTOM_NAMESPACE_API_RESOURCE_API_GROUP, + version: CUSTOM_NAMESPACE_API_RESOURCE_API_VERSION, + plural: CUSTOM_NAMESPACE_API_RESOURCE_RESOURCE_NAME, + isEnabled: Boolean(clusterName !== undefined && !isCustomNamespaceResource), }) const clustersInSidebar = clusterList ? clusterList.map(mappedClusterToOptionInSidebar) : [] From dfd83addb6bfeb68c96e7238fb7006825183ed43 Mon Sep 17 00:00:00 2001 From: typescreep Date: Tue, 11 Nov 2025 04:01:35 +0300 Subject: [PATCH 10/32] handle wsurl change before connect --- .../ListInsideClusterAndNs/ListInsideClusterAndNs.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/organisms/ListInsideClusterAndNs/ListInsideClusterAndNs.tsx b/src/components/organisms/ListInsideClusterAndNs/ListInsideClusterAndNs.tsx index 8576d24..b3e752c 100644 --- a/src/components/organisms/ListInsideClusterAndNs/ListInsideClusterAndNs.tsx +++ b/src/components/organisms/ListInsideClusterAndNs/ListInsideClusterAndNs.tsx @@ -30,7 +30,7 @@ export const ListInsideClusterAndNs: FC = () => { const [selectedCluster, setSelectedCluster] = useState() const [selectedNamespace, setSelectedNamespace] = useState() - const isCustomNamespaceResource = + const isCustomNamespaceResource: boolean = CUSTOM_NAMESPACE_API_RESOURCE_API_GROUP && typeof CUSTOM_NAMESPACE_API_RESOURCE_API_GROUP === 'string' && CUSTOM_NAMESPACE_API_RESOURCE_API_GROUP.length > 0 && @@ -73,7 +73,7 @@ export const ListInsideClusterAndNs: FC = () => { group: CUSTOM_NAMESPACE_API_RESOURCE_API_GROUP, version: CUSTOM_NAMESPACE_API_RESOURCE_API_VERSION, plural: CUSTOM_NAMESPACE_API_RESOURCE_RESOURCE_NAME, - isEnabled: Boolean(selectedCluster !== undefined && !isCustomNamespaceResource), + isEnabled: Boolean(selectedCluster !== undefined && isCustomNamespaceResource), }) return ( From 67d5b09bab691b07ac07c8ffc66efa75391cc10e Mon Sep 17 00:00:00 2001 From: typescreep Date: Tue, 11 Nov 2025 05:29:33 +0300 Subject: [PATCH 11/32] outlets --- src/App.tsx | 86 ++++-------- .../FactoryAdminPage/AddComponentModal.tsx | 52 ------- src/pages/FactoryAdminPage/AntdCardForm.tsx | 73 ---------- src/pages/FactoryAdminPage/AntdTextForm.tsx | 55 -------- .../FactoryAdminPage/AppComponentAdmin.tsx | 128 ------------------ src/pages/FactoryAdminPage/ComponentForm.tsx | 15 -- src/pages/FactoryAdminPage/ComponentForm2.tsx | 27 ---- src/pages/FactoryAdminPage/ComponentNode.tsx | 64 --------- .../FactoryAdminPage/DynamicComponentForm.tsx | 111 --------------- .../FactoryAdminPage/EditComponentModal.tsx | 34 ----- src/pages/FactoryAdminPage/TextWithIdForm.tsx | 39 ------ src/pages/FactoryAdminPage/index.ts | 1 - src/pages/FactoryAdminPage/types.ts | 26 ---- src/pages/FactoryAdminPage/utils.ts | 111 --------------- src/pages/FactoryPage/FactoryPage.tsx | 53 +++----- src/pages/FormApiPage/FormApiPage.tsx | 97 ------------- src/pages/FormBuiltinPage/FormBuiltinPage.tsx | 82 ----------- src/pages/FormCrdPage/FormCrdPage.tsx | 97 ------------- src/pages/Forms/FormApiPage/FormApiPage.tsx | 87 ++++++++++++ src/pages/{ => Forms}/FormApiPage/index.ts | 0 .../Forms/FormBuiltinPage/FormBuiltinPage.tsx | 71 ++++++++++ .../{ => Forms}/FormBuiltinPage/index.ts | 0 src/pages/Forms/FormCrdPage/FormCrdPage.tsx | 87 ++++++++++++ src/pages/{ => Forms}/FormCrdPage/index.ts | 0 src/pages/Forms/index.ts | 3 + .../ListInsideApiByApiGroupPage.tsx | 0 .../ListInsideApiByApiGroupPage/index.ts | 0 .../ListInsideApiPage/ListInsideApiPage.tsx | 0 .../{ => Insides}/ListInsideApiPage/index.ts | 0 .../ListInsideClustersAndNsPage.tsx | 0 .../ListInsideClustersAndNsPage/index.ts | 0 .../ListInsideCrdByApiGroupPage.tsx | 0 .../ListInsideCrdByApiGroupPage/index.ts | 0 src/pages/Insides/index.ts | 4 + .../ListThenWatchPage/ListThenWatchPage.tsx | 81 ----------- src/pages/ListThenWatchPage/index.ts | 1 - src/pages/TableApiPage/TableApiPage.tsx | 97 ------------- .../TableBuiltinPage/TableBuiltinPage.tsx | 83 ------------ src/pages/TableCrdPage/TableCrdPage.tsx | 79 ----------- .../Tables/TableApiPage/TableApiPage.tsx | 103 ++++++++++++++ src/pages/{ => Tables}/TableApiPage/index.ts | 0 .../TableBuiltinPage/TableBuiltinPage.tsx | 86 ++++++++++++ .../{ => Tables}/TableBuiltinPage/index.ts | 0 .../Tables/TableCrdPage/TableCrdPage.tsx | 84 ++++++++++++ src/pages/{ => Tables}/TableCrdPage/index.ts | 0 src/pages/Tables/index.ts | 3 + src/pages/index.ts | 33 +++-- src/templates/AppShell/AppShell.tsx | 88 ++++++++++++ src/templates/AppShell/index.ts | 2 + src/templates/index.ts | 3 + 50 files changed, 680 insertions(+), 1466 deletions(-) delete mode 100644 src/pages/FactoryAdminPage/AddComponentModal.tsx delete mode 100644 src/pages/FactoryAdminPage/AntdCardForm.tsx delete mode 100644 src/pages/FactoryAdminPage/AntdTextForm.tsx delete mode 100644 src/pages/FactoryAdminPage/AppComponentAdmin.tsx delete mode 100644 src/pages/FactoryAdminPage/ComponentForm.tsx delete mode 100644 src/pages/FactoryAdminPage/ComponentForm2.tsx delete mode 100644 src/pages/FactoryAdminPage/ComponentNode.tsx delete mode 100644 src/pages/FactoryAdminPage/DynamicComponentForm.tsx delete mode 100644 src/pages/FactoryAdminPage/EditComponentModal.tsx delete mode 100644 src/pages/FactoryAdminPage/TextWithIdForm.tsx delete mode 100644 src/pages/FactoryAdminPage/index.ts delete mode 100644 src/pages/FactoryAdminPage/types.ts delete mode 100644 src/pages/FactoryAdminPage/utils.ts delete mode 100644 src/pages/FormApiPage/FormApiPage.tsx delete mode 100644 src/pages/FormBuiltinPage/FormBuiltinPage.tsx delete mode 100644 src/pages/FormCrdPage/FormCrdPage.tsx create mode 100644 src/pages/Forms/FormApiPage/FormApiPage.tsx rename src/pages/{ => Forms}/FormApiPage/index.ts (100%) create mode 100644 src/pages/Forms/FormBuiltinPage/FormBuiltinPage.tsx rename src/pages/{ => Forms}/FormBuiltinPage/index.ts (100%) create mode 100644 src/pages/Forms/FormCrdPage/FormCrdPage.tsx rename src/pages/{ => Forms}/FormCrdPage/index.ts (100%) create mode 100644 src/pages/Forms/index.ts rename src/pages/{ => Insides}/ListInsideApiByApiGroupPage/ListInsideApiByApiGroupPage.tsx (100%) rename src/pages/{ => Insides}/ListInsideApiByApiGroupPage/index.ts (100%) rename src/pages/{ => Insides}/ListInsideApiPage/ListInsideApiPage.tsx (100%) rename src/pages/{ => Insides}/ListInsideApiPage/index.ts (100%) rename src/pages/{ => Insides}/ListInsideClustersAndNsPage/ListInsideClustersAndNsPage.tsx (100%) rename src/pages/{ => Insides}/ListInsideClustersAndNsPage/index.ts (100%) rename src/pages/{ => Insides}/ListInsideCrdByApiGroupPage/ListInsideCrdByApiGroupPage.tsx (100%) rename src/pages/{ => Insides}/ListInsideCrdByApiGroupPage/index.ts (100%) create mode 100644 src/pages/Insides/index.ts delete mode 100644 src/pages/ListThenWatchPage/ListThenWatchPage.tsx delete mode 100644 src/pages/ListThenWatchPage/index.ts delete mode 100644 src/pages/TableApiPage/TableApiPage.tsx delete mode 100644 src/pages/TableBuiltinPage/TableBuiltinPage.tsx delete mode 100644 src/pages/TableCrdPage/TableCrdPage.tsx create mode 100644 src/pages/Tables/TableApiPage/TableApiPage.tsx rename src/pages/{ => Tables}/TableApiPage/index.ts (100%) create mode 100644 src/pages/Tables/TableBuiltinPage/TableBuiltinPage.tsx rename src/pages/{ => Tables}/TableBuiltinPage/index.ts (100%) create mode 100644 src/pages/Tables/TableCrdPage/TableCrdPage.tsx rename src/pages/{ => Tables}/TableCrdPage/index.ts (100%) create mode 100644 src/pages/Tables/index.ts create mode 100644 src/templates/AppShell/AppShell.tsx create mode 100644 src/templates/AppShell/index.ts diff --git a/src/App.tsx b/src/App.tsx index ecae2df..e97f190 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -18,20 +18,19 @@ import { ListInsideApiPage, ListInsideCrdByApiGroupPage, ListInsideApiByApiGroupPage, - TableCrdPage, + // TableCrdPage, TableApiPage, TableBuiltinPage, FormBuiltinPage, FormApiPage, - FormCrdPage, + // FormCrdPage, FactoryPage, - FactoryAdminPage, + // FactoryAdminPage, SearchPage, - ListThenWatchPage, } from 'pages' import { getBasePrefix } from 'utils/getBaseprefix' import { colorsLight, colorsDark, sizes } from 'constants/colors' -import { MainLayout } from 'templates/MainLayout' +import { MainLayout, AppShell } from 'templates' type TAppProps = { isFederation?: boolean @@ -62,6 +61,25 @@ export const App: FC = ({ isFederation, forcedTheme }) => { } /> } /> } /> + + }> + {/* } /> */} + } /> + } /> + {/* } /> */} + } /> + } /> + } /> + + }> + {/* } /> */} + } /> + } /> + {/* } /> */} + } /> + } /> + + } /> } /> = ({ isFederation, forcedTheme }) => { path={`${prefix}/inside/:clusterName/:namespace?/apis-by-api/:apiGroup/:apiVersion/`} element={} /> - } - /> - } - /> - } - /> - } - /> - } - /> - } - /> - } - /> - } - /> - } - /> - } - /> - } - /> - } - /> - } - /> + } /> - } /> - } - /> ) diff --git a/src/pages/FactoryAdminPage/AddComponentModal.tsx b/src/pages/FactoryAdminPage/AddComponentModal.tsx deleted file mode 100644 index f2d7616..0000000 --- a/src/pages/FactoryAdminPage/AddComponentModal.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import React, { useState } from 'react' -import { Modal, Button, Form, Select } from 'antd' -import { ComponentType } from './types' - -export const componentTypes: ComponentType[] = [ - 'antdText', - 'antdCard', - 'antdFlex', - 'antdRow', - 'antdCol', - 'partsOfUrl', - 'multiQuery', - 'parsedText', -] - -interface AddComponentModalProps { - onAdd: (type: ComponentType) => void - title?: string -} - -export const AddComponentModal: React.FC = ({ onAdd, title = 'Add Component' }) => { - const [visible, setVisible] = useState(false) - const [form] = Form.useForm() - - const handleSubmit = (values: { type: ComponentType }) => { - onAdd(values.type) - setVisible(false) - form.resetFields() - } - - return ( - <> - - setVisible(false)} footer={null}> -
- - - - -
-
- - ) -} diff --git a/src/pages/FactoryAdminPage/AntdCardForm.tsx b/src/pages/FactoryAdminPage/AntdCardForm.tsx deleted file mode 100644 index 7e97207..0000000 --- a/src/pages/FactoryAdminPage/AntdCardForm.tsx +++ /dev/null @@ -1,73 +0,0 @@ -/* eslint-disable no-console */ -/* eslint-disable no-param-reassign */ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import React, { useEffect } from 'react' -import { Form, Input, Select, Button, Switch } from 'antd' - -const { TextArea } = Input -const { Option } = Select - -interface AntdCardFormProps { - initialValues: any // This would be `TDynamicComponentsAppTypeMap['antdCard']` - onSave: (data: any) => void -} - -export const AntdCardForm: React.FC = ({ initialValues, onSave }) => { - const [form] = Form.useForm() - - useEffect(() => { - form.setFieldsValue(initialValues) - }, [initialValues, form]) - - const handleSubmit = (values: any) => { - try { - if (values.style) { - values.style = JSON.parse(values.style) - } - } catch (e) { - console.log('Invalid JSON for style', e) - return - } - - onSave(values) - } - - return ( -
- - - - - - - - - - - - - - - - - -