Use typescript api for user pictures and allow imports across js files

* Add imports paths for js files in node
* Add a ts version of fetchPaginated
* Update documentation
This commit is contained in:
2024-10-09 20:59:12 +02:00
parent 9247696c1c
commit 9199f91151
8 changed files with 111 additions and 10 deletions

View File

@ -1,5 +1,7 @@
import { paginated } from "#core:utils/api";
import { HttpReader, ZipWriter } from "@zip.js/zip.js";
import { showSaveFilePicker } from "native-file-system-adapter";
import { picturesFetchPictures } from "#openapi";
/**
* @typedef UserProfile
@ -28,14 +30,14 @@ import { showSaveFilePicker } from "native-file-system-adapter";
/**
* @typedef PicturePageConfig
* @param {string} apiUrl Url of the api endpoint to fetch pictures from the user
* @param {number} userId Id of the user to get the pictures from
**/
/**
* Load user picture page with a nice download bar
* @param {PicturePageConfig} Configuration
**/
window.loadPicturePage = (config) => {
window.window.loadPicturePage = (config) => {
document.addEventListener("alpine:init", () => {
Alpine.data("user_pictures", () => ({
isDownloading: false,
@ -44,8 +46,10 @@ window.loadPicturePage = (config) => {
albums: {},
async init() {
// biome-ignore lint/correctness/noUndeclaredVariables: imported from script.json
this.pictures = await fetchPaginated(config.apiUrl);
this.pictures = await paginated(picturesFetchPictures, {
// biome-ignore lint/style/useNamingConvention: api is in snake_case
query: { users_identified: [config.userId] },
});
this.albums = this.pictures.reduce((acc, picture) => {
if (!acc[picture.album]) {
acc[picture.album] = [];

View File

@ -0,0 +1,46 @@
import type { Options, RequestResult } from "@hey-api/client-fetch";
interface PaginatedResponse<T> {
count: number;
next: string | null;
previous: string | null;
results: T[];
}
interface PaginatedRequest {
query?: {
page?: number;
// biome-ignore lint/style/useNamingConvention: api is in snake_case
page_size?: number;
};
}
type PaginatedEndpoint<T> = <ThrowOnError extends boolean = false>(
options?: Options<PaginatedRequest, ThrowOnError>,
) => RequestResult<PaginatedResponse<T>, unknown, ThrowOnError>;
export const paginated = async <T>(
endpoint: PaginatedEndpoint<T>,
options?: PaginatedRequest,
) => {
const maxPerPage = 199;
options.query.page_size = maxPerPage;
options.query.page = 1;
const firstPage = (await endpoint(options)).data;
const results = firstPage.results;
const nbElements = firstPage.count;
const nbPages = Math.ceil(nbElements / maxPerPage);
if (nbPages > 1) {
const promises: Promise<T[]>[] = [];
for (let i = 2; i <= nbPages; i++) {
const nextPage = structuredClone(options);
nextPage.query.page = i;
promises.push(endpoint(nextPage).then((res) => res.data.results));
}
results.push(...(await Promise.all(promises)).flat());
}
return results;
};