04/24 Added import website in bulk

This commit is contained in:
2026-04-24 13:57:49 -04:00
parent 5f2a4e4749
commit 88b5e85c5b
7 changed files with 567 additions and 33 deletions
+144 -4
View File
@@ -375,6 +375,20 @@ class AiSummaryView(ttk.Frame):
).pack(side="left", padx=(0, 4))
self._criteria_tree.bind("<Double-1>",
lambda _: self._open_edit_criterion())
else:
# User (read-only): provide a View Details button and double-click binding
btn_bar = tk.Frame(self._criteria_card, bg=C["surface"], pady=4)
btn_bar.pack(fill="x")
tk.Button(
btn_bar, text="👁 View Details",
command=self._open_view_criterion,
bg=C["surface2"], fg=C["text"],
activebackground=C["accent"], activeforeground=C["white"],
relief="flat", font=FONT_SMALL, cursor="hand2",
padx=8, pady=3,
).pack(side="left", padx=(0, 4))
self._criteria_tree.bind("<Double-1>",
lambda _: self._open_view_criterion())
tk.Label(
self._criteria_card,
@@ -444,6 +458,27 @@ class AiSummaryView(ttk.Frame):
CriterionDialog(self, self.current_user,
criterion_data=data, on_save=self._load_criteria_tree)
def _open_view_criterion(self):
"""Open a read-only detail dialog for the selected criterion (user role)."""
cid = self._get_selected_criterion_id()
if not cid:
show_error("Please select a criterion to view.")
return
try:
from models import get_all_criteria
all_rows = {r["id"]: r for r in get_all_criteria()}
data = all_rows.get(cid)
except Exception as e:
show_error(f"Could not load criterion: {e}")
return
if not data:
show_error("Criterion not found.")
return
logger.info(
f"Criterion id={cid} viewed by user_id={self.current_user['id']}."
)
CriterionDetailDialog(self, data)
def _delete_criterion(self):
cid = self._get_selected_criterion_id()
if not cid:
@@ -1194,6 +1229,109 @@ class AiSummaryView(ttk.Frame):
# Criterion Add / Edit Dialog (admin only)
# ------------------------------------------------------------------------------
class CriterionDetailDialog(tk.Toplevel):
"""Read-only modal dialog that displays the full details of an AI evaluation criterion.
Shown to regular users who click 'View Details' or double-click a row in the
criteria treeview. Admins continue to use CriterionDialog (edit mode) instead.
"""
def __init__(self, parent, criterion_data: dict):
super().__init__(parent)
self._data = criterion_data
self.title("Criterion Details")
self.configure(bg=COLOURS["bg"])
self.resizable(False, False)
self.grab_set()
self._build_ui()
self._centre()
def _centre(self):
self.update_idletasks()
w, h = 560, 380
x = (self.winfo_screenwidth() - w) // 2
y = (self.winfo_screenheight() - h) // 2
self.geometry(f"{w}x{h}+{x}+{y}")
def _build_ui(self):
C = COLOURS
d = self._data
# ── Header ────────────────────────────────────────────────────────────
hdr = tk.Frame(self, bg=C["surface"], padx=24, pady=14)
hdr.pack(fill="x")
status_text = "Active" if d.get("is_active") else "Inactive"
status_color = C["accent"] if d.get("is_active") else C["danger"]
tk.Label(
hdr,
text=d.get("title") or "Untitled",
bg=C["surface"], fg=C["text"],
font=FONT_HEADING, wraplength=480, justify="left",
).pack(anchor="w")
meta_row = tk.Frame(hdr, bg=C["surface"])
meta_row.pack(anchor="w", pady=(4, 0))
tk.Label(
meta_row,
text=f"Sort order: {d.get('sort_order', 0)}",
bg=C["surface"], fg=C["text_dim"],
font=FONT_SMALL,
).pack(side="left")
tk.Label(
meta_row, text=" · ",
bg=C["surface"], fg=C["text_dim"],
font=FONT_SMALL,
).pack(side="left")
tk.Label(
meta_row, text=status_text,
bg=C["surface"], fg=status_color,
font=FONT_SMALL,
).pack(side="left")
ttk.Separator(self, orient="horizontal").pack(fill="x", padx=0)
# ── Description (scrollable, read-only) ───────────────────────────────
body = tk.Frame(self, bg=C["bg"], padx=24, pady=16)
body.pack(fill="both", expand=True)
tk.Label(
body, text="Description",
bg=C["bg"], fg=C["text_dim"],
font=FONT_SMALL,
).pack(anchor="w", pady=(0, 4))
txt_frame = tk.Frame(body, bg=C["surface2"])
txt_frame.pack(fill="both", expand=True)
vsb = ttk.Scrollbar(txt_frame, orient="vertical")
vsb.pack(side="right", fill="y")
txt = tk.Text(
txt_frame, wrap="word",
bg=C["surface2"], fg=C["text"],
relief="flat", font=FONT,
state="normal",
yscrollcommand=vsb.set,
padx=10, pady=8,
)
txt.insert("1.0", d.get("description") or "No description provided.")
txt.config(state="disabled") # read-only after inserting content
txt.pack(fill="both", expand=True)
vsb.config(command=txt.yview)
# ── Footer ────────────────────────────────────────────────────────────
ttk.Separator(self, orient="horizontal").pack(fill="x")
footer = ttk.Frame(self)
footer.pack(fill="x", padx=24, pady=12)
ttk.Button(
footer, text="Close",
command=self.destroy,
).pack(side="right")
class CriterionDialog(tk.Toplevel):
"""Modal dialog for creating or editing an AI evaluation criterion."""
@@ -1207,14 +1345,16 @@ class CriterionDialog(tk.Toplevel):
self.title("Edit Criterion" if self.is_edit else "Add Criterion")
self.configure(bg=COLOURS["bg"])
self.resizable(False, False)
self.resizable(False, True) # allow vertical resize for varied DPI/fonts
self.grab_set()
self._build_ui()
self._centre()
def _centre(self):
self.update_idletasks()
w, h = 560, 400
# Height increased to 520 so buttons are always visible at standard DPI.
# The dialog is vertically resizable so higher-DPI systems can expand it.
w, h = 560, 520
x = (self.winfo_screenwidth() - w) // 2
y = (self.winfo_screenheight() - h) // 2
self.geometry(f"{w}x{h}+{x}+{y}")
@@ -1250,7 +1390,7 @@ class CriterionDialog(tk.Toplevel):
desc_vsb = ttk.Scrollbar(desc_frame, orient="vertical")
desc_vsb.pack(side="right", fill="y")
self._desc_txt = tk.Text(
desc_frame, height=6, wrap="word",
desc_frame, height=5, wrap="word",
bg=C["surface2"], fg=C["text"],
insertbackground=C["text"],
relief="flat", font=FONT,
@@ -1545,4 +1685,4 @@ def _human_size(n: int) -> str:
if n < 1024:
return f"{n:.0f} {unit}"
n /= 1024
return f"{n:.1f} GB"
return f"{n:.1f} GB"