mirror of
				https://github.com/ae-utbm/sith.git
				synced 2025-10-31 17:13:08 +00:00 
			
		
		
		
	Add AutoCompleteSelectGroup
This commit is contained in:
		| @@ -9,7 +9,12 @@ import type { | ||||
|   TomSettings, | ||||
| } from "tom-select/dist/types/types"; | ||||
| import type { escape_html } from "tom-select/dist/types/utils"; | ||||
| import { type UserProfileSchema, userSearchUsers } from "#openapi"; | ||||
| import { | ||||
|   type GroupSchema, | ||||
|   type UserProfileSchema, | ||||
|   groupSearchGroup, | ||||
|   userSearchUsers, | ||||
| } from "#openapi"; | ||||
|  | ||||
| @registerComponent("autocomplete-select") | ||||
| class AutocompleteSelect extends inheritHtmlElement("select") { | ||||
| @@ -56,14 +61,9 @@ class AutocompleteSelect extends inheritHtmlElement("select") { | ||||
|  | ||||
|   connectedCallback() { | ||||
|     super.connectedCallback(); | ||||
|     // Collect all options nodes and put them into the select node | ||||
|     const options: Element[] = []; // We need to make a copy to delete while iterating | ||||
|     for (const child of this.children) { | ||||
|       if (child.tagName.toLowerCase() === "option") { | ||||
|         options.push(child); | ||||
|       } | ||||
|     } | ||||
|     for (const option of options) { | ||||
|     for (const option of Array.from(this.children).filter( | ||||
|       (child) => child.tagName.toLowerCase() === "option", | ||||
|     )) { | ||||
|       this.removeChild(option); | ||||
|       this.node.appendChild(option); | ||||
|     } | ||||
| @@ -158,6 +158,18 @@ abstract class AjaxSelect extends AutocompleteSelect { | ||||
|       }, | ||||
|     }; | ||||
|   } | ||||
|  | ||||
|   protected attachBehaviors() { | ||||
|     super.attachBehaviors(); | ||||
|  | ||||
|     // Gather selected options, they must be added with slots like `<slot>json</slot>` | ||||
|     for (const value of Array.from(this.children) | ||||
|       .filter((child) => child.tagName.toLowerCase() === "slot") | ||||
|       .map((slot) => JSON.parse(slot.innerHTML))) { | ||||
|       this.widget.addOption(value, true); | ||||
|       this.widget.addItem(value[this.valueField]); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| @registerComponent("user-ajax-select") | ||||
| @@ -172,9 +184,6 @@ export class UserAjaxSelect extends AjaxSelect { | ||||
|     } | ||||
|     return []; | ||||
|   } | ||||
|   protected tomSelectSettings(): RecursivePartial<TomSettings> { | ||||
|     return super.tomSelectSettings(); | ||||
|   } | ||||
|  | ||||
|   protected renderOption(item: UserProfileSchema, sanitize: typeof escape_html) { | ||||
|     return `<div class="select-item"> | ||||
| @@ -191,3 +200,27 @@ export class UserAjaxSelect extends AjaxSelect { | ||||
|     return `<span><i class="fa fa-times"></i>${sanitize(item.display_name)}</span>`; | ||||
|   } | ||||
| } | ||||
|  | ||||
| @registerComponent("group-ajax-select") | ||||
| export class GroupsAjaxSelect extends AjaxSelect { | ||||
|   protected valueField = "id"; | ||||
|   protected labelField = "name"; | ||||
|  | ||||
|   protected async search(query: string): Promise<TomOption[]> { | ||||
|     const resp = await groupSearchGroup({ query: { search: query } }); | ||||
|     if (resp.data) { | ||||
|       return resp.data.results; | ||||
|     } | ||||
|     return []; | ||||
|   } | ||||
|  | ||||
|   protected renderOption(item: GroupSchema, sanitize: typeof escape_html) { | ||||
|     return `<div class="select-item"> | ||||
|             <span class="select-item-text">${sanitize(item.name)}</span> | ||||
|           </div>`; | ||||
|   } | ||||
|  | ||||
|   protected renderItem(item: GroupSchema, sanitize: typeof escape_html) { | ||||
|     return `<span><i class="fa fa-times"></i>${sanitize(item.name)}</span>`; | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -7,4 +7,5 @@ | ||||
|   <optgroup label="{{ group_name }}">{% endif %}{% for widget in group_choices %} | ||||
|     {% include widget.template_name %}{% endfor %}{% if group_name %} | ||||
|       </optgroup>{% endif %}{% endfor %} | ||||
| {% for sel in selected %}<slot style="display: none">{{ sel }}</slot>{% endfor %} | ||||
| </{{ component }}> | ||||
| @@ -1,11 +1,27 @@ | ||||
| from django.contrib.staticfiles.storage import staticfiles_storage | ||||
| from django.db.models import Model | ||||
| from django.forms import Select, SelectMultiple | ||||
| from ninja import ModelSchema | ||||
|  | ||||
| from core.models import Group, User | ||||
| from core.schemas import GroupSchema, UserProfileSchema | ||||
|  | ||||
|  | ||||
| class AutoCompleteSelectMixin: | ||||
|     component_name = "autocomplete-select" | ||||
|     template_name = "core/widgets/autocomplete_select.jinja" | ||||
|     is_ajax = False | ||||
|     model: Model | None = None | ||||
|     schema: ModelSchema | None = None | ||||
|     pk = "id" | ||||
|  | ||||
|     def __init__(self, attrs=None, choices=()): | ||||
|         if self.is_ajax: | ||||
|             choices = ()  # Avoid computing anything when in ajax mode | ||||
|         super().__init__(attrs=attrs, choices=choices) | ||||
|  | ||||
|     @property | ||||
|     def is_ajax(self): | ||||
|         return self.model and self.schema | ||||
|  | ||||
|     def optgroups(self, name, value, attrs=None): | ||||
|         """Don't create option groups when doing ajax""" | ||||
| @@ -27,6 +43,13 @@ class AutoCompleteSelectMixin: | ||||
|                 staticfiles_storage.url("core/components/ajax-select.scss"), | ||||
|             ], | ||||
|         } | ||||
|         if self.is_ajax: | ||||
|             context["selected"] = [ | ||||
|                 self.schema.from_orm(obj).json() | ||||
|                 for obj in self.model.objects.filter( | ||||
|                     **{f"{self.pk}__in": context["widget"]["value"]} | ||||
|                 ).all() | ||||
|             ] | ||||
|         return context | ||||
|  | ||||
|  | ||||
| @@ -38,9 +61,23 @@ class AutoCompleteSelectMultiple(AutoCompleteSelectMixin, SelectMultiple): ... | ||||
|  | ||||
| class AutoCompleteSelectUser(AutoCompleteSelectMixin, Select): | ||||
|     component_name = "user-ajax-select" | ||||
|     is_ajax = True | ||||
|     model = User | ||||
|     schema = UserProfileSchema | ||||
|  | ||||
|  | ||||
| class AutoCompleteSelectMultipleUser(AutoCompleteSelectMixin, SelectMultiple): | ||||
|     component_name = "user-ajax-select" | ||||
|     is_ajax = True | ||||
|     model = User | ||||
|     schema = UserProfileSchema | ||||
|  | ||||
|  | ||||
| class AutoCompleteSelectGroup(AutoCompleteSelectMixin, Select): | ||||
|     component_name = "group-ajax-select" | ||||
|     model = Group | ||||
|     schema = GroupSchema | ||||
|  | ||||
|  | ||||
| class AutoCompleteSelectMultipleGroup(AutoCompleteSelectMixin, SelectMultiple): | ||||
|     component_name = "group-ajax-select" | ||||
|     model = Group | ||||
|     schema = GroupSchema | ||||
|   | ||||
| @@ -15,7 +15,7 @@ from core.views.forms import SelectDateTime | ||||
| from core.views.widgets.markdown import MarkdownInput | ||||
| from core.views.widgets.select import ( | ||||
|     AutoCompleteSelect, | ||||
|     AutoCompleteSelectMultiple, | ||||
|     AutoCompleteSelectMultipleGroup, | ||||
|     AutoCompleteSelectUser, | ||||
| ) | ||||
| from election.models import Candidature, Election, ElectionList, Role, Vote | ||||
| @@ -157,10 +157,10 @@ class ElectionForm(forms.ModelForm): | ||||
|             "candidature_groups", | ||||
|         ] | ||||
|         widgets = { | ||||
|             "edit_groups": AutoCompleteSelectMultiple, | ||||
|             "view_groups": AutoCompleteSelectMultiple, | ||||
|             "vote_groups": AutoCompleteSelectMultiple, | ||||
|             "candidature_groups": AutoCompleteSelectMultiple, | ||||
|             "edit_groups": AutoCompleteSelectMultipleGroup, | ||||
|             "view_groups": AutoCompleteSelectMultipleGroup, | ||||
|             "vote_groups": AutoCompleteSelectMultipleGroup, | ||||
|             "candidature_groups": AutoCompleteSelectMultipleGroup, | ||||
|         } | ||||
|  | ||||
|     start_date = forms.DateTimeField( | ||||
|   | ||||
		Reference in New Issue
	
	Block a user