Rack: draw the UniFi UACC blank 24-port keystone patch panel
Lint / JS (eslint) (push) Successful in 7s
Lint / Python (flake8) (push) Successful in 58s
Lint / Notify on failure (push) Skipped
Lint / Deploy (push) Skipped
Lint / JS (eslint) (pull_request) Successful in 11s
Lint / Python (flake8) (pull_request) Successful in 1m6s
Lint / Notify on failure (pull_request) Skipped
Lint / Deploy (pull_request) Skipped
Security / Python Security (bandit) (push) Successful in 1m0s
Test / Python Tests (pytest) (push) Successful in 1m59s
Security / Python Security (bandit) (pull_request) Successful in 1m42s
Test / Python Tests (pytest) (pull_request) Successful in 1m0s
Lint / JS (eslint) (push) Successful in 7s
Lint / Python (flake8) (push) Successful in 58s
Lint / Notify on failure (push) Skipped
Lint / Deploy (push) Skipped
Lint / JS (eslint) (pull_request) Successful in 11s
Lint / Python (flake8) (pull_request) Successful in 1m6s
Lint / Notify on failure (pull_request) Skipped
Lint / Deploy (pull_request) Skipped
Security / Python Security (bandit) (push) Successful in 1m0s
Test / Python Tests (pytest) (push) Successful in 1m59s
Security / Python Security (bandit) (pull_request) Successful in 1m42s
Test / Python Tests (pytest) (pull_request) Successful in 1m0s
Front drawing "UniFi Patch Panel Blank 24" draws the real panel, laid out from the CC0 NetBox devicetype-library image: grey steel face, darker ears with oval holes, 24 keystone openings with the cable-support bar behind them, and a cable slot at each end. Ports with a documented cable get a keystone jack; cutsheet marks, port labels and run highlighting work as on the generic panel. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -105,6 +105,48 @@ function shelfHtml(item) {
|
||||
</div>`;
|
||||
}
|
||||
|
||||
// Ubiquiti UACC-Rack-Panel-Patch-Blank-24, laid out from the CC0 NetBox devicetype-library image
|
||||
// (elevation-images/Ubiquiti/ubiquiti-uacc-rack-panel-patch-blank-24.front.png): a grey steel face,
|
||||
// darker ears with oval holes, 24 square keystone openings in one row with the cable-support bar
|
||||
// behind them, and a narrow cable slot at each end. A port with a documented cable gets a keystone jack.
|
||||
function uaccPanelSvg(item) {
|
||||
const W = 1178, H = 108, x0 = 107, pitch = 40.5, ow = 34, oy = 36, oh = 40;
|
||||
const count = Math.min(item.port_count || 24, 24);
|
||||
const ports = [];
|
||||
for (let n = 1; n <= count; n++) {
|
||||
const x = x0 + (n - 1) * pitch;
|
||||
const m = item.ports[String(n)];
|
||||
const label = item.labels[String(n)] || '';
|
||||
const title = [`Port ${n}`, label && `"${label}"`, m ? m.text : 'not on the cutsheet'].filter(Boolean).join(' · ');
|
||||
const attrs = m ? ` data-run="${m.run.join(' ')}" data-cable="${m.cable_id}" tabindex="0" role="link"` : '';
|
||||
const jack = m ? `<rect class="ua-keystone" x="${x + 3}" y="${oy + 3}" width="${ow - 6}" height="${oh - 6}" rx="2"/>
|
||||
<path class="ua-keystone-hole" d="M${x + 7} ${oy + 13} h20 v14 h-4 v4 h-12 v-4 h-4 z"/>` : '';
|
||||
ports.push(`<g class="rack-pp-port ua-port${m ? ` rack-pp-${m.mark}` : ''}"${attrs}>
|
||||
<title>${esc(title)}</title>
|
||||
<rect class="ua-open" x="${x}" y="${oy}" width="${ow}" height="${oh}"/>
|
||||
<rect class="ua-bar" x="${x}" y="${oy + 19}" width="${ow}" height="5"/>
|
||||
${jack}
|
||||
<rect class="rack-pp-jack ua-mark" x="${x - 1}" y="${oy - 1}" width="${ow + 2}" height="${oh + 2}" rx="1"/>
|
||||
<text class="ua-num" x="${x + ow / 2}" y="${oy - 6}" text-anchor="middle">${n}</text>
|
||||
${label ? `<text class="ua-label" x="${x + ow / 2}" y="${oy + oh + 12}" text-anchor="middle">${esc(label.length > 7 ? `${label.slice(0, 6)}…` : label)}</text>` : ''}
|
||||
<rect class="rack-pp-hit" x="${x - 3}" y="${oy - 16}" width="${pitch}" height="${oh + 32}"/>
|
||||
</g>`);
|
||||
}
|
||||
const hole = (x, y) => `<rect class="ua-hole" x="${x}" y="${y}" width="22" height="13" rx="6.5"/>`;
|
||||
return `<svg class="rack-svg" viewBox="0 0 ${W} ${H}" preserveAspectRatio="none" role="group"
|
||||
aria-label="${esc(item.name)} patch panel">
|
||||
<title>${esc(item.name)}</title>
|
||||
<rect class="ua-ear" x="0" y="2" width="44" height="${H - 4}" rx="3"/>
|
||||
<rect class="ua-ear" x="${W - 44}" y="2" width="44" height="${H - 4}" rx="3"/>
|
||||
${hole(8, 12)}${hole(8, 83)}${hole(W - 30, 12)}${hole(W - 30, 83)}
|
||||
<rect class="ua-face" x="36" y="0" width="${W - 72}" height="${H}" rx="2"/>
|
||||
<rect class="ua-lip" x="36" y="0" width="${W - 72}" height="4"/>
|
||||
<rect class="ua-open" x="62" y="${oy}" width="28" height="${oh}"/><rect class="ua-bar" x="62" y="${oy + 19}" width="28" height="5"/>
|
||||
<rect class="ua-open" x="${W - 95}" y="${oy}" width="28" height="${oh}"/><rect class="ua-bar" x="${W - 95}" y="${oy + 19}" width="28" height="5"/>
|
||||
${ports.join('')}
|
||||
</svg>`;
|
||||
}
|
||||
|
||||
function plateHtml(item) {
|
||||
const unlinked = item.kind === 'device' && !item.linked;
|
||||
const sub = [item.device !== item.name ? item.device : '', KIND_TEXT[item.kind] || item.kind, item.location,
|
||||
@@ -129,6 +171,7 @@ function itemHtml(item) {
|
||||
else if (item.switch && isRackFaceplate(item.switch.model)) body = switchHtml(item);
|
||||
else if (CHASSIS_FACEPLATES[item.chassis]) body = switchHtml(item, CHASSIS_FACEPLATES[item.chassis]);
|
||||
else if (item.chassis && RACK_FRONTS[item.chassis]) body = rackFrontSvg(item.chassis, item);
|
||||
else if (item.kind === 'patch_panel' && item.chassis === 'uacc-patch-24') body = uaccPanelSvg(item);
|
||||
else if (item.kind === 'patch_panel') body = panelSvg(item);
|
||||
else if (item.kind === 'shelf') body = shelfHtml(item);
|
||||
else body = plateHtml(item);
|
||||
|
||||
@@ -1567,3 +1567,20 @@ body.fp-marks-off .fp-svg .fp-mark { display: none; }
|
||||
.rf-unvr-dot { fill: #ffffff; stroke: #c4c6ca; }
|
||||
.rf-screen { fill: #0f1726; }
|
||||
.rf-screen-ring { fill: none; stroke-width: 3; }
|
||||
|
||||
/* Ubiquiti UACC-Rack-Panel-Patch-Blank-24 (static/rack.js uaccPanelSvg) */
|
||||
.ua-ear { fill: #6f7277; }
|
||||
.ua-hole { fill: #15181c; }
|
||||
.ua-face { fill: #8e9095; stroke: #6c6f74; }
|
||||
.ua-lip { fill: #a6a8ad; }
|
||||
.ua-open { fill: #17191d; }
|
||||
.ua-bar { fill: #9a9ca1; }
|
||||
.ua-keystone { fill: #101113; stroke: #2b2d31; }
|
||||
.ua-keystone-hole { fill: #2f3236; }
|
||||
.ua-num { fill: #2b2d31; font-size: 9px; font-family: Arial, Helvetica, sans-serif; }
|
||||
.ua-label { fill: #1f2124; font-size: 8.5px; font-weight: 700; font-family: Arial, Helvetica, sans-serif; }
|
||||
.ua-mark { fill: none; stroke: transparent; }
|
||||
.rack-pp-ok .ua-mark { stroke: #00b860; stroke-width: 2.5; }
|
||||
.rack-pp-bad .ua-mark { stroke: #e0312b; stroke-width: 3; }
|
||||
.rack-pp-doc .ua-mark { stroke: #4c5662; stroke-width: 2; }
|
||||
.rack-pp-port.rack-hl .ua-mark { fill: rgba(0,212,255,.25); stroke: #00b8e6; stroke-width: 3.5; }
|
||||
|
||||
Reference in New Issue
Block a user