Compare commits

...

23 Commits

Author SHA1 Message Date
Dave Horton
6bb81a499b bump version 2022-04-06 08:19:56 -04:00
Dave Horton
58f97dcfb2 show trace_id in recent calls detail display 2022-03-28 19:35:43 -04:00
Dave Horton
23a067b6dd bump version 2022-03-08 20:20:46 -05:00
Andrew
92db20965e moved building to Dockefile instead of entrypoint (#39)
* moved building to Dockefile instead of entrypoint

* moved enviroment variable to gloabl

* updated to use process env during build to allow use of window global var

* added new line

* updated constants for window.jambonz

* removed NODE_ENV in favor of just window.JAMBONZ

* removed unrequired and change const per pull request
2022-02-23 07:40:05 -05:00
akirilyuk
8f8d635bd3 fix all security vulnerabilities (#41)
Co-authored-by: akirilyuk <a.kirilyuk@cognigy.com>
2022-02-17 07:33:00 -05:00
dependabot[bot]
b075028b7b Bump follow-redirects from 1.14.7 to 1.14.8 (#40)
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.14.7 to 1.14.8.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.14.7...v1.14.8)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-14 21:25:01 -05:00
Dave Horton
b5f2e5fc25 bump version 2022-02-09 15:43:14 -05:00
Dave Horton
6390cc6b81 add missing Azure regions 2022-02-03 08:59:47 -05:00
Dave Horton
d7db92f0c7 update version to 0.7.2 2022-01-31 07:32:10 -05:00
Dave Horton
f5201d2d69 Feature/wellsaid tts (#38)
* initial changes to support WellSaid TTS

* disable stt choice for WellSaid since they dont provide
2022-01-27 08:07:22 -05:00
akirilyuk
128ca045b0 update depenecies and fix security vulnerabilities (#37)
Co-authored-by: akirilyuk <a.kirilyuk@cognigy.com>
2022-01-14 08:00:35 -05:00
Dave Horton
3403996946 bump version 2021-12-21 09:43:00 -05:00
Dave Horton
87dbb461e0 added docker publish 2021-12-13 14:18:43 -05:00
Dave Horton
9bce9c5510 version bump 2021-12-13 09:55:03 -05:00
Brandon Lee Kitajchuk
2db5f26dbf Subspace (#35)
* pushing up what ive got from laptop

* beginnings of a UI for setting up subspace on a jambonz account

* enable the env flag and move content to right place

* changes to support subspace (thanks to nimbleape)

* fix column names

* Implement SIP realm selection for Subspace API calls

* Hook up Subspace disable method

* Finish up Subspace API handling

Co-authored-by: Dan Jenkins <dan@nimblea.pe>
Co-authored-by: Dave Horton <daveh@beachdognet.com>
2021-12-06 17:58:42 -05:00
Dave Horton
bfc7cc971c version bump 2021-12-02 19:34:28 -05:00
Dave Horton
35f353c905 bugfix: azure tts needs to be referenced by ShortName (#33) 2021-11-19 14:31:30 -05:00
Brandon Lee Kitajchuk
922d664bf8 Add Microsoft vendor to Jambonz Webapp (#32)
* Add Microsoft vendor to Speech Form

Add Microsoft vendor to Application Form

Clean up UI for Speech and Application forms

* Remove Sbcs from SpeechServiceAddEdit Form
2021-11-17 20:49:31 -05:00
Dave Horton
ff4d6b6e11 version bump 2021-11-03 13:53:11 -04:00
Dave Horton
70387ff4f1 bump version 2021-10-21 13:09:07 -04:00
Dave Horton
7a4c583345 bump version 2021-10-21 13:01:30 -04:00
Brandon Lee Kitajchuk
d54fbc4782 Update IP whitelist tooltips for carrier form (#29) 2021-10-21 11:41:19 -04:00
Brandon Lee Kitajchuk
14dd1319d9 SMS for Carrier Form (#28) 2021-10-17 12:29:26 -04:00
41 changed files with 28214 additions and 10819 deletions

2
.env
View File

@@ -1 +1 @@
REACT_APP_API_BASE_URL=http://[ip]:[port]/v1
REACT_APP_API_BASE_URL=http://127.0.0.1:3002/v1

View File

@@ -2,15 +2,12 @@
"extends": "react-app",
"rules": {
"linebreak-style": [
"error",
"unix"
"error",
"unix"
],
"semi": [
"error",
"always"
],
"no-trailing-spaces": [
"error"
"error",
"always"
]
}
}
}

51
.github/workflows/docker-publish.yml vendored Normal file
View File

@@ -0,0 +1,51 @@
name: Docker
on:
push:
# Publish `main` as Docker `latest` image.
branches:
- main
# Publish `v1.2.3` tags as releases.
tags:
- v*
env:
IMAGE_NAME: webapp
jobs:
push:
runs-on: ubuntu-latest
if: github.event_name == 'push'
steps:
- uses: actions/checkout@v2
- name: Build image
run: docker build . --file Dockerfile --tag $IMAGE_NAME
- name: Log into registry
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
- name: Push image
run: |
IMAGE_ID=ghcr.io/${{ github.repository_owner }}/$IMAGE_NAME
# Change all uppercase to lowercase
IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]')
# Strip git ref prefix from version
VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,')
# Strip "v" prefix from tag name
[[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//')
# Use Docker `latest` tag convention
[ "$VERSION" == "main" ] && VERSION=latest
echo IMAGE_ID=$IMAGE_ID
echo VERSION=$VERSION
docker tag $IMAGE_NAME $IMAGE_ID:$VERSION
docker push $IMAGE_ID:$VERSION

View File

@@ -1,8 +1,10 @@
FROM node: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 node:alpine as webapp
@@ -10,6 +12,7 @@ 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"]

View File

@@ -2,7 +2,9 @@
PUBLIC_IPV4="$(curl --fail -qs whatismyip.akamai.com)"
API_PORT="${API_PORT:-3000}"
API_VERSION="${API_VERSION:-v1}"
echo "REACT_APP_API_BASE_URL=${REACT_APP_API_BASE_URL:-http://$PUBLIC_IPV4:$API_PORT/$API_VERSION}" > /opt/app/.env
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
cd /opt/app/
npm run build
npm run serve
TAG="<script>window.JAMBONZ = { APP_API_BASE_URL: '${REACT_APP_API_BASE_URL}'};</script>"
sed -i -e "\@</head>@i\ $TAG" ./build/index.html
npm run serve

32650
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,10 +1,9 @@
{
"name": "jambonz-cpaas-ui",
"version": "1.0.0",
"private": true,
"name": "jambonz-webapp",
"version": "v0.7.5",
"dependencies": {
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.5.0",
"@testing-library/jest-dom": "^5.16.1",
"@testing-library/react": "^12.1.2",
"@testing-library/user-event": "^7.2.1",
"antd": "^4.15.4",
"axios": "^0.21.1",
@@ -13,8 +12,8 @@
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-router-dom": "^5.1.2",
"react-scripts": "3.4.1",
"serve": "^11.3.0",
"react-scripts": "^5.0.0",
"serve": "^13.0.2",
"styled-components": "^5.0.1"
},
"scripts": {

View File

@@ -1,4 +1,5 @@
/* eslint-disable react-hooks/exhaustive-deps */
/* eslint-disable no-undef */
import React, { useContext, useEffect, useState, useRef } from 'react';
import axios from 'axios';
import { useHistory, useLocation } from 'react-router-dom';
@@ -16,6 +17,7 @@ import { Link as ReactRouterLink } from 'react-router-dom';
import { ServiceProviderValueContext, ServiceProviderMethodContext } from '../../contexts/ServiceProviderContext';
import LogoJambong from "../../images/LogoJambong.svg";
import AddModalButton from '../elements/AddModalButton';
import { APP_API_BASE_URL } from "../../constants";
const StyledNav = styled.nav`
position: relative;
@@ -106,7 +108,7 @@ const Nav = () => {
if (history.location.pathname !== '' && jwt) {
const serviceProvidersResponse = await axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: '/ServiceProviders',
headers: {
Authorization: `Bearer ${jwt}`,
@@ -137,7 +139,7 @@ const Nav = () => {
const serviceProviderResponse = await axios({
method: 'post',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: `/ServiceProviders`,
headers: {
Authorization: `Bearer ${jwt}`,

View File

@@ -3,7 +3,8 @@ import axios from 'axios';
import styled from 'styled-components';
import { useHistory } from 'react-router-dom';
import { NotificationDispatchContext } from '../../contexts/NotificationContext';
import { ServiceProviderValueContext } from '../../contexts/ServiceProviderContext';
// import { ServiceProviderValueContext } from '../../contexts/ServiceProviderContext';
import { APP_API_BASE_URL } from "../../constants";
const Container = styled.div`
margin-top: 0.25rem;
@@ -21,7 +22,7 @@ const Container = styled.div`
const Sbcs = props => {
let history = useHistory();
const dispatch = useContext(NotificationDispatchContext);
const currentServiceProvider = useContext(ServiceProviderValueContext);
// const currentServiceProvider = useContext(ServiceProviderValueContext);
const [ sbcs, setSbcs ] = useState('');
useEffect(() => {
const getAPIData = async () => {
@@ -37,8 +38,9 @@ const Sbcs = props => {
}
const sbcResults = await axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
url: `/Sbcs?service_provider_sid=${currentServiceProvider}`,
baseURL: APP_API_BASE_URL,
// url: `/Sbcs?service_provider_sid=${currentServiceProvider}`,
url: '/Sbcs',
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
},

View File

@@ -220,7 +220,8 @@ const TableContent = props => {
contentToDelete.name ||
contentToDelete.number ||
contentToDelete.tenant_fqdn ||
contentToDelete.token
contentToDelete.token ||
contentToDelete.vendor
) && (
<Modal
title={`Are you sure you want to delete the following ${props.name}?`}

View File

@@ -111,6 +111,7 @@ const Checkbox = (props, ref) => {
name={props.id}
type="checkbox"
checked={props.checked}
disabled={props.disabled}
onChange={props.onChange}
value={props.value}
ref={inputRef}

View File

@@ -2,19 +2,8 @@ import React, { useContext } from 'react';
import styled from 'styled-components/macro';
import { NotificationDispatchContext } from '../../contexts/NotificationContext';
import Button from './Button';
import Span from './Span';
const Span = styled.span`
text-align: left;
${props => props.hasBorder ? `
height: 2.25rem;
display: flex;
align-items: center;
width: 100%;
padding: 0 1rem;
border: 1px solid #B6B6B6;
border-radius: 0.125rem;
` : ''}
`;
const StyledButton = styled(Button)`
margin-left: 1rem;

View File

@@ -10,6 +10,7 @@ const Select = styled.select`
border-radius: 0.125rem;
background: #fff;
color: inherit;
max-width: 230px;
&:focus {
border-color: #565656;
outline: none;

View File

@@ -0,0 +1,16 @@
import styled from 'styled-components/macro';
const Span = styled.span`
text-align: left;
${props => props.hasBorder ? `
height: 2.25rem;
display: flex;
align-items: center;
width: 100%;
padding: 0 1rem;
border: 1px solid #B6B6B6;
border-radius: 0.125rem;
` : ''}
`;
export default Span;

View File

@@ -1,7 +1,11 @@
import styled from 'styled-components/macro';
import React, { useState, useRef, useEffect, useCallback } from 'react';
import Link from './Link';
const Tooltip = styled.span`
display: none;
label > span:hover > & {
display: inline;
position: absolute;
@@ -14,15 +18,105 @@ const Tooltip = styled.span`
box-shadow: 0 0.375rem 0.25rem rgba(0, 0, 0, 0.12),
0 0 0.25rem rgba(0, 0, 0, 0.18);
z-index: 80;
${props => !props.large ? `
white-space: nowrap;
` : `
text-align: left;
width: 22rem;
bottom: calc(100% + 0.5rem);
`}
white-space: nowrap;
}
`;
const StyledLinkWithTooltip = styled.span`
position: relative;
> span {
font-size: 14px;
position: absolute;
left: 50%;
transform: translate3d(-50%, calc(-100% - 5px), 0);
padding: 0.75rem 1rem;
border-radius: 0.25rem;
border: 1px solid #C6C6C6;
background: #FFF;
z-index: 80;
white-space: pre;
&:after {
content: "";
width: 0;
height: 0;
border-left: 8px solid transparent;
border-right: 8px solid transparent;
border-top: 8px solid #FFF;
position: absolute;
left: 50%;
top: 100%;
transform: translateX(-50%);
z-index: 2;
}
&:before {
content: "";
width: 0;
height: 0;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-top: 10px solid #C6C6C6;
position: absolute;
left: 50%;
top: 100%;
transform: translateX(-50%);
z-index: 1;
}
}
`;
const LinkWithTooltip = props => {
const [isActive, setIsActive] = useState(false);
const tooltipRef = useRef();
const triggerRef = useRef();
const handleLinkClick = useCallback(() => {
setIsActive((oldActive) => {
const newActive = !oldActive;
return newActive;
});
}, [setIsActive]);
const handleOuterClick = useCallback((e) => {
if (!tooltipRef.current) {
return;
}
if (tooltipRef.current.contains(e.target)) {
return;
}
if (triggerRef.current.contains(e.target)) {
return;
}
handleLinkClick();
}, [tooltipRef, triggerRef, handleLinkClick]);
useEffect(() => {
document.addEventListener('click', handleOuterClick, false);
return () => document.removeEventListener('click', handleOuterClick, false);
}, [handleOuterClick]);
return (
<StyledLinkWithTooltip>
<Link to="#" onClick={handleLinkClick}>
<span ref={triggerRef}>{props.children}</span>
</Link>
{isActive ? (
<span ref={tooltipRef}>
{props.tipText}
</span>
) : null}
</StyledLinkWithTooltip>
);
};
export {
LinkWithTooltip,
};
export default Tooltip;

View File

@@ -1,3 +1,4 @@
/* eslint-disable no-undef */
import React, { useState, useEffect, useContext, useRef } from 'react';
import { useHistory } from 'react-router-dom';
import axios from 'axios';
@@ -6,6 +7,7 @@ import { ServiceProviderValueContext } from '../../contexts/ServiceProviderConte
import Form from '../elements/Form';
import Input from '../elements/Input';
import Label from '../elements/Label';
import Radio from '../elements/Radio';
import Select from '../elements/Select';
import InputGroup from '../elements/InputGroup';
import PasswordInput from '../elements/PasswordInput';
@@ -17,8 +19,10 @@ import Button from '../elements/Button';
import Link from '../elements/Link';
import Tooltip from '../elements/Tooltip';
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";
const StyledInputGroup = styled(InputGroup)`
position: relative;
@@ -61,6 +65,9 @@ const AccountForm = props => {
const refQueueWebhook = useRef(null);
const refQueueUser = useRef(null);
const refQueuePassword = useRef(null);
const refSubspaceId = useRef(null);
const refSubspaceSecret = useRef(null);
const refSubspaceOtherSip = useRef(null);
// Form inputs
const [ name, setName ] = useState('');
@@ -68,13 +75,24 @@ const AccountForm = props => {
const [ deviceCallingApplication, setDeviceCallingApplication ] = useState('');
const [ regWebhook, setRegWebhook ] = useState('');
const [ regMethod, setRegMethod ] = useState('POST');
const [ regUser, setRegUser ] = useState('' || '');
const [ regPassword, setRegPassword ] = useState('' || '');
const [ regUser, setRegUser ] = useState('');
const [ regPassword, setRegPassword ] = useState('');
const [ webhookSecret, setWebhookSecret ] = useState('');
const [ queueWebhook, setQueueWebhook ] = useState('');
const [ queueMethod, setQueueMethod ] = useState('POST');
const [ queueUser, setQueueUser ] = useState('' || '');
const [ queuePassword, setQueuePassword ] = useState('' || '');
const [ queueUser, setQueueUser ] = useState('');
const [ queuePassword, setQueuePassword ] = useState('');
const [ hasSubspace, setHasSubspace ] = useState(false);
const [ subspaceId, setSubspaceId ] = useState('');
const [ subspaceSecret, setSubspaceSecret ] = useState('');
const [ subspaceSipTeleportId, setSubspaceSipTeleportId ] = useState('');
const [ subspaceSipTeleportEntryPoints, setSubspaceSipTeleportEntryPoints ] = useState([]);
const [ showSubspaceModal, setShowSubspaceModal ] = useState(false);
const [ generatingSubspace, setGeneratingSubspace ] = useState(false);
const [ subspaceSipRealm, setSubspaceSipRealm ] = useState('');
const [ sbcs, setSbcs ] = useState([]);
const [ subspaceSipRealmOtherValue, setSubspaceSipRealmOtherValue ] = useState('');
const [ subspaceEnable, setSubspaceEnable ] = useState(false);
// Invalid form inputs
const [ invalidName, setInvalidName ] = useState(false);
@@ -85,6 +103,10 @@ const AccountForm = props => {
const [ invalidQueueWebhook, setInvalidQueueWebhook ] = useState(false);
const [ invalidQueueUser, setInvalidQueueUser ] = useState(false);
const [ invalidQueuePassword, setInvalidQueuePassword ] = useState(false);
// eslint-disable-next-line no-unused-vars
const [ invalidSubspaceId, setInvalidSubspaceId ] = useState(false);
// eslint-disable-next-line no-unused-vars
const [ invalidSubspaceClient, setInvalidSubspaceClient ] = useState(false);
const [ showLoader, setShowLoader ] = useState(true);
const [ errorMessage, setErrorMessage ] = useState('');
@@ -110,6 +132,14 @@ const AccountForm = props => {
}
};
const handleSubspaceMenuOpen = sid => {
if (menuOpen === sid) {
setMenuOpen(null);
} else {
setMenuOpen(sid);
}
};
const copyWebhookSecret = async e => {
e.preventDefault();
setMenuOpen(null);
@@ -141,7 +171,7 @@ const AccountForm = props => {
setGeneratingSecret(true);
const apiKeyResponse = await axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: `/Accounts/${accountSid}/WebhookSecret?regenerate=true`,
headers: {
Authorization: `Bearer ${jwt}`,
@@ -164,6 +194,96 @@ const AccountForm = props => {
}
};
const toggleSubspaceTeleport = (enable, e) => {
e.preventDefault();
setMenuOpen(null);
setSubspaceEnable(enable);
setShowSubspaceModal(true);
};
const resetSubspaceState = () => {
setMenuOpen(null);
setShowSubspaceModal(false);
setSubspaceSipRealmOtherValue('');
setGeneratingSubspace(false);
setSubspaceEnable(false);
setSubspaceSipRealm('');
};
const handleSubspaceEnable = async () => {
try {
setGeneratingSubspace(true);
const destination = subspaceSipRealm === 'other'
? subspaceSipRealmOtherValue
: subspaceSipRealm;
const response = await axios({
method: 'post',
baseURL: APP_API_BASE_URL,
url: `/Accounts/${accountSid}/SubspaceTeleport`,
headers: {
Authorization: `Bearer ${jwt}`,
},
data: { destination },
});
if (response.status === 200) {
setSubspaceSipTeleportId(response.data.subspace_sip_teleport_id || '');
setSubspaceSipTeleportEntryPoints(response.data.subspace_sip_teleport_destinations || []);
dispatch({
type: 'ADD',
level: 'success',
message: 'Successfully enabled subspace teleport.',
});
}
resetSubspaceState();
} catch (err) {
resetSubspaceState();
if (err.response.status === 500 && err.response.data.msg === 'Too Many Requests') {
dispatch({
type: 'ADD',
level: 'error',
message: 'You have already created the maximum number of SIP Teleports allowed for your Subspace account.',
});
} else {
handleErrors({ err, history, dispatch });
}
}
};
const handleSubspaceDisable = async () => {
try {
setGeneratingSubspace(true);
const response = await axios({
method: 'delete',
baseURL: APP_API_BASE_URL,
url: `/Accounts/${accountSid}/SubspaceTeleport`,
headers: {
Authorization: `Bearer ${jwt}`,
},
});
if (response.status === 204) {
setSubspaceSipTeleportId('');
setSubspaceSipTeleportEntryPoints([]);
dispatch({
type: 'ADD',
level: 'success',
message: `Successfully disabled subspace teleport.`,
});
}
resetSubspaceState();
} catch (err) {
resetSubspaceState();
handleErrors({ err, history, dispatch });
}
};
useEffect(() => {
const getAccounts = async () => {
try {
@@ -180,7 +300,7 @@ const AccountForm = props => {
const promiseList = [];
const accountsPromise = axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: '/Accounts',
headers: {
Authorization: `Bearer ${jwt}`,
@@ -191,7 +311,7 @@ const AccountForm = props => {
if (props.type === 'edit') {
const applicationsPromise = axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: '/Applications',
headers: {
Authorization: `Bearer ${jwt}`,
@@ -200,6 +320,16 @@ const AccountForm = props => {
promiseList.push(applicationsPromise);
}
const sbcsPromise = await axios({
method: 'get',
baseURL: APP_API_BASE_URL,
url: '/Sbcs',
headers: {
Authorization: `Bearer ${jwt}`,
},
});
promiseList.push(sbcsPromise);
const promiseAllValues = await Promise.all(promiseList);
const accountsData = (promiseAllValues[0] && promiseAllValues[0].data) || [];
@@ -212,6 +342,7 @@ const AccountForm = props => {
});
setAccountApplications(accountApplicationsData);
}
setSbcs(promiseAllValues[2].data);
if (props.type === 'setup' && accountsData.length > 1) {
history.push('/internal/accounts');
@@ -254,7 +385,11 @@ const AccountForm = props => {
setQueueUser((acc.queue_event_hook && acc.queue_event_hook.username) || '');
setQueuePassword((acc.queue_event_hook && acc.queue_event_hook.password) || '');
setWebhookSecret(acc.webhook_secret || '');
setSubspaceId(acc.subspace_client_id || '');
setSubspaceSecret(acc.subspace_client_secret || '');
setSubspaceSipTeleportId(acc.subspace_sip_teleport_id || '');
setSubspaceSipTeleportEntryPoints(acc.subspace_sip_teleport_destinations ? JSON.parse(acc.subspace_sip_teleport_destinations) : []);
setHasSubspace(acc.subspace_client_id ? true : false);
if (
(acc.registration_hook && acc.registration_hook.username) ||
(acc.registration_hook && acc.registration_hook.password)
@@ -404,6 +539,8 @@ const AccountForm = props => {
password: queuePassword || null,
},
webhook_secret: webhookSecret || null,
subspace_client_id: subspaceId || null,
subspace_client_secret: subspaceSecret || null,
};
if (props.type === 'add') {
@@ -420,7 +557,7 @@ const AccountForm = props => {
await axios({
method: props.type === 'add' ? 'post' : 'put',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url,
headers: {
Authorization: `Bearer ${jwt}`,
@@ -480,6 +617,19 @@ const AccountForm = props => {
},
];
const subspaceMenuItems = [
{
type: 'button',
name: 'Enable',
action: toggleSubspaceTeleport.bind(toggleSubspaceTeleport, true),
},
{
type: 'button',
name: 'Disable',
action: toggleSubspaceTeleport.bind(toggleSubspaceTeleport, false),
},
];
return (
showLoader
? <Loader
@@ -596,7 +746,7 @@ const AccountForm = props => {
<Select
large={props.type === 'setup'}
name="method"
id="method"
id="regMethod"
value={regMethod}
onChange={e => setRegMethod(e.target.value)}
>
@@ -665,7 +815,7 @@ const AccountForm = props => {
<Select
large={props.type === 'setup'}
name="method"
id="method"
id="queueMethod"
value={queueMethod}
onChange={e => setQueueMethod(e.target.value)}
>
@@ -711,6 +861,137 @@ const AccountForm = props => {
</Button>
)}
{ process.env.REACT_APP_ENABLE_SUBSPACE ? (
<>
<Label htmlFor="subspaceId">Subspace</Label>
<InputGroup>
<Input
large={props.type === 'setup'}
name="subspaceId"
id="subspaceId"
value={subspaceId}
onChange={e => setSubspaceId(e.target.value)}
placeholder="Client Id for Subspace"
ref={refSubspaceId}
style={{ margin: '0 4px' }}
/>
<PasswordInput
large={props.type === 'setup'}
allowShowPassword
name="subspaceSecret"
id="subspaceSecret"
password={subspaceSecret}
setPassword={setSubspaceSecret}
setErrorMessage={setErrorMessage}
placeholder="Client Secret for Subspace"
ref={refSubspaceSecret}
style={{ margin: '0 4px' }}
/>
<StyledInputGroup>
<TableMenu
disabled={!hasSubspace}
sid="subspace"
open={menuOpen === "subspace"}
handleMenuOpen={handleSubspaceMenuOpen}
menuItems={subspaceSipTeleportId ? [subspaceMenuItems[1]] : [subspaceMenuItems[0]]}
/>
</StyledInputGroup>
</InputGroup>
{subspaceSipTeleportId ? (
<div style={{ gridColumn: 2, textAlign: 'left' }}>
<div>Subspace is now enabled. To send your traffic through Subspace:</div>
{subspaceSipTeleportEntryPoints.map(entrypoint => (
<div key={entrypoint.transport_type}>
<Span>send {entrypoint.transport_type.split('_').join(' and ')} traffic to&nbsp;</Span>
<CopyableText text={entrypoint.address} textType="Address" />
</div>
))}
</div>
) : null}
{showSubspaceModal && (
<Modal
title={subspaceEnable ? 'Have Subspace send SIP to:' : 'Are you sure you want to delete your Subspace SIP Teleport?'}
loader={generatingSubspace}
hideButtons={generatingSubspace}
maskClosable={!generatingSubspace}
actionText={subspaceEnable ? 'Save' : 'Disable'}
content={
<ModalContainer>
{subspaceEnable ? (
<>
{sipRealm && (
<Radio
noLeftMargin
name="subspaceSipRealm"
id="sipRealmAccount"
label={sipRealm}
checked={subspaceSipRealm === sipRealm}
onChange={() => {
setSubspaceSipRealm(sipRealm);
setSubspaceSipRealmOtherValue('');
}}
/>
)}
{sbcs.map((sbc) => {
return (
<Radio
key={sbc.ipv4}
noLeftMargin
name="subspaceSipRealm"
id={sbc.sbc_address_sid}
label={`${sbc.ipv4}:${sbc.port}`}
checked={subspaceSipRealm === `${sbc.ipv4}:${sbc.port}`}
onChange={() => {
setSubspaceSipRealm(`${sbc.ipv4}:${sbc.port}`);
setSubspaceSipRealmOtherValue('');
}}
/>
);
})}
<Radio
noLeftMargin
name="subspaceSipRealm"
id="sipRealmOther"
label="Other"
checked={subspaceSipRealm === 'other'}
onChange={() => {
setSubspaceSipRealm('other');
setTimeout(() => refSubspaceOtherSip.current.focus(), 0);
}}
/>
{subspaceSipRealm === 'other' && (
<Input
ref={refSubspaceOtherSip}
name="subspaceSipRealm"
id="sipRealmOtherValue"
value={subspaceSipRealmOtherValue}
onChange={e => setSubspaceSipRealmOtherValue(e.target.value)}
placeholder="IP address or DNS name"
style={{ marginTop: '8px' }}
/>
)}
</>
) : null}
</ModalContainer>
}
handleCancel={() => {
setShowSubspaceModal(false);
resetSubspaceState();
}}
handleSubmit={() => {
if (subspaceEnable) {
handleSubspaceEnable();
} else {
handleSubspaceDisable();
}
}}
/>
)}
</>
) : null }
{errorMessage && (
<FormError grid message={errorMessage} />
)}

View File

@@ -1,3 +1,4 @@
/* eslint-disable no-undef */
import React, { useState, useEffect, useContext, useRef } from 'react';
import { useHistory } from 'react-router-dom';
import axios from 'axios';
@@ -15,8 +16,12 @@ import SpeechSynthesisLanguageGoogle from '../../data/SpeechSynthesisLanguageGoo
import SpeechSynthesisLanguageAws from '../../data/SpeechSynthesisLanguageAws';
import SpeechRecognizerLanguageGoogle from '../../data/SpeechRecognizerLanguageGoogle';
import SpeechRecognizerLanguageAws from '../../data/SpeechRecognizerLanguageAws';
import SpeechRecognizerLanguageMicrosoft from '../../data/SpeechRecognizerLanguageMicrosoft';
import SpeechSynthesisLanguageMicrosoft from '../../data/SpeechSynthesisLanguageMicrosoft';
import SpeechSynthesisLanguageWellSaid from '../../data/SpeechSynthesisLanguageWellSaid';
import Loader from '../blocks/Loader';
import CopyableText from '../elements/CopyableText';
import { APP_API_BASE_URL } from "../../constants";
const ApplicationForm = props => {
let history = useHistory();
@@ -100,7 +105,7 @@ const ApplicationForm = props => {
const accountsPromise = axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: '/Accounts',
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
@@ -108,7 +113,7 @@ const ApplicationForm = props => {
});
const applicationsPromise = axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: '/Applications',
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
@@ -391,7 +396,7 @@ const ApplicationForm = props => {
await axios({
method,
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url,
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
@@ -745,6 +750,14 @@ const ApplicationForm = props => {
? SpeechSynthesisLanguageGoogle.find(l => (
l.code === speechSynthesisLanguage
))
: e.target.value === 'microsoft'
? SpeechSynthesisLanguageMicrosoft.find(l => (
l.code === speechSynthesisLanguage
))
: e.target.value === 'wellsaid'
? SpeechSynthesisLanguageWellSaid.find(l => (
l.code === speechSynthesisLanguage
))
: SpeechSynthesisLanguageAws.find(l => (
l.code === speechSynthesisLanguage
));
@@ -758,9 +771,13 @@ const ApplicationForm = props => {
return;
}
newLang = SpeechSynthesisLanguageAws.find(l => (
l.code === 'en-US'
));
newLang = e.target.value === 'aws'
? SpeechSynthesisLanguageAws.find(l => (
l.code === 'en-US'
))
: SpeechSynthesisLanguageMicrosoft.find(l => (
l.code === 'en-US'
));
}
// Update state to reflect first voice option for language
@@ -769,6 +786,8 @@ const ApplicationForm = props => {
>
<option value="google">Google</option>
<option value="aws">AWS</option>
<option value="microsoft">Microsoft</option>
<option value="wellsaid">WellSaid</option>
</Select>
<Label middle htmlFor="speechSynthesisLanguage">Language</Label>
<Select
@@ -792,6 +811,14 @@ const ApplicationForm = props => {
? SpeechSynthesisLanguageGoogle.find(l => (
l.code === e.target.value
))
: speechSynthesisVendor === 'microsoft'
? SpeechSynthesisLanguageMicrosoft.find(l => (
l.code === e.target.value
))
: speechSynthesisVendor === 'wellsaid'
? SpeechSynthesisLanguageWellSaid.find(l => (
l.code === e.target.value
))
: SpeechSynthesisLanguageAws.find(l => (
l.code === e.target.value
));
@@ -804,6 +831,14 @@ const ApplicationForm = props => {
SpeechSynthesisLanguageGoogle.map(l => (
<option key={l.code} value={l.code}>{l.name}</option>
))
) : speechSynthesisVendor === 'microsoft' ? (
SpeechSynthesisLanguageMicrosoft.map(l => (
<option key={l.code} value={l.code}>{l.name}</option>
))
) : speechSynthesisVendor === 'wellsaid' ? (
SpeechSynthesisLanguageWellSaid.map(l => (
<option key={l.code} value={l.code}>{l.name}</option>
))
) : (
SpeechSynthesisLanguageAws.map(l => (
<option key={l.code} value={l.code}>{l.name}</option>
@@ -824,6 +859,18 @@ const ApplicationForm = props => {
.map(m => m.voices.map(v => (
<option key={v.value} value={v.value}>{v.name}</option>
)))
) : speechSynthesisVendor === 'microsoft' ? (
SpeechSynthesisLanguageMicrosoft
.filter(l => l.code === speechSynthesisLanguage)
.map(m => m.voices.map(v => (
<option key={v.value} value={v.value}>{v.name}</option>
)))
) : speechSynthesisVendor === 'wellsaid' ? (
SpeechSynthesisLanguageWellSaid
.filter(l => l.code === speechSynthesisLanguage)
.map(m => m.voices.map(v => (
<option key={v.value} value={v.value}>{v.name}</option>
)))
) : (
SpeechSynthesisLanguageAws
.filter(l => l.code === speechSynthesisLanguage)
@@ -862,6 +909,7 @@ const ApplicationForm = props => {
>
<option value="google">Google</option>
<option value="aws">AWS</option>
<option value="microsoft">Microsoft</option>
</Select>
<Label middle htmlFor="speechRecognizerLanguage">Language</Label>
<Select
@@ -875,6 +923,10 @@ const ApplicationForm = props => {
SpeechRecognizerLanguageGoogle.map(l => (
<option key={l.code} value={l.code}>{l.name}</option>
))
) : speechRecognizerVendor === 'microsoft' ? (
SpeechRecognizerLanguageMicrosoft.map(l => (
<option key={l.code} value={l.code}>{l.name}</option>
))
) : (
SpeechRecognizerLanguageAws.map(l => (
<option key={l.code} value={l.code}>{l.name}</option>

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,4 @@
/* eslint-disable no-undef */
import React, { useState, useEffect, useContext, useRef } from 'react';
import { useHistory } from 'react-router-dom';
import axios from 'axios';
@@ -10,6 +11,7 @@ import InputGroup from '../elements/InputGroup';
import FormError from '../blocks/FormError';
import Loader from '../blocks/Loader';
import Button from '../elements/Button';
import { APP_API_BASE_URL } from "../../constants";
const MsTeamsTenantForm = props => {
@@ -54,7 +56,7 @@ const MsTeamsTenantForm = props => {
const tenantsPromise = axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: '/MicrosoftTeamsTenants',
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
@@ -62,7 +64,7 @@ const MsTeamsTenantForm = props => {
});
const accountsPromise = axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: '/Accounts',
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
@@ -70,7 +72,7 @@ const MsTeamsTenantForm = props => {
});
const applicationsPromise = axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: '/Applications',
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
@@ -86,7 +88,7 @@ const MsTeamsTenantForm = props => {
if (props.type === 'add') {
promises.push(axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: '/ServiceProviders',
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
@@ -247,7 +249,7 @@ const MsTeamsTenantForm = props => {
await axios({
method,
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url,
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,

View File

@@ -1,3 +1,4 @@
/* eslint-disable no-undef */
import React, { useState, useEffect, useContext, useRef } from 'react';
import { useHistory } from 'react-router-dom';
import axios from 'axios';
@@ -12,6 +13,7 @@ import FormError from '../blocks/FormError';
import Loader from '../blocks/Loader';
import Button from '../elements/Button';
import phoneNumberFormat from '../../helpers/phoneNumberFormat';
import { APP_API_BASE_URL } from "../../constants";
const PhoneNumberForm = props => {
@@ -60,7 +62,7 @@ const PhoneNumberForm = props => {
const sipTrunksPromise = axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: '/VoipCarriers',
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
@@ -68,7 +70,7 @@ const PhoneNumberForm = props => {
});
const accountsPromise = axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: '/Accounts',
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
@@ -76,7 +78,7 @@ const PhoneNumberForm = props => {
});
const applicationsPromise = axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: '/Applications',
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
@@ -84,7 +86,7 @@ const PhoneNumberForm = props => {
});
const phoneNumbersPromise = axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: '/PhoneNumbers',
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
@@ -276,7 +278,7 @@ const PhoneNumberForm = props => {
await axios({
method,
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url,
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,

View File

@@ -1,3 +1,4 @@
/* eslint-disable no-undef */
import React, { useState, useEffect, useContext, useRef } from 'react';
import { useHistory } from 'react-router-dom';
import axios from 'axios';
@@ -15,6 +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";
const Td = styled.td`
padding: 0.5rem 0;
@@ -74,7 +76,7 @@ const SettingsForm = () => {
const serviceProvidersResponse = await axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: `/ServiceProviders`,
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
@@ -119,7 +121,7 @@ const SettingsForm = () => {
axios({
method: 'delete',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: `/ServiceProviders/${serviceProviderSid}`,
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
@@ -208,7 +210,7 @@ const SettingsForm = () => {
await axios({
method: 'put',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: `/ServiceProviders/${serviceProviderSid}`,
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,

View File

@@ -1,3 +1,4 @@
/* eslint-disable no-undef */
import React, { useState, useEffect, useContext, useRef } from 'react';
import { useParams, useHistory } from 'react-router-dom';
import axios from 'axios';
@@ -18,8 +19,10 @@ import Code from '../elements/Code';
import FormError from '../blocks/FormError';
import Button from '../elements/Button';
import Loader from '../blocks/Loader';
import { ServiceProviderValueContext } from '../../contexts/ServiceProviderContext'
import { ServiceProviderValueContext } from '../../contexts/ServiceProviderContext';
import MicrosoftAzureRegions from '../../data/MicrosoftAzureRegions';
import { APP_API_BASE_URL } from "../../constants";
const StyledButtonGroup = styled(InputGroup)`
@media (max-width: 576.98px) {
@@ -67,10 +70,14 @@ const SpeechServicesAddEdit = (props) => {
// Refs
const refVendorGoogle = useRef(null);
const refVendorAws = useRef(null);
const refVendorMs = useRef(null);
const refVendorWellSaid = useRef(null);
const refAccessKeyId = useRef(null);
const refSecretAccessKey = useRef(null);
const refUseForTts = useRef(null);
const refUseForStt = useRef(null);
const refApiKey = useRef(null);
const refRegion = useRef(null);
// Form inputs
const [ vendor, setVendor ] = useState('');
@@ -82,14 +89,20 @@ const SpeechServicesAddEdit = (props) => {
const [ useForStt, setUseForStt ] = useState(false);
const [ accounts, setAccounts ] = useState([]);
const [ accountSid, setAccountSid ] = useState('');
const [ apiKey, setApiKey ] = useState('');
const [ region, setRegion ] = useState('');
// Invalid form inputs
const [ invalidVendorGoogle, setInvalidVendorGoogle ] = useState(false);
const [ invalidVendorAws, setInvalidVendorAws ] = useState(false);
const [ invalidVendorMs, setInvalidVendorMs ] = useState(false);
const [ invalidVendorWellSaid, setInvalidVendorWellSaid ] = useState(false);
const [ invalidAccessKeyId, setInvalidAccessKeyId ] = useState(false);
const [ invalidSecretAccessKey, setInvalidSecretAccessKey ] = useState(false);
const [ invalidUseForTts, setInvalidUseForTts ] = useState(false);
const [ invalidUseForStt, setInvalidUseForStt ] = useState(false);
const [ invalidApiKey, setInvalidApiKey ] = useState(false);
const [ invalidRegion, setInvalidRegion ] = useState(false);
const [ originalTtsValue, setOriginalTtsValue ] = useState(null);
const [ originalSttValue, setOriginalSttValue ] = useState(null);
@@ -105,7 +118,7 @@ const SpeechServicesAddEdit = (props) => {
try {
const accountsResponse = await axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: '/Accounts',
headers: {
Authorization: `Bearer ${jwt}`,
@@ -117,7 +130,7 @@ const SpeechServicesAddEdit = (props) => {
if (type === 'edit') {
const speechCredential = await axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: `/ServiceProviders/${currentServiceProvider}/SpeechCredentials/${speech_service_sid}`,
headers: {
Authorization: `Bearer ${jwt}`,
@@ -139,6 +152,8 @@ const SpeechServicesAddEdit = (props) => {
setDisplayedServiceKey( displayedServiceKeyJson || '');
setAccessKeyId( speechCredential.data.access_key_id || '');
setSecretAccessKey( speechCredential.data.secret_access_key || '');
setApiKey( speechCredential.data.api_key || '');
setRegion( speechCredential.data.region || '');
setUseForTts( speechCredential.data.use_for_tts || false);
setUseForStt( speechCredential.data.use_for_stt || false);
setOriginalTtsValue( speechCredential.data.use_for_tts || false);
@@ -206,10 +221,13 @@ const SpeechServicesAddEdit = (props) => {
setErrorMessage('');
setInvalidVendorGoogle(false);
setInvalidVendorAws(false);
setInvalidVendorMs(false);
setInvalidVendorWellSaid(false);
setInvalidAccessKeyId(false);
setInvalidSecretAccessKey(false);
setInvalidUseForTts(false);
setInvalidUseForStt(false);
setInvalidApiKey(false);
let errorMessages = [];
let focusHasBeenSet = false;
@@ -217,6 +235,8 @@ const SpeechServicesAddEdit = (props) => {
errorMessages.push('Please select a vendor.');
setInvalidVendorGoogle(true);
setInvalidVendorAws(true);
setInvalidVendorMs(true);
setInvalidVendorWellSaid(true);
if (!focusHasBeenSet) {
refVendorGoogle.current.focus();
focusHasBeenSet = true;
@@ -245,6 +265,33 @@ const SpeechServicesAddEdit = (props) => {
}
}
if (vendor === 'microsoft' && !apiKey) {
errorMessages.push('Please provide an API key.');
setInvalidApiKey(true);
if (!focusHasBeenSet) {
refApiKey.current.focus();
focusHasBeenSet = true;
}
}
if (vendor === 'microsoft' && !region) {
errorMessages.push('Please select a region.');
setInvalidRegion(true);
if (!focusHasBeenSet) {
refRegion.current.focus();
focusHasBeenSet = true;
}
}
if (vendor === 'wellsaid' && !apiKey) {
errorMessages.push('Please provide an API key.');
setInvalidApiKey(true);
if (!focusHasBeenSet) {
refApiKey.current.focus();
focusHasBeenSet = true;
}
}
if (errorMessages.length > 1) {
setErrorMessage(errorMessages);
return;
@@ -266,7 +313,7 @@ const SpeechServicesAddEdit = (props) => {
const postResults = await axios({
method,
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url,
headers: {
Authorization: `Bearer ${jwt}`,
@@ -276,6 +323,8 @@ const SpeechServicesAddEdit = (props) => {
service_key: vendor === 'google' ? JSON.stringify(serviceKey) : null,
access_key_id: vendor === 'aws' ? accessKeyId : null,
secret_access_key: vendor === 'aws' ? secretAccessKey : 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,
@@ -297,7 +346,7 @@ const SpeechServicesAddEdit = (props) => {
if (useForTts || useForStt) {
const testResults = await axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: `/ServiceProviders/${currentServiceProvider}/SpeechCredentials/${speech_service_sid}/test`,
headers: {
Authorization: `Bearer ${jwt}`,
@@ -342,7 +391,7 @@ const SpeechServicesAddEdit = (props) => {
if (type === 'add') {
await axios({
method: 'delete',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: `/ServiceProviders/${currentServiceProvider}/SpeechCredentials/${speech_service_sid}`,
headers: {
Authorization: `Bearer ${jwt}`,
@@ -353,7 +402,7 @@ const SpeechServicesAddEdit = (props) => {
if (type === 'edit') {
await axios({
method,
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url,
headers: {
Authorization: `Bearer ${jwt}`,
@@ -444,6 +493,28 @@ const SpeechServicesAddEdit = (props) => {
ref={refVendorAws}
disabled={type === 'edit'}
/>
<Radio
name="vendor"
id="microsoft"
label="Microsoft"
checked={vendor === 'microsoft'}
onChange={() => setVendor('microsoft')}
invalid={invalidVendorMs}
ref={refVendorMs}
disabled={type === 'edit'}
/>
<Radio
name="vendor"
id="wellsaid"
label="WellSaid"
checked={vendor === 'wellsaid'}
onChange={() => setVendor('wellsaid')}
invalid={invalidVendorWellSaid}
ref={refVendorWellSaid}
disabled={type === 'edit'}
/>
</InputGroup>
<Label htmlFor="account">Used by</Label>
@@ -512,11 +583,61 @@ const SpeechServicesAddEdit = (props) => {
disabled={type === 'edit'}
/>
</>
) : vendor === 'microsoft' ? (
<>
<Label htmlFor="apiKey">API Key</Label>
<Input
name="apiKey"
id="apiKey"
value={apiKey}
onChange={e => setApiKey(e.target.value)}
placeholder=""
invalid={invalidApiKey}
ref={refApiKey}
disabled={type === 'edit'}
/>
<Label htmlFor="region">Region</Label>
<Select
name="region"
id="region"
value={region}
onChange={e => setRegion(e.target.value)}
ref={refRegion}
invalid={invalidRegion}
>
<option value="">
All regions
</option>
{MicrosoftAzureRegions.map(r => (
<option
key={r.value}
value={r.value}
>
{r.name}
</option>
))}
</Select>
</>
) : vendor === 'wellsaid' ? (
<>
<Label htmlFor="apiKey">API Key</Label>
<Input
name="apiKey"
id="apiKey"
value={apiKey}
onChange={e => setApiKey(e.target.value)}
placeholder=""
invalid={invalidApiKey}
ref={refApiKey}
disabled={type === 'edit'}
/>
</>
) : (
null
)}
{vendor === 'google' || vendor === 'aws' ? (
{['google', 'aws', 'microsoft', 'wellsaid'].includes(vendor) ? (
<>
<div/>
<Checkbox
@@ -535,13 +656,15 @@ const SpeechServicesAddEdit = (props) => {
name="useForStt"
id="useForStt"
label="Use for speech-to-text"
disabled={'wellsaid' === vendor}
checked={useForStt}
onChange={e => setUseForStt(e.target.checked)}
invalid={invalidUseForStt}
ref={refUseForStt}
/>
</>
) : (
) :
(
null
)}

View File

@@ -1,3 +1,4 @@
/* eslint-disable no-undef */
import React, { useState, useEffect, useRef } from 'react';
import { useHistory } from 'react-router-dom';
import axios from 'axios';
@@ -7,6 +8,7 @@ import Button from '../elements/Button';
import Input from '../elements/Input';
import PasswordInput from '../elements/PasswordInput';
import FormError from '../blocks/FormError';
import { APP_API_BASE_URL } from "../../constants";
const Login = props => {
let history = useHistory();
@@ -58,7 +60,7 @@ const Login = props => {
// Log in
const response = await axios({
method: 'post',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: '/login',
data: { username, password },
});
@@ -84,7 +86,7 @@ const Login = props => {
//-----------------------------------------------------------------------------
const serviceProvidersPromise = axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: '/serviceProviders',
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
@@ -93,7 +95,7 @@ const Login = props => {
const accountsPromise = axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: '/Accounts',
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
@@ -102,7 +104,7 @@ const Login = props => {
const applicationsPromise = axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: '/applications',
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
@@ -111,7 +113,7 @@ const Login = props => {
const voipCarriersPromise = axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: '/voipCarriers',
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,

View File

@@ -1,3 +1,4 @@
/* eslint-disable no-undef */
import React, { useEffect, useContext } from 'react';
import { useParams, useHistory } from 'react-router-dom';
import axios from 'axios';
@@ -5,6 +6,7 @@ import { NotificationDispatchContext } from '../../../contexts/NotificationConte
import InternalTemplate from '../../templates/InternalTemplate';
import AccountForm from '../../forms/AccountForm';
import TableContent from '../../blocks/TableContent.js';
import { APP_API_BASE_URL } from "../../../constants";
const AccountsAddEdit = () => {
let history = useHistory();
@@ -31,7 +33,7 @@ const AccountsAddEdit = () => {
}
const results = await axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: `/Accounts/${account_sid}/ApiKeys`,
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
@@ -112,7 +114,7 @@ const AccountsAddEdit = () => {
}
const result = await axios({
method: 'post',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: '/Apikeys',
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
@@ -167,7 +169,7 @@ const AccountsAddEdit = () => {
}
await axios({
method: 'delete',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: `/Apikeys/${apiKeyToDelete.sid}`,
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,

View File

@@ -1,3 +1,4 @@
/* eslint-disable no-undef */
import React, { useEffect, useContext } from 'react';
import { useHistory } from 'react-router-dom';
import axios from 'axios';
@@ -5,6 +6,7 @@ import { NotificationDispatchContext } from '../../../contexts/NotificationConte
import InternalTemplate from '../../templates/InternalTemplate';
import TableContent from '../../blocks/TableContent.js';
import { ServiceProviderValueContext } from '../../../contexts/ServiceProviderContext';
import { APP_API_BASE_URL } from "../../../constants";
const AccountsList = () => {
let history = useHistory();
@@ -31,7 +33,7 @@ const AccountsList = () => {
if(!currentServiceProvider) return [];
const results = await axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: `/ServiceProviders/${currentServiceProvider}/Accounts`,
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
@@ -43,6 +45,7 @@ const AccountsList = () => {
sip_realm: a.sip_realm,
url_reg: a.registration_hook && a.registration_hook.url,
url_queue: a.queue_event_hook && a.queue_event_hook.url,
subspace_enabled: a.subspace_sip_teleport_id ? 'Enabled' : ''
}));
return(simplifiedAccounts);
} catch (err) {
@@ -93,7 +96,7 @@ const AccountsList = () => {
// or if the account has any API keys
const applicationsPromise = axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: '/Applications',
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
@@ -101,7 +104,7 @@ const AccountsList = () => {
});
const phoneNumbersPromise = axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: '/PhoneNumbers',
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
@@ -109,7 +112,7 @@ const AccountsList = () => {
});
const msTeamsTenantsPromise = axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: '/MicrosoftTeamsTenants',
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
@@ -117,7 +120,7 @@ const AccountsList = () => {
});
const apiKeysPromise = axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: `/Accounts/${accountToDelete.sid}/ApiKeys`,
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
@@ -178,7 +181,7 @@ const AccountsList = () => {
// Delete account
await axios({
method: 'delete',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: `/Accounts/${accountToDelete.sid}`,
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
@@ -220,7 +223,7 @@ const AccountsList = () => {
{ header: 'AccountSid', key: 'sid' },
{ header: 'SIP Realm', key: 'sip_realm' },
{ header: 'Registration Webhook', key: 'url_reg' },
{ header: 'Queue Event Webhook', key: 'url_queue' },
{ header: 'Queue Event Webhook', key: 'url_queue' }
]}
formatContentToDelete={formatAccountToDelete}
deleteContent={deleteAccount}

View File

@@ -1,5 +1,6 @@
/* eslint-disable react-hooks/exhaustive-deps */
/* eslint-disable react/react-in-jsx-scope */
/* eslint-disable no-undef */
import React, { useContext, useState, useEffect } from "react";
import { useHistory } from "react-router-dom";
import axios from "axios";
@@ -14,6 +15,7 @@ import Select from "../../../components/elements/Select";
import AntdTable from "../../../components/blocks/AntdTable";
import handleErrors from "../../../helpers/handleErrors";
import { ServiceProviderValueContext } from '../../../contexts/ServiceProviderContext';
import { APP_API_BASE_URL } from "../../../constants";
const StyledButton = styled(Button)`
& > span {
@@ -115,7 +117,7 @@ const AlertsIndex = () => {
const alerts = await axios({
method: "get",
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: `/Accounts/${account}/Alerts`,
headers: {
Authorization: `Bearer ${jwt}`,
@@ -171,7 +173,7 @@ const AlertsIndex = () => {
setLoading(true);
const accountResponse = await axios({
method: "get",
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: `/ServiceProviders/${currentServiceProvider}/Accounts`,
headers: {
Authorization: `Bearer ${jwt}`,

View File

@@ -1,4 +1,5 @@
/* eslint-disable react-hooks/exhaustive-deps */
/* eslint-disable no-undef */
import React, { useEffect, useContext, useState, useCallback } from 'react';
import { useHistory } from 'react-router-dom';
import axios from 'axios';
@@ -10,6 +11,7 @@ import Select from "../../../components/elements/Select";
import InputGroup from "../../../components/elements/InputGroup";
import { ServiceProviderValueContext } from '../../../contexts/ServiceProviderContext';
import handleErrors from "../../../helpers/handleErrors";
import { APP_API_BASE_URL } from "../../../constants";
const FilterLabel = styled.span`
color: #231f20;
@@ -57,7 +59,7 @@ const ApplicationsList = () => {
try {
const accountResponse = await axios({
method: "get",
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: `/ServiceProviders/${currentServiceProvider}/Accounts`,
headers: {
Authorization: `Bearer ${jwt}`,
@@ -100,7 +102,7 @@ const ApplicationsList = () => {
}
const applicationsPromise = axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: `/Accounts/${account}/Applications`,
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
@@ -173,7 +175,7 @@ const ApplicationsList = () => {
// check if any account or Microsoft Teams Tenant uses this application
const accountsPromise = axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: '/Accounts',
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
@@ -181,7 +183,7 @@ const ApplicationsList = () => {
});
const msTeamsTenantsPromise = axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: '/MicrosoftTeamsTenants',
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
@@ -226,7 +228,7 @@ const ApplicationsList = () => {
// Delete application
await axios({
method: 'delete',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: `/Applications/${applicationToDelete.sid}`,
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,

View File

@@ -2,7 +2,6 @@ import React, { useEffect } from 'react';
import { useParams } from 'react-router-dom';
import InternalTemplate from '../../templates/InternalTemplate';
import CarrierForm from '../../forms/CarrierForm';
import Sbcs from '../../blocks/Sbcs';
const CarriersAddEdit = () => {
let { voip_carrier_sid } = useParams();
@@ -15,7 +14,6 @@ const CarriersAddEdit = () => {
<InternalTemplate
type="form"
title={pageTitle}
subtitle={<Sbcs />}
breadcrumbs={[
{ name: 'Carriers', url: '/internal/carriers' },
{ name: pageTitle },

View File

@@ -1,4 +1,5 @@
/* eslint-disable react-hooks/exhaustive-deps */
/* eslint-disable no-undef */
import React, { useEffect, useContext, useState } from 'react';
import axios from 'axios';
import { useHistory, useLocation } from 'react-router-dom';
@@ -7,12 +8,12 @@ import styled from 'styled-components/macro';
import { NotificationDispatchContext } from '../../../contexts/NotificationContext';
import InternalTemplate from '../../templates/InternalTemplate';
import TableContent from '../../blocks/TableContent.js';
import Sbcs from '../../blocks/Sbcs';
import sortSipGateways from '../../../helpers/sortSipGateways';
import { ServiceProviderValueContext } from '../../../contexts/ServiceProviderContext';
import InputGroup from '../../../components/elements/InputGroup';
import Select from '../../../components/elements/Select';
import handleErrors from '../../../helpers/handleErrors';
import { APP_API_BASE_URL } from "../../../constants";
const FilterLabel = styled.span`
color: #231f20;
@@ -65,7 +66,7 @@ const CarriersList = () => {
try {
const accountResponse = await axios({
method: "get",
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: `/ServiceProviders/${currentServiceProvider}/Accounts`,
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
@@ -107,7 +108,7 @@ const CarriersList = () => {
// Get all SIP trunks
const trunkResults = await axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: `/ServiceProviders/${currentServiceProvider}/VoipCarriers`,
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
@@ -123,7 +124,7 @@ const CarriersList = () => {
for (const t of trunkResultsFiltered) {
const gws = await axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: `/SipGateways?voip_carrier_sid=${t.voip_carrier_sid}`,
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
@@ -204,7 +205,7 @@ const CarriersList = () => {
for (const sid of carrierToDelete.gatewaysSid) {
await axios({
method: 'delete',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: `/SipGateways/${sid}`,
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
@@ -214,7 +215,7 @@ const CarriersList = () => {
// delete sip trunk
await axios({
method: 'delete',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: `/VoipCarriers/${carrierToDelete.sid}`,
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
@@ -246,7 +247,6 @@ const CarriersList = () => {
title="Carriers"
addButtonText="Add a Carrier"
addButtonLink="/internal/carriers/add"
subtitle={<Sbcs />}
>
<StyledInputGroup flexEnd space>
<FilterLabel htmlFor="account">Used By:</FilterLabel>

View File

@@ -1,9 +1,11 @@
/* eslint-disable no-undef */
import React, { useEffect, useContext } from 'react';
import axios from 'axios';
import { useHistory } from 'react-router-dom';
import { NotificationDispatchContext } from '../../../contexts/NotificationContext';
import InternalTemplate from '../../templates/InternalTemplate';
import TableContent from '../../blocks/TableContent.js';
import { APP_API_BASE_URL } from "../../../constants";
const MsTeamsTenantsList = () => {
let history = useHistory();
@@ -28,7 +30,7 @@ const MsTeamsTenantsList = () => {
}
const msTeamsTenantsPromise = axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: '/MicrosoftTeamsTenants',
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
@@ -36,7 +38,7 @@ const MsTeamsTenantsList = () => {
});
const accountsPromise = axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: '/Accounts',
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
@@ -44,7 +46,7 @@ const MsTeamsTenantsList = () => {
});
const applicationsPromise = axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: '/Applications',
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
@@ -114,7 +116,7 @@ const MsTeamsTenantsList = () => {
}
await axios({
method: 'delete',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: `/MicrosoftTeamsTenants/${tenant.sid}`,
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,

View File

@@ -1,3 +1,4 @@
/* eslint-disable no-undef */
import React, { useState, useEffect, useContext, useCallback } from 'react';
import axios from 'axios';
import { useHistory } from 'react-router-dom';
@@ -6,6 +7,7 @@ import InternalTemplate from '../../templates/InternalTemplate';
import TableContent from '../../blocks/TableContent.js';
import phoneNumberFormat from '../../../helpers/phoneNumberFormat';
import { ServiceProviderValueContext } from '../../../contexts/ServiceProviderContext';
import { APP_API_BASE_URL } from "../../../constants";
const PhoneNumbersList = () => {
let history = useHistory();
@@ -33,7 +35,7 @@ const PhoneNumbersList = () => {
if(!currentServiceProvider) return [];
const phoneNumbersPromise = axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: `/ServiceProviders/${currentServiceProvider}/PhoneNumbers`,
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
@@ -41,7 +43,7 @@ const PhoneNumbersList = () => {
});
const accountsPromise = axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: `/ServiceProviders/${currentServiceProvider}/Accounts`,
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
@@ -49,7 +51,7 @@ const PhoneNumbersList = () => {
});
const applicationsPromise = axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: `/ServiceProviders/${currentServiceProvider}/Applications`,
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
@@ -57,7 +59,7 @@ const PhoneNumbersList = () => {
});
const sipTrunksPromise = axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: `/ServiceProviders/${currentServiceProvider}/VoipCarriers`,
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
@@ -150,7 +152,7 @@ const PhoneNumbersList = () => {
}
await axios({
method: 'delete',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: `/PhoneNumbers/${phoneNumber.sid}`,
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
@@ -192,7 +194,7 @@ const PhoneNumbersList = () => {
for (const sid of phoneNumberSids) {
await axios({
method: 'put',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: `/PhoneNumbers/${sid}`,
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,

View File

@@ -1,4 +1,5 @@
/* eslint-disable react-hooks/exhaustive-deps */
/* eslint-disable no-undef */
import React, { useContext, useEffect, useState } from "react";
import { useHistory } from "react-router-dom";
import axios from "axios";
@@ -15,6 +16,7 @@ import InputGroup from "../../../components/elements/InputGroup";
import Select from "../../../components/elements/Select";
import handleErrors from "../../../helpers/handleErrors";
import { ServiceProviderValueContext } from '../../../contexts/ServiceProviderContext';
import { APP_API_BASE_URL } from "../../../constants";
const FilterLabel = styled.span`
color: #231f20;
@@ -83,7 +85,7 @@ const PcapButton = ({call_data, account_sid, jwt_token}) => {
useEffect(() => {
axios({
method: "get",
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: `/Accounts/${account_sid}/RecentCalls/${call_data.sip_callid}`,
headers: {
Authorization: `Bearer ${jwt_token}`,
@@ -92,7 +94,7 @@ const PcapButton = ({call_data, account_sid, jwt_token}) => {
if (result_1.status === 200 && result_1.data.total > 0) {
axios({
method: "get",
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: `/Accounts/${account_sid}/RecentCalls/${call_data.sip_callid}/pcap`,
headers: {
Authorization: `Bearer ${jwt_token}`,
@@ -242,7 +244,7 @@ const RecentCallsIndex = () => {
setLoading(true);
const result = await axios({
method: "get",
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: `/Accounts/${account}/RecentCalls`,
headers: {
Authorization: `Bearer ${jwt}`,
@@ -267,6 +269,7 @@ const RecentCallsIndex = () => {
to: phoneNumberFormat(item.to),
status: item.answered ? "answered" : item.termination_reason,
duration: timeFormat(item.duration),
trace_id: item.trace_id
}));
setRecentCallsData(recentCalls);
@@ -299,6 +302,7 @@ const RecentCallsIndex = () => {
"remote_host",
"sip_status",
"trunk",
"trace_id"
];
return (
@@ -376,7 +380,7 @@ const RecentCallsIndex = () => {
setLoading(true);
const accountResponse = await axios({
method: "get",
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: `/ServiceProviders/${currentServiceProvider}/Accounts`,
headers: {
Authorization: `Bearer ${jwt}`,

View File

@@ -2,7 +2,6 @@ import React, { useEffect } from 'react';
import { useParams } from 'react-router-dom';
import InternalTemplate from '../../templates/InternalTemplate';
import SpeechForm from '../../forms/SpeechForm';
import Sbcs from '../../blocks/Sbcs';
const SpeechServicesAddEdit = () => {
let { speech_service_sid } = useParams();
@@ -14,7 +13,6 @@ const SpeechServicesAddEdit = () => {
<InternalTemplate
type="form"
title={pageTitle}
subtitle={<Sbcs />}
breadcrumbs={[
{ name: 'Speech Services', url: '/internal/speech-services' },
{ name: pageTitle },

View File

@@ -1,4 +1,5 @@
/* eslint-disable react-hooks/exhaustive-deps */
/* eslint-disable no-undef */
import React, { useContext, useState, useEffect } from 'react';
import { useHistory, useLocation } from 'react-router-dom';
import axios from 'axios';
@@ -9,9 +10,9 @@ import handleErrors from '../../../helpers/handleErrors';
import InternalTemplate from '../../templates/InternalTemplate';
import TableContent from '../../../components/blocks/TableContent';
import { ServiceProviderValueContext } from '../../../contexts/ServiceProviderContext';
import Sbcs from '../../blocks/Sbcs';
import InputGroup from '../../../components/elements/InputGroup';
import Select from '../../../components/elements/Select';
import { APP_API_BASE_URL } from "../../../constants";
const FilterLabel = styled.span`
color: #231f20;
@@ -61,7 +62,7 @@ const SpeechServicesList = () => {
try {
const accountResponse = await axios({
method: "get",
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: `/ServiceProviders/${currentServiceProvider}/Accounts`,
headers: {
Authorization: `Bearer ${jwt}`,
@@ -106,7 +107,7 @@ const SpeechServicesList = () => {
`/ServiceProviders/${currentServiceProvider}/SpeechCredentials`;
const speechServices = await axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: speechApiUrl,
headers: {
Authorization: `Bearer ${jwt}`,
@@ -117,7 +118,7 @@ const SpeechServicesList = () => {
if (s.use_for_stt || s.use_for_tts) {
return axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: `/ServiceProviders/${currentServiceProvider}/SpeechCredentials/${s.speech_credential_sid}/test`,
headers: {
Authorization: `Bearer ${jwt}`,
@@ -237,7 +238,7 @@ const SpeechServicesList = () => {
// Delete speech service
await axios({
method: 'delete',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: `/ServiceProviders/${currentServiceProvider}/SpeechCredentials/${speechServiceToDelete.sid}`,
headers: {
Authorization: `Bearer ${jwt}`,
@@ -268,7 +269,6 @@ const SpeechServicesList = () => {
<InternalTemplate
type="normalTable"
title="Speech Services"
subtitle={<Sbcs />}
addButtonText="Add Speech Service"
addButtonLink="/internal/speech-services/add"
>

View File

@@ -1,3 +1,4 @@
/* eslint-disable no-undef */
import React, { useState, useEffect, useContext, useRef } from 'react';
import { useHistory } from 'react-router-dom';
import axios from 'axios';
@@ -8,6 +9,7 @@ import Button from '../../elements/Button';
import Input from '../../elements/Input';
import FormError from '../../blocks/FormError';
import Loader from '../../blocks/Loader';
import { APP_API_BASE_URL } from "../../../constants";
const CreatePassword = () => {
let history = useHistory();
@@ -63,7 +65,7 @@ const CreatePassword = () => {
//-----------------------------------------------------------------------------
const serviceProvidersPromise = axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: '/serviceProviders',
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
@@ -72,7 +74,7 @@ const CreatePassword = () => {
const accountsPromise = axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: '/Accounts',
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
@@ -81,7 +83,7 @@ const CreatePassword = () => {
const applicationsPromise = axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: '/applications',
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
@@ -90,7 +92,7 @@ const CreatePassword = () => {
const voipCarriersPromise = axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: '/voipCarriers',
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
@@ -235,7 +237,7 @@ const CreatePassword = () => {
const response = await axios({
method: 'put',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: `/Users/${user_sid}`,
data: {
old_password,

2
src/constants.js Normal file
View File

@@ -0,0 +1,2 @@
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;

View File

@@ -1,6 +1,7 @@
import React, { useState, createContext, useContext } from 'react';
import axios from 'axios';
import { NotificationDispatchContext } from './NotificationContext';
import { APP_API_BASE_URL } from "../constants";
export const ShowMsTeamsStateContext = createContext();
export const ShowMsTeamsDispatchContext = createContext();
@@ -13,7 +14,7 @@ export function ShowMsTeamsProvider(props) {
try {
const serviceProvidersResponse = await axios({
method: 'get',
baseURL: process.env.REACT_APP_API_BASE_URL,
baseURL: APP_API_BASE_URL,
url: '/ServiceProviders',
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,

View File

@@ -0,0 +1,94 @@
export default [
{
name: 'Asia (East)',
value: 'eastasia'
},
{
name: 'Asia (Southeast)',
value: 'southeastasia'
},
{
name: 'Australia (East)',
value: 'australiaeast'
},
{
name: 'Brazil (South)',
value: 'brazilsouth'
},
{
name: 'Canada (Central)',
value: 'canadacentral'
},
{
name: 'Europe (North)',
value: 'northeurope'
},
{
name: 'Europe (West)',
value: 'westeurope'
},
{
name: 'France (Central)',
value: 'francecentral'
},
{
name: 'Switzerland (North)',
value: 'switzerlandnorth'
},
{
name: 'India (Central)',
value: 'centralindia'
},
{
name: 'Japan (West)',
value: 'japanwest'
},
{
name: 'Japan (East)',
value: 'japaneast'
},
{
name: 'Korea (Central)',
value: 'koreacentral'
},
{
name: 'South Africa (North)',
value: 'southafricanorth'
},
{
name: 'UK (South)',
value: 'uksouth'
},
{
name: 'US (Cental)',
value: 'centralus'
},
{
name: 'US (West Central)',
value: 'westcentralus'
},
{
name: 'US (East)',
value: 'eastus'
},
{
name: 'US (East 2)',
value: 'eastus2'
},
{
name: 'US (North Central)',
value: 'northcentralus'
},
{
name: 'US (South Central)',
value: 'southcentralus'
},
{
name: 'US (West)',
value: 'westus'
},
{
name: 'US (West 2)',
value: 'westus2'
},
];

View File

@@ -0,0 +1,422 @@
export default [
{
name: 'Arabic (Algeria)',
code: 'ar-DZ'
},
{
name: 'Arabic (Bahrain)',
code: 'ar-BH'
},
{
name: 'Arabic (Egypt)',
code: 'ar-EG'
},
{
name: 'Arabic (Iraq)',
code: 'ar-IQ'
},
{
name: 'Arabic (Israel)',
code: 'ar-IL'
},
{
name: 'Arabic (Jordan)',
code: 'ar-JO'
},
{
name: 'Arabic (Kuwait)',
code: 'ar-KW'
},
{
name: 'Arabic (Lebanon)',
code: 'ar-LB'
},
{
name: 'Arabic (Libya)',
code: 'ar-LY'
},
{
name: 'Arabic (Morocco)',
code: 'ar-MA'
},
{
name: 'Arabic (Oman)',
code: 'ar-OM'
},
{
name: 'Arabic (Qatar)',
code: 'ar-QA'
},
{
name: 'Arabic (Saudi Arabia)',
code: 'ar-SA'
},
{
name: 'Arabic (Palestinian Authority)',
code: 'ar-PS'
},
{
name: 'Arabic (Syria)',
code: 'ar-SY'
},
{
name: 'Arabic (Tunisia)',
code: 'ar-TN'
},
{
name: 'Arabic (United Arab Emirates)',
code: 'ar-AE'
},
{
name: 'Arabic (Yemen)',
code: 'ar-YE'
},
{
name: 'Bulgarian (Bulgaria)',
code: 'bg-BG'
},
{
name: 'Catalan (Spain)',
code: 'ca-ES'
},
{
name: 'Chinese (Cantonese, Traditional)',
code: 'zh-HK'
},
{
name: 'Chinese (Mandarin, Simplified)',
code: 'zh-CN'
},
{
name: 'Chinese (Taiwanese Mandarin)',
code: 'zh-TW'
},
{
name: 'Croatian (Croatia)',
code: 'hr-HR'
},
{
name: 'Czech (Czech)',
code: 'cs-CZ'
},
{
name: 'Danish (Denmark)',
code: 'da-DK'
},
{
name: 'Dutch (Netherlands)',
code: 'nl-NL'
},
{
name: 'English (Australia)',
code: 'en-AU'
},
{
name: 'English (Canada)',
code: 'en-CA'
},
{
name: 'English (Ghana)',
code: 'en-GH'
},
{
name: 'English (Hong Kong)',
code: 'en-HK'
},
{
name: 'English (India)',
code: 'en-IN'
},
{
name: 'English (Ireland)',
code: 'en-IE'
},
{
name: 'English (Kenya)',
code: 'en-KE'
},
{
name: 'English (New Zealand)',
code: 'en-NZ'
},
{
name: 'English (Nigeria)',
code: 'en-NG'
},
{
name: 'English (Philippines)',
code: 'en-PH'
},
{
name: 'English (Singapore)',
code: 'en-SG'
},
{
name: 'English (South Africa)',
code: 'en-ZA'
},
{
name: 'English (Tanzania)',
code: 'en-TZ'
},
{
name: 'English (United Kingdom)',
code: 'en-GB'
},
{
name: 'English (United States)',
code: 'en-US'
},
{
name: 'Estonian(Estonia)',
code: 'et-EE'
},
{
name: 'Filipino (Philippines)',
code: 'fil-PH'
},
{
name: 'Finnish (Finland)',
code: 'fi-FI'
},
{
name: 'French (Canada)',
code: 'fr-CA'
},
{
name: 'French (France)',
code: 'fr-FR'
},
{
name: 'French (Switzerland)',
code: 'fr-CH'
},
{
name: 'German (Austria)',
code: 'de-AT'
},
{
name: 'German (Switzerland)',
code: 'de-CH'
},
{
name: 'German (Germany)',
code: 'de-DE'
},
{
name: 'Greek (Greece)',
code: 'el-GR'
},
{
name: 'Gujarati (Indian)',
code: 'gu-IN'
},
{
name: 'Hebrew (Israel)',
code: 'he-IL'
},
{
name: 'Hindi (India)',
code: 'hi-IN'
},
{
name: 'Hungarian (Hungary)',
code: 'hu-HU'
},
{
name: 'Indonesian (Indonesia)',
code: 'id-ID'
},
{
name: 'Irish (Ireland)',
code: 'ga-IE'
},
{
name: 'Italian (Italy)',
code: 'it-IT'
},
{
name: 'Japanese (Japan)',
code: 'ja-JP'
},
{
name: 'Kannada (India)',
code: 'kn-IN'
},
{
name: 'Korean (Korea)',
code: 'ko-KR'
},
{
name: 'Latvian (Latvia)',
code: 'lv-LV'
},
{
name: 'Lithuanian (Lithuania)',
code: 'lt-LT'
},
{
name: 'Malay (Malaysia)',
code: 'ms-MY'
},
{
name: 'Maltese (Malta)',
code: 'mt-MT'
},
{
name: 'Marathi (India)',
code: 'mr-IN'
},
{
name: 'Norwegian (Bokmål, Norway)',
code: 'nb-NO'
},
{
name: 'Persian (Iran)',
code: 'fa-IR'
},
{
name: 'Polish (Poland)',
code: 'pl-PL'
},
{
name: 'Portuguese (Brazil)',
code: 'pt-BR'
},
{
name: 'Portuguese (Portugal)',
code: 'pt-PT'
},
{
name: 'Romanian (Romania)',
code: 'ro-RO'
},
{
name: 'Russian (Russia)',
code: 'ru-RU'
},
{
name: 'Slovak (Slovakia)',
code: 'sk-SK'
},
{
name: 'Slovenian (Slovenia)',
code: 'sl-SI'
},
{
name: 'Spanish (Argentina)',
code: 'es-AR'
},
{
name: 'Spanish (Bolivia)',
code: 'es-BO'
},
{
name: 'Spanish (Chile)',
code: 'es-CL'
},
{
name: 'Spanish (Colombia)',
code: 'es-CO'
},
{
name: 'Spanish (Costa Rica)',
code: 'es-CR'
},
{
name: 'Spanish (Cuba)',
code: 'es-CU'
},
{
name: 'Spanish (Dominican Republic)',
code: 'es-DO'
},
{
name: 'Spanish (Ecuador)',
code: 'es-EC'
},
{
name: 'Spanish (El Salvador)',
code: 'es-SV'
},
{
name: 'Spanish (Equatorial Guinea)',
code: 'es-GQ'
},
{
name: 'Spanish (Guatemala)',
code: 'es-GT'
},
{
name: 'Spanish (Honduras)',
code: 'es-HN'
},
{
name: 'Spanish (Mexico)',
code: 'es-MX'
},
{
name: 'Spanish (Nicaragua)',
code: 'es-NI'
},
{
name: 'Spanish (Panama)',
code: 'es-PA'
},
{
name: 'Spanish (Paraguay)',
code: 'es-PY'
},
{
name: 'Spanish (Peru)',
code: 'es-PE'
},
{
name: 'Spanish (Puerto Rico)',
code: 'es-PR'
},
{
name: 'Spanish (Spain)',
code: 'es-ES'
},
{
name: 'Spanish (Uruguay)',
code: 'es-UY'
},
{
name: 'Spanish (USA)',
code: 'es-US'
},
{
name: 'Spanish (Venezuela)',
code: 'es-VE'
},
{
name: 'Swahili (Kenya)',
code: 'sw-KE'
},
{
name: 'Swedish (Sweden)',
code: 'sv-SE'
},
{
name: 'Tamil (India)',
code: 'ta-IN'
},
{
name: 'Telugu (India)',
code: 'te-IN'
},
{
name: 'Thai (Thailand)',
code: 'th-TH'
},
{
name: 'Turkish (Turkey)',
code: 'tr-TR'
},
{
name: 'Vietnamese (Vietnam)',
code: 'vi-VN'
},
];

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,39 @@
export default [
{
code: 'en-US',
name: 'English (US)',
voices: [
{ value: '3', name: 'Alana B.' },
{ value: '4', name: 'Ramona J.' },
{ value: '5', name: 'Ramona J. (promo)' },
{ value: '7', name: 'Wade C.' },
{ value: '8', name: 'Sofia H.' },
{ value: '9', name: 'David D.' },
{ value: '11', name: 'Isabel V.' },
{ value: '12', name: 'Ava H.' },
{ value: '13', name: 'Jeremy G.' },
{ value: '14', name: 'Nicole L.' },
{ value: '15', name: 'Paige L.' },
{ value: '16', name: 'Tobin A.' },
{ value: '17', name: 'Kai M.' },
{ value: '18', name: 'Tristan F.' },
{ value: '19', name: 'Patrick K.' },
{ value: '20', name: 'Soifia H. (promo)' },
{ value: '21', name: 'Damian P. (promo)' },
{ value: '22', name: 'Jodi P. (promo)' },
{ value: '23', name: 'Lee M. (promo)' },
{ value: '24', name: 'Selene R. (promo)' },
{ value: '26', name: 'Wade C. (promo)' },
{ value: '27', name: 'Joe F.' },
{ value: '28', name: 'Joe F. (promo)' },
{ value: '29', name: 'Garry J. (character)' },
{ value: '33', name: 'Jude D.' },
{ value: '34', name: 'Eric S. (promo)' },
{ value: '35', name: 'Chase J.' },
{ value: '37', name: 'Steve B. (promo)' },
{ value: '38', name: 'Bella B. (promo)' },
{ value: '39', name: 'Tilda C. (promo)' },
{ value: '41', name: 'Paul B. (promo)' }
],
}
];