Skip to content

Commit

Permalink
add processing property to wrapped actions
Browse files Browse the repository at this point in the history
  • Loading branch information
joshuaboud committed May 31, 2024
1 parent 8210527 commit 1465326
Showing 1 changed file with 47 additions and 9 deletions.
56 changes: 47 additions & 9 deletions houston-common-ui/lib/composables/wrapActions.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,60 @@
import { ResultAsync } from "neverthrow";
import { globalProcessingWrapResult } from "@/composables/useGlobalProcessingState";
import { reportError } from "@/components/NotificationView.vue";
import { ref, reactive, type Ref, watchEffect } from "vue";

export type Action<TParams extends Array<any>, TOk, TErr extends Error> = (
..._: TParams
) => ResultAsync<TOk, TErr>;

export type WrappedAction<
TParams extends Array<any>,
TOk,
TErr extends Error,
> = Action<TParams, TOk, TErr> & {
/**
* Tracks whether the action is executing
*/
processing: Ref<boolean>;
};

export type WrappedActions<
Actions extends {
[action: string]: Action<any, any, any>;
},
> = {
[Prop in keyof Actions]: Actions[Prop] extends Action<
infer TParams,
infer TOk,
infer TErr
>
? WrappedAction<TParams, TOk, TErr>
: never;
};

/**
* Make an action affect global processing state (loading spinners) and report errors as notifications
* @param action
* @returns
*/
export function wrapAction<TParams extends Array<any>, TOk, TErr extends Error>(
action: Action<TParams, TOk, TErr>
) {
const wrappedAction = (...params: TParams) =>
globalProcessingWrapResult(action)(...params).mapErr((e) => { e.message = `Error in ${action.name}: ${e.message}`; return reportError(e) });
Object.defineProperty(wrappedAction, 'name', {
): WrappedAction<TParams, TOk, TErr> {
const wrappedAction = (...params: TParams) => {
wrappedAction.processing.value = true;
return globalProcessingWrapResult(action)(...params)
.map((r: TOk) => {
wrappedAction.processing.value = false;
return r;
})
.mapErr((e) => {
wrappedAction.processing.value = false;
e.message = `Error in ${action.name}: ${e.message}`;
return reportError(e);
});
};
wrappedAction.processing = ref(false);
Object.defineProperty(wrappedAction, "name", {
value: `${action.name} (wrapped)`,
writable: false,
});
Expand All @@ -36,12 +74,12 @@ export function wrapAction<TParams extends Array<any>, TOk, TErr extends Error>(
* import { getServer } from "@45drives/houston-common-lib";
* import { wrapActions } from "@45drives/houston-common-ui";
* import { ref, onMounted } from "vue";
*
*
* const settings = ref<Settings>();
*
*
* const loadSettings = () =>
* getServer().andThen(loadSettingsFromServer).map(s => settings.value = s);
*
*
* const updateSettings = (settings) =>
* getServer()
* .andThen(server => updateSettingsOnServer(server, settings))
Expand All @@ -57,7 +95,7 @@ export function wrapAction<TParams extends Array<any>, TOk, TErr extends Error>(
* // call actions.loadSettings() and actions.updateSettings(settings) when you want user feedback
* // plain non-wrapped loadSettings() and updateSettings(settings) still available to call from other actions
* </script>
*
*
* <template>
* <button @click="actions.updateSettings(settings)">Apply</button>
* </template>
Expand All @@ -75,4 +113,4 @@ export const wrapActions = <
funcName,
wrapAction(func),
])
) as Actions;
) as WrappedActions<Actions>;

0 comments on commit 1465326

Please sign in to comment.