diff --git a/src/pganec/tui.py b/src/pganec/tui.py index 7bb2fa7..b513efa 100644 --- a/src/pganec/tui.py +++ b/src/pganec/tui.py @@ -20,6 +20,10 @@ logger = logging.getLogger(__name__) # --- КОНФИГ_ПЕРЕМЕННЕЫ которые использоваться в приложении (возможно стоит перенести в другой файл) --- DB_FOR_BACKUP = "db_4b" +# --- Типы для шагов выбора --- +STEP_TYPE_SERVER = "select_server" +STEP_TYPE_DATABASE = "select_database" +STEP_TYPE_DESTINATION = "select_destination" # --- Кастомный обработчик логирования (для Textual) --- class TextualLogHandler(logging.Handler): @@ -49,23 +53,24 @@ class MainMenu(Static): def compose(self) -> ComposeResult: yield Horizontal( Button(label="Backup (DB\u2192Dump)", id="backup", classes="main-menu-button"), - Button(label="Restore (Dump\u2192DB)", id="restore"), - Button(label="Copy (DB\u2192DB)", id="copy", variant="error"), - Button(label="Service", id="service"), - Button(label="Quit", id="quit", variant="error"), + Button(label="Restore (Dump\u2192DB)", id="restore", classes="main-menu-button"), + Button(label="Copy (DB\u2192DB)", id="copy", classes="main-menu-button"), + Button(label="Service", id="service", classes="main-menu-button"), + Button(label="Quit", id="quit", variant="error", classes="main-menu-button"), id="menu", ) # --- Виджет для "встроенного" выбора --- class SelectionWidget(Static): # Наследуем от Static """ - Виджет для отображения опций выбора бекапа внутри основного экрана. + Виджет для многошагового выбора опций. + Отображает предыдущие выборы и текущие опции. """ @property def app(self) -> "PGanecApp": """ Возвращает ссылку на приложение PGanecApp , к которому принадлежит этот виджет. Нужно для доступа к методам - и состоянию приложения (и статического анализатора, т.к. класс PGanecApp описан ниже и "отсюда не виден"). + и состоянию приложения (и статического анализатора, так как класс PGanecApp описан ниже и "отсюда не виден"). :return: """ return super().app # type: ignore @@ -73,20 +78,40 @@ class SelectionWidget(Static): # Наследуем от Static def __init__(self, app_config: Optional[Dict[str, Any]] = None, - action_type=None, + action_type: Optional[str] = None, **kwargs): super().__init__(**kwargs) self.app_config = app_config if app_config is not None else {} - self.action_type = action_type # Сохраняем тип действия + self.overall_action_type = action_type # Сохраняем тип действия ("backup", "restore", "copy", "service") + self.current_step = 0 # Текущий шаг выбора (многоэтапный выбор), начинаем с 0 + self.selections: Dict[int, Any] = {} # Хранит выборы: {0: server_conf, 1: db_name, 2: dest_path} self._button_id_to_data_map: Dict[str, Any] = {} # Карта для хранения значений опций + logger.debug( + f"SelectionWidget initialized: action: '{self.overall_action_type}' / current_step: {self.current_step}" + ) + # SelectionWidget(Static) def compose(self) -> ComposeResult: - # options: List[Tuple[str, str]] = [] # Список опций для выбора - self._button_id_to_data_map.clear() # Очищаем карту значений - num_count = 1 - if self.action_type == "backup": - yield Label("Выберите BD-сервер для бэкапа:") + self._button_id_to_data_map.clear() # Очищаем карту значений + num_count = 1 # Для нумерации опций текущего шага + + # --- Отображение уже сделанных выборов --- + if self.current_step > 0 and 0 in self.selections: + server_conf = self.selections[0] + server_name = server_conf.get("name", "Неизвестный сервер") + yield Static(f"1. Сервер: {server_name}", classes="previous-selection") + + if self.current_step > 1 and 1 in self.selections: + db_name = self.selections[1] + yield Static(f"2. База данных: {db_name}", classes="previous-selection") + + if self.current_step > 2 and 2 in self.selections: # Если есть третий шаг и он сделан + dest_info = self.selections[2] # Может быть строка или словарь + yield Static(f"3. Назначение: {dest_info}", classes="previous-selection") + + if self.overall_action_type == "backup": + yield Label("Backup (DB\u2192Dump): Выберите BD-сервер:") # ... тут будет список серверов if "servers" in self.app_config: logger.info(f"TUI: Обнаружено {len(self.app_config['servers'])} серверов в конфигурации.") @@ -107,16 +132,16 @@ class SelectionWidget(Static): # Наследуем от Static self._button_id_to_data_map[button_id] = {"type": DB_FOR_BACKUP, "config": server_conf} num_count += 1 - elif self.action_type == "restore": + elif self.overall_action_type == "restore": yield Label("Выберите том для восстановления:") if "targets" in self.app_config: logger.info(f"TUI: Обнаружено {len(self.app_config['targets'])} томов в конфигурации.") yield Static("Тут будет список...", classes="placeholder-text") # Временная заглушка # ... тут будет список томов - elif self.action_type == "copy": + elif self.overall_action_type == "copy": yield Label("Выберите BD-сервер (откуда копировать):") # ... тут будет список серверов - elif self.action_type == "service": + elif self.overall_action_type == "service": yield Label("Служебные функции:") # ... тут будут служебные функции @@ -139,7 +164,7 @@ class SelectionWidget(Static): # Наследуем от Static except Exception as e: # except DOMQuery.DoesNotExist: logger.error(f"SelectionWidget: Ошибка при установке фокуса в Виджете: {e}") - # logger.warning(f"SelectionWidget: OptionList не найден для установки фокуса (action_type: {self.action_type}).") + # logger.warning(f"SelectionWidget: OptionList не найден для установки фокуса (overall_action_type: {self.overall_action_type}).") # Можно сразу установить фокус на первый элемент, если он есть # self.query_one(OptionList).focus() или self.query_one(Button).focus() @@ -149,14 +174,14 @@ class SelectionWidget(Static): # Наследуем от Static button_id = event.button.id button_data = self._button_id_to_data_map.get(button_id) # <--- Извлекаем данные по ID кнопки - logger.info(f"SelectionWidget ({self.action_type}): нажата кнопка-опция id='{button_id}', data={button_data}") + logger.info(f"SelectionWidget ({self.overall_action_type}): нажата кнопка-опция id='{button_id}', data={button_data}") if button_data: action_type_from_data = button_data.get("type") if action_type_from_data == DB_FOR_BACKUP: server_config = button_data.get("config") # <--- Получаем полную конфигурацию сервера logger.info( - f"SelectionWidget ({self.action_type}): выбран сервер {server_config.get('name') if isinstance(server_config, dict) else server_config}. Далее - выбор БД/дампа.") + f"SelectionWidget ({self.overall_action_type}): выбран сервер {server_config.get('name') if isinstance(server_config, dict) else server_config}. Далее - выбор БД/дампа.") # Тут будет логика для перехода к следующему шагу, используя server_config self.app.bell() # ... другие обработчики ...