Collection Speed Improvements (#874)

* Add UltraSlimCollectionSerializer and update CollectionViewSet for optimized listing

- Introduced UltraSlimCollectionSerializer for efficient data representation.
- Updated CollectionViewSet to use the new serializer for list actions.
- Enhanced queryset optimizations with prefetching for related images.
- Modified frontend components to support SlimCollection type for better performance.

* Optimize rendering of collection cards by adding a unique key to the each block
This commit is contained in:
Sean Morley
2025-09-22 08:34:23 -04:00
committed by GitHub
parent 240c617010
commit 8a0f7310b0
7 changed files with 203 additions and 86 deletions

View File

@@ -9,7 +9,7 @@
import ShareVariant from '~icons/mdi/share-variant';
import { goto } from '$app/navigation';
import type { Location, Collection, User } from '$lib/types';
import type { Location, Collection, User, SlimCollection, ContentImage } from '$lib/types';
import { addToast } from '$lib/toasts';
import { t } from 'svelte-i18n';
@@ -55,7 +55,21 @@
}
}
export let collection: Collection;
export let collection: Collection | SlimCollection;
let location_images: ContentImage[] = [];
if ('location_images' in collection) {
location_images = collection.location_images;
} else {
location_images = collection.locations.flatMap((location: Location) => location.images);
}
let locationLength: number = 0;
if ('location_count' in collection) {
locationLength = collection.location_count;
} else {
locationLength = collection.locations.length;
}
async function deleteCollection() {
let res = await fetch(`/api/collections/${collection.id}`, {
@@ -92,11 +106,7 @@
>
<!-- Image Carousel -->
<div class="relative overflow-hidden rounded-t-2xl">
<CardCarousel
images={collection.locations.flatMap((location) => location.images)}
name={collection.name}
icon="📚"
/>
<CardCarousel images={location_images} name={collection.name} icon="📚" />
<!-- Badge Overlay -->
<div class="absolute top-4 left-4 flex flex-col gap-2">
@@ -124,7 +134,7 @@
<!-- Adventure Count -->
<p class="text-sm text-base-content/70">
{collection.locations.length}
{locationLength}
{$t('locations.locations')}
</p>

View File

@@ -1,5 +1,5 @@
<script lang="ts">
import type { Collection, User } from '$lib/types';
import type { Collection, SlimCollection, User } from '$lib/types';
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
import { onMount } from 'svelte';
@@ -11,7 +11,7 @@
import Share from '~icons/mdi/share';
import Clear from '~icons/mdi/close';
export let collection: Collection;
export let collection: SlimCollection | Collection;
// Extended user interface to include status
interface UserWithStatus extends User {
@@ -160,6 +160,7 @@
<dialog id="my_modal_1" class="modal">
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
<div
class="modal-box w-11/12 max-w-5xl p-6 space-y-6"
role="dialog"

View File

@@ -137,6 +137,23 @@ export type Collection = {
link?: string | null;
};
export type SlimCollection = {
id: string;
user: string;
name: string;
description: string;
is_public: boolean;
start_date: string | null;
end_date: string | null;
is_archived: boolean;
link: string | null;
created_at: string;
updated_at: string;
location_images: ContentImage[];
location_count: number;
shared_with: string[];
};
export type GeocodeSearchResult = {
lat?: string;
lon?: string;

View File

@@ -1,7 +1,7 @@
import { redirect } from '@sveltejs/kit';
import type { PageServerLoad } from './$types';
const PUBLIC_SERVER_URL = process.env['PUBLIC_SERVER_URL'];
import type { Location, Collection } from '$lib/types';
import type { Location, Collection, SlimCollection } from '$lib/types';
import type { Actions } from '@sveltejs/kit';
import { fetchCSRFToken } from '$lib/index.server';
@@ -62,11 +62,11 @@ export const load = (async (event) => {
next: collectionsData.next,
previous: collectionsData.previous,
count: collectionsData.count,
sharedCollections: sharedData as Collection[],
sharedCollections: sharedData as SlimCollection[],
currentPage,
order_by,
order_direction,
archivedCollections: archivedData as Collection[],
archivedCollections: archivedData as SlimCollection[],
invites: invitesData
}
};

View File

@@ -5,7 +5,7 @@
import CollectionLink from '$lib/components/CollectionLink.svelte';
import CollectionModal from '$lib/components/CollectionModal.svelte';
import NotFound from '$lib/components/NotFound.svelte';
import type { Collection, CollectionInvite } from '$lib/types';
import type { Collection, CollectionInvite, SlimCollection } from '$lib/types';
import { t } from 'svelte-i18n';
import Plus from '~icons/mdi/plus';
@@ -23,9 +23,9 @@
export let data: any;
console.log('Collections page data:', data);
let collections: Collection[] = data.props.adventures || [];
let sharedCollections: Collection[] = data.props.sharedCollections || [];
let archivedCollections: Collection[] = data.props.archivedCollections || [];
let collections: SlimCollection[] = data.props.adventures || [];
let sharedCollections: SlimCollection[] = data.props.sharedCollections || [];
let archivedCollections: SlimCollection[] = data.props.archivedCollections || [];
let newType: string = '';
let resultsPerPage: number = 25;
@@ -142,7 +142,7 @@
}
}
function saveOrCreate(event: CustomEvent<Collection>) {
function saveOrCreate(event: CustomEvent<SlimCollection>) {
if (collections.find((collection) => collection.id === event.detail.id)) {
collections = collections.map((collection) => {
if (collection.id === event.detail.id) {
@@ -156,8 +156,8 @@
isShowingCollectionModal = false;
}
function editCollection(event: CustomEvent<Collection>) {
collectionToEdit = event.detail;
function editCollection(event: CustomEvent<SlimCollection>) {
collectionToEdit = event.detail as unknown as Collection;
isShowingCollectionModal = true;
}
@@ -181,7 +181,7 @@
}
}
function saveEdit(event: CustomEvent<Collection>) {
function saveEdit(event: CustomEvent<SlimCollection>) {
collections = collections.map((adventure) => {
if (adventure.id === event.detail.id) {
return event.detail;
@@ -490,7 +490,7 @@
<div
class="grid grid-cols-1 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-2 xl:grid-cols-3 gap-6"
>
{#each currentCollections as collection}
{#each currentCollections as collection (collection.id)}
<CollectionCard
type=""
{collection}