Skip to content

Commit

Permalink
UI fixes for versioning support of API Products
Browse files Browse the repository at this point in the history
  • Loading branch information
HiranyaKavishani committed Sep 27, 2023
1 parent c5c556d commit 6bf2a91
Show file tree
Hide file tree
Showing 9 changed files with 142 additions and 54 deletions.
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 @@ -146,7 +146,7 @@ function copyAPIConfig(api) {
responseCachingEnabled: api.responseCachingEnabled,
cacheTimeout: api.cacheTimeout,
visibility: api.visibility,
isDefaultVersion: api.isDefaultVersion,
isDefaultVersion: api.isDefaultVersion || false,
enableSchemaValidation: api.enableSchemaValidation,
accessControlRoles: [...api.accessControlRoles],
visibleRoles: [...api.visibleRoles],
Expand Down Expand Up @@ -562,9 +562,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 @@ -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,7 +115,7 @@ class CreateNewVersion extends React.Component {

componentDidMount() {
const { api } = this.props;
if (api.serviceInfo !== null) {
if (api.serviceInfo !== null || api.serviceInfo === undefined) {
const promisedServices = ServiceCatalog.getServiceByName(api.serviceInfo);
promisedServices.then((data) => {
const array = data.list.map((item) => item.version);
Expand Down Expand Up @@ -168,28 +169,54 @@ 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,
// eslint-disable-next-line no-empty
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);
}
});
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);
}
});
} 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);
}
});
}
}

/**
Expand Down Expand Up @@ -224,7 +251,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 @@ -205,7 +205,7 @@ const APIDetailsTopMenu = (props) => {
className={classes.backLink}
>
<Box width={70} height={50} marginLeft={1}>
<ThumbnailView api={api} width={70} height={50} imageUpdate={imageUpdate}
<ThumbnailView api={api} width={70} height={50} imageUpdate={imageUpdate}
updateAPI={updateAPI} />
</Box>
<div style={{ marginLeft: theme.spacing(1), maxWidth: 500 }}>
Expand All @@ -218,7 +218,7 @@ const APIDetailsTopMenu = (props) => {
<Typography id='itest-api-name-version' variant='h4' component='h1' className={classes.apiName}>
{api.name}
{' '}
{isAPIProduct ? '' : ':' + api.version}
{api.version}
</Typography>
<Typography variant='caption' gutterBottom align='left'>
<FormattedMessage
Expand Down Expand Up @@ -402,8 +402,10 @@ const APIDetailsTopMenu = (props) => {
)}
{/* Page error banner */}
{/* end of Page error banner */}
{isAPIProduct || api.isRevision
? null : <CreateNewVersionButton buttonClass={classes.viewInStoreLauncher} api={api} />}
{api.isRevision
? null :
<CreateNewVersionButton buttonClass={classes.viewInStoreLauncher}
api={api} isAPIProduct={isAPIProduct} />}
{(isDownloadable) && <VerticalDivider height={70} />}
<div className={classes.downloadApi}>
{(isDownloadable) && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ const styles = (theme) => ({
* @constructor
*/
function CreateNewVersionButton(props) {
const { api, classes } = props;
const { api, classes, isAPIProduct } = props;
return (
<>
{/* allowing create new version based on scopes */}
Expand All @@ -86,7 +86,7 @@ function CreateNewVersionButton(props) {
<VerticalDivider height={70} />
<Link
className={classes.createNewVersion}
to={'/apis/' + api.id + '/new_version'}
to={(isAPIProduct ? '/api-products/' : '/apis/') + api.id + '/new_version'}
style={{ minWidth: 95 }}
>

Expand All @@ -110,6 +110,7 @@ CreateNewVersionButton.propTypes = {
api: PropTypes.shape({
id: PropTypes.string,
}).isRequired,
isAPIProduct: PropTypes.bool.isRequired,
history: PropTypes.shape({ push: PropTypes.func }).isRequired,
classes: PropTypes.shape({}).isRequired,
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -972,6 +972,10 @@ class Details extends Component {
component={() => <Properties api={api} />}
/>
<Route path={Details.subPaths.NEW_VERSION} component={() => <CreateNewVersion />} />
<Route
path={Details.subPaths.NEW_VERSION_PRODUCT}
component={() => <CreateNewVersion />} />

<Route path={Details.subPaths.SUBSCRIPTIONS} component={() => <Subscriptions />} />
<Route
path={Details.subPaths.MONETIZATION}
Expand Down Expand Up @@ -1047,6 +1051,7 @@ Details.subPaths = {
PROPERTIES: '/apis/:api_uuid/properties',
PROPERTIES_PRODUCT: '/api-products/:apiprod_uuid/properties',
NEW_VERSION: '/apis/:api_uuid/new_version',
NEW_VERSION_PRODUCT: '/api-products/:api_uuid/new_version',
MONETIZATION: '/apis/:api_uuid/monetization',
MONETIZATION_PRODUCT: '/api-products/:apiprod_uuid/monetization',
EXTERNAL_STORES: '/apis/:api_uuid/external-devportals',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -248,19 +248,17 @@ class APIThumb extends Component {
</Typography>
</div>
<div className={classes.thumbInfo}>
{isAPIProduct ? null : (
<div className={classes.row}>
<div className={classes.thumbLeft}>
<Typography variant='subtitle1'>{api.version}</Typography>
</div>
<div className={classes.row}>
<div className={classes.thumbLeft}>
<Typography variant='subtitle1'>{api.version}</Typography>
</div>

<div className={classes.thumbLeft}>
<Typography variant='caption' gutterBottom align='left'>
<FormattedMessage defaultMessage='Version' id='Apis.Listing.ApiThumb.version' />
</Typography>
</div>
<div className={classes.thumbLeft}>
<Typography variant='caption' gutterBottom align='left'>
<FormattedMessage defaultMessage='Version' id='Apis.Listing.ApiThumb.version' />
</Typography>
</div>
)}
</div>
<div className={classes.row}>
<div className={classes.thumbRight}>
<Typography variant='subtitle1' align='right' className={classes.contextBox}>
Expand Down
36 changes: 31 additions & 5 deletions portals/publisher/src/main/webapp/source/src/app/data/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -462,11 +462,11 @@ class API extends Resource {
* @param callback {function} A callback function to invoke after receiving successful response.
* @returns {promise} With given callback attached to the success chain else API invoke promise.
*/
createNewAPIVersion(version, isDefaultVersion, serviceVersion, callback = null) {
createNewAPIVersion(apiId, version, isDefaultVersion, serviceVersion, callback = null) {
const promise_copy_api = this.client.then(client => {
return client.apis['APIs'].createNewAPIVersion(
{
apiId: this.id,
apiId: this.id || apiId,
newVersion: version,
serviceVersion: serviceVersion,
defaultVersion: isDefaultVersion,
Expand All @@ -481,6 +481,32 @@ class API extends Resource {
}
}


/**
* Create a new version of a given API Product
* @param version {string} new API Product version.
* @param isDefaultVersion specifies whether new API Product version is set as default version
* @param callback {function} A callback function to invoke after receiving successful response.
* @returns {promise} With given callback attached to the success chain else API Product invoke promise.
*/
createNewAPIProductVersion(apiProductId, version, isDefaultVersion, callback = null) {
const promise_copy_api_products = this.client.then(client => {
return client.apis['API Products'].createNewAPIProductVersion(
{
newVersion: version,
apiProductId: apiProductId,
defaultVersion: isDefaultVersion,
},
this._requestMetaData(),
);
});
if (callback) {
return promise_copy_api_products.then(callback);
} else {
return promise_copy_api_products;
}
}

/**
* Mock sample responses for Inline Prototyping
* of a swagger OAS defintion
Expand Down Expand Up @@ -770,7 +796,7 @@ class API extends Resource {
});
return promised_update;
}

/**
* Update an api via PUT HTTP method, Need to give the updated API object as the argument.
* @param api {Object} Updated API object(JSON) which needs to be updated
Expand Down Expand Up @@ -2875,7 +2901,7 @@ class API extends Resource {
);
});
}

/**
* Add a common operation policy
* @param {Object} policySpec policy specification of the common operation policy to upload
Expand Down Expand Up @@ -2958,7 +2984,7 @@ class API extends Resource {
);
});
}

/**
* Get API Operation Policies
* @param {String} apiId UUID of the API
Expand Down

0 comments on commit 6bf2a91

Please sign in to comment.