mirror of https://github.com/fmartingr/iosfu.git
Working on base GUI components loader using a depth-three layout: Category->Panel->Section.
Added some fancy error/success messages.
This commit is contained in:
parent
f65e477241
commit
f084b77405
|
@ -1,4 +1,4 @@
|
|||
from flask import Flask, session, render_template, redirect, url_for
|
||||
from flask import Flask, session, render_template, redirect, url_for, flash
|
||||
|
||||
from iosfu.plugin.library import Library
|
||||
from iosfu.gui.core import GUIController
|
||||
|
@ -23,11 +23,25 @@ backup_manager = BackupManager()
|
|||
backup_manager.lookup()
|
||||
|
||||
|
||||
#
|
||||
# CONTEXT
|
||||
#
|
||||
@server.context_processor
|
||||
def backup_list():
|
||||
return dict(backups=backup_manager.backups)
|
||||
|
||||
|
||||
@server.context_processor
|
||||
def category_list():
|
||||
return dict(categories=controller._categories)
|
||||
|
||||
|
||||
@server.context_processor
|
||||
def current_section():
|
||||
# Empty so jinja can stop yelling at me
|
||||
return dict(current=dict())
|
||||
|
||||
|
||||
#
|
||||
# ROUTES
|
||||
#
|
||||
|
@ -39,23 +53,43 @@ def main():
|
|||
return render_template('main.jinja')
|
||||
|
||||
|
||||
@server.route("/<panel_id>")
|
||||
def panel(panel_id=None):
|
||||
@server.route("/<category>/")
|
||||
def category(category):
|
||||
"""
|
||||
Category
|
||||
"""
|
||||
# ctx = {'current': {'category': category}}
|
||||
panels = controller._categories[category]
|
||||
if len(panels) == 1:
|
||||
go = redirect(url_for('panel', category=category, panel_id=panels[0]))
|
||||
else:
|
||||
# TODO: List Panels? Send to main?
|
||||
go = 'TODO'
|
||||
return go
|
||||
|
||||
|
||||
@server.route("/<category>/<panel_id>/")
|
||||
def panel(category, panel_id):
|
||||
"""
|
||||
Panel
|
||||
"""
|
||||
panel = controller.load_panel(panel_id)
|
||||
return "{}".format(panel().__slug__)
|
||||
ctx = {'current': {'category': category, 'panel': panel}}
|
||||
template, context = panel.render(ctx)
|
||||
return render_template(template, **ctx)
|
||||
|
||||
|
||||
@server.route("/<panel_id>.<section_id>")
|
||||
def section(panel_id=None, section_id=None):
|
||||
@server.route("/<category>/<panel_id>/<section_id>/")
|
||||
def section(category, panel_id, section_id):
|
||||
"""
|
||||
Section
|
||||
"""
|
||||
panel = controller.load_panel(panel_id)
|
||||
section = panel.get_section(section_id)
|
||||
return "{}.{}".format(panel.__slug__, section.__slug__)
|
||||
ctx = {'current': {
|
||||
'category': category, 'panel': panel, 'section': section}}
|
||||
template, context = section.render(ctx)
|
||||
return render_template(template, **ctx)
|
||||
|
||||
|
||||
@server.route("/backup/<backup_id>/")
|
||||
|
@ -67,12 +101,17 @@ def select_backup(backup_id):
|
|||
backup = backup_manager.backups[backup_id]
|
||||
if backup.valid:
|
||||
session['backup'] = backup_id
|
||||
flash('Changed to backup {}'.format(backup_id), 'success')
|
||||
else:
|
||||
del session['backup']
|
||||
flash('The backup you selected is invalid.', 'danger')
|
||||
# Delete current selected backup -if any
|
||||
if 'backup' in session:
|
||||
del session['backup']
|
||||
except:
|
||||
# Backup is not loaded / do not exist
|
||||
# session['backup'] does not exist
|
||||
# Delete current selected backup -if any
|
||||
if 'backup' in session:
|
||||
del session['backup']
|
||||
flash('The backup you selected was not found.', 'danger')
|
||||
|
||||
return redirect(url_for('main'))
|
||||
|
|
|
@ -39,6 +39,12 @@ class GUIPanel(GUIComponent):
|
|||
if section_id in self._section_map:
|
||||
return self.sections[self._section_map[section_id]]()
|
||||
|
||||
def render(self, *args, **kwargs):
|
||||
"""
|
||||
Main render method
|
||||
"""
|
||||
return 'Base GUIPanel'
|
||||
|
||||
#
|
||||
# Privates
|
||||
#
|
||||
|
@ -74,6 +80,12 @@ class GUISection(GUIComponent):
|
|||
if not self.id and self.name:
|
||||
self.id = "{}".format(slugify(self.name))
|
||||
|
||||
def render(self, *args, **kwargs):
|
||||
"""
|
||||
Base rendering method
|
||||
"""
|
||||
return "Base GUIComponent"
|
||||
|
||||
@property
|
||||
def __slug__(self):
|
||||
return self.id
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
from importlib import import_module
|
||||
|
||||
from iosfu.utils import slugify
|
||||
from .components.base import GUIPanel
|
||||
|
||||
|
||||
|
@ -10,16 +11,29 @@ class GUIController(object):
|
|||
|
||||
_panels = {}
|
||||
_sections = {}
|
||||
_categories = {}
|
||||
|
||||
def register_panel(self, panel_component):
|
||||
"""
|
||||
Decorator to register GUIPanels
|
||||
Decorator to register GUIPanels.
|
||||
"""
|
||||
ins = panel_component()
|
||||
assert isinstance(ins, GUIPanel)
|
||||
self._panels[ins.__slug__] = panel_component
|
||||
slug = ins.__slug__
|
||||
|
||||
# Append panel to instance manager
|
||||
self._panels[slug] = panel_component
|
||||
|
||||
# Category handling
|
||||
category = slugify(ins.category)
|
||||
if ins.category not in self._categories:
|
||||
self._categories[category] = []
|
||||
self._categories[category].append(slug)
|
||||
|
||||
def load_from_library(self, library):
|
||||
"""
|
||||
Loads all available GUI modules from plugins loaded by the library.
|
||||
"""
|
||||
for k, plugin in library.plugins.items():
|
||||
plugin_module = plugin.__module__
|
||||
gui_module = "{0}.{1}".format(
|
||||
|
@ -33,5 +47,8 @@ class GUIController(object):
|
|||
print(error)
|
||||
|
||||
def load_panel(self, panel_id):
|
||||
"""
|
||||
Returns the given GUIPanel instance.
|
||||
"""
|
||||
if panel_id in self._panels:
|
||||
return self._panels[panel_id]()
|
||||
|
|
|
@ -15,12 +15,15 @@
|
|||
<nav class="navbar navbar-default navbar-static-top" role="navigation">
|
||||
<div class="container">
|
||||
<!-- Left -->
|
||||
<a class="navbar-brand" href="#">
|
||||
<a class="navbar-brand" href="/">
|
||||
iOSFU
|
||||
</a>
|
||||
<ul class="nav navbar-nav">
|
||||
<li class="active"><a href="#">Link 1</a></li>
|
||||
<li><a href="#">Link 2</a></li>
|
||||
{% for category in categories %}
|
||||
<li {% if current.category == category %}class="active"{% endif %}>
|
||||
<a href="/{{ category }}">{{ category|title }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
<!-- Right -->
|
||||
|
@ -37,13 +40,13 @@
|
|||
Change <b class="caret"></b>
|
||||
</a>
|
||||
<!-- Backup list -->
|
||||
<ul class="dropdown-menu">
|
||||
<ul class="dropdown-menu text-right">
|
||||
{% for backup_id in backups %}
|
||||
<li>
|
||||
{% if backups[backup_id].valid %}
|
||||
<a href="/backup/{{ backup_id }}/">{{ backup_id }}</a>
|
||||
{% else %}
|
||||
<a href="/backup/{{ backup_id }}/" data-toggle="tooltip" title="This backup seems invalid">
|
||||
<a href="/backup/{{ backup_id }}/" data-toggle="tooltip" title="This backup seems invalid" data-placement="left">
|
||||
{{ backup_id }}
|
||||
<span class="glyphicon glyphicon-exclamation-sign text-danger"></span>
|
||||
</a>
|
||||
|
@ -57,15 +60,41 @@
|
|||
</nav>
|
||||
|
||||
<div class="container">
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
{% for category, message in messages %}
|
||||
<div class="alert alert-{{ category }}">{{ message }}</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<ol class="breadcrumb">
|
||||
<li><a href="/">iOSFU</a></li>
|
||||
<li><a href="#">-- Plugin --</a></li>
|
||||
<li class="active">-- Section --</li>
|
||||
{% if current.category %}
|
||||
<li><a href="/{{ current.category }}/">{{ current.category|title }}</a></li>
|
||||
{% endif %}
|
||||
{% if current.panel %}
|
||||
<li class="active">
|
||||
<a href="/{{ current.category }}/{{ current.panel.id }}/">{{ current.panel.name }}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if current.section %}
|
||||
<li class="active">
|
||||
<!-- <a href="/{{ current.category }}/{{ current.panel }}/{{ current.section }}"> -->
|
||||
{{ current.section }}
|
||||
<!-- </a> -->
|
||||
</li>
|
||||
{% endif %}
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<!-- JS -->
|
||||
<script src="https://code.jquery.com/jquery.js"></script>
|
||||
<script src="/static/bootstrap/js/bootstrap.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
// Init tooltips
|
||||
$(function(){
|
||||
$('[data-toggle=tooltip]').tooltip()
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -19,7 +19,12 @@ class DeviceInfoPanel(GUIPanel):
|
|||
|
||||
name = 'Device info'
|
||||
|
||||
category = 'Base'
|
||||
|
||||
sections = [
|
||||
Main,
|
||||
VersionInfo
|
||||
]
|
||||
|
||||
def render(self, context):
|
||||
return 'main.jinja', context
|
||||
|
|
Loading…
Reference in New Issue