discussed changes

This commit is contained in:
eglehelms
2022-12-07 18:10:52 +01:00
parent bb460c82ef
commit 27cc99287d
12 changed files with 370 additions and 379 deletions
@@ -186,6 +186,9 @@ export const AccountForm = ({ apps, limits, account }: AccountFormProps) => {
.then(() => {
account.refetch();
toastSuccess("Account updated successfully");
if (user?.scope !== USER_ACCOUNT) {
navigate(ROUTE_INTERNAL_ACCOUNTS);
}
})
.catch((error) => {
toastError(error.msg);
@@ -164,6 +164,7 @@ export const ApplicationForm = ({ application }: ApplicationFormProps) => {
.then(() => {
application.refetch();
toastSuccess("Application updated successfully");
navigate(`${ROUTE_INTERNAL_APPLICATIONS}`);
})
.catch((error) => {
toastError(error.msg);
+269 -320
View File
@@ -36,7 +36,6 @@ import {
AccountSelect,
ApplicationSelect,
} from "src/components/forms";
import { ScopedAccess } from "src/components/scoped-access";
import { MSG_REQUIRED_FIELDS } from "src/constants";
import { ROUTE_INTERNAL_CARRIERS } from "src/router/routes";
import { toastError, toastSuccess, useSelectState } from "src/store";
@@ -53,7 +52,6 @@ import type {
Smpp,
Application,
} from "src/api/types";
import { Scope } from "src/store/types";
type CarrierFormProps = {
carrier?: UseApiDataMap<Carrier>;
@@ -512,6 +510,7 @@ export const CarrierForm = ({
toastSuccess("Carrier updated successfully");
carrier.refetch();
navigate(ROUTE_INTERNAL_CARRIERS);
})
.catch((error) => {
toastError(error.msg);
@@ -748,122 +747,117 @@ export const CarrierForm = ({
</>
)}
</fieldset>
<ScopedAccess
user={user}
scope={accountSid ? Scope.account : Scope.service_provider}
>
<fieldset>
<Checkzone
hidden
name="sip_credentials"
label="Outbound Authentication"
initialCheck={initialRegister}
handleChecked={(e) => {
if (!e.target.checked) {
setSipUser("");
setSipPass("");
setSipRealm("");
setSipRegister(false);
setFromUser("");
setFromDomain("");
setRegPublicIpInContact(false);
}
<fieldset>
<Checkzone
hidden
name="sip_credentials"
label="Outbound Authentication"
initialCheck={initialRegister}
handleChecked={(e) => {
if (!e.target.checked) {
setSipUser("");
setSipPass("");
setSipRealm("");
setSipRegister(false);
setFromUser("");
setFromDomain("");
setRegPublicIpInContact(false);
}
}}
>
<MS>
Does your carrier require authentication on outbound calls?
</MS>
<label htmlFor="sip_username">
Username {sipPass || sipRegister ? <span>*</span> : ""}
</label>
<input
id="sip_username"
name="sip_username"
type="text"
value={sipUser}
placeholder="SIP username for authenticating outbound calls"
required={sipRegister || sipPass.length > 0}
onChange={(e) => {
setSipUser(e.target.value);
}}
>
<MS>
Does your carrier require authentication on outbound calls?
</MS>
<label htmlFor="sip_username">
Username {sipPass || sipRegister ? <span>*</span> : ""}
</label>
/>
<label htmlFor="sip_password">
Password
{sipUser || sipRegister ? <span>*</span> : ""}
</label>
<Passwd
id="sip_password"
name="sip_password"
value={sipPass}
placeholder="SIP password for authenticating outbound calls"
required={sipRegister || sipUser.length > 0}
onChange={(e) => {
setSipPass(e.target.value);
}}
/>
<label htmlFor="sip_register" className="chk">
<input
id="sip_username"
name="sip_username"
type="text"
value={sipUser}
placeholder="SIP username for authenticating outbound calls"
required={sipRegister || sipPass.length > 0}
onChange={(e) => {
setSipUser(e.target.value);
}}
id="sip_register"
name="sip_register"
type="checkbox"
checked={sipRegister}
onChange={(e) => setSipRegister(e.target.checked)}
/>
<label htmlFor="sip_password">
Password
{sipUser || sipRegister ? <span>*</span> : ""}
</label>
<Passwd
id="sip_password"
name="sip_password"
value={sipPass}
placeholder="SIP password for authenticating outbound calls"
required={sipRegister || sipUser.length > 0}
onChange={(e) => {
setSipPass(e.target.value);
}}
/>
<label htmlFor="sip_register" className="chk">
<div>Require SIP Register</div>
</label>
{sipRegister && (
<>
<MS>
Carrier requires SIP Register before sending outbound
calls.
</MS>
<label htmlFor="sip_realm">
SIP Realm{sipRegister ? <span>*</span> : ""}
</label>
<input
id="sip_register"
name="sip_register"
type="checkbox"
checked={sipRegister}
onChange={(e) => setSipRegister(e.target.checked)}
id="sip_realm"
name="sip_realm"
type="text"
value={sipRealm}
placeholder="SIP realm for registration"
required={sipRegister}
onChange={(e) => setSipRealm(e.target.value)}
/>
<div>Require SIP Register</div>
</label>
{sipRegister && (
<>
<MS>
Carrier requires SIP Register before sending outbound
calls.
</MS>
<label htmlFor="sip_realm">
SIP Realm{sipRegister ? <span>*</span> : ""}
</label>
<label htmlFor="from_user">SIP From User</label>
<input
id="from_user"
name="from_user"
type="text"
value={fromUser}
placeholder="Optional: specify user part of SIP From header"
onChange={(e) => setFromUser(e.target.value)}
/>
<label htmlFor="from_domain">SIP From Domain</label>
<input
id="from_domain"
name="from_domain"
type="text"
value={fromDomain}
placeholder="Optional: specify host part of SIP From header"
onChange={(e) => setFromDomain(e.target.value)}
/>
<label htmlFor="reg_public_ip_in_contact" className="chk">
<input
id="sip_realm"
name="sip_realm"
type="text"
value={sipRealm}
placeholder="SIP realm for registration"
required={sipRegister}
onChange={(e) => setSipRealm(e.target.value)}
id="reg_public_ip_in_contact"
name="reg_public_ip_in_contact"
type="checkbox"
checked={regPublicIpInContact}
onChange={(e) =>
setRegPublicIpInContact(e.target.checked)
}
/>
<label htmlFor="from_user">SIP From User</label>
<input
id="from_user"
name="from_user"
type="text"
value={fromUser}
placeholder="Optional: specify user part of SIP From header"
onChange={(e) => setFromUser(e.target.value)}
/>
<label htmlFor="from_domain">SIP From Domain</label>
<input
id="from_domain"
name="from_domain"
type="text"
value={fromDomain}
placeholder="Optional: specify host part of SIP From header"
onChange={(e) => setFromDomain(e.target.value)}
/>
<label htmlFor="reg_public_ip_in_contact" className="chk">
<input
id="reg_public_ip_in_contact"
name="reg_public_ip_in_contact"
type="checkbox"
checked={regPublicIpInContact}
onChange={(e) =>
setRegPublicIpInContact(e.target.checked)
}
/>
<div>Use Public IP in Contact</div>
</label>
</>
)}
</Checkzone>
</fieldset>
</ScopedAccess>
<div>Use Public IP in Contact</div>
</label>
</>
)}
</Checkzone>
</fieldset>
<fieldset>
<Checkzone
hidden
@@ -1028,61 +1022,50 @@ export const CarrierForm = ({
</label>
</div>
</div>
<ScopedAccess
user={user}
scope={
accountSid ? Scope.account : Scope.service_provider
}
<button
className="btnty"
title="Delete SIP Gateway"
type="button"
onClick={() => {
setSipMessage("");
if (sipGateways.length === 1) {
setSipMessage(
"You must provide at least one SIP Gateway."
);
} else {
handleSipGatewayDelete(
sipGateways.find((g2, i2) => i2 === i)
);
setSipGateways(
sipGateways.filter((g2, i2) => i2 !== i)
);
}
}}
>
<button
className="btnty"
title="Delete SIP Gateway"
type="button"
onClick={() => {
setSipMessage("");
if (sipGateways.length === 1) {
setSipMessage(
"You must provide at least one SIP Gateway."
);
} else {
handleSipGatewayDelete(
sipGateways.find((g2, i2) => i2 === i)
);
setSipGateways(
sipGateways.filter((g2, i2) => i2 !== i)
);
}
}}
>
<Icon>
<Icons.Trash2 />
</Icon>
</button>
</ScopedAccess>
<Icon>
<Icons.Trash2 />
</Icon>
</button>
</div>
))}
<ScopedAccess
user={user}
scope={accountSid ? Scope.account : Scope.service_provider}
>
<ButtonGroup left>
<button
className="btnty"
type="button"
title="Add SIP Gateway"
onClick={() => {
setSipMessage("");
addSipGateway();
}}
>
<Icon subStyle="teal">
<Icons.Plus />
</Icon>
</button>
</ButtonGroup>
</ScopedAccess>
<ButtonGroup left>
<button
className="btnty"
type="button"
title="Add SIP Gateway"
onClick={() => {
setSipMessage("");
addSipGateway();
}}
>
<Icon subStyle="teal">
<Icons.Plus />
</Icon>
</button>
</ButtonGroup>
</fieldset>
</Tab>
<Tab id="smpp" label="SMS">
@@ -1104,32 +1087,27 @@ export const CarrierForm = ({
</fieldset>
<fieldset>
<label htmlFor="outbound_smpp">Outbound SMPP</label>
<ScopedAccess
user={user}
scope={accountSid ? Scope.account : Scope.service_provider}
>
<label htmlFor="outbound_id">System ID</label>
<input
id="outbound_id"
name="outbound_id"
type="text"
value={smppSystemId}
placeholder="SMPP system ID to authenticate with"
onChange={(e) => {
setSmppSystemId(e.target.value);
}}
/>
<label htmlFor="outbound_pass">Password</label>
<Passwd
id="outbound_pass"
name="outbound_pass"
value={smppPass}
placeholder="SMPP password to authenticate with"
onChange={(e) => {
setSmppPass(e.target.value);
}}
/>
</ScopedAccess>
<label htmlFor="outbound_id">System ID</label>
<input
id="outbound_id"
name="outbound_id"
type="text"
value={smppSystemId}
placeholder="SMPP system ID to authenticate with"
onChange={(e) => {
setSmppSystemId(e.target.value);
}}
/>
<label htmlFor="outbound_pass">Password</label>
<Passwd
id="outbound_pass"
name="outbound_pass"
value={smppPass}
placeholder="SMPP password to authenticate with"
onChange={(e) => {
setSmppPass(e.target.value);
}}
/>
<label htmlFor="outbound_smpp">
Carrier SMPP Gateways
<span>{smppSystemId || smppPass ? "*" : ""}</span>
@@ -1203,103 +1181,86 @@ export const CarrierForm = ({
</label>
</div>
</div>
<ScopedAccess
user={user}
scope={
accountSid ? Scope.account : Scope.service_provider
}
<button
title="Delete Outbound SMPP Gateway"
type="button"
className="btnty"
onClick={() => {
setSmppOutboundMessage("");
if (
hasLength(smpps) &&
smppGateways.filter((g) => g.outbound).length <=
1 &&
(smppSystemId || smppPass)
) {
setSmppOutboundMessage(
"You must provide at least one Outbound Gateway."
);
} else {
handleSmppGatewayDelete(
smppGateways.find((g2, i2) => i2 === i)
);
setSmppGateways(
smppGateways.filter((g2, i2) => i2 !== i)
);
}
}}
>
<button
title="Delete Outbound SMPP Gateway"
type="button"
className="btnty"
onClick={() => {
setSmppOutboundMessage("");
if (
hasLength(smpps) &&
smppGateways.filter((g) => g.outbound).length <=
1 &&
(smppSystemId || smppPass)
) {
setSmppOutboundMessage(
"You must provide at least one Outbound Gateway."
);
} else {
handleSmppGatewayDelete(
smppGateways.find((g2, i2) => i2 === i)
);
setSmppGateways(
smppGateways.filter((g2, i2) => i2 !== i)
);
}
}}
>
<Icon>
<Icons.Trash2 />
</Icon>
</button>
</ScopedAccess>
<Icon>
<Icons.Trash2 />
</Icon>
</button>
</div>
) : null;
})}
<ScopedAccess
user={user}
scope={accountSid ? Scope.account : Scope.service_provider}
>
<ButtonGroup left>
<button
className="btnty"
type="button"
onClick={() => addSmppGateway({ inbound: 0, outbound: 1 })}
title="Add Outbound SMPP Gateway"
>
<Icon subStyle="teal">
<Icons.Plus />
</Icon>
</button>
</ButtonGroup>
</ScopedAccess>
<ButtonGroup left>
<button
className="btnty"
type="button"
onClick={() => addSmppGateway({ inbound: 0, outbound: 1 })}
title="Add Outbound SMPP Gateway"
>
<Icon subStyle="teal">
<Icons.Plus />
</Icon>
</button>
</ButtonGroup>
</fieldset>
<fieldset>
<label htmlFor="inbound_smpp">Inbound SMPP</label>
<ScopedAccess
user={user}
scope={accountSid ? Scope.account : Scope.service_provider}
>
<label htmlFor="inbound_id">System ID</label>
<input
id="inbound_id"
name="inbound_id"
type="text"
value={smppInboundSystemId}
placeholder="SMPP system ID to authenticate with"
onChange={(e) => {
setSmppInboundSystemId(e.target.value);
}}
/>
<label htmlFor="inbound_pass">
Password
<span>{!hasEmptySmppGateways("inbound") ? "*" : ""}</span>
</label>
<MXS>
<em>
Password is required if whitelisting carrier IP address(es)
below.
</em>
</MXS>
<Passwd
id="inbound_pass"
name="inbound_pass"
value={smppInboundPass}
placeholder="SMPP password for authenticating inbound messages"
required={!hasEmptySmppGateways("inbound")}
onChange={(e) => {
setSmppInboundPass(e.target.value);
}}
/>
</ScopedAccess>
<label htmlFor="inbound_id">System ID</label>
<input
id="inbound_id"
name="inbound_id"
type="text"
value={smppInboundSystemId}
placeholder="SMPP system ID to authenticate with"
onChange={(e) => {
setSmppInboundSystemId(e.target.value);
}}
/>
<label htmlFor="inbound_pass">
Password
<span>{!hasEmptySmppGateways("inbound") ? "*" : ""}</span>
</label>
<MXS>
<em>
Password is required if whitelisting carrier IP address(es)
below.
</em>
</MXS>
<Passwd
id="inbound_pass"
name="inbound_pass"
value={smppInboundPass}
placeholder="SMPP password for authenticating inbound messages"
required={!hasEmptySmppGateways("inbound")}
onChange={(e) => {
setSmppInboundPass(e.target.value);
}}
/>
<label htmlFor="inbound_smpp">
Carrier IP Address(es) to whitelist
</label>
@@ -1345,51 +1306,39 @@ export const CarrierForm = ({
/>
</div>
</div>
<ScopedAccess
user={user}
scope={
accountSid ? Scope.account : Scope.service_provider
}
>
<button
className="btnty"
title="Delete Inbound SMPP Gateway"
type="button"
onClick={() => {
handleSmppGatewayDelete(
smppGateways.find((g2, i2) => i2 === i)
);
<button
className="btnty"
title="Delete Inbound SMPP Gateway"
type="button"
onClick={() => {
handleSmppGatewayDelete(
smppGateways.find((g2, i2) => i2 === i)
);
setSmppGateways(
smppGateways.filter((g2, i2) => i2 !== i)
);
}}
>
<Icon>
<Icons.Trash2 />
</Icon>
</button>
</ScopedAccess>
setSmppGateways(
smppGateways.filter((g2, i2) => i2 !== i)
);
}}
>
<Icon>
<Icons.Trash2 />
</Icon>
</button>
</div>
) : null;
})}
<ScopedAccess
user={user}
scope={accountSid ? Scope.account : Scope.service_provider}
>
<ButtonGroup left>
<button
className="btnty"
type="button"
onClick={() => addSmppGateway({ outbound: 0, inbound: 1 })}
title="Add Inbound SMPP Gateway"
>
<Icon subStyle="teal">
<Icons.Plus />
</Icon>
</button>
</ButtonGroup>
</ScopedAccess>
<ButtonGroup left>
<button
className="btnty"
type="button"
onClick={() => addSmppGateway({ outbound: 0, inbound: 1 })}
title="Add Inbound SMPP Gateway"
>
<Icon subStyle="teal">
<Icons.Plus />
</Icon>
</button>
</ButtonGroup>
</fieldset>
</Tab>
</Tabs>
@@ -17,6 +17,8 @@ import {
Spinner,
SearchFilter,
} from "src/components";
import { ScopedAccess } from "src/components/scoped-access";
import { Gateways } from "./gateways";
import { hasLength, hasValue, useFilteredResults } from "src/utils";
import {
API_ACCOUNTS,
@@ -28,7 +30,7 @@ import {
import { DeleteCarrier } from "./delete";
import type { Account, Carrier, SipGateway, SmppGateway } from "src/api/types";
import { Gateways } from "./gateways";
import { Scope } from "src/store/types";
export const Carriers = () => {
const user = useSelectState("user");
@@ -174,14 +176,19 @@ export const Carriers = () => {
<div className="item" key={carrier.voip_carrier_sid}>
<div className="item__info">
<div className="item__title">
<Link
to={`${ROUTE_INTERNAL_CARRIERS}/${carrier.voip_carrier_sid}/edit`}
title="Edit Carrier"
className="i"
>
<ScopedAccess user={user} scope={Scope.service_provider}>
<Link
to={`${ROUTE_INTERNAL_CARRIERS}/${carrier.voip_carrier_sid}/edit`}
title="Edit Carrier"
className="i"
>
<strong>{carrier.name}</strong>
<Icons.ArrowRight />
</Link>
</ScopedAccess>
{user?.scope === USER_ACCOUNT && (
<strong>{carrier.name}</strong>
<Icons.ArrowRight />
</Link>
)}
</div>
<div className="item__meta">
<div>
@@ -201,22 +208,27 @@ export const Carriers = () => {
<Gateways carrier={carrier} />
</div>
</div>
<div className="item__actions">
<Link
to={`${ROUTE_INTERNAL_CARRIERS}/${carrier.voip_carrier_sid}/edit`}
title="Edit Carrier"
>
<Icons.Edit3 />
</Link>
<button
type="button"
title="Delete Carrier"
onClick={() => setCarrier(carrier)}
className="btnty"
>
<Icons.Trash />
</button>
</div>
<ScopedAccess
user={user}
scope={!accountSid ? Scope.service_provider : Scope.account}
>
<div className="item__actions">
<Link
to={`${ROUTE_INTERNAL_CARRIERS}/${carrier.voip_carrier_sid}/edit`}
title="Edit Carrier"
>
<Icons.Edit3 />
</Link>
<button
type="button"
title="Delete Carrier"
onClick={() => setCarrier(carrier)}
className="btnty"
>
<Icons.Trash />
</button>
</div>
</ScopedAccess>
</div>
))
) : (
@@ -88,6 +88,7 @@ export const PhoneNumberForm = ({ phoneNumber }: PhoneNumberFormProps) => {
.then(() => {
phoneNumber.refetch();
toastSuccess("Phone number updated successfully");
navigate(ROUTE_INTERNAL_PHONE_NUMBERS);
})
.catch((error) => {
toastError(error.msg);
@@ -132,7 +132,7 @@ export const PhoneNumbers = () => {
)
: accounts
}
defaultOption
defaultOption={user?.scope !== USER_ACCOUNT}
/>
</section>
<Section {...(hasLength(filteredPhoneNumbers) && { slim: true })}>
@@ -146,6 +146,7 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
if (credential && credential.data) {
toastSuccess("Speech credential updated successfully");
credential.refetch();
navigate(ROUTE_INTERNAL_SPEECH);
}
})
.catch((error) => {
@@ -22,6 +22,8 @@ import { getUsage } from "./utils";
import { CredentialStatus } from "./status";
import type { SpeechCredential, Account } from "src/api/types";
import { ScopedAccess } from "src/components/scoped-access";
import { Scope } from "src/store/types";
export const SpeechServices = () => {
const user = useSelectState("user");
@@ -142,14 +144,24 @@ export const SpeechServices = () => {
<div className="item" key={credential.speech_credential_sid}>
<div className="item__info">
<div className="item__title">
<Link
to={`${ROUTE_INTERNAL_SPEECH}/${credential.speech_credential_sid}/edit`}
title="Edit application"
className="i"
<ScopedAccess
user={user}
scope={
!accountSid ? Scope.service_provider : Scope.account
}
>
<Link
to={`${ROUTE_INTERNAL_SPEECH}/${credential.speech_credential_sid}/edit`}
title="Edit application"
className="i"
>
<strong>Vendor: {credential.vendor}</strong>
<Icons.ArrowRight />
</Link>
</ScopedAccess>
{user?.scope === USER_ACCOUNT && (
<strong>Vendor: {credential.vendor}</strong>
<Icons.ArrowRight />
</Link>
)}
</div>
<div className="item__meta">
<div>
@@ -191,22 +203,27 @@ export const SpeechServices = () => {
</div>
</div>
</div>
<div className="item__actions">
<Link
to={`${ROUTE_INTERNAL_SPEECH}/${credential.speech_credential_sid}/edit`}
title="Edit speech service"
>
<Icons.Edit3 />
</Link>
<button
type="button"
title="Delete speech service"
onClick={() => setCredential(credential)}
className="btnty"
>
<Icons.Trash />
</button>
</div>
<ScopedAccess
user={user}
scope={!accountSid ? Scope.service_provider : Scope.account}
>
<div className="item__actions">
<Link
to={`${ROUTE_INTERNAL_SPEECH}/${credential.speech_credential_sid}/edit`}
title="Edit speech service"
>
<Icons.Edit3 />
</Link>
<button
type="button"
title="Delete speech service"
onClick={() => setCredential(credential)}
className="btnty"
>
<Icons.Trash />
</button>
</div>
</ScopedAccess>
</div>
);
})
@@ -170,6 +170,7 @@ export const UserForm = ({ user }: UserFormProps) => {
setIsActive(!!user.data.is_active);
setEmail(user.data.email);
setScope(getUserScope(user.data));
user.data.account_sid ? setAccountSid(user.data.account_sid) : false;
}
}, [user]);
+15 -10
View File
@@ -110,17 +110,15 @@ export const Users = () => {
)
: accounts
}
defaultOption
defaultOption={user?.scope !== USER_ACCOUNT}
/>
</section>
<Section slim>
<div className="grid grid--col5">
<div className="grid grid--col3--users">
<div className="grid__row grid__th">
<div>User Name</div>
<div>Email</div>
<div>Scope</div>
<div>Access</div>
<div>Managed resource</div>
<div>&nbsp;</div>
</div>
{!hasValue(users) ? (
@@ -129,13 +127,20 @@ export const Users = () => {
filteredUsers.map((user) => {
return (
<div className="grid__row" key={user.user_sid}>
<div>{user.name}</div>
<div>{user.email}</div>
<div>{user.scope}</div>
<div>
<Link
to={`${ROUTE_INTERNAL_USERS}/${user.user_sid}/edit`}
title="Edit user"
>
<div>{user.name}</div>
</Link>
</div>
<div>
{user.scope === USER_ADMIN
? null
: user.account_name || user.service_provider_name}
? "All"
: user.account_name
? `Account: ${user.account_name}`
: `Service Provider: ${user.service_provider_name}`}
</div>
<div className="item__actions">
<Link
+2 -2
View File
@@ -99,9 +99,9 @@
}
}
&--col5 {
&--col3--users {
.grid__row {
grid-template-columns: [col] 30% [col] 20% [col] 20% [col] 28% [col] 2%;
grid-template-columns: [col] 40% [col] 58% [col] 2%;
grid-template-rows: [row] auto [row] auto [row] [row] auto;
display: grid;
justify-content: space-between;
+1
View File
@@ -34,6 +34,7 @@
display: flex;
align-items: center;
grid-gap: ui-vars.$px02;
color: ui-vars.$jambonz;
+ .item__meta {
@include mixins.small() {