Skip to content
Open
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
19 changes: 19 additions & 0 deletions apps/web/src/TaskDashboard.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,25 @@ describe("task dashboard with paginated API",()=>{
expect(wrapper.text()).toContain("Tarefa 27");
expect(listRequests[1]).toContain("page=2");
});
it("ignores stale load-more results when filters change during pagination",async()=>{
items=Array.from({length:28},(_,i)=>makeTask("task-"+i,"Tarefa "+i));
const wrapper=await render();
let resolvePage!: (value:Response)=>void;
const pending=new Promise<Response>(resolve=>{resolvePage=resolve;});
const original=fetchMock.getMockImplementation() as (url:string,options?:RequestInit)=>Promise<Response>;
fetchMock.mockImplementation((url:string,options?:RequestInit)=>{
if(url.includes("page=2")) return pending;
return original(url,options);
});
await wrapper.find(".task-pagination button").trigger("click");
await wrapper.find("#status-filter").setValue("COMPLETED");
await flushPromises();
expect(wrapper.findAll(".task-card")).toHaveLength(0);
resolvePage(response({data:items.slice(25),pagination:{page:2,limit:25,total:28,totalPages:2}}));
await flushPromises();
expect(wrapper.findAll(".task-card")).toHaveLength(0);
expect(wrapper.find(".task-pagination").exists()).toBe(false);
});
it("applies both filters server-side and preserves global counts",async()=>{
items=[makeTask("task-1","Alta em andamento",{status:"IN_PROGRESS",priority:"HIGH"}),makeTask("task-2","Normal em andamento",{status:"IN_PROGRESS"}),makeTask("task-3","Alta concluída",{status:"COMPLETED",priority:"HIGH"})];
const wrapper=await render();
Expand Down
11 changes: 8 additions & 3 deletions apps/web/src/TaskDashboard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const pageSize = 25;
const filteredTotal = ref(0);
const loadingMore = ref(false);
let loadGeneration = 0;
let loadMoreGeneration = 0;
const loading = ref(true);
const saving = ref(false);
const errorMessage = ref("");
Expand Down Expand Up @@ -122,12 +123,15 @@ async function request<T>(url: string, options?: RequestInit): Promise<T> {

async function loadTasks() {
const generation = ++loadGeneration;
++loadMoreGeneration;
loadingMore.value = false;
loading.value = true;
errorMessage.value = "";
retryLoadAvailable.value = false;
page.value = 1;
tasks.value = [];
summary.value = null;
filteredTotal.value = 0;
try {
const query = new URLSearchParams({ page: "1", limit: String(pageSize) });
if (statusFilter.value !== "ALL") query.set("status", statusFilter.value);
Expand Down Expand Up @@ -158,6 +162,7 @@ async function loadTasks() {
async function loadMoreTasks() {
if (loading.value || loadingMore.value || tasks.value.length >= filteredTotal.value) return;
const generation = loadGeneration;
const moreGeneration = ++loadMoreGeneration;
loadingMore.value = true;
errorMessage.value = "";
try {
Expand All @@ -168,15 +173,15 @@ async function loadMoreTasks() {
if (searchTerm.value) query.set("search", searchTerm.value);
query.set("sort", sortOrder.value);
const result = await request<TaskPage>(taskUrl() + "?" + query.toString());
if (generation !== loadGeneration) return;
if (generation !== loadGeneration || moreGeneration !== loadMoreGeneration) return;
const seen = new Set(tasks.value.map(task => task.id));
tasks.value = [...tasks.value, ...result.data.filter(task => !seen.has(task.id))];
page.value = nextPage;
filteredTotal.value = result.pagination.total;
} catch (error) {
if (generation === loadGeneration) errorMessage.value = error instanceof Error ? error.message : "Falha ao carregar mais tarefas.";
if (generation === loadGeneration && moreGeneration === loadMoreGeneration) errorMessage.value = error instanceof Error ? error.message : "Falha ao carregar mais tarefas.";
} finally {
loadingMore.value = false;
if (moreGeneration === loadMoreGeneration) loadingMore.value = false;
}
}

Expand Down
Loading