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