From effae9f48694605b4fc063bfb498aa8b1db0696a Mon Sep 17 00:00:00 2001 From: jingyang <3161362058@qq.com> Date: Wed, 24 Jul 2024 14:12:29 +0800 Subject: [PATCH 01/13] feat:dbprovider support reconfigure Signed-off-by: jingyang <3161362058@qq.com> --- frontend/pnpm-lock.yaml | 15 ++ frontend/providers/dbprovider/package.json | 2 + .../dbprovider/public/locales/en/common.json | 33 ++-- .../dbprovider/public/locales/zh/common.json | 43 +++--- frontend/providers/dbprovider/src/api/db.ts | 3 + .../src/components/Icon/icons/edit.svg | 5 + .../dbprovider/src/components/Icon/index.tsx | 1 + .../providers/dbprovider/src/constants/db.ts | 82 +++++++++- .../src/pages/api/getConfigByName.ts | 45 ++++++ .../dbprovider/src/pages/api/getDBByName.ts | 28 ++-- .../pages/db/edit/components/EditConfig.tsx | 144 ++++++++++++++++++ .../src/pages/db/edit/components/Form.tsx | 53 ++++++- .../dbprovider/src/pages/db/edit/index.tsx | 43 +++++- frontend/providers/dbprovider/src/store/db.ts | 23 ++- .../providers/dbprovider/src/store/user.ts | 5 +- .../providers/dbprovider/src/types/db.d.ts | 7 +- .../providers/dbprovider/src/utils/adapt.ts | 6 +- .../dbprovider/src/utils/json2Yaml.ts | 55 +++++++ .../providers/dbprovider/src/utils/tools.ts | 102 +++++++++++++ 19 files changed, 625 insertions(+), 70 deletions(-) create mode 100644 frontend/providers/dbprovider/src/components/Icon/icons/edit.svg create mode 100644 frontend/providers/dbprovider/src/pages/api/getConfigByName.ts create mode 100644 frontend/providers/dbprovider/src/pages/db/edit/components/EditConfig.tsx diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index 906a9592be8..daa7336c73b 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -1206,6 +1206,9 @@ importers: immer: specifier: ^9.0.21 version: 9.0.21 + ini: + specifier: ^4.1.3 + version: 4.1.3 js-cookie: specifier: ^3.0.5 version: 3.0.5 @@ -1276,6 +1279,9 @@ importers: '@svgr/webpack': specifier: ^6.5.1 version: 6.5.1 + '@types/ini': + specifier: ^4.1.1 + version: 4.1.1 '@types/js-cookie': specifier: ^3.0.4 version: 3.0.6 @@ -9755,6 +9761,10 @@ packages: /@types/http-errors@2.0.4: resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==} + /@types/ini@4.1.1: + resolution: {integrity: sha512-MIyNUZipBTbyUNnhvuXJTY7B6qNI78meck9Jbv3wk0OgNwRyOOVEKDutAkOs1snB/tx0FafyR6/SN4Ps0hZPeg==} + dev: true + /@types/istanbul-lib-coverage@2.0.6: resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} dev: true @@ -15173,6 +15183,11 @@ packages: resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} dev: false + /ini@4.1.3: + resolution: {integrity: sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dev: false + /inline-style-parser@0.1.1: resolution: {integrity: sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==} dev: false diff --git a/frontend/providers/dbprovider/package.json b/frontend/providers/dbprovider/package.json index a9439b9873b..d10d6a235f0 100644 --- a/frontend/providers/dbprovider/package.json +++ b/frontend/providers/dbprovider/package.json @@ -31,6 +31,7 @@ "github-markdown-css": "^5.2.0", "i18next": "^23.11.5", "immer": "^9.0.21", + "ini": "^4.1.3", "js-cookie": "^3.0.5", "js-yaml": "^4.1.0", "jszip": "^3.10.1", @@ -56,6 +57,7 @@ }, "devDependencies": { "@svgr/webpack": "^6.5.1", + "@types/ini": "^4.1.1", "@types/js-cookie": "^3.0.4", "@types/js-yaml": "^4.0.6", "@types/lodash": "^4.14.199", diff --git a/frontend/providers/dbprovider/public/locales/en/common.json b/frontend/providers/dbprovider/public/locales/en/common.json index ed4ea163fce..a29695d128f 100644 --- a/frontend/providers/dbprovider/public/locales/en/common.json +++ b/frontend/providers/dbprovider/public/locales/en/common.json @@ -1,9 +1,7 @@ { - "age": "Runtime", "Auto": "Automatic", "Backup": "Backup", "Cancel": "Discard", - "confirm": "Confirm", "Containers": "Containers", "Continue": "Continue", "Creating": "Creating", @@ -13,7 +11,6 @@ "Day": "Day", "Delete": "Delete", "Deleting": "Deleting...", - "deploy": "Deploy", "Details": "Details", "Disk": "Storage Size", "Export": "Export", @@ -26,7 +23,6 @@ "Migrating": "Migrating", "Monday": "Monday", "Name": "Name", - "operation": "Operation", "Option": "Optional", "Password": "Password", "Pause": "Pause", @@ -35,14 +31,13 @@ "Perday": "Perday", "Performance": "Performance", "Pod": "Pod", + "Pod Name": "Pod Name", "Port": "Port", - "prompt": "Prompt", "Remark": "Note", "Replicas": "Replicas", "Resources": "Resources", "Restart": "Restart", "Restarting": "Restarting", - "restarts": "Restart Count", "Running": "Running", "Saturday": "Sat", "Save": "Save", @@ -53,11 +48,9 @@ "Success": "succeeded", "Sunday": "Sun", "Thursday": "Thu", - "total_price": "total_price", "Tuesday": "Tue", "Type": "Type", "Unknown": "Unknown", - "update": "Update", "Updating": "Updating", "Username": "Username", "Wednesday": "Wed", @@ -65,11 +58,12 @@ "aborted_connections": "Dropped Connections", "active_connections": "Active Connections", "advanced_configuration": "Advanced Settings", + "age": "Runtime", "anticipated_price": "Projected Cost", "app": { - "resource_quota": "Resource Limits", "cpu_exceeds_quota": "CPU requested exceeds quota. Contact admin.", "memory_exceeds_quota": "Memory requested exceeds quota. Contact admin.", + "resource_quota": "Resource Limits", "storage_exceeds_quota": "Storage requested exceeds quota. Contact admin." }, "app_store": "App Store", @@ -108,6 +102,7 @@ }, "config_form": "Form", "config_info": "Configuration Details", + "confirm": "Confirm", "confirm_delete": "Confirm", "confirm_delete_the_backup": "Confirm deleting this backup?", "confirm_delete_the_migrate": "Confirm deleting the migration record?", @@ -126,6 +121,8 @@ "creation_time": "Creation Time", "current_connections": "Current Connections", "data_migration_config": "Data Migration Settings", + "database_config": "parameters", + "database_edit_config": "Edit database parameters", "database_empty": "You don't have any databases yet", "database_host": "Database Hostname", "database_host_empty": "Please enter the database hostname", @@ -142,6 +139,11 @@ "db_instances_tip": "For optimal performance, use an odd number of {{db}} instances", "db_name": "DataBase Name", "db_table": "DataBase Table", + "dbconfig": { + "no_changes": "No modification yet", + "updates": "Modified parameters", + "updates_tip": "Changing the configuration of mongo and redis databases will cause the database to restart" + }, "delete_anyway": "Force Delete", "delete_backup": "Delete Backup", "delete_failed": "Failed to delete", @@ -149,6 +151,7 @@ "delete_successful": "Deleted successfully", "delete_template_app_tip": "To fully remove this app and all its components, please uninstall it directly from the App Store.", "delete_warning": "Delete Warning", + "deploy": "Deploy", "deploy_database": "Deploy DataBase", "deployment_failed": "Deployment Failed", "deployment_successful": "Deployed Successfully", @@ -169,7 +172,6 @@ "file_upload_failed": "File upload failed", "have_error": "Failed", "hits_ratio": "Hits Ratio", - "migration_preparations": "Migration Preparations Completed", "import_through_file": "Import via File", "important_tips_for_migrating": "Tip: Create a new database in sink DB if source_database and sink_database have overlapping data, to avoid conflicts", "innodb_buffer_pool": "InnoDB Buffer Pool", @@ -209,6 +211,7 @@ "migration_failed": "Migration Failed", "migration_permission_check": "Verifying Migration Permissions", "migration_preparation": "Preparing for Migration", + "migration_preparations": "Migration Preparations Completed", "migration_prompt_information": "To prevent migration failure caused by XXX, please refrain from any operations during the migration process. The migration may take a while for large datasets. Your patience is appreciated.", "migration_successful": "Migration Completed Successfully", "migration_task_created_successfully": "Migration task created", @@ -218,12 +221,13 @@ "no_data_available": "No Data Available", "not_allow_standalone_use": "This application is not allowed to be used alone. Click OK to go to Sealos Desktop for use.", "online_import": "Import Online", + "operation": "Operation", "page_faults": "Page Faults", "pause_error": "Failed to pause the database", "pause_hint": "Pausing the service will stop the calculation of charges for CPU and memory, but charges for storage and external network ports will still apply. Would you like to pause now?", "pause_success": "Database paused", "please_enter": "Please Enter", - "Pod Name": "Pod Name", + "prompt": "Prompt", "query_operations": "Query Operations", "remark_tip": "Contains up to 10 Chinese characters and 30 English characters", "remind": "remind", @@ -231,6 +235,7 @@ "replicas_list": "Pod List", "restart_error": "Failed to restart due to an error", "restart_success": "Restarted successfully. Please wait...", + "restarts": "Restart Count", "restore_backup": "Restore from Backup", "restore_backup_tip": "Restoring a backup will create a new database. Please provide a unique name for the new DB.", "restore_database": "Restore Database from Backup", @@ -240,6 +245,7 @@ "select_a_maximum_of_10_files": "Select up to 10 files", "service_deletion_failed": "Failed to delete the service", "set_auto_backup_successful": "Automatic backup task set successfully", + "single_node_tip": "Single-node DB for development and testing only", "slow_queries": "Slow Queries", "source_database": "Source Database", "start_backup": "Start Backup", @@ -255,8 +261,9 @@ "submit_error": "Error submitting form", "successfully_closed_external_network_access": "Internet access disabled", "table_locks": "Table-level locks", - "single_node_tip": "Single-node DB for development and testing only", + "total_price": "total_price", "turn_on": "Enable", + "update": "Update", "update_database": "Update DataBase", "update_failed": "Update Failed", "update_successful": "Update succeeded", @@ -265,4 +272,4 @@ "use_docs": "Documentation", "version": "Version", "yaml_file": "YAML" -} \ No newline at end of file +} diff --git a/frontend/providers/dbprovider/public/locales/zh/common.json b/frontend/providers/dbprovider/public/locales/zh/common.json index 95ed772beb6..43fe0706bc5 100644 --- a/frontend/providers/dbprovider/public/locales/zh/common.json +++ b/frontend/providers/dbprovider/public/locales/zh/common.json @@ -1,10 +1,7 @@ { - "age": "运行时长", "Auto": "自动", "Backup": "备份", - "basic": "基础配置", "Cancel": "取消", - "confirm": "确认", "Containers": "容器", "Continue": "继续", "Creating": "创建中", @@ -14,7 +11,6 @@ "Day": "天", "Delete": "删除", "Deleting": "删除中", - "deploy": "部署", "Details": "详情", "Disk": "磁盘空间", "Export": "导出", @@ -27,7 +23,6 @@ "Migrating": "正在迁移", "Monday": "周一", "Name": "名字", - "operation": "操作", "Option": "选填", "Password": "密码", "Pause": "暂停", @@ -36,15 +31,13 @@ "Perday": "每日", "Performance": "性能", "Pod": "实例", + "Pod Name": "实例名", "Port": "端口", - "prompt": "提示", "Remark": "备注", - "remind": "提醒", "Replicas": "实例数", "Resources": "资源", "Restart": "重启", "Restarting": "重启中", - "restarts": "重启次数", "Running": "运行中", "Saturday": "周六", "Save": "保存", @@ -52,28 +45,25 @@ "Start": "开始", "Starting": "启动中", "Status": "状态", - "storage_max": "最大存储", - "storage_min": "最小存储", "Success": "成功", "Sunday": "周日", "Thursday": "周四", "Tuesday": "周二", "Type": "类型", "Unknown": "未知", - "update": "变更", "Updating": "变更中", "Username": "用户名", - "version": "版本", "Wednesday": "周三", "Week": "周", "aborted_connections": "异常连接数", "active_connections": "活跃连接数", "advanced_configuration": "高级配置", + "age": "运行时长", "anticipated_price": "预估价格", "app": { - "resource_quota": "资源配额", "cpu_exceeds_quota": "申请的 CPU 超出限制,请联系管理员", "memory_exceeds_quota": "申请的 '内存' 超出限制,请联系管理员", + "resource_quota": "资源配额", "storage_exceeds_quota": "申请的 '存储' 超出限制,请联系管理员" }, "app_store": "应用商店", @@ -93,6 +83,7 @@ "backup_running": "备份中", "backup_success_tip": "备份任务已经成功创建", "backup_time": "备份时间", + "basic": "基础配置", "billing_standards": "计费标准", "block_read_time": "读数据块时间", "block_write_time": "写数据块时间", @@ -111,6 +102,7 @@ }, "config_form": "配置表单", "config_info": "配置信息", + "confirm": "确认", "confirm_delete": "确认删除", "confirm_delete_the_backup": "确认删除该备份?", "confirm_delete_the_migrate": "确定删除迁移记录吗?", @@ -129,6 +121,8 @@ "creation_time": "创建时间", "current_connections": "当前连接数", "data_migration_config": "数据迁移配置", + "database_config": "数据库参数", + "database_edit_config": "编辑数据库参数", "database_empty": "您还没有数据库", "database_host": "数据库主机名", "database_host_empty": "缺少数据库主机名", @@ -145,6 +139,11 @@ "db_instances_tip": "{{db}} 实例数量建议为奇数", "db_name": "数据库名字", "db_table": "数据库表", + "dbconfig": { + "no_changes": "暂无修改", + "updates": "修改的参数", + "updates_tip": "mongo和redis数据库变更配置会导致数据库重启" + }, "delete_anyway": "仍要删除", "delete_backup": "删除备份", "delete_failed": "删除出现意外", @@ -152,6 +151,7 @@ "delete_successful": "删除成功", "delete_template_app_tip": "该应用是通过应用商店部署的,如果您想完全卸载该应用并清理所有相关的组件,请到应用商店中将整个应用删除。", "delete_warning": "删除警告", + "deploy": "部署", "deploy_database": "部署数据库", "deployment_failed": "部署失败", "deployment_successful": "部署成功", @@ -172,7 +172,6 @@ "file_upload_failed": "文件上传失败", "have_error": "出现异常", "hits_ratio": "命中率", - "migration_preparations": "我已阅读并完成迁移准备工作", "import_through_file": "文件导入", "important_tips_for_migrating": "如果 source 数据库中 source_database 和 sink 数据库中 sink_database 的数据库有重叠,应该在sink 数据库中新建 database,以免出现数据重叠", "innodb_buffer_pool": "InnoDB 缓冲池", @@ -212,26 +211,31 @@ "migration_failed": "迁移失败", "migration_permission_check": "迁移权限检查", "migration_preparation": "迁移准备", + "migration_preparations": "我已阅读并完成迁移准备工作", "migration_prompt_information": "迁移时请勿执行操作,以免因XXX导致迁移失败。如数据量较大,迁移时间可能较长,请耐心等待", "migration_successful": "迁移成功", "migration_task_created_successfully": "迁移任务创建成功", "min_replicas": "实例数最小为: ", "monitor_list": "实时监控", + "multi_replica_redis_tip": "Redis 多副本包含 HA 节点,请悉知,预估价格已包含 HA 节点费用", "no_data_available": "暂无数据", "not_allow_standalone_use": "该应用不允许单独使用,点击确认前往 Sealos Desktop 使用。", "online_import": "在线导入", + "operation": "操作", "page_faults": "页错误", "pause_error": "数据库暂停失败", "pause_hint": "暂停服务将停止计算 CPU 和内存等费用,但存储和外网端口仍将产生费用。是否现在暂停?", "pause_success": "数据库已暂停", "please_enter": "请输入", - "Pod Name": "实例名", + "prompt": "提示", "query_operations": "查询操作数", "remark_tip": "最多包含10个中文字符,30个英文字符。", + "remind": "提醒", "replicas_cannot_empty": "实例数不能为空", "replicas_list": "实例列表", "restart_error": "重启出现了意外", "restart_success": "重启成功,请等待", + "restarts": "重启次数", "restore_backup": "恢复备份", "restore_backup_tip": "恢复备份会创建一个新的数据库,你需要提供新的数据库名,并且不能与当前数据库重名。", "restore_database": "恢复数据库备份", @@ -241,6 +245,7 @@ "select_a_maximum_of_10_files": "最多选择 10 个文件", "service_deletion_failed": "Service 删除失败", "set_auto_backup_successful": "设置自动备份任务成功", + "single_node_tip": "单节点数据库仅适用开发测试", "slow_queries": "慢查询", "source_database": "源数据库", "start_backup": "开始备份", @@ -250,19 +255,21 @@ "start_success": "数据库启动成功,请等待", "storage": "磁盘", "storage_cannot_empty": "容量不能为空", + "storage_max": "最大存储", + "storage_min": "最小存储", "storage_range": "容量范围: ", "submit_error": "提交表单错误", "successfully_closed_external_network_access": "已关闭外网访问", "table_locks": "表锁", - "multi_replica_redis_tip": "Redis 多副本包含 HA 节点,请悉知,预估价格已包含 HA 节点费用", - "single_node_tip": "单节点数据库仅适用开发测试", "total_price": "总价", "turn_on": "开启", + "update": "变更", "update_database": "变更数据库", "update_failed": "更新失败", "update_successful": "更新成功", "update_time": "更新时间", "upload_dump_file": "点击上传 Dump 文件", "use_docs": "使用文档", + "version": "版本", "yaml_file": "YAML 文件" -} \ No newline at end of file +} diff --git a/frontend/providers/dbprovider/src/api/db.ts b/frontend/providers/dbprovider/src/api/db.ts index dcd26ac0b67..b538735935b 100644 --- a/frontend/providers/dbprovider/src/api/db.ts +++ b/frontend/providers/dbprovider/src/api/db.ts @@ -14,6 +14,9 @@ export const getMyDBList = () => export const getDBByName = (name: string) => GET(`/api/getDBByName?name=${name}`).then(adaptDBDetail); +export const getConfigByName = ({ name, dbType }: { name: string; dbType: DBType }) => + GET(`/api/getConfigByName?name=${name}&dbType=${dbType}`); + export const createDB = (payload: { dbForm: DBEditType; isEdit: boolean; diff --git a/frontend/providers/dbprovider/src/components/Icon/icons/edit.svg b/frontend/providers/dbprovider/src/components/Icon/icons/edit.svg new file mode 100644 index 00000000000..031f0c1f310 --- /dev/null +++ b/frontend/providers/dbprovider/src/components/Icon/icons/edit.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/frontend/providers/dbprovider/src/components/Icon/index.tsx b/frontend/providers/dbprovider/src/components/Icon/index.tsx index bddb6e52a29..505bb36ade7 100644 --- a/frontend/providers/dbprovider/src/components/Icon/index.tsx +++ b/frontend/providers/dbprovider/src/components/Icon/index.tsx @@ -38,6 +38,7 @@ const map = { infoCircle: require('./icons/infoCircle.svg').default, upperRight: require('./icons/upperRight.svg').default, arrowUp: require('./icons/arrowUp.svg').default, + edit: require('./icons/edit.svg').default, book: require('./icons/book.svg').default, export: require('./icons/export.svg').default, pods: require('./icons/pods.svg').default, diff --git a/frontend/providers/dbprovider/src/constants/db.ts b/frontend/providers/dbprovider/src/constants/db.ts index f90b0933f65..7f33c690500 100644 --- a/frontend/providers/dbprovider/src/constants/db.ts +++ b/frontend/providers/dbprovider/src/constants/db.ts @@ -1,4 +1,4 @@ -import { DBEditType, DBDetailType, PodDetailType } from '@/types/db'; +import { DBEditType, DBDetailType, PodDetailType, DBType } from '@/types/db'; import { CpuSlideMarkList, MemorySlideMarkList } from './editApp'; export const crLabelKey = 'sealos-db-provider-cr'; @@ -222,7 +222,8 @@ export const defaultDBEditValue: DBEditType = { replicas: 1, cpu: CpuSlideMarkList[1].value, memory: MemorySlideMarkList[1].value, - storage: 3 + storage: 3, + config: '' }; export const defaultDBDetail: DBDetailType = { @@ -232,7 +233,8 @@ export const defaultDBDetail: DBDetailType = { status: dbStatusMap.Creating, conditions: [], isDiskSpaceOverflow: false, - labels: {} + labels: {}, + config: '' }; export const defaultPod: PodDetailType = { @@ -293,3 +295,77 @@ export const DBTypeSecretMap = { connectKey: 'milvus' } }; + +export const DBTypeConfigMap: { + [key in DBType]: { + configMapKey: string; + configMapName: string; + type: 'yaml' | 'ini'; + reconfigureName: string; + reconfigureKey: string; + }; +} = { + postgresql: { + configMapName: '-postgresql-pgbouncer-configuration', + configMapKey: 'pgbouncer.ini', + type: 'ini', + reconfigureName: 'postgresql-configuration', + reconfigureKey: 'postgresql.conf' + }, + mongodb: { + type: 'yaml', + configMapName: '-mongodb-mongodb-config', + configMapKey: 'mongodb.conf', + reconfigureName: 'mongodb-config', + reconfigureKey: 'mongodb.conf' + }, + 'apecloud-mysql': { + type: 'ini', + configMapName: '-mysql-mysql-consensusset-config', + configMapKey: 'my.cnf', + reconfigureName: 'mysql-consensusset-config', + reconfigureKey: 'my.cnf' + }, + redis: { + type: 'ini', + configMapName: '-redis-sentinel-redis-replication-config', + configMapKey: 'redis.conf', + reconfigureName: 'redis-replication-config', + reconfigureKey: 'redis.conf' + }, + kafka: { + type: 'ini', + configMapName: '', + configMapKey: '', + reconfigureName: '', + reconfigureKey: '' + }, + qdrant: { + type: 'ini', + configMapName: '', + configMapKey: '', + reconfigureName: '', + reconfigureKey: '' + }, + nebula: { + type: 'ini', + configMapName: '', + configMapKey: '', + reconfigureName: '', + reconfigureKey: '' + }, + weaviate: { + type: 'ini', + configMapName: '', + configMapKey: '', + reconfigureName: '', + reconfigureKey: '' + }, + milvus: { + type: 'ini', + configMapName: '', + configMapKey: '', + reconfigureName: '', + reconfigureKey: '' + } +}; diff --git a/frontend/providers/dbprovider/src/pages/api/getConfigByName.ts b/frontend/providers/dbprovider/src/pages/api/getConfigByName.ts new file mode 100644 index 00000000000..51a4d44339a --- /dev/null +++ b/frontend/providers/dbprovider/src/pages/api/getConfigByName.ts @@ -0,0 +1,45 @@ +import { DBTypeConfigMap } from '@/constants/db'; +import { authSession } from '@/services/backend/auth'; +import { getK8s } from '@/services/backend/kubernetes'; +import { jsonRes } from '@/services/backend/response'; +import { ApiResp } from '@/services/kubernet'; +import { DBType } from '@/types/db'; +import type { NextApiRequest, NextApiResponse } from 'next'; + +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + try { + const { name, dbType } = req.query as { name: string; dbType: DBType }; + if (!name) { + throw new Error('name is empty'); + } + + const { namespace, k8sCore } = await getK8s({ + kubeconfig: await authSession(req) + }); + + const dbConfig = DBTypeConfigMap[dbType]; + const key = name + dbConfig.configMapName; + if (!key) { + return jsonRes(res, { + data: null + }); + } + + const { body } = await k8sCore.readNamespacedConfigMap(key, namespace); + const configData = body?.data && body?.data[dbConfig.configMapKey]; + if (!configData) { + return jsonRes(res, { + data: null + }); + } + + jsonRes(res, { + data: configData + }); + } catch (err: any) { + jsonRes(res, { + code: 500, + error: err + }); + } +} diff --git a/frontend/providers/dbprovider/src/pages/api/getDBByName.ts b/frontend/providers/dbprovider/src/pages/api/getDBByName.ts index 5e68b25a2e4..42efd389183 100644 --- a/frontend/providers/dbprovider/src/pages/api/getDBByName.ts +++ b/frontend/providers/dbprovider/src/pages/api/getDBByName.ts @@ -11,17 +11,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse< throw new Error('name is empty'); } - const { k8sCustomObjects, namespace } = await getK8s({ - kubeconfig: await authSession(req) - }); - - const { body } = await k8sCustomObjects.getNamespacedCustomObject( - 'apps.kubeblocks.io', - 'v1alpha1', - namespace, - 'clusters', - name - ); + const body = await getCluster(req, name); jsonRes(res, { data: body @@ -33,3 +23,19 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse< }); } } + +export async function getCluster(req: NextApiRequest, name: string) { + const { k8sCustomObjects, namespace } = await getK8s({ + kubeconfig: await authSession(req) + }); + + const { body } = await k8sCustomObjects.getNamespacedCustomObject( + 'apps.kubeblocks.io', + 'v1alpha1', + namespace, + 'clusters', + name + ); + + return body; +} diff --git a/frontend/providers/dbprovider/src/pages/db/edit/components/EditConfig.tsx b/frontend/providers/dbprovider/src/pages/db/edit/components/EditConfig.tsx new file mode 100644 index 00000000000..c356bb2baa0 --- /dev/null +++ b/frontend/providers/dbprovider/src/pages/db/edit/components/EditConfig.tsx @@ -0,0 +1,144 @@ +import MyIcon from '@/components/Icon'; +import { DBEditType } from '@/types/db'; +import { + Box, + Button, + Flex, + Modal, + ModalBody, + ModalCloseButton, + ModalContent, + ModalFooter, + ModalHeader, + ModalOverlay, + Textarea, + Text, + Tag +} from '@chakra-ui/react'; +import { useTranslation } from 'next-i18next'; +import { useEffect, useRef, useState } from 'react'; +import { debounce } from 'lodash'; +import { compareDBConfig } from '@/utils/tools'; +import { DBTypeConfigMap } from '@/constants/db'; + +const EditConfig = ({ + defaultConfig, + successCb, + onClose, + dbType +}: { + defaultConfig: DBEditType['config']; + dbType: DBEditType['dbType']; + successCb: (v: string) => void; + onClose: () => void; +}) => { + const { t } = useTranslation(); + const [inputVal, setInputVal] = useState(defaultConfig); + const type = DBTypeConfigMap[dbType].type; + const [isDisabled, setIsDisabled] = useState(false); + + const [differences, setDifferences] = useState< + { + path: string; + oldValue: string; + newValue: string; + }[] + >([]); + + const debouncedDiff = useRef( + debounce((newConfig: string) => { + try { + const diffs = compareDBConfig({ + oldConfig: defaultConfig, + newConfig: newConfig, + type: type + }); + setDifferences(diffs); + const hasDeletedKey = diffs.some((diff) => diff.newValue === undefined); + setIsDisabled(hasDeletedKey); + } catch (error) { + console.error('Failed to parse config:', error); + setDifferences([]); + } + }, 500) + ).current; + + useEffect(() => { + debouncedDiff(inputVal); + }, [inputVal, debouncedDiff]); + + return ( + + + + {t('database_edit_config')} + + + + {t('database_config')} + +