diff --git a/cli/src/core/git.py b/cli/src/core/git.py index 37a5aaf..a886dd6 100644 --- a/cli/src/core/git.py +++ b/cli/src/core/git.py @@ -13,46 +13,58 @@ 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 """ + 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 + 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) + 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, - ] - ) - - # 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(f"Pushing branch '{branch_name}' to origin...") origin = repo.remote(name="origin") origin.push(refspec=f"{branch_name}:{branch_name}").raise_if_error() + except git.GitCommandError as e: + logger.error(f"Push failed due to an error: {e}") + logger.info("Rolling back local Git index changes...") - logger.info("Successfully pushed!") + # 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 - except Exception as e: - logger.info(f"Git Operation Failed: {e}") + # 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.") + + # 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." + ) + + logger.info("Successfully pushed!") def delete_local_branch(repo: git.Repo, branch_name: str): diff --git a/cli/src/core/models.py b/cli/src/core/models.py index 6f00e92..19d2377 100644 --- a/cli/src/core/models.py +++ b/cli/src/core/models.py @@ -1,8 +1,9 @@ import re -from typing import ClassVar +import xml.etree.ElementTree as ET +from typing import Any, 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 @@ -17,6 +18,11 @@ 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" + +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 @@ -127,3 +133,175 @@ class IocsOverview(BaseModel): def write_to_file(self): with open(self.config_path, "w") as f: 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) + config_path: ClassVar[str] = str(SERVICE_MANAGER_UI_FILENAME) + + tree: Any + + @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_elements=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_elements: 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 = int( + (ca_include_height / num_macro_elements * (num_macro_elements + 1)) - ca_include_height + ) + + # 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..8180ab2 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, ServiceRegistry +from core.models import ( + IocsOverview, + MasterHLANames, + MasterIocSubs, + Service, + ServiceManagerUI, + ServiceRegistry, +) from core.utils import get_git_root logger = logging.getLogger(__name__) @@ -23,16 +30,16 @@ 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? 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,6 +56,12 @@ 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) branch_name = f"feature/add-service-{service.dir_name}" delete_local_branch(repo, branch_name) @@ -63,12 +76,8 @@ class ServiceCreator: registry.write_to_config() hla_names.write_to_config() iocs_overview.write_to_file() - - self._append_to_master_ioc_subs( - service_name=service.name_upper, - starton="0", # TODO: ok? - autooff="0", # TODO: ok? - ) + master_ioc_subs.write_to_file() + service_manager.write_to_file() # TODO: can't push if branch already exists in remote git_push_changes( @@ -80,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) @@ -88,6 +98,8 @@ 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 @@ -137,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/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() 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/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 new file mode 100644 index 0000000..329f51a --- /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 + + + + +
\ No newline at end of file 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
+
+
+ + +