ajaxify album loading in the SAS

This commit is contained in:
imperosol 2025-02-21 16:44:56 +01:00
parent cfefd9bd5b
commit b2056064e1
4 changed files with 57 additions and 14 deletions

View File

@ -1,18 +1,24 @@
import { paginated } from "#core:utils/api"; import { paginated } from "#core:utils/api";
import { History, initialUrlParams, updateQueryString } from "#core:utils/history"; import { History, initialUrlParams, updateQueryString } from "#core:utils/history";
import { import {
type AlbumSchema,
type PictureSchema, type PictureSchema,
type PicturesFetchPicturesData, type PicturesFetchPicturesData,
albumFetchAlbum,
picturesFetchPictures, picturesFetchPictures,
} from "#openapi"; } from "#openapi";
interface AlbumConfig { interface AlbumPicturesConfig {
albumId: number; albumId: number;
maxPageSize: number; maxPageSize: number;
} }
interface SubAlbumsConfig {
parentId: number;
}
document.addEventListener("alpine:init", () => { document.addEventListener("alpine:init", () => {
Alpine.data("pictures", (config: AlbumConfig) => ({ Alpine.data("pictures", (config: AlbumPicturesConfig) => ({
pictures: [] as PictureSchema[], pictures: [] as PictureSchema[],
page: Number.parseInt(initialUrlParams.get("page")) || 1, page: Number.parseInt(initialUrlParams.get("page")) || 1,
pushstate: History.Push /* Used to avoid pushing a state on a back action */, pushstate: History.Push /* Used to avoid pushing a state on a back action */,
@ -57,4 +63,23 @@ document.addEventListener("alpine:init", () => {
return Math.ceil(this.pictures.length / config.maxPageSize); return Math.ceil(this.pictures.length / config.maxPageSize);
}, },
})); }));
Alpine.data("albums", (config: SubAlbumsConfig) => ({
albums: [] as AlbumSchema[],
config: config,
loading: false,
async init() {
await this.fetchAlbums();
},
async fetchAlbums() {
this.loading = true;
this.albums = await paginated(albumFetchAlbum, {
// biome-ignore lint/style/useNamingConvention: API is snake_case
query: { parent_id: this.config.parentId },
});
this.loading = false;
},
}));
}); });

View File

@ -2,7 +2,7 @@ import { AjaxSelect } from "#core:core/components/ajax-select-base";
import { registerComponent } from "#core:utils/web-components"; import { registerComponent } from "#core:utils/web-components";
import type { TomOption } from "tom-select/dist/types/types"; import type { TomOption } from "tom-select/dist/types/types";
import type { escape_html } from "tom-select/dist/types/utils"; import type { escape_html } from "tom-select/dist/types/utils";
import { type AlbumAutocompleteSchema, albumSearchAlbum } from "#openapi"; import { type AlbumAutocompleteSchema, albumAutocompleteAlbum } from "#openapi";
@registerComponent("album-ajax-select") @registerComponent("album-ajax-select")
export class AlbumAjaxSelect extends AjaxSelect { export class AlbumAjaxSelect extends AjaxSelect {
@ -11,7 +11,7 @@ export class AlbumAjaxSelect extends AjaxSelect {
protected searchField = ["path", "name"]; protected searchField = ["path", "name"];
protected async search(query: string): Promise<TomOption[]> { protected async search(query: string): Promise<TomOption[]> {
const resp = await albumSearchAlbum({ query: { search: query } }); const resp = await albumAutocompleteAlbum({ query: { search: query } });
if (resp.data) { if (resp.data) {
return resp.data.results; return resp.data.results;
} }

View File

@ -53,15 +53,33 @@
{% endif %} {% endif %}
{% endif %} {% endif %}
{% if children_albums|length > 0 %} {% if show_albums %}
<h4>{% trans %}Albums{% endtrans %}</h4> <div x-data="albums({ parentId: {{ album.id }} })" class="margin-bottom">
<div class="albums"> <h4>{% trans %}Albums{% endtrans %}</h4>
{% for a in children_albums %} <div class="albums" :aria-busy="loading">
{{ display_album(a, is_sas_admin) }} <template x-for="album in albums" :key="album.id">
{% endfor %} <a :href="album.sas_url">
<div
x-data="{thumbUrl: album.thumbnail || '{{ static("core/img/sas.jpg") }}'}"
class="album"
:class="{not_moderated: !album.is_moderated}"
:style="`background-image: url('${thumbUrl}');`"
>
<template x-if="album.is_moderated">
<div class="text" x-text="album.name"></div>
</template>
<template x-if="!album.is_moderated">
<div class="overlay">&nbsp;</div>
<div class="text">{% trans %}To be moderated{% endtrans %}</div>
</template>
</div>
{% if edit_mode %}
<input type="checkbox" name="file_list" :value="album.id">
{% endif %}
</a>
</template>
</div>
</div> </div>
<br>
{% endif %} {% endif %}
<div x-data="pictures({ albumId: {{ album.id }}, maxPageSize: {{ settings.SITH_SAS_IMAGES_PER_PAGE }} })"> <div x-data="pictures({ albumId: {{ album.id }}, maxPageSize: {{ settings.SITH_SAS_IMAGES_PER_PAGE }} })">

View File

@ -186,10 +186,10 @@ class AlbumView(CanViewMixin, DetailView, FormMixin):
kwargs["clipboard"] = SithFile.objects.filter( kwargs["clipboard"] = SithFile.objects.filter(
id__in=self.request.session["clipboard"] id__in=self.request.session["clipboard"]
) )
kwargs["children_albums"] = list( kwargs["show_albums"] = (
Album.objects.viewable_by(self.request.user) Album.objects.viewable_by(self.request.user)
.filter(parent_id=self.object.id) .filter(parent_id=self.object.id)
.order_by("-date") .exists()
) )
return kwargs return kwargs