forked from enviPath/enviPy
[Feature] Search for Permissions, Prep Compound / Structure to be extended, Prep Template overwrites (#347)
Co-authored-by: Tim Lorsbach <tim@lorsba.ch> Reviewed-on: enviPath/enviPy#347
This commit is contained in:
@ -71,24 +71,129 @@
|
||||
<label class="label">
|
||||
<span class="label-text">User or Group</span>
|
||||
</label>
|
||||
<select
|
||||
id="select_grantee"
|
||||
name="grantee"
|
||||
class="select select-bordered w-full select-sm"
|
||||
required
|
||||
<div
|
||||
class="relative"
|
||||
x-data="{
|
||||
searchQuery: '',
|
||||
selectedItem: null,
|
||||
showResults: false,
|
||||
filteredResults: [],
|
||||
allItems: [
|
||||
{% for u in users %}
|
||||
{ type: 'user', name: '{{ u.username }}', url: '{{ u.url }}',
|
||||
display: '{{ u.username }}' },
|
||||
{% endfor %}
|
||||
{% for g in groups %}
|
||||
{ type: 'group', name: '{{ g.name|safe }}', url: '{{ g.url }}',
|
||||
display: '{{ g.name|safe }}' },
|
||||
{% endfor %}
|
||||
],
|
||||
init() {
|
||||
this.filteredResults = this.allItems;
|
||||
},
|
||||
search() {
|
||||
if (this.searchQuery.length === 0) {
|
||||
this.filteredResults = this.allItems;
|
||||
} else {
|
||||
this.filteredResults = this.allItems.filter(item =>
|
||||
item.name.toLowerCase().includes(this.searchQuery.toLowerCase())
|
||||
);
|
||||
}
|
||||
this.showResults = true;
|
||||
},
|
||||
selectItem(item) {
|
||||
this.selectedItem = item;
|
||||
this.searchQuery = item.display;
|
||||
this.showResults = false;
|
||||
},
|
||||
clearSelection() {
|
||||
this.selectedItem = null;
|
||||
this.searchQuery = '';
|
||||
this.showResults = false;
|
||||
}
|
||||
}"
|
||||
@click.away="showResults = false"
|
||||
>
|
||||
<optgroup label="Users">
|
||||
{% for u in users %}
|
||||
<option value="{{ u.url }}">{{ u.username }}</option>
|
||||
{% endfor %}
|
||||
</optgroup>
|
||||
<optgroup label="Groups">
|
||||
{% for g in groups %}
|
||||
<option value="{{ g.url }}">{{ g.name|safe }}</option>
|
||||
{% endfor %}
|
||||
</optgroup>
|
||||
</select>
|
||||
<input
|
||||
type="text"
|
||||
x-model="searchQuery"
|
||||
@input="search()"
|
||||
@focus="showResults = true; search()"
|
||||
@keydown.escape="showResults = false"
|
||||
@keydown.arrow-down.prevent="$refs.resultsList?.children[0]?.focus()"
|
||||
class="input input-bordered w-full input-sm"
|
||||
placeholder="Search users or groups..."
|
||||
autocomplete="off"
|
||||
required
|
||||
/>
|
||||
|
||||
<!-- Clear button -->
|
||||
<button
|
||||
type="button"
|
||||
x-show="searchQuery.length > 0"
|
||||
@click="clearSelection()"
|
||||
class="absolute right-2 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-gray-600"
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
|
||||
<!-- Hidden input for form submission -->
|
||||
<input
|
||||
type="hidden"
|
||||
name="grantee"
|
||||
x-bind:value="selectedItem?.url || ''"
|
||||
required
|
||||
/>
|
||||
|
||||
<!-- Search results dropdown -->
|
||||
<div
|
||||
x-show="showResults && filteredResults.length > 0"
|
||||
x-transition
|
||||
class="absolute z-50 w-full mt-1 bg-base-100 border border-base-300 rounded-lg shadow-lg max-h-60 overflow-y-auto"
|
||||
>
|
||||
<ul x-ref="resultsList" id="resultsList" class="py-1">
|
||||
<template
|
||||
x-for="(item, index) in filteredResults"
|
||||
:key="item.url"
|
||||
>
|
||||
<li>
|
||||
<button
|
||||
type="button"
|
||||
@click="selectItem(item)"
|
||||
@keydown.enter="selectItem(item)"
|
||||
@keydown.escape="showResults = false"
|
||||
@keydown.arrow-up.prevent="index > 0 ? $event.target.parentElement.previousElementSibling?.children[0]?.focus() : null"
|
||||
@keydown.arrow-down.prevent="index < filteredResults.length - 1 ? $event.target.parentElement.nextElementSibling?.children[0]?.focus() : null"
|
||||
class="w-full px-4 py-2 text-left hover:bg-base-200 focus:bg-base-200 focus:outline-none flex items-center space-x-2"
|
||||
>
|
||||
<span
|
||||
x-text="item.type === 'user' ? '👤' : '👥'"
|
||||
class="text-sm opacity-60"
|
||||
></span>
|
||||
<span x-text="item.display"></span>
|
||||
<span
|
||||
x-text="item.type === 'user' ? '(User)' : '(Group)'"
|
||||
class="text-xs opacity-50 ml-auto"
|
||||
></span>
|
||||
</button>
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- No results message -->
|
||||
<div
|
||||
x-show="showResults && filteredResults.length === 0 && searchQuery.length > 0"
|
||||
x-transition
|
||||
class="absolute z-50 w-full mt-1 bg-base-100 border border-base-300 rounded-lg shadow-lg"
|
||||
>
|
||||
<div class="px-4 py-2 text-gray-500 text-sm">
|
||||
No users or groups found
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-span-2 text-center">
|
||||
<label class="label justify-center">
|
||||
<span class="label-text">Read</span>
|
||||
|
||||
Reference in New Issue
Block a user