added example tree structure to urlish and a TODO with a lot to think about
This commit is contained in:
parent
c3cfee6bed
commit
2109e0f81e
1 changed files with 187 additions and 32 deletions
|
|
@ -21,36 +21,41 @@ You should have received a copy of the GNU Affero General Public License
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
"""
|
||||||
|
TODO:
|
||||||
|
|
||||||
|
General:
|
||||||
|
|
||||||
|
- think about if a simple scrollable list of jobs may be a lot easier to use
|
||||||
|
in combination with some tabs for job list, hostgroup jobs, host jobs etc.
|
||||||
|
i think this is a lot more flexible when reloading data. using the current
|
||||||
|
we have to rebuild the complete tree on reloading. or figure out how to
|
||||||
|
rebuild only selected nodes on reload. when using a tab/list based solution
|
||||||
|
we could even build a tab that on shows current errors, one for warnings etc.
|
||||||
|
these could we rebuild on access or on key stroke. these lists then only need
|
||||||
|
some action handlers for disabling/enabling or for showing detailed
|
||||||
|
information about the selected job. i think the tab/list approach is much
|
||||||
|
easier to handle then jumping like a monkey through a tree structure... ;)
|
||||||
|
|
||||||
|
For the tree based solution:
|
||||||
|
|
||||||
|
- remove all this global stuff and set needed stuff as arguments
|
||||||
|
|
||||||
|
- fix mouse handling; nice feature to select stuff using the mouse. currently
|
||||||
|
it raises an exception.
|
||||||
|
"""
|
||||||
|
|
||||||
import urwid
|
import urwid
|
||||||
|
|
||||||
from logging import getLogger
|
from logging import getLogger
|
||||||
|
|
||||||
from linspector.frontends.frontend import Frontend
|
from linspector.frontends.frontend import Frontend
|
||||||
|
|
||||||
__version__ = "0.1.1"
|
__version__ = "0.1.2"
|
||||||
|
|
||||||
logger = getLogger(__name__)
|
logger = getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class JobWidget(urwid.FlowWidget):
|
|
||||||
def __init__(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class JobListBox(urwid.WidgetWrap):
|
|
||||||
def __init__(self):
|
|
||||||
self.body = urwid.SimpleListWalker([])
|
|
||||||
self.listbox = urwid.ListBox(self.body)
|
|
||||||
urwid.WidgetWrap.__init__(self, self.listbox)
|
|
||||||
|
|
||||||
def keypress(self, size, key):
|
|
||||||
if key == ':':
|
|
||||||
main_frame.set_focus('footer')
|
|
||||||
command_prompt.set_caption(':')
|
|
||||||
else:
|
|
||||||
return self.listbox.keypress(size, key)
|
|
||||||
|
|
||||||
|
|
||||||
class CommandPrompt(urwid.Edit):
|
class CommandPrompt(urwid.Edit):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
urwid.Edit.__init__(self, '')
|
urwid.Edit.__init__(self, '')
|
||||||
|
|
@ -141,13 +146,91 @@ class CommandPrompt(urwid.Edit):
|
||||||
return urwid.Edit.keypress(self, size, key)
|
return urwid.Edit.keypress(self, size, key)
|
||||||
|
|
||||||
|
|
||||||
def update(main_loop, user_data):
|
class ExampleTreeWidget(urwid.TreeWidget):
|
||||||
thread_count = interface.get_thread_count()
|
def __init__(self, node):
|
||||||
header_bar.set_text(" Linspector,"
|
self.__super.__init__(node)
|
||||||
" Jobs: " + str(interface.get_job_count()) +
|
#self.expanded = False
|
||||||
" Threads: " + str(thread_count["Num Threads"]) +
|
#self.update_expanded_icon()
|
||||||
"/" + str(thread_count["Max Threads"]))
|
|
||||||
main_loop.set_alarm_in(1, update)
|
def get_display_text(self):
|
||||||
|
return self.get_node().get_value()['name']
|
||||||
|
|
||||||
|
|
||||||
|
class ExampleNode(urwid.TreeNode):
|
||||||
|
def load_widget(self):
|
||||||
|
return ExampleTreeWidget(self)
|
||||||
|
|
||||||
|
|
||||||
|
class ServiceParentNode(urwid.ParentNode):
|
||||||
|
def load_widget(self):
|
||||||
|
return ExampleTreeWidget(self)
|
||||||
|
|
||||||
|
def load_child_keys(self):
|
||||||
|
data = self.get_value()
|
||||||
|
return range(len(data['children']))
|
||||||
|
|
||||||
|
def load_child_node(self, key):
|
||||||
|
childdata = self.get_value()['children'][key]
|
||||||
|
childdepth = self.get_depth() + 1
|
||||||
|
if 'children' in childdata:
|
||||||
|
childclass = ServiceParentNode
|
||||||
|
else:
|
||||||
|
childclass = ExampleNode
|
||||||
|
return childclass(childdata, parent=self, key=key, depth=childdepth)
|
||||||
|
|
||||||
|
|
||||||
|
class HostParentNode(urwid.ParentNode):
|
||||||
|
def load_widget(self):
|
||||||
|
return ExampleTreeWidget(self)
|
||||||
|
|
||||||
|
def load_child_keys(self):
|
||||||
|
data = self.get_value()
|
||||||
|
return range(len(data['children']))
|
||||||
|
|
||||||
|
def load_child_node(self, key):
|
||||||
|
childdata = self.get_value()['children'][key]
|
||||||
|
childdepth = self.get_depth() + 1
|
||||||
|
if 'children' in childdata:
|
||||||
|
childclass = ServiceParentNode
|
||||||
|
else:
|
||||||
|
childclass = ExampleNode
|
||||||
|
return childclass(childdata, parent=self, key=key, depth=childdepth)
|
||||||
|
|
||||||
|
|
||||||
|
class HostgroupParentNode(urwid.ParentNode):
|
||||||
|
def load_widget(self):
|
||||||
|
return ExampleTreeWidget(self)
|
||||||
|
|
||||||
|
def load_child_keys(self):
|
||||||
|
data = self.get_value()
|
||||||
|
return range(len(data['children']))
|
||||||
|
|
||||||
|
def load_child_node(self, key):
|
||||||
|
childdata = self.get_value()['children'][key]
|
||||||
|
childdepth = self.get_depth() + 1
|
||||||
|
if 'children' in childdata:
|
||||||
|
childclass = HostParentNode
|
||||||
|
else:
|
||||||
|
childclass = ExampleNode
|
||||||
|
return childclass(childdata, parent=self, key=key, depth=childdepth)
|
||||||
|
|
||||||
|
|
||||||
|
class RootParentNode(urwid.ParentNode):
|
||||||
|
def load_widget(self):
|
||||||
|
return ExampleTreeWidget(self)
|
||||||
|
|
||||||
|
def load_child_keys(self):
|
||||||
|
data = self.get_value()
|
||||||
|
return range(len(data['children']))
|
||||||
|
|
||||||
|
def load_child_node(self, key):
|
||||||
|
childdata = self.get_value()['children'][key]
|
||||||
|
childdepth = self.get_depth() + 1
|
||||||
|
if 'children' in childdata:
|
||||||
|
childclass = HostgroupParentNode
|
||||||
|
else:
|
||||||
|
childclass = ExampleNode
|
||||||
|
return childclass(childdata, parent=self, key=key, depth=childdepth)
|
||||||
|
|
||||||
|
|
||||||
class UrlishFrontend(Frontend):
|
class UrlishFrontend(Frontend):
|
||||||
|
|
@ -162,26 +245,98 @@ class UrlishFrontend(Frontend):
|
||||||
global loop
|
global loop
|
||||||
global interface
|
global interface
|
||||||
|
|
||||||
palette = [('top', 'white', 'dark red'),
|
palette = [('body', 'white', 'black'),
|
||||||
|
('foot_bar', 'white', 'black'),
|
||||||
|
('top', 'white', 'dark red'),
|
||||||
('status', 'white', 'dark blue'),
|
('status', 'white', 'dark blue'),
|
||||||
('prompt', 'white', 'black')]
|
('prompt', 'white', 'black')]
|
||||||
|
|
||||||
|
foot_text = [('title', "Navigation:"), " ",
|
||||||
|
('key', "UP"), ",", ('key', "DOWN"), ",",
|
||||||
|
('key', "PAGE UP"), ",", ('key', "PAGE DOWN"),
|
||||||
|
" ",
|
||||||
|
('key', "+"), ",",
|
||||||
|
('key', "-"), " ",
|
||||||
|
('key', "LEFT"), " ",
|
||||||
|
('key', "HOME"), " ",
|
||||||
|
('key', "END")]
|
||||||
|
|
||||||
interface = linspector_interface
|
interface = linspector_interface
|
||||||
|
|
||||||
|
top_node = RootParentNode(get_example_tree())
|
||||||
|
job_list_box = urwid.TreeListBox(urwid.TreeWalker(top_node))
|
||||||
|
job_list_box.offset_rows = 1
|
||||||
|
|
||||||
header_message = ' Linspector (' + str(linspector_interface.get_version()) + ')'
|
header_message = ' Linspector (' + str(linspector_interface.get_version()) + ')'
|
||||||
header_bar = urwid.Text(header_message, align='left')
|
header_bar = urwid.Text(header_message, align='left')
|
||||||
header = urwid.Pile([urwid.AttrMap(header_bar, 'top')])
|
header = urwid.Pile([urwid.AttrMap(header_bar, 'top')])
|
||||||
|
|
||||||
command_prompt = CommandPrompt()
|
command_prompt = CommandPrompt()
|
||||||
|
|
||||||
|
foot_bar = urwid.Text(foot_text, align='left')
|
||||||
|
|
||||||
welcome_message = ' Type ":h <Enter>" for help, ":q <Enter>" to quit'
|
welcome_message = ' Type ":h <Enter>" for help, ":q <Enter>" to quit'
|
||||||
status_bar = urwid.Text(welcome_message, align='left')
|
status_bar = urwid.Text(welcome_message, align='left')
|
||||||
footer = urwid.Pile([urwid.AttrMap(status_bar, 'status'), urwid.AttrMap(command_prompt, 'prompt')])
|
footer = urwid.Pile([urwid.AttrMap(foot_bar, 'foot_bar'),
|
||||||
|
urwid.AttrMap(status_bar, 'status'),
|
||||||
job_list_box = JobListBox()
|
urwid.AttrMap(command_prompt, 'prompt')])
|
||||||
|
|
||||||
main_frame = urwid.Frame(body=job_list_box, header=header, footer=footer)
|
main_frame = urwid.Frame(body=job_list_box, header=header, footer=footer)
|
||||||
|
|
||||||
loop = urwid.MainLoop(main_frame, palette)
|
loop = urwid.MainLoop(main_frame, palette, unhandled_input=self.unhandled_input, handle_mouse=False)
|
||||||
loop.set_alarm_in(0, update)
|
loop.set_alarm_in(0, update)
|
||||||
loop.run()
|
loop.run()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def unhandled_input(key):
|
||||||
|
if key in (':'):
|
||||||
|
main_frame.set_focus('footer')
|
||||||
|
command_prompt.set_caption(':')
|
||||||
|
elif key in ('c'):
|
||||||
|
#collapse all children of current node
|
||||||
|
pass
|
||||||
|
elif key in ('C'):
|
||||||
|
#collapse all nodes
|
||||||
|
pass
|
||||||
|
elif key in ('d'):
|
||||||
|
#disable all jobs for current node
|
||||||
|
pass
|
||||||
|
elif key in ('e'):
|
||||||
|
#enable all jobs for current node
|
||||||
|
pass
|
||||||
|
elif key in ('r'):
|
||||||
|
#reload child data of current node
|
||||||
|
pass
|
||||||
|
elif key in ('R'):
|
||||||
|
#reload child data of all nodes
|
||||||
|
pass
|
||||||
|
elif key in ('x'):
|
||||||
|
#expand all children of current node
|
||||||
|
pass
|
||||||
|
elif key in ('X'):
|
||||||
|
#expand all nodes
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def update(main_loop, user_data):
|
||||||
|
thread_count = interface.get_thread_count()
|
||||||
|
header_bar.set_text(" Linspector,"
|
||||||
|
" Jobs: " + str(interface.get_job_count()) +
|
||||||
|
" Threads: " + str(thread_count["Num Threads"]) +
|
||||||
|
"/" + str(thread_count["Max Threads"]))
|
||||||
|
main_loop.set_alarm_in(1, update)
|
||||||
|
|
||||||
|
|
||||||
|
def get_example_tree():
|
||||||
|
retval = {"name": "ROOT", "children": []}
|
||||||
|
for i in range(10):
|
||||||
|
retval['children'].append({"name": "HOSTGROUP " + str(i)})
|
||||||
|
retval['children'][i]['children'] = []
|
||||||
|
for j in range(5):
|
||||||
|
retval['children'][i]['children'].append({"name": "HOST " + str(i) + "." + str(j)})
|
||||||
|
retval['children'][i]['children'][j]['children'] = []
|
||||||
|
for k in range(3):
|
||||||
|
retval['children'][i]['children'][j]['children'].append({"name": "SERVICE " + str(i) +
|
||||||
|
"." + str(j) +
|
||||||
|
"." + str(k)})
|
||||||
|
return retval
|
||||||
Loading…
Add table
Add a link
Reference in a new issue