467 lines
18 KiB
Python
467 lines
18 KiB
Python
|
|
# ui/display.py - 所有 Rich 表格 / 面板展示函数
|
||
|
|
|
||
|
|
import os
|
||
|
|
from typing import Dict, List
|
||
|
|
|
||
|
|
from rich.console import Console
|
||
|
|
from rich.panel import Panel
|
||
|
|
from rich.rule import Rule
|
||
|
|
from rich.table import Table
|
||
|
|
|
||
|
|
import config
|
||
|
|
from constants import CHG_TYPE_LABEL, CHG_TYPE_COLOR
|
||
|
|
from database.models import (
|
||
|
|
ChangeHistory, FunctionalRequirement, Project,
|
||
|
|
)
|
||
|
|
|
||
|
|
console = Console()
|
||
|
|
|
||
|
|
|
||
|
|
def print_banner() -> None:
|
||
|
|
console.print()
|
||
|
|
console.print(Panel.fit(
|
||
|
|
"[bold cyan]🚀 需求分析 & 代码生成工具[/bold cyan]\n"
|
||
|
|
"[dim]Powered by LLM · SQLite · Python[/dim]",
|
||
|
|
border_style="cyan",
|
||
|
|
))
|
||
|
|
console.print()
|
||
|
|
|
||
|
|
|
||
|
|
def print_main_menu() -> None:
|
||
|
|
console.print(Rule("[bold cyan]主菜单[/bold cyan]"))
|
||
|
|
menu_items = [
|
||
|
|
("1", "📁 新建项目", "输入需求 → 分解 → 生成代码"),
|
||
|
|
("2", "🔄 变更项目需求", "变更已有需求 / 变更模块需求 / 新增需求"),
|
||
|
|
("3", "📋 查看所有项目", "列表展示全部项目"),
|
||
|
|
("4", "🔍 查看项目详情", "需求列表 / 模块分组 / 变更历史"),
|
||
|
|
("5", "🗑 删除指定项目", "删除项目及其所有数据"),
|
||
|
|
("0", "🚪 退出", ""),
|
||
|
|
]
|
||
|
|
table = Table(show_header=False, box=None, padding=(0, 2))
|
||
|
|
table.add_column("选项", style="bold yellow", width=4)
|
||
|
|
table.add_column("功能", style="bold", width=22)
|
||
|
|
table.add_column("说明", style="dim", width=38)
|
||
|
|
for key, name, desc in menu_items:
|
||
|
|
table.add_row(f"[{key}]", name, desc)
|
||
|
|
console.print(table)
|
||
|
|
console.print()
|
||
|
|
|
||
|
|
|
||
|
|
def print_projects_table(projects: List[Project]) -> None:
|
||
|
|
if not projects:
|
||
|
|
console.print("[yellow] 暂无项目记录。[/yellow]")
|
||
|
|
return
|
||
|
|
table = Table(title="📋 项目列表", show_lines=True)
|
||
|
|
table.add_column("ID", style="cyan", width=6)
|
||
|
|
table.add_column("项目名", style="bold", width=22)
|
||
|
|
table.add_column("语言", style="magenta", width=12)
|
||
|
|
table.add_column("描述", width=35)
|
||
|
|
table.add_column("输出目录", style="dim", width=30)
|
||
|
|
for p in projects:
|
||
|
|
desc = p.description or ""
|
||
|
|
table.add_row(
|
||
|
|
str(p.id), p.name, p.language or "-",
|
||
|
|
desc[:40] + ("..." if len(desc) > 40 else ""),
|
||
|
|
p.output_dir or "-",
|
||
|
|
)
|
||
|
|
console.print(table)
|
||
|
|
|
||
|
|
|
||
|
|
def print_functional_requirements(reqs: List[FunctionalRequirement]) -> None:
|
||
|
|
if not reqs:
|
||
|
|
console.print("[yellow] 暂无功能需求。[/yellow]")
|
||
|
|
return
|
||
|
|
priority_color = {"high": "red", "medium": "yellow", "low": "green"}
|
||
|
|
status_color = {
|
||
|
|
"pending": "yellow",
|
||
|
|
"generated": "green",
|
||
|
|
"failed": "red",
|
||
|
|
"deleted": "dim",
|
||
|
|
}
|
||
|
|
table = Table(title="📋 功能需求列表", show_lines=True)
|
||
|
|
table.add_column("序号", style="cyan", width=6)
|
||
|
|
table.add_column("ID", style="dim", width=6)
|
||
|
|
table.add_column("模块", style="magenta", width=15)
|
||
|
|
table.add_column("标题", style="bold", width=18)
|
||
|
|
table.add_column("函数名", width=25)
|
||
|
|
table.add_column("优先级", width=8)
|
||
|
|
table.add_column("状态", width=10)
|
||
|
|
table.add_column("描述", width=35)
|
||
|
|
for req in reqs:
|
||
|
|
pc = priority_color.get(req.priority, "white")
|
||
|
|
sc = status_color.get(req.status, "white")
|
||
|
|
desc = req.description
|
||
|
|
table.add_row(
|
||
|
|
str(req.index_no),
|
||
|
|
str(req.id) if req.id else "-",
|
||
|
|
req.module or config.DEFAULT_MODULE,
|
||
|
|
req.title,
|
||
|
|
f"[code]{req.function_name}[/code]",
|
||
|
|
f"[{pc}]{req.priority}[/{pc}]",
|
||
|
|
f"[{sc}]{req.status}[/{sc}]",
|
||
|
|
desc[:40] + "..." if len(desc) > 40 else desc,
|
||
|
|
)
|
||
|
|
console.print(table)
|
||
|
|
|
||
|
|
|
||
|
|
def print_module_summary(reqs: List[FunctionalRequirement]) -> None:
|
||
|
|
module_map: Dict[str, List[str]] = {}
|
||
|
|
for req in reqs:
|
||
|
|
if req.status == "deleted":
|
||
|
|
continue
|
||
|
|
m = req.module or config.DEFAULT_MODULE
|
||
|
|
module_map.setdefault(m, []).append(req.function_name)
|
||
|
|
table = Table(title="📦 功能模块分组", show_lines=True)
|
||
|
|
table.add_column("模块", style="magenta bold", width=20)
|
||
|
|
table.add_column("函数数量", style="cyan", width=8)
|
||
|
|
table.add_column("函数列表", width=50)
|
||
|
|
for module, funcs in sorted(module_map.items()):
|
||
|
|
table.add_row(module, str(len(funcs)), ", ".join(funcs))
|
||
|
|
console.print(table)
|
||
|
|
|
||
|
|
|
||
|
|
def print_module_list(reqs: List[FunctionalRequirement]) -> List[str]:
|
||
|
|
"""打印带序号的模块列表(跳过已删除需求),返回有序模块名列表。"""
|
||
|
|
module_map: Dict[str, List[FunctionalRequirement]] = {}
|
||
|
|
for req in reqs:
|
||
|
|
if req.status == "deleted":
|
||
|
|
continue
|
||
|
|
m = req.module or config.DEFAULT_MODULE
|
||
|
|
module_map.setdefault(m, []).append(req)
|
||
|
|
|
||
|
|
table = Table(title="📦 模块列表", show_lines=True)
|
||
|
|
table.add_column("序号", style="cyan", width=6)
|
||
|
|
table.add_column("模块名", style="magenta bold", width=22)
|
||
|
|
table.add_column("需求数量", style="yellow", width=8)
|
||
|
|
table.add_column("包含函数", width=45)
|
||
|
|
|
||
|
|
modules = sorted(module_map.keys())
|
||
|
|
for i, module in enumerate(modules, 1):
|
||
|
|
funcs = [r.function_name for r in module_map[module]]
|
||
|
|
table.add_row(str(i), module, str(len(funcs)), ", ".join(funcs))
|
||
|
|
console.print(table)
|
||
|
|
return modules
|
||
|
|
|
||
|
|
|
||
|
|
def print_signatures_preview(signatures: List[dict]) -> None:
|
||
|
|
table = Table(title="📄 函数签名预览", show_lines=True)
|
||
|
|
table.add_column("需求编号", style="cyan", width=8)
|
||
|
|
table.add_column("模块", style="magenta", width=15)
|
||
|
|
table.add_column("函数名", style="bold", width=22)
|
||
|
|
table.add_column("参数数", width=6)
|
||
|
|
table.add_column("返回类型", width=10)
|
||
|
|
table.add_column("URL", style="dim", width=28)
|
||
|
|
for sig in signatures:
|
||
|
|
ret = sig.get("return") or {}
|
||
|
|
url = sig.get("url", "")
|
||
|
|
url_display = os.path.basename(url) if url else "[dim]待生成[/dim]"
|
||
|
|
table.add_row(
|
||
|
|
sig.get("requirement_id", "-"),
|
||
|
|
sig.get("module", "-"),
|
||
|
|
sig.get("name", "-"),
|
||
|
|
str(len(sig.get("parameters", {}))),
|
||
|
|
ret.get("type", "void"),
|
||
|
|
url_display,
|
||
|
|
)
|
||
|
|
console.print(table)
|
||
|
|
|
||
|
|
|
||
|
|
def print_change_history(histories: List[ChangeHistory]) -> None:
|
||
|
|
"""以表格形式展示变更历史,含变更类型、模块、需求 ID 等字段。"""
|
||
|
|
if not histories:
|
||
|
|
console.print("[dim] 暂无变更历史。[/dim]")
|
||
|
|
return
|
||
|
|
table = Table(title="🕒 变更历史", show_lines=True)
|
||
|
|
table.add_column("ID", style="cyan", width=6)
|
||
|
|
table.add_column("时间", style="dim", width=20)
|
||
|
|
table.add_column("变更类型", width=14)
|
||
|
|
table.add_column("模块", width=16)
|
||
|
|
table.add_column("需求ID", width=8)
|
||
|
|
table.add_column("变更摘要", width=50)
|
||
|
|
for h in histories:
|
||
|
|
ct = getattr(h, "change_type", "") or ""
|
||
|
|
label = CHG_TYPE_LABEL.get(ct, ct)
|
||
|
|
color = CHG_TYPE_COLOR.get(ct, "white")
|
||
|
|
mod = getattr(h, "module", "") or "-"
|
||
|
|
rid = str(getattr(h, "req_id", "") or "-")
|
||
|
|
ts = str(getattr(h, "created_at", "-"))
|
||
|
|
summary = h.changes
|
||
|
|
if len(summary) > 60:
|
||
|
|
summary = summary[:60] + "..."
|
||
|
|
table.add_row(
|
||
|
|
str(h.id), ts,
|
||
|
|
f"[{color}]{label}[/{color}]",
|
||
|
|
mod, rid, summary,
|
||
|
|
)
|
||
|
|
console.print(table)
|
||
|
|
|
||
|
|
|
||
|
|
def print_req_diff(
|
||
|
|
old_reqs: List[FunctionalRequirement],
|
||
|
|
new_reqs: List[FunctionalRequirement],
|
||
|
|
) -> None:
|
||
|
|
"""并排展示新旧需求对比表格。"""
|
||
|
|
console.print()
|
||
|
|
console.print(Rule("[bold]新旧需求对比[/bold]"))
|
||
|
|
|
||
|
|
old_table = Table(
|
||
|
|
title="❌ 旧需求(将被替换)", show_lines=True, border_style="red",
|
||
|
|
)
|
||
|
|
old_table.add_column("ID", style="dim", width=6)
|
||
|
|
old_table.add_column("标题", style="bold", width=18)
|
||
|
|
old_table.add_column("函数名", width=22)
|
||
|
|
old_table.add_column("描述", width=30)
|
||
|
|
for r in old_reqs:
|
||
|
|
old_table.add_row(
|
||
|
|
str(r.id), r.title, r.function_name,
|
||
|
|
r.description[:30] + "..." if len(r.description) > 30 else r.description,
|
||
|
|
)
|
||
|
|
console.print(old_table)
|
||
|
|
|
||
|
|
new_table = Table(
|
||
|
|
title="✅ 新需求(将被创建)", show_lines=True, border_style="green",
|
||
|
|
)
|
||
|
|
new_table.add_column("序号", style="cyan", width=6)
|
||
|
|
new_table.add_column("标题", style="bold", width=18)
|
||
|
|
new_table.add_column("函数名", width=22)
|
||
|
|
new_table.add_column("描述", width=30)
|
||
|
|
for r in new_reqs:
|
||
|
|
new_table.add_row(
|
||
|
|
str(r.index_no), r.title, r.function_name,
|
||
|
|
r.description[:30] + "..." if len(r.description) > 30 else r.description,
|
||
|
|
)
|
||
|
|
console.print(new_table)
|
||
|
|
console.print()# ui/display.py - 所有 Rich 表格 / 面板展示函数
|
||
|
|
|
||
|
|
import os
|
||
|
|
from typing import Dict, List
|
||
|
|
|
||
|
|
from rich.console import Console
|
||
|
|
from rich.panel import Panel
|
||
|
|
from rich.rule import Rule
|
||
|
|
from rich.table import Table
|
||
|
|
|
||
|
|
import config
|
||
|
|
from constants import CHG_TYPE_LABEL, CHG_TYPE_COLOR
|
||
|
|
from database.models import (
|
||
|
|
ChangeHistory, FunctionalRequirement, Project,
|
||
|
|
)
|
||
|
|
|
||
|
|
console = Console()
|
||
|
|
|
||
|
|
|
||
|
|
def print_banner() -> None:
|
||
|
|
console.print()
|
||
|
|
console.print(Panel.fit(
|
||
|
|
"[bold cyan]🚀 需求分析 & 代码生成工具[/bold cyan]\n"
|
||
|
|
"[dim]Powered by LLM · SQLite · Python[/dim]",
|
||
|
|
border_style="cyan",
|
||
|
|
))
|
||
|
|
console.print()
|
||
|
|
|
||
|
|
|
||
|
|
def print_main_menu() -> None:
|
||
|
|
console.print(Rule("[bold cyan]主菜单[/bold cyan]"))
|
||
|
|
menu_items = [
|
||
|
|
("1", "📁 新建项目", "输入需求 → 分解 → 生成代码"),
|
||
|
|
("2", "🔄 变更项目需求", "变更已有需求 / 变更模块需求 / 新增需求"),
|
||
|
|
("3", "📋 查看所有项目", "列表展示全部项目"),
|
||
|
|
("4", "🔍 查看项目详情", "需求列表 / 模块分组 / 变更历史"),
|
||
|
|
("5", "🗑 删除指定项目", "删除项目及其所有数据"),
|
||
|
|
("0", "🚪 退出", ""),
|
||
|
|
]
|
||
|
|
table = Table(show_header=False, box=None, padding=(0, 2))
|
||
|
|
table.add_column("选项", style="bold yellow", width=4)
|
||
|
|
table.add_column("功能", style="bold", width=22)
|
||
|
|
table.add_column("说明", style="dim", width=38)
|
||
|
|
for key, name, desc in menu_items:
|
||
|
|
table.add_row(f"[{key}]", name, desc)
|
||
|
|
console.print(table)
|
||
|
|
console.print()
|
||
|
|
|
||
|
|
|
||
|
|
def print_projects_table(projects: List[Project]) -> None:
|
||
|
|
if not projects:
|
||
|
|
console.print("[yellow] 暂无项目记录。[/yellow]")
|
||
|
|
return
|
||
|
|
table = Table(title="📋 项目列表", show_lines=True)
|
||
|
|
table.add_column("ID", style="cyan", width=6)
|
||
|
|
table.add_column("项目名", style="bold", width=22)
|
||
|
|
table.add_column("语言", style="magenta", width=12)
|
||
|
|
table.add_column("描述", width=35)
|
||
|
|
table.add_column("输出目录", style="dim", width=30)
|
||
|
|
for p in projects:
|
||
|
|
desc = p.description or ""
|
||
|
|
table.add_row(
|
||
|
|
str(p.id), p.name, p.language or "-",
|
||
|
|
desc[:40] + ("..." if len(desc) > 40 else ""),
|
||
|
|
p.output_dir or "-",
|
||
|
|
)
|
||
|
|
console.print(table)
|
||
|
|
|
||
|
|
|
||
|
|
def print_functional_requirements(reqs: List[FunctionalRequirement]) -> None:
|
||
|
|
if not reqs:
|
||
|
|
console.print("[yellow] 暂无功能需求。[/yellow]")
|
||
|
|
return
|
||
|
|
priority_color = {"high": "red", "medium": "yellow", "low": "green"}
|
||
|
|
status_color = {
|
||
|
|
"pending": "yellow",
|
||
|
|
"generated": "green",
|
||
|
|
"failed": "red",
|
||
|
|
"deleted": "dim",
|
||
|
|
}
|
||
|
|
table = Table(title="📋 功能需求列表", show_lines=True)
|
||
|
|
table.add_column("序号", style="cyan", width=6)
|
||
|
|
table.add_column("ID", style="dim", width=6)
|
||
|
|
table.add_column("模块", style="magenta", width=15)
|
||
|
|
table.add_column("标题", style="bold", width=18)
|
||
|
|
table.add_column("函数名", width=25)
|
||
|
|
table.add_column("优先级", width=8)
|
||
|
|
table.add_column("状态", width=10)
|
||
|
|
table.add_column("描述", width=35)
|
||
|
|
for req in reqs:
|
||
|
|
pc = priority_color.get(req.priority, "white")
|
||
|
|
sc = status_color.get(req.status, "white")
|
||
|
|
desc = req.description
|
||
|
|
table.add_row(
|
||
|
|
str(req.index_no),
|
||
|
|
str(req.id) if req.id else "-",
|
||
|
|
req.module or config.DEFAULT_MODULE,
|
||
|
|
req.title,
|
||
|
|
f"[code]{req.function_name}[/code]",
|
||
|
|
f"[{pc}]{req.priority}[/{pc}]",
|
||
|
|
f"[{sc}]{req.status}[/{sc}]",
|
||
|
|
desc[:40] + "..." if len(desc) > 40 else desc,
|
||
|
|
)
|
||
|
|
console.print(table)
|
||
|
|
|
||
|
|
|
||
|
|
def print_module_summary(reqs: List[FunctionalRequirement]) -> None:
|
||
|
|
module_map: Dict[str, List[str]] = {}
|
||
|
|
for req in reqs:
|
||
|
|
if req.status == "deleted":
|
||
|
|
continue
|
||
|
|
m = req.module or config.DEFAULT_MODULE
|
||
|
|
module_map.setdefault(m, []).append(req.function_name)
|
||
|
|
table = Table(title="📦 功能模块分组", show_lines=True)
|
||
|
|
table.add_column("模块", style="magenta bold", width=20)
|
||
|
|
table.add_column("函数数量", style="cyan", width=8)
|
||
|
|
table.add_column("函数列表", width=50)
|
||
|
|
for module, funcs in sorted(module_map.items()):
|
||
|
|
table.add_row(module, str(len(funcs)), ", ".join(funcs))
|
||
|
|
console.print(table)
|
||
|
|
|
||
|
|
|
||
|
|
def print_module_list(reqs: List[FunctionalRequirement]) -> List[str]:
|
||
|
|
"""打印带序号的模块列表(跳过已删除需求),返回有序模块名列表。"""
|
||
|
|
module_map: Dict[str, List[FunctionalRequirement]] = {}
|
||
|
|
for req in reqs:
|
||
|
|
if req.status == "deleted":
|
||
|
|
continue
|
||
|
|
m = req.module or config.DEFAULT_MODULE
|
||
|
|
module_map.setdefault(m, []).append(req)
|
||
|
|
|
||
|
|
table = Table(title="📦 模块列表", show_lines=True)
|
||
|
|
table.add_column("序号", style="cyan", width=6)
|
||
|
|
table.add_column("模块名", style="magenta bold", width=22)
|
||
|
|
table.add_column("需求数量", style="yellow", width=8)
|
||
|
|
table.add_column("包含函数", width=45)
|
||
|
|
|
||
|
|
modules = sorted(module_map.keys())
|
||
|
|
for i, module in enumerate(modules, 1):
|
||
|
|
funcs = [r.function_name for r in module_map[module]]
|
||
|
|
table.add_row(str(i), module, str(len(funcs)), ", ".join(funcs))
|
||
|
|
console.print(table)
|
||
|
|
return modules
|
||
|
|
|
||
|
|
|
||
|
|
def print_signatures_preview(signatures: List[dict]) -> None:
|
||
|
|
table = Table(title="📄 函数签名预览", show_lines=True)
|
||
|
|
table.add_column("需求编号", style="cyan", width=8)
|
||
|
|
table.add_column("模块", style="magenta", width=15)
|
||
|
|
table.add_column("函数名", style="bold", width=22)
|
||
|
|
table.add_column("参数数", width=6)
|
||
|
|
table.add_column("返回类型", width=10)
|
||
|
|
table.add_column("URL", style="dim", width=28)
|
||
|
|
for sig in signatures:
|
||
|
|
ret = sig.get("return") or {}
|
||
|
|
url = sig.get("url", "")
|
||
|
|
url_display = os.path.basename(url) if url else "[dim]待生成[/dim]"
|
||
|
|
table.add_row(
|
||
|
|
sig.get("requirement_id", "-"),
|
||
|
|
sig.get("module", "-"),
|
||
|
|
sig.get("name", "-"),
|
||
|
|
str(len(sig.get("parameters", {}))),
|
||
|
|
ret.get("type", "void"),
|
||
|
|
url_display,
|
||
|
|
)
|
||
|
|
console.print(table)
|
||
|
|
|
||
|
|
|
||
|
|
def print_change_history(histories: List[ChangeHistory]) -> None:
|
||
|
|
"""以表格形式展示变更历史,含变更类型、模块、需求 ID 等字段。"""
|
||
|
|
if not histories:
|
||
|
|
console.print("[dim] 暂无变更历史。[/dim]")
|
||
|
|
return
|
||
|
|
table = Table(title="🕒 变更历史", show_lines=True)
|
||
|
|
table.add_column("ID", style="cyan", width=6)
|
||
|
|
table.add_column("时间", style="dim", width=20)
|
||
|
|
table.add_column("变更类型", width=14)
|
||
|
|
table.add_column("模块", width=16)
|
||
|
|
table.add_column("需求ID", width=8)
|
||
|
|
table.add_column("变更摘要", width=50)
|
||
|
|
for h in histories:
|
||
|
|
ct = getattr(h, "change_type", "") or ""
|
||
|
|
label = CHG_TYPE_LABEL.get(ct, ct)
|
||
|
|
color = CHG_TYPE_COLOR.get(ct, "white")
|
||
|
|
mod = getattr(h, "module", "") or "-"
|
||
|
|
rid = str(getattr(h, "req_id", "") or "-")
|
||
|
|
ts = str(getattr(h, "created_at", "-"))
|
||
|
|
summary = h.changes
|
||
|
|
if len(summary) > 60:
|
||
|
|
summary = summary[:60] + "..."
|
||
|
|
table.add_row(
|
||
|
|
str(h.id), ts,
|
||
|
|
f"[{color}]{label}[/{color}]",
|
||
|
|
mod, rid, summary,
|
||
|
|
)
|
||
|
|
console.print(table)
|
||
|
|
|
||
|
|
|
||
|
|
def print_req_diff(
|
||
|
|
old_reqs: List[FunctionalRequirement],
|
||
|
|
new_reqs: List[FunctionalRequirement],
|
||
|
|
) -> None:
|
||
|
|
"""并排展示新旧需求对比表格。"""
|
||
|
|
console.print()
|
||
|
|
console.print(Rule("[bold]新旧需求对比[/bold]"))
|
||
|
|
|
||
|
|
old_table = Table(
|
||
|
|
title="❌ 旧需求(将被替换)", show_lines=True, border_style="red",
|
||
|
|
)
|
||
|
|
old_table.add_column("ID", style="dim", width=6)
|
||
|
|
old_table.add_column("标题", style="bold", width=18)
|
||
|
|
old_table.add_column("函数名", width=22)
|
||
|
|
old_table.add_column("描述", width=30)
|
||
|
|
for r in old_reqs:
|
||
|
|
old_table.add_row(
|
||
|
|
str(r.id), r.title, r.function_name,
|
||
|
|
r.description[:30] + "..." if len(r.description) > 30 else r.description,
|
||
|
|
)
|
||
|
|
console.print(old_table)
|
||
|
|
|
||
|
|
new_table = Table(
|
||
|
|
title="✅ 新需求(将被创建)", show_lines=True, border_style="green",
|
||
|
|
)
|
||
|
|
new_table.add_column("序号", style="cyan", width=6)
|
||
|
|
new_table.add_column("标题", style="bold", width=18)
|
||
|
|
new_table.add_column("函数名", width=22)
|
||
|
|
new_table.add_column("描述", width=30)
|
||
|
|
for r in new_reqs:
|
||
|
|
new_table.add_row(
|
||
|
|
str(r.index_no), r.title, r.function_name,
|
||
|
|
r.description[:30] + "..." if len(r.description) > 30 else r.description,
|
||
|
|
)
|
||
|
|
console.print(new_table)
|
||
|
|
console.print()
|