From 5ca668dce698e4e1d21635eaf24b61c24c480186 Mon Sep 17 00:00:00 2001 From: cuisongliu Date: Mon, 27 Jul 2026 11:00:12 +0800 Subject: [PATCH] chore(frontend): remove kubepanel provider (#7105) --- .github/copilot-instructions.md | 2 +- .github/workflows/frontends.yml | 4 - frontend/Makefile | 1 - frontend/pnpm-lock.yaml | 2516 +---------------- frontend/providers/kubepanel/.eslintrc.json | 9 - frontend/providers/kubepanel/.gitignore | 42 - frontend/providers/kubepanel/.prettierignore | 4 - frontend/providers/kubepanel/.prettierrc.js | 20 - frontend/providers/kubepanel/README.md | 37 - frontend/providers/kubepanel/deploy/Kubefile | 9 - .../charts/kubepanel-frontend/Chart.yaml | 6 - .../kubepanel-frontend-values.yaml | 14 - .../kubepanel-frontend/templates/_helpers.tpl | 84 - .../kubepanel-frontend/templates/app.yaml | 19 - .../templates/configmap.yaml | 10 - .../templates/deployment.yaml | 63 - .../kubepanel-frontend/templates/ingress.yaml | 43 - .../kubepanel-frontend/templates/service.yaml | 16 - .../charts/kubepanel-frontend/values.yaml | 61 - .../deploy/kubepanel-frontend-entrypoint.sh | 87 - frontend/providers/kubepanel/dockerfile | 58 - frontend/providers/kubepanel/next.config.js | 11 - frontend/providers/kubepanel/package.json | 61 - .../providers/kubepanel/postcss.config.js | 6 - .../create-resource-templates/ConfigMap.yaml | 17 - .../create-resource-templates/Deployment.yaml | 23 - .../create-resource-templates/Ingress.yaml | 17 - .../PersistentVolumeClaim.yaml | 17 - .../public/create-resource-templates/Pod.yaml | 16 - .../create-resource-templates/Secret.yaml | 8 - .../StatefulSet.yaml | 36 - .../providers/kubepanel/public/favicon.ico | Bin 4286 -> 0 bytes frontend/providers/kubepanel/public/logo.svg | 73 - .../providers/kubepanel/src/api/kubernetes.ts | 112 - .../providers/kubepanel/src/api/platform.ts | 4 - .../src/components/chart/pie-chart.tsx | 70 - .../common/action/action-button.tsx | 58 - .../common/action/create-resource-modal.tsx | 157 - .../common/action/delete-popconfirm.tsx | 122 - .../src/components/common/action/toggle.tsx | 112 - .../common/action/update-editor-modal.tsx | 88 - .../components/common/drawer/drawer-item.tsx | 42 - .../components/common/drawer/drawer-panel.tsx | 19 - .../components/common/drawer/drawer-title.tsx | 9 - .../src/components/common/drawer/drawer.tsx | 30 - .../src/components/common/editor/styled.tsx | 57 - .../common/panel-table/pagination.tsx | 121 - .../common/panel-table/search-filter.tsx | 104 - .../components/common/panel-table/table.tsx | 121 - .../src/components/common/section/section.tsx | 17 - .../src/components/common/sidebar/sidebar.tsx | 108 - .../src/components/common/status-tag.tsx | 14 - .../src/components/common/title/title.tsx | 27 - .../src/components/kube/kube-badge.tsx | 63 - .../src/components/kube/local-date.tsx | 10 - .../detail/kube-object-detail-info-list.tsx | 169 -- .../kube/object/kube-object-affinities.tsx | 246 -- .../kube/object/kube-object-age.tsx | 24 - .../kube/object/kube-object-tolerations.tsx | 42 - .../kube/object/responsive-key-list.tsx | 83 - .../src/components/kube/reactive-duration.tsx | 67 - .../config/config-map/config-map-detail.tsx | 195 -- .../config/config-map/config-map.tsx | 46 - .../config/secret/secret-detail.tsx | 249 -- .../kubepanel-views/config/secret/secret.tsx | 51 - .../custom-resource/bucket/bucket-detail.tsx | 45 - .../custom-resource/bucket/bucket.tsx | 65 - .../cluster/cluster-detail.tsx | 74 - .../custom-resource/cluster/cluster.tsx | 79 - .../custom-resource/devbox/devbox-detail.tsx | 73 - .../custom-resource/devbox/devbox.tsx | 80 - .../network/ingress/ingress-detail.tsx | 123 - .../network/ingress/ingress-path-editor.tsx | 368 --- .../ingress/ingress-visual-editor-drawer.tsx | 345 --- .../network/ingress/ingress.tsx | 66 - .../network/service/service-detail.tsx | 96 - .../network/service/service.tsx | 96 - .../volume-claim/volume-claim-detail.tsx | 79 - .../storage/volume-claim/volume-claim.tsx | 87 - .../workload/deployment/deployment-detail.tsx | 112 - .../workload/deployment/deployment.tsx | 63 - .../workload/overview/event-overview.tsx | 108 - .../workload/overview/overview.tsx | 56 - .../workload/overview/status-chart.tsx | 54 - .../workload/overview/status-overview.tsx | 21 - .../workload/pod/container-detail.tsx | 901 ------ .../workload/pod/container-status-brick.tsx | 29 - .../workload/pod/container-status.tsx | 88 - .../workload/pod/pod-detail-affinities.tsx | 24 - .../pod/pod-detail-security-context.tsx | 244 -- .../workload/pod/pod-detail-statuses.tsx | 27 - .../workload/pod/pod-detail-tolerations.tsx | 26 - .../workload/pod/pod-detail.tsx | 104 - .../workload/pod/pod-status.tsx | 9 - .../kubepanel-views/workload/pod/pod.tsx | 98 - .../workload/pod/probe-card.tsx | 551 ---- .../statefulset/statefulset-detail.tsx | 75 - .../workload/statefulset/statefulset.tsx | 54 - .../kubepanel/src/constants/kube-object.ts | 16 - .../providers/kubepanel/src/constants/pod.ts | 10 - .../kubepanel/src/constants/theme.ts | 70 - .../kubepanel/src/hooks/useConfirm.tsx | 82 - .../kubepanel/src/hooks/useWatcher.tsx | 39 - .../providers/kubepanel/src/k8slens/README.md | 4 - .../src/k8slens/kube-object/index.ts | 6 - .../src/k8slens/kube-object/src/api-types.ts | 415 --- .../k8slens/kube-object/src/kube-object.ts | 102 - .../k8slens/kube-object/src/kube-status.ts | 59 - .../kube-object/src/specifics/bucket.ts | 28 - .../kube-object/src/specifics/cluster.ts | 101 - .../kube-object/src/specifics/config-map.ts | 47 - .../kube-object/src/specifics/daemon-set.ts | 77 - .../kube-object/src/specifics/deployment.ts | 92 - .../kube-object/src/specifics/devbox.ts | 150 - .../kube-object/src/specifics/events.ts | 156 - .../kube-object/src/specifics/index.ts | 18 - .../kube-object/src/specifics/ingress.ts | 192 -- .../k8slens/kube-object/src/specifics/job.ts | 91 - .../src/specifics/persistent-volume-claim.ts | 69 - .../k8slens/kube-object/src/specifics/pod.ts | 843 ------ .../kube-object/src/specifics/replica-set.ts | 77 - .../kube-object/src/specifics/secret.ts | 74 - .../kube-object/src/specifics/service.ts | 143 - .../kube-object/src/specifics/stateful-set.ts | 73 - .../kube-object/src/types/capabilities.ts | 19 - .../kube-object/src/types/container-port.ts | 12 - .../kube-object/src/types/container.ts | 176 -- .../kube-object/src/types/env-from-source.ts | 14 - .../kube-object/src/types/env-source.ts | 13 - .../src/types/env-var-key-selector.ts | 10 - .../kube-object/src/types/env-var-source.ts | 15 - .../k8slens/kube-object/src/types/env-var.ts | 12 - .../kube-object/src/types/exec-action.ts | 19 - .../k8slens/kube-object/src/types/handler.ts | 17 - .../kube-object/src/types/http-get-action.ts | 38 - .../kube-object/src/types/http-header.ts | 19 - .../k8slens/kube-object/src/types/index.ts | 33 - .../kube-object/src/types/lifecycle.ts | 17 - .../src/types/object-field-selector.ts | 9 - .../persistent-volume-claim-template-spec.ts | 12 - .../src/types/pod-security-context.ts | 21 - .../src/types/pod-template-spec.ts | 12 - .../k8slens/kube-object/src/types/probe.ts | 81 - .../src/types/resource-field-selector.ts | 10 - .../src/types/resource-requirements.ts | 25 - .../k8slens/kube-object/src/types/role-ref.ts | 10 - .../k8slens/kube-object/src/types/scale.ts | 27 - .../kube-object/src/types/se-linux-options.ts | 29 - .../kube-object/src/types/seccomp-profile.ts | 29 - .../kube-object/src/types/security-context.ts | 78 - .../src/types/tcp-socket-action.ts | 19 - .../kube-object/src/types/volume-device.ts | 19 - .../kube-object/src/types/volume-mount.ts | 13 - .../types/windows-security-context-options.ts | 43 - .../src/k8slens/kube-object/src/utils.ts | 114 - .../kubepanel/src/k8slens/utilities/index.ts | 5 - .../k8slens/utilities/src/formatDuration.ts | 94 - .../src/k8slens/utilities/src/iter.ts | 328 --- .../src/k8slens/utilities/src/object.ts | 40 - .../k8slens/utilities/src/type-narrowing.ts | 198 -- .../src/k8slens/utilities/src/types.ts | 10 - .../providers/kubepanel/src/pages/404.tsx | 13 - .../providers/kubepanel/src/pages/_app.tsx | 98 - .../kubepanel/src/pages/_document.tsx | 24 - .../src/pages/api/kubernetes/create.ts | 48 - .../src/pages/api/kubernetes/delete.ts | 61 - .../src/pages/api/kubernetes/list.ts | 45 - .../src/pages/api/kubernetes/template.ts | 37 - .../src/pages/api/kubernetes/update.ts | 52 - .../src/pages/api/platform/init-data.ts | 15 - .../src/pages/kubepanel/[[...slug]].tsx | 97 - .../kubepanel/src/pages/kubepanel/layout.tsx | 62 - .../kubepanel/src/services/backend/api.ts | 107 - .../kubepanel/src/services/backend/auth.ts | 35 - .../kubepanel/src/services/backend/error.ts | 83 - .../src/services/backend/kubeconfig.ts | 212 -- .../src/services/backend/response.ts | 58 - .../providers/kubepanel/src/services/error.ts | 34 - .../kubepanel/src/services/kubernet.ts | 9 - .../kubepanel/src/services/request.ts | 82 - .../providers/kubepanel/src/store/global.ts | 15 - .../kubepanel/src/store/k8s/bucket.store.ts | 8 - .../kubepanel/src/store/k8s/cluster.store.ts | 8 - .../src/store/k8s/config-map.store.ts | 8 - .../src/store/k8s/deployment.store.ts | 28 - .../kubepanel/src/store/k8s/devbox.store.ts | 69 - .../kubepanel/src/store/k8s/event.store.ts | 8 - .../kubepanel/src/store/k8s/ingress.store.ts | 8 - .../kubepanel/src/store/k8s/kube.store.ts | 103 - .../kubepanel/src/store/k8s/pod.store.ts | 14 - .../kubepanel/src/store/k8s/secret.store.ts | 8 - .../kubepanel/src/store/k8s/service.store.ts | 8 - .../src/store/k8s/stateful-set.store.ts | 29 - .../src/store/k8s/volume-claim.store.ts | 11 - .../providers/kubepanel/src/store/kube.ts | 12 - .../providers/kubepanel/src/store/static.ts | 20 - .../kubepanel/src/styles/globals.css | 116 - .../kubepanel/src/types/api/base.d.ts | 39 - .../kubepanel/src/types/api/kubenertes.d.ts | 45 - .../providers/kubepanel/src/types/detail.d.ts | 5 - .../kubepanel/src/types/kube-resource.d.ts | 86 - .../providers/kubepanel/src/types/state.d.ts | 44 - .../providers/kubepanel/src/types/util.d.ts | 23 - frontend/providers/kubepanel/src/utils/api.ts | 51 - .../kubepanel/src/utils/condtion-color.ts | 12 - .../kubepanel/src/utils/kube-object-info.ts | 38 - .../kubepanel/src/utils/pie-chart.ts | 14 - .../kubepanel/src/utils/request-controller.ts | 59 - .../kubepanel/src/utils/status-color.ts | 70 - .../providers/kubepanel/src/utils/types.ts | 49 - .../providers/kubepanel/src/utils/user.ts | 14 - .../providers/kubepanel/src/utils/yaml.ts | 43 - .../providers/kubepanel/tailwind.config.js | 34 - frontend/providers/kubepanel/tsconfig.json | 38 - 214 files changed, 32 insertions(+), 17298 deletions(-) delete mode 100644 frontend/providers/kubepanel/.eslintrc.json delete mode 100644 frontend/providers/kubepanel/.gitignore delete mode 100644 frontend/providers/kubepanel/.prettierignore delete mode 100644 frontend/providers/kubepanel/.prettierrc.js delete mode 100644 frontend/providers/kubepanel/README.md delete mode 100644 frontend/providers/kubepanel/deploy/Kubefile delete mode 100644 frontend/providers/kubepanel/deploy/charts/kubepanel-frontend/Chart.yaml delete mode 100644 frontend/providers/kubepanel/deploy/charts/kubepanel-frontend/kubepanel-frontend-values.yaml delete mode 100644 frontend/providers/kubepanel/deploy/charts/kubepanel-frontend/templates/_helpers.tpl delete mode 100644 frontend/providers/kubepanel/deploy/charts/kubepanel-frontend/templates/app.yaml delete mode 100644 frontend/providers/kubepanel/deploy/charts/kubepanel-frontend/templates/configmap.yaml delete mode 100644 frontend/providers/kubepanel/deploy/charts/kubepanel-frontend/templates/deployment.yaml delete mode 100644 frontend/providers/kubepanel/deploy/charts/kubepanel-frontend/templates/ingress.yaml delete mode 100644 frontend/providers/kubepanel/deploy/charts/kubepanel-frontend/templates/service.yaml delete mode 100644 frontend/providers/kubepanel/deploy/charts/kubepanel-frontend/values.yaml delete mode 100755 frontend/providers/kubepanel/deploy/kubepanel-frontend-entrypoint.sh delete mode 100644 frontend/providers/kubepanel/dockerfile delete mode 100644 frontend/providers/kubepanel/next.config.js delete mode 100644 frontend/providers/kubepanel/package.json delete mode 100644 frontend/providers/kubepanel/postcss.config.js delete mode 100644 frontend/providers/kubepanel/public/create-resource-templates/ConfigMap.yaml delete mode 100644 frontend/providers/kubepanel/public/create-resource-templates/Deployment.yaml delete mode 100644 frontend/providers/kubepanel/public/create-resource-templates/Ingress.yaml delete mode 100644 frontend/providers/kubepanel/public/create-resource-templates/PersistentVolumeClaim.yaml delete mode 100644 frontend/providers/kubepanel/public/create-resource-templates/Pod.yaml delete mode 100644 frontend/providers/kubepanel/public/create-resource-templates/Secret.yaml delete mode 100644 frontend/providers/kubepanel/public/create-resource-templates/StatefulSet.yaml delete mode 100644 frontend/providers/kubepanel/public/favicon.ico delete mode 100644 frontend/providers/kubepanel/public/logo.svg delete mode 100644 frontend/providers/kubepanel/src/api/kubernetes.ts delete mode 100644 frontend/providers/kubepanel/src/api/platform.ts delete mode 100644 frontend/providers/kubepanel/src/components/chart/pie-chart.tsx delete mode 100644 frontend/providers/kubepanel/src/components/common/action/action-button.tsx delete mode 100644 frontend/providers/kubepanel/src/components/common/action/create-resource-modal.tsx delete mode 100644 frontend/providers/kubepanel/src/components/common/action/delete-popconfirm.tsx delete mode 100644 frontend/providers/kubepanel/src/components/common/action/toggle.tsx delete mode 100644 frontend/providers/kubepanel/src/components/common/action/update-editor-modal.tsx delete mode 100644 frontend/providers/kubepanel/src/components/common/drawer/drawer-item.tsx delete mode 100644 frontend/providers/kubepanel/src/components/common/drawer/drawer-panel.tsx delete mode 100644 frontend/providers/kubepanel/src/components/common/drawer/drawer-title.tsx delete mode 100644 frontend/providers/kubepanel/src/components/common/drawer/drawer.tsx delete mode 100644 frontend/providers/kubepanel/src/components/common/editor/styled.tsx delete mode 100644 frontend/providers/kubepanel/src/components/common/panel-table/pagination.tsx delete mode 100644 frontend/providers/kubepanel/src/components/common/panel-table/search-filter.tsx delete mode 100644 frontend/providers/kubepanel/src/components/common/panel-table/table.tsx delete mode 100644 frontend/providers/kubepanel/src/components/common/section/section.tsx delete mode 100644 frontend/providers/kubepanel/src/components/common/sidebar/sidebar.tsx delete mode 100644 frontend/providers/kubepanel/src/components/common/status-tag.tsx delete mode 100644 frontend/providers/kubepanel/src/components/common/title/title.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kube/kube-badge.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kube/local-date.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kube/object/detail/kube-object-detail-info-list.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kube/object/kube-object-affinities.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kube/object/kube-object-age.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kube/object/kube-object-tolerations.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kube/object/responsive-key-list.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kube/reactive-duration.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kubepanel-views/config/config-map/config-map-detail.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kubepanel-views/config/config-map/config-map.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kubepanel-views/config/secret/secret-detail.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kubepanel-views/config/secret/secret.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kubepanel-views/custom-resource/bucket/bucket-detail.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kubepanel-views/custom-resource/bucket/bucket.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kubepanel-views/custom-resource/cluster/cluster-detail.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kubepanel-views/custom-resource/cluster/cluster.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kubepanel-views/custom-resource/devbox/devbox-detail.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kubepanel-views/custom-resource/devbox/devbox.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kubepanel-views/network/ingress/ingress-detail.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kubepanel-views/network/ingress/ingress-path-editor.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kubepanel-views/network/ingress/ingress-visual-editor-drawer.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kubepanel-views/network/ingress/ingress.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kubepanel-views/network/service/service-detail.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kubepanel-views/network/service/service.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kubepanel-views/storage/volume-claim/volume-claim-detail.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kubepanel-views/storage/volume-claim/volume-claim.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kubepanel-views/workload/deployment/deployment-detail.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kubepanel-views/workload/deployment/deployment.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kubepanel-views/workload/overview/event-overview.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kubepanel-views/workload/overview/overview.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kubepanel-views/workload/overview/status-chart.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kubepanel-views/workload/overview/status-overview.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kubepanel-views/workload/pod/container-detail.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kubepanel-views/workload/pod/container-status-brick.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kubepanel-views/workload/pod/container-status.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kubepanel-views/workload/pod/pod-detail-affinities.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kubepanel-views/workload/pod/pod-detail-security-context.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kubepanel-views/workload/pod/pod-detail-statuses.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kubepanel-views/workload/pod/pod-detail-tolerations.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kubepanel-views/workload/pod/pod-detail.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kubepanel-views/workload/pod/pod-status.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kubepanel-views/workload/pod/pod.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kubepanel-views/workload/pod/probe-card.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kubepanel-views/workload/statefulset/statefulset-detail.tsx delete mode 100644 frontend/providers/kubepanel/src/components/kubepanel-views/workload/statefulset/statefulset.tsx delete mode 100644 frontend/providers/kubepanel/src/constants/kube-object.ts delete mode 100644 frontend/providers/kubepanel/src/constants/pod.ts delete mode 100644 frontend/providers/kubepanel/src/constants/theme.ts delete mode 100644 frontend/providers/kubepanel/src/hooks/useConfirm.tsx delete mode 100644 frontend/providers/kubepanel/src/hooks/useWatcher.tsx delete mode 100644 frontend/providers/kubepanel/src/k8slens/README.md delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/index.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/api-types.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/kube-object.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/kube-status.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/bucket.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/cluster.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/config-map.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/daemon-set.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/deployment.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/devbox.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/events.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/index.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/ingress.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/job.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/persistent-volume-claim.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/pod.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/replica-set.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/secret.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/service.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/stateful-set.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/types/capabilities.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/types/container-port.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/types/container.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/types/env-from-source.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/types/env-source.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/types/env-var-key-selector.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/types/env-var-source.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/types/env-var.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/types/exec-action.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/types/handler.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/types/http-get-action.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/types/http-header.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/types/index.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/types/lifecycle.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/types/object-field-selector.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/types/persistent-volume-claim-template-spec.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/types/pod-security-context.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/types/pod-template-spec.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/types/probe.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/types/resource-field-selector.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/types/resource-requirements.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/types/role-ref.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/types/scale.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/types/se-linux-options.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/types/seccomp-profile.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/types/security-context.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/types/tcp-socket-action.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/types/volume-device.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/types/volume-mount.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/types/windows-security-context-options.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/kube-object/src/utils.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/utilities/index.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/utilities/src/formatDuration.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/utilities/src/iter.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/utilities/src/object.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/utilities/src/type-narrowing.ts delete mode 100644 frontend/providers/kubepanel/src/k8slens/utilities/src/types.ts delete mode 100644 frontend/providers/kubepanel/src/pages/404.tsx delete mode 100644 frontend/providers/kubepanel/src/pages/_app.tsx delete mode 100644 frontend/providers/kubepanel/src/pages/_document.tsx delete mode 100644 frontend/providers/kubepanel/src/pages/api/kubernetes/create.ts delete mode 100644 frontend/providers/kubepanel/src/pages/api/kubernetes/delete.ts delete mode 100644 frontend/providers/kubepanel/src/pages/api/kubernetes/list.ts delete mode 100644 frontend/providers/kubepanel/src/pages/api/kubernetes/template.ts delete mode 100644 frontend/providers/kubepanel/src/pages/api/kubernetes/update.ts delete mode 100644 frontend/providers/kubepanel/src/pages/api/platform/init-data.ts delete mode 100644 frontend/providers/kubepanel/src/pages/kubepanel/[[...slug]].tsx delete mode 100644 frontend/providers/kubepanel/src/pages/kubepanel/layout.tsx delete mode 100644 frontend/providers/kubepanel/src/services/backend/api.ts delete mode 100644 frontend/providers/kubepanel/src/services/backend/auth.ts delete mode 100644 frontend/providers/kubepanel/src/services/backend/error.ts delete mode 100644 frontend/providers/kubepanel/src/services/backend/kubeconfig.ts delete mode 100644 frontend/providers/kubepanel/src/services/backend/response.ts delete mode 100644 frontend/providers/kubepanel/src/services/error.ts delete mode 100644 frontend/providers/kubepanel/src/services/kubernet.ts delete mode 100644 frontend/providers/kubepanel/src/services/request.ts delete mode 100644 frontend/providers/kubepanel/src/store/global.ts delete mode 100644 frontend/providers/kubepanel/src/store/k8s/bucket.store.ts delete mode 100644 frontend/providers/kubepanel/src/store/k8s/cluster.store.ts delete mode 100644 frontend/providers/kubepanel/src/store/k8s/config-map.store.ts delete mode 100644 frontend/providers/kubepanel/src/store/k8s/deployment.store.ts delete mode 100644 frontend/providers/kubepanel/src/store/k8s/devbox.store.ts delete mode 100644 frontend/providers/kubepanel/src/store/k8s/event.store.ts delete mode 100644 frontend/providers/kubepanel/src/store/k8s/ingress.store.ts delete mode 100644 frontend/providers/kubepanel/src/store/k8s/kube.store.ts delete mode 100644 frontend/providers/kubepanel/src/store/k8s/pod.store.ts delete mode 100644 frontend/providers/kubepanel/src/store/k8s/secret.store.ts delete mode 100644 frontend/providers/kubepanel/src/store/k8s/service.store.ts delete mode 100644 frontend/providers/kubepanel/src/store/k8s/stateful-set.store.ts delete mode 100644 frontend/providers/kubepanel/src/store/k8s/volume-claim.store.ts delete mode 100644 frontend/providers/kubepanel/src/store/kube.ts delete mode 100644 frontend/providers/kubepanel/src/store/static.ts delete mode 100644 frontend/providers/kubepanel/src/styles/globals.css delete mode 100644 frontend/providers/kubepanel/src/types/api/base.d.ts delete mode 100644 frontend/providers/kubepanel/src/types/api/kubenertes.d.ts delete mode 100644 frontend/providers/kubepanel/src/types/detail.d.ts delete mode 100644 frontend/providers/kubepanel/src/types/kube-resource.d.ts delete mode 100644 frontend/providers/kubepanel/src/types/state.d.ts delete mode 100644 frontend/providers/kubepanel/src/types/util.d.ts delete mode 100644 frontend/providers/kubepanel/src/utils/api.ts delete mode 100644 frontend/providers/kubepanel/src/utils/condtion-color.ts delete mode 100644 frontend/providers/kubepanel/src/utils/kube-object-info.ts delete mode 100644 frontend/providers/kubepanel/src/utils/pie-chart.ts delete mode 100644 frontend/providers/kubepanel/src/utils/request-controller.ts delete mode 100644 frontend/providers/kubepanel/src/utils/status-color.ts delete mode 100644 frontend/providers/kubepanel/src/utils/types.ts delete mode 100644 frontend/providers/kubepanel/src/utils/user.ts delete mode 100644 frontend/providers/kubepanel/src/utils/yaml.ts delete mode 100644 frontend/providers/kubepanel/tailwind.config.js delete mode 100644 frontend/providers/kubepanel/tsconfig.json diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index db1f74134..0dfa259ec 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -21,7 +21,7 @@ sudo apt-get update && sudo apt-get install -y pkg-config libdevmapper-dev libbt ### Repository Structure - **`/lifecycle`**: Main sealos CLI and core binaries (sealos, sealctl, lvscare, image-cri-shim) - **`/controllers`**: Multiple Kubernetes controllers with individual Go modules and Makefiles -- **`/frontend`**: Next.js workspace with pnpm, 17 workspace projects (desktop, packages, providers) +- **`/frontend`**: Next.js workspace with pnpm, 16 workspace projects (desktop, packages, providers) - **`/service`**: Backend Go services with individual modules - **`/webhooks`**: Kubernetes admission webhooks - **`/docs`**: Documentation and guides diff --git a/.github/workflows/frontends.yml b/.github/workflows/frontends.yml index a1255afe8..3828f8b99 100644 --- a/.github/workflows/frontends.yml +++ b/.github/workflows/frontends.yml @@ -96,8 +96,6 @@ jobs: - 'frontend/providers/costcenter/**' objectstorage: - 'frontend/providers/objectstorage/**' - kubepanel: - - 'frontend/providers/kubepanel/**' desktop: - 'frontend/desktop/**' - name: Generate build matrix @@ -118,7 +116,6 @@ jobs: "providers/dbprovider" "providers/costcenter" "providers/objectstorage" - "providers/kubepanel" "desktop" ) else @@ -130,7 +127,6 @@ jobs: [[ "${{ steps.filter.outputs.dbprovider }}" == "true" ]] && modules+=("providers/dbprovider") [[ "${{ steps.filter.outputs.costcenter }}" == "true" ]] && modules+=("providers/costcenter") [[ "${{ steps.filter.outputs.objectstorage }}" == "true" ]] && modules+=("providers/objectstorage") - [[ "${{ steps.filter.outputs.kubepanel }}" == "true" ]] && modules+=("providers/kubepanel") [[ "${{ steps.filter.outputs.desktop }}" == "true" ]] && modules+=("desktop") fi diff --git a/frontend/Makefile b/frontend/Makefile index 6bd92c2cb..e88f0d02b 100644 --- a/frontend/Makefile +++ b/frontend/Makefile @@ -22,7 +22,6 @@ buildTargets := \ providers/imagehub \ providers/template \ providers/license \ - providers/kubepanel \ providers/objectstorage buildTargets-all := $(addprefix image-build-,$(buildTargets)) diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index 55ed4ed60..38e61d18c 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -1429,148 +1429,6 @@ importers: specifier: ^4.9.1 version: 4.10.1 - providers/kubepanel: - dependencies: - '@ant-design/charts': - specifier: ^2.6.6 - version: 2.6.6(react-dom@18.3.1)(react@18.3.1)(workerize-loader@2.0.2) - '@ant-design/icons': - specifier: ^6.1.0 - version: 6.1.0(react-dom@18.3.1)(react@18.3.1) - '@ant-design/plots': - specifier: ^2.6.6 - version: 2.6.6(react-dom@18.3.1)(react@18.3.1) - '@chakra-ui/anatomy': - specifier: ^2.2.1 - version: 2.2.2 - '@chakra-ui/icons': - specifier: ^2.1.1 - version: 2.1.1(@chakra-ui/system@2.6.2)(react@18.3.1) - '@chakra-ui/next-js': - specifier: ^2.1.5 - version: 2.2.0(@chakra-ui/react@2.8.2)(@emotion/react@11.11.1)(next@14.2.35)(react@18.3.1) - '@chakra-ui/react': - specifier: ^2.8.1 - version: 2.8.2(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(@types/react@18.3.27)(framer-motion@10.16.5)(react-dom@18.3.1)(react@18.3.1) - '@chakra-ui/system': - specifier: ^2.6.1 - version: 2.6.2(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.3.1) - '@emotion/react': - specifier: ^11.11.1 - version: 11.11.1(@types/react@18.3.27)(react@18.3.1) - '@emotion/styled': - specifier: ^11.11.0 - version: 11.11.0(@emotion/react@11.11.1)(@types/react@18.3.27)(react@18.3.1) - '@monaco-editor/react': - specifier: ^4.7.0 - version: 4.7.0(monaco-editor@0.55.1)(react-dom@18.3.1)(react@18.3.1) - antd: - specifier: ^6.1.0 - version: 6.1.1(moment@2.30.1)(react-dom@18.3.1)(react@18.3.1) - auto-bind: - specifier: ^5.0.1 - version: 5.0.1 - axios: - specifier: ^1.13.2 - version: 1.13.2 - framer-motion: - specifier: ^10.16.4 - version: 10.16.5(react-dom@18.3.1)(react@18.3.1) - i18next: - specifier: ^23.11.5 - version: 23.12.1 - js-yaml: - specifier: ^4.1.1 - version: 4.1.1 - lodash: - specifier: ^4.17.21 - version: 4.17.21 - moment: - specifier: ^2.29.4 - version: 2.30.1 - moment-timezone: - specifier: ^0.5.43 - version: 0.5.45 - monaco-editor: - specifier: ^0.55.1 - version: 0.55.1 - next: - specifier: 14.2.35 - version: 14.2.35(react-dom@18.3.1)(react@18.3.1) - next-i18next: - specifier: ^15.3.0 - version: 15.3.0(i18next@23.12.1)(next@14.2.35)(react-i18next@14.1.2)(react@18.3.1) - nprogress: - specifier: ^0.2.0 - version: 0.2.0 - react: - specifier: 18.3.1 - version: 18.3.1 - react-dom: - specifier: 18.3.1 - version: 18.3.1(react@18.3.1) - react-i18next: - specifier: ^14.1.2 - version: 14.1.2(i18next@23.12.1)(react-dom@18.3.1)(react@18.3.1) - sealos-desktop-sdk: - specifier: workspace:* - version: link:../../packages/client-sdk - type-fest: - specifier: ^5.3.1 - version: 5.3.1 - typed-regex: - specifier: ^0.0.8 - version: 0.0.8 - zustand: - specifier: ^5.0.9 - version: 5.0.9(@types/react@18.3.27)(react@18.3.1) - devDependencies: - '@tailwindcss/postcss': - specifier: ^4.1.17 - version: 4.1.18 - '@types/js-yaml': - specifier: ^4.0.9 - version: 4.0.9 - '@types/lodash': - specifier: ^4.17.21 - version: 4.17.21 - '@types/node': - specifier: ^24.0.0 - version: 24.10.4 - '@types/nprogress': - specifier: ^0.2.3 - version: 0.2.3 - '@types/react': - specifier: 18.3.27 - version: 18.3.27 - autoprefixer: - specifier: ^10.4.22 - version: 10.4.23(postcss@8.5.6) - eslint: - specifier: ^8.57.0 - version: 8.57.0 - eslint-config-next: - specifier: 14.2.3 - version: 14.2.3(eslint@8.57.0)(typescript@5.9.3) - eslint-plugin-xss: - specifier: ^0.1.12 - version: 0.1.12 - postcss: - specifier: ^8.5.6 - version: 8.5.6 - postcss-import: - specifier: ^16.1.1 - version: 16.1.1(postcss@8.5.6) - postcss-nesting: - specifier: ^13.0.2 - version: 13.0.2(postcss@8.5.6) - tailwindcss: - specifier: ^4.1.17 - version: 4.1.18 - typescript: - specifier: ^5.9.3 - version: 5.9.3 - providers/license: dependencies: '@chakra-ui/anatomy': @@ -2444,543 +2302,6 @@ packages: '@jridgewell/trace-mapping': 0.3.25 dev: false - /@ant-design/charts-util@0.0.1-alpha.7(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-Yh0o6EdO6SvdSnStFZMbnUzjyymkVzV+TQ9ymVW9hlVgO/fUkUII3JYSdV+UVcFnYwUF0YiDKuSTLCZNAzg2bQ==} - peerDependencies: - react: '>=16.8.4' - react-dom: '>=16.8.4' - dependencies: - lodash: 4.17.21 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@ant-design/charts-util@0.0.2(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-JuThvtHE8R3PldXzTkL3bmmFf0HVhih49CYinRrkwgovOmvDYaaKHnI53EWJbW8n4Ndcyy8jiZTSkoxcjGS6Zg==} - peerDependencies: - react: '>=16.8.4' - react-dom: '>=16.8.4' - dependencies: - lodash: 4.17.21 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@ant-design/charts@2.6.6(react-dom@18.3.1)(react@18.3.1)(workerize-loader@2.0.2): - resolution: {integrity: sha512-Mw2XqB9c7JoENyewJmtxU+5TU2sW5VEyct2f6n4HjJ/6hBo4ht3qdu965G3UrNLyiRctd47Qje32u+8DeFZ6Bg==} - peerDependencies: - react: '>=16.8.4' - react-dom: '>=16.8.4' - dependencies: - '@ant-design/graphs': 2.1.1(react-dom@18.3.1)(react@18.3.1)(workerize-loader@2.0.2) - '@ant-design/plots': 2.6.6(react-dom@18.3.1)(react@18.3.1) - lodash: 4.17.21 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - transitivePeerDependencies: - - workerize-loader - dev: false - - /@ant-design/colors@8.0.0: - resolution: {integrity: sha512-6YzkKCw30EI/E9kHOIXsQDHmMvTllT8STzjMb4K2qzit33RW2pqCJP0sk+hidBntXxE+Vz4n1+RvCTfBw6OErw==} - dependencies: - '@ant-design/fast-color': 3.0.0 - dev: false - - /@ant-design/cssinjs-utils@2.0.2(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-Mq3Hm6fJuQeFNKSp3+yT4bjuhVbdrsyXE2RyfpJFL0xiYNZdaJ6oFaE3zFrzmHbmvTd2Wp3HCbRtkD4fU+v2ZA==} - peerDependencies: - react: '>=18' - react-dom: '>=18' - dependencies: - '@ant-design/cssinjs': 2.0.1(react-dom@18.3.1)(react@18.3.1) - '@babel/runtime': 7.28.4 - '@rc-component/util': 1.6.0(react-dom@18.3.1)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@ant-design/cssinjs@2.0.1(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-Lw1Z4cUQxdMmTNir67gU0HCpTl5TtkKCJPZ6UBvCqzcOTl/QmMFB6qAEoj8qFl0CuZDX9qQYa3m9+rEKfaBSbA==} - peerDependencies: - react: '>=16.0.0' - react-dom: '>=16.0.0' - dependencies: - '@babel/runtime': 7.28.4 - '@emotion/hash': 0.8.0 - '@emotion/unitless': 0.7.5 - '@rc-component/util': 1.6.0(react-dom@18.3.1)(react@18.3.1) - clsx: 2.1.1 - csstype: 3.2.3 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - stylis: 4.3.6 - dev: false - - /@ant-design/fast-color@3.0.0: - resolution: {integrity: sha512-eqvpP7xEDm2S7dUzl5srEQCBTXZMmY3ekf97zI+M2DHOYyKdJGH0qua0JACHTqbkRnD/KHFQP9J1uMJ/XWVzzA==} - engines: {node: '>=8.x'} - dev: false - - /@ant-design/graphs@2.1.1(react-dom@18.3.1)(react@18.3.1)(workerize-loader@2.0.2): - resolution: {integrity: sha512-qT3Oo8BWeoAmZEy9gfR6uIk+rczbNJ3sWXKonoOD5koATWv7dY0kgvS1JnhdM1QW4FkfPPJTeQVSlRRUtvWDwA==} - peerDependencies: - react: '>=16.8.4' - react-dom: '>=16.8.4' - dependencies: - '@ant-design/charts-util': 0.0.1-alpha.7(react-dom@18.3.1)(react@18.3.1) - '@antv/g6': 5.0.50(workerize-loader@2.0.2) - '@antv/g6-extension-react': 0.2.6(@antv/g6@5.0.50)(react-dom@18.3.1)(react@18.3.1) - '@antv/graphin': 3.0.5(react-dom@18.3.1)(react@18.3.1)(workerize-loader@2.0.2) - lodash: 4.17.21 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - styled-components: 6.1.19(react-dom@18.3.1)(react@18.3.1) - transitivePeerDependencies: - - workerize-loader - dev: false - - /@ant-design/icons-svg@4.4.2: - resolution: {integrity: sha512-vHbT+zJEVzllwP+CM+ul7reTEfBR0vgxFe7+lREAsAA7YGsYpboiq2sQNeQeRvh09GfQgs/GyFEvZpJ9cLXpXA==} - dev: false - - /@ant-design/icons@6.1.0(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-KrWMu1fIg3w/1F2zfn+JlfNDU8dDqILfA5Tg85iqs1lf8ooyGlbkA+TkwfOKKgqpUmAiRY1PTFpuOU2DAIgSUg==} - engines: {node: '>=8'} - peerDependencies: - react: '>=16.0.0' - react-dom: '>=16.0.0' - dependencies: - '@ant-design/colors': 8.0.0 - '@ant-design/icons-svg': 4.4.2 - '@rc-component/util': 1.6.0(react-dom@18.3.1)(react@18.3.1) - clsx: 2.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@ant-design/plots@2.6.6(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-yUcvW/b7FPiIKwCpC0AOYQhHVKFCOpthlizsJx2Tuq7OEzTCLSWjRjT8o8sEWo3CCtIAtAuLY4GOfGdGGz1f0A==} - peerDependencies: - react: '>=16.8.4' - react-dom: '>=16.8.4' - dependencies: - '@ant-design/charts-util': 0.0.2(react-dom@18.3.1)(react@18.3.1) - '@antv/event-emitter': 0.1.3 - '@antv/g': 6.2.1 - '@antv/g2': 5.4.7 - '@antv/g2-extension-plot': 0.2.2 - lodash: 4.17.21 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@ant-design/react-slick@2.0.0(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-HMS9sRoEmZey8LsE/Yo6+klhlzU12PisjrVcydW3So7RdklyEd2qehyU6a7Yp+OYN72mgsYs3NFCyP2lCPFVqg==} - peerDependencies: - react: ^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react-dom: ^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - dependencies: - '@babel/runtime': 7.28.4 - clsx: 2.1.1 - json2mq: 0.2.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - throttle-debounce: 5.0.2 - dev: false - - /@antv/algorithm@0.1.26: - resolution: {integrity: sha512-DVhcFSQ8YQnMNW34Mk8BSsfc61iC1sAnmcfYoXTAshYHuU50p/6b7x3QYaGctDNKWGvi1ub7mPcSY0bK+aN0qg==} - dependencies: - '@antv/util': 2.0.17 - tslib: 2.6.2 - dev: false - - /@antv/component@2.1.11: - resolution: {integrity: sha512-dTdz8VAd3rpjOaGEZTluz82mtzrP4XCtNlNQyrxY7VNRNcjtvpTLDn57bUL2lRu1T+iklKvgbE2llMriWkq9vQ==} - dependencies: - '@antv/g': 6.2.1 - '@antv/scale': 0.4.16 - '@antv/util': 3.3.11 - svg-path-parser: 1.1.0 - dev: false - - /@antv/coord@0.4.7: - resolution: {integrity: sha512-UTbrMLhwJUkKzqJx5KFnSRpU3BqrdLORJbwUbHK2zHSCT3q3bjcFA//ZYLVfIlwqFDXp/hzfMyRtp0c77A9ZVA==} - dependencies: - '@antv/scale': 0.4.16 - '@antv/util': 2.0.17 - gl-matrix: 3.4.3 - dev: false - - /@antv/event-emitter@0.1.3: - resolution: {integrity: sha512-4ddpsiHN9Pd4UIlWuKVK1C4IiZIdbwQvy9i7DUSI3xNJ89FPUFt8lxDYj8GzzfdllV0NkJTRxnG+FvLk0llidg==} - dev: false - - /@antv/expr@1.0.2: - resolution: {integrity: sha512-vrfdmPHkTuiS5voVutKl2l06w1ihBh9A8SFdQPEE+2KMVpkymzGOF1eWpfkbGZ7tiFE15GodVdhhHomD/hdIwg==} - dev: false - - /@antv/g-camera-api@2.0.45: - resolution: {integrity: sha512-LhRFSFJtVvaIZYHG0jYHPx0/+Zwg5aFc+Iw2jo8o73vwGutmx2yNMYSJr/JOExgzulsGzGONezFENfLbccgh5A==} - dependencies: - '@antv/g-lite': 2.5.1 - '@antv/util': 3.3.7 - '@babel/runtime': 7.28.4 - gl-matrix: 3.4.3 - tslib: 2.6.2 - dev: false - - /@antv/g-canvas@2.0.52: - resolution: {integrity: sha512-tZoRfkrvVTe3e9OU+xhpgweTnQIctgaevoN47ZW15ymW792eq0oYRHPzNGsAAnhoFvBIhsT2/xEC9TuPFQdKuQ==} - dependencies: - '@antv/g-lite': 2.5.1 - '@antv/g-plugin-canvas-path-generator': 2.1.26 - '@antv/g-plugin-canvas-picker': 2.3.1 - '@antv/g-plugin-canvas-renderer': 2.5.1 - '@antv/g-plugin-dom-interaction': 2.1.31 - '@antv/g-plugin-html-renderer': 2.3.1 - '@antv/g-plugin-image-loader': 2.3.1 - '@antv/util': 3.3.11 - '@babel/runtime': 7.28.4 - tslib: 2.6.2 - dev: false - - /@antv/g-dom-mutation-observer-api@2.0.42: - resolution: {integrity: sha512-Utu0TZFEeGrBsw3cQD7MZwKBY39Cuys4zMsZpVetYDqQm/SexzqUQeIgCm9V0zJZfXPGEJNSvWL0NV6HGSYT3Q==} - dependencies: - '@antv/g-lite': 2.5.1 - '@babel/runtime': 7.28.4 - dev: false - - /@antv/g-lite@2.5.1: - resolution: {integrity: sha512-58Ul+fZb9qT/PYXMW7zUJrl62Q46MmZYZ6V7XelDZxZCL6LP2F2avDrreDGa3uYrihUjf7IvhVfBDviL4T4sdg==} - dependencies: - '@antv/g-math': 3.0.1 - '@antv/util': 3.3.7 - '@antv/vendor': 1.0.11 - '@babel/runtime': 7.28.4 - eventemitter3: 5.0.1 - gl-matrix: 3.4.3 - tslib: 2.6.2 - dev: false - - /@antv/g-math@3.0.1: - resolution: {integrity: sha512-FvkDBNRpj+HsLINunrL2PW0OlG368MlpHuihbxleuajGim5kra8tgISwCLmAf8Yz2b1CgZ9PvpohqiLzHS7HLg==} - dependencies: - '@antv/util': 3.3.7 - '@babel/runtime': 7.28.4 - gl-matrix: 3.4.3 - tslib: 2.6.2 - dev: false - - /@antv/g-plugin-canvas-path-generator@2.1.26: - resolution: {integrity: sha512-87V9NUbESa4PecvQmdGiQKu2avgLln3OTC1zjtexioOUJEpfTx8NTQeWcyzv6T7mJJMlptznfpkuRyZgDg/1+g==} - dependencies: - '@antv/g-lite': 2.5.1 - '@antv/g-math': 3.0.1 - '@antv/util': 3.3.11 - '@babel/runtime': 7.28.4 - tslib: 2.6.2 - dev: false - - /@antv/g-plugin-canvas-picker@2.3.1: - resolution: {integrity: sha512-h/ZgCuLxFo6xiA/XLGihBvfBjcGayua9buY6sqvyu8fHGA3AvE1RAhA/PeEOCDVBVQFvFLlkP1SaU9c+fqp23Q==} - dependencies: - '@antv/g-lite': 2.5.1 - '@antv/g-math': 3.0.1 - '@antv/g-plugin-canvas-path-generator': 2.1.26 - '@antv/g-plugin-canvas-renderer': 2.5.1 - '@antv/util': 3.3.11 - '@babel/runtime': 7.28.4 - gl-matrix: 3.4.3 - tslib: 2.6.2 - dev: false - - /@antv/g-plugin-canvas-renderer@2.5.1: - resolution: {integrity: sha512-nhKLU2tsMItOHWnPAQR3ryy/tQG4X5f2IGgzp8UjA1r2qwPcS8eB+vt0uqOwlk4Lo0ugujTt4rIIbfAXL6cRfQ==} - dependencies: - '@antv/g-lite': 2.5.1 - '@antv/g-math': 3.0.1 - '@antv/g-plugin-canvas-path-generator': 2.1.26 - '@antv/g-plugin-image-loader': 2.3.1 - '@antv/util': 3.3.11 - '@babel/runtime': 7.28.4 - gl-matrix: 3.4.3 - tslib: 2.6.2 - dev: false - - /@antv/g-plugin-dom-interaction@2.1.31: - resolution: {integrity: sha512-5FKJaVvc1O80yQlSLwyevuZZgYXGzcRHCLjPDwZ9tIa/79S5q9Hc9qkTBS4pM5B85EtHN+wZqVXHZKfm/6a9jA==} - dependencies: - '@antv/g-lite': 2.5.1 - '@babel/runtime': 7.28.4 - tslib: 2.6.2 - dev: false - - /@antv/g-plugin-dragndrop@2.0.42: - resolution: {integrity: sha512-EGrs8om9CwQka1Pgw02namBo1h0iqhskL5i1pD0CFhvCfAU2lxA2EHdYan+8vRQnDQVgXNbS+XAxzI6LQwByUQ==} - dependencies: - '@antv/g-lite': 2.5.1 - '@antv/util': 3.3.11 - '@babel/runtime': 7.28.4 - tslib: 2.6.2 - dev: false - - /@antv/g-plugin-html-renderer@2.3.1: - resolution: {integrity: sha512-s13zOJHbtCIRiSKI1N2xnX+XT253a9npPuJKH8bxbujWbRfXQVW6VaP517hVDeODO3sDklbEuDlMHSF94IP0Hg==} - dependencies: - '@antv/g-lite': 2.5.1 - '@antv/util': 3.3.11 - '@babel/runtime': 7.28.4 - gl-matrix: 3.4.3 - tslib: 2.6.2 - dev: false - - /@antv/g-plugin-image-loader@2.3.1: - resolution: {integrity: sha512-7UKLe2nbg/5YBQN3yy+dir5gHp53tp7rk7JxqnQnB2piXv/eZe6yq5hrfSVn74jwWkoUnjLe8u+++mHgoAsTng==} - dependencies: - '@antv/g-lite': 2.5.1 - '@antv/util': 3.3.11 - '@babel/runtime': 7.28.4 - gl-matrix: 3.4.3 - tslib: 2.6.2 - dev: false - - /@antv/g-plugin-svg-picker@2.0.46: - resolution: {integrity: sha512-Uz7+7tzXQHFDra3Mz/zZKw1OGYtXmXUtx69loIK8+iybviaNNPmjL2Cavj+LvcjvSlHFvNakzFPwBl54Isd74Q==} - dependencies: - '@antv/g-lite': 2.5.1 - '@antv/g-plugin-svg-renderer': 2.4.1 - '@babel/runtime': 7.28.4 - tslib: 2.6.2 - dev: false - - /@antv/g-plugin-svg-renderer@2.4.1: - resolution: {integrity: sha512-7KA3bC3Ilfs52rZvD21spoSxPU5ONsdW7RCZ0wW2qkyLwrCGAJabzdsEP8sF27WWLl/4Pf5QHVP6kcLWvT1eyA==} - dependencies: - '@antv/g-lite': 2.5.1 - '@antv/util': 3.3.7 - '@babel/runtime': 7.28.4 - gl-matrix: 3.4.3 - tslib: 2.6.2 - dev: false - - /@antv/g-svg@2.0.46: - resolution: {integrity: sha512-HWKR1vuBAggah8IRJXamUfJG3O38irsRcpqtQHNsLvoBxn426ZSISI4kjX2fc08xFu3nHy/ZkFQC4m5xd9s6KQ==} - dependencies: - '@antv/g-lite': 2.5.1 - '@antv/g-plugin-dom-interaction': 2.1.31 - '@antv/g-plugin-svg-picker': 2.0.46 - '@antv/g-plugin-svg-renderer': 2.4.1 - '@antv/util': 3.3.7 - '@babel/runtime': 7.28.4 - tslib: 2.6.2 - dev: false - - /@antv/g-web-animations-api@2.1.32: - resolution: {integrity: sha512-4Tf1bJbXxZkBF+DsHS+c6vEiv+ccNRqjeRfmniPOE3vwSVXZCKgvMhhIMQoxz0vVOaxYrDTpchquM5PF64qC0Q==} - dependencies: - '@antv/g-lite': 2.5.1 - '@antv/util': 3.3.7 - '@babel/runtime': 7.28.4 - tslib: 2.6.2 - dev: false - - /@antv/g2-extension-plot@0.2.2: - resolution: {integrity: sha512-KJXCXO7as+h0hDqirGXf1omrNuYzQmY3VmBmp7lIvkepbQ7sz3pPwy895r1FWETGF3vTk5UeFcAF5yzzBHWgbw==} - dependencies: - '@antv/g2': 5.4.7 - '@antv/util': 3.3.7 - '@antv/vendor': 1.0.11 - dev: false - - /@antv/g2@5.4.7: - resolution: {integrity: sha512-pYXOZ4Am+xgQbPshbHlbAsH6+DTPZ2iF8b63Vtfp19CoRuq6oO3cNZl+yweBs2WxLLSxVzjDkwBmB1kZBXOpFg==} - dependencies: - '@antv/component': 2.1.11 - '@antv/coord': 0.4.7 - '@antv/event-emitter': 0.1.3 - '@antv/expr': 1.0.2 - '@antv/g': 6.2.1 - '@antv/g-canvas': 2.0.52 - '@antv/g-plugin-dragndrop': 2.0.42 - '@antv/scale': 0.5.2 - '@antv/util': 3.3.11 - '@antv/vendor': 1.0.11 - flru: 1.0.2 - pdfast: 0.2.0 - dev: false - - /@antv/g6-extension-react@0.2.6(@antv/g6@5.0.50)(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-JWOiWMz/r4jG+Nn2Y28LfohpxfUaf9M/0brLdKBshSVa4DraQFfQvA9OTIbzahLLoxIXsKKG2KteQ9QcXL26Kw==} - peerDependencies: - '@antv/g6': ^5.0.50 - react: '>=16.8' - react-dom: '>=16.8' - dependencies: - '@antv/g': 6.2.1 - '@antv/g-svg': 2.0.46 - '@antv/g6': 5.0.50(workerize-loader@2.0.2) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@antv/g6@5.0.50(workerize-loader@2.0.2): - resolution: {integrity: sha512-L2ZdekSpJreIvSc4DkqGCh2bFmCadDZiR6q9euVtXdLeHPl/YQ4hqTvLIkc7aYO6oE/nC5mPAIOaM6ZiAy7QKA==} - dependencies: - '@antv/algorithm': 0.1.26 - '@antv/component': 2.1.11 - '@antv/event-emitter': 0.1.3 - '@antv/g': 6.2.1 - '@antv/g-canvas': 2.0.52 - '@antv/g-plugin-dragndrop': 2.0.42 - '@antv/graphlib': 2.0.4 - '@antv/hierarchy': 0.6.14 - '@antv/layout': 1.2.14-beta.9(workerize-loader@2.0.2) - '@antv/util': 3.3.11 - bubblesets-js: 2.3.4 - transitivePeerDependencies: - - workerize-loader - dev: false - - /@antv/g@6.2.1: - resolution: {integrity: sha512-RdRXtSKhS8u9xCkJQD6h5YthyyY5w5lTrx6VKyC96iE7YhPqrhEeOEqba9yxAR9tG5yy15Ix6vxBc0zWQ8ZZMA==} - dependencies: - '@antv/g-camera-api': 2.0.45 - '@antv/g-dom-mutation-observer-api': 2.0.42 - '@antv/g-lite': 2.5.1 - '@antv/g-web-animations-api': 2.1.32 - '@babel/runtime': 7.28.4 - dev: false - - /@antv/graphin@3.0.5(react-dom@18.3.1)(react@18.3.1)(workerize-loader@2.0.2): - resolution: {integrity: sha512-V/j8R8Ty44wUqxVIYLdpPuIO8WWCTIVq1eBJg5YRunL5t5o5qAFpC/qkQxslbBMWyKdIH0oWBnvHA74riGi7cw==} - peerDependencies: - react: ^18.0.0 || ^19.1.0 - react-dom: ^18.0.0 || ^19.1.0 - dependencies: - '@antv/g6': 5.0.50(workerize-loader@2.0.2) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - transitivePeerDependencies: - - workerize-loader - dev: false - - /@antv/graphlib@2.0.4: - resolution: {integrity: sha512-zc/5oQlsdk42Z0ib1mGklwzhJ5vczLFiPa1v7DgJkTbgJ2YxRh9xdarf86zI49sKVJmgbweRpJs7Nu5bIiwv4w==} - dependencies: - '@antv/event-emitter': 0.1.3 - dev: false - - /@antv/hierarchy@0.6.14: - resolution: {integrity: sha512-V3uknf7bhynOqQDw2sg+9r9DwZ9pc6k/EcqyTFdfXB1+ydr7urisP0MipIuimucvQKN+Qkd+d6w601r1UIroqQ==} - dev: false - - /@antv/layout@1.2.14-beta.9(workerize-loader@2.0.2): - resolution: {integrity: sha512-wPlwBFMtq2lWZFc89/7Lzb8fjHnyKVZZ9zBb2h+zZIP0YWmVmHRE8+dqCiPKOyOGUXEdDtn813f1g107dCHZlg==} - dependencies: - '@antv/event-emitter': 0.1.3 - '@antv/graphlib': 2.0.4 - '@antv/util': 3.3.11 - '@naoak/workerize-transferable': 0.1.0(workerize-loader@2.0.2) - comlink: 4.4.2 - d3-force: 3.0.0 - d3-force-3d: 3.0.6 - d3-octree: 1.1.0 - d3-quadtree: 3.0.1 - dagre: 0.8.5 - ml-matrix: 6.11.0 - tslib: 2.6.2 - transitivePeerDependencies: - - workerize-loader - dev: false - - /@antv/scale@0.4.16: - resolution: {integrity: sha512-5wg/zB5kXHxpTV5OYwJD3ja6R8yTiqIOkjOhmpEJiowkzRlbEC/BOyMvNUq5fqFIHnMCE9woO7+c3zxEQCKPjw==} - dependencies: - '@antv/util': 3.3.11 - color-string: 1.9.1 - fecha: 4.2.3 - dev: false - - /@antv/scale@0.5.2: - resolution: {integrity: sha512-rTHRAwvpHWC5PGZF/mJ2ZuTDqwwvVBDRph0Uu5PV9BXwzV7K8+9lsqGJ+XHVLxe8c6bKog5nlzvV/dcYb0d5Ow==} - dependencies: - '@antv/util': 3.3.11 - color-string: 1.9.1 - fecha: 4.2.3 - dev: false - - /@antv/util@2.0.17: - resolution: {integrity: sha512-o6I9hi5CIUvLGDhth0RxNSFDRwXeywmt6ExR4+RmVAzIi48ps6HUy+svxOCayvrPBN37uE6TAc2KDofRo0nK9Q==} - dependencies: - csstype: 3.2.3 - tslib: 2.6.2 - dev: false - - /@antv/util@3.3.11: - resolution: {integrity: sha512-FII08DFM4ABh2q5rPYdr0hMtKXRgeZazvXaFYCs7J7uTcWDHUhczab2qOCJLNDugoj8jFag1djb7wS9ehaRYBg==} - dependencies: - fast-deep-equal: 3.1.3 - gl-matrix: 3.4.3 - tslib: 2.6.2 - dev: false - - /@antv/util@3.3.7: - resolution: {integrity: sha512-qqPg7rIPCsJyl7N56jAC25v/99mJ3ApVkgBsGijhiWrEeKvzXBPk1r5P77Pm9nCljpnn+hH8Z3t5AivbEoTJMg==} - dependencies: - fast-deep-equal: 3.1.3 - gl-matrix: 3.4.3 - tslib: 2.6.2 - dev: false - - /@antv/vendor@1.0.11: - resolution: {integrity: sha512-LmhPEQ+aapk3barntaiIxJ5VHno/Tyab2JnfdcPzp5xONh/8VSfed4bo/9xKo5HcUAEydko38vYLfj6lJliLiw==} - dependencies: - '@types/d3-array': 3.2.2 - '@types/d3-color': 3.1.3 - '@types/d3-dispatch': 3.0.7 - '@types/d3-dsv': 3.0.7 - '@types/d3-ease': 3.0.2 - '@types/d3-fetch': 3.0.7 - '@types/d3-force': 3.0.10 - '@types/d3-format': 3.0.4 - '@types/d3-geo': 3.1.0 - '@types/d3-hierarchy': 3.1.7 - '@types/d3-interpolate': 3.0.4 - '@types/d3-path': 3.1.1 - '@types/d3-quadtree': 3.0.6 - '@types/d3-random': 3.0.3 - '@types/d3-scale': 4.0.9 - '@types/d3-scale-chromatic': 3.1.0 - '@types/d3-shape': 3.1.7 - '@types/d3-time': 3.0.4 - '@types/d3-timer': 3.0.2 - d3-array: 3.2.4 - d3-color: 3.1.0 - d3-dispatch: 3.0.1 - d3-dsv: 3.0.1 - d3-ease: 3.0.1 - d3-fetch: 3.0.1 - d3-force: 3.0.0 - d3-force-3d: 3.0.6 - d3-format: 3.1.0 - d3-geo: 3.1.1 - d3-geo-projection: 4.0.0 - d3-hierarchy: 3.1.2 - d3-interpolate: 3.0.1 - d3-path: 3.1.0 - d3-quadtree: 3.0.1 - d3-random: 3.0.1 - d3-regression: 1.3.10 - d3-scale: 4.0.2 - d3-scale-chromatic: 3.1.0 - d3-shape: 3.2.0 - d3-time: 3.1.0 - d3-timer: 3.0.1 - dev: false - /@asamuzakjp/css-color@4.1.0: resolution: {integrity: sha512-9xiBAtLn4aNsa4mDnpovJvBn72tNEIACyvlqaNJ+ADemR+yeMJWnBudOi2qGDviJa7SwcDOU/TRh5dnET7qk0w==} dependencies: @@ -6399,24 +5720,6 @@ packages: engines: {node: '>=18'} dev: true - /@csstools/selector-resolve-nested@3.1.0(postcss-selector-parser@7.1.1): - resolution: {integrity: sha512-mf1LEW0tJLKfWyvn5KdDrhpxHyuxpbNwTIwOYLIvsTffeyOf85j5oIzfG0yosxDgx/sswlqBnESYUcQH0vgZ0g==} - engines: {node: '>=18'} - peerDependencies: - postcss-selector-parser: ^7.0.0 - dependencies: - postcss-selector-parser: 7.1.1 - dev: true - - /@csstools/selector-specificity@5.0.0(postcss-selector-parser@7.1.1): - resolution: {integrity: sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==} - engines: {node: '>=18'} - peerDependencies: - postcss-selector-parser: ^7.0.0 - dependencies: - postcss-selector-parser: 7.1.1 - dev: true - /@date-fns/tz@1.4.1: resolution: {integrity: sha512-P5LUNhtbj6YfI3iJjw5EL9eUAG6OitD0W3fWQcpQjDRc/QIsL0tRNuO1PcDvPccWL1fSTXXdE1ds+l95DV/OFA==} dev: false @@ -6449,10 +5752,6 @@ packages: '@emotion/weak-memoize': 0.4.0 stylis: 4.2.0 - /@emotion/hash@0.8.0: - resolution: {integrity: sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==} - dev: false - /@emotion/hash@0.9.1: resolution: {integrity: sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==} @@ -6531,10 +5830,6 @@ packages: '@types/react': 18.3.27 react: 18.3.1 - /@emotion/unitless@0.7.5: - resolution: {integrity: sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==} - dev: false - /@emotion/unitless@0.8.1: resolution: {integrity: sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==} @@ -7256,6 +6551,7 @@ packages: strip-ansi-cjs: /strip-ansi@6.0.1 wrap-ansi: 8.1.0 wrap-ansi-cjs: /wrap-ansi@7.0.0 + dev: false /@isaacs/fs-minipass@4.0.1: resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} @@ -7309,6 +6605,7 @@ packages: dependencies: '@jridgewell/gen-mapping': 0.3.8 '@jridgewell/trace-mapping': 0.3.25 + dev: true /@jridgewell/sourcemap-codec@1.4.15: resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} @@ -7537,25 +6834,6 @@ packages: - supports-color dev: false - /@monaco-editor/loader@1.7.0: - resolution: {integrity: sha512-gIwR1HrJrrx+vfyOhYmCZ0/JcWqG5kbfG7+d3f/C1LXk2EvzAbHSg3MQ5lO2sMlo9izoAZ04shohfKLVT6crVA==} - dependencies: - state-local: 1.0.7 - dev: false - - /@monaco-editor/react@4.7.0(monaco-editor@0.55.1)(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-cyzXQCtO47ydzxpQtCGSQGOC8Gk3ZUeBXFAxD+CWXYFo5OqZyZUonFl0DwUlTyAfRHntBfw2p3w4s9R6oe1eCA==} - peerDependencies: - monaco-editor: '>= 0.25.0 < 1' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - dependencies: - '@monaco-editor/loader': 1.7.0 - monaco-editor: 0.55.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - /@mongodb-js/saslprep@1.1.1: resolution: {integrity: sha512-t7c5K033joZZMspnHg/gWPE4kandgc2OxE74aYOtGKfgB9VPuVJPix0H6fhmm2erj5PBJ21mqcx34lpIGtUCsQ==} requiresBuild: true @@ -7564,14 +6842,6 @@ packages: dev: false optional: true - /@naoak/workerize-transferable@0.1.0(workerize-loader@2.0.2): - resolution: {integrity: sha512-fDLfuP71IPNP5+zSfxFb52OHgtjZvauRJWbVnpzQ7G7BjcbLjTny0OW1d3ZO806XKpLWNKmeeW3MhE0sy8iwYQ==} - peerDependencies: - workerize-loader: '*' - dependencies: - workerize-loader: 2.0.2(webpack@5.104.1) - dev: false - /@next/bundle-analyzer@14.1.3: resolution: {integrity: sha512-QjMT5RGqvaObprL4Oim4SsjWUW6DxxfG+Fhq9arGw4CHbPBsjQkNWgUtW3WWW/Bjh4VhT+YBsJfxTyBVPHIlVw==} dependencies: @@ -7615,12 +6885,6 @@ packages: dependencies: glob: 7.1.7 - /@next/eslint-plugin-next@14.2.3: - resolution: {integrity: sha512-L3oDricIIjgj1AVnRdRor21gI7mShlSwU/1ZGHmqM3LzHhXXhdkrfeNY5zif25Bi5Dd7fiJHsbhoZCHfXYvlAw==} - dependencies: - glob: 10.3.10 - dev: true - /@next/font@13.1.6: resolution: {integrity: sha512-AITjmeb1RgX1HKMCiA39ztx2mxeAyxl4ljv2UoSBUGAbFFMg8MO7YAvjHCgFhD39hL7YTbFjol04e/BPBH5RzQ==} dev: false @@ -8169,6 +7433,7 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} requiresBuild: true + dev: false optional: true /@playwright/test@1.59.1: @@ -9250,592 +8515,6 @@ packages: resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} dev: false - /@rc-component/async-validator@5.0.4: - resolution: {integrity: sha512-qgGdcVIF604M9EqjNF0hbUTz42bz/RDtxWdWuU5EQe3hi7M8ob54B6B35rOsvX5eSvIHIzT9iH1R3n+hk3CGfg==} - engines: {node: '>=14.x'} - dependencies: - '@babel/runtime': 7.28.4 - dev: false - - /@rc-component/cascader@1.9.0(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-2jbthe1QZrMBgtCvNKkJFjZYC3uKl4N/aYm5SsMvO3T+F+qRT1CGsSM9bXnh1rLj7jDk/GK0natShWF/jinhWQ==} - peerDependencies: - react: '>=18.0.0' - react-dom: '>=18.0.0' - dependencies: - '@rc-component/select': 1.3.6(react-dom@18.3.1)(react@18.3.1) - '@rc-component/tree': 1.1.0(react-dom@18.3.1)(react@18.3.1) - '@rc-component/util': 1.6.0(react-dom@18.3.1)(react@18.3.1) - clsx: 2.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@rc-component/checkbox@1.0.1(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-08yTH8m+bSm8TOqbybbJ9KiAuIATti6bDs2mVeSfu4QfEnyeF6X0enHVvD1NEAyuBWEAo56QtLe++MYs2D9XiQ==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - dependencies: - '@rc-component/util': 1.6.0(react-dom@18.3.1)(react@18.3.1) - clsx: 2.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@rc-component/collapse@1.1.2(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-ilBYk1dLLJHu5Q74dF28vwtKUYQ42ZXIIDmqTuVy4rD8JQVvkXOs+KixVNbweyuIEtJYJ7+t+9GVD9dPc6N02w==} - peerDependencies: - react: '>=18.0.0' - react-dom: '>=18.0.0' - dependencies: - '@babel/runtime': 7.28.4 - '@rc-component/motion': 1.1.6(react-dom@18.3.1)(react@18.3.1) - '@rc-component/util': 1.6.0(react-dom@18.3.1)(react@18.3.1) - clsx: 2.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@rc-component/color-picker@3.0.3(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-V7gFF9O7o5XwIWafdbOtqI4BUUkEUkgdBwp6favy3xajMX/2dDqytFaiXlcwrpq6aRyPLp5dKLAG5RFKLXMeGA==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - dependencies: - '@ant-design/fast-color': 3.0.0 - '@rc-component/util': 1.6.0(react-dom@18.3.1)(react@18.3.1) - clsx: 2.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@rc-component/context@2.0.1(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-HyZbYm47s/YqtP6pKXNMjPEMaukyg7P0qVfgMLzr7YiFNMHbK2fKTAGzms9ykfGHSfyf75nBbgWw+hHkp+VImw==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - dependencies: - '@rc-component/util': 1.6.0(react-dom@18.3.1)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@rc-component/dialog@1.5.1(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-by4Sf/a3azcb89WayWuwG19/Y312xtu8N81HoVQQtnsBDylfs+dog98fTAvLinnpeoWG52m/M7QLRW6fXR3l1g==} - peerDependencies: - react: '>=18.0.0' - react-dom: '>=18.0.0' - dependencies: - '@rc-component/motion': 1.1.6(react-dom@18.3.1)(react@18.3.1) - '@rc-component/portal': 2.0.1(react-dom@18.3.1)(react@18.3.1) - '@rc-component/util': 1.6.0(react-dom@18.3.1)(react@18.3.1) - clsx: 2.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@rc-component/drawer@1.3.0(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-rE+sdXEmv2W25VBQ9daGbnb4J4hBIEKmdbj0b3xpY+K7TUmLXDIlSnoXraIbFZdGyek9WxxGKK887uRnFgI+pQ==} - peerDependencies: - react: '>=18.0.0' - react-dom: '>=18.0.0' - dependencies: - '@rc-component/motion': 1.1.6(react-dom@18.3.1)(react@18.3.1) - '@rc-component/portal': 2.0.1(react-dom@18.3.1)(react@18.3.1) - '@rc-component/util': 1.6.0(react-dom@18.3.1)(react@18.3.1) - clsx: 2.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@rc-component/dropdown@1.0.2(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-6PY2ecUSYhDPhkNHHb4wfeAya04WhpmUSKzdR60G+kMNVUCX2vjT/AgTS0Lz0I/K6xrPMJ3enQbwVpeN3sHCgg==} - peerDependencies: - react: '>=16.11.0' - react-dom: '>=16.11.0' - dependencies: - '@rc-component/trigger': 3.7.2(react-dom@18.3.1)(react@18.3.1) - '@rc-component/util': 1.6.0(react-dom@18.3.1)(react@18.3.1) - clsx: 2.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@rc-component/form@1.5.0(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-clF2Ws00bImVSOfaF4e2dLr631g5QOUD7M7kqb8es6fWXkJ1YO4nmjGJTQ/7QfB7iqY6JED4yV12ftKKD5/8GQ==} - engines: {node: '>=8.x'} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - dependencies: - '@rc-component/async-validator': 5.0.4 - '@rc-component/util': 1.6.0(react-dom@18.3.1)(react@18.3.1) - clsx: 2.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@rc-component/image@1.5.3(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-/NR7QW9uCN8Ugar+xsHZOPvzPySfEhcW2/vLcr7VPRM+THZMrllMRv7LAUgW7ikR+Z67Ab67cgPp5K5YftpJsQ==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - dependencies: - '@rc-component/motion': 1.1.6(react-dom@18.3.1)(react@18.3.1) - '@rc-component/portal': 2.0.1(react-dom@18.3.1)(react@18.3.1) - '@rc-component/util': 1.6.0(react-dom@18.3.1)(react@18.3.1) - clsx: 2.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@rc-component/input-number@1.6.2(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-Gjcq7meZlCOiWN1t1xCC+7/s85humHVokTBI7PJgTfoyw5OWF74y3e6P8PHX104g9+b54jsodFIzyaj6p8LI9w==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - dependencies: - '@rc-component/mini-decimal': 1.1.0 - '@rc-component/util': 1.6.0(react-dom@18.3.1)(react@18.3.1) - clsx: 2.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@rc-component/input@1.1.2(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-Q61IMR47piUBudgixJ30CciKIy9b1H95qe7GgEKOmSJVJXvFRWJllJfQry9tif+MX2cWFXWJf/RXz4kaCeq/Fg==} - peerDependencies: - react: '>=16.0.0' - react-dom: '>=16.0.0' - dependencies: - '@rc-component/util': 1.6.0(react-dom@18.3.1)(react@18.3.1) - clsx: 2.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@rc-component/mentions@1.6.0(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-KIkQNP6habNuTsLhUv0UGEOwG67tlmE7KNIJoQZZNggEZl5lQJTytFDb69sl5CK3TDdISCTjKP3nGEBKgT61CQ==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - dependencies: - '@rc-component/input': 1.1.2(react-dom@18.3.1)(react@18.3.1) - '@rc-component/menu': 1.2.0(react-dom@18.3.1)(react@18.3.1) - '@rc-component/textarea': 1.1.2(react-dom@18.3.1)(react@18.3.1) - '@rc-component/trigger': 3.7.2(react-dom@18.3.1)(react@18.3.1) - '@rc-component/util': 1.6.0(react-dom@18.3.1)(react@18.3.1) - clsx: 2.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@rc-component/menu@1.2.0(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-VWwDuhvYHSnTGj4n6bV3ISrLACcPAzdPOq3d0BzkeiM5cve8BEYfvkEhNoM0PLzv51jpcejeyrLXeMVIJ+QJlg==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - dependencies: - '@rc-component/motion': 1.1.6(react-dom@18.3.1)(react@18.3.1) - '@rc-component/overflow': 1.0.0(react-dom@18.3.1)(react@18.3.1) - '@rc-component/trigger': 3.7.2(react-dom@18.3.1)(react@18.3.1) - '@rc-component/util': 1.6.0(react-dom@18.3.1)(react@18.3.1) - clsx: 2.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@rc-component/mini-decimal@1.1.0: - resolution: {integrity: sha512-jS4E7T9Li2GuYwI6PyiVXmxTiM6b07rlD9Ge8uGZSCz3WlzcG5ZK7g5bbuKNeZ9pgUuPK/5guV781ujdVpm4HQ==} - engines: {node: '>=8.x'} - dependencies: - '@babel/runtime': 7.28.4 - dev: false - - /@rc-component/motion@1.1.6(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-aEQobs/YA0kqRvHIPjQvOytdtdRVyhf/uXAal4chBjxDu6odHckExJzjn2D+Ju1aKK6hx3pAs6BXdV9+86xkgQ==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - dependencies: - '@rc-component/util': 1.6.0(react-dom@18.3.1)(react@18.3.1) - clsx: 2.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@rc-component/mutate-observer@2.0.1(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-AyarjoLU5YlxuValRi+w8JRH2Z84TBbFO2RoGWz9d8bSu0FqT8DtugH3xC3BV7mUwlmROFauyWuXFuq4IFbH+w==} - engines: {node: '>=8.x'} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - dependencies: - '@rc-component/util': 1.6.0(react-dom@18.3.1)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@rc-component/notification@1.2.0(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-OX3J+zVU7rvoJCikjrfW7qOUp7zlDeFBK2eA3SFbGSkDqo63Sl4Ss8A04kFP+fxHSxMDIS9jYVEZtU1FNCFuBA==} - engines: {node: '>=8.x'} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - dependencies: - '@rc-component/motion': 1.1.6(react-dom@18.3.1)(react@18.3.1) - '@rc-component/util': 1.6.0(react-dom@18.3.1)(react@18.3.1) - clsx: 2.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@rc-component/overflow@1.0.0(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-GSlBeoE0XTBi5cf3zl8Qh7Uqhn7v8RrlJ8ajeVpEkNe94HWy5l5BQ0Mwn2TVUq9gdgbfEMUmTX7tJFAg7mz0Rw==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - dependencies: - '@babel/runtime': 7.28.4 - '@rc-component/resize-observer': 1.0.1(react-dom@18.3.1)(react@18.3.1) - '@rc-component/util': 1.6.0(react-dom@18.3.1)(react@18.3.1) - clsx: 2.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@rc-component/pagination@1.2.0(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-YcpUFE8dMLfSo6OARJlK6DbHHvrxz7pMGPGmC/caZSJJz6HRKHC1RPP001PRHCvG9Z/veD039uOQmazVuLJzlw==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - dependencies: - '@rc-component/util': 1.6.0(react-dom@18.3.1)(react@18.3.1) - clsx: 2.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@rc-component/picker@1.9.0(dayjs@1.11.19)(moment@2.30.1)(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-OLisdk8AWVCG9goBU1dWzuH5QlBQk8jktmQ6p0/IyBFwdKGwyIZOSjnBYo8hooHiTdl0lU+wGf/OfMtVBw02KQ==} - engines: {node: '>=12.x'} - peerDependencies: - date-fns: '>= 2.x' - dayjs: '>= 1.x' - luxon: '>= 3.x' - moment: '>= 2.x' - react: '>=16.9.0' - react-dom: '>=16.9.0' - peerDependenciesMeta: - date-fns: - optional: true - dayjs: - optional: true - luxon: - optional: true - moment: - optional: true - dependencies: - '@rc-component/overflow': 1.0.0(react-dom@18.3.1)(react@18.3.1) - '@rc-component/resize-observer': 1.0.1(react-dom@18.3.1)(react@18.3.1) - '@rc-component/trigger': 3.7.2(react-dom@18.3.1)(react@18.3.1) - '@rc-component/util': 1.6.0(react-dom@18.3.1)(react@18.3.1) - clsx: 2.1.1 - dayjs: 1.11.19 - moment: 2.30.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@rc-component/portal@2.0.1(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-46KYuA7Udb1LAaLIdDrfmDz3wzyeEZxIURJCn+heoQVbhtW5PQkhBSQtRus+DUdsknmTFQulxSnqrbX3CI4yXw==} - engines: {node: '>=12.x'} - peerDependencies: - react: '>=18.0.0' - react-dom: '>=18.0.0' - dependencies: - '@rc-component/util': 1.6.0(react-dom@18.3.1)(react@18.3.1) - clsx: 2.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@rc-component/progress@1.0.2(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-WZUnH9eGxH1+xodZKqdrHke59uyGZSWgj5HBM5Kwk5BrTMuAORO7VJ2IP5Qbm9aH3n9x3IcesqHHR0NWPBC7fQ==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - dependencies: - '@rc-component/util': 1.6.0(react-dom@18.3.1)(react@18.3.1) - clsx: 2.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@rc-component/qrcode@1.1.1(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-LfLGNymzKdUPjXUbRP+xOhIWY4jQ+YMj5MmWAcgcAq1Ij8XP7tRmAXqyuv96XvLUBE/5cA8hLFl9eO1JQMujrA==} - engines: {node: '>=8.x'} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - dependencies: - '@babel/runtime': 7.28.4 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@rc-component/rate@1.0.1(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-bkXxeBqDpl5IOC7yL7GcSYjQx9G8H+6kLYQnNZWeBYq2OYIv1MONd6mqKTjnnJYpV0cQIU2z3atdW0j1kttpTw==} - engines: {node: '>=8.x'} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - dependencies: - '@rc-component/util': 1.6.0(react-dom@18.3.1)(react@18.3.1) - clsx: 2.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@rc-component/resize-observer@1.0.1(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-r+w+Mz1EiueGk1IgjB3ptNXLYSLZ5vnEfKHH+gfgj7JMupftyzvUUl3fRcMZe5uMM04x0n8+G2o/c6nlO2+Wag==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - dependencies: - '@rc-component/util': 1.6.0(react-dom@18.3.1)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@rc-component/segmented@1.2.3(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-L7G4S6zUpqHclOXK0wKKN2/VyqHa9tfDNxkoFjWOTPtQ0ROFaBwZhbf1+9sdZfIFkxJkpcShAmDOMEIBaFFqkw==} - peerDependencies: - react: '>=16.0.0' - react-dom: '>=16.0.0' - dependencies: - '@babel/runtime': 7.28.4 - '@rc-component/motion': 1.1.6(react-dom@18.3.1)(react@18.3.1) - '@rc-component/util': 1.6.0(react-dom@18.3.1)(react@18.3.1) - clsx: 2.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@rc-component/select@1.3.6(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-CzbJ9TwmWcF5asvTMZ9BMiTE9CkkrigeOGRPpzCNmeZP7KBwwmYrmOIiKh9tMG7d6DyGAEAQ75LBxzPx+pGTHA==} - engines: {node: '>=8.x'} - peerDependencies: - react: '*' - react-dom: '*' - dependencies: - '@rc-component/overflow': 1.0.0(react-dom@18.3.1)(react@18.3.1) - '@rc-component/trigger': 3.7.2(react-dom@18.3.1)(react@18.3.1) - '@rc-component/util': 1.6.0(react-dom@18.3.1)(react@18.3.1) - '@rc-component/virtual-list': 1.0.2(react-dom@18.3.1)(react@18.3.1) - clsx: 2.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@rc-component/slider@1.0.1(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-uDhEPU1z3WDfCJhaL9jfd2ha/Eqpdfxsn0Zb0Xcq1NGQAman0TWaR37OWp2vVXEOdV2y0njSILTMpTfPV1454g==} - engines: {node: '>=8.x'} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - dependencies: - '@rc-component/util': 1.6.0(react-dom@18.3.1)(react@18.3.1) - clsx: 2.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@rc-component/steps@1.2.2(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-/yVIZ00gDYYPHSY0JP+M+s3ZvuXLu2f9rEjQqiUDs7EcYsUYrpJ/1bLj9aI9R7MBR3fu/NGh6RM9u2qGfqp+Nw==} - engines: {node: '>=8.x'} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - dependencies: - '@rc-component/util': 1.6.0(react-dom@18.3.1)(react@18.3.1) - clsx: 2.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@rc-component/switch@1.0.3(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-Jgi+EbOBquje/XNdofr7xbJQZPYJP+BlPfR0h+WN4zFkdtB2EWqEfvkXJWeipflwjWip0/17rNbxEAqs8hVHfw==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - dependencies: - '@rc-component/util': 1.6.0(react-dom@18.3.1)(react@18.3.1) - clsx: 2.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@rc-component/table@1.9.0(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-cq3P9FkD+F3eglkFYhBuNlHclg+r4jY8+ZIgK7zbEFo6IwpnA77YL/Gq4ensLw9oua3zFCTA6JDu6YgBei0TxA==} - engines: {node: '>=8.x'} - peerDependencies: - react: '>=18.0.0' - react-dom: '>=18.0.0' - dependencies: - '@rc-component/context': 2.0.1(react-dom@18.3.1)(react@18.3.1) - '@rc-component/resize-observer': 1.0.1(react-dom@18.3.1)(react@18.3.1) - '@rc-component/util': 1.6.0(react-dom@18.3.1)(react@18.3.1) - '@rc-component/virtual-list': 1.0.2(react-dom@18.3.1)(react@18.3.1) - clsx: 2.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@rc-component/tabs@1.7.0(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-J48cs2iBi7Ho3nptBxxIqizEliUC+ExE23faspUQKGQ550vaBlv3aGF8Epv/UB1vFWeoJDTW/dNzgIU0Qj5i/w==} - engines: {node: '>=8.x'} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - dependencies: - '@rc-component/dropdown': 1.0.2(react-dom@18.3.1)(react@18.3.1) - '@rc-component/menu': 1.2.0(react-dom@18.3.1)(react@18.3.1) - '@rc-component/motion': 1.1.6(react-dom@18.3.1)(react@18.3.1) - '@rc-component/resize-observer': 1.0.1(react-dom@18.3.1)(react@18.3.1) - '@rc-component/util': 1.6.0(react-dom@18.3.1)(react@18.3.1) - clsx: 2.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@rc-component/textarea@1.1.2(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-9rMUEODWZDMovfScIEHXWlVZuPljZ2pd1LKNjslJVitn4SldEzq5vO1CL3yy3Dnib6zZal2r2DPtjy84VVpF6A==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - dependencies: - '@rc-component/input': 1.1.2(react-dom@18.3.1)(react@18.3.1) - '@rc-component/resize-observer': 1.0.1(react-dom@18.3.1)(react@18.3.1) - '@rc-component/util': 1.6.0(react-dom@18.3.1)(react@18.3.1) - clsx: 2.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@rc-component/tooltip@1.4.0(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-8Rx5DCctIlLI4raR0I0xHjVTf1aF48+gKCNeAAo5bmF5VoR5YED+A/XEqzXv9KKqrJDRcd3Wndpxh2hyzrTtSg==} - peerDependencies: - react: '>=18.0.0' - react-dom: '>=18.0.0' - dependencies: - '@rc-component/trigger': 3.7.2(react-dom@18.3.1)(react@18.3.1) - '@rc-component/util': 1.6.0(react-dom@18.3.1)(react@18.3.1) - clsx: 2.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@rc-component/tour@2.2.1(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-BUCrVikGJsXli38qlJ+h2WyDD6dYxzDA9dV3o0ij6gYhAq6ooT08SUMWOikva9v4KZ2BEuluGl5bPcsjrSoBgQ==} - engines: {node: '>=8.x'} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - dependencies: - '@rc-component/portal': 2.0.1(react-dom@18.3.1)(react@18.3.1) - '@rc-component/trigger': 3.7.2(react-dom@18.3.1)(react@18.3.1) - '@rc-component/util': 1.6.0(react-dom@18.3.1)(react@18.3.1) - clsx: 2.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@rc-component/tree-select@1.4.0(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-I3UAlO2hNqy9CSKc8EBaESgnmKk2QaRzuZ2XHZGFCgsSMkGl06mdF97sVfROM02YIb64ocgLKefsjE0Ch4ocwQ==} - peerDependencies: - react: '*' - react-dom: '*' - dependencies: - '@rc-component/select': 1.3.6(react-dom@18.3.1)(react@18.3.1) - '@rc-component/tree': 1.1.0(react-dom@18.3.1)(react@18.3.1) - '@rc-component/util': 1.6.0(react-dom@18.3.1)(react@18.3.1) - clsx: 2.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@rc-component/tree@1.1.0(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-HZs3aOlvFgQdgrmURRc/f4IujiNBf4DdEeXUlkS0lPoLlx9RoqsZcF0caXIAMVb+NaWqKtGQDnrH8hqLCN5zlA==} - engines: {node: '>=10.x'} - peerDependencies: - react: '*' - react-dom: '*' - dependencies: - '@rc-component/motion': 1.1.6(react-dom@18.3.1)(react@18.3.1) - '@rc-component/util': 1.6.0(react-dom@18.3.1)(react@18.3.1) - '@rc-component/virtual-list': 1.0.2(react-dom@18.3.1)(react@18.3.1) - clsx: 2.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@rc-component/trigger@3.7.2(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-25x+D2k9SAkaK/MNMNmv2Nlv8FH1D9RtmjoMoLEw1Cid+sMV4pAAT5k49ku59UeXaOA1qwLUVrBUMq4A6gUSsQ==} - engines: {node: '>=8.x'} - peerDependencies: - react: '>=18.0.0' - react-dom: '>=18.0.0' - dependencies: - '@rc-component/motion': 1.1.6(react-dom@18.3.1)(react@18.3.1) - '@rc-component/portal': 2.0.1(react-dom@18.3.1)(react@18.3.1) - '@rc-component/resize-observer': 1.0.1(react-dom@18.3.1)(react@18.3.1) - '@rc-component/util': 1.6.0(react-dom@18.3.1)(react@18.3.1) - clsx: 2.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@rc-component/upload@1.1.0(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-LIBV90mAnUE6VK5N4QvForoxZc4XqEYZimcp7fk+lkE4XwHHyJWxpIXQQwMU8hJM+YwBbsoZkGksL1sISWHQxw==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - dependencies: - '@rc-component/util': 1.6.0(react-dom@18.3.1)(react@18.3.1) - clsx: 2.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@rc-component/util@1.6.0(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-YbjuIVAm8InCnXVoA4n6G+uh31yESTxQ6fSY2frZ2/oMSvktoB+bumFUfNN7RKh7YeOkZgOvN2suGtEDhJSX0A==} - peerDependencies: - react: '>=18.0.0' - react-dom: '>=18.0.0' - dependencies: - is-mobile: 5.0.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-is: 18.2.0 - dev: false - - /@rc-component/virtual-list@1.0.2(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-uvTol/mH74FYsn5loDGJxo+7kjkO4i+y4j87Re1pxJBs0FaeuMuLRzQRGaXwnMcV1CxpZLi2Z56Rerj2M00fjQ==} - engines: {node: '>=8.x'} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - dependencies: - '@babel/runtime': 7.28.4 - '@rc-component/resize-observer': 1.0.1(react-dom@18.3.1)(react@18.3.1) - '@rc-component/util': 1.6.0(react-dom@18.3.1)(react@18.3.1) - clsx: 2.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - /@redis/bloom@1.2.0(@redis/client@1.6.1): resolution: {integrity: sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==} peerDependencies: @@ -11777,92 +10456,6 @@ packages: '@types/node': 20.17.32 dev: true - /@types/d3-array@3.2.2: - resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==} - dev: false - - /@types/d3-color@3.1.3: - resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} - dev: false - - /@types/d3-dispatch@3.0.7: - resolution: {integrity: sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==} - dev: false - - /@types/d3-dsv@3.0.7: - resolution: {integrity: sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==} - dev: false - - /@types/d3-ease@3.0.2: - resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==} - dev: false - - /@types/d3-fetch@3.0.7: - resolution: {integrity: sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==} - dependencies: - '@types/d3-dsv': 3.0.7 - dev: false - - /@types/d3-force@3.0.10: - resolution: {integrity: sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==} - dev: false - - /@types/d3-format@3.0.4: - resolution: {integrity: sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==} - dev: false - - /@types/d3-geo@3.1.0: - resolution: {integrity: sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==} - dependencies: - '@types/geojson': 7946.0.14 - dev: false - - /@types/d3-hierarchy@3.1.7: - resolution: {integrity: sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==} - dev: false - - /@types/d3-interpolate@3.0.4: - resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} - dependencies: - '@types/d3-color': 3.1.3 - dev: false - - /@types/d3-path@3.1.1: - resolution: {integrity: sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==} - dev: false - - /@types/d3-quadtree@3.0.6: - resolution: {integrity: sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==} - dev: false - - /@types/d3-random@3.0.3: - resolution: {integrity: sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==} - dev: false - - /@types/d3-scale-chromatic@3.1.0: - resolution: {integrity: sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==} - dev: false - - /@types/d3-scale@4.0.9: - resolution: {integrity: sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==} - dependencies: - '@types/d3-time': 3.0.4 - dev: false - - /@types/d3-shape@3.1.7: - resolution: {integrity: sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==} - dependencies: - '@types/d3-path': 3.1.1 - dev: false - - /@types/d3-time@3.0.4: - resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==} - dev: false - - /@types/d3-timer@3.0.2: - resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==} - dev: false - /@types/debug@4.1.12: resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} dependencies: @@ -11879,22 +10472,9 @@ packages: '@types/node': 20.17.32 dev: true - /@types/eslint-scope@3.7.7: - resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} - dependencies: - '@types/eslint': 9.6.1 - '@types/estree': 1.0.8 - dev: false - - /@types/eslint@9.6.1: - resolution: {integrity: sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==} - dependencies: - '@types/estree': 1.0.8 - '@types/json-schema': 7.0.15 - dev: false - /@types/estree@1.0.8: resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + dev: true /@types/express-serve-static-core@4.17.41: resolution: {integrity: sha512-OaJ7XLaelTgrvlZD8/aa0vvvxZdUmlCn6MtWeB7TkiKW70BQLc9XEPpDLPdbo52ZhXUCrznlWdCHWxJWtdyajA==} @@ -11926,10 +10506,6 @@ packages: '@types/node': 20.17.32 dev: true - /@types/geojson@7946.0.14: - resolution: {integrity: sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg==} - dev: false - /@types/glob@7.2.0: resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} dependencies: @@ -11977,6 +10553,7 @@ packages: /@types/json-schema@7.0.15: resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + dev: true /@types/json5@0.0.29: resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} @@ -12075,12 +10652,6 @@ packages: undici-types: 6.21.0 dev: false - /@types/node@24.10.4: - resolution: {integrity: sha512-vnDVpYPMzs4wunl27jHrfmwojOGKya0xyM3sH+UE5iv5uPS6vX7UIoh6m+vQc5LGBq52HBKPIn/zcSZVzeDEZg==} - dependencies: - undici-types: 7.16.0 - dev: true - /@types/nodemailer@6.4.15: resolution: {integrity: sha512-0EBJxawVNjPkng1zm2vopRctuWVCxk34JcIlRuXSf54habUWdz1FB7wHDqOqvDa8Mtpt0Q3LTXQkAs2LNyK5jQ==} dependencies: @@ -12169,10 +10740,6 @@ packages: '@types/node': 20.17.32 dev: true - /@types/stylis@4.2.5: - resolution: {integrity: sha512-1Xve+NMN7FWjY14vLoY5tL3BVEQ/n42YLwaqJIPYhotZ9uBHt87VceMwWQpzmdEt2TNXIorIFG+YeCUUW7RInw==} - dev: false - /@types/tough-cookie@4.0.5: resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} @@ -12926,112 +11493,6 @@ packages: vue: 3.5.29(typescript@5.2.2) dev: false - /@webassemblyjs/ast@1.14.1: - resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==} - dependencies: - '@webassemblyjs/helper-numbers': 1.13.2 - '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - dev: false - - /@webassemblyjs/floating-point-hex-parser@1.13.2: - resolution: {integrity: sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==} - dev: false - - /@webassemblyjs/helper-api-error@1.13.2: - resolution: {integrity: sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==} - dev: false - - /@webassemblyjs/helper-buffer@1.14.1: - resolution: {integrity: sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==} - dev: false - - /@webassemblyjs/helper-numbers@1.13.2: - resolution: {integrity: sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==} - dependencies: - '@webassemblyjs/floating-point-hex-parser': 1.13.2 - '@webassemblyjs/helper-api-error': 1.13.2 - '@xtuc/long': 4.2.2 - dev: false - - /@webassemblyjs/helper-wasm-bytecode@1.13.2: - resolution: {integrity: sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==} - dev: false - - /@webassemblyjs/helper-wasm-section@1.14.1: - resolution: {integrity: sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==} - dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-buffer': 1.14.1 - '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - '@webassemblyjs/wasm-gen': 1.14.1 - dev: false - - /@webassemblyjs/ieee754@1.13.2: - resolution: {integrity: sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==} - dependencies: - '@xtuc/ieee754': 1.2.0 - dev: false - - /@webassemblyjs/leb128@1.13.2: - resolution: {integrity: sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==} - dependencies: - '@xtuc/long': 4.2.2 - dev: false - - /@webassemblyjs/utf8@1.13.2: - resolution: {integrity: sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==} - dev: false - - /@webassemblyjs/wasm-edit@1.14.1: - resolution: {integrity: sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==} - dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-buffer': 1.14.1 - '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - '@webassemblyjs/helper-wasm-section': 1.14.1 - '@webassemblyjs/wasm-gen': 1.14.1 - '@webassemblyjs/wasm-opt': 1.14.1 - '@webassemblyjs/wasm-parser': 1.14.1 - '@webassemblyjs/wast-printer': 1.14.1 - dev: false - - /@webassemblyjs/wasm-gen@1.14.1: - resolution: {integrity: sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==} - dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - '@webassemblyjs/ieee754': 1.13.2 - '@webassemblyjs/leb128': 1.13.2 - '@webassemblyjs/utf8': 1.13.2 - dev: false - - /@webassemblyjs/wasm-opt@1.14.1: - resolution: {integrity: sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==} - dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-buffer': 1.14.1 - '@webassemblyjs/wasm-gen': 1.14.1 - '@webassemblyjs/wasm-parser': 1.14.1 - dev: false - - /@webassemblyjs/wasm-parser@1.14.1: - resolution: {integrity: sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==} - dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-api-error': 1.13.2 - '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - '@webassemblyjs/ieee754': 1.13.2 - '@webassemblyjs/leb128': 1.13.2 - '@webassemblyjs/utf8': 1.13.2 - dev: false - - /@webassemblyjs/wast-printer@1.14.1: - resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==} - dependencies: - '@webassemblyjs/ast': 1.14.1 - '@xtuc/long': 4.2.2 - dev: false - /@xterm/addon-fit@0.11.0: resolution: {integrity: sha512-jYcgT6xtVYhnhgxh3QgYDnnNMYTcf8ElbxxFzX0IZo+vabQqSPAjC3c1wJrKB5E19VwQei89QCiZZP86DCPF7g==} dev: false @@ -13040,14 +11501,6 @@ packages: resolution: {integrity: sha512-TQwDdQGtwwDt+2cgKDLn0IRaSxYu1tSUjgKarSDkUM0ZNiSRXFpjxEsvc/Zgc5kq5omJ+V0a8/kIM2WD3sMOYg==} dev: false - /@xtuc/ieee754@1.2.0: - resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} - dev: false - - /@xtuc/long@4.2.2: - resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} - dev: false - /@zag-js/dom-query@0.16.0: resolution: {integrity: sha512-Oqhd6+biWyKnhKwFFuZrrf6lxBz2tX2pRQe6grUnYwO6HJ8BcbqZomy2lpOdr+3itlaUqx+Ywj5E5ZZDr/LBfQ==} @@ -13084,15 +11537,6 @@ packages: negotiator: 1.0.0 dev: false - /acorn-import-phases@1.0.4(acorn@8.15.0): - resolution: {integrity: sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==} - engines: {node: '>=10.13.0'} - peerDependencies: - acorn: ^8.14.0 - dependencies: - acorn: 8.15.0 - dev: false - /acorn-jsx@5.3.2(acorn@8.11.2): resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -13121,6 +11565,7 @@ packages: resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} engines: {node: '>=0.4.0'} hasBin: true + dev: true /after@0.8.1: resolution: {integrity: sha512-SuI3vWhCFeSmkmmJ3efyuOkrhGyp/AuHthh3F5DinGYh2kR9t/0xUlm3/Vn2qMScfgg+cKho5fW7TUEYUhYeiA==} @@ -13158,17 +11603,6 @@ packages: ajv: 8.17.1 dev: false - /ajv-formats@2.1.1(ajv@8.17.1): - resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} - peerDependencies: - ajv: ^8.0.0 - peerDependenciesMeta: - ajv: - optional: true - dependencies: - ajv: 8.17.1 - dev: false - /ajv-formats@3.0.1(ajv@8.17.1): resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} peerDependencies: @@ -13180,15 +11614,6 @@ packages: ajv: 8.17.1 dev: false - /ajv-keywords@5.1.0(ajv@8.17.1): - resolution: {integrity: sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==} - peerDependencies: - ajv: ^8.8.2 - dependencies: - ajv: 8.17.1 - fast-deep-equal: 3.1.3 - dev: false - /ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} dependencies: @@ -13247,68 +11672,6 @@ packages: resolution: {integrity: sha512-5bz5T/7FRmlxA37zDXhG6cAwlcZtfnmNLDJra66EEIT3kYlw5aPJdbkJEhm59D6kA4Wi5ict6u6IDYHJaQlH+g==} dev: false - /antd@6.1.1(moment@2.30.1)(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-GBVxq3ShcYN/lEALvLPQDFN0bWjp2gQaFvRIXu4cwvXQcbV/D2FhShhTiNWhXxUk6nVkODBi4Uzo9SfLbDGsng==} - peerDependencies: - react: '>=18.0.0' - react-dom: '>=18.0.0' - dependencies: - '@ant-design/colors': 8.0.0 - '@ant-design/cssinjs': 2.0.1(react-dom@18.3.1)(react@18.3.1) - '@ant-design/cssinjs-utils': 2.0.2(react-dom@18.3.1)(react@18.3.1) - '@ant-design/fast-color': 3.0.0 - '@ant-design/icons': 6.1.0(react-dom@18.3.1)(react@18.3.1) - '@ant-design/react-slick': 2.0.0(react-dom@18.3.1)(react@18.3.1) - '@babel/runtime': 7.28.4 - '@rc-component/cascader': 1.9.0(react-dom@18.3.1)(react@18.3.1) - '@rc-component/checkbox': 1.0.1(react-dom@18.3.1)(react@18.3.1) - '@rc-component/collapse': 1.1.2(react-dom@18.3.1)(react@18.3.1) - '@rc-component/color-picker': 3.0.3(react-dom@18.3.1)(react@18.3.1) - '@rc-component/dialog': 1.5.1(react-dom@18.3.1)(react@18.3.1) - '@rc-component/drawer': 1.3.0(react-dom@18.3.1)(react@18.3.1) - '@rc-component/dropdown': 1.0.2(react-dom@18.3.1)(react@18.3.1) - '@rc-component/form': 1.5.0(react-dom@18.3.1)(react@18.3.1) - '@rc-component/image': 1.5.3(react-dom@18.3.1)(react@18.3.1) - '@rc-component/input': 1.1.2(react-dom@18.3.1)(react@18.3.1) - '@rc-component/input-number': 1.6.2(react-dom@18.3.1)(react@18.3.1) - '@rc-component/mentions': 1.6.0(react-dom@18.3.1)(react@18.3.1) - '@rc-component/menu': 1.2.0(react-dom@18.3.1)(react@18.3.1) - '@rc-component/motion': 1.1.6(react-dom@18.3.1)(react@18.3.1) - '@rc-component/mutate-observer': 2.0.1(react-dom@18.3.1)(react@18.3.1) - '@rc-component/notification': 1.2.0(react-dom@18.3.1)(react@18.3.1) - '@rc-component/pagination': 1.2.0(react-dom@18.3.1)(react@18.3.1) - '@rc-component/picker': 1.9.0(dayjs@1.11.19)(moment@2.30.1)(react-dom@18.3.1)(react@18.3.1) - '@rc-component/progress': 1.0.2(react-dom@18.3.1)(react@18.3.1) - '@rc-component/qrcode': 1.1.1(react-dom@18.3.1)(react@18.3.1) - '@rc-component/rate': 1.0.1(react-dom@18.3.1)(react@18.3.1) - '@rc-component/resize-observer': 1.0.1(react-dom@18.3.1)(react@18.3.1) - '@rc-component/segmented': 1.2.3(react-dom@18.3.1)(react@18.3.1) - '@rc-component/select': 1.3.6(react-dom@18.3.1)(react@18.3.1) - '@rc-component/slider': 1.0.1(react-dom@18.3.1)(react@18.3.1) - '@rc-component/steps': 1.2.2(react-dom@18.3.1)(react@18.3.1) - '@rc-component/switch': 1.0.3(react-dom@18.3.1)(react@18.3.1) - '@rc-component/table': 1.9.0(react-dom@18.3.1)(react@18.3.1) - '@rc-component/tabs': 1.7.0(react-dom@18.3.1)(react@18.3.1) - '@rc-component/textarea': 1.1.2(react-dom@18.3.1)(react@18.3.1) - '@rc-component/tooltip': 1.4.0(react-dom@18.3.1)(react@18.3.1) - '@rc-component/tour': 2.2.1(react-dom@18.3.1)(react@18.3.1) - '@rc-component/tree': 1.1.0(react-dom@18.3.1)(react@18.3.1) - '@rc-component/tree-select': 1.4.0(react-dom@18.3.1)(react@18.3.1) - '@rc-component/trigger': 3.7.2(react-dom@18.3.1)(react@18.3.1) - '@rc-component/upload': 1.1.0(react-dom@18.3.1)(react@18.3.1) - '@rc-component/util': 1.6.0(react-dom@18.3.1)(react@18.3.1) - clsx: 2.1.1 - dayjs: 1.11.19 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - scroll-into-view-if-needed: 3.1.0 - throttle-debounce: 5.0.2 - transitivePeerDependencies: - - date-fns - - luxon - - moment - dev: false - /anymatch@3.1.3: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} @@ -13528,26 +11891,6 @@ packages: engines: {node: '>=4'} dev: false - /auto-bind@5.0.1: - resolution: {integrity: sha512-ooviqdwwgfIfNmDwo94wlshcdzfO64XV0Cg6oDsDYBJfITDz1EngD2z7DkbvCWn+XIMsIqW27sEVF6qcpJrRcg==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dev: false - - /autoprefixer@10.4.23(postcss@8.5.6): - resolution: {integrity: sha512-YYTXSFulfwytnjAPlw8QHncHJmlvFKtczb8InXaAx9Q0LbfDnfEYDE55omerIJKihhmU61Ft+cAOSzQVaBUmeA==} - engines: {node: ^10 || ^12 || >=14} - hasBin: true - peerDependencies: - postcss: ^8.1.0 - dependencies: - browserslist: 4.28.1 - caniuse-lite: 1.0.30001761 - fraction.js: 5.3.4 - picocolors: 1.1.1 - postcss: 8.5.6 - postcss-value-parser: 4.2.0 - dev: true - /available-typed-arrays@1.0.5: resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} engines: {node: '>= 0.4'} @@ -13576,16 +11919,6 @@ packages: resolution: {integrity: sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ==} engines: {node: '>=4'} - /axios@1.13.2: - resolution: {integrity: sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==} - dependencies: - follow-redirects: 1.15.6 - form-data: 4.0.4 - proxy-from-env: 1.1.0 - transitivePeerDependencies: - - debug - dev: false - /axios@1.2.1: resolution: {integrity: sha512-I88cFiGu9ryt/tfVEi4kX2SITsvDddTajXTOFmt2uK1ZVA8LytjtdeyefdQWEf5PU8w+4SSJDoYnggflB5tW4A==} dependencies: @@ -13733,6 +12066,7 @@ packages: /big.js@5.2.2: resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==} + dev: true /bignumber.js@9.1.2: resolution: {integrity: sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==} @@ -13863,10 +12197,6 @@ packages: resolution: {integrity: sha512-gvW7InbIyF8AicrqWoptdW08pUxuhq8BEgowNajy9RhiE86fmGAGl+bLKo6oB8QP0CkqHLowfN0oJdKC/J6LbA==} dev: false - /bubblesets-js@2.3.4: - resolution: {integrity: sha512-DyMjHmpkS2+xcFNtyN00apJYL3ESdp9fTrkDr5+9Qg/GPqFmcWgGsK1akZnttE1XFxJ/VMy4DNNGMGYtmFp1Sg==} - dev: false - /buffer-crc32@0.2.13: resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} @@ -13972,10 +12302,6 @@ packages: engines: {node: '>=10'} dev: true - /camelize@1.0.1: - resolution: {integrity: sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==} - dev: false - /caniuse-lite@1.0.30001594: resolution: {integrity: sha512-VblSX6nYqyJVs8DKFMldE2IVCJjZ225LW00ydtUWwh5hk9IfkTOffO6r8gJNsH0qqqeAF8KrbMYA2VEwTlGW5g==} dev: false @@ -14080,11 +12406,6 @@ packages: engines: {node: '>=18'} dev: false - /chrome-trace-event@1.0.4: - resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} - engines: {node: '>=6.0'} - dev: false - /class-variance-authority@0.7.1: resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} dependencies: @@ -14238,10 +12559,6 @@ packages: dependencies: delayed-stream: 1.0.0 - /comlink@4.4.2: - resolution: {integrity: sha512-OxGdvBmJuNKSCMO4NTl1L47VRp6xn2wG4F/2hYzB6tiCb709otOxtEYCSvK80PtjODfXXZu8ds+Nw5kVCjqd2g==} - dev: false - /comma-separated-tokens@1.0.8: resolution: {integrity: sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==} dev: false @@ -14267,6 +12584,7 @@ packages: /commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + dev: true /commander@7.2.0: resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} @@ -14301,10 +12619,6 @@ packages: /compute-scroll-into-view@3.0.3: resolution: {integrity: sha512-nadqwNxghAGTamwIqQSG433W6OADZx2vCo3UXHNrzTRHK/htu+7+L0zhjEoaeaQVNAi3YgqWDv8+tzf0hRfR+A==} - /compute-scroll-into-view@3.1.0: - resolution: {integrity: sha512-rj8l8pD4bJ1nx+dAkMhV1xB5RuZEyVysfxJqB1pRchh1KVvwOv9b7CGB8ZfjTImVv2oF+sYMUkMZq6Na5Ftmbg==} - dev: false - /concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} @@ -14478,11 +12792,6 @@ packages: dependencies: tiny-invariant: 1.3.1 - /css-color-keywords@1.0.0: - resolution: {integrity: sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==} - engines: {node: '>=4'} - dev: false - /css-select@4.3.0: resolution: {integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==} dependencies: @@ -14497,14 +12806,6 @@ packages: resolution: {integrity: sha512-HYPSb7y/Z7BNDCOrakL4raGO2zltZkbeXyAd6Tg9obzix6QhzxCotdBl6VT0Dv4vZfJGVz3WL/xaEI9Ly3ul0g==} dev: false - /css-to-react-native@3.2.0: - resolution: {integrity: sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==} - dependencies: - camelize: 1.0.1 - css-color-keywords: 1.0.0 - postcss-value-parser: 4.2.0 - dev: false - /css-tree@1.1.3: resolution: {integrity: sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==} engines: {node: '>=8.0.0'} @@ -14526,12 +12827,6 @@ packages: engines: {node: '>= 6'} dev: true - /cssesc@3.0.0: - resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} - engines: {node: '>=4'} - hasBin: true - dev: true - /csso@4.2.0: resolution: {integrity: sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==} engines: {node: '>=8.0.0'} @@ -14583,181 +12878,6 @@ packages: engines: {node: '>=0.4.0'} dev: false - /d3-array@3.2.4: - resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} - engines: {node: '>=12'} - dependencies: - internmap: 2.0.3 - dev: false - - /d3-binarytree@1.0.2: - resolution: {integrity: sha512-cElUNH+sHu95L04m92pG73t2MEJXKu+GeKUN1TJkFsu93E5W8E9Sc3kHEGJKgenGvj19m6upSn2EunvMgMD2Yw==} - dev: false - - /d3-color@3.1.0: - resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} - engines: {node: '>=12'} - dev: false - - /d3-dispatch@3.0.1: - resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} - engines: {node: '>=12'} - dev: false - - /d3-dsv@3.0.1: - resolution: {integrity: sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==} - engines: {node: '>=12'} - hasBin: true - dependencies: - commander: 7.2.0 - iconv-lite: 0.6.3 - rw: 1.3.3 - dev: false - - /d3-ease@3.0.1: - resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} - engines: {node: '>=12'} - dev: false - - /d3-fetch@3.0.1: - resolution: {integrity: sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==} - engines: {node: '>=12'} - dependencies: - d3-dsv: 3.0.1 - dev: false - - /d3-force-3d@3.0.6: - resolution: {integrity: sha512-4tsKHUPLOVkyfEffZo1v6sFHvGFwAIIjt/W8IThbp08DYAsXZck+2pSHEG5W1+gQgEvFLdZkYvmJAbRM2EzMnA==} - engines: {node: '>=12'} - dependencies: - d3-binarytree: 1.0.2 - d3-dispatch: 3.0.1 - d3-octree: 1.1.0 - d3-quadtree: 3.0.1 - d3-timer: 3.0.1 - dev: false - - /d3-force@3.0.0: - resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==} - engines: {node: '>=12'} - dependencies: - d3-dispatch: 3.0.1 - d3-quadtree: 3.0.1 - d3-timer: 3.0.1 - dev: false - - /d3-format@3.1.0: - resolution: {integrity: sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==} - engines: {node: '>=12'} - dev: false - - /d3-geo-projection@4.0.0: - resolution: {integrity: sha512-p0bK60CEzph1iqmnxut7d/1kyTmm3UWtPlwdkM31AU+LW+BXazd5zJdoCn7VFxNCHXRngPHRnsNn5uGjLRGndg==} - engines: {node: '>=12'} - hasBin: true - dependencies: - commander: 7.2.0 - d3-array: 3.2.4 - d3-geo: 3.1.1 - dev: false - - /d3-geo@3.1.1: - resolution: {integrity: sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==} - engines: {node: '>=12'} - dependencies: - d3-array: 3.2.4 - dev: false - - /d3-hierarchy@3.1.2: - resolution: {integrity: sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==} - engines: {node: '>=12'} - dev: false - - /d3-interpolate@3.0.1: - resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} - engines: {node: '>=12'} - dependencies: - d3-color: 3.1.0 - dev: false - - /d3-octree@1.1.0: - resolution: {integrity: sha512-F8gPlqpP+HwRPMO/8uOu5wjH110+6q4cgJvgJT6vlpy3BEaDIKlTZrgHKZSp/i1InRpVfh4puY/kvL6MxK930A==} - dev: false - - /d3-path@3.1.0: - resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} - engines: {node: '>=12'} - dev: false - - /d3-quadtree@3.0.1: - resolution: {integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==} - engines: {node: '>=12'} - dev: false - - /d3-random@3.0.1: - resolution: {integrity: sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==} - engines: {node: '>=12'} - dev: false - - /d3-regression@1.3.10: - resolution: {integrity: sha512-PF8GWEL70cHHWpx2jUQXc68r1pyPHIA+St16muk/XRokETzlegj5LriNKg7o4LR0TySug4nHYPJNNRz/W+/Niw==} - dev: false - - /d3-scale-chromatic@3.1.0: - resolution: {integrity: sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==} - engines: {node: '>=12'} - dependencies: - d3-color: 3.1.0 - d3-interpolate: 3.0.1 - dev: false - - /d3-scale@4.0.2: - resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} - engines: {node: '>=12'} - dependencies: - d3-array: 3.2.4 - d3-format: 3.1.0 - d3-interpolate: 3.0.1 - d3-time: 3.1.0 - d3-time-format: 2.3.0 - dev: false - - /d3-shape@3.2.0: - resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==} - engines: {node: '>=12'} - dependencies: - d3-path: 3.1.0 - dev: false - - /d3-time-format@2.3.0: - resolution: {integrity: sha512-guv6b2H37s2Uq/GefleCDtbe0XZAuy7Wa49VGkPVPMfLL9qObgBST3lEHJBMUp8S7NdLQAGIvr2KXk8Hc98iKQ==} - dependencies: - d3-time: 1.1.0 - dev: false - - /d3-time@1.1.0: - resolution: {integrity: sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA==} - dev: false - - /d3-time@3.1.0: - resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==} - engines: {node: '>=12'} - dependencies: - d3-array: 3.2.4 - dev: false - - /d3-timer@3.0.1: - resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} - engines: {node: '>=12'} - dev: false - - /dagre@0.8.5: - resolution: {integrity: sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw==} - dependencies: - graphlib: 2.1.8 - lodash: 4.17.21 - dev: false - /damerau-levenshtein@1.0.8: resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} @@ -14827,10 +12947,6 @@ packages: resolution: {integrity: sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==} dev: false - /dayjs@1.11.19: - resolution: {integrity: sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==} - dev: false - /debounce@1.2.1: resolution: {integrity: sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==} @@ -15165,12 +13281,6 @@ packages: domelementtype: 2.3.0 dev: true - /dompurify@3.2.7: - resolution: {integrity: sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==} - optionalDependencies: - '@types/trusted-types': 2.0.7 - dev: false - /dompurify@3.3.0: resolution: {integrity: sha512-r+f6MYR1gGN1eJv0TVQbhA7if/U7P87cdPl3HN5rikqaBSBxLiCb/b9O+2eG0cxz0ghyU+mU1QkbsOwERMYlWQ==} optionalDependencies: @@ -15223,6 +13333,7 @@ packages: /eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + dev: false /ecc-jsbn@0.1.2: resolution: {integrity: sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==} @@ -15272,6 +13383,7 @@ packages: /emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + dev: false /emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} @@ -15279,6 +13391,7 @@ packages: /emojis-list@3.0.0: resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==} engines: {node: '>= 4'} + dev: true /encodeurl@2.0.0: resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} @@ -15347,6 +13460,7 @@ packages: dependencies: graceful-fs: 4.2.11 tapable: 2.2.1 + dev: true /entities@2.2.0: resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==} @@ -15548,10 +13662,6 @@ packages: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} dev: true - /es-module-lexer@2.0.0: - resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==} - dev: false - /es-object-atoms@1.1.1: resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} engines: {node: '>= 0.4'} @@ -15802,31 +13912,6 @@ packages: - eslint-import-resolver-webpack - supports-color - /eslint-config-next@14.2.3(eslint@8.57.0)(typescript@5.9.3): - resolution: {integrity: sha512-ZkNztm3Q7hjqvB1rRlOX8P9E/cXRL9ajRcs8jufEtwMfTVYRqnmtnaSu57QqHyBlovMuiB8LEzfLBkh5RYV6Fg==} - peerDependencies: - eslint: ^7.23.0 || ^8.0.0 - typescript: '>=3.3.1' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@next/eslint-plugin-next': 14.2.3 - '@rushstack/eslint-patch': 1.10.4 - '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.9.3) - eslint: 8.57.0 - eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.0) - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) - eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.0) - eslint-plugin-react: 7.37.2(eslint@8.57.0) - eslint-plugin-react-hooks: 4.6.0(eslint@8.57.0) - typescript: 5.9.3 - transitivePeerDependencies: - - eslint-import-resolver-webpack - - supports-color - dev: true - /eslint-import-resolver-node@0.3.9: resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} dependencies: @@ -15950,29 +14035,6 @@ packages: - supports-color dev: true - /eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.0): - resolution: {integrity: sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==} - engines: {node: ^14.18.0 || >=16.0.0} - peerDependencies: - eslint: '*' - eslint-plugin-import: '*' - dependencies: - debug: 4.4.1 - enhanced-resolve: 5.18.1 - eslint: 8.57.0 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) - fast-glob: 3.3.2 - get-tsconfig: 4.7.2 - is-core-module: 2.15.1 - is-glob: 4.0.3 - transitivePeerDependencies: - - '@typescript-eslint/parser' - - eslint-import-resolver-node - - eslint-import-resolver-webpack - - supports-color - dev: true - /eslint-module-utils@2.12.0(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.33.0): resolution: {integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==} engines: {node: '>=4'} @@ -16122,7 +14184,7 @@ packages: - supports-color dev: true - /eslint-module-utils@2.12.0(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0): + /eslint-module-utils@2.12.0(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint@8.57.0): resolution: {integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==} engines: {node: '>=4'} peerDependencies: @@ -16147,7 +14209,6 @@ packages: debug: 3.2.7 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.0) transitivePeerDependencies: - supports-color dev: true @@ -16237,7 +14298,7 @@ packages: doctrine: 2.1.0 eslint: 8.33.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.33.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.33.0) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -16327,43 +14388,6 @@ packages: - supports-color dev: true - /eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0): - resolution: {integrity: sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - dependencies: - '@rtsao/scc': 1.1.0 - '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.9.3) - array-includes: 3.1.8 - array.prototype.findlastindex: 1.2.5 - array.prototype.flat: 1.3.2 - array.prototype.flatmap: 1.3.2 - debug: 3.2.7 - doctrine: 2.1.0 - eslint: 8.57.0 - eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) - hasown: 2.0.2 - is-core-module: 2.15.1 - is-glob: 4.0.3 - minimatch: 3.1.2 - object.fromentries: 2.0.8 - object.groupby: 1.0.3 - object.values: 1.2.0 - semver: 6.3.1 - string.prototype.trimend: 1.0.8 - tsconfig-paths: 3.15.0 - transitivePeerDependencies: - - eslint-import-resolver-typescript - - eslint-import-resolver-webpack - - supports-color - dev: true - /eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0)(eslint@8.57.0): resolution: {integrity: sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==} engines: {node: '>=4'} @@ -16384,7 +14408,7 @@ packages: doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint@8.57.0) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -16473,30 +14497,6 @@ packages: safe-regex-test: 1.0.3 string.prototype.includes: 2.0.1 - /eslint-plugin-jsx-a11y@6.10.2(eslint@8.57.0): - resolution: {integrity: sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==} - engines: {node: '>=4.0'} - peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9 - dependencies: - aria-query: 5.3.2 - array-includes: 3.1.8 - array.prototype.flatmap: 1.3.2 - ast-types-flow: 0.0.8 - axe-core: 4.10.2 - axobject-query: 4.1.0 - damerau-levenshtein: 1.0.8 - emoji-regex: 9.2.2 - eslint: 8.57.0 - hasown: 2.0.2 - jsx-ast-utils: 3.3.5 - language-tags: 1.0.9 - minimatch: 3.1.2 - object.fromentries: 2.0.8 - safe-regex-test: 1.0.3 - string.prototype.includes: 2.0.1 - dev: true - /eslint-plugin-jsx-a11y@6.8.0(eslint@8.33.0): resolution: {integrity: sha512-Hdh937BS3KdwwbBaKd5+PLCOmYY6U4f2h9Z2ktwtNKvIdIEu137rjYbcb9ApSbVJfWxANNuiKTD/9tOKjK9qOA==} engines: {node: '>=4.0'} @@ -16607,15 +14607,6 @@ packages: eslint: 8.42.0 dev: true - /eslint-plugin-react-hooks@4.6.0(eslint@8.57.0): - resolution: {integrity: sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==} - engines: {node: '>=10'} - peerDependencies: - eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 - dependencies: - eslint: 8.57.0 - dev: true - /eslint-plugin-react@7.33.2(eslint@8.33.0): resolution: {integrity: sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==} engines: {node: '>=4'} @@ -16744,48 +14735,6 @@ packages: string.prototype.matchall: 4.0.11 string.prototype.repeat: 1.0.0 - /eslint-plugin-react@7.37.2(eslint@8.57.0): - resolution: {integrity: sha512-EsTAnj9fLVr/GZleBLFbj/sSuXeWmp1eXIN60ceYnZveqEaUCyW4X+Vh4WTdUhCkW4xutXYqTXCUSyqD4rB75w==} - engines: {node: '>=4'} - peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 - dependencies: - array-includes: 3.1.8 - array.prototype.findlast: 1.2.5 - array.prototype.flatmap: 1.3.2 - array.prototype.tosorted: 1.1.4 - doctrine: 2.1.0 - es-iterator-helpers: 1.1.0 - eslint: 8.57.0 - estraverse: 5.3.0 - hasown: 2.0.2 - jsx-ast-utils: 3.3.5 - minimatch: 3.1.2 - object.entries: 1.1.8 - object.fromentries: 2.0.8 - object.values: 1.2.0 - prop-types: 15.8.1 - resolve: 2.0.0-next.5 - semver: 6.3.1 - string.prototype.matchall: 4.0.11 - string.prototype.repeat: 1.0.0 - dev: true - - /eslint-plugin-xss@0.1.12: - resolution: {integrity: sha512-L5oYaD//ZE7fKNtWUfVgYTRW19jrZlvaHe2swyFLxXQ5pwVQLivi5m92rtXd/ww8yqg4Drasqyi0hlBmhf9YQg==} - engines: {node: '>=0.10.0'} - dependencies: - requireindex: 1.1.0 - dev: true - - /eslint-scope@5.1.1: - resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} - engines: {node: '>=8.0.0'} - dependencies: - esrecurse: 4.3.0 - estraverse: 4.3.0 - dev: false - /eslint-scope@7.2.2: resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -17094,11 +15043,6 @@ packages: dependencies: estraverse: 5.3.0 - /estraverse@4.3.0: - resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} - engines: {node: '>=4.0'} - dev: false - /estraverse@5.3.0: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} @@ -17123,11 +15067,7 @@ packages: /eventemitter3@5.0.1: resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} - - /events@3.3.0: - resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} - engines: {node: '>=0.8.x'} - dev: false + dev: true /eventsource-parser@3.0.6: resolution: {integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==} @@ -17338,10 +15278,6 @@ packages: picomatch: 4.0.3 dev: true - /fecha@4.2.3: - resolution: {integrity: sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==} - dev: false - /fetch-blob@3.2.0: resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} engines: {node: ^12.20 || >= 14.13} @@ -17461,11 +15397,6 @@ packages: /flatted@3.3.3: resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} - /flru@1.0.2: - resolution: {integrity: sha512-kWyh8ADvHBFz6ua5xYOPnUroZTT/bwWfrCeL0Wj1dzG4/YOmOcfJ99W8dOVyyynJN35rZ9aCOtHChqQovV7yog==} - engines: {node: '>=6'} - dev: false - /focus-lock@1.0.0: resolution: {integrity: sha512-a8Ge6cdKh9za/GZR/qtigTAk7SrGore56EFcoMshClsh7FLk1zwszc/ltuMfKhx56qeuyL/jWQ4J4axou0iJ9w==} engines: {node: '>=10'} @@ -17515,6 +15446,7 @@ packages: dependencies: cross-spawn: 7.0.6 signal-exit: 4.1.0 + dev: false /forever-agent@0.2.0: resolution: {integrity: sha512-IasWSRIlfPnBZY1K9jEUK3PwsScR4mrcK+aNBJzGoPnW+S9b6f8I8ScyH4cehEOFNqnjGpP2gCaA22gqSV1xQA==} @@ -17566,17 +15498,6 @@ packages: mime-types: 2.1.35 dev: false - /form-data@4.0.4: - resolution: {integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==} - engines: {node: '>= 6'} - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - es-set-tostringtag: 2.1.0 - hasown: 2.0.2 - mime-types: 2.1.35 - dev: false - /format@0.2.2: resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==} engines: {node: '>=0.4.x'} @@ -17618,10 +15539,6 @@ packages: engines: {node: '>= 0.6'} dev: false - /fraction.js@5.3.4: - resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} - dev: true - /framer-motion@10.16.5(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-GEzVjOYP2MIpV9bT/GbhcsBNoImG3/2X3O/xVNWmktkv9MdJ7P/44zELm/7Fjb+O3v39SmKFnoDQB32giThzpg==} peerDependencies: @@ -17864,10 +15781,6 @@ packages: resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==} dev: false - /gl-matrix@3.4.3: - resolution: {integrity: sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA==} - dev: false - /glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -17894,6 +15807,7 @@ packages: minimatch: 9.0.5 minipass: 7.1.2 path-scurry: 1.10.1 + dev: false /glob@7.1.7: resolution: {integrity: sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==} @@ -18017,12 +15931,6 @@ packages: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} dev: true - /graphlib@2.1.8: - resolution: {integrity: sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==} - dependencies: - lodash: 4.17.21 - dev: false - /gud@1.0.0: resolution: {integrity: sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw==} dev: false @@ -18659,11 +16567,6 @@ packages: hasown: 2.0.2 side-channel: 1.1.0 - /internmap@2.0.3: - resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} - engines: {node: '>=12'} - dev: false - /interpret@1.4.0: resolution: {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==} engines: {node: '>= 0.10'} @@ -18703,10 +16606,6 @@ packages: is-decimal: 1.0.4 dev: false - /is-any-array@2.0.1: - resolution: {integrity: sha512-UtilS7hLRu++wb/WBAw9bNuP1Eg04Ivn1vERJck8zJthEvXCBEBpGR/33u/xLKWEQf95803oalHrVDptcAvFdQ==} - dev: false - /is-arguments@1.1.1: resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} engines: {node: '>= 0.4'} @@ -18815,6 +16714,7 @@ packages: /is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} + dev: false /is-fullwidth-code-point@4.0.0: resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} @@ -18847,10 +16747,6 @@ packages: /is-map@2.0.2: resolution: {integrity: sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==} - /is-mobile@5.0.0: - resolution: {integrity: sha512-Tz/yndySvLAEXh+Uk8liFCxOwVH6YutuR74utvOcu7I9Di+DwM0mtdPVZNaVvvBUM2OXxne/NhOs1zAO7riusQ==} - dev: false - /is-module@1.0.0: resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} dev: true @@ -19051,6 +16947,7 @@ packages: '@isaacs/cliui': 8.0.2 optionalDependencies: '@pkgjs/parseargs': 0.11.0 + dev: false /jest-worker@26.6.2: resolution: {integrity: sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==} @@ -19061,15 +16958,6 @@ packages: supports-color: 7.2.0 dev: true - /jest-worker@27.5.1: - resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} - engines: {node: '>= 10.13.0'} - dependencies: - '@types/node': 20.17.32 - merge-stream: 2.0.0 - supports-color: 8.1.1 - dev: false - /jiti@2.4.2: resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==} hasBin: true @@ -19217,12 +17105,6 @@ packages: /json-stringify-safe@5.0.1: resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} - /json2mq@0.2.0: - resolution: {integrity: sha512-SzoRg7ux5DWTII9J2qkrZrqV1gt+rTaoufMxEzXbS26Uid0NwaJd123HcoB80TgubEppxxIGdNxCx50fEoEWQA==} - dependencies: - string-convert: 0.2.1 - dev: false - /json3@3.2.6: resolution: {integrity: sha512-KA+GHhYTLTo7Ri4DyjwUgW8kn98AYtVZtBC94qL5yD0ZSYct8/eF8qBmTNyk+gPE578bKeIL4WBq+MUyd1I26g==} deprecated: Please use the native JSON object instead of JSON 3 @@ -19673,11 +17555,6 @@ packages: wrap-ansi: 9.0.0 dev: true - /loader-runner@4.3.1: - resolution: {integrity: sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==} - engines: {node: '>=6.11.5'} - dev: false - /loader-utils@1.4.2: resolution: {integrity: sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==} engines: {node: '>=4.0.0'} @@ -19687,15 +17564,6 @@ packages: json5: 1.0.2 dev: true - /loader-utils@2.0.4: - resolution: {integrity: sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==} - engines: {node: '>=8.9.0'} - dependencies: - big.js: 5.2.2 - emojis-list: 3.0.0 - json5: 2.2.3 - dev: false - /locate-path@5.0.0: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} engines: {node: '>=8'} @@ -19800,6 +17668,7 @@ packages: /lru-cache@10.1.0: resolution: {integrity: sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==} engines: {node: 14 || >=16.14} + dev: false /lru-cache@11.2.4: resolution: {integrity: sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==} @@ -19895,12 +17764,6 @@ packages: resolution: {integrity: sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==} dev: false - /marked@14.0.0: - resolution: {integrity: sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ==} - engines: {node: '>= 18'} - hasBin: true - dev: false - /math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} @@ -20810,6 +18673,7 @@ packages: engines: {node: '>=16 || 14 >=14.17'} dependencies: brace-expansion: 2.0.1 + dev: false /minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} @@ -20846,6 +18710,7 @@ packages: /minipass@7.1.2: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} + dev: false /minizlib@2.1.2: resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} @@ -20884,50 +18749,6 @@ packages: hasBin: true dev: false - /ml-array-max@1.2.4: - resolution: {integrity: sha512-BlEeg80jI0tW6WaPyGxf5Sa4sqvcyY6lbSn5Vcv44lp1I2GR6AWojfUvLnGTNsIXrZ8uqWmo8VcG1WpkI2ONMQ==} - dependencies: - is-any-array: 2.0.1 - dev: false - - /ml-array-min@1.2.3: - resolution: {integrity: sha512-VcZ5f3VZ1iihtrGvgfh/q0XlMobG6GQ8FsNyQXD3T+IlstDv85g8kfV0xUG1QPRO/t21aukaJowDzMTc7j5V6Q==} - dependencies: - is-any-array: 2.0.1 - dev: false - - /ml-array-rescale@1.3.7: - resolution: {integrity: sha512-48NGChTouvEo9KBctDfHC3udWnQKNKEWN0ziELvY3KG25GR5cA8K8wNVzracsqSW1QEkAXjTNx+ycgAv06/1mQ==} - dependencies: - is-any-array: 2.0.1 - ml-array-max: 1.2.4 - ml-array-min: 1.2.3 - dev: false - - /ml-matrix@6.11.0: - resolution: {integrity: sha512-7jr9NmFRkaUxbKslfRu3aZOjJd2LkSitCGv+QH9PF0eJoEG7jIpjXra1Vw8/kgao8+kHCSsJONG6vfWmXQ+/Eg==} - dependencies: - is-any-array: 2.0.1 - ml-array-rescale: 1.3.7 - dev: false - - /moment-timezone@0.5.45: - resolution: {integrity: sha512-HIWmqA86KcmCAhnMAN0wuDOARV/525R2+lOLotuGFzn4HO+FH+/645z2wx0Dt3iDv6/p61SIvKnDstISainhLQ==} - dependencies: - moment: 2.30.1 - dev: false - - /moment@2.30.1: - resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==} - dev: false - - /monaco-editor@0.55.1: - resolution: {integrity: sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==} - dependencies: - dompurify: 3.2.7 - marked: 14.0.0 - dev: false - /mongodb-connection-string-url@2.6.0: resolution: {integrity: sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==} dependencies: @@ -21078,10 +18899,6 @@ packages: engines: {node: '>= 0.6'} dev: false - /neo-async@2.6.2: - resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} - dev: false - /next-i18next@15.3.0(i18next@23.12.1)(next@13.1.6)(react-i18next@14.1.2)(react@18.3.1): resolution: {integrity: sha512-bq7Cc9XJFcmGOCLnyEtHaeJ3+JJNsI/8Pkj9BaHAnhm4sZ9vNNC4ZsaqYnlRZ7VH5ypSo73fEqLK935jLsmCvQ==} engines: {node: '>=14'} @@ -21793,6 +19610,7 @@ packages: dependencies: lru-cache: 10.1.0 minipass: 7.1.2 + dev: false /path-to-regexp@0.1.3: resolution: {integrity: sha512-sd4vSOW+DCM6A5aRICI1CWaC7nufnzVpZfuh5T0VXshxxzFWuaFcvqKovAFLNGReOc+uZRptpcpPmn7CDvzLuA==} @@ -21811,10 +19629,6 @@ packages: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} dev: true - /pdfast@0.2.0: - resolution: {integrity: sha512-cq6TTu6qKSFUHwEahi68k/kqN2mfepjkGrG9Un70cgdRRKLKY6Rf8P8uvP2NvZktaQZNF3YE7agEkLj0vGK9bA==} - dev: false - /performance-now@2.1.0: resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==} @@ -21836,11 +19650,6 @@ packages: hasBin: true dev: true - /pify@2.3.0: - resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} - engines: {node: '>=0.10.0'} - dev: true - /pixelmatch@7.1.0: resolution: {integrity: sha512-1wrVzJ2STrpmONHKBy228LM1b84msXDUoAzVEl0R8Mz4Ce6EPr+IVtxm8+yvrqLYMHswREkjYFaMxnyGnaY3Ng==} hasBin: true @@ -21893,41 +19702,6 @@ packages: resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} engines: {node: '>= 0.4'} - /postcss-import@16.1.1(postcss@8.5.6): - resolution: {integrity: sha512-2xVS1NCZAfjtVdvXiyegxzJ447GyqCeEI5V7ApgQVOWnros1p5lGNovJNapwPpMombyFBfqDwt7AD3n2l0KOfQ==} - engines: {node: '>=18.0.0'} - peerDependencies: - postcss: ^8.0.0 - dependencies: - postcss: 8.5.6 - postcss-value-parser: 4.2.0 - read-cache: 1.0.0 - resolve: 1.22.8 - dev: true - - /postcss-nesting@13.0.2(postcss@8.5.6): - resolution: {integrity: sha512-1YCI290TX+VP0U/K/aFxzHzQWHWURL+CtHMSbex1lCdpXD1SoR2sYuxDu5aNI9lPoXpKTCggFZiDJbwylU0LEQ==} - engines: {node: '>=18'} - peerDependencies: - postcss: ^8.4 - dependencies: - '@csstools/selector-resolve-nested': 3.1.0(postcss-selector-parser@7.1.1) - '@csstools/selector-specificity': 5.0.0(postcss-selector-parser@7.1.1) - postcss: 8.5.6 - postcss-selector-parser: 7.1.1 - dev: true - - /postcss-selector-parser@7.1.1: - resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==} - engines: {node: '>=4'} - dependencies: - cssesc: 3.0.0 - util-deprecate: 1.0.2 - dev: true - - /postcss-value-parser@4.2.0: - resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} - /postcss@8.4.14: resolution: {integrity: sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==} engines: {node: ^10 || ^12 || >=14} @@ -21945,15 +19719,6 @@ packages: picocolors: 1.1.1 source-map-js: 1.2.1 - /postcss@8.4.49: - resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} - engines: {node: ^10 || ^12 || >=14} - dependencies: - nanoid: 3.3.11 - picocolors: 1.1.1 - source-map-js: 1.2.1 - dev: false - /postcss@8.5.6: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} @@ -22164,6 +19929,7 @@ packages: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} dependencies: safe-buffer: 5.2.1 + dev: true /range-parser@1.0.0: resolution: {integrity: sha512-wOH5LIH2ZHo0P7/bwkR+aNbJ+kv3CHVX4B8qs9GqbtY29fi1bGPV5xczrutN20G+Z4XhRqRMTW3q0S4iyJJPfw==} @@ -22485,12 +20251,6 @@ packages: dependencies: loose-envify: 1.4.0 - /read-cache@1.0.0: - resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} - dependencies: - pify: 2.3.0 - dev: true - /readable-stream@2.3.8: resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} dependencies: @@ -22810,11 +20570,6 @@ packages: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} - /requireindex@1.1.0: - resolution: {integrity: sha512-LBnkqsDE7BZKvqylbmn7lTIVdpx4K/QCduRATpO5R+wtPmky/a8pN1bO2D6wXppn1497AJF9mNjqAXr6bdl9jg==} - engines: {node: '>=0.10.5'} - dev: true - /reserved-identifiers@1.2.0: resolution: {integrity: sha512-yE7KUfFvaBFzGPs5H3Ops1RevfUEsDc5Iz65rOwWg4lE8HJSYtle77uul3+573457oHvBKuHYDl/xqUkKpEEdw==} engines: {node: '>=18'} @@ -23013,10 +20768,6 @@ packages: dependencies: queue-microtask: 1.2.3 - /rw@1.3.3: - resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} - dev: false - /sade@1.8.1: resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} engines: {node: '>=6'} @@ -23091,22 +20842,6 @@ packages: dependencies: loose-envify: 1.4.0 - /schema-utils@4.3.3: - resolution: {integrity: sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==} - engines: {node: '>= 10.13.0'} - dependencies: - '@types/json-schema': 7.0.15 - ajv: 8.17.1 - ajv-formats: 2.1.1(ajv@8.17.1) - ajv-keywords: 5.1.0(ajv@8.17.1) - dev: false - - /scroll-into-view-if-needed@3.1.0: - resolution: {integrity: sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ==} - dependencies: - compute-scroll-into-view: 3.1.0 - dev: false - /semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true @@ -23170,12 +20905,6 @@ packages: randombytes: 2.1.0 dev: true - /serialize-javascript@6.0.2: - resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} - dependencies: - randombytes: 2.1.0 - dev: false - /serve-static@1.3.2: resolution: {integrity: sha512-KwjCeYUx7IM1neg8/P0+O1DZsl76XcOSuV0ZxrI0r60vwGlcjMjKOYCK/OFLJy/a2CFuIyAa/x0PuQ0yuG+IgQ==} engines: {node: '>= 0.8.0'} @@ -23244,10 +20973,6 @@ packages: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} dev: false - /shallowequal@1.1.0: - resolution: {integrity: sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==} - dev: false - /sharp@0.32.6: resolution: {integrity: sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==} engines: {node: '>=14.15.0'} @@ -23529,6 +21254,7 @@ packages: dependencies: buffer-from: 1.1.2 source-map: 0.6.1 + dev: true /source-map@0.5.7: resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} @@ -23537,6 +21263,7 @@ packages: /source-map@0.6.1: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} + dev: true /sourcemap-codec@1.4.8: resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} @@ -23606,10 +21333,6 @@ packages: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} dev: true - /state-local@1.0.7: - resolution: {integrity: sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==} - dev: false - /statuses@2.0.1: resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} engines: {node: '>= 0.8'} @@ -23655,10 +21378,6 @@ packages: engines: {node: '>=0.6.19'} dev: true - /string-convert@0.2.1: - resolution: {integrity: sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==} - dev: false - /string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -23666,6 +21385,7 @@ packages: emoji-regex: 8.0.0 is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 + dev: false /string-width@5.1.2: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} @@ -23674,6 +21394,7 @@ packages: eastasianwidth: 0.2.0 emoji-regex: 9.2.2 strip-ansi: 7.1.0 + dev: false /string-width@7.2.0: resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} @@ -23846,26 +21567,6 @@ packages: inline-style-parser: 0.1.1 dev: false - /styled-components@6.1.19(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-1v/e3Dl1BknC37cXMhwGomhO8AkYmN41CqyX9xhUDxry1ns3BFQy2lLDRQXJRdVVWB9OHemv/53xaStimvWyuA==} - engines: {node: '>= 16'} - peerDependencies: - react: '>= 16.8.0' - react-dom: '>= 16.8.0' - dependencies: - '@emotion/is-prop-valid': 1.2.2 - '@emotion/unitless': 0.8.1 - '@types/stylis': 4.2.5 - css-to-react-native: 3.2.0 - csstype: 3.1.3 - postcss: 8.4.49 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - shallowequal: 1.1.0 - stylis: 4.3.2 - tslib: 2.6.2 - dev: false - /styled-jsx@5.1.1(@babel/core@7.23.5)(react@18.3.1): resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==} engines: {node: '>= 12.0.0'} @@ -23904,14 +21605,6 @@ packages: /stylis@4.2.0: resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==} - /stylis@4.3.2: - resolution: {integrity: sha512-bhtUjWd/z6ltJiQwg0dUfxEJ+W+jdqQd8TbWLWyeIJHlnsqmGLRFFd8e5mA0AZi/zx90smXRlN66YMTcaSFifg==} - dev: false - - /stylis@4.3.6: - resolution: {integrity: sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==} - dev: false - /supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} @@ -23925,13 +21618,6 @@ packages: dependencies: has-flag: 4.0.0 - /supports-color@8.1.1: - resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} - engines: {node: '>=10'} - dependencies: - has-flag: 4.0.0 - dev: false - /supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} @@ -23948,10 +21634,6 @@ packages: resolution: {integrity: sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==} dev: true - /svg-path-parser@1.1.0: - resolution: {integrity: sha512-jGCUqcQyXpfe38R7RFfhrMyfXcBmpMNJI/B+4CE9/Unkh98UporAc461GTthv+TVDuZXsBx7/WiwJb1Oh4tt4A==} - dev: false - /svgo@2.8.0: resolution: {integrity: sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==} engines: {node: '>=10.13.0'} @@ -24013,11 +21695,6 @@ packages: resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} engines: {node: '>=6'} - /tapable@2.3.0: - resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} - engines: {node: '>=6'} - dev: false - /tar-fs@2.1.1: resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==} dependencies: @@ -24094,30 +21771,6 @@ packages: - supports-color dev: false - /terser-webpack-plugin@5.3.16(webpack@5.104.1): - resolution: {integrity: sha512-h9oBFCWrq78NyWWVcSwZarJkZ01c2AyGrzs1crmHZO3QUg9D61Wu4NPjBy69n7JqylFF5y+CsUZYmYEIZ3mR+Q==} - engines: {node: '>= 10.13.0'} - peerDependencies: - '@swc/core': '*' - esbuild: '*' - uglify-js: '*' - webpack: ^5.1.0 - peerDependenciesMeta: - '@swc/core': - optional: true - esbuild: - optional: true - uglify-js: - optional: true - dependencies: - '@jridgewell/trace-mapping': 0.3.31 - jest-worker: 27.5.1 - schema-utils: 4.3.3 - serialize-javascript: 6.0.2 - terser: 5.44.1 - webpack: 5.104.1 - dev: false - /terser@5.24.0: resolution: {integrity: sha512-ZpGR4Hy3+wBEzVEnHvstMvqpD/nABNelQn/z2r0fjVWGQsN3bpOLzQlqDxmb4CDZnXq5lpjnQ+mHQLAOpfM5iw==} engines: {node: '>=10'} @@ -24129,25 +21782,9 @@ packages: source-map-support: 0.5.21 dev: true - /terser@5.44.1: - resolution: {integrity: sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==} - engines: {node: '>=10'} - hasBin: true - dependencies: - '@jridgewell/source-map': 0.3.5 - acorn: 8.15.0 - commander: 2.20.3 - source-map-support: 0.5.21 - dev: false - /text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} - /throttle-debounce@5.0.2: - resolution: {integrity: sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==} - engines: {node: '>=12.22'} - dev: false - /through2@4.0.2: resolution: {integrity: sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==} dependencies: @@ -24540,10 +22177,6 @@ packages: is-typed-array: 1.1.15 possible-typed-array-names: 1.0.0 - /typed-regex@0.0.8: - resolution: {integrity: sha512-1XkGm1T/rUngbFROIOw9wPnMAKeMsRoc+c9O6GwOHz6aH/FrJFtcyd2sHASbT0OXeGLot5N1shPNpwHGTv9RdQ==} - dev: false - /typedarray@0.0.6: resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} dev: false @@ -24586,10 +22219,6 @@ packages: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} dev: false - /undici-types@7.16.0: - resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} - dev: true - /unhead@1.11.20: resolution: {integrity: sha512-3AsNQC0pjwlLqEYHLjtichGWankK8yqmocReITecmpB1H0aOabeESueyy+8X1gyJx4ftZVwo9hqQ4O3fPWffCA==} dependencies: @@ -25649,14 +23278,6 @@ packages: graceful-fs: 4.2.11 dev: false - /watchpack@2.4.4: - resolution: {integrity: sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==} - engines: {node: '>=10.13.0'} - dependencies: - glob-to-regexp: 0.4.1 - graceful-fs: 4.2.11 - dev: false - /web-encoding@1.1.5: resolution: {integrity: sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA==} dependencies: @@ -25709,52 +23330,6 @@ packages: - bufferutil - utf-8-validate - /webpack-sources@3.3.3: - resolution: {integrity: sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==} - engines: {node: '>=10.13.0'} - dev: false - - /webpack@5.104.1: - resolution: {integrity: sha512-Qphch25abbMNtekmEGJmeRUhLDbe+QfiWTiqpKYkpCOWY64v9eyl+KRRLmqOFA2AvKPpc9DC6+u2n76tQLBoaA==} - engines: {node: '>=10.13.0'} - hasBin: true - peerDependencies: - webpack-cli: '*' - peerDependenciesMeta: - webpack-cli: - optional: true - dependencies: - '@types/eslint-scope': 3.7.7 - '@types/estree': 1.0.8 - '@types/json-schema': 7.0.15 - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/wasm-edit': 1.14.1 - '@webassemblyjs/wasm-parser': 1.14.1 - acorn: 8.15.0 - acorn-import-phases: 1.0.4(acorn@8.15.0) - browserslist: 4.28.1 - chrome-trace-event: 1.0.4 - enhanced-resolve: 5.18.4 - es-module-lexer: 2.0.0 - eslint-scope: 5.1.1 - events: 3.3.0 - glob-to-regexp: 0.4.1 - graceful-fs: 4.2.11 - json-parse-even-better-errors: 2.3.1 - loader-runner: 4.3.1 - mime-types: 2.1.35 - neo-async: 2.6.2 - schema-utils: 4.3.3 - tapable: 2.3.0 - terser-webpack-plugin: 5.3.16(webpack@5.104.1) - watchpack: 2.4.4 - webpack-sources: 3.3.3 - transitivePeerDependencies: - - '@swc/core' - - esbuild - - uglify-js - dev: false - /whatwg-encoding@3.1.1: resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} engines: {node: '>=18'} @@ -25889,15 +23464,6 @@ packages: engines: {node: '>=0.4.0'} dev: false - /workerize-loader@2.0.2(webpack@5.104.1): - resolution: {integrity: sha512-HoZ6XY4sHWxA2w0WpzgBwUiR3dv1oo7bS+oCwIpb6n54MclQ/7KXdXsVIChTCygyuHtVuGBO1+i3HzTt699UJQ==} - peerDependencies: - webpack: '*' - dependencies: - loader-utils: 2.0.4 - webpack: 5.104.1 - dev: false - /wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} @@ -25905,6 +23471,7 @@ packages: ansi-styles: 4.3.0 string-width: 4.2.3 strip-ansi: 6.0.1 + dev: false /wrap-ansi@8.1.0: resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} @@ -25913,6 +23480,7 @@ packages: ansi-styles: 6.2.1 string-width: 5.1.2 strip-ansi: 7.1.0 + dev: false /wrap-ansi@9.0.0: resolution: {integrity: sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==} @@ -26186,28 +23754,6 @@ packages: use-sync-external-store: 1.5.0(react@18.3.1) dev: true - /zustand@5.0.9(@types/react@18.3.27)(react@18.3.1): - resolution: {integrity: sha512-ALBtUj0AfjJt3uNRQoL1tL2tMvj6Gp/6e39dnfT6uzpelGru8v1tPOGBzayOWbPJvujM8JojDk3E1LxeFisBNg==} - engines: {node: '>=12.20.0'} - peerDependencies: - '@types/react': '>=18.0.0' - immer: '>=9.0.6' - react: '>=18.0.0' - use-sync-external-store: '>=1.2.0' - peerDependenciesMeta: - '@types/react': - optional: true - immer: - optional: true - react: - optional: true - use-sync-external-store: - optional: true - dependencies: - '@types/react': 18.3.27 - react: 18.3.1 - dev: false - /zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} dev: false diff --git a/frontend/providers/kubepanel/.eslintrc.json b/frontend/providers/kubepanel/.eslintrc.json deleted file mode 100644 index 0da65fdb8..000000000 --- a/frontend/providers/kubepanel/.eslintrc.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": ["next", "next/core-web-vitals"], - "plugins": ["xss"], - "rules": { - "react-hooks/rules-of-hooks": 0, - "xss/no-mixed-html": "error", - "import/no-commonjs": 0 - } -} diff --git a/frontend/providers/kubepanel/.gitignore b/frontend/providers/kubepanel/.gitignore deleted file mode 100644 index da4ef4aea..000000000 --- a/frontend/providers/kubepanel/.gitignore +++ /dev/null @@ -1,42 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.js - -# testing -/coverage - -# next.js -/.next/ -/out/ - -# production -/build - -# misc -.DS_Store -*.pem - -# debug -npm-debug.log* -yarn-debug.log* -yarn-error.log* -.pnpm-debug.log* - -# local env files -.env*.local - -# vercel -.vercel - -# typescript -*.tsbuildinfo -next-env.d.ts -/public/trainData/ -/.vscode/ -platform.json -.yalc/ -yalc.lock -data/*.local \ No newline at end of file diff --git a/frontend/providers/kubepanel/.prettierignore b/frontend/providers/kubepanel/.prettierignore deleted file mode 100644 index ab9a493f2..000000000 --- a/frontend/providers/kubepanel/.prettierignore +++ /dev/null @@ -1,4 +0,0 @@ -dist -.vscode -**/.DS_Store -node_modules diff --git a/frontend/providers/kubepanel/.prettierrc.js b/frontend/providers/kubepanel/.prettierrc.js deleted file mode 100644 index 8bc336a36..000000000 --- a/frontend/providers/kubepanel/.prettierrc.js +++ /dev/null @@ -1,20 +0,0 @@ -module.exports = { - printWidth: 100, - tabWidth: 2, - useTabs: false, - semi: true, - singleQuote: true, - quoteProps: 'as-needed', - jsxSingleQuote: false, - trailingComma: 'none', - bracketSpacing: true, - jsxBracketSameLine: false, - arrowParens: 'always', - rangeStart: 0, - rangeEnd: Infinity, - requirePragma: false, - insertPragma: false, - proseWrap: 'preserve', - htmlWhitespaceSensitivity: 'css', - endOfLine: 'lf' -}; diff --git a/frontend/providers/kubepanel/README.md b/frontend/providers/kubepanel/README.md deleted file mode 100644 index a939e3002..000000000 --- a/frontend/providers/kubepanel/README.md +++ /dev/null @@ -1,37 +0,0 @@ -## How to dev - -1. First,you should refer to `frontend/README.md` ’s `How to dev` part. - -2. Then you should config your env. - - 1. Create a new file `.env.local` in frontend/providers/kubepanel directory. - - 2. ``` - NEXT_PUBLIC_MOCK_USER="" - SEALOS_DOMAIN="dev.sealos.top" - NODE_ENV="development" - ``` - - 3. Then we should get our `NEXT_PUBLIC_MOCK_USER` - - 1. go to `dev.sealos.top` and login (firstly you goin this website,you are signuping,so go on.) - - 2. Refer this picture,you should open `Console-application`,and get your own `session.state.session.kubeconfig`,copy as JSON string. - - ![image-20240423105724369](https://raw.githubusercontent.com/mlhiter/typora-images/master/202404231101028.png) - -3. After that,have your own `test 3000 `page - - > Why you should have that? - > - > If you open your own dev in `localhost:3000` directly,you cannot have sealos desktop border,which maybe influence your style. - - 1. This url:[website](https://cloud.sealos.run/?openapp=system-template%3FtemplateName%3Done-step-shortcuts) - - 2. ![image-20240423111024336](https://raw.githubusercontent.com/mlhiter/typora-images/master/202404231110609.png) - - 3. Refresh website. - - 4. Then you can get your own dev in this. - - ![image-20240423111123308](https://raw.githubusercontent.com/mlhiter/typora-images/master/202404231111720.png) \ No newline at end of file diff --git a/frontend/providers/kubepanel/deploy/Kubefile b/frontend/providers/kubepanel/deploy/Kubefile deleted file mode 100644 index 1df32281e..000000000 --- a/frontend/providers/kubepanel/deploy/Kubefile +++ /dev/null @@ -1,9 +0,0 @@ -FROM scratch - -USER 65532:65532 - -COPY registry registry -COPY charts charts -COPY kubepanel-frontend-entrypoint.sh kubepanel-frontend-entrypoint.sh - -CMD ["bash kubepanel-frontend-entrypoint.sh"] diff --git a/frontend/providers/kubepanel/deploy/charts/kubepanel-frontend/Chart.yaml b/frontend/providers/kubepanel/deploy/charts/kubepanel-frontend/Chart.yaml deleted file mode 100644 index 8cd88d22b..000000000 --- a/frontend/providers/kubepanel/deploy/charts/kubepanel-frontend/Chart.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: v2 -name: kubepanel-frontend -description: Sealos Kube Panel Frontend Helm Chart -type: application -version: 1.0.0 -appVersion: "latest" diff --git a/frontend/providers/kubepanel/deploy/charts/kubepanel-frontend/kubepanel-frontend-values.yaml b/frontend/providers/kubepanel/deploy/charts/kubepanel-frontend/kubepanel-frontend-values.yaml deleted file mode 100644 index ebbfab230..000000000 --- a/frontend/providers/kubepanel/deploy/charts/kubepanel-frontend/kubepanel-frontend-values.yaml +++ /dev/null @@ -1,14 +0,0 @@ -# Custom values for kubepanel-frontend helm chart. -# This file contains user-customizable configurations. - -replicaCount: 1 - -resources: - limits: - cpu: 1000m - memory: 1024Mi - requests: - cpu: 10m - memory: 128Mi - -kubepanelConfig: diff --git a/frontend/providers/kubepanel/deploy/charts/kubepanel-frontend/templates/_helpers.tpl b/frontend/providers/kubepanel/deploy/charts/kubepanel-frontend/templates/_helpers.tpl deleted file mode 100644 index 7bbd858d3..000000000 --- a/frontend/providers/kubepanel/deploy/charts/kubepanel-frontend/templates/_helpers.tpl +++ /dev/null @@ -1,84 +0,0 @@ -{{/* Expand the name of the chart. */}} -{{- define "kubepanel-frontend.name" -}} -{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* Create a default fully qualified app name. */}} -{{- define "kubepanel-frontend.fullname" -}} -{{- if .Values.fullnameOverride }} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- $name := default .Chart.Name .Values.nameOverride }} -{{- if contains $name .Release.Name }} -{{- .Release.Name | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} -{{- end }} -{{- end }} -{{- end }} - -{{- define "kubepanel-frontend.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{- define "kubepanel-frontend.labels" -}} -helm.sh/chart: {{ include "kubepanel-frontend.chart" . }} -{{ include "kubepanel-frontend.selectorLabels" . }} -{{ include "kubepanel-frontend.recommendedLabels" . }} -{{- if .Chart.AppVersion }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} -{{- end }} -app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- end }} - -{{- define "kubepanel-frontend.selectorLabels" -}} -app: {{ include "kubepanel-frontend.fullname" . }} -{{- end }} - -{{- define "kubepanel-frontend.recommendedLabels" -}} -app.kubernetes.io/name: {{ include "kubepanel-frontend.name" . }} -app.kubernetes.io/instance: {{ .Release.Name }} -{{- end }} - -{{- define "kubepanel-frontend.scheme" -}} -{{- if eq (toString .Values.kubepanelConfig.disableHttps) "true" -}}http{{- else -}}https{{- end -}} -{{- end }} - -{{- define "kubepanel-frontend.port" -}} -{{- $scheme := include "kubepanel-frontend.scheme" . -}} -{{- $port := toString .Values.kubepanelConfig.cloudPort -}} -{{- if eq $scheme "http" -}} -{{- $port = toString .Values.kubepanelConfig.httpPort -}} -{{- end -}} -{{- if or (and (eq $scheme "https") (or (eq $port "") (eq $port "443"))) (and (eq $scheme "http") (or (eq $port "") (eq $port "80"))) -}} -{{- "" -}} -{{- else -}} -{{- $port -}} -{{- end }} -{{- end }} - -{{- define "kubepanel-frontend.portSuffix" -}} -{{- $port := include "kubepanel-frontend.port" . -}} -{{- if $port -}}:{{ $port }}{{- end -}} -{{- end }} - -{{- define "kubepanel-frontend.portEnv" -}} -{{- $port := include "kubepanel-frontend.port" . -}} -{{- if $port -}}:{{ $port }}{{- end -}} -{{- end }} - -{{- define "kubepanel-frontend.cloudOrigin" -}} -{{- include "kubepanel-frontend.scheme" . -}}://{{ .Values.kubepanelConfig.cloudDomain }}{{ include "kubepanel-frontend.portSuffix" . }} -{{- end }} - -{{- define "kubepanel-frontend.wildcardCloudOrigin" -}} -{{- include "kubepanel-frontend.scheme" . -}}://*.{{ .Values.kubepanelConfig.cloudDomain }}{{ include "kubepanel-frontend.portSuffix" . }} -{{- end }} - -{{- define "kubepanel-frontend.host" -}} -{{- default (printf "kubepanel.%s" .Values.kubepanelConfig.cloudDomain) .Values.ingress.host -}} -{{- end }} - -{{- define "kubepanel-frontend.appUrl" -}} -{{- include "kubepanel-frontend.scheme" . -}}://{{ include "kubepanel-frontend.host" . }}{{ include "kubepanel-frontend.portSuffix" . }} -{{- end }} diff --git a/frontend/providers/kubepanel/deploy/charts/kubepanel-frontend/templates/app.yaml b/frontend/providers/kubepanel/deploy/charts/kubepanel-frontend/templates/app.yaml deleted file mode 100644 index 615b82161..000000000 --- a/frontend/providers/kubepanel/deploy/charts/kubepanel-frontend/templates/app.yaml +++ /dev/null @@ -1,19 +0,0 @@ -apiVersion: app.sealos.io/v1 -kind: App -metadata: - name: kubepanel - namespace: app-system -spec: - data: - desc: Kube Panel - url: {{ include "kubepanel-frontend.appUrl" . | quote }} - icon: {{ printf "%s/logo.svg" (include "kubepanel-frontend.appUrl" .) | quote }} - i18n: - zh: - name: 资源监控 - zh-Hans: - name: 资源监控 - menuData: - name: Kube Panel - type: iframe - displayType: normal diff --git a/frontend/providers/kubepanel/deploy/charts/kubepanel-frontend/templates/configmap.yaml b/frontend/providers/kubepanel/deploy/charts/kubepanel-frontend/templates/configmap.yaml deleted file mode 100644 index 7bd074f04..000000000 --- a/frontend/providers/kubepanel/deploy/charts/kubepanel-frontend/templates/configmap.yaml +++ /dev/null @@ -1,10 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ include "kubepanel-frontend.fullname" . }}-config - namespace: {{ .Release.Namespace }} - labels: - {{- include "kubepanel-frontend.labels" . | nindent 4 }} -data: - config.yaml: |- - addr: :3000 diff --git a/frontend/providers/kubepanel/deploy/charts/kubepanel-frontend/templates/deployment.yaml b/frontend/providers/kubepanel/deploy/charts/kubepanel-frontend/templates/deployment.yaml deleted file mode 100644 index 76601c3b3..000000000 --- a/frontend/providers/kubepanel/deploy/charts/kubepanel-frontend/templates/deployment.yaml +++ /dev/null @@ -1,63 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ include "kubepanel-frontend.fullname" . }} - namespace: {{ .Release.Namespace }} - labels: - {{- include "kubepanel-frontend.labels" . | nindent 4 }} -spec: - replicas: {{ .Values.replicaCount }} - selector: - matchLabels: - {{- include "kubepanel-frontend.selectorLabels" . | nindent 6 }} - strategy: - type: RollingUpdate - rollingUpdate: - maxUnavailable: 25% - maxSurge: 25% - template: - metadata: - labels: - {{- include "kubepanel-frontend.labels" . | nindent 8 }} - {{- with .Values.podAnnotations }} - annotations: - {{- toYaml . | nindent 8 }} - {{- end }} - spec: - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - securityContext: - {{- toYaml .Values.podSecurityContext | nindent 8 }} - containers: - - name: {{ .Chart.Name }} - image: {{ .Values.image | quote }} - imagePullPolicy: {{ .Values.imagePullPolicy }} - {{- if .Values.securityContext }} - securityContext: - {{- toYaml .Values.securityContext | nindent 12 }} - {{- end }} - resources: - {{- toYaml .Values.resources | nindent 12 }} - env: - - name: SEALOS_DOMAIN - value: {{ .Values.kubepanelConfig.cloudDomain | quote }} - - name: SEALOS_PORT - value: {{ include "kubepanel-frontend.portEnv" . | quote }} - ports: - - name: http - containerPort: {{ .Values.service.port }} - protocol: TCP - volumeMounts: - - name: kubepanel-frontend-volume - mountPath: /config.yaml - subPath: config.yaml - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - volumes: - - name: kubepanel-frontend-volume - configMap: - name: {{ include "kubepanel-frontend.fullname" . }}-config diff --git a/frontend/providers/kubepanel/deploy/charts/kubepanel-frontend/templates/ingress.yaml b/frontend/providers/kubepanel/deploy/charts/kubepanel-frontend/templates/ingress.yaml deleted file mode 100644 index 5724f2d4d..000000000 --- a/frontend/providers/kubepanel/deploy/charts/kubepanel-frontend/templates/ingress.yaml +++ /dev/null @@ -1,43 +0,0 @@ -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: {{ include "kubepanel-frontend.fullname" . }} - namespace: {{ .Release.Namespace }} - annotations: - kubernetes.io/ingress.class: {{ .Values.ingress.className | quote }} - nginx.ingress.kubernetes.io/enable-cors: "true" - nginx.ingress.kubernetes.io/cors-allow-methods: "PUT, GET, POST, DELETE, PATCH, OPTIONS" - nginx.ingress.kubernetes.io/cors-allow-origin: "{{ include "kubepanel-frontend.cloudOrigin" . }}, {{ include "kubepanel-frontend.wildcardCloudOrigin" . }}" - nginx.ingress.kubernetes.io/cors-allow-credentials: "true" - nginx.ingress.kubernetes.io/cors-max-age: "600" - nginx.ingress.kubernetes.io/backend-protocol: "HTTP" - nginx.ingress.kubernetes.io/configuration-snippet: | - more_clear_headers "X-Frame-Options:"; - more_set_headers "Content-Security-Policy: default-src * blob: data: *.{{ .Values.kubepanelConfig.cloudDomain }}{{ include "kubepanel-frontend.portSuffix" . }} {{ .Values.kubepanelConfig.cloudDomain }}{{ include "kubepanel-frontend.portSuffix" . }}; img-src * data: blob: resource: *.{{ .Values.kubepanelConfig.cloudDomain }}{{ include "kubepanel-frontend.portSuffix" . }} {{ .Values.kubepanelConfig.cloudDomain }}{{ include "kubepanel-frontend.portSuffix" . }}; connect-src * wss: blob: resource:; style-src 'self' 'unsafe-inline' blob: *.{{ .Values.kubepanelConfig.cloudDomain }}{{ include "kubepanel-frontend.portSuffix" . }} {{ .Values.kubepanelConfig.cloudDomain }}{{ include "kubepanel-frontend.portSuffix" . }} resource:; script-src 'self' 'unsafe-inline' 'unsafe-eval' blob: *.{{ .Values.kubepanelConfig.cloudDomain }}{{ include "kubepanel-frontend.portSuffix" . }} {{ .Values.kubepanelConfig.cloudDomain }}{{ include "kubepanel-frontend.portSuffix" . }} resource: *.baidu.com *.bdstatic.com https://js.stripe.com; frame-src 'self' *.{{ .Values.kubepanelConfig.cloudDomain }}{{ include "kubepanel-frontend.portSuffix" . }} {{ .Values.kubepanelConfig.cloudDomain }}{{ include "kubepanel-frontend.portSuffix" . }} mailto: tel: weixin: mtt: *.baidu.com https://js.stripe.com; frame-ancestors 'self' {{ include "kubepanel-frontend.cloudOrigin" . }} {{ include "kubepanel-frontend.wildcardCloudOrigin" . }}"; - more_set_headers "X-Xss-Protection: 1; mode=block"; - higress.io/response-header-control-remove: X-Frame-Options - higress.io/response-header-control-update: | - Content-Security-Policy "default-src * blob: data: *.{{ .Values.kubepanelConfig.cloudDomain }}{{ include "kubepanel-frontend.portSuffix" . }} {{ .Values.kubepanelConfig.cloudDomain }}{{ include "kubepanel-frontend.portSuffix" . }}; img-src * data: blob: resource: *.{{ .Values.kubepanelConfig.cloudDomain }}{{ include "kubepanel-frontend.portSuffix" . }} {{ .Values.kubepanelConfig.cloudDomain }}{{ include "kubepanel-frontend.portSuffix" . }}; connect-src * wss: blob: resource:; style-src 'self' 'unsafe-inline' blob: *.{{ .Values.kubepanelConfig.cloudDomain }}{{ include "kubepanel-frontend.portSuffix" . }} {{ .Values.kubepanelConfig.cloudDomain }}{{ include "kubepanel-frontend.portSuffix" . }} resource:; script-src 'self' 'unsafe-inline' 'unsafe-eval' blob: *.{{ .Values.kubepanelConfig.cloudDomain }}{{ include "kubepanel-frontend.portSuffix" . }} {{ .Values.kubepanelConfig.cloudDomain }}{{ include "kubepanel-frontend.portSuffix" . }} resource: *.baidu.com *.bdstatic.com https://js.stripe.com; frame-src 'self' *.{{ .Values.kubepanelConfig.cloudDomain }}{{ include "kubepanel-frontend.portSuffix" . }} {{ .Values.kubepanelConfig.cloudDomain }}{{ include "kubepanel-frontend.portSuffix" . }} mailto: tel: weixin: mtt: *.baidu.com https://js.stripe.com; frame-ancestors 'self' {{ include "kubepanel-frontend.cloudOrigin" . }} {{ include "kubepanel-frontend.wildcardCloudOrigin" . }}" - X-Xss-Protection "1; mode=block" - {{- with .Values.ingress.annotations }} - {{- toYaml . | nindent 4 }} - {{- end }} -spec: - ingressClassName: {{ .Values.ingress.className | quote }} - rules: - - host: {{ include "kubepanel-frontend.host" . | quote }} - http: - paths: - - pathType: Prefix - path: / - backend: - service: - name: {{ include "kubepanel-frontend.fullname" . }} - port: - number: {{ .Values.service.port }} - {{- if not (eq (toString .Values.kubepanelConfig.disableHttps) "true") }} - tls: - - hosts: - - {{ include "kubepanel-frontend.host" . | quote }} - secretName: {{ .Values.kubepanelConfig.certSecretName | quote }} - {{- end }} diff --git a/frontend/providers/kubepanel/deploy/charts/kubepanel-frontend/templates/service.yaml b/frontend/providers/kubepanel/deploy/charts/kubepanel-frontend/templates/service.yaml deleted file mode 100644 index 2fdcc35cb..000000000 --- a/frontend/providers/kubepanel/deploy/charts/kubepanel-frontend/templates/service.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - labels: - {{- include "kubepanel-frontend.labels" . | nindent 4 }} - name: {{ include "kubepanel-frontend.fullname" . }} - namespace: {{ .Release.Namespace }} -spec: - type: {{ .Values.service.type }} - ports: - - name: http - port: {{ .Values.service.port }} - protocol: TCP - targetPort: {{ .Values.service.port }} - selector: - {{- include "kubepanel-frontend.selectorLabels" . | nindent 4 }} diff --git a/frontend/providers/kubepanel/deploy/charts/kubepanel-frontend/values.yaml b/frontend/providers/kubepanel/deploy/charts/kubepanel-frontend/values.yaml deleted file mode 100644 index e2d893f5d..000000000 --- a/frontend/providers/kubepanel/deploy/charts/kubepanel-frontend/values.yaml +++ /dev/null @@ -1,61 +0,0 @@ -# Default values for kubepanel-frontend helm chart. - -image: ghcr.io/labring/sealos-kubepanel-frontend:latest -imagePullPolicy: Always - -imagePullSecrets: [] -fullnameOverride: "kubepanel-frontend" - -replicaCount: 1 - -podAnnotations: {} -podLabels: {} - -podSecurityContext: - runAsNonRoot: true - runAsUser: 1001 - -securityContext: - runAsNonRoot: true - runAsUser: 1001 - allowPrivilegeEscalation: false - capabilities: - drop: - - "ALL" - -service: - type: ClusterIP - port: 3000 - -ingress: - className: nginx - host: "" - annotations: {} - -kubepanelConfig: - cloudDomain: "127.0.0.1.nip.io" - cloudPort: "" - httpPort: "" - disableHttps: false - certSecretName: "wildcard-cert" - -resources: - limits: - cpu: 1000m - memory: 1024Mi - requests: - cpu: 10m - memory: 128Mi - -affinity: - podAntiAffinity: - preferredDuringSchedulingIgnoredDuringExecution: - - weight: 100 - podAffinityTerm: - labelSelector: - matchExpressions: - - key: "app" - operator: In - values: - - kubepanel-frontend - topologyKey: "kubernetes.io/hostname" diff --git a/frontend/providers/kubepanel/deploy/kubepanel-frontend-entrypoint.sh b/frontend/providers/kubepanel/deploy/kubepanel-frontend-entrypoint.sh deleted file mode 100755 index a28975170..000000000 --- a/frontend/providers/kubepanel/deploy/kubepanel-frontend-entrypoint.sh +++ /dev/null @@ -1,87 +0,0 @@ -#!/bin/bash -set -e - -RELEASE_NAME=${RELEASE_NAME:-"kubepanel-frontend"} -RELEASE_NAMESPACE=${RELEASE_NAMESPACE:-"kubepanel-frontend"} -CHART_PATH=${CHART_PATH:-"./charts/kubepanel-frontend"} -HELM_OPTS=${HELM_OPTS:-""} -HELM_OPTIONS=${HELM_OPTIONS:-""} -AUTO_CONFIG_HELM_OPTS="" - -get_cm_value() { - local namespace="$1" - local name="$2" - local key="$3" - kubectl get configmap "${name}" -n "${namespace}" -o "jsonpath={.data.${key}}" 2>/dev/null || true -} - -add_set_string() { - local key="$1" - local value="$2" - if [ -n "${value}" ]; then - AUTO_CONFIG_HELM_OPTS="${AUTO_CONFIG_HELM_OPTS} --set-string ${key}=${value}" - fi -} - -SEALOS_CLOUD_DOMAIN=${SEALOS_CLOUD_DOMAIN:-"${cloudDomain:-$(get_cm_value sealos-system sealos-config cloudDomain)}"} -add_set_string kubepanelConfig.cloudDomain "${SEALOS_CLOUD_DOMAIN}" -SEALOS_CLOUD_PORT=${SEALOS_CLOUD_PORT:-"${cloudPort:-$(get_cm_value sealos-system sealos-config cloudPort)}"} -add_set_string kubepanelConfig.cloudPort "${SEALOS_CLOUD_PORT}" -SEALOS_HTTP_PORT=${SEALOS_HTTP_PORT:-"${httpPort:-$(get_cm_value sealos-system sealos-config httpPort)}"} -add_set_string kubepanelConfig.httpPort "${SEALOS_HTTP_PORT}" -SEALOS_DISABLE_HTTPS=${SEALOS_DISABLE_HTTPS:-"${disableHttps:-$(get_cm_value sealos-system sealos-config disableHttps)}"} -add_set_string kubepanelConfig.disableHttps "${SEALOS_DISABLE_HTTPS}" -SEALOS_CERT_SECRET_NAME=${SEALOS_CERT_SECRET_NAME:-"${certSecretName:-$(get_cm_value sealos-system sealos-config certSecretName)}"} -add_set_string kubepanelConfig.certSecretName "${SEALOS_CERT_SECRET_NAME}" - - -adopt_namespaced_resource() { - local namespace="$1" - local kind="$2" - local name="$3" - if kubectl -n "${namespace}" get "${kind}" "${name}" >/dev/null 2>&1; then - echo "Adopting ${kind} ${namespace}/${name}..." - kubectl -n "${namespace}" label "${kind}" "${name}" app.kubernetes.io/managed-by=Helm --overwrite >/dev/null 2>&1 || true - kubectl -n "${namespace}" annotate "${kind}" "${name}" meta.helm.sh/release-name="${RELEASE_NAME}" meta.helm.sh/release-namespace="${RELEASE_NAMESPACE}" --overwrite >/dev/null 2>&1 || true - fi -} - -adopt_cluster_resource() { - local kind="$1" - local name="$2" - if kubectl get "${kind}" "${name}" >/dev/null 2>&1; then - echo "Adopting ${kind} ${name}..." - kubectl label "${kind}" "${name}" app.kubernetes.io/managed-by=Helm --overwrite >/dev/null 2>&1 || true - kubectl annotate "${kind}" "${name}" meta.helm.sh/release-name="${RELEASE_NAME}" meta.helm.sh/release-namespace="${RELEASE_NAMESPACE}" --overwrite >/dev/null 2>&1 || true - fi -} - -echo "Checking and adopting existing resources..." -if kubectl get namespace "${RELEASE_NAMESPACE}" >/dev/null 2>&1; then - kubectl label namespace "${RELEASE_NAMESPACE}" app.kubernetes.io/managed-by=Helm --overwrite >/dev/null 2>&1 || true - kubectl annotate namespace "${RELEASE_NAMESPACE}" meta.helm.sh/release-name="${RELEASE_NAME}" meta.helm.sh/release-namespace="${RELEASE_NAMESPACE}" --overwrite >/dev/null 2>&1 || true - - adopt_namespaced_resource "${RELEASE_NAMESPACE}" configmap kubepanel-frontend-config - adopt_namespaced_resource "${RELEASE_NAMESPACE}" service kubepanel-frontend - adopt_namespaced_resource "${RELEASE_NAMESPACE}" deployment kubepanel-frontend - adopt_namespaced_resource "${RELEASE_NAMESPACE}" ingress kubepanel-frontend -fi - -adopt_namespaced_resource app-system apps.app.sealos.io kubepanel - - -SERVICE_NAME="kubepanel-frontend" -USER_VALUES_PATH="/root/.sealos/cloud/values/core/${SERVICE_NAME}-values.yaml" - -if [ ! -f "${USER_VALUES_PATH}" ]; then - mkdir -p "$(dirname "${USER_VALUES_PATH}")" - cp "./charts/kubepanel-frontend/kubepanel-frontend-values.yaml" "${USER_VALUES_PATH}" -fi - -HELM_ARGS="${AUTO_CONFIG_HELM_OPTS} ${HELM_OPTIONS} ${HELM_OPTS}" - -echo "Deploying Helm chart..." -helm upgrade -i "${RELEASE_NAME}" -n "${RELEASE_NAMESPACE}" --create-namespace "${CHART_PATH}" \ - -f "./charts/kubepanel-frontend/values.yaml" \ - -f "${USER_VALUES_PATH}" \ - ${HELM_ARGS} diff --git a/frontend/providers/kubepanel/dockerfile b/frontend/providers/kubepanel/dockerfile deleted file mode 100644 index b33d0b3d3..000000000 --- a/frontend/providers/kubepanel/dockerfile +++ /dev/null @@ -1,58 +0,0 @@ -# Install dependencies only when needed -FROM node:current-alpine AS deps -# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed. -RUN apk add --no-cache libc6-compat && npm install -g pnpm -WORKDIR /app - -# Install dependencies based on the preferred package manager -COPY package.json pnpm-lock.yaml* ./ -RUN \ - [ -f pnpm-lock.yaml ] && pnpm install || \ - (echo "Lockfile not found." && exit 1) - -# Rebuild the source code only when needed -FROM node:current-alpine AS builder -WORKDIR /app -COPY --from=deps /app/node_modules ./node_modules -COPY . . - -# Next.js collects completely anonymous telemetry data about general usage. -# Learn more here: https://nextjs.org/telemetry -# Uncomment the following line in case you want to disable telemetry during the build. -ENV NEXT_TELEMETRY_DISABLED 1 -ENV NEXT_PUBLIC_MOCK_USER '' - -RUN npm install -g pnpm && pnpm run build - -# Production image, copy all the files and run next -FROM node:current-alpine AS runner -WORKDIR /app - -ENV NODE_ENV production -# Uncomment the following line in case you want to disable telemetry during runtime. -ENV NEXT_TELEMETRY_DISABLED 1 - -RUN addgroup --system --gid 1001 nodejs -RUN adduser --system --uid 1001 nextjs - -RUN sed -i 's/https/http/' /etc/apk/repositories -RUN apk add curl \ - && apk add ca-certificates \ - && update-ca-certificates - -# You only need to copy next.config.js if you are NOT using the default configuration -# COPY --from=builder /app/next.config.js ./ -COPY --from=builder /app/public ./public -COPY --from=builder /app/package.json ./package.json -# COPY --from=builder /app/.env* . - -# Automatically leverage output traces to reduce image size -# https://nextjs.org/docs/advanced-features/output-file-tracing -COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ -COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static - -USER nextjs - -EXPOSE 3000 - -CMD ["pnpm", "run", "start"] diff --git a/frontend/providers/kubepanel/next.config.js b/frontend/providers/kubepanel/next.config.js deleted file mode 100644 index 1c2e4f5c2..000000000 --- a/frontend/providers/kubepanel/next.config.js +++ /dev/null @@ -1,11 +0,0 @@ -/** @type {import('next').NextConfig} */ -const path = require('path'); - -const nextConfig = { - output: 'standalone', - reactStrictMode: false, - compress: true, - transpilePackages: ['monaco-editor'] -}; - -module.exports = nextConfig; diff --git a/frontend/providers/kubepanel/package.json b/frontend/providers/kubepanel/package.json deleted file mode 100644 index b64e5772a..000000000 --- a/frontend/providers/kubepanel/package.json +++ /dev/null @@ -1,61 +0,0 @@ -{ - "name": "kubepanel", - "version": "1.0.0", - "private": true, - "scripts": { - "dev": "next dev --turbo", - "build": "next build", - "start": "next start", - "lint": "next lint" - }, - "dependencies": { - "@ant-design/charts": "^2.6.6", - "@ant-design/icons": "^6.1.0", - "@ant-design/plots": "^2.6.6", - "@chakra-ui/anatomy": "^2.2.1", - "@chakra-ui/icons": "^2.1.1", - "@chakra-ui/next-js": "^2.1.5", - "@chakra-ui/react": "^2.8.1", - "@chakra-ui/system": "^2.6.1", - "@emotion/react": "^11.11.1", - "@emotion/styled": "^11.11.0", - "@monaco-editor/react": "^4.7.0", - "antd": "^6.1.0", - "auto-bind": "^5.0.1", - "axios": "^1.13.2", - "framer-motion": "^10.16.4", - "i18next": "^23.11.5", - "js-yaml": "^4.1.1", - "lodash": "^4.17.21", - "moment": "^2.29.4", - "moment-timezone": "^0.5.43", - "monaco-editor": "^0.55.1", - "next": "14.2.35", - "next-i18next": "^15.3.0", - "nprogress": "^0.2.0", - "react": "18.3.1", - "react-dom": "18.3.1", - "react-i18next": "^14.1.2", - "sealos-desktop-sdk": "workspace:*", - "type-fest": "^5.3.1", - "typed-regex": "^0.0.8", - "zustand": "^5.0.9" - }, - "devDependencies": { - "@tailwindcss/postcss": "^4.1.17", - "@types/js-yaml": "^4.0.9", - "@types/lodash": "^4.17.21", - "@types/node": "^24.0.0", - "@types/nprogress": "^0.2.3", - "@types/react": "18.3.27", - "autoprefixer": "^10.4.22", - "eslint": "^8.57.0", - "eslint-config-next": "14.2.3", - "eslint-plugin-xss": "^0.1.12", - "postcss": "^8.5.6", - "postcss-import": "^16.1.1", - "postcss-nesting": "^13.0.2", - "tailwindcss": "^4.1.17", - "typescript": "^5.9.3" - } -} diff --git a/frontend/providers/kubepanel/postcss.config.js b/frontend/providers/kubepanel/postcss.config.js deleted file mode 100644 index 16cb49fe4..000000000 --- a/frontend/providers/kubepanel/postcss.config.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - plugins: { - // Tailwind v4 requires @tailwindcss/postcss as the PostCSS entry. - '@tailwindcss/postcss': {} - } -}; diff --git a/frontend/providers/kubepanel/public/create-resource-templates/ConfigMap.yaml b/frontend/providers/kubepanel/public/create-resource-templates/ConfigMap.yaml deleted file mode 100644 index b365cf9f0..000000000 --- a/frontend/providers/kubepanel/public/create-resource-templates/ConfigMap.yaml +++ /dev/null @@ -1,17 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: game-demo -data: - # property-like keys; each key maps to a simple value - player_initial_lives: "3" - ui_properties_file_name: "user-interface.properties" - - # file-like keys - game.properties: | - enemy.types=aliens,monsters - player.maximum-lives=5 - user-interface.properties: | - color.good=purple - color.bad=yellow - allow.textmode=true diff --git a/frontend/providers/kubepanel/public/create-resource-templates/Deployment.yaml b/frontend/providers/kubepanel/public/create-resource-templates/Deployment.yaml deleted file mode 100644 index 17dd4b454..000000000 --- a/frontend/providers/kubepanel/public/create-resource-templates/Deployment.yaml +++ /dev/null @@ -1,23 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: nginx-deployment - labels: - app: nginx -spec: - replicas: 3 - selector: - matchLabels: - app: nginx - template: - metadata: - labels: - app: nginx - spec: - containers: - - name: nginx - image: nginx:1.14.2 - ports: - - containerPort: 80 - securityContext: - allowPrivilegeEscalation: false diff --git a/frontend/providers/kubepanel/public/create-resource-templates/Ingress.yaml b/frontend/providers/kubepanel/public/create-resource-templates/Ingress.yaml deleted file mode 100644 index 76640b944..000000000 --- a/frontend/providers/kubepanel/public/create-resource-templates/Ingress.yaml +++ /dev/null @@ -1,17 +0,0 @@ -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: minimal-ingress - annotations: - nginx.ingress.kubernetes.io/rewrite-target: / -spec: - rules: - - http: - paths: - - path: /testpath - pathType: Prefix - backend: - service: - name: test - port: - number: 80 diff --git a/frontend/providers/kubepanel/public/create-resource-templates/PersistentVolumeClaim.yaml b/frontend/providers/kubepanel/public/create-resource-templates/PersistentVolumeClaim.yaml deleted file mode 100644 index ad4339906..000000000 --- a/frontend/providers/kubepanel/public/create-resource-templates/PersistentVolumeClaim.yaml +++ /dev/null @@ -1,17 +0,0 @@ -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: myclaim -spec: - accessModes: - - ReadWriteOnce - volumeMode: Filesystem - resources: - requests: - storage: 8Gi - storageClassName: slow - selector: - matchLabels: - release: "stable" - matchExpressions: - - {key: environment, operator: In, values: [dev]} diff --git a/frontend/providers/kubepanel/public/create-resource-templates/Pod.yaml b/frontend/providers/kubepanel/public/create-resource-templates/Pod.yaml deleted file mode 100644 index b63e39eea..000000000 --- a/frontend/providers/kubepanel/public/create-resource-templates/Pod.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: v1 -kind: Pod -metadata: - name: static-web - labels: - role: myrole -spec: - containers: - - name: web - image: nginx - ports: - - name: web - containerPort: 80 - protocol: TCP - securityContext: - allowPrivilegeEscalation: false diff --git a/frontend/providers/kubepanel/public/create-resource-templates/Secret.yaml b/frontend/providers/kubepanel/public/create-resource-templates/Secret.yaml deleted file mode 100644 index 191e2d779..000000000 --- a/frontend/providers/kubepanel/public/create-resource-templates/Secret.yaml +++ /dev/null @@ -1,8 +0,0 @@ -apiVersion: v1 -kind: Secret -metadata: - name: secret-basic-auth -type: kubernetes.io/basic-auth -stringData: - username: admin - password: t0p-Secret diff --git a/frontend/providers/kubepanel/public/create-resource-templates/StatefulSet.yaml b/frontend/providers/kubepanel/public/create-resource-templates/StatefulSet.yaml deleted file mode 100644 index f4f881fb0..000000000 --- a/frontend/providers/kubepanel/public/create-resource-templates/StatefulSet.yaml +++ /dev/null @@ -1,36 +0,0 @@ -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: web -spec: - selector: - matchLabels: - app: nginx # has to match .spec.template.metadata.labels - serviceName: "nginx" - replicas: 3 # by default is 1 - template: - metadata: - labels: - app: nginx # has to match .spec.selector.matchLabels - spec: - terminationGracePeriodSeconds: 10 - containers: - - name: nginx - image: registry.k8s.io/nginx-slim:0.8 - ports: - - containerPort: 80 - name: web - volumeMounts: - - name: www - mountPath: /usr/share/nginx/html - securityContext: - allowPrivilegeEscalation: false - volumeClaimTemplates: - - metadata: - name: www - spec: - accessModes: [ "ReadWriteOnce" ] - storageClassName: "my-storage-class" - resources: - requests: - storage: 1Gi diff --git a/frontend/providers/kubepanel/public/favicon.ico b/frontend/providers/kubepanel/public/favicon.ico deleted file mode 100644 index eba27e52d377de6dc3ebee3c8fe0ae88a348ad2f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4286 zcmeHIOK#gR5Tzj?TC_mv4_Yc+Sb(h}%K$wGwbdW84@y+ge0 zu35T3QFb2bktQ@n+e))3DuW(s$ayn-GearWqhDDn{Hrfosn<%W6B?vaGaAslht`HK z{P2qZ|6Ld;ORc9y&nCzEtTMwn<|js%U9h^?RAz8HHGLb7%JlCi#o$x*R-bmkjoIK_ z@Jub56@y;)jGnIwbkZ-N-@?p#C2?rvxfGmJI`Y@ z_gQGm?@!4gY-6!PCwpz5{Bt~q%C?%7e7WztxO)!uk=l>DA;Lj@pSjxF@WHj$!lGt@2_ZI)^{uXgtdrVNL?4-(#CT;xQW#v&MRwC+C9hI z#bQP?^u4du(M - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/frontend/providers/kubepanel/src/api/kubernetes.ts b/frontend/providers/kubepanel/src/api/kubernetes.ts deleted file mode 100644 index eb65ab08c..000000000 --- a/frontend/providers/kubepanel/src/api/kubernetes.ts +++ /dev/null @@ -1,112 +0,0 @@ -import { - KubeJsonApiDataFor, - KubeObject, - isJsonApiData, - isPartialJsonApiData -} from '@/k8slens/kube-object'; -import { bindPredicate, hasTypedProperty, isTypedArray } from '@/k8slens/utilities'; -import { ErrnoCode, buildErrno } from '@/services/backend/error'; -import { DELETE, GET, POST, PUT } from '@/services/request'; -import { KubeList } from '@/types/kube-resource'; -import { isKubeList } from '@/utils/types'; - -/** - * Retrieves a yaml-like template of a specified kind from Backend API. - * - * @param kind The kind of resource to retrieve. - * @returns A promise that resolves to a `SuccessResponse` containing the yaml-like template. - */ -export function getTemplate(kind: string) { - return GET>(`/api/kubernetes/template?kind=${kind}`); -} - -/** - * Retrieves a list of resources of a specified kind from the Backend API. - * - * @param kind The kind of resource to retrieve. - * @returns A promise that resolves to a `SuccessResponse` containing the list of resources. - */ -export async function listResources< - Object extends KubeObject = KubeObject, - Data extends KubeJsonApiDataFor = KubeJsonApiDataFor ->(kind: string): Promise>> { - const res = await GET>>(`/api/kubernetes/list?kind=${kind}`); - - if ( - isKubeList(res.data) && - hasTypedProperty(res.data, 'items', bindPredicate(isTypedArray, isPartialJsonApiData)) - ) { - return res; - } - - throw buildErrno('Response is not correct type', ErrnoCode.ServerInternalError); -} - -/** - * Creates a resource of the specified kind using the provided data. - * - * @param kind The kind of resource to create. - * @param data The data to use for creating the resource. - * @returns A Promise that resolves to a `SuccessResponse` containing the created resource data. - */ -export async function createResource< - Object extends KubeObject = KubeObject, - Data extends KubeJsonApiDataFor = KubeJsonApiDataFor ->(kind: string, data: string): Promise> { - const res = await POST>(`/api/kubernetes/create?kind=${kind}`, { - data - }); - - if (isJsonApiData(res.data)) { - return res; - } - - throw buildErrno('Response is not correct type', ErrnoCode.ServerInternalError); -} - -/** - * Deletes a resource from the Kubernetes cluster. - * - * @param kind The kind of resource to delete. - * @param name The name of the resource to delete. - * @return A promise that resolves with a `SuccessResponse` containing the data, which is old resource data, - * if the resource is deleted successfully. - */ -export async function deleteResource< - Object extends KubeObject = KubeObject, - Data extends KubeJsonApiDataFor = KubeJsonApiDataFor ->(kind: string, name: string): Promise> { - const res = await DELETE>('/api/kubernetes/delete', { - kind, - name - }); - - if (isJsonApiData(res.data)) { - return res; - } - - throw buildErrno('Response is not correct type', ErrnoCode.ServerInternalError); -} - -/** - * Updates a resource in the Kubernetes API. - * - * @param kind The type of resource to update. - * @param name The name of the resource to update. - * @param data The updated data for the resource. - * @return A promise that resolves to a `SuccessResponse` containing the old data. - */ -export async function updateResource< - Object extends KubeObject = KubeObject, - Data extends KubeJsonApiDataFor = KubeJsonApiDataFor ->(kind: string, name: string, data: string): Promise> { - const res = await PUT>(`/api/kubernetes/update?kind=${kind}&name=${name}`, { - data - }); - - if (isJsonApiData(res.data)) { - return res; - } - - throw buildErrno('Response is not correct type', ErrnoCode.ServerInternalError); -} diff --git a/frontend/providers/kubepanel/src/api/platform.ts b/frontend/providers/kubepanel/src/api/platform.ts deleted file mode 100644 index fe45e20a9..000000000 --- a/frontend/providers/kubepanel/src/api/platform.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { Response } from '@/pages/api/platform/init-data'; -import { GET } from '@/services/request'; - -export const getInitData = () => GET('/api/platform/init-data'); diff --git a/frontend/providers/kubepanel/src/components/chart/pie-chart.tsx b/frontend/providers/kubepanel/src/components/chart/pie-chart.tsx deleted file mode 100644 index f02f39825..000000000 --- a/frontend/providers/kubepanel/src/components/chart/pie-chart.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import { sum } from 'lodash'; -import dynamic from 'next/dynamic'; - -export type PieChartData = { - type: string; - value: number; -}; - -interface PieChartProps { - title: string; - data: Array; - color: (type: string) => string; -} - -// @ts-ignore - @ant-design/plots has complex types that cause deep instantiation in full tsc -const DynamicPie = dynamic(() => import('@ant-design/plots').then((item) => item.Pie), { - ssr: false -}); - -export const PieChart = ({ title, data, color }: PieChartProps) => { - const total = sum(data.map((d) => d.value)); - - const config = { - data: data, - angleField: 'value', - colorField: 'type', - color: data.map((item) => color(item.type)), - width: 220, - height: 350, - innerRadius: 0.6, - radius: 0.92, - label: false, - legend: { - position: 'bottom' as const, - layout: 'vertical' as const, - offsetY: -30, - marker: { - symbol: 'square' as const, - style: { - r: 6 - } - }, - itemSpacing: 13 - }, - annotations: [ - { - type: 'text', - style: { - text: `${title}\n${total}`, - x: '50%', - y: '50%', - textAlign: 'center', - fontSize: 16, - fontWeight: '500', - textBaseline: 'middle' - } - } - ], - tooltip: { - items: [ - (d: any) => ({ - name: d.type, - value: d.value - }) - ] - } - }; - - return ; -}; diff --git a/frontend/providers/kubepanel/src/components/common/action/action-button.tsx b/frontend/providers/kubepanel/src/components/common/action/action-button.tsx deleted file mode 100644 index bca55f956..000000000 --- a/frontend/providers/kubepanel/src/components/common/action/action-button.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import { KubeObject } from '@/k8slens/kube-object'; -import { CloseOutlined, MoreOutlined, RetweetOutlined } from '@ant-design/icons'; -import { Button, Dropdown, type MenuProps } from 'antd'; -import { useState } from 'react'; -import { DeletePopconfirm } from './delete-popconfirm'; -import { UpdateEditorModal } from './update-editor-modal'; - -interface Props { - obj: K; -} - -export const ActionButton = ({ obj }: Props) => { - const [openUpdateModal, setOpenUpdateModal] = useState(false); - - const items: MenuProps['items'] = [ - { - key: 'delete', - label: ( - - - - ) - }, - { - key: 'update', - label: ( - - ) - } - ].filter((item) => item.label); - - return ( - // wrapper to stop click event propagation -
e.stopPropagation()}> - - - - - - setOpenUpdateModal(false)} - onOk={() => setOpenUpdateModal(false)} - /> -
- ); -}; diff --git a/frontend/providers/kubepanel/src/components/common/action/create-resource-modal.tsx b/frontend/providers/kubepanel/src/components/common/action/create-resource-modal.tsx deleted file mode 100644 index 7b45a5db4..000000000 --- a/frontend/providers/kubepanel/src/components/common/action/create-resource-modal.tsx +++ /dev/null @@ -1,157 +0,0 @@ -import { createResource, getTemplate } from '@/api/kubernetes'; -import StyledEditor from '@/components/common/editor/styled'; -import Title from '@/components/common/title/title'; -import { KubeObjectKind } from '@/constants/kube-object'; -import { buildErrorResponse } from '@/services/backend/response'; -import { Button, Flex, Modal, Spin, notification } from 'antd'; -import { editor as EditorNS } from 'monaco-editor'; -import { useCallback, useRef, useState } from 'react'; -import { TemplateToggle, TemplateToggleChooseEventHandler } from './toggle'; - -interface Props { - open: boolean; - setClose: () => void; -} - -const defaultTemplate = 'Please select a template first.'; -const noticeKey = 'createResource'; - -export const CreateResourceModal = ({ open, setClose }: Props) => { - const [disabled, setDisabled] = useState(true); - const [kind, setKind] = useState(undefined); - const [loading, setLoading] = useState(false); - const [template, setTemplate] = useState(defaultTemplate); - const [confirmLoading, setConfirmLoading] = useState(false); - const [notifyApi, contextHolder] = notification.useNotification(); - const editorRef = useRef(null); - const onEditorMount = (editor: EditorNS.IStandaloneCodeEditor) => { - editorRef.current = editor; - }; - - const onChoose = useCallback( - (kind) => { - setKind(kind); - setDisabled(false); - const storage = localStorage.getItem(`template-${kind}`); - if (storage) { - setTemplate(storage); - return; - } - setLoading(true); - // fetch template - getTemplate(kind) - .then((res) => { - setTemplate(res.data); - }) - .catch((err: any) => { - const errResp = buildErrorResponse(err); - notifyApi.error({ - key: noticeKey, - message: errResp.error.reason, - description: errResp.error.message - }); - }) - .finally(() => { - setLoading(false); - }); - }, - [notifyApi] - ); - - const onCreate = useCallback(() => { - setConfirmLoading(true); - const editor = editorRef.current; - if (!editor) { - setConfirmLoading(false); - notifyApi.error({ - key: noticeKey, - message: 'Editor Not Found', - description: 'Please reopen the create resource panel, sorry for the inconvenience.' - }); - return; - } - if (!kind) { - setConfirmLoading(false); - notifyApi.error({ - key: noticeKey, - message: 'Template Not Found', - description: 'Please select a template first, sorry for the inconvenience.' - }); - return; - } - const value = editor.getValue(); - createResource(kind, value) - .then(() => { - notifyApi.success({ - key: noticeKey, - message: 'Success', - description: 'Your resource has been created.' - }); - }) - .catch((err: any) => { - const errResp = buildErrorResponse(err); - notifyApi.error({ - key: noticeKey, - message: errResp.error.reason, - description: errResp.error.message - }); - }) - .finally(() => { - setConfirmLoading(false); - }); - }, [kind, notifyApi]); - return ( - <> - {contextHolder} - - Cancel - , - - ]} - > - - Create Resource - - - - - - - - - - ); -}; diff --git a/frontend/providers/kubepanel/src/components/common/action/delete-popconfirm.tsx b/frontend/providers/kubepanel/src/components/common/action/delete-popconfirm.tsx deleted file mode 100644 index c35eb72dc..000000000 --- a/frontend/providers/kubepanel/src/components/common/action/delete-popconfirm.tsx +++ /dev/null @@ -1,122 +0,0 @@ -import { deleteResource } from '@/api/kubernetes'; -import { KubeObjectKind } from '@/constants/kube-object'; -import { KubeObject } from '@/k8slens/kube-object'; -import { buildErrorResponse } from '@/services/backend/response'; -import { - useBucketStore, - useClusterStore, - useConfigMapStore, - useDeploymentStore, - useDevboxStore, - useIngressStore, - usePodStore, - useSecretStore, - useServiceStore, - useStatefulSetStore, - useVolumeClaimStore -} from '@/store/kube'; -import { WarningOutlined } from '@ant-design/icons'; -import { Popconfirm, message } from 'antd'; -import { useEffect, useState } from 'react'; - -interface Props { - obj: K; - children: React.ReactNode; -} - -export function DeletePopconfirm({ obj, children }: Props) { - if (!obj) return null; - const [confirmLoading, setConfirmLoading] = useState(false); - const msgKey = `deletedMsg-${obj.getId()}`; - - const bucketStore = useBucketStore(); - const clusterStore = useClusterStore(); - const configMapStore = useConfigMapStore(); - const deploymentStore = useDeploymentStore(); - const devboxStore = useDevboxStore(); - const ingressStore = useIngressStore(); - const podStore = usePodStore(); - const secretStore = useSecretStore(); - const serviceStore = useServiceStore(); - const statefulSetStore = useStatefulSetStore(); - const volumeClaimStore = useVolumeClaimStore(); - - const getStore = () => { - switch (obj.kind) { - case KubeObjectKind.Bucket: - return bucketStore; - case KubeObjectKind.Cluster: - return clusterStore; - case KubeObjectKind.ConfigMap: - return configMapStore; - case KubeObjectKind.Deployment: - return deploymentStore; - case KubeObjectKind.Devbox: - case KubeObjectKind.DevboxOld: - return devboxStore; - case KubeObjectKind.Ingress: - return ingressStore; - case KubeObjectKind.Pod: - return podStore; - case KubeObjectKind.Secret: - return secretStore; - case KubeObjectKind.Service: - return serviceStore; - case KubeObjectKind.StatefulSet: - return statefulSetStore; - case KubeObjectKind.PersistentVolumeClaim: - return volumeClaimStore; - default: - return null; - } - }; - - return ( - <> - - Are you sure to delete{' '} - - {obj.kind}: {obj.getName()} - - ? - - } - icon={} - onConfirm={() => { - setConfirmLoading(true); - deleteResource(obj.kind, obj.getName()) - .then((res) => { - const store = getStore(); - if (store) { - store.remove(obj); - } - console.log('res', res); - message.success({ - content: `Successfully deleted ${res.data.kind} ${res.data.metadata.name}`, - key: msgKey, - duration: 3 - }); - }) - .catch((err) => { - const errResp = buildErrorResponse(err); - message.error({ - content: `Failed to delete ${obj.kind} ${obj.getName()}: ${errResp.error.message}`, - key: msgKey - }); - }) - .finally(() => { - setConfirmLoading(false); - }); - }} - okText="Yes" - okButtonProps={{ loading: confirmLoading }} - cancelText="No" - > - {children} - - - ); -} diff --git a/frontend/providers/kubepanel/src/components/common/action/toggle.tsx b/frontend/providers/kubepanel/src/components/common/action/toggle.tsx deleted file mode 100644 index 53436894b..000000000 --- a/frontend/providers/kubepanel/src/components/common/action/toggle.tsx +++ /dev/null @@ -1,112 +0,0 @@ -import { KubeObjectKind } from '@/constants/kube-object'; -import { - DashboardOutlined, - DatabaseOutlined, - DownOutlined, - GatewayOutlined, - SettingOutlined -} from '@ant-design/icons'; -import { Dropdown, MenuProps, Space } from 'antd'; -import { useCallback, useState } from 'react'; - -const items: MenuProps['items'] = [ - { - key: 'Workload', - label: 'Workload', - icon: , - children: [ - { - key: KubeObjectKind.Pod, - label: 'Pod' - }, - { - key: KubeObjectKind.Deployment, - label: 'Deployment' - }, - { - key: KubeObjectKind.StatefulSet, - label: 'Stateful Set' - } - ] - }, - { - key: 'Network', - label: 'Network', - icon: , - children: [ - { - key: KubeObjectKind.Ingress, - label: 'Ingress' - } - ] - }, - { - key: 'Config', - label: 'Config', - icon: , - children: [ - { - key: KubeObjectKind.ConfigMap, - label: 'Config Map' - }, - { - key: KubeObjectKind.Secret, - label: 'Secret' - } - ] - }, - { - key: 'Storage', - label: 'Storage', - icon: , - children: [ - { - key: KubeObjectKind.PersistentVolumeClaim, - label: 'Persistent Volume Claim' - } - ] - } -]; - -export type TemplateToggleChooseEventHandler = (kind: KubeObjectKind) => void; - -interface TemplateToggleProps { - onChoose: TemplateToggleChooseEventHandler; -} - -const placeholder = 'Choose a Template'; - -export function TemplateToggle({ onChoose }: TemplateToggleProps) { - const [input, setInput] = useState(placeholder); - const [hovered, setHovered] = useState(false); - - const onClick = useCallback['onClick']>( - (e) => { - setInput(e.key); - onChoose(e.key as KubeObjectKind); - }, - [setInput, onChoose] - ); - - return ( -
- setHovered(e)}> - - - {input} - - - - -
- ); -} diff --git a/frontend/providers/kubepanel/src/components/common/action/update-editor-modal.tsx b/frontend/providers/kubepanel/src/components/common/action/update-editor-modal.tsx deleted file mode 100644 index a0dbaa418..000000000 --- a/frontend/providers/kubepanel/src/components/common/action/update-editor-modal.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import { updateResource } from '@/api/kubernetes'; -import StyledEditor from '@/components/common/editor/styled'; -import Title from '@/components/common/title/title'; -import { KubeObject } from '@/k8slens/kube-object'; -import { buildErrorResponse } from '@/services/backend/response'; -import { dumpKubeObject } from '@/utils/yaml'; -import { Button, Modal, message } from 'antd'; -import { editor } from 'monaco-editor'; -import { useRef } from 'react'; - -interface Props { - obj?: K; - open: boolean; - onCancel: () => void; - onOk: () => void; -} - -export const UpdateEditorModal = ({ - obj, - open, - onCancel, - onOk -}: Props) => { - if (!obj) return null; - - const [msgApi, contextHolder] = message.useMessage(); - const msgKey = 'updatedMsg'; - const editorRef = useRef(); - - const editorValue = dumpKubeObject(obj); - - return ( - <> - {contextHolder} - - Cancel - , - - ]} - > - - {obj.kind}: {obj.getName()} - - (editorRef.current = editor)} - value={editorValue} - language="yaml" - /> - - - ); -}; diff --git a/frontend/providers/kubepanel/src/components/common/drawer/drawer-item.tsx b/frontend/providers/kubepanel/src/components/common/drawer/drawer-item.tsx deleted file mode 100644 index aae11566f..000000000 --- a/frontend/providers/kubepanel/src/components/common/drawer/drawer-item.tsx +++ /dev/null @@ -1,42 +0,0 @@ -interface DrawerItemProps { - name: React.ReactNode; - value?: React.ReactNode; - hidden?: boolean; - padding?: boolean; - className?: string; - vertical?: boolean; -} - -export const DrawerItem = ({ - name, - value, - hidden = false, - padding = true, - className = '', - vertical = false -}: DrawerItemProps) => { - if (hidden) return null; - - if (vertical) { - return ( -
- {name} -
{value}
-
- ); - } - - return ( -
- {name} -
{value}
-
- ); -}; diff --git a/frontend/providers/kubepanel/src/components/common/drawer/drawer-panel.tsx b/frontend/providers/kubepanel/src/components/common/drawer/drawer-panel.tsx deleted file mode 100644 index 14583b710..000000000 --- a/frontend/providers/kubepanel/src/components/common/drawer/drawer-panel.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { DrawerTitle } from './drawer-title'; - -interface Props { - title?: React.ReactNode; - children: React.ReactNode; -} - -export const DrawerPanel = ({ title, children }: Props) => { - return ( -
- {title && ( -
- {typeof title === 'string' ? {title} : title} -
- )} -
{children}
-
- ); -}; diff --git a/frontend/providers/kubepanel/src/components/common/drawer/drawer-title.tsx b/frontend/providers/kubepanel/src/components/common/drawer/drawer-title.tsx deleted file mode 100644 index 57cc68ae4..000000000 --- a/frontend/providers/kubepanel/src/components/common/drawer/drawer-title.tsx +++ /dev/null @@ -1,9 +0,0 @@ -interface Props { - children: React.ReactNode; -} - -export const DrawerTitle = ({ children }: Props) => { - return ( -
{children}
- ); -}; diff --git a/frontend/providers/kubepanel/src/components/common/drawer/drawer.tsx b/frontend/providers/kubepanel/src/components/common/drawer/drawer.tsx deleted file mode 100644 index c27d40a68..000000000 --- a/frontend/providers/kubepanel/src/components/common/drawer/drawer.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { CloseOutlined } from '@ant-design/icons'; -import { Drawer as AntdDrawer } from 'antd'; -interface Props { - title: string; - children: React.ReactNode; - open: boolean; - onClose: () => void; - width?: string | number; - extra?: React.ReactNode; -} -export const Drawer = ({ title, children, open, onClose, width = '550px', extra }: Props) => { - return ( - } - title={{title}} - width={width} - extra={extra} - onClose={onClose} - destroyOnHidden - > -
{children}
-
- ); -}; diff --git a/frontend/providers/kubepanel/src/components/common/editor/styled.tsx b/frontend/providers/kubepanel/src/components/common/editor/styled.tsx deleted file mode 100644 index d0d38d494..000000000 --- a/frontend/providers/kubepanel/src/components/common/editor/styled.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import { monacoTheme } from '@/constants/theme'; -import { EditorProps } from '@monaco-editor/react'; -import { Spin } from 'antd'; -import dynamic from 'next/dynamic'; -import { useEffect } from 'react'; - -const Editor = dynamic( - () => import('@monaco-editor/react').then((mod) => ({ default: mod.Editor })), - { - ssr: false, - loading: () => ( -
- -
- ) - } -); - -interface StyledEditorProps extends EditorProps { - wrapperClassName?: string; -} - -export default function StyledEditor({ wrapperClassName = '', ...props }: StyledEditorProps) { - useEffect(() => { - if (typeof window !== 'undefined') { - import('monaco-editor').then((monaco) => { - try { - monaco.editor.defineTheme('kubepanel', monacoTheme); - } catch (e) { - console.warn('Failed to define Monaco theme:', e); - } - }); - } - }, []); - - return ( -
- } - options={{ - minimap: { enabled: false }, // Hide minimap - scrollBeyondLastLine: false, // Remove whitespace at bottom - scrollbar: { - useShadows: false, - vertical: 'auto' - }, - ...props.options // Allow overrides - }} - {...props} - /> -
- ); -} diff --git a/frontend/providers/kubepanel/src/components/common/panel-table/pagination.tsx b/frontend/providers/kubepanel/src/components/common/panel-table/pagination.tsx deleted file mode 100644 index 570633576..000000000 --- a/frontend/providers/kubepanel/src/components/common/panel-table/pagination.tsx +++ /dev/null @@ -1,121 +0,0 @@ -import { LeftOutlined, RightOutlined } from '@ant-design/icons'; -import { useMemo, useState } from 'react'; - -interface SwitchButtonProps { - onClick?: () => void; - disabled: boolean; - icon: React.ReactNode; -} - -const SwitchButton = ({ onClick, disabled, icon }: SwitchButtonProps) => { - const baseClass = - 'flex items-center justify-center w-8 h-8 rounded-md transition-colors duration-200 border border-[#E8E8E8] bg-white'; - const stateClass = disabled - ? 'cursor-not-allowed text-gray-300 bg-gray-50 border-gray-100' // Disabled: lighter grey, no border - : 'cursor-pointer text-gray-600 hover:text-[#1890FF] hover:border-[#1890FF] hover:bg-[#E6F7FF]'; // Active: Blue hover - - return ( - - ); -}; - -export const PanelPagination = ({ - total, - current, - pageSize, - onChange -}: { - total: number; - current: number; - pageSize: number; - onChange: (page: number) => void; -}) => { - const totalPage = Math.ceil(total / pageSize); - const [inputVal, setInputVal] = useState(current.toString()); - - // Sync input with external current page change - useMemo(() => { - setInputVal(current.toString()); - }, [current]); - - const handleValuesChange = (e: React.ChangeEvent) => { - const val = e.target.value; - if (/^\d*$/.test(val)) { - setInputVal(val); - } - }; - - const handleKeyDown = (e: React.KeyboardEvent) => { - if (e.key === 'Enter') { - let val = parseInt(inputVal); - if (isNaN(val) || val < 1) val = 1; - if (val > totalPage) val = totalPage; - onChange(val); - setInputVal(val.toString()); - } - }; - - const handleBlur = () => { - let val = parseInt(inputVal); - if (isNaN(val) || val < 1) val = 1; - if (val > totalPage) val = totalPage; - // Only trigger change if different (optional, but good for UX) - if (val !== current) { - onChange(val); - } - setInputVal(val.toString()); - }; - - const isFirst = current === 1; - const isLast = current === totalPage; - - return ( -
- {/* Total Items Text */} - Total Items: {total} - -
- {/* Previous Button */} - } - onClick={() => onChange(current - 1)} - disabled={isFirst} - /> - - {/* Pager Block: Input / Total */} -
- - / - {/* THE REQUESTED DOM STRUCTURE FOR "2" */} - {totalPage} -
- - {/* Next Button */} - } - onClick={() => onChange(current + 1)} - disabled={isLast} - /> -
-
- ); -}; diff --git a/frontend/providers/kubepanel/src/components/common/panel-table/search-filter.tsx b/frontend/providers/kubepanel/src/components/common/panel-table/search-filter.tsx deleted file mode 100644 index c3d97f947..000000000 --- a/frontend/providers/kubepanel/src/components/common/panel-table/search-filter.tsx +++ /dev/null @@ -1,104 +0,0 @@ -import { SearchOutlined } from '@ant-design/icons'; -import { Input, InputRef } from 'antd'; -import { ColumnType } from 'antd/lib/table'; -import { useCallback, useEffect, useRef, useState } from 'react'; - -interface SearchFilterPanelProps { - onSearched: (value: string) => void; - visible: boolean; -} - -function SearchFilterPanel({ onSearched, visible }: SearchFilterPanelProps) { - const searchInput = useRef(null); - const [searchText, setSearchText] = useState(''); - - useEffect(() => { - if (visible) { - setTimeout(() => searchInput.current?.focus(), 100); - } - }, [visible]); - - return ( -
- } - allowClear - onChange={(e) => { - onSearched(e.target.value); - setSearchText(e.target.value); - }} - value={searchText} - /> -
- ); -} - -interface HighlightNameProps { - name: string; - highlight: string; - enable?: boolean; -} - -function HighlightName({ name, highlight, enable = true }: HighlightNameProps) { - if (!enable) { - return <>{name}; - } - - const begin_idx = name.toLocaleLowerCase().indexOf(highlight.toLocaleLowerCase()); - if (begin_idx === -1) { - return <>{name}; - } - - const end_idx = begin_idx + highlight.length; - const begin = name.slice(0, begin_idx); - const middle = name.slice(begin_idx, end_idx); - const end = name.slice(end_idx); - - return ( - <> - {begin} - {middle} - {end} - - ); -} - -export function useSearchNameFilterProps( - getName: (value: any, data: DataType) => string -): ColumnType & { searchText: string; filterFn: (record: DataType) => boolean } { - const [searchText, setSearchText] = useState(''); - const [searched, setSearched] = useState(false); - const [visible, setVisible] = useState(false); - - const filterFn = useCallback( - (record: DataType) => { - if (!searchText) return true; - return getName(null, record).toLocaleLowerCase().includes(searchText.toLocaleLowerCase()); - }, - [searchText, getName] - ); - - return { - filterDropdown({ setSelectedKeys, confirm }) { - return ( - { - setSelectedKeys([value]); - setSearchText(value); - setSearched(true); - confirm({ closeDropdown: false }); - }} - visible={visible} - /> - ); - }, - onFilterDropdownOpenChange: (visible) => setVisible(visible), - render: (value, data) => ( - - ), - searchText, - filterFn - }; -} diff --git a/frontend/providers/kubepanel/src/components/common/panel-table/table.tsx b/frontend/providers/kubepanel/src/components/common/panel-table/table.tsx deleted file mode 100644 index a72992de2..000000000 --- a/frontend/providers/kubepanel/src/components/common/panel-table/table.tsx +++ /dev/null @@ -1,121 +0,0 @@ -import { Section } from '@/components/common/section/section'; -import Title from '@/components/common/title/title'; -import { useWatcher } from '@/hooks/useWatcher'; -import { KubeObject } from '@/k8slens/kube-object'; -import { KubeStoreAction } from '@/types/state'; -import { Table, TableProps } from 'antd'; -import { useEffect, useMemo, useState } from 'react'; -import { PanelPagination } from './pagination'; -import { useSearchNameFilterProps } from './search-filter'; - -type DefaultRecordType = Record; - -export interface DetailDrawerProps { - open: boolean; - obj: T | null; - onClose: () => void; -} - -interface Props extends Omit, 'title'> { - sectionTitle: string; - getRowKey: (record: RecordType) => string; - getDetailItem: (record: RecordType) => Item; - initializers: Array['initialize']>; - DetailDrawer: (props: DetailDrawerProps) => JSX.Element | null; -} - -export const PanelTable = ( - tableProps: Props -) => { - const { - scroll = { x: true }, - sectionTitle: title, - columns = [], - DetailDrawer, - getRowKey, - getDetailItem, - initializers - } = tableProps; - - const [selectedItem, setSelectedItem] = useState(null); - const [openDetail, setOpenDetail] = useState(false); - const [currentPage, setCurrentPage] = useState(1); - const PAGE_SIZE = 15; - - const cxtHolder = useWatcher({ initializers }); - const searchNameFilterProps = useSearchNameFilterProps((_, record) => - getDetailItem(record).getName() - ); - - const dataSource = useMemo(() => tableProps.dataSource || [], [tableProps.dataSource]); - - // Apply filter based on searchText - const filteredData = useMemo(() => { - return dataSource.filter(searchNameFilterProps.filterFn); - }, [dataSource, searchNameFilterProps.filterFn]); - - const total = filteredData.length; - - // Reset to page 1 when search text changes - useEffect(() => { - setCurrentPage(1); - }, [searchNameFilterProps.searchText]); - - // Calculate current page data after filtering - const currentData = useMemo(() => { - const start = (currentPage - 1) * PAGE_SIZE; - const end = start + PAGE_SIZE; - return filteredData.slice(start, end); - }, [filteredData, currentPage]); - - const modifiedCols = useMemo(() => { - const { searchText, filterFn, ...filterProps } = searchNameFilterProps; - return [ - { - title: 'Name', - key: 'name', - className: 'min-w-[150px]', - ellipsis: true, - filteredValue: searchText ? [searchText] : [], - ...filterProps - }, - ...columns - ]; - }, [columns, searchNameFilterProps]); - - return ( -
- {cxtHolder} - {title} - ({ - onClick: () => { - setSelectedItem(getDetailItem(record)); - setOpenDetail(true); - } - })} - /> - {total > 0 && ( - setCurrentPage(page)} - /> - )} - {/* nextjs prerender fix */} - {DetailDrawer && ( - setOpenDetail(false)} /> - )} - - ); -}; diff --git a/frontend/providers/kubepanel/src/components/common/section/section.tsx b/frontend/providers/kubepanel/src/components/common/section/section.tsx deleted file mode 100644 index ad79a3800..000000000 --- a/frontend/providers/kubepanel/src/components/common/section/section.tsx +++ /dev/null @@ -1,17 +0,0 @@ -interface SectionProps { - children: React.ReactNode; -} - -/** - * Renders a section component with the provided children. - * - * @param {SectionProps} children - The children to render within the section. - * @return {JSX.Element} The rendered section component. - */ -export function Section({ children }: SectionProps) { - return ( -
- {children} -
- ); -} diff --git a/frontend/providers/kubepanel/src/components/common/sidebar/sidebar.tsx b/frontend/providers/kubepanel/src/components/common/sidebar/sidebar.tsx deleted file mode 100644 index a444300de..000000000 --- a/frontend/providers/kubepanel/src/components/common/sidebar/sidebar.tsx +++ /dev/null @@ -1,108 +0,0 @@ -import { - AppstoreOutlined, - DashboardOutlined, - DatabaseOutlined, - GatewayOutlined, - ReloadOutlined, - SettingOutlined -} from '@ant-design/icons'; -import { Button, Flex, Menu, MenuProps } from 'antd'; -import { useRouter } from 'next/router'; - -type MenuItem = Required['items'][number]; - -export enum SideNavItemKey { - Overview = 'overview', - Pod = 'pod', - Deployment = 'deployment', - ConfigMap = 'config-map', - PersistentVolumeClaim = 'volume-claim', - StatefulSet = 'stateful-set', - Secret = 'secret', - Ingress = 'ingress', - Service = 'service', - // CustomResource - Devbox = 'devbox', - Cluster = 'cluster', - Bucket = 'bucket' -} - -function getItem( - label: React.ReactNode, - key: React.Key, - icon?: React.ReactNode, - children?: MenuItem[], - type?: 'group' -): MenuItem { - return { - key, - icon, - children, - label, - type - } as MenuItem; -} - -const items: MenuProps['items'] = [ - getItem('Workload', 'workload', , [ - getItem('Overview', SideNavItemKey.Overview), - getItem('Pods', SideNavItemKey.Pod), - getItem('Deployments', SideNavItemKey.Deployment), - getItem('Stateful Sets', SideNavItemKey.StatefulSet) - ]), - getItem('Config', 'config', , [ - getItem('Config Maps', SideNavItemKey.ConfigMap), - getItem('Secrets', SideNavItemKey.Secret) - ]), - getItem('Network', 'network', , [ - getItem('Ingress', SideNavItemKey.Ingress), - getItem('Service', SideNavItemKey.Service) - ]), - getItem('Storage', 'storage', , [ - getItem('Persistent Volume Claims', SideNavItemKey.PersistentVolumeClaim) - ]), - getItem('CustomResource', 'custom-resource', , [ - getItem('Devbox', SideNavItemKey.Devbox), - getItem('Cluster', SideNavItemKey.Cluster), - getItem('Bucket', SideNavItemKey.Bucket) - ]) -]; - -interface Props { - onClick?: (key: SideNavItemKey) => void; - selectedKey?: SideNavItemKey; -} - -export const ResourceSideNav = ({ - onClick = () => {}, - selectedKey = SideNavItemKey.Overview -}: Props) => { - const router = useRouter(); - - return ( - -
-
-
- KubePanel -
-
-
- onClick(key as SideNavItemKey)} - /> - - ); -}; diff --git a/frontend/providers/kubepanel/src/components/common/status-tag.tsx b/frontend/providers/kubepanel/src/components/common/status-tag.tsx deleted file mode 100644 index 7a227e69e..000000000 --- a/frontend/providers/kubepanel/src/components/common/status-tag.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { Tag } from 'antd'; -import React from 'react'; - -// Fix for "Tag cannot be used as a JSX component" lint error -const AnyTag = Tag as any; - -interface StatusTagProps { - color?: string; - children: React.ReactNode; -} - -export const StatusTag = ({ color, children }: StatusTagProps) => { - return {children}; -}; diff --git a/frontend/providers/kubepanel/src/components/common/title/title.tsx b/frontend/providers/kubepanel/src/components/common/title/title.tsx deleted file mode 100644 index 3e04daa98..000000000 --- a/frontend/providers/kubepanel/src/components/common/title/title.tsx +++ /dev/null @@ -1,27 +0,0 @@ -interface PageTitleProps { - children: string | string[]; - className?: string; - type: 'primary' | 'secondary' | 'table'; -} - -const titleClassName: Record = { - primary: 'text-2xl font-medium', - secondary: 'text-xl font-medium', - table: 'text-xs font-medium text-gray-500' -}; - -/** - * Renders a title component with the specified type and children. - * - * @param {PageTitleProps} props - The properties of the title component. - * @param {ReactNode} props.children - The content of the title component. - * @param {string} props.type - The type of the title component. - * @return {JSX.Element} The rendered title component. - */ -export default function Title({ children, type, className }: PageTitleProps) { - return ( -
- {children} -
- ); -} diff --git a/frontend/providers/kubepanel/src/components/kube/kube-badge.tsx b/frontend/providers/kubepanel/src/components/kube/kube-badge.tsx deleted file mode 100644 index 5e17fd77f..000000000 --- a/frontend/providers/kubepanel/src/components/kube/kube-badge.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import { useEffect, useRef, useState } from 'react'; - -interface KubeBadgeProps { - label: React.ReactNode; - expandedLabel?: React.ReactNode; - disabled?: boolean; - expandable?: boolean; - color?: { textColor?: string; backgroundColor?: string }; -} - -export const KubeBadge = ({ - label, - expandedLabel, - expandable = true, - color, - disabled = false, - className -}: KubeBadgeProps & { className?: string }) => { - const spanRef = useRef(null); - const [isExpanded, setIsExpanded] = useState(false); - const [isExpandable, setIsExpandable] = useState(false); - - useEffect(() => { - const checkExpandable = () => { - if (spanRef.current) { - const { offsetWidth = 0, scrollWidth = 0 } = spanRef.current; - setIsExpandable((expandable && offsetWidth < scrollWidth) || !!expandedLabel); - } - }; - - checkExpandable(); - // 添加延迟检查以确保渲染完成 - const timer = setTimeout(checkExpandable, 100); - return () => clearTimeout(timer); - }, [expandable, expandedLabel, label]); - - const onClick = (e: React.MouseEvent) => { - if (isExpandable) { - setIsExpanded(!isExpanded); - } - e.stopPropagation(); - }; - - const { textColor, backgroundColor } = color ?? {}; - const disabledClass = disabled && 'opacity-50 cursor-not-allowed'; - const expandableClass = isExpandable && 'cursor-pointer'; - const bgColorClass = backgroundColor ? `bg-${backgroundColor}` : 'bg-[#FDFDFD]'; - - return ( -
- - {isExpanded && expandedLabel ? expandedLabel : label} - -
- ); -}; diff --git a/frontend/providers/kubepanel/src/components/kube/local-date.tsx b/frontend/providers/kubepanel/src/components/kube/local-date.tsx deleted file mode 100644 index dfc5514a6..000000000 --- a/frontend/providers/kubepanel/src/components/kube/local-date.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import moment from 'moment-timezone'; - -export type LocaleDateProps = { - date: string; - localeTimezone: string; -}; - -export const LocaleDate = ({ date, localeTimezone }: LocaleDateProps) => ( - <>{`${moment.tz(date, localeTimezone).format()}`} -); diff --git a/frontend/providers/kubepanel/src/components/kube/object/detail/kube-object-detail-info-list.tsx b/frontend/providers/kubepanel/src/components/kube/object/detail/kube-object-detail-info-list.tsx deleted file mode 100644 index 77d8d9a5c..000000000 --- a/frontend/providers/kubepanel/src/components/kube/object/detail/kube-object-detail-info-list.tsx +++ /dev/null @@ -1,169 +0,0 @@ -import { DrawerItem } from '@/components/common/drawer/drawer-item'; -import { KubeObject } from '@/k8slens/kube-object'; -import { getKubeObjectInfo } from '@/utils/kube-object-info'; -import { getStatusTextTone } from '@/utils/status-color'; -import { Box } from '@chakra-ui/react'; -import { Divider } from 'antd'; -import { KubeBadge } from '../../kube-badge'; -import { KubeObjectAge } from '../kube-object-age'; - -interface Props { - obj: KubeObject; -} - -export const KubeObjectInfoList = ({ obj }: Props) => { - const { - creationTimestamp, - name, - uid, - resourceVersion, - labels, - annotations, - finalizers, - ownerRefs - } = getKubeObjectInfo(obj); - - return ( - <> -
-
-
- Name - {name} -
-
- Created - - - -
-
- Status - - {(() => { - const status = - (obj as any).getStatusMessage?.() || - (obj as any).getStatus?.() || - (obj as any).status?.phase || - '-'; - const textTone = getStatusTextTone(status); - const colorClass = - textTone === 'success' - ? 'text-green-600' - : textTone === 'warning' - ? 'text-yellow-600' - : textTone === 'danger' - ? 'text-red-600' - : 'text-[#262626]'; - return {status}; - })()} - -
-
- {uid}} /> - {finalizers.length > 0 && ( - - {finalizers.map((label) => ( - - ))} -
- } - /> - )} - {ownerRefs.length > 0 && ( - ( - - {kind}{' '} - - {name} - - - ))} - /> - )} - - - {(labels.length > 0 || annotations.length > 0) && ( -
- {labels.length > 0 && ( - - {[...labels].sort().map((label) => { - const sepIndex = label.indexOf(': '); - if (sepIndex === -1) - return ; - const key = label.slice(0, sepIndex); - const value = label.slice(sepIndex + 2); - return ( - - {key} - : - {value} - - } - className="m-0!" - /> - ); - })} -
- } - /> - )} - {annotations.length > 0 && ( - - {[...annotations].sort().map((label) => { - if (label.startsWith('kubectl.kubernetes.io/last-applied-configuration')) { - return ( - - ); - } - const sepIndex = label.indexOf(': '); - if (sepIndex === -1) - return ; - const key = label.slice(0, sepIndex); - const value = label.slice(sepIndex + 2); - - return ( - - {key} - : - {value} - - } - className="m-0!" - /> - ); - })} - - } - /> - )} - - )} - <>{(labels.length > 0 || annotations.length > 0) && } - - ); -}; diff --git a/frontend/providers/kubepanel/src/components/kube/object/kube-object-affinities.tsx b/frontend/providers/kubepanel/src/components/kube/object/kube-object-affinities.tsx deleted file mode 100644 index fb535c7b9..000000000 --- a/frontend/providers/kubepanel/src/components/kube/object/kube-object-affinities.tsx +++ /dev/null @@ -1,246 +0,0 @@ -import { - Affinity, - LabelMatchExpression, - LabelSelector, - NodeAffinity, - PodAffinity, - SpecificAffinity -} from '@/k8slens/kube-object'; -import React from 'react'; - -interface Props { - affinity: Affinity; -} - -// --- Helper: Render a single LabelMatchExpression as natural language --- -const renderExpression = (expr: LabelMatchExpression): string => { - const { key, operator, values } = expr; - switch (operator) { - case 'In': - return `${key} in [${values?.join(', ') || ''}]`; - case 'NotIn': - return `${key} not in [${values?.join(', ') || ''}]`; - case 'Exists': - return `${key} exists`; - case 'DoesNotExist': - return `${key} does not exist`; - default: - return `${key} ${operator} ${(values as string[] | undefined)?.join(', ') || ''}`; - } -}; - -// --- Helper: Render LabelSelector as badges --- -const SelectorBadges = ({ selector }: { selector?: LabelSelector }) => { - if (!selector) return null; - - const labels = selector.matchLabels ? Object.entries(selector.matchLabels) : []; - const expressions = selector.matchExpressions || []; - - if (labels.length === 0 && expressions.length === 0) return null; - - return ( -
- {labels.map(([k, v]) => ( - - {k} - : - {v} - - ))} - {expressions.map((expr, i) => ( - - {renderExpression(expr)} - - ))} -
- ); -}; - -// --- NodeAffinity Rendering --- -const NodeAffinityCard = ({ affinity }: { affinity: SpecificAffinity }) => { - const required = - (affinity.requiredDuringSchedulingIgnoredDuringExecution as any)?.nodeSelectorTerms || []; - const preferred = affinity.preferredDuringSchedulingIgnoredDuringExecution || []; - - if (required.length === 0 && preferred.length === 0) return null; - - return ( -
-
Node Affinity
- {required.map((term: any, i: number) => ( -
- - Required - - : - node - {term.matchExpressions?.map((expr: any, k: number) => ( -
- {k > 0 && and} - {expr.key} - {expr.operator.toLowerCase()} - {expr.values && ( - - [{expr.values.join(', ')}] - - )} -
- ))} - {term.matchFields?.map((expr: any, k: number) => ( -
- {(k > 0 || (term.matchExpressions?.length ?? 0) > 0) && ( - and - )} - {expr.key} - {expr.operator.toLowerCase()} - {expr.values && ( - - [{expr.values.join(', ')}] - - )} -
- ))} -
- ))} - - {preferred.map((pref: any, i: number) => ( -
- - Preferred - - (weight: {pref.weight}) - : - node - {pref.preference?.matchExpressions?.map((expr: any, j: number) => ( -
- {j > 0 && and} - {expr.key} - {expr.operator.toLowerCase()} - {expr.values && ( - - [{expr.values.join(', ')}] - - )} -
- ))} -
- ))} -
- ); -}; - -// --- PodAffinity / PodAntiAffinity Rendering --- -const PodAffinityCard = ({ - title, - affinity -}: { - title: string; - affinity: SpecificAffinity; -}) => { - const isAnti = title.includes('Anti'); - const required = affinity.requiredDuringSchedulingIgnoredDuringExecution; - const preferred = affinity.preferredDuringSchedulingIgnoredDuringExecution; - - const hasRequired = (required?.length || 0) > 0; - const hasPreferred = (preferred?.length || 0) > 0; - - if (!hasRequired && !hasPreferred) return null; - - const actionText = isAnti ? 'Avoid pods' : 'Run with pods'; - - const renderSelector = (selector?: LabelSelector) => { - if (!selector) return any; - const parts: React.ReactNode[] = []; - if (selector.matchLabels) { - Object.entries(selector.matchLabels).forEach(([k, v]) => { - parts.push( - - {k}={v} - - ); - }); - } - if (selector.matchExpressions) { - selector.matchExpressions.forEach((expr, i) => { - parts.push( - - {expr.key} {expr.operator.toLowerCase()}{' '} - {expr.values ? `[${expr.values.join(', ')}]` : ''} - - ); - }); - } - if (parts.length === 0) return any; - return ( - - {parts.map((p, i) => ( - - {i > 0 && ,} - {p} - - ))} - - ); - }; - - return ( -
-
{title}
- {required?.map((term, i) => ( -
- - Required - - : - {actionText.toLowerCase()} - {renderSelector(term.labelSelector)} - in - {term.topologyKey} - {(term as any).namespaces && ( - - (ns: {(term as any).namespaces.join(', ')}) - - )} -
- ))} - - {preferred?.map((pref, i) => { - const weight = (pref as any).weight; - const term = (pref as any).podAffinityTerm || pref; - - return ( -
- - Preferred - - (weight: {weight}) - : - {actionText.toLowerCase()} - {renderSelector(term.labelSelector)} - in - {term.topologyKey} -
- ); - })} -
- ); -}; - -// --- Main Component --- -export const KubeObjectAffinities = ({ affinity }: Props) => { - const { nodeAffinity, podAffinity, podAntiAffinity } = affinity; - - return ( -
- {nodeAffinity && } - {podAffinity && } - {podAntiAffinity && } -
- ); -}; diff --git a/frontend/providers/kubepanel/src/components/kube/object/kube-object-age.tsx b/frontend/providers/kubepanel/src/components/kube/object/kube-object-age.tsx deleted file mode 100644 index a9c1d6d6b..000000000 --- a/frontend/providers/kubepanel/src/components/kube/object/kube-object-age.tsx +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import { ReactiveDuration } from '../reactive-duration'; - -export interface KubeObjectAgeProps { - obj: { - metadata: { - creationTimestamp?: string; - }; - }; - - /** - * Whether the display string should prefer length over precision - * @default true - */ - compact?: boolean; -} - -export const KubeObjectAge = ({ obj, compact = true }: KubeObjectAgeProps) => ( - -); diff --git a/frontend/providers/kubepanel/src/components/kube/object/kube-object-tolerations.tsx b/frontend/providers/kubepanel/src/components/kube/object/kube-object-tolerations.tsx deleted file mode 100644 index 62d324f76..000000000 --- a/frontend/providers/kubepanel/src/components/kube/object/kube-object-tolerations.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { Toleration } from '@/k8slens/kube-object'; - -interface Props { - tolerations: Array; -} - -export const KubeObjectTolerations = ({ tolerations }: Props) => { - return ( -
- {tolerations.map((toleration, index) => { - const op = (toleration.operator || 'Equal').toLowerCase(); - return ( -
- when - - {toleration.key || 'all keys'} - - {op === 'exists' ? 'exists' : 'equals'} - {op !== 'exists' && ( - - {toleration.value !== undefined ? toleration.value : '""'} - - )} - : - {toleration.effect ? ( - - {toleration.effect} - - ) : ( - - All effects - - )} - {typeof toleration.tolerationSeconds === 'number' && ( - ({toleration.tolerationSeconds}s) - )} -
- ); - })} -
- ); -}; diff --git a/frontend/providers/kubepanel/src/components/kube/object/responsive-key-list.tsx b/frontend/providers/kubepanel/src/components/kube/object/responsive-key-list.tsx deleted file mode 100644 index a34a7142a..000000000 --- a/frontend/providers/kubepanel/src/components/kube/object/responsive-key-list.tsx +++ /dev/null @@ -1,83 +0,0 @@ -import { Tag, Tooltip } from 'antd'; -import { useEffect, useRef, useState } from 'react'; - -export const ResponsiveKeyList = ({ keys }: { keys: string[] }) => { - const containerRef = useRef(null); - const [visibleCount, setVisibleCount] = useState(3); - const [containerWidth, setContainerWidth] = useState(0); - - useEffect(() => { - if (!containerRef.current) return; - const observer = new ResizeObserver((entries) => { - for (const entry of entries) { - setContainerWidth(entry.contentRect.width); - } - }); - observer.observe(containerRef.current); - return () => observer.disconnect(); - }, []); - - useEffect(() => { - if (containerWidth === 0) return; - let currentWidth = 0; - let count = 0; - const GAP = 4; - const OVERFLOW_TAG_WIDTH = 45; // Width for +99 tag - const TAG_PADDING = 16; - const CHAR_WIDTH = 7.5; // Approx width for standard font - - for (let i = 0; i < keys.length; i++) { - const key = keys[i]; - if (!key) continue; - const keyWidth = key.length * CHAR_WIDTH + TAG_PADDING; - - // If this is the last item and it fits, good. - // If not last, we need to check if it fits ALONG with the overflow tag space - if (i === keys.length - 1) { - if (currentWidth + keyWidth <= containerWidth) { - count++; - } - } else { - // Check if adding this key + potential overflow tag fits - if (currentWidth + keyWidth + GAP + OVERFLOW_TAG_WIDTH <= containerWidth) { - currentWidth += keyWidth + GAP; - count++; - } else { - break; - } - } - } - // Always show at least 1 if possible, or 0 if width is tiny - setVisibleCount(Math.max(1, count)); - }, [containerWidth, keys]); - - if (keys.length === 0) return <>-; - - const visibleKeys = keys.slice(0, visibleCount); - const hiddenKeys = keys.slice(visibleCount); - - return ( -
- {visibleKeys.map((key) => ( - - {key} - - ))} - {hiddenKeys.length > 0 && ( - - {hiddenKeys.map((key) => ( - {key} - ))} -
- } - > - - +{hiddenKeys.length} - - - )} - - ); -}; diff --git a/frontend/providers/kubepanel/src/components/kube/reactive-duration.tsx b/frontend/providers/kubepanel/src/components/kube/reactive-duration.tsx deleted file mode 100644 index c7588120f..000000000 --- a/frontend/providers/kubepanel/src/components/kube/reactive-duration.tsx +++ /dev/null @@ -1,67 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import { formatDuration } from '@/k8slens/utilities'; -import { useEffect, useState } from 'react'; - -export interface ReactiveDurationProps { - timestamp: string | undefined; - - /** - * Whether the display string should prefer length over precision - * @default true - */ - compact?: boolean; -} - -const everySecond = 1000; -const everyMinute = 60 * 1000; - -/** - * This function computes a reasonable update interval, matching `formatDuration`'s rules on when to display seconds - */ -function computeUpdateInterval(creationTimestampEpoch: number, compact: boolean): number { - const seconds = Math.floor((Date.now() - creationTimestampEpoch) / 1000); - const minutes = Math.floor(seconds / 60); - - if (minutes < 10) { - return everySecond; - } - - if (compact) { - return everyMinute; - } - - if (minutes < 60 * 3) { - return everySecond; - } - - return everyMinute; -} - -export const ReactiveDuration = ({ timestamp, compact = true }: ReactiveDurationProps) => { - if (!timestamp) { - return <><unknown>; - } - const timestampSeconds = new Date(timestamp).getTime(); - - const [duration, setDuration] = useState(Date.now() - timestampSeconds); - const [ms, setMs] = useState(computeUpdateInterval(timestampSeconds, compact)); - - useEffect(() => { - const interval = setInterval(() => { - const nextMs = computeUpdateInterval(timestampSeconds, compact); - if (ms !== nextMs) { - setMs(computeUpdateInterval(timestampSeconds, compact)); - clearInterval(interval); - } - setDuration(Date.now() - timestampSeconds); - }, ms); - - return () => clearInterval(interval); - }, [compact, ms, timestampSeconds]); - - return {formatDuration(duration, compact)}; -}; diff --git a/frontend/providers/kubepanel/src/components/kubepanel-views/config/config-map/config-map-detail.tsx b/frontend/providers/kubepanel/src/components/kubepanel-views/config/config-map/config-map-detail.tsx deleted file mode 100644 index cf714cd92..000000000 --- a/frontend/providers/kubepanel/src/components/kubepanel-views/config/config-map/config-map-detail.tsx +++ /dev/null @@ -1,195 +0,0 @@ -import { updateResource } from '@/api/kubernetes'; -import { Drawer } from '@/components/common/drawer/drawer'; -import { DrawerPanel } from '@/components/common/drawer/drawer-panel'; -import { KubeObjectInfoList } from '@/components/kube/object/detail/kube-object-detail-info-list'; -import { ConfigMap } from '@/k8slens/kube-object'; -import { useConfigMapStore } from '@/store/kube'; -import { dumpKubeObject } from '@/utils/yaml'; -import { CloseOutlined, EditOutlined, SaveOutlined } from '@ant-design/icons'; -import { Button, Input } from 'antd'; -import useMessage from 'antd/lib/message/useMessage'; -import { entries, isEqual } from 'lodash'; -import React from 'react'; - -const ConfigMapDetail = ({ obj: configMap, open, onClose }: DetailDrawerProps) => { - if (!configMap || !(configMap instanceof ConfigMap)) { - return null; - } - - const [isEditing, setIsEditing] = React.useState(false); - const [isSaving, setIsSaving] = React.useState(false); - const [msgApi, contextHolder] = useMessage(); - const { initialize } = useConfigMapStore(); - - const originalData = React.useMemo(() => { - const map: Record = {}; - entries(configMap.data).forEach(([key, val]) => { - map[key] = val ?? ''; - }); - return map; - }, [configMap.data]); - - const [formValues, setFormValues] = React.useState>(originalData); - - React.useEffect(() => { - setFormValues(originalData); - }, [originalData]); - - // Reset editing state when drawer closes or ConfigMap changes - React.useEffect(() => { - if (!open) { - setIsEditing(false); - } - }, [open]); - - const id = configMap?.getId(); - React.useEffect(() => { - setIsEditing(false); - }, [id]); - - const data = Array.from(entries(formValues)); - const simpleData = data.filter(([_, val]) => !val?.includes('\n') && (val?.length || 0) < 50); - const complexData = data.filter(([_, val]) => val?.includes('\n') || (val?.length || 0) >= 50); - - const isModified = !isEqual(originalData, formValues); - - const handleSave = () => { - setIsSaving(true); - updateResource( - configMap.kind, - configMap.getName(), - dumpKubeObject({ - ...configMap, - data: formValues - }) - ) - .then(() => { - msgApi.success('Saved'); - initialize(() => {}, true); - setIsEditing(false); - }) - .catch((err) => { - msgApi.error(err?.message || 'Save failed'); - }) - .finally(() => setIsSaving(false)); - }; - - return ( - -
- - - - - {data.length > 0 && ( -
- {contextHolder} -
-
Data
-
- {!isEditing && ( - - )} - {isEditing && ( - <> - - - - )} -
-
- - {simpleData.length > 0 && ( -
-
Entries
-
- {simpleData.map(([name, value]) => { - const isLong = name.length >= 30 || (value?.length || 0) >= 30; - return ( -
- {name} - {isEditing ? ( - - setFormValues((prev) => ({ ...prev, [name]: e.target.value })) - } - /> - ) : ( -
- - {value} - -
- )} -
- ); - })} -
-
- )} - - {complexData.length > 0 && ( -
-
Files
-
- {complexData.map(([name, value = '']) => ( -
-
{name}
- {isEditing ? ( - - setFormValues((prev) => ({ ...prev, [name]: e.target.value })) - } - /> - ) : ( -
-                          {value}
-                        
- )} -
- ))} -
-
- )} -
- )} -
-
- ); -}; - -export default ConfigMapDetail; diff --git a/frontend/providers/kubepanel/src/components/kubepanel-views/config/config-map/config-map.tsx b/frontend/providers/kubepanel/src/components/kubepanel-views/config/config-map/config-map.tsx deleted file mode 100644 index d0d047acc..000000000 --- a/frontend/providers/kubepanel/src/components/kubepanel-views/config/config-map/config-map.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { ActionButton } from '@/components/common/action/action-button'; -import { PanelTable } from '@/components/common/panel-table/table'; -import { KubeObjectAge } from '@/components/kube/object/kube-object-age'; -import { ResponsiveKeyList } from '@/components/kube/object/responsive-key-list'; -import { ConfigMap } from '@/k8slens/kube-object'; -import { useConfigMapStore } from '@/store/kube'; -import { ColumnsType } from 'antd/es/table'; -import { useEffect, useRef, useState } from 'react'; -import ConfigMapDetail from './config-map-detail'; - -const columns: ColumnsType = [ - { - title: 'Keys', - key: 'keys', - render: (_, configMap) => - }, - { - title: 'Age', - key: 'age', - render: (_, configMap) => - }, - { - fixed: 'right', - key: 'action', - render: (_, configMap) => - } -]; - -const ConfigMapOverviewPage = () => { - const { items, initialize, isLoaded } = useConfigMapStore(); - - return ( - configMap.getId()} - initializers={[initialize]} - getDetailItem={(configMap) => configMap} - /> - ); -}; - -export default ConfigMapOverviewPage; diff --git a/frontend/providers/kubepanel/src/components/kubepanel-views/config/secret/secret-detail.tsx b/frontend/providers/kubepanel/src/components/kubepanel-views/config/secret/secret-detail.tsx deleted file mode 100644 index cb406c56d..000000000 --- a/frontend/providers/kubepanel/src/components/kubepanel-views/config/secret/secret-detail.tsx +++ /dev/null @@ -1,249 +0,0 @@ -import { Secret } from '@/k8slens/kube-object'; -import { useSecretStore } from '@/store/kube'; -import { DrawerPanel } from '@/components/common/drawer/drawer-panel'; -import { KubeObjectInfoList } from '@/components/kube/object/detail/kube-object-detail-info-list'; -import { Drawer } from '@/components/common/drawer/drawer'; -import React from 'react'; -import { Button, Input, Space } from 'antd'; -import { EyeInvisibleOutlined, EyeOutlined, CloseOutlined, SaveOutlined } from '@ant-design/icons'; -import { entries, isEqual } from 'lodash'; -import { dumpKubeObject } from '@/utils/yaml'; -import useMessage from 'antd/lib/message/useMessage'; -import { updateResource } from '@/api/kubernetes'; -import { buildErrorResponse } from '@/services/backend/response'; - -type RevealableInput = { - name: string; - value: string; - onChange?: (value: string) => void; -}; - -const SecretDataInput = ({ - name, - value, - onChange, - isComplex, - revealed -}: RevealableInput & { isComplex?: boolean; revealed: boolean }) => { - return ( -
- {name} - {isComplex ? ( - revealed ? ( - onChange?.(e.target.value)} - /> - ) : ( -
- Hidden content -
- ) - ) : revealed ? ( - onChange?.(e.target.value)} - visibilityToggle={{ visible: true }} - iconRender={() => null} // Hide individual toggle - /> - ) : ( - null} - /> - )} -
- ); -}; - -const SecretDataForm = ({ secret }: { secret: Secret }) => { - const [isSaving, setIsSaving] = React.useState(false); - const [isRevealed, setIsRevealed] = React.useState(false); - const [msgApi, contextHolder] = useMessage(); - const { initialize } = useSecretStore(); - - // Clean Data Map tracking - // We need state to track edits to enable/disable button - // originalData is static reference for comparison. - const originalData = React.useMemo(() => { - const map: Record = {}; - entries(secret.data).forEach(([key, val]) => { - map[key] = Buffer.from(val || '', 'base64').toString(); - }); - return map; - }, [secret.data]); - - const [formValues, setFormValues] = React.useState>(originalData); - - // Sync formValues if secret changes externally (though usually drawer remounts) - React.useEffect(() => { - setFormValues(originalData); - }, [originalData]); - - const isModified = !isEqual(originalData, formValues); - - // Process data for hybrid layout based on current form values - const processedData = React.useMemo(() => { - return entries(formValues).map(([key, val]) => { - // Treat as complex (File) if it has newlines or is very long (>100 chars) - const isComplex = val.includes('\n') || val.length > 100; - // Treat as long entry (Full width in grid) if distinctively long (>30 chars) or key is long - const isLong = val.length >= 30 || key.length >= 30; - return { key, val, isComplex, isLong }; - }); - }, [formValues]); - - const simpleData = processedData.filter((d) => !d.isComplex); - const complexData = processedData.filter((d) => d.isComplex); - - const handleSave = () => { - setIsSaving(true); - // Re-encode values - const encodedData: Record = {}; - entries(formValues).forEach(([key, val]) => { - encodedData[key] = Buffer.from(val, 'ascii').toString('base64'); - }); - - updateResource( - secret.kind, - secret.getName(), - dumpKubeObject({ - ...secret, - data: encodedData - }) - ) - .then(() => { - msgApi.success('Saved'); - initialize(() => {}, true); - // Implicitly originalData will update via parent refresh or we should wait for props update - // But for UX we just reset saving - }) - .catch((err) => { - const errResp = buildErrorResponse(err); - msgApi.error(errResp.error.message); - }) - .finally(() => { - setIsSaving(false); - }); - }; - - return ( -
- {contextHolder} - - {/* Global Data Header & Toggle */} -
-
Data
-
- {!isRevealed ? ( - - ) : ( - <> - - - - )} -
-
- - {simpleData.length > 0 && ( -
-
Entries
-
- {simpleData.map(({ key, val, isLong }) => ( -
- { - setFormValues((prev) => ({ ...prev, [key]: newValue })); - }} - /> -
- ))} -
-
- )} - - {complexData.length > 0 && ( -
-
Files
-
- {complexData.map(({ key, val }) => ( - { - setFormValues((prev) => ({ ...prev, [key]: newValue })); - }} - /> - ))} -
-
- )} - - {/* Inline buttons now moved to header; keep spacer for layout consistency if needed */} -
- ); -}; - -const SecretDetail = ({ obj: secret, open, onClose }: DetailDrawerProps) => { - if (!secret || !(secret instanceof Secret)) return null; - - const hasData = secret.data && Object.keys(secret.data).length > 0; - - return ( - -
- - - - - {hasData && ( -
- -
- )} -
-
- ); -}; - -export default SecretDetail; diff --git a/frontend/providers/kubepanel/src/components/kubepanel-views/config/secret/secret.tsx b/frontend/providers/kubepanel/src/components/kubepanel-views/config/secret/secret.tsx deleted file mode 100644 index eb14f0b3a..000000000 --- a/frontend/providers/kubepanel/src/components/kubepanel-views/config/secret/secret.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import { KubeObjectAge } from '@/components/kube/object/kube-object-age'; -import { Secret } from '@/k8slens/kube-object'; -import { ColumnsType } from 'antd/lib/table'; -import { useSecretStore } from '@/store/kube'; -import SecretDetail from './secret-detail'; -import { ResponsiveKeyList } from '@/components/kube/object/responsive-key-list'; -import { PanelTable } from '@/components/common/panel-table/table'; -import { ActionButton } from '@/components/common/action/action-button'; - -const columns: ColumnsType = [ - { - title: 'Keys', - key: 'keys', - render: (_, secret) => - }, - { - title: 'Type', - key: 'type', - dataIndex: 'type', - width: 250 // Keeping Type explicit width as it's usually short but important - }, - { - title: 'Age', - key: 'age', - render: (_, secret) => - }, - { - fixed: 'right', - key: 'action', - render: (_, secret) => - } -]; - -const SecretOverviewPage = () => { - const { items, initialize, isLoaded } = useSecretStore(); - - return ( - secret.getId()} - initializers={[initialize]} - getDetailItem={(secret) => secret} - /> - ); -}; - -export default SecretOverviewPage; diff --git a/frontend/providers/kubepanel/src/components/kubepanel-views/custom-resource/bucket/bucket-detail.tsx b/frontend/providers/kubepanel/src/components/kubepanel-views/custom-resource/bucket/bucket-detail.tsx deleted file mode 100644 index e5dee41f2..000000000 --- a/frontend/providers/kubepanel/src/components/kubepanel-views/custom-resource/bucket/bucket-detail.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import { Bucket } from '@/k8slens/kube-object/src/specifics/bucket'; -import { DrawerItem } from '@/components/common/drawer/drawer-item'; -import { DrawerPanel } from '@/components/common/drawer/drawer-panel'; -import { Drawer } from '@/components/common/drawer/drawer'; -import { KubeObjectInfoList } from '@/components/kube/object/detail/kube-object-detail-info-list'; -import { DetailDrawerProps } from '@/components/common/panel-table/table'; -import { StatusTag } from '@/components/common/status-tag'; - -const getPolicyColor = (policy: string) => { - switch (policy) { - case 'publicRead': - return 'green'; - case 'publicReadwrite': - return 'orange'; - case 'private': - return 'default'; - default: - return 'blue'; - } -}; - -const BucketDetail = ({ open, obj: bucket, onClose }: DetailDrawerProps) => { - if (!bucket) return null; - - return ( - - - - - - {bucket.getPolicy() || '-'} - - } - /> - - - - - ); -}; - -export default BucketDetail; diff --git a/frontend/providers/kubepanel/src/components/kubepanel-views/custom-resource/bucket/bucket.tsx b/frontend/providers/kubepanel/src/components/kubepanel-views/custom-resource/bucket/bucket.tsx deleted file mode 100644 index c7d7663b1..000000000 --- a/frontend/providers/kubepanel/src/components/kubepanel-views/custom-resource/bucket/bucket.tsx +++ /dev/null @@ -1,65 +0,0 @@ -import { Bucket } from '@/k8slens/kube-object/src/specifics/bucket'; -import { KubeObjectAge } from '@/components/kube/object/kube-object-age'; -import { PanelTable } from '@/components/common/panel-table/table'; -import { useBucketStore } from '@/store/kube'; -import { ActionButton } from '@/components/common/action/action-button'; -import BucketDetail from './bucket-detail'; -import type { ColumnsType } from 'antd/es/table'; -import { StatusTag } from '@/components/common/status-tag'; - -const getPolicyColor = (policy: string) => { - switch (policy) { - case 'publicRead': - return 'green'; - case 'publicReadwrite': - return 'orange'; - case 'private': - return 'default'; - default: - return 'blue'; - } -}; - -const columns: ColumnsType = [ - { - title: 'Policy', - key: 'policy', - render: (_, bucket) => ( - {bucket.getPolicy() || '-'} - ) - }, - { - title: 'Bucket Name', - key: 'bucketName', - render: (_, bucket) => bucket.getBucketName() || '-' - }, - { - title: 'Age', - key: 'age', - render: (_, bucket) => - }, - { - fixed: 'right', - key: 'action', - render: (_, bucket) => - } -]; - -const BucketPage = () => { - const { items, initialize, isLoaded } = useBucketStore(); - - return ( - - columns={columns} - loading={!isLoaded} - dataSource={items} - sectionTitle="Bucket" - getRowKey={(bucket) => bucket.getId()} - getDetailItem={(bucket) => bucket} - DetailDrawer={BucketDetail} - initializers={[initialize]} - /> - ); -}; - -export default BucketPage; diff --git a/frontend/providers/kubepanel/src/components/kubepanel-views/custom-resource/cluster/cluster-detail.tsx b/frontend/providers/kubepanel/src/components/kubepanel-views/custom-resource/cluster/cluster-detail.tsx deleted file mode 100644 index 915754ee1..000000000 --- a/frontend/providers/kubepanel/src/components/kubepanel-views/custom-resource/cluster/cluster-detail.tsx +++ /dev/null @@ -1,74 +0,0 @@ -import { Drawer } from '@/components/common/drawer/drawer'; -import { DrawerItem } from '@/components/common/drawer/drawer-item'; -import { DrawerPanel } from '@/components/common/drawer/drawer-panel'; -import { DetailDrawerProps } from '@/components/common/panel-table/table'; -import { StatusTag } from '@/components/common/status-tag'; -import { KubeObjectInfoList } from '@/components/kube/object/detail/kube-object-detail-info-list'; -import { Cluster } from '@/k8slens/kube-object/src/specifics/cluster'; - -const getPhaseColor = (phase: string) => { - switch (phase) { - case 'Running': - return 'green'; - case 'Stopped': - case 'Deleting': - return 'default'; - case 'Creating': - case 'Updating': - return 'blue'; - case 'Failed': - return 'red'; - default: - return 'orange'; - } -}; - -const ClusterDetail = ({ open, obj: cluster, onClose }: DetailDrawerProps) => { - if (!cluster) return null; - - return ( - - - - - {cluster.getPhase()} - } - /> - - - - - - - CPU: {cluster.getCpu() || '-'}  /  Memory: {cluster.getMemory() || '-'}{' '} -  /  Storage: {cluster.getStorage() || '-'} - - } - /> - - - - Enabled - ) : ( - Disabled - ) - } - /> - - - - - ); -}; - -export default ClusterDetail; diff --git a/frontend/providers/kubepanel/src/components/kubepanel-views/custom-resource/cluster/cluster.tsx b/frontend/providers/kubepanel/src/components/kubepanel-views/custom-resource/cluster/cluster.tsx deleted file mode 100644 index decdea403..000000000 --- a/frontend/providers/kubepanel/src/components/kubepanel-views/custom-resource/cluster/cluster.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import { Cluster } from '@/k8slens/kube-object/src/specifics/cluster'; -import { KubeObjectAge } from '@/components/kube/object/kube-object-age'; -import { PanelTable } from '@/components/common/panel-table/table'; -import { useClusterStore } from '@/store/kube'; -import { ActionButton } from '@/components/common/action/action-button'; -import ClusterDetail from './cluster-detail'; -import type { ColumnsType } from 'antd/es/table'; -import { StatusTag } from '@/components/common/status-tag'; - -const getPhaseColor = (phase: string) => { - switch (phase) { - case 'Running': - return 'green'; - case 'Stopped': - case 'Deleting': - return 'default'; - case 'Creating': - case 'Updating': - return 'blue'; - case 'Failed': - return 'red'; - default: - return 'orange'; - } -}; - -const columns: ColumnsType = [ - { - title: 'Phase', - key: 'phase', - render: (_, cluster) => ( - {cluster.getPhase()} - ) - }, - { - title: 'Definition', - key: 'definition', - render: (_, cluster) => cluster.getClusterDefinition() || '-' - }, - { - title: 'Version', - key: 'version', - render: (_, cluster) => cluster.getClusterVersion() || '-' - }, - { - title: 'Replicas', - key: 'replicas', - render: (_, cluster) => cluster.getReplicas() - }, - { - title: 'Age', - key: 'age', - render: (_, cluster) => - }, - { - fixed: 'right', - key: 'action', - render: (_, cluster) => - } -]; - -const ClusterPage = () => { - const { items, initialize, isLoaded } = useClusterStore(); - - return ( - - columns={columns} - loading={!isLoaded} - dataSource={items} - sectionTitle="Cluster" - getRowKey={(cluster) => cluster.getId()} - getDetailItem={(cluster) => cluster} - DetailDrawer={ClusterDetail} - initializers={[initialize]} - /> - ); -}; - -export default ClusterPage; diff --git a/frontend/providers/kubepanel/src/components/kubepanel-views/custom-resource/devbox/devbox-detail.tsx b/frontend/providers/kubepanel/src/components/kubepanel-views/custom-resource/devbox/devbox-detail.tsx deleted file mode 100644 index ba4874c13..000000000 --- a/frontend/providers/kubepanel/src/components/kubepanel-views/custom-resource/devbox/devbox-detail.tsx +++ /dev/null @@ -1,73 +0,0 @@ -import { Drawer } from '@/components/common/drawer/drawer'; -import { DrawerItem } from '@/components/common/drawer/drawer-item'; -import { DrawerPanel } from '@/components/common/drawer/drawer-panel'; -import { DetailDrawerProps } from '@/components/common/panel-table/table'; -import { StatusTag } from '@/components/common/status-tag'; -import { KubeObjectInfoList } from '@/components/kube/object/detail/kube-object-detail-info-list'; -import { Devbox } from '@/k8slens/kube-object/src/specifics/devbox'; - -const getStateColor = (state: string) => { - switch (state.toLowerCase()) { - case 'running': - return 'green'; - case 'stopped': - return 'default'; - case 'pending': - return 'orange'; - case 'error': - case 'failed': - return 'red'; - default: - return 'blue'; - } -}; - -const DevboxDetail = ({ open, obj: devbox, onClose }: DetailDrawerProps) => { - if (!devbox) return null; - - const networkType = devbox.getNetworkType(); - const nodePort = devbox.getNodePort(); - const networkDisplay = networkType ? ( -
- - {networkType} - - {nodePort && {nodePort}} -
- ) : ( - '-' - ); - - return ( - - - - - {devbox.getState()} - } - /> - - - - - - - CPU: {devbox.getCpu() || '-'}  /  Memory: {devbox.getMemory() || '-'}{' '} -  /  Storage: {devbox.getStorageLimit() || '-'} - - } - /> - - - - - ); -}; - -export default DevboxDetail; diff --git a/frontend/providers/kubepanel/src/components/kubepanel-views/custom-resource/devbox/devbox.tsx b/frontend/providers/kubepanel/src/components/kubepanel-views/custom-resource/devbox/devbox.tsx deleted file mode 100644 index 9450cc24d..000000000 --- a/frontend/providers/kubepanel/src/components/kubepanel-views/custom-resource/devbox/devbox.tsx +++ /dev/null @@ -1,80 +0,0 @@ -import { Devbox } from '@/k8slens/kube-object/src/specifics/devbox'; -import { KubeObjectAge } from '@/components/kube/object/kube-object-age'; -import { PanelTable } from '@/components/common/panel-table/table'; -import { useDevboxStore } from '@/store/kube'; -import { ActionButton } from '@/components/common/action/action-button'; -import DevboxDetail from './devbox-detail'; -import type { ColumnsType } from 'antd/es/table'; -import { StatusTag } from '@/components/common/status-tag'; - -const getStateColor = (state: string | undefined | null) => { - // Ensure state is a string before calling toLowerCase - const stateStr = typeof state === 'string' ? state : String(state || ''); - switch (stateStr.toLowerCase()) { - case 'running': - return 'green'; - case 'stopped': - return 'default'; - case 'pending': - return 'orange'; - case 'error': - case 'failed': - return 'red'; - default: - return 'blue'; - } -}; - -const columns: ColumnsType = [ - { - title: 'State', - key: 'state', - render: (_, devbox) => ( - {devbox.getState()} - ) - }, - { - title: 'CPU', - key: 'cpu', - render: (_, devbox) => devbox.getCpu() || '-' - }, - { - title: 'Memory', - key: 'memory', - render: (_, devbox) => devbox.getMemory() || '-' - }, - { - title: 'Storage', - key: 'storage', - render: (_, devbox) => devbox.getStorageLimit() || '-' - }, - { - title: 'Age', - key: 'age', - render: (_, devbox) => - }, - { - fixed: 'right', - key: 'action', - render: (_, devbox) => - } -]; - -const DevboxPage = () => { - const { items, initialize, isLoaded } = useDevboxStore(); - - return ( - - columns={columns} - loading={!isLoaded} - dataSource={items} - sectionTitle="Devbox" - getRowKey={(devbox) => devbox.getId()} - getDetailItem={(devbox) => devbox} - DetailDrawer={DevboxDetail} - initializers={[initialize]} - /> - ); -}; - -export default DevboxPage; diff --git a/frontend/providers/kubepanel/src/components/kubepanel-views/network/ingress/ingress-detail.tsx b/frontend/providers/kubepanel/src/components/kubepanel-views/network/ingress/ingress-detail.tsx deleted file mode 100644 index 9c7146424..000000000 --- a/frontend/providers/kubepanel/src/components/kubepanel-views/network/ingress/ingress-detail.tsx +++ /dev/null @@ -1,123 +0,0 @@ -import { updateResource } from '@/api/kubernetes'; -import { Drawer } from '@/components/common/drawer/drawer'; -import { DrawerPanel } from '@/components/common/drawer/drawer-panel'; -import { KubeObjectInfoList } from '@/components/kube/object/detail/kube-object-detail-info-list'; -import { Ingress, IngressRule } from '@/k8slens/kube-object'; -import { buildErrorResponse } from '@/services/backend/response'; -import { useIngressStore } from '@/store/kube'; -import { dumpKubeObject } from '@/utils/yaml'; -import { SaveOutlined } from '@ant-design/icons'; -import { Button, message } from 'antd'; -import { useEffect, useState } from 'react'; -import IngressPathEditor from './ingress-path-editor'; - -const IngressDetail = ({ obj: ingress, open, onClose }: DetailDrawerProps) => { - if (!ingress || !(ingress instanceof Ingress)) return null; - - const [isEditing, setIsEditing] = useState(false); - const [draftRules, setDraftRules] = useState([]); - const [submitting, setSubmitting] = useState(false); - const { items, initialize } = useIngressStore(); - const [msgApi, contextHolder] = message.useMessage(); - const msgKey = 'ingressEditMsg'; - - const latest = items.find((it) => it.getId() === ingress.getId()) ?? ingress; - - // Reset editing state when drawer opens/closes or ingress changes - useEffect(() => { - if (!open) { - setIsEditing(false); - setDraftRules([]); - } - }, [open]); - - const id = ingress?.getId(); - useEffect(() => { - setIsEditing(false); - setDraftRules([]); - }, [id]); - - const handleSave = async () => { - try { - setSubmitting(true); - - const updated: Partial = { - ...latest, - spec: { - ...latest.spec, - rules: draftRules - } - }; - - msgApi.loading({ content: 'Updating Ingress...', key: msgKey }, 0); - const yaml = dumpKubeObject(updated); - const res = await updateResource(latest.kind, latest.getName(), yaml); - msgApi.success({ - content: `Updated ${res.data.kind} ${res.data.metadata.name}`, - key: msgKey - }); - - // Refresh the store to ensure the detail view shows the latest rules immediately - await initialize(() => {}, true); - setIsEditing(false); - } catch (err: any) { - const resp = buildErrorResponse(err); - msgApi.error({ - content: `Update failed: ${resp.error.message}`, - key: msgKey - }); - } finally { - setSubmitting(false); - } - }; - - const handleCancel = () => { - setIsEditing(false); - }; - - return ( - <> - {contextHolder} - - - - -
- Rules - {!isEditing ? ( - - ) : ( -
- - -
- )} -
- - setDraftRules(rules)} - /> -
-
- - ); -}; - -export default IngressDetail; diff --git a/frontend/providers/kubepanel/src/components/kubepanel-views/network/ingress/ingress-path-editor.tsx b/frontend/providers/kubepanel/src/components/kubepanel-views/network/ingress/ingress-path-editor.tsx deleted file mode 100644 index 2b1b8e4cc..000000000 --- a/frontend/providers/kubepanel/src/components/kubepanel-views/network/ingress/ingress-path-editor.tsx +++ /dev/null @@ -1,368 +0,0 @@ -import { - ComputedIngressRoute, - computeRuleDeclarations, - ExtensionsBackend, - Ingress, - IngressRule, - NetworkingBackend -} from '@/k8slens/kube-object'; -import { DeleteOutlined, PlusOutlined } from '@ant-design/icons'; -import { Button, Input, Select, Table, Tooltip } from 'antd'; -import { ColumnsType } from 'antd/lib/table'; -import { isEqual } from 'lodash'; -import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; - -interface IngressPathEditorProps { - ingress: Ingress; - isEditing?: boolean; - onChange?: (rules: IngressRule[]) => void; -} - -type PathForm = { - path?: string; - pathType: 'Exact' | 'Prefix'; - serviceName: string; - servicePort?: number | string; -}; - -type RuleForm = { - host: string; - paths: PathForm[]; -}; - -const IngressPathEditor = ({ ingress, isEditing = false, onChange }: IngressPathEditorProps) => { - const [rules, setRules] = useState([]); - - const convertIngressToForm = useMemo(() => { - return (ing: Ingress): RuleForm[] => { - if (!ing || !ing.spec) { - return []; - } - return ( - ing.spec.rules?.map((rule) => ({ - host: rule.host || '*', - paths: (rule.http?.paths || []).map((p) => ({ - path: p.path || '/', - pathType: - p.pathType === 'ImplementationSpecific' - ? 'Prefix' - : (p.pathType as 'Exact' | 'Prefix') || 'Prefix', - serviceName: - (p.backend as NetworkingBackend)?.service?.name ?? - (p.backend as ExtensionsBackend)?.serviceName ?? - '', - servicePort: - (p.backend as NetworkingBackend)?.service?.port?.number ?? - (p.backend as NetworkingBackend)?.service?.port?.name ?? - (p.backend as ExtensionsBackend)?.servicePort - })) - })) || [] - ); - }; - }, []); - - const resetDraft = useCallback( - (ing: Ingress) => { - setRules(convertIngressToForm(ing)); - }, - [convertIngressToForm] - ); - - useEffect(() => { - if (!isEditing) { - resetDraft(ingress); - } - }, [ingress, isEditing, resetDraft]); - - useEffect(() => { - if (isEditing) { - resetDraft(ingress); - } - }, [isEditing, ingress, resetDraft]); - - const draftRules = useMemo(() => { - return rules.map((rule) => ({ - host: rule.host === '*' ? undefined : rule.host, - http: { - paths: rule.paths.map((p) => ({ - pathType: p.pathType, - path: p.path, - backend: { - service: { - name: p.serviceName, - port: - typeof p.servicePort === 'number' - ? { number: p.servicePort } - : (() => { - const asNum = Number(p.servicePort); - return Number.isFinite(asNum) - ? { number: asNum } - : { name: String(p.servicePort || '') }; - })() - } - } - })) - } - })) as IngressRule[]; - }, [rules]); - - const lastSentRef = useRef(); - - useEffect(() => { - if (!isEditing) { - lastSentRef.current = undefined; - return; - } - if (!isEqual(draftRules, lastSentRef.current)) { - lastSentRef.current = draftRules; - onChange?.(draftRules); - } - }, [draftRules, isEditing, onChange]); - - const addPath = (ruleIndex: number) => { - setRules((prev) => { - const newRules = [...prev]; - const rule = newRules[ruleIndex]; - if (!rule) return newRules; - rule.paths.push({ - path: '', - pathType: 'Prefix', - serviceName: '', - servicePort: '' - }); - return newRules; - }); - }; - - const removePath = (ruleIndex: number, pathIndex: number) => { - setRules((prev) => { - const newRules = [...prev]; - const rule = newRules[ruleIndex]; - if (!rule) return newRules; - rule.paths.splice(pathIndex, 1); - return newRules; - }); - }; - - const updatePath = (ruleIndex: number, pathIndex: number, field: keyof PathForm, value: any) => { - setRules((prev) => { - const newRules = [...prev]; - const rule = newRules[ruleIndex]; - if (!rule) return newRules; - const path = rule.paths[pathIndex]; - if (!path) return newRules; - rule.paths[pathIndex] = { - ...path, - [field]: value, - // Ensure pathType is always defined - pathType: field === 'pathType' ? (value as 'Exact' | 'Prefix') : path.pathType - }; - return newRules; - }); - }; - - const displayRules = isEditing ? rules : convertIngressToForm(ingress); - - if (!isEditing) { - if (!ingress) { - return null; - } - return ( -
- {ingress.getRules().map((rule, idx) => { - const pathTypeMap = new Map(); - rule.http?.paths?.forEach((p) => { - const pathKey = p.path || '/'; - pathTypeMap.set(pathKey, p.pathType || 'Prefix'); - }); - - const rulesColumns: ColumnsType = [ - { - key: 'path', - title: 'Path', - render: (_, { pathname, displayAsLink, url }) => { - const text = pathname === '' ? '_' : pathname; - const pathType = pathTypeMap.get(pathname) || 'Prefix'; - const typeLabel = pathType === 'Prefix' ? '≈' : pathType === 'Exact' ? '=' : '~'; - const typeColor = - pathType === 'Prefix' ? '#1890ff' : pathType === 'Exact' ? '#52c41a' : '#722ed1'; - - return ( -
- - - {typeLabel} - - - {displayAsLink ? ( - - ) : ( - {text} - )} -
- ); - } - }, - { - key: 'backends', - title: 'Service', - dataIndex: 'service' - } - ]; - - return ( -
- {rule.http && ( -
record.url} - title={() => { - const tlsEntry = ingress.spec.tls?.find((tls) => - tls.hosts?.includes(rule.host || '') - ); - const isHttps = !!tlsEntry; - const protocol = isHttps ? 'https' : 'http'; - - return ( -
- - {isHttps ? ( - - - {protocol.toUpperCase()} - - - ) : ( - - {protocol.toUpperCase()} - - )} - - {rule.host || '*'} -
- ); - }} - /> - )} - - ); - })} - - ); - } - - return ( -
- {displayRules.map((rule, ruleIndex) => ( -
-
-
- - {rule.host ? `Host: ${rule.host}` : 'Host: *'} - - -
-
- {rule.paths.map((path, pathIndex) => ( -
-
-
- - updatePath(ruleIndex, pathIndex, 'path', e.target.value)} - readOnly={String(path.path || '').trim() === '/'} - disabled={String(path.path || '').trim() === '/'} - /> -
-
-
-
- - - updatePath(ruleIndex, pathIndex, 'serviceName', e.target.value) - } - readOnly={String(path.path || '').trim() === '/'} - disabled={String(path.path || '').trim() === '/'} - /> -
-
- - - updatePath(ruleIndex, pathIndex, 'servicePort', e.target.value) - } - readOnly={String(path.path || '').trim() === '/'} - disabled={String(path.path || '').trim() === '/'} - /> -
-
-
- ))} -
-
-
- ))} -
- ); -}; - -export default IngressPathEditor; diff --git a/frontend/providers/kubepanel/src/components/kubepanel-views/network/ingress/ingress-visual-editor-drawer.tsx b/frontend/providers/kubepanel/src/components/kubepanel-views/network/ingress/ingress-visual-editor-drawer.tsx deleted file mode 100644 index 666c392fd..000000000 --- a/frontend/providers/kubepanel/src/components/kubepanel-views/network/ingress/ingress-visual-editor-drawer.tsx +++ /dev/null @@ -1,345 +0,0 @@ -import { Form, Input, Button, Select, Space, message, Modal } from 'antd'; -import { Drawer } from '@/components/common/drawer/drawer'; -import { Ingress, ExtensionsBackend, NetworkingBackend } from '@/k8slens/kube-object'; -import { updateResource } from '@/api/kubernetes'; -import { buildErrorResponse } from '@/services/backend/response'; -import { dumpKubeObject } from '@/utils/yaml'; -import { PlusOutlined, DeleteOutlined, SaveOutlined } from '@ant-design/icons'; -import { useEffect, useState, useCallback } from 'react'; - -type PathForm = { - path?: string; - pathType: 'Exact' | 'Prefix' | 'ImplementationSpecific'; - serviceName: string; - servicePort?: number | string; -}; - -type RuleForm = { - paths: PathForm[]; -}; - -type FormValues = { - rules: RuleForm[]; - tls: { secretName: string }[]; -}; - -interface Props { - ingress?: Ingress | null; - open: boolean; - onCancel: () => void; - onOk: () => void; -} - -export const IngressVisualEditorDrawer = ({ ingress, open, onCancel, onOk }: Props) => { - if (!ingress) return null; - - const [form] = Form.useForm(); - const [msgApi, contextHolder] = message.useMessage(); - const msgKey = 'ingressVisualEditMsg'; - const [submitting, setSubmitting] = useState(false); - - // Helper function to check if path is root path - const getPathValue = useCallback( - (fieldName: number, pathFieldName: number): string => { - return String( - form.getFieldValue(['rules', fieldName, 'paths'])?.[pathFieldName]?.path ?? '' - ).trim(); - }, - [form] - ); - - const isRootPath = useCallback( - (fieldName: number, pathFieldName: number): boolean => { - return getPathValue(fieldName, pathFieldName) === '/'; - }, - [getPathValue] - ); - - const initialValues: FormValues = { - rules: - ingress.spec.rules?.map((rule) => ({ - paths: (rule.http?.paths || []).map((p) => ({ - path: p.path || '/', - pathType: p.pathType || 'Prefix', - serviceName: - (p.backend as NetworkingBackend)?.service?.name ?? - (p.backend as ExtensionsBackend)?.serviceName ?? - '', - servicePort: - (p.backend as NetworkingBackend)?.service?.port?.number ?? - (p.backend as NetworkingBackend)?.service?.port?.name ?? - (p.backend as ExtensionsBackend)?.servicePort - })) - })) || [], - tls: [] - }; - - // Ensure the form reflects original ingress data each time the drawer opens - useEffect(() => { - if (open) { - form.setFieldsValue(initialValues); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [open, ingress]); - - const handleSubmit = async () => { - try { - setSubmitting(true); - const values = await form.validateFields(); - - const newRules = (ingress.spec.rules || []).map((origRule, idx) => ({ - host: origRule.host, - http: { - paths: (values.rules[idx]?.paths || origRule.http?.paths || []).map((p) => { - // Type guard: check if p is PathForm (has serviceName/servicePort) or HTTPIngressPath - const isPathForm = 'serviceName' in p && 'servicePort' in p; - if (isPathForm) { - const pathForm = p as PathForm; - return { - pathType: pathForm.pathType, - path: pathForm.path, - backend: { - service: { - name: pathForm.serviceName, - port: - typeof pathForm.servicePort === 'number' - ? { number: pathForm.servicePort } - : (() => { - const asNum = Number(pathForm.servicePort); - return Number.isFinite(asNum) - ? { number: asNum } - : { name: String(pathForm.servicePort || '') }; - })() - } - } - }; - } else { - // It's HTTPIngressPath, use it as-is - return p; - } - }) - } - })); - - const updated: Partial = { - ...ingress, - spec: { - ...ingress.spec, - rules: newRules - } - }; - - msgApi.loading({ content: 'Updating Ingress...', key: msgKey }, 0); - const yaml = dumpKubeObject(updated); - const res = await updateResource(ingress.kind, ingress.getName(), yaml); - msgApi.success({ - content: `Updated ${res.data.kind} ${res.data.metadata.name}`, - key: msgKey - }); - onOk(); - } catch (err: any) { - const resp = buildErrorResponse(err); - msgApi.error({ - content: `Update failed: ${resp.error.message}`, - key: msgKey - }); - } finally { - setSubmitting(false); - } - }; - - const handleCancel = () => { - if (form.isFieldsTouched(true)) { - Modal.confirm({ - title: 'Discard changes?', - content: 'Unsaved changes will be lost.', - okText: 'Confirm', - cancelText: 'Continue Editing', - onOk: () => { - form.setFieldsValue(initialValues); - onCancel(); - } - }); - } else { - form.setFieldsValue(initialValues); - onCancel(); - } - }; - - return ( - <> - {contextHolder} - - - - - } - > -
- - {(fields) => ( -
- {fields.map((field) => ( -
-
- Host: {ingress.spec.rules?.[field.name]?.host || '*'} -
- - {(pathFields, { add: addPath, remove: removePath }) => ( -
-
- Paths - -
- {pathFields.map((pf) => ( -
- - - - - - - - - - - - - - { - const prevPath = - prev?.rules?.[field.name]?.paths?.[pf.name]?.path; - const currPath = - curr?.rules?.[field.name]?.paths?.[pf.name]?.path; - return prevPath !== currPath; - }} - > - {() => { - const isRoot = isRootPath(field.name, pf.name); - return ( -
- ))} -
- )} -
-
- ))} -
- )} -
- -
- - ); -}; - -export default IngressVisualEditorDrawer; diff --git a/frontend/providers/kubepanel/src/components/kubepanel-views/network/ingress/ingress.tsx b/frontend/providers/kubepanel/src/components/kubepanel-views/network/ingress/ingress.tsx deleted file mode 100644 index 60a4448cb..000000000 --- a/frontend/providers/kubepanel/src/components/kubepanel-views/network/ingress/ingress.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import { KubeObjectAge } from '@/components/kube/object/kube-object-age'; -import { Ingress, computeRouteDeclarations } from '@/k8slens/kube-object'; -import { ColumnsType } from 'antd/lib/table'; -import { useIngressStore } from '@/store/kube'; -import { Button } from 'antd'; -import IngressDetail from './ingress-detail'; -import { PanelTable } from '@/components/common/panel-table/table'; -import { ActionButton } from '@/components/common/action/action-button'; - -const columns: ColumnsType = [ - { - title: 'Rules', - key: 'rules', - render: (_, ingress) => - computeRouteDeclarations(ingress).map((decl) => ( -
- {decl.displayAsLink ? ( - <> - - {` ⇢ ${decl.service}`} - - ) : ( - <>{`${decl.url} ⇢ ${decl.service}`} - )} -
- )) - }, - { - title: 'Age', - key: 'age', - render: (_, ingress) => - }, - { - fixed: 'right', - key: 'action', - render: (_, ingress) => - } -]; - -const IngressOverviewPage = () => { - const { items, initialize, isLoaded } = useIngressStore(); - - return ( - ingress.getId()} - initializers={[initialize]} - getDetailItem={(ingress) => ingress} - /> - ); -}; - -export default IngressOverviewPage; diff --git a/frontend/providers/kubepanel/src/components/kubepanel-views/network/service/service-detail.tsx b/frontend/providers/kubepanel/src/components/kubepanel-views/network/service/service-detail.tsx deleted file mode 100644 index bbaf7da1a..000000000 --- a/frontend/providers/kubepanel/src/components/kubepanel-views/network/service/service-detail.tsx +++ /dev/null @@ -1,96 +0,0 @@ -import { Drawer } from '@/components/common/drawer/drawer'; -import { DrawerPanel } from '@/components/common/drawer/drawer-panel'; -import { KubeObjectInfoList } from '@/components/kube/object/detail/kube-object-detail-info-list'; -import { ComputedIngressRoute, ILoadBalancerIngress, Service } from '@/k8slens/kube-object'; -import { Button, Table } from 'antd'; -import { ColumnsType } from 'antd/lib/table'; - -const rulesColumns: ColumnsType = [ - { - key: 'path', - title: 'Path', - dataIndex: 'pathname', - render: (pathname: string) => (pathname === '' ? '_' : pathname) - }, - { - key: 'link', - title: 'Link', - render: (_, { displayAsLink, url }) => - displayAsLink ? ( - - ) : ( - url - ) - }, - { - key: 'backends', - title: 'Backends', - dataIndex: 'service' - } -]; - -const pointsColumns: ColumnsType = [ - { - key: 'hostname', - title: 'Hostname', - dataIndex: 'hostname', - render: (hostname?: string) => (hostname ? '_' : hostname) - }, - { - key: 'ip', - title: 'IP', - dataIndex: 'ip', - render: (ip?: string) => (ip ? '_' : ip) - } -]; - -const IngressPoints = ({ points }: { points?: ILoadBalancerIngress[] }) => { - if (!points || points.length === 0) { - return null; - } - - return ( -
- ); -}; - -const ServiceDetail = ({ obj: service, open, onClose }: DetailDrawerProps) => { - if (!service || !(service instanceof Service)) return null; - return ( - - - -
-
- Cluster IP - {service.getClusterIp()} -
-
- Type - {service.getType()} -
-
- Ports -
- {service.getPorts().map((port) => ( - - {port.toString()} - - ))} -
-
-
-
-
- ); -}; - -export default ServiceDetail; diff --git a/frontend/providers/kubepanel/src/components/kubepanel-views/network/service/service.tsx b/frontend/providers/kubepanel/src/components/kubepanel-views/network/service/service.tsx deleted file mode 100644 index b803b520c..000000000 --- a/frontend/providers/kubepanel/src/components/kubepanel-views/network/service/service.tsx +++ /dev/null @@ -1,96 +0,0 @@ -import { KubeObjectAge } from '@/components/kube/object/kube-object-age'; -import { - KubeObject, - KubeObjectMetadata, - KubeObjectScope, - Service, - computeRouteDeclarations -} from '@/k8slens/kube-object'; -import { ColumnsType } from 'antd/lib/table'; -import { useServiceStore } from '@/store/kube'; -import { Button } from 'antd'; -import ServiceDetail from './service-detail'; -import { PanelTable } from '@/components/common/panel-table/table'; -import { ActionButton } from '@/components/common/action/action-button'; - -const columns: ColumnsType = [ - { - title: 'ClusterIps', - key: 'ClusterIps', - render: (_, service: Service) => ( -
- {service.getClusterIps().map((ip) => ( - - {ip} - - ))} -
- ) - }, - { - title: 'Type', - key: 'type', - render: (_, service: Service) => {service.getType()} - }, - { - title: 'Selector', - key: 'selector', - render: (_, service: Service) => ( -
- {service.getSelector().map((selector) => ( - - {selector} - - ))} -
- ) - }, - { - title: 'Ports', - key: 'ports', - render: (_, service: Service) => ( -
- {service.getPorts().map((port) => ( - - {port.toString()} - - ))} -
- ) - }, - { - title: 'Status', - key: 'status', - render: (_, service: Service) => {service.getStatus()} - }, - { - title: 'Age', - key: 'age', - render: (_, service: Service) => - }, - { - key: 'action', - fixed: 'right', - width: 20, - render: (_, service: Service) => - } -]; - -const ServiceOverviewPage = () => { - const { items, initialize, isLoaded } = useServiceStore(); - - return ( - service.getId()} - initializers={[initialize]} - getDetailItem={(service) => service} - /> - ); -}; - -export default ServiceOverviewPage; diff --git a/frontend/providers/kubepanel/src/components/kubepanel-views/storage/volume-claim/volume-claim-detail.tsx b/frontend/providers/kubepanel/src/components/kubepanel-views/storage/volume-claim/volume-claim-detail.tsx deleted file mode 100644 index d48d88e31..000000000 --- a/frontend/providers/kubepanel/src/components/kubepanel-views/storage/volume-claim/volume-claim-detail.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import { PersistentVolumeClaim, Pod } from '@/k8slens/kube-object'; -import { Drawer } from '@/components/common/drawer/drawer'; -import { KubeObjectInfoList } from '@/components/kube/object/detail/kube-object-detail-info-list'; -import { DrawerItem } from '@/components/common/drawer/drawer-item'; -import { KubeBadge } from '@/components/kube/kube-badge'; -import React from 'react'; -import { DrawerPanel } from '@/components/common/drawer/drawer-panel'; -import { isArray } from 'lodash'; - -const PersistentVolumeClaimDetail = ({ - obj, - open, - onClose -}: DetailDrawerProps<{ volumeClaim: PersistentVolumeClaim; pods: Pod[] }>) => { - if (!obj) return null; - - const { volumeClaim, pods } = obj; - if (!volumeClaim || !(volumeClaim instanceof PersistentVolumeClaim)) return null; - if (!pods || !isArray(pods)) return null; - - const { storageClassName, accessModes } = volumeClaim.spec; - - // const storageClassDetailsUrl = getDetailsUrl(storageClassApi.formatUrlForNotListing({ - // name: storageClassName, - // })); - - return ( - - - - - - - ( - - {pod.getName()} - - ))} - /> - - - {(volumeClaim.getMatchLabels().length > 0 || - volumeClaim.getMatchExpressions().length > 0) && ( - <> -
Selector
- {volumeClaim.getMatchLabels().length > 0 && ( - - {volumeClaim.getMatchLabels().map((label) => ( - - ))} - - } - /> - )} - {volumeClaim.getMatchExpressions().length > 0 && ( - ( - - - - - - ))} - /> - )} - - )} -
-
- ); -}; - -export default PersistentVolumeClaimDetail; diff --git a/frontend/providers/kubepanel/src/components/kubepanel-views/storage/volume-claim/volume-claim.tsx b/frontend/providers/kubepanel/src/components/kubepanel-views/storage/volume-claim/volume-claim.tsx deleted file mode 100644 index 9ab6dd70b..000000000 --- a/frontend/providers/kubepanel/src/components/kubepanel-views/storage/volume-claim/volume-claim.tsx +++ /dev/null @@ -1,87 +0,0 @@ -import { KubeObjectAge } from '@/components/kube/object/kube-object-age'; -import { PersistentVolumeClaim, Pod } from '@/k8slens/kube-object'; -import { ColumnsType } from 'antd/es/table'; -import PersistentVolumeClaimDetail from './volume-claim-detail'; -import { usePodStore, useVolumeClaimStore } from '@/store/kube'; -import { PanelTable } from '@/components/common/panel-table/table'; -import { ActionButton } from '@/components/common/action/action-button'; - -const columns: ColumnsType<{ volumeClaim: PersistentVolumeClaim; pods: Pod[] }> = [ - { - title: 'Storage Class', - key: 'storageClass', - render: (_, { volumeClaim }) => volumeClaim.spec.storageClassName - }, - { - title: 'Size', - key: 'size', - render: (_, { volumeClaim }) => volumeClaim.getStorage() - }, - { - title: 'Pods', - key: 'pods', - ellipsis: true, - render: (_, { volumeClaim, pods }) => { - const podsNames = volumeClaim.getPods(pods).map((pod) => pod.getName()); - return ( -
- {podsNames.map((name) => ( - - {name} - - ))} -
- ); - } - }, - { - title: 'Status', - key: 'status', - render: (_, { volumeClaim }) => volumeClaim.getStatus() - }, - { - title: 'Age', - key: 'age', - render: (_, { volumeClaim }) => - }, - { - key: 'action', - fixed: 'right', - render: (_, { volumeClaim }) => - } -]; - -const PersistentVolumeClaimOverviewPage = () => { - const { - items: volumeClaims, - initialize: initializeVolumeClaims, - isLoaded: isVolumeClaimsLoaded - } = useVolumeClaimStore(); - const { items: pods, initialize: initializePods, isLoaded: isPodsLoaded } = usePodStore(); - - const dataSource = volumeClaims.map((volumeClaim) => ({ - volumeClaim, - pods - })); - - return ( - ( - - )} - getRowKey={({ volumeClaim }) => volumeClaim.getId()} - initializers={[initializeVolumeClaims, initializePods]} - getDetailItem={(record) => record.volumeClaim} - /> - ); -}; - -export default PersistentVolumeClaimOverviewPage; diff --git a/frontend/providers/kubepanel/src/components/kubepanel-views/workload/deployment/deployment-detail.tsx b/frontend/providers/kubepanel/src/components/kubepanel-views/workload/deployment/deployment-detail.tsx deleted file mode 100644 index 0b2f5f6fd..000000000 --- a/frontend/providers/kubepanel/src/components/kubepanel-views/workload/deployment/deployment-detail.tsx +++ /dev/null @@ -1,112 +0,0 @@ -import { Drawer } from '@/components/common/drawer/drawer'; -import { DrawerItem } from '@/components/common/drawer/drawer-item'; -import { DrawerPanel } from '@/components/common/drawer/drawer-panel'; -import { KubeBadge } from '@/components/kube/kube-badge'; -import { KubeObjectInfoList } from '@/components/kube/object/detail/kube-object-detail-info-list'; -import { Deployment } from '@/k8slens/kube-object'; -import { useDeploymentStore } from '@/store/kube'; -import { getConditionTextTone } from '@/utils/condtion-color'; -import { Divider, Tooltip, Typography } from 'antd'; -import ContainerDetail from '../pod/container-detail'; -import PodDetailAffinities from '../pod/pod-detail-affinities'; -import PodDetailSecurityContext from '../pod/pod-detail-security-context'; -import PodDetailTolerations from '../pod/pod-detail-tolerations'; - -const DeploymentDetail = ({ obj: dep, open, onClose }: DetailDrawerProps) => { - if (!dep || !(dep instanceof Deployment)) { - return null; - } - - const { status, spec } = dep; - const selectors = dep.getSelectors(); - const conditions = dep.getConditions(); - const { initialize } = useDeploymentStore(); - - return ( - - - - - {`${spec.replicas} desired, ${status?.updatedReplicas ?? 0} updated, `} - {`${status?.replicas ?? 0} total, ${status?.availableReplicas ?? 0} available`} - - } - /> - {selectors.length > 0 && ( - - {[...selectors].sort().map((label) => { - const sepIndex = label.indexOf(': '); - if (sepIndex === -1) - return ; - const key = label.slice(0, sepIndex); - const value = label.slice(sepIndex + 2); - return ( - - {key} - : - {value} - - } - className="m-0!" - /> - ); - })} - - } - /> - )} - - - {conditions.map(({ type, message, lastTransitionTime }) => ( - -

{message}

-
-

Last transition time: {lastTransitionTime ?? ''}

- - } - > - - {type} - -
- ))} - - } - /> - - - initialize(() => {}, true)} - /> - - - initialize(() => {}, true)} - /> -
-
- ); -}; - -export default DeploymentDetail; diff --git a/frontend/providers/kubepanel/src/components/kubepanel-views/workload/deployment/deployment.tsx b/frontend/providers/kubepanel/src/components/kubepanel-views/workload/deployment/deployment.tsx deleted file mode 100644 index 3d43abaa8..000000000 --- a/frontend/providers/kubepanel/src/components/kubepanel-views/workload/deployment/deployment.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import { KubeObjectAge } from '@/components/kube/object/kube-object-age'; -import { Deployment } from '@/k8slens/kube-object'; -import { getConditionTextTone } from '@/utils/condtion-color'; -import { Tooltip, Typography } from 'antd'; -import { ColumnsType } from 'antd/es/table'; -import DeploymentDetail from './deployment-detail'; -import { useDeploymentStore } from '@/store/kube'; -import { PanelTable } from '@/components/common/panel-table/table'; -import { ActionButton } from '@/components/common/action/action-button'; - -const columns: ColumnsType = [ - { - title: 'Pods', - key: 'pods', - render: (_, dep) => { - const { replicas = 0, availableReplicas = 0 } = dep.status ?? {}; - return `${availableReplicas}/${replicas}`; - } - }, - - { - title: 'Conditions', - key: 'conditions', - render: (_, dep) => - dep.getConditions().map(({ type, message }) => ( - - - {type} - - - )) - }, - { - title: 'Age', - dataIndex: 'creationTimestamp', - key: 'age', - render: (_, dep) => - }, - { - key: 'action', - fixed: 'right', - render: (_, dep) => - } -]; - -const DeploymentOverviewPage = () => { - const { items, initialize, isLoaded } = useDeploymentStore(); - - return ( - deployment.getId()} - initializers={[initialize]} - getDetailItem={(deployment) => deployment} - /> - ); -}; - -export default DeploymentOverviewPage; diff --git a/frontend/providers/kubepanel/src/components/kubepanel-views/workload/overview/event-overview.tsx b/frontend/providers/kubepanel/src/components/kubepanel-views/workload/overview/event-overview.tsx deleted file mode 100644 index 19ba6d011..000000000 --- a/frontend/providers/kubepanel/src/components/kubepanel-views/workload/overview/event-overview.tsx +++ /dev/null @@ -1,108 +0,0 @@ -import Title from '@/components/common/title/title'; -import { KubeObjectAge } from '@/components/kube/object/kube-object-age'; -import { ReactiveDuration } from '@/components/kube/reactive-duration'; -import { useWatcher } from '@/hooks/useWatcher'; -import { KubeEvent, ObjectReference } from '@/k8slens/kube-object'; -import { useEventStore } from '@/store/k8s/event.store'; -import { Table, Typography } from 'antd'; -import { ColumnsType } from 'antd/lib/table'; - -const columns: ColumnsType = [ - { - title: Type, - key: 'type', - dataIndex: 'type', - fixed: 'start', - width: 80, - align: 'center', - render: (type: string | undefined) => { - if (!type) return 'Unknown'; - return type; - } - }, - { - title: Message, - key: 'message', - dataIndex: 'message', - render: (message: string | undefined, event: KubeEvent) => { - if (!message) return ''; - - switch (event.type) { - case 'Warning': - return {message}; - case 'Normal': - default: - return message; - } - } - }, - { - title: Involved Object, - key: 'involved-object', - dataIndex: 'involvedObject', - render: (involvedObject: Required | undefined) => { - if (!involvedObject) return ''; - return {involvedObject.name}; - } - }, - { - title: Source, - key: 'source', - width: 200, - render: (_, event: KubeEvent) => event.getSource() - }, - { - title: Count, - dataIndex: 'count', - key: 'count', - width: 70, - fixed: 'end', - align: 'center', - render: (count: number | undefined) => { - if (!count) return ''; - return count; - } - }, - { - title: Age, - key: 'age', - width: 80, - fixed: 'end', - align: 'center', - render: (_, event: KubeEvent) => { - return ; - } - }, - { - title: Last Seen, - key: 'last-seen', - width: 80, - fixed: 'end', - align: 'center', - render: (_, event: KubeEvent) => { - return ; - } - } -]; - -const EventOverview = () => { - const { items, initialize, isLoaded } = useEventStore(); - const cxtHolder = useWatcher({ initializers: [initialize] }); - - return ( - <> - {cxtHolder} -
event.getId()} - dataSource={items.slice(0, 10)} - pagination={false} - scroll={{ x: 'max-content' }} - /> - - ); -}; - -export default EventOverview; diff --git a/frontend/providers/kubepanel/src/components/kubepanel-views/workload/overview/overview.tsx b/frontend/providers/kubepanel/src/components/kubepanel-views/workload/overview/overview.tsx deleted file mode 100644 index bec93b05a..000000000 --- a/frontend/providers/kubepanel/src/components/kubepanel-views/workload/overview/overview.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import { Flex } from 'antd'; -import WorkloadStatusOverview from './status-overview'; -import { convertToPieChartStatusData } from '@/utils/pie-chart'; -import { countBy, entries, startCase } from 'lodash'; -import { - getDeploymentsStatuses, - getStatefulSetsStatuses, - useDeploymentStore, - usePodStore, - useStatefulSetStore -} from '@/store/kube'; -import { Section } from '@/components/common/section/section'; -import Title from '@/components/common/title/title'; -import EventOverview from './event-overview'; -import { useWatcher } from '@/hooks/useWatcher'; - -const OverviewPage = () => { - const { items: pods, initialize: initializePods } = usePodStore(); - - const getPodStatuses = countBy(pods, (pod) => pod.getStatus()); - - const { items: deps, initialize: initializeDeployments } = useDeploymentStore(); - const { items: stats, initialize: initializeStatefulSets } = useStatefulSetStore(); - - const cxtHolder = useWatcher({ - initializers: [initializePods, initializeDeployments, initializeStatefulSets] - }); - - const statuses = { - Pod: convertToPieChartStatusData(getPodStatuses), - Deployment: convertToPieChartStatusData(getDeploymentsStatuses(deps, pods)), - StatefulSet: convertToPieChartStatusData(getStatefulSetsStatuses(stats, pods)) - }; - - const overviewStatuses = entries(statuses).map(([key, value]) => ({ - title: startCase(key), - data: value - })); - - return ( - -
- Overview -
- -
-
-
- Events - -
-
- ); -}; - -export default OverviewPage; diff --git a/frontend/providers/kubepanel/src/components/kubepanel-views/workload/overview/status-chart.tsx b/frontend/providers/kubepanel/src/components/kubepanel-views/workload/overview/status-chart.tsx deleted file mode 100644 index 1a9325f56..000000000 --- a/frontend/providers/kubepanel/src/components/kubepanel-views/workload/overview/status-chart.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import { PieChart } from '@/components/chart/pie-chart'; - -type WorkloadStatusType = - | 'Running' - | 'Scheduled' - | 'Pending' - | 'Suspended' - | 'Evicted' - | 'Failed' - | 'Succeeded' - | 'Terminated' - | 'Terminating' - | 'Unknown' - | 'Empty' - | 'Complete'; - -export type WorkloadStatusData = { - type: WorkloadStatusType; - value: number; -}; - -const statusBackgroundColorMapping = { - Running: '#039855', - Scheduled: '#399c3d', - Pending: '#F79009', - Suspended: '#ff9800', - Evicted: '#ce3933', - Succeeded: '#206923', - Failed: '#D92D20', - Terminated: '#9dabb5', - Terminating: '#9dabb5', - Unknown: '#EDEDED', - Empty: '#ededed', - Complete: '#206923' -} as { [key in WorkloadStatusType]: string }; - -const WorkloadStatus = ({ title, data }: { title: string; data?: Array }) => { - if (!data) return null; - if (data.length === 0) { - data = [{ type: 'Empty', value: 0 }]; - } - - return ( - statusBackgroundColorMapping[type as WorkloadStatusType] - }} - /> - ); -}; - -export default WorkloadStatus; diff --git a/frontend/providers/kubepanel/src/components/kubepanel-views/workload/overview/status-overview.tsx b/frontend/providers/kubepanel/src/components/kubepanel-views/workload/overview/status-overview.tsx deleted file mode 100644 index 796442c4c..000000000 --- a/frontend/providers/kubepanel/src/components/kubepanel-views/workload/overview/status-overview.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { Flex } from 'antd'; -import WorkloadStatus, { WorkloadStatusData } from './status-chart'; - -export interface WorkloadStatusOverviewData { - title: string; - data: Array; - onClickTitle?: () => void; -} - -const WorkloadStatusOverview = ({ data }: { data?: Array }) => { - if (!data) return null; - return ( - - {data.map(({ title, data, onClickTitle }) => ( - - ))} - - ); -}; - -export default WorkloadStatusOverview; diff --git a/frontend/providers/kubepanel/src/components/kubepanel-views/workload/pod/container-detail.tsx b/frontend/providers/kubepanel/src/components/kubepanel-views/workload/pod/container-detail.tsx deleted file mode 100644 index bcbe67bc9..000000000 --- a/frontend/providers/kubepanel/src/components/kubepanel-views/workload/pod/container-detail.tsx +++ /dev/null @@ -1,901 +0,0 @@ -import { updateResource } from '@/api/kubernetes'; -import { DrawerItem } from '@/components/common/drawer/drawer-item'; -import { KubeBadge } from '@/components/kube/kube-badge'; -import { - Container, - DaemonSet, - Deployment, - Job, - Pod, - ReplicaSet, - StatefulSet -} from '@/k8slens/kube-object'; -import { buildErrorResponse } from '@/services/backend/response'; -import { dumpKubeObject } from '@/utils/yaml'; -import { CheckOutlined, CloseOutlined, EditOutlined, SaveOutlined } from '@ant-design/icons'; -import { Button, InputNumber, Select, Tooltip } from 'antd'; -import useMessage from 'antd/lib/message/useMessage'; -import { cloneDeep, isEqual, keys } from 'lodash'; -import React, { useEffect, useMemo, useState } from 'react'; -import ContainerStatus, { ContainerLastState } from './container-status'; -import ContainerStatusBrick from './container-status-brick'; -import ProbeCard, { ExtendedProbe } from './probe-card'; - -interface Props { - pod?: Pod; - containers?: Container[]; - initContainers?: Container[]; - editable?: boolean; - workload?: Deployment | StatefulSet | DaemonSet | ReplicaSet | Job | Pod; - onUpdate?: () => void; -} - -const ContainerDetail = ({ - pod, - containers: propContainers, - initContainers: propInitContainers, - editable = true, - workload, - onUpdate -}: Props) => { - const initContainers = useMemo( - () => (pod ? pod.getInitContainers() : propInitContainers || []), - [pod, propInitContainers] - ); - const containers = useMemo( - () => (pod ? pod.getContainers() : propContainers || []), - [pod, propContainers] - ); - - if (initContainers.length === 0 && containers.length === 0) return null; - - const [selectedContainer, setSelectedContainer] = useState( - containers[0]?.name || initContainers[0]?.name || '' - ); - - const podId = pod?.getId(); - useEffect(() => { - setSelectedContainer(containers[0]?.name || initContainers[0]?.name || ''); - }, [podId, containers, initContainers]); - - const currentContainer = - containers.find((c) => c.name === selectedContainer) || - initContainers.find((c) => c.name === selectedContainer); - const isInit = !!initContainers.find((c) => c.name === selectedContainer); - - const renderOptionLabel = (container: Container, isInit: boolean) => { - let state = ''; - let status = undefined; - - if (pod) { - status = pod.getContainerStatuses().find((status) => status.name === container.name); - const stateKeys = status ? keys(status?.state ?? {}) : []; - state = stateKeys[0] ?? ''; - } - - return ( -
- {pod && } - {container.name} - {isInit && ' (Init)'} -
- ); - }; - - const options = [ - { - label: 'Init Containers', - options: initContainers.map((c) => ({ - label: renderOptionLabel(c, true), - value: c.name - })) - }, - { - label: 'Containers', - options: containers.map((c) => ({ - label: renderOptionLabel(c, false), - value: c.name - })) - } - ].filter((group) => group.options.length > 0); - - const isSingleContainer = containers.length + initContainers.length <= 1; - - return ( - <> -
-
Containers
- setProbeType(val as ProbeType)} - options={[ - { value: 'none', label: 'Null' }, - { value: 'httpGet', label: 'HTTP GET' }, - { value: 'tcpSocket', label: 'TCP Socket' }, - { value: 'exec', label: 'Exec' }, - { value: 'grpc', label: 'gRPC' } - ]} - /> - {probeType === 'httpGet' && ( - { - setHttpUrl(e.target.value); - const parsed = parseHttpUrl(e.target.value); - setHttpFields((prev) => ({ - ...prev, - scheme: parsed.scheme, - host: parsed.host || '', - port: parsed.port, - path: parsed.path - })); - }} - /> - )} - {probeType === 'tcpSocket' && ( - setTcpPort(val ?? undefined)} - /> - )} - {probeType === 'grpc' && ( - <> - - setGrpcFields((prev) => ({ ...prev, port: val ?? undefined })) - } - /> - - setGrpcFields((prev) => ({ ...prev, service: e.target.value })) - } - /> - - )} - {probeType === 'exec' && ( - setExecCommand(e.target.value)} - /> - )} - - - )} -
- -
-
- First probe - {isEditing ? ( - - - setTiming((prev) => ({ ...prev, initialDelaySeconds: val ?? 0 })) - } - /> - - ) : ( - - {displayProbe?.initialDelaySeconds ?? 0} - - )} - s after startup, then every - {isEditing ? ( - - setTiming((prev) => ({ ...prev, periodSeconds: val ?? 1 }))} - /> - - ) : ( - - {displayProbe?.periodSeconds ?? 0} - - )} - s with - {isEditing ? ( - - setTiming((prev) => ({ ...prev, timeoutSeconds: val ?? 1 }))} - /> - - ) : ( - - {displayProbe?.timeoutSeconds ?? 0} - - )} - s timeout. -
- -
- Status changes after - {isEditing ? ( - - - setTiming((prev) => ({ ...prev, successThreshold: val ?? 1 })) - } - /> - - ) : ( - - {displayProbe?.successThreshold ?? 0} - - )} - success or - {isEditing ? ( - - - setTiming((prev) => ({ ...prev, failureThreshold: val ?? 1 })) - } - /> - - ) : ( - - {displayProbe?.failureThreshold ?? 0} - - )} - consecutive failures. -
-
- - )} - - ); -}; - -export default ProbeCard; diff --git a/frontend/providers/kubepanel/src/components/kubepanel-views/workload/statefulset/statefulset-detail.tsx b/frontend/providers/kubepanel/src/components/kubepanel-views/workload/statefulset/statefulset-detail.tsx deleted file mode 100644 index 374bf2963..000000000 --- a/frontend/providers/kubepanel/src/components/kubepanel-views/workload/statefulset/statefulset-detail.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import { Drawer } from '@/components/common/drawer/drawer'; -import { DrawerItem } from '@/components/common/drawer/drawer-item'; -import { DrawerPanel } from '@/components/common/drawer/drawer-panel'; -import { DetailDrawerProps } from '@/components/common/panel-table/table'; -import { KubeBadge } from '@/components/kube/kube-badge'; -import { KubeObjectInfoList } from '@/components/kube/object/detail/kube-object-detail-info-list'; -import { StatefulSet } from '@/k8slens/kube-object'; -import { useStatefulSetStore } from '@/store/kube'; -import { Divider } from 'antd'; -import ContainerDetail from '../pod/container-detail'; -import PodDetailAffinities from '../pod/pod-detail-affinities'; -import PodDetailSecurityContext from '../pod/pod-detail-security-context'; -import PodDetailTolerations from '../pod/pod-detail-tolerations'; - -const StatefulSetDetail = ({ obj: stat, open, onClose }: DetailDrawerProps) => { - if (!stat || !(stat instanceof StatefulSet)) return null; - - const selectors = stat.getSelectors(); - const spec = stat.spec; - const { initialize } = useStatefulSetStore(); - - return ( - - - - {selectors.length > 0 && ( - - {[...selectors].sort().map((label) => { - const sepIndex = label.indexOf(': '); - if (sepIndex === -1) - return ; - const key = label.slice(0, sepIndex); - const value = label.slice(sepIndex + 2); - return ( - - {key} - : - {value} - - } - className="m-0!" - /> - ); - })} - - } - /> - )} - - - initialize(() => {}, true)} - /> - - initialize(() => {}, true)} - /> - - - ); -}; - -export default StatefulSetDetail; diff --git a/frontend/providers/kubepanel/src/components/kubepanel-views/workload/statefulset/statefulset.tsx b/frontend/providers/kubepanel/src/components/kubepanel-views/workload/statefulset/statefulset.tsx deleted file mode 100644 index e130ffbde..000000000 --- a/frontend/providers/kubepanel/src/components/kubepanel-views/workload/statefulset/statefulset.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import { KubeObjectAge } from '@/components/kube/object/kube-object-age'; -import { StatefulSet } from '@/k8slens/kube-object'; -import { ColumnsType } from 'antd/es/table'; -import StatefulSetDetail from './statefulset-detail'; -import { usePodStore, useStatefulSetStore } from '@/store/kube'; -import { PanelTable } from '@/components/common/panel-table/table'; -import { ActionButton } from '@/components/common/action/action-button'; - -const columns: ColumnsType = [ - { - title: 'Pods', - key: 'pods', - render: (_, stat) => { - const { readyReplicas = 0, replicas = 0 } = stat.status ?? {}; - return `${readyReplicas}/${replicas}`; - } - }, - - { - title: 'Age', - key: 'age', - render: (_, stat) => - }, - { - key: 'action', - fixed: 'right', - render: (_, stat) => - } -]; - -const StatefulSetOverviewPage = () => { - // The detailed information of Stateful Set resource needs to be provided by Pod resource. - const { initialize: initializePods, isLoaded: isPodsLoaded } = usePodStore(); - const { - items: stats, - initialize: initializeStats, - isLoaded: isStatsLoaded - } = useStatefulSetStore(); - - return ( - stat.getId()} - initializers={[initializeStats, initializePods]} - getDetailItem={(stat) => stat} - /> - ); -}; - -export default StatefulSetOverviewPage; diff --git a/frontend/providers/kubepanel/src/constants/kube-object.ts b/frontend/providers/kubepanel/src/constants/kube-object.ts deleted file mode 100644 index 5116680ef..000000000 --- a/frontend/providers/kubepanel/src/constants/kube-object.ts +++ /dev/null @@ -1,16 +0,0 @@ -export enum KubeObjectKind { - Pod = 'Pod', - Deployment = 'Deployment', - StatefulSet = 'StatefulSet', - ConfigMap = 'ConfigMap', - PersistentVolumeClaim = 'PersistentVolumeClaim', - Secret = 'Secret', - Ingress = 'Ingress', - Event = 'Event', - Service = 'Service', - // CustomResource - Devbox = 'Devbox', - DevboxOld = 'DevboxOld', - Cluster = 'Cluster', - Bucket = 'Bucket' -} diff --git a/frontend/providers/kubepanel/src/constants/pod.ts b/frontend/providers/kubepanel/src/constants/pod.ts deleted file mode 100644 index 4f0ec0164..000000000 --- a/frontend/providers/kubepanel/src/constants/pod.ts +++ /dev/null @@ -1,10 +0,0 @@ -export const PodStatusMessage = [ - 'Evicted', - 'Terminating', - 'Waiting', - 'Terminated', - 'Pending', - 'Running', - 'Succeeded', - 'Failed' -]; diff --git a/frontend/providers/kubepanel/src/constants/theme.ts b/frontend/providers/kubepanel/src/constants/theme.ts deleted file mode 100644 index d999535eb..000000000 --- a/frontend/providers/kubepanel/src/constants/theme.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { ThemeConfig } from 'antd'; -import { editor } from 'monaco-editor'; - -export const theme: ThemeConfig = { - components: { - Menu: { - itemSelectedBg: '#1118240D', - itemSelectedColor: '#0884DD', - itemHoverColor: '#485264', - itemHoverBg: '#1118240D', - itemColor: '#485264' - }, - Collapse: { - headerPadding: 0 - }, - Table: { - headerBorderRadius: 0, - headerBg: '#F6F8F9' - }, - Tooltip: { - colorBgSpotlight: '#FFFFFF', - colorTextLightSolid: '#000000' - } - }, - token: { - controlItemBgHover: '#1118240D' - }, - cssVar: {} -}; - -export const monacoTheme: editor.IStandaloneThemeData = { - base: 'vs', - inherit: false, - rules: [ - { - token: 'string', - foreground: 'E82F72' - }, - { - token: 'symbol', - foreground: '027A48' - }, - { - token: 'number', - foreground: '667085' - }, - { - token: 'comment', - foreground: '9E53C1' - }, - { - token: 'operators', - foreground: '027A48' - }, - { - token: 'keyword', - foreground: '00A9A6' - } - ], - colors: { - 'editor.foreground': '#0770BC', - 'editor.background': '#FBFBFC', - 'editor.selectionBackground': '#DBF3FF', - 'editor.lineHighlightBackground': '#F4F4F7', - 'editorLineNumber.foreground': '#787A90', - 'editorLineNumber.activeForeground': '#219bf4', - 'editorCursor.foreground': '#111824', - 'editorWhitespace.foreground': '#BBBBBB' - } -}; diff --git a/frontend/providers/kubepanel/src/hooks/useConfirm.tsx b/frontend/providers/kubepanel/src/hooks/useConfirm.tsx deleted file mode 100644 index dcf848b30..000000000 --- a/frontend/providers/kubepanel/src/hooks/useConfirm.tsx +++ /dev/null @@ -1,82 +0,0 @@ -import { - AlertDialog, - AlertDialogBody, - AlertDialogContent, - AlertDialogFooter, - AlertDialogHeader, - AlertDialogOverlay, - Button, - useDisclosure -} from '@chakra-ui/react'; -import { useCallback, useRef } from 'react'; - -export const useConfirm = ({ - title = 'Prompt', - content, - confirmText = 'Confirm' -}: { - title?: string; - content: string; - confirmText?: string; -}) => { - const { isOpen, onOpen, onClose } = useDisclosure(); - // const { t } = useTranslation(); - const cancelRef = useRef(null); - const confirmCb = useRef(); - const cancelCb = useRef(); - - return { - openConfirm: useCallback( - (confirm?: any, cancel?: any) => { - return function () { - onOpen(); - confirmCb.current = confirm; - cancelCb.current = cancel; - }; - }, - [onOpen] - ), - ConfirmChild: useCallback( - () => ( - - - - - {/* {t(title)} */} - {title} - - - {content} - - - - - - - - - ), - // [confirmText, content, isOpen, onClose, t, title] - [confirmText, content, isOpen, onClose, title] - ) - }; -}; diff --git a/frontend/providers/kubepanel/src/hooks/useWatcher.tsx b/frontend/providers/kubepanel/src/hooks/useWatcher.tsx deleted file mode 100644 index 37004a035..000000000 --- a/frontend/providers/kubepanel/src/hooks/useWatcher.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { APICallback, KubeStoreAction } from '@/types/state'; -import useNotification from 'antd/lib/notification/useNotification'; - -import { useEffect, useRef } from 'react'; - -interface Props { - initializers: Array['initialize']>; -} - -export function useWatcher({ initializers }: Props) { - const [notifyApi, cxtHolder] = useNotification(); - const initializersRef = useRef(initializers); - const hasRunRef = useRef(false); - - useEffect(() => { - // Update the ref with the latest initializers - initializersRef.current = initializers; - }, [initializers]); - - useEffect(() => { - // Only run once per component mount - if (hasRunRef.current) return; - hasRunRef.current = true; - - const callback: APICallback = (_, e) => { - if (e) { - notifyApi.error({ - message: e.error.reason, - description: e.error.message, - duration: 5 - }); - } - }; - - Promise.allSettled(initializersRef.current.map((initializer) => initializer(callback, true))); - }, [notifyApi]); // Only run once per component mount (guarded by hasRunRef) - - return cxtHolder; -} diff --git a/frontend/providers/kubepanel/src/k8slens/README.md b/frontend/providers/kubepanel/src/k8slens/README.md deleted file mode 100644 index 004331ac9..000000000 --- a/frontend/providers/kubepanel/src/k8slens/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# k8slens - -This folder use [Lens](https://github.com/lensapp/lens)' source code. -We obey MIT License. diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/index.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/index.ts deleted file mode 100644 index d21d2e86b..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -export * from './src/api-types'; -export * from './src/kube-object'; -export * from './src/kube-status'; -export * from './src/specifics'; -export * from './src/types'; -export * from './src/utils'; diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/api-types.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/api-types.ts deleted file mode 100644 index 0d7df9e1e..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/api-types.ts +++ /dev/null @@ -1,415 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -/** - * The metadata for LIST requests to the KubeApi - */ -export interface KubeJsonApiListMetadata { - resourceVersion: string; - selfLink?: string; -} - -export interface KubeJsonApiDataList { - kind: string; - apiVersion: string; - items: T[]; - metadata: KubeJsonApiListMetadata; -} - -export interface KubeJsonApiData< - Metadata extends KubeJsonApiObjectMetadata = KubeJsonApiObjectMetadata, - Status = unknown, - Spec = unknown -> { - readonly kind: string; - readonly apiVersion: string; - metadata: Metadata; - status?: Status; - spec?: Spec; - [otherKeys: string]: unknown; -} - -export type KubeJsonApiDataFor = K extends { - metadata: infer Metadata; - status?: infer Status; - spec?: infer Spec; -} - ? KubeJsonApiData< - Metadata extends KubeJsonApiObjectMetadata ? Metadata : KubeJsonApiObjectMetadata, - Status, - Spec - > - : never; - -export interface KubeObjectConstructorData { - readonly kind?: string; - readonly namespaced?: boolean; - readonly apiBase?: string; -} - -export type KubeObjectConstructor< - K extends { - kind: string; - apiVersion: string; - metadata: KubeObjectMetadata; - }, - Data -> = (new (data: Data) => K) & KubeObjectConstructorData; - -export interface OwnerReference { - apiVersion: string; - kind: string; - name: string; - uid: string; - controller?: boolean; - blockOwnerDeletion?: boolean; -} - -export type KubeTemplateObjectMetadata = Pick< - KubeJsonApiObjectMetadata, - 'annotations' | 'finalizers' | 'generateName' | 'labels' | 'ownerReferences' -> & { - name?: string; - namespace?: ScopedNamespace; -}; - -export interface BaseKubeJsonApiObjectMetadata { - /** - * Annotations is an unstructured key value map stored with a resource that may be set by - * external tools to store and retrieve arbitrary metadata. They are not queryable and should be - * preserved when modifying objects. - * - * More info: http://kubernetes.io/docs/user-guide/annotations - */ - annotations?: Partial>; - - /** - * The name of the cluster which the object belongs to. This is used to distinguish resources - * with same name and namespace in different clusters. This field is not set anywhere right now - * and api server is going to ignore it if set in create or update request. - */ - clusterName?: string; - - /** - * CreationTimestamp is a timestamp representing the server time when this object was created. It - * is not guaranteed to be set in happens-before order across separate operations. Clients may - * not set this value. It is represented in RFC3339 form and is in UTC. Populated by the system. - * - * More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - */ - readonly creationTimestamp?: string; - - /** - * Number of seconds allowed for this object to gracefully terminate before it will be removed - * from the system. Only set when deletionTimestamp is also set. May only be shortened. - */ - readonly deletionGracePeriodSeconds?: number; - - /** - * DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This field - * is set by the server when a graceful deletion is requested by the user, and is not directly - * settable by a client. The resource is expected to be deleted (no longer visible from resource - * lists, and not reachable by name) after the time in this field, once the finalizers list is - * empty. As long as the finalizers list contains items, deletion is blocked. Once the - * `deletionTimestamp` is set, this value may not be unset or be set further into the future, - * although it may be shortened or the resource may be deleted prior to this time. For example, - * a user may request that a pod is deleted in 30 seconds. The Kubelet will react by sending a - * graceful termination signal to the containers in the pod. After that 30 seconds, the Kubelet - * will send a hard termination signal (SIGKILL) to the container and after cleanup, remove the - * pod from the API. In the presence of network partitions, this object may still exist after - * this timestamp, until an administrator or automated process can determine the resource is - * fully terminated. If not set, graceful deletion of the object has not been requested. - * Populated by the system when a graceful deletion is requested. - * - * More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - */ - readonly deletionTimestamp?: string; - - /** - * Must be empty before the object is deleted from the registry. Each entry is an identifier for - * the responsible component that will remove the entry from the list. If the deletionTimestamp - * of the object is non-nil, entries in this list can only be removed. Finalizers may be - * processed and removed in any order. Order is NOT enforced because it introduces significant - * risk of stuck finalizers. finalizers is a shared field, any actor with permission can reorder - * it. If the finalizer list is processed in order, then this can lead to a situation in which - * the component responsible for the first finalizer in the list is waiting for a signal (field - * value, external system, or other) produced by a component responsible for a finalizer later in - * the list, resulting in a deadlock. Without enforced ordering finalizers are free to order - * amongst themselves and are not vulnerable to ordering changes in the list. - */ - finalizers?: string[]; - - /** - * GenerateName is an optional prefix, used by the server, to generate a unique name ONLY IF the - * Name field has not been provided. If this field is used, the name returned to the client will - * be different than the name passed. This value will also be combined with a unique suffix. The - * provided value has the same validation rules as the Name field, and may be truncated by the - * length of the suffix required to make the value unique on the server. If this field is - * specified and the generated name exists, the server will NOT return a 409 - instead, it will - * either return 201 Created or 500 with Reason ServerTimeout indicating a unique name could not - * be found in the time allotted, and the client should retry (optionally after the time indicated - * in the Retry-After header). Applied only if Name is not specified. - * - * More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency - */ - generateName?: string; - - /** - * A sequence number representing a specific generation of the desired state. Populated by the - * system. - */ - readonly generation?: number; - - /** - * Map of string keys and values that can be used to organize and categorize (scope and select) - * objects. May match selectors of replication controllers and services. - * - * More info: http://kubernetes.io/docs/user-guide/labels - */ - labels?: Partial>; - - /** - * ManagedFields maps workflow-id and version to the set of fields that are managed by that - * workflow. This is mostly for internal housekeeping, and users typically shouldn't need to set - * or understand this field. A workflow can be the user's name, a controller's name, or the name - * of a specific apply path like "ci-cd". The set of fields is always in the version that the - * workflow used when modifying the object. - */ - managedFields?: unknown[]; - - /** - * Name must be unique within a namespace. Is required when creating resources, although some - * resources may allow a client to request the generation of an appropriate name automatically. - * Name is primarily intended for creation idempotence and configuration definition. - * - * More info: http://kubernetes.io/docs/user-guide/identifiers#names - */ - readonly name: string; - - /** - * Namespace defines the space within which each name must be unique. An empty namespace is - * equivalent to the "default" namespace, but "default" is the canonical representation. Not all - * objects are required to be scoped to a namespace - the value of this field for those objects - * will be empty. Must be a DNS_LABEL. Cannot be updated. More info: http://kubernetes.io/docs/user-guide/namespaces - */ - readonly namespace?: ScopedNamespace; - - /** - * List of objects depended by this object. If ALL objects in the list have been deleted, this - * object will be garbage collected. If this object is managed by a controller, then an entry in - * this list will point to this controller, with the controller field set to true. There cannot - * be more than one managing controller. - */ - ownerReferences?: OwnerReference[]; - - /** - * An opaque value that represents the internal version of this object that can be used by - * clients to determine when objects have changed. May be used for optimistic concurrency, change - * detection, and the watch operation on a resource or set of resources. Clients must treat these - * values as opaque and passed unmodified back to the server. They may only be valid for a - * particular resource or set of resources. Populated by the system. Value must be treated as - * opaque by clients. - * - * More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency - */ - readonly resourceVersion?: string; - - /** - * SelfLink is a URL representing this object. Populated by the system. - */ - readonly selfLink?: string; - - /** - * UID is the unique in time and space value for this object. It is typically generated by the - * server on successful creation of a resource and is not allowed to change on PUT operations. - * Populated by the system. - * - * More info: http://kubernetes.io/docs/user-guide/identifiers#uids - */ - readonly uid?: string; - - [key: string]: unknown; -} - -export type KubeJsonApiObjectMetadata = - BaseKubeJsonApiObjectMetadata & - (Namespaced extends KubeObjectScope.Namespace ? { readonly namespace: string } : {}); - -export type KubeObjectMetadata = - KubeJsonApiObjectMetadata & { - readonly selfLink: string; - }; - -export type NamespaceScopedMetadata = KubeObjectMetadata; -export type ClusterScopedMetadata = KubeObjectMetadata; - -export interface KubeStatusData { - kind: string; - apiVersion: string; - code: number; - message?: string; - reason?: string; - status?: string; -} - -export interface EvictionObject { - kind: 'Eviction'; - apiVersion: string | 'policy/v1'; - metadata: Partial; - deleteOptions?: { - kind?: string; - apiVersion?: string; - dryRun?: string[]; - gracePeriodSeconds?: number; - orphanDependents?: boolean; - propagationPolicy?: string; - preconditions?: { - resourceVersion: string; - uid: string; - }[]; - }; -} - -export interface BaseKubeObjectCondition { - /** - * Last time the condition transit from one status to another. - * - * @type Date - */ - lastTransitionTime?: string; - /** - * A human readable message indicating details about last transition. - */ - message?: string; - /** - * brief (usually one word) reason for the condition's last transition. - */ - reason?: string; - /** - * Status of the condition - */ - status: 'True' | 'False' | 'Unknown'; - /** - * Type of the condition - */ - type: string; -} - -export interface KubeObjectStatus { - conditions?: BaseKubeObjectCondition[]; -} - -export type KubeMetaField = keyof KubeJsonApiObjectMetadata; - -export class KubeCreationError extends Error { - constructor( - message: string, - public data: unknown - ) { - super(message); - } -} - -export type LabelMatchExpression = { - /** - * The label key that the selector applies to. - */ - key: string; -} & ( - | { - /** - * This represents the key's relationship to a set of values. - */ - operator: 'Exists' | 'DoesNotExist'; - values?: undefined; - } - | { - operator: 'In' | 'NotIn'; - /** - * The set of values for to match according to the operator for the label. - */ - values: string[]; - } -); - -export interface Toleration { - key?: string; - operator?: string; - effect?: string; - value?: string; - tolerationSeconds?: number; -} - -export interface ObjectReference { - apiVersion?: string; - fieldPath?: string; - kind?: string; - name: string; - namespace?: string; - resourceVersion?: string; - uid?: string; -} - -export interface LocalObjectReference { - name: string; -} - -export interface TypedLocalObjectReference { - apiGroup?: string; - kind: string; - name: string; -} - -export interface NodeAffinity { - nodeSelectorTerms?: LabelSelector[]; - weight: number; - preference: LabelSelector; -} - -export interface PodAffinity { - labelSelector: LabelSelector; - topologyKey: string; -} - -export interface SpecificAffinity { - requiredDuringSchedulingIgnoredDuringExecution?: T[]; - preferredDuringSchedulingIgnoredDuringExecution?: T[]; -} - -export interface Affinity { - nodeAffinity?: SpecificAffinity; - podAffinity?: SpecificAffinity; - podAntiAffinity?: SpecificAffinity; -} - -export interface LabelSelector { - matchLabels?: Partial>; - matchExpressions?: LabelMatchExpression[]; -} - -export enum KubeObjectScope { - Namespace, - Cluster -} - -export type ScopedNamespace = - Namespaced extends KubeObjectScope.Namespace - ? string - : Namespaced extends KubeObjectScope.Cluster - ? undefined - : string | undefined; - -export interface RawKubeObject< - Metadata extends KubeObjectMetadata = KubeObjectMetadata, - Status = Record, - Spec = Record -> { - apiVersion: string; - kind: string; - metadata: Metadata; - status?: Status; - spec?: Spec; - [otherFields: string]: unknown; -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/kube-object.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/kube-object.ts deleted file mode 100644 index 073cc2bec..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/kube-object.ts +++ /dev/null @@ -1,102 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import { isObject, isString } from '@/k8slens/utilities'; -import autoBind from 'auto-bind'; -import type { KubeJsonApiData, KubeObjectMetadata, KubeObjectScope } from './api-types'; -import { KubeCreationError } from './api-types'; -import { filterOutResourceApplierAnnotations, stringifyLabels } from './utils'; - -export class KubeObject< - Metadata extends KubeObjectMetadata = KubeObjectMetadata, - Status = unknown, - Spec = unknown -> { - static readonly kind?: string; - - static readonly namespaced?: boolean; - - static readonly apiBase?: string; - - apiVersion!: string; - - kind!: string; - - metadata!: Metadata; - - status?: Status; - - spec!: Spec; - - /** - * @deprecated Switch to using {@link stringifyLabels} instead - */ - static stringifyLabels = stringifyLabels; - - constructor(data: KubeJsonApiData) { - if (!isObject(data)) { - throw new TypeError(`Cannot create a KubeObject from ${typeof data}`); - } - - if (!isObject(data.metadata)) { - throw new KubeCreationError( - `Cannot create a KubeObject from an object without metadata`, - data - ); - } - - if (!isString(data.metadata.name)) { - throw new KubeCreationError( - `Cannot create a KubeObject from an object without metadata.name being a string`, - data - ); - } - - Object.assign(this, data); - autoBind(this); - } - - getId(): string { - return this.metadata.uid ?? this.metadata.selfLink; - } - - getResourceVersion(): string { - return this.metadata.resourceVersion ?? ''; - } - - getName(): string { - return this.metadata.name; - } - - getNs(): Metadata['namespace'] { - // avoid "null" serialization via JSON.stringify when post data - return this.metadata.namespace || undefined; - } - - getFinalizers(): string[] { - return this.metadata.finalizers || []; - } - - getLabels(): string[] { - return KubeObject.stringifyLabels(this.metadata.labels); - } - - getAnnotations(filter = false): string[] { - const labels = KubeObject.stringifyLabels(this.metadata.annotations); - - if (!filter) { - return labels; - } - - return labels.filter(filterOutResourceApplierAnnotations); - } - - getOwnerRefs() { - const refs = this.metadata.ownerReferences || []; - const namespace = this.getNs(); - - return refs.map((ownerRef) => ({ ...ownerRef, namespace })); - } -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/kube-status.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/kube-status.ts deleted file mode 100644 index c770848f0..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/kube-status.ts +++ /dev/null @@ -1,59 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import { - hasOptionalTypedProperty, - hasTypedProperty, - isNumber, - isObject, - isString -} from '@/k8slens/utilities'; -import type { KubeStatusData } from './api-types'; - -/** - * Is the shape of {@link object} correct for {@link KubeStatusData} - * @param object Some object - * @returns - */ -export function isKubeStatusData(object: unknown): object is KubeStatusData { - return ( - isObject(object) && - hasTypedProperty(object, 'kind', isString) && - hasTypedProperty(object, 'apiVersion', isString) && - hasTypedProperty(object, 'code', isNumber) && - (hasOptionalTypedProperty(object, 'message', isString) || - hasOptionalTypedProperty(object, 'reason', isString) || - hasOptionalTypedProperty(object, 'status', isString)) && - object.kind === 'Status' - ); -} - -export class KubeStatus { - public readonly kind = 'Status'; - - public readonly apiVersion: string; - - public readonly code: number; - - public readonly message: string; - - public readonly reason: string; - - public readonly status: string; - - constructor(data: KubeStatusData) { - this.apiVersion = data.apiVersion; - this.code = data.code; - this.message = data.message || ''; - this.reason = data.reason || ''; - this.status = data.status || ''; - } - - getExplanation(): string { - const { code, message, reason, status } = this; - - return `${code}: ${message || reason || status}`; - } -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/bucket.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/bucket.ts deleted file mode 100644 index 6be80b1ce..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/bucket.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { KubeObjectMetadata, KubeObjectScope } from '../api-types'; -import { KubeObject } from '../kube-object'; - -export interface BucketSpec { - policy?: string; -} - -export interface BucketStatus { - name?: string; -} - -export class Bucket extends KubeObject< - KubeObjectMetadata, - BucketStatus, - BucketSpec -> { - static readonly kind = 'Bucket'; - static readonly namespaced = true; - static readonly apiBase = '/apis/objectstorage.sealos.io/v1/objectstoragebuckets'; - - getPolicy(): string { - return this.spec?.policy || ''; - } - - getBucketName(): string { - return this.status?.name || ''; - } -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/cluster.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/cluster.ts deleted file mode 100644 index d4306aaa4..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/cluster.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { KubeObjectMetadata, KubeObjectScope } from '../api-types'; -import { KubeObject } from '../kube-object'; - -export interface ClusterComponentSpec { - componentDefRef?: string; - name?: string; - replicas?: number; - resources?: { - limits?: { cpu?: string; memory?: string }; - requests?: { cpu?: string; memory?: string }; - }; - volumeClaimTemplates?: Array<{ - name?: string; - spec?: { - resources?: { - requests?: { storage?: string }; - }; - }; - }>; -} - -export interface ClusterSpec { - clusterDefinitionRef?: string; - clusterVersionRef?: string; - terminationPolicy?: string; - componentSpecs?: ClusterComponentSpec[]; - backup?: { - enabled?: boolean; - cronExpression?: string; - method?: string; - }; -} - -export interface ClusterComponentStatus { - phase?: string; - podsReady?: boolean; -} - -export interface ClusterStatus { - phase?: string; - components?: Record; - conditions?: Array<{ - type?: string; - status?: string; - reason?: string; - message?: string; - }>; -} - -export class Cluster extends KubeObject< - KubeObjectMetadata, - ClusterStatus, - ClusterSpec -> { - static readonly kind = 'Cluster'; - static readonly namespaced = true; - static readonly apiBase = '/apis/apps.kubeblocks.io/v1alpha1/clusters'; - - getPhase(): string { - return this.status?.phase || 'Unknown'; - } - - getClusterDefinition(): string { - return this.spec?.clusterDefinitionRef || ''; - } - - getClusterVersion(): string { - return this.spec?.clusterVersionRef || ''; - } - - getTerminationPolicy(): string { - return this.spec?.terminationPolicy || ''; - } - - getReplicas(): number { - return this.spec?.componentSpecs?.[0]?.replicas || 0; - } - - getCpu(): string { - return this.spec?.componentSpecs?.[0]?.resources?.limits?.cpu || ''; - } - - getMemory(): string { - return this.spec?.componentSpecs?.[0]?.resources?.limits?.memory || ''; - } - - getStorage(): string { - return ( - this.spec?.componentSpecs?.[0]?.volumeClaimTemplates?.[0]?.spec?.resources?.requests - ?.storage || '' - ); - } - - isBackupEnabled(): boolean { - return this.spec?.backup?.enabled || false; - } - - getComponentPhase(componentName: string): string { - return this.status?.components?.[componentName]?.phase || ''; - } -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/config-map.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/config-map.ts deleted file mode 100644 index 596d46493..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/config-map.ts +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import autoBind from 'auto-bind'; -import type { - KubeJsonApiData, - KubeObjectMetadata, - KubeObjectScope, - NamespaceScopedMetadata -} from '../api-types'; -import { KubeObject } from '../kube-object'; - -export interface ConfigMapData - extends KubeJsonApiData, void, void> { - data?: Partial>; - binaryData?: Partial>; - immutable?: boolean; -} - -export class ConfigMap extends KubeObject { - static kind = 'ConfigMap'; - - static namespaced = true; - - static apiBase = '/api/v1/configmaps'; - - data: Partial>; - - binaryData: Partial>; - - immutable?: boolean; - - constructor({ data, binaryData, immutable, ...rest }: ConfigMapData) { - super(rest); - autoBind(this); - - this.data = data ?? {}; - this.binaryData = binaryData ?? {}; - this.immutable = immutable; - } - - getKeys(): string[] { - return Object.keys(this.data); - } -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/daemon-set.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/daemon-set.ts deleted file mode 100644 index 6b9e54211..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/daemon-set.ts +++ /dev/null @@ -1,77 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import type { KubeObjectStatus, LabelSelector, NamespaceScopedMetadata } from '../api-types'; -import { KubeObject } from '../kube-object'; -import type { PodTemplateSpec } from '../types/pod-template-spec'; - -export interface RollingUpdateDaemonSet { - maxUnavailable?: number | string; - maxSurge?: number | string; -} - -export interface DaemonSetUpdateStrategy { - type: string; - rollingUpdate: RollingUpdateDaemonSet; -} - -export interface DaemonSetSpec { - selector: LabelSelector; - template: PodTemplateSpec; - updateStrategy: DaemonSetUpdateStrategy; - minReadySeconds?: number; - revisionHistoryLimit?: number; -} - -export interface DaemonSetStatus extends KubeObjectStatus { - collisionCount?: number; - currentNumberScheduled: number; - desiredNumberScheduled: number; - numberAvailable?: number; - numberMisscheduled: number; - numberReady: number; - numberUnavailable?: number; - observedGeneration?: number; - updatedNumberScheduled?: number; -} - -export class DaemonSet extends KubeObject { - static kind = 'DaemonSet'; - - static namespaced = true; - - static apiBase = '/apis/apps/v1/daemonsets'; - - getSelectors(): string[] { - return KubeObject.stringifyLabels(this.spec.selector.matchLabels); - } - - getNodeSelectors(): string[] { - return KubeObject.stringifyLabels(this.spec.template.spec?.nodeSelector); - } - - getTemplateLabels(): string[] { - return KubeObject.stringifyLabels(this.spec.template.metadata?.labels); - } - - getTolerations() { - return this.spec.template.spec?.tolerations ?? []; - } - - getAffinity() { - return this.spec.template.spec?.affinity; - } - - getAffinityNumber() { - return Object.keys(this.getAffinity() ?? {}).length; - } - - getImages() { - const containers = this.spec.template?.spec?.containers ?? []; - const initContainers = this.spec.template?.spec?.initContainers ?? []; - - return [...containers, ...initContainers].map((container) => container.image); - } -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/deployment.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/deployment.ts deleted file mode 100644 index babf50547..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/deployment.ts +++ /dev/null @@ -1,92 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import type { KubeObjectStatus, LabelSelector, NamespaceScopedMetadata } from '../api-types'; -import { KubeObject } from '../kube-object'; -import type { PodSpec } from './pod'; - -export interface DeploymentSpec { - replicas: number; - selector: LabelSelector; - template: { - metadata: { - creationTimestamp?: string; - labels: Partial>; - annotations?: Partial>; - }; - spec: PodSpec; - }; - strategy: { - type: string; - rollingUpdate: { - maxUnavailable: number; - maxSurge: number; - }; - }; -} - -export interface DeploymentStatus extends KubeObjectStatus { - observedGeneration: number; - replicas: number; - updatedReplicas: number; - readyReplicas: number; - availableReplicas?: number; -} - -export class Deployment extends KubeObject< - NamespaceScopedMetadata, - DeploymentStatus, - DeploymentSpec -> { - static kind = 'Deployment'; - - static namespaced = true; - - static apiBase = '/apis/apps/v1/deployments'; - - getSelectors(): string[] { - return KubeObject.stringifyLabels(this.spec.selector.matchLabels); - } - - getNodeSelectors(): string[] { - return KubeObject.stringifyLabels(this.spec.template.spec.nodeSelector); - } - - getTemplateLabels(): string[] { - return KubeObject.stringifyLabels(this.spec.template.metadata.labels); - } - - getTolerations() { - return this.spec.template.spec.tolerations ?? []; - } - - getAffinity() { - return this.spec.template.spec.affinity; - } - - getAffinityNumber() { - return Object.keys(this.getAffinity() ?? {}).length; - } - - getConditions(activeOnly = false) { - const { conditions = [] } = this.status ?? {}; - - if (activeOnly) { - return conditions.filter((c) => c.status === 'True'); - } - - return conditions; - } - - getConditionsText(activeOnly = true) { - return this.getConditions(activeOnly) - .map(({ type }) => type) - .join(' '); - } - - getReplicas() { - return this.spec.replicas || 0; - } -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/devbox.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/devbox.ts deleted file mode 100644 index 6a764b68a..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/devbox.ts +++ /dev/null @@ -1,150 +0,0 @@ -import { KubeObjectMetadata, KubeObjectScope } from '../api-types'; -import { KubeObject } from '../kube-object'; - -export interface DevboxSpec { - state?: string; - resource?: { - cpu?: string; - memory?: string; - }; - image?: string; - runtimeClassName?: string; - storageLimit?: string; - templateID?: string; - network?: { - type?: string; - }; - config?: { - user?: string; - workingDir?: string; - appPorts?: Array<{ - name: string; - port: number; - protocol?: string; - }>; - ports?: Array<{ - containerPort: number; - name: string; - protocol?: string; - }>; - }; -} - -export interface DevboxStatus { - phase?: string; - state?: string; - node?: string; - network?: { - type?: string; - nodePort?: number; - tailnet?: string; - }; - lastContainerStatus?: { - image?: string; - name?: string; - ready?: boolean; - restartCount?: number; - started?: boolean; - state?: { - running?: { startedAt?: string }; - waiting?: { reason?: string; message?: string }; - terminated?: { reason?: string; exitCode?: number }; - }; - }; - contentID?: string; -} - -export class Devbox extends KubeObject< - KubeObjectMetadata, - DevboxStatus, - DevboxSpec -> { - static readonly kind = 'Devbox'; - static readonly namespaced = true; - static readonly apiBase = '/apis/devbox.sealos.io/v1alpha2/devboxes'; - - getPhase(): string { - return this.status?.phase || 'Unknown'; - } - - getState(): string { - const statusState = this.status?.state; - const specState = this.spec?.state; - - // If status.state is a string, use it - if (typeof statusState === 'string') { - return statusState; - } - - // If status.state is an object (container state), extract the state key - if (statusState && typeof statusState === 'object') { - if ('running' in statusState) return 'Running'; - if ('waiting' in statusState) return 'Waiting'; - if ('terminated' in statusState) return 'Terminated'; - } - - // Fallback to spec.state or default - if (typeof specState === 'string') { - return specState; - } - - return 'Unknown'; - } - - getImage(): string { - return this.spec?.image || ''; - } - - getRuntimeClassName(): string { - return this.spec?.runtimeClassName || ''; - } - - getCpu(): string { - return this.spec?.resource?.cpu || ''; - } - - getMemory(): string { - return this.spec?.resource?.memory || ''; - } - - getStorageLimit(): string { - return this.spec?.storageLimit || ''; - } - - getNode(): string { - return this.status?.node || ''; - } - - getNodePort(): number | undefined { - return this.status?.network?.nodePort; - } - - getNetworkType(): string { - return this.status?.network?.type || this.spec?.network?.type || ''; - } - - getContainerStatus(): string { - const state = this.status?.lastContainerStatus?.state; - if (state?.running) return 'Running'; - if (state?.waiting) return state.waiting.reason || 'Waiting'; - if (state?.terminated) return state.terminated.reason || 'Terminated'; - return ''; - } - - getUser(): string { - return this.spec?.config?.user || ''; - } - - getWorkingDir(): string { - return this.spec?.config?.workingDir || ''; - } - - getAppPorts(): Array<{ name: string; port: number; protocol?: string }> { - return this.spec?.config?.appPorts || []; - } - - getSshPort(): number | undefined { - const sshPort = this.spec?.config?.ports?.find((p) => p.name === 'devbox-ssh-port'); - return sshPort?.containerPort; - } -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/events.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/events.ts deleted file mode 100644 index 885cf0a2d..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/events.ts +++ /dev/null @@ -1,156 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import { formatDuration } from '@/k8slens/utilities'; -import moment from 'moment'; -import type { - KubeJsonApiData, - KubeObjectMetadata, - KubeObjectScope, - ObjectReference -} from '../api-types'; -import { KubeObject } from '../kube-object'; - -export interface EventSeries { - count?: number; - lastObservedTime?: string; -} - -export interface EventSource { - component?: string; - host?: string; -} - -export interface KubeEventData extends KubeJsonApiData< - KubeObjectMetadata, - void, - void -> { - action?: string; - count?: number; - eventTime?: string; - firstTimestamp?: string; - involvedObject: Required; - lastTimestamp?: string; - message?: string; - reason?: string; - related?: ObjectReference; - reportingComponent?: string; - reportingInstance?: string; - series?: EventSeries; - source?: EventSource; - type?: string; -} - -export class KubeEvent extends KubeObject< - KubeObjectMetadata, - void, - void -> { - static kind = 'Event'; - - static namespaced = true; - - static apiBase = '/api/v1/events'; - - action?: string; - - count?: number; - - eventTime?: string; - - firstTimestamp?: string; - - involvedObject: Required; - - lastTimestamp?: string; - - message?: string; - - reason?: string; - - related?: ObjectReference; - - reportingComponent?: string; - - reportingInstance?: string; - - series?: EventSeries; - - source?: EventSource; - - /** - * Current supported values are: - * - "Normal" - * - "Warning" - */ - type?: string; - - constructor({ - action, - count, - eventTime, - firstTimestamp, - involvedObject, - lastTimestamp, - message, - reason, - related, - reportingComponent, - reportingInstance, - series, - source, - type, - ...rest - }: KubeEventData) { - super(rest); - this.action = action; - this.count = count; - this.eventTime = eventTime; - this.firstTimestamp = firstTimestamp; - this.involvedObject = involvedObject; - this.lastTimestamp = lastTimestamp; - this.message = message; - this.reason = reason; - this.related = related; - this.reportingComponent = reportingComponent; - this.reportingInstance = reportingInstance; - this.series = series; - this.source = source; - this.type = type; - } - - isWarning() { - return this.type === 'Warning'; - } - - getSource() { - if (!this.source?.component) { - return ''; - } - - const { component, host = '' } = this.source; - - return `${component} ${host}`; - } - - /** - * @deprecated This function is not reactive to changing of time. If rendering use `` instead - */ - getFirstSeenTime() { - const diff = moment().diff(this.firstTimestamp); - - return formatDuration(diff, true); - } - - /** - * @deprecated This function is not reactive to changing of time. If rendering use `` instead - */ - getLastSeenTime() { - const diff = moment().diff(this.lastTimestamp); - - return formatDuration(diff, true); - } -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/index.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/index.ts deleted file mode 100644 index 471f7ca6b..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/index.ts +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -export * from './cluster'; -export * from './config-map'; -export * from './daemon-set'; -export * from './deployment'; -export * from './events'; -export * from './ingress'; -export * from './job'; -export * from './persistent-volume-claim'; -export * from './pod'; -export * from './replica-set'; -export * from './secret'; -export * from './service'; -export * from './stateful-set'; diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/ingress.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/ingress.ts deleted file mode 100644 index 5417f2b94..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/ingress.ts +++ /dev/null @@ -1,192 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import { hasTypedProperty, isString, iter } from '@/k8slens/utilities'; -import type { RequireExactlyOne } from 'type-fest'; -import type { NamespaceScopedMetadata, TypedLocalObjectReference } from '../api-types'; -import { KubeObject } from '../kube-object'; - -export interface ILoadBalancerIngress { - hostname?: string; - ip?: string; -} - -// extensions/v1beta1 -export interface ExtensionsBackend { - serviceName?: string; - servicePort?: number | string; -} - -// networking.k8s.io/v1 -export interface NetworkingBackend { - service?: IngressService; -} - -export type IngressBackend = (ExtensionsBackend | NetworkingBackend) & { - resource?: TypedLocalObjectReference; -}; - -export interface IngressService { - name: string; - port: RequireExactlyOne<{ - name: string; - number: number; - }>; -} - -function isExtensionsBackend(backend: IngressBackend): backend is ExtensionsBackend { - return hasTypedProperty(backend, 'serviceName', isString); -} - -// eslint-disable-next-line xss/no-mixed-html -const unknownPortString = ''; - -/** - * Format an ingress backend into the name of the service and port - * @param backend The ingress target - */ -export function getBackendServiceNamePort(backend: IngressBackend | undefined): string { - if (!backend) { - return unknownPortString; - } - - if (isExtensionsBackend(backend)) { - return `${backend.serviceName}:${backend.servicePort}`; - } - - if (backend.service) { - const { name, port } = backend.service; - - return `${name}:${port.number ?? port.name}`; - } - - return unknownPortString; -} - -export interface HTTPIngressPath { - pathType: 'Exact' | 'Prefix' | 'ImplementationSpecific'; - path?: string; - backend?: IngressBackend; -} - -export interface HTTPIngressRuleValue { - paths: HTTPIngressPath[]; -} - -export interface IngressRule { - host?: string; - http?: HTTPIngressRuleValue; -} - -export interface IngressSpec { - tls: { - secretName: string; - hosts?: string[]; - }[]; - rules?: IngressRule[]; - // extensions/v1beta1 - backend?: ExtensionsBackend; - /** - * The default backend which is exactly on of: - * - service - * - resource - */ - defaultBackend?: RequireExactlyOne< - NetworkingBackend & { - resource: { - apiGroup: string; - kind: string; - name: string; - }; - } - >; -} - -export interface IngressStatus { - loadBalancer: { - ingress?: ILoadBalancerIngress[]; - }; -} - -export class Ingress extends KubeObject { - static readonly kind = 'Ingress'; - - static readonly namespaced = true; - - static readonly apiBase = '/apis/networking.k8s.io/v1/ingresses'; - - getRules() { - return this.spec.rules ?? []; - } - - getRoutes(): string[] { - return computeRouteDeclarations(this).map(({ url, service }) => `${url} ⇢ ${service}`); - } - - getHosts() { - const { - spec: { rules = [] } - } = this; - - return [...iter.filterMap(rules, (rule) => rule.host)]; - } - - getPorts() { - const ports: number[] = []; - const { - spec: { tls, rules = [], backend, defaultBackend } - } = this; - const httpPort = 80; - const tlsPort = 443; - // Note: not using the port name (string) - const servicePort = defaultBackend?.service?.port.number ?? backend?.servicePort; - - if (rules.length > 0) { - if (rules.some((rule) => rule.http)) { - ports.push(httpPort); - } - } else if (servicePort !== undefined) { - ports.push(Number(servicePort)); - } - - if (tls && tls.length > 0) { - ports.push(tlsPort); - } - - return ports.join(', '); - } - - getLoadBalancers() { - return ( - this.status?.loadBalancer?.ingress?.map((address) => address.hostname || address.ip) ?? [] - ); - } -} - -export interface ComputedIngressRoute { - displayAsLink: boolean; - pathname: string; - url: string; - service: string; -} - -export function computeRuleDeclarations( - ingress: Ingress, - rule: IngressRule -): ComputedIngressRoute[] { - const { host = '*', http: { paths } = { paths: [] } } = rule; - const protocol = (ingress.spec?.tls?.length ?? 0) === 0 ? 'http' : 'https'; - - return paths.map(({ path = '/', backend }) => ({ - displayAsLink: !host.includes('*'), - pathname: path, - url: `${protocol}://${host}${path}`, - service: getBackendServiceNamePort(backend) - })); -} - -export function computeRouteDeclarations(ingress: Ingress): ComputedIngressRoute[] { - return ingress.getRules().flatMap((rule) => computeRuleDeclarations(ingress, rule)); -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/job.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/job.ts deleted file mode 100644 index 1299b6b63..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/job.ts +++ /dev/null @@ -1,91 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import type { KubeObjectStatus, LabelSelector, NamespaceScopedMetadata } from '../api-types'; -import { KubeObject } from '../kube-object'; -import type { Container } from '../types/container'; -import type { PodSpec } from './pod'; - -export interface JobSpec { - parallelism?: number; - completions?: number; - backoffLimit?: number; - selector?: LabelSelector; - template: { - metadata: { - creationTimestamp?: string; - labels?: Partial>; - annotations?: Partial>; - }; - spec: PodSpec; - }; - containers?: Container[]; - restartPolicy?: string; - terminationGracePeriodSeconds?: number; - dnsPolicy?: string; - serviceAccountName?: string; - serviceAccount?: string; - schedulerName?: string; -} - -export interface JobStatus extends KubeObjectStatus { - startTime: string; - completionTime: string; - succeeded: number; -} - -export class Job extends KubeObject { - static readonly kind = 'Job'; - - static readonly namespaced = true; - - static readonly apiBase = '/apis/batch/v1/jobs'; - - getSelectors(): string[] { - return KubeObject.stringifyLabels(this.spec.selector?.matchLabels); - } - - getNodeSelectors(): string[] { - return KubeObject.stringifyLabels(this.spec.template.spec.nodeSelector); - } - - getTemplateLabels(): string[] { - return KubeObject.stringifyLabels(this.spec.template.metadata.labels); - } - - getTolerations() { - return this.spec.template.spec.tolerations ?? []; - } - - getAffinity() { - return this.spec.template.spec.affinity; - } - - getAffinityNumber() { - return Object.keys(this.getAffinity() ?? {}).length; - } - - getDesiredCompletions() { - return this.spec.completions ?? 0; - } - - getCompletions() { - return this.status?.succeeded ?? 0; - } - - getParallelism() { - return this.spec.parallelism; - } - - getCondition() { - // Type of Job condition could be only Complete or Failed - // https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.21/#jobcondition-v1-batch - return this.status?.conditions?.find(({ status }) => status === 'True'); - } - - getImages() { - return this.spec.template.spec.containers?.map((container) => container.image) ?? []; - } -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/persistent-volume-claim.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/persistent-volume-claim.ts deleted file mode 100644 index f0dd590a5..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/persistent-volume-claim.ts +++ /dev/null @@ -1,69 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import { object } from '@/k8slens/utilities'; -import type { - LabelSelector, - NamespaceScopedMetadata, - TypedLocalObjectReference -} from '../api-types'; -import { KubeObject } from '../kube-object'; -import type { ResourceRequirements } from '../types/resource-requirements'; -import type { Pod } from './pod'; - -export interface PersistentVolumeClaimSpec { - accessModes?: string[]; - dataSource?: TypedLocalObjectReference; - dataSourceRef?: TypedLocalObjectReference; - resources?: ResourceRequirements; - selector?: LabelSelector; - storageClassName?: string; - volumeMode?: string; - volumeName?: string; -} - -export interface PersistentVolumeClaimStatus { - phase: string; // Pending -} - -export class PersistentVolumeClaim extends KubeObject< - NamespaceScopedMetadata, - PersistentVolumeClaimStatus, - PersistentVolumeClaimSpec -> { - static readonly kind = 'PersistentVolumeClaim'; - - static readonly namespaced = true; - - static readonly apiBase = '/api/v1/persistentvolumeclaims'; - - getPods(pods: Pod[]): Pod[] { - return pods - .filter((pod) => pod.getNs() === this.getNs()) - .filter( - (pod) => - pod - .getVolumes() - .filter((volume) => volume.persistentVolumeClaim?.claimName === this.getName()).length > - 0 - ); - } - - getStorage(): string { - return this.spec.resources?.requests?.storage ?? '-'; - } - - getMatchLabels(): string[] { - return object.entries(this.spec.selector?.matchLabels).map(([name, val]) => `${name}:${val}`); - } - - getMatchExpressions() { - return this.spec.selector?.matchExpressions ?? []; - } - - getStatus(): string { - return this.status?.phase ?? '-'; - } -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/pod.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/pod.ts deleted file mode 100644 index 3eb46bad1..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/pod.ts +++ /dev/null @@ -1,843 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import type { RequireExactlyOne } from 'type-fest'; -import type { - Affinity, - KubeObjectMetadata, - LocalObjectReference, - NamespaceScopedMetadata, - Toleration -} from '../api-types'; -import { KubeObject } from '../kube-object'; -import type { - Container, - ObjectFieldSelector, - PodSecurityContext, - Probe, - ResourceFieldSelector -} from '../types'; -import type { PersistentVolumeClaimSpec } from './persistent-volume-claim'; -import type { SecretReference } from './secret'; - -// Reference: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#read-log-pod-v1-core -export interface PodLogsQuery { - container?: string; - tailLines?: number; - timestamps?: boolean; - sinceTime?: string; // Date.toISOString()-format - follow?: boolean; - previous?: boolean; -} - -export enum PodStatusPhase { - TERMINATED = 'Terminated', - FAILED = 'Failed', - PENDING = 'Pending', - RUNNING = 'Running', - SUCCEEDED = 'Succeeded', - EVICTED = 'Evicted' -} - -export interface ContainerStateRunning { - startedAt: string; -} - -export interface ContainerStateWaiting { - reason: string; - message: string; -} - -export interface ContainerStateTerminated { - startedAt: string; - finishedAt: string; - exitCode: number; - reason: string; - containerID?: string; - message?: string; - signal?: number; -} - -/** - * ContainerState holds a possible state of container. Only one of its members - * may be specified. If none of them is specified, the default one is - * `ContainerStateWaiting`. - */ -export interface ContainerState { - running?: ContainerStateRunning; - waiting?: ContainerStateWaiting; - terminated?: ContainerStateTerminated; -} - -export type ContainerStateValues = Partial; - -export interface PodContainerStatus { - name: string; - state?: ContainerState; - lastState?: ContainerState; - ready: boolean; - restartCount: number; - image: string; - imageID: string; - containerID?: string; - started?: boolean; -} - -export interface AwsElasticBlockStoreSource { - volumeID: string; - fsType: string; -} - -export interface AzureDiskSource { - /** - * The name of the VHD blob object OR the name of an Azure managed data disk if `kind` is `"Managed"`. - */ - diskName: string; - /** - * The URI of the vhd blob object OR the `resourceID` of an Azure managed data disk if `kind` is `"Managed"`. - */ - diskURI: string; - /** - * Kind of disk - * @default "Shared" - */ - kind?: 'Shared' | 'Dedicated' | 'Managed'; - /** - * Disk caching mode. - * @default "None" - */ - cachingMode?: 'None' | 'ReadOnly' | 'ReadWrite'; - /** - * The filesystem type to mount. - * @default "ext4" - */ - fsType?: string; - /** - * Whether the filesystem is used as readOnly. - * @default false - */ - readonly?: boolean; -} - -export interface AzureFileSource { - /** - * The name of the secret that contains both Azure storage account name and key. - */ - secretName: string; - /** - * The share name to be used. - */ - shareName: string; - /** - * In case the secret is stored in a different namespace. - * @default "default" - */ - secretNamespace?: string; - /** - * Whether the filesystem is used as readOnly. - */ - readOnly: boolean; -} - -export interface CephfsSource { - /** - * List of Ceph monitors - */ - monitors: string[]; - /** - * Used as the mounted root, rather than the full Ceph tree. - * @default "/" - */ - path?: string; - /** - * The RADOS user name. - * @default "admin" - */ - user?: string; - /** - * The path to the keyring file. - * @default "/etc/ceph/user.secret" - */ - secretFile?: string; - /** - * Reference to Ceph authentication secrets. If provided, then the secret overrides `secretFile` - */ - secretRef?: SecretReference; - /** - * Whether the filesystem is used as readOnly. - * - * @default false - */ - readOnly?: boolean; -} - -export interface CinderSource { - volumeID: string; - fsType: string; - /** - * @default false - */ - readOnly?: boolean; - secretRef?: SecretReference; -} - -export interface ConfigMapSource { - name: string; - items: { - key: string; - path: string; - }[]; -} - -export interface DownwardApiSource { - items: { - path: string; - fieldRef: { - fieldPath: string; - }; - }[]; -} - -export interface EphemeralSource { - volumeClaimTemplate: { - /** - * All the rest of the fields are ignored and rejected during validation - */ - metadata?: Pick; - spec: PersistentVolumeClaimSpec; - }; -} - -export interface EmptyDirSource { - medium?: string; - sizeLimit?: string; -} - -export interface FiberChannelSource { - /** - * A list of World Wide Names - */ - targetWWNs: string[]; - /** - * Logical Unit number - */ - lun: number; - /** - * The type of filesystem - * @default "ext4" - */ - fsType?: string; - readOnly: boolean; -} - -export interface FlockerSource { - datasetName: string; -} - -export interface FlexVolumeSource { - driver: string; - fsType?: string; - secretRef?: LocalObjectReference; - /** - * @default false - */ - readOnly?: boolean; - options?: Record; -} - -export interface GcePersistentDiskSource { - pdName: string; - fsType: string; -} - -export interface GitRepoSource { - repository: string; - revision: string; -} - -export interface GlusterFsSource { - /** - * The name of the Endpoints object that represents a Gluster cluster configuration. - */ - endpoints: string; - /** - * The Glusterfs volume name. - */ - path: string; - /** - * The boolean that sets the mountpoint readOnly or readWrite. - */ - readOnly: boolean; -} - -export interface HostPathSource { - path: string; - /** - * Determines the sorts of checks that will be done - * @default "" - */ - type?: - | '' - | 'DirectoryOrCreate' - | 'Directory' - | 'FileOrCreate' - | 'File' - | 'Socket' - | 'CharDevice' - | 'BlockDevice'; -} - -export interface IScsiSource { - targetPortal: string; - iqn: string; - lun: number; - fsType: string; - readOnly: boolean; - chapAuthDiscovery?: boolean; - chapAuthSession?: boolean; - secretRef?: SecretReference; -} - -export interface LocalSource { - path: string; -} - -export interface NetworkFsSource { - server: string; - path: string; - readOnly?: boolean; -} - -export interface PersistentVolumeClaimSource { - claimName: string; -} - -export interface PhotonPersistentDiskSource { - pdID: string; - /** - * @default "ext4" - */ - fsType?: string; -} - -export interface PortworxVolumeSource { - volumeID: string; - fsType?: string; - readOnly?: boolean; -} - -export interface KeyToPath { - key: string; - path: string; - mode?: number; -} - -export interface ConfigMapProjection { - name: string; - items?: KeyToPath[]; - optional?: boolean; -} - -export interface DownwardAPIVolumeFile { - path: string; - fieldRef?: ObjectFieldSelector; - resourceFieldRef?: ResourceFieldSelector; - mode?: number; -} - -export interface DownwardAPIProjection { - items?: DownwardAPIVolumeFile[]; -} - -export interface SecretProjection { - name: string; - items?: KeyToPath[]; - optional?: boolean; -} - -export interface ServiceAccountTokenProjection { - audience?: string; - expirationSeconds?: number; - path: string; -} - -export interface VolumeProjection { - secret?: SecretProjection; - downwardAPI?: DownwardAPIProjection; - configMap?: ConfigMapProjection; - serviceAccountToken?: ServiceAccountTokenProjection; -} - -export interface ProjectedSource { - sources?: VolumeProjection[]; - defaultMode?: number; -} - -export interface QuobyteSource { - registry: string; - volume: string; - /** - * @default false - */ - readOnly?: boolean; - /** - * @default "serivceaccount" - */ - user?: string; - group?: string; - tenant?: string; -} - -export interface RadosBlockDeviceSource { - monitors: string[]; - image: string; - /** - * @default "ext4" - */ - fsType?: string; - /** - * @default "rbd" - */ - pool?: string; - /** - * @default "admin" - */ - user?: string; - /** - * @default "/etc/ceph/keyring" - */ - keyring?: string; - secretRef?: SecretReference; - /** - * @default false - */ - readOnly?: boolean; -} - -export interface ScaleIoSource { - gateway: string; - system: string; - secretRef?: LocalObjectReference; - /** - * @default false - */ - sslEnabled?: boolean; - protectionDomain?: string; - storagePool?: string; - /** - * @default "ThinProvisioned" - */ - storageMode?: 'ThickProvisioned' | 'ThinProvisioned'; - volumeName: string; - /** - * @default "xfs" - */ - fsType?: string; - /** - * @default false - */ - readOnly?: boolean; -} - -export interface SecretSource { - secretName: string; - items?: { - key: string; - path: string; - mode?: number; - }[]; - defaultMode?: number; - optional?: boolean; -} - -export interface StorageOsSource { - volumeName: string; - /** - * @default Pod.metadata.namespace - */ - volumeNamespace?: string; - /** - * @default "ext4" - */ - fsType?: string; - /** - * @default false - */ - readOnly?: boolean; - secretRef?: LocalObjectReference; -} - -export interface VsphereVolumeSource { - volumePath: string; - /** - * @default "ext4" - */ - fsType?: string; - storagePolicyName?: string; - storagePolicyID?: string; -} - -export interface ContainerStorageInterfaceSource { - driver: string; - /** - * @default false - */ - readOnly?: boolean; - /** - * @default "ext4" - */ - fsType?: string; - volumeAttributes?: Record; - controllerPublishSecretRef?: SecretReference; - nodeStageSecretRef?: SecretReference; - nodePublishSecretRef?: SecretReference; - controllerExpandSecretRef?: SecretReference; -} - -export interface PodVolumeVariants { - awsElasticBlockStore: AwsElasticBlockStoreSource; - azureDisk: AzureDiskSource; - azureFile: AzureFileSource; - cephfs: CephfsSource; - cinder: CinderSource; - configMap: ConfigMapSource; - csi: ContainerStorageInterfaceSource; - downwardAPI: DownwardApiSource; - emptyDir: EmptyDirSource; - ephemeral: EphemeralSource; - fc: FiberChannelSource; - flexVolume: FlexVolumeSource; - flocker: FlockerSource; - gcePersistentDisk: GcePersistentDiskSource; - gitRepo: GitRepoSource; - glusterfs: GlusterFsSource; - hostPath: HostPathSource; - iscsi: IScsiSource; - local: LocalSource; - nfs: NetworkFsSource; - persistentVolumeClaim: PersistentVolumeClaimSource; - photonPersistentDisk: PhotonPersistentDiskSource; - portworxVolume: PortworxVolumeSource; - projected: ProjectedSource; - quobyte: QuobyteSource; - rbd: RadosBlockDeviceSource; - scaleIO: ScaleIoSource; - secret: SecretSource; - storageos: StorageOsSource; - vsphereVolume: VsphereVolumeSource; -} - -/** - * The valid kinds of volume - */ -export type PodVolumeKind = keyof PodVolumeVariants; - -export type PodSpecVolume = RequireExactlyOne & { - name: string; -}; - -export interface HostAlias { - ip: string; - hostnames: string[]; -} - -export interface Sysctl { - name: string; - value: string; -} - -export interface TopologySpreadConstraint {} - -export interface PodSpec { - activeDeadlineSeconds?: number; - affinity?: Affinity; - automountServiceAccountToken?: boolean; - containers?: Container[]; - dnsPolicy?: string; - enableServiceLinks?: boolean; - ephemeralContainers?: unknown[]; - hostAliases?: HostAlias[]; - hostIPC?: boolean; - hostname?: string; - hostNetwork?: boolean; - hostPID?: boolean; - imagePullSecrets?: LocalObjectReference[]; - initContainers?: Container[]; - nodeName?: string; - nodeSelector?: Partial>; - overhead?: Partial>; - preemptionPolicy?: string; - priority?: number; - priorityClassName?: string; - readinessGates?: unknown[]; - restartPolicy?: string; - runtimeClassName?: string; - schedulerName?: string; - securityContext?: PodSecurityContext; - serviceAccount?: string; - serviceAccountName?: string; - setHostnameAsFQDN?: boolean; - shareProcessNamespace?: boolean; - subdomain?: string; - terminationGracePeriodSeconds?: number; - tolerations?: Toleration[]; - topologySpreadConstraints?: TopologySpreadConstraint[]; - volumes?: PodSpecVolume[]; -} - -export interface PodCondition { - lastProbeTime?: number; - lastTransitionTime?: string; - message?: string; - reason?: string; - type: string; - status: string; -} - -export interface PodStatus { - phase: string; - conditions: PodCondition[]; - hostIP: string; - podIP: string; - podIPs?: { - ip: string; - }[]; - startTime: string; - initContainerStatuses?: PodContainerStatus[]; - containerStatuses?: PodContainerStatus[]; - qosClass?: string; - reason?: string; -} - -export class Pod extends KubeObject { - static kind = 'Pod'; - - static namespaced = true; - - static apiBase = '/api/v1/pods'; - - getAffinityNumber() { - return Object.keys(this.getAffinity()).length; - } - - getInitContainers() { - return this.spec?.initContainers ?? []; - } - - getContainers() { - return this.spec?.containers ?? []; - } - - getAllContainers() { - return [...this.getContainers(), ...this.getInitContainers()]; - } - - getRunningContainers() { - const runningContainerNames = new Set( - this.getContainerStatuses() - .filter(({ state }) => state?.running) - .map(({ name }) => name) - ); - - return this.getAllContainers().filter(({ name }) => runningContainerNames.has(name)); - } - - getContainerStatuses(includeInitContainers = true): PodContainerStatus[] { - const { containerStatuses = [], initContainerStatuses = [] } = this.status ?? {}; - - if (includeInitContainers) { - return [...containerStatuses, ...initContainerStatuses]; - } - - return [...containerStatuses]; - } - - getRestartsCount(): number { - const { containerStatuses = [] } = this.status ?? {}; - - return containerStatuses.reduce((totalCount, { restartCount }) => totalCount + restartCount, 0); - } - - getQosClass() { - return this.status?.qosClass || ''; - } - - getReason() { - return this.status?.reason || ''; - } - - getPriorityClassName() { - return this.spec?.priorityClassName || ''; - } - - getRuntimeClassName() { - return this.spec?.runtimeClassName || ''; - } - - getServiceAccountName() { - return this.spec?.serviceAccountName || ''; - } - - getStatus(): PodStatusPhase { - const phase = this.getStatusPhase(); - const reason = this.getReason(); - const trueConditionTypes = new Set( - this.getConditions() - .filter(({ status }) => status === 'True') - .map(({ type }) => type) - ); - const isInGoodCondition = ['Initialized', 'Ready'].every((condition) => - trueConditionTypes.has(condition) - ); - - if (reason === PodStatusPhase.EVICTED) { - return PodStatusPhase.EVICTED; - } - - if (phase === PodStatusPhase.FAILED) { - return PodStatusPhase.FAILED; - } - - if (phase === PodStatusPhase.SUCCEEDED) { - return PodStatusPhase.SUCCEEDED; - } - - if (phase === PodStatusPhase.RUNNING && isInGoodCondition) { - return PodStatusPhase.RUNNING; - } - - return PodStatusPhase.PENDING; - } - - // Returns pod phase or container error if occurred - getStatusMessage(): string { - if (this.getReason() === PodStatusPhase.EVICTED) { - return 'Evicted'; - } - - if (this.metadata.deletionTimestamp) { - return 'Terminating'; - } - - return this.getStatusPhase() || 'Waiting'; - } - - getStatusPhase() { - return this.status?.phase; - } - - getConditions() { - return this.status?.conditions ?? []; - } - - getVolumes() { - return this.spec?.volumes ?? []; - } - - getTolerations() { - return this.spec?.tolerations ?? []; - } - - getAffinity(): Affinity { - return this.spec?.affinity ?? {}; - } - - hasIssues() { - for (const { type, status } of this.getConditions()) { - if (type === 'Ready' && status !== 'True') { - return true; - } - } - - for (const { state } of this.getContainerStatuses()) { - if (state?.waiting?.reason === 'CrashLookBackOff') { - return true; - } - } - - return this.getStatusPhase() !== 'Running'; - } - - getLivenessProbe(container: Container) { - return this.getProbe(container, container.livenessProbe); - } - - getReadinessProbe(container: Container) { - return this.getProbe(container, container.readinessProbe); - } - - getStartupProbe(container: Container) { - return this.getProbe(container, container.startupProbe); - } - - private getProbe(container: Container, probe: Probe | undefined): string[] { - const probeItems: string[] = []; - - if (!probe) { - return probeItems; - } - - const { - httpGet, - exec, - tcpSocket, - initialDelaySeconds = 0, - timeoutSeconds = 0, - periodSeconds = 0, - successThreshold = 0, - failureThreshold = 0 - } = probe; - - // HTTP Request - if (httpGet) { - const { path = '', port, host = '', scheme = 'HTTP' } = httpGet; - const resolvedPort = - typeof port === 'number' - ? port - : // Try and find the port number associated witht the name or fallback to the name itself - container.ports?.find((containerPort) => containerPort.name === port)?.containerPort || - port; - - probeItems.push('http-get', `${scheme.toLowerCase()}://${host}:${resolvedPort}${path}`); - } - - // Command - if (exec?.command) { - probeItems.push(`exec [${exec.command.join(' ')}]`); - } - - // TCP Probe - if (tcpSocket?.port) { - probeItems.push(`tcp-socket :${tcpSocket.port}`); - } - - probeItems.push( - `delay=${initialDelaySeconds}s`, - `timeout=${timeoutSeconds}s`, - `period=${periodSeconds}s`, - `#success=${successThreshold}`, - `#failure=${failureThreshold}` - ); - - return probeItems; - } - - getNodeName(): string | undefined { - return this.spec?.nodeName; - } - - getSelectedNodeOs(): string | undefined { - return ( - this.spec?.nodeSelector?.['kubernetes.io/os'] || - this.spec?.nodeSelector?.['beta.kubernetes.io/os'] - ); - } - - getIPs(): string[] { - const podIPs = this.status?.podIPs ?? []; - - return podIPs.map((value) => value.ip); - } -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/replica-set.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/replica-set.ts deleted file mode 100644 index 2e7d79e4e..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/replica-set.ts +++ /dev/null @@ -1,77 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import type { KubeObjectStatus, LabelSelector, NamespaceScopedMetadata } from '../api-types'; -import { KubeObject } from '../kube-object'; -import type { PodTemplateSpec } from '../types/pod-template-spec'; - -export interface ReplicaSetSpec { - replicas?: number; - selector: LabelSelector; - template?: PodTemplateSpec; - minReadySeconds?: number; -} - -export interface ReplicaSetStatus extends KubeObjectStatus { - replicas: number; - fullyLabeledReplicas?: number; - readyReplicas?: number; - availableReplicas?: number; - observedGeneration?: number; -} - -export class ReplicaSet extends KubeObject< - NamespaceScopedMetadata, - ReplicaSetStatus, - ReplicaSetSpec -> { - static kind = 'ReplicaSet'; - - static namespaced = true; - - static apiBase = '/apis/apps/v1/replicasets'; - - getSelectors(): string[] { - return KubeObject.stringifyLabels(this.spec.selector.matchLabels); - } - - getNodeSelectors(): string[] { - return KubeObject.stringifyLabels(this.spec.template?.spec?.nodeSelector); - } - - getTemplateLabels(): string[] { - return KubeObject.stringifyLabels(this.spec.template?.metadata?.labels); - } - - getTolerations() { - return this.spec.template?.spec?.tolerations ?? []; - } - - getAffinity() { - return this.spec.template?.spec?.affinity; - } - - getAffinityNumber() { - return Object.keys(this.getAffinity() ?? {}).length; - } - - getDesired() { - return this.spec.replicas ?? 0; - } - - getCurrent() { - return this.status?.availableReplicas ?? 0; - } - - getReady() { - return this.status?.readyReplicas ?? 0; - } - - getImages() { - const containers = this.spec.template?.spec?.containers ?? []; - - return containers.map((container) => container.image); - } -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/secret.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/secret.ts deleted file mode 100644 index dd3a95b28..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/secret.ts +++ /dev/null @@ -1,74 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import autoBind from 'auto-bind'; -import type { - KubeJsonApiData, - KubeObjectMetadata, - KubeObjectScope, - NamespaceScopedMetadata -} from '../api-types'; -import { KubeObject } from '../kube-object'; - -export enum SecretType { - Opaque = 'Opaque', - ServiceAccountToken = 'kubernetes.io/service-account-token', - Dockercfg = 'kubernetes.io/dockercfg', - DockerConfigJson = 'kubernetes.io/dockerconfigjson', - BasicAuth = 'kubernetes.io/basic-auth', - SSHAuth = 'kubernetes.io/ssh-auth', - TLS = 'kubernetes.io/tls', - BootstrapToken = 'bootstrap.kubernetes.io/token' -} - -export const reverseSecretTypeMap = { - [SecretType.Opaque]: 'Opaque', - [SecretType.ServiceAccountToken]: 'ServiceAccountToken', - [SecretType.Dockercfg]: 'Dockercfg', - [SecretType.DockerConfigJson]: 'DockerConfigJson', - [SecretType.BasicAuth]: 'BasicAuth', - [SecretType.SSHAuth]: 'SSHAuth', - [SecretType.TLS]: 'TLS', - [SecretType.BootstrapToken]: 'BootstrapToken' -}; - -export interface SecretReference { - name: string; - namespace?: string; -} - -export interface SecretData - extends KubeJsonApiData, void, void> { - type: SecretType; - data?: Partial>; -} - -export class Secret extends KubeObject { - static readonly kind = 'Secret'; - - static readonly namespaced = true; - - static readonly apiBase = '/api/v1/secrets'; - - type: SecretType; - - data: Partial>; - - constructor({ data = {}, type, ...rest }: SecretData) { - super(rest); - autoBind(this); - - this.data = data; - this.type = type; - } - - getKeys(): string[] { - return Object.keys(this.data); - } - - getToken() { - return this.data.token; - } -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/service.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/service.ts deleted file mode 100644 index a12dc556e..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/service.ts +++ /dev/null @@ -1,143 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import type { NamespaceScopedMetadata } from '../api-types'; -import { KubeObject } from '../kube-object'; - -export interface ServicePortSpec { - name?: string; - protocol: string; - port: number; - targetPort: number; - nodePort?: number; -} - -export class ServicePort { - name?: string; - - protocol: string; - - port: number; - - targetPort: number; - - nodePort?: number; - - constructor(data: ServicePortSpec) { - this.name = data.name; - this.protocol = data.protocol; - this.port = data.port; - this.targetPort = data.targetPort; - this.nodePort = data.nodePort; - } - - toString() { - const targetPort = this.nodePort - ? `:${this.nodePort}` - : this.port !== this.targetPort - ? `:${this.targetPort}` - : ''; - - return `${this.port}${targetPort}/${this.protocol}`; - } -} - -export interface ServiceSpec { - type: string; - clusterIP: string; - clusterIPs?: string[]; - externalTrafficPolicy?: string; - externalName?: string; - loadBalancerIP?: string; - loadBalancerSourceRanges?: string[]; - sessionAffinity: string; - selector: Partial>; - ports: ServicePortSpec[]; - healthCheckNodePort?: number; - externalIPs?: string[]; // https://kubernetes.io/docs/concepts/services-networking/service/#external-ips - topologyKeys?: string[]; - ipFamilies?: string[]; - ipFamilyPolicy?: string; - allocateLoadBalancerNodePorts?: boolean; - loadBalancerClass?: string; - internalTrafficPolicy?: string; -} - -export interface ServiceStatus { - loadBalancer?: { - ingress?: { - ip?: string; - hostname?: string; - }[]; - }; -} - -export class Service extends KubeObject { - static readonly kind = 'Service'; - - static readonly namespaced = true; - - static readonly apiBase = '/api/v1/services'; - - getClusterIp() { - return this.spec.clusterIP; - } - - getClusterIps() { - return this.spec.clusterIPs || []; - } - - getExternalIps() { - const lb = this.getLoadBalancer(); - - if (lb?.ingress) { - return lb.ingress.map((val) => val.ip || val.hostname); - } - - if (Array.isArray(this.spec?.externalIPs)) { - return this.spec.externalIPs; - } - - return []; - } - - getType() { - return this.spec.type || '-'; - } - - getSelector(): string[] { - if (!this.spec.selector) { - return []; - } - - return Object.entries(this.spec.selector).map((val) => val.join('=')); - } - - getPorts(): ServicePort[] { - const ports = this.spec.ports || []; - - return ports.map((p) => new ServicePort(p)); - } - - getLoadBalancer() { - return this.status?.loadBalancer; - } - - isActive() { - return this.getType() !== 'LoadBalancer' || this.getExternalIps().length > 0; - } - - getStatus() { - return this.isActive() ? 'Active' : 'Pending'; - } - - getIpFamilies() { - return this.spec.ipFamilies || []; - } - - getIpFamilyPolicy() { - return this.spec.ipFamilyPolicy || ''; - } -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/stateful-set.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/stateful-set.ts deleted file mode 100644 index bf366e087..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/specifics/stateful-set.ts +++ /dev/null @@ -1,73 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import type { LabelSelector, NamespaceScopedMetadata } from '../api-types'; -import { KubeObject } from '../kube-object'; -import type { PersistentVolumeClaimTemplateSpec } from '../types/persistent-volume-claim-template-spec'; -import type { PodTemplateSpec } from '../types/pod-template-spec'; - -export interface StatefulSetSpec { - serviceName: string; - replicas: number; - selector: LabelSelector; - template: PodTemplateSpec; - volumeClaimTemplates: PersistentVolumeClaimTemplateSpec[]; -} - -export interface StatefulSetStatus { - observedGeneration: number; - replicas: number; - currentReplicas: number; - readyReplicas: number; - currentRevision: string; - updateRevision: string; - collisionCount: number; -} - -export class StatefulSet extends KubeObject< - NamespaceScopedMetadata, - StatefulSetStatus, - StatefulSetSpec -> { - static readonly kind = 'StatefulSet'; - - static readonly namespaced = true; - - static readonly apiBase = '/apis/apps/v1/statefulsets'; - - getSelectors(): string[] { - return KubeObject.stringifyLabels(this.spec.selector.matchLabels); - } - - getNodeSelectors(): string[] { - return KubeObject.stringifyLabels(this.spec.template.spec?.nodeSelector); - } - - getTemplateLabels(): string[] { - return KubeObject.stringifyLabels(this.spec.template.metadata?.labels); - } - - getTolerations() { - return this.spec.template.spec?.tolerations ?? []; - } - - getAffinity() { - return this.spec.template.spec?.affinity ?? {}; - } - - getAffinityNumber() { - return Object.keys(this.getAffinity()).length; - } - - getReplicas() { - return this.spec.replicas || 0; - } - - getImages() { - const containers = this.spec.template?.spec?.containers ?? []; - - return containers.map((container) => container.image); - } -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/capabilities.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/capabilities.ts deleted file mode 100644 index baea13c68..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/capabilities.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -/** - * Adds and removes POSIX capabilities from running containers. - */ -export interface Capabilities { - /** - * Added capabilities - */ - add?: string[]; - - /** - * Removed capabilities - */ - drop?: string[]; -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/container-port.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/container-port.ts deleted file mode 100644 index fba1fa530..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/container-port.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -export interface ContainerPort { - containerPort: number; - hostIP?: string; - hostPort?: number; - name?: string; - protocol?: 'UDP' | 'TCP' | 'SCTP'; -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/container.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/container.ts deleted file mode 100644 index edec057cb..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/container.ts +++ /dev/null @@ -1,176 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import type { ContainerPort } from './container-port'; -import type { EnvFromSource } from './env-from-source'; -import type { EnvVar } from './env-var'; -import type { Lifecycle } from './lifecycle'; -import type { Probe } from './probe'; -import type { ResourceRequirements } from './resource-requirements'; -import type { SecurityContext } from './security-context'; -import type { VolumeDevice } from './volume-device'; -import type { VolumeMount } from './volume-mount'; - -/** - * A single application container that you want to run within a pod. - */ -export interface Container { - /** - * Arguments to the entrypoint. The docker image's CMD is used if this is not provided. Variable - * references `$(VAR_NAME)` are expanded using the container's environment. - * - * If a variable cannot be resolved, the reference in the input string will be unchanged. - * Double `$$` are reduced to a single `$`, which allows for escaping the `$(VAR_NAME)` syntax: - * i.e. `"$$(VAR_NAME)"` will produce the string literal `"$(VAR_NAME)`". - * - * Escaped references will never be expanded, regardless of whether the variable exists or not. - * Cannot be updated. - * - * More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell - */ - args?: string[]; - - /** - * Entrypoint array. Not executed within a shell. The docker image's ENTRYPOINT is used if this - * is not provided. Variable references `$(VAR_NAME)` are expanded using the container's - * environment. - * - * If a variable cannot be resolved, the reference in the input string will be unchanged. - * Double `$$` are reduced to a single `$`, which allows for escaping the `$(VAR_NAME)` syntax: - * i.e. `"$$(VAR_NAME)"` will produce the string literal `"$(VAR_NAME)`". - * - * Escaped references will never be expanded, regardless of whether the variable exists or not. - * Cannot be updated. - * - * More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell - */ - command?: string[]; - - /** - * List of environment variables to set in the container. Cannot be updated. - */ - env?: EnvVar[]; - - /** - * List of sources to populate environment variables in the container. The keys defined within a - * source must be a C_IDENTIFIER. All invalid keys will be reported as an event when the - * container is starting. - * - * When a key exists in multiple sources, the value associated with the last source will take - * precedence. Values defined by an Env with a duplicate key will take precedence. Cannot be - * updated. - */ - envFrom?: EnvFromSource[]; - - /** - * Docker image name. - * - * More info: https://kubernetes.io/docs/concepts/containers/images - */ - image?: string; - - /** - * Image pull policy. Defaults to `"Always"` if :latest tag is specified, or `"IfNotPresent"` - * otherwise. Cannot be updated. - * - * More info: https://kubernetes.io/docs/concepts/containers/images#updating-images - */ - imagePullPolicy?: 'Always' | 'Never' | 'IfNotPresent'; - - lifecycle?: Lifecycle; - livenessProbe?: Probe; - - /** - * Name of the container specified as a DNS_LABEL. Each container in a pod must have a unique - * name. Cannot be updated. - */ - name: string; - - /** - * List of ports to expose from the container. Exposing a port here gives the system additional - * information about the network connections a container uses, but is primarily informational. - * Not specifying a port here DOES NOT prevent that port from being exposed. Any port which is - * listening on the default `"0.0.0.0"` address inside a container will be accessible from the - * network. Cannot be updated. - */ - ports?: ContainerPort[]; - - readinessProbe?: Probe; - resources?: ResourceRequirements; - securityContext?: SecurityContext; - startupProbe?: Probe; - - /** - * Whether this container should allocate a buffer for stdin in the container runtime. If this is - * not set, reads from stdin in the container will always result in EOF. - * - * @default false - */ - stdin?: boolean; - - /** - * Whether the container runtime should close the stdin channel after it has been opened by a - * single attach. When stdin is true the stdin stream will remain open across multiple attach - * sessions. - * - * If stdinOnce is set to true, stdin is opened on container start, is empty until the first - * client attaches to stdin, and then remains open and accepts data until the client disconnects, - * at which time stdin is closed and remains closed until the container is restarted. - * - * If this flag is false, a container processes that reads from stdin will never receive an EOF. - * - * @default false - */ - stdinOnce?: boolean; - - /** - * Path at which the file to which the container's termination message will be written - * is mounted into the container's filesystem. Message written is intended to be brief final - * status, such as an assertion failure message. - * - * Will be truncated by the node if greater than 4096 bytes. - * The total message length across all containers will be limited to 12kb. Cannot be updated. - * - * @default "/dev/termination-log" - */ - terminationMessagePath?: string; - - /** - * Indicate how the termination message should be populated. - * - * - `File`: will use the contents of {@link terminationMessagePath} to populate the container - * status message on both success and failure. - * - * - `FallbackToLogsOnError`: will use the last chunk of container log output if the - * termination message file is empty and the container exited with an error. - * - * The log output is limited to 2048 bytes or 80 lines, whichever is smaller. Cannot be updated. - * - * @default "File" - */ - terminationMessagePolicy?: 'File' | 'FallbackToLogsOnError'; - - /** - * Whether this container should allocate a TTY for itself, also requires 'stdin' to be true. - * - * @default false - */ - tty?: boolean; - - /** - * volumeDevices is the list of block devices to be used by the container. - */ - volumeDevices?: VolumeDevice[]; - - /** - * Pod volumes to mount into the container's filesystem. Cannot be updated. - */ - volumeMounts?: VolumeMount[]; - - /** - * Container's working directory. If not specified, the container runtime's default will be used, - * which might be configured in the container image. Cannot be updated. - */ - workingDir?: string; -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/env-from-source.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/env-from-source.ts deleted file mode 100644 index 4656fb970..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/env-from-source.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import type { EnvSource } from './env-source'; - -export interface EnvFromSource { - configMapRef?: EnvSource; - /** - * An identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER. - */ - prefix?: string; - secretRef?: EnvSource; -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/env-source.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/env-source.ts deleted file mode 100644 index a841c0720..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/env-source.ts +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import type { LocalObjectReference } from '../api-types'; - -export interface EnvSource extends LocalObjectReference { - /** - * Whether the object must be defined - */ - optional?: boolean; -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/env-var-key-selector.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/env-var-key-selector.ts deleted file mode 100644 index 3aca6d79b..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/env-var-key-selector.ts +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -export interface EnvVarKeySelector { - key: string; - name?: string; - optional?: boolean; -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/env-var-source.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/env-var-source.ts deleted file mode 100644 index 7a22d372c..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/env-var-source.ts +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import type { EnvVarKeySelector } from './env-var-key-selector'; -import type { ObjectFieldSelector } from './object-field-selector'; -import type { ResourceFieldSelector } from './resource-field-selector'; - -export interface EnvVarSource { - configMapKeyRef?: EnvVarKeySelector; - fieldRef?: ObjectFieldSelector; - resourceFieldRef?: ResourceFieldSelector; - secretKeyRef?: EnvVarKeySelector; -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/env-var.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/env-var.ts deleted file mode 100644 index 8fbb09afa..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/env-var.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import type { EnvVarSource } from './env-var-source'; - -export interface EnvVar { - name: string; - value?: string; - valueFrom?: EnvVarSource; -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/exec-action.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/exec-action.ts deleted file mode 100644 index abfd1947c..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/exec-action.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -/** - * ExecAction describes a "run in container" action. - */ -export interface ExecAction { - /** - * Command is the command line to execute inside the container, the working directory for the - * command is root ('\\') in the container's filesystem. The command is simply exec'd, it is not - * run inside a shell, so traditional shell instructions ('|', etc) won't work. To use a shell, - * you need to explicitly call out to that shell. - * - * Exit status of 0 is treated as live/healthy and non-zero is unhealthy. - */ - command?: string[]; -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/handler.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/handler.ts deleted file mode 100644 index 1618cdea3..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/handler.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import type { ExecAction } from './exec-action'; -import type { HttpGetAction } from './http-get-action'; -import type { TcpSocketAction } from './tcp-socket-action'; - -/** - * Handler defines a specific action that should be taken. - */ -export interface Handler { - exec?: ExecAction; - httpGet?: HttpGetAction; - tcpSocket?: TcpSocketAction; -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/http-get-action.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/http-get-action.ts deleted file mode 100644 index dd26fb6a2..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/http-get-action.ts +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import type { HttpHeader } from './http-header'; - -/** - * An action based on HTTP Get requests. - */ -export interface HttpGetAction { - /** - * Host name to connect to, defaults to the pod IP. You probably want to set \"Host\" in httpHeaders instead. - */ - host?: string; - - /** - * Custom headers to set in the request. HTTP allows repeated headers. - */ - httpHeaders?: HttpHeader[]; - - /** - * Path to access on the HTTP server. - */ - path?: string; - - /** - * The PORT to request from. - */ - port: string | number; - - /** - * Scheme to use for connecting to the host. - * - * @default "HTTP" - */ - scheme?: string; -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/http-header.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/http-header.ts deleted file mode 100644 index d70b42afd..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/http-header.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -/** - * A custom header to be used in HTTP probes and get actions - */ -export interface HttpHeader { - /** - * Field name - */ - name: string; - - /** - * The value of the field - */ - value: string; -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/index.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/index.ts deleted file mode 100644 index ca58ec6b9..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/index.ts +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -export * from './capabilities'; -export * from './container'; -export * from './container-port'; -export * from './env-from-source'; -export * from './env-source'; -export * from './env-var'; -export * from './env-var-key-selector'; -export * from './env-var-source'; -export * from './exec-action'; -export * from './handler'; -export * from './http-get-action'; -export * from './http-header'; -export * from './lifecycle'; -export * from './object-field-selector'; -export * from './persistent-volume-claim-template-spec'; -export * from './pod-security-context'; -export * from './pod-template-spec'; -export * from './probe'; -export * from './resource-field-selector'; -export * from './resource-requirements'; -export * from './role-ref'; -export * from './scale'; -export * from './se-linux-options'; -export * from './seccomp-profile'; -export * from './tcp-socket-action'; -export * from './volume-device'; -export * from './volume-mount'; -export * from './windows-security-context-options'; diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/lifecycle.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/lifecycle.ts deleted file mode 100644 index aa1d2f51b..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/lifecycle.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import type { Handler } from './handler'; - -/** - * Lifecycle describes actions that the management system should take in response to container - * lifecycle events. For the PostStart and PreStop lifecycle handlers, management of the container - * blocks until the action is complete, unless the container process fails, in which case the - * handler is aborted. - */ -export interface Lifecycle { - postStart?: Handler; - preStop?: Handler; -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/object-field-selector.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/object-field-selector.ts deleted file mode 100644 index 8593456ff..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/object-field-selector.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -export interface ObjectFieldSelector { - apiVersion?: string; - fieldPath: string; -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/persistent-volume-claim-template-spec.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/persistent-volume-claim-template-spec.ts deleted file mode 100644 index ba8671602..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/persistent-volume-claim-template-spec.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import type { KubeObjectScope, KubeTemplateObjectMetadata } from '../api-types'; -import type { PersistentVolumeClaimSpec } from '../specifics/persistent-volume-claim'; - -export interface PersistentVolumeClaimTemplateSpec { - metadata?: KubeTemplateObjectMetadata; - spec?: PersistentVolumeClaimSpec; -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/pod-security-context.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/pod-security-context.ts deleted file mode 100644 index 629f140a7..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/pod-security-context.ts +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import type { Sysctl } from '../specifics/pod'; -import type { SeLinuxOptions } from './se-linux-options'; -import type { SeccompProfile } from './seccomp-profile'; -import type { WindowsSecurityContextOptions } from './windows-security-context-options'; - -export interface PodSecurityContext { - fsGroup?: number; - fsGroupChangePolicy?: string; - runAsGroup?: number; - runAsNonRoot?: boolean; - runAsUser?: number; - seLinuxOptions?: SeLinuxOptions; - seccompProfile?: SeccompProfile; - supplementalGroups?: number[]; - sysctls?: Sysctl; - windowsOptions?: WindowsSecurityContextOptions; -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/pod-template-spec.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/pod-template-spec.ts deleted file mode 100644 index a99c86ba1..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/pod-template-spec.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import type { KubeObjectScope, KubeTemplateObjectMetadata } from '../api-types'; -import type { PodSpec } from '../specifics/pod'; - -export interface PodTemplateSpec { - metadata?: KubeTemplateObjectMetadata; - spec?: PodSpec; -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/probe.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/probe.ts deleted file mode 100644 index 69cbcb84b..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/probe.ts +++ /dev/null @@ -1,81 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import type { ExecAction } from './exec-action'; -import type { HttpGetAction } from './http-get-action'; -import type { TcpSocketAction } from './tcp-socket-action'; - -/** - * Describes a health check to be performed against a container to determine whether - * it is alive or ready to receive traffic. - */ -export interface Probe { - exec?: ExecAction; - - /** - * Minimum consecutive failures for the probe to be considered failed after having succeeded. - * - * @default 3 - * @minimum 1 - */ - failureThreshold?: number; - - httpGet?: HttpGetAction; - - /** - * Duration after the container has started before liveness probes are initiated. - * - * More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - */ - initialDelaySeconds?: number; - - /** - * How often to perform the probe. - * - * @default 10 - * @minimum 1 - */ - periodSeconds?: number; - - /** - * Minimum consecutive successes for the probe to be considered successful after having failed. - * - * Must be 1 for liveness and startup. - * - * @default 1 - * @minimum 1 - */ - successThreshold?: number; - - tcpSocket?: TcpSocketAction; - - /** - * Duration the pod needs to terminate gracefully upon probe failure. - * - * The grace period is the duration in seconds after the processes running in the pod are sent a - * termination signal and the time when the processes are forcibly halted with a kill signal. - * - * Set this value longer than the expected cleanup time for your process. - * - * If this value is not set, the pod's terminationGracePeriodSeconds will be used. Otherwise, - * this value overrides the value provided by the pod spec. Value must be non-negative integer. - * The value zero indicates stop immediately via the kill signal (no opportunity to shut down). - * - * This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. - * - * @minimum 1 - */ - terminationGracePeriodSeconds?: number; - - /** - * Duration after which the probe times out. - * - * More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - * - * @default 1 - * @minimum 1 - */ - timeoutSeconds?: number; -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/resource-field-selector.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/resource-field-selector.ts deleted file mode 100644 index 972750618..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/resource-field-selector.ts +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -export interface ResourceFieldSelector { - containerName?: string; - divisor?: string; - resource: string; -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/resource-requirements.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/resource-requirements.ts deleted file mode 100644 index 7d4155f22..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/resource-requirements.ts +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -/** - * ResourceRequirements describes the compute resource requirements. - */ -export interface ResourceRequirements { - /** - * Limits describes the maximum amount of compute resources allowed. - * - * More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - */ - limits?: Partial>; - - /** - * Requests describes the minimum amount of compute resources required. If Requests is omitted - * for a container, it defaults to Limits if that is explicitly specified, otherwise to an - * implementation-defined value. - * - * More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - */ - requests?: Partial>; -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/role-ref.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/role-ref.ts deleted file mode 100644 index 60e9bdda7..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/role-ref.ts +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -export interface RoleRef { - apiGroup: string; - kind: string; - name: string; -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/scale.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/scale.ts deleted file mode 100644 index b1777ae5e..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/scale.ts +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import type { KubeObjectMetadata } from '../api-types'; - -export interface Scale { - apiVersion: 'autoscaling/v1'; - kind: 'Scale'; - metadata: KubeObjectMetadata; - spec: { - replicas: number; - }; - status: { - replicas: number; - selector: string; - }; -} - -export interface ScaleCreateOptions { - apiVersion?: 'autoscaling/v1'; - kind?: 'Scale'; - spec: { - replicas: number; - }; -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/se-linux-options.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/se-linux-options.ts deleted file mode 100644 index 9e3c62919..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/se-linux-options.ts +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -/** - * SELinuxOptions are the labels to be applied to the container - */ -export interface SeLinuxOptions { - /** - * The SELinux `level` label that applies to the container. - */ - level?: string; - - /** - * The SELinux `role` label that applies to the container. - */ - role?: string; - - /** - * The SELinux `type` label that applies to the container. - */ - type?: string; - - /** - * The SELinux `user` label that applies to the container. - */ - user?: string; -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/seccomp-profile.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/seccomp-profile.ts deleted file mode 100644 index 664a4f2cc..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/seccomp-profile.ts +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -/** - * Defines a pod's or a container's seccomp profile settings. Only one profile source may be set. - */ -export interface SeccompProfile { - /** - * Indicates a profile defined in a file on the node should be used. The profile must be - * preconfigured on the node to work. Must be a descending path, relative to the kubelet's - * configured seccomp profile location. Must only be set if type is "Localhost". - */ - localhostProfile?: string; - - /** - * Indicates which kind of seccomp profile will be applied. - * - * Options: - * - * | Value | Description | - * |--|--| - * | `Localhost` | A profile defined in a file on the node should be used. | - * | `RuntimeDefault` | The container runtime default profile should be used. | - * | `Unconfined` | No profile should be applied. | - */ - type: 'Localhost' | 'RuntimeDefault' | 'Unconfined'; -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/security-context.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/security-context.ts deleted file mode 100644 index df008e8e6..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/security-context.ts +++ /dev/null @@ -1,78 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. - * All rights reserved. - * Licensed under MIT License. - * See LICENSE in root directory for more information. - */ - -import type { Capabilities } from './capabilities'; -import type { SeLinuxOptions } from './se-linux-options'; -import type { SeccompProfile } from './seccomp-profile'; -import type { WindowsSecurityContextOptions } from './windows-security-context-options'; - -/** - * SecurityContext holds security configuration that will be applied to a container. - * Some fields are present in both SecurityContext and PodSecurityContext. - * When both are set, the values in SecurityContext take precedence. - */ -export interface SecurityContext { - /** - * AllowPrivilegeEscalation controls whether a process can gain more privileges than its parent process. - * This bool directly controls if the no_new_privs flag will be set on the container process. - * AllowPrivilegeEscalation is true always when the container is: 1) run as Privileged 2) has CAP_SYS_ADMIN - */ - allowPrivilegeEscalation?: boolean; - - capabilities?: Capabilities; - - /** - * Run container in privileged mode. - * Processes in privileged containers are essentially equivalent to root on the host. - * - * @default false - */ - privileged?: boolean; - - /** - * procMount denotes the type of proc mount to use for the containers. - * The default is DefaultProcMount which uses the container runtime defaults for readonly paths and masked paths. - * This requires the ProcMountType feature flag to be enabled. - */ - procMount?: string; - - /** - * Whether this container has a read-only root filesystem. - * @default false - */ - readOnlyRootFilesystem?: boolean; - - /** - * The GID to run the entrypoint of the container process. - * Uses runtime default if unset. - * May also be set in PodSecurityContext. - * If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. - */ - runAsGroup?: number; - - /** - * Indicates that the container must run as a non-root user. - * If true, the Kubelet will validate the image at runtime to ensure that it does not run as UID 0 (root) - * and fail to start the container if it does. - * If unset or false, no such validation will be performed. - * May also be set in PodSecurityContext. - * If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. - */ - runAsNonRoot?: boolean; - - /** - * The UID to run the entrypoint of the container process. - * Defaults to user specified in image metadata if unspecified. - * May also be set in PodSecurityContext. - * If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. - */ - runAsUser?: number; - - seLinuxOptions?: SeLinuxOptions; - seccompProfile?: SeccompProfile; - windowsOptions?: WindowsSecurityContextOptions; -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/tcp-socket-action.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/tcp-socket-action.ts deleted file mode 100644 index 02f180582..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/tcp-socket-action.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -/** - * An action based on opening a socket - */ -export interface TcpSocketAction { - /** - * Host name to connect to, defaults to the pod IP. - */ - host?: string; - - /** - * Port to connect to - */ - port: number | string; -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/volume-device.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/volume-device.ts deleted file mode 100644 index 1dacaafe2..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/volume-device.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -/** - * A mapping of a raw block device within a container. - */ -export interface VolumeDevice { - /** - * The path inside of the container that the device will be mapped to. - */ - devicePath: string; - - /** - * Must match the name of a persistentVolumeClaim in the pod - */ - name: string; -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/volume-mount.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/volume-mount.ts deleted file mode 100644 index 0066d8896..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/volume-mount.ts +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -export interface VolumeMount { - name: string; - readOnly?: boolean; - mountPath: string; - mountPropagation?: string; - subPath?: string; - subPathExpr?: string; -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/windows-security-context-options.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/windows-security-context-options.ts deleted file mode 100644 index 00f74a8c2..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/types/windows-security-context-options.ts +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -/** - * Windows-specific options and credentials. - */ -export interface WindowsSecurityContextOptions { - /** - * The location of the GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) - * inlines the contents of the GMSA credential spec named by the GMSACredentialSpecName field. - */ - gmsaCredentialSpec?: string; - - /** - * The name of the GMSA credential spec to use. - */ - gmsaCredentialSpecName?: string; - - /** - * Determines if a container should be run as a 'Host Process' container. - * - * This field is alpha-level and will only be honored by components that enable the - * WindowsHostProcessContainers feature flag. - * - * Setting this field without the feature flag will result in errors when validating the Pod. - * - * All of a Pod's containers must have the same effective HostProcess value (it is not allowed to - * have a mix of HostProcess containers and non-HostProcess containers). - * - * In addition, if HostProcess is true then HostNetwork must also be set to true. - */ - hostProcess?: boolean; - - /** - * The UserName in Windows to run the entrypoint of the container process. - * Defaults to the user specified in image metadata if unspecified. - * May also be set in PodSecurityContext. - * If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. - */ - runAsUserName?: string; -} diff --git a/frontend/providers/kubepanel/src/k8slens/kube-object/src/utils.ts b/frontend/providers/kubepanel/src/k8slens/kube-object/src/utils.ts deleted file mode 100644 index f647e24e2..000000000 --- a/frontend/providers/kubepanel/src/k8slens/kube-object/src/utils.ts +++ /dev/null @@ -1,114 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import { - bindPredicate, - hasOptionalTypedProperty, - hasTypedProperty, - isObject, - isRecord, - isString, - isTypedArray -} from '@/k8slens/utilities'; -import type { - KubeJsonApiData, - KubeJsonApiDataList, - KubeJsonApiListMetadata, - KubeJsonApiObjectMetadata, - KubeObjectMetadata, - KubeObjectScope -} from './api-types'; - -const resourceApplierAnnotationsForFiltering = ['kubectl.kubernetes.io/last-applied-configuration']; - -export const filterOutResourceApplierAnnotations = (label: string) => - !resourceApplierAnnotationsForFiltering.some((key) => label.startsWith(key)); - -export function isKubeObjectNonSystem( - item: KubeJsonApiData | { metadata: KubeObjectMetadata } -) { - return !item.metadata.name?.startsWith('system:'); -} - -export function isJsonApiData(object: unknown): object is KubeJsonApiData { - return ( - isObject(object) && - hasTypedProperty(object, 'kind', isString) && - hasTypedProperty(object, 'apiVersion', isString) && - hasTypedProperty(object, 'metadata', isKubeJsonApiMetadata) - ); -} - -export function isKubeJsonApiListMetadata(object: unknown): object is KubeJsonApiListMetadata { - return ( - isObject(object) && - hasOptionalTypedProperty(object, 'resourceVersion', isString) && - hasOptionalTypedProperty(object, 'selfLink', isString) - ); -} - -export function isKubeJsonApiMetadata(object: unknown): object is KubeJsonApiObjectMetadata { - return ( - isObject(object) && - hasTypedProperty(object, 'uid', isString) && - hasTypedProperty(object, 'name', isString) && - hasTypedProperty(object, 'resourceVersion', isString) && - hasOptionalTypedProperty(object, 'selfLink', isString) && - hasOptionalTypedProperty(object, 'namespace', isString) && - hasOptionalTypedProperty(object, 'creationTimestamp', isString) && - hasOptionalTypedProperty(object, 'continue', isString) && - hasOptionalTypedProperty(object, 'finalizers', bindPredicate(isTypedArray, isString)) && - hasOptionalTypedProperty(object, 'labels', bindPredicate(isRecord, isString, isString)) && - hasOptionalTypedProperty(object, 'annotations', bindPredicate(isRecord, isString, isString)) - ); -} - -export function isPartialJsonApiMetadata( - object: unknown -): object is Partial { - return ( - isObject(object) && - hasOptionalTypedProperty(object, 'uid', isString) && - hasOptionalTypedProperty(object, 'name', isString) && - hasOptionalTypedProperty(object, 'resourceVersion', isString) && - hasOptionalTypedProperty(object, 'selfLink', isString) && - hasOptionalTypedProperty(object, 'namespace', isString) && - hasOptionalTypedProperty(object, 'creationTimestamp', isString) && - hasOptionalTypedProperty(object, 'continue', isString) && - hasOptionalTypedProperty(object, 'finalizers', bindPredicate(isTypedArray, isString)) && - hasOptionalTypedProperty(object, 'labels', bindPredicate(isRecord, isString, isString)) && - hasOptionalTypedProperty(object, 'annotations', bindPredicate(isRecord, isString, isString)) - ); -} - -export function isPartialJsonApiData(object: unknown): object is Partial { - return ( - isObject(object) && - hasOptionalTypedProperty(object, 'kind', isString) && - hasOptionalTypedProperty(object, 'apiVersion', isString) && - hasOptionalTypedProperty(object, 'metadata', isPartialJsonApiMetadata) - ); -} - -export function isJsonApiDataList( - object: unknown, - verifyItem: (val: unknown) => val is T -): object is KubeJsonApiDataList { - return ( - isObject(object) && - hasTypedProperty(object, 'kind', isString) && - hasTypedProperty(object, 'apiVersion', isString) && - hasTypedProperty(object, 'metadata', isKubeJsonApiListMetadata) && - hasTypedProperty(object, 'items', bindPredicate(isTypedArray, verifyItem)) - ); -} - -export function stringifyLabels(labels?: Partial>): string[] { - if (!labels) { - return []; - } - - return Object.entries(labels).map(([name, value]) => `${name}: ${value}`); -} diff --git a/frontend/providers/kubepanel/src/k8slens/utilities/index.ts b/frontend/providers/kubepanel/src/k8slens/utilities/index.ts deleted file mode 100644 index b4b94d3b6..000000000 --- a/frontend/providers/kubepanel/src/k8slens/utilities/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from './src/formatDuration'; -export * from './src/iter'; -export * from './src/object'; -export * from './src/type-narrowing'; -export * from './src/types'; diff --git a/frontend/providers/kubepanel/src/k8slens/utilities/src/formatDuration.ts b/frontend/providers/kubepanel/src/k8slens/utilities/src/formatDuration.ts deleted file mode 100644 index 1be65f780..000000000 --- a/frontend/providers/kubepanel/src/k8slens/utilities/src/formatDuration.ts +++ /dev/null @@ -1,94 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import moment from 'moment'; - -/** - * This function formats durations in a more human readable form. - * @param timeValue the duration in milliseconds to format - */ -export function formatDuration(timeValue: number, compact = true) { - const duration = moment.duration(timeValue, 'milliseconds'); - const seconds = Math.floor(duration.asSeconds()); - const separator = compact ? '' : ' '; - - if (seconds < 0) { - return '0s'; - } else if (seconds < 60 * 2) { - return `${seconds}s`; - } - - const minutes = Math.floor(duration.asMinutes()); - - if (minutes < 10) { - const seconds = duration.seconds(); - - return getMeaningfulValues([minutes, seconds], ['m', 's'], separator); - } else if (minutes < 60 * 3) { - if (!compact) { - return getMeaningfulValues([minutes, duration.seconds()], ['m', 's']); - } - - return `${minutes}m`; - } - - const hours = Math.floor(duration.asHours()); - - if (hours < 8) { - const minutes = duration.minutes(); - - return getMeaningfulValues([hours, minutes], ['h', 'm'], separator); - } else if (hours < 48) { - if (compact) { - return `${hours}h`; - } else { - return getMeaningfulValues([hours, duration.minutes()], ['h', 'm']); - } - } - - const days = Math.floor(duration.asDays()); - - if (days < 8) { - const hours = duration.hours(); - - if (compact) { - return getMeaningfulValues([days, hours], ['d', 'h'], separator); - } else { - return getMeaningfulValues([days, hours, duration.minutes()], ['d', 'h', 'm']); - } - } - const years = Math.floor(duration.asYears()); - - if (years < 2) { - if (compact) { - return `${days}d`; - } else { - return getMeaningfulValues([days, duration.hours(), duration.minutes()], ['d', 'h', 'm']); - } - } else if (years < 8) { - const days = duration.days(); - - if (compact) { - return getMeaningfulValues([years, days], ['y', 'd'], separator); - } - } - - if (compact) { - return `${years}y`; - } - - return getMeaningfulValues( - [years, duration.days(), duration.hours(), duration.minutes()], - ['y', 'd', 'h', 'm'] - ); -} - -function getMeaningfulValues(values: number[], suffixes: string[], separator = ' ') { - return values - .map((a, i): [number, string] => [a, suffixes[i] ?? '']) - .filter(([dur]) => dur > 0) - .map(([dur, suf]) => dur + suf) - .join(separator); -} diff --git a/frontend/providers/kubepanel/src/k8slens/utilities/src/iter.ts b/frontend/providers/kubepanel/src/k8slens/utilities/src/iter.ts deleted file mode 100644 index 07f732542..000000000 --- a/frontend/providers/kubepanel/src/k8slens/utilities/src/iter.ts +++ /dev/null @@ -1,328 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -export type Falsy = false | 0 | '' | null | undefined; - -interface Iterator extends Iterable { - filter(fn: (val: T) => unknown): Iterator; - filterMap(fn: (val: T) => Falsy | U): Iterator; - find(fn: (val: T) => unknown): T | undefined; - collect(fn: (values: Iterable) => U): U; - toArray(): T[]; - toMap(): T extends [infer K, infer V] ? Map : never; - toSet(): Set; - map(fn: (val: T) => U): Iterator; - flatMap(fn: (val: T) => U[]): Iterator; - concat(src2: IterableIterator): Iterator; - join(sep?: string): string; - take(count: number): Iterator; -} - -function chain(src: IterableIterator): Iterator { - return { - filter: (fn) => chain(filter(src, fn)), - filterMap: (fn) => chain(filterMap(src, fn)), - map: (fn) => chain(map(src, fn)), - flatMap: (fn) => chain(flatMap(src, fn)), - find: (fn) => find(src, fn), - join: (sep) => join(src, sep), - collect: (fn) => fn(src), - toArray: () => [...src], - toMap: () => new Map(src as IterableIterator<[any, any]>) as any, - toSet: () => new Set(src), - concat: (src2) => chain(concat(src, src2)), - take: (count) => chain(take(src, count)), - [Symbol.iterator]: () => src - }; -} - -/** - * Create a new type safe empty Iterable - * @returns An `Iterable` that yields 0 items - */ -function* newEmpty(): IterableIterator {} - -/** - * Creates a new `Iterable` that yields at most n items from src. - * Does not modify `src` which can be used later. - * @param src An initial iterator - * @param n The maximum number of elements to take from src. Yields up to the floor of `n` and 0 items if n < 0 - */ -function* take(src: Iterable, n: number): IterableIterator { - outer: for (let i = 0; i < n; i += 1) { - for (const item of src) { - yield item; - continue outer; - } - - // if we are here that means that `src` has been exhausted. Don't bother trying again. - break outer; - } -} - -/** - * Creates a new iterator that iterates (lazily) over its input and yields the - * result of `fn` for each item. - * @param src A type that can be iterated over - * @param fn The function that is called for each value - */ -function* map(src: Iterable, fn: (from: T) => U): IterableIterator { - for (const from of src) { - yield fn(from); - } -} - -/** - * The single layer flattening of an iterator, discarding `Falsy` values. - * @param src A type that can be iterated over - * @param fn The function that returns either an iterable over items that should be filtered out or a `Falsy` value indicating that it should be ignored - */ -function* filterFlatMap( - src: Iterable, - fn: (from: T) => Iterable | Falsy -): IterableIterator { - for (const from of src) { - if (!from) { - continue; - } - - const mapping = fn(from); - - if (!mapping) { - continue; - } - - for (const mapped of mapping) { - if (mapped) { - yield mapped; - } - } - } -} - -/** - * Returns a new iterator that yields the items that each call to `fn` would produce - * @param src A type that can be iterated over - * @param fn A function that returns an iterator - */ -function* flatMap(src: Iterable, fn: (from: T) => Iterable): IterableIterator { - for (const from of src) { - yield* fn(from); - } -} - -/** - * Creates a new iterator that iterates (lazily) over its input and yields the - * items that return a `truthy` value from `fn`. - * @param src A type that can be iterated over - * @param fn The function that is called for each value - */ -function* filter(src: Iterable, fn: (from: T) => any): IterableIterator { - for (const from of src) { - if (fn(from)) { - yield from; - } - } -} - -/** - * Creates a new iterator that iterates (lazily) over its input and yields the - * result of `fn` when it is `truthy` - * @param src A type that can be iterated over - * @param fn The function that is called for each value - */ -function* filterMap(src: Iterable, fn: (from: T) => U | Falsy): IterableIterator { - for (const from of src) { - const res = fn(from); - - if (res) { - yield res; - } - } -} - -/** - * Creates a new iterator that iterates (lazily) over its input and yields the - * result of `fn` when it is not null or undefined - * @param src A type that can be iterated over - * @param fn The function that is called for each value - */ -function* filterMapStrict( - src: Iterable, - fn: (from: T) => U | null | undefined -): IterableIterator { - for (const from of src) { - const res = fn(from); - - if (res != null) { - yield res; - } - } -} - -/** - * Iterate through `src` until `match` returns a truthy value - * @param src A type that can be iterated over - * @param match A function that should return a truthy value for the item that you want to find - * @returns The first entry that `match` returns a truthy value for, or `undefined` - */ -function find(src: Iterable, match: (i: T) => any): T | undefined { - for (const from of src) { - if (match(from)) { - return from; - } - } - - return void 0; -} - -/** - * Iterate over `src` calling `reducer` with the previous produced value and the current - * yielded value until `src` is exhausted. Then return the final value. - * @param src The value to iterate over - * @param reducer A function for producing the next item from an accumulation and the current item - * @param initial The initial value for the iteration - */ -function reduce>( - src: Iterable, - reducer: (acc: R, cur: T) => R, - initial: R -): R; - -function reduce(src: Iterable, reducer: (acc: R, cur: T) => R, initial: R): R { - let acc = initial; - - for (const item of src) { - acc = reducer(acc, item); - } - - return acc; -} - -/** - * A convenience function for reducing over an iterator of strings and concatenating them together - * @param src The value to iterate over - * @param connector The string value to intersperse between the yielded values - * @returns The concatenated entries of `src` interspersed with copies of `connector` - */ -function join(src: IterableIterator, connector = ','): string { - const iterSrc = src[Symbol.iterator](); - const first = iterSrc.next(); - - if (first.done === true) { - return ''; - } - - return reduce(iterSrc, (acc, cur) => `${acc}${connector}${cur}`, `${first.value}`); -} - -/** - * Iterate `n` times and then return the next value. - * @param src The value to iterate over - * @param n The zero-index value for the item to return to. - */ -function nth(src: Iterable, n: number): T | undefined { - const iterator = src[Symbol.iterator](); - - while (n-- > 0) { - iterator.next(); - } - - return iterator.next().value; -} - -/** - * A convenience function to get the first item of an iterator - * @param src The value to iterate over - */ -function first(src: Iterable): T | undefined { - return nth(src, 0); -} - -/** - * Iterate through `src` and return `true` if `fn` returns a truthy value for every yielded value. - * Otherwise, return `false`. This function short circuits. - * @param src The type to be iterated over - * @param fn A function to check each iteration - */ -function every(src: Iterable, fn: (val: T) => any): boolean { - for (const val of src) { - if (!fn(val)) { - return false; - } - } - - return true; -} - -function* concat(...sources: IterableIterator[]): IterableIterator { - for (const source of sources) { - for (const val of source) { - yield val; - } - } -} - -/** - * Split an iterable into several arrays with matching fields - * @param from The iterable of items to split up - * @param field The field of each item to split over - * @param parts What each array will be filtered to - * @returns A `parts.length` tuple of `T[]` where each array has matching `field` values - */ -function nFircate(from: Iterable, field: keyof T, parts: []): []; -function nFircate(from: Iterable, field: keyof T, parts: [T[typeof field]]): [T[]]; -function nFircate( - from: Iterable, - field: keyof T, - parts: [T[typeof field], T[typeof field]] -): [T[], T[]]; -function nFircate( - from: Iterable, - field: keyof T, - parts: [T[typeof field], T[typeof field], T[typeof field]] -): [T[], T[], T[]]; -function nFircate(from: Iterable, field: keyof T, parts: T[typeof field][]): T[][] { - if (new Set(parts).size !== parts.length) { - throw new TypeError('Duplicate parts entries'); - } - - const res = Array.from(parts, () => [] as T[]); - - for (const item of from) { - const index = parts.indexOf(item[field]); - - if (index < 0) { - continue; - } - - const targetArray = res[index]; - if (targetArray) { - targetArray.push(item); - } - } - - return res; -} - -export const iter = { - chain, - concat, - every, - filter, - filterFlatMap, - filterMap, - filterMapStrict, - find, - first, - flatMap, - join, - map, - nFircate, - newEmpty, - nth, - reduce, - take -}; diff --git a/frontend/providers/kubepanel/src/k8slens/utilities/src/object.ts b/frontend/providers/kubepanel/src/k8slens/utilities/src/object.ts deleted file mode 100644 index e1af059be..000000000 --- a/frontend/providers/kubepanel/src/k8slens/utilities/src/object.ts +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -/** - * A better typed version of `Object.fromEntries` where the keys are known to - * be a specific subset - */ -function fromEntries(entries: Iterable): Record { - return Object.fromEntries(entries) as Record; -} - -function keys(obj: Partial>): K[]; -function keys(obj: Record): K[] { - return Object.keys(obj) as K[]; -} - -function entries(obj: Partial> | null | undefined): [K, V][]; -function entries( - obj: Partial> | null | undefined -): [K, V][]; -function entries( - obj: Record | null | undefined -): [K, V][]; -function entries( - obj: Record | null | undefined -): [K, V][] { - if (obj && typeof obj == 'object') { - return Object.entries(obj) as never; - } - - return [] as never; -} - -export const object = { - entries, - fromEntries, - keys -}; diff --git a/frontend/providers/kubepanel/src/k8slens/utilities/src/type-narrowing.ts b/frontend/providers/kubepanel/src/k8slens/utilities/src/type-narrowing.ts deleted file mode 100644 index 277320983..000000000 --- a/frontend/providers/kubepanel/src/k8slens/utilities/src/type-narrowing.ts +++ /dev/null @@ -1,198 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -/** - * Narrows `val` to include the property `key` (if true is returned) - * @param val The object to be tested - * @param key The key to test if it is present on the object (must be a literal for tsc to do any meaningful typing) - */ -export function hasOwnProperty( - val: S, - key: K -): val is S & { [key in K]: unknown } { - // this call syntax is for when `val` was created by `Object.create(null)` - return Object.prototype.hasOwnProperty.call(val, key); -} - -/** - * Narrows `val` to a static type that includes fields of names in `keys` - * @param val the value that we are trying to type narrow - * @param keys the key names (must be literals for tsc to do any meaningful typing) - */ -export function hasOwnProperties( - val: S, - ...keys: K[] -): val is S & { [key in K]: unknown } { - return keys.every((key) => hasOwnProperty(val, key)); -} - -/** - * Narrows `val` to include the property `key` with type `V` - * @param val the value that we are trying to type narrow - * @param key The key to test if it is present on the object (must be a literal for tsc to do any meaningful typing) - * @param isValid a function to check if the field is valid - */ -export function hasTypedProperty( - val: S, - key: K, - isValid: (value: unknown) => value is V -): val is S & { [key in K]: V } { - return hasOwnProperty(val, key) && isValid(val[key]); -} - -/** - * Narrows `val` to include the property `key` with type string - * @param val the value that we are trying to type narrow - * @param key The key to test if it is present on the object (must be a literal for tsc to do any meaningful typing) - */ -export function hasStringProperty( - val: S, - key: K -): val is S & { [key in K]: string } { - return hasOwnProperty(val, key) && isString(val[key]); -} - -/** - * Narrows `val` to include the property `key` with type `V | undefined` or doesn't contain it - * @param val the value that we are trying to type narrow - * @param key The key to test if it is present on the object (must be a literal for tsc to do any meaningful typing) - * @param isValid a function to check if the field (when present) is valid - */ -export function hasOptionalTypedProperty( - val: S, - key: K, - isValid: (value: unknown) => value is V -): val is S & { [key in K]?: V } { - if (hasOwnProperty(val, key)) { - return typeof val[key] === 'undefined' || isValid(val[key]); - } - - return true; -} - -/** - * isRecord checks if `val` matches the signature `Record` or `{ [label in T]: V }` - * @param val The value to be checked - * @param isKey a function for checking if the key is of the correct type - * @param isValue a function for checking if a value is of the correct type - */ -export function isRecord( - val: unknown, - isKey: (key: unknown) => key is T, - isValue: (value: unknown) => value is V -): val is Record { - return isObject(val) && Object.entries(val).every(([key, value]) => isKey(key) && isValue(value)); -} - -/** - * isTypedArray checks if `val` is an array and all of its entries are of type `T` - * @param val The value to be checked - * @param isEntry a function for checking if an entry is the correct type - */ -export function isTypedArray(val: unknown, isEntry: (entry: unknown) => entry is T): val is T[] { - return Array.isArray(val) && val.every(isEntry); -} - -/** - * checks if val is of type string - * @param val the value to be checked - */ -export function isString(val: unknown): val is string { - return typeof val === 'string'; -} - -/** - * checks if val is of type Buffer - * @param val the value to be checked - */ export function isBuffer(val: unknown): val is Buffer { - return val instanceof Buffer; -} - -/** - * checks if val is of type number - * @param val the value to be checked - */ -export function isNumber(val: unknown): val is number { - return typeof val === 'number'; -} - -/** - * checks if val is of type boolean - * @param val the value to be checked - */ -export function isBoolean(val: unknown): val is boolean { - return typeof val === 'boolean'; -} - -/** - * checks if val is of type object and isn't null - * @param val the value to be checked - */ -export function isObject(val: unknown): val is Record { - return typeof val === 'object' && val !== null; -} - -/** - * checks if `val` is defined, useful for filtering out undefined values in a strict manner - */ -export function isDefined(val: T | undefined | null): val is T { - return val != null; -} - -export function isFunction(val: unknown): val is (...args: unknown[]) => unknown { - return typeof val === 'function'; -} - -/** - * Checks if the value in the second position is non-nullable - */ -export function hasDefinedTupleValue( - pair: readonly [K, V | undefined | null] -): pair is [K, V] { - return pair[1] != null; -} - -/** - * Creates a new predicate function (with the same predicate) from `fn`. Such - * that it can be called with just the value to be tested. - * - * This is useful for when using `hasOptionalProperty` and `hasTypedProperty` - * @param fn A typescript user predicate function to be bound - * @param boundArgs the set of arguments to be passed to `fn` in the new function - */ -export function bindPredicate( - fn: (arg1: unknown, ...args: FnArgs) => arg1 is T, - ...boundArgs: FnArgs -): (arg1: unknown) => arg1 is T { - return (arg1: unknown): arg1 is T => fn(arg1, ...boundArgs); -} - -export function hasDefiniteField( - field: Field -): (val: T) => val is T & { [f in Field]-?: NonNullable } { - return (val): val is T & { [f in Field]-?: NonNullable } => val[field] != null; -} - -export function isPromiseLike( - res: unknown -): res is Promise | { then: (fn: (val: unknown) => any) => Promise } { - if (res instanceof Promise) { - return true; - } - - return isObject(res) && hasTypedProperty(res, 'then', isFunction); -} - -export function isPromiseSettledRejected( - result: PromiseSettledResult -): result is PromiseRejectedResult { - return result.status === 'rejected'; -} - -export function isPromiseSettledFulfilled( - result: PromiseSettledResult -): result is PromiseFulfilledResult { - return result.status === 'fulfilled'; -} diff --git a/frontend/providers/kubepanel/src/k8slens/utilities/src/types.ts b/frontend/providers/kubepanel/src/k8slens/utilities/src/types.ts deleted file mode 100644 index d446700f1..000000000 --- a/frontend/providers/kubepanel/src/k8slens/utilities/src/types.ts +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -export type OptionVariant = { - type: Key; -} & Pick & { - [OtherKey in Exclude]?: undefined; - }; diff --git a/frontend/providers/kubepanel/src/pages/404.tsx b/frontend/providers/kubepanel/src/pages/404.tsx deleted file mode 100644 index 54dab961e..000000000 --- a/frontend/providers/kubepanel/src/pages/404.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { useRouter } from 'next/router'; -import { useEffect } from 'react'; - -const NonePage = () => { - const router = useRouter(); - useEffect(() => { - router.push('/kubepanel'); - }, [router]); - - return
; -}; - -export default NonePage; diff --git a/frontend/providers/kubepanel/src/pages/_app.tsx b/frontend/providers/kubepanel/src/pages/_app.tsx deleted file mode 100644 index 2615dcce4..000000000 --- a/frontend/providers/kubepanel/src/pages/_app.tsx +++ /dev/null @@ -1,98 +0,0 @@ -import { useConfirm } from '@/hooks/useConfirm'; -import { useGlobalStore } from '@/store/global'; -import { SEALOS_DOMAIN, loadInitData } from '@/store/static'; -import { loader } from '@monaco-editor/react'; -import { throttle } from 'lodash'; -import type { AppProps } from 'next/app'; -import Head from 'next/head'; -import { Router, useRouter } from 'next/router'; -import NProgress from 'nprogress'; -import { useEffect } from 'react'; -import { createSealosApp, sealosApp } from 'sealos-desktop-sdk/app'; - -// Client-side Monaco configuration -if (typeof window !== 'undefined') { - import('monaco-editor').then((monaco) => { - loader.config({ monaco }); - }); -} - -import '@/styles/globals.css'; -import 'nprogress/nprogress.css'; - -//Binding router events. -Router.events.on('routeChangeStart', () => NProgress.start()); -Router.events.on('routeChangeComplete', () => NProgress.done()); -Router.events.on('routeChangeError', () => NProgress.done()); - -export default function App({ Component, pageProps }: AppProps) { - const router = useRouter(); - const { setScreenWidth, setLastRoute } = useGlobalStore(); - const { openConfirm, ConfirmChild } = useConfirm({ - title: 'Redirect Notice', - content: 'This app cannot run standalone. Click confirm to open Sealos Desktop.' - }); - - // app init - useEffect(() => { - NProgress.start(); - - const response = createSealosApp(); - - (async () => { - try { - const res = await sealosApp.getSession(); - localStorage.setItem('session', JSON.stringify(res)); - } catch (err) { - if (!process.env.NEXT_PUBLIC_MOCK_USER) { - localStorage.removeItem('session'); - openConfirm(() => { - window.open(`https://${SEALOS_DOMAIN}`, '_self'); - })(); - } - } - })(); - NProgress.done(); - - return response; - }, [openConfirm]); - - // add resize event - useEffect(() => { - const resize = throttle((e: Event) => { - const documentWidth = document.documentElement.clientWidth || document.body.clientWidth; - setScreenWidth(documentWidth); - }, 200); - window.addEventListener('resize', resize); - const documentWidth = document.documentElement.clientWidth || document.body.clientWidth; - setScreenWidth(documentWidth); - - return () => { - window.removeEventListener('resize', resize); - }; - }, [setScreenWidth]); - - // init - useEffect(() => { - loadInitData(); - }, []); - - // record route - useEffect(() => { - return () => { - setLastRoute(router.asPath); - }; - }, [router.asPath, router.pathname, setLastRoute]); - return ( - <> - - Kube Panel - - - - - - - - ); -} diff --git a/frontend/providers/kubepanel/src/pages/_document.tsx b/frontend/providers/kubepanel/src/pages/_document.tsx deleted file mode 100644 index 9f4606140..000000000 --- a/frontend/providers/kubepanel/src/pages/_document.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { Head, Html, Main, NextScript } from 'next/document'; - -export default function Document() { - return ( - - - - - - - - - - - {/* fix: tailwind css conflict with antd - * @link https://github.com/ant-design/ant-design/issues/38794#issuecomment-1345475630 - */} - -
- - - - ); -} diff --git a/frontend/providers/kubepanel/src/pages/api/kubernetes/create.ts b/frontend/providers/kubepanel/src/pages/api/kubernetes/create.ts deleted file mode 100644 index 747b74124..000000000 --- a/frontend/providers/kubepanel/src/pages/api/kubernetes/create.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { hasTypedProperty, isObject } from '@/k8slens/utilities'; -import { getApiUrl } from '@/services/backend/api'; -import { authKubeConfig } from '@/services/backend/auth'; -import { ErrnoCode, buildErrno } from '@/services/backend/error'; -import { handlerAxiosError, sendErrorResponse } from '@/services/backend/response'; -import { CreateQuery, CreateResponse } from '@/types/api/kubenertes'; -import { mustGetTypedProperty } from '@/utils/api'; -import axios from 'axios'; -import yaml from 'js-yaml'; -import { isString, merge } from 'lodash'; -import { NextApiRequest, NextApiResponse } from 'next'; - -function isCreateQuery(query: unknown): query is CreateQuery { - return isObject(query) && hasTypedProperty(query, 'kind', isString); -} - -export default async function handler(req: NextApiRequest, resp: NextApiResponse) { - try { - if (req.method !== 'POST') - throw buildErrno('Request Method is not allowed', ErrnoCode.UserMethodNotAllow); - - const { namespace, config } = authKubeConfig(req.headers); - if (!isCreateQuery(req.query)) - throw buildErrno(`There has some invalid query in ${req.query}`, ErrnoCode.UserBadRequest); - - const { kind } = req.query; - const url = getApiUrl(kind, namespace); - const createdData = yaml.load(mustGetTypedProperty(req.body, 'data', isString, 'string')); - - const data = merge(createdData, { - kind, - metadata: { - namespace - } - }); - - const res = await axios.post(url, data, config); - resp.status(res.status).json({ - code: res.status, - data: res.data - }); - } catch (err: any) { - sendErrorResponse( - resp, - handlerAxiosError(err, ErrnoCode.APICreateRequestError, ErrnoCode.APICreateResponseError) - ); - } -} diff --git a/frontend/providers/kubepanel/src/pages/api/kubernetes/delete.ts b/frontend/providers/kubepanel/src/pages/api/kubernetes/delete.ts deleted file mode 100644 index f58527fa5..000000000 --- a/frontend/providers/kubepanel/src/pages/api/kubernetes/delete.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { hasTypedProperty } from '@/k8slens/utilities'; -import { getApiUrl } from '@/services/backend/api'; -import { authKubeConfig } from '@/services/backend/auth'; -import { ErrnoCode, buildErrno } from '@/services/backend/error'; -import { handlerAxiosError, sendErrorResponse } from '@/services/backend/response'; -import { DeleteQuery, DeleteResponse } from '@/types/api/kubenertes'; -import axios from 'axios'; -import { isObject, isString } from 'lodash'; -import { NextApiRequest, NextApiResponse } from 'next'; - -function isDeleteQuery(query: unknown): query is DeleteQuery { - return ( - isObject(query) && - hasTypedProperty(query, 'kind', isString) && - hasTypedProperty(query, 'name', isString) - ); -} - -export default async function handler(req: NextApiRequest, resp: NextApiResponse) { - try { - if (req.method !== 'DELETE') - throw buildErrno('Request Method is not allowed', ErrnoCode.UserMethodNotAllow); - - const { namespace, config } = authKubeConfig(req.headers); - - if (!isDeleteQuery(req.query)) - throw buildErrno(`There has some invalid query in ${req.query}`, ErrnoCode.UserBadRequest); - - const { kind, name } = req.query; - const url = getApiUrl(kind, namespace, name); - - let resourceData; - try { - const getRes = await axios.get(url, config); - resourceData = getRes.data; - } catch (getErr: any) { - if (getErr.response?.status !== 404) { - throw getErr; - } - } - - const deleteConfig = { - ...config, - params: { - propagationPolicy: 'Background' - } - }; - - const res = await axios.delete(url, deleteConfig); - - resp.status(res.status).json({ - code: res.status, - data: resourceData || res.data - }); - } catch (err: any) { - sendErrorResponse( - resp, - handlerAxiosError(err, ErrnoCode.APIDeleteRequestError, ErrnoCode.APIDeleteResponseError) - ); - } -} diff --git a/frontend/providers/kubepanel/src/pages/api/kubernetes/list.ts b/frontend/providers/kubepanel/src/pages/api/kubernetes/list.ts deleted file mode 100644 index 1b6476d62..000000000 --- a/frontend/providers/kubepanel/src/pages/api/kubernetes/list.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { hasOptionalTypedProperty, hasTypedProperty } from '@/k8slens/utilities'; -import { getApiUrl } from '@/services/backend/api'; -import { authKubeConfig } from '@/services/backend/auth'; -import { ErrnoCode, buildErrno } from '@/services/backend/error'; -import { handlerAxiosError, sendErrorResponse } from '@/services/backend/response'; -import { ListQuery, ListResponse } from '@/types/api/kubenertes'; -import { KubeList } from '@/types/kube-resource'; -import axios from 'axios'; -import { isObject, isString } from 'lodash'; -import type { NextApiRequest, NextApiResponse } from 'next'; - -function isListQuery(query: unknown): query is ListQuery { - return ( - isObject(query) && - hasTypedProperty(query, 'kind', isString) && - hasOptionalTypedProperty(query, 'limit', isString) - ); -} - -export default async function handler(req: NextApiRequest, resp: NextApiResponse) { - try { - if (req.method !== 'GET') - throw buildErrno('Request Method is not allowed', ErrnoCode.UserMethodNotAllow); - - const { namespace, config } = authKubeConfig(req.headers); - if (!isListQuery(req.query)) { - throw buildErrno(`There has some invalid query in ${req.query}`, ErrnoCode.UserBadRequest); - } - - // TODO: list limited items - const { kind, limit } = req.query; - const url = getApiUrl(kind, namespace); - - const res = await axios.get(url, config); - resp.status(res.status).json({ - code: res.status, - data: res.data as KubeList - }); - } catch (err: any) { - sendErrorResponse( - resp, - handlerAxiosError(err, ErrnoCode.APIListRequestError, ErrnoCode.APIListResponseError) - ); - } -} diff --git a/frontend/providers/kubepanel/src/pages/api/kubernetes/template.ts b/frontend/providers/kubepanel/src/pages/api/kubernetes/template.ts deleted file mode 100644 index 0904312c2..000000000 --- a/frontend/providers/kubepanel/src/pages/api/kubernetes/template.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { hasTypedProperty } from '@/k8slens/utilities'; -import { ErrnoCode, buildErrno } from '@/services/backend/error'; -import { sendErrorResponse } from '@/services/backend/response'; -import { TemplateQuery, TemplateResponse } from '@/types/api/kubenertes'; -import fs from 'fs'; -import { isObject, isString } from 'lodash'; -import { NextApiRequest, NextApiResponse } from 'next'; -function isTemplateQuery(query: unknown): query is TemplateQuery { - return isObject(query) && hasTypedProperty(query, 'kind', isString); -} - -export default function handler(req: NextApiRequest, resp: NextApiResponse) { - try { - if (req.method !== 'GET') - throw buildErrno('Request Method is not allowed', ErrnoCode.UserMethodNotAllow); - - if (!isTemplateQuery(req.query)) - throw buildErrno(`There has some invalid query in ${req.query}`, ErrnoCode.UserBadRequest); - - const { kind } = req.query; - const templatePath = `${process.cwd()}/public/create-resource-templates/${kind}.yaml`; - - if (!fs.existsSync(templatePath)) - throw buildErrno(`Template "${kind}" not found`, ErrnoCode.UserBadRequest); - - const template = fs.readFileSync(templatePath, 'utf8'); - if (template === '') - throw buildErrno(`Read template "${kind}" failed`, ErrnoCode.ServerInternalError); - - resp.status(200).json({ - code: 200, - data: template - }); - } catch (err: any) { - sendErrorResponse(resp, err); - } -} diff --git a/frontend/providers/kubepanel/src/pages/api/kubernetes/update.ts b/frontend/providers/kubepanel/src/pages/api/kubernetes/update.ts deleted file mode 100644 index b8f9b039c..000000000 --- a/frontend/providers/kubepanel/src/pages/api/kubernetes/update.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { hasTypedProperty, isObject } from '@/k8slens/utilities'; -import { getApiUrl } from '@/services/backend/api'; -import { authKubeConfig } from '@/services/backend/auth'; -import { ErrnoCode, buildErrno } from '@/services/backend/error'; -import { handlerAxiosError, sendErrorResponse } from '@/services/backend/response'; -import { UpdateQuery, UpdateResponse } from '@/types/api/kubenertes'; -import { mustGetTypedProperty } from '@/utils/api'; -import axios from 'axios'; -import yaml from 'js-yaml'; -import { isString, merge } from 'lodash'; -import { NextApiRequest, NextApiResponse } from 'next'; - -function isUpdateQuery(query: unknown): query is UpdateQuery { - return ( - isObject(query) && - hasTypedProperty(query, 'kind', isString) && - hasTypedProperty(query, 'name', isString) - ); -} - -export default async function handler(req: NextApiRequest, resp: NextApiResponse) { - try { - if (req.method !== 'PUT') - throw buildErrno('Request Method is not allowed', ErrnoCode.UserMethodNotAllow); - - const { namespace, config } = authKubeConfig(req.headers); - if (!isUpdateQuery(req.query)) - throw buildErrno(`There has some invalid query in ${req.query}`, ErrnoCode.UserBadRequest); - - const { kind, name } = req.query; - const url = getApiUrl(kind, namespace, name); - const updatedData = yaml.load(mustGetTypedProperty(req.body, 'data', isString, 'string')); - - const data = merge(updatedData, { - metadata: { - name, - namespace - } - }); - - const res = await axios.put(url, data, config); - resp.status(res.status).json({ - code: res.status, - data: res.data - }); - } catch (err: any) { - sendErrorResponse( - resp, - handlerAxiosError(err, ErrnoCode.APIUpdateRequestError, ErrnoCode.APIUpdateResponseError) - ); - } -} diff --git a/frontend/providers/kubepanel/src/pages/api/platform/init-data.ts b/frontend/providers/kubepanel/src/pages/api/platform/init-data.ts deleted file mode 100644 index 390faa200..000000000 --- a/frontend/providers/kubepanel/src/pages/api/platform/init-data.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { NextApiRequest, NextApiResponse } from 'next'; - -export type Response = { - SEALOS_DOMAIN: string; -}; - -export default async function handler( - req: NextApiRequest, - res: NextApiResponse> -) { - res.status(200).json({ - code: 200, - data: { SEALOS_DOMAIN: process.env.SEALOS_DOMAIN || 'cloud.sealos.io' } - }); -} diff --git a/frontend/providers/kubepanel/src/pages/kubepanel/[[...slug]].tsx b/frontend/providers/kubepanel/src/pages/kubepanel/[[...slug]].tsx deleted file mode 100644 index 84906fa3e..000000000 --- a/frontend/providers/kubepanel/src/pages/kubepanel/[[...slug]].tsx +++ /dev/null @@ -1,97 +0,0 @@ -import { CreateResourceModal } from '@/components/common/action/create-resource-modal'; -import ConfigMapOverviewPage from '@/components/kubepanel-views/config/config-map/config-map'; -import SecretOverviewPage from '@/components/kubepanel-views/config/secret/secret'; -import BucketPage from '@/components/kubepanel-views/custom-resource/bucket/bucket'; -import ClusterPage from '@/components/kubepanel-views/custom-resource/cluster/cluster'; -import DevboxPage from '@/components/kubepanel-views/custom-resource/devbox/devbox'; -import IngressOverviewPage from '@/components/kubepanel-views/network/ingress/ingress'; -import ServiceOverviewPage from '@/components/kubepanel-views/network/service/service'; -import PersistentVolumeClaimOverviewPage from '@/components/kubepanel-views/storage/volume-claim/volume-claim'; -import DeploymentOverviewPage from '@/components/kubepanel-views/workload/deployment/deployment'; -import OverviewPage from '@/components/kubepanel-views/workload/overview/overview'; -import PodOverviewPage from '@/components/kubepanel-views/workload/pod/pod'; -import StatefulSetOverviewPage from '@/components/kubepanel-views/workload/statefulset/statefulset'; -import { PlusOutlined } from '@ant-design/icons'; -import { FloatButton } from 'antd'; -import { useRouter } from 'next/router'; -import { useEffect, useState } from 'react'; -import { SideNavItemKey } from '../../components/common/sidebar/sidebar'; -import AppLayout from './layout'; - -const switchPage = (key: SideNavItemKey): React.ReactNode => { - switch (key) { - case SideNavItemKey.Overview: - return ; - case SideNavItemKey.Pod: - return ; - case SideNavItemKey.Deployment: - return ; - case SideNavItemKey.StatefulSet: - return ; - case SideNavItemKey.ConfigMap: - return ; - case SideNavItemKey.PersistentVolumeClaim: - return ; - case SideNavItemKey.Secret: - return ; - case SideNavItemKey.Ingress: - return ; - case SideNavItemKey.Service: - return ; - case SideNavItemKey.Devbox: - return ; - case SideNavItemKey.Cluster: - return ; - case SideNavItemKey.Bucket: - return ; - default: - return ; - } -}; - -const Home = () => { - const router = useRouter(); - const [sideNavItemKey, setSideNavItemKey] = useState(SideNavItemKey.Overview); - const [openCreateResourceModal, setOpenCreateResourceModal] = useState(false); - - useEffect(() => { - if (router.isReady) { - const { slug } = router.query; - const currentTab = Array.isArray(slug) && slug.length > 0 ? slug[0] : SideNavItemKey.Overview; - const key = Object.values(SideNavItemKey).find((k) => k === currentTab); - if (key) { - setSideNavItemKey(key); - } - } - }, [router.isReady, router.query, router.query.slug]); - - const handleSideNavClick = (key: SideNavItemKey) => { - setSideNavItemKey(key); - const path = key === SideNavItemKey.Overview ? '/kubepanel' : `/kubepanel/${key}`; - router.push(path, undefined, { shallow: true }); - }; - - return ( - - {switchPage(sideNavItemKey)} - } - tooltip="Create a resource." - style={{ - left: 24, - bottom: 30, - width: 48, - height: 48 - }} - type="primary" - onClick={() => setOpenCreateResourceModal(true)} - /> - setOpenCreateResourceModal(false)} - /> - - ); -}; - -export default Home; diff --git a/frontend/providers/kubepanel/src/pages/kubepanel/layout.tsx b/frontend/providers/kubepanel/src/pages/kubepanel/layout.tsx deleted file mode 100644 index a56e92de9..000000000 --- a/frontend/providers/kubepanel/src/pages/kubepanel/layout.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import { ResourceSideNav, SideNavItemKey } from '@/components/common/sidebar/sidebar'; -import { theme } from '@/constants/theme'; -import { ConfigProvider, Layout } from 'antd'; -import { CollapseType } from 'antd/es/layout/Sider'; -import { useCallback, useState } from 'react'; - -const { Sider, Content } = Layout; - -interface Props { - children: React.ReactNode; - onClickSideNavItem?: (key: SideNavItemKey) => void; - selectedKey?: SideNavItemKey; -} - -type CollapseCallback = (collapsed: boolean, type: CollapseType) => void; - -const siderWidth = 256; -const collapsedWidth = 0; - -export default function AppLayout({ children, onClickSideNavItem, selectedKey }: Props) { - const [contentMargin, setContentMargin] = useState(siderWidth); - - const onCollapse = useCallback((collapsed, _) => { - setContentMargin(collapsed ? collapsedWidth : siderWidth); - }, []); - - return ( - - - - - - - - {children} - - - - - ); -} diff --git a/frontend/providers/kubepanel/src/services/backend/api.ts b/frontend/providers/kubepanel/src/services/backend/api.ts deleted file mode 100644 index ddf11040b..000000000 --- a/frontend/providers/kubepanel/src/services/backend/api.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { KubeObjectKind } from '@/constants/kube-object'; -import { ErrnoCode, buildErrno } from './error'; - -/** - * Retrieves the API URL based on the given kind and namespace. - * - * @param kind The kind of Kubernetes resource. - * @param namespace The namespace of the API object. - * @param name The name of Kubernetes resource. - * @return The API URL. - */ -export function getApiUrl(kind: string, namespace: string, name?: string) { - const baseParams = ApiBaseParamsRecord[kind as KubeObjectKind]; - if (!baseParams) { - throw buildErrno(`Invalid kind ${kind}`, ErrnoCode.UserBadRequest); - } - return [ - baseParams.apiPrefix, - baseParams.apiGroup, - baseParams.apiVersion, - 'namespaces', - namespace, - baseParams.resource, - name - ] - .filter(Boolean) - .join('/'); -} - -const ApiBaseParamsRecord: Record = { - [KubeObjectKind.Pod]: { - apiPrefix: 'api', - // undefined means 'core' group, the following records will not write this property - // because 'core' group won't be used to build url - apiGroup: undefined, - apiVersion: 'v1', - resource: 'pods' - }, - [KubeObjectKind.Deployment]: { - apiPrefix: 'apis', - apiGroup: 'apps', - apiVersion: 'v1', - resource: 'deployments' - }, - [KubeObjectKind.StatefulSet]: { - apiPrefix: 'apis', - apiGroup: 'apps', - apiVersion: 'v1', - resource: 'statefulsets' - }, - [KubeObjectKind.ConfigMap]: { - apiPrefix: 'api', - apiVersion: 'v1', - resource: 'configmaps' - }, - [KubeObjectKind.PersistentVolumeClaim]: { - apiPrefix: 'api', - apiVersion: 'v1', - resource: 'persistentvolumeclaims' - }, - [KubeObjectKind.Secret]: { - apiPrefix: 'api', - apiVersion: 'v1', - resource: 'secrets' - }, - [KubeObjectKind.Ingress]: { - apiPrefix: 'apis', - apiGroup: 'networking.k8s.io', - apiVersion: 'v1', - resource: 'ingresses' - }, - [KubeObjectKind.Event]: { - apiPrefix: 'api', - apiVersion: 'v1', - resource: 'events' - }, - [KubeObjectKind.Service]: { - apiPrefix: 'api', - apiVersion: 'v1', - resource: 'services' - }, - // CustomResource - [KubeObjectKind.Devbox]: { - apiPrefix: 'apis', - apiGroup: 'devbox.sealos.io', - apiVersion: 'v1alpha2', - resource: 'devboxes' - }, - [KubeObjectKind.DevboxOld]: { - apiPrefix: 'apis', - apiGroup: 'devbox.sealos.io', - apiVersion: 'v1alpha1', - resource: 'devboxes' - }, - [KubeObjectKind.Cluster]: { - apiPrefix: 'apis', - apiGroup: 'apps.kubeblocks.io', - apiVersion: 'v1alpha1', - resource: 'clusters' - }, - [KubeObjectKind.Bucket]: { - apiPrefix: 'apis', - apiGroup: 'objectstorage.sealos.io', - apiVersion: 'v1', - resource: 'objectstoragebuckets' - } -}; diff --git a/frontend/providers/kubepanel/src/services/backend/auth.ts b/frontend/providers/kubepanel/src/services/backend/auth.ts deleted file mode 100644 index 6e37ce760..000000000 --- a/frontend/providers/kubepanel/src/services/backend/auth.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { IncomingHttpHeaders } from 'http'; -import { ErrnoCode, buildErrno } from './error'; -import { getAxiosRequestConfig, getCurrentContextObject, loadKubeConfig } from './kubeconfig'; - -/** - * Authenticates the Kubernetes configuration based on the incoming HTTP header. - * - * @param header The HTTP header containing the authentication information. - * @throws If the header is empty or the authorization property is empty. - * @throws If the current context or namespace is not found in the Kubernetes configuration. - * @returns An object containing the namespace and Axios request configuration. - */ -export function authKubeConfig(header: IncomingHttpHeaders) { - if (!header) throw buildErrno('Request header is empty', ErrnoCode.UserUnauthorized); - const { authorization } = header; - if (!authorization || authorization === '') - throw buildErrno('Authorization property in Header is empty', ErrnoCode.UserUnauthorized); - - const yaml = decodeURIComponent(authorization); - try { - const kc = loadKubeConfig(yaml); - const currentContextObj = getCurrentContextObject(kc.contexts, kc.currentContext); - if (!currentContextObj) throw new Error('Current context not found'); - if (!currentContextObj.namespace) throw new Error('Namespace not found'); - - const axiosRequestConfig = getAxiosRequestConfig(kc); - - return { - namespace: currentContextObj.namespace, - config: axiosRequestConfig - }; - } catch (err: any) { - throw buildErrno(err.message, ErrnoCode.UserUnauthorized); - } -} diff --git a/frontend/providers/kubepanel/src/services/backend/error.ts b/frontend/providers/kubepanel/src/services/backend/error.ts deleted file mode 100644 index b5e9e4794..000000000 --- a/frontend/providers/kubepanel/src/services/backend/error.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { hasTypedProperty } from '@/k8slens/utilities'; -import { isError, isNumber, isString } from 'lodash'; - -/** - * An error for bug tracking and good error notification. - */ -export class Errno extends Error { - readonly reason: string; - readonly code: number; - readonly errno: number; - - /** - * Constructs a new instance of the Errno class. - * - * @param code Http status code - * @param message Error detail, should be human readable and informative - * @param reason Error summary of what caused the error - * @param errno Internal defined error code - * @example const err = new Errno("Not Found", "Can't not find a resource called 'error'", 20000); - */ - constructor(code: number, errno: number, reason?: string, message?: string) { - super(message ?? 'Sorry, something went wrong and got no supported message for this error.'); - this.name = 'Errno'; - this.reason = reason ?? 'Unknown Error'; - this.code = code; - this.errno = errno; - } -} - -export function isErrno(err: unknown): err is Errno { - return ( - isError(err) && - err.name === 'Errno' && - hasTypedProperty(err, 'reason', isString) && - hasTypedProperty(err, 'code', isNumber) - ); -} - -export enum ErrnoCode { - // User error - UserBadRequest = 10000, - UserMethodNotAllow = 10001, - UserUnauthorized = 10002, - - // Server error - ServerInternalError = 20000, - - // API server error - APIWatchResponseError = 30000, - APIWatchRequestError = 30001, - APIListResponseError = 30002, - APIListRequestError = 30003, - APIUpdateRequestError = 30004, - APIUpdateResponseError = 30005, - APICreateRequestError = 30006, - APICreateResponseError = 30007, - APIDeleteRequestError = 30008, - APIDeleteResponseError = 30009 -} - -/** - * Generates an Errno object based on the given message and ErrnoCode. - * - * @warning **It's a simple way to build an Errno object, for building it with more details, use the `Errno` class.** - * - * @param message The message to be included in the Errno object. - * @param errnoCode The ErrnoCode to determine the properties of the Errno object. - * @return The generated Errno object. - */ -export function buildErrno(message: string, errnoCode: ErrnoCode) { - switch (errnoCode) { - case ErrnoCode.UserBadRequest: - return new Errno(404, errnoCode, 'Bad Request', message); - case ErrnoCode.UserMethodNotAllow: - return new Errno(405, errnoCode, 'Method Not Allow', message); - case ErrnoCode.UserUnauthorized: - return new Errno(401, errnoCode, 'Unauthorized', message); - case ErrnoCode.ServerInternalError: - return new Errno(500, errnoCode, 'Internal Server Error', message); - default: - return new Errno(500, errnoCode, 'Internal Server Error', message); - } -} diff --git a/frontend/providers/kubepanel/src/services/backend/kubeconfig.ts b/frontend/providers/kubepanel/src/services/backend/kubeconfig.ts deleted file mode 100644 index b08e16d23..000000000 --- a/frontend/providers/kubepanel/src/services/backend/kubeconfig.ts +++ /dev/null @@ -1,212 +0,0 @@ -import { AxiosRequestConfig } from 'axios'; -import https from 'https'; -import jsYaml from 'js-yaml'; -import { camelCase, entries } from 'lodash'; -import { KebabCasedPropertiesDeep, ReadonlyDeep } from 'type-fest'; - -type Cluster = { - server: string; - tlsServerName?: string; - insecureSkipTlsVerify?: boolean; - certificateAuthorityData?: string; -}; - -type AuthInfo = Partial<{ - clientCertificateData: string; - clientKeyData: string; - token: string; - username: string; - password: string; - authProvider: AuthProviderConfig; -}>; - -type Context = { - cluster: string; - user: string; - namespace?: string; -}; - -type NamedItem = { - name: string; -} & { - [K in keyof T]: T[K]; -}; - -type AuthProviderConfig = { - name: string; - config: ReadonlyDeep>; -}; - -type YamlKubeConfig = KebabCasedPropertiesDeep; - -type KubeConfig = { - clusters: NamedItem[]; - users: NamedItem[]; - contexts: NamedItem[]; - currentContext: string; -}; - -/** - * Load kubeconfig from a YAML string and return a Kubernetes configuration object. - * - * @param yaml The YAML string representing the kubeconfig. - * @return The Kubernetes configuration object. - */ -export function loadKubeConfig(yaml: string): KubeConfig { - const yamlKC = jsYaml.load(yaml) as YamlKubeConfig; - - // YAML kubeconfig uses 'current-context' (kebab-case), but KebabCasedPropertiesDeep type - // expects accessing via original structure. We need to access it via bracket notation. - const currentContext = (yamlKC as any)['current-context'] as string | undefined; - if (!currentContext) throw new Error('current-context is required in kubeconfig'); - return { - clusters: loadNamedItems(yamlKC.clusters, 'cluster', ['server']), - users: loadNamedItems(yamlKC.users, 'user'), - contexts: loadNamedItems(yamlKC.contexts, 'context', ['cluster', 'user']), - currentContext - }; -} - -type NonUndefinedKeys = { - [K in keyof T]-?: undefined extends T[K] ? never : K; -}[keyof T]; - -function loadNamedItems( - namedItems: NamedItem[], - itemType: 'cluster' | 'user' | 'context', - required?: NonUndefinedKeys[] -): NamedItem[] { - return namedItems.map((namedItem, idx) => { - if (!namedItem.name) { - throw new Error(`"name" is required in ${itemType}s[${idx}]`); - } - - // for parse yaml file - const item = namedItem[itemType as keyof NamedItem] as T; - if (!item) { - throw new Error(`${itemType} is required in ${itemType}s[${idx}]`); - } - if (required) { - required.forEach((key) => { - if (!item[key]) throw new Error(`${String(key)} is required in ${itemType}s[${idx}]`); - }); - } - - const converted: Record = { name: namedItem.name }; - - entries(item).forEach(([key, value]) => { - converted[camelCase(key)] = value; - }); - - return converted as NamedItem; - }); -} - -/** - * Finds and returns the named context object from the given array of contexts. - * - * @param contexts The array of named context objects. - * @param currentContext The name of the current context. - * @return The named context object that matches the current context, or undefined if not found. - */ -export function getCurrentContextObject( - contexts: Array>, - currentContext: string -): NamedItem | undefined { - return contexts.find((item) => item.name === currentContext); -} - -/** - * Finds and returns the user object from the given array of users that matches the name of the current context object's user. - * - * @param users The array of users to search through. - * @param currentContextObject The current context object containing the user name to match. - * @return The user object with the matching name, or undefined if not found. - */ -export function getCurrentUserObject( - users: Array>, - currentContextObject: NamedItem -) { - return users.find((item) => item.name === currentContextObject.user); -} - -/** - * Finds and returns the current cluster object from the given array of clusters - * based on the name of the current context object's cluster. - * - * @param clusters The array of clusters to search in. - * @param currentContextObject The current context object. - * @return The current cluster object, or undefined if not found. - */ -export function getCurrentClusterObject( - clusters: Array>, - currentContextObject: NamedItem -) { - return clusters.find((item) => item.name === currentContextObject.cluster); -} - -/** - * Generates an `AxiosRequestConfig` based on the provided kubeConfig. - * - * @param kubeConfig The kubeConfig object that contains the necessary information for generating the Axios request configuration. - * @return `AxiosRequestConfig` - */ -export function getAxiosRequestConfig(kubeConfig: KubeConfig): AxiosRequestConfig { - const contextObj = getCurrentContextObject(kubeConfig.contexts, kubeConfig.currentContext); - if (!contextObj) { - throw new Error('cannot get a current context in kubeconfig'); - } - const userObj = getCurrentUserObject(kubeConfig.users, contextObj); - if (!userObj) { - throw new Error('cannot get a current user in kubeconfig'); - } - const clusterObj = getCurrentClusterObject(kubeConfig.clusters, contextObj); - if (!clusterObj) { - throw new Error('cannot get a current cluster in kubeconfig'); - } - - const config: AxiosRequestConfig = {}; - - const skipTlsVerify = clusterObj.insecureSkipTlsVerify === true; - - // HTTPS - const rejectUnauthorized = skipTlsVerify ? false : true; - - const ca = bufferFrom(clusterObj.certificateAuthorityData); - const cert = bufferFrom(userObj.clientCertificateData); - const key = bufferFrom(userObj.clientKeyData); - - config.httpsAgent = new https.Agent({ - rejectUnauthorized, - ca, - cert, - key, - servername: clusterObj.tlsServerName - }); - - // Authorization Header - const authorization = userObj.token ? `Bearer ${userObj.token}` : ''; - - config.headers = { - Authorization: authorization, - 'Content-Type': 'application/json' - }; - - // Auth - config.auth = - userObj.username && userObj.password - ? { - username: userObj.username, - password: userObj.password - } - : undefined; - - // Base URL - config.baseURL = clusterObj.server.replace(/\/$/, ''); - return config; -} - -function bufferFrom(data: string | undefined): Buffer | undefined { - if (!data) return undefined; - return Buffer.from(data, 'base64'); -} diff --git a/frontend/providers/kubepanel/src/services/backend/response.ts b/frontend/providers/kubepanel/src/services/backend/response.ts deleted file mode 100644 index a327296fa..000000000 --- a/frontend/providers/kubepanel/src/services/backend/response.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { KubeStatus } from '@/types/kube-resource'; -import { isAxiosError } from 'axios'; -import { NextApiResponse } from 'next'; -import { Errno, ErrnoCode, buildErrno, isErrno } from './error'; - -/** - * Builds an error response. - * - * @param error - The error object or value. - * @returns `ErrorResponse` - */ -export function buildErrorResponse(error: unknown) { - let errResp: ErrorResponse; - if (isErrno(error)) { - errResp = { - code: error.code, - error: { - errno: error.errno, - message: error.message, - reason: error.reason - } - }; - } else { - errResp = buildErrorResponse( - buildErrno("It's not your problem, it's ours", ErrnoCode.ServerInternalError) - ); - } - return errResp; -} - -/** - * Sends an error response to the Next.js API response object. - * - * @param res The Next.js API response object. - * @param error The error object. - */ -export function sendErrorResponse(res: NextApiResponse, error: Error) { - const errResp = buildErrorResponse(error); - res.status(errResp.code).json(errResp); -} - -/** - * - * - * @param error A error object can be not a `AxiosError` object. - * @param reqErrnoCode ErrnoCode for the API request error. - * @param respErrnoCode ErrnoCode for the API response error. - * - * @returns An `Errno` object or original error object determining is `AxiosError` or not. - */ -export function handlerAxiosError(error: Error, reqErrnoCode: ErrnoCode, respErrnoCode: ErrnoCode) { - if (!isAxiosError(error)) return error; - if (error.response) { - const kubeStatus = error.response.data as KubeStatus; - return new Errno(error.response.status, respErrnoCode, kubeStatus.reason, kubeStatus.message); - } - return new Errno(500, reqErrnoCode, error.name, error.message); -} diff --git a/frontend/providers/kubepanel/src/services/error.ts b/frontend/providers/kubepanel/src/services/error.ts deleted file mode 100644 index 49f87ec6b..000000000 --- a/frontend/providers/kubepanel/src/services/error.ts +++ /dev/null @@ -1,34 +0,0 @@ -export const ERROR_TEXT: Record = { - ETIMEDOUT: 'Server timeout' -}; -export const openaiError: Record = { - context_length_exceeded: 'Context length exceeded, please reset the conversation.', - Unauthorized: 'API key is invalid.', - rate_limit_reached: 'API rate limited, please try again later.', - 'Bad Request': 'Bad Request — possibly too much content.', - 'Too Many Requests': 'Too many requests, please slow down.', - 'Bad Gateway': 'Bad Gateway, please retry.' -}; -export const proxyError: Record = { - ECONNABORTED: true, - ECONNRESET: true -}; - -export enum ERROR_ENUM { - unAuthorization = 'unAuthorization' -} -export const ERROR_RESPONSE: Record< - any, - { - code: number; - statusText: string; - message: string; - data?: any; - } -> = { - [ERROR_ENUM.unAuthorization]: { - code: 403, - statusText: ERROR_ENUM.unAuthorization, - message: 'Invalid credentials' - } -}; diff --git a/frontend/providers/kubepanel/src/services/kubernet.ts b/frontend/providers/kubepanel/src/services/kubernet.ts deleted file mode 100644 index 1990ffd9e..000000000 --- a/frontend/providers/kubepanel/src/services/kubernet.ts +++ /dev/null @@ -1,9 +0,0 @@ -export interface ApiResp { - code: number; - message: string; - data?: T; -} - -const isApiResp = (x: any): x is ApiResp => - typeof x.code === 'number' && typeof x.message === 'string'; -export { isApiResp }; diff --git a/frontend/providers/kubepanel/src/services/request.ts b/frontend/providers/kubepanel/src/services/request.ts deleted file mode 100644 index 2b0ca2979..000000000 --- a/frontend/providers/kubepanel/src/services/request.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { isSuccessResponse } from '@/utils/types'; -import { getUserKubeConfig } from '@/utils/user'; -import axios, { - AxiosHeaders, - AxiosRequestConfig, - AxiosResponse, - InternalAxiosRequestConfig -} from 'axios'; -import { ErrnoCode, buildErrno } from './backend/error'; - -const request = axios.create({ - baseURL: '/', - withCredentials: true, - timeout: 60000 -}); - -// request interceptor -request.interceptors.request.use((config: InternalAxiosRequestConfig) => { - // auto append service prefix - if (config.url && !config.url?.startsWith('/api/')) { - config.url = '' + config.url; - } - let _headers: AxiosHeaders = config.headers; - - //获取token,并将其添加至请求头中 - _headers['Authorization'] = encodeURIComponent(getUserKubeConfig()); - if (!config.headers || config.headers['Content-Type'] === '') { - _headers['Content-Type'] = 'application/json'; - } - - config.headers = _headers; - return config; -}); - -request.interceptors.response.use((response: AxiosResponse) => { - const { data } = response; - - if (!isSuccessResponse(data)) - return Promise.reject( - buildErrno('Response is not correct type', ErrnoCode.ServerInternalError) - ); - - return response.data; -}); - -export function GET( - url: string, - data?: { [key: string]: any }, - config?: AxiosRequestConfig -): Promise { - return request.get(url, { - params: data, - ...config - }); -} - -export function POST( - url: string, - data?: { [key: string]: any }, - config?: AxiosRequestConfig -): Promise { - return request.post(url, data, config); -} - -export function DELETE( - url: string, - data?: { [key: string]: any }, - config?: AxiosRequestConfig -): Promise { - return request.delete(url, { - params: data, - ...config - }); -} - -export function PUT( - url: string, - data?: { [key: string]: any }, - config?: AxiosRequestConfig -): Promise { - return request.put(url, data, config); -} diff --git a/frontend/providers/kubepanel/src/store/global.ts b/frontend/providers/kubepanel/src/store/global.ts deleted file mode 100644 index 594d188a8..000000000 --- a/frontend/providers/kubepanel/src/store/global.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { create } from 'zustand'; - -type State = { - screenWidth: number; - setScreenWidth: (e: number) => void; - lastRoute: string; - setLastRoute: (val: string) => void; -}; - -export const useGlobalStore = create()((set) => ({ - screenWidth: 1440, - setScreenWidth: (e) => set({ screenWidth: e }), - lastRoute: '/', - setLastRoute: (val) => set({ lastRoute: val }) -})); diff --git a/frontend/providers/kubepanel/src/store/k8s/bucket.store.ts b/frontend/providers/kubepanel/src/store/k8s/bucket.store.ts deleted file mode 100644 index a77cdb1be..000000000 --- a/frontend/providers/kubepanel/src/store/k8s/bucket.store.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Bucket } from '@/k8slens/kube-object/src/specifics/bucket'; -import { KubeStore } from '@/types/state'; -import { create } from 'zustand'; -import { createKubeStoreSlice } from './kube.store'; - -export const useBucketStore = create>()((...a) => ({ - ...createKubeStoreSlice(Bucket.kind, Bucket)(...a) -})); diff --git a/frontend/providers/kubepanel/src/store/k8s/cluster.store.ts b/frontend/providers/kubepanel/src/store/k8s/cluster.store.ts deleted file mode 100644 index 2bda8ecb5..000000000 --- a/frontend/providers/kubepanel/src/store/k8s/cluster.store.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Cluster } from '@/k8slens/kube-object/src/specifics/cluster'; -import { KubeStore } from '@/types/state'; -import { create } from 'zustand'; -import { createKubeStoreSlice } from './kube.store'; - -export const useClusterStore = create>()((...a) => ({ - ...createKubeStoreSlice(Cluster.kind, Cluster)(...a) -})); diff --git a/frontend/providers/kubepanel/src/store/k8s/config-map.store.ts b/frontend/providers/kubepanel/src/store/k8s/config-map.store.ts deleted file mode 100644 index bb968ad58..000000000 --- a/frontend/providers/kubepanel/src/store/k8s/config-map.store.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { ConfigMap } from '@/k8slens/kube-object'; -import { ConfigMapStore } from '@/types/state'; -import { create } from 'zustand'; -import { createKubeStoreSlice } from './kube.store'; - -export const useConfigMapStore = create()((...a) => ({ - ...createKubeStoreSlice(ConfigMap.kind, ConfigMap)(...a) -})); diff --git a/frontend/providers/kubepanel/src/store/k8s/deployment.store.ts b/frontend/providers/kubepanel/src/store/k8s/deployment.store.ts deleted file mode 100644 index e9600aac5..000000000 --- a/frontend/providers/kubepanel/src/store/k8s/deployment.store.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Deployment, Pod, PodStatusPhase } from '@/k8slens/kube-object'; -import { DeploymentStore } from '@/types/state'; -import { create } from 'zustand'; -import { createKubeStoreSlice, getByLabel } from './kube.store'; - -export function getDeploymentsStatuses(deps: Deployment[], pods: Pod[]) { - const status = { running: 0, failed: 0, pending: 0 }; - - deps.forEach((deployment) => { - const statuses = new Set( - getByLabel(pods, deployment.getTemplateLabels()).map((pod) => pod.getStatus()) - ); - - if (statuses.has(PodStatusPhase.FAILED)) { - status.failed++; - } else if (statuses.has(PodStatusPhase.PENDING)) { - status.pending++; - } else { - status.running++; - } - }); - - return status; -} - -export const useDeploymentStore = create()((...a) => ({ - ...createKubeStoreSlice(Deployment.kind, Deployment)(...a) -})); diff --git a/frontend/providers/kubepanel/src/store/k8s/devbox.store.ts b/frontend/providers/kubepanel/src/store/k8s/devbox.store.ts deleted file mode 100644 index e41e006d2..000000000 --- a/frontend/providers/kubepanel/src/store/k8s/devbox.store.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { listResources } from '@/api/kubernetes'; -import { KubeObjectKind } from '@/constants/kube-object'; -import { KubeObjectConstructor } from '@/k8slens/kube-object'; -import { Devbox } from '@/k8slens/kube-object/src/specifics/devbox'; -import { isDefined } from '@/k8slens/utilities'; -import { buildErrorResponse } from '@/services/backend/response'; -import { KubeList } from '@/types/kube-resource'; -import { KubeStore } from '@/types/state'; -import { create } from 'zustand'; -import { createKubeStoreSlice } from './kube.store'; - -export const useDevboxStore = create>()((...a) => ({ - ...createKubeStoreSlice(Devbox.kind, Devbox)(...a), - async initialize(callback, force = false) { - const { kind, objConstructor, isLoaded } = a[1](); // get() - const set = a[0]; // set() - - if (isLoaded && !force) return; - - try { - const res = await listResources(kind); - const parsed = parseResponse(res.data, kind, objConstructor); - set({ - items: parsed.sort((a, b) => a.getName().localeCompare(b.getName())), - isLoaded: true, - resourceVersion: res.data.metadata.resourceVersion - }); - callback(res.code); - } catch (err: any) { - if (err?.code === 404 || err?.status === 404 || err?.response?.status === 404) { - // Fallback to v1alpha1 - try { - const res = await listResources(KubeObjectKind.DevboxOld); - const parsed = parseResponse(res.data, kind, objConstructor); - set({ - items: parsed.sort((a, b) => a.getName().localeCompare(b.getName())), - isLoaded: true, - resourceVersion: res.data.metadata.resourceVersion - }); - callback(res.code); - return; - } catch (fallbackErr) { - callback(undefined, buildErrorResponse(fallbackErr)); - } - } else { - callback(undefined, buildErrorResponse(err)); - } - } - } -})); - -const parseResponse = ( - data: KubeList, - kind: string, - objectConstructor: KubeObjectConstructor -): Devbox[] => { - const KubeObjectConstructor = objectConstructor; - const { apiVersion, items } = data; - return items - .map((item) => { - if (!item.metadata) return undefined; - return new KubeObjectConstructor({ - ...item, - kind, - apiVersion - }); - }) - .filter(isDefined); -}; diff --git a/frontend/providers/kubepanel/src/store/k8s/event.store.ts b/frontend/providers/kubepanel/src/store/k8s/event.store.ts deleted file mode 100644 index d29c9c984..000000000 --- a/frontend/providers/kubepanel/src/store/k8s/event.store.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { KubeEvent, KubeEventData } from '@/k8slens/kube-object'; -import { EventStore } from '@/types/state'; -import { create } from 'zustand'; -import { createKubeStoreSlice } from './kube.store'; - -export const useEventStore = create()((...a) => ({ - ...createKubeStoreSlice(KubeEvent.kind, KubeEvent)(...a) -})); diff --git a/frontend/providers/kubepanel/src/store/k8s/ingress.store.ts b/frontend/providers/kubepanel/src/store/k8s/ingress.store.ts deleted file mode 100644 index 0106f9c90..000000000 --- a/frontend/providers/kubepanel/src/store/k8s/ingress.store.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Ingress } from '@/k8slens/kube-object'; -import { IngressStore } from '@/types/state'; -import { create } from 'zustand'; -import { createKubeStoreSlice } from './kube.store'; - -export const useIngressStore = create()((...a) => ({ - ...createKubeStoreSlice(Ingress.kind, Ingress)(...a) -})); diff --git a/frontend/providers/kubepanel/src/store/k8s/kube.store.ts b/frontend/providers/kubepanel/src/store/k8s/kube.store.ts deleted file mode 100644 index eeb00d1c9..000000000 --- a/frontend/providers/kubepanel/src/store/k8s/kube.store.ts +++ /dev/null @@ -1,103 +0,0 @@ -import { listResources } from '@/api/kubernetes'; -import { KubeJsonApiDataFor, KubeObject, KubeObjectConstructor } from '@/k8slens/kube-object'; -import { isDefined } from '@/k8slens/utilities'; -import { buildErrorResponse } from '@/services/backend/response'; -import { KubeList } from '@/types/kube-resource'; -import { APICallback, KubeStore } from '@/types/state'; -import { entries } from 'lodash'; -import { StateCreator } from 'zustand'; - -export function createKubeStoreSlice< - K extends KubeObject = KubeObject, - Data extends KubeJsonApiDataFor = KubeJsonApiDataFor ->(kind: K['kind'], objConstructor: KubeObjectConstructor): StateCreator> { - return (set, get) => ({ - items: [], - kind, - isLoaded: false, - resourceVersion: '', - objConstructor, - modify(item: K) { - set((state) => { - const arr = [...state.items]; - const idx = arr.findIndex((i) => i.getName() === item.getName()); - if (idx === -1) { - arr.push(item); - } else { - arr[idx] = item; - } - return { items: arr.sort((a, b) => a.getName().localeCompare(b.getName())) }; - }); - }, - remove(item: K) { - set((state) => { - const items = state.items.filter((i) => i.getName() !== item.getName()); - return { items }; - }); - }, - async initialize(callback: APICallback, force = false) { - const { kind, objConstructor, isLoaded } = get(); - - if (isLoaded && !force) return; - try { - const res = await listResources(kind); - const parsed = parseResponse(res.data, kind, objConstructor); - set({ - items: parsed.sort((a, b) => a.getName().localeCompare(b.getName())), - isLoaded: true, - resourceVersion: res.data.metadata.resourceVersion - }); - callback(res.code); - } catch (err) { - callback(undefined, buildErrorResponse(err)); - } - } - }); -} - -export function getByLabel( - items: K[], - labels: string[] | Partial> -): K[] { - if (Array.isArray(labels)) { - return items.filter((item: K) => { - const itemLabels = item.getLabels(); - - return labels.every((label) => itemLabels.includes(label)); - }); - } else { - return items.filter((item: K) => { - const itemLabels = item.metadata.labels || {}; - - return entries(labels).every(([key, value]) => itemLabels[key] === value); - }); - } -} - -const parseResponse = < - K extends KubeObject = KubeObject, - Data extends KubeJsonApiDataFor = KubeJsonApiDataFor ->( - data: KubeList, - kind: string, - objectConstructor: KubeObjectConstructor -): K[] => { - const KubeObjectConstructor = objectConstructor; - - const { apiVersion, items } = data; - - return items - .map((item) => { - if (!item.metadata) { - return undefined; - } - - const object = new KubeObjectConstructor({ - ...item, - kind, - apiVersion - }); - return object; - }) - .filter(isDefined); -}; diff --git a/frontend/providers/kubepanel/src/store/k8s/pod.store.ts b/frontend/providers/kubepanel/src/store/k8s/pod.store.ts deleted file mode 100644 index e1fc01946..000000000 --- a/frontend/providers/kubepanel/src/store/k8s/pod.store.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Pod } from '@/k8slens/kube-object'; -import { PodStore } from '@/types/state'; -import { create } from 'zustand'; -import { createKubeStoreSlice } from './kube.store'; - -export const usePodStore = create()((...a) => ({ - ...createKubeStoreSlice(Pod.kind, Pod)(...a) -})); - -export function getPodsByOwnerId(pods: Pod[], workloadId: string): Pod[] { - return pods.filter((pod) => { - return pod.getOwnerRefs().find((owner) => owner.uid === workloadId); - }); -} diff --git a/frontend/providers/kubepanel/src/store/k8s/secret.store.ts b/frontend/providers/kubepanel/src/store/k8s/secret.store.ts deleted file mode 100644 index 0379ccc8c..000000000 --- a/frontend/providers/kubepanel/src/store/k8s/secret.store.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Secret, SecretData } from '@/k8slens/kube-object'; -import { SecretStore } from '@/types/state'; -import { create } from 'zustand'; -import { createKubeStoreSlice } from './kube.store'; - -export const useSecretStore = create()((...a) => ({ - ...createKubeStoreSlice(Secret.kind, Secret)(...a) -})); diff --git a/frontend/providers/kubepanel/src/store/k8s/service.store.ts b/frontend/providers/kubepanel/src/store/k8s/service.store.ts deleted file mode 100644 index fd754aa2f..000000000 --- a/frontend/providers/kubepanel/src/store/k8s/service.store.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Service } from '@/k8slens/kube-object'; -import { ServiceStore } from '@/types/state'; -import { create } from 'zustand'; -import { createKubeStoreSlice } from './kube.store'; - -export const useServiceStore = create()((...a) => ({ - ...createKubeStoreSlice(Service.kind, Service)(...a) -})); diff --git a/frontend/providers/kubepanel/src/store/k8s/stateful-set.store.ts b/frontend/providers/kubepanel/src/store/k8s/stateful-set.store.ts deleted file mode 100644 index bd797931c..000000000 --- a/frontend/providers/kubepanel/src/store/k8s/stateful-set.store.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { Pod, PodStatusPhase, StatefulSet } from '@/k8slens/kube-object'; -import { StatefulSetStore } from '@/types/state'; -import { create } from 'zustand'; -import { createKubeStoreSlice } from './kube.store'; -import { getPodsByOwnerId } from './pod.store'; - -export function getStatefulSetsStatuses(statefulSets: StatefulSet[], pods: Pod[]) { - const status = { running: 0, failed: 0, pending: 0 }; - - for (const statefulSet of statefulSets) { - const statuses = new Set( - getPodsByOwnerId(pods, statefulSet.getId()).map((pod) => pod.getStatus()) - ); - - if (statuses.has(PodStatusPhase.FAILED)) { - status.failed++; - } else if (statuses.has(PodStatusPhase.PENDING)) { - status.pending++; - } else { - status.running++; - } - } - - return status; -} - -export const useStatefulSetStore = create()((...a) => ({ - ...createKubeStoreSlice(StatefulSet.kind, StatefulSet)(...a) -})); diff --git a/frontend/providers/kubepanel/src/store/k8s/volume-claim.store.ts b/frontend/providers/kubepanel/src/store/k8s/volume-claim.store.ts deleted file mode 100644 index 54bb89c0b..000000000 --- a/frontend/providers/kubepanel/src/store/k8s/volume-claim.store.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { PersistentVolumeClaim } from '@/k8slens/kube-object'; -import { VolumeClaimStore } from '@/types/state'; -import { create } from 'zustand'; -import { createKubeStoreSlice } from './kube.store'; - -export const useVolumeClaimStore = create()((...a) => ({ - ...createKubeStoreSlice( - PersistentVolumeClaim.kind, - PersistentVolumeClaim - )(...a) -})); diff --git a/frontend/providers/kubepanel/src/store/kube.ts b/frontend/providers/kubepanel/src/store/kube.ts deleted file mode 100644 index 33935e10c..000000000 --- a/frontend/providers/kubepanel/src/store/kube.ts +++ /dev/null @@ -1,12 +0,0 @@ -export * from './k8s/bucket.store'; -export * from './k8s/cluster.store'; -export * from './k8s/config-map.store'; -export * from './k8s/deployment.store'; -export * from './k8s/devbox.store'; -export * from './k8s/ingress.store'; -export * from './k8s/kube.store'; -export * from './k8s/pod.store'; -export * from './k8s/secret.store'; -export * from './k8s/service.store'; -export * from './k8s/stateful-set.store'; -export * from './k8s/volume-claim.store'; diff --git a/frontend/providers/kubepanel/src/store/static.ts b/frontend/providers/kubepanel/src/store/static.ts deleted file mode 100644 index 66cbeb2d2..000000000 --- a/frontend/providers/kubepanel/src/store/static.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { getInitData } from '@/api/platform'; - -export let SEALOS_DOMAIN: string; - -export const loadInitData = async () => { - try { - const res = await getInitData(); - SEALOS_DOMAIN = res.SEALOS_DOMAIN; - - return { - SEALOS_DOMAIN - }; - } catch (err) { - console.error(err); - } - - return { - SEALOS_DOMAIN - }; -}; diff --git a/frontend/providers/kubepanel/src/styles/globals.css b/frontend/providers/kubepanel/src/styles/globals.css deleted file mode 100644 index 5b73e8a9b..000000000 --- a/frontend/providers/kubepanel/src/styles/globals.css +++ /dev/null @@ -1,116 +0,0 @@ -@import 'tailwindcss'; -@import 'antd/dist/reset.css'; - -@theme { - --color-color-ok: #039855; - --color-color-warning: #ff9800; - --color-color-error: #ce3933; - --color-color-success: #206923; - --color-color-terminated: #9dabb5; - --color-color-vague: #ededed; - --color-color-info: #2d81a4; - --color-color-border: #d9d9d9; -} - -*, -::before, -::after { - box-sizing: border-box; - border-width: 0; - border-style: solid; - border-color: theme('borderColor.DEFAULT', currentColor); -} - -::before, -::after { - --tw-content: ''; -} - -/* Sidebar Menu - Necessary for custom sidebar styling */ -.kubepanel-sidebar-menu.ant-menu { - background: transparent !important; -} - -.kubepanel-sidebar-menu .ant-menu-item { - margin: 0 !important; - width: 100% !important; - border-radius: 4px !important; - color: #71717a !important; - margin-bottom: 2px !important; -} - -.kubepanel-sidebar-menu .ant-menu-submenu-title { - margin: 0 !important; - width: 100% !important; - border-radius: 4px !important; - color: #71717a !important; - margin-bottom: 2px !important; -} - -.kubepanel-sidebar-menu .ant-menu-item:hover, -.kubepanel-sidebar-menu .ant-menu-submenu-title:hover { - color: #18181b !important; - background-color: #f4f4f5 !important; -} - -.kubepanel-sidebar-menu .ant-menu-item-selected { - background-color: #f4f4f5 !important; - color: #18181b !important; - font-weight: 500; -} - -.ant-menu.ant-menu-sub.ant-menu-inline { - background-color: transparent !important; -} - -.ant-menu-submenu-active .ant-menu-submenu-title, -.ant-menu-submenu-selected .ant-menu-submenu-title, -.ant-menu-submenu-open .ant-menu-submenu-title { - color: #18181b !important; -} - -/* Modal - Full screen modal for YAML editor */ -.ant-modal { - width: 100vw !important; - max-width: 100vw !important; - top: 0; - padding-bottom: 0; -} - -.ant-modal-content { - border-radius: 0% !important; -} - -.ant-modal-body { - height: calc(100vh - 85px); - overflow-y: auto; -} - -.ant-modal-close { - margin-top: 1%; - margin-right: 1%; -} - -.ant-modal-close-x svg { - width: 1.5em; - height: 1.5em; - color: #111824; -} - -/* Collapse - Fix icon alignment */ -.ant-collapse-header { - align-items: center !important; - padding: 12px 0 !important; -} - -.ant-collapse-header .ant-collapse-expand-icon { - height: 100% !important; - display: flex !important; - align-items: center !important; - padding-inline-end: 0 !important; -} - -/* Table row cursor */ -.ant-table-tbody tr { - cursor: pointer; -} diff --git a/frontend/providers/kubepanel/src/types/api/base.d.ts b/frontend/providers/kubepanel/src/types/api/base.d.ts deleted file mode 100644 index 6b0220946..000000000 --- a/frontend/providers/kubepanel/src/types/api/base.d.ts +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Basic response format for API - * - * @warning It is not allowed to use `BasicResponse` as a return type in API - */ -type BasicResponse = { - code: number; -}; - -/** - * Basic error response format for API - * - * @example const resp: ErrorResponse = {code: 404, error: {errno: 10000, message: "Not Found", reason: "Can't not find a resource called 'error'"}} - */ -type ErrorResponse = Merge< - BasicResponse, - { error: { errno: number; message: string; reason: string } } ->; - -/** - * Basic success response format for API - * - * @example const resp: SuccessResponse<{message: string}> = {code: 200, errno: 0, data: {message: "Success"}} - */ -type SuccessResponse = Merge; - -type ApiPrefix = 'api' | 'apis'; -type ApiGroup = string; -type ApiVersion = 'v1' | 'v1alpha1' | 'v1alpha2' | 'v1beta1'; - -/** - * Kubernetes API URL Params - */ -type KubeApiUrlParams = { - apiPrefix: ApiPrefix; - apiGroup?: ApiGroup; - apiVersion: ApiVersion; - resource: string; -}; diff --git a/frontend/providers/kubepanel/src/types/api/kubenertes.d.ts b/frontend/providers/kubepanel/src/types/api/kubenertes.d.ts deleted file mode 100644 index a08196d95..000000000 --- a/frontend/providers/kubepanel/src/types/api/kubenertes.d.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { KubeObject } from '../kube-resource'; - -/** - * Basic API query - * - * @example - * For a Pod resource called "nginx" - * ```ts - * const query = {kind: "Pod", name: "nginx"} - * ``` - */ -type KubeQuery = { - kind: string; - name: string; -}; - -type WatchQuery = Merge< - Optional, - { - resourceVersion: string; - } ->; -type WatchResponse = SuccessResponse> | ErrorResponse; - -type TemplateQuery = { - kind: string; -}; -type TemplateResponse = SuccessResponse | ErrorResponse; - -type ListQuery = Merge< - Omit, - { - limit?: number; - } ->; -type ListResponse = SuccessResponse> | ErrorResponse; - -type UpdateQuery = KubeQuery; -type UpdateResponse = SuccessResponse | ErrorResponse; - -type CreateQuery = Omit; -type CreateResponse = SuccessResponse | ErrorResponse; - -type DeleteQuery = KubeQuery; -type DeleteResponse = SuccessResponse | ErrorResponse; diff --git a/frontend/providers/kubepanel/src/types/detail.d.ts b/frontend/providers/kubepanel/src/types/detail.d.ts deleted file mode 100644 index 911997a20..000000000 --- a/frontend/providers/kubepanel/src/types/detail.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -type DetailDrawerProps = { - obj: K | null; - onClose: () => void; - open: boolean; -}; diff --git a/frontend/providers/kubepanel/src/types/kube-resource.d.ts b/frontend/providers/kubepanel/src/types/kube-resource.d.ts deleted file mode 100644 index e42d5bf07..000000000 --- a/frontend/providers/kubepanel/src/types/kube-resource.d.ts +++ /dev/null @@ -1,86 +0,0 @@ -/** - * Kubernetes basic object data - */ -export type KubeBasicData = { - apiVersion: string; - kind: string; - metadata: Meta; -}; - -/** - * Kubernetes StatusDetails - * - * @link https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#statusdetails-v1-meta - */ -export type KubeStatusDetails = { - causes?: Array<{ - field: string; - message: string; - reason: string; - }>; - group: string; - kind: string; - name: string; - retryAfterSeconds: number; - uid: string; -}; - -/** - * Kubernetes Status - * - * @link https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#status-v1-meta - */ -export type KubeStatus = Merge< - KubeBasicData, - { - code: number; - details?: KubeStatusDetails; - message: string; - reason: string; - status: 'Success' | 'Failure'; - } ->; - -/** - * Kubernetes ListMeta - * @link https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#listmeta-v1-meta - */ -export type KubeListMeta = { - continue?: string; - remainingItemCount?: number; - resourceVersion: string; -}; - -/** - * Kubernetes List - * - * @typeParam Type of a specific `KubeBasicData` - * @link https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#listmeta-v1-meta - */ -export type KubeList = Merge< - KubeBasicData, - { - items: T[]; - } ->; -/** - * Kubernetes WatchEvent - * - * @typeParam Type of a specific `KubeBasicData` - * @link https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#watchevent-v1-meta - */ -export type WatchEvent = - | { - object: T; - type: 'ADDED' | 'MODIFIED' | 'DELETED'; - } - | { - object?: T; - type: 'ERROR'; - } - | { - object: KubeBasicData<{ resourceVersion: string }>; - type: 'BOOKMARK'; - }; - -export type KubeObject = KubeBasicData; diff --git a/frontend/providers/kubepanel/src/types/state.d.ts b/frontend/providers/kubepanel/src/types/state.d.ts deleted file mode 100644 index 528f59357..000000000 --- a/frontend/providers/kubepanel/src/types/state.d.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { - ConfigMap, - Deployment, - Ingress, - KubeEvent, - KubeObject, - KubeObjectConstructor, - PersistentVolumeClaim, - Pod, - Secret, - StatefulSet -} from '@/k8slens/kube-object'; - -type APICallback = (successResp?: number, errResp?: ErrorResponse) => void; - -type KubeStoreState = { - items: Array; - kind: K['kind']; - objConstructor: KubeObjectConstructor; - isLoaded: boolean; - resourceVersion: string; -}; - -type KubeStoreAction = { - modify: (item: K) => void; - remove: (item: K) => void; - initialize: (callback: APICallback, force?: boolean) => void; -}; - -type KubeStore = KubeStoreState & KubeStoreAction; - -type StatusesComputed = { - getStatuses: Record; -}; - -type PodStore = KubeStore; -type DeploymentStore = KubeStore; -type StatefulSetStore = KubeStore; -type ConfigMapStore = KubeStore; -type VolumeClaimStore = KubeStore; -type SecretStore = KubeStore; -type IngressStore = KubeStore; -type EventStore = KubeStore; -type ServiceStore = KubeStore; diff --git a/frontend/providers/kubepanel/src/types/util.d.ts b/frontend/providers/kubepanel/src/types/util.d.ts deleted file mode 100644 index 97e205b34..000000000 --- a/frontend/providers/kubepanel/src/types/util.d.ts +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Set some properties to be optional - * - * @typeParam T Type - * @typeParam K Keys - * @example Optional<{a: string, b: number}, 'a'> = {a: string | undefined, b: number} - * @example Optional<{a: string, b: number}, 'a' | 'b'> = {a: string | undefined, b: number | undefined} - */ -type Optional = Merge< - { [P in K]?: T[P] }, - { - [P in Exclude]: T[P]; - } ->; - -/** - * Merge two types for a better prompting effect - * - * @example Merge<{a: string}, {b: number}> = {a: string, b: number} - */ -type Merge = { - [P in keyof T | keyof U]: P extends keyof U ? U[P] : P extends keyof T ? T[P] : never; -}; diff --git a/frontend/providers/kubepanel/src/utils/api.ts b/frontend/providers/kubepanel/src/utils/api.ts deleted file mode 100644 index 28192ac17..000000000 --- a/frontend/providers/kubepanel/src/utils/api.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { hasOwnProperty } from '@/k8slens/utilities'; - -/** - * A function that retrieves the value of a specified key from an object. - * - * @param {T} obj - The object from which to retrieve the value. - * @param {Key} key - The key of the value to retrieve. - * @return {unknown} The value associated with the specified key. - * @throws {Error} If the specified key is not found in the object. - */ -export function mustGetProperty(obj: T, key: Key): unknown { - if (hasOwnProperty(obj, key)) return obj[key]; - throw new Error(`${String(key)} was not found in Object ${JSON.stringify(obj)}`); -} - -/** - * Maps an array of keys to their corresponding values in an object. - * - * @param {object} obj - The object to get the properties from. - * @param {Array} keys - The keys to retrieve from the object. - * @return {Array} An array of the values corresponding to the keys in the object. - */ -export function mustGetProperties( - obj: T, - keys: Key[] -): unknown[] { - return keys.map((key) => mustGetProperty(obj, key)); -} - -/** - * A function that retrieves a typed property from an object, and throws an error if the property value does not pass a validation function. - * - * @param {T} obj - The object to retrieve the property from. - * @param {Key} key - The key of the property to retrieve. - * @param {(value: any) => value is Type} validator - A validation function that checks if the property value is of the specified type. - * @param {Type} typeName - The name of the type expected for the property value. - * @returns {Type} - The value of the property if it passes the validation function. - * @throws {Error} - Throws an error if the property value does not pass the validation function. - */ -export function mustGetTypedProperty( - obj: T, - key: Key, - validator: (value: any) => value is Type, - typeName: Type -): Type { - const value = mustGetProperty(obj, key); - if (!validator(value)) { - throw new Error(`${String(key)} was not ${typeName} type in Object ${JSON.stringify(obj)}`); - } - return value; -} diff --git a/frontend/providers/kubepanel/src/utils/condtion-color.ts b/frontend/providers/kubepanel/src/utils/condtion-color.ts deleted file mode 100644 index 82e79f22e..000000000 --- a/frontend/providers/kubepanel/src/utils/condtion-color.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { TextProps } from 'antd/es/typography/Text'; -import { snakeCase } from 'lodash'; - -const conditionTextToneMap: Record = { - available: 'success', - progressing: 'secondary', - replica_failure: 'danger' -}; - -export const getConditionTextTone = (condition: string): TextProps['type'] | undefined => { - return conditionTextToneMap[snakeCase(condition)]; -}; diff --git a/frontend/providers/kubepanel/src/utils/kube-object-info.ts b/frontend/providers/kubepanel/src/utils/kube-object-info.ts deleted file mode 100644 index 12c570aae..000000000 --- a/frontend/providers/kubepanel/src/utils/kube-object-info.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { KubeObject, KubeObjectMetadata, KubeObjectScope } from '@/k8slens/kube-object'; - -export type OwnerRef< - Metadata extends KubeObjectMetadata = KubeObjectMetadata -> = { - namespace: Metadata['namespace']; - apiVersion: string; - kind: string; - name: string; - uid: string; - - controller?: boolean | undefined; - blockOwnerDeletion?: boolean | undefined; -}; - -export type KubeObjectInfo = { - creationTimestamp?: string; - name: string; - uid: string; - resourceVersion: string; - labels: Array; - annotations: Array; - finalizers: Array; - ownerRefs: Array; -}; - -export const getKubeObjectInfo = (obj: K): KubeObjectInfo => { - return { - creationTimestamp: obj.metadata.creationTimestamp, - name: obj.metadata.name, - uid: obj.getId(), - resourceVersion: obj.getResourceVersion(), - labels: obj.getLabels(), - annotations: obj.getAnnotations(), - finalizers: obj.getFinalizers(), - ownerRefs: obj.getOwnerRefs() - }; -}; diff --git a/frontend/providers/kubepanel/src/utils/pie-chart.ts b/frontend/providers/kubepanel/src/utils/pie-chart.ts deleted file mode 100644 index 2f0b8764d..000000000 --- a/frontend/providers/kubepanel/src/utils/pie-chart.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { WorkloadStatusData } from '@/components/kubepanel-views/workload/overview/status-chart'; -import { Dictionary, capitalize, entries } from 'lodash'; - -export const convertToPieChartStatusData = (dict: Dictionary) => { - return entries(dict) - .filter(([_, value]) => value !== 0) - .map( - ([key, value]) => - ({ - type: capitalize(key), - value - }) as WorkloadStatusData - ); -}; diff --git a/frontend/providers/kubepanel/src/utils/request-controller.ts b/frontend/providers/kubepanel/src/utils/request-controller.ts deleted file mode 100644 index 646ee9490..000000000 --- a/frontend/providers/kubepanel/src/utils/request-controller.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { range } from 'lodash'; - -export type RequestControllerProps = { - timeoutDuration: number; - limit?: number; -}; - -// TODO: task tag -type Task = () => Promise; - -export class RequestController { - private readonly timeoutDuration: number; // ms - private readonly limit: number; - private tasks: Array = []; - private index: number = 0; - private results: Array = []; - - constructor(props: RequestControllerProps) { - this.timeoutDuration = props.timeoutDuration; - this.limit = props.limit ?? 3; - } - - private static timeout(ms: number) { - return new Promise((reject) => - setTimeout(() => { - reject(new Error('Timeout Error')); - }, ms) - ); - } - - private async executeTask(index: number): Promise { - const task = this.tasks[index]; - - if (!task) return; - this.index++; - try { - const res = await Promise.race([task(), RequestController.timeout(this.timeoutDuration)]); - this.results[this.index] = res ?? null; - } catch (err: any) { - this.results[this.index] = err; - } - return this.executeTask(this.index); - } - - private stop() { - this.index = this.tasks.length; - } - - async runTasks(tasks: Array) { - this.stop(); - this.index = 0; - this.tasks = tasks; - this.results = []; - - await Promise.allSettled(range(this.limit).map((index) => this.executeTask(index))); - - return this.results; - } -} diff --git a/frontend/providers/kubepanel/src/utils/status-color.ts b/frontend/providers/kubepanel/src/utils/status-color.ts deleted file mode 100644 index e54faa72e..000000000 --- a/frontend/providers/kubepanel/src/utils/status-color.ts +++ /dev/null @@ -1,70 +0,0 @@ -import type { BadgeProps } from 'antd'; -import type { TextProps } from 'antd/es/typography/Text'; -import { snakeCase } from 'lodash'; - -type TextTone = TextProps['type']; -type BadgeTone = BadgeProps['status']; - -const statusTextToneMapping: Record = { - running: 'success', - pending: 'warning', - evicted: 'danger', - waiting: 'warning', - succeeded: 'success', - failed: 'danger', - terminated: 'secondary', - terminating: 'secondary', - completed: 'success', - crash_loop_back_off: 'danger', - error: 'danger', - container_creating: 'secondary' -}; - -const statusBadgeToneMapping: Record = { - running: 'success', - pending: 'warning', - evicted: 'error', - waiting: 'warning', - succeeded: 'success', - failed: 'error', - terminated: 'default', - terminating: 'default', - completed: 'success', - crash_loop_back_off: 'error', - error: 'error', - container_creating: 'processing' -}; - -export const getStatusTextTone = (status: string): TextTone | undefined => { - return statusTextToneMapping[snakeCase(status)]; -}; - -export const getStatusBadgeTone = (status: string): BadgeTone | undefined => { - return statusBadgeToneMapping[snakeCase(status)]; -}; - -// Tag color mapping for Ant Design Tag component -// Used for Devbox state, Cluster phase, Bucket policy, etc. -const statusTagColorMapping: Record = { - // Common states - running: 'green', - pending: 'orange', - stopped: 'default', - error: 'red', - failed: 'red', - unknown: 'blue', - - // Cluster phases - creating: 'blue', - updating: 'blue', - deleting: 'default', - - // Bucket policies - public_read: 'green', - public_readwrite: 'orange', - private: 'default' -}; - -export const getStatusTagColor = (status: string): string => { - return statusTagColorMapping[snakeCase(status)] || 'blue'; -}; diff --git a/frontend/providers/kubepanel/src/utils/types.ts b/frontend/providers/kubepanel/src/utils/types.ts deleted file mode 100644 index 8775b469b..000000000 --- a/frontend/providers/kubepanel/src/utils/types.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { hasOptionalTypedProperty, hasOwnProperty, hasTypedProperty } from '@/k8slens/utilities'; -import { KubeList } from '@/types/kube-resource'; -import { isArray, isNumber, isObject, isString } from 'lodash'; - -export function isSuccessResponse(data: unknown): data is SuccessResponse { - return isObject(data) && hasTypedProperty(data, 'code', isNumber) && hasOwnProperty(data, 'data'); -} - -function isAPIError(data: unknown): data is { - errno: number; - message: string; - reason: string; -} { - return ( - isObject(data) && - hasTypedProperty(data, 'errno', isNumber) && - hasTypedProperty(data, 'message', isString) && - hasTypedProperty(data, 'reason', isString) - ); -} - -export function isErrorResponse(data: unknown): data is ErrorResponse { - return ( - isObject(data) && - hasTypedProperty(data, 'code', isNumber) && - hasTypedProperty(data, 'error', isAPIError) - ); -} - -function isKubeListMetadata( - data: unknown -): data is { resourceVersion: string; continue?: string; remainingItemCount?: number } { - return ( - isObject(data) && - hasTypedProperty(data, 'resourceVersion', isString) && - hasOptionalTypedProperty(data, 'continue', isString) && - hasOptionalTypedProperty(data, 'remainingItemCount', isNumber) - ); -} - -export function isKubeList(data: unknown): data is KubeList { - return ( - isObject(data) && - hasTypedProperty(data, 'apiVersion', isString) && - hasTypedProperty(data, 'items', isArray) && - hasTypedProperty(data, 'kind', isString) && - hasTypedProperty(data, 'metadata', isKubeListMetadata) - ); -} diff --git a/frontend/providers/kubepanel/src/utils/user.ts b/frontend/providers/kubepanel/src/utils/user.ts deleted file mode 100644 index e0a62ee70..000000000 --- a/frontend/providers/kubepanel/src/utils/user.ts +++ /dev/null @@ -1,14 +0,0 @@ -export const getUserKubeConfig = () => { - let kubeConfig: string = - process.env.NODE_ENV === 'development' ? process.env.NEXT_PUBLIC_MOCK_USER || '' : ''; - - try { - const store = localStorage.getItem('session'); - if (!kubeConfig && store) { - kubeConfig = JSON.parse(store)?.kubeconfig; - } - } catch (err) { - err; - } - return kubeConfig; -}; diff --git a/frontend/providers/kubepanel/src/utils/yaml.ts b/frontend/providers/kubepanel/src/utils/yaml.ts deleted file mode 100644 index 4b6b1b219..000000000 --- a/frontend/providers/kubepanel/src/utils/yaml.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { KubeObject } from '@/k8slens/kube-object'; -import { dump } from 'js-yaml'; -import { PartialDeep } from 'type-fest'; - -export function dumpKubeObject(obj: PartialDeep) { - const objWithoutFunction: Record = {}; - for (const [key, value] of Object.entries(obj)) { - if (typeof value !== 'function') { - objWithoutFunction[key] = value; - } - } - - // Remove managedFields from metadata if it exists - if (objWithoutFunction.metadata) { - if (objWithoutFunction.metadata.managedFields) { - delete objWithoutFunction.metadata.managedFields; - } - // Remove last-applied-configuration annotation - if ( - objWithoutFunction.metadata.annotations && - objWithoutFunction.metadata.annotations['kubectl.kubernetes.io/last-applied-configuration'] - ) { - delete objWithoutFunction.metadata.annotations[ - 'kubectl.kubernetes.io/last-applied-configuration' - ]; - } - } - - // Reorder keys: apiVersion, kind, metadata, ...others, spec, status - const { apiVersion, kind, metadata, spec, status, ...others } = objWithoutFunction; - const orderedObj: Record = {}; - - if (apiVersion) orderedObj.apiVersion = apiVersion; - if (kind) orderedObj.kind = kind; - if (metadata) orderedObj.metadata = metadata; - - Object.assign(orderedObj, others); - - if (spec) orderedObj.spec = spec; - if (status) orderedObj.status = status; - - return dump(orderedObj); -} diff --git a/frontend/providers/kubepanel/tailwind.config.js b/frontend/providers/kubepanel/tailwind.config.js deleted file mode 100644 index 8945a515b..000000000 --- a/frontend/providers/kubepanel/tailwind.config.js +++ /dev/null @@ -1,34 +0,0 @@ -/** @type {import('tailwindcss').Config} */ -module.exports = { - content: ['./src/**/*.{js,ts,jsx,tsx,mdx}'], - /** - * fix: tailwind css conflict with antd - * @link https://github.com/ant-design/ant-design/issues/38794#issuecomment-1345475630 - */ - corePlugins: { - preflight: false - }, - important: '#app', - theme: { - extend: { - colors: { - color: { - ok: '#039855', - warning: '#ff9800', - error: '#ce3933', - success: '#206923', - terminated: '#9dabb5', - vague: '#ededed', - info: '#2d81a4', - border: '#d9d9d9' - } - } - } - }, - safelist: [ - { - pattern: /(bg|text|border)-color-(.*)/ - } - ], - plugins: [] -}; diff --git a/frontend/providers/kubepanel/tsconfig.json b/frontend/providers/kubepanel/tsconfig.json deleted file mode 100644 index 2ec2ce764..000000000 --- a/frontend/providers/kubepanel/tsconfig.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "compilerOptions": { - "noUncheckedIndexedAccess": true, - "experimentalDecorators": true, - "useDefineForClassFields": true, - "target": "ESNext", - "lib": [ - "dom", - "dom.iterable", - "esnext" - ], - "allowJs": true, - "skipLibCheck": true, - "strict": true, - "noEmit": true, - "esModuleInterop": true, - "module": "esnext", - "moduleResolution": "node", - "resolveJsonModule": true, - "isolatedModules": true, - "jsx": "preserve", - "incremental": true, - "paths": { - "@/*": [ - "./src/*" - ] - }, - "forceConsistentCasingInFileNames": true - }, - "include": [ - "next-env.d.ts", - "**/*.ts", - "**/*.tsx" - ], - "exclude": [ - "node_modules" - ] -} \ No newline at end of file