fix: minor comments, TODO items and formatting

This has almost no impact, outside of rewording some items.
This commit is contained in:
Régis Behmo 2025-08-12 21:30:24 +02:00 committed by Régis Behmo
parent 097be3e3fe
commit b60655ed54
7 changed files with 37 additions and 29 deletions

View File

@ -17,8 +17,8 @@ from quart import (
request,
url_for,
)
from quart.helpers import WerkzeugResponse
from quart.typing import ResponseTypes
from werkzeug.sansio.response import Response as BaseResponse
from tutor.plugins.v1 import discover_package
from tutordeck.server.utils import current_page_plugins, pagination_context
@ -80,7 +80,7 @@ async def plugin_store_list() -> str:
"name": p.name,
"url": p.url,
"index": p.index,
"author": p.author.split("<")[0].strip(),
"author": tutorclient.Client.get_plugin_author(p),
"description": p.short_description,
"is_installed": p.name in g.installed_plugins,
"is_enabled": p.name in g.enabled_plugins,
@ -102,13 +102,16 @@ async def plugin_store_list() -> str:
@app.get("/plugin/installed/list")
async def plugin_installed_list() -> str:
# TODO IMPORTANT this displays only the plugins that are in the store. When a plugin
# is installed locally but not in the store, we must display it here anyway.
# TODO this is duplicated code from plugin_store_list
search_query = request.args.get("search", "")
plugins: list[dict[str, t.Any]] = [
{
"name": p.name,
"url": p.url,
"index": p.index,
"author": p.author.split("<")[0].strip(),
"author": tutorclient.Client.get_plugin_author(p),
"description": p.short_description,
"is_enabled": p.name in g.enabled_plugins,
}
@ -129,15 +132,16 @@ async def plugin(name: str) -> Response:
if not index_entry:
return Response("Plugin not found", status=404)
# TODO this seq_command_executed argument is confusing and causing issues, for
# instance with the "unset" button. We need to get rid of it.
seq_command_executed = request.args.get("seq_command_executed")
author = index_entry.author.split("<")[0].strip()
description = markdown(index_entry.description)
rendered_template = await render_template(
"plugin.html",
plugin_name=name,
is_enabled=name in g.enabled_plugins,
is_installed=name in g.installed_plugins,
author_name=author,
author_name=tutorclient.Client.get_plugin_author(index_entry),
plugin_description=description,
seq_command_executed=seq_command_executed,
plugin_config_unique=tutorclient.Client.plugin_config_unique(name),
@ -146,6 +150,7 @@ async def plugin(name: str) -> Response:
)
# Redirect to plugin page
# TODO this is useful only after a POST to plugin/<name>/update. I don't think these two things should be handled in the same place.
response = Response(rendered_template, status=200, content_type="text/html")
response.headers["HX-Redirect"] = url_for(
"plugin", name=name, seq_command_executed=seq_command_executed
@ -188,11 +193,12 @@ async def plugin_toggle(name: str) -> Response:
@app.post("/plugin/<name>/install")
async def plugin_install(name: str) -> WerkzeugResponse:
async def plugin_install(name: str) -> BaseResponse:
async def bg_install_and_reload() -> None:
tutorclient.CliPool.run_parallel(app, ["plugins", "install", name])
while tutorclient.CliPool.THREAD and tutorclient.CliPool.THREAD.is_alive():
await asyncio.sleep(0.1)
# TODO this is hackish. How can we improve?
discover_package(importlib_metadata.entry_points().__getitem__(name))
asyncio.create_task(bg_install_and_reload())
@ -205,7 +211,7 @@ async def plugin_install(name: str) -> WerkzeugResponse:
@app.post("/plugin/<name>/upgrade")
async def plugin_upgrade(name: str) -> WerkzeugResponse:
async def plugin_upgrade(name: str) -> BaseResponse:
tutorclient.CliPool.run_parallel(app, ["plugins", "upgrade", name])
return redirect(
url_for(
@ -344,7 +350,7 @@ async def suggest() -> Response:
@app.post("/command")
async def command() -> WerkzeugResponse:
async def command() -> BaseResponse:
form = await request.form
command_string = form.get("command", "")
command_args = command_string.split()

View File

@ -46,7 +46,7 @@
</div>
</a>
{% endif %}
{% for page_number in range(1, pagination.total_pages + 1) %}
{% for page_number in range(1, pagination.total_pages + 1) %}
<a hx-get="{{ url_for('plugin_store_list', page=page_number)}}" hx-target="#plugins-list">
<div class="pagination-button">
{{ page_number }}

View File

@ -8,16 +8,12 @@ Developer Mode
Search for any tutor command and execute it with a single click.
{% endblock %}
{% block page_button %}
{% endblock %}
{% block searchbar %}
{% endblock %}
{% block warning %}
{% endblock %}
{% set sidebar_active_tab = "advanced" %}
{% block workspace_content %}

View File

@ -39,4 +39,4 @@ This will run Launch Platform to apply all plugin changes. This may take a few m
}
ShowRunCommandButton();
</script>
{% endblock %}
{% endblock %}

View File

@ -40,7 +40,7 @@
{% else %}
<p>N/A</p>
{% endif %}
<button type="submit">Update All</button>
<button type="submit">Save changes</button>
</form>
{% endif %}
@ -79,6 +79,7 @@
bar.style.display = isPluginInstalled ? 'flex' : 'none';
}
async function checkIfPluginInstalled(pluginName) {
// TODO let's avoid hard-coded urls
const response = await fetch(`/plugin/${pluginName}/is-installed`);
const data = await response.json();
return data.installed;

View File

@ -9,7 +9,7 @@ View all your installed plugins in one place.
{% endblock %}
{% block page_button %}
<button class=" open-modal-button" type="button">Apply Changes</button>
<button class="open-modal-button" type="button">Apply Changes</button>
{% endblock %}
{% set sidebar_active_tab = "my-plugins" %}

View File

@ -114,7 +114,8 @@ class Cli:
self.log_to_file(e.args[0])
self.log_to_file("\nCancelled!\n")
except SystemExit:
# TODO Is there a better way to notify command completion???
# TODO Is there a better way to notify command completion??? The
# frontend relies on this hard-coded string to detect launch completion.
self.log_to_file("\nSuccess!")
def stop(self) -> None:
@ -326,9 +327,7 @@ class Client:
@classmethod
def plugins_matching_pattern(cls, pattern: str) -> list[str]:
return [
plugin._data["name"]
for plugin in cls.plugins_in_store()
if plugin.match(pattern)
plugin.name for plugin in cls.plugins_in_store() if plugin.match(pattern)
]
@classmethod
@ -356,19 +355,25 @@ class Client:
key: user_config.get(key, value) for key, value in config_defaults.items()
}
@classmethod
def get_plugin_author(cls, index_entry: tutor.plugins.indexes.IndexEntry) -> str:
return index_entry.author.split("<")[0].strip()
@classmethod
def autocomplete(cls, partial_command: str) -> list[dict[str, str]]:
"""
Handle CLI command completion via click_repl.ClickCompleter
https://github.com/click-contrib/click-repl/blob/master/click_repl/_completer.py
"""
cli = tutor.commands.cli.cli
ctx = click.Context(cli, info_name=cli.name, parent=None)
completer = click_repl.ClickCompleter(cli, ctx)
document = Document(partial_command, len(partial_command))
completions = list(completer.get_completions(document, None))
suggestions = []
for completion in completions:
suggestions.append(
{
"text": completion.text,
"display": completion.display,
}
)
return suggestions
return [
{
"text": completion.text,
"display": completion.display,
}
for completion in completions
]