diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Create/AIAPI/APICreateAIAPI.jsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Create/AIAPI/APICreateAIAPI.jsx
index a7547ac59af..0f3df1df12d 100644
--- a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Create/AIAPI/APICreateAIAPI.jsx
+++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Create/AIAPI/APICreateAIAPI.jsx
@@ -32,6 +32,8 @@ import Alert from 'AppComponents/Shared/Alert';
import CircularProgress from '@mui/material/CircularProgress';
import DefaultAPIForm from 'AppComponents/Apis/Create/Components/DefaultAPIForm';
import APICreateBase from 'AppComponents/Apis/Create/Components/APICreateBase';
+import { API_SECURITY_API_KEY }
+ from 'AppComponents/Apis/Details/Configuration/components/APISecurity/components/apiSecurityConstants';
import ProvideAIOpenAPI from './Steps/ProvideAIOpenAPI';
@@ -143,6 +145,7 @@ export default function ApiCreateAIAPI(props) {
llmProviderName,
llmProviderApiVersion,
},
+ securityScheme: [API_SECURITY_API_KEY]
};
if (endpoint) {
additionalProperties.endpointConfig = {
diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Configuration/RuntimeConfiguration.jsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Configuration/RuntimeConfiguration.jsx
index e07572396c5..ec0a8a245e0 100644
--- a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Configuration/RuntimeConfiguration.jsx
+++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Configuration/RuntimeConfiguration.jsx
@@ -388,9 +388,20 @@ export default function RuntimeConfiguration() {
case 'saveButtonDisabled':
setSaveButtonDisabled(value);
return state;
- case 'aiConfiguration':
+ case 'aiConfiguration': {
nextState.aiConfiguration = value;
+ const { throttlingConfiguration } = nextState.aiConfiguration;
+ if (throttlingConfiguration) {
+ throttlingConfiguration.isTokenBasedThrottlingEnabled = !!(
+ throttlingConfiguration.productionMaxPromptTokenCount ||
+ throttlingConfiguration.productionMaxCompletionTokenCount ||
+ throttlingConfiguration.productionMaxTotalTokenCount ||
+ throttlingConfiguration.sandboxMaxPromptTokenCount ||
+ throttlingConfiguration.sandboxMaxCompletionTokenCount ||
+ throttlingConfiguration.sandboxMaxTotalTokenCount)
+ }
return nextState;
+ }
default:
return state;
}
diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Configuration/components/AIBackendRateLimiting/BackendRateLimiting.jsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Configuration/components/AIBackendRateLimiting/BackendRateLimiting.jsx
index 771ee8f04a5..b3e5fd4b0c4 100644
--- a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Configuration/components/AIBackendRateLimiting/BackendRateLimiting.jsx
+++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Configuration/components/AIBackendRateLimiting/BackendRateLimiting.jsx
@@ -19,10 +19,6 @@ import React from 'react';
import PropTypes from 'prop-types';
import Grid from '@mui/material/Grid';
-import { Switch, Typography } from '@mui/material';
-
-import { isRestricted } from 'AppData/AuthManager';
-import { useAPI } from 'AppComponents/Apis/Details/components/ApiContext';
import BackendRateLimitingForm from './BackendRateLimitingForm';
// import { useIntl } from 'react-intl';
@@ -36,43 +32,9 @@ import BackendRateLimitingForm from './BackendRateLimitingForm';
*/
export default function BackendRateLimiting(props) {
const { api, configDispatcher } = props;
- const [apiFromContext] = useAPI();
- // const intl = useIntl();
-
- function handleOnChangeTokenBasedSwitch({ target: { checked } }) {
- let throttlingConfiguration = {};
- if (api.aiConfiguration && api.aiConfiguration.throttlingConfiguration) {
- throttlingConfiguration = api.aiConfiguration.throttlingConfiguration;
- }
- const dispatchValue = {
- ...api.aiConfiguration,
- throttlingConfiguration: {
- ...throttlingConfiguration,
- isTokenBasedThrottlingEnabled: checked
- }
- }
- configDispatcher({
- action: 'aiConfiguration',
- value: dispatchValue,
- })
- }
return (
<>
-
-
- Token Based Throttling
-
-
-
+
diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Configuration/components/AIBackendRateLimiting/CommonRateLimitingForm.jsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Configuration/components/AIBackendRateLimiting/CommonRateLimitingForm.jsx
index 1d3114c2093..73e32f3a6fa 100644
--- a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Configuration/components/AIBackendRateLimiting/CommonRateLimitingForm.jsx
+++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Configuration/components/AIBackendRateLimiting/CommonRateLimitingForm.jsx
@@ -45,8 +45,8 @@ export default function CommonRateLimitingForm(props) {
function validateValue(value) {
const validity = commonFormProps.validator ?
commonFormProps.validator.validate(value, { abortEarly: false }).error
- : APIValidation.isReqNumber.validate(value, { abortEarly: false }).error;
- if (validity === null) {
+ : APIValidation.isNumber.validate(value, { abortEarly: false }).error;
+ if (validity === null || !value) {
setIsValueValid(true);
configDispatcher({ action: 'saveButtonDisabled', value: false });
} else {
diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Configuration/components/AIBackendRateLimiting/RequestCountRateLimit.jsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Configuration/components/AIBackendRateLimiting/RequestCountRateLimit.jsx
new file mode 100644
index 00000000000..080486fc457
--- /dev/null
+++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Configuration/components/AIBackendRateLimiting/RequestCountRateLimit.jsx
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved.
+ *
+ * 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
+ *
+ * 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 from 'react';
+import PropTypes from 'prop-types';
+import { Grid, InputAdornment, TextField } from '@mui/material';
+import { useIntl } from 'react-intl';
+
+import { isRestricted } from 'AppData/AuthManager';
+import RequestCountRateLimitUnit from './RequestCountRateLimitUnit';
+
+
+export default function RequestCountRateLimit(props) {
+
+ const { api, configDispatcher, isProduction } = props;
+ const intl = useIntl();
+ let maxTpsValue;
+ if (api.maxTps) {
+ maxTpsValue = isProduction ? api.maxTps.production : api.maxTps.sandbox;
+ } else {
+ maxTpsValue = '';
+ }
+
+ return (<>
+
+ {
+ const value = isProduction ?
+ { ...api.maxTps, production: event.target.value } :
+ { ...api.maxTps, sandbox: event.target.value };
+ configDispatcher({
+ action: 'maxTps',
+ value,
+ });
+ }}
+ value={api.maxTps !== null ? maxTpsValue : ''}
+ disabled={isRestricted(['apim:api_create'], api)}
+ InputProps={{
+ endAdornment:
+
+ ,
+ }}
+ />
+
+ >);
+}
+
+RequestCountRateLimit.propTypes = {
+ api: PropTypes.shape({}).isRequired,
+ configDispatcher: PropTypes.func.isRequired,
+ isProduction: PropTypes.bool.isRequired,
+};
\ No newline at end of file
diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Configuration/components/AIBackendRateLimiting/RequestCountRateLimitUnit.jsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Configuration/components/AIBackendRateLimiting/RequestCountRateLimitUnit.jsx
new file mode 100644
index 00000000000..cbc941945aa
--- /dev/null
+++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Configuration/components/AIBackendRateLimiting/RequestCountRateLimitUnit.jsx
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved.
+ *
+ * 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
+ *
+ * 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 from 'react';
+import PropTypes from 'prop-types';
+import { MenuItem, TextField } from '@mui/material';
+
+// time unit enum
+const timeUnitEnum = {
+ SECOND: 'SECOND',
+ MINUTE: 'MINUTE',
+ HOUR: 'HOUR',
+};
+
+export default function RequestCountRateLimitUnit(props) {
+ const { api, configDispatcher, isProduction } = props; //eslint-disable-line
+ // const intl = useIntl();
+
+ let maxTpsUnitValue;
+ if (api.maxTps) {
+ maxTpsUnitValue = isProduction ? api.maxTps.productionTimeUnit : api.maxTps.sandboxTimeUnit;
+ }
+
+ if (!maxTpsUnitValue) {
+ maxTpsUnitValue = timeUnitEnum.SECOND;
+ }
+
+ return (
+ <>
+ {
+ const value = isProduction ?
+ { ...api.maxTps, productionTimeUnit: event.target.value } :
+ { ...api.maxTps, sandboxTimeUnit: event.target.value };
+ configDispatcher({
+ action: 'maxTps',
+ value,
+ });
+ }}
+ margin='none'
+ variant='standard'
+ sx={{
+ '& .MuiInputBase-root': {
+ '&:before': { borderBottom: 'none' }, // Remove underline
+ '&:after': { borderBottom: 'none' }, // Remove underline
+ },
+ }}
+ >
+ {Object.keys(timeUnitEnum).map((unit) => (
+
+ ))}
+
+ >
+ );
+}
+
+RequestCountRateLimitUnit.propTypes = {
+ api: PropTypes.shape({}).isRequired,
+ configDispatcher: PropTypes.func.isRequired,
+ isProduction: PropTypes.bool.isRequired,
+};
\ No newline at end of file
diff --git a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/EndpointOverview.jsx b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/EndpointOverview.jsx
index ef8a306dd2a..dde20031c64 100644
--- a/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/EndpointOverview.jsx
+++ b/portals/publisher/src/main/webapp/source/src/app/components/Apis/Details/Endpoints/EndpointOverview.jsx
@@ -288,6 +288,10 @@ function EndpointOverview(props) {
supportedEndpointTypes = [
{ key: 'http', value: 'HTTP/REST Endpoint' },
];
+ } else if (type === 'http' && api.aiConfiguration) {
+ supportedEndpointTypes = [
+ { key: 'http', value: 'HTTP/REST Endpoint' },
+ ]
} else {
supportedEndpointTypes = [
{ key: 'http', value: 'HTTP/REST Endpoint' },
@@ -727,7 +731,22 @@ function EndpointOverview(props) {
value={endpointType.key === 'MOCKED_OAS' ? 'INLINE' : endpointType.key}
onChange={handleEndpointTypeSelect}
>
- {supportedEnpointTypes.map((endpoint) => {
+ {!api.aiConfiguration && supportedEnpointTypes.map((endpoint) => {
+ return (
+
+ )}
+ label={endpoint.value}
+ />
+ );
+ })}
+ {api.aiConfiguration && supportedEnpointTypes.map((endpoint) => {
return (
{
setSwagger(resp.obj);
}).catch((err) => {
- console.err(err);
+ console.error(err);
});
}
}, []);
diff --git a/portals/publisher/src/main/webapp/source/src/app/data/APIValidation.js b/portals/publisher/src/main/webapp/source/src/app/data/APIValidation.js
index 3e168820e73..7836867ed7a 100644
--- a/portals/publisher/src/main/webapp/source/src/app/data/APIValidation.js
+++ b/portals/publisher/src/main/webapp/source/src/app/data/APIValidation.js
@@ -198,7 +198,7 @@ const definition = {
websubOperationTarget: Joi.string().regex(/^[^{}]*$/).required(),
name: Joi.string().min(1).max(255),
email: Joi.string().email({ tlds: false }).required(),
- isReqNumber: Joi.number().required(),
+ isNumber: Joi.number(),
};
export default definition;