Tentative Web UI for the Printer device. (#676)

* Tentative Web UI for the Printer device.

* timeout must be a positive value

* Change the attach device class method to accept a dict with arbitrary key value pairs of parameters to be passed to the protobuf interface, rather than hard coded ones. Also renames the RaCtlCmds.attach_image() class method to attach_device().

* Make download_to_iso() use the new attach interface.

* Dynamically get the form items for support devices.

* Change the data structure returned by RaCtlCmds.get_device_types() to a dict, which contains the supported parameters and their default values. Leverage this data in the web ui to derive the form fields from the capabilities of rascsi.

* Tweak UI labels.

* Update FileCmds.read_config() to work with the new RaCtlCmds.attach_device() method.

* Check for numeric value.

* Streamline the UI for support devices.

* Handle support devices better by the oled screen.

* Clean up html.

* Dynamically adjust form field size based on data length.
This commit is contained in:
Daniel Markstedt 2022-02-19 00:04:14 -08:00 committed by GitHub
parent 81ca3c0ce8
commit 2184992ce7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 97 additions and 72 deletions

View File

@ -8,7 +8,7 @@ WORK_DIR = getcwd()
REMOVABLE_DEVICE_TYPES = ("SCCD", "SCRM", "SCMO") REMOVABLE_DEVICE_TYPES = ("SCCD", "SCRM", "SCMO")
NETWORK_DEVICE_TYPES = ("SCDP", "SCBR") NETWORK_DEVICE_TYPES = ("SCDP", "SCBR")
SUPPORT_DEVICE_TYPES = ("SCHS", ) SUPPORT_DEVICE_TYPES = ("SCLP", "SCHS")
# There may be a more elegant way to get the HOME dir of the user that installed RaSCSI # There may be a more elegant way to get the HOME dir of the user that installed RaSCSI
HOME_DIR = "/".join(WORK_DIR.split("/")[0:3]) HOME_DIR = "/".join(WORK_DIR.split("/")[0:3])

View File

@ -450,17 +450,16 @@ class FileCmds:
for row in config["devices"]: for row in config["devices"]:
kwargs = { kwargs = {
"device_type": row["device_type"], "device_type": row["device_type"],
"image": row["image"],
"unit": int(row["unit"]), "unit": int(row["unit"]),
"vendor": row["vendor"], "vendor": row["vendor"],
"product": row["product"], "product": row["product"],
"revision": row["revision"], "revision": row["revision"],
"block_size": row["block_size"], "block_size": row["block_size"],
"params": dict(row["params"]),
} }
params = dict(row["params"]) if row["image"]:
for param in params.keys(): kwargs["params"]["file"] = row["image"]
kwargs[param] = params[param] self.ractl.attach_device(row["id"], **kwargs)
self.ractl.attach_image(row["id"], **kwargs)
# The config file format in RaSCSI 21.10 is using a list data type at the top level. # The config file format in RaSCSI 21.10 is using a list data type at the top level.
# If future config file formats return to the list data type, # If future config file formats return to the list data type,
# introduce more sophisticated format detection logic here. # introduce more sophisticated format detection logic here.
@ -470,17 +469,17 @@ class FileCmds:
kwargs = { kwargs = {
"device_type": row["device_type"], "device_type": row["device_type"],
"image": row["image"], "image": row["image"],
# "un" for backwards compatibility
"unit": int(row["un"]), "unit": int(row["un"]),
"vendor": row["vendor"], "vendor": row["vendor"],
"product": row["product"], "product": row["product"],
"revision": row["revision"], "revision": row["revision"],
"block_size": row["block_size"], "block_size": row["block_size"],
"params": dict(row["params"]),
} }
params = dict(row["params"]) if row["image"]:
for param in params.keys(): kwargs["params"]["file"] = row["image"]
kwargs[param] = params[param] self.ractl.attach_device(row["id"], **kwargs)
self.ractl.attach_image(row["id"], **kwargs) logging.warning("%s is in an obsolete config file format", file_name)
else: else:
return {"status": False, return {"status": False,
"return_code": ReturnCodes.READCONFIG_INVALID_CONFIG_FILE_FORMAT} "return_code": ReturnCodes.READCONFIG_INVALID_CONFIG_FILE_FORMAT}

View File

@ -125,7 +125,8 @@ class RaCtlCmds:
Sends a DEVICE_TYPES_INFO command to the server. Sends a DEVICE_TYPES_INFO command to the server.
Returns a dict with: Returns a dict with:
- (bool) status - (bool) status
- (list) of (str) device_types (device types that RaSCSI supports, ex. SCHD, SCCD, etc) - (dict) device_types, where keys are the four letter device type acronym,
and the value is a (dict) of supported parameters and their default values.
""" """
command = proto.PbCommand() command = proto.PbCommand()
command.operation = proto.PbOperation.DEVICE_TYPES_INFO command.operation = proto.PbOperation.DEVICE_TYPES_INFO
@ -135,9 +136,13 @@ class RaCtlCmds:
data = self.sock_cmd.send_pb_command(command.SerializeToString()) data = self.sock_cmd.send_pb_command(command.SerializeToString())
result = proto.PbResult() result = proto.PbResult()
result.ParseFromString(data) result.ParseFromString(data)
device_types = [] device_types = {}
for prop in result.device_types_info.properties: import logging
device_types.append(proto.PbDeviceType.Name(prop.type)) for device in result.device_types_info.properties:
params = {}
for key, value in device.properties.default_params.items():
params[key] = value
device_types[proto.PbDeviceType.Name(device.type)] = params
return {"status": result.status, "device_types": device_types} return {"status": result.status, "device_types": device_types}
def get_image_files_info(self): def get_image_files_info(self):
@ -167,7 +172,7 @@ class RaCtlCmds:
"scan_depth": scan_depth, "scan_depth": scan_depth,
} }
def attach_image(self, scsi_id, **kwargs): def attach_device(self, scsi_id, **kwargs):
""" """
Takes (int) scsi_id and kwargs containing 0 or more device properties Takes (int) scsi_id and kwargs containing 0 or more device properties
@ -185,14 +190,15 @@ class RaCtlCmds:
devices.id = int(scsi_id) devices.id = int(scsi_id)
if "device_type" in kwargs.keys(): if "device_type" in kwargs.keys():
if kwargs["device_type"] not in [None, ""]: if kwargs["device_type"]:
devices.type = proto.PbDeviceType.Value(str(kwargs["device_type"])) devices.type = proto.PbDeviceType.Value(str(kwargs["device_type"]))
if "unit" in kwargs.keys(): if "unit" in kwargs.keys():
if kwargs["unit"] not in [None, ""]: if kwargs["unit"]:
devices.unit = kwargs["unit"] devices.unit = kwargs["unit"]
if "image" in kwargs.keys(): if "params" in kwargs.keys():
if kwargs["image"] not in [None, ""]: if isinstance(kwargs["params"], dict):
devices.params["file"] = kwargs["image"] for param in kwargs["params"]:
devices.params[param] = kwargs["params"][param]
# Handling the inserting of media into an attached removable type device # Handling the inserting of media into an attached removable type device
device_type = kwargs.get("device_type", None) device_type = kwargs.get("device_type", None)
@ -214,23 +220,21 @@ class RaCtlCmds:
"parameters": parameters, "parameters": parameters,
} }
command.operation = proto.PbOperation.INSERT command.operation = proto.PbOperation.INSERT
# Handling attaching a new device # Handling attaching a new device
else: else:
command.operation = proto.PbOperation.ATTACH command.operation = proto.PbOperation.ATTACH
if "interfaces" in kwargs.keys():
if kwargs["interfaces"] not in [None, ""]:
devices.params["interfaces"] = kwargs["interfaces"]
if "vendor" in kwargs.keys(): if "vendor" in kwargs.keys():
if kwargs["vendor"] is not None: if kwargs["vendor"]:
devices.vendor = kwargs["vendor"] devices.vendor = kwargs["vendor"]
if "product" in kwargs.keys(): if "product" in kwargs.keys():
if kwargs["product"] is not None: if kwargs["product"]:
devices.product = kwargs["product"] devices.product = kwargs["product"]
if "revision" in kwargs.keys(): if "revision" in kwargs.keys():
if kwargs["revision"] is not None: if kwargs["revision"]:
devices.revision = kwargs["revision"] devices.revision = kwargs["revision"]
if "block_size" in kwargs.keys(): if "block_size" in kwargs.keys():
if kwargs["block_size"] not in [None, ""]: if kwargs["block_size"]:
devices.block_size = int(kwargs["block_size"]) devices.block_size = int(kwargs["block_size"])
command.devices.append(devices) command.devices.append(devices)

View File

@ -188,9 +188,11 @@ def formatted_output():
else: else:
output.append(f"{line['id']} {line['device_type'][2:4]} {line['status']}") output.append(f"{line['id']} {line['device_type'][2:4]} {line['status']}")
# Special handling of devices that don't use image files # Special handling of devices that don't use image files
elif line["device_type"] in (NETWORK_DEVICE_TYPES + SUPPORT_DEVICE_TYPES): elif line["device_type"] in (NETWORK_DEVICE_TYPES):
output.append(f"{line['id']} {line['device_type'][2:4]} {line['vendor']} " output.append(f"{line['id']} {line['device_type'][2:4]} {line['vendor']} "
f"{line['product']}") f"{line['product']}")
elif line["device_type"] in (SUPPORT_DEVICE_TYPES):
output.append(f"{line['id']} {line['device_type'][2:4]} {line['product']}")
# Print only the Vendor/Product info if it's not generic RaSCSI # Print only the Vendor/Product info if it's not generic RaSCSI
elif line["vendor"] not in "RaSCSI": elif line["vendor"] not in "RaSCSI":
output.append(f"{line['id']} {line['device_type'][2:4]} {line['file']} " output.append(f"{line['id']} {line['device_type'][2:4]} {line['file']} "

View File

@ -68,13 +68,15 @@ def extend_device_names(device_types):
elif device_type == "SCMO": elif device_type == "SCMO":
device_name = _("Magneto-Optical") device_name = _("Magneto-Optical")
elif device_type == "SCCD": elif device_type == "SCCD":
device_name = _("CD-ROM / DVD") device_name = _("CD / DVD")
elif device_type == "SCBR": elif device_type == "SCBR":
device_name = _("X68000 Host Bridge") device_name = _("X68000 Host Bridge")
elif device_type == "SCDP": elif device_type == "SCDP":
device_name = _("DaynaPORT SCSI/Link") device_name = _("DaynaPORT SCSI/Link")
elif device_type == "SCLP":
device_name = _("Printer")
elif device_type == "SCHS": elif device_type == "SCHS":
device_name = _("Host Service") device_name = _("Host Services")
else: else:
device_name = _("Unknown Device") device_name = _("Unknown Device")
mapped_device_types[device_type] = device_name mapped_device_types[device_type] = device_name

View File

@ -316,17 +316,6 @@
<tr style="border: none"> <tr style="border: none">
<td style="border: none; vertical-align:top;"> <td style="border: none; vertical-align:top;">
<form action="/scsi/attach_network" method="post"> <form action="/scsi/attach_network" method="post">
<label for="if">{{ _("Interface:") }}</label>
<select name="if">
{% for if in netinfo["ifs"] %}
<option value="{{ if }}">
{{ if }}
</option>
{% endfor %}
</select>
<label for="ip">{{ _("Static IP (optional):") }}</label>
<input name="ip" type="text" size="15" placeholder="10.10.20.1" minlength="7" maxlength="15" pattern="^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$">
<input name="mask" type="number" size="2" placeholder="24" min="16" max="30">
<label for="type">{{ _("Type:") }}</label> <label for="type">{{ _("Type:") }}</label>
<select name="type"> <select name="type">
{% for type in NETWORK_DEVICE_TYPES %} {% for type in NETWORK_DEVICE_TYPES %}
@ -339,6 +328,17 @@
</option> </option>
{% endfor %} {% endfor %}
</select> </select>
<label for="if">{{ _("Interface:") }}</label>
<select name="if">
{% for if in netinfo["ifs"] %}
<option value="{{ if }}">
{{ if }}
</option>
{% endfor %}
</select>
<label for="ip">{{ _("Static IP (optional):") }}</label>
<input name="ip" type="text" size="15" placeholder="10.10.20.1" minlength="7" maxlength="15" pattern="^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$">
<input name="mask" type="number" size="2" placeholder="24" min="16" max="30">
<label for="scsi_id">{{ _("SCSI ID:") }}</label> <label for="scsi_id">{{ _("SCSI ID:") }}</label>
<select name="scsi_id"> <select name="scsi_id">
{% for id in scsi_ids %} {% for id in scsi_ids %}
@ -372,22 +372,23 @@
</li> </li>
</ul> </ul>
</details> </details>
<table style="border: none"> <table border="black" cellpadding="3">
<tr style="border: none"> {% for type in SUPPORT_DEVICE_TYPES %}
<td style="border: none; vertical-align:top;"> <tr>
<td>
<div>{{ _("Type:") }} <strong>{{ device_types[type] }}</strong></div>
</td>
<td>
<form action="/scsi/attach_support" method="post"> <form action="/scsi/attach_support" method="post">
<label for="type">{{ _("Type:") }}</label> <input name="type" type="hidden" value="{{ type }}">
<select name="type"> {% for key, value in device_params[type].items() %}
{% for type in SUPPORT_DEVICE_TYPES %} <label for="{{ key }}">{{ key }}:</label>
<option value="{{ type }}"> {% if value.isnumeric() %}
{% for key, value in device_types.items() %} <input name="{{ key }}" type="number" size="{{ value|length }}" value="{{ value }}">
{% if key == type %} {% else %}
{{ value }} <input name="{{ key }}" type="text" size="{{ value|length }}" value="{{ value }}">
{% endif %} {% endif %}
{% endfor %} {% endfor %}
</option>
{% endfor %}
</select>
<label for="scsi_id">{{ _("SCSI ID:") }}</label> <label for="scsi_id">{{ _("SCSI ID:") }}</label>
<select name="scsi_id"> <select name="scsi_id">
{% for id in scsi_ids %} {% for id in scsi_ids %}
@ -402,6 +403,7 @@
</form> </form>
</td> </td>
</tr> </tr>
{% endfor %}
</table> </table>
<hr/> <hr/>

View File

@ -117,7 +117,7 @@ def index():
image_files = file_cmds.list_images() image_files = file_cmds.list_images()
config_files = file_cmds.list_config_files() config_files = file_cmds.list_config_files()
mapped_device_types = extend_device_names(device_types["device_types"]) mapped_device_types = extend_device_names(device_types["device_types"].keys())
extended_image_files = [] extended_image_files = []
for image in image_files["files"]: for image in image_files["files"]:
@ -180,6 +180,7 @@ def index():
current_log_level=server_info["current_log_level"], current_log_level=server_info["current_log_level"],
netinfo=ractl.get_network_info(), netinfo=ractl.get_network_info(),
device_types=mapped_device_types, device_types=mapped_device_types,
device_params=device_types["device_types"],
free_disk=int(disk["free"] / 1024 / 1024), free_disk=int(disk["free"] / 1024 / 1024),
valid_file_suffix=valid_file_suffix, valid_file_suffix=valid_file_suffix,
cdrom_file_suffix=tuple(server_info["sccd"]), cdrom_file_suffix=tuple(server_info["sccd"]),
@ -501,11 +502,23 @@ def attach_support_device():
""" """
Attaches a support device Attaches a support device
""" """
scsi_id = request.form.get("scsi_id") params = {}
unit = request.form.get("unit") for item in request.form:
device_type = request.form.get("type") if item == "scsi_id":
kwargs = {"unit": int(unit), "device_type": device_type} scsi_id = request.form.get(item)
process = ractl.attach_image(scsi_id, **kwargs) elif item == "unit":
unit = request.form.get(item)
elif item == "type":
device_type = request.form.get(item)
else:
params.update({item: request.form.get(item)})
kwargs = {
"unit": int(unit),
"device_type": device_type,
"params": params,
}
process = ractl.attach_device(scsi_id, **kwargs)
process = ReturnCodeMapper.add_msg(process) process = ReturnCodeMapper.add_msg(process)
if process["status"]: if process["status"]:
flash(_( flash(_(
@ -525,7 +538,7 @@ def attach_support_device():
@APP.route("/scsi/attach_network", methods=["POST"]) @APP.route("/scsi/attach_network", methods=["POST"])
@login_required @login_required
def attach_network_adapter(): def attach_network_device():
""" """
Attaches a network adapter device Attaches a network adapter device
""" """
@ -560,12 +573,11 @@ def attach_network_adapter():
kwargs = {"unit": int(unit), "device_type": device_type} kwargs = {"unit": int(unit), "device_type": device_type}
if interface != "": if interface != "":
arg = interface
if "" not in (ip_addr, mask): if "" not in (ip_addr, mask):
arg += (":" + ip_addr + "/" + mask) interface += (":" + ip_addr + "/" + mask)
kwargs["interfaces"] = arg kwargs["params"] = {"interfaces": interface}
process = ractl.attach_image(scsi_id, **kwargs) process = ractl.attach_device(scsi_id, **kwargs)
process = ReturnCodeMapper.add_msg(process) process = ReturnCodeMapper.add_msg(process)
if process["status"]: if process["status"]:
flash(_( flash(_(
@ -585,7 +597,7 @@ def attach_network_adapter():
@APP.route("/scsi/attach", methods=["POST"]) @APP.route("/scsi/attach", methods=["POST"])
@login_required @login_required
def attach(): def attach_image():
""" """
Attaches a file image as a device Attaches a file image as a device
""" """
@ -595,7 +607,7 @@ def attach():
unit = request.form.get("unit") unit = request.form.get("unit")
device_type = request.form.get("type") device_type = request.form.get("type")
kwargs = {"unit": int(unit), "image": file_name} kwargs = {"unit": int(unit), "params": {"file": file_name}}
# The most common block size is 512 bytes # The most common block size is 512 bytes
expected_block_size = 512 expected_block_size = 512
@ -623,7 +635,7 @@ def attach():
kwargs["block_size"] = conf["block_size"] kwargs["block_size"] = conf["block_size"]
expected_block_size = conf["block_size"] expected_block_size = conf["block_size"]
process = ractl.attach_image(scsi_id, **kwargs) process = ractl.attach_device(scsi_id, **kwargs)
process = ReturnCodeMapper.add_msg(process) process = ReturnCodeMapper.add_msg(process)
if process["status"]: if process["status"]:
flash(_("Attached %(file_name)s to SCSI ID %(id_number)s LUN %(unit_number)s", flash(_("Attached %(file_name)s to SCSI ID %(id_number)s LUN %(unit_number)s",
@ -812,7 +824,11 @@ def download_to_iso():
flash(process["msg"], "error") flash(process["msg"], "error")
return redirect(url_for("index")) return redirect(url_for("index"))
process_attach = ractl.attach_image(scsi_id, device_type="SCCD", image=process["file_name"]) process_attach = ractl.attach_device(
scsi_id,
device_type="SCCD",
params={"file": process["file_name"]},
)
process_attach = ReturnCodeMapper.add_msg(process_attach) process_attach = ReturnCodeMapper.add_msg(process_attach)
if process_attach["status"]: if process_attach["status"]:
flash(_("Attached to SCSI ID %(id_number)s", id_number=scsi_id)) flash(_("Attached to SCSI ID %(id_number)s", id_number=scsi_id))