Skip to content

Commit

Permalink
Merge pull request #7168 from ashanthamara/actions
Browse files Browse the repository at this point in the history
Add getActionByActionId API call in the Action UI
  • Loading branch information
ashanthamara authored Dec 2, 2024
2 parents 65b7080 + d6e7e35 commit 4fbd8f3
Show file tree
Hide file tree
Showing 8 changed files with 193 additions and 28 deletions.
6 changes: 6 additions & 0 deletions .changeset/violet-lobsters-smile.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@wso2is/admin.actions.v1": minor
"@wso2is/i18n": patch
---

Add getActionByActionId api to actions ui
64 changes: 64 additions & 0 deletions features/admin.actions.v1/api/use-get-action-by-id.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/**
* Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com).
*
* WSO2 LLC. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import useRequest, {
RequestConfigInterface,
RequestErrorInterface,
RequestResultInterface
} from "@wso2is/admin.core.v1/hooks/use-request";
import { store } from "@wso2is/admin.core.v1/store";
import { HttpMethods } from "@wso2is/core/models";
import isEmpty from "lodash-es/isEmpty";
import { ActionResponseInterface } from "../models/actions";

/**
* Hook to get the action configurations by id.
*
* @param actionType - Type of the action.
* @param actionId - ID of the action.
* @returns SWR response object containing the data, error, isLoading, isValidating, mutate.
*/
const useGetActionById = <Data = ActionResponseInterface, Error = RequestErrorInterface>
(actionType: string, actionId: string): RequestResultInterface<Data, Error> => {

const requestConfig: RequestConfigInterface = {
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
method: HttpMethods.GET,
url: `${ store.getState().config.endpoints.actions }/${ actionType }/${ actionId }`
};

const shouldFetch: boolean = !isEmpty(actionId);

const { data, error, isLoading, isValidating, mutate } = useRequest<Data, Error>(
shouldFetch ? requestConfig : null,
{ shouldRetryOnError: false }
);

return {
data,
error,
isLoading,
isValidating,
mutate
};
};

export default useGetActionById;
6 changes: 3 additions & 3 deletions features/admin.actions.v1/api/use-get-actions-by-type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,16 @@ import useRequest, {
} from "@wso2is/admin.core.v1/hooks/use-request";
import { store } from "@wso2is/admin.core.v1/store";
import { HttpMethods } from "@wso2is/core/models";
import { ActionResponseInterface } from "../models/actions";
import { ActionBasicResponseInterface } from "../models/actions";

/**
* Hook to get the action configurations.
* Hook to get the actions configurations by action type.
*
* @param actionType - Type of the action.
* @param shouldFetch - Should fetch the data.
* @returns SWR response object containing the data, error, isLoading, isValidating, mutate.
*/
const useGetActionsByType = <Data = ActionResponseInterface[], Error = RequestErrorInterface>
const useGetActionsByType = <Data = ActionBasicResponseInterface[], Error = RequestErrorInterface>
(actionType: string, shouldFetch: boolean = true): RequestResultInterface<Data, Error> => {

const requestConfig: RequestConfigInterface = {
Expand Down
7 changes: 6 additions & 1 deletion features/admin.actions.v1/components/action-config-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import { Dispatch } from "redux";
import { Icon } from "semantic-ui-react";
import createAction from "../api/create-action";
import updateAction from "../api/update-action";
import useGetActionById from "../api/use-get-action-by-id";
import useGetActionsByType from "../api/use-get-actions-by-type";
import { ActionsConstants } from "../constants/actions-constants";
import {
Expand Down Expand Up @@ -106,6 +107,10 @@ const ActionConfigForm: FunctionComponent<ActionConfigFormInterface> = ({
mutate: mutateActions
} = useGetActionsByType(actionTypeApiPath);

const {
mutate: mutateAction
} = useGetActionById(actionTypeApiPath, initialValues?.id);

/**
* The following useEffect is used to set the current Action Authentication Type.
*/
Expand Down Expand Up @@ -342,7 +347,7 @@ const ActionConfigForm: FunctionComponent<ActionConfigFormInterface> = ({
.then(() => {
handleSuccess(ActionsConstants.UPDATE);
setIsAuthenticationUpdateFormState(false);
mutateActions();
mutateAction();
})
.catch((error: AxiosError) => {
handleError(error, ActionsConstants.UPDATE);
Expand Down
42 changes: 39 additions & 3 deletions features/admin.actions.v1/models/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
* under the License.
*/

import { HttpMethod } from "@asgardeo/auth-react";
import { FeatureStatusLabel } from "@wso2is/admin.feature-gate.v1/models/feature-status";
import { ReactNode } from "react";

Expand Down Expand Up @@ -102,6 +103,31 @@ interface AuthenticationInterface {
properties: Partial<AuthenticationPropertiesInterface>;
}

/**
* Link Relation type.
*/
enum Relation {
SELF = "self"
}

/**
* Link Interface.
*/
interface LinkInterface {
/**
* Url of the endpoint.
*/
href: string;
/**
* Http method.
*/
method: HttpMethod
/**
* Relation to the resource.
*/
rel: Relation;
}

/**
* Authentication Properties.
*/
Expand Down Expand Up @@ -129,9 +155,9 @@ export interface AuthenticationPropertiesInterface {
}

/**
* Action Basic Response.
* Action Base Response.
*/
export interface ActionBasicResponseInterface {
export interface ActionBaseResponseInterface {
/**
* ID of the Action.
*/
Expand All @@ -154,10 +180,20 @@ export interface ActionBasicResponseInterface {
status: ActionStatus;
}

/**
* Action Basic Response.
*/
export interface ActionBasicResponseInterface extends ActionBaseResponseInterface {
/**
* Links of the Action.
*/
links: LinkInterface[];
}

/**
* Action Response.
*/
export interface ActionResponseInterface extends ActionBasicResponseInterface {
export interface ActionResponseInterface extends ActionBaseResponseInterface {
/**
* Endpoint configuration of the Action.
*/
Expand Down
64 changes: 51 additions & 13 deletions features/admin.actions.v1/pages/action-configuration-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import { Dispatch } from "redux";
import { Checkbox, CheckboxProps, Grid } from "semantic-ui-react";
import changeActionStatus from "../api/change-action-status";
import deleteAction from "../api/delete-action";
import useGetActionById from "../api/use-get-action-by-id";
import useGetActionsByType from "../api/use-get-actions-by-type";
import ActionConfigForm from "../components/action-config-form";
import { ActionsConstants } from "../constants/actions-constants";
Expand Down Expand Up @@ -97,20 +98,29 @@ const ActionConfigurationPage: FunctionComponent<ActionConfigurationPageInterfac
mutate: mutateActions
} = useGetActionsByType(actionTypeApiPath);

const isLoading: boolean = isActionsLoading || !actions || !Array.isArray(actions);
const actionId: string = useMemo(() => actions?.[0]?.id || null, [ actions ]);

const {
data: action,
error: actionFetchRequestError,
isLoading: isActionLoading,
mutate: mutateAction
} = useGetActionById(actionTypeApiPath, actionId);

const isLoading: boolean = isActionsLoading || !actions || !Array.isArray(actions) || isActionLoading;

const actionInitialValues: ActionConfigFormPropertyInterface = useMemo(() => {
if (actions) {
if (action) {
return {
authenticationType: actions[0]?.endpoint?.authentication?.type.toString(),
endpointUri: actions[0]?.endpoint?.uri,
id: actions[0]?.id,
name: actions[0]?.name
authenticationType: action?.endpoint?.authentication?.type.toString(),
endpointUri: action?.endpoint?.uri,
id: action?.id,
name: action?.name
};
} else {
return null;
}
}, [ actions ]);
}, [ action ]);

useEffect(() => {
if (actions?.length >= 1) {
Expand All @@ -122,7 +132,7 @@ const ActionConfigurationPage: FunctionComponent<ActionConfigurationPageInterfac
}, [ actions ]);

/**
* The following useEffect is used to handle if any error occurs while fetching the Action.
* The following useEffect is used to handle if any error occurs while fetching Actions by Type.
*/
useEffect(() => {
if (isActionsLoading || !actionsFetchRequestError) {
Expand All @@ -132,23 +142,51 @@ const ActionConfigurationPage: FunctionComponent<ActionConfigurationPageInterfac
if (actionsFetchRequestError.response?.data?.description) {
dispatch(
addAlert<AlertInterface>({
description: t("actions:notification.error.fetch.description",
description: t("actions:notification.error.fetchByType.description",
{ description: actionsFetchRequestError.response.data.description }),
level: AlertLevels.ERROR,
message: t("actions:notification.error.fetch.message")
message: t("actions:notification.error.fetchByType.message")
})
);
} else {
dispatch(
addAlert<AlertInterface>({
description: t("actions:notification.genericError.fetch.description"),
description: t("actions:notification.genericError.fetchByType.description"),
level: AlertLevels.ERROR,
message: t("actions:notification.genericError.fetch.message")
message: t("actions:notification.genericError.fetchByType.message")
})
);
}
}, [ isActionsLoading, actionsFetchRequestError ]);

/**
* The following useEffect is used to handle if any error occurs while fetching the Action by Id.
*/
useEffect(() => {
if (isActionLoading || !actionFetchRequestError) {
return;
}

if (actionFetchRequestError.response?.data?.description) {
dispatch(
addAlert<AlertInterface>({
description: t("actions:notification.error.fetchById.description",
{ description: actionFetchRequestError.response.data.description }),
level: AlertLevels.ERROR,
message: t("actions:notification.error.fetchById.message")
})
);
} else {
dispatch(
addAlert<AlertInterface>({
description: t("actions:notification.genericError.fetchById.description"),
level: AlertLevels.ERROR,
message: t("actions:notification.genericError.fetchById.message")
})
);
}
}, [ isActionLoading, actionFetchRequestError ]);

/**
* Handles the back button click event.
*/
Expand Down Expand Up @@ -258,7 +296,7 @@ const ActionConfigurationPage: FunctionComponent<ActionConfigurationPageInterfac
handleError(error, toggleOperation);
})
.finally(() => {
mutateActions();
mutateAction();
setIsSubmitting(false);
});
};
Expand Down
12 changes: 10 additions & 2 deletions modules/i18n/src/models/namespaces/actions-ns.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,11 @@ export interface actionsNS {
description: string;
message: string;
};
fetch: {
fetchById: {
description: string;
message: string;
};
fetchByType: {
description: string;
message: string;
};
Expand Down Expand Up @@ -185,7 +189,11 @@ export interface actionsNS {
description: string;
message: string;
};
fetch: {
fetchById: {
description: string;
message: string;
};
fetchByType: {
description: string;
message: string;
};
Expand Down
20 changes: 14 additions & 6 deletions modules/i18n/src/translations/en-US/portals/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,13 +162,17 @@ export const actions: actionsNS = {
description: "{{description}}",
message: "Error deleting the action."
},
fetch: {
fetchById: {
description: "{{description}}",
message: "Error fetching the action."
message: "Error retrieving the action."
},
fetchByType: {
description: "{{description}}",
message: "Error retrieving actions."
},
typesFetch: {
description: "{{description}}",
message: "Error fetching the action types."
message: "Error retrieving the action types."
},
update: {
description: "{{description}}",
Expand All @@ -192,12 +196,16 @@ export const actions: actionsNS = {
description: "Couldn't delete the action.",
message: "Something went wrong."
},
fetch: {
description: "Couldn't fetch the action.",
fetchById: {
description: "Couldn't retrieve the action.",
message: "Something went wrong."
},
fetchByType: {
description: "Couldn't retrieve actions.",
message: "Something went wrong."
},
typesFetch: {
description: "Couldn't fetch the action types.",
description: "Couldn't retrieve the action types.",
message: "Something went wrong."
},
update: {
Expand Down

0 comments on commit 4fbd8f3

Please sign in to comment.