Stage 06.2 - system settings navigation and product information screens
This commit is contained in:
@@ -1,2 +1,4 @@
|
||||
# app/src/core/constants.py
|
||||
|
||||
APP_NAME = "Dzentra Bot"
|
||||
APP_VERSION = "2.0.0"
|
||||
@@ -183,8 +183,8 @@ def build_system_text(*, include_updated_at: bool = False) -> str:
|
||||
|
||||
text = (
|
||||
"<b>🖥️ Система</b>\n"
|
||||
f"🔸 <b>{snapshot.mode_label}</b>\n"
|
||||
f"⏱️ {snapshot.timezone_name}\n\n"
|
||||
f"🔸 <b>{snapshot.mode_label}</b>\n\n"
|
||||
# f"⏱️ {snapshot.timezone_name}\n\n"
|
||||
f"{components_block}"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
# app/src/telegram/handlers/auto.py
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from aiogram import F, Router
|
||||
from aiogram.fsm.context import FSMContext
|
||||
from aiogram.types import Message
|
||||
from aiogram.types import CallbackQuery, InlineKeyboardMarkup, Message
|
||||
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||||
|
||||
from src.telegram.menus import AUTO_TEXT
|
||||
|
||||
@@ -10,8 +13,37 @@ from src.telegram.menus import AUTO_TEXT
|
||||
router = Router(name="auto")
|
||||
|
||||
|
||||
@router.message(F.text == "🤖 Авто")
|
||||
def _auto_keyboard() -> InlineKeyboardMarkup:
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.button(text="🛠️ Настройки", callback_data="settings:auto")
|
||||
builder.adjust(1)
|
||||
return builder.as_markup()
|
||||
|
||||
|
||||
async def _render_auto_screen(
|
||||
target_message: Message,
|
||||
*,
|
||||
edit_mode: bool,
|
||||
) -> None:
|
||||
if edit_mode:
|
||||
await target_message.edit_text(AUTO_TEXT, reply_markup=_auto_keyboard())
|
||||
else:
|
||||
await target_message.answer(AUTO_TEXT, reply_markup=_auto_keyboard())
|
||||
|
||||
|
||||
@router.message(F.text.in_({"🤖 Автоторговля", "🤖 Авто"}))
|
||||
async def open_auto(message: Message, state: FSMContext) -> None:
|
||||
# Глобальный экран: всегда выходим из текущего FSM-сценария.
|
||||
await state.clear()
|
||||
await message.answer(AUTO_TEXT)
|
||||
await _render_auto_screen(message, edit_mode=False)
|
||||
|
||||
|
||||
@router.callback_query(F.data == "auto:home")
|
||||
async def open_auto_from_callback(callback: CallbackQuery, state: FSMContext) -> None:
|
||||
await state.clear()
|
||||
|
||||
if callback.message is None:
|
||||
await callback.answer("Сообщение не найдено", show_alert=True)
|
||||
return
|
||||
|
||||
await _render_auto_screen(callback.message, edit_mode=True)
|
||||
await callback.answer()
|
||||
@@ -8,6 +8,8 @@ from aiogram.types import CallbackQuery, InlineKeyboardMarkup, Message
|
||||
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||||
|
||||
from src.core.system_status import build_system_text, get_system_snapshot, has_system_alerts
|
||||
from src.core.config import load_settings
|
||||
from src.core.constants import APP_NAME, APP_VERSION
|
||||
from src.trading.journal.service import JournalService
|
||||
|
||||
|
||||
@@ -161,6 +163,77 @@ async def open_system_management(callback: CallbackQuery) -> None:
|
||||
await callback.answer()
|
||||
|
||||
|
||||
@router.callback_query(F.data == "settings:auto")
|
||||
async def open_auto_settings(callback: CallbackQuery) -> None:
|
||||
if callback.message is None:
|
||||
await callback.answer("Сообщение не найдено", show_alert=True)
|
||||
return
|
||||
|
||||
text = (
|
||||
"<b>🤖 Автоторговля</b>\n\n"
|
||||
"<b>СИСТЕМА</b> · Настройки\n\n"
|
||||
"Статус: —\n"
|
||||
"Стратегия: —\n"
|
||||
"Риск: —\n\n"
|
||||
"В разработке."
|
||||
)
|
||||
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.button(text="⬅️ Назад", callback_data="system:management")
|
||||
builder.button(text="🤖 Автоторговля", callback_data="auto:home")
|
||||
builder.adjust(2)
|
||||
|
||||
await callback.message.edit_text(text, reply_markup=builder.as_markup())
|
||||
await callback.answer()
|
||||
|
||||
|
||||
@router.callback_query(F.data == "settings:trade")
|
||||
async def open_trade_settings(callback: CallbackQuery) -> None:
|
||||
if callback.message is None:
|
||||
await callback.answer("Сообщение не найдено", show_alert=True)
|
||||
return
|
||||
|
||||
text = (
|
||||
"<b>📊 Торговля</b>\n\n"
|
||||
"<b>СИСТЕМА</b> · Настройки\n\n"
|
||||
"Инструмент: —\n"
|
||||
"Тип ордера по умолчанию: —\n"
|
||||
"Пресеты количества: —\n\n"
|
||||
"В разработке."
|
||||
)
|
||||
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.button(text="⬅️ Назад", callback_data="system:management")
|
||||
builder.button(text="📊 Торговля", callback_data="trade:home")
|
||||
builder.adjust(2)
|
||||
|
||||
await callback.message.edit_text(text, reply_markup=builder.as_markup())
|
||||
await callback.answer()
|
||||
|
||||
|
||||
@router.callback_query(F.data == "settings:general")
|
||||
async def open_general_settings(callback: CallbackQuery) -> None:
|
||||
if callback.message is None:
|
||||
await callback.answer("Сообщение не найдено", show_alert=True)
|
||||
return
|
||||
|
||||
text = (
|
||||
"<b>🌍 Общие</b>\n\n"
|
||||
"<b>СИСТЕМА</b> · Настройки\n\n"
|
||||
"Режим аккаунта: —\n"
|
||||
"Часовой пояс: —\n"
|
||||
"Язык интерфейса: ru\n\n"
|
||||
"В разработке."
|
||||
)
|
||||
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.button(text="⬅️ Назад", callback_data="system:management")
|
||||
builder.adjust(1)
|
||||
|
||||
await callback.message.edit_text(text, reply_markup=builder.as_markup())
|
||||
await callback.answer()
|
||||
|
||||
|
||||
@router.callback_query(F.data == "settings:journal")
|
||||
async def open_journal_settings(callback: CallbackQuery) -> None:
|
||||
if callback.message is None:
|
||||
@@ -184,7 +257,7 @@ async def open_journal_settings(callback: CallbackQuery) -> None:
|
||||
builder.button(text="🗄 Архив", callback_data="settings:journal_archive")
|
||||
builder.button(text="📦 Лимит", callback_data="settings:journal_limit")
|
||||
builder.button(text="⏳ Хранение", callback_data="settings:journal_retention")
|
||||
builder.button(text="⬅️ Назад", callback_data="system:control")
|
||||
builder.button(text="⬅️ Назад", callback_data="system:management")
|
||||
builder.button(text="📒 Журнал", callback_data="journal:1")
|
||||
builder.adjust(2, 2, 2)
|
||||
|
||||
@@ -195,6 +268,88 @@ async def open_journal_settings(callback: CallbackQuery) -> None:
|
||||
await callback.answer()
|
||||
|
||||
|
||||
@router.callback_query(F.data == "settings:journal_archive")
|
||||
async def open_journal_archive_settings(callback: CallbackQuery) -> None:
|
||||
if callback.message is None:
|
||||
await callback.answer("Сообщение не найдено", show_alert=True)
|
||||
return
|
||||
|
||||
text = (
|
||||
"<b>🗄 Архив</b>\n\n"
|
||||
"<b>СИСТЕМА</b> · Настройки · Журнал\n\n"
|
||||
"Автоматический архив журнала: —\n"
|
||||
"Формат архива: —\n"
|
||||
"Периодичность: —\n\n"
|
||||
"В разработке."
|
||||
)
|
||||
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.button(text="⬅️ Назад", callback_data="settings:journal")
|
||||
builder.button(text="📒 Журнал", callback_data="journal:1")
|
||||
builder.adjust(2)
|
||||
|
||||
await callback.message.edit_text(text, reply_markup=builder.as_markup())
|
||||
await callback.answer()
|
||||
|
||||
|
||||
@router.callback_query(F.data == "settings:journal_limit")
|
||||
async def open_journal_limit_settings(callback: CallbackQuery) -> None:
|
||||
if callback.message is None:
|
||||
await callback.answer("Сообщение не найдено", show_alert=True)
|
||||
return
|
||||
|
||||
text = (
|
||||
"<b>📦 Лимит</b>\n\n"
|
||||
"<b>СИСТЕМА</b> · Настройки · Журнал\n\n"
|
||||
"Текущий лимит: —\n\n"
|
||||
"Доступные варианты:"
|
||||
)
|
||||
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.button(text="1 000", callback_data="settings:journal_limit_stub")
|
||||
builder.button(text="5 000", callback_data="settings:journal_limit_stub")
|
||||
builder.button(text="10 000", callback_data="settings:journal_limit_stub")
|
||||
builder.button(text="∞", callback_data="settings:journal_limit_stub")
|
||||
builder.button(text="⬅️ Назад", callback_data="settings:journal")
|
||||
builder.adjust(2, 2, 1)
|
||||
|
||||
await callback.message.edit_text(text, reply_markup=builder.as_markup())
|
||||
await callback.answer()
|
||||
|
||||
|
||||
@router.callback_query(F.data == "settings:journal_retention")
|
||||
async def open_journal_retention_settings(callback: CallbackQuery) -> None:
|
||||
if callback.message is None:
|
||||
await callback.answer("Сообщение не найдено", show_alert=True)
|
||||
return
|
||||
|
||||
text = (
|
||||
"<b>⏳ Хранение</b>\n\n"
|
||||
"<b>СИСТЕМА</b> · Настройки · Журнал\n\n"
|
||||
"Текущий срок хранения: —\n\n"
|
||||
"Доступные варианты:"
|
||||
)
|
||||
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.button(text="7 дней", callback_data="settings:journal_retention_stub")
|
||||
builder.button(text="30 дней", callback_data="settings:journal_retention_stub")
|
||||
builder.button(text="90 дней", callback_data="settings:journal_retention_stub")
|
||||
builder.button(text="∞", callback_data="settings:journal_retention_stub")
|
||||
builder.button(text="⬅️ Назад", callback_data="settings:journal")
|
||||
builder.adjust(2, 2, 1)
|
||||
|
||||
await callback.message.edit_text(text, reply_markup=builder.as_markup())
|
||||
await callback.answer()
|
||||
|
||||
|
||||
@router.callback_query(F.data.in_({
|
||||
"settings:journal_limit_stub",
|
||||
"settings:journal_retention_stub",
|
||||
}))
|
||||
async def journal_settings_stub(callback: CallbackQuery) -> None:
|
||||
await callback.answer("Настройка скоро появится", show_alert=True)
|
||||
|
||||
|
||||
@router.callback_query(F.data == "system:back")
|
||||
async def back_to_system(callback: CallbackQuery) -> None:
|
||||
if callback.message is None:
|
||||
@@ -216,4 +371,39 @@ async def back_to_system(callback: CallbackQuery) -> None:
|
||||
|
||||
@router.callback_query(F.data == "system:about")
|
||||
async def open_system_about(callback: CallbackQuery) -> None:
|
||||
await callback.answer("О продукте скоро появится")
|
||||
if callback.message is None:
|
||||
await callback.answer("Сообщение не найдено", show_alert=True)
|
||||
return
|
||||
|
||||
settings = load_settings()
|
||||
journal = JournalService()
|
||||
|
||||
journal.log_ui_info(
|
||||
event_type="system_about_opened",
|
||||
message="Открыта информация о продукте.",
|
||||
screen="system",
|
||||
action="about",
|
||||
user_id=callback.from_user.id if callback.from_user else None,
|
||||
chat_id=callback.message.chat.id if callback.message.chat else None,
|
||||
)
|
||||
|
||||
text = (
|
||||
"<b>ℹ️ Информация</b>\n\n"
|
||||
"<b>СИСТЕМА</b>\n\n"
|
||||
f"<b>{APP_NAME}</b>\n"
|
||||
f"Версия: {APP_VERSION}\n"
|
||||
f"Режим: {'DEMO' if 'demo' in settings.exchange_base_url.lower() else 'LIVE'}\n"
|
||||
f"Часовой пояс: {settings.tz}\n\n"
|
||||
"Торговый Telegram-бот для контроля рынка, портфеля, журнала событий "
|
||||
"и будущей автоторговли."
|
||||
)
|
||||
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.button(text="⬅️ Назад", callback_data="system:back")
|
||||
builder.adjust(1)
|
||||
|
||||
await callback.message.edit_text(
|
||||
text,
|
||||
reply_markup=builder.as_markup(),
|
||||
)
|
||||
await callback.answer()
|
||||
@@ -33,7 +33,7 @@ def _trade_home_keyboard() -> InlineKeyboardMarkup:
|
||||
builder.button(text="📝 Ордер", callback_data="trade:new_order")
|
||||
builder.button(text="📂 Ордера", callback_data="trade:orders")
|
||||
builder.button(text="📜 История", callback_data="trade:history")
|
||||
builder.button(text="⚙️ Настройки", callback_data="trade:settings")
|
||||
builder.button(text="🛠️ Настройки", callback_data="settings:trade")
|
||||
builder.adjust(2, 2)
|
||||
return builder.as_markup()
|
||||
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
# 0014 — System Navigation and Journal Settings
|
||||
|
||||
## Решение
|
||||
Вынести журнал и системные настройки в отдельный раздел “Система” с многоуровневой навигацией.
|
||||
|
||||
## Причины
|
||||
- разгрузить главное меню
|
||||
- разделить operational UI и settings UI
|
||||
- упростить масштабирование новых системных экранов
|
||||
|
||||
## Последствия
|
||||
- появляется единый navigation pattern
|
||||
- журнал становится отдельным subsystem
|
||||
- проще расширять настройки
|
||||
17
docs/decisions/0014-system-settings-navigation.md
Normal file
17
docs/decisions/0014-system-settings-navigation.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# 0014 — System settings as centralized navigation hub
|
||||
|
||||
## Решение
|
||||
|
||||
Все настройки продукта централизуются через экран Система → Настройки.
|
||||
|
||||
## Причины
|
||||
|
||||
- единая точка входа
|
||||
|
||||
- масштабируемость
|
||||
|
||||
- понятная UX-структура
|
||||
|
||||
## Последствия
|
||||
|
||||
- все разделы получают связку экран ↔ настройки
|
||||
@@ -76,7 +76,9 @@
|
||||
✔ system navigation redesign
|
||||
|
||||
### 06.2
|
||||
⏳ archive / backup
|
||||
✔ system settings navigation
|
||||
✔ product information screen
|
||||
✔ settings stubs
|
||||
|
||||
### 06.3
|
||||
⏳ retention / limits
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
# Stage 06.2 — System Settings Navigation and Product Information
|
||||
|
||||
## Что сделано
|
||||
|
||||
### 1. Экран ℹ️ Информация
|
||||
Добавлен полноценный экран информации о продукте.
|
||||
|
||||
Показывает:
|
||||
- название продукта
|
||||
- версия
|
||||
- режим работы (DEMO / LIVE)
|
||||
- timezone
|
||||
- описание продукта
|
||||
|
||||
---
|
||||
|
||||
### 2. Новый navigation pattern
|
||||
|
||||
Добавлена двусторонняя навигация:
|
||||
|
||||
СИСТЕМА ↔ НАСТРОЙКИ ↔ ЭКРАНЫ
|
||||
|
||||
Реализовано для:
|
||||
|
||||
- 🤖 Автоторговля
|
||||
- 📊 Торговля
|
||||
- 📒 Журнал
|
||||
|
||||
---
|
||||
|
||||
### 3. Настройки Журнала
|
||||
|
||||
Добавлены отдельные экраны:
|
||||
|
||||
- 🗑 Очистка
|
||||
- 🗄 Архив
|
||||
- 📦 Лимит
|
||||
- ⏳ Хранение
|
||||
|
||||
---
|
||||
|
||||
### 4. Заглушки настроек
|
||||
|
||||
Созданы шаблонные экраны:
|
||||
|
||||
#### 🤖 Автоторговля
|
||||
- статус
|
||||
- стратегия
|
||||
- риск
|
||||
|
||||
#### 📊 Торговля
|
||||
- инструмент
|
||||
- тип ордера
|
||||
- пресеты количества
|
||||
|
||||
#### 🌍 Общие
|
||||
- режим
|
||||
- timezone
|
||||
- язык
|
||||
|
||||
---
|
||||
|
||||
### 5. Обновление UI
|
||||
|
||||
Убран timezone с главного экрана Система.
|
||||
|
||||
Экран стал компактнее.
|
||||
|
||||
---
|
||||
|
||||
## Commit
|
||||
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "Stage 06.2 - system settings navigation and product information screens"
|
||||
Reference in New Issue
Block a user