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

chore: add per_page parameter to page #301

Merged
merged 2 commits into from
Mar 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 137 additions & 0 deletions src/lib/ui/ExtensionsList.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,140 @@ test('check categories', async () => {
const category2 = screen.getByText('category2');
expect(category2).toBeInTheDocument();
});

test('if per_page is passed into window.location.search then it should be used to filter extensions', async () => {
// Mock query to be last 1
vi.spyOn(window, 'location', 'get').mockReturnValue({
search: '?per_page=1',
} as unknown as Location);

const extensionsByCategories: ExtensionByCategoryInfo[] = [
{
category: 'category1',
extensions: [
{
displayName: 'dummy1',
versions: [
{
version: '1.0.0',
// Todays date minus 1 day, to make sure it is NOT the most recent one (we want to show dummy2)
lastUpdated: new Date(new Date().setDate(new Date().getDate() - 1)),
files: [],
},
],
} as unknown as CatalogExtensionInfo,
],
},
{
category: 'category2',
extensions: [
{
displayName: 'dummy2',
versions: [
{
version: '1.0.0',
lastUpdated: new Date(),
files: [],
},
],
} as unknown as CatalogExtensionInfo,
],
},
];

render(ExtensionsList, { extensionsByCategories });

// Make sure that displayname dummy2 is shown, as it is the "most" up to date one.
const dummy2 = screen.getByText('dummy2');
expect(dummy2).toBeInTheDocument();

// Dummy1 should NOT be shown
const dummy1 = screen.queryByText('dummy1');
expect(dummy1).not.toBeInTheDocument();

// Categories category1 and category2 should be NOT shown
const category1 = screen.queryByText('category1');
expect(category1).not.toBeInTheDocument();

const category2 = screen.queryByText('category2');
expect(category2).not.toBeInTheDocument();
});

test('if per_page is passed in with 4, it should show last 4 extensions even if there is 5 in the list', async () => {
// Mock query to be last 4
vi.spyOn(window, 'location', 'get').mockReturnValue({
search: '?per_page=4',
} as unknown as Location);

const extensionsByCategories: ExtensionByCategoryInfo[] = [
{
category: 'category1',
extensions: [
{
displayName: 'dummy1',
versions: [
{
version: '1.0.0',
lastUpdated: new Date(new Date().setDate(new Date().getDate() - 1)),
files: [],
},
],
} as unknown as CatalogExtensionInfo,
{
displayName: 'dummy2',
versions: [
{
version: '1.0.0',
lastUpdated: new Date(new Date().setDate(new Date().getDate() - 2)),
files: [],
},
],
} as unknown as CatalogExtensionInfo,
{
displayName: 'dummy3',
versions: [
{
version: '1.0.0',
lastUpdated: new Date(new Date().setDate(new Date().getDate() - 3)),
files: [],
},
],
} as unknown as CatalogExtensionInfo,
{
displayName: 'dummy4',
versions: [
{
version: '1.0.0',
lastUpdated: new Date(new Date().setDate(new Date().getDate() - 4)),
files: [],
},
],
} as unknown as CatalogExtensionInfo,
{
displayName: 'dummy5',
versions: [
{
version: '1.0.0',
lastUpdated: new Date(new Date().setDate(new Date().getDate() - 5)),
files: [],
},
],
} as unknown as CatalogExtensionInfo,
],
},
];

render(ExtensionsList, { extensionsByCategories });

// Make sure that displayname dummy4 is shown, as it is the "most" up to date one.
const dummy4 = screen.getByText('dummy4');
expect(dummy4).toBeInTheDocument();

// Dummy5 should NOT be shown, as it's the "oldest" one.
const dummy5 = screen.queryByText('dummy5');
expect(dummy5).not.toBeInTheDocument();

// Categories category1 should be NOT shown
const category1 = screen.queryByText('category1');
expect(category1).not.toBeInTheDocument();
});
54 changes: 49 additions & 5 deletions src/lib/ui/ExtensionsList.svelte
Original file line number Diff line number Diff line change
@@ -1,13 +1,57 @@
<script lang="ts">
import type { ExtensionByCategoryInfo } from '$lib/api/extensions-info';
import type { CatalogExtensionInfo, ExtensionByCategoryInfo } from '$lib/api/extensions-info';

import ExtensionByCategoryCard from './ExtensionByCategoryCard.svelte';
import ExtensionsByCategory from './ExtensionsByCategory.svelte';

const { extensionsByCategories }: { extensionsByCategories: ExtensionByCategoryInfo[] } = $props();
interface Props {
extensionsByCategories: ExtensionByCategoryInfo[];
}
let { extensionsByCategories }: Props = $props();

let filteredExtensions = $state<CatalogExtensionInfo[]>([]);
let showCategories = $state<boolean>(true);

// Get the per_page from the URL
function getPerPageLimit(): number | undefined {
const perPage = new URLSearchParams(window.location.search).get('per_page');
return perPage ? parseInt(perPage, 10) : undefined;
}

// Sort extensions based upon the last updated date based upon what's in .versions array
function getSortedExtensions(extensions: CatalogExtensionInfo[]): CatalogExtensionInfo[] {
return [...extensions].sort((a, b) => {
const aLastUpdated = a.versions?.[a.versions.length - 1]?.lastUpdated ?? 0;
const bLastUpdated = b.versions?.[b.versions.length - 1]?.lastUpdated ?? 0;
return Number(bLastUpdated) - Number(aLastUpdated);
});
}

$effect(() => {
const limit = getPerPageLimit();
showCategories = !limit;

if (limit) {
const allExtensions = extensionsByCategories.flatMap(({ extensions }) => extensions);
filteredExtensions = getSortedExtensions(allExtensions).slice(0, limit);
}
});
</script>

<div class="flex flex-col h-full">
{#each extensionsByCategories as extensionByCategoryInfo}
<ExtensionsByCategory {extensionByCategoryInfo} />
{/each}
{#if showCategories}
{#each extensionsByCategories as extensionByCategoryInfo}
Copy link
Contributor

Choose a reason for hiding this comment

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

issue (non blocking) but not sure why: looks like we have existing tab characters

Copy link
Contributor Author

Choose a reason for hiding this comment

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

hmm, looks like pnpm format:fixdoes not actually do svelte files too

<ExtensionsByCategory {extensionByCategoryInfo} />
{/each}
{:else}
<div
class="mt-2 grid min-[920px]:grid-cols-2 min-[1180px]:grid-cols-3 gap-3"
role="region"
aria-label="Filtered extensions"
>
{#each filteredExtensions as extension}
<ExtensionByCategoryCard {extension} />
{/each}
</div>
{/if}
</div>
Loading