Added uploads, part renaming, bulk data import acceptance

This commit is contained in:
2025-12-17 13:57:47 +11:00
parent aaa1f7520a
commit ae9e1d6e7e
14 changed files with 3325 additions and 11 deletions

View File

@@ -15,10 +15,175 @@ from apis.digikey_api import suggest_category_from_digikey
# ------------ Pages ------------
class HomePage(ttk.Frame):
"""Always listening; on scan -> ask Part-DB; route to View or Create."""
"""Home page with tools and settings."""
def __init__(self, master, app):
super().__init__(master)
self.app = app
ttk.Label(self, text="Part-DB Helper", font=("Segoe UI", 16, "bold")).pack(pady=(18,8))
# Settings section
settings_frame = ttk.LabelFrame(self, text="Settings", padding=10)
settings_frame.pack(fill="x", padx=20, pady=(0,10))
# Mode toggle (Live/Dry Run)
mode_frame = ttk.Frame(settings_frame)
mode_frame.pack(fill="x", pady=2)
ttk.Label(mode_frame, text="Standardization Mode:", width=20).pack(side="left")
self.mode_var = tk.StringVar(value="live")
ttk.Radiobutton(mode_frame, text="Live (Make Changes)", variable=self.mode_var, value="live").pack(side="left", padx=5)
ttk.Radiobutton(mode_frame, text="Dry Run (Preview Only)", variable=self.mode_var, value="dry").pack(side="left", padx=5)
# Provider update toggle
provider_frame = ttk.Frame(settings_frame)
provider_frame.pack(fill="x", pady=2)
ttk.Label(provider_frame, text="Provider Updates:", width=20).pack(side="left")
self.provider_var = tk.BooleanVar(value=True)
ttk.Checkbutton(provider_frame, text="Update from information providers (Digi-Key, etc.)", variable=self.provider_var).pack(side="left", padx=5)
# Tools section
ttk.Separator(self, orient="horizontal").pack(fill="x", pady=10, padx=20)
ttk.Label(self, text="Tools", font=("Segoe UI", 14, "bold")).pack(pady=(0,10))
tools_frame = ttk.Frame(self)
tools_frame.pack(pady=(0,10))
ttk.Button(tools_frame, text="Scanner", command=self.goto_scanner, width=25).pack(pady=4)
ttk.Button(tools_frame, text="Accept Import Jobs", command=self.run_accept_jobs, width=25).pack(pady=4)
ttk.Button(tools_frame, text="Run Bulk Add", command=self.run_bulk_add, width=25).pack(pady=4)
ttk.Button(tools_frame, text="Import from CSV Files", command=self.run_import_csv, width=25).pack(pady=4)
ttk.Button(tools_frame, text="Update Components", command=self.run_standardize_components, width=25).pack(pady=4)
def goto_scanner(self):
"""Navigate to scanner page."""
self.app.goto_scanner()
def run_accept_jobs(self):
"""Launch the accept import jobs automation in a new thread."""
from workflows.accept_import_jobs import run_accept_import_jobs
def work():
run_accept_import_jobs(auto_close=True)
t = threading.Thread(target=work, daemon=True)
t.start()
messagebox.showinfo("Started", "Import job acceptance automation started in browser.\nCheck the browser window for progress.")
def run_bulk_add(self):
"""Launch the bulk add workflow."""
from workflows.bulk_add import run_bulk_add
def work():
run_bulk_add()
t = threading.Thread(target=work, daemon=True)
t.start()
messagebox.showinfo("Started", "Bulk add workflow started in browser.\nCheck the browser window for progress.")
def run_import_csv(self):
"""Launch the CSV import workflow."""
update_providers = self.provider_var.get()
from workflows.import_from_csv import run_import_from_csv
from ui.progress_dialog import ProgressDialog
# Create progress dialog
progress = ProgressDialog(self.app, "Importing from CSV")
def progress_callback(current, total, status):
progress.update(current, total, status)
return progress.is_cancelled()
def work():
try:
run_import_from_csv(update_providers=update_providers, progress_callback=progress_callback)
finally:
progress.close()
# Show completion message
self.app.after(0, lambda: messagebox.showinfo("Import Complete", "CSV import finished!\nCheck console for details."))
t = threading.Thread(target=work, daemon=True)
t.start()
def run_standardize_components(self):
"""Launch the component standardization workflow."""
dry_run = (self.mode_var.get() == "dry")
from workflows.standardize_components import run_standardize_components
from ui.progress_dialog import ProgressDialog
# Create progress dialog - self.app is the Tk root
progress = ProgressDialog(self.app, "Standardizing Components")
def progress_callback(current, total, status):
progress.update(current, total, status)
return progress.is_cancelled()
def work():
try:
run_standardize_components(dry_run=dry_run, progress_callback=progress_callback)
finally:
progress.close()
t = threading.Thread(target=work, daemon=True)
t.start()
def run_standardize_passives(self):
"""Launch the passive components standardization workflow."""
dry_run = (self.mode_var.get() == "dry")
from workflows.standardize_passives import run_standardize_passives
from ui.progress_dialog import ProgressDialog
# Create progress dialog - self.app is the Tk root
progress = ProgressDialog(self.app, "Standardizing Passives")
def progress_callback(current, total, status):
progress.update(current, total, status)
return progress.is_cancelled()
def work():
try:
run_standardize_passives(category_name="Passives", dry_run=dry_run, progress_callback=progress_callback)
finally:
progress.close()
t = threading.Thread(target=work, daemon=True)
t.start()
def run_standardize_asdmb(self):
"""Launch the ASDMB crystal standardization workflow."""
dry_run = (self.mode_var.get() == "dry")
provider_update = self.provider_var.get() and not dry_run
from workflows.standardize_asdmb import run_standardize_asdmb
from ui.progress_dialog import ProgressDialog
# Create progress dialog - self.app is the Tk root
progress = ProgressDialog(self.app, "Standardizing ASDMB Crystals")
def progress_callback(current, total, status):
progress.update(current, total, status)
return progress.is_cancelled()
def work():
try:
run_standardize_asdmb(category_name="Clock - ASDMB", dry_run=dry_run, update_providers=provider_update, progress_callback=progress_callback)
finally:
progress.close()
t = threading.Thread(target=work, daemon=True)
t.start()
class ScannerPage(ttk.Frame):
"""Scanner page for scanning Digi-Key labels."""
def __init__(self, master, app):
super().__init__(master)
self.app = app
# Back button
ttk.Button(self, text="← Back to Home", command=self.app.goto_home).pack(anchor="w", padx=10, pady=10)
ttk.Label(self, text="Scan a Digi-Key code", font=("Segoe UI", 16, "bold")).pack(pady=(18,8))
ttk.Label(self, text=f"Listening on {COM_PORT} @ {BAUD_RATE}").pack(pady=(0,12))
@@ -29,7 +194,7 @@ class HomePage(ttk.Frame):
ttk.Entry(wrap, textvariable=self.last_var, state="readonly").pack(side="left", fill="x", expand=True, padx=(8,0))
ttk.Label(self, text="(This page listens continuously. Just scan another label.)", foreground="#666").pack()
def on_scan(self, raw: str):
self.last_var.set(raw)
fields = parse_digikey(raw)
@@ -50,6 +215,7 @@ class HomePage(ttk.Frame):
# No part -> prepare creation
self.app.goto_create(fields, raw)
class ViewPage(ttk.Frame):
"""Shows existing part summary + button to force Digi-Key provider update."""
def __init__(self, master, app):
@@ -275,10 +441,11 @@ class App(tk.Tk):
self.pdb = PartDB(PARTDB_BASE, PARTDB_TOKEN)
self.home = HomePage(self, self)
self.scanner = ScannerPage(self, self)
self.view = ViewPage(self, self)
self.create = CreatePage(self, self)
for f in (self.home, self.view, self.create):
for f in (self.home, self.scanner, self.view, self.create):
f.grid(row=0, column=0, sticky="nsew")
# start listening thread once
@@ -290,10 +457,13 @@ class App(tk.Tk):
def on_scan(self, flat: str):
if self.busy:
return # ignore scans during provider update
self.home.on_scan(flat)
self.scanner.on_scan(flat)
def goto_home(self):
self.home.tkraise()
def goto_scanner(self):
self.scanner.tkraise()
def goto_view(self, summary: dict):
self.view.set_summary(summary)