Switch to select multiple for editing permissions
Closed this issue · 7 comments
Claude artifact showing what it could look like if I use this rather than the table of checkboxes:
https://claude.site/artifacts/3b83782b-74d3-4759-ac68-523fe2a905eb
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Group Permissions UI</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/choices.js/10.2.0/choices.min.css">
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
background-color: #f0f0f0;
}
.container {
background-color: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
h1 {
color: #333;
}
.group-row {
display: flex;
align-items: center;
margin-bottom: 10px;
padding: 10px;
background-color: #f9f9f9;
border-radius: 4px;
}
.group-name {
width: 150px;
font-weight: bold;
color: #4a4a4a;
}
select[multiple] {
min-width: 200px;
}
/* Choices.js custom styles */
.choices__inner {
min-height: 30px;
padding: 4px 7.5px 4px 3.75px;
}
.choices__list--multiple .choices__item {
font-size: 12px;
padding: 2px 5px;
margin-bottom: 0;
}
</style>
</head>
<body>
<div class="container">
<h1>Group Permissions</h1>
<div id="groups-container">
<div class="group-row">
<span class="group-name">staff (1)</span>
<select multiple id="select-staff">
<option value="insert-row">insert-row</option>
<option value="delete-row">delete-row</option>
<option value="update-row">update-row</option>
<option value="alter-table" selected>alter-table</option>
<option value="drop-table">drop-table</option>
</select>
</div>
<div class="group-row">
<span class="group-name">devs (5)</span>
<select multiple id="select-devs">
<option value="insert-row" selected>insert-row</option>
<option value="delete-row" selected>delete-row</option>
<option value="update-row" selected>update-row</option>
<option value="alter-table" selected>alter-table</option>
<option value="drop-table">drop-table</option>
</select>
</div>
<div class="group-row">
<span class="group-name">newgroup (0)</span>
<select multiple id="select-newgroup">
<option value="insert-row">insert-row</option>
<option value="delete-row">delete-row</option>
<option value="update-row">update-row</option>
<option value="alter-table" selected>alter-table</option>
<option value="drop-table">drop-table</option>
</select>
</div>
<div class="group-row">
<span class="group-name">muppets (5)</span>
<select multiple id="select-muppets">
<option value="insert-row">insert-row</option>
<option value="delete-row">delete-row</option>
<option value="update-row">update-row</option>
<option value="alter-table">alter-table</option>
<option value="drop-table">drop-table</option>
</select>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/choices.js/10.2.0/choices.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
const selects = document.querySelectorAll('select[multiple]');
selects.forEach(select => {
new Choices(select, {
removeItemButton: true,
classNames: {
containerOuter: 'choices custom-choices',
}
});
});
});
</script>
</body>
</html>
Conversation transcript: https://gist.github.com/simonw/7b87b24cd53daf8ea05170c3c8013e3c
I started with this screenshot:
Originally posted by @simonw in #23 (comment)
I think this UI will work better on narrow screens and will expand to handle more permissions.
I think I need to introduce an opt-in mechanism to Datasette core classes, maybe a class of core
- which can be used directly on the button or can be put on a wrapper element, such as a form.
I'm tempted to get Playwright tests working here, as seen in https://github.com/simonw/datasette-search-all/blob/main/tests/test_playwright.py
Another problem: https://github.com/simonw/datasette/blob/832f76ce26ffb2f3e27a006ff90254374bd90e61/datasette/utils/asgi.py#L138-L140
async def post_vars(self):
body = await self.post_body()
return dict(parse_qsl(body.decode("utf-8"), keep_blank_values=True))
That means that a ` will only return the first selected item at the moment. need to work around that (and then fix it in Datasette core).
For the moment I'll work around that problem like so:
from datasette.utils import MultiParams
body = await self.post_body()
post_vars = MultiParams(parse_qs(qs=body, keep_blank_values=True))