85 lines
3.9 KiB
Python
85 lines
3.9 KiB
Python
|
|
"""Сравнение пакетов между серверами."""
|
||
|
|
import flet as ft
|
||
|
|
|
||
|
|
from app.core import servers as servers_core
|
||
|
|
from app.core.diff import diff_servers
|
||
|
|
from app.core.ssh import SSHClient
|
||
|
|
from app.ui.components import snack
|
||
|
|
|
||
|
|
|
||
|
|
class DiffPage(ft.Column):
|
||
|
|
def __init__(self, page: ft.Page, go):
|
||
|
|
super().__init__(expand=True, scroll=ft.ScrollMode.AUTO, spacing=12)
|
||
|
|
self._page = page
|
||
|
|
servers = servers_core.list_servers()
|
||
|
|
opts = [ft.dropdown.Option(str(s.id), s.name) for s in servers]
|
||
|
|
|
||
|
|
self.dd_a = ft.Dropdown(label="Сервер A", options=opts, width=250)
|
||
|
|
self.dd_b = ft.Dropdown(label="Сервер B", options=opts, width=250)
|
||
|
|
self.user_only = ft.Checkbox(label="только пользовательские пакеты", value=True)
|
||
|
|
self.result = ft.Column(spacing=8)
|
||
|
|
|
||
|
|
self.controls = [
|
||
|
|
ft.Text("Сравнение серверов", size=28, weight=ft.FontWeight.BOLD),
|
||
|
|
ft.Row([
|
||
|
|
self.dd_a, self.dd_b, self.user_only,
|
||
|
|
ft.FilledButton("Сравнить", icon=ft.Icons.COMPARE_ARROWS,
|
||
|
|
on_click=self._compare),
|
||
|
|
]),
|
||
|
|
self.result,
|
||
|
|
]
|
||
|
|
|
||
|
|
def _compare(self, e):
|
||
|
|
if not self.dd_a.value or not self.dd_b.value or self.dd_a.value == self.dd_b.value:
|
||
|
|
snack(self._page, "Выберите два разных сервера", error=True)
|
||
|
|
return
|
||
|
|
self.result.controls = [ft.ProgressBar()]
|
||
|
|
self._page.update()
|
||
|
|
|
||
|
|
async def _do():
|
||
|
|
a = servers_core.get_server(int(self.dd_a.value))
|
||
|
|
b = servers_core.get_server(int(self.dd_b.value))
|
||
|
|
async with SSHClient(a) as ca, SSHClient(b) as cb:
|
||
|
|
diff = await diff_servers(ca, cb, self.user_only.value)
|
||
|
|
|
||
|
|
self.result.controls = [
|
||
|
|
ft.Row([
|
||
|
|
self._section(f"Только на {a.name} ({len(diff.only_a)})",
|
||
|
|
[f"{p.name} {p.version}" for p in diff.only_a],
|
||
|
|
ft.Colors.BLUE_300),
|
||
|
|
self._section(f"Только на {b.name} ({len(diff.only_b)})",
|
||
|
|
[f"{p.name} {p.version}" for p in diff.only_b],
|
||
|
|
ft.Colors.GREEN_300),
|
||
|
|
], vertical_alignment=ft.CrossAxisAlignment.START),
|
||
|
|
ft.Text(f"Различаются версии ({len(diff.version_mismatch)})",
|
||
|
|
weight=ft.FontWeight.BOLD, size=16),
|
||
|
|
ft.DataTable(columns=[
|
||
|
|
ft.DataColumn(ft.Text("Пакет")),
|
||
|
|
ft.DataColumn(ft.Text(a.name)),
|
||
|
|
ft.DataColumn(ft.Text(b.name)),
|
||
|
|
], rows=[
|
||
|
|
ft.DataRow(cells=[
|
||
|
|
ft.DataCell(ft.Text(m.name)),
|
||
|
|
ft.DataCell(ft.Text(m.version_a, size=12)),
|
||
|
|
ft.DataCell(ft.Text(m.version_b, size=12,
|
||
|
|
color=ft.Colors.ORANGE_300)),
|
||
|
|
]) for m in diff.version_mismatch[:100]
|
||
|
|
]) if diff.version_mismatch else ft.Text("версии совпадают",
|
||
|
|
color=ft.Colors.GREY_500),
|
||
|
|
]
|
||
|
|
self._page.update()
|
||
|
|
self._page.run_task(_do)
|
||
|
|
|
||
|
|
def _section(self, title, items, color):
|
||
|
|
return ft.Container(expand=True, content=ft.Column([
|
||
|
|
ft.Text(title, weight=ft.FontWeight.BOLD, color=color),
|
||
|
|
ft.Container(
|
||
|
|
height=300, border=ft.Border.all(1, ft.Colors.GREY_800),
|
||
|
|
border_radius=8, padding=8,
|
||
|
|
content=ft.Column([
|
||
|
|
ft.Text(i, size=11, font_family="Consolas") for i in items
|
||
|
|
] or [ft.Text("—", color=ft.Colors.GREY_600)],
|
||
|
|
scroll=ft.ScrollMode.AUTO, spacing=1),
|
||
|
|
),
|
||
|
|
]))
|