Files
fusionpbx/app/active_calls/resources/javascript/arrows.js
frytimo d5286a12bc Websockets (#7393)
* 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>
2025-06-24 13:07:57 -06:00

298 lines
9.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* 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 leftearpiece top, then arc to the rightearpiece 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;
}