Merge remote-tracking branch 'origin/release'
This commit is contained in:
commit
de5ac9bee0
@ -0,0 +1,2 @@
|
||||
- [Feature] Only allow command cancellation from relevant page. (by @mlabeeb03)
|
||||
- [Feature] Add link to developer panel while command is in progress. (by @mlabeeb03)
|
||||
@ -9,7 +9,6 @@ from markdown import markdown
|
||||
from quart import (
|
||||
Quart,
|
||||
Response,
|
||||
abort,
|
||||
g,
|
||||
jsonify,
|
||||
make_response,
|
||||
@ -126,7 +125,6 @@ async def plugin_installed_list() -> str:
|
||||
@app.get("/plugin/<name>")
|
||||
async def plugin(name: str) -> Response:
|
||||
# TODO check that plugin exists
|
||||
show_logs = request.args.get("show_logs")
|
||||
seq_command_executed = request.args.get("seq_command_executed")
|
||||
author = next(
|
||||
(
|
||||
@ -151,7 +149,6 @@ async def plugin(name: str) -> Response:
|
||||
is_installed=name in g.installed_plugins,
|
||||
author_name=author,
|
||||
plugin_description=description,
|
||||
show_logs=show_logs,
|
||||
seq_command_executed=seq_command_executed,
|
||||
plugin_config_unique=tutorclient.Client.plugin_config_unique(name),
|
||||
plugin_config_defaults=tutorclient.Client.plugin_config_defaults(name),
|
||||
@ -214,7 +211,6 @@ async def plugin_install(name: str) -> WerkzeugResponse:
|
||||
url_for(
|
||||
"plugin",
|
||||
name=name,
|
||||
show_logs=True,
|
||||
)
|
||||
)
|
||||
|
||||
@ -226,14 +222,13 @@ async def plugin_upgrade(name: str) -> WerkzeugResponse:
|
||||
url_for(
|
||||
"plugin",
|
||||
name=name,
|
||||
show_logs=True,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@app.post("/plugins/update")
|
||||
async def plugins_update() -> WerkzeugResponse:
|
||||
tutorclient.CliPool.run_parallel(app, ["plugins", "update"])
|
||||
tutorclient.CliPool.run_sequential(["plugins", "update"])
|
||||
return redirect(url_for("plugin_store"))
|
||||
|
||||
|
||||
@ -286,7 +281,6 @@ async def cli_local_launch() -> str:
|
||||
tutorclient.CliPool.run_parallel(app, ["local", "launch", "--non-interactive"])
|
||||
return await render_template(
|
||||
"local_launch.html",
|
||||
show_logs=True,
|
||||
)
|
||||
|
||||
|
||||
@ -349,7 +343,6 @@ async def cli_stop() -> Response:
|
||||
async def advanced() -> str:
|
||||
return await render_template(
|
||||
"advanced.html",
|
||||
show_logs=True,
|
||||
)
|
||||
|
||||
|
||||
@ -366,7 +359,5 @@ async def command() -> WerkzeugResponse:
|
||||
form = await request.form
|
||||
command_string = form.get("command", "")
|
||||
command_args = command_string.split()
|
||||
if tutorclient.CliPool.is_thread_alive():
|
||||
abort(400, description="Command execution already in progress")
|
||||
tutorclient.CliPool.run_parallel(app, command_args)
|
||||
return redirect(url_for("advanced"))
|
||||
|
||||
@ -113,3 +113,40 @@ function setToastContent(cmd) {
|
||||
toastFooter.style.display = config.showFooter ? "flex" : "none";
|
||||
}
|
||||
}
|
||||
|
||||
// Each page defines its own relevant commands, we use them to check
|
||||
// if the currently running commands belong the currently opened page or not
|
||||
let relevantCommands = [];
|
||||
let onDeveloperPage = false;
|
||||
function onRelevantPage(command) {
|
||||
if (onDeveloperPage) {
|
||||
// Developer page is relevant to all commands
|
||||
return true;
|
||||
}
|
||||
return relevantCommands.some((prefix) => command.startsWith(prefix));
|
||||
}
|
||||
|
||||
function activateInputs() {
|
||||
document.querySelectorAll("button").forEach((button) => {
|
||||
button.disabled = false;
|
||||
});
|
||||
document.querySelectorAll("input").forEach((input) => {
|
||||
input.disabled = false;
|
||||
});
|
||||
document.querySelectorAll(".form-switch").forEach((formSwitch) => {
|
||||
formSwitch.style.opacity = 1;
|
||||
});
|
||||
document.getElementById("warning-command-running").style.display = "none";
|
||||
}
|
||||
function deactivateInputs() {
|
||||
document.querySelectorAll("button").forEach((button) => {
|
||||
button.disabled = true;
|
||||
});
|
||||
document.querySelectorAll("input").forEach((input) => {
|
||||
input.disabled = true;
|
||||
});
|
||||
document.querySelectorAll(".form-switch").forEach((formSwitch) => {
|
||||
formSwitch.style.opacity = 0.5;
|
||||
});
|
||||
document.getElementById("warning-command-running").style.display = "flex";
|
||||
}
|
||||
|
||||
@ -23,14 +23,21 @@ htmx.on("htmx:sseBeforeMessage", function (evt) {
|
||||
const data = JSON.parse(evt.detail.data);
|
||||
const command = data.command;
|
||||
|
||||
// This means a parallel command just started its execution
|
||||
if (!executedNewCommand && data.thread_alive) {
|
||||
ShowCancelCommandButton();
|
||||
// This means a parallel command is executing
|
||||
if (data.thread_alive) {
|
||||
// Check if we are on the same page on which the actual command was executed
|
||||
// Each page defines its relevant commands which are sent to `onRelevantPage` function to check if we are on the relevant page
|
||||
if (onRelevantPage(command)) {
|
||||
ShowCancelCommandButton();
|
||||
logsElement.style.display = "block";
|
||||
} else {
|
||||
// If we are not on relevant page we don't show the cancel button and disable all inputs
|
||||
deactivateInputs();
|
||||
}
|
||||
executedNewCommand = true;
|
||||
}
|
||||
|
||||
const parallelCommandCompleted =
|
||||
executedNewCommand && !data.thread_alive;
|
||||
const parallelCommandCompleted = executedNewCommand && !data.thread_alive;
|
||||
|
||||
const onPluginPage = typeof pluginName !== "undefined";
|
||||
// Note that sequential commands are only executed on the plugins page
|
||||
@ -40,6 +47,7 @@ htmx.on("htmx:sseBeforeMessage", function (evt) {
|
||||
parallelCommandCompleted ||
|
||||
(onPluginPage && sequentialCommandExecuted)
|
||||
) {
|
||||
activateInputs();
|
||||
// There are certain commands for which we do not show the toast message
|
||||
// Only show the toast if it was set in the `setToastContent` function and if the command ran successfully
|
||||
if (data.stdout.includes("Success!")) {
|
||||
|
||||
@ -23,6 +23,11 @@ $green-1: #edfff7;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
button:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
@mixin command {
|
||||
width: 9em;
|
||||
height: 3em;
|
||||
@ -355,6 +360,26 @@ main {
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 2em;
|
||||
}
|
||||
}
|
||||
#warning-command-running {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
display: none;
|
||||
border: 1px solid $gray-2;
|
||||
border-radius: 0.5em;
|
||||
align-items: center;
|
||||
font-size: 1.25em;
|
||||
color: $gray-4;
|
||||
padding: 0.5em 1em;
|
||||
margin-top: 1em;
|
||||
span {
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 2em;
|
||||
}
|
||||
@ -689,6 +714,7 @@ main {
|
||||
|
||||
.tutor-logs-container {
|
||||
#tutor-logs {
|
||||
display: none;
|
||||
width: 100%;
|
||||
background-color: black;
|
||||
color: white;
|
||||
|
||||
@ -34,6 +34,8 @@ Search for any tutor command and execute it with a single click.
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
onDeveloperPage = true;
|
||||
logsElement.style.display = "block";
|
||||
runCommandButton = document.querySelector('.run-command-button')
|
||||
cancelCommandButton = document.querySelector('.cancel-command-button')
|
||||
const toggleButtons = ({run = false, cancel = false} = {}) => {
|
||||
|
||||
@ -49,7 +49,13 @@
|
||||
</nav>
|
||||
|
||||
<section>
|
||||
<header>{% block workspace_header %}{% endblock %}</header>
|
||||
<header>
|
||||
<div id="warning-command-running">
|
||||
<img src="{{ url_for('static', filename='/img/Featured icon.svg')}}" alt="">
|
||||
<span>Command execution in progress. <a href="{{ url_for('advanced') }}">Click here</a> to view details.</span>
|
||||
</div>
|
||||
{% block workspace_header %}{% endblock %}
|
||||
</header>
|
||||
<section>
|
||||
{% block workspace_content %}
|
||||
{% endblock %}
|
||||
@ -111,10 +117,6 @@
|
||||
{% endif %}
|
||||
<script>
|
||||
const logsElement = document.getElementById("tutor-logs");
|
||||
show_logs = '{{ show_logs }}' === 'True';
|
||||
if (!show_logs){
|
||||
logsElement.style.display = 'none';
|
||||
}
|
||||
</script>
|
||||
{% block scripts %}{% endblock %}
|
||||
<script src="{{ url_for('static', filename='js/logs.js') }}"></script>
|
||||
|
||||
@ -24,6 +24,7 @@ This will run Launch Platform to apply all plugin changes. This may take a few m
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
relevantCommands = ["tutor local launch --non-interactive"];
|
||||
localLaunchButton = document.getElementById('local-launch-button')
|
||||
cancelLocalLaunchButton = document.getElementById('cancel-local-launch-button')
|
||||
const toggleButtons = ({run = false, cancel = false} = {}) => {
|
||||
|
||||
@ -53,6 +53,8 @@
|
||||
pluginInstallButton = document.getElementById('plugin-install-button');
|
||||
cancelCommandButton = document.getElementById('cancel-command-button');
|
||||
|
||||
relevantCommands = ["tutor plugins install", "tutor plugins upgrade"];
|
||||
|
||||
const toggleButtons = ({install = false, upgrade = false, cancel = false} = {}) => {
|
||||
pluginInstallButton.style.display = install ? 'block' : 'none';
|
||||
pluginUpgradeButton.style.display = upgrade ? 'block' : 'none';
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user