Skip to content
This repository was archived by the owner on Oct 15, 2025. It is now read-only.

Commit 4f7eead

Browse files
committed
fix(challenge): Prevent bloated query update AJAX
1 parent 8286e07 commit 4f7eead

File tree

3 files changed

+47
-39
lines changed

3 files changed

+47
-39
lines changed

assets/controllers/challenge_executor_controller.ts

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,44 +5,65 @@ import { basicSetup, EditorView } from "codemirror";
55

66
export default class extends Controller<HTMLElement> {
77
static values = {
8-
modelName: String,
98
editorSelector: String,
9+
submitButtonSelector: String,
1010
};
1111

12-
declare modelNameValue: string;
1312
declare editorSelectorValue: string;
13+
declare submitButtonSelectorValue: string;
1414

15-
view: EditorView | undefined;
15+
#editorView: EditorView | undefined;
1616

1717
async connect() {
1818
const component = await getComponent(this.element);
19+
const lastQuery = this.element.dataset["lastQuery"];
1920

20-
const modelName = this.modelNameValue;
21-
const editorSelector = this.editorSelectorValue;
22-
23-
const $editor = this.element.querySelector(editorSelector);
21+
const $editor = this.element.querySelector(this.editorSelectorValue);
2422
if (!$editor) {
25-
throw new Error(`Element not found: ${editorSelector}`);
23+
throw new Error(`Element not found: ${this.editorSelectorValue}`);
2624
}
2725

28-
const lastQuery = this.element.dataset["lastQuery"];
26+
const $submitButton = this.element.querySelector(this.submitButtonSelectorValue);
27+
if (!$submitButton || !($submitButton instanceof HTMLButtonElement)) {
28+
throw new Error(`Element not found or not a button: ${this.submitButtonSelectorValue}`);
29+
}
2930

30-
this.view = new EditorView({
31+
// Create the code editor with the last query.
32+
const editorView = new EditorView({
3133
doc: lastQuery,
3234
extensions: [
3335
basicSetup,
3436
sql(),
35-
EditorView.updateListener.of((update) => {
36-
component.set(modelName, update.state.doc.toString(), true, true);
37+
EditorView.updateListener.of(() => {
38+
const doc = editorView.state.doc.toString();
39+
40+
if (doc.trim() === "" || doc === lastQuery) {
41+
// Disable the button if the user does not query something new.
42+
$submitButton.disabled = true;
43+
} else {
44+
// Enable the button if the user types something.
45+
$submitButton.disabled = false;
46+
}
3747
}),
3848
],
3949
parent: $editor,
4050
});
51+
this.#editorView = editorView;
52+
53+
// If the user presses the submit button, we'll send the query to the server.
54+
$submitButton.addEventListener("click", async () => {
55+
const query = editorView.state.doc.toString();
56+
57+
console.debug("Executing query", { query });
58+
await component.action("execute", {
59+
query,
60+
});
61+
});
4162
}
4263

4364
disconnect() {
4465
super.disconnect();
4566

46-
this.view?.destroy();
67+
this.#editorView?.destroy();
4768
}
4869
}

src/Twig/Components/Challenge/Executor.php

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Symfony\Component\Serializer\SerializerInterface;
1616
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
1717
use Symfony\UX\LiveComponent\Attribute\LiveAction;
18+
use Symfony\UX\LiveComponent\Attribute\LiveArg;
1819
use Symfony\UX\LiveComponent\Attribute\LiveProp;
1920
use Symfony\UX\LiveComponent\ComponentToolsTrait;
2021
use Symfony\UX\LiveComponent\DefaultActionTrait;
@@ -38,12 +39,6 @@ public function __construct(
3839
#[LiveProp]
3940
public User $user;
4041

41-
/**
42-
* @var string the query to execute
43-
*/
44-
#[LiveProp(writable: true)]
45-
public string $query;
46-
4742
public function getPreviousQuery(): string
4843
{
4944
$se = $this->solutionEventRepository->findOneBy([
@@ -55,19 +50,21 @@ public function getPreviousQuery(): string
5550
}
5651

5752
#[LiveAction]
58-
public function execute(SerializerInterface $serializer): void
59-
{
60-
if ('' === $this->query) {
53+
public function execute(
54+
SerializerInterface $serializer,
55+
#[LiveArg] string $query,
56+
): void {
57+
if ('' === $query) {
6158
return;
6259
}
6360

6461
$solutionEvent = (new SolutionEvent())
6562
->setQuestion($this->question)
6663
->setSubmitter($this->user)
67-
->setQuery($this->query);
64+
->setQuery($query);
6865

6966
try {
70-
$result = $this->questionDbRunnerService->getQueryResult($this->question, $this->query);
67+
$result = $this->questionDbRunnerService->getQueryResult($this->question, $query);
7168

7269
$answer = $this->questionDbRunnerService->getAnswerResult($this->question);
7370
$same = $result === $answer;

templates/components/Challenge/Executor.html.twig

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,19 @@
11
{% set previousQuery = this.previousQuery %}
22

33
<section {{ attributes.defaults({class: 'challenge-sql-executor'}|merge(stimulus_controller('challenge-executor', {
4-
modelName: 'query',
54
editorSelector: '.challenge-sql-executor__editor',
5+
submitButtonSelector: '.challenge-sql-executor__action__submit',
66
}))) }} data-last-query="{{ previousQuery }}">
77
<section class="challenge-sql-executor__actions hstack">
88
<div class="challenge-sql-executor__actions__left me-auto">
99
{% block actions %}{% endblock %}
1010
</div>
1111

1212
<div class="challenge-sql-executor__actions__right">
13-
{% if query is not empty and query is not same as(previousQuery) %}
14-
<button type="button" class="btn btn-primary"
15-
data-loading="action(execute)|addAttribute(disabled)"
16-
data-action="live#action"
17-
data-live-action-param="execute">
18-
<i class="bi bi-send"></i>
19-
提交
20-
</button>
21-
{% else %}
22-
<button type="button" class="btn btn-primary" disabled>
23-
<i class="bi bi-send"></i>
24-
提交
25-
</button>
26-
{% endif %}
13+
<button type="button" class="btn btn-primary challenge-sql-executor__action__submit">
14+
<i class="bi bi-send"></i>
15+
提交
16+
</button>
2717
</div>
2818
</section>
2919
<hr>

0 commit comments

Comments
 (0)