From 353130225ed303bcedad1404c985c6be216b0a43 Mon Sep 17 00:00:00 2001 From: Benjamin Labrecque Date: Thu, 9 Jul 2026 09:52:41 +0200 Subject: [PATCH 01/27] ui: add service manager --- qt/A_BD_ServiceManager.ui | 1325 +++++++++++++++++++++++++++++++++ qt/A_BD_ServiceManager_inc.ui | 754 +++++++++++++++++++ 2 files changed, 2079 insertions(+) create mode 100644 qt/A_BD_ServiceManager.ui create mode 100644 qt/A_BD_ServiceManager_inc.ui diff --git a/qt/A_BD_ServiceManager.ui b/qt/A_BD_ServiceManager.ui new file mode 100644 index 0000000..9d8b5ec --- /dev/null +++ b/qt/A_BD_ServiceManager.ui @@ -0,0 +1,1325 @@ + + + MainWindow + + + + 0 + 0 + 1320 + 595 + + + + MainWindow + + + /*################################################*/ +/*# Settings for new templates/forms #*/ +/*################################################*/ +QMainWindow#MainWindow, QWidget#Form, QDialog#Dialog{ + background: rgba(236, 236, 236, 255); +} + +QMainWindow#MainWindow[transparent=true], QWidget#Form[transparent=true], QDialog#Dialog[transparent=true]{ + background: rgba(0, 0, 0, 0); +} + +/*-----------------------------------------------*/ +/* Title */ +/*-----------------------------------------------*/ +/* Operation panels */ +caLabel[statusTip="Operation"]{ + color: rgba(0, 0, 0, 255); + font: bold 18pt; + font-family: Sans Serif; + padding: 1px; + margin: 0px; + qproperty-alignment: AlignLeft; + qproperty-frameShape: StyledPanel; + /*qproperty-geometry: rect(-2 0 1600 33);*/ + background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, + stop:0 rgba(218, 218, 218, 255), + stop:0.5 rgba(200, 200, 200, 255), + stop:1 rgba(218, 218, 218, 255)); +} + + QGroupBox { + background: rgba(225,225,225,255); + border: 2px solid black; + border-radius: 5px; + margin-top: 1ex; /* leave space at the top for the title */ + } + + + + + + 1530 + 150 + 121 + 20 + + + + Reload + + + RELOAD + + + A + + + AGEBD-ALH:MASTER-GUIRELOAD + + + caCalc::TriggerZeroToOne + + + + + + 1580 + 220 + 70 + 20 + + + + + + + 1529 + 120 + 121 + 20 + + + + CONTROL-ONOFF + + + CONTROL-ONOFF + + + !A + + + AGEBD-ALH:MASTER-ONOFF + + + + + + 0 + 146 + 1320 + 450 + + + + QTabWidget::South + + + 0 + + + + Required Services + + + + + 0 + 0 + 1319 + 420 + + + + IOC=AGEBD-CPCL-DBPM3CURR,service=DBPM3CURR,name=DBPM3Current,panel=1,svc_exist=1,panelcmd=A_BD_DBPM3Current.ui;IOC=AGEBD-CPCL-TAUBPM,service=TAUBPM,name=LifetimeBPM,panel=1,svc_exist=1,panelcmd=A_BD_LifetimeBPM.ui;IOC=AGEBD-CPCL-TAUPCT,service=TAUPCT,name=LifetimePCT,panel=1,svc_exist=1,panelcmd=A_BD_LifetimePCT.ui;IOC=AGEBD-CPCL-TIMING,service=TIMING,name=Timing,panel=1,svc_exist=1,panelcmd=A_BD_Timing.ui;IOC=AGEBD-CPCL-SCRUBBING,service=SCRUBBING,name=Scrubbing,panel=1,svc_exist=1,panelcmd=A_BD_Scrubbing.ui;IOC=AGEBD-CPCL-INJECTIONGUARD,service=INJECTIONGUARD,name=InjectionGuard,panel=1,svc_exist=1,panelcmd=A_BD_InjectionGuard.ui;IOC=AGEBD-CPCL-POSTMORTEMLOG,service=POSTMORTEMLOG,name=PostMortemLog,panel=1,svc_exist=1,panelcmd=A_BD_PostMortemLog.ui;IOC=AGEBD-CPCL-TUNEBUMP,service=TUNEBUMP,name=TuneBump,panel=1,svc_exist=1,panelcmd=A_BD_TuneBump.ui;IOC=AGEBD-CPCL-PLOTS,service=PLOTS,name=Plots,panel=0,svc_exist=1,panelcmd=A_BD_Plots.ui;IOC=AGEBD-CPCL-ORBITBUMP,service=ORBITBUMP,name=OrbitBump,panel=1,svc_exist=0,panelcmd=A_BD_OrbitBump.ui;IOC=AGEBD-CPCL-TUNEFBX,service=TUNEFBX,name=Hor. Tune Feedback,panel=1,svc_exist=1,panelcmd=A_BD_TuneBump.ui;IOC=AGEBD-CPCL-TUNEFBY,service=TUNEFBY,name=Ver. Tune Feedback,panel=1,svc_exist=1,panelcmd=A_BD_TuneBump.ui + + + A_BD_ServiceManager_inc.ui + + + 12 + + + true + + + 2 + + + + + + 7580 + 0 + 20 + 351 + + + + Qt::Vertical + + + + + + Optional Services + + + + + 1178 + 0 + 20 + 90 + + + + Qt::Vertical + + + + + + 328 + 0 + 20 + 90 + + + + Qt::Vertical + + + + + + 758 + -2 + 20 + 90 + + + + Qt::Vertical + + + + + + 108 + 0 + 20 + 90 + + + + Qt::Vertical + + + + + + 558 + -2 + 20 + 90 + + + + Qt::Vertical + + + + + + 0 + 0 + 1320 + 371 + + + + IOC=AGEBD-CPCL-NTURNS,service=NTURNS,name=NTurns,panel=1,svc_exist=1,panelcmd=A_BD_NTurns.ui;IOC=AGEBD-CPCL-TOPUPTOOL,service=TOPUPTOOL,name=TopUpTool,panel=1,svc_exist=1,panelcmd=A_BD_TopUpTool.ui;IOC=AGEBD-CPCL-TUNE,service=TUNE,name=Tune,panel=1,svc_exist=1,panelcmd=A_BD_Tune.ui;IOC=AGEOP-CPCL-SHIFTTOOL,service=SHIFTTOOL,name=Shifttool,panel=1,svc_exist=1,panelcmd=A_OP_SchichtProtokollTool.ui,macro=FACILITY=SLS + + + A_BD_ServiceManager_inc.ui + + + 4 + + + 2 + + + + + + + + 779 + 60 + 181 + 40 + + + + + 16 + 75 + true + + + + Started + + + Qt::AlignCenter + + + ESimpleLabel::None + + + + + + 1080 + 60 + 101 + 40 + + + + + 16 + 75 + true + + + + Status + + + Qt::AlignCenter + + + ESimpleLabel::None + + + + + + 970 + 60 + 100 + 40 + + + + + 16 + 75 + true + + + + Version + + + Qt::AlignCenter + + + ESimpleLabel::None + + + + + + 1190 + 60 + 130 + 40 + + + + + 16 + 75 + true + + + + Panel + + + Qt::AlignCenter + + + ESimpleLabel::None + + + + + + 129 + 60 + 201 + 40 + + + + + 16 + 75 + true + + + + Service + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + ESimpleLabel::None + + + + + + 620 + 60 + 101 + 40 + + + + + 16 + 75 + true + + + + Pause + + + Qt::AlignCenter + + + ESimpleLabel::None + + + + + + 580 + 60 + 28 + 31 + + + + + 8 + 75 + true + + + + Alive + + + caLabelVertical::Up + + + + + + 10 + 60 + 101 + 40 + + + + + 16 + 75 + true + + + + IOC + + + Qt::AlignCenter + + + ESimpleLabel::None + + + + + + 340 + 60 + 201 + 40 + + + + + 16 + 75 + true + + + + Qt::LeftToRight + + + Systemd + + + Qt::PlainText + + + Qt::AlignCenter + + + ESimpleLabel::None + + + + + + 730 + 60 + 28 + 31 + + + + + 6 + 75 + true + + + + Active + + + caLabelVertical::Up + + + + + + 1203 + 110 + 30 + 30 + + + + + 183 + 157 + 92 + + + + P + + + A_BD_Master.ui + + + + + + + + + 580 + 110 + 30 + 30 + + + + + 0 + 0 + + + + + 0 + 0 + + + + true + + + false + + + 28 + + + 28 + + + true + + + false + + + AGEBD-ALH:MASTER-ALIVE + + + caLed::Alarm + + + + + + 780 + 110 + 180 + 30 + + + + AGEBD-ALH:MASTER-STARTTIME + + + caLineEdit::Default + + + caLineEdit::onBackground + + + caLineEdit::User + + + + + + 1080 + 110 + 100 + 30 + + + + AGEBD-ALH:MASTER-STATUS + + + caLineEdit::Default + + + caLineEdit::onBackground + + + caLineEdit::User + + + + + + 970 + 110 + 100 + 30 + + + + AGEBD-ALH:MASTER-VERSION + + + caLineEdit::Default + + + caLineEdit::onBackground + + + caLineEdit::User + + + + + + 620 + 110 + 100 + 30 + + + + AGEBD-ALH:MASTER-ONOFF + + + caChoice::Column + + + 1 + + + + + + 730 + 110 + 30 + 30 + + + + + 0 + 0 + + + + + 0 + 0 + + + + true + + + false + + + 28 + + + 28 + + + true + + + false + + + AGEBD-ALH:MASTER-ONOFF-RB + + + caLed::Alarm + + + + + + 10 + 110 + 30 + 30 + + + + + 0 + 0 + + + + + 0 + 0 + + + + true + + + false + + + 28 + + + 28 + + + true + + + false + + + AGEBD-CPCL-MASTER:STATUS + + + caLed::Alarm + + + + + + 45 + 110 + 30 + 30 + + + + + 183 + 157 + 92 + + + + P + + + /ioc/modules/qt/iocStats.ui + + + IOC=AGEBD-CPCL-MASTER; + + + + + + 129 + 110 + 201 + 30 + + + + MASTER + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 110 + 60 + 20 + 90 + + + + Qt::Vertical + + + + + + 330 + 60 + 20 + 90 + + + + Qt::Vertical + + + + + + 760 + 60 + 20 + 90 + + + + Qt::Vertical + + + + + + 1180 + 60 + 20 + 90 + + + + Qt::Vertical + + + + + + 560 + 60 + 20 + 90 + + + + Qt::Vertical + + + + + + 10 + 90 + 1300 + 16 + + + + Qt::Horizontal + + + + + + 10 + 35 + 181 + 22 + + + + Expert Mode + + + Expert-Mode + + + caToggleButton::Height + + + 0 + + + 1 + + + + + + 1530 + 180 + 121 + 20 + + + + Expert-Mode + + + Expert-Mode + + + A + + + + + + 1.000000000000000 + + + 0 + + + + + + 340 + 100 + 131 + 50 + + + + caFrame::IfZero + + + + + + Expert-Mode + + + + + 60 + 10 + 61 + 30 + + + + Restart + + + + 160 + 160 + 160 + + + + caScriptButton::Invisible + + + false + + + ssh svcusr-sls2hla@sls-vserv-bd-hla01 systemctl --user restart AGEBD-SERVICE-MASTER.service + + + + + + 10 + 10 + 41 + 30 + + + + SSH + + + + 160 + 160 + 160 + + + + caScriptButton::Invisible + + + false + + + terminator -e "ssh svcusr-sls2hla@sls-vserv-bd-hla01" + + + + + + + 470 + 110 + 91 + 30 + + + + + 8 + + + + Logs + + + EPushButton::None + + + AGEBD-MASTER:MASTER-LOGS-REQ + + + Logs + + + + 160 + 160 + 160 + + + + CONTROL-ONOFF + + + + + + 1 + + + + + + 130 + 40 + 120 + 40 + + + + caFrame::IfZero + + + Expert-Mode + + + + + + 1240 + 100 + 71 + 50 + + + + caFrame::IfZero + + + Expert-Mode + + + + + 0 + 10 + 70 + 30 + + + + false + + + AGEBD-ALH:MASTER-GUIRELOAD + + + Reload + + + + 160 + 160 + 160 + + + + + 230 + 230 + 230 + + + + + + + + + + 1 + + + + + + + 82 + 100 + 41 + 50 + + + + caFrame::IfZero + + + Expert-Mode + + + + + 0 + 10 + 30 + 30 + + + + + 18 + + + + + + + EPushButton::None + + + AGEBD-CPCL-MASTER:RESTART + + + + + + + 160 + 160 + 160 + + + + + + + + + + 1 + + + + + + + 0 + 0 + 1320 + 32 + + + + + Sans Serif + 18 + 75 + false + true + + + + Operation + + + Service Overview + + + Qt::AlignLeading + + + + 218 + 218 + 218 + + + + caLabel::Default + + + + + + + caChoice + QWidget +
caChoice
+
+ + caRelatedDisplay + QWidget +
caRelatedDisplay
+
+ + caMessageButton + QPushButton +
caMessageButton
+
+ + caToggleButton + QCheckBox +
caToggleButton
+
+ + caFrame + QFrame +
caFrame
+ 1 +
+ + caLabel + QLabel +
caLabel
+
+ + caLabelVertical + QWidget +
caLabelVertical
+
+ + caInclude + QWidget +
caInclude
+
+ + caLed + QWidget +
caLed
+
+ + caLineEdit + QLineEdit +
caLineEdit
+
+ + caCalc + QLabel +
caCalc
+
+ + wmSignalPropagator + QLabel +
wmSignalPropagator
+
+ + caScriptButton + QWidget +
caScriptButton
+
+
+ + + + cacalc_2 + emitSignal(bool) + wmsignalpropagator + reloadwindow() + + + 1480 + 170 + + + 1480 + 220 + + + + +
diff --git a/qt/A_BD_ServiceManager_inc.ui b/qt/A_BD_ServiceManager_inc.ui new file mode 100644 index 0000000..5e56705 --- /dev/null +++ b/qt/A_BD_ServiceManager_inc.ui @@ -0,0 +1,754 @@ + + + MainWindow + + + + 0 + 0 + 1319 + 30 + + + + MainWindow + + + + + + 8 + 0 + 30 + 30 + + + + + 0 + 0 + + + + + 0 + 0 + + + + true + + + false + + + 28 + + + 28 + + + true + + + false + + + $(IOC):STATUS + + + caLed::Alarm + + + + + + 43 + 0 + 30 + 30 + + + + + 183 + 157 + 92 + + + + P + + + /ioc/modules/qt/iocStats.ui + + + IOC=$(IOC) + + + + + + 1200 + 0 + 110 + 40 + + + + caFrame::Calc + + + caFrame::All + + + $(panel) + + + + + + + + + + + 0 + 0 + 30 + 30 + + + + + 183 + 157 + 92 + + + + P + + + $(panelcmd) + + + $(macro) + + + + + + + 277 + 0 + 900 + 120 + + + + caFrame::Calc + + + $(svc_exist) + + + + + 800 + 0 + 100 + 30 + + + + AGEBD-ALH:$(service)-STATUS + + + caLineEdit::Default + + + caLineEdit::onBackground + + + caLineEdit::User + + + + + + 220 + 0 + 60 + 30 + + + + + 8 + + + + Restart + + + EPushButton::None + + + AGEBD-MASTER:$(service)-RESTART-REQ + + + Restart + + + + 160 + 160 + 160 + + + + CONTROL-ONOFF + + + + + + 1 + + + + + + 690 + 0 + 100 + 30 + + + + AGEBD-ALH:$(service)-VERSION + + + caLineEdit::Default + + + caLineEdit::onBackground + + + caLineEdit::User + + + + + + 340 + 0 + 100 + 30 + + + + AGEBD-ALH:$(service)-ONOFF + + + caChoice::Column + + + 1 + + + + + + 500 + 0 + 180 + 30 + + + + AGEBD-ALH:$(service)-STARTTIME + + + caLineEdit::Default + + + caLineEdit::onBackground + + + caLineEdit::User + + + + + + 300 + 0 + 30 + 30 + + + + + 0 + 0 + + + + + 0 + 0 + + + + true + + + false + + + 28 + + + 28 + + + true + + + false + + + AGEBD-ALH:$(service)-ALIVE + + + caLed::Alarm + + + + + + 170 + 0 + 40 + 30 + + + + + 8 + + + + Logs + + + EPushButton::None + + + AGEBD-MASTER:$(service)-LOGS-REQ + + + Logs + + + + 160 + 160 + 160 + + + + CONTROL-ONOFF + + + + + + 1 + + + + + + 450 + 0 + 30 + 30 + + + + + 0 + 0 + + + + + 0 + 0 + + + + true + + + false + + + 28 + + + 28 + + + true + + + false + + + AGEBD-ALH:$(service)-ONOFF-RB + + + caLed::Alarm + + + + + + 481 + 0 + 20 + 30 + + + + Qt::Vertical + + + + + + + 130 + 0 + 201 + 30 + + + + $(name) + + + Qt::MarkdownText + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 108 + 0 + 20 + 30 + + + + Qt::Vertical + + + + + + 328 + 0 + 20 + 30 + + + + Qt::Vertical + + + + + + 558 + 0 + 20 + 30 + + + + Qt::Vertical + + + + + + 1178 + 0 + 20 + 30 + + + + Qt::Vertical + + + + + + 340 + 0 + 101 + 40 + + + + caFrame::IfZero + + + Expert-Mode + + + + + 60 + 0 + 40 + 30 + + + + + 8 + + + + Start + + + EPushButton::None + + + AGEBD-MASTER:$(service)-START-REQ + + + Start + + + + 160 + 160 + 160 + + + + CONTROL-ONOFF + + + + + + 1 + + + + + + 10 + 0 + 40 + 30 + + + + + 8 + + + + KILL + + + EPushButton::None + + + AGEBD-MASTER:$(service)-ABORT-REQ + + + KILL + + + + 148 + 0 + 0 + + + + CONTROL-ONOFF + + + + + + 1 + + + + + + + 80 + 0 + 41 + 30 + + + + caFrame::IfZero + + + Expert-Mode + + + + + 0 + 0 + 30 + 30 + + + + + 18 + + + + + + + EPushButton::None + + + $(IOC):RESTART + + + + + + + 160 + 160 + 160 + + + + + + + + + + 1 + + + + + + + 1240 + 0 + 71 + 40 + + + + caFrame::IfZero + + + Expert-Mode + + + + + 0 + 0 + 70 + 30 + + + + AGEBD-ALH:$(service)-GUIRELOAD + + + Reload + + + + 160 + 160 + 160 + + + + + + + + + + 1 + + + + + + + + caChoice + QWidget +
caChoice
+
+ + caRelatedDisplay + QWidget +
caRelatedDisplay
+
+ + caMessageButton + QPushButton +
caMessageButton
+
+ + caFrame + QFrame +
caFrame
+ 1 +
+ + caLabel + QLabel +
caLabel
+
+ + caLed + QWidget +
caLed
+
+ + caLineEdit + QLineEdit +
caLineEdit
+
+
+ + +
-- 2.54.0 From 6e9365db0b3fa5f7a30d0f7e20ade9b955d8b804 Mon Sep 17 00:00:00 2001 From: Benjamin Labrecque Date: Thu, 9 Jul 2026 10:23:00 +0200 Subject: [PATCH 02/27] ui: use subs --- docs/ui.md | 4 +++- qt/A_BD_ServiceManager.ui | 2 +- qt/required_services.subs | 17 +++++++++++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 qt/required_services.subs diff --git a/docs/ui.md b/docs/ui.md index 28504ff..db6fcf2 100644 --- a/docs/ui.md +++ b/docs/ui.md @@ -9,4 +9,6 @@ ssh -J sls-lc -X labrec_b@sls-vserv-bd-hla01-dev.psi.ch Macro substitution ``` caqtdm -m'TESTAGEBDALH=AGEBD-ALH' A_BD_ServiceManager.ui -``` \ No newline at end of file +``` + +# TODO: remove/delete old autodeployed ui files \ No newline at end of file diff --git a/qt/A_BD_ServiceManager.ui b/qt/A_BD_ServiceManager.ui index 9d8b5ec..c943b72 100644 --- a/qt/A_BD_ServiceManager.ui +++ b/qt/A_BD_ServiceManager.ui @@ -138,7 +138,7 @@ caLabel[statusTip="Operation"]{ - IOC=AGEBD-CPCL-DBPM3CURR,service=DBPM3CURR,name=DBPM3Current,panel=1,svc_exist=1,panelcmd=A_BD_DBPM3Current.ui;IOC=AGEBD-CPCL-TAUBPM,service=TAUBPM,name=LifetimeBPM,panel=1,svc_exist=1,panelcmd=A_BD_LifetimeBPM.ui;IOC=AGEBD-CPCL-TAUPCT,service=TAUPCT,name=LifetimePCT,panel=1,svc_exist=1,panelcmd=A_BD_LifetimePCT.ui;IOC=AGEBD-CPCL-TIMING,service=TIMING,name=Timing,panel=1,svc_exist=1,panelcmd=A_BD_Timing.ui;IOC=AGEBD-CPCL-SCRUBBING,service=SCRUBBING,name=Scrubbing,panel=1,svc_exist=1,panelcmd=A_BD_Scrubbing.ui;IOC=AGEBD-CPCL-INJECTIONGUARD,service=INJECTIONGUARD,name=InjectionGuard,panel=1,svc_exist=1,panelcmd=A_BD_InjectionGuard.ui;IOC=AGEBD-CPCL-POSTMORTEMLOG,service=POSTMORTEMLOG,name=PostMortemLog,panel=1,svc_exist=1,panelcmd=A_BD_PostMortemLog.ui;IOC=AGEBD-CPCL-TUNEBUMP,service=TUNEBUMP,name=TuneBump,panel=1,svc_exist=1,panelcmd=A_BD_TuneBump.ui;IOC=AGEBD-CPCL-PLOTS,service=PLOTS,name=Plots,panel=0,svc_exist=1,panelcmd=A_BD_Plots.ui;IOC=AGEBD-CPCL-ORBITBUMP,service=ORBITBUMP,name=OrbitBump,panel=1,svc_exist=0,panelcmd=A_BD_OrbitBump.ui;IOC=AGEBD-CPCL-TUNEFBX,service=TUNEFBX,name=Hor. Tune Feedback,panel=1,svc_exist=1,panelcmd=A_BD_TuneBump.ui;IOC=AGEBD-CPCL-TUNEFBY,service=TUNEFBY,name=Ver. Tune Feedback,panel=1,svc_exist=1,panelcmd=A_BD_TuneBump.ui + @required_services.subs A_BD_ServiceManager_inc.ui diff --git a/qt/required_services.subs b/qt/required_services.subs new file mode 100644 index 0000000..c748f12 --- /dev/null +++ b/qt/required_services.subs @@ -0,0 +1,17 @@ +# required_services.substitutions +# Service configurations for caInclude + +file A_BD_ServiceManager_inc.ui { + { IOC="AGEBD-CPCL-DBPM3CURR", service="DBPM3CURR", name="DBPM3Current", panel="1", svc_exist="1", panelcmd="A_BD_DBPM3Current.ui" } + { IOC="AGEBD-CPCL-TAUBPM", service="TAUBPM", name="LifetimeBPM", panel="1", svc_exist="1", panelcmd="A_BD_LifetimeBPM.ui" } + { IOC="AGEBD-CPCL-TAUPCT", service="TAUPCT", name="LifetimePCT", panel="1", svc_exist="1", panelcmd="A_BD_LifetimePCT.ui" } + { IOC="AGEBD-CPCL-TIMING", service="TIMING", name="Timing", panel="1", svc_exist="1", panelcmd="A_BD_Timing.ui" } + { IOC="AGEBD-CPCL-SCRUBBING", service="SCRUBBING", name="Scrubbing", panel="1", svc_exist="1", panelcmd="A_BD_Scrubbing.ui" } + { IOC="AGEBD-CPCL-INJECTION*", service="INJECTIONGUARD", name="InjectionGuard", panel="1", svc_exist="1", panelcmd="A_BD_InjectionGuard.ui" } + { IOC="AGEBD-CPCL-POSTMORTEM*", service="POSTMORTEMLOG", name="PostMortemLog", panel="1", svc_exist="1", panelcmd="A_BD_PostMortemLog.ui" } + { IOC="AGEBD-CPCL-TUNEBUMP", service="TUNEBUMP", name="TuneBump", panel="1", svc_exist="1", panelcmd="A_BD_TuneBump.ui" } + { IOC="AGEBD-CPCL-PLOTS", service="PLOTS", name="Plots", panel="0", svc_exist="1", panelcmd="A_BD_Plots.ui" } + { IOC="AGEBD-CPCL-ORBITBUMP", service="ORBITBUMP", name="OrbitBump", panel="1", svc_exist="0", panelcmd="A_BD_OrbitBump.ui" } + { IOC="AGEBD-CPCL-TUNEFBX", service="TUNEFBX", name="Hor. Tune FB", panel="1", svc_exist="1", panelcmd="A_BD_TuneBump.ui" } + { IOC="AGEBD-CPCL-TUNEFBY", service="TUNEFBY", name="Ver. Tune FB", panel="1", svc_exist="1", panelcmd="A_BD_TuneBump.ui" } +} \ No newline at end of file -- 2.54.0 From 02ba1e5868f608adc0488b4c6e7186f00daf669f Mon Sep 17 00:00:00 2001 From: Benjamin Labrecque Date: Thu, 9 Jul 2026 11:26:10 +0200 Subject: [PATCH 03/27] fix: undo subs --- qt/A_BD_ServiceManager.ui | 2 +- qt/required_services.subs | 17 ----------------- 2 files changed, 1 insertion(+), 18 deletions(-) delete mode 100644 qt/required_services.subs diff --git a/qt/A_BD_ServiceManager.ui b/qt/A_BD_ServiceManager.ui index c943b72..9d8b5ec 100644 --- a/qt/A_BD_ServiceManager.ui +++ b/qt/A_BD_ServiceManager.ui @@ -138,7 +138,7 @@ caLabel[statusTip="Operation"]{ - @required_services.subs + IOC=AGEBD-CPCL-DBPM3CURR,service=DBPM3CURR,name=DBPM3Current,panel=1,svc_exist=1,panelcmd=A_BD_DBPM3Current.ui;IOC=AGEBD-CPCL-TAUBPM,service=TAUBPM,name=LifetimeBPM,panel=1,svc_exist=1,panelcmd=A_BD_LifetimeBPM.ui;IOC=AGEBD-CPCL-TAUPCT,service=TAUPCT,name=LifetimePCT,panel=1,svc_exist=1,panelcmd=A_BD_LifetimePCT.ui;IOC=AGEBD-CPCL-TIMING,service=TIMING,name=Timing,panel=1,svc_exist=1,panelcmd=A_BD_Timing.ui;IOC=AGEBD-CPCL-SCRUBBING,service=SCRUBBING,name=Scrubbing,panel=1,svc_exist=1,panelcmd=A_BD_Scrubbing.ui;IOC=AGEBD-CPCL-INJECTIONGUARD,service=INJECTIONGUARD,name=InjectionGuard,panel=1,svc_exist=1,panelcmd=A_BD_InjectionGuard.ui;IOC=AGEBD-CPCL-POSTMORTEMLOG,service=POSTMORTEMLOG,name=PostMortemLog,panel=1,svc_exist=1,panelcmd=A_BD_PostMortemLog.ui;IOC=AGEBD-CPCL-TUNEBUMP,service=TUNEBUMP,name=TuneBump,panel=1,svc_exist=1,panelcmd=A_BD_TuneBump.ui;IOC=AGEBD-CPCL-PLOTS,service=PLOTS,name=Plots,panel=0,svc_exist=1,panelcmd=A_BD_Plots.ui;IOC=AGEBD-CPCL-ORBITBUMP,service=ORBITBUMP,name=OrbitBump,panel=1,svc_exist=0,panelcmd=A_BD_OrbitBump.ui;IOC=AGEBD-CPCL-TUNEFBX,service=TUNEFBX,name=Hor. Tune Feedback,panel=1,svc_exist=1,panelcmd=A_BD_TuneBump.ui;IOC=AGEBD-CPCL-TUNEFBY,service=TUNEFBY,name=Ver. Tune Feedback,panel=1,svc_exist=1,panelcmd=A_BD_TuneBump.ui A_BD_ServiceManager_inc.ui diff --git a/qt/required_services.subs b/qt/required_services.subs deleted file mode 100644 index c748f12..0000000 --- a/qt/required_services.subs +++ /dev/null @@ -1,17 +0,0 @@ -# required_services.substitutions -# Service configurations for caInclude - -file A_BD_ServiceManager_inc.ui { - { IOC="AGEBD-CPCL-DBPM3CURR", service="DBPM3CURR", name="DBPM3Current", panel="1", svc_exist="1", panelcmd="A_BD_DBPM3Current.ui" } - { IOC="AGEBD-CPCL-TAUBPM", service="TAUBPM", name="LifetimeBPM", panel="1", svc_exist="1", panelcmd="A_BD_LifetimeBPM.ui" } - { IOC="AGEBD-CPCL-TAUPCT", service="TAUPCT", name="LifetimePCT", panel="1", svc_exist="1", panelcmd="A_BD_LifetimePCT.ui" } - { IOC="AGEBD-CPCL-TIMING", service="TIMING", name="Timing", panel="1", svc_exist="1", panelcmd="A_BD_Timing.ui" } - { IOC="AGEBD-CPCL-SCRUBBING", service="SCRUBBING", name="Scrubbing", panel="1", svc_exist="1", panelcmd="A_BD_Scrubbing.ui" } - { IOC="AGEBD-CPCL-INJECTION*", service="INJECTIONGUARD", name="InjectionGuard", panel="1", svc_exist="1", panelcmd="A_BD_InjectionGuard.ui" } - { IOC="AGEBD-CPCL-POSTMORTEM*", service="POSTMORTEMLOG", name="PostMortemLog", panel="1", svc_exist="1", panelcmd="A_BD_PostMortemLog.ui" } - { IOC="AGEBD-CPCL-TUNEBUMP", service="TUNEBUMP", name="TuneBump", panel="1", svc_exist="1", panelcmd="A_BD_TuneBump.ui" } - { IOC="AGEBD-CPCL-PLOTS", service="PLOTS", name="Plots", panel="0", svc_exist="1", panelcmd="A_BD_Plots.ui" } - { IOC="AGEBD-CPCL-ORBITBUMP", service="ORBITBUMP", name="OrbitBump", panel="1", svc_exist="0", panelcmd="A_BD_OrbitBump.ui" } - { IOC="AGEBD-CPCL-TUNEFBX", service="TUNEFBX", name="Hor. Tune FB", panel="1", svc_exist="1", panelcmd="A_BD_TuneBump.ui" } - { IOC="AGEBD-CPCL-TUNEFBY", service="TUNEFBY", name="Ver. Tune FB", panel="1", svc_exist="1", panelcmd="A_BD_TuneBump.ui" } -} \ No newline at end of file -- 2.54.0 From 8f12f2b975d5d2346a5efe8c3818372f15843c1a Mon Sep 17 00:00:00 2001 From: Benjamin Labrecque Date: Thu, 9 Jul 2026 13:44:49 +0200 Subject: [PATCH 04/27] chore: update ui service manager of new service --- cli/src/core/models.py | 129 ++++++++++++++++++++++++++++++++ cli/src/core/service_creator.py | 67 +++++++++-------- cli/src/service.py | 13 +++- 3 files changed, 177 insertions(+), 32 deletions(-) diff --git a/cli/src/core/models.py b/cli/src/core/models.py index 6f00e92..cad5637 100644 --- a/cli/src/core/models.py +++ b/cli/src/core/models.py @@ -1,4 +1,5 @@ import re +import xml.etree.ElementTree as ET from typing import ClassVar import yaml @@ -17,6 +18,8 @@ MASTER_HLA_NAMES_FILENAME = MASTER_SERVICE_CONFIG_DIR / "hla_names.yml" IOCS_OVERVIEW_FILENAME = REPO_ROOT / "docs" / "ioc" / "ioc_overview.md" +SERVICE_MANAGER_UI_FILENAME = REPO_ROOT / "qt" / "A_BD_ServiceManager.ui" + class Service(BaseModel): name: str @@ -127,3 +130,129 @@ class IocsOverview(BaseModel): def write_to_file(self): with open(self.config_path, "w") as f: f.write(self.content) + + +# TODO: maybe separate models into their own files +class ServiceManagerUI(BaseModel): + config_path: ClassVar[str] = str(SERVICE_MANAGER_UI_FILENAME) + + tree: ET.ElementTree[ET.Element[str]] + + @classmethod + def read_from_file(cls) -> "ServiceManagerUI": + tree = ET.parse(cls.config_path) + return ServiceManagerUI(tree=tree) + + def update_xml(self, service: Service, ui_name: str, panelcmd: str) -> None: + num_macro_elements = self._update_macro(service=service, ui_name=ui_name, panelcmd=panelcmd) + self._update_heights(num_macro_elemnts=num_macro_elements) + + def _update_macro(self, service: Service, ui_name: str, panelcmd: str) -> int: + new_macro_element = _ServiceManagerUIMacroElement( + service_name_upper=service.name_upper, ui_name=ui_name, panelcmd=panelcmd + ) + + num_macro_elements = None + root = self.tree.getroot() + for widget in root.iter("widget"): + if widget.get("class") == "caInclude" and widget.get("name") == "cainclude": + for prop in widget.findall("property"): + # Update the macro data string + if prop.get("name") == "macro": + string_elem = prop.find("string") + if string_elem is not None and string_elem.text is not None: + string_elem.text = ( + string_elem.text + ";" + new_macro_element.to_string() + ) + # Dynamically update the count match so caInclude renders all rows + if prop.get("name") == "numberOfItems": + number_elem = prop.find("number") + assert number_elem is not None and number_elem.text is not None + num_macro_elements = int(number_elem.text) + number_elem.text = str(num_macro_elements + 1) + + assert num_macro_elements is not None, "could not find number of macro elements in xml" + return num_macro_elements + + def _update_heights(self, num_macro_elemnts: int) -> None: + """ + There are 3 heights to be adjusted: + + 1. Main window + 2. Tab widget + 3. Widget inside the tab widget + """ + root = self.tree.getroot() + + ca_include_height = self._get_height_cainclude() + height_to_add = ca_include_height / num_macro_elemnts * (num_macro_elemnts + 1) + + # 1. Main window + mainwindow = root.find(".//widget[@class='QMainWindow']") + if mainwindow is not None: + rect = mainwindow.find("./property[@name='geometry']/rect") + assert rect is not None + height = rect.find("height") + assert height is not None and height.text is not None + height.text = str(int(height.text) + height_to_add) + + for widget in root.iter("widget"): + widget_name = widget.get("name") + + # 2. Tab widget + if widget_name == "tabWidget": + rect = widget.find("./property[@name='geometry']/rect") + assert rect is not None + height = rect.find("height") + assert height is not None and height.text is not None + height.text = str(int(height.text) + height_to_add) + + # 3. Widget inside the tab widget + elif widget_name == "cainclude": + rect = widget.find("./property[@name='geometry']/rect") + assert rect is not None + height = rect.find("height") + assert height is not None and height.text is not None + height.text = str(int(height.text) + height_to_add) + + def _get_height_cainclude(self) -> int: + """ + Get the height of the area that includes all the services + """ + root = self.tree.getroot() + cainclude_height = None + + for widget in root.iter("widget"): + widget_name = widget.get("name") + + # Target the caInclude Widget of Required Services + if widget_name == "cainclude": + rect = widget.find("./property[@name='geometry']/rect") + assert rect is not None + height = rect.find("height") + assert height is not None and height.text is not None + cainclude_height = int(height.text) + + assert cainclude_height, "could not get height of cainclude widget" + return cainclude_height + + def write_to_file(self) -> None: + self.tree.write(self.config_path, encoding="utf-8", xml_declaration=True) + + +class _ServiceManagerUIMacroElement(BaseModel): + service_name_upper: str + ui_name: str + panel: int = 1 + svc_exist: int = 1 + panelcmd: str + + def to_string(self) -> str: + return ( + f"IOC=AGEBD-CPCL-{self.service_name_upper}," + f"service={self.service_name_upper}," + f"name={self.ui_name}," + f"panel={self.panel}," + f"svc_exist={self.svc_exist}," + f"panelcmd={self.panelcmd}" + ) diff --git a/cli/src/core/service_creator.py b/cli/src/core/service_creator.py index 835ed1a..bbb9040 100644 --- a/cli/src/core/service_creator.py +++ b/cli/src/core/service_creator.py @@ -14,7 +14,7 @@ from core.git import ( git_push_changes, switch_branch, ) -from core.models import IocsOverview, MasterHLANames, Service, ServiceRegistry +from core.models import IocsOverview, MasterHLANames, Service, ServiceManagerUI, ServiceRegistry from core.utils import get_git_root logger = logging.getLogger(__name__) @@ -30,9 +30,11 @@ MASTER_IOC_SUBS_FILE = MASTER_SERVICE_DIR / "ioc" / "AGEBD-CPCL-MASTER_main.subs class ServiceCreator: - def __init__(self, user: str, ioc_description: str) -> None: + def __init__(self, user: str, ioc_description: str, ui_name: str, panelcmd: str) -> None: self.user = user self.ioc_description = ioc_description + self.ui_name = ui_name + self.panelcmd = panelcmd def add_service(self, name: str): repo = git.Repo(REPO_ROOT) @@ -49,45 +51,50 @@ class ServiceCreator: iocs_overview_old = IocsOverview.read_from_file() iocs_overview = IocsOverview.read_from_file() iocs_overview.add_ioc(service, description=self.ioc_description) + service_manager_old = ServiceManagerUI.read_from_file() + service_manager = ServiceManagerUI.read_from_file() + service_manager.update_xml(service=service, ui_name=self.ui_name, panelcmd=self.panelcmd) - branch_name = f"feature/add-service-{service.dir_name}" - delete_local_branch(repo, branch_name) - switch_branch(repo, branch_name) + # branch_name = f"feature/add-service-{service.dir_name}" + # delete_local_branch(repo, branch_name) + # switch_branch(repo, branch_name) try: - self._render_new_service_templates( - service=service, - user=self.user, - ) - self._generate_uv_lock(service=service) - registry.write_to_config() - hla_names.write_to_config() - iocs_overview.write_to_file() + # self._render_new_service_templates( + # service=service, + # user=self.user, + # ) + # self._generate_uv_lock(service=service) + # registry.write_to_config() + # hla_names.write_to_config() + # iocs_overview.write_to_file() + service_manager.write_to_file() - self._append_to_master_ioc_subs( - service_name=service.name_upper, - starton="0", # TODO: ok? - autooff="0", # TODO: ok? - ) + # self._append_to_master_ioc_subs( + # service_name=service.name_upper, + # starton="0", # TODO: ok? + # autooff="0", # TODO: ok? + # ) # TODO: can't push if branch already exists in remote - git_push_changes( - repo=repo, - branch_name=branch_name, - service_dir_rel_path=f"services/{service.dir_name}/current", - registry_file_rel_path="config/services_registry.yml", - # TODO: maybe assert/get correct master service dirname from registry - master_hla_names_rel_path="services/master/current/app/config/hla_names.yml", - master_ioc_subs_rel_path="services/master/current/ioc/AGEBD-CPCL-MASTER_main.subs", - iocs_overview_rel_path="docs/ioc/ioc_overview.md", - commit_msg=f"feature: add new service {service.name_lower}", - ) - switch_branch(repo, original_branch) + # git_push_changes( + # repo=repo, + # branch_name=branch_name, + # service_dir_rel_path=f"services/{service.dir_name}/current", + # registry_file_rel_path="config/services_registry.yml", + # # TODO: maybe assert/get correct master service dirname from registry + # master_hla_names_rel_path="services/master/current/app/config/hla_names.yml", + # master_ioc_subs_rel_path="services/master/current/ioc/AGEBD-CPCL-MASTER_main.subs", + # iocs_overview_rel_path="docs/ioc/ioc_overview.md", + # commit_msg=f"feature: add new service {service.name_lower}", + # ) + # switch_branch(repo, original_branch) except Exception as e: shutil.rmtree(Path(SERVICE_DEST_DIR / service.dir_name), ignore_errors=True) registry_old.write_to_config() hla_names_old.write_to_config() iocs_overview_old.write_to_file() + service_manager_old.write_to_file() switch_branch(repo, original_branch) raise e diff --git a/cli/src/service.py b/cli/src/service.py index 96da23e..ff60fc7 100644 --- a/cli/src/service.py +++ b/cli/src/service.py @@ -16,12 +16,21 @@ def add( ioc_description: str = typer.Option( ..., "--ioc-description", "-d", help="See /docs/ioc/ioc_overview.md for examples" ), + ui_name: str = typer.Option( + ..., "--ui-name", help="See /qt/A_BD_ServiceManager.ui for examples" + ), + panelcmd: str = typer.Option( + ..., "--panelcmd", "-p", help="See /qt/A_BD_ServiceManager.ui for examples" + ), ): init_logging() - ServiceCreator( + service_creator = ServiceCreator( user=user, # TODO: read from 'whoami'? ioc_description=ioc_description, - ).add_service(name=name) + ui_name=ui_name, # TODO: make this standard? + panelcmd=panelcmd, # TODO: make this standard? + ) + service_creator.add_service(name=name) @service.command() -- 2.54.0 From 2b9a42e05bace02859b3a65c033eb590d6f7c9e4 Mon Sep 17 00:00:00 2001 From: Benjamin Labrecque Date: Thu, 9 Jul 2026 13:49:10 +0200 Subject: [PATCH 05/27] chore: update ui service manager of new service --- cli/src/core/models.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cli/src/core/models.py b/cli/src/core/models.py index cad5637..344b547 100644 --- a/cli/src/core/models.py +++ b/cli/src/core/models.py @@ -3,7 +3,7 @@ import xml.etree.ElementTree as ET from typing import ClassVar import yaml -from pydantic import BaseModel, field_validator +from pydantic import BaseModel, ConfigDict, field_validator from core.enums import ServiceStatus from core.utils import get_git_root @@ -134,6 +134,7 @@ class IocsOverview(BaseModel): # TODO: maybe separate models into their own files class ServiceManagerUI(BaseModel): + model_config = ConfigDict(arbitrary_types_allowed=True) config_path: ClassVar[str] = str(SERVICE_MANAGER_UI_FILENAME) tree: ET.ElementTree[ET.Element[str]] -- 2.54.0 From 5b9a94c270de1d0825de4e05e3c0c4148bf48c42 Mon Sep 17 00:00:00 2001 From: Benjamin Labrecque Date: Thu, 9 Jul 2026 13:49:25 +0200 Subject: [PATCH 06/27] chore: update ui service manager of new service --- cli/src/core/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/src/core/models.py b/cli/src/core/models.py index 344b547..bd8704a 100644 --- a/cli/src/core/models.py +++ b/cli/src/core/models.py @@ -137,7 +137,7 @@ class ServiceManagerUI(BaseModel): model_config = ConfigDict(arbitrary_types_allowed=True) config_path: ClassVar[str] = str(SERVICE_MANAGER_UI_FILENAME) - tree: ET.ElementTree[ET.Element[str]] + tree: ET.ElementTree @classmethod def read_from_file(cls) -> "ServiceManagerUI": -- 2.54.0 From 175ae7d7c0c73d4d60476e18803304a6326bd9e8 Mon Sep 17 00:00:00 2001 From: Benjamin Labrecque Date: Thu, 9 Jul 2026 13:54:09 +0200 Subject: [PATCH 07/27] chore: update ui service manager of new service --- cli/src/core/models.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/cli/src/core/models.py b/cli/src/core/models.py index bd8704a..8404add 100644 --- a/cli/src/core/models.py +++ b/cli/src/core/models.py @@ -146,7 +146,7 @@ class ServiceManagerUI(BaseModel): def update_xml(self, service: Service, ui_name: str, panelcmd: str) -> None: num_macro_elements = self._update_macro(service=service, ui_name=ui_name, panelcmd=panelcmd) - self._update_heights(num_macro_elemnts=num_macro_elements) + self._update_heights(num_macro_elements=num_macro_elements) def _update_macro(self, service: Service, ui_name: str, panelcmd: str) -> int: new_macro_element = _ServiceManagerUIMacroElement( @@ -175,7 +175,7 @@ class ServiceManagerUI(BaseModel): assert num_macro_elements is not None, "could not find number of macro elements in xml" return num_macro_elements - def _update_heights(self, num_macro_elemnts: int) -> None: + def _update_heights(self, num_macro_elements: int) -> None: """ There are 3 heights to be adjusted: @@ -186,7 +186,9 @@ class ServiceManagerUI(BaseModel): root = self.tree.getroot() ca_include_height = self._get_height_cainclude() - height_to_add = ca_include_height / num_macro_elemnts * (num_macro_elemnts + 1) + height_to_add = ( + ca_include_height / num_macro_elements * (num_macro_elements + 1) + ) - ca_include_height # 1. Main window mainwindow = root.find(".//widget[@class='QMainWindow']") -- 2.54.0 From e534a43dbdfd1e3fe70eeaf0e72e10db989026ed Mon Sep 17 00:00:00 2001 From: Benjamin Labrecque Date: Thu, 9 Jul 2026 13:55:16 +0200 Subject: [PATCH 08/27] chore: update ui service manager of new service --- cli/src/core/models.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cli/src/core/models.py b/cli/src/core/models.py index 8404add..7d37e26 100644 --- a/cli/src/core/models.py +++ b/cli/src/core/models.py @@ -186,9 +186,9 @@ class ServiceManagerUI(BaseModel): root = self.tree.getroot() ca_include_height = self._get_height_cainclude() - height_to_add = ( - ca_include_height / num_macro_elements * (num_macro_elements + 1) - ) - ca_include_height + height_to_add = int( + (ca_include_height / num_macro_elements * (num_macro_elements + 1)) - ca_include_height + ) # 1. Main window mainwindow = root.find(".//widget[@class='QMainWindow']") -- 2.54.0 From 901a116955a7819553bb5a760e21f640e1c3908b Mon Sep 17 00:00:00 2001 From: Benjamin Labrecque Date: Thu, 9 Jul 2026 14:02:21 +0200 Subject: [PATCH 09/27] chore: update ui service manager of new service --- cli/src/core/models.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/cli/src/core/models.py b/cli/src/core/models.py index 7d37e26..b376c2c 100644 --- a/cli/src/core/models.py +++ b/cli/src/core/models.py @@ -1,6 +1,7 @@ import re import xml.etree.ElementTree as ET from typing import ClassVar +from xml.dom import minidom import yaml from pydantic import BaseModel, ConfigDict, field_validator @@ -240,7 +241,13 @@ class ServiceManagerUI(BaseModel): return cainclude_height def write_to_file(self) -> None: - self.tree.write(self.config_path, encoding="utf-8", xml_declaration=True) + raw_string = ET.tostring(self.tree.getroot(), encoding="utf-8") + parsed_dom = minidom.parseString(raw_string) + + # Write out the file text while natively preserving XML entities + with open(self.config_path, "w", encoding="utf-8") as f: + f.write(parsed_dom.toxml()) + self.tree.write(self.config_path, encoding="utf-8", xml_declaration=True) class _ServiceManagerUIMacroElement(BaseModel): -- 2.54.0 From fb4e5d3a35f407f3b4bfa16d3149a40c33ecbb40 Mon Sep 17 00:00:00 2001 From: Benjamin Labrecque Date: Thu, 9 Jul 2026 14:04:11 +0200 Subject: [PATCH 10/27] chore: update ui service manager of new service --- cli/src/core/models.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/cli/src/core/models.py b/cli/src/core/models.py index b376c2c..7d37e26 100644 --- a/cli/src/core/models.py +++ b/cli/src/core/models.py @@ -1,7 +1,6 @@ import re import xml.etree.ElementTree as ET from typing import ClassVar -from xml.dom import minidom import yaml from pydantic import BaseModel, ConfigDict, field_validator @@ -241,13 +240,7 @@ class ServiceManagerUI(BaseModel): return cainclude_height def write_to_file(self) -> None: - raw_string = ET.tostring(self.tree.getroot(), encoding="utf-8") - parsed_dom = minidom.parseString(raw_string) - - # Write out the file text while natively preserving XML entities - with open(self.config_path, "w", encoding="utf-8") as f: - f.write(parsed_dom.toxml()) - self.tree.write(self.config_path, encoding="utf-8", xml_declaration=True) + self.tree.write(self.config_path, encoding="utf-8", xml_declaration=True) class _ServiceManagerUIMacroElement(BaseModel): -- 2.54.0 From 25add4ef713ec0e8a83778e675f0065594011a5b Mon Sep 17 00:00:00 2001 From: Benjamin Labrecque Date: Thu, 9 Jul 2026 14:04:55 +0200 Subject: [PATCH 11/27] ui-update: service manager ui --- qt/A_BD_ServiceManager.ui | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/qt/A_BD_ServiceManager.ui b/qt/A_BD_ServiceManager.ui index 9d8b5ec..51a58e3 100644 --- a/qt/A_BD_ServiceManager.ui +++ b/qt/A_BD_ServiceManager.ui @@ -1,4 +1,4 @@ - + MainWindow @@ -7,7 +7,7 @@ 0 0 1320 - 595 + 630 @@ -29,7 +29,7 @@ QMainWindow#MainWindow[transparent=true], QWidget#Form[transparent=true], QDialo /* Title */ /*-----------------------------------------------*/ /* Operation panels */ -caLabel[statusTip="Operation"]{ +caLabel[statusTip="Operation"]{ color: rgba(0, 0, 0, 255); font: bold 18pt; font-family: Sans Serif; @@ -115,7 +115,7 @@ caLabel[statusTip="Operation"]{ 0 146 1320 - 450 + 485 @@ -134,17 +134,17 @@ caLabel[statusTip="Operation"]{ 0 0 1319 - 420 + 455 - IOC=AGEBD-CPCL-DBPM3CURR,service=DBPM3CURR,name=DBPM3Current,panel=1,svc_exist=1,panelcmd=A_BD_DBPM3Current.ui;IOC=AGEBD-CPCL-TAUBPM,service=TAUBPM,name=LifetimeBPM,panel=1,svc_exist=1,panelcmd=A_BD_LifetimeBPM.ui;IOC=AGEBD-CPCL-TAUPCT,service=TAUPCT,name=LifetimePCT,panel=1,svc_exist=1,panelcmd=A_BD_LifetimePCT.ui;IOC=AGEBD-CPCL-TIMING,service=TIMING,name=Timing,panel=1,svc_exist=1,panelcmd=A_BD_Timing.ui;IOC=AGEBD-CPCL-SCRUBBING,service=SCRUBBING,name=Scrubbing,panel=1,svc_exist=1,panelcmd=A_BD_Scrubbing.ui;IOC=AGEBD-CPCL-INJECTIONGUARD,service=INJECTIONGUARD,name=InjectionGuard,panel=1,svc_exist=1,panelcmd=A_BD_InjectionGuard.ui;IOC=AGEBD-CPCL-POSTMORTEMLOG,service=POSTMORTEMLOG,name=PostMortemLog,panel=1,svc_exist=1,panelcmd=A_BD_PostMortemLog.ui;IOC=AGEBD-CPCL-TUNEBUMP,service=TUNEBUMP,name=TuneBump,panel=1,svc_exist=1,panelcmd=A_BD_TuneBump.ui;IOC=AGEBD-CPCL-PLOTS,service=PLOTS,name=Plots,panel=0,svc_exist=1,panelcmd=A_BD_Plots.ui;IOC=AGEBD-CPCL-ORBITBUMP,service=ORBITBUMP,name=OrbitBump,panel=1,svc_exist=0,panelcmd=A_BD_OrbitBump.ui;IOC=AGEBD-CPCL-TUNEFBX,service=TUNEFBX,name=Hor. Tune Feedback,panel=1,svc_exist=1,panelcmd=A_BD_TuneBump.ui;IOC=AGEBD-CPCL-TUNEFBY,service=TUNEFBY,name=Ver. Tune Feedback,panel=1,svc_exist=1,panelcmd=A_BD_TuneBump.ui + IOC=AGEBD-CPCL-DBPM3CURR,service=DBPM3CURR,name=DBPM3Current,panel=1,svc_exist=1,panelcmd=A_BD_DBPM3Current.ui;IOC=AGEBD-CPCL-TAUBPM,service=TAUBPM,name=LifetimeBPM,panel=1,svc_exist=1,panelcmd=A_BD_LifetimeBPM.ui;IOC=AGEBD-CPCL-TAUPCT,service=TAUPCT,name=LifetimePCT,panel=1,svc_exist=1,panelcmd=A_BD_LifetimePCT.ui;IOC=AGEBD-CPCL-TIMING,service=TIMING,name=Timing,panel=1,svc_exist=1,panelcmd=A_BD_Timing.ui;IOC=AGEBD-CPCL-SCRUBBING,service=SCRUBBING,name=Scrubbing,panel=1,svc_exist=1,panelcmd=A_BD_Scrubbing.ui;IOC=AGEBD-CPCL-INJECTIONGUARD,service=INJECTIONGUARD,name=InjectionGuard,panel=1,svc_exist=1,panelcmd=A_BD_InjectionGuard.ui;IOC=AGEBD-CPCL-POSTMORTEMLOG,service=POSTMORTEMLOG,name=PostMortemLog,panel=1,svc_exist=1,panelcmd=A_BD_PostMortemLog.ui;IOC=AGEBD-CPCL-TUNEBUMP,service=TUNEBUMP,name=TuneBump,panel=1,svc_exist=1,panelcmd=A_BD_TuneBump.ui;IOC=AGEBD-CPCL-PLOTS,service=PLOTS,name=Plots,panel=0,svc_exist=1,panelcmd=A_BD_Plots.ui;IOC=AGEBD-CPCL-ORBITBUMP,service=ORBITBUMP,name=OrbitBump,panel=1,svc_exist=0,panelcmd=A_BD_OrbitBump.ui;IOC=AGEBD-CPCL-TUNEFBX,service=TUNEFBX,name=Hor. Tune Feedback,panel=1,svc_exist=1,panelcmd=A_BD_TuneBump.ui;IOC=AGEBD-CPCL-TUNEFBY,service=TUNEFBY,name=Ver. Tune Feedback,panel=1,svc_exist=1,panelcmd=A_BD_TuneBump.ui;IOC=AGEBD-CPCL-PLAYGROUND,service=PLAYGROUND,name=Playground,panel=1,svc_exist=1,panelcmd=A_BD_Playground.ui A_BD_ServiceManager_inc.ui - 12 + 13 true @@ -543,7 +543,7 @@ caLabel[statusTip="Operation"]{ A_BD_Master.ui - + @@ -933,7 +933,7 @@ caLabel[statusTip="Operation"]{ A - + 1.000000000000000 @@ -955,7 +955,7 @@ caLabel[statusTip="Operation"]{ caFrame::IfZero - + Expert-Mode @@ -1015,7 +1015,7 @@ caLabel[statusTip="Operation"]{ false - terminator -e "ssh svcusr-sls2hla@sls-vserv-bd-hla01" + terminator -e "ssh svcusr-sls2hla@sls-vserv-bd-hla01" @@ -1056,7 +1056,7 @@ caLabel[statusTip="Operation"]{ CONTROL-ONOFF - + 1 @@ -1126,10 +1126,10 @@ caLabel[statusTip="Operation"]{ - + - + 1 @@ -1185,10 +1185,10 @@ caLabel[statusTip="Operation"]{ - + - + 1 @@ -1303,7 +1303,7 @@ caLabel[statusTip="Operation"]{
caScriptButton
- + cacalc_2 @@ -1322,4 +1322,4 @@ caLabel[statusTip="Operation"]{ - + \ No newline at end of file -- 2.54.0 From 2810ced0139b60985fd0b7b34d9e6cc6c487320a Mon Sep 17 00:00:00 2001 From: Benjamin Labrecque Date: Thu, 9 Jul 2026 14:12:17 +0200 Subject: [PATCH 12/27] ui-update: service manager ui --- cli/src/core/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/src/core/models.py b/cli/src/core/models.py index 7d37e26..808c0a0 100644 --- a/cli/src/core/models.py +++ b/cli/src/core/models.py @@ -1,6 +1,6 @@ import re import xml.etree.ElementTree as ET -from typing import ClassVar +from typing import Any, ClassVar import yaml from pydantic import BaseModel, ConfigDict, field_validator @@ -137,7 +137,7 @@ class ServiceManagerUI(BaseModel): model_config = ConfigDict(arbitrary_types_allowed=True) config_path: ClassVar[str] = str(SERVICE_MANAGER_UI_FILENAME) - tree: ET.ElementTree + tree: Any @classmethod def read_from_file(cls) -> "ServiceManagerUI": -- 2.54.0 From 72c6414f3134db4df7a775295a17f048f58dde42 Mon Sep 17 00:00:00 2001 From: Benjamin Labrecque Date: Thu, 9 Jul 2026 14:13:40 +0200 Subject: [PATCH 13/27] chore: update ui service manager of new service --- qt/A_BD_ServiceManager.ui | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/qt/A_BD_ServiceManager.ui b/qt/A_BD_ServiceManager.ui index 51a58e3..9d8b5ec 100644 --- a/qt/A_BD_ServiceManager.ui +++ b/qt/A_BD_ServiceManager.ui @@ -1,4 +1,4 @@ - + MainWindow @@ -7,7 +7,7 @@ 0 0 1320 - 630 + 595
@@ -29,7 +29,7 @@ QMainWindow#MainWindow[transparent=true], QWidget#Form[transparent=true], QDialo /* Title */ /*-----------------------------------------------*/ /* Operation panels */ -caLabel[statusTip="Operation"]{ +caLabel[statusTip="Operation"]{ color: rgba(0, 0, 0, 255); font: bold 18pt; font-family: Sans Serif; @@ -115,7 +115,7 @@ caLabel[statusTip="Operation"]{ 0 146 1320 - 485 + 450 @@ -134,17 +134,17 @@ caLabel[statusTip="Operation"]{ 0 0 1319 - 455 + 420 - IOC=AGEBD-CPCL-DBPM3CURR,service=DBPM3CURR,name=DBPM3Current,panel=1,svc_exist=1,panelcmd=A_BD_DBPM3Current.ui;IOC=AGEBD-CPCL-TAUBPM,service=TAUBPM,name=LifetimeBPM,panel=1,svc_exist=1,panelcmd=A_BD_LifetimeBPM.ui;IOC=AGEBD-CPCL-TAUPCT,service=TAUPCT,name=LifetimePCT,panel=1,svc_exist=1,panelcmd=A_BD_LifetimePCT.ui;IOC=AGEBD-CPCL-TIMING,service=TIMING,name=Timing,panel=1,svc_exist=1,panelcmd=A_BD_Timing.ui;IOC=AGEBD-CPCL-SCRUBBING,service=SCRUBBING,name=Scrubbing,panel=1,svc_exist=1,panelcmd=A_BD_Scrubbing.ui;IOC=AGEBD-CPCL-INJECTIONGUARD,service=INJECTIONGUARD,name=InjectionGuard,panel=1,svc_exist=1,panelcmd=A_BD_InjectionGuard.ui;IOC=AGEBD-CPCL-POSTMORTEMLOG,service=POSTMORTEMLOG,name=PostMortemLog,panel=1,svc_exist=1,panelcmd=A_BD_PostMortemLog.ui;IOC=AGEBD-CPCL-TUNEBUMP,service=TUNEBUMP,name=TuneBump,panel=1,svc_exist=1,panelcmd=A_BD_TuneBump.ui;IOC=AGEBD-CPCL-PLOTS,service=PLOTS,name=Plots,panel=0,svc_exist=1,panelcmd=A_BD_Plots.ui;IOC=AGEBD-CPCL-ORBITBUMP,service=ORBITBUMP,name=OrbitBump,panel=1,svc_exist=0,panelcmd=A_BD_OrbitBump.ui;IOC=AGEBD-CPCL-TUNEFBX,service=TUNEFBX,name=Hor. Tune Feedback,panel=1,svc_exist=1,panelcmd=A_BD_TuneBump.ui;IOC=AGEBD-CPCL-TUNEFBY,service=TUNEFBY,name=Ver. Tune Feedback,panel=1,svc_exist=1,panelcmd=A_BD_TuneBump.ui;IOC=AGEBD-CPCL-PLAYGROUND,service=PLAYGROUND,name=Playground,panel=1,svc_exist=1,panelcmd=A_BD_Playground.ui + IOC=AGEBD-CPCL-DBPM3CURR,service=DBPM3CURR,name=DBPM3Current,panel=1,svc_exist=1,panelcmd=A_BD_DBPM3Current.ui;IOC=AGEBD-CPCL-TAUBPM,service=TAUBPM,name=LifetimeBPM,panel=1,svc_exist=1,panelcmd=A_BD_LifetimeBPM.ui;IOC=AGEBD-CPCL-TAUPCT,service=TAUPCT,name=LifetimePCT,panel=1,svc_exist=1,panelcmd=A_BD_LifetimePCT.ui;IOC=AGEBD-CPCL-TIMING,service=TIMING,name=Timing,panel=1,svc_exist=1,panelcmd=A_BD_Timing.ui;IOC=AGEBD-CPCL-SCRUBBING,service=SCRUBBING,name=Scrubbing,panel=1,svc_exist=1,panelcmd=A_BD_Scrubbing.ui;IOC=AGEBD-CPCL-INJECTIONGUARD,service=INJECTIONGUARD,name=InjectionGuard,panel=1,svc_exist=1,panelcmd=A_BD_InjectionGuard.ui;IOC=AGEBD-CPCL-POSTMORTEMLOG,service=POSTMORTEMLOG,name=PostMortemLog,panel=1,svc_exist=1,panelcmd=A_BD_PostMortemLog.ui;IOC=AGEBD-CPCL-TUNEBUMP,service=TUNEBUMP,name=TuneBump,panel=1,svc_exist=1,panelcmd=A_BD_TuneBump.ui;IOC=AGEBD-CPCL-PLOTS,service=PLOTS,name=Plots,panel=0,svc_exist=1,panelcmd=A_BD_Plots.ui;IOC=AGEBD-CPCL-ORBITBUMP,service=ORBITBUMP,name=OrbitBump,panel=1,svc_exist=0,panelcmd=A_BD_OrbitBump.ui;IOC=AGEBD-CPCL-TUNEFBX,service=TUNEFBX,name=Hor. Tune Feedback,panel=1,svc_exist=1,panelcmd=A_BD_TuneBump.ui;IOC=AGEBD-CPCL-TUNEFBY,service=TUNEFBY,name=Ver. Tune Feedback,panel=1,svc_exist=1,panelcmd=A_BD_TuneBump.ui A_BD_ServiceManager_inc.ui - 13 + 12 true @@ -543,7 +543,7 @@ caLabel[statusTip="Operation"]{ A_BD_Master.ui - + @@ -933,7 +933,7 @@ caLabel[statusTip="Operation"]{ A - + 1.000000000000000 @@ -955,7 +955,7 @@ caLabel[statusTip="Operation"]{ caFrame::IfZero - + Expert-Mode @@ -1015,7 +1015,7 @@ caLabel[statusTip="Operation"]{ false - terminator -e "ssh svcusr-sls2hla@sls-vserv-bd-hla01" + terminator -e "ssh svcusr-sls2hla@sls-vserv-bd-hla01" @@ -1056,7 +1056,7 @@ caLabel[statusTip="Operation"]{ CONTROL-ONOFF - + 1 @@ -1126,10 +1126,10 @@ caLabel[statusTip="Operation"]{ - + - + 1 @@ -1185,10 +1185,10 @@ caLabel[statusTip="Operation"]{ - + - + 1 @@ -1303,7 +1303,7 @@ caLabel[statusTip="Operation"]{
caScriptButton
- + cacalc_2 @@ -1322,4 +1322,4 @@ caLabel[statusTip="Operation"]{ - \ No newline at end of file + -- 2.54.0 From 71c20c2a764cb1161ec568b1861488c1db95045c Mon Sep 17 00:00:00 2001 From: Benjamin Labrecque Date: Thu, 9 Jul 2026 14:18:28 +0200 Subject: [PATCH 14/27] chore: update ui service manager of new service --- cli/src/core/service_creator.py | 57 +++++++++++++++++---------------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/cli/src/core/service_creator.py b/cli/src/core/service_creator.py index bbb9040..ba8ea67 100644 --- a/cli/src/core/service_creator.py +++ b/cli/src/core/service_creator.py @@ -55,40 +55,41 @@ class ServiceCreator: service_manager = ServiceManagerUI.read_from_file() service_manager.update_xml(service=service, ui_name=self.ui_name, panelcmd=self.panelcmd) - # branch_name = f"feature/add-service-{service.dir_name}" - # delete_local_branch(repo, branch_name) - # switch_branch(repo, branch_name) + branch_name = f"feature/add-service-{service.dir_name}" + delete_local_branch(repo, branch_name) + switch_branch(repo, branch_name) try: - # self._render_new_service_templates( - # service=service, - # user=self.user, - # ) - # self._generate_uv_lock(service=service) - # registry.write_to_config() - # hla_names.write_to_config() - # iocs_overview.write_to_file() + self._render_new_service_templates( + service=service, + user=self.user, + ) + self._generate_uv_lock(service=service) + registry.write_to_config() + hla_names.write_to_config() + iocs_overview.write_to_file() service_manager.write_to_file() - # self._append_to_master_ioc_subs( - # service_name=service.name_upper, - # starton="0", # TODO: ok? - # autooff="0", # TODO: ok? - # ) + self._append_to_master_ioc_subs( + service_name=service.name_upper, + starton="0", # TODO: ok? + autooff="0", # TODO: ok? + ) # TODO: can't push if branch already exists in remote - # git_push_changes( - # repo=repo, - # branch_name=branch_name, - # service_dir_rel_path=f"services/{service.dir_name}/current", - # registry_file_rel_path="config/services_registry.yml", - # # TODO: maybe assert/get correct master service dirname from registry - # master_hla_names_rel_path="services/master/current/app/config/hla_names.yml", - # master_ioc_subs_rel_path="services/master/current/ioc/AGEBD-CPCL-MASTER_main.subs", - # iocs_overview_rel_path="docs/ioc/ioc_overview.md", - # commit_msg=f"feature: add new service {service.name_lower}", - # ) - # switch_branch(repo, original_branch) + raise + git_push_changes( + repo=repo, + branch_name=branch_name, + service_dir_rel_path=f"services/{service.dir_name}/current", + registry_file_rel_path="config/services_registry.yml", + # TODO: maybe assert/get correct master service dirname from registry + master_hla_names_rel_path="services/master/current/app/config/hla_names.yml", + master_ioc_subs_rel_path="services/master/current/ioc/AGEBD-CPCL-MASTER_main.subs", + iocs_overview_rel_path="docs/ioc/ioc_overview.md", + commit_msg=f"feature: add new service {service.name_lower}", + ) + switch_branch(repo, original_branch) except Exception as e: shutil.rmtree(Path(SERVICE_DEST_DIR / service.dir_name), ignore_errors=True) registry_old.write_to_config() -- 2.54.0 From 629243d4f5645f298f4479298aecb1caff2659ab Mon Sep 17 00:00:00 2001 From: Benjamin Labrecque Date: Thu, 9 Jul 2026 14:29:10 +0200 Subject: [PATCH 15/27] chore: update ui service manager of new service --- cli/src/core/models.py | 46 ++++++++++++++++++++++++++++ cli/src/core/service_creator.py | 53 ++++++++------------------------- config/services_registry.yml | 6 ++-- qt/A_BD_ServiceManager.ui | 26 ++++++++-------- 4 files changed, 75 insertions(+), 56 deletions(-) diff --git a/cli/src/core/models.py b/cli/src/core/models.py index 808c0a0..19d2377 100644 --- a/cli/src/core/models.py +++ b/cli/src/core/models.py @@ -20,6 +20,9 @@ IOCS_OVERVIEW_FILENAME = REPO_ROOT / "docs" / "ioc" / "ioc_overview.md" SERVICE_MANAGER_UI_FILENAME = REPO_ROOT / "qt" / "A_BD_ServiceManager.ui" +MASTER_SERVICE_DIR = REPO_ROOT / "services" / "master" / "current" +MASTER_IOC_SUBS_FILE = MASTER_SERVICE_DIR / "ioc" / "AGEBD-CPCL-MASTER_main.subs" + class Service(BaseModel): name: str @@ -132,6 +135,49 @@ class IocsOverview(BaseModel): f.write(self.content) +class MasterIocSubs(BaseModel): + config_path: ClassVar[str] = str(MASTER_IOC_SUBS_FILE) + + content: str + + @classmethod + def read_from_file(cls) -> "MasterIocSubs": + with open(cls.config_path) as f: + file_content = f.read() + + return MasterIocSubs(content=file_content) + + def update_content( + self, + service_name: str, + starton: str = "0", # TODO: ok defaults? + autooff: str = "0", # TODO: ok defaults? + ): + """ + Parses the configuration text and appends a new row before the closing bracket. + """ + quoted_service = f'"{service_name}"' + new_row = f' {{ "{{{{ agebd_env }}}}", {quoted_service:<22} , "{starton}", "{autooff}" }}' + + # Use regex to find the last closing curly brace of the configuration block + # This targets the line that contains only a lone closing brace, optional spaces, and maybe a comma/semicolon. + pattern = r"(\s*\n\s*\}(?:;|,)?\s*$)" + + if re.search(pattern, self.content, re.MULTILINE): + # Insert our new row right before that closing brace line + self.content = re.sub( + pattern, f"\n{new_row}\\1", self.content, count=1, flags=re.MULTILINE + ) + else: + raise ValueError( + "Could not locate the closing structure format '}' inside the configuration." + ) + + def write_to_file(self) -> None: + with open(self.config_path, "w") as f: + f.write(self.content) + + # TODO: maybe separate models into their own files class ServiceManagerUI(BaseModel): model_config = ConfigDict(arbitrary_types_allowed=True) diff --git a/cli/src/core/service_creator.py b/cli/src/core/service_creator.py index ba8ea67..1d45bf4 100644 --- a/cli/src/core/service_creator.py +++ b/cli/src/core/service_creator.py @@ -14,7 +14,14 @@ from core.git import ( git_push_changes, switch_branch, ) -from core.models import IocsOverview, MasterHLANames, Service, ServiceManagerUI, ServiceRegistry +from core.models import ( + IocsOverview, + MasterHLANames, + MasterIocSubs, + Service, + ServiceManagerUI, + ServiceRegistry, +) from core.utils import get_git_root logger = logging.getLogger(__name__) @@ -23,8 +30,6 @@ REPO_ROOT = get_git_root(__file__) SERVICE_TEMPLATES_DIR = REPO_ROOT / "templates" / "service" SERVICE_DEST_DIR = REPO_ROOT / "services" -MASTER_SERVICE_DIR = REPO_ROOT / "services" / "master" / "current" -MASTER_IOC_SUBS_FILE = MASTER_SERVICE_DIR / "ioc" / "AGEBD-CPCL-MASTER_main.subs" # TODO: lots of hardcoded paths. Create config object? @@ -51,6 +56,9 @@ class ServiceCreator: iocs_overview_old = IocsOverview.read_from_file() iocs_overview = IocsOverview.read_from_file() iocs_overview.add_ioc(service, description=self.ioc_description) + master_ioc_subs_old = MasterIocSubs.read_from_file() + master_ioc_subs = MasterIocSubs.read_from_file() + master_ioc_subs.update_content(service_name=service.name_upper) service_manager_old = ServiceManagerUI.read_from_file() service_manager = ServiceManagerUI.read_from_file() service_manager.update_xml(service=service, ui_name=self.ui_name, panelcmd=self.panelcmd) @@ -68,14 +76,9 @@ class ServiceCreator: registry.write_to_config() hla_names.write_to_config() iocs_overview.write_to_file() + master_ioc_subs.write_to_file() service_manager.write_to_file() - self._append_to_master_ioc_subs( - service_name=service.name_upper, - starton="0", # TODO: ok? - autooff="0", # TODO: ok? - ) - # TODO: can't push if branch already exists in remote raise git_push_changes( @@ -95,6 +98,7 @@ class ServiceCreator: registry_old.write_to_config() hla_names_old.write_to_config() iocs_overview_old.write_to_file() + master_ioc_subs_old.write_to_file() service_manager_old.write_to_file() switch_branch(repo, original_branch) raise e @@ -145,34 +149,3 @@ class ServiceCreator: logger.error(f"Exit Code: {e.returncode}") logger.error(f"Details:\n{e.stderr}") raise UVError(e.stderr) from e - - def _append_to_master_ioc_subs( - self, - service_name: str, - starton: str, - autooff: str, - ) -> None: - """ - Parses the configuration text and appends a new row before the closing bracket. - """ - with open(MASTER_IOC_SUBS_FILE) as f: - file_content = f.read() - - quoted_service = f'"{service_name}"' - new_row = f' {{ "{{{{ agebd_env }}}}", {quoted_service:<22} , "{starton}", "{autooff}" }}' - - # Use regex to find the last closing curly brace of the configuration block - # This targets the line that contains only a lone closing brace, optional spaces, and maybe a comma/semicolon. - pattern = r"(\s*\n\s*\}(?:;|,)?\s*$)" - - if re.search(pattern, file_content, re.MULTILINE): - # Insert our new row right before that closing brace line - updated_content = re.sub( - pattern, f"\n{new_row}\\1", file_content, count=1, flags=re.MULTILINE - ) - with open(MASTER_IOC_SUBS_FILE, "w") as f: - f.write(updated_content) - else: - raise ValueError( - "Could not locate the closing structure format '}' inside the configuration." - ) diff --git a/config/services_registry.yml b/config/services_registry.yml index 48cbad7..21b4297 100644 --- a/config/services_registry.yml +++ b/config/services_registry.yml @@ -1,5 +1,5 @@ next_available_ioc_port: 50001 services: - - name: master - ioc_port: 50000 - status: active +- name: master + ioc_port: 50000 + status: active diff --git a/qt/A_BD_ServiceManager.ui b/qt/A_BD_ServiceManager.ui index 9d8b5ec..329f51a 100644 --- a/qt/A_BD_ServiceManager.ui +++ b/qt/A_BD_ServiceManager.ui @@ -1,4 +1,4 @@ - + MainWindow @@ -29,7 +29,7 @@ QMainWindow#MainWindow[transparent=true], QWidget#Form[transparent=true], QDialo /* Title */ /*-----------------------------------------------*/ /* Operation panels */ -caLabel[statusTip="Operation"]{ +caLabel[statusTip="Operation"]{ color: rgba(0, 0, 0, 255); font: bold 18pt; font-family: Sans Serif; @@ -543,7 +543,7 @@ caLabel[statusTip="Operation"]{ A_BD_Master.ui
- + @@ -933,7 +933,7 @@ caLabel[statusTip="Operation"]{ A - + 1.000000000000000 @@ -955,7 +955,7 @@ caLabel[statusTip="Operation"]{ caFrame::IfZero - + Expert-Mode @@ -1015,7 +1015,7 @@ caLabel[statusTip="Operation"]{ false - terminator -e "ssh svcusr-sls2hla@sls-vserv-bd-hla01" + terminator -e "ssh svcusr-sls2hla@sls-vserv-bd-hla01" @@ -1056,7 +1056,7 @@ caLabel[statusTip="Operation"]{ CONTROL-ONOFF - + 1 @@ -1126,10 +1126,10 @@ caLabel[statusTip="Operation"]{ - + - + 1 @@ -1185,10 +1185,10 @@ caLabel[statusTip="Operation"]{ - + - + 1 @@ -1303,7 +1303,7 @@ caLabel[statusTip="Operation"]{
caScriptButton
- + cacalc_2 @@ -1322,4 +1322,4 @@ caLabel[statusTip="Operation"]{ - + \ No newline at end of file -- 2.54.0 From 098aa74f171cc71f475687938e3e4b069a7c4df7 Mon Sep 17 00:00:00 2001 From: Benjamin Labrecque Date: Thu, 9 Jul 2026 14:29:36 +0200 Subject: [PATCH 16/27] chore: update ui service manager of new service --- cli/src/core/service_creator.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cli/src/core/service_creator.py b/cli/src/core/service_creator.py index 1d45bf4..15d2607 100644 --- a/cli/src/core/service_creator.py +++ b/cli/src/core/service_creator.py @@ -80,7 +80,6 @@ class ServiceCreator: service_manager.write_to_file() # TODO: can't push if branch already exists in remote - raise git_push_changes( repo=repo, branch_name=branch_name, -- 2.54.0 From 5168a13761df662c9f621a93b2c76771afc1cb7d Mon Sep 17 00:00:00 2001 From: Benjamin Labrecque Date: Thu, 9 Jul 2026 14:31:19 +0200 Subject: [PATCH 17/27] chore: update ui service manager of new service --- cli/src/core/git.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/src/core/git.py b/cli/src/core/git.py index 37a5aaf..78f5c15 100644 --- a/cli/src/core/git.py +++ b/cli/src/core/git.py @@ -52,7 +52,7 @@ def git_push_changes( logger.info("Successfully pushed!") except Exception as e: - logger.info(f"Git Operation Failed: {e}") + raise RuntimeError(f"Git Operation Failed: {e}") from e def delete_local_branch(repo: git.Repo, branch_name: str): -- 2.54.0 From 9081d3ef517c9db052a08e265bbf33ffd9c6a7d0 Mon Sep 17 00:00:00 2001 From: Benjamin Labrecque Date: Thu, 9 Jul 2026 14:35:37 +0200 Subject: [PATCH 18/27] chore: update ui service manager of new service --- cli/src/core/git.py | 58 +++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/cli/src/core/git.py b/cli/src/core/git.py index 78f5c15..8ab43b6 100644 --- a/cli/src/core/git.py +++ b/cli/src/core/git.py @@ -18,41 +18,37 @@ def git_push_changes( """ Push newly created service to Gitea """ - try: - logger.info( - "Staging files inside: " - f"{service_dir_rel_path}, " - f"{registry_file_rel_path}, " - f"{master_hla_names_rel_path}, " - f"{master_ioc_subs_rel_path}..." - f"{iocs_overview_rel_path}..." - ) - repo.index.add( - [ - service_dir_rel_path, - registry_file_rel_path, - master_hla_names_rel_path, - master_ioc_subs_rel_path, - iocs_overview_rel_path, - ] - ) + logger.info( + "Staging files inside: " + f"{service_dir_rel_path}, " + f"{registry_file_rel_path}, " + f"{master_hla_names_rel_path}, " + f"{master_ioc_subs_rel_path}..." + f"{iocs_overview_rel_path}..." + ) + repo.index.add( + [ + service_dir_rel_path, + registry_file_rel_path, + master_hla_names_rel_path, + master_ioc_subs_rel_path, + iocs_overview_rel_path, + ] + ) - # Check if there are changes to avoid empty commit crashes - if not repo.is_dirty(index=True, working_tree=False): - logger.info("No changes detected. Skipping commit.") - return + # Check if there are changes to avoid empty commit crashes + if not repo.is_dirty(index=True, working_tree=False): + logger.info("No changes detected. Skipping commit.") + return - logger.info("Committing changes...") - repo.index.commit(commit_msg) + logger.info("Committing changes...") + repo.index.commit(commit_msg) - logger.info(f"Pushing branch '{branch_name}' to origin...") - origin = repo.remote(name="origin") - origin.push(refspec=f"{branch_name}:{branch_name}").raise_if_error() + logger.info(f"Pushing branch '{branch_name}' to origin...") + origin = repo.remote(name="origin") + origin.push(refspec=f"{branch_name}:{branch_name}").raise_if_error() - logger.info("Successfully pushed!") - - except Exception as e: - raise RuntimeError(f"Git Operation Failed: {e}") from e + logger.info("Successfully pushed!") def delete_local_branch(repo: git.Repo, branch_name: str): -- 2.54.0 From 3f7f392de09a17f967c85f0f4b3deb6906e525e5 Mon Sep 17 00:00:00 2001 From: Benjamin Labrecque Date: Thu, 9 Jul 2026 14:42:09 +0200 Subject: [PATCH 19/27] chore: update ui service manager of new service --- cli/src/core/git.py | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/cli/src/core/git.py b/cli/src/core/git.py index 8ab43b6..61fc247 100644 --- a/cli/src/core/git.py +++ b/cli/src/core/git.py @@ -26,15 +26,14 @@ def git_push_changes( f"{master_ioc_subs_rel_path}..." f"{iocs_overview_rel_path}..." ) - repo.index.add( - [ - service_dir_rel_path, - registry_file_rel_path, - master_hla_names_rel_path, - master_ioc_subs_rel_path, - iocs_overview_rel_path, - ] - ) + files_to_stage = [ + service_dir_rel_path, + registry_file_rel_path, + master_hla_names_rel_path, + master_ioc_subs_rel_path, + iocs_overview_rel_path, + ] + repo.index.add(files_to_stage) # Check if there are changes to avoid empty commit crashes if not repo.is_dirty(index=True, working_tree=False): @@ -44,9 +43,14 @@ def git_push_changes( logger.info("Committing changes...") repo.index.commit(commit_msg) - logger.info(f"Pushing branch '{branch_name}' to origin...") - origin = repo.remote(name="origin") - origin.push(refspec=f"{branch_name}:{branch_name}").raise_if_error() + try: + logger.info(f"Pushing branch '{branch_name}' to origin...") + origin = repo.remote(name="origin") + origin.push(refspec=f"{branch_name}:{branch_name}").raise_if_error() + except Exception as e: + logger.info("Git resetting files") + repo.index.reset(files_to_stage) + raise e logger.info("Successfully pushed!") -- 2.54.0 From 589ae5c097766cca16ecbe9bf0fd76a9d769b8d9 Mon Sep 17 00:00:00 2001 From: Benjamin Labrecque Date: Thu, 9 Jul 2026 14:46:14 +0200 Subject: [PATCH 20/27] chore: update ui service manager of new service --- cli/src/core/git.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/cli/src/core/git.py b/cli/src/core/git.py index 61fc247..96646a9 100644 --- a/cli/src/core/git.py +++ b/cli/src/core/git.py @@ -48,9 +48,21 @@ def git_push_changes( origin = repo.remote(name="origin") origin.push(refspec=f"{branch_name}:{branch_name}").raise_if_error() except Exception as e: - logger.info("Git resetting files") - repo.index.reset(files_to_stage) - raise e + logger.error(f"Push failed due to an error: {e}") + logger.info("Rolling back local Git index changes...") + + # Step A: Undo the local commit if it was created (moves HEAD back 1 commit, keeps changes) + # This prevents leaving a dead/unpushed commit on your local branch + try: + repo.head.reset("HEAD~1", index=True, working_tree=False) + except Exception: + # Fallback if the exception happened BEFORE the commit step even ran + pass + + # Step B: Unstage the specific files (Equivalent to: git reset HEAD ) + # This leaves the files intact but removes them from the staging area + repo.index.reset(paths=files_to_stage) + logger.info("Staging area successfully reset to clean state.") logger.info("Successfully pushed!") -- 2.54.0 From e4b9e6fdbd6ef0ae9493acf0c9406f8039f2945b Mon Sep 17 00:00:00 2001 From: Benjamin Labrecque Date: Thu, 9 Jul 2026 14:47:38 +0200 Subject: [PATCH 21/27] chore: update ui service manager of new service --- cli/src/core/git.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cli/src/core/git.py b/cli/src/core/git.py index 96646a9..4db5a9a 100644 --- a/cli/src/core/git.py +++ b/cli/src/core/git.py @@ -64,6 +64,8 @@ def git_push_changes( repo.index.reset(paths=files_to_stage) logger.info("Staging area successfully reset to clean state.") + raise e + logger.info("Successfully pushed!") -- 2.54.0 From ed85cbd932c47cbcf05e706e04ef824236cd8d2f Mon Sep 17 00:00:00 2001 From: Benjamin Labrecque Date: Thu, 9 Jul 2026 14:50:38 +0200 Subject: [PATCH 22/27] chore: update ui service manager of new service --- cli/src/core/git.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cli/src/core/git.py b/cli/src/core/git.py index 4db5a9a..71fefed 100644 --- a/cli/src/core/git.py +++ b/cli/src/core/git.py @@ -47,7 +47,7 @@ def git_push_changes( logger.info(f"Pushing branch '{branch_name}' to origin...") origin = repo.remote(name="origin") origin.push(refspec=f"{branch_name}:{branch_name}").raise_if_error() - except Exception as e: + except git.GitCommandError as e: logger.error(f"Push failed due to an error: {e}") logger.info("Rolling back local Git index changes...") @@ -64,7 +64,8 @@ def git_push_changes( repo.index.reset(paths=files_to_stage) logger.info("Staging area successfully reset to clean state.") - raise e + error_reason = e.stderr.strip() if e.stderr else "Unknown remote error" + raise RuntimeError(f"Failed to push to git due to: {error_reason}") logger.info("Successfully pushed!") -- 2.54.0 From 6dd325d5a516cb1a078db7d8d273b0b930bb2e49 Mon Sep 17 00:00:00 2001 From: Benjamin Labrecque Date: Thu, 9 Jul 2026 14:52:21 +0200 Subject: [PATCH 23/27] chore: update ui service manager of new service --- cli/src/core/git.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/src/core/git.py b/cli/src/core/git.py index 71fefed..98df4df 100644 --- a/cli/src/core/git.py +++ b/cli/src/core/git.py @@ -65,7 +65,7 @@ def git_push_changes( logger.info("Staging area successfully reset to clean state.") error_reason = e.stderr.strip() if e.stderr else "Unknown remote error" - raise RuntimeError(f"Failed to push to git due to: {error_reason}") + raise RuntimeError(f"Failed to push to git due to: {error_reason}, {e.stdout}, {e.status}") logger.info("Successfully pushed!") -- 2.54.0 From 3a716715e84dcdd8dfb98f8e47684517107e786f Mon Sep 17 00:00:00 2001 From: Benjamin Labrecque Date: Thu, 9 Jul 2026 14:54:12 +0200 Subject: [PATCH 24/27] chore: update ui service manager of new service --- cli/src/core/git.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cli/src/core/git.py b/cli/src/core/git.py index 98df4df..0c512a6 100644 --- a/cli/src/core/git.py +++ b/cli/src/core/git.py @@ -64,8 +64,9 @@ def git_push_changes( repo.index.reset(paths=files_to_stage) logger.info("Staging area successfully reset to clean state.") - error_reason = e.stderr.strip() if e.stderr else "Unknown remote error" - raise RuntimeError(f"Failed to push to git due to: {error_reason}, {e.stdout}, {e.status}") + raise RuntimeError( + f"Failed to push to git due to: {e}. Does the branch already exist in Gitea?" + ) logger.info("Successfully pushed!") -- 2.54.0 From 6ad780701a691f6886bc3c1599ed0e0dc081fda2 Mon Sep 17 00:00:00 2001 From: Benjamin Labrecque Date: Thu, 9 Jul 2026 14:56:20 +0200 Subject: [PATCH 25/27] chore: update ui service manager of new service --- cli/src/core/git.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/src/core/git.py b/cli/src/core/git.py index 0c512a6..70abcf9 100644 --- a/cli/src/core/git.py +++ b/cli/src/core/git.py @@ -65,7 +65,7 @@ def git_push_changes( logger.info("Staging area successfully reset to clean state.") raise RuntimeError( - f"Failed to push to git due to: {e}. Does the branch already exist in Gitea?" + f"Failed to push to git due to: {e}.\nDoes the branch already exist in Gitea?" ) logger.info("Successfully pushed!") -- 2.54.0 From 1790cc9ccf56146c0b6ea8028623fb32dd46bff6 Mon Sep 17 00:00:00 2001 From: Benjamin Labrecque Date: Thu, 9 Jul 2026 14:57:21 +0200 Subject: [PATCH 26/27] chore: update ui service manager of new service --- cli/src/core/git.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cli/src/core/git.py b/cli/src/core/git.py index 70abcf9..b253c1e 100644 --- a/cli/src/core/git.py +++ b/cli/src/core/git.py @@ -64,8 +64,9 @@ def git_push_changes( repo.index.reset(paths=files_to_stage) logger.info("Staging area successfully reset to clean state.") + # TODO: we could also force push... need to think about workflow though. raise RuntimeError( - f"Failed to push to git due to: {e}.\nDoes the branch already exist in Gitea?" + f"Failed to push to git due to: {e}.\nDoes the branch already exist in Gitea? If yes, it needs to be deleted first" ) logger.info("Successfully pushed!") -- 2.54.0 From 6b64c43582d2fde09f03d6a72ef2f26f53cd6d0e Mon Sep 17 00:00:00 2001 From: Benjamin Labrecque Date: Thu, 9 Jul 2026 14:59:48 +0200 Subject: [PATCH 27/27] chore: update ui service manager of new service --- cli/src/core/git.py | 13 ++++--------- cli/src/core/service_creator.py | 1 + 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/cli/src/core/git.py b/cli/src/core/git.py index b253c1e..a886dd6 100644 --- a/cli/src/core/git.py +++ b/cli/src/core/git.py @@ -13,26 +13,21 @@ def git_push_changes( master_hla_names_rel_path: str, master_ioc_subs_rel_path: str, iocs_overview_rel_path: str, + service_manager_ui_rel_path: str, commit_msg: str, ): """ Push newly created service to Gitea """ - logger.info( - "Staging files inside: " - f"{service_dir_rel_path}, " - f"{registry_file_rel_path}, " - f"{master_hla_names_rel_path}, " - f"{master_ioc_subs_rel_path}..." - f"{iocs_overview_rel_path}..." - ) files_to_stage = [ service_dir_rel_path, registry_file_rel_path, master_hla_names_rel_path, master_ioc_subs_rel_path, iocs_overview_rel_path, + service_manager_ui_rel_path, ] + logger.info(f"Staging files inside: {files_to_stage}") repo.index.add(files_to_stage) # Check if there are changes to avoid empty commit crashes @@ -66,7 +61,7 @@ def git_push_changes( # TODO: we could also force push... need to think about workflow though. raise RuntimeError( - f"Failed to push to git due to: {e}.\nDoes the branch already exist in Gitea? If yes, it needs to be deleted first" + f"Failed to push to git due to: {e}.\nDoes the branch already exist in Gitea? If yes, it needs to be deleted first." ) logger.info("Successfully pushed!") diff --git a/cli/src/core/service_creator.py b/cli/src/core/service_creator.py index 15d2607..8180ab2 100644 --- a/cli/src/core/service_creator.py +++ b/cli/src/core/service_creator.py @@ -89,6 +89,7 @@ class ServiceCreator: master_hla_names_rel_path="services/master/current/app/config/hla_names.yml", master_ioc_subs_rel_path="services/master/current/ioc/AGEBD-CPCL-MASTER_main.subs", iocs_overview_rel_path="docs/ioc/ioc_overview.md", + service_manager_ui_rel_path="qt/A_BD_ServiceManager.ui", commit_msg=f"feature: add new service {service.name_lower}", ) switch_branch(repo, original_branch) -- 2.54.0