Address Sonarcloud issues for the html code; improve on css styles (#892)

Refactor and clean up code to conform to SonarCloud static analysis, improve readability and semantics.
- Add labels for each form input, and tweak placeholder text accordingly.
- Move CSS styles to the stylesheet; minor tweaks for clarity and consistency
- Use the legacy align=center attribute for centering paragraphs (backwards compatible)
- Remove all instances of using tables for layout
- Add header tags to all remaining tables, with scope parameters.
- Add descriptions to each table
- Move drive reference hyperlinks to the drive name column (addresses "same link text leads to different URL" code smell.)
- Inject lang parameters to each html tag
- Standardize on h2 tags as top header for each template
- Add 'json' to config file UI elements, to communicate actual file name/format
- Clean up indentation
- Dropbox styling: Added a colored outline, added padding to more clearly communicate its function. Hid the (X) SVG that indicates failure, since failure is already communicated by the error text. Also, the SVG always obstructed the file name or error so was quite counter-productive.
This commit is contained in:
Daniel Markstedt 2022-10-07 13:13:29 -07:00 committed by GitHub
parent 90ace5fd53
commit d1a703418c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 469 additions and 491 deletions

View File

@ -2,19 +2,7 @@ body {
color: black; color: black;
background-color: white; background-color: white;
font-family: Arial, Helvetica, sans-serif; font-family: Arial, Helvetica, sans-serif;
text-decoration:none; text-decoration: none;
}
h1 {
color: white;
font-size:20px;
background-color:black;
}
h2 {
color: black;
font-size:16px;
margin: 0px;
} }
a { a {
@ -27,10 +15,50 @@ form {
table, tr, td { table, tr, td {
border: 1px solid black; border: 1px solid black;
border-collapse:collapse; border-collapse: collapse;
margin: none; margin: none;
} }
h1 {
color: white;
font-size: 20px;
}
h2 {
color: black;
font-size: large;
font-weight: bold;
margin: 3px;
}
summary.heading {
color: black;
font-size: large;
font-weight: bold;
margin: 3px;
}
div.header {
color: white;
background-color: black;
}
div.footer {
font-family: monospace;
}
div.logged_in {
background-color: green;
}
div.logged_out {
background-color: red;
}
input.lun {
width: 36px;
}
div.flash { div.flash {
margin-top: 5px; margin-top: 5px;
margin-bottom: 5px; margin-bottom: 5px;
@ -61,71 +89,76 @@ div.flash div.info {
} }
td.inactive { td.inactive {
text-align:center; text-align: center;
background-color:tan; background-color: tan;
} }
summary.heading { ul.inline_list {
color: black; list-style: none;
font-size: large;
font-weight: bold;
margin: 0px;
} }
.dropzone, .dropzone * { .dropzone, .dropzone * {
box-sizing: border-box; box-sizing: border-box;
} }
.dropzone { .dropzone {
position: relative; position: relative;
}
.dropzone .dz-button {
position: relative;
background-color: white;
color: black;
border: 2px dashed blue;
padding: 12px 28px;
} }
.dropzone .dz-preview { .dropzone .dz-preview {
position: relative; position: relative;
display: inline-block; display: inline-block;
width: 120px; width: 120px;
margin: .5em; margin: .5em;
} }
.dropzone .dz-preview .dz-progress { .dropzone .dz-preview .dz-progress {
display: block; display: block;
height: 15px; height: 15px;
border: 1px solid #aaa; border: 1px solid #aaa;
} }
.dropzone .dz-preview .dz-progress .dz-upload { .dropzone .dz-preview .dz-progress .dz-upload {
display: block; display: block;
height: 100%; height: 100%;
width: 0; width: 0;
background: green; background: green;
} }
.dropzone .dz-preview .dz-error-message { .dropzone .dz-preview .dz-error-message {
color: red; color: red;
display: none; display: none;
} }
.dropzone .dz-preview.dz-error .dz-error-message { .dropzone .dz-preview.dz-error .dz-error-message {
display: block; display: block;
} }
.dropzone .dz-preview.dz-error .dz-error-mark { .dropzone .dz-preview.dz-error .dz-error-mark {
display: block; display: block;
filter: drop-shadow(0px 0px 2px red); filter: drop-shadow(0px 0px 2px red);
opacity: 0;
} }
.dropzone .dz-preview.dz-success .dz-success-mark { .dropzone .dz-preview.dz-success .dz-success-mark {
display: block; display: block;
filter: drop-shadow(0px 0px 2px green); filter: drop-shadow(0px 0px 2px green);
} }
.dropzone .dz-preview .dz-error-mark, .dropzone .dz-preview .dz-success-mark { .dropzone .dz-preview .dz-error-mark, .dropzone .dz-preview .dz-success-mark {
position: absolute; position: absolute;
display: none; display: none;
left: 30px; top: 30px;
top: 30px; width: 54px;
width: 54px; height: 58px;
height: 58px; left: 50%;
left: 50%; margin-left: -27px;
margin-left: -27px;
} }

View File

@ -1,80 +1,76 @@
<!doctype html> <!doctype html>
<html> <html lang="{{ env["locale"] }}">
<head> <head>
<title>{{ _("RaSCSI Reloaded Control Page") }} [{{ env["host"] }}]</title> <title>{{ _("RaSCSI Reloaded Control Page") }} [{{ env["host"] }}]</title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
<link rel="apple-touch-icon" sizes="57x57" href="/pwa/apple-icon-57x57.png"> <link rel="apple-touch-icon" sizes="57x57" href="/pwa/apple-icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/pwa/apple-icon-60x60.png"> <link rel="apple-touch-icon" sizes="60x60" href="/pwa/apple-icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/pwa/apple-icon-72x72.png"> <link rel="apple-touch-icon" sizes="72x72" href="/pwa/apple-icon-72x72.png">
<link rel="apple-touch-icon" sizes="76x76" href="/pwa/apple-icon-76x76.png"> <link rel="apple-touch-icon" sizes="76x76" href="/pwa/apple-icon-76x76.png">
<link rel="apple-touch-icon" sizes="114x114" href="/pwa/apple-icon-114x114.png"> <link rel="apple-touch-icon" sizes="114x114" href="/pwa/apple-icon-114x114.png">
<link rel="apple-touch-icon" sizes="120x120" href="/pwa/apple-icon-120x120.png"> <link rel="apple-touch-icon" sizes="120x120" href="/pwa/apple-icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/pwa/apple-icon-144x144.png"> <link rel="apple-touch-icon" sizes="144x144" href="/pwa/apple-icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/pwa/apple-icon-152x152.png"> <link rel="apple-touch-icon" sizes="152x152" href="/pwa/apple-icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/pwa/apple-icon-180x180.png"> <link rel="apple-touch-icon" sizes="180x180" href="/pwa/apple-icon-180x180.png">
<link rel="icon" type="image/png" sizes="192x192" href="/pwa/android-icon-192x192.png"> <link rel="icon" type="image/png" sizes="192x192" href="/pwa/android-icon-192x192.png">
<link rel="icon" type="image/png" sizes="32x32" href="/pwa/favicon-32x32.png"> <link rel="icon" type="image/png" sizes="32x32" href="/pwa/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="96x96" href="/pwa/favicon-96x96.png"> <link rel="icon" type="image/png" sizes="96x96" href="/pwa/favicon-96x96.png">
<link rel="icon" type="image/png" sizes="16x16" href="/pwa/favicon-16x16.png"> <link rel="icon" type="image/png" sizes="16x16" href="/pwa/favicon-16x16.png">
<link rel="manifest" href="/pwa/manifest.json"> <link rel="manifest" href="/pwa/manifest.json">
<meta name="msapplication-TileColor" content="#ffffff"> <meta name="msapplication-TileColor" content="#ffffff">
<meta name="msapplication-TileImage" content="/pwa/ms-icon-144x144.png"> <meta name="msapplication-TileImage" content="/pwa/ms-icon-144x144.png">
<meta name="theme-color" content="#ffffff"> <meta name="theme-color" content="#ffffff">
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}"> <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
<script type="application/javascript"> <script type="application/javascript">
var processNotify = function(Notification) { var processNotify = function(Notification) {
document.getElementById("flash").innerHTML = "<div class=\"info\">" + Notification + "{{ _(" This process may take a while, and will continue in the background if you navigate away from this page.") }}</div>"; document.getElementById("flash").innerHTML = "<div class=\"info\">" + Notification + "{{ _(" This process may take a while, and will continue in the background if you navigate away from this page.") }}</div>";
window.scrollTo(0,0); window.scrollTo(0,0);
} }
var shutdownNotify = function(Notification) { var shutdownNotify = function(Notification) {
document.getElementById("flash").innerHTML = "<div class=\"info\">" + Notification + "{{ _(" The Web Interface will become unresponsive momentarily. Reload this page after the Pi has started up again.") }}</div>"; document.getElementById("flash").innerHTML = "<div class=\"info\">" + Notification + "{{ _(" The Web Interface will become unresponsive momentarily. Reload this page after the Pi has started up again.") }}</div>";
window.scrollTo(0,0); window.scrollTo(0,0);
} }
</script> </script>
<script type="application/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.9.3/min/dropzone.min.js"></script>
<script type="application/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.9.3/min/dropzone.min.js"></script>
</head> </head>
<body> <body>
<div class="content">
<div class="header"> <div class="header">
{% if env["auth_active"] %} {% if env["auth_active"] %}
{% if env["username"] %} {% if env["username"] %}
<span style="display: inline-block; width: 100%; color: white; background-color: green; text-align: center; vertical-align: center; font-family: Arial, Helvetica, sans-serif;">{{ _("Logged in as <em>%(username)s</em>", username=env["username"]) }} &#8211; <a href="/logout">{{ _("Log Out") }}</a></span> <div align="center" class="logged_in">
{{ _("Logged in as <em>%(username)s</em>", username=env["username"]) }} - <a href="/logout">{{ _("Log Out") }}</a>
</div>
{% else %} {% else %}
<span style="display: inline-block; width: 100%; color: white; background-color: red; text-align: center; vertical-align: center; font-family: Arial, Helvetica, sans-serif;"> <div align="center" class="logged_out">
<form method="POST" action="/login"> <form method="POST" action="/login">
<div>{{ _("Log In to Use Web Interface") }}</div> <div>{{ _("Log In to Use Web Interface") }}</div>
<input type="text" name="username" placeholder="{{ _("Username") }}"> <label for="username">{{ _("Username") }}</label>
<input type="password" name="password" placeholder="{{ _("Password") }}"> <input type="text" name="username" id="username">
<label for="password">{{ _("Password") }}</label>
<input type="password" name="password" id="password">
<input type="submit" value="Login"> <input type="submit" value="Login">
</form> </form>
</span> </div>
{% endif %} {% endif %}
{% else %} {% else %}
<span style="display: inline-block; width: 100%; color: white; background-color: green; text-align: center; vertical-align: center; font-family: Arial, Helvetica, sans-serif;">{{ _("Web Interface Authentication Disabled") }} &#8211; {{ _("See <a href=\"%(url)s\" target=\"_blank\">Wiki</a> for more information", url="https://github.com/akuker/RASCSI/wiki/Web-Interface#enable-authentication") }}</span> <div align="center" class="logged_out">
{{ _("Web Interface Authentication Disabled") }} - {{ _("See <a href=\"%(url)s\" target=\"_blank\">Wiki</a> for more information", url="https://github.com/akuker/RASCSI/wiki/Web-Interface#enable-authentication") }}
</div>
{% endif %} {% endif %}
<table width="100%" style="background-color: black;"> <div align="center">
<tbody> <a href="/">
<tr align="center"> <h1>{{ _("RaSCSI Reloaded Control Page") }}</h1>
<td> </a>
<a href="/"> </div>
<h1>{{ _("RaSCSI Reloaded Control Page") }}</h1> <div>
</a> hostname: {{ env["host"] }} ip: {{ env["ip_addr"] }}
</td> </div>
</tr>
<tr>
<td style="color: white;">
hostname: {{ env["host"] }} ip: {{ env["ip_addr"] }}
</td>
</tr>
</tbody>
</table>
</div> </div>
<div class="flash" id="flash"> <div class="flash" id="flash">
{% for category, message in get_flashed_messages(with_categories=true) %} {% for category, message in get_flashed_messages(with_categories=true) %}
@ -88,9 +84,27 @@
<div class="content"> <div class="content">
{% block content %}{% endblock content %} {% block content %}{% endblock content %}
</div> </div>
<div class="footer"> <div align="center" class="footer">
<center><tt>{{ _("RaSCSI Reloaded version: ") }}<strong>{{ version }} <a href="https://github.com/akuker/RASCSI/commit/{{ env["running_env"]["git"] }}" target="_blank">{{ env["running_env"]["git"][:7] }}</a></strong></tt></center> <div>
<center><tt>{{ _("Pi environment: ") }}{{ env["running_env"]["env"] }}</tt></center> {% if env["netatalk_configured"] == 1 %}
{{ _("The AppleShare server is running. No active connections.") }}
{% endif %}
{% if env["netatalk_configured"] == 2 %}
{{ _("%(value)d active AFP connection", value=(env["netatalk_configured"] - 1)) }}
{% elif env["netatalk_configured"] > 2 %}
{{ _("%(value)d active AFP connections", value=(env["netatalk_configured"] - 1)) }}
{% endif %}
</div>
<div>
{% if env["macproxy_configured"] %}
{{ _("Macproxy is running at %(ip_addr)s (default port 5000)", ip_addr=env['ip_addr']) }}
{% endif %}
</div>
<div>
{{ _("RaSCSI Reloaded version: ") }}<b>{{ env["version"] }} <a href="https://github.com/akuker/RASCSI/commit/{{ env["running_env"]["git"] }}" target="_blank">{{ env["running_env"]["git"][:7] }}</a></b>
</div>
<div>
{{ _("Pi environment: ") }}{{ env["running_env"]["env"] }}
</div>
</div> </div>
</div>
</body> </body>

View File

@ -1,52 +1,52 @@
{% extends "base.html" %} {% extends "base.html" %}
{% block content %} {% block content %}
<h3>{{ _("Detailed Info for Attached Devices") }}</h3> <h2>{{ _("Detailed Info for Attached Devices") }}</h2>
{% for device in devices %} {% for device in devices %}
<p> <p>
<table border="black" cellpadding="3"> <table border="black" cellpadding="3" summary="Detailed information for attached devices">
<tr> <tr>
<td><i>{{ _("SCSI ID") }}</i></td> <th scope="row">{{ _("SCSI ID") }}</th>
<td>{{ device["id"] }}</td> <td>{{ device["id"] }}</td>
</tr> </tr>
<tr> <tr>
<td><i>{{ _("LUN") }}</i></td> <th scope="row">{{ _("LUN") }}</th>
<td>{{ device["unit"] }}</td> <td>{{ device["unit"] }}</td>
</tr> </tr>
<tr> <tr>
<td><i>{{ _("Type") }}</i></td> <th scope="row">{{ _("Type") }}</th>
<td>{{ device["device_type"] }}</td> <td>{{ device["device_type"] }}</td>
</tr> </tr>
<tr> <tr>
<td><i>{{ _("Status") }}</i></td> <th scope="row">{{ _("Status") }}</th>
<td>{{ device["status"] }}</td> <td>{{ device["status"] }}</td>
</tr> </tr>
<tr> <tr>
<td><i>{{ _("File") }}</i></td> <th scope="row">{{ _("File") }}</th>
<td>{{ device["image"] }}</td> <td>{{ device["image"] }}</td>
</tr> </tr>
<tr> <tr>
<td><i>{{ _("Parameters") }}</i></td> <th scope="row">{{ _("Parameters") }}</th>
<td>{{ device["params"] }}</td> <td>{{ device["params"] }}</td>
</tr> </tr>
<tr> <tr>
<td><i>{{ _("Vendor") }}</i></td> <th scope="row">{{ _("Vendor") }}</th>
<td>{{ device["vendor"] }}</td> <td>{{ device["vendor"] }}</td>
</tr> </tr>
<tr> <tr>
<td><i>{{ _("Product") }}</i></td> <th scope="row">{{ _("Product") }}</th>
<td>{{ device["product"] }}</td> <td>{{ device["product"] }}</td>
</tr> </tr>
<tr> <tr>
<td><i>{{ _("Revision") }}</i></td> <th scope="row">{{ _("Revision") }}</th>
<td>{{ device["revision"] }}</td> <td>{{ device["revision"] }}</td>
</tr> </tr>
<tr> <tr>
<td><i>{{ _("Block Size") }}</i></td> <th scope="row">{{ _("Block Size") }}</th>
<td>{{ device["block_size"] }}</td> <td>{{ device["block_size"] }}</td>
</tr> </tr>
<tr> <tr>
<td><i>{{ _("Image Size") }}</i></td> <th scope="row">{{ _("Image Size") }}</th>
<td>{{ device["size"] }}</td> <td>{{ device["size"] }}</td>
</tr> </tr>
</table> </table>

View File

@ -1,7 +1,7 @@
{% extends "base.html" %} {% extends "base.html" %}
{% block content %} {% block content %}
<h3>{{ _("Disk Image Details: %(file_name)s", file_name=file_name) }}</h3> <h2>{{ _("Disk Image Details: %(file_name)s", file_name=file_name) }}</h2>
<p><pre>{{ diskinfo }}</pre></p> <p><pre>{{ diskinfo }}</pre></p>
<p><a href="/">{{ _("Go to Home") }}</a></p> <p><a href="/">{{ _("Go to Home") }}</a></p>

View File

@ -5,33 +5,32 @@
<p>{{ _("These device profiles are provided as-is with no guarantee to work equally to the actual physical device they are named after. You may need to provide appropirate device drivers and/or configuration parameters for them to function properly. If you would like to see data modified, or have additional devices to add to the list, please raise an issue ticket at <a href=\"%(url)s\">GitHub</a>.", url="https://github.com/akuker/RASCSI/issues") }}</p> <p>{{ _("These device profiles are provided as-is with no guarantee to work equally to the actual physical device they are named after. You may need to provide appropirate device drivers and/or configuration parameters for them to function properly. If you would like to see data modified, or have additional devices to add to the list, please raise an issue ticket at <a href=\"%(url)s\">GitHub</a>.", url="https://github.com/akuker/RASCSI/issues") }}</p>
<h2>{{ _("Hard Disk Drives") }}</h2> <h2>{{ _("Hard Disk Drives") }}</h2>
<table cellpadding="3" border="black"> <table cellpadding="3" border="black" summary="List of hard drives">
<tbody> <tbody>
<tr> <tr>
<td><b>{{ _("Name") }}</b></td> <th scope="col">{{ _("Name") }}</th>
<td><b>{{ _("Size (MiB)") }}</b></td> <th scope="col">{{ _("Size (MiB)") }}</th>
<td><b>{{ _("Description") }}</b></td> <th scope="col">{{ _("Description") }}</th>
<td><b>{{ _("Ref.") }}</b></td> <th scope="col">{{ _("Action") }}</th>
<td><b>{{ _("Action") }}</b></td>
</tr> </tr>
{% for hd in drive_properties['hd_conf']|sort(attribute='name') %} {% for hd in drive_properties['hd_conf']|sort(attribute='name') %}
<tr> <tr>
<td style="text-align:center">{{ hd.name }}</td> <td align="center">
<td style="text-align:center">{{ hd.size_mb }}</td> {% if hd.url != "" %}
<td style="text-align:left">{{ hd.description }}</td> <a href="{{ hd.url }}">{{ hd.name }}</a>
<td style="text-align:left"> {% else %}
{% if hd.url != "" %} {{ hd.name }}
<a href="{{ hd.url }}">{{ _("Link") }}</a> {% endif %}
{% else %} </td>
- <td align="center">{{ hd.size_mb }}</td>
{% endif %} <td>{{ hd.description }}</td>
</td> <td>
<td style="text-align:left">
<form action="/drive/create" method="post"> <form action="/drive/create" method="post">
<input type="hidden" name="drive_name" value="{{ hd.name }}"> <input type="hidden" name="drive_name" value="{{ hd.name }}">
{{ _("Size:") }} <input type="number" name="size" min="512" max="274877906944" step="512" value="{{ hd.size }}">{{ _("B") }} <label for="size_{{ hd.name }}">{{ _("Size:") }}</label>
<label for="file_name">{{ _("Save as:") }}</label> <input type="number" name="size" id="size_{{ hd.name }}" min="512" max="274877906944" step="512" value="{{ hd.size }}">{{ _("B") }}
<input type="text" name="file_name" value="{{ hd.secure_name }}" required />.{{ hd.file_type }} <label for="file_name_{{ hd.name }}">{{ _("Save as:") }}</label>
<input type="text" name="file_name" id="file_name_{{ hd.name }}" value="{{ hd.secure_name }}" required />.{{ hd.file_type }}
<input type="submit" value="{{ _("Create") }}" /> <input type="submit" value="{{ _("Create") }}" />
</form> </form>
</td> </td>
@ -44,38 +43,36 @@
<h2>{{ _("CD/DVD Drives") }}</h2> <h2>{{ _("CD/DVD Drives") }}</h2>
<p><em>{{ _("This will create a properties file for the given CD-ROM or DVD image. No new image file will be created.") }}</em></p> <p><em>{{ _("This will create a properties file for the given CD-ROM or DVD image. No new image file will be created.") }}</em></p>
<table cellpadding="3" border="black"> <table cellpadding="3" border="black" summary="List of CD-ROM or DVD drives">
<tbody> <tbody>
<tr> <tr>
<td><b>{{ _("Name") }}</b></td> <th scope="col">{{ _("Name") }}</th>
<td><b>{{ _("Size (MiB)") }}</b></td> <th scope="col">{{ _("Size (MiB)") }}</th>
<td><b>{{ _("Description") }}</b></td> <th scope="col">{{ _("Description") }}</th>
<td><b>{{ _("Ref.") }}</b></td> <th scope="col">{{ _("Action") }}</th>
<td><b>{{ _("Action") }}</b></td>
</tr> </tr>
{% for cd in drive_properties['cd_conf']|sort(attribute='name') %} {% for cd in drive_properties['cd_conf']|sort(attribute='name') %}
<tr> <tr>
<td style="text-align:center">{{ cd.name }}</td> <td align="center">
<td style="text-align:center">{{ cd.size_mb }}</td> {% if cd.url != "" %}
<td style="text-align:left">{{ cd.description }}</td> <a href="{{ cd.url }}">{{ cd.name }}</a>
<td style="text-align:left"> {% else %}
{% if cd.url != "" %} {{ cd.name }}
<a href="{{ cd.url }}">{{ _("Link") }}</a> {% endif %}
{% else %}
-
{% endif %}
</td> </td>
<td style="text-align:left"> <td align="center">{{ cd.size_mb }}</td>
<td>{{ cd.description }}</td>
<td>
<form action="/drive/cdrom" method="post"> <form action="/drive/cdrom" method="post">
<input type="hidden" name="drive_name" value="{{ cd.name }}"> <input type="hidden" name="drive_name" value="{{ cd.name }}">
<label for="file_name">{{ _("Create for:") }}</label> <label for="file_name_{{ cd.name }}">{{ _("Create for:") }}</label>
<select type="select" name="file_name"> <select type="select" name="file_name" id="file_name_{{ cd.name }}">
{% for file in files|sort(attribute='name') %} {% for file in files|sort(attribute='name') %}
{% if file["name"].lower().endswith(cdrom_file_suffix) %} {% if file["name"].lower().endswith(env['cd_suffixes']) %}
<option value="{{ file["name"] }}">{{ file["name"].replace(base_dir, '') }}</option> <option value="{{ file["name"] }}">{{ file["name"].replace(env["image_dir"], '') }}</option>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
</select> </select>
<input type="submit" value="{{ _("Create") }}" /> <input type="submit" value="{{ _("Create") }}" />
</form> </form>
</td> </td>
@ -87,33 +84,32 @@
<hr/> <hr/>
<h2>{{ _("Removable Disk Drives") }}</h2> <h2>{{ _("Removable Disk Drives") }}</h2>
<table cellpadding="3" border="black"> <table cellpadding="3" border="black" summary="List of removable disk drives">
<tbody> <tbody>
<tr> <tr>
<td><b>{{ _("Name") }}</b></td> <th scope="col">{{ _("Name") }}</th>
<td><b>{{ _("Size (MiB)") }}</b></td> <th scope="col">{{ _("Size (MiB)") }}</th>
<td><b>{{ _("Description") }}</b></td> <th scope="col">{{ _("Description") }}</th>
<td><b>{{ _("Ref.") }}</b></td> <th scope="col">{{ _("Action") }}</th>
<td><b>{{ _("Action") }}</b></td>
</tr> </tr>
{% for rm in drive_properties['rm_conf']|sort(attribute='name') %} {% for rm in drive_properties['rm_conf']|sort(attribute='name') %}
<tr> <tr>
<td style="text-align:center">{{ rm.name }}</td> <td align="center">
<td style="text-align:center">{{ rm.size_mb }}</td> {% if rm.url != "" %}
<td style="text-align:left">{{ rm.description }}</td> <a href="{{ rm.url }}">{{ rm.name }}</a>
<td style="text-align:left"> {% else %}
{% if rm.url != "" %} {{ rm.name }}
<a href="{{ rm.url }}">{{ _("Link") }}</a> {% endif %}
{% else %}
-
{% endif %}
</td> </td>
<td style="text-align:left"> <td align="center">{{ rm.size_mb }}</td>
<td>{{ rm.description }}</td>
<td>
<form action="/drive/create" method="post"> <form action="/drive/create" method="post">
<input type="hidden" name="drive_name" value="{{ rm.name }}"> <input type="hidden" name="drive_name" value="{{ rm.name }}">
{{ _("Size:") }} <input type="number" name="size" min="512" max="274877906944" step="512" value="{{ rm.size }}">{{ _("B") }} <label for="size_{{ rm.name }}">{{ _("Size:") }}</label>
<label for="file_name">{{ _("Save as:") }}</label> <input type="number" name="size" id="size_{{ rm.name }}" min="512" max="274877906944" step="512" value="{{ rm.size }}">{{ _("B") }}
<input type="text" name="file_name" value="{{ rm.secure_name }}" required />.{{ rm.file_type }} <label for="file_name_{{ rm.name }}">{{ _("Save as:") }}</label>
<input type="text" name="file_name" id="file_name_{{ rm.name }}" value="{{ rm.secure_name }}" required />.{{ rm.file_type }}
<input type="submit" value="{{ _("Create") }}" /> <input type="submit" value="{{ _("Create") }}" />
</form> </form>
</td> </td>

View File

@ -7,17 +7,19 @@
</summary> </summary>
<ul> <ul>
<li>{{ _("Displays the currently attached devices for each available SCSI ID.") }}</li> <li>{{ _("Displays the currently attached devices for each available SCSI ID.") }}</li>
<li>{{ _("Save and load device configurations, stored as json files in <tt>%(config_dir)s</tt>", config_dir=CFG_DIR) }}</tt></li> <li>{{ _("Save and load device configurations, stored as json files in <tt>%(config_dir)s</tt>", config_dir=CFG_DIR) }}</li>
<li>{{ _("To have a particular device configuration load when RaSCSI starts, save it as <em>default</em>.") }}</li> <li>{{ _("To have a particular device configuration load when RaSCSI starts, save it as <em>default</em>.") }}</li>
</ul> </ul>
</details> </details>
<p><form action="/config/load" method="post"> <p>
<select name="name" required="" width="14"> <form action="/config/load" method="post">
<label for="config_load_name">{{ _("File name") }}</label>
<select name="name" id="config_load_name" required="" width="14">
{% if config_files %} {% if config_files %}
{% for config in config_files|sort %} {% for config in config_files|sort %}
<option value="{{ config }}"> <option value="{{ config }}">
{{ config.replace(".json", '') }} {{ config }}
</option> </option>
{% endfor %} {% endfor %}
{% else %} {% else %}
@ -28,53 +30,59 @@
</select> </select>
<input name="load" type="submit" value="{{ _("Load") }}" onclick="return confirm('{{ _("Detach all current device and Load configuration?") }}')"> <input name="load" type="submit" value="{{ _("Load") }}" onclick="return confirm('{{ _("Detach all current device and Load configuration?") }}')">
<input name="delete" type="submit" value="{{ _("Delete") }}" onclick="return confirm('{{ _("Delete configuration file?") }}')"> <input name="delete" type="submit" value="{{ _("Delete") }}" onclick="return confirm('{{ _("Delete configuration file?") }}')">
</form></p> </form>
</p>
<p><form action="/config/save" method="post"> <p>
<input name="name" placeholder="default" size="20"> <form action="/config/save" method="post">
<label for="config_save_name">{{ _("File name") }}</label>
<input name="name" id="config_save_name" placeholder="default" size="20">
.{{ CONFIG_FILE_SUFFIX }}
<input type="submit" value="{{ _("Save") }}"> <input type="submit" value="{{ _("Save") }}">
</form></p> </form>
</p>
<table border="black" cellpadding="3"> <table border="black" cellpadding="3" summary="List of attached devices">
<tbody> <tbody>
<tr> <tr>
<td><b>{{ _("ID") }}</b></td> <th scope="col">{{ _("ID") }}</th>
{% if units %} {% if units %}
<td><b>{{ _("LUN") }}</b></td> <th scope="col">{{ _("LUN") }}</th>
{% endif %} {% endif %}
<td><b>{{ _("Device") }}</b></td> <th scope="col">{{ _("Device") }}</th>
<td><b>{{ _("Parameters") }}</b></td> <th scope="col">{{ _("Parameters") }}</th>
<td><b>{{ _("Product") }}</b></td> <th scope="col">{{ _("Product") }}</th>
<td><b>{{ _("Actions") }}</b></td> <th scope="col">{{ _("Actions") }}</th>
</tr> </tr>
{% for device in devices | sort(attribute='id') %} {% for device in devices | sort(attribute='id') %}
<tr> <tr>
{% if device["id"] not in reserved_scsi_ids %} {% if device["id"] not in reserved_scsi_ids %}
<td style="text-align:center">{{ device.id }}</td> <td align="center">{{ device.id }}</td>
{% if units %} {% if units %}
<td style="text-align:center">{{ device.unit }}</td> <td align="center">{{ device.unit }}</td>
{% endif %} {% endif %}
<td style="text-align:center">{{ device.device_name }}</td> <td align="center">{{ device.device_name }}</td>
<td style="text-align:left"> <td>
{% if "No Media" in device.status %} {% if "No Media" in device.status %}
<form action="/scsi/attach" method="post"> <form action="/scsi/attach" method="post">
<input name="scsi_id" type="hidden" value="{{ device.id }}"> <input name="scsi_id" type="hidden" value="{{ device.id }}">
<input name="unit" type="hidden" value="{{ device.unit }}"> <input name="unit" type="hidden" value="{{ device.unit }}">
<input name="type" type="hidden" value="{{ device.device_type }}"> <input name="type" type="hidden" value="{{ device.device_type }}">
<input name="file_size" type="hidden" value="{{ device.size }}"> <input name="file_size" type="hidden" value="{{ device.size }}">
<select type="select" name="file_name"> <label for="device_list_file_name_{{ device.id }}_{{ device.unit }}">{{ _("File name") }}</label>
<select type="select" name="file_name" id="device_list_file_name_{{ device.id }}_{{ device.unit }}">
{% for f in files|sort(attribute='name') %} {% for f in files|sort(attribute='name') %}
{% if device.device_type == "SCCD" %} {% if device.device_type == "SCCD" %}
{% if f["name"].lower().endswith(cdrom_file_suffix) %} {% if f["name"].lower().endswith(env['cd_suffixes']) %}
<option value="{{ f["name"] }}">{{ f["name"].replace(base_dir, '') }}</option> <option value="{{ f["name"] }}">{{ f["name"].replace(env["image_dir"], '') }}</option>
{% endif %} {% endif %}
{% elif device.device_type == "SCRM" %} {% elif device.device_type == "SCRM" %}
{% if f["name"].lower().endswith(removable_file_suffix) %} {% if f["name"].lower().endswith(env['rm_suffixes']) %}
<option value="{{ f["name"] }}">{{ f["name"].replace(base_dir, '') }}</option> <option value="{{ f["name"] }}">{{ f["name"].replace(env["image_dir"], '') }}</option>
{% endif %} {% endif %}
{% elif device.device_type == "SCMO" %} {% elif device.device_type == "SCMO" %}
{% if f["name"].lower().endswith(mo_file_suffix) %} {% if f["name"].lower().endswith(env['mo_suffixes']) %}
<option value="{{ f["name"] }}">{{ f["name"].replace(base_dir, '') }}</option> <option value="{{ f["name"] }}">{{ f["name"].replace(env["image_dir"], '') }}</option>
{% endif %} {% endif %}
{% endif %} {% endif %}
{% endfor %} {% endfor %}
@ -97,7 +105,7 @@
{% endif %} {% endif %}
{% endif %} {% endif %}
</td> </td>
<td style="text-align:center"> <td align="center">
{% if device.vendor != "RaSCSI" %} {% if device.vendor != "RaSCSI" %}
{{ device.vendor }} {{ device.vendor }}
{% endif %} {% endif %}
@ -106,8 +114,8 @@
{{ device.revision }} {{ device.revision }}
{% endif %} {% endif %}
</td> </td>
<td style="text-align:center"> <td align="center">
{% if device.id in scsi_ids["occupied_ids"] %} {% if device.id in scsi_ids["occupied_ids"] %}
{% if device.device_type in REMOVABLE_DEVICE_TYPES and "No Media" not in device.status %} {% if device.device_type in REMOVABLE_DEVICE_TYPES and "No Media" not in device.status %}
<form action="/scsi/eject" method="post" onsubmit="return confirm('{{ _("Eject Disk? WARNING: On Mac OS, eject the Disk in the Finder instead!") }}')"> <form action="/scsi/eject" method="post" onsubmit="return confirm('{{ _("Eject Disk? WARNING: On Mac OS, eject the Disk in the Finder instead!") }}')">
<input name="scsi_id" type="hidden" value="{{ device.id }}"> <input name="scsi_id" type="hidden" value="{{ device.id }}">
@ -120,13 +128,13 @@
<input name="unit" type="hidden" value="{{ device.unit }}"> <input name="unit" type="hidden" value="{{ device.unit }}">
<input type="submit" value="{{ _("Detach") }}"> <input type="submit" value="{{ _("Detach") }}">
</form> </form>
{% else %} {% else %}
<form action="/scsi/reserve" method="post" onsubmit="var memo = prompt('{{ _("Enter a memo for this reservation") }}'); if (memo === null) event.preventDefault(); document.getElementById('memo_{{ device.id }}').value = memo;"> <form action="/scsi/reserve" method="post" onsubmit="var memo = prompt('{{ _("Enter a memo for this reservation") }}'); if (memo === null) event.preventDefault(); document.getElementById('memo_{{ device.id }}').value = memo;">
<input name="scsi_id" type="hidden" value="{{ device.id }}"> <input name="scsi_id" type="hidden" value="{{ device.id }}">
<input name="memo" id="memo_{{ device.id }}" type="hidden" value=""> <input name="memo" id="memo_{{ device.id }}" type="hidden" value="">
<input type="submit" value="{{ _("Reserve") }}"> <input type="submit" value="{{ _("Reserve") }}">
</form> </form>
{% endif %} {% endif %}
</td> </td>
{% else %} {% else %}
<td class="inactive">{{ device.id }}</td> <td class="inactive">{{ device.id }}</td>
@ -148,20 +156,14 @@
</tbody> </tbody>
</table> </table>
<table style="border: none;" cellpadding="3"> <p>
<tr style="border: none;"> <form action="/scsi/detach_all" method="post" onsubmit="return confirm('{{ _("Detach all SCSI Devices?") }}')">
<td style="border: none;"> <input type="submit" value="{{ _("Detach All Devices") }}">
<form action="/scsi/detach_all" method="post" onsubmit="return confirm('{{ _("Detach all SCSI Devices?") }}')"> </form>
<input type="submit" value="{{ _("Detach All Devices") }}"> <form action="/scsi/info" method="post">
</form> <input type="submit" value="{{ _("Show Device Info") }}">
</td> </form>
<td style="border: none;"> </p>
<form action="/scsi/info" method="post">
<input type="submit" value="{{ _("Show Device Info") }}">
</form>
</td>
</tr>
</table>
<hr/> <hr/>
@ -170,7 +172,7 @@
{{ _("Image File Management") }} {{ _("Image File Management") }}
</summary> </summary>
<ul> <ul>
<li>{{ _("Manage image files in the active RaSCSI image directory: <tt>%(directory)s</tt> with a scan depth of %(scan_depth)s.", directory=base_dir, scan_depth=scan_depth) }}</li> <li>{{ _("Manage image files in the active RaSCSI image directory: <tt>%(directory)s</tt> with a scan depth of %(scan_depth)s.", directory=env["image_dir"], scan_depth=scan_depth) }}</li>
<li>{{ _("Select a valid SCSI ID and <a href=\"%(url)s\" target=\"_blank\">LUN</a> to attach to. Unless you know what you're doing, always use LUN 0.", url="https://en.wikipedia.org/wiki/Logical_unit_number") }} <li>{{ _("Select a valid SCSI ID and <a href=\"%(url)s\" target=\"_blank\">LUN</a> to attach to. Unless you know what you're doing, always use LUN 0.", url="https://en.wikipedia.org/wiki/Logical_unit_number") }}
</li> </li>
<li>{{ _("If RaSCSI was unable to detect the media type associated with the image, you get to choose the type from the dropdown.") }}</li> <li>{{ _("If RaSCSI was unable to detect the media type associated with the image, you get to choose the type from the dropdown.") }}</li>
@ -187,12 +189,12 @@
</ul> </ul>
</details> </details>
<table border="black" cellpadding="3"> <table border="black" cellpadding="3" summary="List of files in the image directory">
<tbody> <tbody>
<tr style="font-weight: bold;"> <tr>
<td>{{ _("File") }}</td> <th scope="col">{{ _("File") }}</th>
<td>{{ _("Size") }}</td> <th scope="col">{{ _("Size") }}</th>
<td>{{ _("Actions") }}</td> <th scope="col">{{ _("Actions") }}</th>
</tr> </tr>
{% for file in files|sort(attribute='name') %} {% for file in files|sort(attribute='name') %}
<tr> <tr>
@ -202,12 +204,12 @@
<summary> <summary>
{{ file["name"] }} {{ file["name"] }}
</summary> </summary>
<ul style="list-style: none;"> <ul class="inline_list">
{% for key in file["prop"] %} {% for key in file["prop"] %}
<li>{{ key }}: {{ file['prop'][key] }}</li> <li>{{ key }}: {{ file['prop'][key] }}</li>
{% endfor %} {% endfor %}
<form action="/files/download" method="post"> <form action="/files/download" method="post">
<input name="file" type="hidden" value="{{ CFG_DIR }}/{{ file['name'].replace(base_dir, '') }}.{{ PROPERTIES_SUFFIX }}"> <input name="file" type="hidden" value="{{ CFG_DIR }}/{{ file['name'].replace(env['image_dir'], '') }}.{{ PROPERTIES_SUFFIX }}">
<input type="submit" value="{{ _("Properties File") }} &#8595;"> <input type="submit" value="{{ _("Properties File") }} &#8595;">
</form> </form>
</ul> </ul>
@ -219,7 +221,7 @@
<summary> <summary>
{{ file["name"] }} {{ file["name"] }}
</summary> </summary>
<ul style="list-style: none;"> <ul class="inline_list">
{% for member in file["archive_contents"] %} {% for member in file["archive_contents"] %}
{% if not member["is_properties_file"] %} {% if not member["is_properties_file"] %}
<li> <li>
@ -233,7 +235,7 @@
<input type="submit" value="{{ _("Extract") }}" onclick="processNotify('{{ _("Extracting a single file...") }}')"> <input type="submit" value="{{ _("Extract") }}" onclick="processNotify('{{ _("Extracting a single file...") }}')">
</form> </form>
</summary> </summary>
<ul style="list-style: none;"> <ul class="inline_list">
<li>{{ member["related_properties_file"] }}</li> <li>{{ member["related_properties_file"] }}</li>
</ul> </ul>
</details> </details>
@ -254,9 +256,9 @@
{% else %} {% else %}
<td>{{ file["name"] }}</td> <td>{{ file["name"] }}</td>
{% endif %} {% endif %}
<td style="text-align:center"> <td align="center">
<form action="/files/download" method="post"> <form action="/files/download" method="post">
<input name="file" type="hidden" value="{{ base_dir }}/{{ file['name'] }}"> <input name="file" type="hidden" value="{{ env["image_dir"] }}/{{ file['name'] }}">
<input type="submit" value="{{ file['size_mb'] }} {{ _("MiB") }} &#8595;"> <input type="submit" value="{{ file['size_mb'] }} {{ _("MiB") }} &#8595;">
</form> </form>
</td> </td>
@ -275,23 +277,24 @@
<form action="/scsi/attach" method="post"> <form action="/scsi/attach" method="post">
<input name="file_name" type="hidden" value="{{ file['name'] }}"> <input name="file_name" type="hidden" value="{{ file['name'] }}">
<input name="file_size" type="hidden" value="{{ file['size'] }}"> <input name="file_size" type="hidden" value="{{ file['size'] }}">
<label for="id">{{ _("ID") }}</label> <label for="image_list_scsi_id_{{ file["name"] }}">{{ _("ID") }}</label>
<select name="scsi_id"> <select name="scsi_id" id="image_list_scsi_id_{{ file["name"] }}">
{% for id in scsi_ids["valid_ids"] %} {% for id in scsi_ids["valid_ids"] %}
<option name="id" value="{{id}}"{% if id == scsi_ids["recommended_id"] %} selected{% endif %}> <option name="id" value="{{id}}"{% if id == scsi_ids["recommended_id"] %} selected{% endif %}>
{{ id }} {{ id }}
</option> </option>
{% endfor %} {% endfor %}
</select> </select>
<label for="unit">{{ _("LUN") }}</label> <label for="image_list_unit_{{ file["name"] }}">{{ _("LUN") }}</label>
<input name="unit" type="number" value="0" min="0" max="31" step="1"> <input class="lun" name="unit" id="image_list_unit_{{ file["name"] }}" type="number" value="0" min="0" max="31" step="1" size="3">
{% if file["detected_type"] != "UNDEFINED" %} {% if file["detected_type"] != "UNDEFINED" %}
<input name="type" type="hidden" value="{{ file['detected_type'] }}"> <input name="type" type="hidden" value="{{ file['detected_type'] }}">
{{ file['detected_type_name'] }} {{ file['detected_type_name'] }}
{% else %} {% else %}
<select name="type"> <label for="image_list_type_{{ file["name"] }}">{{ _("Type") }}</label>
<select name="type" id="image_list_type_{{ file["name"] }}">
<option selected disabled value=""> <option selected disabled value="">
{{ _("Select media type") }} {{ _("Unknown") }}
</option> </option>
{% for key, value in device_types.items() %} {% for key, value in device_types.items() %}
{% if key in DISK_DEVICE_TYPES %} {% if key in DISK_DEVICE_TYPES %}
@ -344,7 +347,7 @@
<ul> <ul>
{% if bridge_configured %} {% if bridge_configured %}
<li>{{ _("The <tt>rascsi_bridge</tt> network bridge is active and ready to be used by an emulated network adapter!") }}</li> <li>{{ _("The <tt>rascsi_bridge</tt> network bridge is active and ready to be used by an emulated network adapter!") }}</li>
{% else %} {% else %}
<li>{{ _("Please configure the <tt>rascsi_bridge</tt> network bridge before attaching an emulated network adapter!") }}</li> <li>{{ _("Please configure the <tt>rascsi_bridge</tt> network bridge before attaching an emulated network adapter!") }}</li>
{% endif %} {% endif %}
<li>{{ _("If you have a DHCP setup, choose only the interface you have configured the bridge with. You can ignore the inet field when attaching.") }}</li> <li>{{ _("If you have a DHCP setup, choose only the interface you have configured the bridge with. You can ignore the inet field when attaching.") }}</li>
@ -355,11 +358,11 @@
</li> </li>
</ul> </ul>
</details> </details>
<table border="black" cellpadding="3"> <table border="black" cellpadding="3" summary="List of peripheral devices">
<tr style="font-weight: bold;"> <tr>
<td>{{ _("Device") }}</td> <th scope="col">{{ _("Device") }}</th>
<td>{{ _("Key") }}</td> <th scope="col">{{ _("Key") }}</th>
<td>{{ _("Parameters and Actions") }}</td> <th scope="col">{{ _("Parameters and Actions") }}</th>
</tr> </tr>
{% for type in REMOVABLE_DEVICE_TYPES + PERIPHERAL_DEVICE_TYPES %} {% for type in REMOVABLE_DEVICE_TYPES + PERIPHERAL_DEVICE_TYPES %}
<tr> <tr>
@ -373,11 +376,11 @@
<form action="/scsi/attach_device" method="post"> <form action="/scsi/attach_device" method="post">
<input name="type" type="hidden" value="{{ type }}"> <input name="type" type="hidden" value="{{ type }}">
{% for key, value in device_types[type]["params"] | dictsort %} {% for key, value in device_types[type]["params"] | dictsort %}
<label for="param_{{ key }}">{{ key }}:</label> <label for="param_{{ type }}_{{ key }}">{{ key }}:</label>
{% if value.isnumeric() %} {% if value.isnumeric() %}
<input name="param_{{ key }}" id="param_{{ key }}" type="number" value="{{ value }}"> <input name="param_{{ key }}" id="param_{{ type }}_{{ key }}" type="number" value="{{ value }}">
{% elif key == "interface" %} {% elif key == "interface" %}
<select name="param_{{ key }}" id="param_{{ key }}"> <select name="param_{{ key }}" id="param_{{ type }}_{{ key }}">
{% for if in netinfo["ifs"] %} {% for if in netinfo["ifs"] %}
<option value="{{ if }}"> <option value="{{ if }}">
{{ if }} {{ if }}
@ -385,12 +388,12 @@
{% endfor %} {% endfor %}
</select> </select>
{% else %} {% else %}
<input name="param_{{ key }}" id="param_{{ key }}" type="text" size="{{ value|length }}" placeholder="{{ value }}"> <input name="param_{{ key }}" id="param_{{ type }}_{{ key }}" type="text" size="{{ value|length }}" placeholder="{{ value }}">
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{% if type in REMOVABLE_DEVICE_TYPES %} {% if type in REMOVABLE_DEVICE_TYPES %}
<label for="drive_name">{{ _("Masquerade as:") }}</label> <label for="{{ type }}_drive_name">{{ _("Masquerade as:") }}</label>
<select name="drive_name"> <select name="drive_name" id="{{ type }}_drive_name">
<option value=""> <option value="">
{{ _("None") }} {{ _("None") }}
</option> </option>
@ -417,16 +420,16 @@
{% endif %} {% endif %}
</select> </select>
{% endif %} {% endif %}
<label for="scsi_id">{{ _("SCSI ID:") }}</label> <label for="{{ type }}_scsi_id">{{ _("ID") }}</label>
<select name="scsi_id"> <select name="scsi_id" id="{{ type }}_scsi_id">
{% for id in scsi_ids["valid_ids"] %} {% for id in scsi_ids["valid_ids"] %}
<option value="{{ id }}"{% if id == scsi_ids["recommended_id"] %} selected{% endif %}> <option value="{{ id }}"{% if id == scsi_ids["recommended_id"] %} selected{% endif %}>
{{ id }} {{ id }}
</option> </option>
{% endfor %} {% endfor %}
</select> </select>
<label for="unit">{{ _("LUN") }}</label> <label for="{{ type }}_unit">{{ _("LUN") }}</label>
<input name="unit" type="number" value="0" min="0" max="31" step="1"> <input class="lun" name="unit" id="{{ type }}_unit" type="number" value="0" min="0" max="31" step="1" size="3">
<input type="submit" value="{{ _("Attach") }}"> <input type="submit" value="{{ _("Attach") }}">
</form> </form>
</td> </td>
@ -446,21 +449,16 @@
</ul> </ul>
</details> </details>
<table style="border: none;"> <form name="dropper" action="/files/upload" method="post" class="dropzone dz-clickable" enctype="multipart/form-data" id="dropper">
<tr style="border: none;"> <p>
<td style="border: none; vertical-align:top;"> <label for="upload_destination">{{ _("Target directory:") }}</label>
<form name="dropper" action="/files/upload" method="post" class="dropzone dz-clickable" enctype="multipart/form-data" id="dropper"> <select name="destination" id="upload_destination">
<p> <option value="images">{{ env["image_dir"] }}</option>
<label for="destination">{{ _("Target directory:") }}</label> <option value="afp">{{ AFP_DIR }}</option>
<select name="destination"> </select>
<option value="images">{{ base_dir }}</option> </p>
<option value="afp">{{ AFP_DIR }}</option> </form>
</select>
</p>
</form>
</td>
</tr>
</table>
<script type="application/javascript"> <script type="application/javascript">
Dropzone.options.dropper = { Dropzone.options.dropper = {
paramName: 'file', paramName: 'file',
@ -502,22 +500,16 @@
</ul> </ul>
</details> </details>
<table style="border: none"> <form action="/files/download_url" method="post">
<tr style="border: none"> <label for="download_destination">{{ _("Target directory:") }}</label>
<td style="border: none; vertical-align:top;"> <select name="destination" id="download_destination">
<form action="/files/download_url" method="post"> <option value="images">{{ env["image_dir"] }}</option>
<label for="destination">{{ _("Target directory:") }}</label> <option value="afp">{{ AFP_DIR }}</option>
<select name="destination"> </select>
<option value="images">{{ base_dir }}</option> <label for="download_url">{{ _("URL:") }}</label>
<option value="afp">{{ AFP_DIR }}</option> <input name="url" id="download_url" required="" type="url">
</select> <input type="submit" value="{{ _("Download") }}" onclick="processNotify('{{ _("Downloading File...") }}')">
<label for="url">{{ _("URL:") }}</label> </form>
<input name="url" placeholder="{{ _("URL") }}" required="" type="url">
<input type="submit" value="{{ _("Download") }}" onclick="processNotify('{{ _("Downloading File...") }}')">
</form>
</td>
</tr>
</table>
<hr/> <hr/>
@ -531,46 +523,41 @@
<li>{{ _("If the downloaded file is a zip archive, we will attempt to unzip it and store the resulting files.") }}</li> <li>{{ _("If the downloaded file is a zip archive, we will attempt to unzip it and store the resulting files.") }}</li>
</ul> </ul>
</details> </details>
<table style="border: none">
<tr style="border: none"> <form action="/files/download_to_iso" method="post">
<td style="border: none; vertical-align:top;"> <label for="iso_url">{{ _("URL:") }}</label>
<label for="scsi_id">{{ _("SCSI ID:") }}</label> <input name="url" id="iso_url" required="" type="url">
<form action="/files/download_to_iso" method="post"> <label for="iso_type">{{ _("Type:") }}</label>
<select name="scsi_id"> <select name="type" id="iso_type">
{% for id in scsi_ids["valid_ids"] %} <option value="-hfs">
<option value="{{ id }}"{% if id == scsi_ids["recommended_id"] %} selected{% endif %}> HFS
{{ id }} </option>
</option> <option value="-iso-level 1">
{% endfor %} ISO-9660 Level 1
</select> </option>
<label for="url">{{ _("URL:") }}</label> <option value="-iso-level 2">
<input name="url" placeholder="{{ _("URL") }}" required="" type="url"> ISO-9660 Level 2
<label for="type">{{ _("Type:") }}</label> </option>
<select name="type"> <option value="-iso-level 3">
<option value="-hfs"> ISO-9660 Level 3
HFS </option>
</option> <option value="-J">
<option value="-iso-level 1"> Joliet
ISO-9660 Level 1 </option>
</option> <option value="-r">
<option value="-iso-level 2"> Rock Ridge
ISO-9660 Level 2 </option>
</option> </select>
<option value="-iso-level 3"> <label for="iso_scsi_id">{{ _("ID") }}</label>
ISO-9660 Level 3 <select name="scsi_id" id="iso_scsi_id">
</option> {% for id in scsi_ids["valid_ids"] %}
<option value="-J"> <option value="{{ id }}"{% if id == scsi_ids["recommended_id"] %} selected{% endif %}>
Joliet {{ id }}
</option> </option>
<option value="-r"> {% endfor %}
Rock Ridge </select>
</option> <input type="submit" value="{{ _("Download and Mount CD-ROM image") }}" onclick="processNotify('{{ _("Downloading File and generating CD-ROM image...") }}')">
</select> </form>
<input type="submit" value="{{ _("Download and Mount CD-ROM image") }}" onclick="processNotify('{{ _("Downloading File and generating CD-ROM image...") }}')">
</form>
</td>
</tr>
</table>
<hr/> <hr/>
@ -582,38 +569,33 @@
<li>{{ _("Please refer to <a href=\"%(url)s\" target=\"_blank\">wiki documentation</a> to learn more about the supported image file types.", url="https://github.com/akuker/RASCSI/wiki/Supported-Device-Types#image-types") }}</li> <li>{{ _("Please refer to <a href=\"%(url)s\" target=\"_blank\">wiki documentation</a> to learn more about the supported image file types.", url="https://github.com/akuker/RASCSI/wiki/Supported-Device-Types#image-types") }}</li>
</ul> </ul>
</details> </details>
<table style="border: none">
<tr style="border: none"> <form action="/files/create" method="post">
<td style="border: none; vertical-align:top;"> <label for="image_create_file_name">{{ _("File Name:") }}</label>
<form action="/files/create" method="post"> <input name="file_name" id="image_create_file_name" required="" type="text">
<label for="file_name">{{ _("File Name:") }}</label> <label for="image_create_type">{{ _("Type:") }}</label>
<input name="file_name" placeholder="{{ _("File Name") }}" required="" type="text"> <select name="type" id="image_create_type">
<label for="type">{{ _("Type:") }}</label> {% for key, value in image_suffixes_to_create.items() %}
<select name="type"> <option value="{{ key }}">
{% for key, value in image_suffixes_to_create.items() %} {{ value }} [.{{ key }}]
<option value="{{ key }}"> </option>
{{ value }} [.{{ key }}] {% endfor %}
</option> </select>
{% endfor %} <label for="image_create_size">{{ _("Size:") }}</label>
</select> <input name="size" id="image_create_size" type="number" placeholder="{{ _("MiB") }}" min="1" max="262144" required>
<label for="size">{{ _("Size:") }}</label> <label for="image_create_drive_name">{{ _("Masquerade as:") }}</label>
<input name="size" type="number" placeholder="{{ _("MiB") }}" min="1" max="262144" required> <select name="drive_name" id="image_create_drive_name">
<label for="drive_name">{{ _("Masquerade as:") }}</label> <option value="">
<select name="drive_name"> {{ _("None") }}
<option value=""> </option>
{{ _("None") }} {% for drive in drive_properties["hd_conf"] | sort(attribute='name') %}
</option> <option value="{{ drive.name }}">
{% for drive in drive_properties["hd_conf"] | sort(attribute='name') %} {{ drive.name }}
<option value="{{ drive.name }}"> </option>
{{ drive.name }} {% endfor %}
</option> </select>
{% endfor %} <input type="submit" value="{{ _("Create") }}">
</select> </form>
<input type="submit" value="{{ _("Create") }}">
</form>
</td>
</tr>
</table>
<hr/> <hr/>
@ -638,35 +620,30 @@
<li>{{ _("Fetch a certain number of lines of system logs with the given scope.") }}</li> <li>{{ _("Fetch a certain number of lines of system logs with the given scope.") }}</li>
</ul> </ul>
</details> </details>
<table style="border: none">
<tr style="border: none"> <form action="/logs/show" method="post">
<td style="border: none; vertical-align:top;"> <label for="log_lines">{{ _("Log Lines:") }}</label>
<form action="/logs/show" method="post"> <input name="lines" id="log_lines" type="number" value="200" min="0" max="99999" step="100">
<label for="lines">{{ _("Log Lines:") }}</label> <label for="log_scope">{{ _("Scope:") }}</label>
<input name="lines" type="number" value="200" min="0" max="99999" step="100"> <select name="scope" id="log_scope">
<label for="scope">{{ _("Scope:") }}</label> <option value="">
<select name="scope"> {{ _("All logs") }}
<option value=""> </option>
{{ _("All logs") }} <option value="rascsi">
</option> rascsi
<option value="rascsi"> </option>
rascsi <option value="rascsi-web">
</option> rascsi-web
<option value="rascsi-web"> </option>
rascsi-web <option value="rascsi-oled">
</option> rascsi-oled
<option value="rascsi-oled"> </option>
rascsi-oled <option value="rascsi-ctrlboard">
</option> rascsi-ctrlboard
<option value="rascsi-ctrlboard"> </option>
rascsi-ctrlboard </select>
</option> <input type="submit" value="{{ _("Show Logs") }}">
</select> </form>
<input type="submit" value="{{ _("Show Logs") }}">
</form>
</td>
</tr>
</table>
<hr/> <hr/>
@ -679,23 +656,18 @@
<li>{{ _("The current dropdown selection indicates the active log level.") }}</li> <li>{{ _("The current dropdown selection indicates the active log level.") }}</li>
</ul> </ul>
</details> </details>
<table style="border: none">
<tr style="border: none"> <form action="/logs/level" method="post">
<td style="border: none; vertical-align:top;"> <label for="log_level">{{ _("Log Level:") }}</label>
<form action="/logs/level" method="post"> <select name="level" id="log_level">
<label for="level">{{ _("Log Level:") }}</label> {% for level in log_levels %}
<select name="level"> <option value="{{ level }}"{% if level == current_log_level %} selected{% endif %}>
{% for level in log_levels %} {{ level }}
<option value="{{ level }}"{% if level == current_log_level %} selected{% endif %}> </option>
{{ level }} {% endfor %}
</option> </select>
{% endfor %} <input type="submit" value="{{ _("Set Log Level") }}">
</select> </form>
<input type="submit" value="{{ _("Set Log Level") }}">
</form>
</td>
</tr>
</table>
<hr/> <hr/>
@ -707,23 +679,18 @@
<li>{{ _("Change the Web Interface language.") }}</li> <li>{{ _("Change the Web Interface language.") }}</li>
</ul> </ul>
</details> </details>
<table style="border: none">
<tr style="border: none"> <form action="/language" method="post">
<td style="border: none; vertical-align:top;"> <label for="locale">{{ _("Language:") }}</label>
<form action="/language" method="post"> <select name="locale" id="locale">
<label for="language">{{ _("Language:") }}</label> {% for locale in locales %}
<select name="locale"> <option value="{{ locale.language }}">
{% for locale in locales %} {{ locale.language }} - {{ locale.display_name }}
<option value="{{ locale.language }}"> </option>
{{ locale.language }} - {{ locale.display_name }} {% endfor %}
</option> </select>
{% endfor %} <input type="submit" value="{{ _("Change Language") }}">
</select> </form>
<input type="submit" value="{{ _("Change Language") }}">
</form>
</td>
</tr>
</table>
<hr/> <hr/>
@ -736,39 +703,16 @@
<li>{{ _("IMPORTANT: Always shut down the Pi before turning off the power. Failing to do so may lead to data loss.") }}</li> <li>{{ _("IMPORTANT: Always shut down the Pi before turning off the power. Failing to do so may lead to data loss.") }}</li>
</ul> </ul>
</details> </details>
<table style="border: none">
<tr style="border: none"> <form action="/pi/reboot" method="post" onclick="if (confirm('{{ _("Reboot the Raspberry Pi?") }}')) shutdownNotify('{{ _("Rebooting the Raspberry Pi...") }}'); else event.preventDefault();">
<td style="border: none; vertical-align:top;"> <input type="submit" value="{{ _("Reboot Raspberry Pi") }}">
<form action="/pi/reboot" method="post" onclick="if (confirm('{{ _("Reboot the Raspberry Pi?") }}')) shutdownNotify('{{ _("Rebooting the Raspberry Pi...") }}'); else event.preventDefault();"> </form>
<input type="submit" value="{{ _("Reboot Raspberry Pi") }}"> <form action="/pi/shutdown" method="post" onclick="if (confirm('{{ _("Shut down the Raspberry Pi?") }}')) shutdownNotify('{{ _("Shutting down the Raspberry Pi...") }}'); else event.preventDefault();">
</form> <input type="submit" value="{{ _("Shut Down Raspberry Pi") }}">
</td> </form>
<td style="border: none; vertical-align:top;">
<form action="/pi/shutdown" method="post" onclick="if (confirm('{{ _("Shut down the Raspberry Pi?") }}')) shutdownNotify('{{ _("Shutting down the Raspberry Pi...") }}'); else event.preventDefault();">
<input type="submit" value="{{ _("Shut Down Raspberry Pi") }}">
</form>
</td>
</tr>
</table>
<hr/> <hr/>
<a href="/sys/manpage?app=rascsi"><p>{{ _("Read the RaSCSI Manual") }}</p></a> <a href="/sys/manpage?app=rascsi"><p>{{ _("Read the RaSCSI Manual") }}</p></a>
<center><tt>
{% if netatalk_configured == 1 %}
{{ _("The AppleShare server is running. No active connections.") }}
{% endif %}
{% if netatalk_configured == 2 %}
{{ _("%(value)d active AFP connection", value=(netatalk_configured - 1)) }}
{% elif netatalk_configured > 2 %}
{{ _("%(value)d active AFP connections", value=(netatalk_configured - 1)) }}
{% endif %}
</center></tt>
<center><tt>
{% if macproxy_configured %}
<center><tt>{{ _("Macproxy is running at %(ip_addr)s (default port 5000)", ip_addr=env['ip_addr']) }}</tt></center>
{% endif %}
</center></tt>
{% endblock content %} {% endblock content %}

View File

@ -1,7 +1,7 @@
{% extends "base.html" %} {% extends "base.html" %}
{% block content %} {% block content %}
<h3>{{ _("System Logs: %(scope)s %(lines)s lines", scope=scope, lines=lines) }}</h3> <h2>{{ _("System Logs: %(scope)s %(lines)s lines", scope=scope, lines=lines) }}</h2>
<p><pre>{{ logs }}</pre></p> <p><pre>{{ logs }}</pre></p>
<p><a href="/">{{ _("Go to Home") }}</a></p> <p><a href="/">{{ _("Go to Home") }}</a></p>

View File

@ -1,7 +1,7 @@
{% extends "base.html" %} {% extends "base.html" %}
{% block content %} {% block content %}
<h1>{{ _("Manual for %(app)s:", app=app) }}</h1> <h2>{{ _("Manual for %(app)s", app=app) }}</h2>
{{ manpage | safe }} {{ manpage | safe }}
<p><a href="/">{{ _("Go to Home") }}</a></p> <p><a href="/">{{ _("Go to Home") }}</a></p>

View File

@ -75,6 +75,7 @@ def get_env_info():
""" """
Get information about the app/host environment Get information about the app/host environment
""" """
server_info = ractl_cmd.get_server_info()
ip_addr, host = sys_cmd.get_ip_and_host() ip_addr, host = sys_cmd.get_ip_and_host()
if "username" in session: if "username" in session:
@ -89,6 +90,14 @@ def get_env_info():
"ip_addr": ip_addr, "ip_addr": ip_addr,
"host": host, "host": host,
"free_disk_space": int(sys_cmd.disk_space()["free"] / 1024 / 1024), "free_disk_space": int(sys_cmd.disk_space()["free"] / 1024 / 1024),
"locale": get_locale(),
"version": server_info["version"],
"image_dir": server_info["image_dir"],
"netatalk_configured": sys_cmd.running_proc("afpd"),
"macproxy_configured": sys_cmd.running_proc("macproxy"),
"cd_suffixes": tuple(server_info["sccd"]),
"rm_suffixes": tuple(server_info["scrm"]),
"mo_suffixes": tuple(server_info["scmo"]),
} }
@ -233,35 +242,29 @@ def index():
return response( return response(
template="index.html", template="index.html",
locales=get_supported_locales(), locales=get_supported_locales(),
netinfo=ractl_cmd.get_network_info(),
bridge_configured=sys_cmd.is_bridge_setup(), bridge_configured=sys_cmd.is_bridge_setup(),
netatalk_configured=sys_cmd.running_proc("afpd"),
macproxy_configured=sys_cmd.running_proc("macproxy"),
devices=formatted_devices, devices=formatted_devices,
attached_images=attached_images,
files=extended_image_files, files=extended_image_files,
config_files=config_files, config_files=config_files,
base_dir=server_info["image_dir"], device_types=device_types,
scan_depth=server_info["scan_depth"], scan_depth=server_info["scan_depth"],
CFG_DIR=CFG_DIR,
AFP_DIR=AFP_DIR,
scsi_ids=scsi_ids,
attached_images=attached_images,
units=units,
reserved_scsi_ids=reserved_scsi_ids,
RESERVATIONS=RESERVATIONS,
max_file_size=int(int(MAX_FILE_SIZE) / 1024 / 1024),
version=server_info["version"],
log_levels=server_info["log_levels"], log_levels=server_info["log_levels"],
current_log_level=server_info["current_log_level"], current_log_level=server_info["current_log_level"],
netinfo=ractl_cmd.get_network_info(), scsi_ids=scsi_ids,
device_types=device_types, units=units,
reserved_scsi_ids=reserved_scsi_ids,
image_suffixes_to_create=image_suffixes_to_create, image_suffixes_to_create=image_suffixes_to_create,
valid_image_suffixes=valid_image_suffixes, valid_image_suffixes=valid_image_suffixes,
cdrom_file_suffix=tuple(server_info["sccd"]),
removable_file_suffix=tuple(server_info["scrm"]),
mo_file_suffix=tuple(server_info["scmo"]),
drive_properties=drive_properties, drive_properties=drive_properties,
max_file_size=int(int(MAX_FILE_SIZE) / 1024 / 1024),
RESERVATIONS=RESERVATIONS,
CFG_DIR=CFG_DIR,
AFP_DIR=AFP_DIR,
PROPERTIES_SUFFIX=PROPERTIES_SUFFIX, PROPERTIES_SUFFIX=PROPERTIES_SUFFIX,
ARCHIVE_FILE_SUFFIXES=ARCHIVE_FILE_SUFFIXES, ARCHIVE_FILE_SUFFIXES=ARCHIVE_FILE_SUFFIXES,
CONFIG_FILE_SUFFIX=CONFIG_FILE_SUFFIX,
REMOVABLE_DEVICE_TYPES=ractl_cmd.get_removable_device_types(), REMOVABLE_DEVICE_TYPES=ractl_cmd.get_removable_device_types(),
DISK_DEVICE_TYPES=ractl_cmd.get_disk_device_types(), DISK_DEVICE_TYPES=ractl_cmd.get_disk_device_types(),
PERIPHERAL_DEVICE_TYPES=ractl_cmd.get_peripheral_device_types(), PERIPHERAL_DEVICE_TYPES=ractl_cmd.get_peripheral_device_types(),
@ -291,15 +294,10 @@ def drive_list():
"mo_conf": [], "mo_conf": [],
} }
server_info = ractl_cmd.get_server_info()
return response( return response(
template="drives.html", template="drives.html",
files=file_cmd.list_images()["files"], files=file_cmd.list_images()["files"],
base_dir=server_info["image_dir"],
drive_properties=drive_properties, drive_properties=drive_properties,
version=server_info["version"],
cdrom_file_suffix=tuple(server_info["sccd"]),
) )
@ -469,7 +467,6 @@ def show_diskinfo():
template="diskinfo.html", template="diskinfo.html",
file_name=file_name, file_name=file_name,
diskinfo=diskinfo, diskinfo=diskinfo,
version=server_info["version"],
) )
return response( return response(
@ -493,7 +490,6 @@ def show_manpage():
message=_("%(app)s is not a recognized RaSCSI app", app=app) message=_("%(app)s is not a recognized RaSCSI app", app=app)
) )
server_info = ractl_cmd.get_server_info()
file_path = f"{WEB_DIR}/../../../doc/{app}.1" file_path = f"{WEB_DIR}/../../../doc/{app}.1"
html_to_strip = [ html_to_strip = [
"Content-type", "Content-type",
@ -521,7 +517,6 @@ def show_manpage():
template="manpage.html", template="manpage.html",
app=app, app=app,
manpage=formatted_manpage, manpage=formatted_manpage,
version=server_info["version"],
) )
return response( return response(
@ -540,13 +535,11 @@ def show_logs():
returncode, logs = sys_cmd.get_logs(lines, scope) returncode, logs = sys_cmd.get_logs(lines, scope)
if returncode == 0: if returncode == 0:
server_info = ractl_cmd.get_server_info()
return response( return response(
template="logs.html", template="logs.html",
scope=scope, scope=scope,
lines=lines, lines=lines,
logs=logs, logs=logs,
version=server_info["version"],
) )
return response( return response(
@ -764,13 +757,11 @@ def device_info():
""" """
Displays detailed info for all attached devices Displays detailed info for all attached devices
""" """
server_info = ractl_cmd.get_server_info()
process = ractl_cmd.list_devices() process = ractl_cmd.list_devices()
if process["status"]: if process["status"]:
return response( return response(
template="deviceinfo.html", template="deviceinfo.html",
devices=process["device_list"], devices=process["device_list"],
version=server_info["version"],
) )
return response(error=True, message=_("No devices attached")) return response(error=True, message=_("No devices attached"))