Make every live edit reach the device, and warn when it doesn't
In live mode the device is now written first and the document only takes what the device accepted. Every live_hooks failure records a reason, and warn_failure() shows it in a dialog and the status bar instead of failing silently. - Move, properties, OX page editor: rejected values are rolled back and listed - Add/remove link: no longer edits the DOM alone when an end can't be resolved - Add/delete component: report why the device refused - Tidy Layout: sends each new position to the device, reverts refusals, marks the document dirty, and pushes no undo step in live mode - User Manager: add (one Sox add carrying cred/perm/prov), edit and delete now go to the device - Binary Buf slots (e.g. User.cred) are sent as Buf bytes, not as Str text - Bump version to 0.0.0.136 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+57
-3
@@ -17,6 +17,8 @@ from tkinter import font as tkfont, messagebox, ttk
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
import app_state
|
||||
import live_hooks
|
||||
import sax_file
|
||||
import undo
|
||||
from sax_dom import set_prop_value
|
||||
|
||||
@@ -425,9 +427,32 @@ class _UserDialog:
|
||||
def _apply_add(self, username, password):
|
||||
elem = ET.Element("comp", name=username, type="sys::User")
|
||||
cred = _hash_credentials(username, password)
|
||||
ET.SubElement(elem, "prop", name="cred", val=cred)
|
||||
ET.SubElement(elem, "prop", name="perm", val=str(self._perm_val))
|
||||
ET.SubElement(elem, "prop", name="prov", val=str(self._prov_val))
|
||||
values = {"cred": cred, "perm": str(self._perm_val), "prov": str(self._prov_val)}
|
||||
|
||||
if app_state.live_mode:
|
||||
# One Sox add carrying every config value, so the user never exists on the
|
||||
# device without its password and rights.
|
||||
try:
|
||||
config = sax_file.build_config_values("sys::User", values)
|
||||
except (ValueError, TypeError) as e:
|
||||
live_hooks.warn_failure("Add User", f"User '{username}' was not added to the device",
|
||||
f"A value does not fit its slot: {e}")
|
||||
return
|
||||
new_id = live_hooks.live_add_component(
|
||||
self._service_comp, "sys", "User", username, config)
|
||||
if new_id is None:
|
||||
live_hooks.warn_failure("Add User", f"User '{username}' was not added to the device")
|
||||
return
|
||||
elem.set("id", str(new_id))
|
||||
|
||||
for name, val in values.items():
|
||||
ET.SubElement(elem, "prop", name=name, val=val)
|
||||
|
||||
if app_state.live_mode:
|
||||
self._service_comp.append(elem)
|
||||
app_state.mark_dirty()
|
||||
app_state.set_status(f"User '{username}' added to device.")
|
||||
return
|
||||
|
||||
index = len(list(self._service_comp))
|
||||
cmd = undo.AddComponentCommand(self._service_comp, index, elem, label="add user")
|
||||
@@ -458,6 +483,25 @@ class _UserDialog:
|
||||
if not changes:
|
||||
return
|
||||
|
||||
if app_state.live_mode:
|
||||
failures = []
|
||||
for elem, prop, _old, new in changes:
|
||||
if live_hooks.live_set_prop_value(elem, prop, new):
|
||||
set_prop_value(elem, prop, new)
|
||||
app_state.mark_dirty()
|
||||
else:
|
||||
failures.append(f"{prop}: {live_hooks.last_error}")
|
||||
if failures:
|
||||
live_hooks.warn_failure(
|
||||
"Edit User",
|
||||
f"{len(failures)} of {len(changes)} change(s) to user '{username}' did "
|
||||
"not reach the device and were not applied",
|
||||
"\n".join(f" • {failure}" for failure in failures),
|
||||
)
|
||||
else:
|
||||
app_state.set_status(f"User '{username}' updated on device.")
|
||||
return
|
||||
|
||||
cmd = undo.SlotValueCommand(changes, label="edit user")
|
||||
cmd.redo()
|
||||
undo.push(cmd)
|
||||
@@ -593,6 +637,16 @@ class UserServicePanel:
|
||||
parent=self.frame.winfo_toplevel()):
|
||||
return
|
||||
|
||||
if app_state.live_mode:
|
||||
if not live_hooks.live_delete_component(user_elem):
|
||||
live_hooks.warn_failure("Delete User", f"User '{name}' was not deleted from the device")
|
||||
return
|
||||
self.comp.remove(user_elem)
|
||||
app_state.mark_dirty()
|
||||
app_state.set_status(f"User '{name}' deleted from device.")
|
||||
self._after_change()
|
||||
return
|
||||
|
||||
index = list(self.comp).index(user_elem)
|
||||
cmd = undo.AddComponentCommand(self.comp, index, user_elem, label="delete user")
|
||||
cmd.undo()
|
||||
|
||||
Reference in New Issue
Block a user