From 79532e4ac55921169fba23284c1cdad3e1ffb09c Mon Sep 17 00:00:00 2001 From: Gianluca Zuccarelli Date: Fri, 20 Dec 2024 13:58:33 +0000 Subject: [PATCH] store/cockpitApi: add delete endpoint --- src/store/cockpitApi.ts | 37 +++++++++++++++++++++--- src/store/enhancedCockpitApi.ts | 42 ++++++++++++++++++++++++++++ src/store/enhancedImageBuilderApi.ts | 2 +- src/test/mocks/cockpit/index.ts | 5 ++++ 4 files changed, 81 insertions(+), 5 deletions(-) create mode 100644 src/store/enhancedCockpitApi.ts diff --git a/src/store/cockpitApi.ts b/src/store/cockpitApi.ts index b326918a..3e4f70a1 100644 --- a/src/store/cockpitApi.ts +++ b/src/store/cockpitApi.ts @@ -1,3 +1,5 @@ +import path from 'path'; + // Note: for the on-prem version of the frontend we have configured // this so that we check `node_modules` and `pkg/lib` for packages. // To get around this for the hosted service, we have configured @@ -14,6 +16,8 @@ import { GetArchitecturesApiArg, GetBlueprintsApiArg, GetBlueprintsApiResponse, + DeleteBlueprintApiResponse, + DeleteBlueprintApiArg, BlueprintItem, } from './imageBuilderApi'; @@ -45,18 +49,18 @@ export const cockpitApi = emptyCockpitApi.injectEndpoints({ >({ queryFn: async () => { try { - const path = await getBlueprintsPath(); + const blueprintsDir = await getBlueprintsPath(); // we probably don't need any more information other // than the entries from the directory - const info = await fsinfo(path, ['entries'], { + const info = await fsinfo(blueprintsDir, ['entries'], { superuser: 'try', }); const entries = Object.entries(info?.entries || {}); const blueprints: BlueprintItem[] = await Promise.all( entries.map(async ([filename]) => { - const file = cockpit.file(`${path}/${filename}`); + const file = cockpit.file(path.join(blueprintsDir, filename)); const contents = await file.read(); const parsed = toml.parse(contents); @@ -89,8 +93,33 @@ export const cockpitApi = emptyCockpitApi.injectEndpoints({ } }, }), + deleteBlueprint: builder.mutation< + DeleteBlueprintApiResponse, + DeleteBlueprintApiArg + >({ + queryFn: async ({ id: filename }) => { + try { + const blueprintsDir = await getBlueprintsPath(); + const filepath = path.join(blueprintsDir, filename); + + await cockpit.spawn(['rm', filepath], { + superuser: 'try', + }); + + return { + data: {}, + }; + } catch (error) { + return { error }; + } + }, + }), }; }, }); -export const { useGetBlueprintsQuery, useGetArchitecturesQuery } = cockpitApi; +export const { + useGetBlueprintsQuery, + useDeleteBlueprintMutation, + useGetArchitecturesQuery, +} = cockpitApi; diff --git a/src/store/enhancedCockpitApi.ts b/src/store/enhancedCockpitApi.ts new file mode 100644 index 00000000..044e6cb1 --- /dev/null +++ b/src/store/enhancedCockpitApi.ts @@ -0,0 +1,42 @@ +import { addNotification } from '@redhat-cloud-services/frontend-components-notifications/redux'; + +import { cockpitApi } from './cockpitApi'; +import { errorMessage } from './enhancedImageBuilderApi'; + +const enhancedApi = cockpitApi.enhanceEndpoints({ + addTagTypes: ['Blueprints'], + endpoints: { + getBlueprints: { + providesTags: () => { + return [{ type: 'Blueprints' }]; + }, + }, + deleteBlueprint: { + invalidatesTags: [{ type: 'Blueprints' }], + onQueryStarted: async (_, { dispatch, queryFulfilled }) => { + queryFulfilled + .then(() => { + dispatch( + addNotification({ + variant: 'success', + title: 'Blueprint was deleted', + }) + ); + }) + .catch((err) => { + dispatch( + addNotification({ + variant: 'danger', + title: 'Blueprint could not be deleted', + description: `Status code ${err.error.status}: ${errorMessage( + err + )}`, + }) + ); + }); + }, + }, + }, +}); + +export { enhancedApi as cockpitApi }; diff --git a/src/store/enhancedImageBuilderApi.ts b/src/store/enhancedImageBuilderApi.ts index ffc9367b..bbb34e03 100644 --- a/src/store/enhancedImageBuilderApi.ts +++ b/src/store/enhancedImageBuilderApi.ts @@ -3,7 +3,7 @@ import { addNotification } from '@redhat-cloud-services/frontend-components-noti import { imageBuilderApi } from './imageBuilderApi'; /* eslint-disable @typescript-eslint/no-explicit-any */ -const errorMessage = (err: any) => { +export const errorMessage = (err: any) => { let msg = err.error.statusText; if ( err.error.data?.errors && diff --git a/src/test/mocks/cockpit/index.ts b/src/test/mocks/cockpit/index.ts index fa6b414a..01ade249 100644 --- a/src/test/mocks/cockpit/index.ts +++ b/src/test/mocks/cockpit/index.ts @@ -22,4 +22,9 @@ export default { close: () => {}, }; }, + spawn: (args: string[], attributes: object): Promise => { + return new Promise((resolve) => { + resolve(''); + }); + }, };