new files for version 2.1, themes, modular css

pull/10/head
Steve Nyemba 4 months ago
parent 8b119a7133
commit 9b035b9950

@ -0,0 +1,28 @@
"""
This file handles all things configuration i.e even the parts of the configuration we are interested in
"""
import os
import json
def get (path) :
if os.path.exists(path) :
f = open(path)
_conf = json.loads(f.read())
f.close()
else:
_conf = {}
return _conf
def _isvalid(_allowed,**_args):
if not list(set(_allowed) - set(_args.keys())) :
_pargs = {}
for key in _allowed :
_pargs [key] = _args[key]
return _pargs
return False
def write(_config, path):
f = open(path,'w')
f.write( json.dumps(_config)) ;
f.close()

@ -0,0 +1,77 @@
"""
This file handles the structure (strict) of the configuration file,
Not all elements are programmatically editable (for now)
"""
import meta
class Section :
def build (self,**_args):
_data = {}
for _attr in dir(self):
if not _attr.startswith('_') and _attr not in ['build','update']:
_kwargs = _args if _attr not in _args or type(_args[_attr]) !=dict else _args[_attr]
_data[_attr] = getattr(self,_attr)(**_kwargs)
_name = type (self).__name__.lower()
return {_name:_data }
def update(self,_default,**_args) :
for _attr in _default.keys():
if _attr in _args :
_default[_attr] = _args[_attr]
return _default
class System (Section) :
def logo(self,**_args):
return 'www/html/_assets/images/logo.png' if 'logo' not in _args else _args['logo']
def theme (self,**_args):
"""
setting the theme given the name of the theme
:name name of the theme to set (optional)
"""
return 'default' if 'name' not in _args else _args['name']
def version(self,**_args):
return meta.__version__ if 'version' not in _args else _args['version']
def context (self,**_args):
return "" if 'context' not in _args else _args['context']
def app (self,**_args):
_data = {'debug':True,'port':8084,'threaded':True,'host':'0.0.0.0'}
return self.update(_data,**_args)
def source(self,**_args):
_data = {'id':'disk'}
if set(['key','auth']) & set(_args.keys()):
#
# key: reboot the app & auth: for cloud access
#
for _attr in ['key','auth'] :
if _attr in _args:
_data[_attr] = _args[_attr]
_data = self.update(_data,**_args)
return _data
class Layout (Section):
def index (self,**_args):
return "index.html" if 'index' not in _args else _args['index']
def root(self,**_args):
return 'wwww/html' if 'root' not in _args else _args['root']
def footer(self,**_args):
return [{'text':'Powered by QCMS'}] if 'footer' not in _args else _args['footer']
def on(self,**_args):
return {'load':{}} if 'on' not in _args else _args['on']
def order(self,**_args):
return {'menu':[]} if 'order' not in _args else _args['order']
# def menu (self,**_args):
# return {'menu':[]} if 'menu' not in _args else _args['menu']
def overwrite(self,**_args):
return {}
def header (self,**_args):
_data = {"title":"QCMS Project", "subtitle":"Powered by Python Flask"}
return self.update(_data,**_args)

@ -0,0 +1,42 @@
import json
import pandas as pd
import importlib
import importlib.util
import os
def stats (_config) :
"""
Returns the statistics of the plugins
"""
_data = []
for _name in _config :
_log = {"files":_name,"loaded":len(_config[_name]),"logs":json.dumps(_config[_name])}
_data.append(_log)
return pd.DataFrame(_data)
pass
def load(_path,_filename,_name) :
"""
This function will load external module form a given location and return a pointer to a function in a given module
:path absolute path of the file (considered plugin) to be loaded
:name name of the function to be applied
"""
# _path = _args['path'] #os.sep.join([_args['root'],'plugin'])
if os.path.isdir(_path):
files = os.listdir(_path)
if files :
files = [name for name in files if name.endswith('.py') and name == _filename]
if files:
_path = os.sep.join([_path,files[0]])
else:
return None
else:
return None
#-- We have a file ...
# _name = _args['name']
spec = importlib.util.spec_from_file_location(_filename, _path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return getattr(module,_name) if hasattr(module,_name) else None

File diff suppressed because one or more lines are too long

@ -0,0 +1,44 @@
"""
This class implements the base infrastructure to handle themes, the class must leverage
default themes will be stored in layout.root._assets.themes, The expected files in a theme are the following:
- borders
- buttons
- layout
- menu
- header
If the following are not available then we should load the default one.
This would avoid crashes but would come at the expense of a lack of consistent visual layout (alas)
"""
import requests
import os
URL = os.environ['QCMS_HOME_URL'] if 'QCMS_HOME_URL' in os.environ else 'https://dev.the-phi.com/qcms'
def current (_system) :
return _system['theme']
def List (_url = URL) :
"""
calling qcms to list the available URL
"""
try:
_url = '/'.join([_url,'api','themes','List'])
return requests.get(_url).json()
except Exception as e:
pass
return []
def Get(theme,_url= URL) :
"""
This function retrieves a particular theme from a remote source
The name should be in the list provided by the above function
"""
try:
_url = '/'.join([_url,'api','themes','Get']) +f'?theme={theme}'
return requests.get(_url).json()
except Exception as e:
pass
return {}
def installed (path):
return os.listdir(os.sep.join([path,'_assets','themes']))
def Set(theme,_system) :
_system['theme'] = theme
return _system

@ -0,0 +1,10 @@
.dialog-title {
background-color:#FF6500;color:#FFFFFF;
text-transform:capitalize; font-weight:bold; align-items:center;display:grid; grid-template-columns:auto 32px;
}
.dialog-button {
display:grid;
grid-template-columns: auto 115px;
gap:4px;
}

@ -0,0 +1,18 @@
.source-code {
background-color: #000000; COLOR:#ffffff;
font-family: 'Courier New', Courier, monospace;
padding:8px;
padding-left:10px;
text-wrap: wrap;
width:calc(100% - 40px);
border-left:8px solid #CAD5E0; margin-left:10px; font-weight: bold;
font-size:14px;
}
.editor {
background-color:#f3f3f3;
color:#000000;
}
.editor .keyword {color: #4682b4; font-weight:bold}
.code-comment { font-style: italic; color:gray; font-size:13px;}
Loading…
Cancel
Save