mirror of
https://github.com/ae-utbm/sith.git
synced 2024-12-22 07:41:14 +00:00
Make a generic AjaxSelect abstract class
This commit is contained in:
parent
f78b968075
commit
0af3505c2a
@ -112,42 +112,72 @@ class AutocompleteSelect extends inheritHtmlElement("select") {
|
||||
}
|
||||
}
|
||||
|
||||
@registerComponent("user-ajax-select")
|
||||
export class UserAjaxSelect extends AutocompleteSelect {
|
||||
public filter?: <T>(items: T[]) => T[];
|
||||
|
||||
abstract class AjaxSelect extends AutocompleteSelect {
|
||||
protected filter?: (items: TomOption[]) => TomOption[] = null;
|
||||
protected minCharNumberForSearch = 2;
|
||||
|
||||
protected abstract valueField: string;
|
||||
protected abstract labelField: string;
|
||||
protected abstract renderOption(
|
||||
item: TomOption,
|
||||
sanitize: typeof escape_html,
|
||||
): string;
|
||||
protected abstract renderItem(item: TomOption, sanitize: typeof escape_html): string;
|
||||
protected abstract search(query: string): Promise<TomOption[]>;
|
||||
|
||||
public setFilter(filter?: (items: TomOption[]) => TomOption[]) {
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
protected getLoadFunction() {
|
||||
// this will be replaced by TomSelect if we don't wrap it that way
|
||||
return async (query: string, callback: TomLoadCallback) => {
|
||||
const resp = await this.search(query);
|
||||
if (this.filter) {
|
||||
callback(this.filter(resp), []);
|
||||
} else {
|
||||
callback(resp, []);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected tomSelectSettings(): RecursivePartial<TomSettings> {
|
||||
return {
|
||||
...super.tomSelectSettings(),
|
||||
hideSelected: true,
|
||||
diacritics: true,
|
||||
duplicates: false,
|
||||
valueField: "id",
|
||||
labelField: "display_name",
|
||||
valueField: this.valueField,
|
||||
labelField: this.labelField,
|
||||
searchField: [], // Disable local search filter and rely on tested backend
|
||||
load: (query: string, callback: TomLoadCallback) => {
|
||||
userSearchUsers({
|
||||
query: {
|
||||
search: query,
|
||||
},
|
||||
}).then((response) => {
|
||||
if (response.data) {
|
||||
if (this.filter) {
|
||||
callback(this.filter(response.data.results), []);
|
||||
} else {
|
||||
callback(response.data.results, []);
|
||||
}
|
||||
return;
|
||||
}
|
||||
callback([], []);
|
||||
});
|
||||
},
|
||||
load: this.getLoadFunction(),
|
||||
render: {
|
||||
...super.tomSelectSettings().render,
|
||||
option: (item: UserProfileSchema, sanitize: typeof escape_html) => {
|
||||
return `<div class="select-item">
|
||||
option: this.renderOption,
|
||||
item: this.renderItem,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@registerComponent("user-ajax-select")
|
||||
export class UserAjaxSelect extends AjaxSelect {
|
||||
protected valueField = "id";
|
||||
protected labelField = "display_name";
|
||||
|
||||
protected async search(query: string): Promise<TomOption[]> {
|
||||
const resp = await userSearchUsers({ query: { search: query } });
|
||||
if (resp.data) {
|
||||
return resp.data.results;
|
||||
}
|
||||
return [];
|
||||
}
|
||||
protected tomSelectSettings(): RecursivePartial<TomSettings> {
|
||||
return super.tomSelectSettings();
|
||||
}
|
||||
|
||||
protected renderOption(item: UserProfileSchema, sanitize: typeof escape_html) {
|
||||
return `<div class="select-item">
|
||||
<img
|
||||
src="${sanitize(item.profile_pict)}"
|
||||
alt="${sanitize(item.display_name)}"
|
||||
@ -155,11 +185,9 @@ export class UserAjaxSelect extends AutocompleteSelect {
|
||||
/>
|
||||
<span class="select-item-text">${sanitize(item.display_name)}</span>
|
||||
</div>`;
|
||||
},
|
||||
item: (item: UserProfileSchema, sanitize: typeof escape_html) => {
|
||||
return `<span><i class="fa fa-times"></i>${sanitize(item.display_name)}</span>`;
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
protected renderItem(item: UserProfileSchema, sanitize: typeof escape_html) {
|
||||
return `<span><i class="fa fa-times"></i>${sanitize(item.display_name)}</span>`;
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,14 @@
|
||||
import type { Client, Options, RequestResult } from "@hey-api/client-fetch";
|
||||
import { client } from "#openapi";
|
||||
|
||||
interface PaginatedResponse<T> {
|
||||
export interface PaginatedResponse<T> {
|
||||
count: number;
|
||||
next: string | null;
|
||||
previous: string | null;
|
||||
results: T[];
|
||||
}
|
||||
|
||||
interface PaginatedRequest {
|
||||
export interface PaginatedRequest {
|
||||
query?: {
|
||||
page?: number;
|
||||
// biome-ignore lint/style/useNamingConvention: api is in snake_case
|
||||
|
@ -177,7 +177,7 @@ exportToHtml("loadViewer", (config: ViewerConfig) => {
|
||||
} as PicturesFetchPicturesData)
|
||||
).map(PictureWithIdentifications.fromPicture);
|
||||
this.selector = this.$refs.search;
|
||||
this.selector.filter = (users: UserProfileSchema[]) => {
|
||||
this.selector.setFilter((users: UserProfileSchema[]) => {
|
||||
const resp: UserProfileSchema[] = [];
|
||||
const ids = [
|
||||
...(this.currentPicture.identifications || []).map(
|
||||
@ -190,7 +190,7 @@ exportToHtml("loadViewer", (config: ViewerConfig) => {
|
||||
}
|
||||
}
|
||||
return resp;
|
||||
};
|
||||
});
|
||||
this.currentPicture = this.pictures.find(
|
||||
(i: PictureSchema) => i.id === config.firstPictureId,
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user