mirror of
https://github.com/fusionpbx/fusionpbx.git
synced 2025-12-30 17:13:49 +00:00
* Initial commit of websockets * Move app_menu to the active_calls websockets * Fix hangup function * Remove connection wait-state on web socket server so events can process * Add timestamp and debug level to console for service debug output * Remove debug exit * Fix typo for ws_client instead of ws_server * Update app_config.php * Fix typo and remove empty function * Remove call to empty function * Fix the menu to point to the correct location * Remove Logging Class * Rename service file * Rename service file * Fix the in progress browser request * Fix browser reload and implement 'active_calls' default values * Add apply_filter function * Create new permission_filter object * In progress active calls now use filter * Add invalid_uuid_exception class * add event_key_filter to honor user permissions * add and_link and or_link for filters * Fix disconnected subscriber and add filters to honor permissions * Add $key and $value for filter * define a service name * catch throwable instead of exception * Add $key and $value for filter and allow returning null * Update permission checks when loading page * Add apply_filter function to honor subscriber permissions * Add create_filter_chain_for function to honor subscriber permissions * Add apply_filter function to honor subscriber permissions * Add apply_filter function to honor subscriber permissions * create interface to allow filterable payload * create interface to define functions required for websocket services * Pass in service class when creating a service token * Allow key/name and return null for filter * Adjust subscriber exceptions to return the ID of the subscriber * Add event filter to filter chain * Add command line options for ip and port for websockets and switch * update service to use is_a syntax * initial commit of base class for websockets system services * initial commit of the system cpu status service * remove extra line feed * fix path on active_calls * initial proof of concept for cpu status updated by websockets * Allow returning null * Use default settings to set the interval for cpu status broadcast * Improve the CPU percent function for Linux systems * Show more debug information * Allow child processes to re-connect to the web socket service * Fix websockets as plural instead of singular * Add class name list-row * Update active_calls.php * Update active_calls.php * Update websocket_client.js * Update app_config.php * Update app_menu.php * Update debian-websockets.service * Update debian-active_calls.service --------- Co-authored-by: FusionPBX <markjcrane@gmail.com>
298 lines
9.5 KiB
JavaScript
298 lines
9.5 KiB
JavaScript
/*
|
||
* FusionPBX
|
||
* Version: MPL 1.1
|
||
*
|
||
* The contents of this file are subject to the Mozilla Public License Version
|
||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||
* the License. You may obtain a copy of the License at
|
||
* http://www.mozilla.org/MPL/
|
||
*
|
||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||
* for the specific language governing rights and limitations under the
|
||
* License.
|
||
*
|
||
* The Original Code is FusionPBX
|
||
*
|
||
* The Initial Developer of the Original Code is
|
||
* Mark J Crane <markjcrane@fusionpbx.com>
|
||
* Portions created by the Initial Developer are Copyright (C) 2008-2025
|
||
* the Initial Developer. All Rights Reserved.
|
||
*
|
||
* Contributor(s):
|
||
* Mark J Crane <markjcrane@fusionpbx.com>
|
||
* Tim Fry <tim@fusionpbx.com>
|
||
*/
|
||
|
||
function create_arrow(direction, color) {
|
||
switch (direction) {
|
||
case 'inbound':
|
||
arrow = create_arrow_inbound(color);
|
||
break;
|
||
case 'outbound':
|
||
arrow = create_arrow_outbound(color);
|
||
break;
|
||
case 'local':
|
||
arrow = create_arrow_local(color);
|
||
break;
|
||
case 'voicemail':
|
||
arrow = create_voicemail_icon(color);
|
||
break;
|
||
case 'missed':
|
||
arrow = create_inbound_missed(color);
|
||
break;
|
||
}
|
||
return arrow;
|
||
}
|
||
|
||
function create_arrow_outbound(color, gridSize = 25) {
|
||
// Create SVG from SVG Namespace
|
||
const SVG_NS = "http://www.w3.org/2000/svg";
|
||
const svg = document.createElementNS(SVG_NS, "svg");
|
||
|
||
// compute how much to scale the original 24-unit grid
|
||
const scale = gridSize / 25;
|
||
|
||
// Set color
|
||
svg.setAttribute("stroke", color);
|
||
// Set brush width
|
||
svg.setAttribute("width", gridSize);
|
||
svg.setAttribute("height", gridSize);
|
||
svg.setAttribute("viewBox", `0 0 ${gridSize} ${gridSize}`);
|
||
svg.setAttribute("fill", "none");
|
||
svg.setAttribute("stroke-width", 2 * scale);
|
||
svg.setAttribute("stroke-linecap", "round");
|
||
|
||
// Create line
|
||
const line = document.createElementNS(SVG_NS, "line");
|
||
line.setAttribute("x1", (4 * scale).toString());
|
||
line.setAttribute("y1", (20 * scale).toString());
|
||
line.setAttribute("x2", (20 * scale).toString());
|
||
line.setAttribute("y2", (4 * scale).toString());
|
||
svg.appendChild(line);
|
||
|
||
// Create the arrow head (a right-angle triangle)
|
||
const head = document.createElementNS(SVG_NS, "polygon");
|
||
// head.setAttribute("points", "20,4 10,9 15,14");
|
||
head.setAttribute("points", [[20, 4], [10, 9], [15, 14]]
|
||
.map(([x, y]) => `${x * scale},${y * scale}`).join(" ")
|
||
);
|
||
head.setAttribute("fill", color);
|
||
svg.appendChild(head);
|
||
return svg;
|
||
}
|
||
|
||
function create_arrow_inbound(color, gridSize = 25) {
|
||
const SVG_NS = "http://www.w3.org/2000/svg";
|
||
const svg = document.createElementNS(SVG_NS, "svg");
|
||
|
||
// compute how much to scale the original 24-unit grid
|
||
const scale = gridSize / 25;
|
||
|
||
// size and viewport
|
||
svg.setAttribute("width", gridSize);
|
||
svg.setAttribute("height", gridSize);
|
||
svg.setAttribute("viewBox", `0 0 ${gridSize} ${gridSize}`);
|
||
svg.setAttribute("fill", "none");
|
||
svg.setAttribute("stroke", color);
|
||
svg.setAttribute("stroke-width", 2 * scale);
|
||
svg.setAttribute("stroke-linecap", "round");
|
||
|
||
// scaled line from (4,4) → (20,20)
|
||
const line = document.createElementNS(SVG_NS, "line");
|
||
line.setAttribute("x1", (4 * scale).toString());
|
||
line.setAttribute("y1", (4 * scale).toString());
|
||
line.setAttribute("x2", (20 * scale).toString());
|
||
line.setAttribute("y2", (20 * scale).toString());
|
||
svg.appendChild(line);
|
||
|
||
// scaled triangle head: (20,20), (10,15), (15,10)
|
||
const head = document.createElementNS(SVG_NS, "polygon");
|
||
head.setAttribute("points", [[20, 20], [10, 15], [15, 10]]
|
||
.map(([x, y]) => `${x * scale},${y * scale}`).join(" ")
|
||
);
|
||
head.setAttribute("fill", color);
|
||
svg.appendChild(head);
|
||
|
||
return svg;
|
||
}
|
||
|
||
function create_arrow_local(color, gridSize = 25) {
|
||
const SVG_NS = "http://www.w3.org/2000/svg";
|
||
const svg = document.createElementNS(SVG_NS, "svg");
|
||
|
||
// compute how much to scale the original 25-unit grid
|
||
const scale = gridSize / 25;
|
||
|
||
// sizing & styling
|
||
svg.setAttribute("width", gridSize);
|
||
svg.setAttribute("height", gridSize);
|
||
svg.setAttribute("viewBox", `0 0 ${gridSize} ${gridSize}`);
|
||
svg.setAttribute("fill", "none");
|
||
svg.setAttribute("stroke", color);
|
||
svg.setAttribute("stroke-width", 2 * scale);
|
||
svg.setAttribute("stroke-linecap", "round");
|
||
|
||
// shaft
|
||
const line = document.createElementNS(SVG_NS, "line");
|
||
line.setAttribute("x1", 6 * scale);
|
||
line.setAttribute("y1", 12 * scale);
|
||
line.setAttribute("x2", 18 * scale);
|
||
line.setAttribute("y2", 12 * scale);
|
||
svg.appendChild(line);
|
||
|
||
// left arrow head
|
||
const leftHead = document.createElementNS(SVG_NS, "polygon");
|
||
leftHead.setAttribute("points", [[6,8], [2,12], [6,16]]
|
||
.map(([x, y]) => `${x * scale},${y * scale}`).join(" ")
|
||
);
|
||
leftHead.setAttribute("fill", color);
|
||
svg.appendChild(leftHead);
|
||
|
||
// right arrow head
|
||
const rightHead = document.createElementNS(SVG_NS, "polygon");
|
||
rightHead.setAttribute("points", [[18,8], [22,12], [18,16]]
|
||
.map(([x, y]) => `${x * scale},${y * scale}`).join(" ")
|
||
);
|
||
rightHead.setAttribute("fill", color);
|
||
svg.appendChild(rightHead);
|
||
|
||
return svg;
|
||
}
|
||
|
||
function create_inbound_missed(color, gridSize = 25) {
|
||
const SVG_NS = "http://www.w3.org/2000/svg";
|
||
const svg = document.createElementNS(SVG_NS, "svg");
|
||
|
||
// compute how much to scale the original 25-unit grid
|
||
const scale = gridSize / 25;
|
||
|
||
// size and viewport
|
||
svg.setAttribute("width", gridSize);
|
||
svg.setAttribute("height", gridSize);
|
||
svg.setAttribute("viewBox", `0 0 ${gridSize} ${gridSize}`);
|
||
svg.setAttribute("fill", "none");
|
||
svg.setAttribute("stroke", color);
|
||
svg.setAttribute("stroke-width", 2 * scale);
|
||
svg.setAttribute("stroke-linecap", "round");
|
||
|
||
// 5. Reflective bounce polyline
|
||
const bounce = document.createElementNS(SVG_NS, 'polyline');
|
||
bounce.setAttribute('points', [[4, 4], [12, 12], [20, 4]]
|
||
.map(([x, y]) => `${x * scale},${y * scale}`).join(" ")
|
||
);
|
||
bounce.setAttribute('stroke', color);
|
||
bounce.setAttribute('stroke-width', 2 * scale);
|
||
bounce.setAttribute('fill', 'none');
|
||
bounce.setAttribute('stroke-linecap', 'round');
|
||
bounce.setAttribute('marker-end', 'url(#arrowhead)');
|
||
svg.appendChild(bounce);
|
||
|
||
// scaled triangle head: tip[20,4], left wing[17,5], right wing[19, 7]
|
||
const head = document.createElementNS(SVG_NS, "polygon");
|
||
head.setAttribute("points", [[20, 4], [17, 5], [19, 7]]
|
||
.map(([x, y]) => `${x * scale},${y * scale}`).join(" ")
|
||
);
|
||
head.setAttribute("fill", color);
|
||
svg.appendChild(head);
|
||
|
||
// Left earpiece
|
||
const left = document.createElementNS(SVG_NS, 'ellipse');
|
||
left.setAttribute("cx", 4 * scale);
|
||
left.setAttribute("cy", 17 * scale);
|
||
left.setAttribute("rx", 2 * scale);
|
||
left.setAttribute("ry", 1 * scale);
|
||
left.setAttribute("fill", color);
|
||
svg.appendChild(left);
|
||
|
||
// Right earpiece
|
||
const right = document.createElementNS(SVG_NS, 'ellipse');
|
||
right.setAttribute("cx", 18 * scale);
|
||
right.setAttribute("cy", 17 * scale);
|
||
right.setAttribute("rx", 2 * scale);
|
||
right.setAttribute("ry", 1 * scale);
|
||
right.setAttribute("fill", color);
|
||
svg.appendChild(right);
|
||
|
||
// Arc to join left and right
|
||
const startX = 3 * scale; // left cx + rx
|
||
const startY = 17 * scale; // cy - ry
|
||
const endX = 19 * scale; // right cx - rx
|
||
const endY = startY;
|
||
|
||
// choose radii so the handle bows upwards
|
||
const rx = (endX - startX) / 2; // half the distance
|
||
const ry = 2.2 * scale; // controls how tall the arc is
|
||
|
||
const arc = document.createElementNS(SVG_NS, 'path');
|
||
// Move to the left‐earpiece top, then arc to the right‐earpiece top
|
||
const d = `M${startX},${startY} A${rx},${ry} 0 0,1 ${endX},${endY}`;
|
||
arc.setAttribute('d', d);
|
||
arc.setAttribute('stroke', color);
|
||
arc.setAttribute('stroke-width', 2 * scale);
|
||
arc.setAttribute('stroke-linecap', 'round');
|
||
|
||
svg.appendChild(arc);
|
||
return svg;
|
||
}
|
||
|
||
function create_voicemail_icon(fillColor, gridSize = 25) {
|
||
// SVG namespace
|
||
const SVG_NS = 'http://www.w3.org/2000/svg';
|
||
|
||
const scale = gridSize / 25;
|
||
const width = scale * 25;
|
||
const height = scale * 25;
|
||
|
||
// Create the root SVG element
|
||
const svg = document.createElementNS(SVG_NS, 'svg');
|
||
svg.setAttribute('width', width);
|
||
svg.setAttribute('height', height);
|
||
svg.setAttribute('viewBox', '0 0 25 25');
|
||
svg.setAttribute('aria-hidden', 'true');
|
||
|
||
// Border rectangle (inserted first so it's underneath)
|
||
const border = document.createElementNS(SVG_NS, 'rect');
|
||
y = 7;
|
||
border.setAttribute('x', 1);
|
||
border.setAttribute('y', y);
|
||
border.setAttribute('width', 23);
|
||
border.setAttribute('height', 21 - y);
|
||
border.setAttribute('fill', 'none');
|
||
border.setAttribute('stroke', fillColor);
|
||
border.setAttribute('stroke-width', '2');
|
||
svg.appendChild(border);
|
||
|
||
// Left circle
|
||
const left_circle = document.createElementNS(SVG_NS, 'circle');
|
||
left_circle.setAttribute('cx', 7);
|
||
left_circle.setAttribute('cy', 14);
|
||
left_circle.setAttribute('r', 3);
|
||
left_circle.setAttribute('fill', 'none');
|
||
left_circle.setAttribute('stroke', fillColor);
|
||
left_circle.setAttribute('stroke-width', '2');
|
||
svg.appendChild(left_circle);
|
||
|
||
// Right circle
|
||
const right_circle = document.createElementNS(SVG_NS, 'circle');
|
||
right_circle.setAttribute('cx', 18);
|
||
right_circle.setAttribute('cy', 14);
|
||
right_circle.setAttribute('r', 3);
|
||
right_circle.setAttribute('fill', 'none');
|
||
right_circle.setAttribute('stroke', fillColor);
|
||
right_circle.setAttribute('stroke-width', '2');
|
||
svg.appendChild(right_circle);
|
||
|
||
// Connecting line
|
||
const bar = document.createElementNS(SVG_NS, 'line');
|
||
bar.setAttribute('x1', 6);
|
||
bar.setAttribute('y1', 11);
|
||
bar.setAttribute('x2', 19);
|
||
bar.setAttribute('y2', 11);
|
||
bar.setAttribute('stroke', fillColor);
|
||
bar.setAttribute('stroke-width', '2');
|
||
svg.appendChild(bar);
|
||
|
||
return svg;
|
||
}
|