CloudAccountSidePane 数据流分析
完整数据流程图
┌─────────────────────────────────────────────────────────────────────────────┐
│ 1. 后端 API 层 │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ ServerAPI/Requests/Organizations/Organizations.ts │
│ │
│ getCloudOrganizationsAndAccounts(orgId) │
│ ↓ │
│ GET v1/organizations/{orgId}/inventory/cloud-organizations │
│ ↓ │
│ 返回: CloudOrganizationsAndAccountsResponse │
│ { │
│ organizational_accounts: { │
│ [orgId]: { │
│ accounts: { │
│ [accountId]: { │
│ connection_error: { │
│ exception_message: "...", ← 赋值点 1 │
│ error_code: "..." ← 赋值点 1 │
│ } │
│ } │
│ } │
│ } │
│ }, │
│ single_accounts: [{ │
│ account: { │
│ connection_error: { │
│ exception_message: "...", ← 赋值点 1 │
│ error_code: "..." ← 赋值点 1 │
│ } │
│ } │
│ }] │
│ } │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ 2. 数据解析层 │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ responseUtils.ts │
│ │
│ parseOrganizationsAndAccountsResponse(response) │
│ ↓ │
│ parseCloudOrganizationAccountResponseItem(responseItem) │
│ ↓ │
│ 返回: CloudOrganizationAccountAttributes │
│ { │
│ accountId: "...", │
│ exceptionMessage: responseItem.connection_error?.exception_message, │
│ ← 赋值点 2 │
│ errorCode: responseItem.connection_error?.error_code, │
│ ← 赋值点 2 │
│ ... │
│ } │
│ ↓ │
│ 返回: [organizationsData, singleAccountsData] │
│ - organizationsData: Record<string, CloudOrganizationAttributes> │
│ { │
│ [orgId]: { │
│ accounts: { │
│ [accountId]: CloudOrganizationAccountAttributes ← 包含错误信息 │
│ } │
│ } │
│ } │
│ - singleAccountsData: CloudOrganizationAccountAttributes[] │
│ [ │
│ CloudOrganizationAccountAttributes ← 包含错误信息 │
│ ] │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ 3. Hook 层 - 数据获取和状态管理 │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ useCloudOrganizationAccountsData.ts │
│ │
│ const { organizationsData, singleAccountsData } = │
│ useCloudOrganizationAccountsData() │
│ │
│ 内部流程: │
│ 1. 调用 getCloudOrganizationsAndAccounts(orgId) │
│ 2. 调用 parseOrganizationsAndAccountsResponse(response) │
│ 3. 使用 useState 存储: │
│ - organizationsData: Record<string, CloudOrganizationAttributes> │
│ - singleAccountsData: CloudOrganizationAccountAttributes[] │
│ │
│ 返回: │
│ { │
│ organizationsData, ← 包含错误信息 │
│ singleAccountsData, ← 包含错误信息 │
│ ... │
│ } │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ 4. 行数据转换层 │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ useOrganizationsAndAccountsRows.ts │
│ │
│ const { rows } = useOrganizationsAndAccountsRows( │
│ organizationsData, │
│ singleAccountsData, │
│ regionalCoverage, │
│ isCoverageDataLoading │
│ ) │
│ │
│ 内部流程: │
│ 1. 遍历 organizationsData,调用 parseCloudOrganizationAccountsToRows() │
│ 2. 遍历 singleAccountsData,创建 CloudOrganizationAccountRowData │
│ 3. 返回: CloudOrganizationAccountRowData[] │
│ │
│ 返回: │
│ { │
│ rows: CloudOrganizationAccountRowData[] │
│ [ │
│ { │
│ accountId: "...", │
│ exceptionMessage: account.exceptionMessage, ← 赋值点 3 │
│ errorCode: account.errorCode, ← 赋值点 3 │
│ ... │
│ } │
│ ] │
│ } │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ 5. 组织数据转换层 │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ OrganizationAndAccountsInnerTabs.tsx │
│ │
│ createByOrganizationRowData( │
│ filteredOrganizationsAndAccountsRowData: CloudOrganizationAccountRowData[]│
│ ) │
│ │
│ 内部流程: │
│ 1. 按组织分组 CloudOrganizationAccountRowData[] │
│ 2. 创建 AccountsByOrganizationRowData[] │
│ │
│ 返回: │
│ AccountsByOrganizationRowData[] │
│ [ │
│ { │
│ accountRows: CloudOrganizationAccountRowData[] ← 包含错误信息 │
│ [ │
│ { │
│ exceptionMessage: "...", ← 赋值点 4 │
│ errorCode: "...", ← 赋值点 4 │
│ ... │
│ } │
│ ] │
│ } │
│ ] │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ 6. CloudAccountSidePane 数据获取(当前实现) │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ CloudAccountSidePane.tsx │
│ │
│ const { organizationsData, singleAccountsData } = │
│ useCloudOrganizationAccountsData() ← 直接从第 3 层获取 │
│ │
│ // 手动查找匹配的账户 │
│ const accountErrorData = useMemo(() => { │
│ // 在 organizationsData 中查找 │
│ // 在 singleAccountsData 中查找 │
│ return { │
│ exceptionMessage: accountData.exceptionMessage, │
│ errorCode: accountData.errorCode │
│ } │
│ }, [account, organizationsData, singleAccountsData]) │
└─────────────────────────────────────────────────────────────────────────────┘
数据流关键点总结
赋值点追踪
-
赋值点 1: 后端 API 响应
- 位置:
CloudOrganizationAccountResponseItem.connection_error - 包含:
exception_message,error_code
- 位置:
-
赋值点 2: 解析层
- 位置:
responseUtils.ts→parseCloudOrganizationAccountResponseItem() - 转换:
responseItem.connection_error?.exception_message→CloudOrganizationAccountAttributes.exceptionMessage - 转换:
responseItem.connection_error?.error_code→CloudOrganizationAccountAttributes.errorCode
- 位置:
-
赋值点 3: 行数据转换
- 位置:
useOrganizationsAndAccountsRows.ts - 转换:
account.exceptionMessage→CloudOrganizationAccountRowData.exceptionMessage - 转换:
account.errorCode→CloudOrganizationAccountRowData.errorCode
- 位置:
-
赋值点 4: 组织数据转换
- 位置:
createByOrganizationRowData() - 数据保留在:
AccountsByOrganizationRowData.accountRows[].exceptionMessage/errorCode
- 位置:
orgData 的来源追踪
orgData 的创建流程:
-
后端 API →
getCloudOrganizationsAndAccounts()- 返回
CloudOrganizationsAndAccountsResponse.organizational_accounts - 包含组织信息:
org_id,org_display_name,orchestrator_account,aws_management_account
- 返回
-
解析层 →
parseOrganizationsAndAccountsResponse()- 位置:
responseUtils.ts(第88-130行) - 将
organizational_accounts解析为CloudOrganizationAttributes
organizationalAccounts[cloudOrganizationId] = { cloudOrganizationId: cloudOrganizationId, orgDisplayName: orgDisplayName, orchestratorAccount: organizationData.orchestrator_account, awsManagementAccount: organizationData.aws_management_account, accounts: { ... }, // 包含账户信息(包括错误信息) ... } - 位置:
-
Hook 层 →
useCloudOrganizationAccountsData()- 返回
organizationsData: Record<string, CloudOrganizationAttributes>
- 返回
-
行数据转换 →
parseCloudOrganizationAccountsToRows()- 位置:
parseCloudOrganizationAccountsToRows.ts(第26-85行) - 从
cloudOrganization: CloudOrganizationAttributes提取信息创建orgData
orgData: { cloudOrganizationId: cloudOrganization.cloudOrganizationId, // ← 从 CloudOrganizationAttributes 提取 orgDisplayName: cloudOrganization.orgDisplayName, // ← 从 CloudOrganizationAttributes 提取 orchestratorAccount: cloudOrganization.orchestratorAccount, // ← 从 CloudOrganizationAttributes 提取 awsManagementAccount: cloudOrganization.awsManagementAccount // ← 从 CloudOrganizationAttributes 提取 } - 位置:
重要发现:
- ✅ 组织账户:
orgData有值,包含组织信息 - ❌ 单账户:
orgData为null(singleAccountsData中的账户不属于任何组织)
在 CloudAccountSidePane 中的使用:
- 可以通过
accountId在organizationsAndAccountsRowData中查找 - 如果找到的
CloudOrganizationAccountRowData有orgData,说明它属于某个组织 orgData本身不包含错误信息,但同一条CloudOrganizationAccountRowData中包含exceptionMessage和errorCode
当前实现分析
CloudAccountSidePane 当前使用的数据源
- 数据源:
useCloudOrganizationAccountsData()(第 3 层) - 数据结构:
organizationsData: Record<string, CloudOrganizationAttributes>singleAccountsData: CloudOrganizationAccountAttributes[]
- 查找方式: 手动遍历查找匹配的
accountId
可选的数据源
-
第 3 层:
useCloudOrganizationAccountsData()✅ 当前使用- 优点: 原始数据,最完整
- 缺点: 需要手动查找
-
第 4 层:
useOrganizationsAndAccountsRows()- 优点: 已经是扁平化的
CloudOrganizationAccountRowData[],查找更方便 - 缺点: 只在 Settings 页面使用,不是全局可用
- 优点: 已经是扁平化的
-
第 5 层:
byOrganizationData(AccountsByOrganizationRowData[])- 优点: 已经按组织分组,结构清晰
- 缺点: 只在
OrganizationAndAccountsInnerTabs组件内可用
建议的数据传递方案
方案 A: 使用共享 Hook(推荐)
创建一个全局可用的 hook,返回 CloudOrganizationAccountRowData[]:
// hooks/useCloudOrganizationAccountRows.ts
export const useCloudOrganizationAccountRows = () => {
const { organizationsData, singleAccountsData, regionalCoverage, isCoverageDataLoading } =
useCloudOrganizationAccountsData();
return useOrganizationsAndAccountsRows(
organizationsData,
singleAccountsData,
regionalCoverage,
isCoverageDataLoading
);
};
优点:
- 全局可用
- 数据结构扁平化,查找方便
- 包含所有必要信息(包括错误信息)
方案 B: 使用共享存储
将 CloudOrganizationAccountRowData[] 存储在共享的 DataStorage 中,供全局访问。
优点:
- 数据集中管理
- 自动更新和事件通知
缺点:
- 需要额外的存储层
- 可能过度设计
方案 C: 保持当前实现(已实现)
继续使用 useCloudOrganizationAccountsData(),在 CloudAccountSidePane 中手动查找。
优点:
- 已实现
- 不依赖其他组件
缺点:
- 需要手动查找逻辑
- 代码重复(如果其他地方也需要)
推荐方案
推荐使用方案 A: 创建 useCloudOrganizationAccountRows hook,因为:
- 数据结构更友好(扁平数组,易于查找)
- 全局可用
- 代码复用
- 保持数据一致性