Compare commits

...

16 Commits

Author SHA1 Message Date
EgleH
a75ea8fe5c Upgrade legacy app with new node image (#207)
This PR upgrades node base image to node:18.14.0-alpine3.16

This fixes:
Critical vulnerability:
CWE-843: Access of Resource Using Incompatible Type ('Type Confusion')

High vulnerability:
CWE-416: Double Free
CWE-416: Use After Free
2023-02-21 08:26:12 -05:00
Dave Horton
06f826c6da bump version 2023-01-12 16:16:49 -05:00
Dave Horton
20b77575c0 remove /dist folder, which should not have been checked in 2022-12-28 11:25:59 -06:00
Dave Horton
3c3ebe0948 bump version 2022-12-24 12:05:11 -06:00
Dave Horton
4509c52f67 Bugfix/account limits show (#161)
* fix for APP_ENABLE_ACCOUNT_LIMITS_ALL

* further fix

* remove log statements
2022-12-05 09:07:13 -05:00
Dave Horton
4535820828 add support for tracking add'l account limits 2022-11-27 15:29:57 -05:00
Guilherme Rauen
f743ca47a9 simplify build commands, update node image to the latest and most secure (#149)
Co-authored-by: Guilherme Rauen <g.rauen@cognigy.com>
2022-11-11 11:08:45 -05:00
Dave Horton
b8c67143bd add support for Azure custom vocies 2022-11-04 08:27:40 -04:00
Dave Horton
a67f6ad214 update package-lock.json 2022-10-23 12:26:13 -04:00
Markus Frindt
57dd168272 [snyk] Fix vulnerabilities (#137)
Co-authored-by: Markus Frindt <m.frindt@cognigy.com>
2022-10-20 10:24:58 -04:00
Dave Horton
6b7e4a34bb bump version 2022-10-13 16:03:25 -04:00
Dave Horton
50216d5345 comment out azure custom voice for now.. 2022-10-09 17:12:28 +01:00
Dave Horton
4bdbd6fc0f add support for adding new carrier settings for outbound register 2022-10-07 09:42:50 +01:00
xquanluu
ebcdefb945 Fix: update custome speech label content (#132) 2022-10-04 20:13:40 -07:00
xquanluu
6b9d206f4f Legacy: Microsoft custom TTS and STT endpoints (#120)
* feat: add custom tts and stt endpoints for microsoft

* feat: add custom tts and stt endpoints for microsoft

* fix: send null microsoft custom endpoints incase nothing is provided

* fix: don't sent speech credentials in PUT method

* fix:does not clear the custom stt/tts endpoints value when it's disabled

* use tmp state to store custom tts/stt endpoint when enable/disable it
2022-09-30 10:35:23 +01:00
xquanluu
68d88decb5 feat: add Service provider limits and account limits to settings (#112)
* feat: add Service provider limits and account limits to settings

* fix: review comments

* fix: review comments

* fix: review comments

* fix: review comments

* fix: review comment

* fix: review comment

* fix: review comment

* fix: review comment

* fix: review comments

* fix: review comments

* fix: review comments

* fix: review comments
2022-09-27 08:17:27 +01:00
22 changed files with 510 additions and 130 deletions

1
.gitignore vendored
View File

@@ -8,6 +8,7 @@
# production
/build
/dist
# misc
.DS_Store

View File

@@ -1,18 +1,23 @@
FROM node:18.8.0-alpine as builder
RUN apk update && apk add --no-cache python3 make g++
COPY . /opt/app
WORKDIR /opt/app/
COPY package.json ./
RUN npm install
RUN npm run build
RUN npm prune
FROM --platform=linux/amd64 node:18.14.0-alpine3.16 as base
FROM node:18.6.0-alpine as webapp
RUN apk add curl
WORKDIR /opt/app
COPY . /opt/app
COPY --from=builder /opt/app/node_modules ./node_modules
COPY --from=builder /opt/app/build ./build
COPY ./entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
RUN apk --update --no-cache add --virtual .builds-deps build-base curl python3
WORKDIR /opt/app/
FROM base as build
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM base
COPY --from=build /opt/app /opt/app/
RUN chmod +x /opt/app/entrypoint.sh
ENTRYPOINT ["/opt/app/entrypoint.sh"]

View File

@@ -4,7 +4,9 @@ API_PORT="${API_PORT:-3000}"
API_VERSION="${API_VERSION:-v1}"
REACT_APP_API_BASE_URL=${REACT_APP_API_BASE_URL:-http://$PUBLIC_IPV4:$API_PORT/$API_VERSION}
echo "REACT_APP_API_BASE_URL=${REACT_APP_API_BASE_URL}" > /opt/app/.env
REACT_APP_ENABLE_ACCOUNT_LIMITS_ALL=${REACT_APP_ENABLE_ACCOUNT_LIMITS_ALL:-0}
echo "REACT_APP_ENABLE_ACCOUNT_LIMITS_ALL=${REACT_APP_ENABLE_ACCOUNT_LIMITS_ALL}" >> /opt/app/.env
cd /opt/app/
TAG="<script>window.JAMBONZ = { APP_API_BASE_URL: '${REACT_APP_API_BASE_URL}'};</script>"
TAG="<script>window.JAMBONZ = { APP_API_BASE_URL: '${REACT_APP_API_BASE_URL}', APP_ENABLE_ACCOUNT_LIMITS_ALL: ${REACT_APP_ENABLE_ACCOUNT_LIMITS_ALL}};</script>"
sed -i -e "\@</head>@i\ $TAG" ./build/index.html
npm run serve

263
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "jambonz-webapp",
"version": "v0.7.6",
"version": "v0.7.9",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "jambonz-webapp",
"version": "v0.7.6",
"version": "v0.7.9",
"dependencies": {
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^12.1.5",
@@ -2418,6 +2418,58 @@
"node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
}
},
"node_modules/@jridgewell/gen-mapping": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
"integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
"dependencies": {
"@jridgewell/set-array": "^1.0.1",
"@jridgewell/sourcemap-codec": "^1.4.10",
"@jridgewell/trace-mapping": "^0.3.9"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/resolve-uri": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
"integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/set-array": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
"integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/source-map": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz",
"integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==",
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.0",
"@jridgewell/trace-mapping": "^0.3.9"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.4.14",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
"integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw=="
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.17",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz",
"integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==",
"dependencies": {
"@jridgewell/resolve-uri": "3.1.0",
"@jridgewell/sourcemap-codec": "1.4.14"
}
},
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -4243,9 +4295,9 @@
}
},
"node_modules/babel-loader/node_modules/loader-utils": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz",
"integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==",
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz",
"integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==",
"dependencies": {
"big.js": "^5.2.2",
"emojis-list": "^3.0.0",
@@ -4743,13 +4795,19 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001299",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001299.tgz",
"integrity": "sha512-iujN4+x7QzqA2NCSrS5VUy+4gLmRd4xv6vbBBsmfVqTx8bLAD8097euLqQgKxSVLvxjSDcvF1T/i9ocgnUFexw==",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/browserslist"
}
"version": "1.0.30001436",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001436.tgz",
"integrity": "sha512-ZmWkKsnC2ifEPoWUvSAIGyOYwT+keAaaWPHiQ9DfMqS1t6tfuyFYoWR78TeZtznkEQ64+vGXH9cZrElwR2Mrxg==",
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/browserslist"
},
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/caniuse-lite"
}
]
},
"node_modules/case-sensitive-paths-webpack-plugin": {
"version": "2.4.0",
@@ -5745,9 +5803,9 @@
"integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ=="
},
"node_modules/decode-uri-component": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
"integrity": "sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og==",
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz",
"integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==",
"engines": {
"node": ">=0.10"
}
@@ -9909,9 +9967,9 @@
}
},
"node_modules/loader-utils": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz",
"integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==",
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz",
"integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==",
"dependencies": {
"big.js": "^5.2.2",
"emojis-list": "^3.0.0",
@@ -13010,9 +13068,9 @@
}
},
"node_modules/react-dev-utils/node_modules/loader-utils": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.0.tgz",
"integrity": "sha512-HVl9ZqccQihZ7JM85dco1MvO9G+ONvxoGa9rkhzFsneGLKSUg1gJf9bWzhRhcvm2qChhWpebQhP44qxjKIUCaQ==",
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz",
"integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==",
"engines": {
"node": ">= 12.13.0"
}
@@ -13238,14 +13296,25 @@
}
},
"node_modules/recursive-readdir": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz",
"integrity": "sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg==",
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz",
"integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==",
"dependencies": {
"minimatch": "3.0.4"
"minimatch": "^3.0.5"
},
"engines": {
"node": ">=0.10.0"
"node": ">=6.0.0"
}
},
"node_modules/recursive-readdir/node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/redent": {
@@ -13819,9 +13888,9 @@
}
},
"node_modules/serve": {
"version": "13.0.2",
"resolved": "https://registry.npmjs.org/serve/-/serve-13.0.2.tgz",
"integrity": "sha512-71R6fKvNgKrqARAag6lYJNnxDzpH7DCNrMuvPY5PLVaC2PDhJsGTj/34o4o4tPWhTuLgEXqvgnAWbATQ9zGZTQ==",
"version": "13.0.4",
"resolved": "https://registry.npmjs.org/serve/-/serve-13.0.4.tgz",
"integrity": "sha512-Lj8rhXmphJCRQVv5qwu0NQZ2h+0MrRyRJxDZu5y3qLH2i/XY6a0FPj/VmjMUdkJb672MBfE8hJ274PU6JzBd0Q==",
"dependencies": {
"@zeit/schemas": "2.6.0",
"ajv": "6.12.6",
@@ -14730,12 +14799,13 @@
}
},
"node_modules/terser": {
"version": "5.10.0",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.10.0.tgz",
"integrity": "sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA==",
"version": "5.15.1",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.15.1.tgz",
"integrity": "sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw==",
"dependencies": {
"@jridgewell/source-map": "^0.3.2",
"acorn": "^8.5.0",
"commander": "^2.20.0",
"source-map": "~0.7.2",
"source-map-support": "~0.5.20"
},
"bin": {
@@ -14743,14 +14813,6 @@
},
"engines": {
"node": ">=10"
},
"peerDependencies": {
"acorn": "^8.5.0"
},
"peerDependenciesMeta": {
"acorn": {
"optional": true
}
}
},
"node_modules/terser-webpack-plugin": {
@@ -14791,14 +14853,6 @@
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
},
"node_modules/terser/node_modules/source-map": {
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
"integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
"engines": {
"node": ">= 8"
}
},
"node_modules/test-exclude": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
@@ -17794,6 +17848,49 @@
"chalk": "^4.0.0"
}
},
"@jridgewell/gen-mapping": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
"integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
"requires": {
"@jridgewell/set-array": "^1.0.1",
"@jridgewell/sourcemap-codec": "^1.4.10",
"@jridgewell/trace-mapping": "^0.3.9"
}
},
"@jridgewell/resolve-uri": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
"integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w=="
},
"@jridgewell/set-array": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
"integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw=="
},
"@jridgewell/source-map": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz",
"integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==",
"requires": {
"@jridgewell/gen-mapping": "^0.3.0",
"@jridgewell/trace-mapping": "^0.3.9"
}
},
"@jridgewell/sourcemap-codec": {
"version": "1.4.14",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
"integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw=="
},
"@jridgewell/trace-mapping": {
"version": "0.3.17",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz",
"integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==",
"requires": {
"@jridgewell/resolve-uri": "3.1.0",
"@jridgewell/sourcemap-codec": "1.4.14"
}
},
"@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -19142,9 +19239,9 @@
}
},
"loader-utils": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz",
"integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==",
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz",
"integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==",
"requires": {
"big.js": "^5.2.2",
"emojis-list": "^3.0.0",
@@ -19538,9 +19635,9 @@
}
},
"caniuse-lite": {
"version": "1.0.30001299",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001299.tgz",
"integrity": "sha512-iujN4+x7QzqA2NCSrS5VUy+4gLmRd4xv6vbBBsmfVqTx8bLAD8097euLqQgKxSVLvxjSDcvF1T/i9ocgnUFexw=="
"version": "1.0.30001436",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001436.tgz",
"integrity": "sha512-ZmWkKsnC2ifEPoWUvSAIGyOYwT+keAaaWPHiQ9DfMqS1t6tfuyFYoWR78TeZtznkEQ64+vGXH9cZrElwR2Mrxg=="
},
"case-sensitive-paths-webpack-plugin": {
"version": "2.4.0",
@@ -20261,9 +20358,9 @@
"integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ=="
},
"decode-uri-component": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
"integrity": "sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og=="
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz",
"integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ=="
},
"dedent": {
"version": "0.7.0",
@@ -23290,9 +23387,9 @@
"integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw=="
},
"loader-utils": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz",
"integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==",
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz",
"integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==",
"requires": {
"big.js": "^5.2.2",
"emojis-list": "^3.0.0",
@@ -25413,9 +25510,9 @@
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="
},
"loader-utils": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.0.tgz",
"integrity": "sha512-HVl9ZqccQihZ7JM85dco1MvO9G+ONvxoGa9rkhzFsneGLKSUg1gJf9bWzhRhcvm2qChhWpebQhP44qxjKIUCaQ=="
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz",
"integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw=="
},
"path-key": {
"version": "3.1.1",
@@ -25586,11 +25683,21 @@
}
},
"recursive-readdir": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz",
"integrity": "sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg==",
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz",
"integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==",
"requires": {
"minimatch": "3.0.4"
"minimatch": "^3.0.5"
},
"dependencies": {
"minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"requires": {
"brace-expansion": "^1.1.7"
}
}
}
},
"redent": {
@@ -26006,9 +26113,9 @@
}
},
"serve": {
"version": "13.0.2",
"resolved": "https://registry.npmjs.org/serve/-/serve-13.0.2.tgz",
"integrity": "sha512-71R6fKvNgKrqARAag6lYJNnxDzpH7DCNrMuvPY5PLVaC2PDhJsGTj/34o4o4tPWhTuLgEXqvgnAWbATQ9zGZTQ==",
"version": "13.0.4",
"resolved": "https://registry.npmjs.org/serve/-/serve-13.0.4.tgz",
"integrity": "sha512-Lj8rhXmphJCRQVv5qwu0NQZ2h+0MrRyRJxDZu5y3qLH2i/XY6a0FPj/VmjMUdkJb672MBfE8hJ274PU6JzBd0Q==",
"requires": {
"@zeit/schemas": "2.6.0",
"ajv": "6.12.6",
@@ -26710,12 +26817,13 @@
}
},
"terser": {
"version": "5.10.0",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.10.0.tgz",
"integrity": "sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA==",
"version": "5.15.1",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.15.1.tgz",
"integrity": "sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw==",
"requires": {
"@jridgewell/source-map": "^0.3.2",
"acorn": "^8.5.0",
"commander": "^2.20.0",
"source-map": "~0.7.2",
"source-map-support": "~0.5.20"
},
"dependencies": {
@@ -26723,11 +26831,6 @@
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
},
"source-map": {
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
"integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ=="
}
}
},

View File

@@ -1,6 +1,6 @@
{
"name": "jambonz-webapp",
"version": "v0.7.6",
"version": "v0.7.9",
"dependencies": {
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^12.1.5",

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -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 => {
</Button>
)}
{LIMITS.map(({ label, category }) => {
const quantity = localLimits?.find(l => l.category === category)?.quantity;
return <React.Fragment key={category}>
<Label htmlFor={category}>{label}</Label>
<Input
name={category}
id={category}
type="number"
placeholder="Enter Quantity (0=unlimited)"
min="0"
value={quantity >= 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}]);
}
}}
>
</Input>
</React.Fragment>;
})}
{ process.env.REACT_APP_ENABLE_SUBSPACE ? (
<>
<Label htmlFor="subspaceId">Subspace</Label>
@@ -1022,7 +1078,6 @@ const AccountForm = props => {
)}
</>
) : null }
{errorMessage && (
<FormError grid message={errorMessage} />
)}

View File

@@ -221,6 +221,8 @@ const CarrierForm = (props) => {
const refUsername = useRef(null);
const refPassword = useRef(null);
const refRealm = useRef(null);
const refFromUser = useRef(null);
const refFromDomain = useRef(null);
const refIp = useRef([]);
const refPort = useRef([]);
const refInbound = useRef([]);
@@ -250,6 +252,8 @@ const CarrierForm = (props) => {
const [ passwordInvalid, setPasswordInvalid ] = useState(false);
const [ realm, setRealm ] = useState('');
const [ realmInvalid, setRealmInvalid ] = useState(false);
const [ fromUser, setFromUser ] = useState('');
const [ fromDomain, setFromDomain ] = useState('');
const [ sipGateways, setSipGateways ] = useState([
{
sip_gateway_sid: '',
@@ -276,6 +280,7 @@ const CarrierForm = (props) => {
const [suportSIP, setSupportSIP] = useState(false);
const [diversion, setDiversion] = useState("");
const [carrierActive, setCarrierActive] = useState(true);
const [registerHasPublicIp, setRegisterHasPublicIp] = useState(false);
const [predefinedCarriers, setPredefinedCarriers] = useState([]);
const [activeTab, setActiveTab] = useState('1');
const [sbcs, setSbcs] = useState([]);
@@ -438,6 +443,8 @@ const CarrierForm = (props) => {
setUsername(carrier.register_username || '');
setPassword(carrier.register_password || '');
setRealm(carrier.register_sip_realm || '');
setFromUser(carrier.register_from_user || '');
setFromDomain(carrier.register_from_domain || '');
setSipGateways(currentSipGateways.map(s => ({
sip_gateway_sid: s.sip_gateway_sid,
ip: s.ipv4,
@@ -473,6 +480,7 @@ const CarrierForm = (props) => {
setSupportSIP(carrier.diversion ? true : false);
setDiversion(carrier.diversion || '');
setCarrierActive(carrier.is_active === 1);
setRegisterHasPublicIp(carrier.register_public_ip_in_contact === 1);
} else {
const result = await axios({
method: 'get',
@@ -1028,6 +1036,9 @@ const CarrierForm = (props) => {
register_username: username ? username.trim() : null,
register_password: password ? password : null,
register_sip_realm: register ? realm.trim() : null,
register_from_user: register && fromUser ? fromUser.trim() : null,
register_from_domain: register && fromDomain ? fromDomain.trim() : null,
register_public_ip_in_contact: register && registerHasPublicIp ? 1 : 0,
tech_prefix: techPrefix ? techPrefix.trim() : null,
diversion: diversion ? diversion.trim() : null,
is_active: carrierActive ? 1 : 0,
@@ -1484,6 +1495,33 @@ const CarrierForm = (props) => {
invalid={realmInvalid}
ref={refRealm}
/>
<Label htmlFor="fromUser">SIP From User</Label>
<Input
name="fromUser"
id="fromUser"
value={fromUser}
onChange={e => setFromUser(e.target.value)}
placeholder="Optional: specify user part of SIP From header"
ref={refFromUser}
/>
<Label htmlFor="fromDomain">SIP From Domain</Label>
<Input
name="fromDomain"
id="fromDomain"
value={fromDomain}
onChange={e => setFromDomain(e.target.value)}
placeholder="Optional: specify host part of SIP From header"
ref={refFromDomain}
/>
<Label htmlFor="regPublicIp">Use Public IP in Contact</Label>
<Checkbox
noLeftMargin
name="regPublicIp"
id="regPublicIp"
label=""
checked={registerHasPublicIp}
onChange={e => setRegisterHasPublicIp(e.target.checked)}
/>
</>
) : (
null

View File

@@ -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}
/>
<div>{/* needed for CSS grid layout */}</div>
<Checkbox
noLeftMargin
@@ -297,6 +307,30 @@ const SettingsForm = () => {
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 <React.Fragment key={category}>
<Label htmlFor={category}>{label}</Label>
<Input
name={category}
id={category}
type="number"
placeholder="Enter Quantity (0=unlimited)"
min="0"
value={quantity >= 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}]);
}
}}
/>
</React.Fragment>;
})}
{errorMessage && !confirmDelete && (
<FormError grid message={errorMessage} />
)}

View File

@@ -79,6 +79,8 @@ const SpeechServicesAddEdit = (props) => {
const refApiKey = useRef(null);
const refRegion = useRef(null);
const refAwsRegion = useRef(null);
const refUseCustomTts = useRef(null);
const refUseCustomStt = useRef(null);
// Form inputs
const [vendor, setVendor] = useState('');
@@ -93,6 +95,13 @@ const SpeechServicesAddEdit = (props) => {
const [apiKey, setApiKey] = useState('');
const [region, setRegion] = useState('');
const [awsregion, setAwsRegion] = useState('');
const [useCustomTts, setUseCustomTts] = useState(false);
const [useCustomStt, setUseCustomStt] = useState(false);
const [customTtsEndpoint, setCustomTtsEndpoint] = useState('');
const [customSttEndpoint, setCustomSttEndpoint] = useState('');
// eslint-disable-next-line no-unused-vars
const [tmpCustomTtsEndpoint, setTmpCustomTtsEndpoint] = useState('');
const [tmpCustomSttEndpoint, setTmpCustomSttEndpoint] = useState('');
// Invalid form inputs
const [invalidVendorGoogle, setInvalidVendorGoogle] = useState(false);
@@ -106,6 +115,9 @@ const SpeechServicesAddEdit = (props) => {
const [invalidApiKey, setInvalidApiKey] = useState(false);
const [invalidRegion, setInvalidRegion] = useState(false);
const [invalidAwsRegion, setInvalidAwsRegion] = useState(false);
// eslint-disable-next-line no-unused-vars
const [invalidUseCustomTts, setInvalidUseCustomTts] = useState(false);
const [invalidUseCustomStt, setInvalidUseCustomStt] = useState(false);
const [originalTtsValue, setOriginalTtsValue] = useState(null);
const [originalSttValue, setOriginalSttValue] = useState(null);
@@ -162,6 +174,10 @@ const SpeechServicesAddEdit = (props) => {
setUseForStt(speechCredential.data.use_for_stt || false);
setOriginalTtsValue(speechCredential.data.use_for_tts || false);
setOriginalSttValue(speechCredential.data.use_for_stt || false);
setUseCustomTts(speechCredential.data.use_custom_tts || false);
setCustomTtsEndpoint(speechCredential.data.custom_tts_endpoint || '');
setUseCustomStt(speechCredential.data.use_custom_stt || false);
setCustomSttEndpoint(speechCredential.data.custom_stt_endpoint || '');
}
setShowLoader(false);
} catch (err) {
@@ -232,6 +248,8 @@ const SpeechServicesAddEdit = (props) => {
setInvalidUseForTts(false);
setInvalidUseForStt(false);
setInvalidApiKey(false);
setInvalidUseCustomTts(false);
setInvalidUseCustomStt(false);
let errorMessages = [];
let focusHasBeenSet = false;
@@ -305,6 +323,24 @@ const SpeechServicesAddEdit = (props) => {
}
}
if (useCustomTts && !customTtsEndpoint) {
errorMessages.push('Please provide a custom voice endpoint.');
setInvalidUseCustomTts(true);
if (!focusHasBeenSet) {
refUseCustomTts.current.focus();
focusHasBeenSet = true;
}
}
if (useCustomStt && !customSttEndpoint) {
errorMessages.push('Please provide a custom speech endpoint Id.');
setInvalidUseCustomStt(true);
if (!focusHasBeenSet) {
refUseCustomStt.current.focus();
focusHasBeenSet = true;
}
}
if (errorMessages.length > 1) {
setErrorMessage(errorMessages);
return;
@@ -333,16 +369,29 @@ const SpeechServicesAddEdit = (props) => {
},
data: {
vendor,
service_key: vendor === 'google' ? JSON.stringify(serviceKey) : null,
access_key_id: vendor === 'aws' ? accessKeyId : null,
secret_access_key: vendor === 'aws' ? secretAccessKey : null,
aws_region: vendor === 'aws' ? awsregion : null,
api_key: ['microsoft', 'wellsaid'].includes(vendor) ? apiKey : null,
region: vendor === 'microsoft' ? region : null,
use_for_tts: useForTts,
use_for_stt: useForStt,
service_provider_sid: accountSid ? null : currentServiceProvider,
account_sid: accountSid || null,
use_for_tts: useForTts,
use_for_stt: useForStt,
...(vendor === 'google' && method === 'post' && {
service_key: serviceKey ? JSON.stringify(serviceKey) : null,
}),
...(vendor === 'aws' && {
...(method === 'post' && {
access_key_id: accessKeyId || null,
secret_access_key: secretAccessKey || null}),
aws_region: awsregion || null
}),
...(vendor === 'microsoft' && {
region: region || null,
use_custom_tts: useCustomTts ? 1 : 0,
use_custom_stt: useCustomStt ? 1 : 0,
custom_tts_endpoint: customTtsEndpoint || null,
custom_stt_endpoint: customSttEndpoint || null,
}),
...(['wellsaid', 'microsoft'].includes(vendor) && method === 'post' && {
api_key: apiKey || null,
}),
}
});
@@ -655,6 +704,70 @@ const SpeechServicesAddEdit = (props) => {
</option>
))}
</Select>
<div />
<Checkbox
noLeftMargin
name="useACustomVoice"
id="useACustomVoice"
label="Use a custom voice"
checked={useCustomTts}
onChange={e => {
setUseCustomTts(e.target.checked);
if (e.target.checked && tmpCustomTtsEndpoint) {
setCustomTtsEndpoint(tmpCustomTtsEndpoint);
}
if (!e.target.checked) {
setTmpCustomTtsEndpoint(customTtsEndpoint);
setCustomTtsEndpoint("");
}
}}
invalid={invalidUseCustomTts}
ref={refUseCustomTts}
/>
<Label htmlFor="customVoiceEndpoint">Custom voice endpoint Id</Label>
<Input
name="customVoiceEndpoint"
id="customVoiceEndpoint"
value={customTtsEndpoint}
onChange={e => setCustomTtsEndpoint(e.target.value)}
placeholder="Custom voice endpoint"
invalid={invalidUseCustomTts}
ref={refUseCustomTts}
disabled={!useCustomTts}
/>
<div />
<Checkbox
noLeftMargin
name="useACustomSpeechModel"
id="useACustomSpeechModel"
label="Use a custom speech model"
checked={useCustomStt}
onChange={e => {
setUseCustomStt(e.target.checked);
if(e.target.checked && tmpCustomSttEndpoint) {
setCustomSttEndpoint(tmpCustomSttEndpoint);
}
if(!e.target.checked) {
setTmpCustomSttEndpoint(customSttEndpoint);
setCustomSttEndpoint("");
}
}}
invalid={invalidUseCustomStt}
ref={refUseCustomStt}
/>
<Label htmlFor="customSpeechEndpoint">Custom speech endpoint Id</Label>
<Input
name="customSpeechEndpoint"
id="customSpeechEndpoint"
value={customSttEndpoint}
onChange={e => setCustomSttEndpoint(e.target.value)}
placeholder="Custom speech endpoint Id"
invalid={invalidUseCustomStt}
ref={refUseCustomStt}
disabled={!useCustomStt}
/>
</>
) : vendor === 'wellsaid' ? (
<>

View File

@@ -1,2 +1,31 @@
const { REACT_APP_API_BASE_URL } = process.env;
const { REACT_APP_API_BASE_URL, REACT_APP_ENABLE_ACCOUNT_LIMITS_ALL } = process.env;
export const APP_API_BASE_URL = (window.JAMBONZ) ? window.JAMBONZ.APP_API_BASE_URL : REACT_APP_API_BASE_URL;
export const APP_ENABLE_ACCOUNT_LIMITS_ALL = (window.JAMBONZ) ? window.JAMBONZ.APP_ENABLE_ACCOUNT_LIMITS_ALL : JSON.parse(REACT_APP_ENABLE_ACCOUNT_LIMITS_ALL);
export const LIMITS = [
// {
// label: "Max registered devices (0=unlimited)",
// category: "device",
// },
// {
// label: "Max api calls per minute (0=unlimited)",
// category: "api_rate",
// },
{
label: "Max calls",
category: "voice_call_session",
}
];
if (APP_ENABLE_ACCOUNT_LIMITS_ALL || APP_ENABLE_ACCOUNT_LIMITS_ALL === "true") {
LIMITS.push({
label: "Licensed calls",
category: "voice_call_session_license",
});
LIMITS.push({
label: "Max minutes",
category: "voice_call_minutes",
});
LIMITS.push({
label: "Licensed minutes",
category: "voice_call_minutes_license",
});
}