mirror of
https://github.com/penpot/penpot.git
synced 2026-08-24 13:48:51 +00:00
🐛 Fix batch delete sync and keep graph console feed alive
This commit is contained in:
parent
85fc8ae664
commit
4d7bb51984
@ -90,7 +90,7 @@ Graph Console
|
|||||||
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>Cypher query</legend>
|
<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">
|
<div class="row">
|
||||||
<textarea name="query" rows="8" style="width:100%; font-family: monospace;">{{query}}</textarea>
|
<textarea name="query" rows="8" style="width:100%; font-family: monospace;">{{query}}</textarea>
|
||||||
</div>
|
</div>
|
||||||
@ -99,37 +99,39 @@ Graph Console
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if error %}
|
<div id="graph-query-output">
|
||||||
<fieldset>
|
{% if error %}
|
||||||
<legend>Error</legend>
|
<fieldset>
|
||||||
<pre>{{error}}</pre>
|
<legend>Error</legend>
|
||||||
</fieldset>
|
<pre>{{error}}</pre>
|
||||||
{% endif %}
|
</fieldset>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if query-result %}
|
{% if query-result %}
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>Results ({{query-result.row-count}} rows{% if query-result.truncated? %}, truncated{% endif %})</legend>
|
<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%;">
|
<table border="1" cellpadding="4" cellspacing="0" style="border-collapse: collapse; width: 100%;">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
{% for column in query-result.columns %}
|
{% for column in query-result.columns %}
|
||||||
<th>{{column}}</th>
|
<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 %}
|
{% endfor %}
|
||||||
</tr>
|
</tbody>
|
||||||
</thead>
|
</table>
|
||||||
<tbody>
|
</fieldset>
|
||||||
{% for row in query-result.rows %}
|
{% endif %}
|
||||||
<tr>
|
</div>
|
||||||
{% for cell in row %}
|
|
||||||
<td><code>{{cell}}</code></td>
|
|
||||||
{% endfor %}
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</fieldset>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</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();
|
connect();
|
||||||
refreshSyncStatus();
|
refreshSyncStatus();
|
||||||
|
|
||||||
|
|||||||
@ -408,7 +408,9 @@
|
|||||||
{:index (reduce index-remove-shape! index to-delete)
|
{:index (reduce index-remove-shape! index to-delete)
|
||||||
:statements statements
|
:statements statements
|
||||||
:applied? true})
|
: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
|
(defn- apply-add-page
|
||||||
[index {:keys [id name page]}]
|
[index {:keys [id name page]}]
|
||||||
|
|||||||
@ -407,21 +407,38 @@
|
|||||||
::yres/headers {"content-type" "application/json; charset=utf-8"}
|
::yres/headers {"content-type" "application/json; charset=utf-8"}
|
||||||
::yres/body (t/encode-str {:error "no-session"} {:type :json-verbose})}))
|
::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
|
(defn graph-query-handler
|
||||||
[_cfg {:keys [params ::session/profile-id]}]
|
[_cfg {:keys [params ::session/profile-id] :as request}]
|
||||||
(let [query (:query params)]
|
(let [query (:query params)]
|
||||||
(try
|
(try
|
||||||
(let [result (graph.debug/query-session! profile-id query)]
|
(let [result (graph.debug/query-session! profile-id query)]
|
||||||
(graph-console-response profile-id
|
(if (json-request? request)
|
||||||
(graph.debug/console-context profile-id
|
{::yres/status 200
|
||||||
:query query
|
::yres/headers {"content-type" "application/json; charset=utf-8"}
|
||||||
:query-result result)))
|
::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
|
(catch Throwable e
|
||||||
(graph-console-response profile-id
|
(let [error (or (:hint (ex-data e)) (ex-message e))]
|
||||||
(graph.debug/console-context profile-id
|
(if (json-request? request)
|
||||||
:query query
|
{::yres/status 200
|
||||||
:error (or (:hint (ex-data e))
|
::yres/headers {"content-type" "application/json; charset=utf-8"}
|
||||||
(ex-message e))))))))
|
::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
|
(defn import-handler
|
||||||
[{:keys [::db/pool] :as cfg} {:keys [params ::session/profile-id] :as request}]
|
[{:keys [::db/pool] :as cfg} {:keys [params ::session/profile-id] :as request}]
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user