Skip to content

Commit

Permalink
feat: improve failed extension install, initialise and setUserRole tr…
Browse files Browse the repository at this point in the history
…ansaction handling
  • Loading branch information
iamsamgibbs committed Oct 16, 2024
1 parent 76dfa84 commit 5f905ce
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 51 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { waitForDbAfterExtensionAction } from '~frame/Extensions/pages/Extension
import useAsyncFunction from '~hooks/useAsyncFunction.ts';
import useExtensionData, { ExtensionMethods } from '~hooks/useExtensionData.ts';
import { ActionTypes } from '~redux';
import { ExtensionInstallAndEnableErrorStep } from '~redux/sagas/extensions/extensionInstallAndEnable.ts';
import Toast from '~shared/Extensions/Toast/index.ts';
import { type AnyExtensionData } from '~types/extensions.ts';

Expand Down Expand Up @@ -75,7 +76,7 @@ export const useInstall = (extensionData: AnyExtensionData) => {

const [isLoading, setIsLoading] = useState(false);

const showErrorToast = useCallback(() => {
const showInstallErrorToast = useCallback(() => {
toast.error(
<Toast
type="error"
Expand All @@ -85,53 +86,109 @@ export const useInstall = (extensionData: AnyExtensionData) => {
);
}, []);

const handleInstallSuccess = useCallback(async () => {
setIsLoading(true);
setWaitingForActionConfirmation(true);
const showInitialiseErrorToast = useCallback(() => {
toast.error(
<Toast
type="error"
title={{ id: 'extensionEnable.toast.title.error' }}
description={{ id: 'extensionEnable.toast.description.error' }}
/>,
);
}, []);

try {
await waitForDbAfterExtensionAction({
method: ExtensionMethods.INSTALL,
refetchExtensionData,
});
const showSetUserRolesErrorToast = useCallback(() => {
toast.error(
<Toast
type="error"
title={{ id: 'extensionSetUserRoles.toast.title.error' }}
description={{ id: 'extensionSetUserRoles.toast.description.error' }}
/>,
);
}, []);

toast.success(
<Toast
type="success"
title={{ id: 'extensionInstall.toast.title.success' }}
description={{
id: 'extensionInstall.toast.description.success',
}}
/>,
);
const handleInstallSuccess = useCallback(
async ({
initialiseTransactionFailed,
setUserRolesTransactionFailed,
}: {
initialiseTransactionFailed?: boolean;
setUserRolesTransactionFailed?: boolean;
}) => {
setIsLoading(true);
setWaitingForActionConfirmation(true);

try {
await waitForDbAfterExtensionAction({
method: ExtensionMethods.INSTALL,
refetchExtensionData,
initialiseTransactionFailed,
setUserRolesTransactionFailed,
});

toast.success(
<Toast
type="success"
title={{ id: 'extensionInstall.toast.title.success' }}
description={{
id: 'extensionInstall.toast.description.success',
}}
/>,
);

if (initialiseTransactionFailed) {
showInitialiseErrorToast();
}

if (extensionData.initializationParams || extensionData.configurable) {
// Reset the form to the default values using most recent extension data
const updatedExtensionData = await refetchExtensionData();
if (updatedExtensionData) {
reset(getExtensionSettingsDefaultValues(updatedExtensionData));
setActiveTab(ExtensionDetailsPageTabId.Settings);
if (setUserRolesTransactionFailed) {
showSetUserRolesErrorToast();
}

if (extensionData.initializationParams || extensionData.configurable) {
// Reset the form to the default values using most recent extension data
const updatedExtensionData = await refetchExtensionData();
if (updatedExtensionData) {
reset(getExtensionSettingsDefaultValues(updatedExtensionData));
setActiveTab(ExtensionDetailsPageTabId.Settings);
}
}
} catch {
showInstallErrorToast();
} finally {
setIsLoading(false);
setWaitingForActionConfirmation(false);
}
} catch {
showErrorToast();
} finally {
setIsLoading(false);
setWaitingForActionConfirmation(false);
}
}, [
extensionData.configurable,
extensionData.initializationParams,
refetchExtensionData,
reset,
setActiveTab,
setWaitingForActionConfirmation,
showErrorToast,
]);

const handleInstallError = useCallback(() => {
showErrorToast();
}, [showErrorToast]);
},
[
extensionData.configurable,
extensionData.initializationParams,
refetchExtensionData,
reset,
setActiveTab,
setWaitingForActionConfirmation,
showInstallErrorToast,
showInitialiseErrorToast,
showSetUserRolesErrorToast,
],
);

const handleInstallError = useCallback(
(error: any) => {
const { step } = error;

if (step === ExtensionInstallAndEnableErrorStep.Initialise) {
handleInstallSuccess({ initialiseTransactionFailed: true });
return;
}

if (step === ExtensionInstallAndEnableErrorStep.SetUserRoles) {
handleInstallSuccess({ setUserRolesTransactionFailed: true });
return;
}

showInstallErrorToast();
},
[showInstallErrorToast, handleInstallSuccess],
);

return {
handleInstallSuccess,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,15 @@ export const waitForDbAfterExtensionAction = (
latestVersion: number;
}
| {
method: Exclude<ExtensionMethods, ExtensionMethods.UPGRADE>;
method: ExtensionMethods.INSTALL;
initialiseTransactionFailed?: boolean;
setUserRolesTransactionFailed?: boolean;
}
| {
method: Exclude<
ExtensionMethods,
ExtensionMethods.UPGRADE | ExtensionMethods.INSTALL
>;
}
),
) => {
Expand Down Expand Up @@ -50,6 +58,22 @@ export const waitForDbAfterExtensionAction = (

switch (args.method) {
case ExtensionMethods.INSTALL: {
if (
extensionData?.autoEnableAfterInstall &&
!!args.initialiseTransactionFailed
) {
condition = !!extensionData;
break;
}

if (
extensionData?.autoEnableAfterInstall &&
!!args.setUserRolesTransactionFailed
) {
condition = !!extensionData.isEnabled;
break;
}

if (extensionData?.autoEnableAfterInstall) {
condition =
!!extensionData.isEnabled &&
Expand Down Expand Up @@ -77,7 +101,11 @@ export const waitForDbAfterExtensionAction = (
}

case ExtensionMethods.ENABLE: {
condition = !!extensionData?.isInitialized;
// condition = !!extensionData?.isInitialized;

condition =
!!extensionData?.isEnabled &&
extensionData?.missingColonyPermissions.length === 0;
break;
}

Expand Down
2 changes: 2 additions & 0 deletions src/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -970,6 +970,8 @@
"extensionInstallAndEnable.toast.description.success": "The extension has been installed and enabled.",
"extensionInstallAndEnable.toast.title.error": "Extension failed to install or enable",
"extensionInstallAndEnable.toast.description.error": "Due to a transaction error, the extension was not installed or enabled.",
"extensionSetUserRoles.toast.title.error": "Failed to assign extension permissions",
"extensionSetUserRoles.toast.description.error": "Due to a transaction error, the extension was not assigned the permissions it needs to work.",
"extensionSaveChanges.toast.title.success": "Updated",
"extensionSaveChanges.toast.description.success": "The extension parameters have been successfully updated.",
"extensionSaveChanges.toast.title.error": "Extension failed to update",
Expand Down
36 changes: 30 additions & 6 deletions src/redux/sagas/extensions/extensionInstallAndEnable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ import {
getColonyManager,
} from '../utils/index.ts';

export enum ExtensionInstallAndEnableErrorStep {
InstallExtension = 'installExtension',
Initialise = 'initialise',
SetUserRoles = 'setUserRoles',
}

// Saga will attempt to
// 1. Install extension
// Then, if enabledAutomaticallyAfterInstall is true
Expand Down Expand Up @@ -109,8 +115,14 @@ export function* extensionInstallAndEnable({
yield takeFrom(setUserRoles.channel, ActionTypes.TRANSACTION_CREATED);
}

yield initiateTransaction(installExtension.id);
yield waitForTxResult(installExtension.channel);
try {
yield initiateTransaction(installExtension.id);
yield waitForTxResult(installExtension.channel);
} catch (error) {
// Declare an error step for the error handler
error.step = ExtensionInstallAndEnableErrorStep.InstallExtension;
throw error;
}

// If not enabledAutomaticallyAfterInstall return success here
if (!autoEnableAfterInstall) {
Expand Down Expand Up @@ -158,8 +170,14 @@ export function* extensionInstallAndEnable({
const initParams = modifyParams(initializationParams, defaultParams);
yield transactionSetParams(initialise.id, initParams);

yield initiateTransaction(initialise.id);
yield waitForTxResult(initialise.channel);
try {
yield initiateTransaction(initialise.id);
yield waitForTxResult(initialise.channel);
} catch (error) {
// Declare an error step for the error handler
error.step = ExtensionInstallAndEnableErrorStep.Initialise;
throw error;
}
}

const [permissionDomainId, childSkillIndex] = yield getPermissionProofs(
Expand All @@ -181,8 +199,14 @@ export function* extensionInstallAndEnable({
bytes32Roles,
]);

yield initiateTransaction(setUserRoles.id);
yield waitForTxResult(setUserRoles.channel);
try {
yield initiateTransaction(setUserRoles.id);
yield waitForTxResult(setUserRoles.channel);
} catch (error) {
// Declare an error step for the error handler
error.step = ExtensionInstallAndEnableErrorStep.SetUserRoles;
throw error;
}

yield put({
type: ActionTypes.EXTENSION_INSTALL_AND_ENABLE_SUCCESS,
Expand Down

0 comments on commit 5f905ce

Please sign in to comment.