Merge pull request 'fix(silo): fix auth crashes, menu redundancy, and origin connect' (#1) from fix/silo-workbench-bugs into main

Reviewed-on: #1
This commit was merged in pull request #1.
This commit is contained in:
2026-02-07 20:33:25 +00:00
3 changed files with 50 additions and 46 deletions

View File

@@ -44,14 +44,23 @@ class SiloWorkbench(FreeCADGui.Workbench):
"Silo_Commit",
"Silo_Pull",
"Silo_Push",
]
# Menu has management/admin commands (file commands are in File menu
# via the Create module's SiloMenuManipulator)
self.menu_commands = [
"Silo_Info",
"Silo_BOM",
"Silo_TagProjects",
"Silo_SetStatus",
"Silo_Rollback",
"Separator",
"Silo_Settings",
"Silo_Auth",
]
self.appendToolbar("Silo", self.toolbar_commands)
self.appendMenu("Silo", self.toolbar_commands)
self.appendMenu("Silo", self.menu_commands)
def Activated(self):
"""Called when workbench is activated."""
@@ -67,7 +76,9 @@ class SiloWorkbench(FreeCADGui.Workbench):
def _show_shortcut_recommendations(self):
"""Show keyboard shortcut recommendations dialog on first activation."""
try:
param_group = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/KindredSilo")
param_group = FreeCAD.ParamGet(
"User parameter:BaseApp/Preferences/Mod/KindredSilo"
)
if param_group.GetBool("ShortcutsShown", False):
return
param_group.SetBool("ShortcutsShown", True)

View File

@@ -106,6 +106,10 @@ def _get_auth_source() -> str:
return param.GetString("AuthSource", "")
def _get_auth_token() -> str:
return _fc_settings.get_api_token()
# Thin wrappers so command classes can call these without refactoring.
# They delegate to the settings adapter or the shared client.
@@ -848,9 +852,6 @@ class Silo_Save:
# Check if document has unsaved changes
gui_doc = FreeCADGui.getDocument(doc.Name)
is_modified = gui_doc.Modified if gui_doc else True
FreeCAD.Console.PrintMessage(
f"[DEBUG] Modified={is_modified}, FileName={doc.FileName}\n"
)
if gui_doc and not is_modified and doc.FileName:
FreeCAD.Console.PrintMessage("No changes to save.\n")
@@ -858,17 +859,9 @@ class Silo_Save:
# Collect properties BEFORE saving to avoid dirtying the document
# (accessing Shape properties can trigger recompute)
FreeCAD.Console.PrintMessage("[DEBUG] Collecting properties...\n")
properties = collect_document_properties(doc)
# Check modified state after collecting properties
is_modified_after_props = gui_doc.Modified if gui_doc else True
FreeCAD.Console.PrintMessage(
f"[DEBUG] After collect_properties: Modified={is_modified_after_props}\n"
)
# Save locally
FreeCAD.Console.PrintMessage("[DEBUG] Saving to canonical path...\n")
file_path = _sync.save_to_canonical_path(doc, force_rename=True)
if not file_path:
# Fallback to regular save if canonical path fails
@@ -879,24 +872,12 @@ class Silo_Save:
FreeCAD.Console.PrintError("Could not determine save path\n")
return
# Check modified state after save
is_modified_after_save = gui_doc.Modified if gui_doc else True
FreeCAD.Console.PrintMessage(
f"[DEBUG] After save: Modified={is_modified_after_save}\n"
)
# Force clear modified flag if save succeeded (needed for assemblies)
if is_modified_after_save and gui_doc:
FreeCAD.Console.PrintMessage(
"[DEBUG] Attempting to clear Modified flag...\n"
)
if gui_doc and gui_doc.Modified:
try:
gui_doc.Modified = False
FreeCAD.Console.PrintMessage(
f"[DEBUG] After force clear: Modified={gui_doc.Modified}\n"
)
except Exception as e:
FreeCAD.Console.PrintMessage(f"[DEBUG] Could not clear Modified: {e}\n")
except Exception:
pass
FreeCAD.Console.PrintMessage(f"Saved: {file_path}\n")
@@ -909,12 +890,6 @@ class Silo_Save:
new_rev = result["revision_number"]
FreeCAD.Console.PrintMessage(f"Uploaded as revision {new_rev}\n")
# Check modified state after upload
is_modified_after_upload = gui_doc.Modified if gui_doc else True
FreeCAD.Console.PrintMessage(
f"[DEBUG] After upload: Modified={is_modified_after_upload}\n"
)
except Exception as e:
FreeCAD.Console.PrintWarning(f"Upload failed: {e}\n")
FreeCAD.Console.PrintMessage("File saved locally but not uploaded.\n")
@@ -2675,9 +2650,9 @@ class SiloAuthDockWidget:
self._url_label.setText(_get_api_url())
has_token = _client.is_authenticated()
username = _client.auth_username()
role = _client.auth_role()
source = _client.auth_source()
username = _get_auth_username()
role = _get_auth_role()
source = _get_auth_source()
# Check server connectivity
try:

View File

@@ -15,10 +15,10 @@ import FreeCADGui
from .silo_commands import (
_client,
_sync,
collect_document_properties,
find_file_by_part_number,
get_tracked_object,
set_silo_properties,
find_file_by_part_number,
collect_document_properties,
)
@@ -126,19 +126,35 @@ class SiloOrigin:
def connect(self) -> bool:
"""Trigger authentication if needed.
Shows the Silo authentication dialog if not already authenticated.
Shows the Silo login dialog if not already authenticated.
Returns:
True if authenticated after this call
"""
if _client.is_authenticated():
return True
try:
ok, _ = _client.check_connection()
if ok:
return True
except Exception:
pass
# Show auth dialog via existing Silo_Auth command
# Show login dialog directly
try:
cmd = FreeCADGui.Command.get("Silo_Auth")
if cmd:
cmd.Activated()
from PySide import QtWidgets
mw = FreeCADGui.getMainWindow()
if mw is None:
return False
# Find or create the auth dock widget and trigger its login dialog
panel = mw.findChild(QtWidgets.QDockWidget, "SiloDatabaseAuth")
if panel and hasattr(panel, "_auth"):
panel._auth._show_login_dialog()
else:
# Fallback: run the Settings command so the user can configure
FreeCADGui.runCommand("Silo_Settings")
return _client.is_authenticated()
except Exception as e:
FreeCAD.Console.PrintError(f"Silo connect failed: {e}\n")
@@ -379,7 +395,9 @@ class SiloOrigin:
# Upload to Silo
properties = collect_document_properties(doc)
_client._upload_file(obj.SiloPartNumber, str(file_path), properties, comment="")
_client._upload_file(
obj.SiloPartNumber, str(file_path), properties, comment=""
)
# Clear modified flag
doc.Modified = False