collabSupport/integrations/paloalto/urls.js
jmcqueen 9d0dbb071e Add per-app DPI voice-quality checks + widen WAN window to 7d
Adds three new SD-WAN checks (wanAppRtpMos/Loss/Jitter) that measure
REAL voice-traffic quality on actual RTP frames via Prisma DPI, not
synthetic link probes. Graded against the WORST 5-minute window so
transient degradation the 24h link-probe averages smooth away
actually surfaces.

Voice-app selection is tenant-configurable via PRISMA_APP_ID_VOICE +
PRISMA_APP_NAME_VOICE (Webex_Calling_RTP recommended for Webex
Calling shops — the Webex-specific DPI signature excludes non-Webex
UDP noise). Legacy PRISMA_APP_ID_RTP_BASE still honored with a
one-time deprecation warning.

Widens the default WAN look-back from 24h to 7 days: per-app metrics
only get datapoints when calls actually happen, so sporadic Webex
Calling stores (3-4 calls/day) need a wider window for worst-window
statistics to be meaningful. Interval picker snaps 7d to 1hour
buckets (168 pts) to keep payloads bounded while preserving
worst-hour granularity. Hard-capped at 7d — beyond that Prisma
downsamples to 1-day buckets and the signal collapses.

Also:
- Client-side concurrency limiter (PRISMA_MAX_INFLIGHT, default 3)
  to prevent 429 cascades when /voicediag fans out 10+ parallel
  metric fetches
- "View in Prisma UI" deep links in both /phonestatus WAN follow-up
  and /voicediag details, threading through a new
  integrations/paloalto/urls.js builder
- humanizeMetricUnit maps raw API unit strings ("percentage",
  "milliseconds") to display symbols ("%", "ms") to fix
  "11.83percentage" leaking to the UI
- getAppAudio envelope distinguishes not-configured / fetch-failed /
  no-traffic states so misleading "set env var" messages don't fire
  when the real problem is a 429

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-09 13:54:15 -04:00

52 lines
2 KiB
JavaScript

// src/integrations/paloalto/urls.js
//
// Prisma Strata Cloud Manager (UI) URL builders. Lives beside the
// API client so any new deep-link pattern we discover has one
// obvious home and one obvious set of tests.
//
// Kept intentionally tiny: no HTTP, no async, no fancy templating —
// each function is pure ("give me the URL for X"). Consumers should
// pass ids they already have from the API (site.id, appAudio.appId,
// etc.); nothing in here should do its own API lookups.
const PRISMA_UI_DEFAULT_BASE = 'https://stratacloudmanager.paloaltonetworks.com';
/**
* Resolve the Strata Cloud Manager base URL.
*
* Defaults to the production hostname. Overridable via
* `PRISMA_UI_BASE_URL` for tenants using a partner-branded or
* region-specific SCM domain, and for tests. Read at call time so
* tests can toggle without a module cache reset.
*
* The trailing slash is normalized off so all builders below can
* safely concatenate `${base}/path/…`.
*/
export function getPrismaUiBaseUrl() {
const raw = process.env.PRISMA_UI_BASE_URL;
const base = raw && raw.trim() ? raw.trim() : PRISMA_UI_DEFAULT_BASE;
return base.replace(/\/+$/, '');
}
/**
* Deep link into the SCM "Application Path Details" view for a
* single app + site combination. This is the exact page the Prisma
* UI opens when the operator clicks an app on the site's dashboard —
* the RTP/MOS/loss/jitter charts we scrape via `getAppMetric()`.
*
* Sample:
* https://stratacloudmanager.paloaltonetworks.com/insights/
* operational/sdwan-applications/{appId}/site/{siteId}/details
*
* Returns null when either id is missing so callers can no-op
* without a null guard on every render path.
*
* @param {string|number} siteId Numeric Prisma site id
* @param {string|number} appId Numeric Prisma app id
* @returns {string|null}
*/
export function buildAppDetailsUrl(siteId, appId) {
if (!siteId || !appId) return null;
const base = getPrismaUiBaseUrl();
return `${base}/insights/operational/sdwan-applications/${appId}/site/${siteId}/details`;
}