From 2364451d38b5ae1259c29f0d4a53b61b481eaf05 Mon Sep 17 00:00:00 2001 From: 1akshitha Date: Fri, 31 Mar 2023 11:46:32 +0530 Subject: [PATCH 1/9] Add the UI for API level policies --- .../Details/Policies/AttachedPolicyCard.tsx | 3 + .../Policies/AttachedPolicyForm/General.tsx | 5 +- .../Details/Policies/AttachedPolicyList.tsx | 3 + .../Details/Policies/GranularitySelector.tsx | 234 ++++++++++++++++++ .../Apis/Details/Policies/OperationPolicy.tsx | 1 + .../Apis/Details/Policies/Policies.tsx | 211 +++++++++++----- .../Details/Policies/PoliciesExpansion.tsx | 20 +- .../PolicyConfigurationEditDrawer.tsx | 10 +- .../Policies/PolicyConfiguringDrawer.tsx | 3 + .../Apis/Details/Policies/PolicyDropzone.tsx | 4 + .../Apis/Details/Policies/Types.d.ts | 6 + 11 files changed, 424 insertions(+), 76 deletions(-) create mode 100644 portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/GranularitySelector.tsx diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/AttachedPolicyCard.tsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/AttachedPolicyCard.tsx index 3624445dc50..c63014f4157 100644 --- a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/AttachedPolicyCard.tsx +++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/AttachedPolicyCard.tsx @@ -51,6 +51,7 @@ interface AttachedPolicyCardProps { verb: string; target: string; allPolicies: PolicySpec[] | null; + isAPILevelPolicy: boolean; } /** @@ -66,6 +67,7 @@ const AttachedPolicyCard: FC = ({ verb, target, allPolicies, + isAPILevelPolicy, }) => { const classes = useStyles(); const { api } = useContext(ApiContext); @@ -232,6 +234,7 @@ const AttachedPolicyCard: FC = ({ target={target} verb={verb} allPolicies={allPolicies} + isAPILevelPolicy={isAPILevelPolicy} /> )} diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/AttachedPolicyForm/General.tsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/AttachedPolicyForm/General.tsx index ad349e51684..6a32ccec0e7 100644 --- a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/AttachedPolicyForm/General.tsx +++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/AttachedPolicyForm/General.tsx @@ -68,10 +68,11 @@ interface GeneralProps { policySpec: PolicySpec; handleDrawerClose: () => void; isEditMode: boolean; + isAPILevelPolicy: boolean; } const General: FC = ({ - policyObj, setDroppedPolicy, currentFlow, target, verb, apiPolicy, policySpec, handleDrawerClose, isEditMode + policyObj, setDroppedPolicy, currentFlow, target, verb, apiPolicy, policySpec, handleDrawerClose, isEditMode, isAPILevelPolicy }) => { const intl = useIntl(); const classes = useStyles(); @@ -407,7 +408,7 @@ const General: FC = ({ )} ))} - {setDroppedPolicy && ( + {setDroppedPolicy && !isAPILevelPolicy && ( = ({ target, verb, allPolicies, + isAPILevelPolicy, }) => { const reversedPolicyList = [...currentPolicyList].reverse(); const policyListToDisplay = @@ -116,6 +118,7 @@ const AttachedPolicyList: FC = ({ target={target} verb={verb} allPolicies={allPolicies} + isAPILevelPolicy={isAPILevelPolicy} /> ))} diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/GranularitySelector.tsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/GranularitySelector.tsx new file mode 100644 index 00000000000..b821ec8395c --- /dev/null +++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/GranularitySelector.tsx @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2022, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. 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 React, { FC, useState } from 'react'; +import { HelpOutline } from '@material-ui/icons'; +import Tooltip from '@material-ui/core/Tooltip'; +import { + Dialog, + DialogTitle, + DialogContent, + Button, + DialogActions, + Radio, +} from '@material-ui/core'; +import Paper from '@material-ui/core/Paper'; +import Box from '@material-ui/core/Box'; +import Typography from '@material-ui/core/Typography'; +import IconButton from '@material-ui/core/IconButton'; +import Grid from '@material-ui/core/Grid'; +import FormControl from '@material-ui/core/FormControl'; +import RadioGroup from '@material-ui/core/RadioGroup'; +import FormControlLabel from '@material-ui/core/FormControlLabel'; +import { isRestricted } from 'AppData/AuthManager'; +import { useAPI } from 'AppComponents/Apis/Details/components/ApiContext'; +import { FormattedMessage } from 'react-intl'; + +const GranularityTypes = { + APILevel: 'API Level', + OperationLevel: 'Operation Level', +}; + +interface GranularitySelectorProps { + setIsChangedToAPILevel: (isAPILevel: boolean) => void; + isAPILevelPoliciesSelected: boolean; + removeAPIPoliciesForGatewayChange: () => void; +} + +/** + * Renders the Gateway selection section. + * @param {JSON} props Input props from parent components. + * @returns {TSX} Radio group for the API Gateway. + */ +const GranularitySelector: FC = ({ + setIsChangedToAPILevel, + isAPILevelPoliciesSelected, + removeAPIPoliciesForGatewayChange +}) => { + const [apiFromContext] = useAPI(); + let selectedGatewayType; + + const [isDialogBoxVisible, setIsDialogBoxVisible] = useState(false); + // This state is maintained until user gived approval for gateway change. + // Without this state radio buttons will switch even user disagrees to proceed gateway change. + const [isAPILevelSelected, setIsAPILevelSelected] = useState(false); + + const saveAfterGatewayChange = () => { + if (isAPILevelSelected) { + setIsChangedToAPILevel(true); + } else { + setIsChangedToAPILevel(false); + } + removeAPIPoliciesForGatewayChange(); + setIsDialogBoxVisible(false); + } + + if (isAPILevelPoliciesSelected) { + selectedGatewayType = GranularityTypes.APILevel; + } else { + selectedGatewayType = GranularityTypes.OperationLevel; + } + + /** + * Handles accepted gateway type change after approving dialog box. + * @param {event: React.ChangeEvent} event Indicates gateway type radio button change event. + */ + const handleDialogBox = (event: React.ChangeEvent) => { + if(event.target.value === GranularityTypes.APILevel) { + setIsAPILevelSelected(true) + } else { + setIsAPILevelSelected(false); + } + setIsDialogBoxVisible(true); + } + + /** + * Handles discarded gateway type change after cancelling dialog box. + */ + const handleDiscardedGatewayChange = () => { + setIsDialogBoxVisible(false); + }; + + return ( + + + + + + + Policy Granularity + + + + + + + + + + + + } + label='API Level' + labelPlacement='end' + /> + + } + label='Operation Level' + labelPlacement='end' + /> + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default GranularitySelector; diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/OperationPolicy.tsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/OperationPolicy.tsx index b93785a7c89..ff53729cb57 100644 --- a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/OperationPolicy.tsx +++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/OperationPolicy.tsx @@ -185,6 +185,7 @@ const OperationPolicy: FC = ({ allPolicies={allPolicies} isChoreoConnectEnabled={isChoreoConnectEnabled} policyList={policyList} + isAPILevelPolicy={false} /> diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/Policies.tsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/Policies.tsx index 7daf97926e0..78af7fc9cef 100644 --- a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/Policies.tsx +++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/Policies.tsx @@ -37,11 +37,13 @@ import { arrayMove } from '@dnd-kit/sortable'; import OperationPolicy from './OperationPolicy'; import OperationsGroup from './OperationsGroup'; import PolicyList from './PolicyList'; -import type { ApiPolicy, Policy, PolicySpec } from './Types'; +import type { ApiPolicy, Policy, PolicySpec, ApiLevelPolicy } from './Types'; import GatewaySelector from './GatewaySelector'; +import GranularitySelector from './GranularitySelector'; import { ApiOperationContextProvider } from './ApiOperationContext'; import { uuidv4 } from './Utils'; import SaveOperationPolicies from './SaveOperationPolicies'; +import PoliciesExpansion from './PoliciesExpansion'; const Configurations = require('Config'); @@ -74,6 +76,7 @@ const Policies: React.FC = () => { const [allPolicies, setAllPolicies] = useState(null); const [expandedResource, setExpandedResource] = useState(null); const [isChoreoConnectEnabled, setIsChoreoConnectEnabled] = useState(api.gatewayType === 'wso2/choreo-connect'); + const [isAPILevelGranularitySelected, setIsAPILevelGranularitySelected] = useState(api.apiPolicies != null); const { showMultiVersionPolicies } = Configurations.apis; // If Choreo Connect radio button is selected in GatewaySelector, it will pass @@ -82,6 +85,10 @@ const Policies: React.FC = () => { setIsChoreoConnectEnabled(isCCEnabled); } + const setIsChangedToAPILevelPolicies = (isAPILevelSelected: boolean) => { + setIsAPILevelGranularitySelected(isAPILevelSelected); + } + /** * Function to get the initial state of all the operation policies from the API object. * We are setting a unique ID for all the operation policies solely for UI specific operations. @@ -94,28 +101,49 @@ const Policies: React.FC = () => { clonedOperations.forEach((operation: any) => { if (operation.operationPolicies) { const { operationPolicies } = operation; - - // Iterating through the policy list of request flow, response flow and fault flow - for (const flow in operationPolicies) { - if (Object.prototype.hasOwnProperty.call(operationPolicies, flow)) { - const policyArray = operationPolicies[flow]; - policyArray.forEach((policyItem: ApiPolicy) => { - // eslint-disable-next-line no-param-reassign - policyItem.uuid = uuidv4(); - }); - } - } + getInitPolicyState(operationPolicies); } }); return clonedOperations; } + const getInitAPILevelPoliciesState = () => { + const clonedAPIPolicies = cloneDeep(api.apiPolicies); + if (api.apiPolicies != null) { + getInitPolicyState(clonedAPIPolicies); + } + return clonedAPIPolicies || initApiLevelPolicy; + } + + const initApiLevelPolicy: ApiLevelPolicy = { + request: [], + response: [], + fault: [], + }; + + const getInitPolicyState = (policyList: any) => { + // Iterating through the policy list of request flow, response flow and fault flow + for (const flow in policyList) { + if (Object.prototype.hasOwnProperty.call(policyList, flow)) { + const policyArray = policyList[flow]; + policyArray.forEach((policyItem: ApiPolicy) => { + // eslint-disable-next-line no-param-reassign + policyItem.uuid = uuidv4(); + }); + } + } + } + const [apiOperations, setApiOperations] = useState(getInitState); + const [apiLevelPolicies, setApiLevelPolicies] = useState(getInitAPILevelPoliciesState); const [openAPISpec, setOpenAPISpec] = useState(null); useEffect(() => { const currentOperations = getInitState(); setApiOperations(currentOperations); + + const currentAPIPolicies = getInitAPILevelPoliciesState(); + setApiLevelPolicies(currentAPIPolicies); }, [api]); /** @@ -183,6 +211,7 @@ const Policies: React.FC = () => { } const removeAPIPoliciesForGatewayChange = () => { + const newApiOperations: any = cloneDeep(apiOperations); // Set operation policies to the API object newApiOperations.forEach((operation: any) => { @@ -192,19 +221,18 @@ const Policies: React.FC = () => { // Iterating through the policy list of request flow, response flow and fault flow for (const flow in operationPolicies) { if (Object.prototype.hasOwnProperty.call(operationPolicies, flow)) { - operationPolicies[flow] = []; - } } } }); setApiOperations(newApiOperations); + setApiLevelPolicies(initApiLevelPolicy); } useEffect(() => { fetchPolicies(); - }, [isChoreoConnectEnabled]) + }, [isChoreoConnectEnabled, isAPILevelGranularitySelected]) useEffect(() => { // Update the Swagger spec object when API object gets changed @@ -245,12 +273,15 @@ const Policies: React.FC = () => { const updateApiOperations = ( updatedOperation: any, target: string, verb: string, currentFlow: string, ) => { + const newApiOperations: any = cloneDeep(apiOperations); - let operationInAction = newApiOperations.find((op: any) => - op.target === target && op.verb.toLowerCase() === verb.toLowerCase()); + const newApiLevelPolicies: any = cloneDeep(apiLevelPolicies); - const operationFlowPolicy = - operationInAction.operationPolicies[currentFlow].find((p: any) => (p.policyId === updatedOperation.policyId + let operationInAction = (!isAPILevelGranularitySelected) ? newApiOperations.find((op: any) => + op.target === target && op.verb.toLowerCase() === verb.toLowerCase()) : null; + + const operationFlowPolicy = ((isAPILevelGranularitySelected) ? newApiLevelPolicies + : operationInAction.operationPolicies)[currentFlow].find((p: any) => (p.policyId === updatedOperation.policyId && p.uuid === updatedOperation.uuid)); if (operationFlowPolicy) { @@ -259,11 +290,11 @@ const Policies: React.FC = () => { } else { // Add new operation policy const uuid = uuidv4(); - operationInAction.operationPolicies[currentFlow].push({ ...updatedOperation, uuid }); + ((isAPILevelGranularitySelected) ? newApiLevelPolicies : operationInAction.operationPolicies)[currentFlow].push({ ...updatedOperation, uuid }); } // Finally update the state - setApiOperations(newApiOperations); + (isAPILevelGranularitySelected) ? setApiLevelPolicies(newApiLevelPolicies) : setApiOperations(newApiOperations); } /** @@ -294,20 +325,28 @@ const Policies: React.FC = () => { * @param {string} currentFlow depicts which flow needs to be udpated: request, response or fault */ const deleteApiOperation = (uuid: string, target: string, verb: string, currentFlow: string) => { - const newApiOperations: any = cloneDeep(apiOperations); - const operationInAction = newApiOperations.find((op: any) => - op.target === target && op.verb.toLowerCase() === verb.toLowerCase()); - // Find the location of the element using the following logic - /* - [{a:'1'},{a:'2'},{a:'1'}].map( i => i.a) will output ['1', '2', '1'] - [{a:'1'},{a:'2'},{a:'1'}].map( i => i.a).indexOf('2') will output the location of '2' - */ - const index = operationInAction.operationPolicies[currentFlow].map((p: any) => p.uuid).indexOf(uuid); - // delete the element - operationInAction.operationPolicies[currentFlow].splice(index, 1); - // Finally update the state - setApiOperations(newApiOperations); + if (isAPILevelGranularitySelected) { + const newApiLevelPolicies: any = cloneDeep(apiLevelPolicies); + const index = newApiLevelPolicies[currentFlow].map((p: any) => p.uuid).indexOf(uuid); + newApiLevelPolicies[currentFlow].splice(index, 1); + setApiLevelPolicies(newApiLevelPolicies); + } else { + const newApiOperations: any = cloneDeep(apiOperations); + const operationInAction = newApiOperations.find((op: any) => + op.target === target && op.verb.toLowerCase() === verb.toLowerCase()); + // Find the location of the element using the following logic + /* + [{a:'1'},{a:'2'},{a:'1'}].map( i => i.a) will output ['1', '2', '1'] + [{a:'1'},{a:'2'},{a:'1'}].map( i => i.a).indexOf('2') will output the location of '2' + */ + const index = operationInAction.operationPolicies[currentFlow].map((p: any) => p.uuid).indexOf(uuid); + // delete the element + operationInAction.operationPolicies[currentFlow].splice(index, 1); + + // Finally update the state + setApiOperations(newApiOperations); + } } /** @@ -321,15 +360,20 @@ const Policies: React.FC = () => { const rearrangeApiOperations = ( oldIndex: number, newIndex: number, target: string, verb: string, currentFlow: string, ) => { - const newApiOperations: any = cloneDeep(apiOperations); - let operationInAction = newApiOperations.find((op: any) => - op.target === target && op.verb.toLowerCase() === verb.toLowerCase()); - - const policyArray = operationInAction.operationPolicies[currentFlow]; - operationInAction.operationPolicies[currentFlow] = arrayMove(policyArray, oldIndex, newIndex); - - // Finally update the state - setApiOperations(newApiOperations); + + if (isAPILevelGranularitySelected) { + const newAPIPolicies: any = cloneDeep(apiLevelPolicies); + const policyArray = newAPIPolicies[currentFlow]; + newAPIPolicies[currentFlow] = arrayMove(policyArray, oldIndex, newIndex); + setApiLevelPolicies(newAPIPolicies); + } else { + const newApiOperations: any = cloneDeep(apiOperations); + const operationInAction = newApiOperations.find((op: any) => + op.target === target && op.verb.toLowerCase() === verb.toLowerCase()); + const policyArray = operationInAction.operationPolicies[currentFlow]; + operationInAction.operationPolicies[currentFlow] = arrayMove(policyArray, oldIndex, newIndex); + setApiOperations(newApiOperations); + } } /** @@ -338,28 +382,21 @@ const Policies: React.FC = () => { const saveApi = () => { setUpdating(true); const newApiOperations: any = cloneDeep(apiOperations); + const newApiLevelPolicies: any = cloneDeep(apiLevelPolicies); let getewayTypeForPolicies = "wso2/synapse"; const getewayVendorForPolicies = "wso2"; - // Set operation policies to the API object - newApiOperations.forEach((operation: any, index: any, array: any) => { - if (operation.operationPolicies) { - const { operationPolicies } = operation; - - // Iterating through the policy list of request flow, response flow and fault flow - for (const flow in operationPolicies) { - if (Object.prototype.hasOwnProperty.call(operationPolicies, flow)) { - const policyArray = operationPolicies[flow]; - policyArray.forEach((policyItem: ApiPolicy) => { - if (policyItem.uuid) { - // eslint-disable-next-line no-param-reassign - delete policyItem.uuid; - } - }); - } + if (isAPILevelGranularitySelected) { + deletePolicyUuid(newApiLevelPolicies) + } else { + // Set operation policies to the API object + newApiOperations.forEach((operation: any, index: any, array: any) => { + if (operation.operationPolicies) { + const { operationPolicies } = operation; + deletePolicyUuid(operationPolicies) } - } - }); + }); + } // Handles normal policy savings for choreo connect gateway type. if(isChoreoConnectEnabled) { @@ -367,6 +404,7 @@ const Policies: React.FC = () => { } const updatePromise = updateAPI({ + apiPolicies: newApiLevelPolicies, operations: newApiOperations, gatewayVendor: getewayVendorForPolicies, gatewayType: getewayTypeForPolicies}); @@ -376,6 +414,22 @@ const Policies: React.FC = () => { }); } + + const deletePolicyUuid = (operationPolicies: any) => { + // Iterating through the policy list of request flow, response flow and fault flow + for (const flow in operationPolicies) { + if (Object.prototype.hasOwnProperty.call(operationPolicies, flow)) { + const policyArray = operationPolicies[flow]; + policyArray.forEach((policyItem: ApiPolicy) => { + if (policyItem.uuid) { + // eslint-disable-next-line no-param-reassign + delete policyItem.uuid; + } + }); + } + } + } + // handles operations (verbs) for CC policy expansion. const handleVerbsForCC = (verbObject: any) => { const array = Object.entries(verbObject).map(([verb]) => { @@ -391,11 +445,12 @@ const Policies: React.FC = () => { */ const providerValue = useMemo(() => ({ apiOperations, + apiLevelPolicies, updateApiOperations, updateAllApiOperations, deleteApiOperation, rearrangeApiOperations, - }), [apiOperations, updateApiOperations, updateAllApiOperations, deleteApiOperation, rearrangeApiOperations]) + }), [apiOperations, apiLevelPolicies, updateApiOperations, updateAllApiOperations, deleteApiOperation, rearrangeApiOperations]) if (!policies || !openAPISpec || updating) { return @@ -421,11 +476,37 @@ const Policies: React.FC = () => { /> )} + + + - {Object.entries(openAPISpec.paths).map(([target, verbObject]: [string, any]) => ( - + {isAPILevelGranularitySelected ? ( + + + + + + ) : + (Object.entries(openAPISpec.paths).map(([target, verbObject]: [string, any]) => ( { - ))} + )))} diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/PoliciesExpansion.tsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/PoliciesExpansion.tsx index 370334cc54f..6fdaa76575e 100644 --- a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/PoliciesExpansion.tsx +++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/PoliciesExpansion.tsx @@ -57,6 +57,7 @@ interface PoliciesExpansionProps { allPolicies: PolicySpec[] | null; isChoreoConnectEnabled: boolean; policyList: Policy[]; + isAPILevelPolicy: boolean; } const PoliciesExpansion: FC = ({ @@ -65,6 +66,7 @@ const PoliciesExpansion: FC = ({ allPolicies, isChoreoConnectEnabled, policyList, + isAPILevelPolicy, }) => { // Policies attached for each request, response and fault flow const [requestFlowPolicyList, setRequestFlowPolicyList] = useState([]); @@ -78,6 +80,7 @@ const PoliciesExpansion: FC = ({ const classes = useStyles(); const { apiOperations } = useContext(ApiOperationContext); + const { apiLevelPolicies } = useContext(ApiOperationContext); const { api } = useContext(APIContext); useEffect(() => { @@ -102,15 +105,17 @@ const PoliciesExpansion: FC = ({ useEffect(() => { (async () => { - let operationInAction = apiOperations.find( + + let operationInAction = (!isAPILevelPolicy) ? apiOperations.find( (op: any) => op.target === target && op.verb.toLowerCase() === verb.toLowerCase(), - ); + ) : null; + let apiPolicies = (isAPILevelPolicy) ? apiLevelPolicies : null; // Populate request flow attached policy list const requestFlowList: AttachedPolicy[] = []; - const requestFlow = operationInAction.operationPolicies.request; + const requestFlow = (isAPILevelPolicy) ? apiPolicies.request : operationInAction.operationPolicies.request; for (const requestFlowAttachedPolicy of requestFlow) { const { policyId, policyName, policyVersion, uuid } = requestFlowAttachedPolicy; @@ -153,7 +158,7 @@ const PoliciesExpansion: FC = ({ // Populate response flow attached policy list const responseFlowList: AttachedPolicy[] = []; - const responseFlow = operationInAction.operationPolicies.response; + const responseFlow = (isAPILevelPolicy) ? apiPolicies.response : operationInAction.operationPolicies.response; for (const responseFlowAttachedPolicy of responseFlow) { const { policyId, policyName, policyVersion, uuid } = responseFlowAttachedPolicy; @@ -197,7 +202,7 @@ const PoliciesExpansion: FC = ({ if (!isChoreoConnectEnabled) { // Populate fault flow attached policy list const faultFlowList: AttachedPolicy[] = []; - const faultFlow = operationInAction.operationPolicies.fault; + const faultFlow = (isAPILevelPolicy) ? apiPolicies.fault : operationInAction.operationPolicies.fault; for (const faultFlowAttachedPolicy of faultFlow) { const { policyId, policyName, policyVersion, uuid } = faultFlowAttachedPolicy; @@ -239,7 +244,7 @@ const PoliciesExpansion: FC = ({ setFaultFlowPolicyList(faultFlowList); } })(); - }, [apiOperations]); + }, [apiOperations, apiLevelPolicies]); return ( @@ -268,6 +273,7 @@ const PoliciesExpansion: FC = ({ target={target} verb={verb} allPolicies={allPolicies} + isAPILevelPolicy={isAPILevelPolicy} /> @@ -289,6 +295,7 @@ const PoliciesExpansion: FC = ({ target={target} verb={verb} allPolicies={allPolicies} + isAPILevelPolicy={isAPILevelPolicy} /> {!isChoreoConnectEnabled && ( @@ -311,6 +318,7 @@ const PoliciesExpansion: FC = ({ target={target} verb={verb} allPolicies={allPolicies} + isAPILevelPolicy={isAPILevelPolicy} /> )} diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/PolicyConfigurationEditDrawer.tsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/PolicyConfigurationEditDrawer.tsx index fb90ad58249..f0aa5a18708 100644 --- a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/PolicyConfigurationEditDrawer.tsx +++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/PolicyConfigurationEditDrawer.tsx @@ -59,6 +59,7 @@ interface PolicyConfigurationEditDrawerProps { drawerOpen: boolean; setDrawerOpen: React.Dispatch>; allPolicies: PolicySpec[] | null; + isAPILevelPolicy: boolean; } /** @@ -74,10 +75,12 @@ const PolicyConfigurationEditDrawer: FC = ({ allPolicies, drawerOpen, setDrawerOpen, + isAPILevelPolicy, }) => { const classes = useStyles(); const { api } = useContext(ApiContext); const { apiOperations } = useContext(ApiOperationContext); + const { apiLevelPolicies } = useContext(ApiOperationContext); const [policySpec, setPolicySpec] = useState(); useEffect(() => { @@ -102,12 +105,12 @@ const PolicyConfigurationEditDrawer: FC = ({ })(); }, [policyObj]); - const operationInAction = apiOperations.find( + const operationInAction = (!isAPILevelPolicy) ? apiOperations.find( (op: any) => op.target === target && op.verb.toLowerCase() === verb.toLowerCase(), - ); - const operationFlowPolicy = operationInAction.operationPolicies[ + ) : null; + const operationFlowPolicy = ((isAPILevelPolicy) ? apiLevelPolicies : operationInAction.operationPolicies)[ currentFlow ].find((policy: any) => policy.uuid === policyObj?.uniqueKey); @@ -166,6 +169,7 @@ const PolicyConfigurationEditDrawer: FC = ({ apiPolicy={apiPolicy} handleDrawerClose={handleDrawerClose} isEditMode + isAPILevelPolicy={isAPILevelPolicy} /> )} diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/PolicyConfiguringDrawer.tsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/PolicyConfiguringDrawer.tsx index 91db7621d85..ca78c9767e6 100644 --- a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/PolicyConfiguringDrawer.tsx +++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/PolicyConfiguringDrawer.tsx @@ -55,6 +55,7 @@ interface PolicyConfiguringDrawerProps { target: string; verb: string; allPolicies: PolicySpec[] | null; + isAPILevelPolicy: boolean; } /** @@ -69,6 +70,7 @@ const PolicyConfiguringDrawer: FC = ({ target, verb, allPolicies, + isAPILevelPolicy, }) => { const classes = useStyles(); const [drawerOpen, setDrawerOpen] = useState(!!policyObj); @@ -164,6 +166,7 @@ const PolicyConfiguringDrawer: FC = ({ apiPolicy={apiPolicy} handleDrawerClose={handleDrawerClose} isEditMode={false} + isAPILevelPolicy={isAPILevelPolicy} /> diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/PolicyDropzone.tsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/PolicyDropzone.tsx index a6298636479..805c3a31160 100644 --- a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/PolicyDropzone.tsx +++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/PolicyDropzone.tsx @@ -71,6 +71,7 @@ interface PolicyDropzoneProps { target: string; verb: string; allPolicies: PolicySpec[] | null; + isAPILevelPolicy: boolean; } /** @@ -87,6 +88,7 @@ const PolicyDropzone: FC = ({ target, verb, allPolicies, + isAPILevelPolicy, }) => { const classes = useStyles(); const [droppedPolicy, setDroppedPolicy] = useState(null); @@ -129,6 +131,7 @@ const PolicyDropzone: FC = ({ target={target} verb={verb} allPolicies={allPolicies} + isAPILevelPolicy={isAPILevelPolicy} /> )} @@ -141,6 +144,7 @@ const PolicyDropzone: FC = ({ target={target} verb={verb} allPolicies={allPolicies} + isAPILevelPolicy={isAPILevelPolicy} /> )} diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/Types.d.ts b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/Types.d.ts index d961ac77a6c..2f802adc12b 100644 --- a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/Types.d.ts +++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/Types.d.ts @@ -86,3 +86,9 @@ export type ApiPolicy = { parameters: any; uuid?: string; }; + +export type ApiLevelPolicy = { + request?: any[]; + response?: any[]; + fault?: any[]; +}; From e6bc5413d6420491025b7b3e8ce282c79689b3cb Mon Sep 17 00:00:00 2001 From: 1akshitha Date: Fri, 28 Apr 2023 10:36:52 +0530 Subject: [PATCH 2/9] Add support to simultaneously use API level and operation policies for API --- .../Apis/Details/Policies/Policies.tsx | 259 ++++++++++-------- .../Apis/Details/Policies/PoliciesSection.tsx | 177 ++++++++++++ .../Policies/components/PolicyPanel.tsx | 86 ++++++ 3 files changed, 405 insertions(+), 117 deletions(-) create mode 100644 portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/PoliciesSection.tsx create mode 100644 portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/components/PolicyPanel.tsx diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/Policies.tsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/Policies.tsx index 78af7fc9cef..9cb6a812122 100644 --- a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/Policies.tsx +++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/Policies.tsx @@ -16,26 +16,20 @@ * under the License. */ -import { - Grid, makeStyles, Typography, -} from '@material-ui/core'; +import { makeStyles, Typography } from '@material-ui/core'; import Alert from 'AppComponents/Shared/Alert'; import React, { useState, useEffect, useMemo } from 'react'; import cloneDeep from 'lodash.clonedeep'; import Paper from '@material-ui/core/Paper'; import Box from '@material-ui/core/Box'; import { useAPI } from 'AppComponents/Apis/Details/components/ApiContext'; -import { HTML5Backend } from 'react-dnd-html5-backend' +import { HTML5Backend } from 'react-dnd-html5-backend'; import { DndProvider } from 'react-dnd'; import { FormattedMessage } from 'react-intl'; -import CONSTS from 'AppData/Constants'; -import { isRestricted } from 'AppData/AuthManager'; import { mapAPIOperations } from 'AppComponents/Apis/Details/Resources/operationUtils'; import API from 'AppData/api'; import { Progress } from 'AppComponents/Shared'; import { arrayMove } from '@dnd-kit/sortable'; -import OperationPolicy from './OperationPolicy'; -import OperationsGroup from './OperationsGroup'; import PolicyList from './PolicyList'; import type { ApiPolicy, Policy, PolicySpec, ApiLevelPolicy } from './Types'; import GatewaySelector from './GatewaySelector'; @@ -43,11 +37,13 @@ import GranularitySelector from './GranularitySelector'; import { ApiOperationContextProvider } from './ApiOperationContext'; import { uuidv4 } from './Utils'; import SaveOperationPolicies from './SaveOperationPolicies'; -import PoliciesExpansion from './PoliciesExpansion'; +import Tabs from '@material-ui/core/Tabs'; +import Tab from '@material-ui/core/Tab'; +import PolicyPanel from './components/PolicyPanel'; const Configurations = require('Config'); -const useStyles = makeStyles(() => ({ +const useStyles = makeStyles((theme) => ({ gridItem: { display: 'flex', width: '100%', @@ -56,12 +52,35 @@ const useStyles = makeStyles(() => ({ overflowY: 'scroll', }, paper: { - padding:'2px' + padding: '2px', }, ccTypography: { - paddingLeft:'10px', - marginTop:'20px' - } + paddingLeft: '10px', + marginTop: '20px', + }, + titleWrapper: { + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + marginTop: '20px', + }, + tagClass: { + maxWidth: 1000, + overflow: 'hidden', + whiteSpace: 'nowrap', + textOverflow: 'ellipsis', + [theme.breakpoints.down('md')]: { + maxWidth: 800, + }, + }, + flowTabs: { + '& button': { + minWidth: 50, + }, + }, + flowTab: { + fontSize: 'smaller', + }, })); /** @@ -76,8 +95,9 @@ const Policies: React.FC = () => { const [allPolicies, setAllPolicies] = useState(null); const [expandedResource, setExpandedResource] = useState(null); const [isChoreoConnectEnabled, setIsChoreoConnectEnabled] = useState(api.gatewayType === 'wso2/choreo-connect'); - const [isAPILevelGranularitySelected, setIsAPILevelGranularitySelected] = useState(api.apiPolicies != null); + const [isAPILevelTabSelected, setIsAPILevelTabSelected] = useState(api.apiPolicies != null,); const { showMultiVersionPolicies } = Configurations.apis; + const [selectedTab, setSelectedTab] = useState(0); // If Choreo Connect radio button is selected in GatewaySelector, it will pass // value as true to render other UI changes specific to the Choreo Connect. @@ -85,9 +105,6 @@ const Policies: React.FC = () => { setIsChoreoConnectEnabled(isCCEnabled); } - const setIsChangedToAPILevelPolicies = (isAPILevelSelected: boolean) => { - setIsAPILevelGranularitySelected(isAPILevelSelected); - } /** * Function to get the initial state of all the operation policies from the API object. @@ -109,11 +126,11 @@ const Policies: React.FC = () => { const getInitAPILevelPoliciesState = () => { const clonedAPIPolicies = cloneDeep(api.apiPolicies); - if (api.apiPolicies != null) { + if (api.apiPolicies != null) { getInitPolicyState(clonedAPIPolicies); } return clonedAPIPolicies || initApiLevelPolicy; - } + }; const initApiLevelPolicy: ApiLevelPolicy = { request: [], @@ -211,7 +228,6 @@ const Policies: React.FC = () => { } const removeAPIPoliciesForGatewayChange = () => { - const newApiOperations: any = cloneDeep(apiOperations); // Set operation policies to the API object newApiOperations.forEach((operation: any) => { @@ -232,7 +248,10 @@ const Policies: React.FC = () => { useEffect(() => { fetchPolicies(); - }, [isChoreoConnectEnabled, isAPILevelGranularitySelected]) + if (isChoreoConnectEnabled) { + setSelectedTab(1); + } + }, [isChoreoConnectEnabled]); useEffect(() => { // Update the Swagger spec object when API object gets changed @@ -273,14 +292,13 @@ const Policies: React.FC = () => { const updateApiOperations = ( updatedOperation: any, target: string, verb: string, currentFlow: string, ) => { - const newApiOperations: any = cloneDeep(apiOperations); const newApiLevelPolicies: any = cloneDeep(apiLevelPolicies); - let operationInAction = (!isAPILevelGranularitySelected) ? newApiOperations.find((op: any) => + let operationInAction = (!isAPILevelTabSelected) ? newApiOperations.find((op: any) => op.target === target && op.verb.toLowerCase() === verb.toLowerCase()) : null; - const operationFlowPolicy = ((isAPILevelGranularitySelected) ? newApiLevelPolicies + const operationFlowPolicy = ((isAPILevelTabSelected) ? newApiLevelPolicies : operationInAction.operationPolicies)[currentFlow].find((p: any) => (p.policyId === updatedOperation.policyId && p.uuid === updatedOperation.uuid)); @@ -290,11 +308,11 @@ const Policies: React.FC = () => { } else { // Add new operation policy const uuid = uuidv4(); - ((isAPILevelGranularitySelected) ? newApiLevelPolicies : operationInAction.operationPolicies)[currentFlow].push({ ...updatedOperation, uuid }); + ((isAPILevelTabSelected) ? newApiLevelPolicies : operationInAction.operationPolicies)[currentFlow].push({ ...updatedOperation, uuid }); } // Finally update the state - (isAPILevelGranularitySelected) ? setApiLevelPolicies(newApiLevelPolicies) : setApiOperations(newApiOperations); + (isAPILevelTabSelected) ? setApiLevelPolicies(newApiLevelPolicies) : setApiOperations(newApiOperations); } /** @@ -326,7 +344,7 @@ const Policies: React.FC = () => { */ const deleteApiOperation = (uuid: string, target: string, verb: string, currentFlow: string) => { - if (isAPILevelGranularitySelected) { + if (isAPILevelTabSelected) { const newApiLevelPolicies: any = cloneDeep(apiLevelPolicies); const index = newApiLevelPolicies[currentFlow].map((p: any) => p.uuid).indexOf(uuid); newApiLevelPolicies[currentFlow].splice(index, 1); @@ -360,8 +378,7 @@ const Policies: React.FC = () => { const rearrangeApiOperations = ( oldIndex: number, newIndex: number, target: string, verb: string, currentFlow: string, ) => { - - if (isAPILevelGranularitySelected) { + if (isAPILevelTabSelected) { const newAPIPolicies: any = cloneDeep(apiLevelPolicies); const policyArray = newAPIPolicies[currentFlow]; newAPIPolicies[currentFlow] = arrayMove(policyArray, oldIndex, newIndex); @@ -374,7 +391,7 @@ const Policies: React.FC = () => { operationInAction.operationPolicies[currentFlow] = arrayMove(policyArray, oldIndex, newIndex); setApiOperations(newApiOperations); } - } + }; /** * To update the API object with the attached policies on Save. @@ -386,17 +403,14 @@ const Policies: React.FC = () => { let getewayTypeForPolicies = "wso2/synapse"; const getewayVendorForPolicies = "wso2"; - if (isAPILevelGranularitySelected) { - deletePolicyUuid(newApiLevelPolicies) - } else { - // Set operation policies to the API object - newApiOperations.forEach((operation: any, index: any, array: any) => { - if (operation.operationPolicies) { - const { operationPolicies } = operation; - deletePolicyUuid(operationPolicies) - } - }); - } + deletePolicyUuid(newApiLevelPolicies); + // Set operation policies to the API object + newApiOperations.forEach((operation: any, index: any, array: any) => { + if (operation.operationPolicies) { + const { operationPolicies } = operation; + deletePolicyUuid(operationPolicies); + } + }); // Handles normal policy savings for choreo connect gateway type. if(isChoreoConnectEnabled) { @@ -405,15 +419,14 @@ const Policies: React.FC = () => { const updatePromise = updateAPI({ apiPolicies: newApiLevelPolicies, - operations: newApiOperations, - gatewayVendor: getewayVendorForPolicies, - gatewayType: getewayTypeForPolicies}); - updatePromise - .finally(() => { - setUpdating(false); - }); - } - + operations: newApiOperations, + gatewayVendor: getewayVendorForPolicies, + gatewayType: getewayTypeForPolicies, + }); + updatePromise.finally(() => { + setUpdating(false); + }); + }; const deletePolicyUuid = (operationPolicies: any) => { // Iterating through the policy list of request flow, response flow and fault flow @@ -428,7 +441,7 @@ const Policies: React.FC = () => { }); } } - } + }; // handles operations (verbs) for CC policy expansion. const handleVerbsForCC = (verbObject: any) => { @@ -440,6 +453,11 @@ const Policies: React.FC = () => { return array[0] } + const handleTabChange = (tab: number) => { + setIsAPILevelTabSelected(tab === 0); + setSelectedTab(tab); + }; + /** * To memoize the value passed into ApiOperationContextProvider */ @@ -476,75 +494,82 @@ const Policies: React.FC = () => { /> )} - - - - - + + - {isAPILevelGranularitySelected ? ( - - - + + handleTabChange(tab) + } + indicatorColor="primary" + textColor="primary" + variant="fullWidth" + aria-label="Policies local to API" + className={classes.flowTabs} + > + + API Level Policies + + } + id="request-tab" + aria-controls="request-tabpanel" + disabled={isChoreoConnectEnabled} + /> + + Operation Level Policies + + } + id="response-tab" + aria-controls="response-tabpanel" + /> + + + + - - - ) : - (Object.entries(openAPISpec.paths).map(([target, verbObject]: [string, any]) => ( - - - - {Object.entries(verbObject).map(([verb, operation]) => { - return CONSTS.HTTP_METHODS.includes(verb) ? ( - - - - ) : null; - })} - - - - )))} + + diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/PoliciesSection.tsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/PoliciesSection.tsx new file mode 100644 index 00000000000..b3f4f76f48f --- /dev/null +++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/PoliciesSection.tsx @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2022, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. 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 { + Grid, makeStyles, Typography, +} from '@material-ui/core'; +import React, { FC } from 'react'; +import Paper from '@material-ui/core/Paper'; +import Box from '@material-ui/core/Box'; +import CONSTS from 'AppData/Constants'; +import { isRestricted } from 'AppData/AuthManager'; +import OperationPolicy from './OperationPolicy'; +import OperationsGroup from './OperationsGroup'; +import PolicyList from './PolicyList'; +import type {Policy, PolicySpec } from './Types'; +import PoliciesExpansion from './PoliciesExpansion'; + +const Configurations = require('Config'); + +const useStyles = makeStyles((theme) => ({ + gridItem: { + display: 'flex', + width: '100%', + }, + operationListingBox: { + overflowY: 'scroll', + }, + paper: { + padding:'2px' + }, + ccTypography: { + paddingLeft:'10px', + marginTop:'20px' + }, + titleWrapper: { + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + marginTop:'20px' + }, + tagClass: { + maxWidth: 1000, + overflow: 'hidden', + whiteSpace: 'nowrap', + textOverflow: 'ellipsis', + [theme.breakpoints.down('md')]: { + maxWidth: 800, + }, + }, + flowTabs: { + '& button': { + minWidth: 50, + }, + }, +})); + +interface PolicySectionProps { + openAPISpec: any; + isChoreoConnectEnabled: boolean; + isAPILevelGranularitySelected: boolean; + allPolicies: PolicySpec[] | null; + policyList: Policy[]; + api: any; + expandedResource: string | null; + setExpandedResource: React.Dispatch>; + fetchPolicies: () => void; + +} + +/** + * Renders the policy management page. + * @returns {TSX} Policy management page to render. + */ +const PoliciesSection: FC = ({ + openAPISpec, + isChoreoConnectEnabled, + isAPILevelGranularitySelected, + allPolicies, + policyList, + api, + expandedResource, + setExpandedResource, + fetchPolicies, + }) => { + const classes = useStyles(); + let borderColor = ""; + + return ( + + {isAPILevelGranularitySelected ? ( + + + + + + + + + ) : ( + + {Object.entries(openAPISpec.paths).map( + ([target, verbObject]: [string, any]) => ( + + + + {Object.entries(verbObject).map(([verb, operation]) => { + return CONSTS.HTTP_METHODS.includes(verb) ? ( + + + + ) : null; + })} + + + + ) + )} + + )} + + ); + }; + + + +export default PoliciesSection; diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/components/PolicyPanel.tsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/components/PolicyPanel.tsx new file mode 100644 index 00000000000..ec51fe6d28a --- /dev/null +++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/components/PolicyPanel.tsx @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2022, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. 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 { Box } from '@material-ui/core'; +import React, { FC } from 'react'; +import DraggablePolicyCard from '../DraggablePolicyCard'; +import PoliciesSection from '../PoliciesSection'; +import type { Policy, PolicySpec } from '../Types'; + +interface PolicyPanelProps { + children?: React.ReactNode; + index: number; + selectedTab: number; + openAPISpec: any; + isChoreoConnectEnabled: boolean; + isAPILevelGranularitySelected: boolean; + allPolicies: PolicySpec[] | null; + policyList: Policy[]; + api: any; + expandedResource: string | null; + setExpandedResource: React.Dispatch>; + fetchPolicies: () => void; +} + +/** + * Tab panel component to render content of a particular tab. + * Renders the available policy list under the relevant flow related tab (i.e. request, response or fault). + * @param {JSON} props Input props from parent components. + * @returns {TSX} Tab panel. + */ +const PolicyPanel: FC = ({ + index, + selectedTab, + openAPISpec, + isChoreoConnectEnabled, + isAPILevelGranularitySelected, + allPolicies, + policyList, + api, + expandedResource, + setExpandedResource, + fetchPolicies, +}) => { + const flowNames = ['request', 'response', 'fault']; + const currentFlow = flowNames[index]; + + return ( + + ); +}; + +export default PolicyPanel; From 8697bb2bfb818ce20064357852b0ef5203c703c3 Mon Sep 17 00:00:00 2001 From: 1akshitha Date: Fri, 28 Apr 2023 10:45:39 +0530 Subject: [PATCH 3/9] Clean unused imports, format the code --- .../Details/Policies/GranularitySelector.tsx | 234 ------------------ .../Apis/Details/Policies/Policies.tsx | 2 - .../Apis/Details/Policies/PoliciesSection.tsx | 122 +++++---- .../Policies/components/PolicyPanel.tsx | 18 +- 4 files changed, 65 insertions(+), 311 deletions(-) delete mode 100644 portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/GranularitySelector.tsx diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/GranularitySelector.tsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/GranularitySelector.tsx deleted file mode 100644 index b821ec8395c..00000000000 --- a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/GranularitySelector.tsx +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Copyright (c) 2022, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. - * - * WSO2 Inc. 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 React, { FC, useState } from 'react'; -import { HelpOutline } from '@material-ui/icons'; -import Tooltip from '@material-ui/core/Tooltip'; -import { - Dialog, - DialogTitle, - DialogContent, - Button, - DialogActions, - Radio, -} from '@material-ui/core'; -import Paper from '@material-ui/core/Paper'; -import Box from '@material-ui/core/Box'; -import Typography from '@material-ui/core/Typography'; -import IconButton from '@material-ui/core/IconButton'; -import Grid from '@material-ui/core/Grid'; -import FormControl from '@material-ui/core/FormControl'; -import RadioGroup from '@material-ui/core/RadioGroup'; -import FormControlLabel from '@material-ui/core/FormControlLabel'; -import { isRestricted } from 'AppData/AuthManager'; -import { useAPI } from 'AppComponents/Apis/Details/components/ApiContext'; -import { FormattedMessage } from 'react-intl'; - -const GranularityTypes = { - APILevel: 'API Level', - OperationLevel: 'Operation Level', -}; - -interface GranularitySelectorProps { - setIsChangedToAPILevel: (isAPILevel: boolean) => void; - isAPILevelPoliciesSelected: boolean; - removeAPIPoliciesForGatewayChange: () => void; -} - -/** - * Renders the Gateway selection section. - * @param {JSON} props Input props from parent components. - * @returns {TSX} Radio group for the API Gateway. - */ -const GranularitySelector: FC = ({ - setIsChangedToAPILevel, - isAPILevelPoliciesSelected, - removeAPIPoliciesForGatewayChange -}) => { - const [apiFromContext] = useAPI(); - let selectedGatewayType; - - const [isDialogBoxVisible, setIsDialogBoxVisible] = useState(false); - // This state is maintained until user gived approval for gateway change. - // Without this state radio buttons will switch even user disagrees to proceed gateway change. - const [isAPILevelSelected, setIsAPILevelSelected] = useState(false); - - const saveAfterGatewayChange = () => { - if (isAPILevelSelected) { - setIsChangedToAPILevel(true); - } else { - setIsChangedToAPILevel(false); - } - removeAPIPoliciesForGatewayChange(); - setIsDialogBoxVisible(false); - } - - if (isAPILevelPoliciesSelected) { - selectedGatewayType = GranularityTypes.APILevel; - } else { - selectedGatewayType = GranularityTypes.OperationLevel; - } - - /** - * Handles accepted gateway type change after approving dialog box. - * @param {event: React.ChangeEvent} event Indicates gateway type radio button change event. - */ - const handleDialogBox = (event: React.ChangeEvent) => { - if(event.target.value === GranularityTypes.APILevel) { - setIsAPILevelSelected(true) - } else { - setIsAPILevelSelected(false); - } - setIsDialogBoxVisible(true); - } - - /** - * Handles discarded gateway type change after cancelling dialog box. - */ - const handleDiscardedGatewayChange = () => { - setIsDialogBoxVisible(false); - }; - - return ( - - - - - - - Policy Granularity - - - - - - - - - - - - } - label='API Level' - labelPlacement='end' - /> - - } - label='Operation Level' - labelPlacement='end' - /> - - - - - - - - - - - - - - - - - - - - - - - - ); -}; - -export default GranularitySelector; diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/Policies.tsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/Policies.tsx index 9cb6a812122..6d794f2dfc9 100644 --- a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/Policies.tsx +++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/Policies.tsx @@ -549,7 +549,6 @@ const Policies: React.FC = () => { setExpandedResource={ setExpandedResource } - fetchPolicies={fetchPolicies} /> { setExpandedResource={ setExpandedResource } - fetchPolicies={fetchPolicies} /> diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/PoliciesSection.tsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/PoliciesSection.tsx index b3f4f76f48f..f6e05418f56 100644 --- a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/PoliciesSection.tsx +++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/PoliciesSection.tsx @@ -20,18 +20,14 @@ import { Grid, makeStyles, Typography, } from '@material-ui/core'; import React, { FC } from 'react'; -import Paper from '@material-ui/core/Paper'; import Box from '@material-ui/core/Box'; import CONSTS from 'AppData/Constants'; import { isRestricted } from 'AppData/AuthManager'; import OperationPolicy from './OperationPolicy'; import OperationsGroup from './OperationsGroup'; -import PolicyList from './PolicyList'; import type {Policy, PolicySpec } from './Types'; import PoliciesExpansion from './PoliciesExpansion'; -const Configurations = require('Config'); - const useStyles = makeStyles((theme) => ({ gridItem: { display: 'flex', @@ -78,7 +74,6 @@ interface PolicySectionProps { api: any; expandedResource: string | null; setExpandedResource: React.Dispatch>; - fetchPolicies: () => void; } @@ -95,19 +90,42 @@ const PoliciesSection: FC = ({ api, expandedResource, setExpandedResource, - fetchPolicies, - }) => { +}) => { const classes = useStyles(); let borderColor = ""; - + return ( {isAPILevelGranularitySelected ? ( - + - + + + + + + + ) : ( + + {Object.entries(openAPISpec.paths).map( + ([target, verbObject]: [string, any]) => ( + + = ({ spacing={1} alignItems="stretch" > - + {Object.entries(verbObject).map(([verb, operation]) => { + return CONSTS.HTTP_METHODS.includes(verb) ? ( + + + + ) : null; + })} - - - ) : ( - - {Object.entries(openAPISpec.paths).map( - ([target, verbObject]: [string, any]) => ( - - - - {Object.entries(verbObject).map(([verb, operation]) => { - return CONSTS.HTTP_METHODS.includes(verb) ? ( - - - - ) : null; - })} - - - + + ) )} - - )} + + )} ); - }; - +}; + export default PoliciesSection; diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/components/PolicyPanel.tsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/components/PolicyPanel.tsx index ec51fe6d28a..a33966d8e4a 100644 --- a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/components/PolicyPanel.tsx +++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/components/PolicyPanel.tsx @@ -1,7 +1,7 @@ /* - * Copyright (c) 2022, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. * - * WSO2 Inc. licenses this file to you under the Apache License, + * 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 @@ -18,7 +18,6 @@ import { Box } from '@material-ui/core'; import React, { FC } from 'react'; -import DraggablePolicyCard from '../DraggablePolicyCard'; import PoliciesSection from '../PoliciesSection'; import type { Policy, PolicySpec } from '../Types'; @@ -34,12 +33,11 @@ interface PolicyPanelProps { api: any; expandedResource: string | null; setExpandedResource: React.Dispatch>; - fetchPolicies: () => void; } /** * Tab panel component to render content of a particular tab. - * Renders the available policy list under the relevant flow related tab (i.e. request, response or fault). + * Renders the policy section under the relevant tab (i.e. API Level or Operation Level). * @param {JSON} props Input props from parent components. * @returns {TSX} Tab panel. */ @@ -54,17 +52,16 @@ const PolicyPanel: FC = ({ api, expandedResource, setExpandedResource, - fetchPolicies, }) => { - const flowNames = ['request', 'response', 'fault']; - const currentFlow = flowNames[index]; + const tabs = ['api-level', 'operation-level']; + const currentTab = tabs[index]; return ( From b9166d3669e20f26be8bc26701e67630c3e21fb2 Mon Sep 17 00:00:00 2001 From: 1akshitha Date: Fri, 28 Apr 2023 15:46:54 +0530 Subject: [PATCH 4/9] Add an info message to mention the order of execution of policies --- .../Apis/Details/Policies/Policies.tsx | 1 - .../Apis/Details/Policies/PoliciesSection.tsx | 53 +++++++------------ 2 files changed, 20 insertions(+), 34 deletions(-) diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/Policies.tsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/Policies.tsx index 6d794f2dfc9..c54216abc8e 100644 --- a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/Policies.tsx +++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/Policies.tsx @@ -33,7 +33,6 @@ import { arrayMove } from '@dnd-kit/sortable'; import PolicyList from './PolicyList'; import type { ApiPolicy, Policy, PolicySpec, ApiLevelPolicy } from './Types'; import GatewaySelector from './GatewaySelector'; -import GranularitySelector from './GranularitySelector'; import { ApiOperationContextProvider } from './ApiOperationContext'; import { uuidv4 } from './Utils'; import SaveOperationPolicies from './SaveOperationPolicies'; diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/PoliciesSection.tsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/PoliciesSection.tsx index f6e05418f56..0aa8e5b78c9 100644 --- a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/PoliciesSection.tsx +++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/PoliciesSection.tsx @@ -27,42 +27,21 @@ import OperationPolicy from './OperationPolicy'; import OperationsGroup from './OperationsGroup'; import type {Policy, PolicySpec } from './Types'; import PoliciesExpansion from './PoliciesExpansion'; +import MuiAlert from 'AppComponents/Shared/MuiAlert'; +import { FormattedMessage } from 'react-intl'; +import Alert from '@material-ui/lab/Alert'; -const useStyles = makeStyles((theme) => ({ + + + +const useStyles = makeStyles((theme:any) => ({ gridItem: { display: 'flex', width: '100%', }, - operationListingBox: { - overflowY: 'scroll', - }, - paper: { - padding:'2px' - }, - ccTypography: { - paddingLeft:'10px', - marginTop:'20px' - }, - titleWrapper: { - display: 'flex', - flexDirection: 'row', - alignItems: 'center', - marginTop:'20px' - }, - tagClass: { - maxWidth: 1000, - overflow: 'hidden', - whiteSpace: 'nowrap', - textOverflow: 'ellipsis', - [theme.breakpoints.down('md')]: { - maxWidth: 800, - }, - }, - flowTabs: { - '& button': { - minWidth: 50, - }, - }, + alert: { + backgroundColor: 'transparent' + } })); interface PolicySectionProps { @@ -100,7 +79,9 @@ const PoliciesSection: FC = ({ - + + API level policies will execute before Operation Level Policies + = ({ ) : ( - + + {!isChoreoConnectEnabled && ( + + API level policies will execute before Operation Level Policies + )} {Object.entries(openAPISpec.paths).map( ([target, verbObject]: [string, any]) => ( From a44a75dad7645e413ba03f32410bce68143a5b18 Mon Sep 17 00:00:00 2001 From: 1akshitha Date: Mon, 8 May 2023 13:51:40 +0530 Subject: [PATCH 5/9] latest changes --- .../Apis/Details/Policies/Policies.tsx | 64 +++------ .../Apis/Details/Policies/PoliciesSection.tsx | 122 ++++++++---------- .../Policies/components/PolicyPanel.tsx | 6 +- 3 files changed, 76 insertions(+), 116 deletions(-) diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/Policies.tsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/Policies.tsx index c54216abc8e..557796f0b93 100644 --- a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/Policies.tsx +++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/Policies.tsx @@ -57,21 +57,6 @@ const useStyles = makeStyles((theme) => ({ paddingLeft: '10px', marginTop: '20px', }, - titleWrapper: { - display: 'flex', - flexDirection: 'row', - alignItems: 'center', - marginTop: '20px', - }, - tagClass: { - maxWidth: 1000, - overflow: 'hidden', - whiteSpace: 'nowrap', - textOverflow: 'ellipsis', - [theme.breakpoints.down('md')]: { - maxWidth: 800, - }, - }, flowTabs: { '& button': { minWidth: 50, @@ -94,9 +79,9 @@ const Policies: React.FC = () => { const [allPolicies, setAllPolicies] = useState(null); const [expandedResource, setExpandedResource] = useState(null); const [isChoreoConnectEnabled, setIsChoreoConnectEnabled] = useState(api.gatewayType === 'wso2/choreo-connect'); - const [isAPILevelTabSelected, setIsAPILevelTabSelected] = useState(api.apiPolicies != null,); + const [isAPILevelTabSelected, setIsAPILevelTabSelected] = useState(api.apiPolicies != null); const { showMultiVersionPolicies } = Configurations.apis; - const [selectedTab, setSelectedTab] = useState(0); + const [selectedTab, setSelectedTab] = useState((api.apiPolicies != null) ? 0 : 1); // If Choreo Connect radio button is selected in GatewaySelector, it will pass // value as true to render other UI changes specific to the Choreo Connect. @@ -297,15 +282,15 @@ const Policies: React.FC = () => { let operationInAction = (!isAPILevelTabSelected) ? newApiOperations.find((op: any) => op.target === target && op.verb.toLowerCase() === verb.toLowerCase()) : null; - const operationFlowPolicy = ((isAPILevelTabSelected) ? newApiLevelPolicies - : operationInAction.operationPolicies)[currentFlow].find((p: any) => (p.policyId === updatedOperation.policyId + const flowPolicy = ((isAPILevelTabSelected) ? newApiLevelPolicies + : operationInAction.operationPolicies)[currentFlow].find((p: any) => (p.policyId === updatedOperation.policyId && p.uuid === updatedOperation.uuid)); - if (operationFlowPolicy) { - // Edit operation policy - operationFlowPolicy.parameters = { ...updatedOperation.parameters }; + if (flowPolicy) { + // Edit policy + flowPolicy.parameters = { ...updatedOperation.parameters }; } else { - // Add new operation policy + // Add new policy const uuid = uuidv4(); ((isAPILevelTabSelected) ? newApiLevelPolicies : operationInAction.operationPolicies)[currentFlow].push({ ...updatedOperation, uuid }); } @@ -416,15 +401,16 @@ const Policies: React.FC = () => { getewayTypeForPolicies = "wso2/choreo-connect"; } - const updatePromise = updateAPI({ - apiPolicies: newApiLevelPolicies, + const updatePromise = updateAPI({ operations: newApiOperations, + apiPolicies: newApiLevelPolicies, gatewayVendor: getewayVendorForPolicies, - gatewayType: getewayTypeForPolicies, - }); - updatePromise.finally(() => { - setUpdating(false); + gatewayType: getewayTypeForPolicies }); + updatePromise + .finally(() => { + setUpdating(false); + }); }; const deletePolicyUuid = (operationPolicies: any) => { @@ -494,11 +480,7 @@ const Policies: React.FC = () => { )} - + { aria-controls="response-tabpanel" /> - + { index={1} selectedTab={selectedTab} openAPISpec={openAPISpec} - isChoreoConnectEnabled={ - isChoreoConnectEnabled - } - isAPILevelGranularitySelected={false} + isChoreoConnectEnabled={isChoreoConnectEnabled} + isAPILevelTabSelected={false} allPolicies={allPolicies} policyList={policies} api={localAPI} diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/PoliciesSection.tsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/PoliciesSection.tsx index 0aa8e5b78c9..5f92f214bc4 100644 --- a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/PoliciesSection.tsx +++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/PoliciesSection.tsx @@ -1,7 +1,7 @@ /* - * Copyright (c) 2022, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. * - * WSO2 Inc. licenses this file to you under the Apache License, + * 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 @@ -16,44 +16,36 @@ * under the License. */ -import { - Grid, makeStyles, Typography, -} from '@material-ui/core'; +import { Grid, makeStyles, Typography } from '@material-ui/core'; import React, { FC } from 'react'; import Box from '@material-ui/core/Box'; import CONSTS from 'AppData/Constants'; import { isRestricted } from 'AppData/AuthManager'; import OperationPolicy from './OperationPolicy'; import OperationsGroup from './OperationsGroup'; -import type {Policy, PolicySpec } from './Types'; +import type { Policy, PolicySpec } from './Types'; import PoliciesExpansion from './PoliciesExpansion'; -import MuiAlert from 'AppComponents/Shared/MuiAlert'; -import { FormattedMessage } from 'react-intl'; import Alert from '@material-ui/lab/Alert'; - - - -const useStyles = makeStyles((theme:any) => ({ +const useStyles = makeStyles((theme: any) => ({ gridItem: { display: 'flex', width: '100%', }, alert: { - backgroundColor: 'transparent' - } + backgroundColor: 'transparent', + }, })); interface PolicySectionProps { openAPISpec: any; isChoreoConnectEnabled: boolean; - isAPILevelGranularitySelected: boolean; + isAPILevelTabSelected: boolean; allPolicies: PolicySpec[] | null; policyList: Policy[]; api: any; expandedResource: string | null; setExpandedResource: React.Dispatch>; - } /** @@ -63,7 +55,7 @@ interface PolicySectionProps { const PoliciesSection: FC = ({ openAPISpec, isChoreoConnectEnabled, - isAPILevelGranularitySelected, + isAPILevelTabSelected, allPolicies, policyList, api, @@ -71,28 +63,21 @@ const PoliciesSection: FC = ({ setExpandedResource, }) => { const classes = useStyles(); - let borderColor = ""; + let borderColor = ''; return ( - {isAPILevelGranularitySelected ? ( - - - API level policies will execute before Operation Level Policies - = ({ ) : ( - - {!isChoreoConnectEnabled && ( - - API level policies will execute before Operation Level Policies - )} + + {!isChoreoConnectEnabled && ( + + API level policies will execute before Operation + Level Policies + + )} {Object.entries(openAPISpec.paths).map( ([target, verbObject]: [string, any]) => ( - - - {Object.entries(verbObject).map(([verb, operation]) => { - return CONSTS.HTTP_METHODS.includes(verb) ? ( - - - - ) : null; - })} + + + {Object.entries(verbObject).map( + ([verb, operation]) => { + return CONSTS.HTTP_METHODS.includes( + verb, + ) ? ( + + + + ) : null; + }, + )} - ) + ), )} )} @@ -153,6 +137,4 @@ const PoliciesSection: FC = ({ ); }; - - export default PoliciesSection; diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/components/PolicyPanel.tsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/components/PolicyPanel.tsx index a33966d8e4a..3d91221a3f5 100644 --- a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/components/PolicyPanel.tsx +++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/components/PolicyPanel.tsx @@ -27,7 +27,7 @@ interface PolicyPanelProps { selectedTab: number; openAPISpec: any; isChoreoConnectEnabled: boolean; - isAPILevelGranularitySelected: boolean; + isAPILevelTabSelected: boolean; allPolicies: PolicySpec[] | null; policyList: Policy[]; api: any; @@ -46,7 +46,7 @@ const PolicyPanel: FC = ({ selectedTab, openAPISpec, isChoreoConnectEnabled, - isAPILevelGranularitySelected, + isAPILevelTabSelected, allPolicies, policyList, api, @@ -67,7 +67,7 @@ const PolicyPanel: FC = ({ Date: Tue, 9 May 2023 11:00:59 +0530 Subject: [PATCH 6/9] remove duplicate state and fix the margins of alert --- .../Apis/Details/Policies/Policies.tsx | 22 ++++++++++--------- .../Apis/Details/Policies/PoliciesSection.tsx | 4 +++- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/Policies.tsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/Policies.tsx index 557796f0b93..03155304fb7 100644 --- a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/Policies.tsx +++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/Policies.tsx @@ -79,7 +79,6 @@ const Policies: React.FC = () => { const [allPolicies, setAllPolicies] = useState(null); const [expandedResource, setExpandedResource] = useState(null); const [isChoreoConnectEnabled, setIsChoreoConnectEnabled] = useState(api.gatewayType === 'wso2/choreo-connect'); - const [isAPILevelTabSelected, setIsAPILevelTabSelected] = useState(api.apiPolicies != null); const { showMultiVersionPolicies } = Configurations.apis; const [selectedTab, setSelectedTab] = useState((api.apiPolicies != null) ? 0 : 1); @@ -89,6 +88,10 @@ const Policies: React.FC = () => { setIsChoreoConnectEnabled(isCCEnabled); } + //Tabs + const apiLevelTab = 0; + const operationLevelTab = 1; + /** * Function to get the initial state of all the operation policies from the API object. @@ -279,10 +282,10 @@ const Policies: React.FC = () => { const newApiOperations: any = cloneDeep(apiOperations); const newApiLevelPolicies: any = cloneDeep(apiLevelPolicies); - let operationInAction = (!isAPILevelTabSelected) ? newApiOperations.find((op: any) => + let operationInAction = (selectedTab == operationLevelTab) ? newApiOperations.find((op: any) => op.target === target && op.verb.toLowerCase() === verb.toLowerCase()) : null; - const flowPolicy = ((isAPILevelTabSelected) ? newApiLevelPolicies + const flowPolicy = ((selectedTab == apiLevelTab) ? newApiLevelPolicies : operationInAction.operationPolicies)[currentFlow].find((p: any) => (p.policyId === updatedOperation.policyId && p.uuid === updatedOperation.uuid)); @@ -292,11 +295,11 @@ const Policies: React.FC = () => { } else { // Add new policy const uuid = uuidv4(); - ((isAPILevelTabSelected) ? newApiLevelPolicies : operationInAction.operationPolicies)[currentFlow].push({ ...updatedOperation, uuid }); + ((selectedTab == apiLevelTab) ? newApiLevelPolicies : operationInAction.operationPolicies)[currentFlow].push({ ...updatedOperation, uuid }); } // Finally update the state - (isAPILevelTabSelected) ? setApiLevelPolicies(newApiLevelPolicies) : setApiOperations(newApiOperations); + (selectedTab == apiLevelTab) ? setApiLevelPolicies(newApiLevelPolicies) : setApiOperations(newApiOperations); } /** @@ -328,7 +331,7 @@ const Policies: React.FC = () => { */ const deleteApiOperation = (uuid: string, target: string, verb: string, currentFlow: string) => { - if (isAPILevelTabSelected) { + if (selectedTab == apiLevelTab) { const newApiLevelPolicies: any = cloneDeep(apiLevelPolicies); const index = newApiLevelPolicies[currentFlow].map((p: any) => p.uuid).indexOf(uuid); newApiLevelPolicies[currentFlow].splice(index, 1); @@ -362,7 +365,7 @@ const Policies: React.FC = () => { const rearrangeApiOperations = ( oldIndex: number, newIndex: number, target: string, verb: string, currentFlow: string, ) => { - if (isAPILevelTabSelected) { + if (selectedTab == apiLevelTab) { const newAPIPolicies: any = cloneDeep(apiLevelPolicies); const policyArray = newAPIPolicies[currentFlow]; newAPIPolicies[currentFlow] = arrayMove(policyArray, oldIndex, newIndex); @@ -439,7 +442,6 @@ const Policies: React.FC = () => { } const handleTabChange = (tab: number) => { - setIsAPILevelTabSelected(tab === 0); setSelectedTab(tab); }; @@ -516,7 +518,7 @@ const Policies: React.FC = () => { { } /> ({ }, alert: { backgroundColor: 'transparent', + marginTop: '-25px', + marginBottom: '-15px', }, })); @@ -90,7 +92,7 @@ const PoliciesSection: FC = ({ {!isChoreoConnectEnabled && ( - + API level policies will execute before Operation Level Policies From f37c3f56c003dfc07453b41f0a450fadad908db6 Mon Sep 17 00:00:00 2001 From: 1akshitha Date: Fri, 12 May 2023 16:15:18 +0530 Subject: [PATCH 7/9] Address review comments --- .../publisher/src/main/webapp/site/public/locales/en.json | 6 ++++++ .../src/main/webapp/site/public/locales/raw.en.json | 3 +++ .../components/Apis/Details/Policies/PoliciesSection.tsx | 8 ++++++-- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/portals/publisher/src/main/webapp/site/public/locales/en.json b/portals/publisher/src/main/webapp/site/public/locales/en.json index 262a712f542..f6e9d7ac363 100644 --- a/portals/publisher/src/main/webapp/site/public/locales/en.json +++ b/portals/publisher/src/main/webapp/site/public/locales/en.json @@ -5711,6 +5711,12 @@ "value": "Response Flow" } ], + "Apis.Details.Policies.PoliciesSection.info": [ + { + "type": 0, + "value": "API level policies will execute before operation level policies" + } + ], "Apis.Details.Policies.PolicyConfigurationEditDrawer.title": [ { "type": 0, diff --git a/portals/publisher/src/main/webapp/site/public/locales/raw.en.json b/portals/publisher/src/main/webapp/site/public/locales/raw.en.json index 4a355f58c1e..4f90455c036 100644 --- a/portals/publisher/src/main/webapp/site/public/locales/raw.en.json +++ b/portals/publisher/src/main/webapp/site/public/locales/raw.en.json @@ -2712,6 +2712,9 @@ "Apis.Details.Policies.PoliciesExpansion.response.flow.title": { "defaultMessage": "Response Flow" }, + "Apis.Details.Policies.PoliciesSection.info": { + "defaultMessage": "API level policies will execute before operation level policies" + }, "Apis.Details.Policies.PolicyConfigurationEditDrawer.title": { "defaultMessage": "Configure {policy}" }, diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/PoliciesSection.tsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/PoliciesSection.tsx index 0d900b31bcf..6bbab79aa1f 100644 --- a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/PoliciesSection.tsx +++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/PoliciesSection.tsx @@ -26,6 +26,7 @@ import OperationsGroup from './OperationsGroup'; import type { Policy, PolicySpec } from './Types'; import PoliciesExpansion from './PoliciesExpansion'; import Alert from '@material-ui/lab/Alert'; +import { FormattedMessage } from 'react-intl'; const useStyles = makeStyles((theme: any) => ({ gridItem: { @@ -93,8 +94,11 @@ const PoliciesSection: FC = ({ > {!isChoreoConnectEnabled && ( - API level policies will execute before Operation - Level Policies + + )} {Object.entries(openAPISpec.paths).map( From e832653be46e405e65fe09e1a0cf56de4b0d61ca Mon Sep 17 00:00:00 2001 From: Ashera Silva Date: Mon, 19 Jun 2023 19:57:18 +0530 Subject: [PATCH 8/9] Refactor codebase --- .../Policies/AttachedPolicyForm/General.tsx | 13 +- .../Apis/Details/Policies/Policies.tsx | 180 ++++++++++-------- .../Details/Policies/PoliciesExpansion.tsx | 10 +- .../Apis/Details/Policies/PoliciesSection.tsx | 101 +++++----- 4 files changed, 163 insertions(+), 141 deletions(-) diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/AttachedPolicyForm/General.tsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/AttachedPolicyForm/General.tsx index 6a32ccec0e7..3bdb75f82a1 100644 --- a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/AttachedPolicyForm/General.tsx +++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/AttachedPolicyForm/General.tsx @@ -72,7 +72,16 @@ interface GeneralProps { } const General: FC = ({ - policyObj, setDroppedPolicy, currentFlow, target, verb, apiPolicy, policySpec, handleDrawerClose, isEditMode, isAPILevelPolicy + policyObj, + setDroppedPolicy, + currentFlow, + target, + verb, + apiPolicy, + policySpec, + handleDrawerClose, + isEditMode, + isAPILevelPolicy, }) => { const intl = useIntl(); const classes = useStyles(); @@ -335,7 +344,7 @@ const General: FC = ({ name={spec.name} type={spec.type.toLowerCase() === 'integer' ? 'number' : 'text'} value={getValue(spec)} - onChange={(e) => onInputChange(e, spec.type)} + onChange={(e: any) => onInputChange(e, spec.type)} fullWidth /> )} diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/Policies.tsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/Policies.tsx index 03155304fb7..8cb373a33fe 100644 --- a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/Policies.tsx +++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/Policies.tsx @@ -30,19 +30,19 @@ import { mapAPIOperations } from 'AppComponents/Apis/Details/Resources/operation import API from 'AppData/api'; import { Progress } from 'AppComponents/Shared'; import { arrayMove } from '@dnd-kit/sortable'; +import Tabs from '@material-ui/core/Tabs'; +import Tab from '@material-ui/core/Tab'; import PolicyList from './PolicyList'; import type { ApiPolicy, Policy, PolicySpec, ApiLevelPolicy } from './Types'; import GatewaySelector from './GatewaySelector'; import { ApiOperationContextProvider } from './ApiOperationContext'; import { uuidv4 } from './Utils'; import SaveOperationPolicies from './SaveOperationPolicies'; -import Tabs from '@material-ui/core/Tabs'; -import Tab from '@material-ui/core/Tab'; import PolicyPanel from './components/PolicyPanel'; const Configurations = require('Config'); -const useStyles = makeStyles((theme) => ({ +const useStyles = makeStyles(() => ({ gridItem: { display: 'flex', width: '100%', @@ -88,10 +88,28 @@ const Policies: React.FC = () => { setIsChoreoConnectEnabled(isCCEnabled); } - //Tabs + // Tabs const apiLevelTab = 0; const operationLevelTab = 1; + const initApiLevelPolicy: ApiLevelPolicy = { + request: [], + response: [], + fault: [], + } + + const getInitPolicyState = (policyList: any) => { + // Iterating through the policy list of request flow, response flow and fault flow + for (const flow in policyList) { + if (Object.prototype.hasOwnProperty.call(policyList, flow)) { + const policyArray = policyList[flow]; + policyArray.forEach((policyItem: ApiPolicy) => { + // eslint-disable-next-line no-param-reassign + policyItem.uuid = uuidv4(); + }); + } + } + } /** * Function to get the initial state of all the operation policies from the API object. @@ -119,25 +137,6 @@ const Policies: React.FC = () => { return clonedAPIPolicies || initApiLevelPolicy; }; - const initApiLevelPolicy: ApiLevelPolicy = { - request: [], - response: [], - fault: [], - }; - - const getInitPolicyState = (policyList: any) => { - // Iterating through the policy list of request flow, response flow and fault flow - for (const flow in policyList) { - if (Object.prototype.hasOwnProperty.call(policyList, flow)) { - const policyArray = policyList[flow]; - policyArray.forEach((policyItem: ApiPolicy) => { - // eslint-disable-next-line no-param-reassign - policyItem.uuid = uuidv4(); - }); - } - } - } - const [apiOperations, setApiOperations] = useState(getInitState); const [apiLevelPolicies, setApiLevelPolicies] = useState(getInitAPILevelPoliciesState); const [openAPISpec, setOpenAPISpec] = useState(null); @@ -171,11 +170,11 @@ const Policies: React.FC = () => { if (showMultiVersionPolicies) { // Get the union of policies depending on the policy display name and version unionByPolicyDisplayName = [...mergedList - .reduce((map, obj) => map.set(obj.name + obj.version, obj), new Map()).values()]; + .reduce((map, obj) => map.set(obj.name + obj.version, obj), new Map()).values()]; } else { // Get the union of policies depending on the policy display name unionByPolicyDisplayName = [...mergedList - .reduce((map, obj) => map.set(obj.name, obj), new Map()).values()]; + .reduce((map, obj) => map.set(obj.name, obj), new Map()).values()]; } unionByPolicyDisplayName.sort( (a: Policy, b: Policy) => a.name.localeCompare(b.name)) @@ -282,12 +281,25 @@ const Policies: React.FC = () => { const newApiOperations: any = cloneDeep(apiOperations); const newApiLevelPolicies: any = cloneDeep(apiLevelPolicies); - let operationInAction = (selectedTab == operationLevelTab) ? newApiOperations.find((op: any) => - op.target === target && op.verb.toLowerCase() === verb.toLowerCase()) : null; - - const flowPolicy = ((selectedTab == apiLevelTab) ? newApiLevelPolicies - : operationInAction.operationPolicies)[currentFlow].find((p: any) => (p.policyId === updatedOperation.policyId - && p.uuid === updatedOperation.uuid)); + const operationInAction = + selectedTab === operationLevelTab + ? newApiOperations.find( + (op: any) => + op.target === target && + op.verb.toLowerCase() === verb.toLowerCase(), + ) + : null; + + const flowPolicy = ( + selectedTab === apiLevelTab + ? newApiLevelPolicies + : operationInAction.operationPolicies + )[currentFlow].find( + (p: any) => + p.policyId === updatedOperation.policyId && + p.uuid === updatedOperation.uuid, + ); + if (flowPolicy) { // Edit policy @@ -295,11 +307,17 @@ const Policies: React.FC = () => { } else { // Add new policy const uuid = uuidv4(); - ((selectedTab == apiLevelTab) ? newApiLevelPolicies : operationInAction.operationPolicies)[currentFlow].push({ ...updatedOperation, uuid }); + (selectedTab === apiLevelTab ? newApiLevelPolicies : operationInAction + .operationPolicies)[currentFlow].push({ ...updatedOperation, uuid } + ); } // Finally update the state - (selectedTab == apiLevelTab) ? setApiLevelPolicies(newApiLevelPolicies) : setApiOperations(newApiOperations); + if (selectedTab === apiLevelTab) { + setApiLevelPolicies(newApiLevelPolicies); + } else { + setApiOperations(newApiOperations); + } } /** @@ -331,7 +349,7 @@ const Policies: React.FC = () => { */ const deleteApiOperation = (uuid: string, target: string, verb: string, currentFlow: string) => { - if (selectedTab == apiLevelTab) { + if (selectedTab === apiLevelTab) { const newApiLevelPolicies: any = cloneDeep(apiLevelPolicies); const index = newApiLevelPolicies[currentFlow].map((p: any) => p.uuid).indexOf(uuid); newApiLevelPolicies[currentFlow].splice(index, 1); @@ -365,7 +383,7 @@ const Policies: React.FC = () => { const rearrangeApiOperations = ( oldIndex: number, newIndex: number, target: string, verb: string, currentFlow: string, ) => { - if (selectedTab == apiLevelTab) { + if (selectedTab === apiLevelTab) { const newAPIPolicies: any = cloneDeep(apiLevelPolicies); const policyArray = newAPIPolicies[currentFlow]; newAPIPolicies[currentFlow] = arrayMove(policyArray, oldIndex, newIndex); @@ -380,6 +398,21 @@ const Policies: React.FC = () => { } }; + const deletePolicyUuid = (operationPolicies: any) => { + // Iterating through the policy list of request flow, response flow and fault flow + for (const flow in operationPolicies) { + if (Object.prototype.hasOwnProperty.call(operationPolicies, flow)) { + const policyArray = operationPolicies[flow]; + policyArray.forEach((policyItem: ApiPolicy) => { + if (policyItem.uuid) { + // eslint-disable-next-line no-param-reassign + delete policyItem.uuid; + } + }); + } + } + }; + /** * To update the API object with the attached policies on Save. */ @@ -392,7 +425,7 @@ const Policies: React.FC = () => { deletePolicyUuid(newApiLevelPolicies); // Set operation policies to the API object - newApiOperations.forEach((operation: any, index: any, array: any) => { + newApiOperations.forEach((operation: any) => { if (operation.operationPolicies) { const { operationPolicies } = operation; deletePolicyUuid(operationPolicies); @@ -416,31 +449,6 @@ const Policies: React.FC = () => { }); }; - const deletePolicyUuid = (operationPolicies: any) => { - // Iterating through the policy list of request flow, response flow and fault flow - for (const flow in operationPolicies) { - if (Object.prototype.hasOwnProperty.call(operationPolicies, flow)) { - const policyArray = operationPolicies[flow]; - policyArray.forEach((policyItem: ApiPolicy) => { - if (policyItem.uuid) { - // eslint-disable-next-line no-param-reassign - delete policyItem.uuid; - } - }); - } - } - }; - - // handles operations (verbs) for CC policy expansion. - const handleVerbsForCC = (verbObject: any) => { - const array = Object.entries(verbObject).map(([verb]) => { - return verb; - }) - // returns the first element since CC handles resource level policies only. - // therefore returning only the first verb (operation) here for the resource. - return array[0] - } - const handleTabChange = (tab: number) => { setSelectedTab(tab); }; @@ -448,14 +456,24 @@ const Policies: React.FC = () => { /** * To memoize the value passed into ApiOperationContextProvider */ - const providerValue = useMemo(() => ({ - apiOperations, - apiLevelPolicies, - updateApiOperations, - updateAllApiOperations, - deleteApiOperation, - rearrangeApiOperations, - }), [apiOperations, apiLevelPolicies, updateApiOperations, updateAllApiOperations, deleteApiOperation, rearrangeApiOperations]) + const providerValue = useMemo( + () => ({ + apiOperations, + apiLevelPolicies, + updateApiOperations, + updateAllApiOperations, + deleteApiOperation, + rearrangeApiOperations, + }), + [ + apiOperations, + apiLevelPolicies, + updateApiOperations, + updateAllApiOperations, + deleteApiOperation, + rearrangeApiOperations, + ], + ); if (!policies || !openAPISpec || updating) { return @@ -481,8 +499,8 @@ const Policies: React.FC = () => { /> )} - - + + { onChange={(event, tab) => handleTabChange(tab) } - indicatorColor="primary" - textColor="primary" - variant="fullWidth" - aria-label="Policies local to API" + indicatorColor='primary' + textColor='primary' + variant='fullWidth' + aria-label='Policies local to API' className={classes.flowTabs} > { API Level Policies } - id="request-tab" - aria-controls="request-tabpanel" + id='request-tab' + aria-controls='request-tabpanel' disabled={isChoreoConnectEnabled} /> { Operation Level Policies } - id="response-tab" - aria-controls="response-tabpanel" + id='response-tab' + aria-controls='response-tabpanel' /> - + = ({ useEffect(() => { (async () => { - let operationInAction = (!isAPILevelPolicy) ? apiOperations.find( + const operationInAction = (!isAPILevelPolicy) ? apiOperations.find( (op: any) => op.target === target && op.verb.toLowerCase() === verb.toLowerCase(), ) : null; - let apiPolicies = (isAPILevelPolicy) ? apiLevelPolicies : null; + const apiPolicies = (isAPILevelPolicy) ? apiLevelPolicies : null; // Populate request flow attached policy list const requestFlowList: AttachedPolicy[] = []; @@ -158,7 +158,7 @@ const PoliciesExpansion: FC = ({ // Populate response flow attached policy list const responseFlowList: AttachedPolicy[] = []; - const responseFlow = (isAPILevelPolicy) ? apiPolicies.response : operationInAction.operationPolicies.response; + const responseFlow = isAPILevelPolicy ? apiPolicies.response : operationInAction.operationPolicies.response; for (const responseFlowAttachedPolicy of responseFlow) { const { policyId, policyName, policyVersion, uuid } = responseFlowAttachedPolicy; @@ -202,7 +202,7 @@ const PoliciesExpansion: FC = ({ if (!isChoreoConnectEnabled) { // Populate fault flow attached policy list const faultFlowList: AttachedPolicy[] = []; - const faultFlow = (isAPILevelPolicy) ? apiPolicies.fault : operationInAction.operationPolicies.fault; + const faultFlow = isAPILevelPolicy ? apiPolicies.fault : operationInAction.operationPolicies.fault; for (const faultFlowAttachedPolicy of faultFlow) { const { policyId, policyName, policyVersion, uuid } = faultFlowAttachedPolicy; @@ -219,7 +219,7 @@ const PoliciesExpansion: FC = ({ const policyObj = allPolicies?.find( (policy: PolicySpec) => policy.name === policyName && - policy.version == policyVersion, + policy.version === policyVersion, ); if (policyObj) { faultFlowList.push({ ...policyObj, uniqueKey: uuid }); diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/PoliciesSection.tsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/PoliciesSection.tsx index 6bbab79aa1f..ca3960160af 100644 --- a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/PoliciesSection.tsx +++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/PoliciesSection.tsx @@ -16,19 +16,19 @@ * under the License. */ -import { Grid, makeStyles, Typography } from '@material-ui/core'; +import { Grid, makeStyles } from '@material-ui/core'; import React, { FC } from 'react'; import Box from '@material-ui/core/Box'; import CONSTS from 'AppData/Constants'; import { isRestricted } from 'AppData/AuthManager'; +import Alert from '@material-ui/lab/Alert'; +import { FormattedMessage } from 'react-intl'; import OperationPolicy from './OperationPolicy'; import OperationsGroup from './OperationsGroup'; import type { Policy, PolicySpec } from './Types'; import PoliciesExpansion from './PoliciesExpansion'; -import Alert from '@material-ui/lab/Alert'; -import { FormattedMessage } from 'react-intl'; -const useStyles = makeStyles((theme: any) => ({ +const useStyles = makeStyles(() => ({ gridItem: { display: 'flex', width: '100%', @@ -66,77 +66,72 @@ const PoliciesSection: FC = ({ setExpandedResource, }) => { const classes = useStyles(); - let borderColor = ''; + const borderColor = ''; return ( {isAPILevelTabSelected ? ( - + ) : ( - + {!isChoreoConnectEnabled && ( - - + + )} - {Object.entries(openAPISpec.paths).map( - ([target, verbObject]: [string, any]) => ( - - ( + + + - - {Object.entries(verbObject).map( - ([verb, operation]) => { - return CONSTS.HTTP_METHODS.includes( - verb, - ) ? ( - - - - ) : null; - }, - )} - - - - ), - )} + {Object.entries(verbObject).map(([verb, operation]) => { + return CONSTS.HTTP_METHODS.includes(verb) ? ( + + + + ) : null; + })} + + + + ))} )} From 97e36bd318472baf218b09ea9ffffb4ac773911d Mon Sep 17 00:00:00 2001 From: Ashera Silva Date: Tue, 11 Jul 2023 00:23:28 +0530 Subject: [PATCH 9/9] Fix cypress test failure --- .../Apis/Details/Policies/Policies.tsx | 8 ++-- .../fixtures/api_artifacts/sampleAddHeader.j2 | 1 - .../api_artifacts/samplePolicyTemplate.j2 | 1 + .../017-api-policies/00-common-policy.spec.js | 24 +++++----- .../01-api-specific-policy.spec.js | 46 +++++++------------ ...only-user-cannot-create-update-api.spec.js | 2 +- 6 files changed, 33 insertions(+), 49 deletions(-) delete mode 100644 tests/cypress/fixtures/api_artifacts/sampleAddHeader.j2 create mode 100644 tests/cypress/fixtures/api_artifacts/samplePolicyTemplate.j2 diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/Policies.tsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/Policies.tsx index 8cb373a33fe..065b8a1a862 100644 --- a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/Policies.tsx +++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/Policies.tsx @@ -520,8 +520,8 @@ const Policies: React.FC = () => { API Level Policies } - id='request-tab' - aria-controls='request-tabpanel' + id='api-level-policies-tab' + aria-controls='api-level-policies-tabpanel' disabled={isChoreoConnectEnabled} /> { Operation Level Policies } - id='response-tab' - aria-controls='response-tabpanel' + id='operation-level-policies-tab' + aria-controls='operation-level-policies-tabpanel' /> diff --git a/tests/cypress/fixtures/api_artifacts/sampleAddHeader.j2 b/tests/cypress/fixtures/api_artifacts/sampleAddHeader.j2 deleted file mode 100644 index f5fe3c8f586..00000000000 --- a/tests/cypress/fixtures/api_artifacts/sampleAddHeader.j2 +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tests/cypress/fixtures/api_artifacts/samplePolicyTemplate.j2 b/tests/cypress/fixtures/api_artifacts/samplePolicyTemplate.j2 new file mode 100644 index 00000000000..31cb54dcc61 --- /dev/null +++ b/tests/cypress/fixtures/api_artifacts/samplePolicyTemplate.j2 @@ -0,0 +1 @@ + diff --git a/tests/cypress/integration/publisher/017-api-policies/00-common-policy.spec.js b/tests/cypress/integration/publisher/017-api-policies/00-common-policy.spec.js index 4b0e01221aa..17f9fae173d 100644 --- a/tests/cypress/integration/publisher/017-api-policies/00-common-policy.spec.js +++ b/tests/cypress/integration/publisher/017-api-policies/00-common-policy.spec.js @@ -28,14 +28,14 @@ describe("Common Policies", () => { it("Common Policy", () => { cy.visit(`/publisher/policies`); cy.get('[data-testid="add-new-common-policy"]').click(); - cy.get('#name').type('Add Header sample test'); + cy.get('#name').type('Common Policy Sample'); cy.get('#version').type('1'); - cy.get('input[name="description"]').type('Sample add header policy description'); + cy.get('input[name="description"]').type('Sample common policy description'); cy.get('#fault-select-check-box').uncheck() - //upload the policy file + // Upload policy file cy.get('#upload-policy-file-for-policy').then(function () { - const filepath = `api_artifacts/sampleAddHeader.j2` + const filepath = `api_artifacts/samplePolicyTemplate.j2` cy.get('input[type="file"]').attachFile(filepath) }); @@ -44,21 +44,19 @@ describe("Common Policies", () => { cy.get('[data-testid="add-policy-attribute-display-name-btn"]').type('Header Name'); cy.get('#attribute-require-btn').click(); - //save common policy + // Save Common policy cy.get('[data-testid="policy-create-save-btn"]').click(); cy.wait(2000); - //View Common policy - cy.get('[aria-label="View Add Header sample test"]').click(); - //Download file - cy.get('[data-testid="download-policy-file"]').click(); - const downloadsFolder = Cypress.config('downloadsFolder') - const downloadedFilename = `${downloadsFolder}/swagger.yaml`; + // View Common policy + cy.get('[aria-label="View Common Policy Sample"]').click(); + // Download file + cy.get('[data-testid="download-policy-file"]').click(); cy.get('[data-testid="done-view-policy-file"]').click(); - //Delete Common Policy - cy.get('[aria-label="Delete Add Header sample test"]').click(); + // Delete Common Policy + cy.get('[aria-label="Delete Common Policy Sample"]').click(); cy.contains('Yes').click(); cy.logoutFromPublisher(); diff --git a/tests/cypress/integration/publisher/017-api-policies/01-api-specific-policy.spec.js b/tests/cypress/integration/publisher/017-api-policies/01-api-specific-policy.spec.js index 66ffa02cfd1..bf85357980f 100644 --- a/tests/cypress/integration/publisher/017-api-policies/01-api-specific-policy.spec.js +++ b/tests/cypress/integration/publisher/017-api-policies/01-api-specific-policy.spec.js @@ -26,7 +26,6 @@ describe("Common Policies", () => { cy.loginToPublisher(publisher, password); }) - it("Api Specific Policy", { retries: { runMode: 3, @@ -36,51 +35,38 @@ describe("Common Policies", () => { Utils.addAPI({}).then((apiId) => { apiTestId = apiId; cy.visit(`/publisher/apis/${apiId}/policies`); - //Create API Specific Policy + + // Create API Specific Policy cy.get('[data-testid="add-new-api-specific-policy"]', {timeout: Cypress.config().largeTimeout}).click(); - cy.get('#name').type('Add Header sample test'); + cy.get('#name').type('API Specific Policy Sample'); cy.get('#version').type('1'); - cy.get('input[name="description"]').type('Sample add header policy description'); + cy.get('input[name="description"]').type('Sample API specific policy description'); cy.get('#fault-select-check-box').uncheck() - //upload the policy file + // Upload policy file cy.get('#upload-policy-file-for-policy').then(function () { - const filepath = `api_artifacts/sampleAddHeader.j2` + const filepath = `api_artifacts/samplePolicyTemplate.j2` cy.get('input[type="file"]').attachFile(filepath) }); cy.get('#add-policy-attributes-btn').click(); - cy.get('[data-testid="add-policy-attribute-name-btn"]').type('headerName'); - cy.get('[data-testid="add-policy-attribute-display-name-btn"]').type('Header Name'); + cy.get('[data-testid="add-policy-attribute-name-btn"]').type('sampleAttribute'); + cy.get('[data-testid="add-policy-attribute-display-name-btn"]').type('Sample Attribute'); cy.get('#attribute-require-btn').click(); - //save common policy + + // Save API specific policy cy.get('[data-testid="policy-create-save-btn"]').click(); cy.wait(2000); - //View API Specific Policy - cy.contains('Add Header sample test').trigger('mouseover'); - cy.get('[aria-label="view-AddHeadersampletest"]').click({force:true}); - //Download file + // View API specific policy + cy.contains('API Specific Policy Sample').trigger('mouseover'); + cy.get('[aria-label="view-APISpecificPolicySample"]').click({force:true}); + + // Download file cy.get('[data-testid="download-policy-file"]').click(); - cy.wait(2000); cy.get('[data-testid="done-view-policy-file"]').click(); - //Drag and Drop Policy - const dataTransfer = new DataTransfer(); - cy.contains('Add Header sample test').trigger('dragstart', { - dataTransfer - }); - - cy.contains('Drag and drop policies here').trigger('drop', { - // cy.('[data-testid="drop-policy-zone-request"]').trigger('drop', { - dataTransfer - }); - cy.get('#headerName').type('Testing'); - cy.get('[data-testid="policy-attached-details-save"]').click(); - cy.get('[data-testid="custom-select-save-button"]').scrollIntoView().click(); - cy.visit(`/publisher/apis/${apiId}/scopes`); - cy.visit(`/publisher/apis/${apiId}/policies`); - cy.wait(2000); + cy.logoutFromPublisher(); }); }); diff --git a/tests/cypress/integration/publisher/019-read-only-user/00-verify-that-read-only-user-cannot-create-update-api.spec.js b/tests/cypress/integration/publisher/019-read-only-user/00-verify-that-read-only-user-cannot-create-update-api.spec.js index 5fd768c2883..72102ebd6f8 100644 --- a/tests/cypress/integration/publisher/019-read-only-user/00-verify-that-read-only-user-cannot-create-update-api.spec.js +++ b/tests/cypress/integration/publisher/019-read-only-user/00-verify-that-read-only-user-cannot-create-update-api.spec.js @@ -270,7 +270,7 @@ describe("publisher-019-00 : Verify that read only user cannot create updte api" cy.get('[data-testid="create-policy-form"]').get('[data-testid="displayname"]').type("test name"); cy.get('[data-testid="create-policy-form"]').get('[data-testid="gateway-details-panel"]') .get('[data-testid="file-drop-zone"]').then(function () { - cy.get('input[type="file"]').attachFile('api_artifacts/sampleAddHeader.j2'); + cy.get('input[type="file"]').attachFile('api_artifacts/samplePolicyTemplate.j2'); }); cy.get('[data-testid="create-policy-form"]').get('[data-testid="policy-add-btn-panel"]') .get('[data-testid="policy-create-save-btn"]').should('be.disabled');