'use strict'; /* exported RACK_FRONTS, CHASSIS_FACEPLATES, rackFrontSvg */ // Drawn fronts for rack gear Gandalf can't read a faceplate from: custom-built servers. Chosen per cutsheet item ("Front drawing"). Each one // shows the device's live status on its power light when the item is linked to a device. // // Spec: { label, units, width, height, draw(ctx) -> SVG markup }, ctx: { status, name }. // Width:height should be about 10.5:1 per rack unit so the drawing fills its slot. const FRONT_STATUS = { up: '#2fd36b', degraded: '#ffb300', down: '#e0312b' }; function frontLed(status) { return FRONT_STATUS[status] || '#6b737d'; } function ears(w, h, cls = 'rf-ear') { // Rack ears with their mounting slots, both sides const slots = Array.from({ length: Math.round(h / 105) }, (_, i) => 105 * i + 52); const holes = x => slots.map(y => ``).join(''); return `${holes(12)} ${holes(w - 21)}`; } function vents(x0, x1, y, h = 8, gap = 6, seg = 120) { const out = []; for (let x = x0; x + seg <= x1; x += seg + gap) out.push(``); return out.join(''); } function powerButton(cx, cy, r, status) { return ` `; } function usbA(x, y) { return ``; } function usbC(x, y) { return ``; } function keyLock(cx, cy) { return ``; } function brand(x, y, text, anchor = 'start') { return `${text}`; } function driveBay(x, y, w, h, vertical) { // A hot-swap bay: tray face, latch and activity light const latch = vertical ? `` : ``; const led = vertical ? `` : ``; return `${latch}${led}`; } const RACK_FRONTS = { // Sliger CX4712 4U with its faceplate off (as driveAtlas draws it): two 5.25" blanks side by // side, ten 3.5" hot-swap bays standing on edge in one row, a narrow I/O strip on the right. 'sliger-cx4712': { label: 'Sliger CX4712 4U (10-bay)', units: 4, width: 1100, height: 420, draw({ status }) { // Bays numbered left to right, the local convention driveAtlas uses for this case const bays = Array.from({ length: 10 }, (_, i) => `${driveBay(78 + i * 86, 150, 78, 228, true)} ${i + 1}`).join(''); return `${ears(1100, 420, 'rf-ear-dark')} ${vents(98, 480, 74, 7, 8, 40)}${vents(530, 912, 74, 7, 8, 40)} ${bays} ${powerButton(1002, 78, 20, status)} ${usbA(991, 130)}${usbA(991, 150)}${usbC(995, 176)} ${keyLock(1002, 220)} ${brand(1002, 372, 'SLIGER', 'middle')}`; }, }, // Rosewill RSV-L4500U 4U: the perforated, lockable drop-down door over the fan wall // (15 bays sit behind it), D-handles on the ears, I/O strip with power and USB on the right. 'rosewill-rsv-l4500u': { label: 'Rosewill RSV-L4500U 4U (15-bay)', units: 4, width: 1100, height: 420, draw({ status }) { const fan = cx => ` ${[0, 72, 144, 216, 288].map(a => ``).join('')}`; const handle = x => ``; return `${ears(1100, 420, 'rf-ear-dark')} ${handle(36)}${handle(1048)} ${fan(225)}${fan(504)}${fan(783)} ${powerButton(997, 62, 18, status)} ${usbA(986, 160)}${usbA(986, 180)} ${keyLock(997, 232)} ${brand(997, 388, 'ROSEWILL', 'middle')}`; }, }, // Generic servers, for gear without a specific drawing 'server-1u': genericServer(1, 4), 'server-2u': genericServer(2, 12), 'server-4u': genericServer(4, 24), }; function genericServer(units, bays) { const H = 105 * units; return { label: `Generic ${units}U server`, units, width: 1100, height: H, draw({ status }) { const rows = Math.max(1, Math.round(units * 0.75)); const cols = Math.ceil(bays / rows); const bw = Math.min(118, 720 / cols - 8); const bh = (H - 30 - (rows - 1) * 8) / rows; const out = []; for (let r = 0; r < rows; r++) { for (let c = 0; c < cols && r * cols + c < bays; c++) out.push(driveBay(60 + c * (bw + 8), 15 + r * (bh + 8), bw, bh, false)); } return `${ears(1100, H, 'rf-ear-dark')} ${out.join('')} ${vents(810, 1040, 18, 7, 6, 36)}${units > 1 ? vents(810, 1040, H - 26, 7, 6, 36) : ''} ${powerButton(1020, H / 2, Math.min(18, H / 5), status)}`; }, }; } // Front drawings that are full faceplates in faceplates.js (same parts as the UniFi gear) const CHASSIS_FACEPLATES = { 'unvr-pro': 'UNVRPRO', // For a new switch before UniFi reports it (or under a model code not mapped yet) 'usw-pro-max-24-poe': 'USPM24P', 'usw-pro-max-48-poe': 'USPM48P', }; // The markup for one item's drawn front, or '' when the key is unknown function rackFrontSvg(key, ctx) { const spec = RACK_FRONTS[key]; if (!spec) return ''; return ` ${lt.escHtml(`${ctx.name} · ${spec.label}${ctx.status ? ` · ${ctx.status}` : ''}`)} ${spec.draw(ctx)} `; }