mirror of
https://github.com/penpot/penpot.git
synced 2026-08-07 21:38:48 +00:00
🐛 Fix batch delete sync and keep graph console feed alive
This commit is contained in:
parent
97e339ee5d
commit
ad0ad3e75a
@ -90,7 +90,7 @@ Graph Console
|
||||
|
||||
<fieldset>
|
||||
<legend>Cypher query</legend>
|
||||
<form method="post" action="/dbg/actions/graph-query">
|
||||
<form id="graph-query-form" method="post" action="/dbg/actions/graph-query">
|
||||
<div class="row">
|
||||
<textarea name="query" rows="8" style="width:100%; font-family: monospace;">{{query}}</textarea>
|
||||
</div>
|
||||
@ -99,37 +99,39 @@ Graph Console
|
||||
</div>
|
||||
</form>
|
||||
</fieldset>
|
||||
{% endif %}
|
||||
|
||||
{% if error %}
|
||||
<fieldset>
|
||||
<legend>Error</legend>
|
||||
<pre>{{error}}</pre>
|
||||
</fieldset>
|
||||
{% endif %}
|
||||
<div id="graph-query-output">
|
||||
{% if error %}
|
||||
<fieldset>
|
||||
<legend>Error</legend>
|
||||
<pre>{{error}}</pre>
|
||||
</fieldset>
|
||||
{% endif %}
|
||||
|
||||
{% if query-result %}
|
||||
<fieldset>
|
||||
<legend>Results ({{query-result.row-count}} rows{% if query-result.truncated? %}, truncated{% endif %})</legend>
|
||||
<table border="1" cellpadding="4" cellspacing="0" style="border-collapse: collapse; width: 100%;">
|
||||
<thead>
|
||||
<tr>
|
||||
{% for column in query-result.columns %}
|
||||
<th>{{column}}</th>
|
||||
{% if query-result %}
|
||||
<fieldset>
|
||||
<legend>Results ({{query-result.row-count}} rows{% if query-result.truncated? %}, truncated{% endif %})</legend>
|
||||
<table border="1" cellpadding="4" cellspacing="0" style="border-collapse: collapse; width: 100%;">
|
||||
<thead>
|
||||
<tr>
|
||||
{% for column in query-result.columns %}
|
||||
<th>{{column}}</th>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for row in query-result.rows %}
|
||||
<tr>
|
||||
{% for cell in row %}
|
||||
<td><code>{{cell}}</code></td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for row in query-result.rows %}
|
||||
<tr>
|
||||
{% for cell in row %}
|
||||
<td><code>{{cell}}</code></td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</fieldset>
|
||||
</tbody>
|
||||
</table>
|
||||
</fieldset>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</section>
|
||||
</main>
|
||||
@ -302,6 +304,77 @@ Graph Console
|
||||
});
|
||||
}
|
||||
|
||||
function escapeHtml(text) {
|
||||
return String(text)
|
||||
.replace(/&/g, "&")
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">")
|
||||
.replace(/"/g, """);
|
||||
}
|
||||
|
||||
function renderQueryOutput(data) {
|
||||
const output = document.getElementById("graph-query-output");
|
||||
if (!output) return;
|
||||
|
||||
if (data.error) {
|
||||
output.innerHTML =
|
||||
"<fieldset><legend>Error</legend>"
|
||||
+ "<pre>" + escapeHtml(data.error) + "</pre></fieldset>";
|
||||
return;
|
||||
}
|
||||
|
||||
const result = data["query-result"];
|
||||
if (!result) {
|
||||
output.innerHTML = "";
|
||||
return;
|
||||
}
|
||||
|
||||
const truncated = result["truncated?"] ? ", truncated" : "";
|
||||
let html =
|
||||
"<fieldset><legend>Results ("
|
||||
+ escapeHtml(String(result["row-count"]))
|
||||
+ " rows" + truncated + ")</legend>"
|
||||
+ "<table border=\"1\" cellpadding=\"4\" cellspacing=\"0\""
|
||||
+ " style=\"border-collapse: collapse; width: 100%;\">"
|
||||
+ "<thead><tr>";
|
||||
|
||||
(result.columns || []).forEach(function (column) {
|
||||
html += "<th>" + escapeHtml(column) + "</th>";
|
||||
});
|
||||
html += "</tr></thead><tbody>";
|
||||
|
||||
(result.rows || []).forEach(function (row) {
|
||||
html += "<tr>";
|
||||
row.forEach(function (cell) {
|
||||
html += "<td><code>" + escapeHtml(cell) + "</code></td>";
|
||||
});
|
||||
html += "</tr>";
|
||||
});
|
||||
|
||||
html += "</tbody></table></fieldset>";
|
||||
output.innerHTML = html;
|
||||
}
|
||||
|
||||
const queryForm = document.getElementById("graph-query-form");
|
||||
if (queryForm) {
|
||||
queryForm.addEventListener("submit", function (event) {
|
||||
event.preventDefault();
|
||||
const formData = new FormData(queryForm);
|
||||
fetch("/dbg/actions/graph-query", {
|
||||
method: "POST",
|
||||
headers: { "Accept": "application/json" },
|
||||
body: formData
|
||||
})
|
||||
.then(function (resp) { return resp.text(); })
|
||||
.then(function (text) {
|
||||
renderQueryOutput(parseTransitMap(JSON.parse(text)));
|
||||
})
|
||||
.catch(function (err) {
|
||||
renderQueryOutput({ error: String(err) });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
connect();
|
||||
refreshSyncStatus();
|
||||
|
||||
|
||||
@ -408,7 +408,9 @@
|
||||
{:index (reduce index-remove-shape! index to-delete)
|
||||
:statements statements
|
||||
:applied? true})
|
||||
{:index index :statements [] :applied? false :reason :missing-shape}))
|
||||
;; Penpot emits one :del-obj per selected shape; an earlier change in the
|
||||
;; same batch may have already removed this node (e.g. parent + child).
|
||||
{:index index :statements [] :applied? true}))
|
||||
|
||||
(defn- apply-add-page
|
||||
[index {:keys [id name page]}]
|
||||
|
||||
@ -403,21 +403,38 @@
|
||||
::yres/headers {"content-type" "application/json; charset=utf-8"}
|
||||
::yres/body (t/encode-str {:error "no-session"} {:type :json-verbose})}))
|
||||
|
||||
(defn- json-request?
|
||||
[request]
|
||||
(some-> request
|
||||
(yreq/get-header "accept")
|
||||
(str/includes? "application/json")))
|
||||
|
||||
(defn graph-query-handler
|
||||
[_cfg {:keys [params ::session/profile-id]}]
|
||||
[_cfg {:keys [params ::session/profile-id] :as request}]
|
||||
(let [query (:query params)]
|
||||
(try
|
||||
(let [result (graph.debug/query-session! profile-id query)]
|
||||
(graph-console-response profile-id
|
||||
(graph.debug/console-context profile-id
|
||||
:query query
|
||||
:query-result result)))
|
||||
(if (json-request? request)
|
||||
{::yres/status 200
|
||||
::yres/headers {"content-type" "application/json; charset=utf-8"}
|
||||
::yres/body (t/encode-str {:query query
|
||||
:query-result result}
|
||||
{:type :json-verbose})}
|
||||
(graph-console-response profile-id
|
||||
(graph.debug/console-context profile-id
|
||||
:query query
|
||||
:query-result result))))
|
||||
(catch Throwable e
|
||||
(graph-console-response profile-id
|
||||
(graph.debug/console-context profile-id
|
||||
:query query
|
||||
:error (or (:hint (ex-data e))
|
||||
(ex-message e))))))))
|
||||
(let [error (or (:hint (ex-data e)) (ex-message e))]
|
||||
(if (json-request? request)
|
||||
{::yres/status 200
|
||||
::yres/headers {"content-type" "application/json; charset=utf-8"}
|
||||
::yres/body (t/encode-str {:query query :error error}
|
||||
{:type :json-verbose})}
|
||||
(graph-console-response profile-id
|
||||
(graph.debug/console-context profile-id
|
||||
:query query
|
||||
:error error))))))))
|
||||
|
||||
(defn import-handler
|
||||
[{:keys [::db/pool] :as cfg} {:keys [params ::session/profile-id] :as request}]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user