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

Trwałe filtry wyszukiwania #1129

Merged
merged 9 commits into from
Jan 3, 2022
Merged

Trwałe filtry wyszukiwania #1129

merged 9 commits into from
Jan 3, 2022

Conversation

JMendyk
Copy link
Contributor

@JMendyk JMendyk commented Nov 12, 2021

Trwałe filtry wyszukiwania (patrz #1024)

Opis problemu, rozważone oraz wybrane rozwiązanie są opisane w https://hackmd.io/6tclhbJnQVq4d9TF2iwNMg.

Lista zadań i powiązanych PRów:

* Add button to clear filters' state

* Add clear filters' button in offer's CourseFilter.vue

* Remove .$data. usage in Select- and TextFilter

* Remove mine needlessly verbose comment
@JMendyk JMendyk marked this pull request as ready for review November 29, 2021 13:17
@JMendyk JMendyk requested a review from mbuszka November 29, 2021 13:20
Copy link
Collaborator

@mbuszka mbuszka left a comment

Choose a reason for hiding this comment

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

Dziękuję Panom, wygląda (i działa) to wszystko bardzo dobrze. Kilka drobnych uwag zostawiłem w komentarzach do konkretnych plików. Jak już zostaną rozwiązane prosiłbym też o krótki opis zmian oraz tego jak działa zarządzanie filtrami w opisie PR.

Comment on lines +48 to +49
for (let i = 0; i < semesterLinks.length; i++) {
const link: Element = semesterLinks[i];
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit: Czy pętla for-of nie byłaby tutaj odpowiedniejsza

Copy link
Contributor

Choose a reason for hiding this comment

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

Przy próbie bezpośredniego iterowania po semesterLinks za pomocą for-of, Vetur zgłasza błąd:

Type 'HTMLCollectionOf' must have a '[Symbol.iterator]()' method that returns an iterator. Vetur(2488)

Należałoby więc utworzyć tablicę z tego obiektu za pomocą Array.from():

Suggested change
for (let i = 0; i < semesterLinks.length; i++) {
const link: Element = semesterLinks[i];
for (const link of Array.from(semesterLinks)) {

Nie byłem pewien czy takie rozwiązanie byłoby lepsze od zastosowania zwykłej pętli for.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Myślę, że można zostawić jak jest.

Comment on lines 43 to 50
const filterableProperties = [
"name",
"tags",
"courseType",
"effects",
"owner",
"recommendedForFirstYear",
];
Copy link
Collaborator

Choose a reason for hiding this comment

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

Czy dałoby się (łatwo) generować tę listę na podstawie template'u?

Copy link
Contributor

Choose a reason for hiding this comment

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

Komponent CourseFilter musiałby mieć dostęp do zagnieżdżonych w swoim template komponentów. W tym celu należałoby każdemu z nich przypisać identyfikator poprzez atrybut ref, tak aby móc się do nich odwoływać za pomocą this.$refs.

Wtedy listę filterableProperties można by było wygenerować następująco:

const filterableProperties = Object.values(this.$refs).map((filter: any) => filter.property);

Copy link
Collaborator

Choose a reason for hiding this comment

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

To chyba warto tak zrobić, w kontekście deduplikacji między widokiem w courses, prototype (i pewnie niedługo też w vote).

Copy link
Contributor

Choose a reason for hiding this comment

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

Zawarłem te zmiany w PR #1156.

// As shown by `selected` type, we expect the `allLabels` to have keys
// of type `number`. However, none(?) key-obtaining methods have signature
// that would thread this information. Thus, we annotate this here.
return keys(this.allLabels) as unknown as number[];
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit: Czy nie wystarczy tutaj return keys(this.allLabels) as number[];

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Tak, ta konstrukcja wygląda bardzo sztucznie.

Bez as unknown Vetur zgłasza ostrzeżenie celem zapobiegnięcia niezamierzonej nietrywialnej zmianie informacji o typie

Conversion of type 'string[]' to type 'number[]' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
Type 'string' is not comparable to type 'number'.
Vetur(2352)

Pisząc ten kod zbyt pobieżnie zapoznałem się z jego niuansami.

Funkcja keys zwraca listę o elementach typu string, bo klucze obiektów w JS są typu string. Pozostałe typy są konwertowane do string gdy są używane na potrzeby "bycia kluczem". Jednak przykładowo Chrome w narzędziach deweloperskich wyświetlając obiekty sugeruje, że klucze są jednak liczbami 🤷‍♂️.

W omawianym kodzie przyjmujemy jednak że klucze są liczbami, co jest dodatkowo wzmocnione anotacją typową KVDict dla allLabels, gdzie

export interface KVDict {
  [key: number]: string;
}

Moglibyśmy więc alternatywnie napisać (ku tej opcji się skłaniam)

return keys(this.allLabels).map(Numbers);

lub skorzystać z typu Map<K, V>, w którym klucze rzeczywiście są ustalonego typu, jednak praca z tą strukturą jest istotnie inna (set/get zamiast indeksowania).

Copy link
Collaborator

Choose a reason for hiding this comment

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

A czy jest dla nas właściwie istotne, czy te indeksy są liczbami?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ma to znaczenie w kontekście funkcji intersection w IntersectionFilter, która używa operatora równości SameValueZero (który patrzy m.in. na typy).

Ostatecznie wybrałem opcję z mapowaniem kluczy na wartości liczbowe w computed property: #1155.

Comment on lines 94 to 102
this.$store.subscribe((mutation, _) => {
switch (mutation.type) {
case "filters/clearFilters":
this.allLabelKeys
.filter((key) => this.selected[key])
.forEach(this.toggle);
break;
}
});
Copy link
Collaborator

Choose a reason for hiding this comment

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

Rozważyłbym tutaj przełączenie wartości filtrów i pojedyncze wywołanie odświeżające query string na koniec. Aktualna implementacji generuje O(n) odświeżeń adresu, co jest zauważalne przy większej ilości wybranych labelek.

Copy link
Collaborator

@mbuszka mbuszka left a comment

Choose a reason for hiding this comment

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

Dziękuję, wygląda to bardzo dobrze.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants