Feature admin only numbers & carrier (#587)

* Hide create carrier/number controls if ADMIN_CARRIER env var is set

* hide add caririer button

* add to example .env

* hide delete phone number
This commit is contained in:
Sam Machin
2026-01-07 13:01:12 +00:00
committed by GitHub
parent c33eb46ce0
commit c9fcdb08eb
5 changed files with 74 additions and 40 deletions

4
.env
View File

@@ -31,4 +31,6 @@
## AWS region for enabling Recent Call Feature server logs
#VITE_APP_AWS_REGION=us-west-2
## enable lazy loading for phone numbers (improves performance when managing large quantities)
# VITE_APP_ENABLE_PHONE_NUMBER_LAZY_LOAD=true
# VITE_APP_ENABLE_PHONE_NUMBER_LAZY_LOAD=true
# hides controlls to add Carrier and Phone number from non Admin/SP Users (also need to set flag on API server to block API calls)
#VITE_ADMIN_CARRIER=1

View File

@@ -18,7 +18,7 @@ DISABLE_CALL_RECORDING=${DISABLE_CALL_RECORDING:-false}
# Serialize window global to provide the API URL to static frontend dist
# This is declared and utilized in the web app: src/api/constants.ts
SCRIPT_TAG="<script>window.JAMBONZ = {API_BASE_URL: \"${API_BASE_URL}\",DISABLE_LCR: \"${DISABLE_LCR}\",DISABLE_JAEGER_TRACING: \"${DISABLE_JAEGER_TRACING}\",DISABLE_CUSTOM_SPEECH: \"${DISABLE_CUSTOM_SPEECH}\",ENABLE_FORGOT_PASSWORD: \"${ENABLE_FORGOT_PASSWORD}\",DISABLE_CALL_RECORDING: \"${DISABLE_CALL_RECORDING}\"};</script>"
SCRIPT_TAG="<script>window.JAMBONZ = {API_BASE_URL: \"${API_BASE_URL}\",DISABLE_LCR: \"${DISABLE_LCR}\",DISABLE_JAEGER_TRACING: \"${DISABLE_JAEGER_TRACING}\",DISABLE_CUSTOM_SPEECH: \"${DISABLE_CUSTOM_SPEECH}\",ENABLE_FORGOT_PASSWORD: \"${ENABLE_FORGOT_PASSWORD}\",DISABLE_CALL_RECORDING: \"${DISABLE_CALL_RECORDING}\",ADMIN_CARRIER: \"${ADMIN_CARRIER}\"};</script>"
sed -i -e "\@</head>@i\ $SCRIPT_TAG" ./dist/index.html
# Start the frontend web app static server

View File

@@ -35,6 +35,7 @@ interface JambonzWindowObject {
DISABLE_ADDITIONAL_SPEECH_VENDORS: string;
AWS_REGION: string;
ENABLE_PHONE_NUMBER_LAZY_LOAD: string;
ADMIN_CARRIER: string;
}
declare global {
@@ -110,6 +111,8 @@ export const STRIPE_PUBLISHABLE_KEY: string =
window.JAMBONZ?.STRIPE_PUBLISHABLE_KEY ||
import.meta.env.VITE_APP_STRIPE_PUBLISHABLE_KEY;
export const ADMIN_CARRIER: string =
window.JAMBONZ?.ADMIN_CARRIER || import.meta.env.VITE_ADMIN_CARRIER || "0";
/** TCP Max Port */
export const TCP_MAX_PORT = 65535;

View File

@@ -31,6 +31,9 @@ import {
ENABLE_HOSTED_SYSTEM,
PER_PAGE_SELECTION,
USER_ACCOUNT,
ADMIN_CARRIER,
USER_ADMIN,
USER_SP,
} from "src/api/constants";
import { DeleteCarrier } from "./delete";
@@ -202,13 +205,16 @@ export const Carriers = () => {
</M>
)}
</div>
<Link to={`${ROUTE_INTERNAL_CARRIERS}/add`} title="Add a Carrier">
{" "}
<Icon>
<Icons.Plus />
</Icon>
</Link>
{((ADMIN_CARRIER === "1" &&
(user?.scope === USER_ADMIN || user?.scope === USER_SP)) ||
ADMIN_CARRIER === "0") && (
<Link to={`${ROUTE_INTERNAL_CARRIERS}/add`} title="Add a Carrier">
{" "}
<Icon>
<Icons.Plus />
</Icon>
</Link>
)}
</section>
<section className="filters filters--multi">
<SearchFilter
@@ -325,11 +331,15 @@ export const Carriers = () => {
)}
</div>
</Section>
<Section clean>
<Button small as={Link} to={`${ROUTE_INTERNAL_CARRIERS}/add`}>
Add carrier
</Button>
</Section>
{((ADMIN_CARRIER === "1" &&
(user?.scope === USER_ADMIN || user?.scope === USER_SP)) ||
ADMIN_CARRIER === "0") && (
<Section clean>
<Button small as={Link} to={`${ROUTE_INTERNAL_CARRIERS}/add`}>
Add carrier
</Button>
</Section>
)}
<footer>
<ButtonGroup>
<MS>

View File

@@ -28,7 +28,13 @@ import { hasLength, hasValue, formatPhoneNumber } from "src/utils";
import { DeletePhoneNumber } from "./delete";
import type { Account, PhoneNumber, Carrier, Application } from "src/api/types";
import { PER_PAGE_SELECTION, USER_ACCOUNT } from "src/api/constants";
import {
PER_PAGE_SELECTION,
USER_ACCOUNT,
USER_ADMIN,
ADMIN_CARRIER,
USER_SP,
} from "src/api/constants";
import { ScopedAccess } from "src/components/scoped-access";
import { Scope } from "src/store/types";
import { getAccountFilter, setLocation } from "src/store/localStore";
@@ -185,16 +191,20 @@ export const PhoneNumbers = () => {
<>
<section className="mast">
<H1 className="h2">Phone numbers</H1>
{hasLength(accounts) && hasLength(carriers) && (
<Link
to={`${ROUTE_INTERNAL_PHONE_NUMBERS}/add`}
title="Add a phone number"
>
<Icon>
<Icons.Plus />
</Icon>
</Link>
)}
{hasLength(accounts) &&
hasLength(carriers) &&
((ADMIN_CARRIER === "1" &&
(user?.scope === USER_ADMIN || user?.scope === USER_SP)) ||
ADMIN_CARRIER === "0") && (
<Link
to={`${ROUTE_INTERNAL_PHONE_NUMBERS}/add`}
title="Add a phone number"
>
<Icon>
<Icons.Plus />
</Icon>
</Link>
)}
</section>
<section className="filters filters--multi">
<SearchFilter
@@ -368,14 +378,19 @@ export const PhoneNumbers = () => {
>
<Icons.Edit3 />
</Link>
<button
type="button"
title="Delete phone number"
onClick={() => setPhoneNumber(phoneNumber)}
className="btnty"
>
<Icons.Trash />
</button>
{((ADMIN_CARRIER === "1" &&
(user?.scope === USER_ADMIN ||
user?.scope === USER_SP)) ||
ADMIN_CARRIER === "0") && (
<button
type="button"
title="Delete phone number"
onClick={() => setPhoneNumber(phoneNumber)}
className="btnty"
>
<Icons.Trash />
</button>
)}
</div>
</div>
);
@@ -404,13 +419,17 @@ export const PhoneNumbers = () => {
)}
</div>
</Section>
<Section clean>
{hasLength(accounts) && hasLength(carriers) && (
<Button small as={Link} to={`${ROUTE_INTERNAL_PHONE_NUMBERS}/add`}>
Add phone number
</Button>
)}
</Section>
{((ADMIN_CARRIER === "1" &&
(user?.scope === USER_ADMIN || user?.scope === USER_SP)) ||
ADMIN_CARRIER === "0") && (
<Section clean>
{hasLength(accounts) && hasLength(carriers) && (
<Button small as={Link} to={`${ROUTE_INTERNAL_PHONE_NUMBERS}/add`}>
Add phone number
</Button>
)}
</Section>
)}
<footer>
<ButtonGroup>
<MS>