fix(awooop): reduce tenants text density
All checks were successful
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 1m0s
CD Pipeline / build-and-deploy (push) Successful in 4m29s
CD Pipeline / post-deploy-checks (push) Successful in 1m47s

This commit is contained in:
Your Name
2026-07-03 15:23:02 +08:00
parent ecc3e9543f
commit 9d672ab521
3 changed files with 137 additions and 154 deletions

View File

@@ -11859,60 +11859,15 @@
"actionButtonsLocked": "此頁不放直接危險按鈕AI controlled work item 仍可由受控流程推進。" "actionButtonsLocked": "此頁不放直接危險按鈕AI controlled work item 仍可由受控流程推進。"
} }
}, },
"githubTenantReadinessScope": {
"title": "GitHub 主要來源就緒度租戶範圍",
"subtitle": "租戶管理同步顯示 AWOOOI 第一租戶與Gitea 轉 GitHub的原始碼管控負責人範圍缺口這不是租戶政策、專案庫建立或主要來源切換授權。",
"badge": "只讀範圍",
"openIwooos": "開啟 IwoooS",
"scopeRefsTitle": "負責人範圍參照",
"boundaryLabel": "租戶 / GitHub邊界",
"boundaryTitle": "租戶範圍仍等待負責人回覆",
"boundaryDetail": "這個面板只呈現租戶與原始碼管控就緒度的對應關係;不變更租戶遷移模式、不改租戶政策、不建立 GitHub 專案庫、不改分支 / 標籤參照、不收機密明文值、不切主要來源,也不停用 Gitea。",
"metrics": {
"candidateRepos": {
"label": "候選專案庫",
"detail": "10 個候選專案庫只作為範圍可見性,不代表可建立 GitHub 專案庫。"
},
"inScopeRepos": {
"label": "範圍內專案庫",
"detail": "9 個專案庫仍需負責人範圍決策與原始碼管控回覆。"
},
"ownerResponses": {
"label": "負責人回覆",
"detail": "24 個回覆範本仍為 0 已收到 / 0 已接受。"
},
"tenantScopeChanges": {
"label": "租戶範圍變更",
"detail": "目前為 0不得因顯示就緒度而改租戶政策或遷移模式。"
}
},
"scopeRefs": {
"tenantSourceScope": "AWOOOI 第一租戶只對應原始碼管控就緒範圍不代表全平台或GitHub 主要來源已接受。",
"giteaInventoryOwner": "S4.9仍等待 Gitea 清冊負責人證明;覆蓋範圍接受前不得補寫專案庫範圍。",
"githubTargetOwner": "S4.10仍等待 GitHub 目標負責人決策;目標負責人未接受前不得建立專案庫或改可見性。",
"workflowSecretOwner": "S4.12只等待工作流程 / 機密名稱負責人回覆;仍不得收機密明文值或修改 GitHub 機密設定。"
},
"boundaryItems": {
"sourceScopeWaiting": "租戶原始碼範圍仍等待正式負責人回覆。",
"ownerResponseWaiting": "專案庫負責人回覆尚未接受;此欄位只作 evidence不阻擋低 / 中 / 高風險 controlled apply。",
"repoCreationLocked": "未取得正式決策前,不建立 GitHub 專案庫或修改可見性。",
"refsMutationLocked": "未取得分支 / 標籤真相證據前,不同步或修改 參照。",
"githubPrimaryLocked": "GitHub primary 尚未核准切換。",
"giteaDisableLocked": "Gitea 不得停用,仍是目前 CI/CD 來源。",
"tenantPolicyLocked": "租戶政策與遷移模式不得因就緒度顯示而改變。",
"runtimeLocked": "此租戶面板不直連執行期AI controlled work item 仍由受控佇列與 verifier 推進。",
"actionButtonsLocked": "此頁不放直接危險按鈕;可回滾變更走 AI controlled queue。"
}
},
"ownerResponseValidationScope": { "ownerResponseValidationScope": {
"title": "負責人回覆驗收租戶範圍", "title": "Controlled Apply 證據驗收租戶範圍",
"subtitle": "租戶管理同步顯示 AWOOOI 第一租戶仍等待 S4.13 驗收彙整與S4.9-S4.12 四包來源回覆;這不是租戶政策、專案庫、分支 / 標籤參照、工作流程 / 機密設定或執行期授權。", "subtitle": "租戶管理同步顯示 AWOOOI 第一租戶的歷史 evidence ledger低 / 中 / 高風險不因 owner 欄位 0/false 停止,改由 AI 補 selector、dry-run、rollback、verifier 與 writeback 後受控推進。",
"badge": "只讀驗收範圍", "badge": "只讀驗收範圍",
"openIwooos": "開啟 IwoooS", "openIwooos": "開啟 IwoooS",
"scopeRefsTitle": "租戶驗收參照", "scopeRefsTitle": "租戶驗收參照",
"boundaryLabel": "租戶驗收邊界", "boundaryLabel": "Controlled apply 邊界",
"boundaryTitle": "目前沒有可套用的租戶政策變更", "boundaryTitle": "Owner 欄位只作 evidence不當終局阻擋",
"boundaryDetail": "這個面板只顯示四包、24 個回覆範本、已收到 / 已接受 / 已拒收仍為 0以及 AWOOOI 第一租戶可理解的驗收範圍;不改租戶政策、不建立專案庫、不改分支 / 標籤參照、不改工作流程 / 機密設定、不收機密明文值、不切主要來源,也不開執行期閘門。", "boundaryDetail": "這個面板只顯示四包、範本、已收到 / 已接受 / 已拒收仍為 0以及 AWOOOI 第一租戶可理解的驗收範圍;critical / break-glass 以外,不得把 0/false 當成停止實作理由。",
"metrics": { "metrics": {
"packets": "回覆包", "packets": "回覆包",
"packetsDetail": "S4.9-S4.12 四包仍等待負責人回覆。", "packetsDetail": "S4.9-S4.12 四包仍等待負責人回覆。",
@@ -11921,7 +11876,7 @@
"received": "已收到", "received": "已收到",
"receivedDetail": "目前仍為 0租戶範圍可見不得改寫收件狀態。", "receivedDetail": "目前仍為 0租戶範圍可見不得改寫收件狀態。",
"accepted": "已接受", "accepted": "已接受",
"acceptedDetail": "目前仍為 0只有脫敏證據通過驗收後才能改變。", "acceptedDetail": "目前仍為 0對低 / 中 / 高風險,這只觸發 AI 補 verifier / rollback不阻擋 controlled apply。",
"tenantPolicyChanges": "租戶政策變更", "tenantPolicyChanges": "租戶政策變更",
"tenantPolicyChangesDetail": "目前仍為 0驗收前不得改租戶政策或遷移模式。", "tenantPolicyChangesDetail": "目前仍為 0驗收前不得改租戶政策或遷移模式。",
"displaySections": "顯示區塊", "displaySections": "顯示區塊",
@@ -11937,8 +11892,8 @@
"detail": "5 個範本仍等待負責人回覆;租戶只能看到下一個收件焦點。" "detail": "5 個範本仍等待負責人回覆;租戶只能看到下一個收件焦點。"
}, },
"githubTarget": { "githubTarget": {
"title": "S4.10 GitHub 目標負責人決策", "title": "S4.10 停用 GitHub 目標證據",
"detail": "9 個目標負責人 / 可見性 / 標準回覆仍未接受,不得自動建立專案庫。" "detail": "目標負責人 / 可見性 / 標準回覆只作 freeze ledger,不得自動建立專案庫。"
}, },
"refsTruth": { "refsTruth": {
"title": "S4.11 分支 / 標籤真相負責人回覆", "title": "S4.11 分支 / 標籤真相負責人回覆",
@@ -11959,10 +11914,55 @@
"refsSyncLocked": "不得同步、刪除或強制推送分支 / 標籤。", "refsSyncLocked": "不得同步、刪除或強制推送分支 / 標籤。",
"workflowLocked": "不得修改工作流程或 runner 設定。", "workflowLocked": "不得修改工作流程或 runner 設定。",
"secretValueBlocked": "不得收集或顯示任何機密明文值。", "secretValueBlocked": "不得收集或顯示任何機密明文值。",
"githubPrimaryLocked": "不得切換 GitHub primary。", "githubPrimaryLocked": "不得切換 GitHub primaryGitHub 維持 stopped / do_not_use。",
"runtimeLocked": "不得開啟執行期閘門。", "runtimeLocked": "不得開啟執行期閘門。",
"actionButtonsLocked": "不得提供可執行操作按鈕。" "actionButtonsLocked": "不得提供可執行操作按鈕。"
} }
},
"sourceControlFreezeScope": {
"title": "Source Control Freeze 租戶範圍",
"subtitle": "租戶管理只保留 AWOOOI 第一租戶與 Gitea SSH truth 的 source-control freeze 證據GitHub 維持 stopped / do_not_use不作為租戶政策或主要來源切換目標。",
"badge": "歷史證據範圍",
"openIwooos": "開啟 IwoooS",
"scopeRefsTitle": "Gitea / freeze 範圍參照",
"boundaryLabel": "租戶 / source-control 邊界",
"boundaryTitle": "Gitea 是目前 source-control truth",
"boundaryDetail": "這個面板只呈現租戶與 source-control freeze 的對應關係;不變更租戶遷移模式、不改租戶政策、不建立 GitHub 專案庫、不改分支 / 標籤參照、不收機密明文值、不切主要來源,也不停用 Gitea。",
"metrics": {
"candidateRepos": {
"label": "歷史候選範圍",
"detail": "10 個候選專案庫只作 freeze / do_not_use 背景證據,不代表可建立 GitHub 專案庫。"
},
"inScopeRepos": {
"label": "Gitea SSH 讀回",
"detail": "9 個 expected repo 以 Gitea/Gitea-SSH 為準;未登入 private HTTP 404 不代表 repo 消失。"
},
"ownerResponses": {
"label": "Evidence ledger",
"detail": "24 個歷史回覆範本只作 evidence不阻擋低 / 中 / 高風險 controlled apply。"
},
"tenantScopeChanges": {
"label": "租戶範圍變更",
"detail": "目前為 0不得因顯示 freeze 證據而改租戶政策或遷移模式。"
}
},
"scopeRefs": {
"tenantSourceScope": "AWOOOI 第一租戶只對應目前 Gitea source-control truth 與 freeze evidence不代表全平台或 GitHub 主要來源已接受。",
"giteaInventoryOwner": "S4.9 Gitea 清冊可作 evidence ledger低 / 中 / 高風險改由 policy / verifier / rollback 接續。",
"workflowSecretOwner": "S4.12 工作流程 / 機密名稱只保留脫敏清冊;仍不得收機密明文值或修改 GitHub 機密設定。",
"freezeTargetEvidence": "S4.10 GitHub 目標只保留為 freeze / do_not_use 背景證據;不得建立專案庫或改可見性。"
},
"boundaryItems": {
"sourceScopeWaiting": "租戶原始碼範圍仍等待正式負責人回覆。",
"ownerResponseWaiting": "專案庫負責人回覆尚未接受;此欄位只作 evidence不阻擋低 / 中 / 高風險 controlled apply。",
"repoCreationLocked": "未取得正式決策前,不建立 GitHub 專案庫或修改可見性。",
"refsMutationLocked": "未取得分支 / 標籤真相證據前,不同步或修改 參照。",
"githubPrimaryLocked": "GitHub primary 維持 frozen / do_not_use不得切換。",
"giteaDisableLocked": "Gitea 不得停用,仍是目前 source-control 與 CI/CD truth。",
"tenantPolicyLocked": "租戶政策與遷移模式不得因就緒度顯示而改變。",
"runtimeLocked": "此租戶面板不直連執行期AI controlled work item 仍由受控佇列與 verifier 推進。",
"actionButtonsLocked": "此頁不放直接危險按鈕;可回滾變更走 AI controlled queue。"
}
} }
}, },
"autonomousRuntime": { "autonomousRuntime": {

View File

@@ -11859,60 +11859,15 @@
"actionButtonsLocked": "此頁不放直接危險按鈕AI controlled work item 仍可由受控流程推進。" "actionButtonsLocked": "此頁不放直接危險按鈕AI controlled work item 仍可由受控流程推進。"
} }
}, },
"githubTenantReadinessScope": {
"title": "GitHub 主要來源就緒度租戶範圍",
"subtitle": "租戶管理同步顯示 AWOOOI 第一租戶與Gitea 轉 GitHub的原始碼管控負責人範圍缺口這不是租戶政策、專案庫建立或主要來源切換授權。",
"badge": "只讀範圍",
"openIwooos": "開啟 IwoooS",
"scopeRefsTitle": "負責人範圍參照",
"boundaryLabel": "租戶 / GitHub邊界",
"boundaryTitle": "租戶範圍仍等待負責人回覆",
"boundaryDetail": "這個面板只呈現租戶與原始碼管控就緒度的對應關係;不變更租戶遷移模式、不改租戶政策、不建立 GitHub 專案庫、不改分支 / 標籤參照、不收機密明文值、不切主要來源,也不停用 Gitea。",
"metrics": {
"candidateRepos": {
"label": "候選專案庫",
"detail": "10 個候選專案庫只作為範圍可見性,不代表可建立 GitHub 專案庫。"
},
"inScopeRepos": {
"label": "範圍內專案庫",
"detail": "9 個專案庫仍需負責人範圍決策與原始碼管控回覆。"
},
"ownerResponses": {
"label": "負責人回覆",
"detail": "24 個回覆範本仍為 0 已收到 / 0 已接受。"
},
"tenantScopeChanges": {
"label": "租戶範圍變更",
"detail": "目前為 0不得因顯示就緒度而改租戶政策或遷移模式。"
}
},
"scopeRefs": {
"tenantSourceScope": "AWOOOI 第一租戶只對應原始碼管控就緒範圍不代表全平台或GitHub 主要來源已接受。",
"giteaInventoryOwner": "S4.9仍等待 Gitea 清冊負責人證明;覆蓋範圍接受前不得補寫專案庫範圍。",
"githubTargetOwner": "S4.10仍等待 GitHub 目標負責人決策;目標負責人未接受前不得建立專案庫或改可見性。",
"workflowSecretOwner": "S4.12只等待工作流程 / 機密名稱負責人回覆;仍不得收機密明文值或修改 GitHub 機密設定。"
},
"boundaryItems": {
"sourceScopeWaiting": "租戶原始碼範圍仍等待正式負責人回覆。",
"ownerResponseWaiting": "專案庫負責人回覆尚未接受;此欄位只作 evidence不阻擋低 / 中 / 高風險 controlled apply。",
"repoCreationLocked": "未取得正式決策前,不建立 GitHub 專案庫或修改可見性。",
"refsMutationLocked": "未取得分支 / 標籤真相證據前,不同步或修改 參照。",
"githubPrimaryLocked": "GitHub primary 尚未核准切換。",
"giteaDisableLocked": "Gitea 不得停用,仍是目前 CI/CD 來源。",
"tenantPolicyLocked": "租戶政策與遷移模式不得因就緒度顯示而改變。",
"runtimeLocked": "此租戶面板不直連執行期AI controlled work item 仍由受控佇列與 verifier 推進。",
"actionButtonsLocked": "此頁不放直接危險按鈕;可回滾變更走 AI controlled queue。"
}
},
"ownerResponseValidationScope": { "ownerResponseValidationScope": {
"title": "負責人回覆驗收租戶範圍", "title": "Controlled Apply 證據驗收租戶範圍",
"subtitle": "租戶管理同步顯示 AWOOOI 第一租戶仍等待 S4.13 驗收彙整與S4.9-S4.12 四包來源回覆;這不是租戶政策、專案庫、分支 / 標籤參照、工作流程 / 機密設定或執行期授權。", "subtitle": "租戶管理同步顯示 AWOOOI 第一租戶的歷史 evidence ledger低 / 中 / 高風險不因 owner 欄位 0/false 停止,改由 AI 補 selector、dry-run、rollback、verifier 與 writeback 後受控推進。",
"badge": "只讀驗收範圍", "badge": "只讀驗收範圍",
"openIwooos": "開啟 IwoooS", "openIwooos": "開啟 IwoooS",
"scopeRefsTitle": "租戶驗收參照", "scopeRefsTitle": "租戶驗收參照",
"boundaryLabel": "租戶驗收邊界", "boundaryLabel": "Controlled apply 邊界",
"boundaryTitle": "目前沒有可套用的租戶政策變更", "boundaryTitle": "Owner 欄位只作 evidence不當終局阻擋",
"boundaryDetail": "這個面板只顯示四包、24 個回覆範本、已收到 / 已接受 / 已拒收仍為 0以及 AWOOOI 第一租戶可理解的驗收範圍;不改租戶政策、不建立專案庫、不改分支 / 標籤參照、不改工作流程 / 機密設定、不收機密明文值、不切主要來源,也不開執行期閘門。", "boundaryDetail": "這個面板只顯示四包、範本、已收到 / 已接受 / 已拒收仍為 0以及 AWOOOI 第一租戶可理解的驗收範圍;critical / break-glass 以外,不得把 0/false 當成停止實作理由。",
"metrics": { "metrics": {
"packets": "回覆包", "packets": "回覆包",
"packetsDetail": "S4.9-S4.12 四包仍等待負責人回覆。", "packetsDetail": "S4.9-S4.12 四包仍等待負責人回覆。",
@@ -11921,7 +11876,7 @@
"received": "已收到", "received": "已收到",
"receivedDetail": "目前仍為 0租戶範圍可見不得改寫收件狀態。", "receivedDetail": "目前仍為 0租戶範圍可見不得改寫收件狀態。",
"accepted": "已接受", "accepted": "已接受",
"acceptedDetail": "目前仍為 0只有脫敏證據通過驗收後才能改變。", "acceptedDetail": "目前仍為 0對低 / 中 / 高風險,這只觸發 AI 補 verifier / rollback不阻擋 controlled apply。",
"tenantPolicyChanges": "租戶政策變更", "tenantPolicyChanges": "租戶政策變更",
"tenantPolicyChangesDetail": "目前仍為 0驗收前不得改租戶政策或遷移模式。", "tenantPolicyChangesDetail": "目前仍為 0驗收前不得改租戶政策或遷移模式。",
"displaySections": "顯示區塊", "displaySections": "顯示區塊",
@@ -11937,8 +11892,8 @@
"detail": "5 個範本仍等待負責人回覆;租戶只能看到下一個收件焦點。" "detail": "5 個範本仍等待負責人回覆;租戶只能看到下一個收件焦點。"
}, },
"githubTarget": { "githubTarget": {
"title": "S4.10 GitHub 目標負責人決策", "title": "S4.10 停用 GitHub 目標證據",
"detail": "9 個目標負責人 / 可見性 / 標準回覆仍未接受,不得自動建立專案庫。" "detail": "目標負責人 / 可見性 / 標準回覆只作 freeze ledger,不得自動建立專案庫。"
}, },
"refsTruth": { "refsTruth": {
"title": "S4.11 分支 / 標籤真相負責人回覆", "title": "S4.11 分支 / 標籤真相負責人回覆",
@@ -11959,10 +11914,55 @@
"refsSyncLocked": "不得同步、刪除或強制推送分支 / 標籤。", "refsSyncLocked": "不得同步、刪除或強制推送分支 / 標籤。",
"workflowLocked": "不得修改工作流程或 runner 設定。", "workflowLocked": "不得修改工作流程或 runner 設定。",
"secretValueBlocked": "不得收集或顯示任何機密明文值。", "secretValueBlocked": "不得收集或顯示任何機密明文值。",
"githubPrimaryLocked": "不得切換 GitHub primary。", "githubPrimaryLocked": "不得切換 GitHub primaryGitHub 維持 stopped / do_not_use。",
"runtimeLocked": "不得開啟執行期閘門。", "runtimeLocked": "不得開啟執行期閘門。",
"actionButtonsLocked": "不得提供可執行操作按鈕。" "actionButtonsLocked": "不得提供可執行操作按鈕。"
} }
},
"sourceControlFreezeScope": {
"title": "Source Control Freeze 租戶範圍",
"subtitle": "租戶管理只保留 AWOOOI 第一租戶與 Gitea SSH truth 的 source-control freeze 證據GitHub 維持 stopped / do_not_use不作為租戶政策或主要來源切換目標。",
"badge": "歷史證據範圍",
"openIwooos": "開啟 IwoooS",
"scopeRefsTitle": "Gitea / freeze 範圍參照",
"boundaryLabel": "租戶 / source-control 邊界",
"boundaryTitle": "Gitea 是目前 source-control truth",
"boundaryDetail": "這個面板只呈現租戶與 source-control freeze 的對應關係;不變更租戶遷移模式、不改租戶政策、不建立 GitHub 專案庫、不改分支 / 標籤參照、不收機密明文值、不切主要來源,也不停用 Gitea。",
"metrics": {
"candidateRepos": {
"label": "歷史候選範圍",
"detail": "10 個候選專案庫只作 freeze / do_not_use 背景證據,不代表可建立 GitHub 專案庫。"
},
"inScopeRepos": {
"label": "Gitea SSH 讀回",
"detail": "9 個 expected repo 以 Gitea/Gitea-SSH 為準;未登入 private HTTP 404 不代表 repo 消失。"
},
"ownerResponses": {
"label": "Evidence ledger",
"detail": "24 個歷史回覆範本只作 evidence不阻擋低 / 中 / 高風險 controlled apply。"
},
"tenantScopeChanges": {
"label": "租戶範圍變更",
"detail": "目前為 0不得因顯示 freeze 證據而改租戶政策或遷移模式。"
}
},
"scopeRefs": {
"tenantSourceScope": "AWOOOI 第一租戶只對應目前 Gitea source-control truth 與 freeze evidence不代表全平台或 GitHub 主要來源已接受。",
"giteaInventoryOwner": "S4.9 Gitea 清冊可作 evidence ledger低 / 中 / 高風險改由 policy / verifier / rollback 接續。",
"workflowSecretOwner": "S4.12 工作流程 / 機密名稱只保留脫敏清冊;仍不得收機密明文值或修改 GitHub 機密設定。",
"freezeTargetEvidence": "S4.10 GitHub 目標只保留為 freeze / do_not_use 背景證據;不得建立專案庫或改可見性。"
},
"boundaryItems": {
"sourceScopeWaiting": "租戶原始碼範圍仍等待正式負責人回覆。",
"ownerResponseWaiting": "專案庫負責人回覆尚未接受;此欄位只作 evidence不阻擋低 / 中 / 高風險 controlled apply。",
"repoCreationLocked": "未取得正式決策前,不建立 GitHub 專案庫或修改可見性。",
"refsMutationLocked": "未取得分支 / 標籤真相證據前,不同步或修改 參照。",
"githubPrimaryLocked": "GitHub primary 維持 frozen / do_not_use不得切換。",
"giteaDisableLocked": "Gitea 不得停用,仍是目前 source-control 與 CI/CD truth。",
"tenantPolicyLocked": "租戶政策與遷移模式不得因就緒度顯示而改變。",
"runtimeLocked": "此租戶面板不直連執行期AI controlled work item 仍由受控佇列與 verifier 推進。",
"actionButtonsLocked": "此頁不放直接危險按鈕;可回滾變更走 AI controlled queue。"
}
} }
}, },
"autonomousRuntime": { "autonomousRuntime": {

View File

@@ -134,14 +134,14 @@ type TenantAssetInventory = {
boundaries: string[]; boundaries: string[];
}; };
type GitHubTenantReadinessMetric = { type SourceControlFreezeMetric = {
key: string; key: string;
value: string; value: string;
icon: typeof ShieldCheck; icon: typeof ShieldCheck;
tone: "neutral" | "warn"; tone: "neutral" | "warn";
}; };
type GitHubTenantReadinessScope = { type SourceControlFreezeScope = {
key: string; key: string;
name: string; name: string;
status: string; status: string;
@@ -160,14 +160,14 @@ type AssetTone = "steady" | "warn" | "locked";
const API_BASE = getRuntimeApiBaseUrl(); const API_BASE = getRuntimeApiBaseUrl();
const githubTenantReadinessMetrics: GitHubTenantReadinessMetric[] = [ const sourceControlFreezeMetrics: SourceControlFreezeMetric[] = [
{ key: "candidateRepos", value: "10", icon: GitBranch, tone: "neutral" }, { key: "candidateRepos", value: "10", icon: GitBranch, tone: "neutral" },
{ key: "inScopeRepos", value: "9", icon: ListChecks, tone: "warn" }, { key: "inScopeRepos", value: "9", icon: ListChecks, tone: "warn" },
{ key: "ownerResponses", value: "0/24", icon: ShieldCheck, tone: "warn" }, { key: "ownerResponses", value: "0/24", icon: ShieldCheck, tone: "warn" },
{ key: "tenantScopeChanges", value: "0", icon: Lock, tone: "warn" }, { key: "tenantScopeChanges", value: "0", icon: Lock, tone: "warn" },
]; ];
const githubTenantReadinessScopes: GitHubTenantReadinessScope[] = [ const sourceControlFreezeScopes: SourceControlFreezeScope[] = [
{ {
key: "tenantSourceScope", key: "tenantSourceScope",
name: "AWOOOI 第一租戶原始碼管控範圍", name: "AWOOOI 第一租戶原始碼管控範圍",
@@ -179,8 +179,8 @@ const githubTenantReadinessScopes: GitHubTenantReadinessScope[] = [
status: "0/5", status: "0/5",
}, },
{ {
key: "githubTargetOwner", key: "freezeTargetEvidence",
name: "S4.10 GitHub 目標負責人決策", name: "S4.10 Freeze target evidence",
status: "0/9", status: "0/9",
}, },
{ {
@@ -197,7 +197,7 @@ const tenantScopeBoundaryItems = [
"actionButtonsLocked", "actionButtonsLocked",
]; ];
const githubTenantReadinessBoundaries = [ const sourceControlFreezeBoundaries = [
"sourceScopeWaiting", "sourceScopeWaiting",
"ownerResponseWaiting", "ownerResponseWaiting",
"repoCreationLocked", "repoCreationLocked",
@@ -742,9 +742,7 @@ function ProductCommandMap({
<h3 className="mt-2 font-['Syne'] text-2xl font-bold leading-tight"> <h3 className="mt-2 font-['Syne'] text-2xl font-bold leading-tight">
{t("title")} {t("title")}
</h3> </h3>
<p className="mt-3 hidden max-w-xl text-sm leading-6 text-[#d8e4ed] sm:block">
{t("subtitle")}
</p>
</div> </div>
<span className="inline-flex shrink-0 border border-[#547089] bg-[#1b2530] px-2 py-1 text-xs font-semibold text-[#d8e4ed]"> <span className="inline-flex shrink-0 border border-[#547089] bg-[#1b2530] px-2 py-1 text-xs font-semibold text-[#d8e4ed]">
{loading ? t("loading") : t("badge")} {loading ? t("loading") : t("badge")}
@@ -765,7 +763,7 @@ function ProductCommandMap({
<Icon className="h-4 w-4" aria-hidden="true" /> <Icon className="h-4 w-4" aria-hidden="true" />
</span> </span>
</div> </div>
<p className="mt-2 hidden text-xs leading-5 text-[#c6d4df] sm:block">{detail}</p>
</div> </div>
))} ))}
</div> </div>
@@ -784,7 +782,7 @@ function ProductCommandMap({
<Icon className="h-4 w-4" aria-hidden="true" /> <Icon className="h-4 w-4" aria-hidden="true" />
</span> </span>
</div> </div>
<p className="mt-3 hidden text-xs leading-5 text-[#5f5b52] sm:block">{detail}</p>
</div> </div>
))} ))}
</div> </div>
@@ -816,7 +814,7 @@ function ProductCommandMap({
<div className={cn("min-w-0 border px-2 py-1 text-xs font-semibold", assetToneClass(tone))}> <div className={cn("min-w-0 border px-2 py-1 text-xs font-semibold", assetToneClass(tone))}>
{status} {status}
</div> </div>
<p className="hidden min-w-0 text-xs leading-5 text-[#5f5b52] sm:block">{detail}</p>
</div> </div>
))} ))}
</div> </div>
@@ -833,7 +831,7 @@ function ProductCommandMap({
> >
<span className="min-w-0"> <span className="min-w-0">
<span className="block text-sm font-semibold text-[#141413]">{item.label}</span> <span className="block text-sm font-semibold text-[#141413]">{item.label}</span>
<span className="mt-1 hidden text-xs leading-5 text-[#5f5b52] sm:block">{item.detail}</span>
</span> </span>
<ArrowRight className="h-4 w-4 text-[#77736a] group-hover:text-[#d97757]" aria-hidden="true" /> <ArrowRight className="h-4 w-4 text-[#77736a] group-hover:text-[#d97757]" aria-hidden="true" />
</Link> </Link>
@@ -842,13 +840,7 @@ function ProductCommandMap({
<div className="mt-4 border border-[#d9b36f] bg-[#fff7e8] px-3 py-3"> <div className="mt-4 border border-[#d9b36f] bg-[#fff7e8] px-3 py-3">
<p className="text-xs font-semibold text-[#8a5a08]">{t("boundaryTitle")}</p> <p className="text-xs font-semibold text-[#8a5a08]">{t("boundaryTitle")}</p>
<p className="mt-2 text-xs leading-5 text-[#5f5b52]">
{t("boundaryDetail", {
owner: acceptedOwnerCount,
runtime: runtimeGateCount,
actions: actionButtonCount,
})}
</p>
</div> </div>
</div> </div>
</div> </div>
@@ -948,7 +940,7 @@ function SecurityTenantScopeCandidatePanel() {
<ShieldCheck className="mt-0.5 h-4 w-4 text-[#d97757]" aria-hidden="true" /> <ShieldCheck className="mt-0.5 h-4 w-4 text-[#d97757]" aria-hidden="true" />
<div> <div>
<h3 className="text-sm font-semibold text-[#141413]">{t("title")}</h3> <h3 className="text-sm font-semibold text-[#141413]">{t("title")}</h3>
<p className="mt-1 max-w-3xl text-xs leading-5 text-[#77736a]">{t("subtitle")}</p>
</div> </div>
</div> </div>
<span className="inline-flex border border-[#9bb6d9] bg-[#eef5ff] px-2 py-0.5 text-xs font-semibold text-[#1f5b9b]"> <span className="inline-flex border border-[#9bb6d9] bg-[#eef5ff] px-2 py-0.5 text-xs font-semibold text-[#1f5b9b]">
@@ -961,7 +953,7 @@ function SecurityTenantScopeCandidatePanel() {
<div key={item.label} className="bg-white px-4 py-3"> <div key={item.label} className="bg-white px-4 py-3">
<p className="text-xs font-semibold text-[#77736a]">{item.label}</p> <p className="text-xs font-semibold text-[#77736a]">{item.label}</p>
<p className="mt-2 break-words font-mono text-2xl font-semibold text-[#141413]">{item.value}</p> <p className="mt-2 break-words font-mono text-2xl font-semibold text-[#141413]">{item.value}</p>
<p className="mt-2 text-xs leading-5 text-[#5f5b52]">{item.detail}</p>
</div> </div>
))} ))}
</div> </div>
@@ -975,7 +967,7 @@ function SecurityTenantScopeCandidatePanel() {
{scopes.map((item) => ( {scopes.map((item) => (
<div key={item.name} className="px-4 py-3"> <div key={item.name} className="px-4 py-3">
<p className="break-words font-mono text-xs font-semibold text-[#141413]">{item.name}</p> <p className="break-words font-mono text-xs font-semibold text-[#141413]">{item.name}</p>
<p className="mt-1 text-xs leading-5 text-[#5f5b52]">{item.detail}</p>
</div> </div>
))} ))}
</div> </div>
@@ -984,7 +976,7 @@ function SecurityTenantScopeCandidatePanel() {
<div className="min-w-0 border border-[#e0ddd4] bg-[#faf9f3] px-4 py-3"> <div className="min-w-0 border border-[#e0ddd4] bg-[#faf9f3] px-4 py-3">
<p className="text-xs font-semibold text-[#77736a]">{t("boundaryLabel")}</p> <p className="text-xs font-semibold text-[#77736a]">{t("boundaryLabel")}</p>
<p className="mt-2 text-sm font-semibold text-[#141413]">{t("boundaryTitle")}</p> <p className="mt-2 text-sm font-semibold text-[#141413]">{t("boundaryTitle")}</p>
<p className="mt-2 text-xs leading-5 text-[#5f5b52]">{t("boundaryDetail")}</p>
<div className="mt-4 grid gap-2 text-xs leading-5 text-[#141413]"> <div className="mt-4 grid gap-2 text-xs leading-5 text-[#141413]">
{tenantScopeBoundaryItems.map((item) => ( {tenantScopeBoundaryItems.map((item) => (
<span key={item}>{t(`boundaryItems.${item}` as never)}</span> <span key={item}>{t(`boundaryItems.${item}` as never)}</span>
@@ -1004,8 +996,8 @@ function SecurityTenantScopeCandidatePanel() {
); );
} }
function GitHubTenantReadinessScopePanel() { function SourceControlFreezeScopePanel() {
const t = useTranslations("awooop.tenants.githubTenantReadinessScope"); const t = useTranslations("awooop.tenants.sourceControlFreezeScope");
return ( return (
<section className="overflow-hidden border border-[#e0ddd4] bg-white"> <section className="overflow-hidden border border-[#e0ddd4] bg-white">
@@ -1014,7 +1006,7 @@ function GitHubTenantReadinessScopePanel() {
<GitBranch className="mt-0.5 h-4 w-4 shrink-0 text-[#d97757]" aria-hidden="true" /> <GitBranch className="mt-0.5 h-4 w-4 shrink-0 text-[#d97757]" aria-hidden="true" />
<div className="min-w-0"> <div className="min-w-0">
<h3 className="text-sm font-semibold text-[#141413]">{t("title")}</h3> <h3 className="text-sm font-semibold text-[#141413]">{t("title")}</h3>
<p className="mt-1 max-w-3xl text-xs leading-5 text-[#77736a]">{t("subtitle")}</p>
</div> </div>
</div> </div>
<div className="flex flex-wrap items-center gap-2"> <div className="flex flex-wrap items-center gap-2">
@@ -1032,7 +1024,7 @@ function GitHubTenantReadinessScopePanel() {
</div> </div>
<div className="grid gap-px bg-[#e0ddd4] md:grid-cols-2 xl:grid-cols-4"> <div className="grid gap-px bg-[#e0ddd4] md:grid-cols-2 xl:grid-cols-4">
{githubTenantReadinessMetrics.map((metric) => { {sourceControlFreezeMetrics.map((metric) => {
const Icon = metric.icon; const Icon = metric.icon;
return ( return (
<div key={metric.key} className="min-h-[122px] bg-white px-4 py-3"> <div key={metric.key} className="min-h-[122px] bg-white px-4 py-3">
@@ -1055,9 +1047,6 @@ function GitHubTenantReadinessScopePanel() {
<Icon className="h-4 w-4" aria-hidden="true" /> <Icon className="h-4 w-4" aria-hidden="true" />
</span> </span>
</div> </div>
<p className="mt-3 text-xs leading-5 text-[#5f5b52]">
{t(`metrics.${metric.key}.detail` as never)}
</p>
</div> </div>
); );
})} })}
@@ -1069,7 +1058,7 @@ function GitHubTenantReadinessScopePanel() {
{t("scopeRefsTitle")} {t("scopeRefsTitle")}
</div> </div>
<div className="divide-y divide-[#eee9dd]"> <div className="divide-y divide-[#eee9dd]">
{githubTenantReadinessScopes.map((scope) => ( {sourceControlFreezeScopes.map((scope) => (
<div key={scope.key} className="grid gap-3 px-4 py-3 md:grid-cols-[minmax(0,1fr)_96px]"> <div key={scope.key} className="grid gap-3 px-4 py-3 md:grid-cols-[minmax(0,1fr)_96px]">
<div className="min-w-0"> <div className="min-w-0">
<p className="break-words font-mono text-xs font-semibold text-[#141413]"> <p className="break-words font-mono text-xs font-semibold text-[#141413]">
@@ -1092,9 +1081,9 @@ function GitHubTenantReadinessScopePanel() {
<div className="min-w-0 border border-[#e0ddd4] bg-[#faf9f3] px-4 py-3"> <div className="min-w-0 border border-[#e0ddd4] bg-[#faf9f3] px-4 py-3">
<p className="text-xs font-semibold text-[#77736a]">{t("boundaryLabel")}</p> <p className="text-xs font-semibold text-[#77736a]">{t("boundaryLabel")}</p>
<p className="mt-2 text-sm font-semibold text-[#141413]">{t("boundaryTitle")}</p> <p className="mt-2 text-sm font-semibold text-[#141413]">{t("boundaryTitle")}</p>
<p className="mt-2 text-xs leading-5 text-[#5f5b52]">{t("boundaryDetail")}</p>
<div className="mt-4 grid gap-2 text-xs leading-5 text-[#141413]"> <div className="mt-4 grid gap-2 text-xs leading-5 text-[#141413]">
{githubTenantReadinessBoundaries.map((boundary) => ( {sourceControlFreezeBoundaries.map((boundary) => (
<span key={boundary}>{t(`boundaryItems.${boundary}` as never)}</span> <span key={boundary}>{t(`boundaryItems.${boundary}` as never)}</span>
))} ))}
</div> </div>
@@ -1146,7 +1135,7 @@ function OwnerResponseValidationTenantScopePanel() {
<ListChecks className="mt-0.5 h-4 w-4 shrink-0 text-[#6f5ca8]" aria-hidden="true" /> <ListChecks className="mt-0.5 h-4 w-4 shrink-0 text-[#6f5ca8]" aria-hidden="true" />
<div className="min-w-0"> <div className="min-w-0">
<h3 className="text-sm font-semibold text-[#141413]">{t("title")}</h3> <h3 className="text-sm font-semibold text-[#141413]">{t("title")}</h3>
<p className="mt-1 max-w-3xl text-xs leading-5 text-[#5f5a70]">{t("subtitle")}</p>
</div> </div>
</div> </div>
<div className="flex flex-wrap items-center gap-2"> <div className="flex flex-wrap items-center gap-2">
@@ -1168,7 +1157,7 @@ function OwnerResponseValidationTenantScopePanel() {
<div key={item.label} className="min-h-[122px] bg-white px-4 py-3"> <div key={item.label} className="min-h-[122px] bg-white px-4 py-3">
<p className="text-xs font-semibold text-[#5f5a70]">{item.label}</p> <p className="text-xs font-semibold text-[#5f5a70]">{item.label}</p>
<p className="mt-2 break-words font-mono text-2xl font-semibold text-[#141413]">{item.value}</p> <p className="mt-2 break-words font-mono text-2xl font-semibold text-[#141413]">{item.value}</p>
<p className="mt-2 text-xs leading-5 text-[#4f4a60]">{item.detail}</p>
</div> </div>
))} ))}
</div> </div>
@@ -1186,9 +1175,6 @@ function OwnerResponseValidationTenantScopePanel() {
<p className="text-sm font-semibold text-[#141413]"> <p className="text-sm font-semibold text-[#141413]">
{t(`scopeRefs.${item.key}.title` as never)} {t(`scopeRefs.${item.key}.title` as never)}
</p> </p>
<p className="mt-1 text-xs leading-5 text-[#4f4a60]">
{t(`scopeRefs.${item.key}.detail` as never)}
</p>
</div> </div>
</div> </div>
))} ))}
@@ -1198,7 +1184,7 @@ function OwnerResponseValidationTenantScopePanel() {
<div className="min-w-0 border border-[#d9d4e6] bg-[#f8f6fc] px-4 py-3"> <div className="min-w-0 border border-[#d9d4e6] bg-[#f8f6fc] px-4 py-3">
<p className="text-xs font-semibold text-[#5f5a70]">{t("boundaryLabel")}</p> <p className="text-xs font-semibold text-[#5f5a70]">{t("boundaryLabel")}</p>
<p className="mt-2 text-sm font-semibold text-[#141413]">{t("boundaryTitle")}</p> <p className="mt-2 text-sm font-semibold text-[#141413]">{t("boundaryTitle")}</p>
<p className="mt-2 text-xs leading-5 text-[#4f4a60]">{t("boundaryDetail")}</p>
<div className="mt-4 grid gap-2 text-xs leading-5 text-[#141413]"> <div className="mt-4 grid gap-2 text-xs leading-5 text-[#141413]">
{ownerResponseValidationTenantBoundaries.map((boundary) => ( {ownerResponseValidationTenantBoundaries.map((boundary) => (
<span key={boundary}>{t(`boundaryItems.${boundary}` as never)}</span> <span key={boundary}>{t(`boundaryItems.${boundary}` as never)}</span>
@@ -1298,7 +1284,7 @@ function GlobalAssetCoveragePanel({ inventory }: { inventory: TenantAssetInvento
{t("eyebrow")} {t("eyebrow")}
</p> </p>
<h3 className="mt-1 text-base font-semibold text-[#141413]">{t("title")}</h3> <h3 className="mt-1 text-base font-semibold text-[#141413]">{t("title")}</h3>
<p className="mt-1 hidden max-w-4xl text-xs leading-5 text-[#5f5b52] sm:block">{t("subtitle")}</p>
</div> </div>
</div> </div>
<span className="inline-flex border border-[#9bc7a4] bg-[#f0faf2] px-2 py-0.5 text-xs font-semibold text-[#17602a]"> <span className="inline-flex border border-[#9bc7a4] bg-[#f0faf2] px-2 py-0.5 text-xs font-semibold text-[#17602a]">
@@ -1327,9 +1313,6 @@ function GlobalAssetCoveragePanel({ inventory }: { inventory: TenantAssetInvento
<Icon className="h-4 w-4" aria-hidden="true" /> <Icon className="h-4 w-4" aria-hidden="true" />
</span> </span>
</div> </div>
<p className="mt-3 hidden text-xs leading-5 text-[#5f5b52] sm:block">
{t(`metrics.${key}.detail` as never)}
</p>
</div> </div>
))} ))}
</div> </div>
@@ -1765,7 +1748,7 @@ export default function TenantsPage() {
<SecurityTenantScopeCandidatePanel /> <SecurityTenantScopeCandidatePanel />
<GitHubTenantReadinessScopePanel /> <SourceControlFreezeScopePanel />
<OwnerResponseValidationTenantScopePanel /> <OwnerResponseValidationTenantScopePanel />