From 401b0899171e1acd3a891e8b7f467962e37babb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E5=B7=9D?= Date: Tue, 27 Feb 2024 11:15:44 +0800 Subject: [PATCH 1/9] feat:add database with owner refs #187040 --- src/common/network/database.ts | 11 ++- src/locales/must/strings/en-US.json | 4 +- src/locales/must/strings/zh-CN.json | 2 + src/locales/must/strings/zh-TW.json | 4 +- .../Info/ChangeProjectModal/index.tsx | 2 +- .../Database/AddDataBaseButton/index.tsx | 69 ++++++++++++++----- 6 files changed, 69 insertions(+), 23 deletions(-) diff --git a/src/common/network/database.ts b/src/common/network/database.ts index 10f611fd8..c1423164d 100644 --- a/src/common/network/database.ts +++ b/src/common/network/database.ts @@ -36,7 +36,7 @@ export async function listDatabases( */ containsUnassigned?: boolean, existed?: boolean, - includesPermittedAction?: boolean + includesPermittedAction?: boolean, ): Promise> { const res = await request.get(`/api/v2/database/databases`, { params: { @@ -48,7 +48,7 @@ export async function listDatabases( environmentId, containsUnassigned, existed, - includesPermittedAction + includesPermittedAction, }, }); @@ -70,11 +70,16 @@ export async function createDataBase(database: DeepPartial): Promise< return res?.data; } -export async function updateDataBase(databaseIds: number[], projectId: number): Promise { +export async function updateDataBase( + databaseIds: number[], + projectId: number, + ownerIds: number[], +): Promise { const res = await request.post(`/api/v2/database/databases/transfer`, { data: { databaseIds, projectId, + ownerIds, }, }); return res?.data; diff --git a/src/locales/must/strings/en-US.json b/src/locales/must/strings/en-US.json index 84c01ab48..e075b5cb2 100644 --- a/src/locales/must/strings/en-US.json +++ b/src/locales/must/strings/en-US.json @@ -4837,6 +4837,7 @@ "odc.component.DetailContent.CreationTime": "Created At", "odc.Datasource.Info.CharacterEncoding": "Character Set", "odc.Database.AddDataBaseButton.SelectAnUnassignedDatabase": "Select a database that hasn't been assigned to a project", + "odc.Database.AddDataBaseButton.SelectDatabaseOwner": "Select a database owner", "odc.MaskingAlgorithm.components.ViewMaskingAlgorithmDrawer.NotEnabled": "Disabled", "odc.Env.components.EditPropertyComponent.EnterLabel": "Specify a {label}", "odc.Setting.Info.EnterADescription": "Enter the description", @@ -4950,6 +4951,7 @@ "odc.SensitiveRule.components.CheckboxInput.SelectAtLeastOneRecognition": "Select at least one identification object.", "odc.NewSSODrawerButton.SSOForm.AuthorizeTheServerToCall": "The URL for the authorization server to call back ODC. If a callback allowlist is available for SSO, add the allowlist.", "odc.Database.AddDataBaseButton.Database": "Database", + "odc.Database.AddDataBaseButton.DatabaseOwner": "Owner; If not selected, the system will default to the project administrator", "odc.component.TaskTable.Status": "Status", "odc.ExternalIntegration.SqlInterceptor.FailedToEnable": "Enabling failed.", "odc.SensitiveColumn.components.ScanForm.EnterAColumnName": "Enter a column name", @@ -6259,4 +6261,4 @@ "odc.src.component.Task.PartitionTask.DetailContent.CreationTime": "Created At", "odc.src.component.Task.PartitionTask.DetailContent.NextExecutionTime": "Next Execution Time", "odc.src.page.Secure.components.RecordPage.ApplicationProjectPermissions": "Apply for Project Permissions" -} \ No newline at end of file +} diff --git a/src/locales/must/strings/zh-CN.json b/src/locales/must/strings/zh-CN.json index cec05d160..95b8381fc 100644 --- a/src/locales/must/strings/zh-CN.json +++ b/src/locales/must/strings/zh-CN.json @@ -2861,6 +2861,7 @@ "odc.component.TaskTable.No": "编号", "odc.component.FormModal.TheNameCannotExceedCharacters": "名称不超过 64 个字符", "odc.Database.AddDataBaseButton.Database": "数据库", + "odc.Database.AddDataBaseButton.DatabaseOwner": "数据库负责人(未设置时默认是项目负责人)", "odc.MaskingAlgorithm.components.ViewMaskingAlgorithmDrawer.Enable": "启用", "odc.DataArchiveTask.CreateModal.ArchiveRange.PleaseSelect": "请选择", "odc.Script.ScriptFile.SearchScript": "搜索脚本", @@ -3285,6 +3286,7 @@ "odc.ResourceTree.Nodes.synonym.CommonSynonyms": "公共同义词", "odc.component.ResourceSelector.IncludingDataSourcesProjectsRoles": "包括数据源、项目、角色、用户的管理权限(新建/管理/编辑/查看)", "odc.Database.AddDataBaseButton.SelectAnUnassignedDatabase": "请选择未分配项目的数据库", + "odc.Database.AddDataBaseButton.SelectDatabaseOwner": "请选择数据库的负责人", "odc.DataArchiveTask.CreateModal.VariableConfig.Hours": "小时", "odc.component.FormModal.EnterATaskFlowName": "请输入任务流程名称", "odc.NewSSODrawerButton.SSOForm.AuthenticationMethodUsedWhenSending": "在向资源服务器发送资源请求中的承载访问令牌时使用的身份验证方法", diff --git a/src/locales/must/strings/zh-TW.json b/src/locales/must/strings/zh-TW.json index 31ef2aa9d..43f920dc1 100644 --- a/src/locales/must/strings/zh-TW.json +++ b/src/locales/must/strings/zh-TW.json @@ -5015,6 +5015,7 @@ "odc.Datasource.NewDatasourceDrawer.NewButton.CreateADataSource": "建立資料來源", "odc.DataClearTask.CreateModal.VariableConfig.VariableConfiguration": "變數配置", "odc.Database.AddDataBaseButton.SelectAnUnassignedDatabase": "請選擇未分配專案的資料庫", + "odc.Database.AddDataBaseButton.SelectDatabaseOwner": "請選擇資料庫的負責人", "odc.Datasource.Info.CharacterEncoding": "字元編碼", "odc.component.DetailContent.CreationTime": "建立時間", "odc.MaskingAlgorithm.components.ViewMaskingAlgorithmDrawer.NotEnabled": "未啟用", @@ -5130,6 +5131,7 @@ "odc.SensitiveRule.components.CheckboxInput.SelectAtLeastOneRecognition": "至少勾選一個識別對象", "odc.NewSSODrawerButton.SSOForm.AuthorizeTheServerToCall": "授權伺服器回調 ODC 服務的地址,如果 SSO 有回調白名單,需要進行加白", "odc.Database.AddDataBaseButton.Database": "資料庫", + "odc.Database.AddDataBaseButton.DatabaseOwner": "負責人(未設置時默認是項目負責人)", "odc.component.TaskTable.Status": "狀態", "odc.ExternalIntegration.SqlInterceptor.FailedToEnable": "啟用失敗", "odc.SensitiveColumn.components.ScanForm.EnterAColumnName": "請輸入列名", @@ -6259,4 +6261,4 @@ "odc.src.component.Task.PartitionTask.DetailContent.CreationTime": "建立時間", "odc.src.component.Task.PartitionTask.DetailContent.NextExecutionTime": "下一次執行時間", "odc.src.page.Secure.components.RecordPage.ApplicationProjectPermissions": "申請專案許可權" -} \ No newline at end of file +} diff --git a/src/page/Datasource/Info/ChangeProjectModal/index.tsx b/src/page/Datasource/Info/ChangeProjectModal/index.tsx index 503c83194..2739c03da 100644 --- a/src/page/Datasource/Info/ChangeProjectModal/index.tsx +++ b/src/page/Datasource/Info/ChangeProjectModal/index.tsx @@ -54,7 +54,7 @@ export default function ChangeProjectModal({ visible, database, close, onSuccess onOk={async () => { const value = await form.validateFields(); console.log(value); - const isSuccess = await updateDataBase([database?.id], value.project); + const isSuccess = await updateDataBase([database?.id], value.project, []); if (isSuccess) { message.success( formatMessage({ diff --git a/src/page/Project/Database/AddDataBaseButton/index.tsx b/src/page/Project/Database/AddDataBaseButton/index.tsx index 21e31af75..3895842a8 100644 --- a/src/page/Project/Database/AddDataBaseButton/index.tsx +++ b/src/page/Project/Database/AddDataBaseButton/index.tsx @@ -19,12 +19,13 @@ import { listDatabases, updateDataBase } from '@/common/network/database'; import RiskLevelLabel from '@/component/RiskLevelLabel'; import { formatMessage } from '@/util/intl'; import { useRequest } from 'ahooks'; -import { useContext, useState } from 'react'; +import { useContext, useMemo, useState } from 'react'; import { Button, Col, Form, message, Modal, Row, Select, Tooltip } from 'antd'; import Icon from '@ant-design/icons'; import { getDataSourceStyle, getDataSourceStyleByConnectType } from '@/common/datasource'; import ProjectContext from '../../ProjectContext'; -import { ProjectRole } from '@/d.ts/project'; +import { IProject, ProjectRole } from '@/d.ts/project'; +import { DefaultOptionType } from 'antd/es/select'; interface IProps { projectId: number; onSuccess: () => void; @@ -34,7 +35,21 @@ export default function AddDataBaseButton({ projectId, onSuccess }: IProps) { const { project } = useContext(ProjectContext); const [form] = Form.useForm<{ databaseIds: number[]; + ownerIds?: number[]; }>(); + const projectUserOptions: DefaultOptionType[] = useMemo(() => { + const userMap = new Map(); + project?.members?.forEach((mem) => { + const { id, name } = mem; + if (!userMap.has(id)) { + userMap.set(id, { + value: id, + label: name, + }); + } + }); + return [...userMap.values()]; + }, [project?.members]); const { run, loading } = useRequest(updateDataBase, { manual: true, }); @@ -46,18 +61,20 @@ export default function AddDataBaseButton({ projectId, onSuccess }: IProps) { }, ], }); - const { data: dataSource, loading: dataSourceLoading, run: fetchDataSource } = useRequest( - getConnectionDetail, - { - manual: true, - }, - ); - const { data: databases, loading: databasesListLoading, run: fetchDatabases } = useRequest( - listDatabases, - { - manual: true, - }, - ); + const { + data: dataSource, + loading: dataSourceLoading, + run: fetchDataSource, + } = useRequest(getConnectionDetail, { + manual: true, + }); + const { + data: databases, + loading: databasesListLoading, + run: fetchDatabases, + } = useRequest(listDatabases, { + manual: true, + }); function close() { setOpen(false); form.resetFields(); @@ -67,7 +84,7 @@ export default function AddDataBaseButton({ projectId, onSuccess }: IProps) { if (!formData) { return; } - const isSuccess = await run(formData?.databaseIds, projectId); + const isSuccess = await run(formData?.databaseIds, projectId, formData?.ownerIds); if (isSuccess) { message.success( formatMessage({ @@ -154,8 +171,7 @@ export default function AddDataBaseButton({ projectId, onSuccess }: IProps) { isDisabled ? formatMessage( { - id: - 'odc.src.page.Project.Database.AddDataBaseButton.ThisDataSourceHasBeen', + id: 'odc.src.page.Project.Database.AddDataBaseButton.ThisDataSourceHasBeen', }, { itemProjectName: item?.projectName, @@ -234,6 +250,25 @@ export default function AddDataBaseButton({ projectId, onSuccess }: IProps) { })} + + + + + + ); +} diff --git a/src/page/Project/Database/index.tsx b/src/page/Project/Database/index.tsx index b9645b17f..b1d2c4342 100644 --- a/src/page/Project/Database/index.tsx +++ b/src/page/Project/Database/index.tsx @@ -47,15 +47,26 @@ import setting from '@/store/setting'; import datasourceStatus from '@/store/datasourceStatus'; import { observer } from 'mobx-react'; import StatusName from './StatusName'; +import ChangeOwnerModal from '@/page/Project/Database/ChangeOwnerModal'; interface IProps { id: string; } + +/** + * 数据库负责人的最大个数 + */ +const DB_OWNER_MAX_COUNT = 3; + const Database: React.FC = ({ id }) => { const { project } = useContext(ProjectContext); const [total, setTotal] = useState(0); const [searchValue, setSearchValue] = useState(''); const [data, setData] = useState([]); const [visible, setVisible] = useState(false); + /** + * 修改负责人弹窗显示与隐藏 + */ + const [changeOwnerModalVisible, setChangeOwnerModalVisible] = useState(false); const [database, setDatabase] = useState(null); const params = useRef({ pageSize: 0, @@ -71,7 +82,16 @@ const Database: React.FC = ({ id }) => { params.current.current = current; params.current.environmentId = environmentId; const res = await listDatabases( - parseInt(id), null, current, pageSize, name, environmentId, null, null, true); + parseInt(id), + null, + current, + pageSize, + name, + environmentId, + null, + null, + true, + ); if (res) { datasourceStatus.asyncUpdateStatus(res?.contents?.map((item) => item?.dataSource?.id)); setData(res?.contents); @@ -104,7 +124,13 @@ const Database: React.FC = ({ id }) => { const statusMap = datasourceStatus.statusMap; return ( reload()} projectId={parseInt(id)} />} + title={ + reload()} + projectId={parseInt(id)} + maxOwnerCount={DB_OWNER_MAX_COUNT} + /> + } extra={ = ({ id }) => { fixed: 'left', ellipsis: true, render: (name, record) => { - const hasChangeAuth = record.authorizedPermissionTypes?.includes(DatabasePermissionType.CHANGE); - const hasQueryAuth = record.authorizedPermissionTypes?.includes(DatabasePermissionType.QUERY); - const disabled = !hasChangeAuth && !hasQueryAuth; + const hasChangeAuth = record.authorizedPermissionTypes?.includes( + DatabasePermissionType.CHANGE, + ); + const hasQueryAuth = record.authorizedPermissionTypes?.includes( + DatabasePermissionType.QUERY, + ); + const disabled = !hasChangeAuth && !hasQueryAuth; if (!record.existed) { return disabled ? (
{name}
@@ -172,6 +202,17 @@ const Database: React.FC = ({ id }) => { ); }, }, + { + title: formatMessage({ + id: 'odc.Project.Database.Owner', + }), + //项目角色 + dataIndex: 'owners', + width: 170, + render(v) { + return v?.map(({ name }) => name)?.join(' | '); + }, + }, { title: formatMessage({ id: 'odc.Project.Database.DataSource', @@ -266,9 +307,15 @@ const Database: React.FC = ({ id }) => { const disableTransfer = !!record?.dataSource?.projectId && !config?.schema?.innerSchema?.includes(record?.name); - const hasExportAuth = record.authorizedPermissionTypes?.includes(DatabasePermissionType.EXPORT); - const hasChangeAuth = record.authorizedPermissionTypes?.includes(DatabasePermissionType.CHANGE); - const hasQueryAuth = record.authorizedPermissionTypes?.includes(DatabasePermissionType.QUERY); + const hasExportAuth = record.authorizedPermissionTypes?.includes( + DatabasePermissionType.EXPORT, + ); + const hasChangeAuth = record.authorizedPermissionTypes?.includes( + DatabasePermissionType.CHANGE, + ); + const hasQueryAuth = record.authorizedPermissionTypes?.includes( + DatabasePermissionType.QUERY, + ); return ( {config?.features?.task?.includes(TaskType.EXPORT) && setting.enableDBExport && ( @@ -352,12 +399,27 @@ const Database: React.FC = ({ id }) => { { formatMessage({ id: 'odc.src.page.Project.Database.ModifyTheProject', - }) /* + }) /* 修改所属项目 */ } + { + // TODO tracert.click('a3112.b64002.c330858.d367387'); + setChangeOwnerModalVisible(true); + setDatabase(record); + }} + // TODO disabled={!hasChangeAuth || disableTransfer} + > + { + formatMessage({ + id: 'odc.src.page.Project.Database.ModifyOwner', + }) /* 修改负责人*/ + } + ); }, @@ -380,6 +442,13 @@ const Database: React.FC = ({ id }) => { close={() => setVisible(false)} onSuccess={() => reload()} /> + setChangeOwnerModalVisible(false)} + onSuccess={() => reload()} + maxOwnerCount={DB_OWNER_MAX_COUNT} + /> From 3780a7b4f265d16fe101a1b0f128a5b6f4195462 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E5=B7=9D?= Date: Tue, 27 Feb 2024 17:58:32 +0800 Subject: [PATCH 3/9] style: owner empty text --- src/locales/must/strings/en-US.json | 1 + src/locales/must/strings/zh-CN.json | 1 + src/locales/must/strings/zh-TW.json | 1 + src/page/Project/Database/index.tsx | 15 ++++++++++++--- 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/locales/must/strings/en-US.json b/src/locales/must/strings/en-US.json index c77d8fe1a..4000427ba 100644 --- a/src/locales/must/strings/en-US.json +++ b/src/locales/must/strings/en-US.json @@ -5057,6 +5057,7 @@ "odc.Env.components.InnerEnvironment.RuleType": "Rule Type", "odc.Project.Database.DatabaseName": "Database Name", "odc.Project.Database.Owner": "Database Owner", + "odc.Project.Database.OwnerEmptyText": "Not set", "odc.Project.Sensitive.SensitiveColumn": "Sensitive Column", "odc.Project.Database.LogOnToTheDatabase": "Log on to Database", "odc.Form.DBTypeItem.DataSourceType": "Data Source Type", diff --git a/src/locales/must/strings/zh-CN.json b/src/locales/must/strings/zh-CN.json index 83aabbb36..c5d3c2460 100644 --- a/src/locales/must/strings/zh-CN.json +++ b/src/locales/must/strings/zh-CN.json @@ -2893,6 +2893,7 @@ "odc.components.SensitiveRule.Cancel": "取消", "odc.Project.Database.DatabaseName": "数据库名称", "odc.Project.Database.Owner": "负责人", + "odc.Project.Database.OwnerEmptyText": "未设置", "odc.ExternalIntegration.SqlInterceptor.AreYouSureYouWant": "是否确认删除{title}?", "odc.components.SensitiveColumn.Disable": "禁用", "odc.component.CommonDetailModal.TaskTools.Rollback": "回滚", diff --git a/src/locales/must/strings/zh-TW.json b/src/locales/must/strings/zh-TW.json index 3e1fcb4b2..0f2559409 100644 --- a/src/locales/must/strings/zh-TW.json +++ b/src/locales/must/strings/zh-TW.json @@ -4702,6 +4702,7 @@ "odc.Env.components.InnerEnvironment.RuleType": "規則類型", "odc.Project.Database.DatabaseName": "資料庫名稱", "odc.Project.Database.Owner": "負責人", + "odc.Project.Database.OwnerEmptyText": "未設置", "odc.Project.Sensitive.SensitiveColumn": "敏感列", "odc.Project.Database.LogOnToTheDatabase": "登入資料庫", "odc.Form.DBTypeItem.DataSourceType": "資料來源類型", diff --git a/src/page/Project/Database/index.tsx b/src/page/Project/Database/index.tsx index b1d2c4342..e3362daa4 100644 --- a/src/page/Project/Database/index.tsx +++ b/src/page/Project/Database/index.tsx @@ -208,9 +208,18 @@ const Database: React.FC = ({ id }) => { }), //项目角色 dataIndex: 'owners', - width: 170, + ellipsis: true, + width: 160, render(v) { - return v?.map(({ name }) => name)?.join(' | '); + return v?.length > 0 ? ( + v.map(({ name }) => name)?.join(' | ') + ) : ( + + {formatMessage({ + id: 'odc.Project.Database.OwnerEmptyText', + })} + + ); }, }, { @@ -298,7 +307,7 @@ const Database: React.FC = ({ id }) => { }), //操作 dataIndex: 'actions', - width: 200, + width: 170, render(_, record) { if (!record.existed) { return '-'; From 4777496645fed008d9bb5f78a85b46d99d852610 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E5=B7=9D?= Date: Tue, 27 Feb 2024 18:49:06 +0800 Subject: [PATCH 4/9] feat:approval with database owner refs #187040 --- src/d.ts/index.ts | 1 + src/locales/must/strings/en-US.json | 1 + src/locales/must/strings/zh-CN.json | 1 + src/locales/must/strings/zh-TW.json | 1 + .../RiskLevel/components/CreateApproval.tsx | 21 ++++++++++++++----- 5 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/d.ts/index.ts b/src/d.ts/index.ts index 48b9293ec..35f3b1c1f 100644 --- a/src/d.ts/index.ts +++ b/src/d.ts/index.ts @@ -147,6 +147,7 @@ export enum IManagerResourceType { integration = 'ODC_INTEGRATION', environment = 'ODC_ENVIRONMENT', individual_organization = 'ODC_INDIVIDUAL_ORGANIZATION', + database = 'ODC_DATABASE', } export enum actionTypes { diff --git a/src/locales/must/strings/en-US.json b/src/locales/must/strings/en-US.json index 4000427ba..6a2ac2a7a 100644 --- a/src/locales/must/strings/en-US.json +++ b/src/locales/must/strings/en-US.json @@ -5247,6 +5247,7 @@ "odc.Datasource.Info.AreYouSureYouWant": "Are you sure you want to delete it?", "odc.DataClearTask.DetailContent.DataCleansing": "Data Cleanup", "odc.component.AuthNode.Role": "Role", + "odc.component.AuthNode.Role.DatabaseOwner": "DataBase Owner", "odc.page.Gateway.newCloudConnection.PersonalSpaceDoesNotExist": "The personal workspace does not exist.", "odc.component.ResourceSelector.const.DataSource": "Data Source", "odc.page.Secure.interface.NoNeedToImprove": "Improvement Not Required", diff --git a/src/locales/must/strings/zh-CN.json b/src/locales/must/strings/zh-CN.json index c5d3c2460..414f28e72 100644 --- a/src/locales/must/strings/zh-CN.json +++ b/src/locales/must/strings/zh-CN.json @@ -3174,6 +3174,7 @@ "odc.Env.components.EditRuleDrawer.Edit": "编辑", "odc.component.FormModal.Disable": "停用", "odc.component.AuthNode.Role": "角色", + "odc.component.AuthNode.Role.DatabaseOwner": "数据库负责人", "odc.page.Gateway.newCloudConnection.PersonalSpaceDoesNotExist": "个人空间不存在!", "odc.component.ResourceSelector.const.DataSource": "数据源", "odc.SensitiveRule.components.FormSensitiveRuleDrawer.TableName": "表名", diff --git a/src/locales/must/strings/zh-TW.json b/src/locales/must/strings/zh-TW.json index 0f2559409..a7f786a49 100644 --- a/src/locales/must/strings/zh-TW.json +++ b/src/locales/must/strings/zh-TW.json @@ -4825,6 +4825,7 @@ "odc.DataClearTask.DetailContent.DataCleansing": "資料清理", "odc.Datasource.Info.AreYouSureYouWant": "確認刪除嗎?", "odc.component.AuthNode.Role": "角色", + "odc.component.AuthNode.Role.DatabaseOwner": "資料庫負責人", "odc.page.Gateway.newCloudConnection.PersonalSpaceDoesNotExist": "個人空間不存在!", "odc.component.ResourceSelector.const.DataSource": "資料來源", "odc.page.Secure.interface.NoNeedToImprove": "無需改進", diff --git a/src/page/Secure/RiskLevel/components/CreateApproval.tsx b/src/page/Secure/RiskLevel/components/CreateApproval.tsx index 563d124ac..e708ea295 100644 --- a/src/page/Secure/RiskLevel/components/CreateApproval.tsx +++ b/src/page/Secure/RiskLevel/components/CreateApproval.tsx @@ -15,16 +15,23 @@ */ import { getIntegrationList, getResourceRoles } from '@/common/network/manager'; -import { IntegrationType } from '@/d.ts'; +import { IManagerResourceType, IntegrationType } from '@/d.ts'; import { projectRoleTextMap } from '@/page/Project/User'; import { useEffect, useState } from 'react'; import FormModal from '../../Approval/component/FormModal'; +import { formatMessage } from '@/util/intl'; interface ICreateApprovalProps { editId: number; formModalVisible: boolean; setFormModalVisible: React.Dispatch>; reloadData: () => void; } +/** + * 数据库类型的Role文本映射 + */ +const databaseRoleTextMap = { + OWNER: formatMessage({ id: 'odc.component.AuthNode.Role.DatabaseOwner' }) /* 数据库负责人 */, +}; const CreateApproval: React.FC = ({ editId, formModalVisible, @@ -36,10 +43,14 @@ const CreateApproval: React.FC = ({ const loadRoles = async () => { const res = await getResourceRoles(); - const roles = res?.contents.map(({ roleName, id }) => ({ - name: projectRoleTextMap?.[roleName], - id, - })); + const roles = res?.contents.map(({ roleName, id, resourceType }) => { + const textMap = + resourceType === IManagerResourceType.database ? databaseRoleTextMap : projectRoleTextMap; + return { + name: textMap?.[roleName], + id, + }; + }); setRoles(roles); }; const loadIntegrations = async () => { From 74de1ab721870da0f3dc9ed7c1888d66c7c391c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E5=B7=9D?= Date: Wed, 28 Feb 2024 13:34:07 +0800 Subject: [PATCH 5/9] feat:load roles with resourceType --- src/common/network/manager.ts | 4 +++- src/d.ts/database.ts | 2 +- .../Database/AddDataBaseButton/index.tsx | 7 ++++++- .../Project/Database/ChangeOwnerModal/index.tsx | 17 +++++++++++++---- src/page/Project/Database/const.ts | 4 ++++ src/page/Project/Database/index.tsx | 12 ++++-------- .../RiskLevel/components/CreateApproval.tsx | 4 +++- 7 files changed, 34 insertions(+), 16 deletions(-) create mode 100644 src/page/Project/Database/const.ts diff --git a/src/common/network/manager.ts b/src/common/network/manager.ts index c6cbd6963..0910c2ee4 100644 --- a/src/common/network/manager.ts +++ b/src/common/network/manager.ts @@ -418,7 +418,9 @@ export async function getTaskFlowExists(name: string): Promise { export async function getResourceRoles( params?: IRequestListParamsV2, ): Promise> { - const result = await request.get('/api/v2/iam/resourceRoles'); + const result = await request.get('/api/v2/iam/resourceRoles', { + params, + }); return result?.data; } diff --git a/src/d.ts/database.ts b/src/d.ts/database.ts index 778135914..1a4e6f41d 100644 --- a/src/d.ts/database.ts +++ b/src/d.ts/database.ts @@ -57,7 +57,7 @@ export interface IDatabase { */ export interface IDatabaseOwner { accountName: string; - userId: number; + id: number; name: string; } diff --git a/src/page/Project/Database/AddDataBaseButton/index.tsx b/src/page/Project/Database/AddDataBaseButton/index.tsx index 00c7a9369..e2738a031 100644 --- a/src/page/Project/Database/AddDataBaseButton/index.tsx +++ b/src/page/Project/Database/AddDataBaseButton/index.tsx @@ -26,6 +26,7 @@ import { getDataSourceStyle, getDataSourceStyleByConnectType } from '@/common/da import ProjectContext from '../../ProjectContext'; import { IProject, ProjectRole } from '@/d.ts/project'; import { DefaultOptionType } from 'antd/es/select'; +import { DB_OWNER_MAX_COUNT } from '@/page/Project/Database/const'; interface IProps { projectId: number; onSuccess: () => void; @@ -35,7 +36,11 @@ interface IProps { maxOwnerCount?: number; } -export default function AddDataBaseButton({ projectId, onSuccess, maxOwnerCount = 3 }: IProps) { +export default function AddDataBaseButton({ + projectId, + onSuccess, + maxOwnerCount = DB_OWNER_MAX_COUNT, +}: IProps) { const [open, setOpen] = useState(false); const { project } = useContext(ProjectContext); /** diff --git a/src/page/Project/Database/ChangeOwnerModal/index.tsx b/src/page/Project/Database/ChangeOwnerModal/index.tsx index 197c26f3d..699e0b8f2 100644 --- a/src/page/Project/Database/ChangeOwnerModal/index.tsx +++ b/src/page/Project/Database/ChangeOwnerModal/index.tsx @@ -13,14 +13,15 @@ * limitations under the License. */ +import { updateDataBase } from '@/common/network/database'; import { IDatabase } from '@/d.ts/database'; +import { DB_OWNER_MAX_COUNT } from '@/page/Project/Database/const'; import { formatMessage } from '@/util/intl'; +import { useRequest } from 'ahooks'; import { Form, Modal, Select, message } from 'antd'; import { DefaultOptionType } from 'antd/es/select'; -import { useCallback, useContext, useMemo, useState } from 'react'; +import { useCallback, useContext, useEffect, useMemo, useState } from 'react'; import ProjectContext from '../../ProjectContext'; -import { updateDataBase } from '@/common/network/database'; -import { useRequest } from 'ahooks'; interface IProps { visible: boolean; @@ -35,7 +36,7 @@ export default function ChangeOwnerModal({ database, close, onSuccess, - maxOwnerCount = 3, + maxOwnerCount = DB_OWNER_MAX_COUNT, }: IProps) { const { project } = useContext(ProjectContext); @@ -88,6 +89,14 @@ export default function ChangeOwnerModal({ } }, [database?.id, database?.project?.id, close, onSuccess]); + useEffect(() => { + if (visible) { + form.setFieldsValue({ + ownerIds: database?.owners?.map(({ id }) => id) || [], + }); + } + }, [visible]); + return ( = ({ id }) => { const { project } = useContext(ProjectContext); const [total, setTotal] = useState(0); @@ -307,7 +303,7 @@ const Database: React.FC = ({ id }) => { }), //操作 dataIndex: 'actions', - width: 170, + width: 236, render(_, record) { if (!record.existed) { return '-'; @@ -417,11 +413,11 @@ const Database: React.FC = ({ id }) => { { - // TODO tracert.click('a3112.b64002.c330858.d367387'); + // TODO tracert.click('id'); setChangeOwnerModalVisible(true); setDatabase(record); }} - // TODO disabled={!hasChangeAuth || disableTransfer} + // TODO disabled={权限|配置} > { formatMessage({ diff --git a/src/page/Secure/RiskLevel/components/CreateApproval.tsx b/src/page/Secure/RiskLevel/components/CreateApproval.tsx index e708ea295..86666ed13 100644 --- a/src/page/Secure/RiskLevel/components/CreateApproval.tsx +++ b/src/page/Secure/RiskLevel/components/CreateApproval.tsx @@ -42,7 +42,9 @@ const CreateApproval: React.FC = ({ const [integrations, setIntegrations] = useState([]); const loadRoles = async () => { - const res = await getResourceRoles(); + const res = await getResourceRoles({ + resourceType: [IManagerResourceType.project, IManagerResourceType.database], + }); const roles = res?.contents.map(({ roleName, id, resourceType }) => { const textMap = resourceType === IManagerResourceType.database ? databaseRoleTextMap : projectRoleTextMap; From 5bec2bc56b2f764450f991e1fbfa70452c2c405b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E5=B7=9D?= Date: Thu, 29 Feb 2024 16:41:33 +0800 Subject: [PATCH 6/9] perf: submit loading refs #1870404 --- src/page/Project/Database/AddDataBaseButton/index.tsx | 3 ++- src/page/Project/Database/ChangeOwnerModal/index.tsx | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/page/Project/Database/AddDataBaseButton/index.tsx b/src/page/Project/Database/AddDataBaseButton/index.tsx index e2738a031..6ec795121 100644 --- a/src/page/Project/Database/AddDataBaseButton/index.tsx +++ b/src/page/Project/Database/AddDataBaseButton/index.tsx @@ -69,7 +69,7 @@ export default function AddDataBaseButton({ }); return [...userMap.values()]; }, [project?.members, ownerIds, maxOwnerCount]); - const { run, loading } = useRequest(updateDataBase, { + const { run, loading: saveDatabaseLoading } = useRequest(updateDataBase, { manual: true, }); const { data: dataSourceList, loading: dataSourceListLoading } = useRequest(getConnectionList, { @@ -139,6 +139,7 @@ export default function AddDataBaseButton({ })} /*添加数据库*/ onOk={submit} onCancel={close} + confirmLoading={saveDatabaseLoading} >
{ form.resetFields(); close(); From 0fc4e4568114da85e9d5ef6f56897e8e1916cf87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E5=B7=9D?= Date: Tue, 5 Mar 2024 10:20:00 +0800 Subject: [PATCH 7/9] feat:update owner with new interface refs #187040 --- src/common/network/database.ts | 14 ++++++++++++++ .../Project/Database/ChangeOwnerModal/index.tsx | 4 ++-- src/page/Project/Database/index.tsx | 3 +-- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/common/network/database.ts b/src/common/network/database.ts index c1423164d..f814b791c 100644 --- a/src/common/network/database.ts +++ b/src/common/network/database.ts @@ -85,6 +85,20 @@ export async function updateDataBase( return res?.data; } +export async function updateDataBaseOwner( + databaseIds: number[], + projectId: number, + ownerIds: number[], +): Promise { + const res = await request.put(`/api/v2/database/databases/owner/${projectId}`, { + data: { + databaseIds, + ownerIds, + }, + }); + return res?.data; +} + export async function getDatabase( databaseId: number, ignoreError?: boolean, diff --git a/src/page/Project/Database/ChangeOwnerModal/index.tsx b/src/page/Project/Database/ChangeOwnerModal/index.tsx index 4d3b8842b..9540b9568 100644 --- a/src/page/Project/Database/ChangeOwnerModal/index.tsx +++ b/src/page/Project/Database/ChangeOwnerModal/index.tsx @@ -13,7 +13,7 @@ * limitations under the License. */ -import { updateDataBase } from '@/common/network/database'; +import { updateDataBaseOwner } from '@/common/network/database'; import { IDatabase } from '@/d.ts/database'; import { DB_OWNER_MAX_COUNT } from '@/page/Project/Database/const'; import { formatMessage } from '@/util/intl'; @@ -40,7 +40,7 @@ export default function ChangeOwnerModal({ }: IProps) { const { project } = useContext(ProjectContext); - const { run: startUpdateDataBase, loading: saveOwnerLoading } = useRequest(updateDataBase, { + const { run: startUpdateDataBase, loading: saveOwnerLoading } = useRequest(updateDataBaseOwner, { manual: true, }); diff --git a/src/page/Project/Database/index.tsx b/src/page/Project/Database/index.tsx index 613e89ca2..eca8307c6 100644 --- a/src/page/Project/Database/index.tsx +++ b/src/page/Project/Database/index.tsx @@ -411,9 +411,8 @@ const Database: React.FC = ({ id }) => { { - // TODO tracert.click('id'); setChangeOwnerModalVisible(true); setDatabase(record); }} From 3a250aa8fe16e4193329c61ece79da73294a8bbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E5=B7=9D?= Date: Thu, 7 Mar 2024 16:55:23 +0800 Subject: [PATCH 8/9] perf: showSearch when update db_owner --- src/page/Project/Database/ChangeOwnerModal/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/page/Project/Database/ChangeOwnerModal/index.tsx b/src/page/Project/Database/ChangeOwnerModal/index.tsx index 9540b9568..981613927 100644 --- a/src/page/Project/Database/ChangeOwnerModal/index.tsx +++ b/src/page/Project/Database/ChangeOwnerModal/index.tsx @@ -138,7 +138,7 @@ export default function ChangeOwnerModal({ style={{ width: '100%', }} - optionFilterProp="children" + optionFilterProp="label" options={projectUserOptions} /> From f4fb463ad927fb02d933d5898c7c985b7972345a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E5=B7=9D?= Date: Fri, 8 Mar 2024 18:52:04 +0800 Subject: [PATCH 9/9] set changeOwner permission #refs 192840 --- src/page/Project/Database/index.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/page/Project/Database/index.tsx b/src/page/Project/Database/index.tsx index eca8307c6..620481e53 100644 --- a/src/page/Project/Database/index.tsx +++ b/src/page/Project/Database/index.tsx @@ -49,6 +49,7 @@ import { observer } from 'mobx-react'; import StatusName from './StatusName'; import ChangeOwnerModal from '@/page/Project/Database/ChangeOwnerModal'; import { DB_OWNER_MAX_COUNT } from '@/page/Project/Database/const'; +import { ProjectRole } from '@/d.ts/project'; interface IProps { id: string; } @@ -321,6 +322,10 @@ const Database: React.FC = ({ id }) => { const hasQueryAuth = record.authorizedPermissionTypes?.includes( DatabasePermissionType.QUERY, ); + const curRoles = project?.currentUserResourceRoles || []; + const hasChangeOwnerAuth = curRoles.some((role) => + [ProjectRole.OWNER, ProjectRole.DBA].includes(role), + ); return ( {config?.features?.task?.includes(TaskType.EXPORT) && setting.enableDBExport && ( @@ -416,7 +421,7 @@ const Database: React.FC = ({ id }) => { setChangeOwnerModalVisible(true); setDatabase(record); }} - // TODO disabled={权限|配置} + disabled={!hasChangeOwnerAuth} > { formatMessage({