mirror of
https://github.com/simonw/datasette.git
synced 2025-12-10 16:51:24 +01:00
Fix minor irritation with /-/allowed UI
This commit is contained in:
parent
7d9d7acb0b
commit
ee62bf9bdc
3 changed files with 32 additions and 28 deletions
|
|
@ -42,7 +42,7 @@
|
||||||
<div class="form-section">
|
<div class="form-section">
|
||||||
<label for="child">Filter by child (optional):</label>
|
<label for="child">Filter by child (optional):</label>
|
||||||
<input type="text" id="child" name="child" placeholder="e.g., table name">
|
<input type="text" id="child" name="child" placeholder="e.g., table name">
|
||||||
<small>Filter results to a specific child resource (requires parent)</small>
|
<small>Filter results to a specific child resource (requires parent to be set)</small>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-section">
|
<div class="form-section">
|
||||||
|
|
@ -236,12 +236,15 @@ function displayError(data) {
|
||||||
const parentInput = document.getElementById('parent');
|
const parentInput = document.getElementById('parent');
|
||||||
const childInput = document.getElementById('child');
|
const childInput = document.getElementById('child');
|
||||||
|
|
||||||
childInput.addEventListener('focus', () => {
|
parentInput.addEventListener('input', () => {
|
||||||
|
childInput.disabled = !parentInput.value;
|
||||||
if (!parentInput.value) {
|
if (!parentInput.value) {
|
||||||
alert('Please specify a parent resource first before filtering by child resource.');
|
childInput.value = '';
|
||||||
parentInput.focus();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Initialize disabled state
|
||||||
|
childInput.disabled = !parentInput.value;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
||||||
|
|
@ -189,22 +189,6 @@ class AllowedResourcesView(BaseView):
|
||||||
name = "allowed"
|
name = "allowed"
|
||||||
has_json_alternate = False
|
has_json_alternate = False
|
||||||
|
|
||||||
CANDIDATE_SQL = {
|
|
||||||
"view-table": (
|
|
||||||
"SELECT database_name AS parent, table_name AS child FROM catalog_tables",
|
|
||||||
{},
|
|
||||||
),
|
|
||||||
"view-database": (
|
|
||||||
"SELECT database_name AS parent, NULL AS child FROM catalog_databases",
|
|
||||||
{},
|
|
||||||
),
|
|
||||||
"view-instance": ("SELECT NULL AS parent, NULL AS child", {}),
|
|
||||||
"execute-sql": (
|
|
||||||
"SELECT database_name AS parent, NULL AS child FROM catalog_databases",
|
|
||||||
{},
|
|
||||||
),
|
|
||||||
}
|
|
||||||
|
|
||||||
async def get(self, request):
|
async def get(self, request):
|
||||||
await self.ds.refresh_schemas()
|
await self.ds.refresh_schemas()
|
||||||
|
|
||||||
|
|
@ -218,11 +202,29 @@ class AllowedResourcesView(BaseView):
|
||||||
|
|
||||||
if not as_format:
|
if not as_format:
|
||||||
# Render the HTML form (even if query parameters are present)
|
# Render the HTML form (even if query parameters are present)
|
||||||
|
# Put most common/interesting actions first
|
||||||
|
priority_actions = [
|
||||||
|
"view-instance",
|
||||||
|
"view-database",
|
||||||
|
"view-table",
|
||||||
|
"view-query",
|
||||||
|
"execute-sql",
|
||||||
|
"insert-row",
|
||||||
|
"update-row",
|
||||||
|
"delete-row",
|
||||||
|
]
|
||||||
|
actions = list(self.ds.actions.keys())
|
||||||
|
# Priority actions first (in order), then remaining alphabetically
|
||||||
|
sorted_actions = [a for a in priority_actions if a in actions]
|
||||||
|
sorted_actions.extend(
|
||||||
|
sorted(a for a in actions if a not in priority_actions)
|
||||||
|
)
|
||||||
|
|
||||||
return await self.render(
|
return await self.render(
|
||||||
["debug_allowed.html"],
|
["debug_allowed.html"],
|
||||||
request,
|
request,
|
||||||
{
|
{
|
||||||
"supported_actions": sorted(self.CANDIDATE_SQL.keys()),
|
"supported_actions": sorted_actions,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -232,11 +234,6 @@ class AllowedResourcesView(BaseView):
|
||||||
return Response.json({"error": "action parameter is required"}, status=400)
|
return Response.json({"error": "action parameter is required"}, status=400)
|
||||||
if action not in self.ds.actions:
|
if action not in self.ds.actions:
|
||||||
return Response.json({"error": f"Unknown action: {action}"}, status=404)
|
return Response.json({"error": f"Unknown action: {action}"}, status=404)
|
||||||
if action not in self.CANDIDATE_SQL:
|
|
||||||
return Response.json(
|
|
||||||
{"error": f"Action '{action}' is not supported by this endpoint"},
|
|
||||||
status=400,
|
|
||||||
)
|
|
||||||
|
|
||||||
actor = request.actor if isinstance(request.actor, dict) else None
|
actor = request.actor if isinstance(request.actor, dict) else None
|
||||||
actor_id = actor.get("id") if actor else None
|
actor_id = actor.get("id") if actor else None
|
||||||
|
|
|
||||||
|
|
@ -69,8 +69,12 @@ async def ds_with_permissions():
|
||||||
("/-/allowed.json", 400, {"error"}),
|
("/-/allowed.json", 400, {"error"}),
|
||||||
# Invalid action
|
# Invalid action
|
||||||
("/-/allowed.json?action=nonexistent", 404, {"error"}),
|
("/-/allowed.json?action=nonexistent", 404, {"error"}),
|
||||||
# Unsupported action (valid but not in CANDIDATE_SQL)
|
# Any valid action works, even if no permission rules exist for it
|
||||||
("/-/allowed.json?action=insert-row", 400, {"error"}),
|
(
|
||||||
|
"/-/allowed.json?action=insert-row",
|
||||||
|
200,
|
||||||
|
{"action", "items", "total", "page"},
|
||||||
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_allowed_json_basic(
|
async def test_allowed_json_basic(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue