From 513e5f65f80baaff15d53510a358440a2b96bf82 Mon Sep 17 00:00:00 2001 From: rusirijayodaillesinghe Date: Fri, 20 Sep 2024 14:27:08 +0530 Subject: [PATCH] UI implementation for allowing to have api policy and a common policy with same name and same version --- .../main/webapp/site/public/locales/en.json | 2 + .../Details/Policies/AttachedPolicyCard.tsx | 6 + .../Details/Policies/AttachedPolicyList.tsx | 6 + .../Apis/Details/Policies/Policies.tsx | 77 ++++-- .../Details/Policies/PoliciesExpansion.tsx | 32 +-- .../Apis/Details/Policies/PolicyDropzone.tsx | 6 + .../Apis/Details/Policies/PolicyList.tsx | 46 +++- .../Details/Policies/components/TabPanel.tsx | 9 +- .../Shared/PoliciesUI/AttachedPolicyCard.tsx | 244 ++++++++++------ .../Shared/PoliciesUI/AttachedPolicyList.tsx | 118 +++++--- .../Shared/PoliciesUI/PoliciesExpansion.tsx | 260 ++++++++++++------ .../Shared/PoliciesUI/PolicyDropzone.tsx | 196 ++++++++----- .../components/Shared/PoliciesUI/TabPanel.tsx | 146 ++++++++-- 13 files changed, 797 insertions(+), 351 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 d035a580099..114e59a042a 100644 --- a/portals/publisher/src/main/webapp/site/public/locales/en.json +++ b/portals/publisher/src/main/webapp/site/public/locales/en.json @@ -1166,6 +1166,8 @@ "Apis.Details.Policies.AttachedPolicyForm.General.reset": "Reset", "Apis.Details.Policies.AttachedPolicyForm.General.save": "Save", "Apis.Details.Policies.AttachedPolicyForm.General.saving": "Saving", + "Apis.Details.Policies.Components.TabPanel.Components.API.Policy.List": "API Policies", + "Apis.Details.Policies.Components.TabPanel.Components.Common.Policy.List": "Common Policies", "Apis.Details.Policies.CreatePolicy.create.new.policy": "Create New Policy", "Apis.Details.Policies.CreatePolicy.create.new.policy.link": "Want to create a common policy that will be visible to all APIs instead?", "Apis.Details.Policies.DeletePolicy.cancel": "Cancel", 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 6f383a69bc8..8336f2bcb38 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 @@ -45,6 +45,8 @@ interface AttachedPolicyCardProps { target: string; allPolicies: PolicySpec[] | null; isAPILevelPolicy: boolean; + listOriginatedFromCommonPolicies: string[]; + isApiRevision: boolean; } /** @@ -61,6 +63,8 @@ const AttachedPolicyCard: FC = ({ target, allPolicies, isAPILevelPolicy, + listOriginatedFromCommonPolicies, + isApiRevision }) => { const { api } = useContext(ApiContext); const { deleteApiOperation } = useContext(ApiOperationContext); @@ -155,6 +159,8 @@ const AttachedPolicyCard: FC = ({ handleDelete={handleDelete} setDrawerOpen={setDrawerOpen} PolicyConfigurationEditDrawer={PolicyConfigurationEditDrawer} + listOriginatedFromCommonPolicies={listOriginatedFromCommonPolicies} + isApiRevision={isApiRevision} /> ); }; diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/AttachedPolicyList.tsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/AttachedPolicyList.tsx index bbd37b06e28..6da49a8725c 100644 --- a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/AttachedPolicyList.tsx +++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/AttachedPolicyList.tsx @@ -38,6 +38,8 @@ interface AttachedPolicyListProps { verb: string; allPolicies: PolicySpec[] | null; isAPILevelPolicy: boolean; + listOriginatedFromCommonPolicies: string[]; + isApiRevision: boolean; } /** @@ -54,6 +56,8 @@ const AttachedPolicyList: FC = ({ verb, allPolicies, isAPILevelPolicy, + listOriginatedFromCommonPolicies, + isApiRevision }) => { const reversedPolicyList = [...currentPolicyList].reverse(); const policyListToDisplay = @@ -105,6 +109,8 @@ const AttachedPolicyList: FC = ({ handleDragEnd={handleDragEnd} policyListToDisplay={policyListToDisplay} AttachedPolicyCard={AttachedPolicyCard} + listOriginatedFromCommonPolicies={listOriginatedFromCommonPolicies} + isApiRevision={isApiRevision} /> ); }; 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 403f7ffe80e..7ce75aa1cc9 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 @@ -91,7 +91,9 @@ const Policies: React.FC = () => { const [api, updateAPI] = useAPI(); const [updating, setUpdating] = useState(false); - const [policies, setPolicies] = useState(null); + const [apiPolicies, setApiPolicies] = useState(null); + const [commonPolicies, setCommonPolicies] = useState(null); + const [policies, setPolicies] = useState([]); const [allPolicies, setAllPolicies] = useState(null); const [expandedResource, setExpandedResource] = useState(null); const [isChoreoConnectEnabled, setIsChoreoConnectEnabled] = useState(api.gatewayType === 'wso2/apk'); @@ -175,53 +177,83 @@ const Policies: React.FC = () => { const commonPoliciesPromise = API.getCommonOperationPolicies(); Promise.all([apiPoliciesPromise, commonPoliciesPromise]).then((response) => { const [apiPoliciesResponse, commonPoliciesResponse] = response; - const apiSpecificPolicies = apiPoliciesResponse.body.list; - const commonPolicies = commonPoliciesResponse.body.list; - const mergedList = [...commonPolicies, ...apiSpecificPolicies]; + const apiSpecificPoliciesList = apiPoliciesResponse.body.list; + const commonPoliciesList = commonPoliciesResponse.body.list; + const mergedList = [...commonPoliciesList, ...apiSpecificPoliciesList]; // Get all common policies and API specific policies setAllPolicies(mergedList); - let unionByPolicyDisplayName; + let apiPolicyByPolicyDisplayName; + let commonPolicyByPolicyDisplayName; 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()]; + // Get the policies depending on the policy display name and version + apiPolicyByPolicyDisplayName = [...apiSpecificPoliciesList + .reduce((map: Map, obj: Policy) => + map.set(obj.name + obj.version, obj), new Map()).values()]; + commonPolicyByPolicyDisplayName = [...commonPoliciesList + .reduce((map: Map, obj: Policy) => + 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()]; + // Get the policies depending on the policy display name + apiPolicyByPolicyDisplayName = [...apiSpecificPoliciesList + .reduce((map: Map, obj: Policy) => + map.set(obj.name, obj), new Map()).values()]; + commonPolicyByPolicyDisplayName = [...commonPoliciesList + .reduce((map: Map, obj: Policy) => + map.set(obj.name, obj), new Map()).values()]; } - unionByPolicyDisplayName.sort( + apiPolicyByPolicyDisplayName.sort( (a: Policy, b: Policy) => a.name.localeCompare(b.name)) + commonPolicyByPolicyDisplayName.sort( + (a: Policy, b: Policy) => a.name.localeCompare(b.name)) + + let filteredApiPolicyByGatewayTypeList = null; + let filteredCommonPolicyByGatewayTypeList = null; - let filteredByGatewayTypeList = null; if (!isChoreoConnectEnabled) { // Get synpase gateway supported policies - filteredByGatewayTypeList = unionByPolicyDisplayName.filter( + filteredApiPolicyByGatewayTypeList = apiPolicyByPolicyDisplayName.filter( + (policy: Policy) => policy.supportedGateways.includes('Synapse')); + filteredCommonPolicyByGatewayTypeList = commonPolicyByPolicyDisplayName.filter( (policy: Policy) => policy.supportedGateways.includes('Synapse')); } else { // Get CC gateway supported policies - filteredByGatewayTypeList = unionByPolicyDisplayName.filter( + filteredApiPolicyByGatewayTypeList = apiPolicyByPolicyDisplayName.filter( + (policy: Policy) => policy.supportedGateways.includes('ChoreoConnect')); + filteredCommonPolicyByGatewayTypeList = commonPolicyByPolicyDisplayName.filter( (policy: Policy) => policy.supportedGateways.includes('ChoreoConnect')); } - let filteredByAPITypeList = null; + let filteredApiPoliciesByAPITypeList = []; + let filteredCommonPoliciesByAPITypeList = []; + if (api.type === "HTTP") { // Get HTTP supported policies - filteredByAPITypeList = filteredByGatewayTypeList.filter( + filteredApiPoliciesByAPITypeList = filteredApiPolicyByGatewayTypeList.filter( + (policy: Policy) => policy.supportedApiTypes.includes('HTTP')); + filteredCommonPoliciesByAPITypeList = filteredCommonPolicyByGatewayTypeList.filter( (policy: Policy) => policy.supportedApiTypes.includes('HTTP')); } else if (api.type === "SOAP"){ // Get SOAP supported policies - filteredByAPITypeList = filteredByGatewayTypeList.filter( + filteredApiPoliciesByAPITypeList = filteredApiPolicyByGatewayTypeList.filter( + (policy: Policy) => policy.supportedApiTypes.includes('SOAP')); + filteredCommonPoliciesByAPITypeList = filteredCommonPolicyByGatewayTypeList.filter( (policy: Policy) => policy.supportedApiTypes.includes('SOAP')); } else if (api.type === "SOAPTOREST"){ // Get SOAP to REST supported policies - filteredByAPITypeList = filteredByGatewayTypeList.filter( + filteredApiPoliciesByAPITypeList = filteredApiPolicyByGatewayTypeList.filter( + (policy: Policy) => policy.supportedApiTypes.includes('SOAPTOREST')); + filteredCommonPoliciesByAPITypeList = filteredCommonPolicyByGatewayTypeList.filter( (policy: Policy) => policy.supportedApiTypes.includes('SOAPTOREST')); } - setPolicies(filteredByAPITypeList); + setApiPolicies(filteredApiPoliciesByAPITypeList); + setCommonPolicies(filteredCommonPoliciesByAPITypeList); + const combinedPolicyList = [...filteredCommonPoliciesByAPITypeList, ...filteredApiPoliciesByAPITypeList]; + combinedPolicyList.sort( + (a: Policy, b: Policy) => a.name.localeCompare(b.name)) + setPolicies(combinedPolicyList); }).catch((error) => { console.error(error); @@ -498,7 +530,7 @@ const Policies: React.FC = () => { ], ); - if (!policies || !openAPISpec || updating) { + if (!apiPolicies || !commonPolicies || !openAPISpec || updating) { return } @@ -597,7 +629,8 @@ const Policies: React.FC = () => { 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 410911f7d91..c3d63da478d 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 @@ -89,6 +89,7 @@ const PoliciesExpansion: FC = ({ const { apiOperations } = useContext(ApiOperationContext); const { apiLevelPolicies } = useContext(ApiOperationContext); const { api } = useContext(APIContext); + const [listOriginatedFromCommonPolicies, setListOriginatedFromCommonPolicies] = useState([]); useEffect(() => { const requestList = []; @@ -119,12 +120,13 @@ const PoliciesExpansion: FC = ({ op.verb.toLowerCase() === verb.toLowerCase(), ) : null; const apiPolicies = (isAPILevelPolicy) ? apiLevelPolicies : null; + const originatedFromCommonPolicies : string[] = []; // Populate request flow attached policy list const requestFlowList: AttachedPolicy[] = []; const requestFlow = (isAPILevelPolicy) ? apiPolicies.request : operationInAction.operationPolicies.request; for (const requestFlowAttachedPolicy of requestFlow) { - const { policyId, policyName, policyVersion, uuid } = + const { policyId, policyName, uuid } = requestFlowAttachedPolicy; if (policyId === null) { // Handling migration flow @@ -136,14 +138,11 @@ const PoliciesExpansion: FC = ({ uniqueKey: uuid, }); } else { - const policyObj = allPolicies?.find( - (policy: PolicySpec) => - policy.name === policyName && - policy.version === policyVersion, - ); + const policyObj = allPolicies?.find((policy: PolicySpec) => policy.id === policyId); if (policyObj) { requestFlowList.push({ ...policyObj, uniqueKey: uuid }); } else { + originatedFromCommonPolicies.push(policyId); try { // eslint-disable-next-line no-await-in-loop const policyResponse = await API.getOperationPolicy( @@ -167,7 +166,7 @@ const PoliciesExpansion: FC = ({ const responseFlowList: AttachedPolicy[] = []; const responseFlow = isAPILevelPolicy ? apiPolicies.response : operationInAction.operationPolicies.response; for (const responseFlowAttachedPolicy of responseFlow) { - const { policyId, policyName, policyVersion, uuid } = + const { policyId, policyName, uuid } = responseFlowAttachedPolicy; if (policyId === null) { // Handling migration flow @@ -179,14 +178,11 @@ const PoliciesExpansion: FC = ({ uniqueKey: uuid, }); } else { - const policyObj = allPolicies?.find( - (policy: PolicySpec) => - policy.name === policyName && - policy.version === policyVersion, - ); + const policyObj = allPolicies?.find((policy: PolicySpec) => policy.id === policyId); if (policyObj) { responseFlowList.push({ ...policyObj, uniqueKey: uuid }); } else { + originatedFromCommonPolicies.push(policyId); try { // eslint-disable-next-line no-await-in-loop const policyResponse = await API.getOperationPolicy( @@ -211,7 +207,7 @@ const PoliciesExpansion: FC = ({ const faultFlowList: AttachedPolicy[] = []; const faultFlow = isAPILevelPolicy ? apiPolicies.fault : operationInAction.operationPolicies.fault; for (const faultFlowAttachedPolicy of faultFlow) { - const { policyId, policyName, policyVersion, uuid } = + const { policyId, policyName, uuid } = faultFlowAttachedPolicy; if (policyId === null) { // Handling migration flow @@ -223,14 +219,11 @@ const PoliciesExpansion: FC = ({ uniqueKey: uuid, }); } else { - const policyObj = allPolicies?.find( - (policy: PolicySpec) => - policy.name === policyName && - policy.version === policyVersion, - ); + const policyObj = allPolicies?.find((policy: PolicySpec) => policy.id === policyId); if (policyObj) { faultFlowList.push({ ...policyObj, uniqueKey: uuid }); } else { + originatedFromCommonPolicies.push(policyId); try { // eslint-disable-next-line no-await-in-loop const policyResponse = await API.getOperationPolicy( @@ -250,6 +243,7 @@ const PoliciesExpansion: FC = ({ } setFaultFlowPolicyList(faultFlowList); } + setListOriginatedFromCommonPolicies(originatedFromCommonPolicies); })(); }, [apiOperations, apiLevelPolicies]); @@ -271,6 +265,8 @@ const PoliciesExpansion: FC = ({ faultFlowDroppablePolicyList={faultFlowDroppablePolicyList} FlowArrow={FlowArrow} PolicyDropzone={PolicyDropzone} + listOriginatedFromCommonPolicies={listOriginatedFromCommonPolicies} + isApiRevision={api.isRevision} /> ); }; 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 8e9292dc0e5..6acd54f73f0 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 @@ -89,6 +89,8 @@ interface PolicyDropzoneProps { verb: string; allPolicies: PolicySpec[] | null; isAPILevelPolicy: boolean; + listOriginatedFromCommonPolicies: string[]; + isApiRevision: boolean; } /** @@ -106,6 +108,8 @@ const PolicyDropzone: FC = ({ verb, allPolicies, isAPILevelPolicy, + listOriginatedFromCommonPolicies, + isApiRevision }) => { const [droppedPolicy, setDroppedPolicy] = useState(null); @@ -134,6 +138,8 @@ const PolicyDropzone: FC = ({ setDroppedPolicy={setDroppedPolicy} AttachedPolicyList={AttachedPolicyList} PolicyConfiguringDrawer={PolicyConfiguringDrawer} + listOriginatedFromCommonPolicies={listOriginatedFromCommonPolicies} + isApiRevision={isApiRevision} /> ); }; diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/PolicyList.tsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/PolicyList.tsx index 49238d88f69..0def6350b96 100644 --- a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/PolicyList.tsx +++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/PolicyList.tsx @@ -68,7 +68,8 @@ const StyledPaper = styled(Paper)(({ theme }: { theme: Theme }) => ({ })); interface PolicyListPorps { - policyList: Policy[]; + apiPolicyList: Policy[]; + commonPolicyList: Policy[]; fetchPolicies: () => void; isChoreoConnectEnabled: boolean; } @@ -78,7 +79,7 @@ interface PolicyListPorps { * @param {JSON} props Input props from parent components. * @returns {TSX} List of policies local to the API segment. */ -const PolicyList: FC = ({policyList, fetchPolicies, isChoreoConnectEnabled}) => { +const PolicyList: FC = ({apiPolicyList, commonPolicyList, fetchPolicies, isChoreoConnectEnabled}) => { const [selectedTab, setSelectedTab] = useState(0); // Request flow related tab is active by default const [dialogOpen, setDialogOpen] = React.useState(false); @@ -176,7 +177,16 @@ const PolicyList: FC = ({policyList, fetchPolicies, isChoreoCon + policy.applicableFlows.includes( + 'request', + ) && + policy.supportedGateways.includes( + gatewayType, + ), + )} + apiPolicyList={apiPolicyList.filter( (policy) => policy.applicableFlows.includes( 'request', @@ -190,7 +200,16 @@ const PolicyList: FC = ({policyList, fetchPolicies, isChoreoCon fetchPolicies={fetchPolicies} /> + policy.applicableFlows.includes( + 'response', + ) && + policy.supportedGateways.includes( + gatewayType, + ), + )} + apiPolicyList={apiPolicyList.filter( (policy) => policy.applicableFlows.includes( 'response', @@ -205,8 +224,23 @@ const PolicyList: FC = ({policyList, fetchPolicies, isChoreoCon /> {!isChoreoConnectEnabled && ( - policy.applicableFlows.includes('fault'), + commonPolicyList={commonPolicyList.filter( + (policy) => + policy.applicableFlows.includes( + 'fault', + ) && + policy.supportedGateways.includes( + gatewayType, + ), + )} + apiPolicyList={apiPolicyList.filter( + (policy) => + policy.applicableFlows.includes( + 'fault', + ) && + policy.supportedGateways.includes( + gatewayType, + ), )} index={2} selectedTab={selectedTab} diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/components/TabPanel.tsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/components/TabPanel.tsx index b4aae4a707b..fae743e7748 100644 --- a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/components/TabPanel.tsx +++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Policies/components/TabPanel.tsx @@ -25,7 +25,8 @@ import type { Policy } from '../Types'; interface TabPanelProps { children?: React.ReactNode; index: number; - policyList: Policy[]; + commonPolicyList: Policy[]; + apiPolicyList: Policy[]; selectedTab: number; fetchPolicies: () => void; } @@ -38,7 +39,8 @@ interface TabPanelProps { */ const TabPanel: FC = ({ index, - policyList, + commonPolicyList, + apiPolicyList, selectedTab, fetchPolicies, }) => { @@ -50,7 +52,8 @@ const TabPanel: FC = ({ selectedTab={selectedTab} index={index} currentFlow={currentFlow} - policyList={policyList} + commonPolicyList={commonPolicyList} + apiPolicyList={apiPolicyList} fetchPolicies={fetchPolicies} DraggablePolicyCard={DraggablePolicyCard} /> diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Shared/PoliciesUI/AttachedPolicyCard.tsx b/portals/publisher/src/main/webapp/source/src/app/components/Shared/PoliciesUI/AttachedPolicyCard.tsx index 8927c228016..84a51b86fc3 100644 --- a/portals/publisher/src/main/webapp/source/src/app/components/Shared/PoliciesUI/AttachedPolicyCard.tsx +++ b/portals/publisher/src/main/webapp/source/src/app/components/Shared/PoliciesUI/AttachedPolicyCard.tsx @@ -24,6 +24,7 @@ import { useSortable } from '@dnd-kit/sortable'; import { CSS } from '@dnd-kit/utilities'; import IconButton from '@mui/material/IconButton'; import Tooltip from '@mui/material/Tooltip'; +import Typography from '@mui/material/Typography'; import DeleteIcon from '@mui/icons-material/Delete'; import CloudDownloadIcon from '@mui/icons-material/CloudDownload'; import Utils from 'AppData/Utils'; @@ -44,7 +45,7 @@ const Root = styled('div')(() => ({ } })); -interface AttachedPolicyCardSharedProps { +interface AttachedPolicyCardSharedBaseProps { policyObj: AttachedPolicy; currentFlow: string; verb: string; @@ -59,28 +60,30 @@ interface AttachedPolicyCardSharedProps { PolicyConfigurationEditDrawer: any; } +// Option 1: `listOriginatedFromCommonPolicies` and `isApiRevision` are provided +interface AttachedPolicyCardWithCommonProps extends AttachedPolicyCardSharedBaseProps { + listOriginatedFromCommonPolicies: string[]; + isApiRevision: boolean; +} + +// Option 2: Neither `listOriginatedFromCommonPolicies` nor `isApiRevision` are provided +interface AttachedPolicyCardWithoutCommonProps extends AttachedPolicyCardSharedBaseProps { + listOriginatedFromCommonPolicies?: undefined; + isApiRevision?: undefined; +} + +// Combine the two using a union type +type AttachedPolicyCardSharedProps = AttachedPolicyCardWithCommonProps | AttachedPolicyCardWithoutCommonProps; + /** * Renders a single sortable policy card. * @param {any} AttachedPolicyCardProps Input props from parent components. * @returns {TSX} Sortable attached policy card UI. */ -const AttachedPolicyCardShared: FC = ({ - policyObj, - currentFlow, - verb, - target, - allPolicies, - isAPILevelPolicy, - drawerOpen, - handleDrawerOpen, - handlePolicyDownload, - handleDelete, - setDrawerOpen, - PolicyConfigurationEditDrawer -}) => { +const AttachedPolicyCardShared: FC = (props) => { - const policyColor = Utils.stringToColor(policyObj.displayName); - const policyBackgroundColor = drawerOpen + const policyColor = Utils.stringToColor(props.policyObj.displayName); + const policyBackgroundColor = props.drawerOpen ? `rgba(${Utils.hexToRGB(policyColor)}, 0.2)` : 'rgba(0, 0, 0, 0)'; const { @@ -90,7 +93,7 @@ const AttachedPolicyCardShared: FC = ({ transform, transition, isDragging, - } = useSortable({ id: policyObj.uniqueKey.toString() }); + } = useSortable({ id: props.policyObj.uniqueKey.toString() }); const style: CSSProperties = { transform: CSS.Transform.toString(transform), @@ -106,70 +109,153 @@ const AttachedPolicyCardShared: FC = ({ backgroundColor: policyBackgroundColor, opacity: isDragging ? 0.5 : 1, }; - return ( - ( -
- +
- - {Utils.stringAvatar( - policyObj.displayName.toUpperCase(), - )} - - - - + {`*${policyType}\n${props.policyObj.displayName} : ${props.policyObj.version}`} + + } + placement='top' > - - - + {Utils.stringAvatar( + props.policyObj.displayName.toUpperCase(), + )} + + + + + + + + + + +
+ {props.drawerOpen && ( + + )} + ) + ); + } else { + return ( + ( +
+ - - - -
- {drawerOpen && ( - - )} -
) - ); + + {Utils.stringAvatar( + props.policyObj.displayName.toUpperCase(), + )} + +
+ + + + + + + + +
+ {props.drawerOpen && ( + + )} +
) + ); + } } export default AttachedPolicyCardShared; diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Shared/PoliciesUI/AttachedPolicyList.tsx b/portals/publisher/src/main/webapp/source/src/app/components/Shared/PoliciesUI/AttachedPolicyList.tsx index 2f651fcb5c6..a68f7c58939 100644 --- a/portals/publisher/src/main/webapp/source/src/app/components/Shared/PoliciesUI/AttachedPolicyList.tsx +++ b/portals/publisher/src/main/webapp/source/src/app/components/Shared/PoliciesUI/AttachedPolicyList.tsx @@ -28,7 +28,7 @@ import { } from '@dnd-kit/sortable'; import type { AttachedPolicy, PolicySpec } from './Types'; -interface AttachedPolicyListSharedProps { +interface AttachedPolicyListSharedBaseProps { currentPolicyList: AttachedPolicy[]; setCurrentPolicyList: React.Dispatch>; currentFlow: string; @@ -42,47 +42,83 @@ interface AttachedPolicyListSharedProps { AttachedPolicyCard: any; } -const AttachedPolicyListShared: FC = ({ - currentPolicyList, - setCurrentPolicyList, - currentFlow, - target, - verb, - allPolicies, - isAPILevelPolicy, - sensors, - handleDragEnd, - policyListToDisplay, - AttachedPolicyCard, -}) => { - return ( - <> - - item.uniqueKey)} - strategy={horizontalListSortingStrategy} +// Option 1: `listOriginatedFromCommonPolicies` and `isApiRevision` are provided +interface AttachedPolicyListWithCommonProps extends AttachedPolicyListSharedBaseProps { + listOriginatedFromCommonPolicies: string[]; + isApiRevision: boolean; +} + +// Option 2: Neither `listOriginatedFromCommonPolicies` nor `isApiRevision` are provided +interface AttachedPolicyListWithoutCommonProps extends AttachedPolicyListSharedBaseProps { + listOriginatedFromCommonPolicies?: undefined; + isApiRevision?: undefined; +} + +// Combine the two using a union type +type AttachedPolicyListSharedProps = AttachedPolicyListWithCommonProps | AttachedPolicyListWithoutCommonProps; + +const AttachedPolicyListShared: FC = (props) => { + if ('listOriginatedFromCommonPolicies' in props) { + return ( + <> + + item.uniqueKey)} + strategy={horizontalListSortingStrategy} + > + {props.policyListToDisplay.map((policy: AttachedPolicy) => ( + + ))} + + + + ); + } else { + return ( + <> + - {policyListToDisplay.map((policy: AttachedPolicy) => ( - - ))} - - - - ); + item.uniqueKey)} + strategy={horizontalListSortingStrategy} + > + {props.policyListToDisplay.map((policy: AttachedPolicy) => ( + + ))} + + + + ); + } }; export default AttachedPolicyListShared; \ No newline at end of file diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Shared/PoliciesUI/PoliciesExpansion.tsx b/portals/publisher/src/main/webapp/source/src/app/components/Shared/PoliciesUI/PoliciesExpansion.tsx index 1bbefed61f7..3c1ab66b246 100644 --- a/portals/publisher/src/main/webapp/source/src/app/components/Shared/PoliciesUI/PoliciesExpansion.tsx +++ b/portals/publisher/src/main/webapp/source/src/app/components/Shared/PoliciesUI/PoliciesExpansion.tsx @@ -39,7 +39,7 @@ const StyledAccordionDetails = styled(AccordionDetails)(({ theme }: { theme: The } })); -interface PoliciesExpansionSharedProps { +interface PoliciesExpansionSharedBaseProps { target: any; verb: string; allPolicies: PolicySpec[] | null; @@ -58,106 +58,192 @@ interface PoliciesExpansionSharedProps { PolicyDropzone: any; } -const PoliciesExpansionShared: FC = ({ - target, - verb, - allPolicies, - isChoreoConnectEnabled, - isAPILevelPolicy, - requestFlowPolicyList, - setRequestFlowPolicyList, - requestFlowDroppablePolicyList, - responseFlowPolicyList, - setResponseFlowPolicyList, - responseFlowDroppablePolicyList, - faultFlowPolicyList, - setFaultFlowPolicyList, - faultFlowDroppablePolicyList, - FlowArrow, - PolicyDropzone -}) => { +// Option 1: `listOriginatedFromCommonPolicies` and `isApiRevision` are provided +interface PoliciesWithCommonProps extends PoliciesExpansionSharedBaseProps { + listOriginatedFromCommonPolicies: string[]; + isApiRevision: boolean; +} + +// Option 2: Neither `listOriginatedFromCommonPolicies` nor `isApiRevision` are provided +interface PoliciesWithoutCommonProps extends PoliciesExpansionSharedBaseProps { + listOriginatedFromCommonPolicies?: undefined; + isApiRevision?: undefined; +} +// Combine the two using a union type +type PoliciesExpansionSharedProps = PoliciesWithCommonProps | PoliciesWithoutCommonProps; - return ( - - - - - - = (props) => { + if ('listOriginatedFromCommonPolicies' in props) { + // Props were passed, use `listOriginatedFromCommonPolicies` and `isApiRevision` + return ( + + + + + + + + + + + + + + + + - - - - - - - + {!props.isChoreoConnectEnabled && ( + + + + + + + + )} + + + + ); + } else { + return ( + + + + + + + + + - - - - - {!isChoreoConnectEnabled && ( - + + - - + - )} + {!props.isChoreoConnectEnabled && ( + + + + + + + + )} + - - - ); + + ); + } }; export default PoliciesExpansionShared; diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Shared/PoliciesUI/PolicyDropzone.tsx b/portals/publisher/src/main/webapp/source/src/app/components/Shared/PoliciesUI/PolicyDropzone.tsx index 863300d7e99..33c584ecabd 100644 --- a/portals/publisher/src/main/webapp/source/src/app/components/Shared/PoliciesUI/PolicyDropzone.tsx +++ b/portals/publisher/src/main/webapp/source/src/app/components/Shared/PoliciesUI/PolicyDropzone.tsx @@ -76,7 +76,7 @@ const Root = styled('div')(({ theme }: { theme: Theme }) => ({ } })); -interface PolicyDropzoneSharedProps { +interface PolicyDropzoneSharedBaseProps { policyDisplayStartDirection: string; currentPolicyList: AttachedPolicy[]; setCurrentPolicyList: React.Dispatch>; @@ -93,76 +93,134 @@ interface PolicyDropzoneSharedProps { PolicyConfiguringDrawer: any; } -const PolicyDropzoneShared: FC = ({ - policyDisplayStartDirection, - currentPolicyList, - setCurrentPolicyList, - currentFlow, - target, - verb, - allPolicies, - isAPILevelPolicy, - drop, - canDrop, - droppedPolicy, - setDroppedPolicy, - AttachedPolicyList, - PolicyConfiguringDrawer -}) => { +// Option 1: `listOriginatedFromCommonPolicies` and `isApiRevision` are provided +interface PolicyDropzoneWithCommonProps extends PolicyDropzoneSharedBaseProps { + listOriginatedFromCommonPolicies: string[]; + isApiRevision: boolean; +} + +// Option 2: Neither `listOriginatedFromCommonPolicies` nor `isApiRevision` are provided +interface PolicyDropzoneWithoutCommonProps extends PolicyDropzoneSharedBaseProps { + listOriginatedFromCommonPolicies?: undefined; + isApiRevision?: undefined; +} - return ( - ( - -
- {currentPolicyList.length === 0 ? ( - - = (props) => { + if ('listOriginatedFromCommonPolicies' in props) { + // Props were passed, use `listOriginatedFromCommonPolicies` and `isApiRevision` + return ( + ( + +
+ {props.currentPolicyList.length === 0 ? ( + + + + ) : ( + + )} +
+
+ {props.droppedPolicy && ( + + )} +
) + ); + } else { + return ( + ( + +
+ {props.currentPolicyList.length === 0 ? ( + + + + ) : ( + - - ) : ( - - )} -
-
- {droppedPolicy && ( - - )} -
) - ); + )} +
+
+ {props.droppedPolicy && ( + + )} +
) + ); + } } export default PolicyDropzoneShared; diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Shared/PoliciesUI/TabPanel.tsx b/portals/publisher/src/main/webapp/source/src/app/components/Shared/PoliciesUI/TabPanel.tsx index bba8939adfc..ec26dc6397b 100644 --- a/portals/publisher/src/main/webapp/source/src/app/components/Shared/PoliciesUI/TabPanel.tsx +++ b/portals/publisher/src/main/webapp/source/src/app/components/Shared/PoliciesUI/TabPanel.tsx @@ -16,51 +16,145 @@ * under the License. */ -import { Box } from '@mui/material'; +import { Box, Accordion, AccordionSummary, AccordionDetails } from '@mui/material'; import React, { FC } from 'react'; +import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; +import Typography from '@mui/material/Typography'; +import { FormattedMessage } from 'react-intl'; import type { Policy } from './Types'; -interface TabPanelSharedProps { +interface TabPanelSharedBaseProps { children?: React.ReactNode; currentFlow: string; index: number; - policyList: Policy[]; selectedTab: number; fetchPolicies: () => void; DraggablePolicyCard: any; } -const TabPanelShared: FC = ({ - selectedTab, - index, - currentFlow, - policyList, - fetchPolicies, - DraggablePolicyCard -}) => { - return ( - + ); + } else { + return ( + + ); + } } export default TabPanelShared; \ No newline at end of file