From 9f2ac70549e96510c10aad3f9377b8c9e86c77d0 Mon Sep 17 00:00:00 2001 From: Gregor Vostrak Date: Tue, 8 Oct 2024 00:25:33 +0200 Subject: [PATCH] add mass delete time entries frontend, closes ST-450 --- resources/js/Pages/Time.vue | 4 +- .../packages/api/src/openapi.json.client.ts | 48 +++++++++++++++++++ .../src/TimeEntry/TimeEntryAggregateRow.vue | 2 +- resources/js/utils/useTimeEntries.ts | 22 +++++++++ 4 files changed, 72 insertions(+), 4 deletions(-) diff --git a/resources/js/Pages/Time.vue b/resources/js/Pages/Time.vue index 70d0bdbc..39033c75 100644 --- a/resources/js/Pages/Time.vue +++ b/resources/js/Pages/Time.vue @@ -57,9 +57,7 @@ async function startTimeEntry( } function deleteTimeEntries(timeEntries: TimeEntry[]) { - timeEntries.forEach((entry) => { - useTimeEntriesStore().deleteTimeEntry(entry.id); - }); + useTimeEntriesStore().deleteTimeEntries(timeEntries); fetchTimeEntries(); } diff --git a/resources/js/packages/api/src/openapi.json.client.ts b/resources/js/packages/api/src/openapi.json.client.ts index a06131c7..7e47cd66 100644 --- a/resources/js/packages/api/src/openapi.json.client.ts +++ b/resources/js/packages/api/src/openapi.json.client.ts @@ -2325,6 +2325,54 @@ Users with the permission `time-entries:view:own` can only use this en }, ], }, + { + method: 'delete', + path: '/v1/organizations/:organization/time-entries', + alias: 'deleteTimeEntries', + requestFormat: 'json', + parameters: [ + { + name: 'organization', + type: 'Path', + schema: z.string(), + }, + { + name: 'ids', + type: 'Query', + schema: z.array(z.string().uuid()), + }, + ], + response: z + .object({ success: z.string(), error: z.string() }) + .passthrough(), + errors: [ + { + status: 401, + description: `Unauthenticated`, + schema: z.object({ message: z.string() }).passthrough(), + }, + { + status: 403, + description: `Authorization error`, + schema: z.object({ message: z.string() }).passthrough(), + }, + { + status: 404, + description: `Not found`, + schema: z.object({ message: z.string() }).passthrough(), + }, + { + status: 422, + description: `Validation error`, + schema: z + .object({ + message: z.string(), + errors: z.record(z.array(z.string())), + }) + .passthrough(), + }, + ], + }, { method: 'put', path: '/v1/organizations/:organization/time-entries/:timeEntry', diff --git a/resources/js/packages/ui/src/TimeEntry/TimeEntryAggregateRow.vue b/resources/js/packages/ui/src/TimeEntry/TimeEntryAggregateRow.vue index 5b61ef16..a81777ad 100644 --- a/resources/js/packages/ui/src/TimeEntry/TimeEntryAggregateRow.vue +++ b/resources/js/packages/ui/src/TimeEntry/TimeEntryAggregateRow.vue @@ -142,7 +142,7 @@ const expanded = ref(false); class="opacity-20 hidden sm:flex group-hover:opacity-100"> diff --git a/resources/js/utils/useTimeEntries.ts b/resources/js/utils/useTimeEntries.ts index 43209eab..fbe92fe7 100644 --- a/resources/js/utils/useTimeEntries.ts +++ b/resources/js/utils/useTimeEntries.ts @@ -168,6 +168,27 @@ export const useTimeEntriesStore = defineStore('timeEntries', () => { } } + async function deleteTimeEntries(timeEntries: TimeEntry[]) { + const organizationId = getCurrentOrganizationId(); + const timeEntryIds = timeEntries.map((entry) => entry.id); + if (organizationId) { + await handleApiRequestNotifications( + () => + api.deleteTimeEntries(undefined, { + queries: { + ids: timeEntryIds, + }, + params: { + organization: organizationId, + }, + }), + 'Time entries deleted successfully', + 'Failed to delete time entries' + ); + await fetchTimeEntries(); + } + } + return { timeEntries, fetchTimeEntries, @@ -177,5 +198,6 @@ export const useTimeEntriesStore = defineStore('timeEntries', () => { fetchMoreTimeEntries, allTimeEntriesLoaded, updateTimeEntries, + deleteTimeEntries, }; });