diff --git a/src/components/forms/AccountForm.js b/src/components/forms/AccountForm.js
index 9f8a0d0..41c53d4 100644
--- a/src/components/forms/AccountForm.js
+++ b/src/components/forms/AccountForm.js
@@ -22,7 +22,7 @@ import CopyableText from '../elements/CopyableText';
import Span from '../elements/Span';
import handleErrors from "../../helpers/handleErrors";
import styled from 'styled-components/macro';
-import { APP_API_BASE_URL } from "../../constants";
+import { APP_API_BASE_URL, LIMITS } from "../../constants";
const StyledInputGroup = styled(InputGroup)`
position: relative;
@@ -94,6 +94,7 @@ const AccountForm = props => {
const [ sbcs, setSbcs ] = useState([]);
const [ subspaceSipRealmOtherValue, setSubspaceSipRealmOtherValue ] = useState('');
const [ subspaceEnable, setSubspaceEnable ] = useState(false);
+ const [localLimits, setLocalLimits] = useState([]);
// Invalid form inputs
const [ invalidName, setInvalidName ] = useState(false);
@@ -319,6 +320,16 @@ const AccountForm = props => {
},
});
promiseList.push(applicationsPromise);
+
+ const limitsPromise = axios({
+ method: 'get',
+ baseURL: APP_API_BASE_URL,
+ url: `/Accounts/${props.account_sid}/Limits`,
+ headers: {
+ Authorization: `Bearer ${jwt}`,
+ },
+ });
+ promiseList.push(limitsPromise);
}
const sbcsPromise = await axios({
@@ -337,13 +348,16 @@ const AccountForm = props => {
setAccounts(accountsData);
if (props.type === 'edit') {
+ // Application Data
const allApplications = (promiseAllValues[1] && promiseAllValues[1].data) || [];
const accountApplicationsData = allApplications.filter(app => {
return app.account_sid === props.account_sid;
});
setAccountApplications(accountApplicationsData);
+ // Limits Data
+ setLocalLimits(promiseAllValues[2]?.data);
}
- setSbcs(promiseAllValues[2]?.data);
+ setSbcs(promiseAllValues[3]?.data);
if (props.type === 'setup' && accountsData.length > 1) {
history.push('/internal/accounts');
@@ -558,7 +572,7 @@ const AccountForm = props => {
? `/Accounts`
: `/Accounts/${accountSid}`;
- await axios({
+ const accountResp = await axios({
method: props.type === 'add' ? 'post' : 'put',
baseURL: APP_API_BASE_URL,
url,
@@ -567,6 +581,23 @@ const AccountForm = props => {
},
data: axiosData,
});
+ // Update Limits
+ const acc_sid = accountSid ? accountSid : accountResp.data.sid;
+ await Promise.all(
+ localLimits.map(l => {
+ const method = l.quantity === "" ? 'delete' : 'post';
+ const limitUrl = l.quantity === "" ? `/Accounts/${props.account_sid}/Limits?category=${l.category}` : `/Accounts/${acc_sid}/Limits`;
+ return axios({
+ method: method,
+ baseURL: APP_API_BASE_URL,
+ url: limitUrl,
+ headers: {
+ Authorization: `Bearer ${jwt}`,
+ },
+ ...(method === 'post' && {data: l})
+ });
+ })
+ );
if (props.type === 'setup') {
isMounted = false;
@@ -892,6 +923,31 @@ const AccountForm = props => {
)}
+ {LIMITS.map(({ label, category }) => {
+ const quantity = localLimits?.find(l => l.category === category)?.quantity;
+ return
+
+ = 0 ? quantity : ""}
+ onChange={e => {
+ const limit = localLimits.find(l => l.category === category);
+ const value = e.target.value ? Number(e.target.value) : "";
+ if (limit) {
+ setLocalLimits(localLimits.map(l => l.category === category ? {...l, quantity: value} : l));
+ } else {
+ setLocalLimits([...localLimits, {category, quantity: value}]);
+ }
+ }}
+ >
+
+
+ ;
+ })}
{ process.env.REACT_APP_ENABLE_SUBSPACE ? (
<>
@@ -1022,7 +1078,6 @@ const AccountForm = props => {
)}
>
) : null }
-
{errorMessage && (
)}
diff --git a/src/components/forms/SettingsForm.js b/src/components/forms/SettingsForm.js
index 8f8ec3c..c428608 100644
--- a/src/components/forms/SettingsForm.js
+++ b/src/components/forms/SettingsForm.js
@@ -16,7 +16,7 @@ import Loader from '../blocks/Loader';
import Modal from '../blocks/Modal';
import { ServiceProviderValueContext } from '../../contexts/ServiceProviderContext';
import handleErrors from "../../helpers/handleErrors";
-import { APP_API_BASE_URL } from "../../constants";
+import { APP_API_BASE_URL, LIMITS } from "../../constants";
const Td = styled.td`
padding: 0.5rem 0;
@@ -60,6 +60,19 @@ const SettingsForm = () => {
const [serviceProviderSid, setServiceProviderSid] = useState('');
const [serviceProviders, setServiceProviders] = useState([]);
const [confirmDelete, setConfirmDelete] = useState(false);
+ const [localLimits, setLocalLimits] = useState([]);
+
+ const callApi = async (path, method, data) => {
+ return await axios({
+ method: method,
+ baseURL: APP_API_BASE_URL,
+ url: path,
+ headers: {
+ Authorization: `Bearer ${localStorage.getItem('token')}`,
+ },
+ ...(data && {data})
+ });
+ };
useEffect(() => {
const getSettingsData = async () => {
@@ -74,14 +87,7 @@ const SettingsForm = () => {
return;
}
- const serviceProvidersResponse = await axios({
- method: 'get',
- baseURL: APP_API_BASE_URL,
- url: `/ServiceProviders`,
- headers: {
- Authorization: `Bearer ${localStorage.getItem('token')}`,
- },
- });
+ const serviceProvidersResponse = await callApi(`/ServiceProviders`, 'get');
const sps = serviceProvidersResponse.data;
const sp = sps.find(s => s.service_provider_sid === currentServiceProvider);
@@ -91,6 +97,12 @@ const SettingsForm = () => {
setServiceProviderSid(sp.service_provider_sid || '');
setEnableMsTeams(sp.ms_teams_fqdn ? true : false);
setSbcDomainName(sp.ms_teams_fqdn || '');
+
+ // Fetch Service provider Limits
+ if (sp.service_provider_sid) {
+ const serviceProvidersLimitsResponse = await callApi(`/ServiceProviders/${sp.service_provider_sid}/Limits`, 'get');
+ setLocalLimits(serviceProvidersLimitsResponse.data);
+ }
} catch (err) {
handleErrors({ err, history, dispatch });
} finally {
@@ -208,15 +220,12 @@ const SettingsForm = () => {
name: serviceProviderName.trim(),
};
- await axios({
- method: 'put',
- baseURL: APP_API_BASE_URL,
- url: `/ServiceProviders/${serviceProviderSid}`,
- headers: {
- Authorization: `Bearer ${localStorage.getItem('token')}`,
- },
- data,
- });
+ await callApi(`/ServiceProviders/${serviceProviderSid}`, 'put', data);
+ await Promise.all(
+ localLimits.map(l => l.quantity === "" ?
+ callApi(`/ServiceProviders/${serviceProviderSid}/Limits?category=${l.category}`, 'delete') :
+ callApi(`/ServiceProviders/${serviceProviderSid}/Limits`, 'post', l))
+ );
refreshMsTeamsData();
@@ -272,6 +281,7 @@ const SettingsForm = () => {
invalid={invalidServiceProviderName}
ref={refServiceProviderName}
/>
+
{/* needed for CSS grid layout */}
{
title={(!enableMsTeams && "You must enable Microsoft Teams Direct Routing in order to provide an SBC Domain Name") || ""}
/>
+ {LIMITS.map(({ label, category }) => {
+ const quantity = localLimits?.find(l => l.category === category)?.quantity;
+ return
+
+ = 0 ? quantity : ""}
+ onChange={e => {
+ const limit = localLimits.find(l => l.category === category);
+ const value = e.target.value ? Number(e.target.value) : "";
+ if (limit) {
+ setLocalLimits(localLimits.map(l => l.category === category ? {...l, quantity: value} : l));
+ } else {
+ setLocalLimits([...localLimits, {category, quantity: value}]);
+ }
+ }}
+ />
+ ;
+ })}
+
{errorMessage && !confirmDelete && (
)}
diff --git a/src/constants.js b/src/constants.js
index a625ba2..9adfa68 100644
--- a/src/constants.js
+++ b/src/constants.js
@@ -1,2 +1,16 @@
const { REACT_APP_API_BASE_URL } = process.env;
export const APP_API_BASE_URL = (window.JAMBONZ) ? window.JAMBONZ.APP_API_BASE_URL : REACT_APP_API_BASE_URL;
+export const LIMITS = [
+ // {
+ // label: "Max registered devices (0=unlimited)",
+ // category: "device",
+ // },
+ // {
+ // label: "Max api calls per minute (0=unlimited)",
+ // category: "api_rate",
+ // },
+ {
+ label: "Max concurrent calls (0=unlimited)",
+ category: "voice_call_session",
+ },
+ ];
\ No newline at end of file