implement run tool that allows running command on more than one node conveniently

This commit is contained in:
Huy Pham 2020-04-22 15:38:29 -07:00
parent 20ecdf70d0
commit 03e291d215
3 changed files with 137 additions and 0 deletions

11
Pipfile Normal file
View file

@ -0,0 +1,11 @@
[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true
[dev-packages]
[packages]
[requires]
python_version = "3.7"

View file

@ -0,0 +1,123 @@
import tkinter as tk
from tkinter import ttk
from core.api.grpc import core_pb2
from core.gui.dialogs.dialog import Dialog
from core.gui.themes import FRAME_PAD, PADY
from core.gui.widgets import CodeText, ListboxScroll
class RunToolDialog(Dialog):
def __init__(self, master, app):
super().__init__(master, app, "Run Tool", modal=True)
self.cmd = tk.StringVar(value="ps ax")
self.app = app
self.result = None
self.node_list = None
self.executable_nodes = {}
self.store_nodes()
self.draw()
def store_nodes(self):
"""
store all CORE nodes (nodes that execute commands) from all existing nodes
"""
for nid, node in self.app.core.canvas_nodes.items():
if node.core_node.type == core_pb2.NodeType.DEFAULT:
self.executable_nodes[node.core_node.name] = nid
def draw(self):
self.top.rowconfigure(0, weight=1)
self.top.columnconfigure(0, weight=5)
self.top.columnconfigure(1, weight=1)
self.draw_command_frame()
self.draw_nodes_frame()
return
def draw_command_frame(self):
# the main frame
frame = ttk.Frame(self.top)
frame.grid(row=0, column=0, sticky="nsew")
frame.columnconfigure(0, weight=1)
frame.rowconfigure(0, weight=1)
frame.rowconfigure(1, weight=1)
labeled_frame = ttk.LabelFrame(frame, text="Command line", padding=FRAME_PAD)
labeled_frame.grid(row=0, column=0, sticky="nsew", pady=PADY)
labeled_frame.rowconfigure(0, weight=1)
labeled_frame.columnconfigure(0, weight=1)
entry = ttk.Entry(labeled_frame, textvariable=self.cmd)
entry.grid(sticky="ew")
# results frame
labeled_frame = ttk.LabelFrame(frame, text="Command results", padding=FRAME_PAD)
labeled_frame.grid(row=1, column=0, sticky="nsew", pady=PADY)
labeled_frame.columnconfigure(0, weight=1)
labeled_frame.rowconfigure(0, weight=5)
labeled_frame.rowconfigure(1, weight=1)
self.result = CodeText(labeled_frame)
self.result.text.config(state=tk.DISABLED, height=15)
self.result.grid(sticky="nsew")
button_frame = ttk.Frame(labeled_frame, padding=FRAME_PAD)
button_frame.grid(sticky="nsew")
button_frame.columnconfigure(0, weight=1)
button_frame.columnconfigure(1, weight=1)
button = ttk.Button(button_frame, text="Run", command=self.click_run)
button.grid(sticky="nsew")
button = ttk.Button(button_frame, text="Close", command=self.destroy)
button.grid(row=0, column=1, sticky="nsew")
def draw_nodes_frame(self):
labeled_frame = ttk.LabelFrame(
self.top, text="Run on these nodes", padding=FRAME_PAD
)
labeled_frame.grid(row=0, column=1, sticky="nsew")
labeled_frame.columnconfigure(0, weight=1)
labeled_frame.rowconfigure(0, weight=5)
labeled_frame.rowconfigure(1, weight=1)
self.node_list = ListboxScroll(labeled_frame)
self.node_list.listbox.config(selectmode=tk.MULTIPLE)
self.node_list.grid(sticky="nsew")
for n in sorted(self.executable_nodes.keys()):
self.node_list.listbox.insert(tk.END, n)
button_frame = ttk.Frame(labeled_frame, padding=FRAME_PAD)
button_frame.grid(sticky="nsew")
button_frame.columnconfigure(0, weight=1)
button_frame.columnconfigure(1, weight=1)
button = ttk.Button(button_frame, text="All", command=self.click_all)
button.grid(sticky="nsew")
button = ttk.Button(button_frame, text="None", command=self.click_none)
button.grid(row=0, column=1, sticky="nsew")
def click_all(self):
self.node_list.listbox.selection_set(0, self.node_list.listbox.size() - 1)
def click_none(self):
self.node_list.listbox.selection_clear(0, self.node_list.listbox.size() - 1)
def click_run(self):
"""
run the command on each of the selected nodes and display the output to result text box
"""
command = self.cmd.get().strip()
self.result.text.config(state=tk.NORMAL)
self.result.text.delete("1.0", tk.END)
self.result.text.insert(
tk.END, f"> {command}\n" * len(self.node_list.listbox.curselection())
)
for selection in self.node_list.listbox.curselection():
node_name = self.node_list.listbox.get(selection)
node_id = self.executable_nodes[node_name]
response = self.app.core.client.node_command(
self.app.core.session_id, node_id, command
)
self.result.text.insert(
tk.END, f"> {node_name} > {command}:\n{response.output}\n"
)
self.result.text.config(state=tk.DISABLED)

View file

@ -9,6 +9,7 @@ from typing import TYPE_CHECKING, Callable
from core.api.grpc import core_pb2
from core.gui.dialogs.customnodes import CustomNodesDialog
from core.gui.dialogs.marker import MarkerDialog
from core.gui.dialogs.runtool import RunToolDialog
from core.gui.graph.enums import GraphMode
from core.gui.graph.shapeutils import ShapeType, is_marker
from core.gui.images import ImageEnum, Images
@ -485,6 +486,8 @@ class Toolbar(ttk.Frame):
def click_run_button(self):
logging.debug("Click on RUN button")
dialog = RunToolDialog(self.app, self.app)
dialog.show()
def click_marker_button(self):
logging.debug("Click on marker button")