From ed01319aa199272714444a21145cc04a38146f65 Mon Sep 17 00:00:00 2001 From: IvanHunters Date: Tue, 28 Apr 2026 03:18:25 +0300 Subject: [PATCH 01/18] feat(dashboard): replace UI with new cozystack-ui (keeping BFF) Replace old openapi-ui with new cozystack-ui that proxies API requests through BFF. Changes: - New UI image: 999669/cozystack-ui:latest@sha256:74e39ad4 - BFF container: kept unchanged for K8s API authentication - New UI includes TypeScript fixes and improved backup pages - nginx configured to proxy /api and /apis to localhost:64231 (BFF) Signed-off-by: IvanHunters --- packages/system/dashboard/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/system/dashboard/values.yaml b/packages/system/dashboard/values.yaml index a5188825..131d71e7 100644 --- a/packages/system/dashboard/values.yaml +++ b/packages/system/dashboard/values.yaml @@ -1,5 +1,5 @@ openapiUI: - image: ghcr.io/cozystack/cozystack/openapi-ui:v1.3.0@sha256:0fa79c373a62840a617ff1ca1b0e31931c13a6cf7b0bb0ff0dc191f047a465a3 + image: 999669/cozystack-ui:latest@sha256:74e39ad4f199fe5bc728793acbfb1d6d4fc76e32894521668a486306d498b71d openapiUIK8sBff: image: ghcr.io/cozystack/cozystack/openapi-ui-k8s-bff:v1.3.0@sha256:1b3ea6d4c7dbbe6a8def3b2807fffdfab2ac4afc39d7a846e57dd491fa168f92 tokenProxy: From ddcc1f2ad651fb47265ba623fe2b56b46c54039f Mon Sep 17 00:00:00 2001 From: IvanHunters Date: Tue, 28 Apr 2026 03:02:59 +0300 Subject: [PATCH 02/18] feat(dashboard): update UI image to amd64 and remove old UI build - Update openapiUI image to amd64 build (sha256:9d8fc5c1...) - Remove old openapi-ui and openapi-ui-k8s-bff build targets from Makefile - Remove old UI Dockerfiles and related files - Add RBAC permissions for cozystack.io/applicationdefinitions to fix 403 errors The new cozystack-ui requires read access to applicationdefinitions API group for marketplace and application catalog functionality. Signed-off-by: IvanHunters --- packages/system/dashboard/Makefile | 34 +------- packages/system/dashboard/templates/rbac.yaml | 8 ++ packages/system/dashboard/templates/web.yaml | 78 ------------------- packages/system/dashboard/values.yaml | 4 +- 4 files changed, 10 insertions(+), 114 deletions(-) diff --git a/packages/system/dashboard/Makefile b/packages/system/dashboard/Makefile index a9f680a3..b136c864 100644 --- a/packages/system/dashboard/Makefile +++ b/packages/system/dashboard/Makefile @@ -5,7 +5,7 @@ include ../../../hack/common-envs.mk include ../../../hack/package.mk update: update-crd update-dockerfiles -image: image-openapi-ui image-openapi-ui-k8s-bff image-token-proxy update-tenant-text +image: image-token-proxy update-tenant-text update-dockerfiles: @@ -18,38 +18,6 @@ update-crd: rm -f crds/_helpers.tpl sed -i '/{{/d' crds/*.yml crds/*.yaml -image-openapi-ui: - docker buildx build images/openapi-ui \ - --provenance false \ - --builder=$(BUILDER) \ - --platform=linux/amd64 \ - --tag $(REGISTRY)/openapi-ui:$(call settag,$(TAG)) \ - --cache-from type=registry,ref=$(REGISTRY)/openapi-ui:latest \ - --cache-to type=inline \ - --metadata-file images/openapi-ui.json \ - --push=$(PUSH) \ - --label "org.opencontainers.image.source=https://github.com/cozystack/cozystack" \ - --load=$(LOAD) - IMAGE="$(REGISTRY)/openapi-ui:$(call settag,$(TAG))@$$(yq e '."containerimage.digest"' images/openapi-ui.json -r)" \ - yq -i '.openapiUI.image = strenv(IMAGE)' values.yaml - rm -f images/openapi-ui.json - -image-openapi-ui-k8s-bff: - docker buildx build images/openapi-ui-k8s-bff \ - --provenance false \ - --builder=$(BUILDER) \ - --platform=linux/amd64 \ - --tag $(REGISTRY)/openapi-ui-k8s-bff:$(call settag,$(TAG)) \ - --cache-from type=registry,ref=$(REGISTRY)/openapi-ui-k8s-bff:latest \ - --cache-to type=inline \ - --metadata-file images/openapi-ui-k8s-bff.json \ - --push=$(PUSH) \ - --label "org.opencontainers.image.source=https://github.com/cozystack/cozystack" \ - --load=$(LOAD) - IMAGE="$(REGISTRY)/openapi-ui-k8s-bff:$(call settag,$(TAG))@$$(yq e '."containerimage.digest"' images/openapi-ui-k8s-bff.json -r)" \ - yq -i '.openapiUIK8sBff.image = strenv(IMAGE)' values.yaml - rm -f images/openapi-ui-k8s-bff.json - image-token-proxy: docker buildx build images/token-proxy \ --provenance false \ diff --git a/packages/system/dashboard/templates/rbac.yaml b/packages/system/dashboard/templates/rbac.yaml index eb687a3e..c64e851f 100644 --- a/packages/system/dashboard/templates/rbac.yaml +++ b/packages/system/dashboard/templates/rbac.yaml @@ -4,6 +4,14 @@ kind: ClusterRole metadata: name: cozystack-dashboard-readonly rules: +- apiGroups: + - cozystack.io + resources: + - applicationdefinitions + verbs: + - get + - list + - watch - apiGroups: - dashboard.cozystack.io resources: diff --git a/packages/system/dashboard/templates/web.yaml b/packages/system/dashboard/templates/web.yaml index 7799afbf..1fd5e850 100644 --- a/packages/system/dashboard/templates/web.yaml +++ b/packages/system/dashboard/templates/web.yaml @@ -38,84 +38,6 @@ spec: topologyKey: kubernetes.io/hostname weight: 100 containers: - - env: - - name: BASE_API_GROUP - value: dashboard.cozystack.io - - name: BASE_API_VERSION - value: v1alpha1 - - name: BASE_NAMESPACE_FULL_PATH - value: "/apis/core.cozystack.io/v1alpha1/tenantnamespaces" - - name: BASE_NAVIGATION_RESOURCE_PLURAL - value: navigations - - name: BASE_NAVIGATION_RESOURCE_NAME - value: navigation - - name: BASE_FRONTEND_PREFIX - value: /openapi-ui - - name: BASE_FACTORY_NAMESPACED_API_KEY - value: base-factory-namespaced-api - - name: BASE_FACTORY_CLUSTERSCOPED_API_KEY - value: base-factory-clusterscoped-api - - name: BASE_FACTORY_NAMESPACED_BUILTIN_KEY - value: base-factory-namespaced-builtin - - name: BASE_FACTORY_CLUSTERSCOPED_BUILTIN_KEY - value: base-factory-clusterscoped-builtin - - name: BASE_NAMESPACE_FACTORY_KEY - value: base-factory-clusterscoped-builtin - - name: BASE_ALLOWED_AUTH_HEADERS - value: user-agent,accept,content-type,origin,referer,accept-encoding,cookie,authorization - - name: LOGGER - value: "true" - - name: LOGGER_WITH_HEADERS - value: "false" - - name: PORT - value: "64231" - image: {{ .Values.openapiUIK8sBff.image | quote }} - imagePullPolicy: IfNotPresent - livenessProbe: - failureThreshold: 3 - httpGet: - path: /healthcheck - port: 64231 - scheme: HTTP - initialDelaySeconds: 3 - periodSeconds: 10 - successThreshold: 1 - timeoutSeconds: 2 - startupProbe: - httpGet: - path: /healthcheck - port: 64231 - scheme: HTTP - failureThreshold: 30 - periodSeconds: 2 - name: bff - ports: - - containerPort: 64231 - name: http-bff - protocol: TCP - resources: - limits: - cpu: 1 - memory: 1Gi - requests: - cpu: 100m - ephemeral-storage: 50Mi - memory: 128Mi - securityContext: - allowPrivilegeEscalation: false - capabilities: - add: [] - drop: - - ALL - privileged: false - readOnlyRootFilesystem: false - runAsGroup: 0 - runAsNonRoot: true - runAsUser: 101 - seccompProfile: - type: RuntimeDefault - terminationMessagePath: /dev/termination-log - terminationMessagePolicy: File - env: - name: BASEPREFIX value: /openapi-ui diff --git a/packages/system/dashboard/values.yaml b/packages/system/dashboard/values.yaml index 131d71e7..65233c34 100644 --- a/packages/system/dashboard/values.yaml +++ b/packages/system/dashboard/values.yaml @@ -1,6 +1,4 @@ openapiUI: - image: 999669/cozystack-ui:latest@sha256:74e39ad4f199fe5bc728793acbfb1d6d4fc76e32894521668a486306d498b71d -openapiUIK8sBff: - image: ghcr.io/cozystack/cozystack/openapi-ui-k8s-bff:v1.3.0@sha256:1b3ea6d4c7dbbe6a8def3b2807fffdfab2ac4afc39d7a846e57dd491fa168f92 + image: 999669/cozystack-ui:latest@sha256:9d8fc5c1a16b5d61e6e6bc9a02621c5d7681de960bb7054a5908a61ab4310799 tokenProxy: image: ghcr.io/cozystack/cozystack/token-proxy:v1.3.0@sha256:2e280991e07853ea48f97b0a42946afffa10d03d6a83d41099ed83e6ffc94fdc From 4de9c50e2f63a846a62660a15915a9636b2f71b4 Mon Sep 17 00:00:00 2001 From: IvanHunters Date: Tue, 28 Apr 2026 03:26:35 +0300 Subject: [PATCH 03/18] fix(dashboard): update UI image with VNC WebSocket fix Update to new image digest with dynamic WebSocket URL fix for VNC connections. VNC now uses window.location instead of hardcoded localhost:8001. Image: 999669/cozystack-ui:latest@sha256:ea4e832c2... Signed-off-by: IvanHunters --- packages/system/dashboard/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/system/dashboard/values.yaml b/packages/system/dashboard/values.yaml index 65233c34..dc0384b0 100644 --- a/packages/system/dashboard/values.yaml +++ b/packages/system/dashboard/values.yaml @@ -1,4 +1,4 @@ openapiUI: - image: 999669/cozystack-ui:latest@sha256:9d8fc5c1a16b5d61e6e6bc9a02621c5d7681de960bb7054a5908a61ab4310799 + image: 999669/cozystack-ui:latest@sha256:ea4e832c277ecf16dde99b4bd82ac5334d03d3c9cb0572fe896e2f128a6e6dc1 tokenProxy: image: ghcr.io/cozystack/cozystack/token-proxy:v1.3.0@sha256:2e280991e07853ea48f97b0a42946afffa10d03d6a83d41099ed83e6ffc94fdc From c7c4f724afd86f11d40bc1864175c81c1a4b17f7 Mon Sep 17 00:00:00 2001 From: IvanHunters Date: Tue, 28 Apr 2026 23:35:46 +0300 Subject: [PATCH 04/18] fix(dashboard): add VNC access permissions and update UI image - Add RBAC permissions for VNC console access to virtual machines - Update cozystack-ui image to latest version with VNC fixes Signed-off-by: IvanHunters --- packages/system/dashboard/templates/rbac.yaml | 14 ++++++++++++++ packages/system/dashboard/values.yaml | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/packages/system/dashboard/templates/rbac.yaml b/packages/system/dashboard/templates/rbac.yaml index c64e851f..b5d2b642 100644 --- a/packages/system/dashboard/templates/rbac.yaml +++ b/packages/system/dashboard/templates/rbac.yaml @@ -36,6 +36,20 @@ rules: - get - list - watch +- apiGroups: + - kubevirt.io + resources: + - virtualmachineinstances + verbs: + - get + - list + - watch +- apiGroups: + - subresources.kubevirt.io + resources: + - virtualmachineinstances/vnc + verbs: + - get --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding diff --git a/packages/system/dashboard/values.yaml b/packages/system/dashboard/values.yaml index dc0384b0..dbe330ea 100644 --- a/packages/system/dashboard/values.yaml +++ b/packages/system/dashboard/values.yaml @@ -1,4 +1,4 @@ openapiUI: - image: 999669/cozystack-ui:latest@sha256:ea4e832c277ecf16dde99b4bd82ac5334d03d3c9cb0572fe896e2f128a6e6dc1 + image: 999669/cozystack-ui:latest@sha256:a93a92a8f7b8d7c4842876215f737d782ad373ff8f4ceb89d7b536945184341e tokenProxy: image: ghcr.io/cozystack/cozystack/token-proxy:v1.3.0@sha256:2e280991e07853ea48f97b0a42946afffa10d03d6a83d41099ed83e6ffc94fdc From 8b037d3045cb22b7bc91eeb58fdcf8f2f007916f Mon Sep 17 00:00:00 2001 From: IvanHunters Date: Tue, 28 Apr 2026 23:38:58 +0300 Subject: [PATCH 05/18] refactor(dashboard): migrate to new cozystack-ui console MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove old openapi-ui implementation and adopt new React-based console: **Removed:** - images/openapi-ui/ - old PRO-Robotech based UI - images/openapi-ui-k8s-bff/ - unused backend-for-frontend - templates/nginx.yaml - separate nginx proxy (replaced by built-in nginx) - templates/configmap.yaml - old UI configuration **Changes:** - Rename web → console throughout all manifests - Rename incloud-web-* → cozy-dashboard-* for all resources - Remove all environment variables (new UI requires no configuration) - Update gatekeeper upstream to point directly to console service - Simplify Makefile (only token-proxy image build remains) - Update values.yaml: openapiUI → console **Architecture changes:** Before: gatekeeper → nginx → web (openapi-ui) After: gatekeeper → console (React SPA with built-in nginx) The new console includes nginx that proxies /api and /apis to K8s API, eliminating the need for a separate nginx deployment. Authentication flow remains unchanged - gatekeeper adds Authorization header which is passed through to K8s API. Breaking change: Resource names changed from incloud-web-* to cozy-dashboard-*. Existing deployments will need migration. Signed-off-by: IvanHunters --- packages/system/dashboard/Makefile | 17 +- .../images/openapi-ui-k8s-bff/Dockerfile | 22 -- .../dashboard/images/openapi-ui/Dockerfile | 69 ------ .../flatmap-unresolved-placeholder.diff | 17 -- .../patches/formlistinput-allow-empty.diff | 37 ---- .../secret-copy-preserve-newlines.diff | 29 --- .../patches/tenantmodules.diff | 50 ----- .../system/dashboard/templates/configmap.yaml | 24 --- .../{nginx-sa.yaml => console-sa.yaml} | 2 +- .../{nginx-svc.yaml => console-svc.yaml} | 8 +- .../templates/{nginx.yaml => console.yaml} | 39 ++-- .../dashboard/templates/gatekeeper.yaml | 4 +- .../dashboard/templates/nginx-config.yaml | 97 --------- .../system/dashboard/templates/web-sa.yaml | 4 - .../system/dashboard/templates/web-svc.yaml | 18 -- packages/system/dashboard/templates/web.yaml | 196 ------------------ packages/system/dashboard/values.yaml | 2 +- 17 files changed, 26 insertions(+), 609 deletions(-) delete mode 100644 packages/system/dashboard/images/openapi-ui-k8s-bff/Dockerfile delete mode 100644 packages/system/dashboard/images/openapi-ui/Dockerfile delete mode 100644 packages/system/dashboard/images/openapi-ui/openapi-k8s-toolkit/patches/flatmap-unresolved-placeholder.diff delete mode 100644 packages/system/dashboard/images/openapi-ui/openapi-k8s-toolkit/patches/formlistinput-allow-empty.diff delete mode 100644 packages/system/dashboard/images/openapi-ui/openapi-k8s-toolkit/patches/secret-copy-preserve-newlines.diff delete mode 100644 packages/system/dashboard/images/openapi-ui/openapi-k8s-toolkit/patches/tenantmodules.diff delete mode 100644 packages/system/dashboard/templates/configmap.yaml rename packages/system/dashboard/templates/{nginx-sa.yaml => console-sa.yaml} (59%) rename packages/system/dashboard/templates/{nginx-svc.yaml => console-svc.yaml} (52%) rename packages/system/dashboard/templates/{nginx.yaml => console.yaml} (72%) delete mode 100644 packages/system/dashboard/templates/nginx-config.yaml delete mode 100644 packages/system/dashboard/templates/web-sa.yaml delete mode 100644 packages/system/dashboard/templates/web-svc.yaml delete mode 100644 packages/system/dashboard/templates/web.yaml diff --git a/packages/system/dashboard/Makefile b/packages/system/dashboard/Makefile index b136c864..b46252a3 100644 --- a/packages/system/dashboard/Makefile +++ b/packages/system/dashboard/Makefile @@ -4,19 +4,7 @@ export NAMESPACE=cozy-$(NAME) include ../../../hack/common-envs.mk include ../../../hack/package.mk -update: update-crd update-dockerfiles -image: image-token-proxy update-tenant-text - - -update-dockerfiles: - @echo Update dockerfiles manually - -update-crd: - rm -rf crds - mkdir -p crds - wget -O- https://github.com/PRO-Robotech/helmfile-manifests/archive/refs/heads/main.tar.gz | tar -C crds -xzvf- helmfile-manifests-main/charts/incloud-main/incloud-web-1.0.0/incloud-web/templates --strip-components=6 - rm -f crds/_helpers.tpl - sed -i '/{{/d' crds/*.yml crds/*.yaml +image: image-token-proxy image-token-proxy: docker buildx build images/token-proxy \ @@ -33,6 +21,3 @@ image-token-proxy: IMAGE="$(REGISTRY)/token-proxy:$(call settag,$(TAG))@$$(yq e '."containerimage.digest"' images/token-proxy.json -r)" \ yq -i '.tokenProxy.image = strenv(IMAGE)' values.yaml rm -f images/token-proxy.json - -update-tenant-text: - sed -i 's|\($$tenantText := "\)[^"]\+|\1$(TAG)|' templates/configmap.yaml diff --git a/packages/system/dashboard/images/openapi-ui-k8s-bff/Dockerfile b/packages/system/dashboard/images/openapi-ui-k8s-bff/Dockerfile deleted file mode 100644 index ea0c900d..00000000 --- a/packages/system/dashboard/images/openapi-ui-k8s-bff/Dockerfile +++ /dev/null @@ -1,22 +0,0 @@ -# imported from https://github.com/PRO-Robotech/openapi-ui-k8s-bff -ARG NODE_VERSION=20.18.1 -FROM node:${NODE_VERSION}-alpine AS builder -WORKDIR /src - -# release/1.4.0 -ARG COMMIT_REF=92e4b618eb9ad17b19827b5a2b7ceab33e8cf534 -RUN wget -O- https://github.com/PRO-Robotech/openapi-ui-k8s-bff/archive/${COMMIT_REF}.tar.gz | tar xzf - --strip-components=1 - -ENV PATH=/src/node_modules/.bin:$PATH -RUN npm install -RUN npm run build - -FROM node:${NODE_VERSION}-alpine -WORKDIR /app -COPY --from=builder /src/package*.json /app/ -COPY --from=builder /src/node_modules /app/node_modules -COPY --from=builder /src/src/swagger/swagger-output.json /app/dist/swagger/swagger-output.json -COPY --from=builder /src/dist /app/dist -EXPOSE 8080 -USER 1001 -CMD [ "node", "/app/dist/index.js"] diff --git a/packages/system/dashboard/images/openapi-ui/Dockerfile b/packages/system/dashboard/images/openapi-ui/Dockerfile deleted file mode 100644 index 82cc6db0..00000000 --- a/packages/system/dashboard/images/openapi-ui/Dockerfile +++ /dev/null @@ -1,69 +0,0 @@ -ARG NODE_VERSION=20.18.1 - -# openapi-k8s-toolkit -# imported from https://github.com/PRO-Robotech/openapi-k8s-toolkit -FROM node:${NODE_VERSION}-alpine AS openapi-k8s-toolkit-builder -RUN apk add git -WORKDIR /src -# release/1.4.0 -ARG COMMIT=d6b9e4ad0d1eb9d3730f7f0c664792c8dda3214d -RUN wget -O- https://github.com/PRO-Robotech/openapi-k8s-toolkit/archive/${COMMIT}.tar.gz | tar -xzvf- --strip-components=1 - -COPY openapi-k8s-toolkit/patches /patches -RUN git apply /patches/*.diff - -RUN npm install -RUN npm install --build-from-source @swc/core -RUN npm run build - - -# openapi-ui -# imported from https://github.com/PRO-Robotech/openapi-ui -FROM node:${NODE_VERSION}-alpine AS builder -#RUN apk add git -WORKDIR /src - -# release/1.4.0 -ARG COMMIT_REF=6addca6939264ef2e39801baa88c1460cc1aa53e -RUN wget -O- https://github.com/PRO-Robotech/openapi-ui/archive/${COMMIT_REF}.tar.gz | tar xzf - --strip-components=1 - -#COPY openapi-ui/patches /patches -#RUN git apply /patches/*.diff - -ENV PATH=/src/node_modules/.bin:$PATH - -RUN npm install - -# add patched openapi-k8s-toolkit -RUN rm -rf node_modules/@prorobotech/openapi-k8s-toolkit/dist -COPY --from=openapi-k8s-toolkit-builder /src/dist node_modules/@prorobotech/openapi-k8s-toolkit/dist - -RUN npm run build - -FROM node:${NODE_VERSION}-alpine AS builder2 -WORKDIR /src -ENV PATH=/src/node_modules/.bin:$PATH - -COPY --from=builder /src/server/package.json ./ -COPY --from=builder /src/server/package-lock.json ./ -RUN npm install -COPY --from=builder /src/server server -COPY --from=builder /src/tsconfig.server.json ./ -COPY --from=builder /src/build /src/build -RUN npm run server:build - -FROM node:${NODE_VERSION}-alpine -WORKDIR /app -COPY --from=builder2 /src/node_modules /app/node_modules -COPY --from=builder2 /src/build /app/build -EXPOSE 8080 -RUN sed -i -e 's|OpenAPI UI|Cozystack|g' build/index.html -# Fix Factory component: return null while loading instead of showing "Factory Not Found" 404 -RUN APP_JS=$(find build -name "App-react.js" -type f | head -1) && \ - if [ -n "$APP_JS" ]; then \ - sed -i 's|const { data: factoryData } = useK8sSmartResource({|const { data: factoryData, isLoading: factoryIsLoading } = useK8sSmartResource({|' "$APP_JS" && \ - sed -i '/Factory Not Found/s/return /return factoryIsLoading ? null : /' "$APP_JS" && \ - echo "Factory loading patch applied to $APP_JS"; \ - fi -USER 1001 -CMD ["node", "/app/build/index.js"] diff --git a/packages/system/dashboard/images/openapi-ui/openapi-k8s-toolkit/patches/flatmap-unresolved-placeholder.diff b/packages/system/dashboard/images/openapi-ui/openapi-k8s-toolkit/patches/flatmap-unresolved-placeholder.diff deleted file mode 100644 index e98861a3..00000000 --- a/packages/system/dashboard/images/openapi-ui/openapi-k8s-toolkit/patches/flatmap-unresolved-placeholder.diff +++ /dev/null @@ -1,17 +0,0 @@ -diff --git a/src/components/molecules/EnrichedTable/organisms/EnrichedTableProvider/utils.ts b/src/components/molecules/EnrichedTable/organisms/EnrichedTableProvider/utils.ts ---- a/src/components/molecules/EnrichedTable/organisms/EnrichedTableProvider/utils.ts -+++ b/src/components/molecules/EnrichedTable/organisms/EnrichedTableProvider/utils.ts -@@ -185,6 +185,11 @@ - return `['${escaped}']` - }) - } -- const jpQueryResult = jp.query(el, `$${resolvedJsonPath}`) -- fieldValue = Array.isArray(jpQueryResult) && jpQueryResult.length === 1 ? jpQueryResult[0] : jpQueryResult -+ if (/_flatMap[^\]]+_Key/.test(resolvedJsonPath)) { -+ // Placeholder was not resolved (row not yet expanded or key missing) — skip query -+ fieldValue = null -+ } else { -+ const jpQueryResult = jp.query(el, `$${resolvedJsonPath}`) -+ fieldValue = Array.isArray(jpQueryResult) && jpQueryResult.length === 1 ? jpQueryResult[0] : jpQueryResult -+ } - } diff --git a/packages/system/dashboard/images/openapi-ui/openapi-k8s-toolkit/patches/formlistinput-allow-empty.diff b/packages/system/dashboard/images/openapi-ui/openapi-k8s-toolkit/patches/formlistinput-allow-empty.diff deleted file mode 100644 index 1c83df7c..00000000 --- a/packages/system/dashboard/images/openapi-ui/openapi-k8s-toolkit/patches/formlistinput-allow-empty.diff +++ /dev/null @@ -1,37 +0,0 @@ -diff --git a/src/localTypes/formExtensions.ts b/src/localTypes/formExtensions.ts ---- a/src/localTypes/formExtensions.ts -+++ b/src/localTypes/formExtensions.ts -@@ -59,2 +59,4 @@ - relatedValuePath?: string -+ allowEmpty?: boolean -+ persistType?: 'str' | 'number' | 'arr' | 'obj' - } -diff --git a/src/components/molecules/BlackholeForm/molecules/FormListInput/FormListInput.tsx b/src/components/molecules/BlackholeForm/molecules/FormListInput/FormListInput.tsx ---- a/src/components/molecules/BlackholeForm/molecules/FormListInput/FormListInput.tsx -+++ b/src/components/molecules/BlackholeForm/molecules/FormListInput/FormListInput.tsx -@@ -149,3 +149,10 @@ - }, [relatedPath, form, arrName, fixedName, relatedFieldValue, onValuesChangeCallBack, isTouchedPeristed]) - -+ // When allowEmpty is set, auto-persist the field so the BFF preserves empty values -+ useEffect(() => { -+ if (customProps.allowEmpty) { -+ persistedControls.onPersistMark(persistName || name, customProps.persistType ?? 'str') -+ } -+ }, [customProps.allowEmpty, customProps.persistType, persistedControls, persistName, name]) -+ - const uri = prepareTemplate({ -@@ -267,5 +274,14 @@ - validateTrigger="onBlur" - hasFeedback={designNewLayout ? { icons: feedbackIcons } : true} - style={{ flex: 1 }} -+ normalize={(value: unknown) => { -+ if (customProps.allowEmpty && (value === undefined || value === null)) { -+ if (customProps.persistType === 'number') return 0 -+ if (customProps.persistType === 'arr') return [] -+ if (customProps.persistType === 'obj') return {} -+ return '' -+ } -+ return value -+ }} - > -