mirror of
https://github.com/simonw/datasette.git
synced 2026-05-27 12:34:37 +02:00
Link to save query from /-/execute-write
This commit is contained in:
parent
c3ceabae03
commit
d6de8e7520
3 changed files with 67 additions and 1 deletions
|
|
@ -119,7 +119,10 @@
|
|||
{% endif %}
|
||||
</div>
|
||||
|
||||
<p><input type="submit" value="Execute" data-execute-write-submit{% if execute_disabled %} disabled{% endif %}></p>
|
||||
<p>
|
||||
<input type="submit" value="Execute" data-execute-write-submit{% if execute_disabled %} disabled{% endif %}>
|
||||
{% if save_query_base_url %}<a href="{{ save_query_url or save_query_base_url }}" class="save-query" data-save-query-link data-save-query-base-url="{{ save_query_base_url }}"{% if not save_query_url %} hidden{% endif %}>Save this query</a>{% endif %}
|
||||
</p>
|
||||
</form>
|
||||
|
||||
<script>
|
||||
|
|
@ -140,6 +143,26 @@ window.addEventListener("DOMContentLoaded", () => {
|
|||
const submitButton = form
|
||||
? form.querySelector("[data-execute-write-submit]")
|
||||
: null;
|
||||
const saveQueryLink = form
|
||||
? form.querySelector("[data-save-query-link]")
|
||||
: null;
|
||||
|
||||
function updateSaveQueryLink(data) {
|
||||
if (!saveQueryLink) {
|
||||
return;
|
||||
}
|
||||
const sql = window.editor
|
||||
? window.editor.state.doc.toString()
|
||||
: executeWriteSqlInput.value;
|
||||
if (!sql.trim() || !data.ok || data.execute_disabled) {
|
||||
saveQueryLink.hidden = true;
|
||||
return;
|
||||
}
|
||||
const url = new URL(saveQueryLink.dataset.saveQueryBaseUrl, window.location.href);
|
||||
url.searchParams.set("sql", sql);
|
||||
saveQueryLink.href = url.pathname + url.search + url.hash;
|
||||
saveQueryLink.hidden = false;
|
||||
}
|
||||
|
||||
window.datasetteSqlParameters.setupSqlParameterRefresh({
|
||||
form,
|
||||
|
|
@ -150,6 +173,7 @@ window.addEventListener("DOMContentLoaded", () => {
|
|||
if (submitButton) {
|
||||
submitButton.disabled = data.execute_disabled;
|
||||
}
|
||||
updateSaveQueryLink(data);
|
||||
},
|
||||
onError(error) {
|
||||
window.datasetteSqlAnalysis.renderAnalysis(analysisSection, {
|
||||
|
|
@ -159,6 +183,9 @@ window.addEventListener("DOMContentLoaded", () => {
|
|||
if (submitButton) {
|
||||
submitButton.disabled = true;
|
||||
}
|
||||
if (saveQueryLink) {
|
||||
saveQueryLink.hidden = true;
|
||||
}
|
||||
},
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1002,6 +1002,26 @@ class ExecuteWriteView(BaseView):
|
|||
except (QueryValidationError, sqlite3.DatabaseError) as ex:
|
||||
analysis_error = getattr(ex, "message", str(ex))
|
||||
|
||||
allow_save_query = await self.ds.allowed(
|
||||
action="execute-sql",
|
||||
resource=DatabaseResource(db.name),
|
||||
actor=request.actor,
|
||||
) and await self.ds.allowed(
|
||||
action="store-query",
|
||||
resource=DatabaseResource(db.name),
|
||||
actor=request.actor,
|
||||
)
|
||||
save_query_base_url = None
|
||||
save_query_url = None
|
||||
if allow_save_query:
|
||||
save_query_base_url = self.ds.urls.database(db.name) + "/-/queries/store"
|
||||
if (
|
||||
sql
|
||||
and analysis_error is None
|
||||
and not any(row["allowed"] is False for row in analysis_rows)
|
||||
):
|
||||
save_query_url = save_query_base_url + "?" + urlencode({"sql": sql})
|
||||
|
||||
response = await self.render(
|
||||
["execute_write.html"],
|
||||
request,
|
||||
|
|
@ -1025,6 +1045,8 @@ class ExecuteWriteView(BaseView):
|
|||
),
|
||||
"table_columns": table_columns,
|
||||
"write_template_tables": write_template_tables,
|
||||
"save_query_url": save_query_url,
|
||||
"save_query_base_url": save_query_base_url,
|
||||
},
|
||||
)
|
||||
response.status = status
|
||||
|
|
|
|||
|
|
@ -1233,6 +1233,12 @@ async def test_execute_write_get_prepopulates_without_executing():
|
|||
assert 'data-sql-template="update"' in response.text
|
||||
assert 'data-sql-template="delete"' in response.text
|
||||
assert 'data-analyze-url="/data/-/execute-write/analyze"' in response.text
|
||||
assert 'data-save-query-base-url="/data/-/queries/store"' in response.text
|
||||
assert "Save this query" in response.text
|
||||
assert (
|
||||
"/data/-/queries/store?sql=insert+into+dogs+%28name%29+values+%28%27Cleo%27%29"
|
||||
in response.text
|
||||
)
|
||||
assert 'addEventListener("paste"' in response.text
|
||||
assert "setupSqlParameterRefresh" in response.text
|
||||
assert "datasetteSqlAnalysis.renderAnalysis" in response.text
|
||||
|
|
@ -1251,6 +1257,17 @@ async def test_execute_write_get_prepopulates_without_executing():
|
|||
)
|
||||
assert '<textarea id="sql-editor" name="sql"></textarea>' in empty_response.text
|
||||
assert 'executeWriteSqlInput.value = "\\n\\n\\n";' in empty_response.text
|
||||
assert "hidden>Save this query</a>" in empty_response.text
|
||||
|
||||
read_only_response = await ds.client.get(
|
||||
"/data/-/execute-write?sql=select+*+from+dogs",
|
||||
actor={"id": "root"},
|
||||
)
|
||||
assert (
|
||||
"Use /-/query for read-only SQL; this endpoint only executes writes"
|
||||
in read_only_response.text
|
||||
)
|
||||
assert "hidden>Save this query</a>" in read_only_response.text
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue