diff --git a/Sources/pyOpenRPA/Orchestrator/__Orchestrator__.py b/Sources/pyOpenRPA/Orchestrator/__Orchestrator__.py index 8a187c22..f7b4b7cf 100755 --- a/Sources/pyOpenRPA/Orchestrator/__Orchestrator__.py +++ b/Sources/pyOpenRPA/Orchestrator/__Orchestrator__.py @@ -16,6 +16,7 @@ from . import BackwardCompatibility # Backward compatibility from v1.1.13 from . import Core from . import Managers from ..Tools import License +from ..Utils import Dictionary if CrossOS.IS_WINDOWS_BOOL: from subprocess import CREATE_NEW_CONSOLE @@ -808,7 +809,7 @@ def OrchestratorSessionRestore(inGSettings=None): inGSettings["StorageDict"] = {} with open('_SessionLast_StorageDict.pickle', 'rb') as lFile: lStorageDictDumpDict = pickle.load(lFile) - Server.__ComplexDictMerge2to1Overwrite__(in1Dict=inGSettings["StorageDict"], + Dictionary.MergeNoException(in1Dict=inGSettings["StorageDict"], in2Dict=lStorageDictDumpDict) # Merge dict 2 into dict 1 if lL: lL.warning(f"Словарь StorageDict был восстановлен из прошлой сессии оркестратора") os.remove("_SessionLast_StorageDict.pickle") # remove the temp file @@ -820,7 +821,7 @@ def OrchestratorSessionRestore(inGSettings=None): inGSettings["ManagersProcessDict"] = {} with open('_SessionLast_GSettings.pickle', 'rb') as lFile: lStorageDictDumpDict = pickle.load(lFile) - Server.__ComplexDictMerge2to1Overwrite__(in1Dict=inGSettings, + Dictionary.MergeNoException(in1Dict=inGSettings, in2Dict=lStorageDictDumpDict) # Merge dict 2 into dict 1 if lL: lL.warning(f"Словарь GSettings был восстановлен из прошлой сессии оркестратора") os.remove("_SessionLast_GSettings.pickle") # remove the temp file @@ -878,7 +879,7 @@ def UACUpdate(inADLoginStr, inADStr="", inADIsDefaultBool=True, inURLList=None, # Check RoleHierarchyAllowedDict in gSettings for the old role hierarchy - include in result. if lUserTurple in inGSettings["ServerDict"]["AccessUsers"]["RuleDomainUserDict"] and "RoleHierarchyAllowedDict" in inGSettings["ServerDict"]["AccessUsers"]["RuleDomainUserDict"][lUserTurple]: lRoleHierarchyAllowedOLDDict = inGSettings["ServerDict"]["AccessUsers"]["RuleDomainUserDict"][lUserTurple]["RoleHierarchyAllowedDict"] - Server.__ComplexDictMerge2to1__(in1Dict=inRoleHierarchyAllowedDict, in2Dict=lRoleHierarchyAllowedOLDDict) # Merge dict 2 into dict 1 + Dictionary.Merge(in1Dict=inRoleHierarchyAllowedDict, in2Dict=lRoleHierarchyAllowedOLDDict) # Merge dict 2 into dict 1 # Create Access item lRuleDomainUserDict = { @@ -1281,7 +1282,7 @@ def GSettingsGet(inGSettings=None): global GSettings # identify the global variable # Merge dictionaries if some new dictionary has come if inGSettings is not None and GSettings is not inGSettings: - GSettings = Server.__ComplexDictMerge2to1Overwrite__(in1Dict = inGSettings, in2Dict = GSettings) + GSettings = Dictionary.MergeNoException(in1Dict = inGSettings, in2Dict = GSettings) return GSettings # Return the result def GSettingsKeyListValueSet(inValue, inKeyList=None, inGSettings = None): diff --git a/Sources/pyOpenRPA/Resources/Web/orpa/orc.js b/Sources/pyOpenRPA/Resources/Web/orpa/orc.js index e4e598e0..22774de9 100755 --- a/Sources/pyOpenRPA/Resources/Web/orpa/orc.js +++ b/Sources/pyOpenRPA/Resources/Web/orpa/orc.js @@ -138,6 +138,23 @@ $(document).ready(function() { mGlobal.Controller.OrchestratorSessionSave() //Save current RDP list session mGlobal.Controller.CMDRunText("timeout 3 & taskkill /f /im OpenRPA_Orchestrator.exe & timeout 2 & cd "+mGlobal.WorkingDirectoryPathStr+" & git reset --hard & git pull & pyOpenRPA.Orchestrator_x64_administrator_startup.cmd"); } + mGlobal.Controller.OrchestratorRestart=function() { + ///Подготовить конфигурацию + lData = [ + { + "Def":"OrchestratorRestart", // def link or def alias (look gSettings["Processor"]["AliasDefDict"]) + "ArgList":[], // Args list + "ArgDict":{}, // Args dictionary + "ArgGSettings": null, // Name of GSettings attribute: str (ArgDict) or index (for ArgList) + "ArgLogger": null // Name of GSettings attribute: str (ArgDict) or index (for ArgList) + } + ] + $.ajax({ + type: "POST", + url: '/orpa/api/activity-list-execute', + data: JSON.stringify(lData) + }); + } ////////////////////////// /////Monitor JS module ////////////////////////// diff --git a/Sources/pyOpenRPA/Utils/Dictionary.py b/Sources/pyOpenRPA/Utils/Dictionary.py new file mode 100644 index 00000000..7869548d --- /dev/null +++ b/Sources/pyOpenRPA/Utils/Dictionary.py @@ -0,0 +1,43 @@ +# Tool to merge complex dictionaries +def Merge(in1Dict, in2Dict): + """ + Сливать словарь in2Dict в in1Dict. В случае конфликта вывести исключение + + :param in1Dict: Исходный словарь. В него будет производится запись. Ссылка на него будет активна + :param in2Dict: Изменяющий словарь. Новые данные, которые будут скопированы в in1Dict + :return: Обновленный словарь in1Dict + """ + lPathList=None + if lPathList is None: lPathList = [] + for lKeyStr in in2Dict: + if lKeyStr in in1Dict: + if isinstance(in1Dict[lKeyStr], dict) and isinstance(in2Dict[lKeyStr], dict): + Merge(in1Dict[lKeyStr], in2Dict[lKeyStr]) + elif in1Dict[lKeyStr] == in2Dict[lKeyStr]: + pass # same leaf value + else: + raise Exception('Conflict at %s' % '.'.join(lPathList + [str(lKeyStr)])) + else: + in1Dict[lKeyStr] = in2Dict[lKeyStr] + return in1Dict + +# Tool to merge complex dictionaries - no exceptions, just overwrite dict 2 in dict 1 +def MergeNoException(in1Dict, in2Dict): + """ + Сливать словарь in2Dict в in1Dict. В случае конфликта перезаписать на значение из in2Dict + + :param in1Dict: Исходный словарь. В него будет производится запись. Ссылка на него будет активна + :param in2Dict: Изменяющий словарь. Новые данные, которые будут скопированы в in1Dict + :return: Обновленный словарь in1Dict + """ + lPathList=None + if lPathList is None: lPathList = [] + for lKeyStr in in2Dict: + if lKeyStr in in1Dict: + if isinstance(in1Dict[lKeyStr], dict) and isinstance(in2Dict[lKeyStr], dict): + MergeNoException(in1Dict[lKeyStr], in2Dict[lKeyStr]) + else: + in1Dict[lKeyStr] = in2Dict[lKeyStr] + else: + in1Dict[lKeyStr] = in2Dict[lKeyStr] + return in1Dict diff --git a/changelog.md b/changelog.md index 626a5ef6..1fd95bfa 100755 --- a/changelog.md +++ b/changelog.md @@ -8,6 +8,7 @@ AGT - AGENT - ОРКЕСТРАТОР - минорные правки в дизайн - Orchestrator.OrchestratorPySearchInit - добавлена возможность импорта пакетов с импользованием relative imports внутри +- Web: Восстановлена функциональность кнопки "Перезагрузить оркестратор" - СТУДИЯ - - UI переведен на русский язык - - обновлен дизайн по аналогии с порталом и Оркестратором