@ -3,30 +3,72 @@ import jinja2
import os
from inspect import signature # For detect count of def args
from . . Web import Basic
import operator
import math
class ControlPanel ( ) :
"""
Manage your control panel on the orchestrator
Control panel has 3 events types :
- onRefreshHTML - run every n ( see settings ) second to detect changes in HTML control panel .
- onRefreshJSON - run every n ( see settings ) second to detect changes in JSON data container to client side .
- onInitJS - run when client reload the Orchestrator web page
. . code - block : : python
# Usage example:
lCPManager = Orchestrator . Managers . ControlPanel ( inControlPanelNameStr = " TestControlPanel " ,
inJinja2TemplatePathStr = " ControlPanel \\ test.html " , inJinja2TemplateRefreshBool = True )
inRefreshHTMLJinja2TemplatePathStr = " ControlPanel \\ test.html " , inJinja2TemplateRefreshBool = True )
If you use Jinja2 you can use next data context :
StorageRobotDict : Orchestrator . StorageRobotGet ( inRobotNameStr = self . mRobotNameStr ) ,
ControlPanelInstance : self ,
OrchestratorModule : Orchestrator ,
RequestInstance : inRequest ,
UserInfoDict : Orchestrator . WebUserInfoGet ( inRequest = inRequest ) ,
UserUACDict : Orchestrator . UACUserDictGet ( inRequest = inRequest ) ,
UserUACCheckDef : inRequest . UACClientCheck ,
EnumerateDef : enumerate ,
OperatorModule : operator ,
MathModule : math
. . code - block : : html
Hello my control panel !
You can use any def from Orchestrator module here in Jinja2 HTML template :
Example : OrchestratorModule . OSCMD ( inCMDStr = " notepad " )
{ { MathModule . pi } }
{ % if UserInfoDict [ ' UserNameUpperStr ' ] == " ND " % }
YES - IT IS ND
{ % endif % }
"""
mControlPanelNameStr = None
mJinja2TemplatePathStr = None
mJinja2TemplateFileNameStr = None
mJinja2Loader = None
mJinja2Env = None
mJinja2Template = None
# Jinja2 consolidated
mJinja2TemplateRefreshBool = None
mJinja2DataUpdateDict = None
# RefreshHTML block
mRefreshHTMLJinja2TemplatePathStr = None
mRefreshHTMLJinja2TemplateFileNameStr = None
mRefreshHTMLJinja2Loader = None
mRefreshHTMLJinja2Env = None
mRefreshHTMLJinja2Template = None
# InitJS block
mInitJSJinja2TemplatePathStr = None
mInitJSJinja2TemplateFileNameStr = None
mInitJSJinja2Loader = None
mInitJSJinja2Env = None
mInitJSJinja2Template = None
mBackwardCompatibilityHTMLDef = None
mBackwardCompatibilityJSDef = None
mBackwardCompatibilityJSONDef = None
def __init__ ( self , inControlPanelNameStr , inJinja2TemplatePathStr = None , inJinja2TemplateRefreshBool = False ) :
mRobotNameStr = None
def __init__ ( self , inControlPanelNameStr , inRefreshHTMLJinja2TemplatePathStr = None , inJinja2TemplateRefreshBool = False , inRobotNameStr = None ) :
"""
Constructor of the control panel manager
@ -37,58 +79,119 @@ class ControlPanel():
if inControlPanelNameStr in Orchestrator . GSettingsGet ( ) [ " ServerDict " ] [ " ControlPanelDict " ] :
raise Exception ( f " Another control panel with name { inControlPanelNameStr } is already exists. Please resolve the error and restart " )
Orchestrator . GSettingsGet ( ) [ " ServerDict " ] [ " ControlPanelDict " ] [ inControlPanelNameStr ] = self
self . Jinja2TemplatePathSet( inJinja2TemplatePathStr = in Jinja2TemplatePathStr)
self . RefreshHTML Jinja2TemplatePathSet( inJinja2TemplatePathStr = in RefreshHTML Jinja2TemplatePathStr)
self . mJinja2TemplateRefreshBool = inJinja2TemplateRefreshBool
self . mControlPanelNameStr = inControlPanelNameStr # Set the name of the control panel
self . mRobotNameStr = inRobotNameStr # Set the robot name for robot it execute
def Jinja2DataUpdateDictSet ( self , inJinja2DataUpdateDict ) :
"""
Set the data dict from the Jinja2 context ( you can add some new params )
: param inJinja2DataUpdateDict : dict , which will be appended to main data context
: return : None
"""
self . mJinja2DataUpdateDict = inJinja2DataUpdateDict
def RefreshHTMLJinja2TemplatePathSet ( self , inJinja2TemplatePathStr ) :
"""
Create Jinja2 env and load the template html
: param inJinja2TemplatePathStr :
: return :
"""
try :
if inJinja2TemplatePathStr is not None :
lSystemLoaderPathStr = " / " . join ( inJinja2TemplatePathStr . split ( " \\ " ) [ 0 : - 1 ] )
lTemplateFileNameStr = inJinja2TemplatePathStr . split ( " \\ " ) [ - 1 ]
self . mRefreshHTMLJinja2TemplateFileNameStr = lTemplateFileNameStr
self . mRefreshHTMLJinja2Loader = jinja2 . FileSystemLoader ( lSystemLoaderPathStr )
self . mRefreshHTMLJinja2Env = jinja2 . Environment ( loader = self . mRefreshHTMLJinja2Loader , trim_blocks = True )
self . mRefreshHTMLJinja2Template = self . mRefreshHTMLJinja2Env . get_template ( lTemplateFileNameStr )
except Exception as e :
Orchestrator . OrchestratorLoggerGet ( ) . exception ( " EXCEPTION WHEN INIT Jinja2 " )
def RefreshHTMLJinja2StrGenerate ( self , inDataDict ) :
"""
Generate the HTML str from the Jinja2 . Pass the context inDataDict
: param inDataDict :
: return :
"""
if self . mJinja2TemplateRefreshBool == True :
self . mRefreshHTMLJinja2Template = self . mRefreshHTMLJinja2Env . get_template ( self . mRefreshHTMLJinja2TemplateFileNameStr )
lHTMLStr = self . mRefreshHTMLJinja2Template . render ( * * inDataDict ) # Render the template into str
return lHTMLStr
def Jinja2TemplatePathSet ( self , inJinja2TemplatePathStr ) :
def InitJS Jinja2TemplatePathSet( self , inJinja2TemplatePathStr ) :
"""
Create Jinja2 env and load the template html
: param inJinja2TemplatePathStr :
: return :
"""
if inJinja2TemplatePathStr is not None :
lSystemLoaderPathStr = " / " . join ( inJinja2TemplatePathStr . split ( " \\ " ) [ 0 : - 1 ] )
lTemplateFileNameStr = inJinja2TemplatePathStr . split ( " \\ " ) [ - 1 ]
self . mJinja2TemplateFileNameStr = lTemplateFileNameStr
self . mJinja2Loader = jinja2 . FileSystemLoader ( lSystemLoaderPathStr )
self . mJinja2Env = jinja2 . Environment ( loader = self . mJinja2Loader , trim_blocks = True )
self . mJinja2Template = self . mJinja2Env . get_template ( lTemplateFileNameStr )
try :
if inJinja2TemplatePathStr is not None :
lSystemLoaderPathStr = " / " . join ( inJinja2TemplatePathStr . split ( " \\ " ) [ 0 : - 1 ] )
lTemplateFileNameStr = inJinja2TemplatePathStr . split ( " \\ " ) [ - 1 ]
self . mInitJSJinja2TemplateFileNameStr = lTemplateFileNameStr
self . mInitJSJinja2Loader = jinja2 . FileSystemLoader ( lSystemLoaderPathStr )
self . mInitJSJinja2Env = jinja2 . Environment ( loader = self . mInitJSJinja2Loader , trim_blocks = True )
self . mInitJSJinja2Template = self . mInitJSJinja2Env . get_template ( lTemplateFileNameStr )
except Exception as e :
Orchestrator . OrchestratorLoggerGet ( ) . exception ( " EXCEPTION WHEN INIT Jinja2 " )
def Jinja2StrGenerate ( self , inDataDict ) :
def InitJS Jinja2StrGenerate( self , inDataDict ) :
"""
Generate the HTML str from the Jinja2 . Pass the context inDataDict
: param inDataDict :
: return :
"""
if self . mJinja2TemplateRefreshBool == True :
self . mJinja2Template = self . mJinja2Env . get_template ( self . mJinja2TemplateFileNameStr )
lHTMLStr = self . mJinja2Template . render ( * * inDataDict ) # Render the template into str
self . m InitJS Jinja2Template = self . m InitJS Jinja2Env. get_template ( self . m InitJS Jinja2TemplateFileNameStr)
lHTMLStr = self . m InitJS Jinja2Template. render ( * * inDataDict ) # Render the template into str
return lHTMLStr
def DataDictGenerate ( self , inRequest ) :
"""
: param inRequest : request handler ( from http . server import BaseHTTPRequestHandler )
: return :
"""
lData = { }
lData = {
" StorageRobotDict " : None ,
" ControlPanelInstance " : self ,
" OrchestratorModule " : Orchestrator ,
" RequestInstance " : inRequest ,
" UserInfoDict " : Orchestrator . WebUserInfoGet ( inRequest = inRequest ) ,
" UserUACDict " : Orchestrator . UACUserDictGet ( inRequest = inRequest ) ,
" UserUACCheckDef " : inRequest . UACClientCheck ,
" EnumerateDef " : enumerate ,
" OperatorModule " : operator ,
" MathModule " : math
}
# Get the robot storage by the robot name (if you set robot name when init)
if self . mRobotNameStr is not None :
lData [ " StorageRobotDict " ] = Orchestrator . StorageRobotGet ( inRobotNameStr = self . mRobotNameStr )
# Checkj Jinja2DataUpdateDict
if self . mJinja2DataUpdateDict is not None :
lData . update ( self . mJinja2DataUpdateDict )
return lData
def OnRefreshHTMLStr ( self , inRequest ) :
"""
Event to generate HTML code of the control panel when refresh time is over .
Support backward compatibility for previous versions .
: param inRequest :
: param inRequest : request handler ( from http . server import BaseHTTPRequestHandler )
: return :
"""
lHTMLStr = None
lL = Orchestrator . OrchestratorLoggerGet ( )
if self . mBackwardCompatibilityHTMLDef is None :
if self . mJinja2Template is not None :
if self . m RefreshHTML Jinja2Template is not None or ( self . mJinja2TemplateRefreshBool == True and self . mRefreshHTMLJinja2TemplateFileNameStr is not None ) :
lDataDict = self . OnRefreshHTMLDataDict ( inRequest = inRequest )
# Jinja code
lHTMLStr = self . Jinja2StrGenerate ( inDataDict = lDataDict )
lHTMLStr = self . RefreshHTML Jinja2StrGenerate( inDataDict = lDataDict )
else :
lHTMLStr = self . BackwardAdapterHTMLDef ( inRequest = inRequest )
# return the str
@ -97,14 +200,27 @@ class ControlPanel():
def OnRefreshHTMLDataDict ( self , inRequest ) :
"""
Event to prepare data context for the futher Jinja2 HTML generation . You can override this def if you want some thing more data
: param inRequest : request handler ( from http . server import BaseHTTPRequestHandler )
: return : dict
"""
return self . DataDictGenerate ( inRequest = inRequest )
def OnRefreshHTMLHashStr ( self , inRequest ) :
"""
Generate the hash the result output HTML . You can override this function if you know how to optimize HTML rendering .
TODO NEED TO MODIFY ServerSettings to work with Hash because of all defs are need do use Hash
: param inRequest : request handler ( from http . server import BaseHTTPRequestHandler )
: return : None - default , hash function is not determined . Str - hash function is working on !
"""
return None
def OnRefreshJSONDict ( self , inRequest ) :
"""
Event to transmit some data from server side to the client side in JSON format . Call when page refresh is initialized
: param inRequest : request handler ( from http . server import BaseHTTPRequestHandler )
: return : Dict type
"""
lResultDict = None
@ -118,15 +234,28 @@ class ControlPanel():
"""
Event when orchestrator web page is init on the client side - you can transmit some java script code is str type to execute it once .
: param inRequest : request handler ( from http . server import BaseHTTPRequestHandler )
: return : " "
"""
lJSStr = " "
if self . mBackwardCompatibilityJSDef is None :
pass
if self . mInitJSJinja2Template is not None or ( self . mJinja2TemplateRefreshBool == True and self . mInitJSJinja2TemplateFileNameStr is not None ) :
lDataDict = self . OnInitJSDataDict ( inRequest = inRequest )
# Jinja code
lJSStr = self . InitJSJinja2StrGenerate ( inDataDict = lDataDict )
else :
lJSStr = self . BackwardAdapterJSDef ( inRequest = inRequest )
return lJSStr
def OnInitJSDataDict ( self , inRequest ) :
"""
Event to prepare data context for the futher Jinja2 JS init generation . You can override this def if you want some thing more data
: param inRequest : request handler ( from http . server import BaseHTTPRequestHandler )
: return : dict
"""
return self . DataDictGenerate ( inRequest = inRequest )
def BackwardAdapterHTMLDef ( self , inRequest ) :
lGS = Orchestrator . GSettingsGet ( )
lL = Orchestrator . OrchestratorLoggerGet ( )