Skip to content

Commit

Permalink
Merge pull request #506 from HiranyaKavishani/main_new
Browse files Browse the repository at this point in the history
[Feature] UI fixes for versioning support of API Products
  • Loading branch information
HiranyaKavishani authored Dec 22, 2023
2 parents 62a8c1b + cc826b3 commit 5103710
Show file tree
Hide file tree
Showing 20 changed files with 345 additions and 89 deletions.
20 changes: 19 additions & 1 deletion portals/publisher/src/main/webapp/site/public/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@
"Apis.Create.APIProduct.APIProductCreateWrapper.sub.heading": [
{
"type": 0,
"value": "Create an API Product by providing a Name, a Context, Resources, and Business Plans (optional)."
"value": "Create an API Product by providing a Name, a Context, a Version, Resources, and Business Plans (optional)."
}
],
"Apis.Create.AsyncAPI.ApiCreateAsyncAPI.advertiseOnly.warning": [
Expand Down Expand Up @@ -225,6 +225,12 @@
"value": "Version"
}
],
"Apis.Create.Components.DefaultAPIForm.api.product.version": [
{
"type": 0,
"value": "Version"
}
],
"Apis.Create.Components.NewTopic.topic.name": [
{
"type": 0,
Expand Down Expand Up @@ -1359,6 +1365,18 @@
"value": "Selected Rate Limiting Policy will be applied to all the requests of this API."
}
],
"Apis.Details.APIProduct.NewVersion.NewVersion.error": [
{
"type": 0,
"value": "Something went wrong while creating a new version!. Error:"
}
],
"Apis.Details.APIProduct.NewVersion.NewVersion.success": [
{
"type": 0,
"value": "Successfully created new version"
}
],
"Apis.Details.AccessControl.roles.help": [
{
"type": 0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
"defaultMessage": "Add Resources"
},
"Apis.Create.APIProduct.APIProductCreateWrapper.sub.heading": {
"defaultMessage": "Create an API Product by providing a Name, a Context, Resources, and Business Plans (optional)."
"defaultMessage": "Create an API Product by providing a Name, a Context, a Version, Resources, and Business Plans (optional)."
},
"Apis.Create.AsyncAPI.ApiCreateAsyncAPI.advertiseOnly.warning": {
"defaultMessage": "API Manager only supports the streaming APIs of types WebSocket, SSE and WebSub. Please create one of the supported types if you want to deploy it in the gateway."
Expand Down Expand Up @@ -98,6 +98,9 @@
"Apis.Create.Components.DefaultAPIForm.api.product.context": {
"defaultMessage": "Context"
},
"Apis.Create.Components.DefaultAPIForm.api.product.version": {
"defaultMessage": "Version"
},
"Apis.Create.Components.DefaultAPIForm.name": {
"defaultMessage": "Name"
},
Expand Down Expand Up @@ -582,6 +585,12 @@
"Apis.Details.APILevelRateLimitingPolicies.components.Configuration.tooltip": {
"defaultMessage": "Selected Rate Limiting Policy will be applied to all the requests of this API."
},
"Apis.Details.APIProduct.NewVersion.NewVersion.error": {
"defaultMessage": "Something went wrong while creating a new version!. Error:"
},
"Apis.Details.APIProduct.NewVersion.NewVersion.success": {
"defaultMessage": "Successfully created new version"
},
"Apis.Details.AccessControl.roles.help": {
"defaultMessage": "Enter valid role and press enter"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ export default function ApiProductCreateWrapper(props) {
<FormattedMessage
id='Apis.Create.APIProduct.APIProductCreateWrapper.sub.heading'
defaultMessage={
'Create an API Product by providing a Name, a Context, Resources, '
'Create an API Product by providing a Name, a Context, a Version, Resources, '
+ 'and Business Plans (optional).'
}
/>
Expand Down Expand Up @@ -190,11 +190,12 @@ export default function ApiProductCreateWrapper(props) {
const createAPIProduct = () => {
setCreating(true);
const {
name, context,
name, context, version,
} = apiInputs;
const apiData = {
name,
context,
version,
policies,
apis: apiResources,
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ export default function DefaultAPIForm(props) {
// Check the provided API validity on mount, TODO: Better to use Joi schema here ~tmkb
useEffect(() => {
onValidate(Boolean(api.name)
&& (isAPIProduct || Boolean(api.version))
&& (Boolean(api.version))
&& Boolean(api.context));
}, []);

Expand All @@ -154,10 +154,9 @@ export default function DefaultAPIForm(props) {
.reduce((acc, cVal) => acc && cVal); // Aggregate the individual validation states
// TODO: refactor following redundant validation.
// The valid state should available in the above reduced state ~tmkb
// if isAPIProduct gets true version validation has been skipped
isFormValid = isFormValid
&& Boolean(api.name)
&& (isAPIProduct || Boolean(api.version))
&& Boolean(api.version)
&& Boolean(api.context);
onValidate(isFormValid, validity);
setValidity(newState);
Expand Down Expand Up @@ -430,7 +429,7 @@ export default function DefaultAPIForm(props) {
</>
) : (
<>
<Grid item md={12}>
<Grid item md={8} xs={6}>
<TextField
fullWidth
id='context'
Expand Down Expand Up @@ -470,6 +469,37 @@ export default function DefaultAPIForm(props) {
variant='outlined'
/>
</Grid>
<Grid item md={4} xs={6}>
<TextField
fullWidth
id='version'
error={Boolean(validity.version)}
label={(
<>
<FormattedMessage
id='Apis.Create.Components.DefaultAPIForm.api.product.version'
defaultMessage='Version'
/>
<sup className={classes.mandatoryStar}>*</sup>
</>
)}
name='version'
value={api.version}
onChange={onChange}
InputProps={{
id: 'itest-id-apiversion-input',
onBlur: ({ target: { value } }) => {
validate('version', value);
},
}}
InputLabelProps={{
for: 'itest-id-apiversion-input',
}}
helperText={validity.version && validity.version.message}
margin='normal'
variant='outlined'
/>
</Grid>
</>
)}
</Grid>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,11 @@ const useStyles = makeStyles((theme) => ({
* @returns {Object} Deep copy of an object
*/
function copyAPIConfig(api) {
let isDefaultVersion = false;
// to set isDefaultVersion of migrated APIProducts as true
if (api.apiType === API.CONSTS.APIProduct && api.isDefaultVersion == null) {
isDefaultVersion = true;
}
const copiedConfig = {
id: api.id,
name: api.name,
Expand All @@ -146,7 +151,7 @@ function copyAPIConfig(api) {
responseCachingEnabled: api.responseCachingEnabled,
cacheTimeout: api.cacheTimeout,
visibility: api.visibility,
isDefaultVersion: api.isDefaultVersion,
isDefaultVersion: api.isDefaultVersion || isDefaultVersion,
enableSchemaValidation: api.enableSchemaValidation,
accessControlRoles: [...api.accessControlRoles],
visibleRoles: [...api.visibleRoles],
Expand Down Expand Up @@ -562,9 +567,7 @@ export default function DesignConfigurations() {
)}
</Box>
<Box py={1}>
{api.apiType !== API.CONSTS.APIProduct && (
<DefaultVersion api={apiConfig} configDispatcher={configDispatcher} />
)}
<DefaultVersion api={apiConfig} configDispatcher={configDispatcher} />
</Box>
<Box pt={2}>
<Button
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,11 +171,12 @@ class LifeCycleUpdate extends Component {
const lifecycleChecklist = this.props.checkList.map((item) => item.value + ':' + item.checked);
const { isAPIProduct } = this.props;
if (isAPIProduct) {
promisedUpdate = this.apiProduct.updateLcState(apiUUID, action, lifecycleChecklist);
} else if (lifecycleChecklist.length > 0) {
promisedUpdate = this.api.updateLcState(apiUUID, action, lifecycleChecklist.toString());
promisedUpdate = this.apiProduct.updateLcState(apiUUID, action, lifecycleChecklist.length > 0
? lifecycleChecklist.toString() : lifecycleChecklist );
} else {
promisedUpdate = this.api.updateLcState(apiUUID, action);
promisedUpdate = (lifecycleChecklist.length > 0)
? this.api.updateLcState(apiUUID, action, lifecycleChecklist.toString())
: this.api.updateLcState(apiUUID, action);
}
promisedUpdate
.then((response) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import FormControlLabel from '@material-ui/core/FormControlLabel';
import Radio from '@material-ui/core/Radio';
import FormLabel from '@material-ui/core/FormLabel';
import Alert from 'AppComponents/Shared/Alert';
import API from 'AppData/api';
import { withAPI } from 'AppComponents/Apis/Details/components/ApiContext';

const styles = (theme) => ({
Expand Down Expand Up @@ -114,15 +115,17 @@ class CreateNewVersion extends React.Component {

componentDidMount() {
const { api } = this.props;
if (api.serviceInfo !== null) {
const promisedServices = ServiceCatalog.getServiceByName(api.serviceInfo);
promisedServices.then((data) => {
const array = data.list.map((item) => item.version);
this.setState({ versionList: array });
}).catch((error) => {
console.error(error);
Alert.error('Error while loading services version');
});
if (api.serviceInfo !== undefined) {
if (api.serviceInfo !== null) {
const promisedServices = ServiceCatalog.getServiceByName(api.serviceInfo);
promisedServices.then((data) => {
const array = data.list.map((item) => item.version);
this.setState({ versionList: array });
}).catch((error) => {
console.error(error);
Alert.error('Error while loading services version');
});
}
}
}

Expand Down Expand Up @@ -168,28 +171,53 @@ class CreateNewVersion extends React.Component {
return;
}
const isDefaultVersionBool = isDefaultVersion === 'yes';
const apiClient = new API();
const { intl } = this.props;
api.createNewAPIVersion(newVersion, isDefaultVersionBool, serviceVersion)
.then((response) => {
this.setState({
redirectToReferrer: true,
apiId: response.obj.id,
if (api.apiType === 'APIPRODUCT') {
apiClient.createNewAPIProductVersion(api.id ,newVersion, isDefaultVersionBool)
.then((response) => {
this.setState({
redirectToReferrer: true,
apiId: response.obj.id,
});
Alert.info(intl.formatMessage({
id: 'Apis.Details.APIProduct.NewVersion.NewVersion.success',
defaultMessage: 'Successfully created new version ',
}) + newVersion);
})
.catch((error) => {
if (error.status === 409) {
this.setState({ valid: { version: { alreadyExists: true } } });
} else {
Alert.error(intl.formatMessage({
id: 'Apis.Details.APIProduct.NewVersion.NewVersion.error',
defaultMessage: 'Something went wrong while creating a new version!. Error: ',
}) + error.status);
}
});
} else {
apiClient.createNewAPIVersion(api.id, newVersion, isDefaultVersionBool, serviceVersion)
.then((response) => {
this.setState({
redirectToReferrer: true,
apiId: response.obj.id,
});
Alert.info(intl.formatMessage({
id: 'Apis.Details.NewVersion.NewVersion.success',
defaultMessage: 'Successfully created new version ',
}) + newVersion);
})
.catch((error) => {
if (error.status === 409) {
this.setState({ valid: { version: { alreadyExists: true } } });
} else {
Alert.error(intl.formatMessage({
id: 'Apis.Details.NewVersion.NewVersion.error',
defaultMessage: 'Something went wrong while creating a new version!. Error: ',
}) + error.status);
}
});
Alert.info(intl.formatMessage({
id: 'Apis.Details.NewVersion.NewVersion.success',
defaultMessage: 'Successfully created new version ',
}) + newVersion);
})
.catch((error) => {
if (error.status === 409) {
this.setState({ valid: { version: { alreadyExists: true } } });
} else {
Alert.error(intl.formatMessage({
id: 'Apis.Details.NewVersion.NewVersion.error',
defaultMessage: 'Something went wrong while creating a new version!. Error: ',
}) + error.status);
}
});
}
}

/**
Expand Down Expand Up @@ -224,7 +252,7 @@ class CreateNewVersion extends React.Component {
isDefaultVersion, newVersion, redirectToReferrer, apiId, valid, serviceVersion, versionList,
} = this.state;
if (redirectToReferrer) {
return <Redirect to={'/apis/' + apiId + '/overview'} />;
return <Redirect to={(api.apiType === 'APIPRODUCT' ? '/api-products/' : '/apis/') + apiId + '/overview'} />;
}

let helperText = '';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,6 @@ const TryOutConsole = () => {
}
}, [publisherSettings]);

const isAPIProduct = api.apiType === 'APIPRODUCT';
const isAdvertised = api.advertiseInfo && api.advertiseInfo.advertised;
const setServersSpec = (spec, serverUrl) => {
let schemes;
Expand Down Expand Up @@ -186,18 +185,12 @@ const TryOutConsole = () => {
}
if (transportPort !== -1) {
const baseURL = `${transport}://${selectedDeployment.vhost}:${transportPort}`;
let url;
if (isAPIProduct) {
url = `${baseURL}${pathSeparator}`
+ `${selectedDeploymentVhost.httpContext}${api.context}`;
} else {
url = `${baseURL}${pathSeparator}`
let url = `${baseURL}${pathSeparator}`
+ `${selectedDeploymentVhost.httpContext}${api.context}/${api.version}`;
if (`${api.context}`.includes('{version}')) {
url = `${baseURL}${pathSeparator}`
if (`${api.context}`.includes('{version}')) {
url = `${baseURL}${pathSeparator}`
+ `${selectedDeploymentVhost.httpContext}${api.context}`
.replaceAll('{version}', `${api.version}`);
}
}
return {url};
}
Expand All @@ -216,16 +209,15 @@ const TryOutConsole = () => {
}
const host = `${selectedDeploymentVhost.host}:${transportPort}`;
let basePath;
if (isAPIProduct) {
basePath = `${pathSeparator}${selectedDeploymentVhost.httpContext}${api.context}`;
} else {
basePath = `${pathSeparator}${selectedDeploymentVhost.
httpContext}${api.context}/${api.version}`;
if (`${api.context}`.includes('{version}')) {
basePath = `${pathSeparator}${selectedDeploymentVhost.httpContext}${api.context}`
.replaceAll('{version}', `${api.version}`);
}

basePath = `${pathSeparator}${selectedDeploymentVhost.
httpContext}${api.context}/${api.version}`;

if (`${api.context}`.includes('{version}')) {
basePath = `${pathSeparator}${selectedDeploymentVhost
.httpContext}${api.context}`.replaceAll('{version}', `${api.version}`);
}

let schemes = api.transport.slice().sort((a, b) => ((a > b) ? -1 : 1));
if (selectedDeploymentVhost.httpPort === -1){
schemes = schemes.filter(item => item !== 'http');
Expand Down
Loading

0 comments on commit 5103710

Please sign in to comment.