ShiErFeng/shierfeng-fastapi-backend/cli/tui/capabilities.py
2026-07-24 09:43:10 +08:00

210 lines
6.4 KiB
Python

from dataclasses import dataclass
from typing import Literal
from cli.tui.copy import TUI_COPY
CapabilityKind = Literal['read_only', 'preview', 'low_risk_action', 'wizard_entry', 'command_hint']
CapabilityScope = Literal['browser', 'detail']
@dataclass(frozen=True)
class TuiCapability:
"""
TUI 页面能力定义。
:param kind: 能力类型
:param slot: 绑定的动作槽位
:param key: 绑定的快捷键
:param label: 展示标签
:param hint_label: 用于顶部提示的简洁标签
:param scope: 能力所在页面范围
"""
kind: CapabilityKind
slot: str
key: str
label: str
hint_label: str
scope: CapabilityScope
@dataclass(frozen=True)
class TuiCapabilitySpec:
"""
TUI 页面能力规格定义。
:param capability_key: 能力标识
:param kind: 能力类型
:param slot: 绑定动作槽位
:param key: 绑定快捷键
"""
capability_key: str
kind: CapabilityKind
slot: str
key: str
_BROWSER_CAPABILITY_SPECS: dict[str, tuple[TuiCapabilitySpec, ...]] = {
'jobs': (
TuiCapabilitySpec('job_run_once', 'low_risk_action', 'primary', 'X'),
TuiCapabilitySpec('job_toggle', 'low_risk_action', 'secondary', 'Z'),
TuiCapabilitySpec('job_sync', 'preview', 'global', 'Y'),
),
'configs': (TuiCapabilitySpec('config_sync', 'low_risk_action', 'global', 'Y'),),
'cache': (
TuiCapabilitySpec('cache_clear_wizard', 'wizard_entry', 'global', 'Y'),
TuiCapabilitySpec('cache_warmup', 'low_risk_action', 'utility', 'W'),
),
'gen': (
TuiCapabilitySpec('gen_export_wizard', 'wizard_entry', 'primary', 'X'),
TuiCapabilitySpec('gen_import_wizard', 'wizard_entry', 'secondary', 'Z'),
TuiCapabilitySpec('gen_export_dry_run', 'preview', 'global', 'Y'),
TuiCapabilitySpec('gen_sync_db', 'low_risk_action', 'utility', 'W'),
),
}
_DETAIL_CAPABILITY_SPECS: dict[str, tuple[TuiCapabilitySpec, ...]] = {
'app': (
TuiCapabilitySpec('app_run', 'wizard_entry', 'primary', 'X'),
TuiCapabilitySpec('app_run_wizard', 'wizard_entry', 'global', 'Y'),
TuiCapabilitySpec('completion_install', 'command_hint', 'utility', 'W'),
),
'database': (
TuiCapabilitySpec('db_upgrade_wizard', 'wizard_entry', 'global', 'Y'),
TuiCapabilitySpec('db_init_dry_run', 'preview', 'utility', 'W'),
),
'ops': (
TuiCapabilitySpec('ops_ping_db', 'low_risk_action', 'primary', 'X'),
TuiCapabilitySpec('ops_ping_redis', 'low_risk_action', 'secondary', 'Z'),
TuiCapabilitySpec('prod_check_wizard', 'wizard_entry', 'global', 'Y'),
),
'crypto': (
TuiCapabilitySpec('crypto_keygen', 'wizard_entry', 'primary', 'X'),
TuiCapabilitySpec('crypto_rotate_dry_run', 'preview', 'global', 'Y'),
),
}
@dataclass(frozen=True)
class TuiCapabilityRegistry:
"""
TUI 页面能力注册表。
该对象集中维护浏览页与详情页的能力描述,避免模块级散落
的字典常量在后续扩展时继续增长。
:param browser_capabilities: 浏览页能力映射
:param detail_capabilities: 详情页能力映射
"""
browser_capabilities: dict[str, tuple[TuiCapability, ...]]
detail_capabilities: dict[str, tuple[TuiCapability, ...]]
@staticmethod
def normalize_view_key(view_key: str) -> str:
"""
规范化页面标识。
:param view_key: 原始页面标识
:return: 规范化后的页面标识
"""
return str(view_key).strip().lower()
def get_browser_capabilities(self, view_key: str) -> tuple[TuiCapability, ...]:
"""
获取浏览页支持的能力列表。
:param view_key: 页面视图标识
:return: 能力列表
"""
return self.browser_capabilities.get(self.normalize_view_key(view_key), ())
def get_detail_capabilities(self, view_key: str) -> tuple[TuiCapability, ...]:
"""
获取详情页支持的能力列表。
:param view_key: 页面视图标识
:return: 能力列表
"""
return self.detail_capabilities.get(self.normalize_view_key(view_key), ())
@dataclass(frozen=True)
class TuiCapabilityRegistryBuilder:
"""
TUI 页面能力注册表构建器。
该对象负责通过统一文案服务构建页面能力定义,避免模块内继续
直接堆叠硬编码的标题和提示标签。
"""
def build_capability(
self,
*,
capability_key: str,
kind: CapabilityKind,
slot: str,
key: str,
scope: CapabilityScope,
) -> TuiCapability:
"""
构建单条能力定义。
:param capability_key: 能力标识
:param kind: 能力类型
:param slot: 绑定动作槽位
:param key: 绑定快捷键
:param scope: 页面范围
:return: 能力定义
"""
return TuiCapability(
kind=kind,
slot=slot,
key=key,
label=TUI_COPY.build_capability_label(capability_key),
hint_label=TUI_COPY.build_capability_hint_label(capability_key),
scope=scope,
)
def build_scope_capabilities(
self,
specs_by_view: dict[str, tuple[TuiCapabilitySpec, ...]],
*,
scope: CapabilityScope,
) -> dict[str, tuple[TuiCapability, ...]]:
"""
根据规格映射构建指定页面范围的能力注册表。
:param specs_by_view: 页面能力规格映射
:param scope: 页面范围
:return: 构建后的能力映射
"""
return {
view_key: tuple(
self.build_capability(
capability_key=spec.capability_key,
kind=spec.kind,
slot=spec.slot,
key=spec.key,
scope=scope,
)
for spec in specs
)
for view_key, specs in specs_by_view.items()
}
def build(self) -> TuiCapabilityRegistry:
"""
构建页面能力注册表。
:return: 能力注册表
"""
return TuiCapabilityRegistry(
browser_capabilities=self.build_scope_capabilities(_BROWSER_CAPABILITY_SPECS, scope='browser'),
detail_capabilities=self.build_scope_capabilities(_DETAIL_CAPABILITY_SPECS, scope='detail'),
)
TUI_CAPABILITY_REGISTRY = TuiCapabilityRegistryBuilder().build()