mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-12-13 13:55:23 -05:00
fix: Improved bulk deletion by reducing refreshs (#6634)
Co-authored-by: David Schinkel <david@zollsoft.de> Co-authored-by: Hayden <64056131+hay-kot@users.noreply.github.com>
This commit is contained in:
58
frontend/composables/partials/use-actions-factory.test.ts
Normal file
58
frontend/composables/partials/use-actions-factory.test.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import { describe, expect, test, vi } from "vitest";
|
||||
import { ref } from "vue";
|
||||
import { useStoreActions } from "./use-actions-factory";
|
||||
import type { BaseCRUDAPI } from "~/lib/api/base/base-clients";
|
||||
|
||||
describe("useStoreActions", () => {
|
||||
const mockApi = {
|
||||
getAll: vi.fn(),
|
||||
createOne: vi.fn(),
|
||||
updateOne: vi.fn(),
|
||||
deleteOne: vi.fn(),
|
||||
} as unknown as BaseCRUDAPI<unknown, unknown, unknown>;
|
||||
|
||||
const mockStore = ref([]);
|
||||
const mockLoading = ref(false);
|
||||
|
||||
test("deleteMany calls deleteOne for each ID and refreshes once", async () => {
|
||||
const actions = useStoreActions("test-store", mockApi, mockStore, mockLoading);
|
||||
|
||||
mockApi.deleteOne = vi.fn().mockResolvedValue({ response: { data: {} } });
|
||||
mockApi.getAll = vi.fn().mockResolvedValue({ data: { items: [] } });
|
||||
|
||||
const ids = ["1", "2", "3"];
|
||||
await actions.deleteMany(ids);
|
||||
|
||||
expect(mockApi.deleteOne).toHaveBeenCalledTimes(3);
|
||||
expect(mockApi.deleteOne).toHaveBeenCalledWith("1");
|
||||
expect(mockApi.deleteOne).toHaveBeenCalledWith("2");
|
||||
expect(mockApi.deleteOne).toHaveBeenCalledWith("3");
|
||||
|
||||
expect(mockApi.getAll).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test("deleteMany handles empty array", async () => {
|
||||
const actions = useStoreActions("test-store", mockApi, mockStore, mockLoading);
|
||||
|
||||
mockApi.deleteOne = vi.fn();
|
||||
mockApi.getAll = vi.fn().mockResolvedValue({ data: { items: [] } });
|
||||
|
||||
await actions.deleteMany([]);
|
||||
|
||||
expect(mockApi.deleteOne).not.toHaveBeenCalled();
|
||||
expect(mockApi.getAll).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test("deleteMany sets loading state", async () => {
|
||||
const actions = useStoreActions("test-store", mockApi, mockStore, mockLoading);
|
||||
|
||||
mockApi.deleteOne = vi.fn().mockResolvedValue({});
|
||||
mockApi.getAll = vi.fn().mockResolvedValue({ data: { items: [] } });
|
||||
|
||||
const promise = actions.deleteMany(["1"]);
|
||||
expect(mockLoading.value).toBe(true);
|
||||
|
||||
await promise;
|
||||
expect(mockLoading.value).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -12,6 +12,7 @@ interface StoreActions<T extends BoundT> extends ReadOnlyStoreActions<T> {
|
||||
createOne(createData: T): Promise<T | null>;
|
||||
updateOne(updateData: T): Promise<T | null>;
|
||||
deleteOne(id: string | number): Promise<T | null>;
|
||||
deleteMany(ids: (string | number)[]): Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -165,11 +166,23 @@ export function useStoreActions<T extends BoundT>(
|
||||
return response?.data || null;
|
||||
}
|
||||
|
||||
async function deleteMany(ids: (string | number)[]) {
|
||||
loading.value = true;
|
||||
for (const id of ids) {
|
||||
await api.deleteOne(id);
|
||||
}
|
||||
if (allRef?.value) {
|
||||
await refresh();
|
||||
}
|
||||
loading.value = false;
|
||||
}
|
||||
|
||||
return {
|
||||
getAll,
|
||||
refresh,
|
||||
createOne,
|
||||
updateOne,
|
||||
deleteOne,
|
||||
deleteMany,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -209,12 +209,8 @@ export default defineNuxtComponent({
|
||||
}
|
||||
|
||||
async function deleteSelected() {
|
||||
for (const item of bulkDeleteTarget.value) {
|
||||
if (!item.id) {
|
||||
continue;
|
||||
}
|
||||
await categoryStore.actions.deleteOne(item.id);
|
||||
}
|
||||
const ids = bulkDeleteTarget.value.map(item => item.id).filter(id => !!id);
|
||||
await categoryStore.actions.deleteMany(ids);
|
||||
bulkDeleteTarget.value = [];
|
||||
}
|
||||
|
||||
|
||||
@@ -528,9 +528,8 @@ export default defineNuxtComponent({
|
||||
}
|
||||
|
||||
async function deleteSelected() {
|
||||
for (const item of bulkDeleteTarget.value) {
|
||||
await foodStore.actions.deleteOne(item.id);
|
||||
}
|
||||
const ids = bulkDeleteTarget.value.map(item => item.id);
|
||||
await foodStore.actions.deleteMany(ids);
|
||||
bulkDeleteTarget.value = [];
|
||||
}
|
||||
|
||||
|
||||
@@ -261,9 +261,8 @@ export default defineNuxtComponent({
|
||||
}
|
||||
|
||||
async function deleteSelected() {
|
||||
for (const item of bulkDeleteTarget.value) {
|
||||
await labelStore.actions.deleteOne(item.id);
|
||||
}
|
||||
const ids = bulkDeleteTarget.value.map(item => item.id);
|
||||
await labelStore.actions.deleteMany(ids);
|
||||
bulkDeleteTarget.value = [];
|
||||
}
|
||||
|
||||
|
||||
@@ -249,9 +249,8 @@ export default defineNuxtComponent({
|
||||
}
|
||||
|
||||
async function deleteSelected() {
|
||||
for (const item of bulkDeleteTarget.value) {
|
||||
await actionStore.actions.deleteOne(item.id);
|
||||
}
|
||||
const ids = bulkDeleteTarget.value.map(item => item.id);
|
||||
await actionStore.actions.deleteMany(ids);
|
||||
bulkDeleteTarget.value = [];
|
||||
}
|
||||
|
||||
|
||||
@@ -211,12 +211,8 @@ export default defineNuxtComponent({
|
||||
}
|
||||
|
||||
async function deleteSelected() {
|
||||
for (const item of bulkDeleteTarget.value) {
|
||||
if (!item.id) {
|
||||
continue;
|
||||
}
|
||||
await tagStore.actions.deleteOne(item.id);
|
||||
}
|
||||
const ids = bulkDeleteTarget.value.map(item => item.id).filter(id => !!id);
|
||||
await tagStore.actions.deleteMany(ids);
|
||||
bulkDeleteTarget.value = [];
|
||||
}
|
||||
|
||||
|
||||
@@ -263,9 +263,8 @@ export default defineNuxtComponent({
|
||||
}
|
||||
|
||||
async function deleteSelected() {
|
||||
for (const item of bulkDeleteTarget.value) {
|
||||
await toolStore.actions.deleteOne(item.id);
|
||||
}
|
||||
const ids = bulkDeleteTarget.value.map(item => item.id);
|
||||
await toolStore.actions.deleteMany(ids);
|
||||
bulkDeleteTarget.value = [];
|
||||
}
|
||||
|
||||
|
||||
@@ -465,9 +465,8 @@ export default defineNuxtComponent({
|
||||
}
|
||||
|
||||
async function deleteSelected() {
|
||||
for (const item of bulkDeleteTarget.value) {
|
||||
await unitActions.deleteOne(item.id);
|
||||
}
|
||||
const ids = bulkDeleteTarget.value.map(item => item.id);
|
||||
await unitActions.deleteMany(ids);
|
||||
bulkDeleteTarget.value = [];
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user