From 3113089f96b278bd5598278b29cce815dd2e16b9 Mon Sep 17 00:00:00 2001 From: Vladyslav Palyvoda Date: Thu, 21 Nov 2024 17:18:08 +0200 Subject: [PATCH] fix: Refactor notifications (#498) --- .../useResourceCRUDMutation/index.test.tsx | 8 +- src/hooks/useResourceCRUDMutation/index.ts | 101 -------- src/hooks/useResourceCRUDMutation/index.tsx | 216 ++++++++++++++++++ .../index.tsx | 77 +++++-- .../hooks/useArgoApplicationCRUD.ts | 48 ++-- .../hooks/useCreateBuildPipelineRun.ts | 16 +- .../hooks/useCreateCleanPipelineRun.ts | 16 +- .../hooks/useCreateDeployPipelineRun.ts | 16 +- src/k8s/groups/default/ResourceQuota/types.ts | 1 - .../configuration/pages/codemie/view.tsx | 32 ++- .../hooks/useConfigurationHandlers.ts | 8 +- src/widgets/PipelineRunActionsMenu/index.tsx | 158 +++++++------ .../components/DeleteDialog/index.tsx | 5 +- src/widgets/ResourceQuotas/types.ts | 1 - 14 files changed, 468 insertions(+), 235 deletions(-) delete mode 100644 src/hooks/useResourceCRUDMutation/index.ts create mode 100644 src/hooks/useResourceCRUDMutation/index.tsx diff --git a/src/hooks/useResourceCRUDMutation/index.test.tsx b/src/hooks/useResourceCRUDMutation/index.test.tsx index 3bfba373e..0927cf115 100644 --- a/src/hooks/useResourceCRUDMutation/index.test.tsx +++ b/src/hooks/useResourceCRUDMutation/index.test.tsx @@ -61,11 +61,9 @@ describe('testing useResourceCRUDMutation hook', () => { expect(result.current.data).toEqual(mutationDataMock); expect(result.current.variables).toEqual(mutationDataMock); expect(mockShowBeforeRequestMessage).toHaveBeenCalledWith(CRUD_TYPES.CREATE, { - customMessage: undefined, entityName: `${result.current.variables.kind} ${result.current.variables.metadata.name}`, }); expect(mockShowRequestSuccessMessage).toHaveBeenCalledWith(CRUD_TYPES.CREATE, { - customMessage: undefined, entityName: `${result.current.variables.kind} ${result.current.variables.metadata.name}`, }); expect(mockShowRequestErrorMessage).not.toHaveBeenCalled(); @@ -90,16 +88,16 @@ describe('testing useResourceCRUDMutation hook', () => { expect(result.current.isError).toBe(true); expect(result.current.error).toEqual({ error: 'error' }); expect(result.current.variables).toEqual(mutationDataMock); + expect(mockShowBeforeRequestMessage).toHaveBeenCalledWith(CRUD_TYPES.EDIT, { - customMessage: undefined, entityName: `${result.current.variables.kind} ${result.current.variables.metadata.name}`, }); + expect(mockShowRequestSuccessMessage).not.toHaveBeenCalled(); + expect(mockShowRequestErrorMessage).toHaveBeenCalledWith(CRUD_TYPES.EDIT, { - customMessage: undefined, entityName: `${result.current.variables.kind} ${result.current.variables.metadata.name}`, }); - expect(mockShowRequestErrorDetailedMessage).toHaveBeenCalledWith(result.current.error); }); }); }); diff --git a/src/hooks/useResourceCRUDMutation/index.ts b/src/hooks/useResourceCRUDMutation/index.ts deleted file mode 100644 index 07019fb70..000000000 --- a/src/hooks/useResourceCRUDMutation/index.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { KubeObjectIface } from '@kinvolk/headlamp-plugin/lib/lib/k8s/cluster'; -import { useMutation, UseMutationResult } from 'react-query'; -import { CRUD_TYPES } from '../../constants/crudTypes'; -import { EDPKubeObjectInterface } from '../../types/k8s'; -import { getDefaultNamespace } from '../../utils/getDefaultNamespace'; -import { useRequestStatusMessages } from '../useResourceRequestStatusMessages'; - -type UseResourceCRUDMutationReturnType< - KubeObjectData, - Mode extends CRUD_TYPES -> = Mode extends CRUD_TYPES.DELETE ? void : KubeObjectData; - -type CustomMessages = { - onMutate?: string; - onError?: string; - onSuccess?: string; -}; - -interface Options { - customMessages?: CustomMessages; - showMessages?: boolean; -} - -export const useResourceCRUDMutation = < - KubeObjectData extends EDPKubeObjectInterface, - Mode extends CRUD_TYPES ->( - mutationKey: string, - kubeObject: KubeObjectIface, - mode: Mode, - options?: Options -): UseMutationResult< - UseResourceCRUDMutationReturnType, - Error, - KubeObjectData -> => { - const showMessages = options?.showMessages ?? true; - - const { - showBeforeRequestMessage, - showRequestErrorMessage, - showRequestSuccessMessage, - showRequestErrorDetailedMessage, - } = useRequestStatusMessages(); - - const namespace = getDefaultNamespace(); - - return useMutation< - UseResourceCRUDMutationReturnType, - Error, - KubeObjectData - >( - mutationKey, - (data) => { - let dataCopy = { ...data }; - - if (!data.metadata?.namespace) { - dataCopy = { - ...dataCopy, - metadata: { - ...dataCopy.metadata, - namespace, - }, - }; - } - - switch (mode) { - case CRUD_TYPES.CREATE: - return kubeObject.apiEndpoint.post(dataCopy); - case CRUD_TYPES.EDIT: - return kubeObject.apiEndpoint.put(dataCopy); - case CRUD_TYPES.DELETE: - return kubeObject.apiEndpoint.delete(dataCopy.metadata.namespace, dataCopy.metadata.name); - } - }, - { - onMutate: (variables) => - showMessages && - showBeforeRequestMessage(mode, { - customMessage: options?.customMessages?.onMutate, - entityName: `${variables.kind} ${variables.metadata.name}`, - }), - onSuccess: (data, variables) => { - showMessages && - showRequestSuccessMessage(mode, { - customMessage: options?.customMessages?.onSuccess, - entityName: `${variables.kind} ${variables.metadata.name}`, - }); - }, - onError: (error, variables) => { - showMessages && - showRequestErrorMessage(mode, { - customMessage: options?.customMessages?.onError, - entityName: `${variables.kind} ${variables.metadata.name}`, - }); - showMessages && showRequestErrorDetailedMessage(error); - console.error(error); - }, - } - ); -}; diff --git a/src/hooks/useResourceCRUDMutation/index.tsx b/src/hooks/useResourceCRUDMutation/index.tsx new file mode 100644 index 000000000..f84648066 --- /dev/null +++ b/src/hooks/useResourceCRUDMutation/index.tsx @@ -0,0 +1,216 @@ +import { KubeObjectIface } from '@kinvolk/headlamp-plugin/lib/lib/k8s/cluster'; +import { OptionsObject } from 'notistack'; +import React from 'react'; +import { useMutation, UseMutationResult } from 'react-query'; +import { Snackbar } from '../../components/Snackbar'; +import { CRUD_TYPES } from '../../constants/crudTypes'; +import { EDPKubeObjectInterface } from '../../types/k8s'; +import { getDefaultNamespace } from '../../utils/getDefaultNamespace'; +import { useRequestStatusMessages } from '../useResourceRequestStatusMessages'; + +type UseResourceCRUDMutationReturnType< + KubeObjectData, + Mode extends CRUD_TYPES +> = Mode extends CRUD_TYPES.DELETE ? void : KubeObjectData; + +interface Message { + message: string; + options?: OptionsObject; +} + +type CustomMessages = { + onMutate?: Message; + onError?: Message; + onSuccess?: Message; +}; + +interface Options { + createCustomMessages?: (item: KubeObjectData) => CustomMessages; + showMessages?: boolean; +} + +export const useResourceCRUDMutation = < + KubeObjectData extends EDPKubeObjectInterface, + Mode extends CRUD_TYPES +>( + mutationKey: string, + kubeObject: KubeObjectIface, + mode: Mode, + options?: Options +): UseMutationResult< + UseResourceCRUDMutationReturnType, + Error, + KubeObjectData +> => { + const showMessages = options?.showMessages ?? true; + + const { + showBeforeRequestMessage, + showRequestErrorMessage, + showRequestSuccessMessage, + showRequestErrorDetailedMessage, + closeSnackbar, + } = useRequestStatusMessages(); + + const namespace = getDefaultNamespace(); + + return useMutation< + UseResourceCRUDMutationReturnType, + Error, + KubeObjectData + >( + mutationKey, + (data) => { + let dataCopy = { ...data }; + + if (!data.metadata?.namespace) { + dataCopy = { + ...dataCopy, + metadata: { + ...dataCopy.metadata, + namespace, + }, + }; + } + + switch (mode) { + case CRUD_TYPES.CREATE: + return kubeObject.apiEndpoint.post(dataCopy); + case CRUD_TYPES.EDIT: + return kubeObject.apiEndpoint.put(dataCopy); + case CRUD_TYPES.DELETE: + return kubeObject.apiEndpoint.delete(dataCopy.metadata.namespace, dataCopy.metadata.name); + } + }, + { + onMutate: (variables) => { + if (!showMessages) { + return; + } + + if (!options?.createCustomMessages) { + showBeforeRequestMessage(mode, { + entityName: `${variables.kind} ${variables.metadata.name}`, + }); + return; + } + + const defaultOptions = { + autoHideDuration: 2000, + anchorOrigin: { + vertical: 'bottom', + horizontal: 'left', + }, + variant: 'info', + content: (key, message) => ( + closeSnackbar(key)} + variant="info" + /> + ), + } as const; + + const customMessage = options?.createCustomMessages(variables)?.onMutate; + + const mergedOptions: OptionsObject = { + ...defaultOptions, + ...(customMessage?.options || {}), + }; + + showBeforeRequestMessage(mode, { + customMessage: { + message: customMessage.message, + options: mergedOptions, + }, + }); + }, + onSuccess: (data, variables) => { + if (!showMessages) { + return; + } + + if (!options?.createCustomMessages) { + showRequestSuccessMessage(mode, { + entityName: `${variables.kind} ${variables.metadata.name}`, + }); + return; + } + + const defaultOptions = { + autoHideDuration: 5000, + anchorOrigin: { + vertical: 'bottom', + horizontal: 'left', + }, + variant: 'success', + content: (key, message) => ( + closeSnackbar(key)} + variant="success" + /> + ), + } as const; + + const customMessage = options?.createCustomMessages(variables)?.onSuccess; + + const mergedOptions: OptionsObject = { + ...defaultOptions, + ...(customMessage?.options || {}), + }; + + showRequestSuccessMessage(mode, { + customMessage: { + message: customMessage.message, + options: mergedOptions, + }, + }); + }, + onError: (error, variables) => { + if (!showMessages) { + return; + } + + if (!options?.createCustomMessages) { + showRequestErrorMessage(mode, { + entityName: `${variables.kind} ${variables.metadata.name}`, + }); + return; + } + + const defaultOptions = { + autoHideDuration: 5000, + anchorOrigin: { + vertical: 'bottom', + horizontal: 'left', + }, + variant: 'error', + content: (key, message) => ( + closeSnackbar(key)} + variant="error" + /> + ), + } as const; + + const customMessage = options?.createCustomMessages(variables)?.onError; + + const mergedOptions: OptionsObject = { + ...defaultOptions, + ...(customMessage?.options || {}), + }; + + showRequestErrorMessage(mode, { + customMessage: { + message: customMessage.message, + options: mergedOptions, + }, + }); + showRequestErrorDetailedMessage(error); + console.error(error); + }, + } + ); +}; diff --git a/src/hooks/useResourceRequestStatusMessages/index.tsx b/src/hooks/useResourceRequestStatusMessages/index.tsx index 840e9b050..0acfbb34f 100644 --- a/src/hooks/useResourceRequestStatusMessages/index.tsx +++ b/src/hooks/useResourceRequestStatusMessages/index.tsx @@ -1,11 +1,14 @@ -import { useSnackbar } from 'notistack'; +import { OptionsObject, useSnackbar } from 'notistack'; import React from 'react'; import { Snackbar } from '../../components/Snackbar'; import { CRUD_TYPES } from '../../constants/crudTypes'; interface Options { - entityName: string; - customMessage?: string; + entityName?: string; + customMessage?: { + message: string; + options?: OptionsObject; + }; } export const useRequestStatusMessages = () => { @@ -15,71 +18,108 @@ export const useRequestStatusMessages = () => { const beforeRequestMessage = (() => { switch (mode) { case CRUD_TYPES.CREATE: - return customMessage || `Applying ${entityName}`; + return `Applying ${entityName}`; case CRUD_TYPES.EDIT: - return customMessage || `Updating ${entityName}`; + return `Updating ${entityName}`; case CRUD_TYPES.DELETE: - return customMessage || `Deleting ${entityName}`; + return `Deleting ${entityName}`; } })(); - enqueueSnackbar(beforeRequestMessage, { + const defaultOptions = { autoHideDuration: 2000, anchorOrigin: { vertical: 'bottom', horizontal: 'left', }, + variant: 'info', content: (key, message) => ( closeSnackbar(key)} variant="info" /> ), - }); + } as const; + + if (customMessage) { + const { message, options = {} } = customMessage; + const mergedOptions = { + ...defaultOptions, + ...options, + }; + enqueueSnackbar(message, mergedOptions); + } else { + enqueueSnackbar(beforeRequestMessage, defaultOptions); + } }; const showRequestSuccessMessage = (mode: CRUD_TYPES, { entityName, customMessage }: Options) => { const requestSuccessMessage = (() => { switch (mode) { case CRUD_TYPES.CREATE: - return customMessage || `${entityName} has been successfully applied`; + return `${entityName} has been successfully applied`; case CRUD_TYPES.EDIT: - return customMessage || `${entityName} has been successfully updated`; + return `${entityName} has been successfully updated`; case CRUD_TYPES.DELETE: - return customMessage || `${entityName} has been successfully deleted`; + return `${entityName} has been successfully deleted`; } })(); - enqueueSnackbar(requestSuccessMessage, { + + const defaultOptions = { autoHideDuration: 5000, anchorOrigin: { vertical: 'bottom', horizontal: 'left', }, + variant: 'success', content: (key, message) => ( closeSnackbar(key)} variant="success" /> ), - }); + } as const; + + if (customMessage) { + const { message, options = {} } = customMessage; + const mergedOptions = { + ...defaultOptions, + ...options, + }; + enqueueSnackbar(message, mergedOptions); + } else { + enqueueSnackbar(requestSuccessMessage, defaultOptions); + } }; const showRequestErrorMessage = (mode: CRUD_TYPES, { entityName, customMessage }: Options) => { const requestErrorMessage = (() => { switch (mode) { case CRUD_TYPES.CREATE: - return customMessage || `Failed to apply ${entityName}`; + return `Failed to apply ${entityName}`; case CRUD_TYPES.EDIT: - return customMessage || `Failed to update ${entityName}`; + return `Failed to update ${entityName}`; case CRUD_TYPES.DELETE: - return customMessage || `Failed to delete ${entityName}`; + return `Failed to delete ${entityName}`; } })(); - enqueueSnackbar(requestErrorMessage, { + const defaultOptions = { autoHideDuration: 5000, anchorOrigin: { vertical: 'bottom', horizontal: 'left', }, + variant: 'error', content: (key, message) => ( closeSnackbar(key)} variant="error" /> ), - }); + } as const; + + if (customMessage) { + const { message, options = {} } = customMessage; + const mergedOptions = { + ...defaultOptions, + ...options, + }; + enqueueSnackbar(message, mergedOptions); + } else { + enqueueSnackbar(requestErrorMessage, defaultOptions); + } }; const showRequestErrorDetailedMessage = (error: unknown) => { @@ -100,5 +140,6 @@ export const useRequestStatusMessages = () => { showRequestSuccessMessage, showRequestErrorMessage, showRequestErrorDetailedMessage, + closeSnackbar, }; }; diff --git a/src/k8s/groups/ArgoCD/Application/hooks/useArgoApplicationCRUD.ts b/src/k8s/groups/ArgoCD/Application/hooks/useArgoApplicationCRUD.ts index 8af68e073..c1221507e 100644 --- a/src/k8s/groups/ArgoCD/Application/hooks/useArgoApplicationCRUD.ts +++ b/src/k8s/groups/ArgoCD/Application/hooks/useArgoApplicationCRUD.ts @@ -21,33 +21,51 @@ export const useArgoApplicationCRUD = () => { ApplicationKubeObjectInterface, CRUD_TYPES.CREATE >('argoApplicationCreateMutation', ApplicationKubeObject, CRUD_TYPES.CREATE, { - customMessages: { - onMutate: 'Creating application...', - onError: 'Failed to create application', - onSuccess: 'Start creating application', - }, + createCustomMessages: () => ({ + onMutate: { + message: 'Creating application...', + }, + onError: { + message: 'Failed to create application', + }, + onSuccess: { + message: 'Start creating application', + }, + }), }); const argoApplicationDeleteMutation = useResourceCRUDMutation< ApplicationKubeObjectInterface, CRUD_TYPES.DELETE >('argoApplicationDeleteMutation', ApplicationKubeObject, CRUD_TYPES.DELETE, { - customMessages: { - onMutate: 'Uninstalling application...', - onError: 'Failed to uninstall application', - onSuccess: 'Start uninstalling application', - }, + createCustomMessages: () => ({ + onMutate: { + message: 'Uninstalling application...', + }, + onError: { + message: 'Failed to uninstall application', + }, + onSuccess: { + message: 'Start uninstalling application', + }, + }), }); const argoApplicationEditMutation = useResourceCRUDMutation< ApplicationKubeObjectInterface, CRUD_TYPES.EDIT >('argoApplicationEditMutation', ApplicationKubeObject, CRUD_TYPES.EDIT, { - customMessages: { - onMutate: 'Updating application...', - onError: 'Failed to update application', - onSuccess: 'Start updating application', - }, + createCustomMessages: () => ({ + onMutate: { + message: 'Updating application...', + }, + onError: { + message: 'Failed to update application', + }, + onSuccess: { + message: 'Start updating application', + }, + }), }); const createArgoApplication = React.useCallback( diff --git a/src/k8s/groups/Tekton/PipelineRun/hooks/useCreateBuildPipelineRun.ts b/src/k8s/groups/Tekton/PipelineRun/hooks/useCreateBuildPipelineRun.ts index 47c796add..c83c596e3 100644 --- a/src/k8s/groups/Tekton/PipelineRun/hooks/useCreateBuildPipelineRun.ts +++ b/src/k8s/groups/Tekton/PipelineRun/hooks/useCreateBuildPipelineRun.ts @@ -18,11 +18,17 @@ export const useCreateBuildPipelineRun = ({ PipelineRunKubeObjectInterface, CRUD_TYPES.CREATE >('buildPipelineRunCreateMutation', PipelineRunKubeObject, CRUD_TYPES.CREATE, { - customMessages: { - onMutate: 'Creating build PipelineRun', - onError: 'Failed to create build PipelineRun', - onSuccess: 'Start building application(s)', - }, + createCustomMessages: () => ({ + onMutate: { + message: 'Creating build PipelineRun', + }, + onError: { + message: 'Failed to create build PipelineRun', + }, + onSuccess: { + message: 'Start building application(s)', + }, + }), }); const createBuildPipelineRun = React.useCallback( diff --git a/src/k8s/groups/Tekton/PipelineRun/hooks/useCreateCleanPipelineRun.ts b/src/k8s/groups/Tekton/PipelineRun/hooks/useCreateCleanPipelineRun.ts index a75389b79..2268302cc 100644 --- a/src/k8s/groups/Tekton/PipelineRun/hooks/useCreateCleanPipelineRun.ts +++ b/src/k8s/groups/Tekton/PipelineRun/hooks/useCreateCleanPipelineRun.ts @@ -22,11 +22,17 @@ export const useCreateCleanPipelineRun = ({ PipelineRunKubeObjectInterface, CRUD_TYPES.CREATE >('cleanPipelineRunCreateMutation', PipelineRunKubeObject, CRUD_TYPES.CREATE, { - customMessages: { - onMutate: 'Creating clean PipelineRun', - onError: 'Failed to create clean PipelineRun', - onSuccess: 'Start cleaning application(s)', - }, + createCustomMessages: () => ({ + onMutate: { + message: 'Creating clean PipelineRun', + }, + onError: { + message: 'Failed to create clean PipelineRun', + }, + onSuccess: { + message: 'Start cleaning application(s)', + }, + }), }); const createCleanPipelineRun = React.useCallback( diff --git a/src/k8s/groups/Tekton/PipelineRun/hooks/useCreateDeployPipelineRun.ts b/src/k8s/groups/Tekton/PipelineRun/hooks/useCreateDeployPipelineRun.ts index 8ad5e98e5..188ac2f4a 100644 --- a/src/k8s/groups/Tekton/PipelineRun/hooks/useCreateDeployPipelineRun.ts +++ b/src/k8s/groups/Tekton/PipelineRun/hooks/useCreateDeployPipelineRun.ts @@ -22,11 +22,17 @@ export const useCreateDeployPipelineRun = ({ PipelineRunKubeObjectInterface, CRUD_TYPES.CREATE >('deployPipelineRunCreateMutation', PipelineRunKubeObject, CRUD_TYPES.CREATE, { - customMessages: { - onMutate: 'Creating deploy PipelineRun', - onError: 'Failed to create deploy PipelineRun', - onSuccess: 'Start deploying application(s)', - }, + createCustomMessages: () => ({ + onMutate: { + message: 'Creating deploy PipelineRun', + }, + onError: { + message: 'Failed to create deploy PipelineRun', + }, + onSuccess: { + message: 'Start deploying application(s)', + }, + }), }); const createDeployPipelineRun = React.useCallback( diff --git a/src/k8s/groups/default/ResourceQuota/types.ts b/src/k8s/groups/default/ResourceQuota/types.ts index 9fa475589..462eba692 100644 --- a/src/k8s/groups/default/ResourceQuota/types.ts +++ b/src/k8s/groups/default/ResourceQuota/types.ts @@ -1,4 +1,3 @@ import { KubeObjectInterface } from '@kinvolk/headlamp-plugin/lib/lib/k8s/cluster'; export interface ResourceQuotaKubeObjectInterface extends KubeObjectInterface {} - diff --git a/src/pages/configuration/pages/codemie/view.tsx b/src/pages/configuration/pages/codemie/view.tsx index 903520f80..84379a158 100644 --- a/src/pages/configuration/pages/codemie/view.tsx +++ b/src/pages/configuration/pages/codemie/view.tsx @@ -178,22 +178,34 @@ export const PageView = () => { CodemieProjectSettingsKubeObjectInterface, CRUD_TYPES.EDIT >('codemieProjectSettingsEditMutation', CodemieProjectSettingsKubeObject, CRUD_TYPES.EDIT, { - customMessages: { - onMutate: 'Applying changes...', - onError: 'Failed to update settings', - onSuccess: 'Start updating settings', - }, + createCustomMessages: () => ({ + onMutate: { + message: 'Applying changes...', + }, + onError: { + message: 'Failed to update settings', + }, + onSuccess: { + message: 'Start updating settings', + }, + }), }); const codemieApplicationEditMutation = useResourceCRUDMutation< CodemieApplicationKubeObjectInterface, CRUD_TYPES.EDIT >('codemieApplicationEditMutation', CodemieApplicationKubeObject, CRUD_TYPES.EDIT, { - customMessages: { - onMutate: 'Applying changes...', - onError: 'Failed to update application', - onSuccess: 'Start updating application', - }, + createCustomMessages: () => ({ + onMutate: { + message: 'Applying changes...', + }, + onError: { + message: 'Failed to update application', + }, + onSuccess: { + message: 'Start updating application', + }, + }), }); const handleEditorSave = ( diff --git a/src/pages/stage-details/components/Applications/hooks/useConfigurationHandlers.ts b/src/pages/stage-details/components/Applications/hooks/useConfigurationHandlers.ts index 297401c4a..cb28329a4 100644 --- a/src/pages/stage-details/components/Applications/hooks/useConfigurationHandlers.ts +++ b/src/pages/stage-details/components/Applications/hooks/useConfigurationHandlers.ts @@ -233,8 +233,12 @@ export const useConfigurationHandlers = ({ const handleClean = React.useCallback(async () => { if (!cleanPipelineRunTemplate) { showRequestErrorMessage(CRUD_TYPES.CREATE, { - customMessage: 'Clean PipelineRun template is not found.', - entityName: 'Clean PipelineRun', + customMessage: { + message: 'Clean PipelineRun template is not found.', + options: { + variant: 'error', + }, + }, }); return; diff --git a/src/widgets/PipelineRunActionsMenu/index.tsx b/src/widgets/PipelineRunActionsMenu/index.tsx index b6f653eaf..bcd49ee44 100644 --- a/src/widgets/PipelineRunActionsMenu/index.tsx +++ b/src/widgets/PipelineRunActionsMenu/index.tsx @@ -7,10 +7,13 @@ import { useHistory } from 'react-router-dom'; import { ActionsMenuList } from '../../components/ActionsMenuList'; import { Snackbar } from '../../components/Snackbar'; import { ACTION_MENU_TYPES } from '../../constants/actionMenuTypes'; +import { CRUD_TYPES } from '../../constants/crudTypes'; import { RESOURCE_ACTIONS } from '../../constants/resourceActions'; +import { useResourceCRUDMutation } from '../../hooks/useResourceCRUDMutation'; import { ICONS } from '../../icons/iconify-icons-mapping'; import { PipelineRunKubeObject } from '../../k8s/groups/Tekton/PipelineRun'; import { PIPELINE_RUN_REASON } from '../../k8s/groups/Tekton/PipelineRun/constants'; +import { PipelineRunKubeObjectInterface } from '../../k8s/groups/Tekton/PipelineRun/types'; import { createRerunPipelineRunInstance } from '../../k8s/groups/Tekton/PipelineRun/utils/createRerunPipelineRunInstance'; import { routePipelineRunDetails } from '../../pages/pipeline-details/route'; import { createKubeAction } from '../../utils/actions/createKubeAction'; @@ -27,10 +30,79 @@ export const PipelineRunActionsMenu = ({ permissions, }: PipelineRunActionsMenuProps) => { const history = useHistory(); - const { enqueueSnackbar, closeSnackbar } = useSnackbar(); + const { closeSnackbar } = useSnackbar(); const status = PipelineRunKubeObject.parseStatusReason(_pipelineRun)?.toLowerCase(); + const pipelineRunCreateMutation = useResourceCRUDMutation< + PipelineRunKubeObjectInterface, + CRUD_TYPES.CREATE + >('pipelineRunCreateMutation', PipelineRunKubeObject, CRUD_TYPES.CREATE, { + createCustomMessages: (item) => ({ + onMutate: { + message: 'Creating a new PipelineRun', + }, + onError: { + message: 'Failed to create a new PipelineRun', + }, + onSuccess: { + message: 'PipelineRun created successfully', + options: { + persist: true, + content: (key, message) => ( + closeSnackbar(key)} + pushLocation={() => + history.push( + createGoToRoute({ + namespace: item.metadata.namespace || getDefaultNamespace(), + name: item.metadata.name, + }) + ) + } + variant={'success'} + /> + ), + }, + }, + }), + }); + + const pipelineRunEditMutation = useResourceCRUDMutation< + PipelineRunKubeObjectInterface, + CRUD_TYPES.EDIT + >('pipelineRunEditMutation', PipelineRunKubeObject, CRUD_TYPES.EDIT, { + createCustomMessages: () => ({ + onMutate: { + message: 'Stopping PipelineRun', + }, + onError: { + message: 'Failed to update PipelineRun', + }, + onSuccess: { + message: 'PipelineRun stopped successfully', + }, + }), + }); + + const pipelineRunDeleteMutation = useResourceCRUDMutation< + PipelineRunKubeObjectInterface, + CRUD_TYPES.DELETE + >('pipelineRunDeleteMutation', PipelineRunKubeObject, CRUD_TYPES.DELETE, { + createCustomMessages: () => ({ + onMutate: { + message: 'Deleting PipelineRun', + }, + onError: { + message: 'Failed to delete PipelineRun', + }, + onSuccess: { + message: 'PipelineRun deleted successfully', + }, + }), + }); + const isInProgress = status === PIPELINE_RUN_REASON.STARTED || status === PIPELINE_RUN_REASON.RUNNING; @@ -64,30 +136,7 @@ export const PipelineRunActionsMenu = ({ handleCloseResourceActionListMenu(); } - PipelineRunKubeObject.apiEndpoint.post(item); - - enqueueSnackbar('The PipelineRun is successfully run.', { - persist: true, - anchorOrigin: { - vertical: 'bottom', - horizontal: 'left', - }, - content: (key, message) => ( - closeSnackbar(key)} - pushLocation={() => - history.push( - createGoToRoute({ - namespace: item.metadata.namespace || getDefaultNamespace(), - name: item.metadata.name, - }) - ) - } - variant="success" - /> - ), - }); + pipelineRunCreateMutation.mutate(item); handleCloseEditor(); }; @@ -115,30 +164,7 @@ export const PipelineRunActionsMenu = ({ const newPipelineRun = createRerunPipelineRunInstance(pipelineRun); - PipelineRunKubeObject.apiEndpoint.post(newPipelineRun); - - enqueueSnackbar('The PipelineRun is successfully rerun.', { - persist: true, - anchorOrigin: { - vertical: 'bottom', - horizontal: 'left', - }, - content: (key, message) => ( - closeSnackbar(key)} - pushLocation={() => - history.push( - createGoToRoute({ - namespace: newPipelineRun.metadata.namespace || getDefaultNamespace(), - name: newPipelineRun.metadata.name, - }) - ) - } - variant="success" - /> - ), - }); + pipelineRunCreateMutation.mutate(newPipelineRun); }, }), createKubeAction({ @@ -172,9 +198,10 @@ export const PipelineRunActionsMenu = ({ handleCloseResourceActionListMenu(); } - const copyPipelineRun = { ...pipelineRun }; - copyPipelineRun.spec.status = 'Cancelled'; - PipelineRunKubeObject.apiEndpoint.put(copyPipelineRun); + const newPipelineRun = { ...pipelineRun }; + newPipelineRun.spec.status = 'Cancelled'; + + pipelineRunEditMutation.mutate(newPipelineRun); }, }), ] @@ -191,26 +218,27 @@ export const PipelineRunActionsMenu = ({ handleCloseResourceActionListMenu(); } - PipelineRunKubeObject.apiEndpoint.delete( - pipelineRun.metadata.namespace, - pipelineRun.metadata.name - ); - onDelete(); + pipelineRunDeleteMutation.mutate(pipelineRun, { + onSuccess: onDelete, + }); }, }), ]; }, [ _pipelineRun, - variant, + permissions.create.PipelineRun.allowed, + permissions.create.PipelineRun.reason, + permissions.update.PipelineRun.allowed, + permissions.update.PipelineRun.reason, + permissions.delete.PipelineRun.allowed, + permissions.delete.PipelineRun.reason, isInProgress, - permissions.create, - permissions.update, - permissions.delete, - enqueueSnackbar, - closeSnackbar, - history, - onDelete, + variant, handleCloseResourceActionListMenu, + pipelineRunCreateMutation, + pipelineRunEditMutation, + pipelineRunDeleteMutation, + onDelete, ]); const groupActions = actions.slice(0, 2); diff --git a/src/widgets/PipelineRunList/components/DeleteDialog/index.tsx b/src/widgets/PipelineRunList/components/DeleteDialog/index.tsx index 55e6c46b3..709a5a5d8 100644 --- a/src/widgets/PipelineRunList/components/DeleteDialog/index.tsx +++ b/src/widgets/PipelineRunList/components/DeleteDialog/index.tsx @@ -64,8 +64,9 @@ export const DeletionDialog = ({ }); showBeforeRequestMessage(CRUD_TYPES.DELETE, { - customMessage: 'Selected PipelineRuns have been deleted', - entityName: 'PipelineRuns', + customMessage: { + message: 'Selected PipelineRuns have been deleted', + }, }); setValue(''); diff --git a/src/widgets/ResourceQuotas/types.ts b/src/widgets/ResourceQuotas/types.ts index 12ff7a3a9..f3f4e1edd 100644 --- a/src/widgets/ResourceQuotas/types.ts +++ b/src/widgets/ResourceQuotas/types.ts @@ -9,4 +9,3 @@ export interface QuotaDetails { export interface ParsedQuotas { [entity: string]: QuotaDetails; } -