From 0847c2e52c26f085ff017f2c51ebaed054c73012 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20G=C3=B3is?= Date: Mon, 22 Jan 2024 17:31:04 +0000 Subject: [PATCH] chore: add new action hooks (#5992) https://linear.app/unleash/issue/2-1857/create-new-action-hooks-on-the-frontend Adds action hooks to help us with CRUD operations on the frontend, similar to https://github.com/Unleash/unleash/pull/5788 and https://github.com/Unleash/unleash/pull/5790 --- .../actions/useActionsApi/useActionsApi.ts | 73 +++++++++++++++++++ .../api/getters/useActions/useActions.ts | 37 ++++++++++ frontend/src/interfaces/action.ts | 27 +++++++ frontend/src/interfaces/uiConfig.ts | 1 + 4 files changed, 138 insertions(+) create mode 100644 frontend/src/hooks/api/actions/useActionsApi/useActionsApi.ts create mode 100644 frontend/src/hooks/api/getters/useActions/useActions.ts create mode 100644 frontend/src/interfaces/action.ts diff --git a/frontend/src/hooks/api/actions/useActionsApi/useActionsApi.ts b/frontend/src/hooks/api/actions/useActionsApi/useActionsApi.ts new file mode 100644 index 0000000000..54032411d3 --- /dev/null +++ b/frontend/src/hooks/api/actions/useActionsApi/useActionsApi.ts @@ -0,0 +1,73 @@ +import { IAction, IActionSet } from 'interfaces/action'; +import useAPI from '../useApi/useApi'; + +const ENDPOINT = 'api/admin/actions'; + +export type ActionPayload = Omit< + IAction, + 'id' | 'createdAt' | 'createdByUserId' +>; + +export type ActionSetPayload = Omit< + IActionSet, + 'id' | 'createdAt' | 'createdByUserId' +> & { + actions: ActionPayload[]; +}; + +export const useActionsApi = () => { + const { loading, makeRequest, createRequest, errors } = useAPI({ + propagateErrors: true, + }); + + const addActionSet = async (actionSet: ActionSetPayload) => { + const requestId = 'addActionSet'; + const req = createRequest( + ENDPOINT, + { + method: 'POST', + body: JSON.stringify(actionSet), + }, + requestId, + ); + + const response = await makeRequest(req.caller, req.id); + return response.json(); + }; + + const updateActionSet = async ( + actionSetId: number, + actionSet: ActionSetPayload, + ) => { + const requestId = 'updateActionSet'; + const req = createRequest( + `${ENDPOINT}/${actionSetId}`, + { + method: 'PUT', + body: JSON.stringify(actionSet), + }, + requestId, + ); + + await makeRequest(req.caller, req.id); + }; + + const removeActionSet = async (actionSetId: number) => { + const requestId = 'removeActionSet'; + const req = createRequest( + `${ENDPOINT}/${actionSetId}`, + { method: 'DELETE' }, + requestId, + ); + + await makeRequest(req.caller, req.id); + }; + + return { + addActionSet, + updateActionSet, + removeActionSet, + errors, + loading, + }; +}; diff --git a/frontend/src/hooks/api/getters/useActions/useActions.ts b/frontend/src/hooks/api/getters/useActions/useActions.ts new file mode 100644 index 0000000000..c709a3f675 --- /dev/null +++ b/frontend/src/hooks/api/getters/useActions/useActions.ts @@ -0,0 +1,37 @@ +import { useMemo } from 'react'; +import { formatApiPath } from 'utils/formatPath'; +import handleErrorResponses from '../httpErrorResponseHandler'; +import { useConditionalSWR } from '../useConditionalSWR/useConditionalSWR'; +import useUiConfig from '../useUiConfig/useUiConfig'; +import { IActionSet } from 'interfaces/action'; +import { useUiFlag } from 'hooks/useUiFlag'; + +const ENDPOINT = 'api/admin/actions'; + +export const useActions = () => { + const { isEnterprise } = useUiConfig(); + const actionsEnabled = useUiFlag('automatedActions'); + + const { data, error, mutate } = useConditionalSWR( + isEnterprise() && actionsEnabled, + { actions: [] }, + formatApiPath(ENDPOINT), + fetcher, + ); + + return useMemo( + () => ({ + actions: (data?.actions ?? []) as IActionSet[], + loading: !error && !data, + refetch: () => mutate(), + error, + }), + [data, error, mutate], + ); +}; + +const fetcher = (path: string) => { + return fetch(path) + .then(handleErrorResponses('Actions')) + .then((res) => res.json()); +}; diff --git a/frontend/src/interfaces/action.ts b/frontend/src/interfaces/action.ts new file mode 100644 index 0000000000..e9a8073e40 --- /dev/null +++ b/frontend/src/interfaces/action.ts @@ -0,0 +1,27 @@ +export interface IActionSet { + id: number; + name: string; + project: string; + actorId: number; + match: IMatch; + actions: IAction[]; + createdAt: string; + createdByUserId: number; +} + +type MatchSource = 'incoming-webhook'; + +export interface IMatch { + source: MatchSource; + sourceId: number; + payload: Record; +} + +export interface IAction { + id: number; + action: string; + sortOrder: number; + executionParams: Record; + createdAt: string; + createdByUserId: number; +} diff --git a/frontend/src/interfaces/uiConfig.ts b/frontend/src/interfaces/uiConfig.ts index 49b9d3435d..64805b24b7 100644 --- a/frontend/src/interfaces/uiConfig.ts +++ b/frontend/src/interfaces/uiConfig.ts @@ -68,6 +68,7 @@ export type UiFlags = { featureSearchFrontend?: boolean; newStrategyConfiguration?: boolean; incomingWebhooks?: boolean; + automatedActions?: boolean; celebrateUnleash?: boolean; increaseUnleashWidth?: boolean; featureSearchFeedback?: boolean;