Skip to content

Commit 4c0ab1f

Browse files
committed
Implement federated gateway publisher UI
1 parent 3b8bf2d commit 4c0ab1f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1989
-1663
lines changed

portals/publisher/src/main/webapp/source/src/app/components/Apis/Apis.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
* under the License.
1717
*/
1818

19-
import React, { Suspense, lazy } from 'react';
19+
import React, { Suspense, lazy} from 'react';
2020
import { Route, Switch, Redirect } from 'react-router-dom';
2121
import Progress from 'AppComponents/Shared/Progress';
2222
import AuthManager from 'AppData/AuthManager';
@@ -73,7 +73,7 @@ const Apis = () => {
7373
}
7474
}}
7575
/>
76-
<Route path='/apis/:apiUUID/' render={(props) => <DeferredDetails {...props} isAPIProduct={false} />} />
76+
<Route path='/apis/:apiUUID/' render={(props) =><DeferredDetails {...props} isAPIProduct={false} />} />
7777
<Route
7878
path='/api-products/:apiProdUUID/'
7979
render={(props) => {

portals/publisher/src/main/webapp/source/src/app/components/Apis/Create/AIAPI/APICreateAIAPI.jsx

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import Typography from '@mui/material/Typography';
2121
import Box from '@mui/material/Box';
2222
import Grid from '@mui/material/Grid';
2323
import { FormattedMessage, useIntl } from 'react-intl';
24-
import { usePublisherSettings } from 'AppComponents/Shared/AppContext';
2524
import Stepper from '@mui/material/Stepper';
2625
import Step from '@mui/material/Step';
2726
import StepLabel from '@mui/material/StepLabel';
@@ -80,7 +79,6 @@ function apiInputsReducer(currentState, inputAction) {
8079
export default function ApiCreateAIAPI(props) {
8180
const [wizardStep, setWizardStep] = useState(0);
8281
const { history, multiGateway } = props;
83-
const { data: settings } = usePublisherSettings();
8482

8583
const [apiInputs, inputsDispatcher] = useReducer(apiInputsReducer, {
8684
type: 'ApiCreateAIAPI',
@@ -124,20 +122,12 @@ export default function ApiCreateAIAPI(props) {
124122
const {
125123
name, version, context, endpoint, gatewayType, policies = ["Unlimited"], inputValue, llmProviderId,
126124
} = apiInputs;
127-
let defaultGatewayType;
128-
if (settings && settings.gatewayTypes.length === 1 && settings.gatewayTypes.includes('Regular')) {
129-
defaultGatewayType = 'wso2/synapse';
130-
} else if (settings && settings.gatewayTypes.length === 1 && settings.gatewayTypes.includes('APK')) {
131-
defaultGatewayType = 'wso2/apk';
132-
} else {
133-
defaultGatewayType = 'default';
134-
}
135125

136126
const additionalProperties = {
137127
name,
138128
version,
139129
context,
140-
gatewayType: defaultGatewayType === 'default' ? gatewayType : defaultGatewayType,
130+
gatewayType,
141131
policies,
142132
subtypeConfiguration: {
143133
subtype: 'AIAPI',

portals/publisher/src/main/webapp/source/src/app/components/Apis/Create/APICreateRoutes.jsx

Lines changed: 68 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,12 @@
1515
* specific language governing permissions and limitations
1616
* under the License.
1717
*/
18-
import React, { useState, useEffect } from 'react';
18+
import React, { useEffect, useState } from 'react';
1919
import { styled } from '@mui/material/styles';
2020
import { Route, Switch } from 'react-router-dom';
2121
import ResourceNotFound from 'AppComponents/Base/Errors/ResourceNotFound';
2222
import { usePublisherSettings } from 'AppComponents/Shared/AppContext';
23+
import { Progress } from 'AppComponents/Shared';
2324
import APICreateDefault from './Default/APICreateDefault';
2425
import APIProductCreateWrapper from './APIProduct/APIProductCreateWrapper';
2526
import ApiCreateSwagger from './OpenAPI/ApiCreateOpenAPI';
@@ -42,6 +43,27 @@ const Root = styled('div')({
4243
},
4344
});
4445

46+
const gatewayDetsils = {
47+
'wso2/synapse': {
48+
value: 'wso2/synapse',
49+
name: 'Regular Gateway',
50+
description: 'API gateway embedded in APIM runtime. Connect directly APIManager.',
51+
isNew: false
52+
},
53+
'wso2/apk': {
54+
value: 'wso2/apk',
55+
name: 'APK Gateway',
56+
description: 'Fast API gateway running on kubernetes designed to manage and secure APIs.',
57+
isNew: true
58+
},
59+
'AWS': {
60+
value: 'AWS',
61+
name: 'AWS Gateway',
62+
description: 'A secure and scalable API gateway from AWS.',
63+
isNew: true
64+
}
65+
};
66+
4567
// Wrapper component to pass additional props
4668
const WithSomeValue = (Component, additionalProps) => (routeProps) => (
4769
<Component {...routeProps} {...additionalProps} />
@@ -54,41 +76,64 @@ const WithSomeValue = (Component, additionalProps) => (routeProps) => (
5476
* @returns @inheritdoc
5577
*/
5678
function APICreateRoutes() {
57-
const { data: settings } = usePublisherSettings();
58-
const [gateway, setGatewayType] = useState(false);
59-
60-
const getGatewayType = () => {
61-
if (settings != null) {
62-
if (settings.gatewayTypes && settings.gatewayTypes.length === 2 ) {
63-
setGatewayType(true);
64-
} else {
65-
setGatewayType(false);
66-
}
67-
}
68-
};
79+
const { data: publisherSettings, isLoading } = usePublisherSettings();
80+
const [apiTypes, setApiTypes] = useState(null);
81+
const [gatewayTypes, setGatewayTypes] = useState(null);
6982

7083
useEffect(() => {
71-
getGatewayType();
72-
}, [settings]);
84+
if (!isLoading) {
85+
setApiTypes(JSON.parse(publisherSettings.gatewayFeatureCatalog).apiTypes);
86+
const data = publisherSettings.gatewayTypes;
87+
const updatedData = data.map(item => {
88+
if (item === "Regular") return "wso2/synapse";
89+
if (item === "APK") return "wso2/apk";
90+
return item;
91+
});
92+
setGatewayTypes(updatedData);
93+
}
94+
}, [isLoading]);
95+
96+
if (isLoading) {
97+
return <Progress per={80} message='Loading app settings ...' />;
98+
}
7399

74100
return (
75101
<Root className={classes.content}>
76102
<Switch>
77-
<Route path='/apis/create/rest' component={WithSomeValue(APICreateDefault, { multiGateway: gateway })}/>
103+
<Route path='/apis/create/rest' component={WithSomeValue(APICreateDefault,
104+
{ multiGateway: apiTypes?.rest
105+
.filter(t=>gatewayTypes.includes(t)).map(type => gatewayDetsils[type]) })}
106+
/>
78107
<Route path='/api-products/create' component={APIProductCreateWrapper} />
79108
<Route path='/apis/create/graphQL' component={WithSomeValue(ApiCreateGraphQL,
80-
{ multiGateway: gateway })}
109+
{ multiGateway: apiTypes?.graphql
110+
.filter(t=>gatewayTypes.includes(t)).map(type => gatewayDetsils[type]) })}
81111
/>
82112
<Route path='/apis/create/openapi' component={WithSomeValue(ApiCreateSwagger,
83-
{ multiGateway: gateway })}
113+
{ multiGateway: apiTypes?.rest
114+
.filter(t=>gatewayTypes.includes(t)).map(type => gatewayDetsils[type]) })}
115+
/>
116+
<Route path='/apis/create/wsdl' component={WithSomeValue(ApiCreateWSDL,
117+
{ multiGateway: apiTypes?.soap
118+
.filter(t=>gatewayTypes.includes(t)).map(type => gatewayDetsils[type]) })}
84119
/>
85-
<Route path='/apis/create/wsdl' component={ApiCreateWSDL} />
86120
{/* TODO: Remove ApiCreateWebSocket components and associated routes */}
87-
<Route path='/apis/create/ws' component={ApiCreateWebSocket} />
88-
<Route path='/apis/create/streamingapi/:apiType' component={APICreateStreamingAPI} />
89-
<Route path='/apis/create/asyncapi' component={APICreateAsyncAPI} />
121+
<Route path='/apis/create/ws' component={WithSomeValue(ApiCreateWebSocket,
122+
{ multiGateway: apiTypes?.ws
123+
.filter(t=>gatewayTypes.includes(t)).map(type => gatewayDetsils[type]) })}
124+
/>
125+
<Route path='/apis/create/streamingapi/:apiType' component={WithSomeValue(APICreateStreamingAPI,
126+
{ multiGateway: apiTypes?.ws
127+
.filter(t=>gatewayTypes.includes(t)).map(type => gatewayDetsils[type]) })}
128+
/>
129+
<Route path='/apis/create/asyncapi' component={WithSomeValue(APICreateAsyncAPI,
130+
{ multiGateway: apiTypes?.ws
131+
.filter(t=>gatewayTypes.includes(t)).map(type => gatewayDetsils[type]) })}
132+
/>
90133
<Route path='/apis/create/ai-api' component={WithSomeValue(ApiCreateAIAPI,
91-
{ multiGateway: gateway })}/>
134+
{ multiGateway: apiTypes?.ai
135+
.filter(t=>gatewayTypes.includes(t)).map(type => gatewayDetsils[type]) })}
136+
/>
92137
<Route component={ResourceNotFound} />
93138
</Switch>
94139
</Root>

portals/publisher/src/main/webapp/source/src/app/components/Apis/Create/AsyncAPI/ApiCreateAsyncAPI.jsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ const StyledAPICreateBase = styled(APICreateBase)((
8181
*/
8282
export default function ApiCreateAsyncAPI(props) {
8383
const [wizardStep, setWizardStep] = useState(0);
84-
const { history } = props;
84+
const { history, multiGateway } = props;
8585
// eslint-disable-next-line no-use-before-define
8686

8787
const [hideEndpoint, setHideEndpoint] = useState(true);
@@ -355,6 +355,7 @@ export default function ApiCreateAsyncAPI(props) {
355355
hideEndpoint={hideEndpoint}
356356
endpointPlaceholderText='Streaming Provider'
357357
appendChildrenBeforeEndpoint
358+
multiGateway={multiGateway}
358359
>
359360
<Grid container spacing={2}>
360361
{apiInputs.gatewayVendor === 'solace'

portals/publisher/src/main/webapp/source/src/app/components/Apis/Create/Components/DefaultAPIForm.jsx

Lines changed: 45 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { styled } from '@mui/material/styles';
2020
import PropTypes from 'prop-types';
2121
import TextField from '@mui/material/TextField';
2222
import Grid from '@mui/material/Grid';
23-
import { InputAdornment, IconButton, Icon } from '@mui/material';
23+
import { InputAdornment, IconButton, Icon, Select, MenuItem, Box } from '@mui/material';
2424
import CircularProgress from '@mui/material/CircularProgress';
2525
import Chip from '@mui/material/Chip';
2626
import Typography from '@mui/material/Typography';
@@ -29,9 +29,6 @@ import APIValidation from 'AppData/APIValidation';
2929
import FormControl from '@mui/material/FormControl';
3030
import FormHelperText from '@mui/material/FormHelperText';
3131
import FormLabel from '@mui/material/FormLabel';
32-
import Radio from '@mui/material/Radio';
33-
import RadioGroup from '@mui/material/RadioGroup';
34-
import FormControlLabel from '@mui/material/FormControlLabel';
3532
import API from 'AppData/api';
3633
import { green } from '@mui/material/colors';
3734

@@ -170,12 +167,6 @@ export default function DefaultAPIForm(props) {
170167
const [isErrorCode, setIsErrorCode] = useState(false);
171168
const iff = (condition, then, otherwise) => (condition ? then : otherwise);
172169

173-
const getBorderColor = (gatewayType) => {
174-
return api.gatewayType === gatewayType
175-
? '2px solid #1976D2'
176-
: '2px solid gray';
177-
};
178-
179170
// Check the provided API validity on mount, TODO: Better to use Joi schema here ~tmkb
180171
useEffect(() => {
181172
onValidate(Boolean(api.name)
@@ -655,87 +646,63 @@ export default function DefaultAPIForm(props) {
655646
}}
656647
/>
657648
)}
658-
{multiGateway &&
649+
{multiGateway && multiGateway.length > 1 &&
659650
<Grid container spacing={2}>
660-
<FormControl component='fieldset'>
651+
<FormControl component='fieldset' fullWidth>
661652
<FormLabel sx={{ marginLeft: '15px', marginTop: '20px' }}>
662653
<FormattedMessage
663654
id='Apis.Create.Components.DefaultAPIForm.select.gateway.type'
664655
defaultMessage='Select Gateway type'
665656
/>
657+
<sup className={classes.mandatoryStar}>*</sup>
666658
</FormLabel>
667-
<RadioGroup
668-
row
669-
aria-label='gateway-type'
670-
name='gatewayType'
659+
<Select
660+
id='gateway-type-select'
671661
value={api.gatewayType}
662+
defaultValue={multiGateway[0].value}
672663
onChange={onChange}
664+
fullWidth
665+
sx={{ marginLeft: '15px', marginTop: '10px', minWidth: 200 }}
666+
inputProps={{ name: 'gatewayType', id: 'gateway-type-select' }}
673667
>
674-
<Grid item xs={6}>
675-
<FormControlLabel
676-
value='wso2/synapse'
677-
className={classes.radioOutline}
678-
control={<Radio />}
679-
label={(
680-
<div>
681-
<span>
682-
<FormattedMessage
683-
id={'Apis.Create.Components.DefaultAPIForm.'
684-
+ 'regular.gateway.type'}
685-
defaultMessage='Regular Gateway'
686-
/>
687-
</span>
688-
<Typography variant='body2' color='textSecondary'>
689-
<FormattedMessage
690-
id={'Apis.Create.Components.DefaultAPIForm.'
691-
+ 'regular.gateway.type.text'}
692-
defaultMessage={'API gateway embedded in APIM '
693-
+ 'runtime. Connect directly APIManager.'}
694-
/>
695-
</Typography>
696-
</div>
697-
)}
698-
sx={{ border: getBorderColor('wso2/synapse') }}
668+
<MenuItem disabled value=''>
669+
<FormattedMessage
670+
id='Apis.Create.Components.DefaultAPIForm.select.gateway.type.placeholder'
671+
defaultMessage='Please select a gateway type'
699672
/>
700-
</Grid>
701-
<Grid item xs={6}>
702-
<FormControlLabel
703-
value='wso2/apk'
704-
className={classes.radioOutline}
705-
control={<Radio />}
706-
label={(
707-
<div>
708-
<span>
709-
<FormattedMessage
710-
id={'Apis.Create.Components.DefaultAPIForm.'
711-
+ 'apk.gateway.type'}
712-
defaultMessage='APK Gateway'
713-
/>
714-
</span>
715-
<span className={`${classes.label} ${classes.newLabel}`}>New</span>
716-
<Typography variant='body2' color='textSecondary'>
717-
<FormattedMessage
718-
id={'Apis.Create.Components.DefaultAPIForm.'
719-
+ 'apk.gateway.type.text'}
720-
defaultMessage={'Fast API gateway running on kubernetes'
721-
+ ' designed to manage and secure APIs.'}
722-
/>
723-
</Typography>
724-
</div>
725-
)}
726-
sx={{ border: getBorderColor('wso2/apk') }}
727-
/>
728-
</Grid>
729-
</RadioGroup>
730-
<FormHelperText sx={{ marginLeft: '15px' }}><FormattedMessage
731-
id={'Apis.Create.Components.DefaultAPIForm.'
732-
+ 'select.gateway.type.helper.text'}
733-
defaultMessage='Select the gateway type where your API will run.'
734-
/>
673+
</MenuItem>
674+
{multiGateway.map((gateway) =>
675+
<MenuItem key={gateway.value} value={gateway.value}>
676+
<Box>
677+
<Grid container direction='row' gap={1} alignItems='center'>
678+
<Grid item>
679+
<Typography variant='body1'>
680+
{gateway.name}
681+
</Typography>
682+
</Grid>
683+
{gateway.isNew &&
684+
<Grid item>
685+
<Chip label='New' color='success' size='small' />
686+
</Grid>
687+
}
688+
</Grid>
689+
<Typography variant='body2' color='textSecondary'>
690+
{gateway.description}
691+
</Typography>
692+
</Box>
693+
</MenuItem>
694+
)}
695+
</Select>
696+
<FormHelperText sx={{ marginLeft: '15px' }}>
697+
<FormattedMessage
698+
id={'Apis.Create.Components.DefaultAPIForm.'
699+
+ 'select.gateway.type.helper.text'}
700+
defaultMessage='Select the gateway type where your API will run.'
701+
/>
735702
</FormHelperText>
736703
</FormControl>
737704
</Grid>
738-
}
705+
}
739706
{!appendChildrenBeforeEndpoint && !!children && children}
740707
</form>
741708
<Grid container direction='row' justifyContent='flex-end' alignItems='center'>
@@ -762,7 +729,7 @@ DefaultAPIForm.defaultProps = {
762729
};
763730
DefaultAPIForm.propTypes = {
764731
api: PropTypes.shape({}),
765-
multiGateway: PropTypes.string.isRequired,
732+
multiGateway: PropTypes.isRequired,
766733
isAPIProduct: PropTypes.shape({}).isRequired,
767734
isWebSocket: PropTypes.shape({}),
768735
onChange: PropTypes.func.isRequired,

0 commit comments

Comments
 (0)