Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MultiselectFilter używający select z parametrem multiple #1325

Merged
merged 42 commits into from
Mar 20, 2024

Conversation

michauciak
Copy link
Contributor

@michauciak michauciak commented Jul 15, 2022

Dodany zostaje filtr MultiselectFilter, który używa znacznika HTML select z parametrem multiple. Użyty jest dla rodzaju przedmiotu i opiekuna przedmiotu. Zapewne wypadałoby też go użyć w ofercie przedmiotów w analogicznych miejscach.

Na komputerze wybieranie wielu pozycji z listy przebiega z użyciem klawisza Ctrl. Wybranie pierwszej wartości na liście, czyli w zasadzie tytułu listy, powoduje wyzerowanie wszelkich zaznaczeń na liście. Wybranie dowolnej pozycji na liście bez klawisza Ctrl powoduje zwyczajny, pojedynczy wybór.

image

Closes #746.

@michauciak michauciak requested a review from lgpawel July 15, 2022 07:01
@lgpawel
Copy link
Contributor

lgpawel commented Jul 16, 2022

Chyba całkiem sprawnie to działa, ale za to trochę topornie wygląda i warto trochę przeorganizować ten panel z filtrami. Mój wstępny pomysł (przy którym oczywiście się nie upieram i chętnie zobaczę lepsze propozycje) byłby taki:

  1. Zrobić układ w dwóch wierszach (zamiast w trzech kolumnach, jak obecnie).
  2. Pierwszy wiersz zawierałby od prawej dwa multiselektory tak jak teraz, każdy na szerokości nieco mniejszej niż obecna ⅓ (treści, które się w nich pojawiają, nie są przesadnie długie), a na reszcie, pod sobą nazwa przedmiotu i ptaszek zalecanych tylko dla pierwszaków (jak będzie więcej miejsca, to napis nie będzie się zawijał – przynajmniej u mnie 😏). Trochę jeszcze nie wiem, co zrobić z przyciskiem czyszczenia filtrów (który, w razie potrzeby, mógłby być wielolinijkowy i zawierać słowo "wszystkie").
  3. W drugim wierszu chmury tagów, z miejscem podzielonym oczywiście po równo.

Co do szczegółów działania i wyglądu multiselektorów: wydaje mi się, że pierwsza pozycja o treści "-- [nazwa własności] --" słabo się broni. Dałbym nagłówek (tak, jak przy chmurach tagów), a pierwszą pozycję nazwał odpowiednio "[Wszystkie]" bądź "[Wszyscy]", można by ją też ostylować na jakąś szarą kursywę czy coś. I to, że ona może być zaznaczona, zwłaszcza razem z innymi, jest dość nielogiczne – efekt kliknięcia na nią jest sensowny taki, jaki jest, ale moim zdaniem powinna być niezaznaczalna.

BTW przeszła mi przez głowę trochę niedobra na tym etapie myśl: a czym to się różni od chmury tagów? (Oprócz tego, że czyszczenie pojedynczego filtra jest wygodniejsze…) Oczywiście opiekunów jest za dużo, żeby ich prezentować w postaci chmury, ale rodzaje przedmiotów? Sam nie mam zdania, bardzo rzadko tych filtrów używam.

@michauciak
Copy link
Contributor Author

Wydaje się, że zasadniczo powyższe uwagi zdołałem uwzględnić:
image

@michauciak
Copy link
Contributor Author

BTW przeszła mi przez głowę trochę niedobra na tym etapie myśl: a czym to się różni od chmury tagów? (Oprócz tego, że czyszczenie pojedynczego filtra jest wygodniejsze…) Oczywiście opiekunów jest za dużo, żeby ich prezentować w postaci chmury, ale rodzaje przedmiotów? Sam nie mam zdania, bardzo rzadko tych filtrów używam.

Tak, też tę myśl mam. Może wystawię jeszcze jedną wersję – z użyciem chmury tagów do jedynie rodzaju przedmiotów. I chyba na tym bym zakończył wtedy zajmowanie się tym issue, wszak wciąż mam poczucie, że każde z tych podejść nie ulepsza, a raczej utrudnia korzystanie z interfejsu w większości sytuacji.

@lgpawel
Copy link
Contributor

lgpawel commented Jul 16, 2022

Nie podzielam sceptycyzmu. Możliwości, już teraz, są nie gorsze niż wcześniej – pojedynczym kliknięciem, po ew. jakimś przescrollowaniu, możemy wybrać pojedynczą grupę. Zajmuje to trochę więcej miejsca, ale to nieuniknione, poza tym zazwyczaj panel filtrów mamy i tak częściowo zwinięty.

Czymś, co odróżnia tagi i efekty od kategorii i właścicieli, co być może jakoś podświadomie uzasadnia inną prezentację, to to, że te pierwsze są z przedmiotami w związku wiele-do-wielu, a te drugie – określone dla nich jednoznacznie. No i są "ważniejsze" 😉

Natomiast otrzymany efekt wizualnie dalej mnie nie przekonuje (mimo że oczywiście wiernie odwzorowuje to, o czym pisałem wcześniej). Proszę poeksperymentować samemu; ja w którymś momencie jeszcze wrócę ze swoją opinią i ew. innymi sugestiami.

@michauciak
Copy link
Contributor Author

Może tak jest odrobinę mniej chaotycznie:
image

@lgpawel
Copy link
Contributor

lgpawel commented Jul 16, 2022

No jest, ale ma też inne wady. Ale już wiem, jak będzie "najlepiej" (mam nadzieję). Jak sam Pan wyżej zauważył, te multiselecty przydałyby się też gdzie indziej, mianowicie w głosowaniu (gdzie dodatkowo jest jeszcze kontrolka semestru, za to z jakiegoś powodu nie ma przycisku "wyczyść") i ofercie (gdzie dochodzi jeszcze status propozycji). A że te układy powinny być do siebie możliwie podobne, to dla listy przedmiotów czy też prototypu planu i tak musimy zostawić wolne miejsce.

Wrócmy więc do układu trzech kolumn, ale chmury tagów będą w środkowej i prawej. W lewej kolejno: nazwa (jak wcześniej), semestr (dla głosowania i oferty), status (dla oferty), ptaszek dla pierwszaków oraz przycisk czyszczenia. Semestr i status też powinny być oczywiście multiselectami. Myślę, że w ich przypadku można dać pełne trzy wiersze i bez pseudopozycji "wszystkie". Docelowo dla nich można by pomyśleć o czymś oszczędniejszym objętościowo, ale to wizja na inny PR raczej.

@michauciak
Copy link
Contributor Author

A zatem
image
image

@lgpawel
Copy link
Contributor

lgpawel commented Jul 16, 2022

OK, ale musimy wprowadzić jakieś sterowanie wysokością kontrolki – dla rodzaju i opiekuna lepiej dalej nie zmniejszać, dla semestru i statusu – warto. Proszę zrobić jeszcze wariant dla głosowania (czy tego nie da się jakoś wyabstrahować swoją drogą?) i sprawdzić czy nie ma niepotrzebnych importów (a chyba są, bo nagle w ogóle nie mamy zwykłych selectów).

@michauciak
Copy link
Contributor Author

Skrócony select dla semestru i statusu:
image

@michauciak
Copy link
Contributor Author

michauciak commented Jul 16, 2022

w głosowaniu (gdzie dodatkowo jest jeszcze kontrolka semestru, za to z jakiegoś powodu nie ma przycisku "wyczyść")

Proszę zrobić jeszcze wariant dla głosowania (czy tego nie da się jakoś wyabstrahować swoją drogą?)

Nawet zabawne się okazuje, że pomimo iż te pliki CourseFilter.vue wydają się tak do siebie podobne, to dodanie

  methods: {
    ...mapMutations("filters", ["clearFilters"]),
  },

w przypadku głosowania powoduje, że w ogóle się nie wyświetlają filtry. Jest tam za to

  computed: {
    ...mapGetters("filters", {
      tester: "visible",
    }),
  },

których nie ma w dwóch pozostałych plikach CourseFilter.vue. Zatem zapewne najpierw warto by przeanalizować to zachowanie.

@lgpawel
Copy link
Contributor

lgpawel commented Jun 4, 2023

Pierwsze wrażenie działania bardzo dobre! Na szybko mam tylko jedną poprawkę do usability: filtry, które modyfikujemy, są zawsze na górze panelu filtrów, i przez to widoczne również, kiedy ten panel jest zwinięty. Dobrze byłoby, żeby były również używalne w tej sytuacji, ale niestety rozwinięta lista opcji danego "chowa się" pod "zwinięciem" panelu – co ważne, inaczej niż w przypadku obecnych dropdownów pojedynczego wyboru. Warto to dopracować.

Z kolei w kwestii czepialstwa estetycznego można by nieco zwiększyć stopień pisma, jakim wyświetlane są opcje w filtrach (mógłby być taki sam, jak dla placeholderów "Wszystkie rodzaje" / "Wszyscy opiekunowie"), a trójkątne ikonki w przyciskach wydają się umieszczone nieco poniżej środka. Sądzę też, że przycisk z "iksem" do czyszczenia stanu filtra mógłby mieć jakąś ramkę i/lub tło (np. takie same jak ten z trójkątem), żeby było widać, gdzie on właściwie jest, ale tu jestem bardziej skłonny zmienić zdanie.

EDIT: układ panelu filtrów w liście przedmiotów został zmieniony zgodnie z dotychczasową dyskusją, ale ona była toczona w innym kontekście, tj. kiedy filtry nowego rodzaju miały mieć wielolinijkowe kontrolki. Udało się je zrobić z kontrolkami jednolinijkowymi, więc nie ma tego powodu zmieniać układu, do którego użytkownicy są już przyzwyczajeni – przywróćmy stary.

@bkaszowski
Copy link
Contributor

Przywróciłem poprzedni układ i wrzuciłem poprawkę związaną ze zwijaniem panelu z filtrami.

@bkaszowski
Copy link
Contributor

Drobne podsumowanie prac:

PR dodaje komponent MultiSelectFilter, który jak nazwa wskazuje pozwala na wybranie wielu filtrów na raz. Komponent jest wrapperem dla komponentu z biblioteki https://vue-multiselect.js.org/, zatem można korzystać z wszystkich funkcjonalności przez nią dostarczanych.

W ramach prac zostały dość mocno zmodyfikowane style dostarczane przez bibliotekę, zatem w celu ułatwienia modyfikacji komponentu, zostały style dodane bezpośrednio do kodu źródłowego i bezpośrednio zmodyfikowane.

Z racji wymogu, że dropdown komponentu musiał być widoczny poza “zwiniętymi” filtrami na stronie, właściwość position wrappera .multiselect_content-wrapper musiał zostać zmieniony z absolute na fixed, w związku z czym dropdown komponentu nie przyjmował szerokości rodzica tylko całego okienka i był zbyt szeroki. Jako rozwiązanie powstała funkcja updateDropdownWidth, która dostosowuje szerokość dropdownu na podstawie szerokości wrappera po stronie JS, a nie CSS.

@lgpawel lgpawel added the fallout from BS5 PRy wymagające dodatkowej uwagi po wdrożeniu Bootstrap 5 na master-dev label Oct 11, 2023
@Telpenarmo Telpenarmo self-assigned this Oct 21, 2023
Kiedy menu jest otwarte, a przynajmniej jeden element wybrany,
wyświetlaj listę zaznaczeń zamiast domyślnego placeholdera
@Telpenarmo
Copy link
Collaborator

Ta zmiana, i to do tej „lepszej” wersji, okazała się bardzo łatwa. Efekt jest rzeczywiście intuicyjny: napis zależy teraz od tylko wyboru elementów, nie od tego, czy menu jest otwarte.

@lgpawel
Copy link
Contributor

lgpawel commented Dec 9, 2023

Pozwoliłem sobie wyedytować wszystkie trzy pliki CourseFilter.vue tak, by były jak najbardziej podobne do siebie. Oczywiście jest to docelowo z myślą o tym, żeby być może je jakoś zdeduplikować, ale to na pewno nie w ramach tego PRa. Proszę o sprawdzenie, najlepiej także eksperymentalne, czy zgodnie z intencją nie zmieniam nic w działaniu stron.

Dobrze, że najświeższa zmiana okazała się nieskomplikowana, natomiast widzę teraz potrzebę jeszcze jednej poprawki: zauważyłem, że przy powybieranych opcjach stan opisującego napisu odzwierciedla kolejność zaznaczania, co jest oczywiście dość idiotyczne. Fajnie byłoby to jakoś normalizować, być może sortując listę selected? Najlepsza byłaby oczywiście dokładnie taka kolejność, jak na liście (wszystkich) opcji.

@Telpenarmo
Copy link
Collaborator

Telpenarmo commented Dec 10, 2023

Dopisałem tę zmianę, chociaż rozwiązanie, które proponuję, nie jest najprostsze.
Niestety, kolejność elementów w menu nie wynika z ich wartości (etykiet ani identyfikatorów), więc zamiast sortować listę zaznaczeń należy sprawdzać kolejność ich występowania w liście wszystkich opcji – o ile, oczywiście, zależy nam na zachowaniu bieżącej kolejności elementów menu, co wydaje mi się pożądane.

Opis oryginalnej implementacji

Zaimplementowałem to też zresztą niedoskonale, używając jako funkcji porównującej liniowego przeszukania pełnej listy. Uznałem, że taka implementacja jest najprostsza, a w przypadku tak małych list inkrementacja wykładnika złożoności nie boli, ale jeśli Pan, lub kto inny, się nie zgadza, mogę też oczywiście zaimplementować coś bardziej złożonego.

Edit: niepotrzebnie się spieszyłem. Wystarczyło pomyśleć o tym jeszcze raz, żeby uświadomić sobie, że zamiast wyświetlać listę selected, odpowiednio posortowaną, lepiej wyświetlić listę options ograniczoną do tych jej elementów, które występują w selected. Jest to znacznie prostsze i wydaje się czytelne.

@lgpawel
Copy link
Contributor

lgpawel commented Dec 15, 2023

To z kolei dobrze, że ja się nie spieszyłem, bo miałem zamiar zaproponować zmianę właśnie w tym duchu 🙂 Teraz jest oczywiście w porządku i działa.

Być może ostatnia rzecz, na którą należałoby zwrócić uwagę, to rzecz z wiadomości/wątku #1325 (comment) (plus ja muszę rozgryźć jeden bardzo techniczny szczegół) i będzie można wreszcie skończyć tę zabawę.

lgpawel and others added 4 commits February 9, 2024 22:08
Zamiast używać definicji skopiowanych z repo MultiSelect
i dostosowywaniu ich, referencjonujemy domyślne style, a następnie
odpowiednio nadpisujemy.
@Telpenarmo
Copy link
Collaborator

Zgodnie z naszą rozmową spróbowałem wyekstrahować różnice pomiędzy dodanym w tym PR plikiem scss a domyślnymi stylami MultiSelectFilter.
Wydaje mi się, że udało mi się to osiągnąć, ale niestety, jak wiadomo, CSS nie jest szczególnie przejrzystym językiem, a szukanie dwóch równoważnych styli jest dosyć trudne -- nie mam więc pewności, czy w przepisywaniu czegoś nie pominąłem.
Styli nadpisujących domyślne wyszło mi około 90 linii (licząc puste). Zdecydowałem się umieścić je bezpośrednio w komponencie, ale nie będzie problemem ewentualne przeniesienie ich do oddzielnego pliku.

Comment on lines 214 to 216
<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>

<style>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spodziewałbym się czegoś z grubsza takiego

Suggested change
<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>
<style>
<style lang="scss" scoped>
@import "~vue-multiselect/dist/vue-multiselect.min.css";

ale proszę samemu sprawdzić/dowiedzieć się, czy ta propozycja (uwzględniając wszystkie jej elementy) ma sens, ja bardziej zgaduję jej formę na podstawie tego, jak wyglądają inne pliki w projekcie. W szczególności nigdzie nie używamy dyrektywy @import w plikach .vue, więc gdyby z jakiegoś kryptycznego powodu nie działała ona tutaj, to będzie należało wywalić to do osobnego pliku .scss (ale poza tą ewentualnością nie widzę w tym momencie takiej potrzeby, optycznie nie wygląda ta sekcja jakoś strasznie).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rzeczywiście, wygląda to lepiej i działa.
Problem jest jedynie z atrybutem "scoped": style wypisane w takim bloku nie nakładają się na te zaimportowane. Mogę więc albo usunąć ten atrybut, albo, jeśli miałoby to w czymś pomóc, zrobić dwa bloki: jeden "scoped" z importem, drugi, pozbawiony go, z całą resztą.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ciekawe, z czego to się bierze; zgaduję, że jest ortogonalne do reszty proponowanej przeze mnie zmiany – czy jeśli będą dwa osobne elementy <style> (w "starej" bądź "nowej" formie, to już chyba nie powinno mieć znaczenia), to które z czterech możliwości nadania im tego atrybutu działają, a które nie?

Dwa bloki to oczywiście żadna herezja, jest na to nawet przykład w https://vuejs.org/api/sfc-css-features.html ale dobrze byłoby to robić wtedy, kiedy chcemy, a nie wtedy, kiedy jesteśmy do tego zmuszeni.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Zgaduję, że problem wynika wprost z semantyki atrybutu scoped: jeśli dobrze rozumiem, to zapewnia on, że style pod nim zadeklarowane obowiązywać będą tylko w komponencie, który ten styl zawiera.
W tym przypadku: komponentem zawierającym styl jest nasz MultiSelectFilter, ale chcemy, aby te style dotyczyły zagnieżdżonego w nim komponentu multiselect.
Dlaczego deklaracja @import działa ze scoped nie rozumiem, ale być może jest jakieś znane silnikowi mapowanie pomiędzy stylami, które importujemy, a komponentem multiselect, dzięki któremu Vue wie, że właśnie w nim powinien te style zastosować.

@lgpawel
Copy link
Contributor

lgpawel commented Feb 27, 2024

Po porównaniu lokalnego pliku SCSS w ostatnim stanie, w jakim istniał on osobno, i https://github.com/shentao/vue-multiselect/blob/master/src/Multiselect.vue który był podany jako punkt wyjścia do modyfikacji, widzę takie przeoczenia (które być może są celowe, ale wtedy proszę o wyjaśnienie):

Dodatkowo trochę nie podoba mi się, że wycofywanie deklaracji, które w oryginalnym stylu się nam nie podobają, odbywa się w bardzo różny sposób...

Warto byłoby uzasadnić (w komentarzach w kodzie?) te różne podejścia, a jeśli przy okazji uda się je ograniczyć, to tym lepiej.

@Telpenarmo
Copy link
Collaborator

Poruszył Pan w swoim komentarzu (o różnicach między moją wersją a tą oryginalną – zawartą w pliku SCSS) wiele wątków, na które trudno byłoby mi odpowiedzieć symetrycznie.
Pozwolę sobie więc odpowiedzieć zmianami w kodzie tam, gdzie zauważone przez Pana różnice są błędne, niepotrzebne lub niespójne (jak np. ustawienie wymiarów w pewnym miejscu na autounset działa tam tak samo); komentarzami w kodzie tam, gdzie różnice są wymagane; natomiast w przypadku styli, których ja nie ująłem w swojej wersji, mogę tylko odpowiedzieć tutaj.
Jeśli chodzi o brakujące style klas multiselect__tags* oraz multiselect_spinner*, to nie uwzględniłem ich, ponieważ ani tagów, ani spinnera nie używamy. Nie chciałem zamieszczać martwego kodu – myślę, że jeśli nawet kiedyś te elementy miałyby być użyte, to i tak lepiej, aby ktoś się im przyjrzał.
Nie wycofałem deklaracji min-height: 40px na elementy listy, ponieważ w naszym przypadku ich wysokość jest stała i nieco przekracza te 40px, a wynika z innych styli (line-height, padding itd.).

Wydaje mi się, że to wszystko, ale nie przeczę, że coś mogło mi umknąć, bardzo proszę zapoznać się z poprawkami i komentarzami.

@lgpawel
Copy link
Contributor

lgpawel commented Feb 28, 2024

Najnowsza zmiana zepsuła jeden detal (commit wcześniej było dobrze), tj. tekst z wielokropkiem wchodzący pod iksa:
image
Właśnie zobaczyłem też, że cały element jest wyższy niż przycisk do rozwijania dropdowna, ale nie sprawdziłem jeszcze, kiedy to się pojawiło też dopiero w najnowszej wersji. Można to poprawić na dwa sposoby, ale lepiej zmniejszyć wysokość całości do wysokości przycisku – wtedy będzie ona taka sama, jak pola (innego rodzaju) po lewej, na nazwę przedmiotu.

(regresji spowodowanej poprzednim commitem)
@Telpenarmo
Copy link
Collaborator

Rzeczywiście, zbyt frywolnie podszedłem do usuwania kodu. Aż dziwne, że nie tego zauważyłem, pewnie to przez późną godzinę.

@lgpawel lgpawel merged commit de3361a into master-dev Mar 20, 2024
4 checks passed
@lgpawel lgpawel deleted the courses-select-multiple branch March 20, 2024 20:04
AThit7 pushed a commit that referenced this pull request Apr 2, 2024
…d. (#1325)

Na stronach z filtrowaniem (wykazy przedmiotów oraz propozycji i wyniki głosowania na nie) zastępujemy dotychczasowy `SelectFilter` (który znika z projektu) filtrem wielokrotnego wyboru zbudowanym w oparciu o nowo dołączoną bibliotekę `vue-multiselect`. Style komponentu dostosowujemy do wyglądu SZ oraz porządkujemy kod JS w plikach wykorzystujących go (w tym uwzględniamy porządek alfabetyczny języka polskiego w _dropdownach_ z prowadzącymi).

Co-authored-by: Jakub Grabarczuk <Telpenarmo@users.noreply.github.com>
Co-authored-by: Bogusz Kaszowski <bkaszowski@users.noreply.github.com>
mbaugustyn pushed a commit that referenced this pull request May 11, 2024
…d. (#1325)

Na stronach z filtrowaniem (wykazy przedmiotów oraz propozycji i wyniki głosowania na nie) zastępujemy dotychczasowy `SelectFilter` (który znika z projektu) filtrem wielokrotnego wyboru zbudowanym w oparciu o nowo dołączoną bibliotekę `vue-multiselect`. Style komponentu dostosowujemy do wyglądu SZ oraz porządkujemy kod JS w plikach wykorzystujących go (w tym uwzględniamy porządek alfabetyczny języka polskiego w _dropdownach_ z prowadzącymi).

Co-authored-by: Jakub Grabarczuk <Telpenarmo@users.noreply.github.com>
Co-authored-by: Bogusz Kaszowski <bkaszowski@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
fallout from BS5 PRy wymagające dodatkowej uwagi po wdrożeniu Bootstrap 5 na master-dev
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Filtrowanie po wielu rodzajach przedmiotu
5 participants