Skip to content
20 changes: 14 additions & 6 deletions src/lib/components/archiveProject.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script lang="ts">
import { Button } from '$lib/elements/forms';
import { DropList, GridItem1, CardContainer } from '$lib/components';
import { DropList, GridItem1, CardContainer, Paginator } from '$lib/components';
import {
Badge,
Icon,
Expand Down Expand Up @@ -146,7 +146,7 @@
}

import { formatName as formatNameHelper } from '$lib/helpers/string';
function formatName(name: string, limit: number = 19) {
function formatName(name: string, limit: number = 16) {
return formatNameHelper(name, limit, $isSmallViewport);
}
</script>
Expand All @@ -160,8 +160,14 @@
</Typography.Text>

<div class="archive-projects-margin">
<CardContainer disableEmpty={true} total={projectsToArchive.length}>
{#each projectsToArchive as project}
<Paginator
items={projectsToArchive}
limit={6}
hidePages={false}
hideFooter={projectsToArchive.length <= 6}>
{#snippet children(items)}
<CardContainer disableEmpty={true} total={projectsToArchive.length}>
{#each items as project}
{@const platforms = filterPlatforms(
project.platforms.map((platform) => getPlatformInfo(platform.type))
)}
Expand Down Expand Up @@ -255,8 +261,10 @@
{/if}
</svelte:fragment>
</GridItem1>
{/each}
</CardContainer>
{/each}
</CardContainer>
{/snippet}
</Paginator>
</div>
</Accordion>
</div>
Expand Down
13 changes: 9 additions & 4 deletions src/routes/(console)/organization-[organization]/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,14 @@
return project.status !== 'active';
}

$: projectsToArchive = data.projects.projects.filter((project) => project.status !== 'active');
$: projectsToArchive = (data.archivedProjectsPage ?? data.projects.projects).filter(
(project) => project.status !== 'active'
);

$: activeProjects = data.projects.projects.filter((project) => project.status === 'active');
$: activeProjects = (data.activeProjectsPage ?? data.projects.projects).filter(
(project) => project.status === 'active'
);
$: activeTotalOverall = data?.activeTotalOverall ?? data?.organization?.projects?.length ?? data?.projects?.total ?? 0;
function clearSearch() {
searchQuery?.clearInput();
}
Expand Down Expand Up @@ -157,7 +162,7 @@
{#if activeProjects.length > 0}
<CardContainer
disableEmpty={!$canWriteProjects}
total={data.projects.total}
total={activeTotalOverall}
offset={data.offset}
on:click={handleCreateProject}>
{#each activeProjects as project}
Expand Down Expand Up @@ -242,7 +247,7 @@
name="Projects"
limit={data.limit}
offset={data.offset}
total={data.projects.total} />
total={activeTotalOverall} />

<!-- Archived Projects Section -->
<ArchiveProject
Expand Down
31 changes: 29 additions & 2 deletions src/routes/(console)/organization-[organization]/+page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,42 @@ export const load: PageLoad = async ({ params, url, route, depends, parent }) =>
search: search || undefined
});

let allProjects: typeof projects.projects = [];
let fetchedCount = 0;
const total = projects.total;

while (fetchedCount < total) {
const next = await sdk.forConsole.projects.list({
queries: [
Query.offset(fetchedCount),
Query.equal('teamId', params.organization),
Query.limit(limit),
Query.orderDesc('')
],
search: search || undefined
});
allProjects = allProjects.concat(next.projects);
fetchedCount += next.projects.length;
if (next.projects.length === 0) break;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Seed aggregation with the first response and avoid redundant page-0 fetch

You drop the first call’s results and refetch from offset 0, doubling cost and latency. Seed allProjects with the initial page and continue from there.

-    let allProjects: typeof projects.projects = [];
-    let fetchedCount = 0;
+    let allProjects: typeof projects.projects = projects.projects.slice();
+    let fetchedCount = allProjects.length;
     const total = projects.total;
 
-    while (fetchedCount < total) {
+    while (fetchedCount < total) {
         const next = await sdk.forConsole.projects.list({
             queries: [
-                Query.offset(fetchedCount),
+                Query.offset(fetchedCount),
                 Query.equal('teamId', params.organization),
-                Query.limit(limit),
+                Query.limit(limit),
                 Query.orderDesc('')
             ],
             search: search || undefined
         });
         allProjects = allProjects.concat(next.projects);
         fetchedCount += next.projects.length;
         if (next.projects.length === 0) break;
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let allProjects: typeof projects.projects = [];
let fetchedCount = 0;
const total = projects.total;
while (fetchedCount < total) {
const next = await sdk.forConsole.projects.list({
queries: [
Query.offset(fetchedCount),
Query.equal('teamId', params.organization),
Query.limit(limit),
Query.orderDesc('')
],
search: search || undefined
});
allProjects = allProjects.concat(next.projects);
fetchedCount += next.projects.length;
if (next.projects.length === 0) break;
}
// Seed with the initial page of projects instead of starting empty
let allProjects: typeof projects.projects = projects.projects.slice();
let fetchedCount = allProjects.length;
const total = projects.total;
while (fetchedCount < total) {
const next = await sdk.forConsole.projects.list({
queries: [
Query.offset(fetchedCount),
Query.equal('teamId', params.organization),
Query.limit(limit),
Query.orderDesc('')
],
search: search || undefined
});
allProjects = allProjects.concat(next.projects);
fetchedCount += next.projects.length;
if (next.projects.length === 0) break;
}
🤖 Prompt for AI Agents
In src/routes/(console)/organization-[organization]/+page.ts around lines 31 to
48, the code currently performs an initial projects fetch but then starts the
loop that refetches from offset 0, doubling cost and latency; instead, perform
the first sdk.forConsole.projects.list call once, initialize allProjects with
that response and set fetchedCount to that response.projects.length, then enter
a loop that requests subsequent pages starting at the current fetchedCount
(using Query.offset(fetchedCount)) until fetchedCount >= total or a page returns
zero items; this removes the redundant page-0 fetch while preserving the same
paging logic.


const allActiveProjects = allProjects.filter((p) => p.status === 'active');
const allArchivedProjects = allProjects.filter((p) => p.status !== 'active');

const activeProjectsForPage = allActiveProjects.slice(offset, offset + limit);

// set `default` if no region!
for (const project of projects.projects) {
for (const project of allProjects) {
project.region ??= 'default';
}

return {
offset,
limit,
projects,
projects: { ...projects, projects: allProjects, total: allActiveProjects.length },
activeProjectsPage: activeProjectsForPage,
archivedProjectsPage: allArchivedProjects,
activeTotalOverall: allActiveProjects.length,
search
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Don’t mutate the projects contract; return aggregates separately

Overwriting projects.projects with all items and projects.total with “active total” breaks consumers expecting API semantics. Keep projects intact and expose new top-level fields for UI.

-        projects: { ...projects, projects: allProjects, total: allActiveProjects.length },
-        activeProjectsPage: activeProjectsForPage,
-        archivedProjectsPage: allArchivedProjects,
-        activeTotalOverall: allActiveProjects.length,
+        projects, // preserve API contract for stores and other consumers
+        activeProjectsPage: activeProjectsForPage,
+        archivedProjectsPage: allArchivedProjects,
+        activeTotalOverall: allActiveProjects.length,
+        // Optionally expose allProjects if needed elsewhere:
+        // allProjects,

🏁 Script executed:

#!/bin/bash
# Audit for consumers that assume `projects.total` is "all results" (not just active).
rg -nP --type=ts --type=svelte -C2 '\bprojects\.total\b'

Length of output: 89


🏁 Script executed:

#!/bin/bash
# Audit for consumers that assume `projects.total` remains the full count
rg -nP -g '*.ts' -g '*.svelte' -C2 '\bprojects\.total\b'

Length of output: 4397


Preserve projects API contract and expose aggregates separately
Overriding projects.projects and projects.total with active-only values breaks UI components that rely on the full project count (plan checks, creation modals, settings pages). Undo the mutation and introduce new top-level fields for the aggregates, for example:

-        projects: { ...projects, projects: allProjects, total: allActiveProjects.length },
+        projects, // preserve API contract
         activeProjectsPage: activeProjectsForPage,
         archivedProjectsPage: allArchivedProjects,
+        activeTotalOverall: allActiveProjects.length,
+        allProjects, // full list if needed

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/routes/(console)/organization-[organization]/+page.ts around lines 63 to
67, the code is mutating the existing projects object by replacing
projects.projects and projects.total with active-only values which breaks
consumers expecting the full projects API; revert that mutation so the original
projects object remains intact and add new top-level fields (e.g.,
activeProjectsPage and activeProjectsTotal or activeProjectsAggregate) to expose
active-only lists and counts, update any callers that need the active-only
values to use these new fields, and ensure the returned payload preserves the
original projects structure while exposing the aggregates separately.

};
};
Loading